/* =====================================================================
   AI BOS Community OS — AI BOS Light Community Theme (default)
   Clean Community SaaS meets Notion-style Workspace.
   Sáng · gọn · dễ đọc · nhiều khoảng trắng · cam tiết chế.
   KHÔNG copy Skool/Notion — chỉ lấy cảm giác sản phẩm.
   ===================================================================== */
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap');

:root{
  /* Surfaces */
  --background:#F7F7F5;
  --surface:#FFFFFF;
  --surface-muted:#F3F3F1;
  /* Nền ô hình trực tiếp. Cố ý KHÔNG dùng --surface: ô video phải tối ở MỌI
     chủ đề, vì viền sáng quanh khuôn hình làm mắt tự bù trừ và người ta tưởng
     camera mình bị tối. Chữ trên nền đó cũng phải sáng theo. */
  --live-o-nen:#12121A;
  --live-o-chu:#E8E8EE;
  --sidebar-bg:#F8F8F6;
  --sidebar-active:#EFEDEA;
  --sidebar-hover:#F1F0ED;

  /* Borders */
  --border:#E5E2DC;
  --border-strong:#D6D2CA;
  /* 🔴 VIỀN CỦA KHỐI CHỨA (card) — CỐ Ý MỜ HƠN --border.
     Founder 2026-08-21, kèm ảnh mẫu: card tách nhau bằng KHOẢNG TRẮNG và một
     lớp bóng rất nhẹ, không bằng đường kẻ. Một trang có 12 cái hộp đóng khung
     thì mắt phải đọc 12 đường kẻ trước khi đọc tới nội dung.
     Vì sao KHÔNG hạ thẳng `--border`: token đó còn dùng cho ô nhập, ô chọn,
     nút viền và đường phân cách — chúng là CHI TIẾT ĐIỀU KHIỂN, WCAG 1.4.11
     đòi tương phản ≥3:1 với nền để người ta còn nhận ra đâu là chỗ gõ được.
     Hộp chứa thì không phải điều khiển, nên được phép mờ. Hai việc khác nhau,
     hai token khác nhau. */
  /* Hạ thêm một nấc (Founder 2026-08-21: "viền vẫn đậm"). #EFEDE8 vẫn đọc ra
     một đường kẻ; #F2F0EB gần như hoà vào mép trắng của card, chỉ còn đủ để mắt
     bắt được cạnh — đúng như bản mẫu, nơi card tách nhau bằng khoảng trắng và
     bóng chứ không bằng đường viền. */
  /* Hạ nấc thứ BA (Founder xin mờ thêm). #E5E2DC → #EFEDE8 → #F2F0EB → #F6F4F1. */
  --border-card:#F6F4F1;

  /* Text */
  --text-primary:#171717;
  --text-secondary:#555555;
  --text-muted:#8A8A8A;
  --text-disabled:#B5B5B5;

  /* Accent (AI BOS orange — tiết chế) */
  /* 🔴 HAI SẮC CAM, HAI VIỆC KHÁC NHAU — luật cứng hạng 1 (WCAG AA), thắng cả
     Brand Guideline. ĐO 22/08/2026 bằng công thức tương phản WCAG:

        #cc6600  trên trắng 3,84 · kem 3,58 · cam nhạt 3,49  → ĐỦ cho NỀN/VIỀN
                 (thành phần giao diện chỉ cần 3:1), KHÔNG đủ cho CHỮ (cần 4,5)
        #a35200  trên trắng 5,58 · kem 5,20 · cam nhạt 5,07  → ĐỦ cho CHỮ ✅

     ⚠️ Đã cân nhắc #b35900 và LOẠI: nó đạt trên trắng (4,83) nhưng TRƯỢT trên
     nền cam nhạt — 4,39 trên --accent-soft và 4,18 trên chip rgba(204,102,0,.14),
     mà đó đúng là hai chỗ accent hay được dùng làm chữ nhất. #a35200 đã có sẵn
     trong file này và đạt mọi nền, nên dùng nó — đừng đẻ thêm token thứ ba.

     LUẬT: accent làm CHỮ  → var(--accent-hover)
           accent làm NỀN/VIỀN/icon → var(--accent) */
  --accent:#cc6600;
  --accent-hover:#a35200;
  --accent-soft:#FFF2E5;
  --accent-border:#F0C399;

  /* Status */
  --success:#22C55E; --success-strong:#15803D; --success-soft:#ECFDF3; --success-border:#BBF7D0;
  --warning:#D97706; --warning-soft:#FFF7ED;
  --danger:#DC2626;  --danger-soft:#FEF2F2;
  --admin-bg:#171717; --admin-text:#FFFFFF;

  /* Shape & depth */
  --radius-sm:8px; --radius-md:12px; --radius-lg:16px; --radius-xl:22px;
  --shadow-soft:0 1px 2px rgba(0,0,0,0.04);
  --shadow-card:0 8px 24px rgba(0,0,0,0.06);
  --shadow-pop:0 12px 36px rgba(0,0,0,0.12);

  --font:'Inter',ui-sans-serif,system-ui,-apple-system,Segoe UI,Arial,sans-serif;
  /* Đo từ ảnh mẫu Founder gửi 2026-08-21 (quy về màn 1440px):
     rail 58 · thanh bên 277 · cột giữa 738 · cột phải 349. */
  --sidebar-w:272px;
  --topbar-h:56px;
  /* Chiều cao THẬT của bottom nav mobile: 59px nội dung + vạch home của iPhone.
     Trước đây mỗi chỗ tự đoán một số cứng (64px ở #os-page, 70px ở .chat) và cả
     hai đều quên env(safe-area-inset-bottom) — trên máy có vạch home là lệch
     ngay ~34px. Từ giờ chỉ có MỘT nguồn cho con số này. */
  --bottomnav-h:calc(59px + env(safe-area-inset-bottom));

  /* Typography tokens (PHẦN 9) — to, dễ đọc như ChatGPT */
  --fs-xs:0.8125rem;   /* 13px - metadata phụ */
  --fs-sm:0.9375rem;   /* 15px - sidebar, button, label */
  --fs-base:1rem;      /* 16px - body */
  --fs-md:1.0625rem;   /* 17px - card title, post body */
  --fs-lg:1.125rem;    /* 18px - post title, section */
  --fs-xl:1.375rem;    /* 22px - page title */
  --fs-2xl:1.75rem;    /* 28px */
  --fs-3xl:2.125rem;   /* 34px - hero */
  --lh-tight:1.25; --lh-normal:1.55; --lh-relaxed:1.7;

  /* aliases để code dùng chung tên ngắn */
  --bg:var(--background);
  --line:var(--border);
  --line-soft:var(--border-strong);
  --text:var(--text-primary);
  --muted:var(--text-secondary);
  --muted-2:var(--text-muted);
  --orange:var(--accent); --orange-deep:var(--accent-hover);
  --orange-soft:var(--accent-hover); --orange-glow:var(--accent-soft);
  --green:var(--success); --green-soft:var(--success-soft);
  --surface-2:var(--surface-muted); --surface-3:#ECEBE7;
}

*{box-sizing:border-box;margin:0;padding:0}
html,body,#os-root{width:100%;max-width:100vw;overflow-x:hidden}
html{-webkit-text-size-adjust:100%;text-size-adjust:100%}
body{overscroll-behavior-x:none}
img,video,canvas{max-width:100%}
svg{flex:0 0 auto}
.nav-item__ic{display:inline-flex;align-items:center;justify-content:center}
.btn svg,.icon-btn svg,.section-head svg,.pill svg,.search svg{display:block}
.btn svg{margin-right:-2px}
.ico-line{display:inline-flex;align-items:center;justify-content:center;color:var(--text-secondary)}
.ico-accent{color:var(--accent-hover)}
.tile__ico{width:40px;height:40px;border-radius:11px;background:var(--surface-muted);display:grid;place-items:center;color:var(--text-secondary)}
.tile__ico--accent{background:var(--accent-soft);color:var(--accent-hover)}
html,body{height:100%}
html{font-size:16px}
body{
  font-family:var(--font);background:var(--background);color:var(--text-primary);
  font-size:var(--fs-base);line-height:1.6;-webkit-font-smoothing:antialiased;
}
a{color:inherit;text-decoration:none}
button{font-family:inherit;cursor:pointer}
::-webkit-scrollbar{width:10px;height:10px}
::-webkit-scrollbar-thumb{background:#DAD7D0;border-radius:8px}
::-webkit-scrollbar-track{background:transparent}
:focus-visible{outline:2px solid var(--accent);outline-offset:2px}

/* ---------- App Shell ---------- */
.shell{display:grid;grid-template-columns:var(--sidebar-w) 1fr;min-height:100vh}
@supports(height:100dvh){.shell{min-height:100dvh}}

/* 🔴 `position:fixed`, KHÔNG phải `sticky` — sửa 25/08/2026.
   Founder: "Fix cứng tab menu bên cột trái giống như trang bảng tin, không cuộn
   lên xuống. Chỉ có 2 cột chính giữa và bên phải cuộn thôi."

   VÌ SAO `sticky` KHÔNG ĂN Ở ĐÂY (đo được trên production):
   `sticky` dính theo TỔ TIÊN CUỘN GẦN NHẤT. Trong app này kẻ cuộn lại là chính
   `<body>` (`overflow-y:auto`), nên sidebar không có tổ tiên cuộn nào ở giữa để
   mà dính vào — nó trôi theo trang. Đo: cuộn 500px thì mép trên sidebar đi từ
   `0` xuống `-500`.
   Trang Bảng tin không lộ lỗi này chỉ vì `#os-page.is-khung` khoá cả trang
   không cho cuộn ở khổ ≥1181px — che mất triệu chứng chứ không sửa nó.

   `fixed` dính theo KHUNG NHÌN nên đúng ở mọi trang, bất kể ai đang cuộn.
   Cột trong lưới `.shell` vẫn giữ nguyên chỗ (grid vẫn khai đủ cột), nên nội
   dung không bị trượt sang trái.
   Chỉ áp từ 768px — dưới mốc đó `.sidebar{display:none}` và app dùng thanh dưới. */
.sidebar{
  background:var(--sidebar-bg);border-right:1px solid var(--border);
  display:flex;flex-direction:column;height:100vh;overflow:hidden;
}
@media(min-width:768px){
  .sidebar{position:fixed;top:0;left:0;width:var(--sidebar-w);z-index:20}
  /* 🔴 `fixed` RÚT SIDEBAR KHỎI LƯỚI — phải xếp chỗ lại cho cột nội dung.
     Lỗi Founder bắt được 25/08/2026 (ảnh Admin Center): một phần tử `fixed` là
     phần tử NGOÀI DÒNG, nên nó không còn chiếm ô nào của grid nữa. Track vẫn
     còn (grid-template-columns không đổi), nhưng `.main` là phần tử trong dòng
     ĐẦU TIÊN nên tự rơi vào cột 1 — đúng cột mà sidebar đang phủ lên. Kết quả:
     bảng nội dung chui xuống dưới sidebar, thanh trên cùng tụt về sát mép trái.
     Khai `grid-column` tường minh thì `.main` về đúng cột cuối.
     `.thu-menu` cũng `position:fixed` nên nó không ăn ô nào — không cần xếp. */
  .shell > .main{grid-column:2}
  .shell--rail > .main{grid-column:3}
  /* Có dải biểu tượng cộng đồng bên trái thì sidebar phải nhích sang đúng bấy
     nhiêu — nếu không nó đè lên dải đó. */
  .shell--rail .sidebar{left:var(--comm-rail-w)}
  /* Thu gọn sidebar: cột co về 0 thì bản `fixed` cũng phải biến mất theo, nếu
     không nó nằm đè lên nội dung mà lưới thì đã thu chỗ lại rồi. */
  .shell--rail.is-thu .sidebar{display:none}
}
.sidebar__brand{display:flex;align-items:center;gap:9px;padding:11px 14px;border-bottom:1px solid var(--border);min-height:var(--topbar-h)}
.brandmark{
  width:34px;height:34px;border-radius:9px;flex:0 0 auto;overflow:hidden;
  background:var(--accent-hover);display:grid;place-items:center;font-weight:800;color:#fff;font-size:15px;
}
.brandmark img{width:100%;height:100%;object-fit:cover;display:block}
.brandmark--green{background:var(--success)}
.sidebar__title{font-weight:700;font-size:15px;letter-spacing:-.01em;line-height:1.15}
.sidebar__title small{display:block;color:var(--text-muted);font-weight:500;font-size:11px}
/* 🔴 FLEX-COLUMN để cụm dưới dồn được xuống chân (Founder chốt 24/08/2026).
   `.nav-group--day-xuong` mang `margin-top:auto`: còn chỗ trống thì nó nuốt hết
   và đẩy cụm xuống sát chân; hết chỗ thì lề tự về 0 và danh sách cuộn như cũ. */
.sidebar__nav{flex:1;overflow-y:auto;padding:8px 8px 16px;display:flex;flex-direction:column}
/* Không cần `flex:0 0 auto` cho `.nav-group`. Em đã thêm dòng đó rồi ĐO và
   thấy nó không đổi gì: flex item mang `min-height:auto` nên đã không co xuống
   dưới chiều cao nội dung — 40 kênh vẫn cho ra đúng 68px như 3 kênh. Giữ một
   luật không gánh việc gì là để lại cho người sau một câu hỏi không có đáp án.
   Phép đo giữ lại ở tests/media/chan-thanh-ben.mjs (so 3 kênh với 40 kênh). */
/* 🔴 PHẢI THẮNG BẰNG ĐỘ ĐẶC HIỆU, KHÔNG BẰNG THỨ TỰ DÒNG.
   Đối thủ còn lại: `.nav-group{margin-top:9px}` (0,1,0), nằm SAU khối này.
   Hai bản vá đầu của em lần lượt là (0,1,0) rồi (0,2,0) — cùng hạng hoặc thấp
   hơn nên đối thủ nằm sau thắng, và luật này KHÔNG BAO GIỜ CHẠY. Nhìn màn hình
   thì y hệt như chưa sửa gì; thứ duy nhất lộ ra là phép thử phá cho ra ĐÚNG
   cùng con số với bản chưa phá. Nay (0,3,0): thắng chắc.
   ⚠️ 05/09/2026: đối thủ thứ hai (`.nav-group--vach…{margin-top:12px}`) đã GỠ
   cùng đường kẻ ngang — xem ghi chú ở ~2314. Không còn `border-top` nào trong
   danh sách cuộn; đường kẻ duy nhất còn lại của thanh bên là của `.sidebar__brand`
   (trên cùng) và `.sidebar__footer` (dưới cùng), hai cái đó KHÔNG bị gỡ. */
.sidebar__nav > .nav-group.nav-group--day-xuong{margin-top:auto}
/* 🔴 CHÂN THANH BÊN — GHIM CỨNG, KHÔNG CUỘN (Founder chốt 24/08/2026).
   `.sidebar` đã là flex-column cao 100vh, `.sidebar__nav` chiếm `flex:1` và tự
   cuộn. Nên khối này chỉ cần `flex:0 0 auto` là nằm chết ở đáy: danh sách kênh
   dài bao nhiêu cũng không đẩy nó đi, và người dùng không phải cuộn xuống cuối
   mới thấy lối vào Admin Center / Hồ sơ.
   Viền TRÊN chứ không phải khung: nó tách chân khỏi danh sách bằng đúng một
   đường, cùng token với mọi đường phân cách khác trong app. */
.sidebar__footer{flex:0 0 auto;padding:8px;border-top:1px solid var(--border);background:var(--sidebar-bg)}
.sidebar__footer .nav-item{margin:0}
.nav-group{margin-top:9px}
.nav-group__label{font-size:11px;text-transform:uppercase;letter-spacing:.07em;color:var(--text-muted);padding:5px 10px 3px;font-weight:600}
.nav-item{
  display:flex;align-items:center;gap:10px;padding:6px 10px;border-radius:var(--radius-sm);
  color:var(--text-secondary);font-weight:500;font-size:14px;margin-bottom:1px;
  transition:background .14s,color .14s;cursor:pointer;
}
.nav-item:hover{background:var(--sidebar-hover);color:var(--text-primary)}
.nav-item.active{background:var(--accent-soft);color:var(--accent-hover);font-weight:600}
.nav-item__ic{width:18px;text-align:center;font-size:15px;flex:0 0 auto}
.nav-item__badge{margin-left:auto;background:var(--accent-hover);color:#fff;font-size:10px;font-weight:700;padding:1px 7px;border-radius:20px}
.nav-item__badge--green{background:var(--success)}
.nav-group--col .nav-group__toggle{display:flex;align-items:center;justify-content:space-between;cursor:pointer;user-select:none}
.nav-group__chev{display:inline-flex;transition:transform .18s;color:var(--text-muted)}
.nav-group--col.is-collapsed .nav-group__chev{transform:rotate(-90deg)}
.nav-group--col.is-collapsed .nav-group__items{display:none}
.kbd{display:inline-flex;gap:2px;font-size:10px;border:1px solid var(--border);border-radius:5px;padding:1px 5px;color:var(--text-muted);background:var(--surface-muted)}
.demo-note{display:inline-flex;align-items:center;gap:6px;font-size:11.5px;font-weight:600;color:var(--warning);background:var(--warning-soft);border:1px solid #FBD9A8;padding:3px 9px;border-radius:20px}
.cmdk{position:fixed;inset:0;z-index:130;display:flex;justify-content:center;padding-top:12vh;background:rgba(23,23,23,.34);backdrop-filter:blur(2px)}
.cmdk__box{width:100%;max-width:560px;height:max-content;background:var(--surface);border:1px solid var(--border-card);border-radius:var(--radius-lg);box-shadow:var(--shadow-pop);overflow:hidden}
.cmdk__in{width:100%;border:none;border-bottom:1px solid var(--border);padding:15px 18px;font-size:15px;outline:none;color:var(--text-primary);background:none}
.cmdk__list{max-height:52vh;overflow-y:auto;padding:6px}
.cmdk__item{display:flex;align-items:center;gap:11px;padding:10px 12px;border-radius:10px;cursor:pointer}
.cmdk__item:hover,.cmdk__item.sel{background:var(--surface-muted)}
.cmdk__type{margin-left:auto;font-size:11px;color:var(--text-muted)}

/* ---------- Topbar ---------- */
.main{display:flex;flex-direction:column;min-width:0}
.topbar{
  height:var(--topbar-h);position:sticky;top:0;z-index:40;
  background:rgba(255,255,255,.85);backdrop-filter:blur(10px);
  border-bottom:1px solid var(--border);
  display:flex;align-items:center;gap:14px;padding:0 22px;
}
.topbar__menu{display:none;background:var(--surface);border:1px solid var(--border-card);color:var(--text-primary);width:38px;height:38px;border-radius:10px;font-size:18px}
.search{
  flex:1;max-width:440px;display:flex;align-items:center;gap:9px;
  background:var(--surface-muted);border:1px solid var(--border);border-radius:12px;padding:9px 13px;
}
.search input{flex:1;background:none;border:none;color:var(--text-primary);font-size:var(--fs-sm);outline:none}
.search input::placeholder{color:var(--text-muted)}
.topbar__spacer{flex:1}
.icon-btn{
  position:relative;width:40px;height:40px;min-width:40px;flex:0 0 auto;border-radius:11px;border:1px solid var(--border);
  background:var(--surface);color:var(--text-primary);font-size:17px;display:grid;place-items:center;
  transition:border-color .14s,background .14s;
}
.icon-btn:hover{border-color:var(--border-strong);background:var(--surface-muted)}
.icon-btn .dot{position:absolute;top:8px;right:9px;width:8px;height:8px;border-radius:50%;background:var(--accent);border:2px solid var(--surface)}
.avatar{
  width:42px;height:42px;border-radius:50%;background:var(--accent-soft);
  border:1px solid var(--accent-border);display:grid;place-items:center;font-weight:700;color:var(--accent-hover);font-size:14px;
}
.avatar--sm{width:34px;height:34px;font-size:12px}
.avatar--lg{width:64px;height:64px;font-size:22px}

/* ---------- Content ---------- */
/* 🔴 KHÔNG cap 1200px nữa. Ảnh mẫu trải HẾT bề ngang cửa sổ — cap lại thì trên
   màn rộng hai bên là hai dải trống, và cột giữa hẹp hơn mẫu đúng bằng phần bị
   cắt. `max-width` lớn chỉ để chữ không dài quá sức đọc trên màn siêu rộng. */
.content{padding:18px 24px 56px;max-width:1680px;width:100%;margin:0 auto}
.page-head{display:flex;align-items:flex-start;gap:14px;flex-wrap:wrap;margin-bottom:22px}
.page-head h1{font-size:var(--fs-2xl);font-weight:800;letter-spacing:-.02em}
.page-head__actions{margin-left:auto;display:flex;gap:10px;flex-wrap:wrap}

/* ---------- Buttons ---------- */
.btn{display:inline-flex;align-items:center;gap:8px;border-radius:var(--radius-md);padding:10px 16px;font-weight:600;font-size:var(--fs-sm);border:1px solid transparent;transition:.14s;white-space:nowrap}
.btn--primary{background:var(--accent-hover);color:#fff;border-color:var(--accent)}
.btn--primary:hover{background:var(--accent-hover);border-color:var(--accent-hover)}
.btn--ghost{background:var(--surface);color:var(--text-primary);border-color:var(--border-strong)}
.btn--ghost:hover{background:var(--surface-muted)}
.btn--soft{background:transparent;color:var(--text-secondary)}
.btn--soft:hover{background:var(--sidebar-hover)}
.btn--green{background:var(--success);color:#fff;border-color:var(--success)}
/* Nút cho hành động KHÔNG LÙI ĐƯỢC (xoá kênh). Đỏ đặc chứ không phải chữ đỏ
   trên nền trắng: ở đây nó đứng cạnh "Huỷ bỏ", và hai nút cùng sắc độ thì tay
   bấm nhanh hơn mắt đọc. Có :hover riêng vì trạng thái trùng màu nền là mất
   phản hồi (luật giao diện #8). */
.btn--danger{background:var(--danger);color:#fff;border-color:var(--danger)}
.btn--danger:hover{filter:brightness(.92)}
.btn--danger:disabled{opacity:.6;cursor:not-allowed}
.btn--sm{padding:8px 13px;font-size:14px;border-radius:10px}
.btn--block{width:100%;justify-content:center}
/* Nút "Mời thành viên" trong card thông tin cộng đồng: viền cam + nền trắng để
   thành một ô riêng, không phải một dòng chữ trôi nổi cuối card.
   Viền cam chứ KHÔNG nền cam đặc — ngay trên nó đã là nút AI AGENT HUB nền cam
   đặc, hai khối cam đặc chồng nhau thì mắt không biết bấm cái nào trước. */
/* `.btn--invite` đã bỏ 07/09/2026: nút "Mời thành viên" dùng chung hệ nút
   với CTA "Khoá Học Mới" (`btn--primary`). Một biến thể riêng cho một nút là
   một chỗ để lệch khỏi hệ thống, và nó đã lệch. */
.lbl-nho{display:block;font-size:12px;font-weight:600;color:var(--muted);margin:0 0 6px}

/* ---------- Cards / grid ---------- */
/* Viền mờ đi thì độ nổi phải bù lại bằng bóng, nếu không card chìm hẳn vào
   nền và trang thành một mảng phẳng không phân lớp. `--shadow-soft` là bóng 1px
   rất nhẹ — đủ để mắt thấy mép, không đủ để thành hiệu ứng. */
.card{background:var(--surface);border:1px solid var(--border-card);border-radius:var(--radius-md);padding:16px;box-shadow:var(--shadow-soft)}
.card--pad-lg{padding:22px}
.card:hover{}
.grid{display:grid;gap:16px}
.g-2{grid-template-columns:repeat(2,1fr)}
.g-3{grid-template-columns:repeat(3,1fr)}
.g-4{grid-template-columns:repeat(4,1fr)}
.stack{display:flex;flex-direction:column;gap:10px}
.row{display:flex;gap:16px;align-items:flex-start}
/* ---------- Bố cục 3 cột ----------
   Cột TRÁI (.sidebar) đã `position:sticky;top:0;height:100vh` — đứng yên sẵn.
   Cột PHẢI ghim ở đây. Cột GIỮA là thứ duy nhất trôi theo trang.

   🔴 DÙNG `sticky`, KHÔNG DÙNG một khung cuộn riêng cho cột giữa.
   Cho cột giữa `overflow-y:auto` cũng ra đúng hình này, nhưng nó tạo một thanh
   cuộn LỒNG bên trong trang, và kéo theo bốn thứ hỏng thật: trình duyệt điện
   thoại không ẩn được thanh địa chỉ khi cuộn (mất ~60px màn hình vĩnh viễn),
   quay lại trang không nhớ được vị trí đang đọc, lăn chuột ở mép cột nhảy sang
   cuộn trang ngoài, và phím Home/End/PageDown chỉ ăn khi con trỏ nằm đúng
   trong khung. Với `sticky`, cuộn vẫn là cuộn của trang — mắt thấy y hệt, tay
   dùng thì đúng như mọi trang web khác.

   `top` = chiều cao thanh trên cùng (nó `sticky;top:0`) + đúng khoảng đệm trên
   của `.content`, để cột phải dừng lại thẳng hàng với chỗ nó bắt đầu.
   `max-height` + `overflow-y:auto`: cột phải cao hơn màn hình thì TỰ nó cuộn —
   không có nó, phần dưới của cột phải nằm ngoài tầm với vĩnh viễn. */
.dash-grid{display:grid;grid-template-columns:minmax(0,1fr) 348px;gap:22px;align-items:start}
.dash-grid>*{min-width:0}
.dash-grid>*:nth-child(2){
  position:sticky;top:calc(var(--topbar-h) + 18px);
  max-height:calc(100vh - var(--topbar-h) - 36px);
  overflow-y:auto;overscroll-behavior:contain;scrollbar-width:thin;
}
.grid>*{min-width:0}

/* ---------- Stat card ---------- */
.stat{background:var(--surface);border:1px solid var(--border-card);border-radius:var(--radius-lg);padding:16px 18px;box-shadow:var(--shadow-soft)}
.stat__ic{width:38px;height:38px;border-radius:10px;display:grid;place-items:center;font-size:18px;background:var(--surface-muted);margin-bottom:12px}
.stat__ic--orange{background:var(--accent-soft);color:var(--accent-hover)}
.stat__ic--green{background:var(--success-soft);color:var(--success-strong)}
.stat__val{font-size:28px;font-weight:800;letter-spacing:-.02em;line-height:1}
.stat__label{color:var(--text-secondary);font-size:var(--fs-sm);margin-top:6px}
.stat__delta{font-size:11.5px;font-weight:600;margin-top:8px}
.up{color:var(--success-strong)} .down{color:var(--danger)}

/* ---------- Section header ---------- */
.section-head{display:flex;align-items:center;gap:10px;margin-bottom:14px}
.section-head h2{font-size:var(--fs-lg);font-weight:700;letter-spacing:-.01em}
.section-head a{margin-left:auto;color:var(--accent-hover);font-size:12.5px;font-weight:600}

/* ---------- Hero ---------- */
.hero{
  position:relative;overflow:hidden;border-radius:var(--radius-xl);padding:28px 30px;
  background:var(--surface);border:1px solid var(--border-card);box-shadow:var(--shadow-soft);
}
.hero::before{content:'';position:absolute;left:0;top:0;bottom:0;width:4px;background:var(--accent)}
.hero h1{font-size:var(--fs-3xl);font-weight:800;letter-spacing:-.025em}
.hero p{color:var(--text-secondary);max-width:640px;margin:10px 0 20px;font-size:var(--fs-md)}
.hero__cta{display:flex;gap:12px;flex-wrap:wrap}
.hero__badge{display:inline-flex;align-items:center;gap:7px;background:var(--success-soft);color:var(--success-strong);border:1px solid var(--success-border);font-size:12px;font-weight:600;padding:5px 12px;border-radius:20px;margin-bottom:14px}
.pulse{width:7px;height:7px;border-radius:50%;background:var(--success);animation:pulse 2s infinite}
@keyframes pulse{0%{box-shadow:0 0 0 0 rgba(34,197,94,.45)}70%{box-shadow:0 0 0 7px rgba(34,197,94,0)}100%{box-shadow:0 0 0 0 rgba(34,197,94,0)}}

/* ---------- Pills / tags ---------- */
.pill{display:inline-flex;align-items:center;gap:5px;font-size:12px;font-weight:600;padding:3px 9px;border-radius:20px;background:var(--surface-muted);color:var(--text-secondary);border:1px solid var(--border);white-space:nowrap;flex:0 0 auto;max-width:100%;overflow:hidden;text-overflow:ellipsis}
.pill--orange{background:var(--accent-soft);color:var(--accent-hover);border-color:var(--accent-border)}
.pill--green{background:var(--success-soft);color:var(--success-strong);border-color:var(--success-border)}
.pill--lock{background:var(--surface-muted);color:var(--text-muted)}
.pill--admin{background:var(--admin-bg);color:var(--admin-text);border-color:var(--admin-bg)}
.pill.is-active{background:var(--accent-hover);color:#fff;border-color:var(--accent)}

/* ---------- Post card ---------- */
.post{background:var(--background);border:1px solid var(--border-card);border-radius:var(--radius-md);padding:13px 16px;transition:border-color .14s,box-shadow .14s;box-shadow:var(--shadow-soft)}
.post:hover{border-color:var(--border-strong)}
.post__head{display:flex;align-items:center;gap:11px;margin-bottom:11px}
.post__meta{font-size:13.5px;color:var(--text-muted);min-width:0;flex:1 1 auto;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.post__tags{margin-left:auto;display:flex;gap:6px;align-items:center;flex:0 0 auto;max-width:62%;overflow:hidden}
.post__meta--detail{white-space:normal;text-overflow:clip}
.post__meta b{color:var(--text-primary);font-weight:600}
.post__title{font-weight:700;font-size:var(--fs-lg);margin-bottom:6px;letter-spacing:-.01em}
.post__body{color:var(--text-secondary);font-size:var(--fs-base)}
.post__foot{display:flex;align-items:center;gap:18px;margin-top:13px;color:var(--text-muted);font-size:13.5px}
.post__foot span{display:inline-flex;align-items:center;gap:6px;cursor:pointer}
.post__foot span:hover{color:var(--text-primary)}

/* ---------- List rows ---------- */
.lrow{display:flex;align-items:center;gap:12px;padding:12px 0;border-bottom:1px solid var(--border)}
.lrow:last-child{border-bottom:none}
.lrow__main{flex:1;min-width:0}
.lrow__title{font-weight:600;font-size:var(--fs-sm)}
.lrow__sub{color:var(--text-secondary);font-size:13px;margin-top:2px}
.rank{width:26px;height:26px;border-radius:8px;display:grid;place-items:center;font-weight:700;font-size:12px;background:var(--surface-muted);color:var(--text-secondary)}
.rank--1{background:var(--accent-hover);color:#fff}
.rank--2{background:var(--border-strong);color:var(--text-primary)}
.rank--3{background:var(--accent-soft);color:var(--accent-hover)}

/* ---------- Progress ---------- */
.progress{height:7px;background:var(--surface-muted);border-radius:20px;overflow:hidden}
.progress__bar{height:100%;background:var(--accent);border-radius:20px}
.progress--green .progress__bar{background:var(--success)}

/* ---------- Level badge ---------- */
.level{display:inline-flex;align-items:center;gap:7px;font-size:12px;font-weight:600;color:var(--accent-hover)}
.level__chip{width:22px;height:22px;border-radius:6px;background:var(--accent-soft);color:var(--accent-hover);display:grid;place-items:center;font-size:11px;font-weight:700}
.badge-ic{width:42px;height:42px;border-radius:11px;display:grid;place-items:center;font-size:20px;background:var(--surface-muted);opacity:.55}
.badge-ic.earned{background:var(--accent-soft);opacity:1}

/* ---------- Course / agent card ---------- */
.tile{background:var(--surface);border:1px solid var(--border-card);border-radius:var(--radius-lg);overflow:hidden;display:flex;flex-direction:column;transition:.14s;box-shadow:var(--shadow-soft)}
.tile:hover{border-color:var(--border-strong);box-shadow:var(--shadow-card)}
.tile__cover{height:96px;background:var(--surface-muted);position:relative;display:grid;place-items:center;font-size:34px}
.tile__cover--orange{background:var(--accent-soft)}
.tile__cover--green{background:var(--success-soft)}
.tile__lock{position:absolute;top:10px;right:10px}
.tile__body{padding:15px 16px;flex:1;display:flex;flex-direction:column;gap:8px}
.tile__title{font-weight:700;font-size:var(--fs-md);letter-spacing:-.01em}
.tile__desc{color:var(--text-secondary);font-size:14.5px;flex:1}
.tile__foot{display:flex;align-items:center;gap:8px;margin-top:4px}

/* ---------- Table ---------- */
.tbl{width:100%;border-collapse:collapse;font-size:14.5px}
.tbl th{text-align:left;color:var(--text-muted);font-weight:600;font-size:12.5px;text-transform:uppercase;letter-spacing:.04em;padding:11px 12px;border-bottom:1px solid var(--border);background:var(--surface-muted)}
.tbl td{padding:12px;border-bottom:1px solid var(--border);vertical-align:middle}
.tbl tr:hover td{background:var(--surface-muted)}
.tbl tr:last-child td{border-bottom:none}

/* ---------- Tabs / filter bar ---------- */
.tabs{display:flex;gap:14px;flex-wrap:wrap;margin-bottom:18px;border-bottom:1px solid var(--border)}
.tab{padding:10px 2px;margin-bottom:-1px;color:var(--text-secondary);font-weight:600;font-size:var(--fs-sm);border-bottom:2px solid transparent}
.tab.active{color:var(--text-primary);border-bottom-color:var(--accent)}
.filterbar{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:18px}

/* ---------- Community hero banner ---------- */
.chero{position:relative;overflow:hidden;border:1px solid var(--border-card);border-radius:24px;background:var(--surface);box-shadow:var(--shadow-soft);margin-bottom:22px}
.chero::before{content:'';position:absolute;left:0;top:0;bottom:0;width:5px;background:var(--accent)}
.chero__grid{display:grid;grid-template-columns:1.3fr 1fr;gap:28px;padding:34px 38px;align-items:center}
.chero__badge{display:inline-flex;align-items:center;gap:7px;background:var(--success-soft);color:var(--success-strong);border:1px solid var(--success-border);font-size:13px;font-weight:600;padding:5px 13px;border-radius:20px}
.chero h1{font-size:var(--fs-3xl);font-weight:800;letter-spacing:-.025em;margin:14px 0 8px}
.chero__sub{font-size:var(--fs-md);color:var(--text-primary);font-weight:500;margin-bottom:8px}
.chero__desc{font-size:var(--fs-sm);color:var(--text-secondary);line-height:1.65;max-width:560px}
.chero__cta{display:flex;gap:12px;flex-wrap:wrap;margin-top:20px}
.chero__visual{display:grid;grid-template-columns:1fr 1fr;gap:12px}
.chero__stat{background:var(--surface-muted);border:1px solid var(--border);border-radius:16px;padding:18px}
.chero__stat .n{font-size:26px;font-weight:800;letter-spacing:-.02em;color:var(--accent-hover)}
.chero__stat .l{font-size:14px;color:var(--text-secondary);margin-top:2px}
.quick-composer{display:flex;align-items:center;gap:12px;background:var(--surface);border:1px solid var(--border-card);border-radius:16px;padding:14px 16px;box-shadow:var(--shadow-soft);cursor:text;margin-bottom:16px}
.quick-composer input{flex:1;border:none;background:none;outline:none;font-size:var(--fs-md);color:var(--text-primary)}
.quick-composer input::placeholder{color:var(--text-muted)}
.chips-scroll{display:flex;gap:8px;overflow-x:auto;padding-bottom:4px;-webkit-overflow-scrolling:touch}
.chips-scroll::-webkit-scrollbar{display:none}
.chips-scroll .pill{white-space:nowrap;flex:0 0 auto}
/* Bản dùng BÊN TRONG một .card có padding 20px (màn đăng nhập, cài đặt cộng
   đồng): margin âm để banner tràn ra sát mép thẻ. Chỉ đúng ở ngữ cảnh đó —
   xem chú thích ở .cinfo > .cinfo-cover bên dưới. */
/* Ảnh bìa cộng đồng ở đầu thẻ. Tỉ lệ 16:9 đúng bằng tỉ lệ ô tải ảnh yêu cầu,
   nên `cover` không cắt mất phần nào. Chưa đặt ảnh thì còn dải màu chủ đề.
   `--accent` chứ không phải mã màu cam cứng: đổi chủ đề cộng đồng là dải này
   đổi theo — trước đây hard-code #cc6600 nên nhóm chọn chủ đề xanh vẫn có một
   mảng cam chình ình ở đầu thẻ. */
.card > .cinfo-cover{aspect-ratio:16/9;background:linear-gradient(120deg,var(--accent),var(--accent-hover));
  background-size:cover;background-position:center;
  border-radius:15px 15px 0 0;margin:-20px -20px 14px}
.cinfo-cover img{max-height:62px;max-width:90%;object-fit:contain}
.check-item{display:flex;align-items:center;gap:11px;padding:9px 0;border-bottom:1px solid var(--border)}
.check-item:last-child{border-bottom:none}
.check-dot{width:22px;height:22px;border-radius:50%;border:2px solid var(--border-strong);flex:0 0 auto;display:grid;place-items:center;color:var(--success)}
.check-dot.done{border-color:var(--success);background:var(--success-soft)}
@media(max-width:900px){.chero__grid{grid-template-columns:1fr;gap:18px;padding:22px 20px}}

/* ---------- Mobile community intro (chỉ hiện < 768px) ---------- */
.community-mobile-intro{display:none}
.mci-cover{height:80px;background:linear-gradient(120deg,#cc6600,#8f4700);border-radius:18px 18px 0 0;display:flex;align-items:center;justify-content:center;padding:0 16px}
.mci-cover img{max-height:52px;max-width:88%;object-fit:contain}
/* 🔴 CÓ ẢNH BÌA THẬT ⇒ HIỆN TRỌN ẢNH, KHÔNG CẮT (Founder 2026-09-04).
   Ô cao cứng ở dòng trên (80px) và ô 60px trong `@media(max-width:767px)` phía
   dưới đều là KHUNG, và `cover` thì cắt ảnh cho vừa khung. Ảnh bìa thật đang
   chạy có tỉ lệ 1.25 → 1.78:1, khung điện thoại là ~5,7:1 ⇒ mất gần 3/4 ảnh.
   `height:auto` trả quyền quyết định chiều cao lại cho chính bức ảnh.
   `max-height` là dây an toàn: ai đó tải ảnh dựng đứng lên thì banner không
   nuốt cả màn hình — tới ngưỡng đó `contain` vẫn hiện TRỌN ảnh, chỉ thu nhỏ.
   🔴 PHẢI VIẾT HAI CLASS `.mci-cover.mci-cover--anh`, không phải một.
   `@media(max-width:767px)` bên dưới cũng khai `.mci-cover{height:60px}` với
   CÙNG độ ưu tiên, mà trong CSS thì khối SAU thắng — một class ở đây sẽ bị khối
   đó đè, và trên điện thoại sửa gì cũng không thấy đổi. Đây đúng cái bẫy đã ghi
   lại ở `.cinfo-cover` phía trên, chỉ khác chỗ. */
.mci-cover.mci-cover--anh{height:auto;min-height:0;padding:0;display:block;background:var(--surface-muted)}
/* 🔴 CŨNG PHẢI HAI CLASS Ở ĐÂY — em đã tính sai một lần và phép đo bắt được.
   `.mci-cover--anh img` là (0,1,1): MỘT class + MỘT thẻ — ĐÚNG BẰNG
   `.mci-cover img` trong `@media(max-width:767px)`, mà khối đó nằm SAU nên nó
   thắng. Kết quả đo ở 375px: ảnh bị kẹp còn 40px, tệ hơn cả bản cũ (60px).
   `.mci-cover.mci-cover--anh img` là (0,2,1) ⇒ thắng bất kể thứ tự.
   Bài học: đừng đếm độ ưu tiên trong đầu — dựng lên rồi ĐO. */
.mci-cover.mci-cover--anh img{display:block;width:100%;height:auto;max-width:none;max-height:72vh;object-fit:contain;border-radius:inherit}
.mci-body{background:var(--surface);border:1px solid var(--border-card);border-top:none;border-radius:0 0 18px 18px;padding:16px 18px 18px}
.mci-body h1{font-size:var(--fs-xl);font-weight:800;letter-spacing:-.02em}
/* Cùng cỡ chữ, cùng màu với .cinfo-desc bên máy tính — hai giao diện đọc ra một
   lời giới thiệu, thì cũng nên trông như một lời giới thiệu.
   .mci-sub đã gỡ cùng đoạn "Mô tả đầy đủ" (2026-08-16). */
.mci-desc{font-size:13.5px;color:var(--text-secondary);margin-top:8px;line-height:1.6}
/* ---------- Community: card "Thông tin cộng đồng" (cột phải) ----------
   Dựng như .mci-* (dải cam + thân có viền) thay vì .card, vì .card có padding
   nên dải cam tràn viền sẽ phải kéo bằng margin âm — dễ lệch khi đổi padding. */
.cinfo{border-radius:18px;box-shadow:var(--shadow-soft)}
/* Card Thông tin cộng đồng KHÔNG có padding bao ngoài — .cinfo-cover và
   .cinfo-body là hai khối xếp chồng, tự dựng nên thẻ. Nên phải HUỶ margin âm
   thừa hưởng từ bản ở trên: không huỷ thì banner rộng hơn phần thân đúng 40px
   và thò ra hai bên, đúng chỗ lệch nhìn thấy trên màn Cộng đồng.
   Chỉ định qua `.cinfo >` để bản dùng trong .card (màn đăng nhập) giữ nguyên
   margin âm của nó — hai ngữ cảnh khác nhau, hai cách canh khác nhau. */
.cinfo>.cinfo-cover{margin:0}
/* 🔴 ĐÂY MỚI LÀ QUY TẮC CÓ HIỆU LỰC cho thẻ `.cinfo`.
   File này có HAI khối `.cinfo-cover` (khối trước ~dòng 387 dành cho thẻ nằm
   trong `.card`). Cùng độ ưu tiên thì khối SAU thắng — nên sửa khối trước là
   sửa vào chỗ không ai đọc. Founder báo "kích thước banner đang sai" đúng vì
   thế: em đổi 16:9 ở khối trên, còn khối này vẫn giữ `height:74px`.
   Nay hai khối nói cùng một điều; đổi thì phải đổi CẢ HAI, hoặc gộp lại. */
.cinfo-cover{aspect-ratio:16/9;background:linear-gradient(120deg,var(--accent),var(--accent-hover));
  background-size:cover;background-position:center;border-radius:18px 18px 0 0}
.cinfo-cover img{max-height:46px;max-width:88%;object-fit:contain;display:block}
.cinfo-body{background:var(--surface);border:1px solid var(--border-card);border-top:none;border-radius:0 0 18px 18px;padding:14px 16px 16px}
.cinfo-stat{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:7px 0;font-size:var(--fs-sm)}
.cinfo-stat+.cinfo-stat{border-top:1px solid var(--border)}
.cinfo-stat>span{color:var(--text-secondary)}
.cinfo-stat>b{font-weight:700;font-variant-numeric:tabular-nums}
.cinfo-name{font-weight:700;font-size:var(--fs-md);line-height:1.3;color:var(--text-primary)}
.cinfo-desc{font-size:13.5px;line-height:1.6;color:var(--text-secondary);margin-top:8px}
.cinfo-links{list-style:none;margin:10px 0 0;padding:0;display:flex;flex-direction:column;gap:2px}
.cinfo-links a{display:flex;align-items:center;gap:7px;padding:4px 0;font-size:13px;
  color:var(--text-secondary);text-decoration:none;min-height:28px}
.cinfo-links a:hover{color:var(--accent-hover)}
.cinfo-links span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* .cinfo-nums/.cinfo-num đã GỠ cùng ô số liệu 3 cột (2026-08-16). Khối đó chỉ có
   ở card máy tính, không có ở khung giới thiệu trên điện thoại — gỡ ở cả hai là
   cách khép khoảng lệch mà không phải nhồi thêm một khối cao vào màn hình hẹp. */
/* Hàng avatar thành viên thật — chồng nhẹ lên nhau như Skool */
.cinfo-faces{display:flex;align-items:center;margin-top:12px;padding-left:5px}
.cinfo-faces>a{margin-left:-5px;display:block;border-radius:50%;box-shadow:0 0 0 2px var(--surface)}
.avatar--xs{width:26px;height:26px;font-size:10px}
/* Hàng Top 5 bấm được — giữ nguyên .lrow, chỉ bỏ gạch chân và thêm phản hồi hover */
.lrow--link{text-decoration:none;color:inherit;border-radius:10px}
.lrow--link:hover{background:var(--surface-muted)}
/* Trang "Người mời": một danh sách hai tầng — người mời, rồi những người họ mời.
   Tầng cha có đường kẻ trên để tách hẳn khỏi nhóm phía trước; tầng con thụt vào
   và bỏ đường kẻ dưới, để mắt đọc được "những dòng này thuộc về dòng trên" mà
   không cần thêm chữ giải thích. */
.lrow--head{border-top:2px solid var(--border-strong);border-bottom:none;padding-top:16px;flex-wrap:wrap}
.lrow--head:first-child{border-top:none;padding-top:4px}
.lrow--sub{padding-left:18px;border-bottom:none;padding-top:8px;padding-bottom:8px}
.lrow--sub .lrow__title{font-weight:500;color:var(--text-secondary)}
/* Nút đứng cuối một hàng có wrap. Trên màn rộng nó dạt về phải; xuống màn hẹp
   hàng đó xuống dòng, và `margin-left:auto` sẽ dán nút vào mép phải kèm một
   khoảng trống dài bên trái — trông như bị bỏ quên. Hẹp thì cho chiếm trọn dòng. */
.push-end{width:100%;justify-content:center;margin-top:4px}
@media (min-width:560px){ .push-end{width:auto;margin-left:auto;margin-top:0} }


/* .mci-stats/.mci-stat/.mci-n/.mci-l đã GỠ cùng ô "Thành viên" trong khung giới
   thiệu trên điện thoại (2026-08-16). Không xoá kiểu mà giữ HTML, cũng không giữ
   kiểu cho HTML đã xoá — bốn lớp không ai dùng sẽ khiến người sau tưởng khối đó
   vẫn còn và đi tìm xem nó vẽ ở đâu. */
.mci-cta{display:flex;gap:10px;flex-wrap:wrap;margin-top:14px}
@media(max-width:767px){
  .community-mobile-intro{display:block;margin-bottom:16px}
  .community-right{display:none}

  /* Khung giới thiệu trên điện thoại: THU GỌN (2026-08-18).
     Trước đây ba nút xuống ba hàng (flex-wrap), nên riêng khối này đã chiếm gần
     nửa màn hình đầu tiên — người mở app phải cuộn qua một tấm bìa mới thấy bài
     viết đầu tiên. Trên một app cộng đồng thì bài viết mới là nội dung. */
  .mci-cover{height:60px;border-radius:16px 16px 0 0}
  .mci-cover img{max-height:40px}
  .mci-body{padding:13px 14px 15px;border-radius:0 0 16px 16px}
  .mci-body h1{font-size:20px}
  .mci-desc{font-size:12.5px;margin-top:6px;line-height:1.5}

  /* Ba nút MỘT HÀNG, chia đều. grid chứ không flex-wrap: mỗi cột 1fr thì nút
     dài nhất không đẩy hai nút kia xuống hàng, và cả ba cao bằng nhau nhờ
     grid tự kéo giãn (flex-wrap thì mỗi hàng tự tính chiều cao riêng). */
  .mci-cta{display:grid;grid-template-columns:repeat(3,1fr);gap:7px;margin-top:12px}
  /* Nhãn nút do Admin đặt, có thể dài ("AI AGENT HUB"). Ở ~90px mỗi cột thì
     nowrap của .btn sẽ làm chữ tràn ra ngoài — cho xuống dòng và căn giữa,
     thà hai dòng chữ gọn còn hơn một dòng bị cắt. */
  .mci-cta .btn{padding:8px 4px;font-size:12px;gap:0;white-space:normal;
    line-height:1.3;text-align:center;justify-content:center;min-width:0}
  /* Bỏ icon: ở bề ngang này mỗi icon ăn ~23px, đúng phần chỗ mà chữ đang thiếu.
     Icon là trang trí (aria-hidden), chữ mới là thứ nói nút làm gì. */
  .mci-cta .btn>svg{display:none}
}

/* ---------- Chat ---------- */
/* Tin nhắn chiếm trọn chiều cao NHƯNG vẫn giữ thanh tab của cộng đồng.
   Chiều cao nay do #os-page.is-chat giữ, .chat chỉ "ăn nốt phần còn lại"
   (flex:1). Nhờ vậy thanh tab cao bao nhiêu — kể cả khi xuống dòng trên máy
   hẹp — khung chat tự co lại đúng bấy nhiêu; không phải trừ một con số cứng,
   và ô nhập tin không bao giờ bị đẩy khuất. */
.ctabs-strip{flex:0 0 auto;padding:0 24px}
#os-page.is-chat{display:flex;flex-direction:column;overflow:hidden;
  height:calc(100vh - var(--topbar-h))}
#os-page.is-chat .chat{height:auto;flex:1;min-height:0}
.chat{display:grid;grid-template-columns:308px 1fr;height:calc(100vh - var(--topbar-h));border-top:1px solid var(--border)}
.chat__list{border-right:1px solid var(--border);overflow-y:auto;background:var(--surface)}
.chat__conv{display:flex;gap:11px;padding:13px 16px;border-bottom:1px solid var(--border);cursor:pointer}
.chat__conv:hover,.chat__conv.active{background:var(--surface-muted)}
.chat__win{display:flex;flex-direction:column;min-width:0;background:var(--background)}
.chat__msgs{flex:1;overflow-y:auto;padding:20px;display:flex;flex-direction:column;gap:12px}
.bubble{max-width:64%;padding:10px 14px;border-radius:14px;font-size:var(--fs-sm);background:var(--surface);border:1px solid var(--border-card);box-shadow:var(--shadow-soft)}
.bubble.me{align-self:flex-end;background:var(--accent-hover);color:#fff;border-color:var(--accent)}
.chat__compose{border-top:1px solid var(--border);padding:14px 18px;display:flex;gap:10px;background:var(--surface)}
/* 16px là mức tối thiểu, không phải lựa chọn thẩm mỹ: dưới 16px thì Safari iOS
   tự phóng to trang khi ô nhập được chọn, và người dùng phải tự thu nhỏ lại sau
   mỗi tin nhắn. */
.chat__compose input{flex:1;background:var(--surface-muted);border:1px solid var(--border);border-radius:12px;padding:11px 14px;color:var(--text-primary);outline:none;font-size:16px}
.chat__compose input:disabled{opacity:.6}
.chat__list-head{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:14px 16px;border-bottom:1px solid var(--border);position:sticky;top:0;background:var(--surface);z-index:1}
.chat__note{padding:12px 16px;border-bottom:1px solid var(--border);background:var(--surface-muted);font-size:var(--fs-xs);color:var(--text-secondary);line-height:1.6}
.chat__empty-list,.chat__msgs-empty{padding:22px 16px;color:var(--text-secondary);font-size:var(--fs-sm);text-align:center;line-height:1.7}
.chat__msgs-empty{margin:auto}
.chat__preview{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.chat__head{display:flex;align-items:center;gap:10px;padding:12px 18px;border-bottom:1px solid var(--border);background:var(--surface);min-height:var(--topbar-h)}
.chat__head-name{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.chat__win-empty{flex:1;display:flex;align-items:center;justify-content:center;padding:24px}
/* Nút quay lại chỉ có nghĩa trên mobile, nơi danh sách hội thoại bị ẩn đi. */
.chat__back{display:none}
.bubble__time{font-size:10px;opacity:.6;margin-top:4px}
/* Thông báo — dòng chưa đọc + chấm đánh dấu. Trước đây tô nền bằng style inline
   với margin âm; tách ra đây để dòng thông báo bấm được (thẻ <a>) vẫn giữ đúng
   dáng của .lrow. */
.lrow--unread{background:var(--accent-soft);margin:0 -18px;padding-left:18px;padding-right:18px}
/* Dòng chưa đọc tràn ra hai mép bằng margin âm, nên nó đè lên góc bo của thẻ và
   để lộ một mảnh trắng vuông ở dòng đầu/cuối. Cắt theo viền thẻ. */
.card--clip{overflow:hidden}
a.lrow{text-decoration:none;color:inherit}
a.lrow:hover{background:var(--surface-muted)}
a.lrow--unread:hover{filter:brightness(.98)}
.noti-dot{width:8px;height:8px;border-radius:50%;background:var(--accent);flex:0 0 auto}
/* Thông báo ĐÃ ĐỌC (2026-08-18). Nền xám thay cho nền cam nhạt, và dòng Ở LẠI
   danh sách — thông báo là lịch sử để tra lại, không phải việc cần dọn.
   Cùng margin âm như .lrow--unread để hai trạng thái tràn mép giống hệt nhau;
   lệch một bên thôi là lúc đổi màu cả dòng nhìn như bị xê dịch.
   Transition để mắt bắt được lúc chuyển — đổi tức thì thì nhìn như nhấp nháy. */
.lrow--daxem{background:var(--surface-muted);margin:0 -18px;padding-left:18px;padding-right:18px}
.lrow--unread,.lrow--daxem{transition:background .35s ease}
/* a.lrow:hover cũng tô đúng màu xám này, nên dòng đã đọc bấm được sẽ mất hẳn
   phản hồi khi rê chuột. Đổi sang tối đi một chút. */
a.lrow--daxem:hover{background:var(--surface-muted);filter:brightness(.97)}
/* Ô mật khẩu có nút con mắt. padding-right chừa chỗ cho nút, nếu không thì mật
   khẩu dài sẽ chạy xuống dưới biểu tượng. */
.field--pw{position:relative}
.field--pw input{padding-right:44px}
.pw-eye{position:absolute;right:8px;bottom:6px;width:32px;height:32px;display:flex;align-items:center;justify-content:center;
  border:none;background:transparent;color:var(--text-muted);cursor:pointer;border-radius:8px}
.pw-eye:hover{color:var(--text-primary);background:var(--surface-muted)}

/* ===== Trang Thành viên — danh sách dòng ===== */
.mbar{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap;margin-bottom:14px}
.mbar__right{display:flex;align-items:center;gap:10px;flex-wrap:wrap;flex:1 1 auto;justify-content:flex-end}
.mbar__search{max-width:320px;flex:1 1 220px}
.mrow{display:flex;align-items:flex-start;gap:14px;padding:16px 18px;border-bottom:1px solid var(--border)}
.mrow:last-child{border-bottom:none}
.mrow:hover{background:var(--surface-muted)}
.mrow__ava{position:relative;flex:0 0 auto;text-decoration:none}
/* Số cấp nằm đè góc avatar. Đặt ở đây thay vì thành một pill riêng để dòng không
   bị đẩy dài thêm — mỗi dòng phải đọc hết được mà không cuộn ngang. */
/* 🔴 GÓC PHẢI, KHÔNG PHẢI GÓC TRÁI — Founder chốt 25/08/2026.
   Một huy hiệu cấp, MỘT góc, cho cả app: thẻ bài viết · trang Thành viên ·
   menu avatar. Trước đó em để menu avatar riêng một biến thể `--phai` còn
   hai chỗ kia vẫn góc trái — hai góc cho cùng một huy hiệu là thứ mắt bắt
   được ngay khi nhìn hai màn hình cạnh nhau. Biến thể đó đã GỠ. */
.mrow__lv,.pm-lv{position:absolute;bottom:-2px;right:-2px;min-width:20px;height:20px;padding:0 5px;border-radius:10px;
  background:var(--accent-hover);color:#fff;font-size:11px;font-weight:700;display:flex;align-items:center;justify-content:center;
  border:2px solid var(--surface)}
/* Huy hiệu cấp trên avatar BÀI VIẾT — cùng một kiểu với trang Thành viên
   (Founder chốt 24/08/2026: bỏ chữ "Lv 1", để con số cạnh avatar).
   🔴 Ô bọc phải `position:relative`, nếu không huy hiệu `position:absolute` sẽ
   neo vào tổ tiên có position gần nhất — tức cả cái card — và văng ra góc bài.
   Huy hiệu nhỏ hơn một chút so với trang Thành viên vì avatar bài cũng nhỏ hơn
   (36px so với avatar--lg), giữ nguyên 20px thì nó chiếm gần nửa mặt người. */
.pm-ava{position:relative;flex:0 0 auto;display:inline-flex}
/* `padding:0 3px` (kế thừa 5px thì số MỘT chữ số ra hình bầu dục 20×17 thay
   vì tròn — đo được). Hai chữ số vẫn nở ra vừa đủ nhờ min-width. */
.pm-lv{min-width:17px;height:17px;padding:0 3px;font-size:10px;border-width:2px;bottom:-1px;right:-1px}
.mrow__main{flex:1 1 auto;min-width:0}
.mrow__name{display:block;font-weight:700;font-size:15.5px;color:var(--text-primary);text-decoration:none}
.mrow__name:hover{color:var(--accent-hover)}
.mrow__handle{font-size:13px;color:var(--text-muted);margin-top:1px}
.mrow__bio{font-size:13.5px;color:var(--text-secondary);margin-top:6px;line-height:1.6;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.mrow__meta{display:flex;align-items:center;gap:14px;flex-wrap:wrap;margin-top:8px;font-size:12.5px;color:var(--text-muted)}
.mrow__meta span{display:inline-flex;align-items:center;gap:5px}
/* Hàng liên hệ — CHỈ hiện với Chủ sở hữu / Quản trị viên. Nền riêng để nhìn là
   biết ngay đây là phần người khác không thấy, tránh admin lỡ chụp màn hình
   chia sẻ mà không để ý mình đang lộ số điện thoại của thành viên. */
.mrow__lienhe{display:flex;align-items:center;gap:14px;flex-wrap:wrap;margin-top:8px;padding:8px 10px;
  background:var(--surface-muted);border:1px dashed var(--border);border-radius:10px;font-size:12.5px}
.mrow__lienhe a{display:inline-flex;align-items:center;gap:5px;color:var(--text-secondary);text-decoration:none}
.mrow__lienhe a:hover{color:var(--accent-hover)}
.mrow__lienhe span{display:inline-flex;align-items:center;gap:5px}
.mrow__cta{flex:0 0 auto;align-self:center;display:flex;align-items:center;gap:6px}
.mrow__kebab{width:32px;height:32px;font-size:18px;line-height:1;color:var(--text-muted)}
.mrow__kebab:hover{color:var(--text-primary);background:var(--surface-muted)}
.pager{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-top:16px}
@media(max-width:600px){
  /* Nút nhắn tin xuống dòng riêng, chiếm hết bề ngang — trên điện thoại một nút
     nhỏ nằm nép bên phải cạnh khối chữ dài là thứ rất khó bấm trúng. */
  .mrow{flex-wrap:wrap}
  .mrow__cta{width:100%;margin-left:56px;justify-content:center}
  .mbar__search{max-width:none}
}
/* Danh bạ "Nhắn tin mới" */
.nc-list{display:flex;flex-direction:column;gap:6px;max-height:52vh;overflow-y:auto}
.nc-row{display:flex;align-items:center;gap:11px;width:100%;padding:10px 12px;border:1px solid var(--border-card);border-radius:12px;background:var(--surface);cursor:pointer;text-align:left}
.nc-row:hover{background:var(--surface-muted)}
.nc-row:disabled{opacity:.5;cursor:default}
.nc-row__main{display:flex;align-items:center;gap:8px;min-width:0;flex-wrap:wrap}

/* ---------- Inputs / forms ---------- */
.field{margin-bottom:14px}
.field label{display:block;font-size:var(--fs-sm);font-weight:600;color:var(--text-secondary);margin-bottom:6px}
.field input,.field textarea,.field select{
  width:100%;background:var(--surface);border:1px solid var(--border-strong);border-radius:var(--radius-md);
  padding:11px 13px;color:var(--text-primary);font-size:var(--fs-base);font-family:inherit;outline:none;
}
.field input:focus,.field textarea:focus,.field select:focus{border-color:var(--accent)}
.field input::placeholder,.field textarea::placeholder{color:var(--text-muted)}

/* ---------- Empty / loading ---------- */
.empty{text-align:center;padding:48px 20px;color:var(--text-secondary);font-size:var(--fs-base)}
.empty__ic{font-size:38px;margin-bottom:12px;opacity:.6}
.skeleton{background:linear-gradient(90deg,var(--surface-muted),#ECEBE7,var(--surface-muted));background-size:200% 100%;animation:sk 1.2s infinite;border-radius:8px}
@keyframes sk{0%{background-position:200% 0}100%{background-position:-200% 0}}

/* ---------- Modal ---------- */
.overlay{position:fixed;inset:0;background:rgba(23,23,23,.38);backdrop-filter:blur(2px);z-index:90;display:grid;place-items:center;padding:20px}
.modal{background:var(--surface);border:1px solid var(--border-card);border-radius:var(--radius-xl);max-width:560px;width:100%;max-height:88vh;overflow-y:auto;box-shadow:var(--shadow-pop)}
.modal__head{display:flex;align-items:center;gap:10px;padding:18px 20px;border-bottom:1px solid var(--border)}
.modal__head h3{font-size:16px;font-weight:700}
.modal__head .icon-btn{margin-left:auto;width:32px;height:32px;font-size:15px}
.modal__body{padding:20px}
.modal__foot{padding:16px 20px;border-top:1px solid var(--border);display:flex;gap:10px;justify-content:flex-end}

/* ---------- Modal dạng BIỂU MẪU (Tạo bài viết, Tạo sự kiện…) ----------
   .modal thường cho cả hộp cuộn, nên với form dài thì tiêu đề và nút "Đăng bài"
   trôi ra khỏi màn hình: người ta gõ xong, không thấy nút đâu, phải cuộn ngược
   xuống mò. Ở đây chỉ PHẦN THÂN cuộn — đầu và chân đứng yên. */
/* Thẻ menu avatar. 560px mặc định là khổ dành cho FORM; menu này chỉ có ba
   dòng chữ ngắn nên để nguyên là một tấm thẻ rộng gần nửa màn hình chứa toàn
   khoảng trắng (Founder 25/08/2026: "tinh gọn card bé lại"). */
.modal--nguoidung{max-width:340px}
.modal--nguoidung .modal__head{padding:14px 16px}
.modal--nguoidung .modal__body{padding:8px}
/* Vùng chạm ≥44px — luật cứng. `.nav-item` mặc định `padding:6px 10px` cho ra
   ~32px, đủ cho chuột nhưng KHÔNG đủ cho ngón tay; trong một thẻ chỉ có ba dòng
   thì nới ra vừa đúng chỗ trống đang thừa. */
.modal--nguoidung .nav-item{padding:11px 10px;font-size:15px}
.modal--form{display:flex;flex-direction:column;overflow:hidden}
.modal--form .modal__head,.modal--form .modal__foot{flex:0 0 auto;background:var(--surface)}
.modal--form .modal__body{flex:1 1 auto;overflow-y:auto;-webkit-overflow-scrolling:touch;overscroll-behavior:contain}
.modal--form .modal__foot{gap:10px;flex-wrap:wrap}
@media(max-width:767px){
  /* Điện thoại: giữ nguyên kiểu bottom-sheet đã có (xem @media 767 phía dưới,
     .modal{max-height:92vh}) — chỉ chỉnh phần bên trong. Đầu và chân dính lại,
     nút chính to bằng ngón cái, và chừa safe-area cho iPhone có thanh gạt. */
  .modal--form .modal__head{padding:14px 16px;position:sticky;top:0;z-index:2}
  .modal--form .modal__body{padding:16px}
  .modal--form .modal__foot{padding:12px 16px calc(12px + env(safe-area-inset-bottom));
    position:sticky;bottom:0;z-index:2;box-shadow:0 -6px 18px rgba(23,23,23,.06)}
  .modal--form .modal__foot .btn--primary{flex:1 1 auto;min-height:46px}
  .modal--form .modal__foot #np-total{flex:1 0 100%;margin:0 0 2px}
}

/* ---------- Toast ---------- */
.toast{position:fixed;bottom:24px;left:50%;transform:translateX(-50%);background:var(--text-primary);border:1px solid var(--text-primary);color:#fff;padding:12px 18px;border-radius:12px;z-index:120;box-shadow:var(--shadow-pop);font-size:13.5px;font-weight:500}
.toast.err{background:var(--danger);border-color:var(--danger)}

/* ---------- Misc ---------- */
.muted{color:var(--text-secondary)} .small{font-size:13px} .b{font-weight:700} .mt{margin-top:14px} .mb{margin-bottom:14px}
.divider{height:1px;background:var(--border);margin:16px 0}
.between{display:flex;align-items:center;justify-content:space-between;gap:12px}
.wrap-tags{display:flex;gap:7px;flex-wrap:wrap}
.copybox{background:var(--surface-muted);border:1px solid var(--border);border-radius:10px;padding:10px 13px;font-family:ui-monospace,Menlo,monospace;font-size:12.5px;color:var(--accent-hover);display:flex;align-items:center;gap:10px}
.copybox code{flex:1;overflow-x:auto}

/* ---------- Post card 2-col + thumbnail góc phải (giữ tỷ lệ, không crop) ---------- */
.post__row{display:flex;gap:16px;align-items:stretch}
.post__main{flex:1;min-width:0;display:flex;flex-direction:column}
.post__main .post__foot{margin-top:auto}
.post__thumb{flex:0 0 144px;width:144px;align-self:center;position:relative;display:block;border-radius:14px;overflow:hidden;background:#F3F3F1;border:1px solid var(--border);aspect-ratio:4/3}
.post__thumb img,.post__thumb video{width:100%;height:100%;object-fit:contain;background:#F3F3F1;display:block}
.post__thumb .thumb-play{position:absolute;inset:0;margin:auto;width:40px;height:40px;border-radius:50%;background:rgba(23,23,23,.55);color:#fff;display:grid;place-items:center;pointer-events:none}
.post__thumb .thumb-more{position:absolute;right:6px;bottom:6px;background:rgba(23,23,23,.7);color:#fff;font-size:12px;font-weight:600;padding:2px 8px;border-radius:8px}
.media-broken-msg{display:none}
.post__thumb img.media-broken,.post__thumb video.media-broken,.pmf-item img.media-broken,.pmf-item video.media-broken,
.pm-thumb img.media-broken,.pm-thumb video.media-broken{display:none}
.post__thumb:has(.media-broken) .media-broken-msg,.post__thumb.has-broken-media .media-broken-msg{display:flex;position:absolute;inset:0;align-items:center;justify-content:center;text-align:center;font-size:12px;color:var(--text-muted);padding:10px}
/* Ô thumbnail của card bài viết — .pm-thumb là cấu trúc đang dùng ở MỌI bề rộng.
   Thiếu khối này thì tệp hỏng hiện ra đúng một hình vuông xám kèm nút play, không
   một chữ giải thích: người đọc tưởng mạng chậm và ngồi đợi mãi. */
.pm-thumb:has(.media-broken),.pm-thumb.has-broken-media{background:var(--surface-muted);border:1px dashed var(--border)}
.pm-thumb:has(.media-broken) .pm-play,.pm-thumb.has-broken-media .pm-play,
.pm-thumb:has(.media-broken) .pm-dur,.pm-thumb.has-broken-media .pm-dur,
.pm-thumb:has(.media-broken) .pm-more-n,.pm-thumb.has-broken-media .pm-more-n{display:none}
.pm-thumb:has(.media-broken) .media-broken-msg,.pm-thumb.has-broken-media .media-broken-msg{display:flex;position:absolute;inset:0;flex-direction:column;gap:5px;
  align-items:center;justify-content:center;text-align:center;font-size:11px;line-height:1.35;
  color:var(--text-muted);padding:8px}
.pm-thumb:has(.media-broken) .media-broken-msg svg,.pm-thumb.has-broken-media .media-broken-msg svg{color:var(--text-disabled)}
.pmf-item{position:relative;min-height:120px}
.pmf-item:has(.media-broken) .media-broken-msg,.pmf-item.has-broken-media .media-broken-msg{display:flex;position:absolute;inset:0;flex-direction:column;gap:8px;align-items:center;justify-content:center;text-align:center;font-size:13px;color:var(--text-muted);padding:18px;background:var(--surface-muted);border-radius:12px}
.pmf-item:has(.media-broken) .media-broken-msg svg,.pmf-item.has-broken-media .media-broken-msg svg{color:var(--text-disabled)}
/* Post detail full media (giữ tỷ lệ) */
.post-media-full{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-top:14px}
.post-media-full.one{grid-template-columns:1fr}
.pmf-item{border-radius:12px;overflow:hidden;background:#F3F3F1;border:1px solid var(--border);max-height:520px;display:flex;align-items:center;justify-content:center}
.pmf-item img,.pmf-item video{width:100%;max-height:520px;object-fit:contain;background:#F3F3F1;display:block}
/* Ảnh ở trang chi tiết bấm được để phóng to — là <button>, nên phải gỡ style mặc định */
.pmf-item--open{padding:0;font:inherit;color:inherit;cursor:zoom-in;width:100%}
.pmf-item--open:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
@media(max-width:560px){.post__row{flex-direction:column}.post__thumb{width:100%;flex-basis:auto;align-self:stretch;aspect-ratio:16/9;order:-1}.post-media-full{grid-template-columns:1fr}}

/* ---------- Post media ---------- */
/* Lưới tệp đính kèm trong composer. Dùng .g-3 thì trên điện thoại lưới co về 1 cột
   và MỘT tấm ảnh chiếm nguyên bề ngang — người ta phải cuộn qua cả màn hình mới
   thấy hết những tệp mình vừa chọn. Ô cố định ~96px cho 3–4 tệp một hàng ở mọi
   bề rộng, đúng vai trò của nó: danh sách để kiểm lại, không phải nơi ngắm ảnh. */
#np-media{grid-template-columns:repeat(auto-fill,minmax(96px,1fr))}
.media-thumb{position:relative;aspect-ratio:1;border-radius:12px;overflow:hidden;border:1px solid var(--border);background:var(--surface-muted)}
.media-thumb img,.media-thumb video{width:100%;height:100%;object-fit:cover;display:block}
.media-file{width:100%;height:100%;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:6px;color:var(--text-secondary);font-size:11px;text-align:center;padding:8px}
.media-x{position:absolute;top:5px;right:5px;width:24px;height:24px;border-radius:50%;background:rgba(23,23,23,.6);color:#fff;border:none;display:grid;place-items:center;cursor:pointer}
.media-badge{position:absolute;top:6px;left:6px;background:rgba(23,23,23,.6);color:#fff;border-radius:6px;padding:2px;display:inline-flex}
.media-prog{position:absolute;inset:auto 0 0 0;background:var(--accent-hover);color:#fff;font-size:11px;font-weight:600;text-align:center;padding:2px}
.media-retry{position:absolute;inset:auto 0 0 0;background:var(--danger);color:#fff;border:none;font-size:11px;padding:3px;cursor:pointer}
.media-thumb.is-failed{border-color:var(--danger)}
.media-size{position:absolute;bottom:5px;left:5px;background:rgba(23,23,23,.6);color:#fff;font-size:10px;font-weight:600;padding:1px 6px;border-radius:6px}
.media-ok{position:absolute;bottom:5px;right:5px;color:var(--success);background:#fff;border-radius:50%;display:inline-flex;padding:1px}
.upload-warn{display:flex;align-items:flex-start;gap:7px;background:var(--warning-soft);color:var(--warning);border:1px solid #FBD9A8;border-radius:10px;padding:9px 12px;font-size:12.5px;font-weight:500;margin-top:10px}
.upload-warn svg{flex:0 0 auto;margin-top:2px}
/* Lỗi của MỘT tệp cụ thể — đỏ, và ở lại cho tới khi người dùng xử lý, khác với
   .upload-warn (nhắc chung, màu cam) và khác toast (biến mất sau 2,4 giây). */
.upload-warn--err{background:var(--danger-soft,#FDECEC);color:var(--danger);border-color:#F5C2C2}
/* Vùng thả tệp: chỉ đổi diện mạo khi đang kéo, không viền đứt thường trực làm rối form */
#np-edit.is-dropping{outline:2px dashed var(--accent);outline-offset:6px;border-radius:12px;background:var(--accent-soft)}
.post-gallery{display:grid;gap:6px;margin-top:12px;border-radius:12px;overflow:hidden}
.post-gallery.n1{grid-template-columns:1fr}
.post-gallery.n2{grid-template-columns:1fr 1fr}
.post-gallery.n3,.post-gallery.n4{grid-template-columns:1fr 1fr}
.post-gallery img,.post-gallery video{width:100%;aspect-ratio:16/10;object-fit:cover;border-radius:8px;border:1px solid var(--border)}
.post-gallery.n1 img,.post-gallery.n1 video{aspect-ratio:16/9}
.file-card{display:flex;align-items:center;gap:10px;padding:10px 12px;border:1px solid var(--border);border-radius:10px;margin-top:8px;background:var(--surface-muted)}

/* ---------- Mobile header/bottomnav/sheet ---------- */
.mobile-only{display:none!important}
.desktop-only{display:flex}
.bottomnav{display:none}
.bn-item{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;padding:8px 0 calc(8px + env(safe-area-inset-bottom));color:var(--text-secondary);min-height:44px}
.bn-item.active{color:var(--accent-hover)}
.bn-ic{position:relative;display:inline-flex}
.bn-lbl{font-size:11px;font-weight:600;letter-spacing:-.01em}
.bn-dot{position:absolute;top:-2px;right:-4px;width:8px;height:8px;border-radius:50%;background:var(--accent);border:1.5px solid var(--surface)}
/* Ảnh đại diện đứng thay biểu tượng ở tab "Menu" (thanh dưới, điện thoại).
   Cao 22px cho khớp biểu tượng 21px của bốn tab kia — lệch một hai pixel là cả
   hàng nhìn thấy ngay. Vùng chạm KHÔNG bị ảnh hưởng: `.bn-item` vẫn `min-height:44px`
   và trải hết một phần năm bề ngang. */
.avatar--bn{width:22px;height:22px;font-size:9px;border-width:1px}
/* Tab đang mở: bốn tab kia đổi MÀU biểu tượng, nhưng ảnh đại diện thì không đổi
   màu được — nên nó nhận một vòng viền màu nhấn để cũng nói được "đang ở đây". */
.bn-item.active .avatar--bn{box-shadow:0 0 0 2px var(--accent-hover)}
.sheet{position:fixed;inset:0;z-index:120;background:rgba(23,23,23,.4);opacity:0;transition:opacity .2s;display:flex;align-items:flex-end}
.sheet.open{opacity:1}
.sheet__box{width:100%;max-height:88vh;background:var(--surface);border-radius:22px 22px 0 0;transform:translateY(100%);transition:transform .24s cubic-bezier(.32,.72,0,1);display:flex;flex-direction:column;overflow:hidden;padding-bottom:env(safe-area-inset-bottom)}
.sheet.open .sheet__box{transform:none}
.sheet__grab{width:38px;height:4px;border-radius:4px;background:var(--border-strong);margin:10px auto 4px}
.sheet__head{display:flex;align-items:center;gap:12px;padding:12px 18px 14px;border-bottom:1px solid var(--border)}
.sheet__body{overflow-y:auto;padding:10px 12px 18px}
.sheet__group{margin-bottom:6px}

/* ---------- Responsive ---------- */
.scrim{display:none}
@media(max-width:1180px){
  .dash-grid{grid-template-columns:1fr}
  /* Một cột thì KHÔNG ghim: cột phải nay nằm DƯỚI cột giữa, ghim nó lại là dán
     một khối chình ình che mất bài viết đang đọc. */
  .dash-grid>*:nth-child(2){position:static;max-height:none;overflow:visible}
}
@media(max-width:1024px){.g-4{grid-template-columns:repeat(2,1fr)}.g-3{grid-template-columns:repeat(2,1fr)}}
/* Tablet: thu gọn sidebar */
@media(max-width:1023px) and (min-width:768px){
  :root{--sidebar-w:208px}
  .sidebar__title small{display:none}
}
/* Mobile: ẩn sidebar, dùng header + bottom nav */
@media(max-width:767px){
  /* iOS không auto-zoom khi focus: mọi control >=16px trên mobile */
  input,textarea,select,.search input{font-size:16px}
  .shell{grid-template-columns:1fr}
  .sidebar{display:none}
  .mobile-only{display:flex!important}
  .desktop-only,.topbar__hide{display:none!important}
  /* Header ghim cố định đầu màn hình + safe-area cho notch iPhone */
  .topbar{
    position:fixed;top:0;left:0;right:0;z-index:55;
    height:calc(var(--topbar-h) + env(safe-area-inset-top));
    padding:env(safe-area-inset-top) 14px 0;gap:8px;
    background:var(--surface);backdrop-filter:blur(10px);
  }
  .topbar__spacer{flex:1}
  /* Brand mobile: 1 dòng, truncate gọn, không wrap */
  .topbar .sidebar__title{min-width:0;max-width:46vw;overflow:hidden;line-height:1.15}
  .topbar .sidebar__title,.topbar .sidebar__title small{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  /* Chừa chỗ cho header fixed để không che nội dung (composer, chips…) */
  .main{padding-top:calc(var(--topbar-h) + env(safe-area-inset-top))}
  /* Footer / Bottom nav ghim cố định cuối màn hình + safe-area */
  .bottomnav{
    display:flex;position:fixed;left:0;right:0;bottom:0;z-index:60;
    background:var(--surface);border-top:1px solid var(--border);box-shadow:0 -1px 8px rgba(0,0,0,.05);
  }
  /* Chừa chỗ cho footer fixed để bài viết cuối không bị che */
  #os-page{padding-bottom:var(--bottomnav-h)}
  /* Trang Tin nhắn tự chiếm trọn phần màn hình còn lại và tự chừa chỗ cho bottom
     nav, nên KHÔNG được cộng thêm padding nữa. Cộng hai lần thì tài liệu cao hơn
     màn hình đúng bằng chiều cao bottom nav, và thứ bị đẩy xuống dưới là ô nhập
     tin — tức là mở chat ra không gõ được gì. */
  #os-page.is-chat{padding-bottom:0}
  .content{padding:16px 14px 24px}
  .g-4,.g-3,.g-2{grid-template-columns:1fr}
  .hero{padding:20px 18px}.hero h1{font-size:22px}
  .page-head h1{font-size:21px}
  /* Một cột. Đang mở một cuộc trò chuyện (.show-win) thì cột đó là khung chat và
     danh sách lùi ra sau nút ←; chưa mở thì màn hình là DANH SÁCH.
     Bản trước để .chat__list{display:none} vô điều kiện — trên điện thoại, người
     dùng không bao giờ thấy được danh sách hội thoại, chỉ mãi ở cuộc trò chuyện
     đầu tiên và không có đường sang cuộc khác. */
  /* Chiều cao = màn hình − header − bottom nav. Ba điểm, mỗi điểm từng là một lỗi:
       · trừ đúng var(--bottomnav-h) thay vì số cứng 70px — số cứng bỏ quên vạch
         home iPhone (~34px), và đó chính là phần đã che mất ô nhập tin;
       · trừ cả env(safe-area-inset-top), vì .topbar mobile cao hơn --topbar-h
         đúng bằng safe-area trên máy có tai thỏ;
       · dùng svh chứ KHÔNG dùng dvh. svh là chiều cao khi thanh công cụ trình
         duyệt ĐANG HIỆN — tức trường hợp chật nhất, nên ô nhập luôn với tới được.
         dvh co giãn theo lúc ẩn/hiện thanh công cụ: khung chat nhảy khi cuộn, và
         đúng lúc thanh công cụ hiện ra thì ô nhập lại bị đẩy khuất. */
  .ctabs-strip{padding:0 14px}
  /* Công thức svh chuyển LÊN trang, không còn nằm ở .chat — xem chú thích ở
     bản desktop. Ba điểm đã tinh chỉnh phía trên giữ nguyên từng chữ. */
  #os-page.is-chat{
    height:calc(100vh  - var(--topbar-h) - env(safe-area-inset-top) - var(--bottomnav-h));
    height:calc(100svh - var(--topbar-h) - env(safe-area-inset-top) - var(--bottomnav-h));
  }
  .chat{grid-template-columns:1fr}
  .chat.show-win .chat__list{display:none}
  .chat:not(.show-win) .chat__win{display:none}
  .chat.show-win .chat__back{display:inline-flex}
  .bubble{max-width:80%}
  .tabs{overflow-x:auto;flex-wrap:nowrap;white-space:nowrap}
  /* Post head: badge xuống dòng riêng khi hẹp, không bóp méo */
  .post__head{flex-wrap:wrap;row-gap:6px}
  .post__tags{max-width:100%;flex-wrap:wrap;row-gap:6px}
  /* Action row trong post detail: cuộn ngang gọn thay vì vỡ */
  .post-detail-actions{display:flex;gap:8px;align-items:center;flex-wrap:nowrap;overflow-x:auto;-webkit-overflow-scrolling:touch}
  .post-detail-actions::-webkit-scrollbar{display:none}
  .post-detail-actions>*{flex:0 0 auto}
  /* 92vh trên iOS Safari đo theo màn hình KHI THANH ĐỊA CHỈ ĐÃ ẨN, nên lúc thanh
     còn hiện thì đáy hộp — chỗ đặt nút "Đăng bài" — nằm dưới mép nhìn thấy. dvh
     đo phần đang thật sự thấy. Giữ 92vh làm bản dự phòng cho trình duyệt cũ. */
  .modal{max-width:100%;border-radius:18px 18px 0 0;align-self:flex-end;max-height:92vh;max-height:92dvh}
  .overlay{align-items:flex-end;padding:0}
}
@media(min-width:768px){.bottomnav{display:none!important}}

/* ===== Admin Guide (#/admin/huong-dan) ===== */
.aguide-warn{display:flex;gap:9px;background:#FFF7D6;border:1px solid #F3D47A;color:#3A2A00;border-radius:12px;padding:12px 14px;margin:12px 0;font-size:14.5px;line-height:1.55;font-weight:500}
.aguide-warn svg{flex:0 0 auto;margin-top:2px;color:var(--accent-hover)}
@media(max-width:880px){
}

/* ===== Auth Landing (pageJoin — đồng bộ banner cộng đồng) ===== */
/* 🔴 CỘT, KHÔNG PHẢI HỘP CĂN GIỮA.
   Trước 2026-08-21 khối này chỉ chứa MỘT thẻ nên `align-items:center` +
   `justify-content:center` là đúng. Nay nó chứa BA khối (thanh trên cùng ·
   thanh tab · thân trang) — để nguyên thì cả ba cùng bị căn giữa và dàn hàng
   NGANG, trang vỡ hoàn toàn. Đó là lỗi Founder báo, và em đã đẩy nó lên
   production: phép đo DOM của em chỉ hỏi "có phần tử đó không", không hỏi "nó
   nằm ở đâu". Từ giờ đổi bố cục thì phải chụp màn hình, không chỉ đếm phần tử.
   Việc căn giữa theo chiều dọc nay thuộc về riêng `.auth-landing__body`. */
.auth-landing{min-height:100vh;min-height:100dvh;background:var(--background);
  display:flex;flex-direction:column}
/* Ba cột như trong app thật: thanh bên (khoá) · nội dung · thẻ tham gia.
   Người nhận link mời nhìn thấy đúng hình dáng nơi họ sắp bước vào, chứ không
   phải một trang đăng ký trơ trọi. */
.auth-shell{flex:1;display:grid;grid-template-columns:var(--sidebar-w) 1fr;min-height:0}
.auth-side{background:var(--sidebar-bg);border-right:1px solid var(--border);
  display:flex;align-items:center;justify-content:center;padding:24px 18px}
.auth-side__khoa{text-align:center;color:var(--text-muted);max-width:210px}
.auth-side__ic{display:grid;place-items:center;width:46px;height:46px;margin:0 auto 12px;
  border-radius:50%;background:var(--surface-muted);color:var(--text-muted)}
.auth-side__khoa b{display:block;color:var(--text-secondary);font-size:var(--fs-sm);margin-bottom:6px}
.auth-side__khoa p{font-size:var(--fs-xs);line-height:1.6}
.auth-main{min-width:0;display:flex;flex-direction:column}
.auth-join{padding:0;overflow:hidden}
.auth-join__body{padding:16px 18px 18px;display:flex;flex-direction:column;gap:8px}
.auth-hero__meta{display:flex;flex-direction:column;gap:2px;margin-top:12px}
/* 🔴 `.cinfo-cover` mang sẵn `margin:-20px -20px 14px` để TRÀN lên mép trên của
   thẻ — đúng khi nó là phần tử ĐẦU TIÊN. Ở đây tiêu đề đứng trước nó (theo mẫu),
   nên margin âm kéo ảnh bìa lên ĐÈ LÊN CHỮ. Ảnh chụp 2026-08-21 lộ ra ngay;
   phép kiểm DOM thì không, vì cả hai phần tử đều tồn tại và đúng thứ tự. */
.auth-hero .cinfo-cover{margin:12px 0 0;border-radius:var(--radius-md)}

/* ---------- Hộp đăng nhập nổi trên trang cộng đồng ----------
   Ảnh bìa tràn hết mép hộp (không bo góc dưới) rồi mới tới form — giống mẫu.
   Đóng hộp là về đúng chỗ vừa đứng, không mất ngữ cảnh. */
.modal--dangnhap .modal__body{padding:18px 20px 20px}
/* Hộp có banner 16:9 nên cần rộng hơn hộp form thường một chút; và phải cuộn
   được khi màn hình thấp — banner cao mà hộp không cuộn thì nút Đăng nhập nằm
   ngoài màn hình và không có cách nào bấm tới. */
.modal--dangnhap{max-width:440px;max-height:92vh;overflow-y:auto}
/* 🔴 KHUNG THEO TỈ LỆ ẢNH, KHÔNG THEO CHIỀU CAO CỨNG.
   `height:132px` + `background-size:cover` nghĩa là ảnh bìa bị CẮT hai đầu —
   Founder 2026-08-21 báo banner không hiện đủ. Ô tải ảnh bìa vốn ghi rõ
   "Ngang 16:9", nên khung phải đúng 16:9 thì `cover` mới không cắt gì.
   `aspect-ratio` chứ không tính tay: chiều cao tự đúng ở mọi bề ngang của hộp,
   kể cả khi hộp co lại trên điện thoại.
   Giới hạn `max-height` để trên màn thấp banner không đẩy nút Đăng nhập xuống
   dưới nếp gấp — người ta mở hộp này để BẤM, không phải để ngắm ảnh. */
.dn-bia{aspect-ratio:16/9;max-height:38vh;background:linear-gradient(120deg,#cc6600,#8f4700);
  border-radius:var(--radius-lg) var(--radius-lg) 0 0;
  display:flex;align-items:center;justify-content:center;padding:0 18px;
  background-size:cover;background-position:center}
.dn-bia img{max-height:80px;max-width:100%;object-fit:contain;display:block}
.dn-ten{font-size:19px;font-weight:800;letter-spacing:-.02em;line-height:1.25}
/* Hai lối phụ trong hộp đăng nhập: Google và nhóm Zalo (mẫu iNET, 25/08/2026).
   Cả hai là nút PHỤ nên dùng `.btn--ghost` — nút chính "Đăng nhập" phải giữ
   được vai trò dẫn mắt, hai nút nữa cùng màu đặc là ba thứ tranh nhau. */
.dn-google{margin-top:10px;gap:9px;min-height:46px}
/* Hai nút mạng xã hội đứng NGANG HÀNG (Founder 25/08/2026).
   `repeat(2,1fr)` chứ không `flex-wrap`: hai nút phải rộng bằng nhau và không
   được rơi xuống dòng khi chữ dài (luật giao diện #6).
   Chỉ có một link ⇒ `--mot` cho nó chiếm cả hàng, không chừa ô trống bên cạnh. */
.dn-mxh{display:grid;grid-template-columns:repeat(2,1fr);gap:8px;margin-top:10px}
.dn-mxh--mot{grid-template-columns:1fr}
.dn-mxh>.btn{min-height:46px;gap:7px;padding-left:8px;padding-right:8px;white-space:nowrap}
.dn-zalo__ic{padding:2px 7px;border-radius:6px;flex:0 0 auto;
  background:#0068FF;color:#fff;font-weight:800;font-size:11px;letter-spacing:-.01em}
.dn-fanpage__ic{width:20px;height:20px;border-radius:6px;flex:0 0 auto;display:grid;place-items:center;
  background:#1877F2;color:#fff;font-weight:800;font-size:13px;line-height:1}
/* Màn rất hẹp (≤359px): hai nhãn cạnh nhau hết chỗ ⇒ xếp dọc, mỗi nút cả hàng.
   Thà hai hàng gọn còn hơn hai nút bị cắt chữ. */
@media(max-width:359px){ .dn-mxh{grid-template-columns:1fr} }
.dn-google__g{width:20px;height:20px;border-radius:50%;flex:0 0 auto;display:grid;place-items:center;
  background:#fff;border:1px solid var(--border);font-weight:800;font-size:12px;color:#4285F4}
/* Vạch "hoặc" — chỉ hiện khi CÓ cả hai lối, nếu không nó ngăn cách một thứ với
   khoảng không. */
.dn-hoac{display:flex;align-items:center;gap:10px;margin:12px 0 2px;color:var(--text-muted);font-size:var(--fs-xs)}
.dn-hoac::before,.dn-hoac::after{content:'';flex:1;height:1px;background:var(--border)}
/* Điện thoại: bỏ thanh bên khoá (một cột trống chiếm nửa màn hình mà không nói
   thêm gì), thẻ tham gia xuống dưới nội dung. */
@media(max-width:1023px){
  .auth-shell{grid-template-columns:1fr}
  .auth-side{display:none}
}
/* MỘT cột. Cột phải (bốn card giới thiệu tính năng) đã gỡ khỏi pageJoin, nên để
   nguyên `1fr 1fr` thì thẻ đăng ký nằm lệch nửa trái với nửa phải trống trơn. */
/* Hai cột: nội dung + thẻ tham gia. Rộng hơn 560px cũ vì nay có video 16:9 —
   ở 560px thì video co lại còn bằng một cái thumbnail. */
.auth-grid{width:100%;max-width:1200px;margin:0 auto;padding:18px 24px 40px;
  display:grid;grid-template-columns:minmax(0,1fr) 300px;gap:22px;align-items:start}
@media(max-width:1023px){
  .auth-grid{grid-template-columns:1fr;padding:16px 14px 32px}
}
.auth-col{min-width:0}
.auth-hero{padding:20px}
.cinfo-cover--auth{height:120px}
.cinfo-cover--auth img{max-height:74px}
.auth-hero__title{font-size:26px;font-weight:800;letter-spacing:-.02em;line-height:1.2;margin-top:2px}
.auth-hero__sub{color:var(--text-secondary);font-size:15px;line-height:1.6;margin-top:8px}
.auth-hero__desc{color:var(--text-muted);font-size:13.5px;line-height:1.6;margin-top:8px}
/* .auth-stats/.auth-stat* đã GỠ cùng bốn ô số liệu ở trang Giới thiệu
   (2026-08-16) — xem ghi chú trong pageJoin(). */
/* Bốn ô số liệu từng nằm giữa phần mô tả và cụm nút, nên khoảng thở phía trên
   cụm nút vốn do `margin:16px 0` của chúng tạo ra. Gỡ khối mà quên chỗ này thì
   nút "Đăng ký tham gia" dính sát vào đoạn chữ ngay trên nó. */
.auth-cta{display:flex;gap:10px;margin-top:18px}
/* 🔴 TRONG THẺ THAM GIA (cột phải, rộng 300px) HAI NÚT PHẢI XẾP CHỒNG.
   Ảnh chụp 2026-08-21 cho thấy "Đăng ký tham gia" bị cắt thành "Đăng ký tham g…"
   khi đứng cạnh "Đăng nhập" trong cột hẹp. Phép kiểm DOM của em không bắt được
   — nó hỏi "nút có tồn tại không", không hỏi "chữ có đọc được không".
   `btn--block` đã nói ý định "chiếm trọn hàng"; hàng cha phải là CỘT thì ý định
   đó mới thành hình. */
/* Bám vào CỘT, không bám vào tên thẻ. Thẻ bên trong đã đổi từ `.auth-join`
   sang thẻ chung `.cinfo` — quy tắc bám tên thẻ liền hết tác dụng và hai nút
   lại bị cắt chữ. Cột phải thì lúc nào cũng hẹp, bất kể bên trong là thẻ nào. */
.auth-aside .auth-cta{flex-direction:column;gap:8px}
.auth-aside .auth-cta .btn{white-space:normal}
/* flex-basis theo NỘI DUNG, không phải 0. Với `flex:1 1 0` hai nút chia đôi bề
   ngang bất kể chữ dài ngắn, nên "Đăng ký tham gia" bị cắt cụt cạnh "Đăng nhập"
   ở màn 375px — đúng lỗi nhìn thấy sau khi gỡ nút demo. */
.auth-cta .btn{flex:1 1 auto;min-width:0;white-space:nowrap}
@media(max-width:880px){ .auth-grid{gap:14px} }
/* ═══ MÀN KHÁCH TRÊN ĐIỆN THOẠI / TABLET — RÚT CÒN ĐÚNG THẺ GỌN ═══
   Founder chốt 25/08/2026 (khoanh khung đỏ trên ảnh): máy tính giữ hai cột,
   điện thoại chỉ còn thẻ giới thiệu gọn.
   Vì sao: khi `.auth-grid` xuống một cột, thẻ LỚN bên trái và thẻ GỌN bên phải
   kể CÙNG một câu chuyện hai lần — cùng ảnh bìa, cùng tên, cùng mô tả ngắn.
   Người lạ phải cuộn hết bản dài mới tới được nút "Đăng ký tham gia", thứ duy
   nhất họ cần bấm. Một màn hình, một câu chuyện, một nút.
   🔴 GIỮ LẠI video giới thiệu nếu nhóm có: thẻ gọn không chứa được video, bỏ nó
   đi là XOÁ tài sản bán hàng tốt nhất của nhóm chứ không phải "tinh gọn". */
@media(max-width:1023px){
  /* Thẻ lên đầu, và KHÔNG cho nó phình theo bề ngang màn hình. Ở 900px thẻ
     "gọn" trải hết 766px thì ảnh bìa cao hơn 400px — nó thôi không còn là
     thẻ gọn nữa, mà thành đúng cái thẻ lớn vừa gỡ đi. 420px là bề ngang thẻ
     vẫn đọc như một thẻ; dưới mốc đó (điện thoại) thì thẻ tự tràn hết. */
  .auth-grid>.auth-aside{order:-1;width:100%;max-width:420px;margin-left:auto;margin-right:auto}
  /* Không có video ⇒ cả cột trái biến mất (không để lại thẻ rỗng, không để lại
     khoảng `gap` mồ côi giữa hai thứ mà một thứ đã tàng hình). */
  .auth-col:not(.auth-col--video){display:none}
  /* Có video ⇒ chỉ còn khung video, bỏ vỏ thẻ: tên và mô tả đã nằm trong thẻ gọn
     ngay bên trên, in lại lần nữa là quay về đúng cái đang sửa. */
  .auth-col--video>.auth-hero{padding:0;border:0;background:none;box-shadow:none}
  .auth-col--video>.auth-hero>:not(.comm-about__video){display:none}
}
/* Xếp dọc sớm hơn nhiều so với mốc 359px cũ: hai nút tiếng Việt có dấu cần chỗ
   rộng hơn hẳn hai nút tiếng Anh cùng nghĩa. */
@media(max-width:430px){
  .auth-cta{flex-direction:column}
}

.nav-item__ext{margin-left:auto;color:var(--text-muted);display:inline-flex}

/* ===== AI Agent Hub — nhóm theo 7 Phase ===== */
.phase-sec{margin-bottom:28px;padding-bottom:8px;border-bottom:1px solid var(--border)}
.phase-sec:last-child{border-bottom:none}
.phase-sec__head{display:flex;align-items:center;gap:10px;margin-bottom:6px}
.phase-sec__head h2{font-size:19px;font-weight:800;letter-spacing:-.01em}
.phase-sec__desc{color:var(--text-secondary);font-size:14.5px;line-height:1.6;margin-bottom:14px;max-width:760px}
.phase-sec__label{display:flex;align-items:center;gap:7px;font-size:13px;font-weight:700;text-transform:uppercase;letter-spacing:.04em;color:var(--text-muted);margin:6px 0 10px}
.phase-sec__label svg{color:var(--accent-hover)}

/* ===== AI Agent Hub — roadmap kiểu Portal (rsteps) ===== */
.phase-pack{margin-left:auto;font-size:12px;font-weight:600;color:var(--accent-hover);background:var(--accent-soft);border:1px solid var(--accent-border);border-radius:8px;padding:3px 9px}
.rsteps{display:flex;flex-direction:column;gap:8px;margin:10px 0 12px}
.rstep{border:1px solid var(--border-card);border-radius:12px;overflow:hidden;background:var(--surface)}
.rstep-agent{display:flex;align-items:center;gap:10px;padding:11px 13px;background:var(--surface-muted)}
.ra-no{flex:0 0 auto;width:26px;height:26px;border-radius:7px;background:var(--accent-hover);color:#fff;font-weight:800;font-size:12px;display:grid;place-items:center}
.ra-name{font-weight:700;color:var(--text-primary);min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ra-name:hover{color:var(--accent-hover)}
.ra-right,.rs-right{margin-left:auto;display:flex;align-items:center;gap:8px;flex:0 0 auto}
.ra-cmd,.rs-cmd{font-family:ui-monospace,Menlo,monospace;font-size:12.5px;color:var(--accent-hover);background:var(--surface);border:1px solid var(--border);border-radius:7px;padding:2px 8px;white-space:nowrap}
.rstep-skill{display:flex;align-items:center;gap:10px;padding:8px 13px 8px 20px;border-top:1px solid var(--border);font-size:14px;color:var(--text-secondary)}
.rs-name{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.al-dl{flex:0 0 auto;width:30px;height:30px;border-radius:8px;display:grid;place-items:center;background:var(--accent-soft);color:var(--accent-hover);border:1px solid var(--accent-border)}
.al-dl:hover{background:var(--accent-hover);color:#fff}
.al-dl--lock{background:var(--surface-muted);color:var(--text-muted);border-color:var(--border)}
.rsteps-out{font-size:13.5px;color:var(--text-secondary);background:var(--surface-muted);border-radius:10px;padding:10px 13px}
.rsteps-out b{color:var(--text-primary)}
@media(max-width:560px){.ra-cmd,.rs-cmd{display:none}.phase-pack{display:none}}

/* ===== AI Agent Hub — Phase accordion (card thu gọn) ===== */
.phase-acc{border:1px solid var(--border-card);border-radius:14px;background:var(--surface);margin-bottom:12px;overflow:hidden;box-shadow:var(--shadow-soft)}
.phase-acc__head{width:100%;display:flex;align-items:center;gap:12px;padding:15px 16px;background:none;border:none;cursor:pointer;text-align:left}
.phase-acc__head:hover{background:var(--surface-muted)}
.phase-acc__title{font-size:16px;font-weight:800;letter-spacing:-.01em;color:var(--text-primary);min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.phase-acc__count{margin-left:auto;flex:0 0 auto;font-size:12.5px;font-weight:600;color:var(--text-muted);white-space:nowrap}
.phase-acc__chev{flex:0 0 auto;display:inline-flex;color:var(--text-muted);transition:transform .2s}
.phase-acc.is-open .phase-acc__chev{transform:rotate(180deg)}
.phase-acc__body{display:none;padding:0 16px 16px}
.phase-acc.is-open .phase-acc__body{display:block}
@media(max-width:560px){.phase-acc__count{display:none}}

/* AI Agent Hub — 7 Phase xếp 2 cột */
.phase-grid{display:grid;grid-template-columns:1fr 1fr;gap:12px;align-items:start}
.phase-grid .phase-acc{margin-bottom:0}
@media(max-width:767px){.phase-grid{grid-template-columns:1fr}}

/* Trên mobile, <small> nằm cùng dòng nên dính liền: "AI BOSCommunity OS". */
.topbar .sidebar__title small{margin-left:6px}

/* =====================================================================
   COMMUNITY — header, composer, post card, bình luận, các trạng thái
   ===================================================================== */
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}
.center{text-align:center;margin-top:14px}
.right{text-align:right}
.linkish{background:none;border:none;padding:0;font:inherit;font-size:13px;font-weight:600;color:var(--text-muted);cursor:pointer}
.linkish:hover{color:var(--text-primary)}
.linkish--danger:hover{color:var(--danger)}
/* Ngăn giữa nhóm "sắp xếp" và nhóm "danh mục" — cả hai đều có 1 pill đang bật,
   không có vạch này thì trông như hai lựa chọn xung khắc cùng bật một lúc. */
.chips-sep{width:1px;flex:0 0 auto;background:var(--border-strong);margin:4px 6px}

/* ---------- Composer ---------- */
.composer{background:var(--surface);border:1px solid var(--border-card);border-radius:var(--radius-md);
  padding:10px 12px;margin-bottom:10px;box-shadow:none}
.composer__top{display:flex;align-items:center;gap:12px;cursor:pointer}
.composer__input{flex:1;min-width:0;background:var(--surface-muted);border:1px solid var(--border);
  border-radius:999px;padding:10px 16px;color:var(--text-muted);font-size:var(--fs-sm);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.composer__top:hover .composer__input{border-color:var(--border-strong);color:var(--text-secondary)}

/* ---------- Post card ---------- */
/* Chỉ card feed xếp tên/vai trò trên, thời gian dưới. Trang chi tiết giữ nguyên
   bố cục cũ (một dòng + <br>) nên phải loại trừ, không thì <br> tách thành item. */
.post__meta:not(.post__meta--detail){display:flex;flex-direction:column;gap:2px;line-height:1.35}
.post__author{display:flex;align-items:center;gap:8px;min-width:0;font-size:var(--fs-sm)}
.post__author b{color:var(--text-primary);font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.post__time{font-size:12.5px;color:var(--text-muted)}
.post__titlelink{display:block;text-decoration:none;color:inherit}
.post__titlelink:hover .post__title{color:var(--accent-hover)}
.post__body{white-space:pre-wrap;overflow-wrap:anywhere}
.post__body.is-clamped{display:-webkit-box;-webkit-line-clamp:5;-webkit-box-orient:vertical;overflow:hidden}
.post__more{margin-top:6px;background:none;border:none;padding:0;font:inherit;font-size:13.5px;
  font-weight:600;color:var(--accent-hover);cursor:pointer}
.post__more:hover{color:var(--accent-hover);text-decoration:underline}
.post__stats{display:flex;align-items:center;gap:16px;flex-wrap:wrap;margin-top:13px;
  color:var(--text-muted);font-size:13px}
.post__stat{display:inline-flex;align-items:center;gap:6px;color:inherit;text-decoration:none}
a.post__stat:hover{color:var(--text-primary)}
.post-actions{display:flex;gap:4px;margin-top:8px;padding-top:6px;border-top:1px solid var(--border)}
.post-action{flex:1;display:inline-flex;align-items:center;justify-content:center;gap:6px;
  min-height:36px;padding:6px 6px;border-radius:8px;background:none;border:none;
  color:var(--text-secondary);font:inherit;font-size:13px;font-weight:600;cursor:pointer;
  text-decoration:none;transition:background .14s,color .14s}
.post-action:hover{background:var(--surface-muted);color:var(--text-primary)}
.post-action.is-on{color:var(--accent-hover)}
.post-action.is-on svg{fill:currentColor}
.post--preview{border-style:dashed}

/* ---------- Feed: loading · error ---------- */
.feed-loading{display:flex;flex-direction:column;gap:14px}
.post--sk{pointer-events:none}
.sk-head{display:flex;align-items:center;gap:11px}
.sk-av{width:34px;height:34px;border-radius:50%;flex:0 0 auto}
.sk-lines{flex:1;display:flex;flex-direction:column;gap:7px}
.sk-l{height:11px;border-radius:6px;width:100%;margin:7px 0 0}
.feed-error{display:flex;align-items:center;gap:14px}
.feed-error__ic{flex:0 0 auto;width:42px;height:42px;border-radius:12px;display:grid;place-items:center;
  background:var(--danger-soft);color:var(--danger)}
.feed-error__main{flex:1;min-width:0}

/* ---------- Bình luận ---------- */
.cmt-compose{display:flex;gap:11px;align-items:flex-start;margin-bottom:16px}
.cmt-compose__main{flex:1;min-width:0}
.cmt-compose textarea{width:100%;background:var(--surface-muted);border:1px solid var(--border);
  border-radius:12px;padding:11px 13px;font-family:inherit;font-size:var(--fs-sm);
  color:var(--text-primary);outline:none;resize:vertical}
.cmt-compose textarea:focus{border-color:var(--accent)}
.cmt-compose .right{margin-top:8px}
.cmt{display:flex;gap:11px;align-items:flex-start}
.cmt__main{flex:1;min-width:0}
.cmt__bubble{background:var(--surface-muted);border:1px solid var(--border);border-radius:14px;padding:10px 13px}
.cmt__head{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.cmt__head b{font-size:var(--fs-sm);font-weight:600}
.cmt__time{margin-left:auto}
.cmt__body{margin-top:5px;color:var(--text-secondary);font-size:var(--fs-sm);
  line-height:1.6;white-space:pre-wrap;overflow-wrap:anywhere}
.cmt__foot{display:flex;gap:16px;margin:6px 0 0 4px}
.post-detail-body{margin-top:14px;font-size:15px;line-height:1.7;color:var(--text-secondary);
  white-space:pre-wrap;overflow-wrap:anywhere}

/* ---------- Composer modal: tab Soạn bài / Xem trước ---------- */
.np-tabs{display:flex;gap:6px;margin-bottom:14px;border-bottom:1px solid var(--border)}
.np-tab{background:none;border:none;border-bottom:2px solid transparent;margin-bottom:-1px;
  padding:8px 12px;min-height:40px;font:inherit;font-size:var(--fs-sm);font-weight:600;
  color:var(--text-muted);cursor:pointer}
.np-tab:hover{color:var(--text-primary)}
.np-tab.is-active{color:var(--accent-hover);border-bottom-color:var(--accent)}
.np-preview .post{box-shadow:none}

/* =====================================================================
   CARD BÀI VIẾT — MOBILE (≤767px). Cấu trúc: tác giả → text trái + thumbnail
   phải → hàng tương tác. Không card lồng card, không khung nền xám quanh ảnh.
   ===================================================================== */
/* Card tràn hết bề ngang màn hình (bù đúng padding ngang 14px của .content trên
   mobile), phần đệm 16px nằm bên trong card — giống dải feed liền mạch của Skool.
   Các bài ngăn nhau bằng một đường viền mảnh, không phải khe hở + bóng đổ. */
.post--m{padding:12px 16px;border:0;border-radius:0;background:var(--background);cursor:pointer;
  border-bottom:1px solid var(--border);margin-left:-14px;margin-right:-14px}
.post--m:last-child{border-bottom:0}
@media(max-width:767px){
  #c-feed{gap:0}                          /* các bài dính nhau, ngăn bằng viền */
  #c-feed .feed-loading{gap:14px;padding:10px 0}
}
/* 🔴 TRÊN MÁY TÍNH, BÀI VIẾT LÀ CARD RỜI — không phải dải liền mạch.
   Founder 2026-08-21: "chiều rộng card vừa đúng khoảng cách bên trong cột giữa,
   đang bị mất" và "viền card vẫn đậm, trên dưới".

   Cả hai cùng một gốc: `feedCardMode()` trả 'mobile' cho MỌI khổ màn, nên máy
   tính cũng dùng `.post--m` — kiểu dải Skool: bỏ viền hai bên, bỏ bo góc, chỉ
   còn `border-bottom`, và lùi ra `-14px` mỗi bên. Con số 14px đó tính cho lề
   ngang của `.content` TRÊN ĐIỆN THOẠI; máy tính lề 24px, nên card thò ra lệch
   hẳn so với ô soạn bài và thanh tab.
   Còn "đậm trên dưới" chính là hệ quả của việc chỉ còn viền ngang: hai bài kề
   nhau xếp `border-bottom` sát nhau thành một vạch liền — mắt đọc ra một đường
   kẻ đậm, dù màu viền đã hạ hai lần.

   Ở đây trả lại đúng hình dạng card: viền đủ bốn cạnh (màu đã mờ), bo góc, bóng
   nhẹ, không lùi âm — nên card rộng ĐÚNG bằng ô soạn bài, và khe 10px của
   `.stack` tách chúng ra thay cho đường kẻ.
   Điện thoại giữ nguyên dải liền mạch: ở khổ hẹp, khe hở + bóng đổ ăn mất chiều
   cao mà không thêm nghĩa gì. */
@media(min-width:768px){
  .post--m{
    margin-left:0;margin-right:0;padding:8px 16px;
    /* 🔴 VIỀN MỜ, MẢNH — Founder chốt 24/08/2026 (lượt sau khi đổi nền card).
       Ba lượt trước Founder xin "mờ hơn" rồi cuối cùng bỏ hẳn viền — ĐÚNG cho
       bối cảnh lúc đó: card còn màu TRẮNG, nên bản thân màu nền đã cắt được
       card khỏi nền và đường kẻ chỉ là thứ thừa ra.
       Nay nền card BẰNG nền app, màu không cắt được gì nữa, nên viền đổi vai:
       từ trang trí thành CẠNH DUY NHẤT. Đây không phải đảo quyết định cũ — bối
       cảnh đã khác.
       Chọn `--border` (#E5E2DC → 1,205:1 trên nền mới): mảnh 1px, mờ thật, và
       là ĐÚNG token đang vẽ đường ngăn bài trên điện thoại ⇒ một ngôn ngữ thị
       giác, không đẻ ra cái thứ hai.
       KHÔNG dùng `--border-card` (#F6F4F1): đo được 1,023:1 — mắt không thấy,
       tức là dựng lại đúng cái tàng hình vừa phải đi sửa. */
    border:1px solid var(--border);border-radius:var(--radius-md);
    /* 🔴 TRẢ BÓNG VỀ MỘT LỚP. Bóng hai lớp là thứ em thêm vào lượt trước ĐỂ BÙ
       cho việc không có viền. Nay đã có viền thật thì giữ cả hai là tách card
       bằng hai cách cùng lúc — card nổi lên như hộp thoại, đúng kiểu rườm rà
       mà R8 cấm. Đây là con số Founder đã tinh chỉnh trước đó, không phải số
       mới. */
    box-shadow:0 1px 3px rgba(0,0,0,.05);
    /* 🔴 MỌI CARD CAO BẰNG NHAU, VÀ VỪA ĐÚNG 3 CARD TRONG KHUNG.
       Founder 2026-08-21 chốt theo ảnh mẫu: một màn hình chứa 3 bài.
       Tính ngược từ khung: màn 900px → khung 844 − ô soạn bài 110 − thanh tab
       và đệm 60 − nút sang trang 50 = 624px cho dòng bài.
       3 card + 2 khe 10px = 624 ⇒ mỗi card ≈ 201px.
       201 = đệm 24 + đầu bài 42 + thân 8 + ô ảnh 104 + hàng nút 30 (≈208, sát).
       Ô ảnh hạ từ 140 → 104px cho khớp; xem quy tắc `.pm-thumb` ngay dưới. */
    /* Đo trên production 1440×900:
         vùng cuộn 709 − đệm trên 18 − ô soạn bài 124 = 567px cho dòng bài.
         3 card + 2 khe 8px = 567 ⇒ mỗi card 183,67px.
       Đặt 183 thì đo ra 184 (làm tròn lên) ⇒ 3×184+16 = 568 > 567, thừa ĐÚNG
       MỘT pixel và card thứ ba rớt ra. Nên chốt 176px: dư ~8px, chịu được cả khi
       ô soạn bài cao hơn một chút (người dùng có ảnh đại diện to hơn, hay chữ
       trong ô soạn xuống dòng).
       🔴 Không tính sát mép. Bố cục sát mép thì chỉ cần một font khác, một thanh
       cuộn khác là vỡ — và người dùng thấy vỡ chứ không thấy con số. */
    min-height:176px;
  }
  /* 🔴 BÀI CUỐI PHẢI CÓ ĐỦ BỐN CẠNH — sửa 24/08/2026.
     Dòng này sinh ra hồi card còn viền `transparent`: nó chỉ để CHIỀU CAO bài
     cuối bằng các bài khác (mobile base đặt `border-bottom:0`), chứ không phải
     để giấu cạnh. Nay viền đã là đường thật, giữ `transparent` ở đây nghĩa là
     card cuối cùng hở đáy — ba cạnh có viền, cạnh dưới không. Mắt bắt ra ngay,
     mà không ai đọc CSS thì không hiểu vì sao chỉ mình nó khác. */
  .post--m:last-child{border-bottom:1px solid var(--border)}
  /* Chặn hai nguồn làm card cao lệch: tiêu đề dài và đoạn trích dài.
     Cắt 2 dòng — chữ bị cắt vẫn đọc được đủ bằng cách bấm vào tiêu đề (nó là
     link sang trang bài), nên đây không phải ngõ cụt. */
  .post--m .pm-title{
    display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;
  }
  .post--m .pm-excerpt,.post--m .pm-excerpt.is-clamped{
    display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;
  }
  /* Bài KHÔNG có ảnh: chừa đúng chỗ ô ảnh để hàng nút của mọi card thẳng hàng.
     Phải bằng ĐÚNG `.pm-thumb` ở khổ này (nay 104px — hạ từ 140 để vừa 3 card).
     Đây mới là thứ quyết định chiều cao card; `min-height` trên `.post--m` chỉ
     là sàn phòng khi bài trống trơn. Đổi một trong hai mà quên cái kia là card
     lệch nhau đúng bằng phần chênh — đã vấp một lần. */
  /* Ô ảnh và chỗ chừa cho nó phải BẰNG NHAU; đổi một trong hai mà quên cái kia
     là card lệch đúng bằng phần chênh (đã vấp một lần với 104 vs 140). */
  /* 🔴 Cắt phần ĐỆM, KHÔNG cắt ô ảnh. Ô ảnh là thứ duy nhất trong card mang
     thông tin thật; thu nó xuống nữa thì thành một chấm không nhìn ra gì.
     Khoảng thở thì cắt được — 2px mỗi chỗ, mắt không nhận ra, mà đủ để card
     thứ ba lọt trọn. */
  .post--m .pm-thumb{width:76px;height:76px}
  .post--m .pm-body{min-height:76px;margin-top:4px}
  /* Ảnh đại diện nhỏ lại Ở KHỔ MÁY TÍNH thôi. Đo được: card còn 210px trong khi
     cần 188 — phần thừa nằm ở đầu bài (avatar 42px) và khoảng cách quanh nó.
     Điện thoại giữ 42px: ở đó ngón tay chạm vào avatar để mở hồ sơ, thu nhỏ là
     phá vùng chạm 44px (luật cứng). */
  .post--m .avatar--m{width:36px;height:36px;font-size:14px}
  .post--m .pm-acts{margin-top:4px;gap:10px}
  /* Chuyển sang từ khối trùng vừa gỡ, với giá trị đã tính lại cho khung 3 card:
     cỡ chữ giữ nguyên; đoạn trích cắt 2 dòng (khối cũ để 4 — đó là một nguồn
     nữa làm card cao lệch); ô ảnh 76px thay cho 140px. */
  .post--m .pm-title{font-size:16px}
  .post--m .pm-excerpt{font-size:14px}
  .post--m .pm-body{gap:14px}
}
.pm-head{display:flex;align-items:flex-start;gap:10px}
.avatar--m{width:42px;height:42px;font-size:15px;flex:0 0 auto}
.pm-who{flex:1;min-width:0}
/* Tên + nhãn vai trò. Chữ phải nằm trong .pm-name__t chứ không thả trực tiếp vào
   .pm-name: text-overflow:ellipsis không có tác dụng lên text node của một flex
   container, tên dài sẽ tràn ra thay vì cắt gọn. */
.pm-name{display:flex;align-items:center;gap:6px;min-width:0}
.pm-name__t{font-weight:700;font-size:14.5px;color:var(--text-primary);line-height:1.3;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* .post__role / .cmt__role / .pm-role đã GỠ cùng nhãn vai trò cạnh tên
   (2026-08-18). Ba lớp không ai dùng sẽ khiến người sau tưởng nhãn đó vẫn còn
   và đi tìm xem nó vẽ ở đâu. */
.pm-sub{margin-top:1px;font-size:12.5px;color:var(--text-muted);line-height:1.35;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pm-tools{flex:0 0 auto;display:flex;align-items:center;gap:4px}
.pm-pin{display:inline-flex;align-items:center;gap:4px;font-size:11px;font-weight:600;
  color:var(--accent-hover);background:var(--accent-soft);border:1px solid var(--accent-border);
  border-radius:999px;padding:2px 8px;white-space:nowrap}
.pm-menu{width:32px;height:32px}

.pm-body{display:flex;gap:12px;align-items:flex-start;margin-top:8px}
.pm-text{flex:1;min-width:0}
.pm-title{font-size:15px;font-weight:700;color:var(--text-primary);line-height:1.35}
.pm-excerpt{margin-top:4px;font-size:14px;line-height:1.5;color:var(--text-secondary);
  white-space:pre-wrap;overflow-wrap:anywhere}
.pm-excerpt.is-clamped{display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden}
.post--m .post__more{margin-top:4px;font-size:13px}

/* Thumbnail vuông bên phải. Ảnh cover ở feed cho đều hàng; bản gốc xem đủ khung
   trong trình xem lớn. Không bọc nền xám — nền chỉ hiện khi ảnh chưa tải. */
.pm-thumb{position:relative;flex:0 0 auto;width:104px;height:104px;padding:0;border:0;
  border-radius:10px;overflow:hidden;background:var(--surface-muted);cursor:pointer;display:block}
.pm-thumb img,.pm-thumb video{width:100%;height:100%;object-fit:cover;display:block}
.pm-play{position:absolute;inset:0;margin:auto;width:34px;height:34px;border-radius:50%;
  background:rgba(0,0,0,.55);color:#fff;display:grid;place-items:center;pointer-events:none}
.pm-dur{position:absolute;right:5px;bottom:5px;background:rgba(0,0,0,.7);color:#fff;
  font-size:10.5px;font-weight:600;padding:1px 5px;border-radius:4px;pointer-events:none}
.pm-dur:empty{display:none}
.pm-more-n{position:absolute;right:5px;top:5px;background:rgba(0,0,0,.65);color:#fff;
  font-size:11px;font-weight:700;padding:2px 7px;border-radius:999px;pointer-events:none}
@media(max-width:359px){.pm-thumb{width:88px;height:88px}}
@media(min-width:430px) and (max-width:767px){.pm-thumb{width:118px;height:118px}}

/* Vùng chạm ≥44px cho cả hai nút tương tác. */
.pm-acts{display:flex;align-items:center;gap:6px;margin-top:8px}
.pm-act{display:inline-flex;align-items:center;gap:7px;min-height:44px;min-width:56px;
  padding:0 10px;border:0;background:none;border-radius:8px;cursor:pointer;text-decoration:none;
  color:var(--text-secondary);font:inherit;font-size:13.5px;font-weight:600}
.pm-act i{font-style:normal}
.pm-act:hover{background:var(--surface-muted);color:var(--text-primary)}
.pm-act.is-on{color:var(--accent-hover)}
.pm-act.is-on svg{fill:currentColor}

/* =====================================================================
   THANH BỘ LỌC FEED: 3 chip nhanh + dropdown chủ đề. Thay cho hàng chip dài
   cuộn ngang trước đây — mobile không còn hàng chip nào.
   ===================================================================== */
.feedbar__sorts{display:flex;gap:6px;flex-wrap:wrap;min-width:0}
/* Dòng "Đang xem kênh X · Xem tất cả" — CHỈ hiện khi đang lọc theo kênh.
   Thay cho ô "Kênh: Tất cả" đã gỡ: ô kia hiện thường trực và phần lớn thời
   gian chỉ nói "Tất cả", tức chiếm một hàng để không nói gì. Dòng này im lặng
   khi không có gì để nói, và khi nói thì mang sẵn đường ra — quan trọng trên
   điện thoại, nơi thanh bên (chỗ đánh dấu kênh đang mở) bị ẩn. */
.kenh-dang-xem{display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding:9px 13px;border-radius:var(--radius-sm);background:var(--accent-soft);
  color:var(--accent-hover);font-size:var(--fs-sm)}
.kenh-dang-xem span{display:inline-flex;align-items:center;gap:7px;min-width:0}
.kenh-dang-xem b{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* Nhãn kín/công khai — dòng phụ, KHÔNG phải huy hiệu màu. Nó là một sự thật
   cần biết, không phải một lời quảng cáo; tô cam lên là nó tranh chỗ với tên
   cộng đồng ngay bên trên. */
.cinfo-kin{display:flex;align-items:center;gap:6px;color:var(--text-secondary);
  font-size:var(--fs-xs);margin:2px 0 6px}
.cinfo-kin svg{flex:0 0 auto;opacity:.75}

/* ---------- Menu "..." trên bài đăng ----------
   Mọc ra TỪ nút vừa bấm (toạ độ do JS đo bằng getBoundingClientRect), không phải
   hộp thoại giữa màn hình: bấm dấu ba chấm ở bài thứ tư mà hộp nhảy ra chính
   giữa thì mắt phải đi tìm lại xem mình vừa bấm vào bài nào.
   `position:fixed` chứ không `absolute`: bài viết nằm trong khung cuộn riêng
   (#c-scroll), absolute sẽ bị cắt mất ở mép khung. */
.pmenu{
  position:fixed;z-index:90;min-width:212px;padding:6px;
  background:var(--surface);border:1px solid var(--border-strong);
  border-radius:var(--radius-md);box-shadow:var(--shadow-pop);
}
.pmenu__item{
  display:flex;align-items:center;gap:10px;width:100%;padding:9px 10px;
  background:none;border:0;border-radius:var(--radius-sm);cursor:pointer;
  font-size:var(--fs-sm);color:var(--text-primary);text-align:left;font-family:inherit;
}
.pmenu__item:hover,.pmenu__item:focus-visible{background:var(--surface-muted);outline:none}
.pmenu__item:focus-visible{box-shadow:inset 0 0 0 2px var(--accent)}
.pmenu__ic{display:inline-flex;flex:0 0 auto;color:var(--text-muted)}
.pmenu__item.is-danger{color:var(--danger)}
.pmenu__item.is-danger .pmenu__ic{color:var(--danger)}
.pmenu__item.is-danger:hover{background:var(--danger-soft)}
/* Nhãn nhóm trong menu — thay cho hai tiêu đề "Vai trò" / "Gỡ khỏi cộng đồng"
   của hộp thoại cũ (Founder chốt 24/08/2026: bỏ hết đoạn văn, giữ tiêu đề). */
.pmenu__nhan{font-size:11px;text-transform:uppercase;letter-spacing:.07em;
  color:var(--text-muted);font-weight:600;padding:8px 10px 4px}
.pmenu__nhan + .pmenu__nhan,.pmenu__item + .pmenu__nhan{
  border-top:1px solid var(--border);margin-top:4px}
/* Mục "đang là": hiện để biết mình đang ở đâu, nhưng không bấm được. */
.pmenu__item--dangla{color:var(--text-muted);cursor:default}
.pmenu__item--dangla .pmenu__ic{color:var(--accent)}

/* Nút "Phát sóng" đứng cạnh ô soạn bài.
   🔴 THEO MÀU CHỦ ĐỀ CỘNG ĐỒNG — Founder chốt 24/08/2026.
   Trước đó nút này đỏ cứng (`--danger`) với lý do "đỏ là quy ước phát trực
   tiếp, và tách hẳn khỏi màu cộng đồng". Lý do đó có thật, nhưng Founder chọn
   ưu tiên tính nhất quán thương hiệu: mở cộng đồng tím mà có một nút đỏ chen
   vào thì nó đọc như một cảnh báo, không như một tính năng.
   Vẫn KHÔNG lẫn với nút đăng bài: nút này là kiểu VIỀN (nền trắng, chữ + viền
   màu), còn các nút chính của app là kiểu ĐẶC (nền màu, chữ trắng).

   🔴 CHỮ DÙNG `--accent-hover`, VIỀN DÙNG `--accent` — đây là luật cứng, không
   phải khẩu vị. Đo cả 8 chủ đề, chữ 15px trên nền trắng:
       --accent làm màu chữ  → macdinh 3,84:1 · hong/soft 4,21 · brandVang/soft 4,19
   Ba chủ đề trượt WCAG AA (≥4,5:1), và chủ đề TRƯỢT NẶNG NHẤT lại là chủ đề
   MẶC ĐỊNH — tức là hầu hết cộng đồng sẽ dính.
       --accent-hover làm màu chữ → thấp nhất 5,07:1, cả 8 chủ đề đạt.
   Viền chỉ để nhận diện nên chuẩn là ≥3:1 (WCAG 1.4.11) — `--accent` thấp nhất
   3,84:1, đạt. Đây đúng cách repo đã xử `brandVang`: sắc gốc xuống làm viền,
   sắc đậm hơn lên làm chữ.
   `flex:0 0 auto` để ô soạn co lại chứ nút không bị bóp méo chữ. */
.btn--live{flex:0 0 auto;gap:7px;background:var(--surface);color:var(--accent-hover);
  border:1px solid var(--accent);padding:9px 14px;font-size:var(--fs-sm)}
.btn--live:hover{background:var(--accent-soft)}
@media(max-width:520px){ .btn--live span{display:none} .btn--live{padding:9px 11px} }

/* Video giới thiệu ở trang Về — khung 16:9, bo góc như ảnh bìa để hai thứ thay
   chỗ nhau mà bố cục không nhảy. `aspect-ratio` chứ không padding-hack: chiều
   cao tự đúng ở mọi bề ngang, không phải tính tay. */
.comm-about__video{position:relative;aspect-ratio:16/9;border-radius:var(--radius-lg);
  overflow:hidden;background:#000;margin-bottom:14px}
.comm-about__video iframe{position:absolute;inset:0;width:100%;height:100%;border:0;display:block}
/* Cột phải trang Về = thẻ thông tin dùng chung + một thẻ hành động ngay dưới.
   Hai thẻ rời chứ không nhồi vào một: phần "cộng đồng này là gì" và phần "tôi
   làm gì tiếp" là hai câu hỏi khác nhau, gộp lại thì nút bị chôn dưới mô tả. */
.comm-about__side{display:flex;flex-direction:column;gap:14px}
/* ═══ ĐIỆN THOẠI: BỎ THẺ TRÙNG Ở TAB GIỚI THIỆU (Founder 25/08/2026) ═══
   Trang Giới thiệu có hai cột. Cột nội dung đã in ảnh bìa (hoặc video) · tên ·
   nhãn riêng tư · phần giới thiệu. Thẻ bên phải in ĐÚNG NHỮNG THỨ ĐÓ lần nữa.
   Ở máy tính hai cột nằm cạnh nhau nên đọc ra hai vai khác nhau; ở điện thoại
   chúng XẾP CHỒNG nên thành hai thẻ giống hệt nhau nối đuôi — Founder: "trùng
   nhau nhìn rối".

   🔴 ẨN ĐÚNG MỘT THẺ, KHÔNG ẨN CẢ CỘT.
   `.comm-about__side` còn chứa nút "Tham gia" / "Xin vào nhóm" / "Rời cộng
   đồng" — những việc KHÔNG có ở cột nội dung. Ẩn cả cột là người chưa vào nhóm
   mở trang này trên điện thoại sẽ không còn đường vào (ngõ cụt — luật 2.1).

   🔴 VÀ CHỈ Ở TRANG NÀY. Selector bó trong `.comm-about__side`, nên thẻ thông
   tin ở Bảng tin không bị đụng — ở đó cột giữa là feed, không hề trùng.

   Đã thử cách khác và SAI: cắt bớt bìa/tên/mô tả ngay trong hàm dựng thẻ. Nó
   sửa được điện thoại nhưng làm cột phải trên máy tính trơ ra mấy cái nút.
   Chỗ hỏng ở khổ nào thì sửa ở khổ đó. */
@media(max-width:1023px){ .comm-about__side .cinfo{display:none} }
/* Thẻ hành động thứ hai của trang Về đã GỠ — nay chỉ còn MỘT thẻ, phần đuôi
   thay bằng `thayCuoi`. Class riêng của nó gỡ cùng lúc với markup, không để lại
   lớp CSS mồ côi cho người sau đi tìm xem nó vẽ ở đâu. */
.comm-about__side .cinfo-body .comm-about__nums{margin-top:10px}
.comm-about__side .cinfo-body .btn{margin-top:8px}

/* ---------- Khung khách vãng lai (chưa đăng nhập) ----------
   Dựng lại hình dáng của app: thanh trên cùng + thanh tab + hai cột. Người nhận
   link mời nhìn thấy ngay đây là một cộng đồng có lớp học, sự kiện, bảng xếp
   hạng — chứ không phải một trang đăng ký trơ trọi. */
.auth-topbar{display:flex;align-items:center;justify-content:space-between;gap:14px;
  height:var(--topbar-h);padding:0 22px;border-bottom:1px solid var(--border);
  background:var(--surface);position:sticky;top:0;z-index:40}
.auth-topbar__brand{display:flex;align-items:center;gap:10px;min-width:0}
.auth-topbar__brand b{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--fs-sm)}
.auth-tabs{max-width:1200px;margin:0 auto;padding:0 24px}
/* 🔴 Tab KHOÁ: nhìn thấy nhưng không bấm được. Ẩn đi thì người ta không biết
   bên trong có gì; hiện mà bấm được thì bấm vào toàn ngõ cụt "không có quyền".
   `cursor:default` + `aria-disabled` để cả chuột lẫn trình đọc màn hình đều
   hiểu — làm mờ không thôi thì người dùng bàn phím vẫn tab vào rồi Enter. */
.auth-tabs .ctabs__item{cursor:default;opacity:.55}
.auth-tabs .ctabs__item:hover{color:var(--text-muted);border-bottom-color:transparent}
.auth-tabs .ctabs__item.is-active{opacity:1}
@media(max-width:767px){ .auth-topbar{padding:0 14px} .auth-tabs{padding:0 14px} }
/* Một dòng giải thích trong chính thẻ giới thiệu. KHÔNG phải một thanh thông
   báo riêng: bản đó có nền, có viền, có nút "Đăng nhập" thứ ba — ba cửa cho
   một việc trên màn 390px, Founder gọi đúng tên là "nhiều quá" (25/08/2026). */
.auth-vi-sao{margin:10px 0 0;font-size:var(--fs-xs);color:var(--text-muted);line-height:1.6}
/* Màn "Phiên đăng nhập đã hết". Dùng lại khung `authShell` nên chỉ cần kiểu cho
   phần ruột — không dựng một khung thứ hai cho một màn hình. */
.phien-het{text-align:center;margin-bottom:18px}
.phien-het__ic{display:grid;place-items:center;width:46px;height:46px;margin:0 auto 12px;
  border-radius:50%;background:var(--accent-soft);color:var(--accent-hover)}
.phien-het h2{font-size:var(--fs-lg);font-weight:800;letter-spacing:-.02em;margin-bottom:6px}
.phien-het p{color:var(--text-secondary);font-size:var(--fs-sm);line-height:1.7}
/* Nút của màn này phải cao BẰNG nút chuẩn của app (đo được 46px ở thẻ giới
   thiệu). Để nguyên `.btn--block` trong khung auth thì nó ra 40px — dưới mốc
   44px của luật cứng về vùng chạm, và nhỏ hơn chính nút cùng vai ở màn khác. */
.phien-het + .btn--block{min-height:46px}
/* Vùng chạm ≥44px trên thiết bị cảm ứng — luật cứng, không phải tuỳ chọn. */
@media(hover:none){ .pmenu__item{padding:12px 10px} .pmenu{min-width:236px} }
.kenh-dang-xem a{flex:0 0 auto;color:var(--accent-hover);font-weight:600;text-decoration:underline}

/* Bảng quản trị chủ đề */
.ac-tbl input{width:100%;padding:6px 9px;border-radius:8px;border:1px solid var(--border);
  background:var(--surface);font:inherit;font-size:13.5px;color:var(--text-primary)}
.ac-tbl .ac-ord{white-space:nowrap;width:88px}
.ac-tbl .ac-num{text-align:right;font-variant-numeric:tabular-nums}
.ac-tbl .ac-act{white-space:nowrap;text-align:right}
.ac-tbl button[disabled]{opacity:.4;cursor:not-allowed}

/* ---------- Trình xem media (dùng chung mobile + desktop) ---------- */
.gal{position:fixed;inset:0;z-index:1200;background:rgba(0,0,0,.92);display:none;
  align-items:center;justify-content:center}
.gal.is-open{display:flex}
.gal__stage{max-width:94vw;max-height:88vh;display:flex;align-items:center;justify-content:center}
/* contain: xem trọn khung hình gốc — không cắt, không kéo giãn. */
.gal__stage img,.gal__stage video{max-width:94vw;max-height:88vh;width:auto;height:auto;
  object-fit:contain;display:block}
.gal__x{position:absolute;top:14px;right:14px;width:44px;height:44px;border-radius:50%;
  border:0;background:rgba(255,255,255,.14);color:#fff;font-size:19px;cursor:pointer}
.gal__nav{position:absolute;top:50%;transform:translateY(-50%);width:44px;height:44px;
  border-radius:50%;border:0;background:rgba(255,255,255,.14);color:#fff;font-size:26px;
  line-height:1;cursor:pointer}
.gal__nav--prev{left:10px} .gal__nav--next{right:10px}
.gal__count{position:absolute;bottom:16px;left:0;right:0;text-align:center;color:#fff;
  font-size:13px;font-weight:600;opacity:.85}

/* ---------- Cột phải: chỉ còn card Thông tin cộng đồng, dính khi cuộn ---------- */
@media(min-width:1181px){
  .community-right{position:sticky;top:calc(var(--topbar-h) + 14px)}

  /* ============================================================
     KHUNG 3 CỘT CỐ ĐỊNH (trang Bảng tin) — Founder 2026-08-21
     Trang KHÔNG cuộn. Thanh tab · ô soạn bài · hai cột bên đứng im.
     CHỈ #c-feed cuộn. Nút sang trang nằm đáy cột giữa, luôn thấy.

     Vì sao không dùng `position:sticky` như bản trước: sticky vẫn để hai cột
     TRÔI THEO TRANG một đoạn rồi mới dính lại, và thanh tab + ô soạn bài thì
     cuộn mất hẳn. Founder báo "vẫn chạy" hai lần — đúng, vì đó không phải thứ
     được yêu cầu.

     `min-height:0` xuất hiện ở mọi mắt xích flex: thiếu nó, phần tử con flex
     mặc định không co xuống dưới kích thước nội dung, nên #c-feed cứ dài ra
     theo số bài và khung cuộn không bao giờ hình thành — trang lại cuộn như cũ.
     ============================================================ */
  #os-page.is-khung{
    height:calc(100vh - var(--topbar-h));overflow:hidden;
    display:flex;flex-direction:column;
  }
  #os-page.is-khung>.content{
    flex:1;min-height:0;display:flex;flex-direction:column;padding-bottom:0;
  }
  /* 🔴 `align-items:stretch` — BẮT BUỘC, và đây là chỗ em đã vấp.
     `.dash-grid` mặc định có `align-items:start` (để cột phải ngắn không bị kéo
     dài ra). Nhưng `start` nghĩa là mỗi cột lấy chiều cao THEO NỘI DUNG — cột
     giữa cao 7200px theo số bài, không bị bó về chiều cao khung, nên `flex:1`
     bên trong nó không có gì để chia và VÙNG CUỘN KHÔNG BAO GIỜ HÌNH THÀNH.
     Khung vẫn `overflow:hidden` nên nhìn thì như đúng, chỉ là bài viết bị cắt
     mất và không cuộn tới được. Đo bằng `scrollHeight > clientHeight` mới thấy;
     nhìn ảnh chụp màn hình thì không. */
  /* 🔴 `grid-template-rows:minmax(0,1fr)` — mắt xích cuối, và là chỗ dễ sót nhất.
     `.dash-grid` đã bị bó đúng chiều cao khung (826px) nhờ flex, NHƯNG hàng của
     nó mặc định là `auto`: hàng vẫn nở theo cột cao nhất (2400px) rồi tràn ra
     ngoài container. `align-items:stretch` không cứu được — nó kéo cột cho bằng
     HÀNG, mà hàng thì đã sai.
     `minmax(0,1fr)` buộc hàng đúng bằng chiều cao container, `min-height:0` trên
     từng cột cho phép chúng co nhỏ hơn nội dung — có cả hai thì vùng cuộn mới
     hình thành. Đo bằng clientHeight của từng mắt xích mới tìm ra; nhìn màn hình
     thì cả ba trạng thái sai đều trông giống nhau. */
  #os-page.is-khung .dash-grid{
    flex:1;min-height:0;align-items:stretch;grid-template-rows:minmax(0,1fr);
  }
  #os-page.is-khung .dash-grid>*{min-height:0}
  /* Cột giữa: ô soạn bài đứng yên ở trên, dòng bài cuộn, nút sang trang ở đáy */
  #os-page.is-khung .dash-grid>*:nth-child(1){
    display:flex;flex-direction:column;min-height:0;
  }
  /* Vùng cuộn bọc CẢ ô soạn bài lẫn dòng bài — xem chú thích trong os-app.js.
     `scrollbar-gutter:stable` thay cho `padding-right` thủ công: nó chừa chỗ
     thanh cuộn ở mức trình duyệt, nên mọi thứ BÊN TRONG khung (ô soạn bài, card
     bài viết) rộng bằng nhau tuyệt đối. Chừa bằng padding thì chỉ những phần tử
     mình nhớ chừa mới đúng, phần tử quên thì lệch — và đó chính là lỗi vừa rồi. */
  /* 🔴 MÉP CẮT PHẢI TRÙNG CHÂN THANH MENU.
     Founder 2026-08-21 vẽ hai vạch: xanh ở chân thanh tab, đỏ ở chỗ nội dung
     đang bị cắt — lệch nhau đúng 18px, chính là `margin-bottom` của `.ctabs`.
     Khoảng đó nằm NGOÀI khung cuộn, nên bài viết trôi qua nó rồi mới bị cắt —
     mắt thấy một mẩu card lơ lửng phía trên, không dính vào đâu.
     Cách sửa: bỏ margin (mép cắt lên đúng chân menu) và trả khoảng thở đó vào
     BÊN TRONG khung bằng `padding-top`. Padding của khung cuộn không cắt nội
     dung — lúc đứng yên vẫn thoáng đúng 18px như cũ, nhưng khi cuộn thì bài
     viết biến mất đúng tại đường kẻ của thanh menu.
     Áp cho CẢ hai cột để chúng không lệch nhau một khoảng 18px. */
  #os-page.is-khung .ctabs{margin-bottom:0}
  #os-page.is-khung #c-scroll{
    flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;
    scrollbar-width:thin;scrollbar-gutter:stable;padding-top:18px;
  }
  /* Khe giữa các card hẹp lại 8px trong khung cố định.
     🔴 VÀ TRIỆT LỀ DỌC CỦA CARD. Đo được: `gap` computed đúng 8px nhưng khoảng
     cách THẬT giữa hai card là 20px — thừa 12px từ một lề dọc thừa hưởng ở chỗ
     khác. Ba khe × 12px = 36px, đúng bằng phần làm card thứ ba rớt ra khỏi khung.
     Bài học: `gap` đúng KHÔNG có nghĩa khoảng cách đúng — phải đo khoảng cách
     giữa hai mép thật (`b2.top − b1.bottom`), không đọc computed style của gap. */
  #os-page.is-khung #c-feed{min-height:0;gap:8px}
  #os-page.is-khung .post--m{margin-top:0;margin-bottom:0}
  #os-page.is-khung #c-pager{flex:0 0 auto;padding:10px 0 14px}
  /* Cột phải: cao trọn khung, tự cuộn nếu nội dung dài hơn */
  #os-page.is-khung .dash-grid>*:nth-child(2){
    position:static;top:auto;height:100%;max-height:none;
    overflow-y:auto;overscroll-behavior:contain;scrollbar-width:thin;padding-top:18px;
  }
}

/* ---------- Phân trang feed ---------- */
.pager{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap;
  margin-top:12px;padding-top:12px;border-top:1px solid var(--border)}
.pager__range{color:var(--text-muted);font-size:13px}
.pager__ctrl{display:flex;align-items:center;gap:4px;margin-left:auto}
.pager__btn{display:inline-flex;align-items:center;justify-content:center;min-width:34px;min-height:34px;
  padding:0 10px;border-radius:8px;border:1px solid var(--border);background:var(--surface);
  color:var(--text-secondary);font:inherit;font-size:13px;font-weight:600;text-decoration:none;cursor:pointer;
  transition:background .14s,color .14s,border-color .14s}
.pager__btn:hover{background:var(--surface-muted);color:var(--text-primary)}
.pager__btn.is-active{background:var(--accent-hover);border-color:var(--accent);color:#fff}
.pager__btn.is-active:hover{background:var(--accent-hover);color:#fff}
/* Vô hiệu hoá thật: chặn cả chuột lẫn bàn phím, không chỉ làm mờ cho có. */
.pager__btn.is-disabled{opacity:.45;pointer-events:none}
.pager__gap{padding:0 4px;color:var(--text-muted);font-size:13px;user-select:none}
.pager__cur{display:none;padding:0 8px;font-size:13px;font-weight:600;color:var(--text-primary)}
@media(max-width:767px){
  /* Mobile gọn: Previous · trang hiện tại · Next. */
  .pager__num,.pager__gap{display:none}
  .pager__cur{display:inline-flex;align-items:center}
  .pager{justify-content:center}
  .pager__ctrl{margin-left:0;width:100%;justify-content:space-between}
  .pager__range{width:100%;text-align:center}
}

/* ---------- Mobile ---------- */
@media(max-width:767px){
  .post-action span{font-size:13px}
  .post__stats{gap:12px}
}
@media(max-width:440px){
  /* Bốn nút trên một hàng hẹp: cấm xuống dòng, nếu không "Bình luận" tách đôi
     và hàng tương tác cao gấp rưỡi các bài khác.
     (Selector này từng bị một biểu thức dọn CSS của em cắt hỏng — dọn class mồ
      côi bằng regex thì phải đọc lại kết quả, đừng tin nó cắt đúng chỗ.) */
  .post-action{gap:4px;padding:6px 2px}
  .post-action span{font-size:11.5px;white-space:nowrap}
  .post-action svg{flex:0 0 auto}
}

/* ---------- Card bài đăng: DESKTOP dùng CHUNG cấu trúc với mobile ----------
   .post--m là cấu trúc DUY NHẤT ở mọi bề rộng (xem feedCardMode trong os-app.js).
   Ở ≥768px chỉ nới kích thước, không đổi thứ tự phần tử: card có viền/bo góc,
   thumbnail to hơn, chữ lớn hơn một nhịp, clamp 4 dòng thay vì 3.

   ⚠️ Khối này phải nằm CUỐI FILE. `.post--m` ở phần Mobile khai báo
   border:0;border-radius:0;padding:12px 16px với cùng độ đặc hiệu — CSS lấy rule
   đứng SAU, nên đặt khối này lên trước sẽ bị ghi đè im lặng (đã gặp thật). */
/* 🔴 KHỐI @media(min-width:768px) THỨ HAI CHO `.post--m` ĐÃ GỠ (2026-08-21).
   Nó đứng SAU khối chính (~dòng 1142) nên nó mới là khối có hiệu lực — và nó
   ghi đè im lặng ba thứ, gây ra ba lỗi Founder báo ở ba lượt khác nhau:
     · `border:1px solid var(--border)`  ⇒ viền đọc `--border` (#E5E2DC), KHÔNG
       đọc `--border-card`. Em hạ `--border-card` BA lần mà card không đổi màu —
       Founder phải nhắc ba lần.
     · `margin-bottom:12px`              ⇒ khe giữa card thành 20px thay vì 8px.
       Em đuổi theo cái 12px này ba lượt, cứ thu nhỏ card mà không tìm ra nguồn.
     · `padding:16px 18px`               ⇒ đệm đo ra 32px trong khi em đặt 16px.
   Các dòng CÒN LẠI của khối (`.pm-title`, `.pm-excerpt`, `.pm-thumb`, `.pm-body`,
   `.pm-acts`) đã chuyển vào khối chính với giá trị đã tính lại cho khung 3 card.

   BÀI HỌC (bẫy B5, tái phát lần thứ hai trong một phiên): trước khi sửa CSS,
   `grep -c` xem selector đó xuất hiện mấy lần. Sửa khối trước trong khi khối sau
   mới có hiệu lực là cách chắc chắn nhất để "sửa rồi mà không đổi gì". */

/* ---------- Admin: hàng chỉnh Liên kết Social / Website ---------- */
.cs-link{display:grid;grid-template-columns:auto 150px 1fr 1.4fr auto;gap:8px;align-items:center}
.cs-link>select,.cs-link>input[type=text],.cs-link>input:not([type]){min-width:0;height:38px;
  border:1px solid var(--border);border-radius:10px;padding:0 10px;background:var(--surface);
  color:var(--text-primary);font-size:13.5px;font-family:inherit}
.cs-link>select:focus,.cs-link>input:focus{outline:2px solid var(--accent-soft);border-color:var(--accent)}
.cs-link .cl-del{flex:0 0 auto;color:var(--danger)}
@media(max-width:1180px){
  .cs-link{grid-template-columns:auto 1fr auto;grid-auto-rows:auto}
  .cs-link>.cl-label{grid-column:2/4}
  .cs-link>.cl-href{grid-column:1/-1}
}
/* Luật chung "mọi control >=16px trên mobile" (dòng 664) THUA ở đây: `input`
   nặng 0,0,1 còn `.cs-link>input:not([type])` nặng 0,2,1. Nên hàng Liên kết vẫn
   13.5px và iOS phóng to trang mỗi lần chạm vào ô — đúng cái luật kia sinh ra để
   chặn. Lặp lại luật ở đúng độ đặc hiệu của nó. */
@media(max-width:767px){
  .cs-link>input,.cs-link>select{font-size:16px}
}

/* ---------- Card bài viết KHÔNG CÓ CHỮ (.post--notext) ----------
   Chỉ MỘT bố cục cho mọi bài: chữ bên trái · ô media vuông nhỏ ở góc phải. Ảnh
   hay video, có chữ hay không, đều nằm trong đúng một khuôn — nhìn xuống feed
   thấy các bài đều nhau và lướt được.

   Bản trước cho bài chỉ-có-media chạy tràn ngang theo tỷ lệ thật. Đúng ở chỗ
   không cắt ảnh, nhưng một video dọc thành khối cao 650px trên desktop: một bài
   chiếm trọn màn hình, các bài sau bị đẩy khuất. Feed không phải chỗ xem media
   cỡ lớn — bấm vào ô là mở trình xem toàn màn hình.

   Còn lại chỉ là dọn khoảng trắng: bài không chữ thì cột chữ rỗng và ô media bị
   kéo tụt xuống giữa card; cho nó bám mép trên để ngang hàng với bài có chữ. */
.post--notext .pm-body{align-items:flex-start}


/* ---------- Trang bài học ---------- */
/* Khung video giữ tỷ lệ 16:9 và co theo bề ngang — iframe của YouTube không tự
   co, để mặc định là nó tràn ra khỏi card trên điện thoại. */
.lesson-video{position:relative;aspect-ratio:16/9;width:100%;margin-bottom:18px;
  border-radius:14px;overflow:hidden;background:#000;border:1px solid var(--border)}
.lesson-video iframe,.lesson-video video{position:absolute;inset:0;width:100%;height:100%;border:0;display:block}
/* Nội dung bài do người soạn gõ tay: giữ khoảng trắng và xuống dòng như họ viết. */
.lesson-body{line-height:1.8;color:var(--text-secondary);font-size:15px;overflow-wrap:anywhere}

/* ---------- Điều hướng bài học + cảm nhận học viên ---------- */
/* Ba nút (Bài trước · Đánh dấu hoàn thành · Bài tiếp) không vừa một hàng ở
   375px — nút thứ ba bị đẩy tràn ra ngoài mép phải và cắt cụt. Cho xuống hàng
   thay vì bắt màn hình rộng ra. */
.lesson-nav{display:flex;justify-content:space-between;align-items:center;gap:10px;flex-wrap:wrap}
.lesson-nav>*{flex:0 1 auto}
@media(max-width:520px){
  .lesson-nav{justify-content:center}
  .lesson-nav>.btn{flex:1 1 auto;min-width:0}
}
/* textarea KHÔNG thừa hưởng font của trang — mặc định của trình duyệt là
   monospace, nên ô cảm nhận hiện ra như một khung gõ mã. */
#cn-input{font-family:inherit;font-size:15px;line-height:1.6;background:var(--surface-muted);
  border:1px solid var(--border);border-radius:12px;padding:10px 12px;color:var(--text-primary);
  resize:vertical}
#cn-input:focus{outline:2px solid var(--accent-soft);border-color:var(--accent)}
/* ≥16px trên mobile, nếu không iOS tự phóng to trang khi chạm vào ô. */
@media(max-width:767px){ #cn-input{font-size:16px} }

/* ---------- Banner khoá học (thay cho icon emoji) ---------- */
/* Khung giữ 16:9 và ảnh phủ kín. Khoá chưa có ảnh thì để dải màu thương hiệu —
   trống trơn nhìn như lỗi tải, còn emoji thì không phải thứ bán được khoá học. */
.tile__cover--course{position:relative;aspect-ratio:16/9;height:auto;padding:0;overflow:hidden}
/* Nền lúc ảnh chưa tải xong. Dùng token, KHÔNG gõ mã màu tối vào đây: test brand
   chặn đúng những mã đó để không ai lén kéo bảng màu tối vào app sáng. Ảnh dùng
   object-fit:cover nên nền chỉ hiện thoáng qua, một tông trung tính là đủ. */
.tile__cover--course.has-img{background:var(--surface-muted)}
.tile__cover--course>img{width:100%;height:100%;object-fit:cover;display:block}
.tile__cover--course:not(.has-img){background:linear-gradient(120deg,var(--accent-soft),#F1E7DC)}
.tile__cover--course .tile__lock{position:absolute;top:10px;right:10px}
/* Ảnh xem trước trong form quản trị */
.cf-cover{aspect-ratio:16/9;width:100%;border-radius:12px;overflow:hidden;border:1px dashed var(--border);
  background:var(--surface-muted);display:grid;place-items:center}
.cf-cover>img{width:100%;height:100%;object-fit:cover;display:block}
/* Ô ảnh nhỏ trong bảng QL Lớp học */
.cf-thumb{flex:0 0 auto;width:52px;aspect-ratio:16/9;border-radius:7px;overflow:hidden;display:block;
  background:linear-gradient(120deg,var(--accent-soft),#F1E7DC)}
.cf-thumb>img{width:100%;height:100%;object-fit:cover;display:block}

/* ---- Phòng xem hội thảo trực tuyến (StreamYard On-Air) ---- */
/* StreamYard xếp khung phát sóng và khung chat CẠNH NHAU, nên tỷ lệ 16/9 quen
   thuộc sẽ bóp video lại còn một dải hẹp. Tài liệu của họ nói chat tự thu lại
   trên màn hình nhỏ — nên khung phải cao hơn trên điện thoại, không thấp hơn.
   Dùng chiều cao theo viewport (có kẹp trên/dưới) thay vì aspect-ratio: người ta
   ngồi xem hết buổi, khung nên lấp đầy màn hình chứ đừng để trống nửa dưới. */
/* Nền dùng token sáng của app, KHÔNG dùng màu đen quen thuộc của trình phát:
   os.css là bảng màu sáng và có test canh điều đó. Nền này chỉ hiện trong lúc
   khung StreamYard đang tải, rồi bị che hoàn toàn. */
.wt-frame{position:relative;width:100%;height:clamp(420px,72vh,760px);background:var(--surface-muted)}
.wt-frame iframe{position:absolute;inset:0;width:100%;height:100%;border:0;display:block}
@media(max-width:768px){.wt-frame{height:clamp(480px,78vh,700px)}}

/* ---- Dải "Buổi trực tuyến" trên thẻ bài viết ----
   Bài của một buổi live phải nhìn ra được NGAY TRÊN FEED. Trước đây khung xem
   chỉ hiện khi bấm vào trong, nên ngoài feed nó trông y hệt một bài trống. */
.post-event{display:flex;align-items:center;gap:12px;margin-top:12px;padding:12px 14px;
  border:1px solid var(--accent-soft);border-radius:12px;background:var(--accent-soft);
  text-decoration:none;color:inherit;transition:filter .15s}
.post-event:hover{filter:brightness(.97)}
.post-event__ic{flex:0 0 auto;width:36px;height:36px;border-radius:50%;display:grid;place-items:center;
  background:var(--accent-hover);color:#fff}
.post-event__main{display:flex;flex-direction:column;gap:2px;min-width:0}
.post-event__main b{font-size:14px;letter-spacing:-.01em}

/* =====================================================================
   Bảng thanh toán khoá học — TÔNG TỐI (2026-08-16)
   Dựng theo đúng khối QR của trang bán hocaionline.com, để người đã thấy
   màn thanh toán ở trang bán nhận ra ngay khi mua khoá lẻ trong app.
   Biến màu KHAI BÁO NGAY TRONG .ck — app là giao diện sáng, đổ token tối ra
   ngoài phạm vi này là làm hỏng mọi thứ còn lại.
   ===================================================================== */
.modal--ck{max-width:620px;background:var(--ck-surface);border-color:var(--ck-border)}
.ck{
  --ck-surface:#161618; --ck-surface-2:#101012;
  --ck-border:#242427; --ck-border-soft:#1c1c1f;
  --ck-text:#EDEDED; --ck-muted:#8A8A8A; --ck-muted-2:#6a6a6d;
  --ck-accent:#CC6600; --ck-accent-dim:rgba(204,102,0,.10); --ck-accent-line:rgba(204,102,0,.32);
  background:var(--ck-surface); color:var(--ck-text);
  padding:clamp(20px,2.8vw,30px); border-radius:var(--radius-xl); text-align:left;
}
.ck__head{display:flex;justify-content:space-between;align-items:flex-start;gap:16px;flex-wrap:wrap;
  padding-bottom:18px;margin-bottom:18px;border-bottom:1px solid var(--ck-border-soft)}
.ck__eyebrow{font-size:11.5px;letter-spacing:.14em;text-transform:uppercase;color:var(--ck-muted-2)}
.ck__title{font-size:19px;font-weight:640;margin-top:6px;letter-spacing:-.01em;color:var(--ck-text)}
.ck__amount{font-size:24px;font-weight:700;color:var(--ck-accent);letter-spacing:-.02em;white-space:nowrap}
.ck__grid{display:grid;grid-template-columns:auto 1fr;gap:clamp(16px,2.4vw,26px);align-items:start}
.ck__qr{border:1px solid var(--ck-border-soft);border-radius:12px;padding:10px;background:#fff;width:max-content}
.ck__qr img{width:190px;height:190px;display:block}
.ck__qr figcaption{font-size:11px;color:#555;text-align:center;margin-top:6px}
.ck__fields{display:grid;gap:12px;min-width:0}
.ck__fields > div{display:grid;gap:3px}
.ck__fields dt{font-size:11.5px;letter-spacing:.08em;text-transform:uppercase;color:var(--ck-muted-2)}
.ck__fields dd{font-size:14px;color:var(--ck-text);display:flex;align-items:center;gap:10px;flex-wrap:wrap;word-break:break-word}
.ck__memo{font-weight:700;color:var(--ck-accent);letter-spacing:.02em}
.ck__copy{font-family:inherit;font-size:11.5px;font-weight:600;color:var(--ck-accent);background:var(--ck-accent-dim);
  border:1px solid var(--ck-accent-line);border-radius:8px;padding:5px 10px;cursor:pointer;transition:background .2s}
.ck__copy:hover{background:rgba(204,102,0,.18)}
.ck__copy.is-copied{color:#a7e5bd;border-color:rgba(34,197,94,.4);background:rgba(34,197,94,.1)}
.ck__hint{font-size:12.5px;color:var(--ck-muted-2);margin-top:18px;line-height:1.55}
.ck__state{display:flex;align-items:center;gap:10px;margin-top:16px;padding:13px 16px;border-radius:11px;
  font-size:14px;border:1px solid var(--ck-border-soft);background:var(--ck-surface-2);color:var(--ck-muted)}
.ck__dot{width:9px;height:9px;border-radius:50%;background:var(--ck-accent);flex-shrink:0;animation:ckpulse 1.4s ease-in-out infinite}
@keyframes ckpulse{0%,100%{opacity:.35}50%{opacity:1}}
.ck__state[data-state="paid"]{border-color:rgba(34,197,94,.35);background:rgba(34,197,94,.08);color:#a7e5bd}
.ck__state[data-state="paid"] .ck__dot{background:#22c55e;animation:none}
.ck__state[data-state="stop"]{border-color:var(--ck-accent-line);background:var(--ck-accent-dim);color:var(--ck-text)}
.ck__state[data-state="stop"] .ck__dot{animation:none}
.ck__warn{margin-top:12px;padding:11px 14px;border-radius:10px;font-size:12.5px;line-height:1.55;
  border:1px solid var(--ck-accent-line);background:var(--ck-accent-dim);color:var(--ck-text)}
.ck__actions{display:flex;flex-wrap:wrap;gap:10px;align-items:center;margin-top:14px}
.ck__btn{font-family:inherit;font-size:13.5px;font-weight:600;color:var(--ck-text);background:var(--ck-surface-2);
  border:1px solid var(--ck-border);border-radius:10px;padding:11px 16px;min-height:44px;cursor:pointer;
  transition:border-color .2s,background .2s}
.ck__btn:hover:not(:disabled){border-color:var(--ck-accent-line);background:var(--ck-accent-dim)}
.ck__btn:disabled{opacity:.55;cursor:default}
.ck__msg{flex:1 1 100%;font-size:12.5px;color:var(--ck-muted-2);line-height:1.55}
/* Điện thoại: QR xuống hàng riêng, căn giữa. Giữ hai cột ở 360px thì QR co lại
   còn ~120px — quét bằng app ngân hàng bắt đầu trượt. */
@media (max-width:560px){
  .ck__grid{grid-template-columns:1fr}
  .ck__qr{margin:0 auto}
  .ck__amount{font-size:21px}
}
@media (prefers-reduced-motion:reduce){.ck__dot{animation:none}}

/* Ô mật khẩu có nút con mắt (2026-08-17).
   Nút nằm ĐÈ trong ô, không đứng cạnh: đặt cạnh thì ở 375px ô nhập bị co lại
   còn một nửa và mật khẩu dài không đọc hết được. padding-right chừa đúng chỗ
   cho nút để chữ không chui xuống dưới nó. */
.pw-wrap{position:relative;display:block}
.pw-wrap input{width:100%;padding-right:46px}
.pw-eye{position:absolute;top:50%;right:6px;transform:translateY(-50%);
  display:inline-flex;align-items:center;justify-content:center;
  width:34px;height:34px;border:0;border-radius:8px;background:transparent;
  color:var(--muted);cursor:pointer;transition:color .15s,background .15s}
.pw-eye:hover{color:var(--text);background:var(--surface-muted)}
.pw-eye.is-on{color:var(--accent-hover)}
.pw-eye:focus-visible{outline:2px solid var(--accent);outline-offset:1px}

/* Thu hồi tin nhắn (045).
   Nút nằm ĐÈ ở mép ngoài bong bóng và chỉ hiện khi rê chuột / chạm vào bong
   bóng — để nguyên thì mỗi tin của mình mang một dấu ✕ lơ lửng, nhìn như tin
   nào cũng đang lỗi. Trên cảm ứng không có hover nên luôn hiện mờ. */
.bubble{position:relative}
/* 🔴 LUÔN HIỆN, chỉ mờ đi. Bản đầu để opacity:0 và chỉ hiện khi rê chuột —
   chủ sở hữu mở app lên không tìm thấy tính năng, tưởng chưa làm. Một nút vô
   hình thì coi như không tồn tại; và trên điện thoại thì không có "rê chuột". */
.bubble__xoa{position:absolute;top:50%;left:-30px;transform:translateY(-50%);
  display:inline-flex;align-items:center;justify-content:center;
  width:24px;height:24px;border:0;border-radius:50%;background:var(--surface-muted);
  color:var(--muted);cursor:pointer;opacity:.42;transition:opacity .15s,color .15s}
.bubble:hover .bubble__xoa,.bubble__xoa:focus-visible{opacity:1}
.bubble__xoa:hover{color:var(--danger)}
.bubble__xoa:disabled{opacity:.4;cursor:default}
.bubble--thu-hoi{background:var(--surface-muted);color:var(--muted);font-style:italic}
.bubble--thu-hoi.me{background:var(--surface-muted);color:var(--muted)}

/* Xoá cuộc trò chuyện (046). Nút nằm trong thẻ <a> của dòng hội thoại nên phải
   nổi lên trên và chỉ hiện khi rê chuột — để nguyên thì mỗi dòng mang một dấu ✕
   cạnh huy hiệu chưa đọc, nhìn rối và dễ bấm nhầm. Cảm ứng: luôn hiện mờ. */
/* 🔴 CHỪA HẲN MỘT LỀ PHẢI cho hai nút (sửa 2026-08-18).
   Trước đây hai nút đặt ở `top:8px` — đúng góc trên bên phải, nơi đã có ĐỒNG HỒ
   và HUY HIỆU CHƯA ĐỌC. Đo trên màn 375px: nút xoá phủ lên huy hiệu, nút
   đọc/chưa đọc phủ lên giờ. Trên máy tính lỗi này bị che vì nút chỉ rõ khi rê
   chuột; trên điện thoại không có "rê chuột" — nút luôn hiện mờ, và chạm vào
   con số chưa đọc là mở hộp thoại XOÁ cuộc trò chuyện.
   Chèn nội dung tránh nút bằng padding, không kéo nút ra chỗ khác: chỉ có
   padding mới bảo đảm chữ dài không bao giờ chui xuống dưới nút. */
.chat__conv{position:relative;padding-right:62px}
/* Hai nút hành động trên dòng hội thoại: đọc/chưa đọc rồi mới đến xoá.
   Xếp nút xoá ra NGOÀI CÙNG bên phải, nút ít nguy hiểm hơn đứng trong — bấm
   trượt một chút thì trúng cái vô hại, không trúng cái xoá. */
.chat__conv-doc,.chat__conv-xoa{position:absolute;top:50%;transform:translateY(-50%);z-index:1;
  display:inline-flex;align-items:center;justify-content:center;
  width:24px;height:24px;border:0;border-radius:50%;background:var(--surface);
  color:var(--muted);cursor:pointer;opacity:.42;transition:opacity .15s,color .15s}
.chat__conv-doc{right:34px}
.chat__conv-xoa{right:6px}
.chat__conv:hover .chat__conv-doc,.chat__conv-doc:focus-visible{opacity:1}
.chat__conv-doc:hover{color:var(--accent-hover);background:var(--surface-muted)}
.chat__conv-doc:disabled{opacity:.4;cursor:default}
.chat__conv:hover .chat__conv-xoa,.chat__conv-xoa:focus-visible{opacity:1}
.chat__conv-xoa:hover{color:var(--danger);background:var(--surface-muted)}
.chat__conv-xoa:disabled{opacity:.4;cursor:default}
/* Cảm ứng: 24px là quá nhỏ để ngón tay bấm trúng, mà bấm trượt ở đây thì trúng
   nút XOÁ. Nới vùng chạm bằng ::after trong suốt — nới chính nút thì hai nút
   dính vào nhau và lề phải phải rộng thêm nữa. */
@media(hover:none){
  .chat__conv-doc,.chat__conv-xoa{opacity:.55}
  .chat__conv-doc::after,.chat__conv-xoa::after{content:'';position:absolute;inset:-7px}
}

/* Nút thu hồi thông báo (049). Cùng lối với nút xoá tin nhắn: LUÔN hiện, chỉ mờ
   đi — một nút chỉ hiện khi rê chuột thì trên điện thoại là không có. */
.lrow--co-nut{position:relative;padding-right:44px}
.noti-thu{position:absolute;top:50%;right:12px;transform:translateY(-50%);
  display:inline-flex;align-items:center;justify-content:center;
  width:24px;height:24px;border:0;border-radius:50%;background:var(--surface-muted);
  color:var(--muted);cursor:pointer;opacity:.42;transition:opacity .15s,color .15s}
.lrow--co-nut:hover .noti-thu,.noti-thu:focus-visible{opacity:1}
.noti-thu:hover{color:var(--danger)}
.noti-thu:disabled{opacity:.4;cursor:default}

/* Link PHỦ cho dòng vừa có nội dung bấm được vừa có nút hành động (050).
   Không bọc cả dòng trong <a> vì nút nằm bên trong link thì mọi cú bấm trượt
   đều thành điều hướng; cũng không bỏ link vì người quản trị sẽ là người duy
   nhất không mở được thứ mình vừa gửi. */
.lrow__phu{position:absolute;inset:0;z-index:0}
.lrow--co-nut > *:not(.lrow__phu){position:relative;z-index:1}
.noti-thu{z-index:2}

/* Nút link đính kèm bài đăng (051). Một nút rõ ràng, không phải chuỗi URL trần
   giữa nội dung — URL dài sẽ tràn thẻ bài trên điện thoại. */
.post-link{display:inline-flex;align-items:center;gap:8px;margin-top:10px;
  padding:9px 14px;border:1px solid var(--border);border-radius:10px;
  background:var(--surface-muted);color:var(--text);font-size:13.5px;font-weight:600;
  max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  transition:border-color .2s,background .2s}
.post-link:hover{border-color:var(--accent-line);background:var(--accent-soft)}

/* Khung mời mua (2026-08-17). Viền cam + nền xám đã GỠ theo yêu cầu: chúng
   đóng khung cả khối, mà thứ cần nổi lên là hai cái NÚT, không phải cái hộp
   chứa chúng. Khung giờ chỉ còn nhiệm vụ gom giá và nút lại gần nhau. */
.pw-box{margin-bottom:14px}
.pw-box__gia{padding-bottom:14px;margin-bottom:14px;border-bottom:1px solid var(--border)}

/* Hai nút ngang hàng: Xem trái · Đăng ký phải.
   Chia đôi bằng nhau — một nút to gấp đôi nút kia là đã trả lời hộ người ta.
   Dưới 420px xếp dọc: hai nút chữ dài nhét vào một hàng hẹp thì chữ bị cắt. */
.pw-2nut{display:grid;grid-template-columns:1fr 1fr;gap:10px}
/* Viền CAM cho nút "Xem khoá học". Nút phụ mặc định viền xám nhạt, đứng cạnh
   nút cam đặc thì nhìn như bị vô hiệu hoá. Viền cam + chữ cam giữ nó ngang hàng
   về mặt thị giác, mà vẫn rõ đâu là hành động chính (nút kia tô đặc). */
.pw-box .btn--soft{background:var(--surface);border:1.5px solid var(--accent);color:var(--accent-hover)}
.pw-box .btn--soft:hover{background:var(--accent-soft)}
.pw-2nut > *{width:100%;justify-content:center}
@media (max-width:420px){.pw-2nut{grid-template-columns:1fr}}

/* =====================================================================
   NHIỀU CỘNG ĐỒNG (migration 057/058)
   Rail đổi cộng đồng · lưới thẻ · trang Về · cài đặt · bảng chọn mobile
   ===================================================================== */

/* --- Shell có thêm một cột ngoài cùng bên trái --------------------------
   Cột này CHỈ xuất hiện khi người dùng thuộc từ hai cộng đồng trở lên
   (os-app.js quyết định), nên bố cục mặc định không đổi với người chỉ ở
   một cộng đồng — tức là gần như tất cả mọi người ở thời điểm ra mắt. */
.shell--rail{grid-template-columns:var(--comm-rail-w) var(--sidebar-w) 1fr}
:root{--comm-rail-w:62px}

.comm-rail{
  background:var(--sidebar-bg);border-right:1px solid var(--border);
  position:sticky;top:0;height:100vh;overflow-y:auto;overflow-x:hidden;
  display:flex;flex-direction:column;align-items:center;gap:9px;padding:11px 0;
}
@supports(height:100dvh){.comm-rail{height:100dvh}}
.comm-rail::-webkit-scrollbar{width:0}
.comm-rail__item,.comm-rail__all{
  position:relative;display:grid;place-items:center;flex:0 0 auto;
  width:40px;height:40px;border-radius:12px;text-decoration:none;color:var(--text-muted);
  transition:border-radius .16s ease,background .16s ease;
}
.comm-rail__item:hover,.comm-rail__all:hover{border-radius:14px;background:var(--surface-muted)}
/* Vạch sáng bên trái báo cộng đồng đang mở. Dùng ::before thay vì đổi màu nền:
   avatar đã chiếm hết ô, đổi nền thì không nhìn thấy gì. */
.comm-rail__item.is-active::before{
  content:'';position:absolute;left:-11px;top:50%;transform:translateY(-50%);
  width:3px;height:24px;border-radius:0 3px 3px 0;background:var(--accent);
}
.comm-rail__item.is-active .comm-ava{box-shadow:0 0 0 2px var(--accent)}
.comm-rail__all{border:1px dashed var(--border);color:var(--text-muted)}
.comm-rail__all:hover{color:var(--accent-hover);border-color:var(--accent-border)}

/* 🔴 DANH SÁCH CUỘN RIÊNG, NÚT "TẤT CẢ" ĐỨNG YÊN.
   Chủ nền tảng có thể có 10, 50 hay 100+ cộng đồng. Nếu cả thanh cùng cuộn
   thì nút "Tất cả cộng đồng" trôi khỏi màn hình đúng lúc người ta cần nó nhất
   — họ cuộn tìm mãi không thấy thì mới bấm vào đó. Nên phần DANH SÁCH cuộn,
   phần cuối neo lại. */
.comm-rail__ds{
  display:flex;flex-direction:column;align-items:center;gap:9px;
  flex:1 1 auto;min-height:0;overflow-y:auto;overflow-x:hidden;width:100%;
  /* Chừa chỗ cho vạch `is-active` ở lề trái, nếu không nó bị cắt khi cuộn. */
  padding-left:11px;margin-left:-11px;
}
.comm-rail__ds::-webkit-scrollbar{width:0}
/* Cộng đồng đã tạm dừng/lưu trữ vẫn HIỆN cho người quản — họ cần vào để xử lý
   — nhưng phải nhìn ra ngay là nó không đang phục vụ. */
.comm-rail__item.is-tam-dung .comm-ava{opacity:.45;filter:grayscale(1)}
.comm-rail__item.is-tam-dung:hover .comm-ava{opacity:.8;filter:grayscale(.3)}

/* --- Ảnh đại diện cộng đồng ------------------------------------------- */
.comm-ava{
  width:36px;height:36px;border-radius:11px;flex:0 0 auto;overflow:hidden;
  background:var(--accent-soft);color:var(--accent-hover);
  display:grid;place-items:center;font-weight:800;font-size:13px;letter-spacing:-.02em;
}
.comm-ava--lg{width:56px;height:56px;border-radius:16px;font-size:19px}
.comm-ava--ghost{background:var(--surface-muted);color:var(--text-muted)}

/* --- Nút đổi cộng đồng trên điện thoại ---------------------------------
   38px là vùng chạm tối thiểu. Nút này KHÔNG ẩn sau hover — trên điện thoại
   không có hover, và một nút chỉ hiện khi rê chuột là một nút không tồn tại. */
.comm-switch{
  display:none;align-items:center;justify-content:center;flex:0 0 auto;
  width:26px;height:26px;margin-left:-2px;padding:0;
  background:none;border:none;color:var(--text-muted);cursor:pointer;border-radius:8px;
}
.comm-switch:hover{background:var(--surface-muted);color:var(--text)}
@media(hover:none){.comm-switch::after{content:'';position:absolute;inset:-7px}}
.comm-switch{position:relative}

/* --- Huy hiệu riêng tư ------------------------------------------------- */
/* 🔴 CHỈ BIỂU TƯỢNG VÀ CHỮ — bỏ nền, bỏ viền (Founder 2026-08-21).
   Trên thẻ cộng đồng, nhãn này nằm giữa TÊN nhóm và MÔ TẢ. Bọc nó trong một
   viên nền màu là dựng thêm một "khối" nữa ở đúng chỗ mắt đang đi từ tên xuống
   mô tả — mắt phải dừng lại đọc một thứ chỉ là chú thích. Nó là SỰ THẬT phụ,
   không phải nhãn cần nổi.
   Màu chữ vẫn phân biệt ba mức, nên vẫn liếc là biết. */
.comm-badge{
  display:inline-flex;align-items:center;gap:6px;font-size:12.5px;font-weight:600;
  padding:0;border:0;background:none;white-space:nowrap;
}
.comm-badge svg{flex:0 0 auto;opacity:.8}
.comm-badge--open{color:var(--success-strong)}
.comm-badge--closed{color:var(--text-secondary)}
.comm-badge--hidden{color:var(--text-muted)}

/* --- Lưới thẻ cộng đồng ------------------------------------------------ */
.comm-sec{margin-top:22px}
.comm-sec__title{font-size:16px;font-weight:700;margin:0 0 12px;letter-spacing:-.01em}
.comm-grid{display:grid;gap:16px;grid-template-columns:repeat(auto-fill,minmax(272px,1fr))}
.comm-card{
  background:var(--surface);border:1px solid var(--border-card);border-radius:var(--radius-lg);
  overflow:hidden;display:flex;flex-direction:column;box-shadow:var(--shadow-soft);
}
.comm-card__cover{aspect-ratio:16/9;background:var(--surface-muted);overflow:hidden}
.comm-card__cover img{width:100%;height:100%;object-fit:cover;display:block}
.comm-card__cover-ghost{width:100%;height:100%;display:grid;place-items:center;background:var(--accent-soft)}
.comm-card__body{padding:14px;display:flex;flex-direction:column;gap:9px;flex:1}
.comm-card__top{display:flex;align-items:center;gap:10px}
.comm-card__name{font-size:17px;font-weight:700;margin:0;letter-spacing:-.01em;line-height:1.25}
/* Mô tả kẹp đúng hai dòng để mọi thẻ trong lưới cao bằng nhau — thẻ so le
   khiến hàng nút bên dưới nhảy chỗ và mắt phải đi tìm lại mỗi lần. */
.comm-card__desc{
  margin:0;font-size:14px;color:var(--text-muted);line-height:1.5;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;
}
.comm-card__stats{display:flex;gap:14px;font-size:13px;color:var(--text-muted);margin-top:auto}
.comm-card__stats span{display:inline-flex;align-items:center;gap:5px}
.comm-card__cta{padding-top:4px}
.comm-card__cta .btn{width:100%;justify-content:center}

/* --- Trang "Về" -------------------------------------------------------- */
.comm-about{display:grid;grid-template-columns:1fr 320px;gap:16px;align-items:start}
.comm-about__cover{aspect-ratio:16/9;border-radius:var(--radius-md);overflow:hidden;margin-bottom:14px;background:var(--surface-muted)}
.comm-about__cover img{width:100%;height:100%;object-fit:cover;display:block}
.comm-about__head{display:flex;align-items:center;gap:13px;margin-bottom:10px}
.comm-about__head h2{margin:0 0 5px;font-size:21px;letter-spacing:-.02em}
.comm-about__nums{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;text-align:center;margin-bottom:12px}
.comm-about__nums b{display:block;font-size:20px;font-weight:800;letter-spacing:-.02em}
.comm-about__nums span{font-size:12px;color:var(--text-muted)}
.comm-about__avas{display:flex;flex-wrap:wrap;gap:5px;margin-bottom:14px}
.comm-about__avas .avatar{width:30px;height:30px;font-size:11px}
.comm-about__side .btn{margin-bottom:8px}
.comm-about__cta .btn{width:100%;justify-content:center}

/* --- Cài đặt cộng đồng ------------------------------------------------- */
.comm-set__row{display:flex;align-items:flex-start;justify-content:space-between;gap:14px}
.comm-set__row h3{margin:0 0 3px}
.comm-set__list{margin:14px 0 0;display:grid;gap:10px}
.comm-set__list div{display:grid;grid-template-columns:130px 1fr;gap:12px;align-items:start}
.comm-set__list dt{color:var(--text-muted);font-size:14px}
.comm-set__list dd{margin:0;font-size:14px;font-weight:500}
.comm-sel{
  font-size:14px;padding:6px 9px;border-radius:9px;
  border:1px solid var(--border);background:var(--surface);color:var(--text);
}
.tbl__who{display:flex;align-items:center;gap:8px}
.tbl__who .avatar{width:28px;height:28px;font-size:11px}
/* Ba nút một hàng thì dùng grid, không dùng flex-wrap: flex-wrap để một nút
   rơi xuống dòng một mình, còn grid thì cả hàng cùng hẹp lại. */
.tbl__cta{display:flex;gap:6px;justify-content:flex-end;white-space:nowrap}

/* --- Chọn mức riêng tư trong form -------------------------------------- */
.comm-vis{display:grid;gap:8px}
.comm-vis__opt{
  display:grid;grid-template-columns:auto 1fr;gap:10px;align-items:start;cursor:pointer;
  padding:11px 12px;border:1px solid var(--border-card);border-radius:var(--radius-md);background:var(--surface);
}
.comm-vis__opt.is-on{border-color:var(--accent);background:var(--accent-soft)}
.comm-vis__opt input{position:absolute;opacity:0;pointer-events:none}
.comm-vis__ic{color:var(--accent-hover);display:grid;place-items:center;margin-top:1px}
.comm-vis__opt b{display:block;font-size:14.5px}
.comm-vis__opt small{display:block;color:var(--text-muted);font-size:13px;line-height:1.45;margin-top:2px}

/* --- Bảng chọn cộng đồng (modal trên điện thoại) ----------------------- */
.modal--sm{max-width:440px}
.comm-pick{display:grid;gap:4px}
.comm-pick__row{
  display:grid;grid-template-columns:auto 1fr auto;gap:11px;align-items:center;
  padding:9px 10px;border-radius:var(--radius-md);text-decoration:none;color:inherit;
}
.comm-pick__row:hover{background:var(--surface-muted)}
/* Trạng thái "đang mở" phải khác hẳn màu hover, nếu không rê chuột lên một
   dòng khác sẽ trông y như dòng đang chọn và mất hẳn phản hồi. */
.comm-pick__row.is-active{background:var(--accent-soft);color:var(--accent-hover)}
.comm-pick__row.is-active:hover{background:var(--accent-soft);filter:brightness(.97)}
.comm-pick__txt{min-width:0}
.comm-pick__txt .b{font-weight:650;font-size:15px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.comm-pick__row--all{border-top:1px solid var(--border);border-radius:0;margin-top:6px;padding-top:12px}

/* --- Điện thoại -------------------------------------------------------- */
@media(max-width:1023px){
  .comm-about{grid-template-columns:1fr}
}
@media(max-width:767px){
  /* Rail không có chỗ trên màn hẹp — đổi cộng đồng bằng nút ở header. */
  .shell--rail{grid-template-columns:1fr}
  .comm-rail{display:none}
  .comm-switch{display:inline-flex}
  .comm-grid{grid-template-columns:1fr;gap:13px}
  .comm-set__row{flex-direction:column;align-items:stretch}
  .comm-set__list div{grid-template-columns:1fr;gap:2px}
  .comm-set__list dt{font-size:12.5px}
}

/* =====================================================================
   KHO KHOÁ HỌC + KHOÁ HỌC CỦA CỘNG ĐỒNG (migration 060)
   ===================================================================== */

/* Ô "Thêm khoá học" — một THẺ trong lưới, không phải một nút lạc lõng phía trên.
   Nó đứng cùng hàng với các khoá đã có nên mắt không phải đi tìm ở chỗ khác,
   và nó giữ nguyên khuôn thẻ nên lưới không so le. */
.tile--them{
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:7px;
  min-height:240px;padding:22px 18px;text-align:center;cursor:pointer;
  background:var(--surface);border:1.5px dashed var(--border-card);border-radius:var(--radius-lg);
  color:var(--text-muted);font:inherit;transition:border-color .16s ease,color .16s ease,background .16s ease;
}
.tile--them:hover{border-color:var(--accent);color:var(--accent-hover);background:var(--accent-soft)}
.tile--them__ic{display:grid;place-items:center;width:46px;height:46px;border-radius:14px;background:var(--surface-muted)}
.tile--them:hover .tile--them__ic{background:#fff}
.tile--them__txt{font-size:15.5px;font-weight:650;color:var(--text)}
.tile--them:hover .tile--them__txt{color:var(--accent-hover)}
.tile--them__sub{font-size:13px;line-height:1.45;max-width:22ch}

/* Nút "···" ở góc ảnh bìa thẻ khoá học — gom mọi việc quản vào một chỗ.
   Thay cho hàng hai nút chữ dài của bản trước: hàng đó chiếm nguyên một dòng
   dưới mỗi thẻ và đẩy "Bắt đầu học" khỏi vị trí kết thúc tự nhiên của thẻ.

   🔴 KHÔNG ẩn sau hover. Trên điện thoại không có hover — một nút chỉ hiện khi
   rê chuột là một nút không tồn tại. */
.tile__cover{position:relative}
.tile__kebab{
  position:absolute;top:8px;right:8px;z-index:2;
  width:30px;height:30px;border-radius:50%;
  /* Chấm TRẮNG (Founder chốt 25/08/2026), nhẹ hơn đĩa trắng đặc cũ.
     🔴 Nền tối mờ KHÔNG phải trang trí: ảnh bìa do người dùng tải lên, có thể
     sáng trắng — chấm trắng đặt trần lên đó là tàng hình. Nền này giữ tương
     phản trên MỌI ảnh bìa, kể cả ảnh chưa tồn tại. */
  background:rgba(0,0,0,.42);color:#fff;border:0;box-shadow:none;
  -webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);
  display:grid;place-items:center;
}
.tile__kebab:hover{background:rgba(0,0,0,.62);color:#fff}
/* Vùng chạm 32px vẽ ra, nới lên 46px cho ngón tay. */
@media(hover:none){ .tile__kebab::after{content:'';position:absolute;inset:-8px} }

@media(max-width:767px){
  .tile--them{min-height:170px}
  /* Đo thật ở 375px: `btn--sm` cho ra nút cao 30px — dưới ngưỡng chạm 38px, tức
     là ngón tay trượt sang thẻ bên cạnh. Nới bằng min-height chứ không bằng
     padding: padding cộng thêm sẽ đẩy chữ lệch khỏi tâm khi nhãn xuống hai dòng. */
  /* Trên màn hẹp lưới còn MỘT cột, nên một ô "Thêm khoá học" cao 170px chiếm
     trọn một màn hình trước khi thấy khoá đầu tiên — người quản mở trang để
     XEM khoá phải cuộn qua nó mỗi lần. Đổi thành một thanh ngang thấp: vẫn ở
     đầu (đúng chỗ mắt dừng), nhưng không còn chắn đường. */
  .tile--them{min-height:0;flex-direction:row;justify-content:flex-start;gap:12px;padding:14px 16px;text-align:left}
  .tile--them__ic{width:38px;height:38px;border-radius:11px;flex:0 0 auto}
  .tile--them__sub{display:none}
}

/* Ô tìm kiếm trong trang (Kho khoá học). Khác .search ở thanh trên cùng: cái
   kia luôn hiện, cái này thuộc về nội dung trang. */
.search--page{
  display:flex;align-items:center;gap:8px;margin-bottom:14px;padding:9px 13px;
  background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-md);
}
.search--page span{display:grid;place-items:center;color:var(--text-muted);flex:0 0 auto}
.search--page input{flex:1;border:none;background:none;outline:none;font-size:15px;color:var(--text);min-width:0}
@media(max-width:767px){ .search--page input{font-size:16px} }

/* =====================================================================
   THANH BÊN — TÁCH KHỐI CỘNG ĐỒNG / TOÀN HỆ THỐNG (2026-08-21)
   ===================================================================== */

/* Khối đầu tiên là CỘNG ĐỒNG ĐANG MỞ, và nhãn nhóm chính là tên cộng đồng đó.
   Cho nó màu accent + không viết hoa: đây là một cái TÊN RIÊNG, không phải một
   nhãn phân loại. Viết hoa toàn bộ như các nhóm khác sẽ làm "Khách Hàng VIP"
   thành "KHÁCH HÀNG VIP" — đọc như đang hét. */
.nav-group--comm > .nav-group__label{
  text-transform:none;font-size:12.5px;letter-spacing:-.01em;
  color:var(--accent-hover);font-weight:700;
  display:flex;align-items:center;gap:6px;
  padding-bottom:5px;
}
/* Chấm nhỏ trước tên: một dấu hiệu im lặng rằng phần dưới đây thuộc về nơi
   đang đứng, không phải toàn app. */
.nav-group--comm > .nav-group__label::before{
  content:'';flex:0 0 auto;width:6px;height:6px;border-radius:50%;
  background:var(--accent);
}

/* 🔴 ĐƯỜNG KẺ TÁCH HAI KHỐI ĐÃ GỠ — Founder chốt 05/09/2026.
   Ở đây trước là `.nav-group--vach{border-top:1px solid var(--border);padding-top:6px}`
   cộng một rule `margin-top:12px`. Cả hai đã gỡ cùng cờ `vachTren` trong NAV và
   class trong renderShell — ba tầng đi cùng nhau, không để lại tầng nào.
   Hai cụm vẫn tách nhau: `.nav-group{margin-top:9px}` ở trên cộng nhãn nhóm
   VIẾT HOA. Ai muốn dựng lại đường kẻ: nhớ nó phải bám PHẠM VI QUYỀN (một cờ
   trong NAV), KHÔNG bám vị trí (`.nav-group--comm + .nav-group`) — bản bám vị
   trí đã sai một lần và phải sửa hai lượt. */

/* =====================================================================
   TRANG CÀI ĐẶT CỘNG ĐỒNG (2026-08-21)
   Mọi thứ thành viên nhìn thấy trong một cộng đồng đều sửa được ở đây.
   ===================================================================== */
.comm-set + .comm-set{margin-top:16px}
.comm-set h3{margin:0 0 12px}
.cs-grid2{display:grid;grid-template-columns:1fr 1fr;gap:12px}

/* Ô chọn ảnh: khung xem trước + hai nút, xếp dọc để nhãn không bị bóp. */
.cs-anh{display:flex;flex-direction:column;gap:8px}
.cs-anh__xem{
  width:96px;height:96px;border-radius:var(--radius-md);overflow:hidden;
  background:var(--surface-muted);border:1px solid var(--border);
  display:grid;place-items:center;
}
.cs-anh__xem--rong{width:100%;max-width:280px;height:auto;aspect-ratio:16/9}
.cs-anh__xem img{width:100%;height:100%;object-fit:cover;display:block}
.cs-anh__nut{display:flex;gap:6px}

/* Khối một nút CTA. `fieldset` thật chứ không phải div: trình đọc màn hình
   đọc `legend` như tiêu đề của nhóm ô nhập bên trong. */
.cs-cta{
  border:1px solid var(--border);border-radius:var(--radius-md);
  padding:12px 14px 4px;margin:0 0 12px;
}
.cs-cta legend{font-size:13px;font-weight:650;padding:0 6px;color:var(--text-muted)}
.cs-switch{display:flex;align-items:center;gap:8px;margin-bottom:10px;font-size:14px;cursor:pointer}
.cs-switch input{width:16px;height:16px;accent-color:var(--accent)}
.cs-link + .cs-link{border-top:1px solid var(--border);padding-top:12px;margin-top:2px}

/* Thanh Lưu dính đáy màn: form dài, cuộn xuống cuối mới bấm được nút lưu là
   bắt người ta nhớ mình đã sửa gì ở tận trên kia. */
.cs-luu{
  position:sticky;bottom:0;z-index:3;
  display:flex;align-items:center;gap:12px;flex-wrap:wrap;
  margin-top:16px;padding:12px 0;
  background:linear-gradient(to top, var(--bg) 70%, transparent);
}

@media(max-width:767px){
  .cs-grid2{grid-template-columns:1fr}
  .cs-anh__xem--rong{max-width:100%}
  .cs-luu .btn{width:100%;justify-content:center;min-height:44px}
}

/* =====================================================================
   THANH TAB CỦA MỘT CỘNG ĐỒNG (2026-08-21)
   Sáu cách nhìn vào cùng một cộng đồng, đặt ngay đầu vùng nội dung.
   ===================================================================== */
.ctabs{
  display:flex;gap:2px;align-items:stretch;
  margin:0 0 18px;border-bottom:1px solid var(--border);
  overflow-x:auto;-webkit-overflow-scrolling:touch;scrollbar-width:none;
}
.ctabs::-webkit-scrollbar{display:none}
.ctabs__item{
  position:relative;flex:0 0 auto;
  padding:11px 14px;font-size:15px;font-weight:550;line-height:1.2;
  color:var(--text-muted);text-decoration:none;white-space:nowrap;
  border-bottom:2px solid transparent;margin-bottom:-1px;
}
.ctabs__item:hover{color:var(--text)}
/* Tab đang mở: gạch chân accent + chữ đậm. KHÔNG dùng nền — nền làm thanh tab
   trông như một hàng nút, và người ta sẽ chờ nó phản hồi như nút. */
.ctabs__item.is-active{color:var(--accent-hover);border-bottom-color:var(--accent);font-weight:700}

@media(max-width:767px){
  .ctabs{margin-bottom:14px}
  /* Vùng chạm: 11px trên + dưới + 15px chữ ≈ 44px, đã đạt ngưỡng. Chỉ nới lề
     hai bên để ngón tay không trượt sang tab cạnh. */
  .ctabs__item{padding:12px 13px;font-size:15px}
}

/* Huy hiệu chưa đọc trên thanh tab cộng đồng (Tin nhắn · Thông báo). */
.ctabs__item{display:inline-flex;align-items:center;gap:6px}
.ctabs__badge{
  display:inline-grid;place-items:center;min-width:18px;height:18px;padding:0 5px;
  border-radius:9px;background:var(--accent-hover);color:#fff;
  font-size:11px;font-weight:700;line-height:1;
}
.ctabs__item.is-active .ctabs__badge{background:var(--accent)}
/* 🔴 KHÔNG CÓ GÌ MỚI THÌ KHÔNG CÓ CHẤM.
   Founder 2026-08-21: hai chấm cam trên tab Tin nhắn / Thông báo sáng vĩnh viễn
   dù không có thông báo nào. Mã JS đã đặt `hidden` khi số = 0 — nhưng
   `display:inline-grid` ở trên ĐÈ mất `[hidden]{display:none}` của trình duyệt,
   nên thẻ vẫn hiện, chỉ là rỗng chữ ⇒ thành một chấm tròn cam không nghĩa gì.
   Một chỉ báo luôn bật thì không còn là chỉ báo: vài lần bấm vào không thấy gì
   mới là người ta thôi tin nó. Quy tắc: hễ đặt `display` cho thứ có thể `hidden`
   thì phải khai lại `[hidden]` ngay bên dưới. */
.ctabs__badge[hidden],.nav-item__badge[hidden]{display:none}

/* Nút "Thêm kênh" trong thanh bên: là <button> nên phải tự dựng lại dáng
   .nav-item (button không kế thừa font/màu của <a>). */
.nav-item--them{
  width:100%;background:none;border:1px dashed var(--border);cursor:pointer;
  font:inherit;color:var(--text-muted);text-align:left;margin-top:4px;
}
.nav-item--them:hover{border-color:var(--accent);color:var(--accent-hover);background:var(--accent-soft)}

/* Thẻ tiến độ cấp của chính người đang xem (trang Bảng xếp hạng). */
.lvcard{display:flex;flex-direction:column;align-items:center;text-align:center;gap:6px;position:relative;padding:22px 18px}
.lvcard .avatar--xl{width:96px;height:96px;font-size:30px;border:3px solid var(--surface);box-shadow:0 0 0 3px var(--accent-soft)}
.lvcard__chip{
  position:absolute;top:96px;left:50%;transform:translateX(28px);
  width:30px;height:30px;border-radius:50%;background:var(--accent-hover);color:#fff;
  display:grid;place-items:center;font-weight:800;font-size:13px;border:3px solid var(--surface);
}
.lvcard__name{font-size:17px;font-weight:750;letter-spacing:-.01em;margin-top:6px}
.lvcard__next{
  margin-top:4px;font-size:13.5px;font-weight:600;color:var(--accent-hover);
  background:var(--accent-soft);border-radius:20px;padding:4px 12px;
}
/* Cấp chưa đạt: ổ khoá thay số. Xám hẳn để mắt lướt qua được ngay. */
.level__chip--khoa{background:var(--surface-muted);color:var(--text-muted)}

/* Ảnh bìa cộng đồng ở đầu hộp đăng nhập/đăng ký (link mời). */
.auth-bia{border-radius:var(--radius-lg);overflow:hidden;aspect-ratio:16/9;background:var(--surface-muted)}
.auth-bia img{width:100%;height:100%;object-fit:cover;display:block}

/* =====================================================================
   TRANG CÀI ĐẶT CỘNG ĐỒNG — nav trái + thân (2026-08-21)
   ===================================================================== */
.cs-wrap{display:grid;grid-template-columns:220px 1fr;gap:16px;align-items:start}
.cs-nav{
  position:sticky;top:calc(var(--topbar-h) + 16px);
  display:flex;flex-direction:column;gap:2px;
  background:var(--surface);border:1px solid var(--border-card);border-radius:var(--radius-lg);padding:8px;
}
.cs-nav__item{
  padding:9px 12px;border-radius:var(--radius-md);font-size:14.5px;font-weight:500;
  color:var(--text-muted);text-decoration:none;line-height:1.3;
}
.cs-nav__item:hover{background:var(--surface-muted);color:var(--text)}
.cs-nav__item.is-active{background:var(--accent-soft);color:var(--accent-hover);font-weight:650}
.cs-than{padding:20px}
.cs-than h3{margin:0 0 12px}
.cs-than h4{margin:0;font-size:15px}

/* Ô đường dẫn: phần gốc cố định + ô nhập + nút copy, ghép thành một khối. */
.cs-url{display:flex;align-items:stretch;border:1px solid var(--border);border-radius:var(--radius-md);overflow:hidden;background:var(--surface)}
.cs-url__base{
  display:grid;place-items:center;padding:0 10px;flex:0 0 auto;
  background:var(--surface-muted);color:var(--text-muted);font-size:13.5px;white-space:nowrap;
}
.cs-url input{flex:1;border:none;outline:none;background:none;padding:9px 10px;font-size:15px;min-width:0}
.cs-url .icon-btn{border:none;border-left:1px solid var(--border);border-radius:0;flex:0 0 auto;width:40px}
.cs-dem{text-align:right;font-size:12.5px;color:var(--text-muted);margin-top:4px}

/* Chủ đề màu */
.cs-themes{display:grid;grid-template-columns:repeat(auto-fill,minmax(170px,1fr));gap:8px}
.cs-theme{
  display:flex;align-items:center;gap:10px;cursor:pointer;
  padding:11px 12px;border:1px solid var(--border-card);border-radius:var(--radius-md);
  font-size:14.5px;font-weight:500;background:var(--surface);
}
.cs-theme.is-on{border-color:var(--accent);background:var(--accent-soft);font-weight:650}
.cs-theme input{position:absolute;opacity:0;pointer-events:none}
.cs-theme__cham{width:26px;height:26px;border-radius:50%;flex:0 0 auto;border:1px solid rgba(0,0,0,.08)}

/* Bật/tắt tab */
.cs-tabs{display:grid;gap:8px}
.cs-tabrow{
  display:flex;align-items:center;justify-content:space-between;gap:14px;cursor:pointer;
  padding:13px 14px;border:1px solid var(--border-card);border-radius:var(--radius-md);background:var(--surface);
}
.cs-tabrow b{display:block;font-size:14.5px}
.cs-tabrow small{display:block;color:var(--text-muted);font-size:13px;line-height:1.45;margin-top:2px}
/* Tab không tắt được: nói bằng MÀU chứ không chỉ bằng `disabled` — một công tắc
   xám mà không giải thích thì người ta bấm mãi rồi tưởng app hỏng. */
.cs-tabrow.is-khoa{background:var(--surface-muted);cursor:default}
.cs-toggle{
  appearance:none;flex:0 0 auto;width:44px;height:26px;border-radius:13px;
  background:var(--border);position:relative;cursor:pointer;transition:background .16s ease;
}
.cs-toggle::after{
  content:'';position:absolute;top:3px;left:3px;width:20px;height:20px;border-radius:50%;
  background:#fff;box-shadow:var(--shadow-soft);transition:transform .16s ease;
}
.cs-toggle:checked{background:var(--accent)}
.cs-toggle:checked::after{transform:translateX(18px)}
.cs-toggle:disabled{opacity:.5;cursor:not-allowed}

@media(max-width:900px){
  .cs-wrap{grid-template-columns:1fr}
  /* Màn hẹp: nav thành hàng cuộn ngang, không còn dính đỉnh. */
  .cs-nav{position:static;flex-direction:row;overflow-x:auto;scrollbar-width:none}
  .cs-nav::-webkit-scrollbar{display:none}
  .cs-nav__item{white-space:nowrap;flex:0 0 auto}
  .cs-themes{grid-template-columns:1fr 1fr}
}
@media(max-width:767px){
  .cs-than{padding:16px}
  .cs-themes{grid-template-columns:1fr}
  .cs-tabrow{padding:12px}
}

/* Một dòng kênh trong thanh bên: link chiếm hết bề ngang, nút "···" nằm trong
   lề phải được chừa sẵn. Chừa bằng padding-right chứ không đặt nút đè lên —
   chỉ padding mới chặn được tên kênh dài tràn xuống dưới nút. */
.nav-kenh{position:relative}
.nav-kenh .nav-item{padding-right:38px}
.nav-kenh.active .nav-item{background:var(--accent-soft);color:var(--accent-hover)}
.nav-kenh__nut{
  position:absolute;right:6px;top:50%;transform:translateY(-50%);
  width:26px;height:26px;border-radius:8px;border:none;background:none;
  color:var(--text-muted);display:grid;place-items:center;cursor:pointer;
}
.nav-kenh__nut:hover{background:var(--surface);color:var(--accent-hover)}
/* Trên điện thoại không có hover nên nút phải LUÔN thấy được, và vùng chạm nới ra. */
@media(hover:none){ .nav-kenh__nut::after{content:'';position:absolute;inset:-8px} }

/* Nút "Phát sóng" trong ô soạn bài. Màu đỏ vì nó KHÔNG cùng loại với Ảnh/Video/
   Tệp — ba nút kia đính kèm vào bài đang soạn, nút này mở một buổi trực tiếp. */

/* =====================================================================
 * PHÒNG HỌP / BUỔI DẠY TRONG APP  (#/c/<slug>/live · xem os-live.js)
 * Nền TỐI có chủ ý — đây là khối duy nhất đi ngược light theme của app.
 * Lý do chức năng, không phải thẩm mỹ: mắt đọc khuôn mặt trên nền tối dễ hơn
 * hẳn, và mọi phần mềm gọi video đều làm vậy. Test màu phải bỏ qua khối này.
 * ===================================================================== */
.live { display:flex; flex-direction:column; gap:12px; }
.live__head { display:flex; align-items:center; justify-content:space-between; gap:12px; flex-wrap:wrap; }
.live__title { display:flex; align-items:center; gap:8px; font-size:16px; }
.live__dot { width:9px; height:9px; border-radius:50%; background:var(--danger); flex:0 0 auto;
  animation:live-tho 2s ease-in-out infinite; }
/* Người bật "giảm chuyển động" thì chấm đứng yên — vẫn đỏ nên vẫn đọc được. */
@media (prefers-reduced-motion:reduce) { .live__dot { animation:none; } }
@keyframes live-tho { 0%,100%{opacity:1} 50%{opacity:.35} }
.live__mode { font-size:12px; padding:3px 9px; border-radius:999px;
  background:var(--accent-soft); color:var(--accent-hover); border:1px solid var(--accent-border); }
.live__count { font-size:13px; color:var(--text-secondary); }

.live__grid { display:grid; grid-template-columns:repeat(var(--cot,1),minmax(0,1fr)); gap:10px;
  background:#111113; border-radius:var(--radius-lg,14px); padding:10px; min-height:340px; align-content:center; }
.live__tile { position:relative; aspect-ratio:16/9; background:#000; border-radius:10px; overflow:hidden; }
.live__tile video { width:100%; height:100%; object-fit:cover; display:block; }
/* Ô của chính mình lật gương — không lật thì đưa tay phải lên lại thấy tay trái,
   ai cũng thấy sai mà không nói ra được sai chỗ nào. */
.live__tile.is-toi video { transform:scaleX(-1); }
.live__ten { position:absolute; left:8px; bottom:8px; max-width:calc(100% - 16px);
  padding:3px 9px; border-radius:6px; background:rgba(0,0,0,.62); color:#fff; font-size:12px;
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.live__cho { grid-column:1/-1; text-align:center; color:#C9C9C9; padding:36px 18px; }
.live__cho p { margin:10px 0 0; font-size:14px; line-height:1.55; }
.live__cho--loi { color:#FFD9D9; }
.live__cho-nut { display:flex; gap:8px; justify-content:center; margin-top:14px; flex-wrap:wrap; }

.live__bar { display:flex; gap:8px; justify-content:center; flex-wrap:wrap; }
.live__btn { display:inline-flex; align-items:center; gap:7px; min-height:44px; padding:0 16px;
  border-radius:999px; border:1px solid var(--border); background:var(--surface);
  color:var(--text-primary); font-size:14px; cursor:pointer; }
.live__btn:hover { background:var(--surface-muted); }
/* Tắt mic/camera phải nhìn ra NGAY từ xa — gạch chéo đỏ, không chỉ đổi chữ. */
.live__btn.is-tat { background:#FEECEC; border-color:#F3B4B4; color:#9F1239; }
.live__btn--out { border-color:#F3B4B4; color:var(--danger); }
.live__btn--out:hover { background:#FEECEC; }
.live__note { text-align:center; font-size:12.5px; color:var(--text-muted); margin:0; line-height:1.6; }

/* --- Bảng "Ngay trong app" trong hộp Phát sóng --- */
.ps-xem { position:relative; aspect-ratio:16/9; background:#111113; border-radius:12px;
  overflow:hidden; margin:12px 0 10px; }
.ps-xem__v { width:100%; height:100%; object-fit:cover; display:block; transform:scaleX(-1); }
.ps-xem__che { position:absolute; inset:0; display:flex; flex-direction:column; align-items:center;
  justify-content:center; gap:10px; color:#C9C9C9; text-align:center; padding:16px; }
.ps-xem__che p { margin:0; font-size:13.5px; }
.ps-xem__che[hidden] { display:none; }
.ps-tb { display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:10px; margin-bottom:10px; }
.ps-tb .field span { display:block; font-size:12.5px; color:var(--text-secondary); margin-bottom:4px; }
.ps-tb select { width:100%; }
@media (max-width:520px) { .ps-tb { grid-template-columns:1fr; } }

/* --- Phòng chờ (phía người đang đợi) --- */
.live__cho-box[hidden] { display:none; }
.live__doi { display:flex; align-items:center; gap:12px;
  border:1px solid var(--accent-border); background:var(--accent-soft);
  border-radius:12px; padding:12px 14px; }
.live__doi > div { flex:1 1 auto; min-width:0; }
.live__doi p { margin:2px 0 0; font-size:13px; color:var(--text-secondary); }
@media (max-width:520px) { .live__doi { flex-wrap:wrap; } }

/* --- Duyệt người vào phòng (phía chủ phòng) ---------------------------
   Gọn: một chip trong tiêu đề + một bảng thả xuống neo dưới nó.
   🔴 Bản trước dùng cả một DẢI CAM chiếm trọn một hàng phía trên khung hình —
   đẩy hình xuống và giành sự chú ý khỏi chính buổi họp. Số người chờ thuộc về
   chỗ mắt đã nhìn để đếm người, tức là cạnh "2/6 người". */
.live__dem-nhom { display:flex; align-items:center; gap:10px; }
.live__cho-chip { min-height:28px; padding:0 11px; border-radius:999px; cursor:pointer;
  border:1px solid var(--accent-border); background:var(--accent-soft);
  color:var(--accent-hover); font-size:12.5px; font-weight:600; white-space:nowrap; }
.live__cho-chip:hover { background:#FFE8D2; }
.live__cho-chip[hidden] { display:none; }
.live__cho-chip::after { content:''; position:absolute; }   /* giữ chỗ cho vùng chạm */
@media (hover:none) { .live__cho-chip { min-height:34px; } }

.live__duyet { min-width:280px; max-width:min(360px, calc(100vw - 16px)); padding:6px; }
.live__duyet-dau { padding:6px 8px 8px; font-size:12.5px; color:var(--text-muted); }
.live__duyet ul { list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:2px; }
.live__duyet li { display:flex; align-items:center; gap:9px; padding:5px 6px; border-radius:8px; }
.live__duyet li:hover { background:var(--surface-muted); }
.live__duyet-ac { width:26px; height:26px; flex:0 0 auto; border-radius:50%;
  background:var(--surface-muted); color:var(--text-secondary);
  display:flex; align-items:center; justify-content:center; font-size:12px; font-weight:700; }
.live__duyet-ten { flex:1 1 auto; min-width:0; overflow:hidden; text-overflow:ellipsis;
  white-space:nowrap; font-size:13.5px; }
.live__duyet-x { width:28px; height:28px; flex:0 0 auto; color:var(--text-muted); }
.live__duyet-x:hover { color:var(--danger); background:#FEECEC; }
.live__duyet-all { width:100%; margin-top:6px; min-height:34px; border-radius:8px; cursor:pointer;
  border:1px solid var(--border); background:var(--surface); font-size:13px; }
.live__duyet-all:hover { background:var(--surface-muted); }

/* --- Ô không có hình: chữ cái đầu + lý do, thay cho hình chữ nhật đen --- */
.live__khong-hinh { position:absolute; inset:0; display:flex; flex-direction:column;
  align-items:center; justify-content:center; gap:6px; background:#17171A; color:#B9B9BE; }
.live__khong-hinh[hidden] { display:none; }
.live__chu-cai { width:56px; height:56px; border-radius:50%; background:#2A2A30; color:#EDEDED;
  display:flex; align-items:center; justify-content:center; font-size:22px; font-weight:700; }
.live__khong-hinh small { font-size:12px; }
/* Chia sẻ màn hình KHÔNG lật gương — lật thì chữ trên màn hình đọc ngược. */
.live__tile.is-man video { transform:none; object-fit:contain; background:#000; }

.live__btn.is-on { background:var(--accent-soft); border-color:var(--accent-border); color:var(--accent-hover); }
/* Đổi camera trước/sau: chỉ có nghĩa ở máy có hai ống kính. Máy tính bàn một
   webcam thì nút này là tiếng ồn — giấu ở màn hình rộng, KHÔNG gỡ khỏi lưới để
   xoay máy là hiện lại ngay. */
@media (min-width:721px) { .live__btn--mat { display:none; } }

/* --- E2 · Bảng báo cáo sau buổi --- */
.live__bc { padding:16px 20px; }
/* Bảng 6 cột trên điện thoại chắc chắn tràn ngang. Cho CUỘN TRONG hộp của nó,
   đừng để cả trang trôi ngang — trang trôi ngang là mất luôn thanh nút. */
.live__bc-cuon { overflow-x:auto; -webkit-overflow-scrolling:touch; }
.live__bc-bang { width:100%; border-collapse:collapse; font-size:13.5px; min-width:520px; }
.live__bc-bang th, .live__bc-bang td { text-align:left; padding:7px 10px;
  border-bottom:1px solid var(--border); white-space:nowrap; }
.live__bc-bang th { font-size:12.5px; color:var(--text-secondary); font-weight:600; }
.live__bc-bang tbody tr:last-child td { border-bottom:0; }
.live__bc-muon { color:#9F1239; font-size:12px; }
@media (max-width:640px) { .live__muc { display:none; } }
.live__cd { margin-top:10px; border-top:1px solid var(--border); padding-top:10px; }
.live__cd summary { cursor:pointer; font-size:13px; color:var(--text-secondary); min-height:32px;
  display:flex; align-items:center; }
.live__nn { position:absolute; right:8px; bottom:8px; padding:3px 9px; border-radius:6px;
  background:rgba(0,0,0,.62); color:#FFD9A8; font-size:11.5px; }
.live__nn[hidden] { display:none; }

/* --- Nút thu/mở thanh bên ---------------------------------------------
   Kiểu dáng theo mẫu ChatGPT/Claude: một biểu tượng xám nhạt, KHÔNG viền màu,
   KHÔNG nền — chỉ hiện nền mờ khi rê chuột. Nút điều hướng phụ mà tô đỏ thì nó
   giành mất sự chú ý của những thứ quan trọng hơn trên màn hình.

   🔴 CHỪA CHỖ, ĐỪNG ĐÈ LÊN. Bản trước đặt nút nổi lên trên thanh đầu trang và
   nó chồng lên ô tìm kiếm (Founder chỉ ra 21/08/2026). Nay lúc thu gọn thì
   thanh đầu trang tự lùi vào 46px — nút có chỗ của riêng nó. */
.thu-menu { position:fixed; top:calc((var(--topbar-h) - 32px) / 2); z-index:60;
  width:32px; height:32px; display:flex; align-items:center; justify-content:center;
  padding:0; border:0; border-radius:8px; background:transparent;
  color:var(--text-muted); cursor:pointer;
  transition:left .18s ease, background .12s ease, color .12s ease; }
.thu-menu:hover { background:var(--surface-muted); color:var(--text-primary); }
.thu-menu:focus-visible { outline:2px solid var(--accent); outline-offset:2px; }
.thu-menu::after { content:''; position:absolute; inset:-6px; }   /* vùng chạm ≥44px */

/* Mở: nút nằm nép bên phải TRONG thanh bên, ngang hàng ô thương hiệu. */
.thu-menu { left:calc(var(--sidebar-w) - 42px); }
.shell--rail .thu-menu { left:calc(var(--comm-rail-w) + var(--sidebar-w) - 42px); }
/* Thu: nút lùi về sát trái, và thanh đầu trang chừa chỗ cho nó. */
.shell.is-thu .thu-menu { left:10px; }
.shell--rail.is-thu .thu-menu { left:calc(var(--comm-rail-w) + 10px); }
.shell.is-thu .topbar { padding-left:46px; }

.shell.is-thu { grid-template-columns:0 1fr; }
.shell--rail.is-thu { grid-template-columns:var(--comm-rail-w) 0 1fr; }
/* 🔴 KHÔNG dùng display:none. `display:none` GỠ HẲN phần tử khỏi lưới, nên lưới
   chỉ còn 2 ô trong khi khuôn vẫn khai 3 cột — phần nội dung tụt vào ô giữa rộng
   `0` và cả trang bị bóp thành một cột hẹp. (Trả giá 21/08/2026.)
   Bóp về 0 nhưng GIỮ NGUYÊN vị trí trong lưới thì khuôn 3 cột vẫn khớp. */
.shell.is-thu .sidebar { width:0; min-width:0; padding:0; border:0;
  overflow:hidden; visibility:hidden; }
.shell.is-thu .content { max-width:none; }
@media (max-width:900px) { .thu-menu { display:none; }   /* mobile đã có menu riêng */
  .shell.is-thu .topbar { padding-left:22px; } }

/* --- Toàn màn hình + phóng một ô --- */
.live.is-to { background:#0B0B0D; padding:16px; height:100vh; box-sizing:border-box;
  display:flex; flex-direction:column; }
/* 🔴 flex:0 0 auto — KHÔNG kéo giãn. `flex:1 1 auto` bắt lưới lấp đầy chiều cao,
   hàng giãn theo và ĐÈ MẤT tỉ lệ 16:9 của ô: ô thành cao lêu nghêu như ảnh
   Founder gửi 21/08/2026. Để lưới tự cao theo tỉ lệ ô, rồi margin:auto căn giữa. */
/* 🔴 `flex:0 1 auto` — KHÔNG grow (giữ nguyên luật 16:9 ở trên), NHƯNG ĐƯỢC
   PHÉP CO. Bản cũ để `0 0 auto` cho cả ba con của một khung cao đúng 100vh:
   không ai co, nên khi tổng chiều cao vượt 100vh thì con CUỐI — thanh nút —
   bị đẩy tuột ra ngoài đáy màn hình. Không cuộn được (khung không overflow),
   không có cách nào với tới. Đủ xảy ra thật: `--con-lai` chừa cứng 160px cho
   đầu + thanh nút, mà `.live__bar` có `flex-wrap:wrap` nên cửa sổ hẹp đẩy nút
   xuống hàng thứ ba là đã ~188px. Người dùng thấy "toàn màn hình làm mất nút".
   NAY: lưới nhường chỗ và tự cuộn; đầu và thanh nút luôn giữ đủ chỗ của mình. */
.live.is-to .live__grid { flex:0 1 auto; min-height:0; overflow:auto; overscroll-behavior:contain; }
.live.is-to .live__head, .live.is-to .live__bar { flex:0 0 auto; }
/* Lưới căn giữa MÀ cuộn được: `center` thường cắt mất phần tràn ở đầu và không
   cuộn tới được. `safe center` bỏ căn giữa đúng lúc bị tràn. Trình duyệt cũ
   không hiểu thì bỏ qua dòng này và giữ `center` như trước — không tệ hơn. */
.live.is-to .live__grid { align-content:safe center; }
.live.is-to .live__title, .live.is-to .live__count { color:#EDEDED; }
/* Phóng một ô: ô được chọn chiếm cả lưới, các ô còn lại nép xuống một hàng nhỏ. */
.live__grid.has-noi-bat { grid-template-columns:1fr; }
.live__grid.has-noi-bat .live__tile { display:none; }
.live__grid.has-noi-bat .live__tile.is-noi-bat { display:block; aspect-ratio:auto; height:100%;
  min-height:340px; }

/* =====================================================================
 * BỐ CỤC LINH ĐỘNG THEO SỐ NGƯỜI (tối đa 6) VÀ THEO VIỆC CÓ CHIA SẺ HAY KHÔNG
 * Nguyên tắc: KHÔNG BAO GIỜ để mất hình của ai. Chia sẻ màn hình thì màn hình
 * to lên, còn mọi người co lại thành một dải — chứ không biến mất.
 * ===================================================================== */
.live__grid { grid-template-rows:repeat(var(--hang,1), minmax(0,1fr));
  max-height:calc(100vh - 300px); }
/* 🔴 ĐỪNG DÒ CHUỖI `style` — ĐÓ LÀ LÝ DO LUẬT CŨ Ở ĐÂY CHƯA TỪNG CHẠY.
 *
 * JS đặt biến bằng `style.setProperty('--hang', 2)`, và trình duyệt ghi thuộc
 * tính ra kèm DẤU CÁCH:  style="--cot: 3; --hang: 2;"
 * Nên `[style*="--hang:2"]` KHÔNG BAO GIỜ khớp. Đo thẳng trên app 22/08/2026:
 *     d.style.setProperty('--hang',2) → getAttribute('style') === "--hang: 2;"
 *     d.matches('[style*="--hang:2"]') === false
 *
 * HẬU QUẢ ĐÃ XẢY RA: ô giữ nguyên 16:9 và rộng bằng cả khung, nên MỘT người
 * trong phòng cho ra ô cao ~1010px trong khi khung chỉ cho ~780px. Ô tràn ra
 * ngoài và vẽ đè lên thanh nút — nút nằm trên mặt người đang họp.
 * (Founder báo 22/08/2026, kèm ảnh chụp.)
 *
 * CÁCH ĐÚNG: dùng thẳng var(). Bó CHIỀU RỘNG của lưới theo chiều cao còn lại
 * rồi để margin đưa vào giữa — ô vẫn 16:9, vẫn căn giữa, và không bao giờ tràn.
 * Một công thức thay cho mọi tổ hợp cột × hàng, không phụ thuộc cách trình
 * duyệt viết chuỗi style.
 */
.live__grid:not(.is-chia-se) {
  --con-lai:calc(100vh - 300px);
  /* 🔴 `max(280px, …)` KHÔNG PHẢI cho đẹp — nó chặn một lỗi biên đã đo được:
     cửa sổ thấp hơn 300px thì `100vh - 300px` ra ÂM, max-width âm, và mọi ô co
     về 0px — phòng họp trống trơn mà không báo lỗi gì. Bắt được 22/08/2026 khi
     đo trong một khung trình duyệt cao 0px. */
  max-width:max(280px, calc((var(--con-lai) - (var(--hang, 1) - 1) * 10px)
                 / var(--hang, 1) * 1.7778 * var(--cot, 1)));
  margin-inline:auto;
}

/* --- Đang có người chia sẻ màn hình --- */
/* 🔴 BỐ CỤC TRÁI–PHẢI (Founder chốt 22/08/2026): màn hình chiếu ~78% bên trái,
   dải người ~22% bên phải. Trước đó là trên–dưới; đổi theo yêu cầu.

   VÌ SAO TRÁI–PHẢI HỢP HƠN VỚI MÀN HÌNH MÁY TÍNH:
   Màn hình máy tính rộng hơn cao. Đặt dải người nằm ngang bên dưới thì nó ăn
   mất chiều CAO — thứ đang khan hiếm — của slide. Đặt dọc bên phải thì nó ăn
   chiều RỘNG, thứ đang dư. Cùng một diện tích dải, slide được cao hơn.

   Bốn ô người là trần cố ý: nhiều hơn thì mỗi ô co lại thành con tem, nhìn
   không ra ai. Người thứ 5 trở đi rơi vào dòng đếm "đang nghe" bên dưới. */
/* 🔴 BA CỘT: màn hình · vạch kéo · dải người (Founder duyệt 22/08/2026)
   Bản trước là lưới 4 hàng cố định, giới hạn 4 ô, người thứ 5 rơi xuống dòng
   đếm và KHÔNG XEM ĐƯỢC. Dải cuộn thì không ai bị giấu — cuộn xuống là thấy hết.
   Vạch kéo cho người dạy tự đổi tỉ lệ: giảng slide thì kéo hẹp dải, thảo luận
   thì kéo rộng ra. */
.live__grid.is-chia-se {
  grid-template-columns:minmax(0,1fr) 8px var(--live-dai, 260px);
  grid-template-rows:minmax(0,1fr);
  align-content:stretch;
}
.live__keo { grid-column:2; grid-row:1; align-self:stretch;
  border:0; padding:0; cursor:col-resize; border-radius:99px;
  background:var(--border, #E5E2DC); position:relative;
  /* 🔴 `touch-action:none` KHÔNG phải cho đẹp: thiếu nó thì trên điện thoại và
     màn hình cảm ứng, trình duyệt nuốt luôn cú chạm để cuộn trang và sự kiện
     `pointermove` không bao giờ bắn ra — vạch nhìn thấy được mà kéo không nhúc
     nhích, không báo lỗi gì. */
  touch-action:none; }
.live__keo:hover, .live__keo.is-keo { background:var(--accent, #cc6600); }
/* Vùng chạm rộng hơn phần nhìn thấy — vạch 8px không đủ cho ngón tay. */
.live__keo::after { content:""; position:absolute; inset:-6px -10px; }
.live__keo:focus-visible { outline:2px solid var(--accent, #cc6600); outline-offset:2px; }

.live__dai { grid-column:3; grid-row:1; display:flex; flex-direction:column; gap:8px;
  overflow-y:auto; overscroll-behavior:contain; min-height:0; scrollbar-width:thin; }
/* Ô người khi ĐANG chia sẻ nằm TRONG dải (hộp cuộn thật), nên không đặt bằng
   `grid-column` nữa — dải mới là thứ chiếm cột 3. Ô chỉ xếp hàng dọc, giữ 16:9. */
.live__dai > .live__tile { flex:0 0 auto; width:100%; aspect-ratio:16/9; height:auto; }

/* Thu gọn dải — khi cần xem slide thật to. */
.live__grid.is-chia-se.is-thu-dai { grid-template-columns:minmax(0,1fr); }
.live__grid.is-chia-se.is-thu-dai .live__keo,
.live__grid.is-chia-se.is-thu-dai .live__dai { display:none; }

/* 🔴 KHÔNG chia sẻ ⇒ `display:contents`, KHÔNG phải lưới lồng trong lưới.
   `display:contents` làm chính cái hộp `.live__dai` biến mất khỏi bố cục, còn
   các ô con NHẢY LÊN làm con trực tiếp của `.live__grid` — đúng y như trước khi
   có dải. Nhờ vậy mọi công thức `--cot`/`--hang` và mọi luật cũ chạy nguyên vẹn.

   Vì sao không dựng lưới thứ hai bên trong: chiều cao ô khi đó tính theo hộp
   con chứ không theo khung ngoài — đúng kiểu sai lệch đã làm ô tràn ra đè lên
   thanh nút hôm 22/08. Một lưới thôi thì không có gì để lệch. */
.live__grid:not(.is-chia-se) .live__keo { display:none; }
.live__grid:not(.is-chia-se) .live__dai { display:contents; }
/* 🔴 Ô người vào CỘT 3, không phải cột 2 — sửa 22/08/2026.
 * Lưới chia sẻ có ba cột: `1fr | 8px vạch kéo | dải người`. Luật cũ đẩy ô người
 * vào cột 2, tức đúng cái vạch kéo rộng 8px — ai chia sẻ màn hình là mặt mọi
 * người bị bóp còn 8px.
 *
 * Dùng `>` (con TRỰC TIẾP) có chủ đích: khi nào phần JS dựng xong lớp bọc
 * `.live__dai` thì ô người nằm TRONG nó, không còn là con trực tiếp nữa, và
 * luật này tự động ngừng áp — không phải nhớ quay lại gỡ. */
/* 🔴 GIỮ LUẬT NÀY DÙ Ô NGƯỜI GIỜ ĐÃ NẰM TRONG `.live__dai`.
 * Đường chạy bình thường không bao giờ chạm tới nó — dấu `>` làm nó tự ngừng áp
 * ngay khi ô người vào trong dải. Nó là lưới an toàn cho ĐÚNG một tình huống đã
 * xảy ra thật lúc 16:38 ngày 22/08: os.css mới lên production trước os-app.js,
 * nên CSS đã có ba cột mà JS chưa dựng `.live__dai`. Ô người là con trực tiếp
 * của lưới, rơi vào cột 2 — tức cái vạch kéo rộng 8px — và mặt cả lớp bị bóp
 * còn 8px. Còn dòng này thì lần lệch nhịp sau chỉ mất cái dải, không mất mặt người. */
.live__grid.is-chia-se > .live__tile { grid-column:3; aspect-ratio:16/9; height:auto; }
.live__grid.is-chia-se > .live__tile.is-man-chinh {
  grid-column:1; grid-row:1; aspect-ratio:auto; height:100%; }
/* Màn hình chia sẻ: xem trọn, đừng cắt mép — cắt là mất nội dung đang trình bày. */
.live__grid.is-chia-se .live__tile.is-man-chinh video { object-fit:contain; background:#000; }
.live__grid.is-chia-se .live__khong-hinh small { display:none; }   /* dải nhỏ, chữ không đủ chỗ */
.live__grid.is-chia-se .live__chu-cai { width:40px; height:40px; font-size:16px; }
@media (max-width:720px) {
  /* 🔴 ĐIỆN THOẠI: VUỐT SANG TRANG, KHÔNG NHỒI VÀO MỘT MÀN HÌNH
     (Founder chốt 22/08/2026)

     375px chia đôi còn 82px — vô dụng cả hai bên. Và khi học trên điện thoại,
     thứ duy nhất cần nhìn là MÀN HÌNH ĐANG CHIẾU. Mọi người khác đẩy sang
     trang sau; muốn xem thì vuốt.

     TRANG 1: màn hình chiếu, chiếm trọn khung.
     TRANG 2+: lưới người, 4 ô mỗi trang.

     Chuyển trang bằng thuộc tính `data-trang` trên lưới — KHÔNG dựng lại thẻ
     video, chỉ đổi cái nào được hiện. Dựng lại là luồng đứt, hình đen chớp,
     và trên máy yếu có khi không hồi lại. */
  .live__grid.is-chia-se {
    grid-template-columns:repeat(2, minmax(0,1fr));
    grid-template-rows:repeat(2, minmax(0,1fr));
    gap:8px; }
  /* 🔴 Điện thoại KHÔNG có vạch kéo và KHÔNG có dải cuộn — 375px chia đôi còn
     82px mỗi bên, vô dụng cả hai. `display:contents` trả ô về làm con trực tiếp
     của lưới, để toàn bộ luật phân trang bên dưới chạy đúng như khi chưa có dải. */
  .live__grid.is-chia-se .live__keo { display:none; }
  .live__grid.is-chia-se .live__dai { display:contents; }

  /* Trang 1 — HAI thứ cần nhìn: NGƯỜI DẠY và MÀN HÌNH ĐANG CHIẾU (hình Founder
     duyệt 22/08/2026). Người dạy ô nhỏ nằm trên, màn hình lấy phần còn lại.

     🔴 Khi người dạy CHÍNH LÀ người đang chia sẻ thì hai thứ đó là MỘT ô — nối
     thẳng máy-với-máy chỉ có một luồng hình mỗi người, nên ô của người chia sẻ
     BIẾN THÀNH ô màn hình. Lúc đó chừa sẵn một hàng 112px cho ô người dạy là
     chừa một khoảng trống rỗng ngay đầu màn hình điện thoại. Luật `:has()` bên
     dưới bắt đúng ca đó và trả màn hình về chiếm trọn khung. */
  .live__grid.is-chia-se[data-trang="1"] { grid-template-rows:112px minmax(0,1fr); }
  .live__grid.is-chia-se[data-trang="1"] .live__tile { display:none; }
  .live__grid.is-chia-se[data-trang="1"] .live__tile.is-nguoi-day {
    display:block; grid-column:1 / -1; grid-row:1; aspect-ratio:16/9;
    height:100%; width:auto; margin-inline:auto; }
  .live__grid.is-chia-se[data-trang="1"] .live__tile.is-man-chinh {
    display:block; grid-column:1 / -1; grid-row:2; aspect-ratio:auto; height:100%; }
  /* Không có ô người dạy RIÊNG ⇒ màn hình lấy trọn cả hai hàng. */
  .live__grid.is-chia-se[data-trang="1"]:not(:has(.live__tile.is-nguoi-day:not(.is-man-chinh))) {
    grid-template-rows:minmax(0,1fr); }
  .live__grid.is-chia-se[data-trang="1"]:not(:has(.live__tile.is-nguoi-day:not(.is-man-chinh)))
    .live__tile.is-man-chinh { grid-row:1; }

  /* Trang 2 trở đi — lưới người, giấu màn hình chiếu. Ô nào thuộc trang nào do
     JS gắn class `is-trang-N`; ở đây chỉ lo hiện/ẩn. */
  .live__grid.is-chia-se:not([data-trang="1"]) .live__tile.is-man-chinh { display:none; }
  .live__grid.is-chia-se:not([data-trang="1"]) .live__tile { display:none; aspect-ratio:16/9; height:auto; }
  .live__grid.is-chia-se:not([data-trang="1"]) .live__tile.is-trang-nay { display:block; }

  /* Chấm chỉ trang — cho biết đang ở đâu và còn mấy trang nữa. */
  .live__cham { display:flex; justify-content:center; gap:7px; padding:8px 0 2px; }
  .live__cham i { width:7px; height:7px; border-radius:99px; background:var(--border,#E5E2DC);
    transition:background .15s; }
  .live__cham i.is-day { background:var(--accent,#cc6600); }
}
@media (min-width:721px) { .live__cham { display:none; } }

/* ---- PHÂN TRANG TRÊN MÁY TÍNH (22/08/2026, lớp 60 người) ------------------
 * 🔴 Ở ĐÂY `display:none` LÀ ĐÚNG, khác với bẫy CE8.
 * Bẫy đó là ẩn MỘT ô mà vẫn muốn giữ khuôn — gỡ khỏi lưới thì khuôn 3 cột chỉ
 * còn 2 ô và nội dung tụt vào ô rộng 0. Ở đây ô thuộc TRANG KHÁC: ta muốn lưới
 * xếp lại chỉ với 6 ô của trang đang xem. Gỡ hẳn mới đúng.
 *
 * Dùng lớp riêng `.co-phan-trang` chứ không dùng lại `[data-trang]` của điện
 * thoại: hai bộ luật cùng chọi vào một thuộc tính là cách chắc chắn để đè nhau.
 */
@media (min-width:721px) {
  .live__grid.co-phan-trang > .live__tile { display:none; }
  .live__grid.co-phan-trang > .live__tile.is-trang-nay { display:block; }
  /* Màn hình đang chiếu KHÔNG bao giờ bị giấu sang trang khác — nó là thứ cả
     lớp đang nhìn. */
  .live__grid.co-phan-trang > .live__tile.is-man-chinh { display:block; }
}

.live__trang { display:flex; align-items:center; justify-content:center; gap:12px;
               padding:10px 0 2px; }
.live__trang[hidden] { display:none !important; }
.live__trang-so { font-size:13px; color:var(--text-secondary,#8A8A8A); min-width:150px;
                  text-align:center; }
.live__tran-xem { margin:2px 0 0; text-align:center; font-size:12.5px;
                  color:var(--text-secondary,#8A8A8A); line-height:1.55; }
.live__tran-xem[hidden] { display:none !important; }
/* Vùng chạm ≥44px kể cả khi nút cao 32px — luật cứng, không đổi vì bố cục. */
@media (hover:none) {
  .live__trang .btn { position:relative; }
  .live__trang .btn::after { content:''; position:absolute; inset:-7px; }
}
@media (max-width:720px) { .live__trang { display:none; } }

/* Thu menu xong thì nội dung nở ra — nhưng PHẢI còn lề. Sát mép màn hình đọc
   rất mỏi mắt, và ô hình dính vào cạnh trông như bị cắt. */
.shell.is-thu .content { padding-left:40px; padding-right:40px; }
@media (max-width:900px) { .shell.is-thu .content { padding-left:16px; padding-right:16px; } }

/* =====================================================================
 * THANH NÚT — gọn, nhẹ, không chiếm chỗ của hình
 * ===================================================================== */
.live__btn { gap:6px; min-height:36px; padding:0 13px; font-size:13px;
  border-color:var(--border-strong); position:relative; }
.live__btn svg { width:16px; height:16px; }
.live__bar { gap:7px; }
/* Vùng chạm vẫn ≥44px trên điện thoại dù nút nhỏ đi — luật a11y không nhượng bộ. */
@media (hover:none) { .live__btn::after { content:''; position:absolute; inset:-5px; } }
@media (max-width:640px) { .live__btn span { display:none; } .live__btn { padding:0 11px; } }

/* Mic SỐNG: vòng sáng nở theo giọng nói, ngay trên icon */
.live__btn.is-song { border-color:#16A34A; color:#15803D; }
.live__btn.is-song::before { content:''; position:absolute; left:9px; top:50%;
  width:18px; height:18px; margin-top:-9px; border-radius:50%;
  background:#16A34A; opacity:calc(var(--song, 0) * .35);
  transform:scale(calc(1 + var(--song, 0) * .9)); pointer-events:none; }
@media (prefers-reduced-motion:reduce) { .live__btn.is-song::before { transform:none; } }
.live__btn:disabled { opacity:.5; cursor:not-allowed; }

/* =====================================================================
 * VẠCH MIC TRÊN TỪNG Ô — góc phải dưới, ai cũng thấy ai đang nói
 * ===================================================================== */
.live__vu { position:absolute; right:8px; bottom:8px; display:flex; align-items:flex-end;
  gap:2px; height:16px; padding:4px 6px; border-radius:6px; background:rgba(0,0,0,.55); }
.live__vu i { width:3px; border-radius:2px; background:rgba(255,255,255,.35); }
.live__vu i:nth-child(1){height:5px} .live__vu i:nth-child(2){height:9px}
.live__vu i:nth-child(3){height:13px} .live__vu i:nth-child(4){height:16px}
.live__vu i.is-sang { background:#22C55E; }

/* Nút tắt mic của một người — chỉ chủ phòng thấy */
.live__tat-mic { position:absolute; right:8px; top:8px; width:30px; height:30px;
  display:flex; align-items:center; justify-content:center; border-radius:8px;
  border:1px solid rgba(255,255,255,.25); background:rgba(0,0,0,.55); color:#FFD9D9;
  cursor:pointer; opacity:0; transition:opacity .15s ease; }
.live__tile:hover .live__tat-mic, .live__tat-mic:focus-visible { opacity:1; }
/* 🔴 opacity:0 tới khi rê chuột = KHÔNG TỒN TẠI trên điện thoại (luật giao diện #1). */
@media (hover:none) { .live__tat-mic { opacity:1; }
  .live__tat-mic::after { content:''; position:absolute; inset:-7px; } }
.live__tat-mic[hidden] { display:none; }

/* Nút "…" của ô người — cùng luật hiện/ẩn với nút tắt mic ngay trên.
   Đặt cạnh nó (right:44px) chứ không chồng lên: hai nút đè nhau thì cú bấm rơi
   vào nút nằm trên và người dùng không hiểu vì sao bấm "tắt mic" lại ra menu. */
.live__o-menu { position:absolute; right:44px; top:8px; width:30px; height:30px;
  display:flex; align-items:center; justify-content:center; border-radius:8px;
  border:1px solid rgba(255,255,255,.25); background:rgba(0,0,0,.55); color:#EDEDED;
  cursor:pointer; opacity:0; transition:opacity .15s ease; }
.live__tile:hover .live__o-menu, .live__o-menu:focus-visible,
.live__o-menu[aria-expanded="true"] { opacity:1; }
/* 🔴 opacity:0 tới khi rê chuột = KHÔNG TỒN TẠI trên điện thoại (luật giao diện #1). */
@media (hover:none) { .live__o-menu { opacity:1; }
  .live__o-menu::after { content:''; position:absolute; inset:-7px; } }
.live__o-menu[hidden] { display:none; }

/* =====================================================================
 * TOÀN MÀN HÌNH — căn giữa cân đối bốn phía, hình lấp đầy
 * ===================================================================== */
.live.is-to { padding:20px 24px 16px; gap:14px; justify-content:center; }
/* 🔴 GIỮ NGUYÊN KHUNG 16:9 khi phóng to — Founder chốt 21/08/2026.
   Kéo giãn cho lấp đầy màn hình thì khung méo và hình bị cắt mất mép. Việc cần
   làm chỉ là CĂN GIỮA: bó chiều rộng lưới sao cho vừa đúng chiều cao còn lại,
   rồi để `margin:auto` đưa nó vào giữa cả bốn phía. */
.live.is-to .live__grid { --con-lai:calc(100vh - 160px);
  max-height:none; height:auto; width:100%; margin:auto;
  align-content:center; justify-content:center; padding:0; background:transparent; }
.live.is-to .live__tile { aspect-ratio:16/9; height:auto; }
/* Bó theo đúng số cột × số hàng đang dùng. Một hàng: rộng = cao × 16/9 × số cột.
   Hai hàng: mỗi hàng chỉ được nửa chiều cao (trừ khe hở 10px giữa hai hàng).
   🔴 Năm dòng cũ ở đây dò `[style*="--cot:1"]` nên CHƯA TỪNG CHẠY (xem giải
   thích dài ở khối lưới phía trên). Nghĩa là tính năng "toàn màn hình vẫn giữ
   16:9, chỉ căn giữa" — thứ Founder chốt 21/08 — thực tế chưa bao giờ có hiệu
   lực. Một công thức var() dưới đây tái lập ĐÚNG cả năm trường hợp cũ. */
.live.is-to .live__grid {
  /* max(280px, …): xem lý do ở khối lưới thường — cửa sổ quá thấp thì phép trừ
     ra âm và ô co về 0. Toàn màn hình trừ ít hơn (160px) nên hiếm gặp hơn,
     nhưng để hai chỗ khác luật là ngày nào đó lệch nhau. */
  max-width:max(280px, calc((var(--con-lai) - (var(--hang, 1) - 1) * 10px)
                 / var(--hang, 1) * 1.7778 * var(--cot, 1)));
}
.live.is-to .live__bar { padding-bottom:4px; }


/* Ô báo tiếng — MỘT chỗ, HAI màu, cả lớp đọc được từ xa:
   ĐỎ + mic gạch chéo = đang tắt   ·   XANH nhảy theo giọng = đang nói. */
.live__vu-tat { display:none; color:#fff; line-height:0; }
.live__vu.is-tat { background:#DC2626; padding:5px 7px; }
.live__vu.is-tat .live__vu-tat { display:block; }
.live__vu.is-tat i { display:none; }

/* 🔴 PHÓNG TO + ĐANG CHIA SẺ — phải khai riêng, không thì hai bộ quy tắc chọi nhau.
   `.live.is-to .live__tile` và `.live__grid.is-chia-se .live__tile` cùng ba lớp
   nên NGANG ĐIỂM; bộ viết sau trong file thắng, và nó áp tỉ lệ 16:9 lên ô màn
   hình đang chia sẻ — khuôn vỡ, hình biến mất. (Founder báo 21/08/2026.)
   Khai tường minh ở đây để bộ "đang chia sẻ" luôn thắng khi cả hai cùng bật. */
.live.is-to .live__grid.is-chia-se {
  max-width:none; width:100%; height:100%;
  grid-template-columns:minmax(0,1fr) 8px var(--live-dai, 260px);
  grid-template-rows:minmax(0,1fr);
  align-content:stretch;
}
/* 🔴 Khối này phải nhắc lại ĐÚNG ba cột của khối thường. Bỏ sót nó thì phóng to
   lúc đang chia sẻ sẽ quay về lưới 4 hàng cũ: vạch kéo rơi vào cột 2 và mặt mọi
   người bị bóp còn 8px — đúng lỗi đã sửa ở khối trên, tái diễn ở chế độ phóng to. */
.live.is-to .live__grid.is-chia-se > .live__tile { aspect-ratio:16/9; height:auto; grid-column:3; }
.live.is-to .live__grid.is-chia-se > .live__tile.is-man-chinh {
  grid-column:1; grid-row:1; aspect-ratio:auto; height:100%; }
@media (max-width:720px) {
  .live.is-to .live__grid.is-chia-se {
    grid-template-columns:minmax(0,1fr);
    grid-template-rows:minmax(0,1fr) 84px; }
  .live.is-to .live__grid.is-chia-se .live__tile { grid-column:1; grid-row:2; aspect-ratio:auto; height:100%; }
  .live.is-to .live__grid.is-chia-se .live__tile.is-man-chinh { grid-column:1; grid-row:1; }
}

/* ── Dòng "đang nghe" — gom người tắt camera (os-app.js → gomNguoiNghe) ──
   Lớp 30 người mà một người bật camera thì 29 ô đen chiếm hết màn hình và bóp
   nhỏ đúng cái ô cần nhìn. Gom lại thành một dòng chữ.
   🔴 Ô bị gom dùng `display:none` — ở ĐÂY thì đúng, vì ta MUỐN nó rời khỏi lưới
   để lưới co lại. (Khác trường hợp đã trả giá trong CE8: ẩn một ô mà vẫn muốn
   giữ khuôn 3 cột thì phải bóp `width:0`, không được gỡ.) */
.live__tile.is-gom { display:none; }

.live__nghe { display:flex; align-items:center; gap:8px; width:100%;
  margin-top:8px; padding:9px 12px; border:1px solid var(--border,#242427);
  border-radius:10px; background:transparent; color:var(--muted,#8A8A8A);
  font:inherit; font-size:13px; text-align:left; cursor:pointer;
  min-height:38px;   /* vùng chạm — luật giao diện số 3 */ }
.live__nghe:hover { filter:brightness(.97); }
.live__nghe:focus-visible { outline:2px solid var(--accent,#cc6600); outline-offset:2px; }
.live__nghe span { flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.live__nghe b { color:var(--text,#EDEDED); font-weight:600; }
.live__nghe em { flex:0 0 auto; font-style:normal; font-weight:700;
  padding:1px 8px; border-radius:999px; background:rgba(204,102,0,.14); color:var(--accent-hover,#a35200); }
/* Mở rộng: hiện hết tên, cho xuống dòng */
.live__nghe[aria-expanded="true"] span { white-space:normal; overflow:visible; }

/* ── TRÒ CHUYỆN TRONG BUỔI (os-app.js → khối chat) ─────────────────────
   Đường duy nhất để học viên lên tiếng khi không chen lời được. */
/* 🔴 `hidden` THUA MỌI LUẬT `display` CỦA MÌNH — Founder báo 22/08/2026:
 * "dấu X chưa hoạt động".
 *
 * Nút X chạy đúng: nó đặt `oNgan.hidden = true`. Nhưng thuộc tính `hidden` chỉ
 * được trình duyệt cho `display:none` ở mức thấp nhất (`[hidden]{display:none}`
 * trong stylesheet mặc định). Bất kỳ luật nào của mình có `display` — ở đây là
 * `.live__chat{display:flex}` — đều THẮNG nó. Nên bấm X thì cờ đổi mà khung
 * vẫn nằm nguyên đó.
 *
 * Cùng họ với bẫy CE8: mã sửa đúng, nhưng thứ đang chạy đè lên nó.
 * Quét cả phòng họp 22/08 thấy SÁU lớp dính: live__bar · live__btn · live__cham
 * · live__chat · live__doi · live__nghe. `live__btn` là cái đáng lo nhất — nút
 * đánh dấu ẩn (vd nút chỉ dành cho chủ phòng) vẫn hiện ra cho mọi người.
 *
 * Một luật dưới đây đóng cả sáu, và mọi lớp thêm sau này. */
.live [hidden], .live__chat[hidden] { display:none !important; }

.live__chat { position:absolute; right:12px; bottom:76px; z-index:5;
  width:min(340px, calc(100vw - 24px)); max-height:min(60vh, 460px);
  display:flex; flex-direction:column;
  background:var(--surface,#fff); border:1px solid var(--border,#E5E2DC);
  border-radius:12px; box-shadow:0 8px 28px rgba(0,0,0,.14); overflow:hidden; }
/* Kéo thả · đổi kích thước · phóng to — Founder chốt 22/08/2026.
   Trước đây khung đóng đinh góc phải dưới và che đúng chỗ slide cần nhìn.
   `resize:both` là bản gốc của trình duyệt: đúng vùng chạm, đúng con trỏ, chạy
   được cả trên máy cảm ứng — không tự dựng tay nắm cho thêm việc. */
.live__chat { resize:both; min-width:250px; min-height:200px;
  max-width:min(92vw, 900px); max-height:88vh; }
.live__chat.is-keo { user-select:none; box-shadow:0 14px 40px rgba(0,0,0,.22); }
/* Phóng to: chiếm gần trọn khung phòng, bỏ mọi kích thước tự đặt. */
.live__chat.is-to { inset:12px; left:12px; top:12px; right:12px; bottom:12px;
  width:auto; height:auto; max-width:none; max-height:none; resize:none; }
/* Toast kèm nút — cho việc cần quyết mà không được chặn người dùng.
   Rộng hơn toast thường vì có cả câu lẫn nút; nút không được xuống dòng. */
.toast--nut { display:flex; align-items:center; gap:12px; max-width:min(92vw, 460px);
  padding-right:10px; }
.toast--nut button { flex:0 0 auto; }

.live__chat-nut { display:flex; align-items:center; gap:2px; flex:0 0 auto; }

.live__chat-dau { display:flex; align-items:center; justify-content:space-between;
  padding:10px 12px; border-bottom:1px solid var(--border,#E5E2DC); flex:0 0 auto;
  cursor:move; touch-action:none; }
.live__chat-dau:focus-visible { outline:2px solid var(--accent,#cc6600); outline-offset:-2px; }
.live__chat-dong { border:0; background:transparent; cursor:pointer; padding:6px;
  border-radius:8px; color:var(--text-2,#6B6B6B); min-width:34px; min-height:34px; }
.live__chat-dong:hover { background:#f2f1ee; }
.live__chat-dong:focus-visible { outline:2px solid var(--accent,#cc6600); outline-offset:2px; }
.live__chat-than { flex:1 1 auto; overflow-y:auto; overscroll-behavior:contain;
  padding:10px 12px; display:flex; flex-direction:column; gap:9px; min-height:80px; }
.live__chat-trong { margin:0; color:var(--text-2,#6B6B6B); font-size:13px; }
.live__tin { display:grid; grid-template-columns:1fr auto; gap:2px 8px; }
.live__tin-ten { font-size:12px; font-weight:600; color:var(--text,#171717); min-width:0;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.live__tin-gio { font-size:11px; color:var(--text-2,#6B6B6B); }
.live__tin-noi { grid-column:1 / -1; margin:0; font-size:13.5px; line-height:1.45;
  /* Tin dài, dán link, hay gõ một chuỗi không dấu cách — đều phải xuống dòng,
     không được đẩy ngang làm vỡ khung. */
  overflow-wrap:anywhere; word-break:break-word; }
.live__tin.is-toi .live__tin-ten { color:var(--accent-hover); }
.live__chat-go { flex:0 0 auto; display:flex; gap:8px; padding:10px 12px;
  border-top:1px solid var(--border,#E5E2DC); }
.live__chat-go input { flex:1 1 auto; min-width:0; font:inherit; font-size:13.5px;
  padding:8px 10px; border:1px solid var(--border,#E5E2DC); border-radius:8px;
  background:var(--surface,#fff); color:var(--text,#171717); min-height:38px; }
.live__chat-go input:focus-visible { outline:2px solid var(--accent,#cc6600); outline-offset:1px; }
.live__chat-go button { flex:0 0 auto; min-height:38px; min-width:42px; }

/* Huy hiệu số tin chưa đọc trên nút Trò chuyện. */
.live__chua-doc { position:absolute; top:2px; right:2px; min-width:17px; height:17px;
  padding:0 4px; border-radius:99px; background:var(--accent,#cc6600); color:#fff;
  font-size:10.5px; font-weight:700; line-height:17px; text-align:center; }
#lv-chat { position:relative; }
/* 🔴 `#lv-them` PHẢI `position:relative` — thêm 04/09/2026 cùng lúc chuyển Giơ
   tay vào menu. `.live__chua-doc` là `position:absolute`, nên nó neo vào tổ tiên
   có định vị GẦN NHẤT. Không có dòng này thì tổ tiên ấy là `.live__them` — cái
   bọc chứa CẢ nút lẫn menu. Hôm nay menu là `position:absolute` nên hộp bọc vừa
   đúng bằng nút và huy hiệu rơi đúng chỗ; nhưng ngày nào menu đổi cách bố trí,
   huy hiệu sẽ trôi đi mà không ai hiểu vì sao. Neo thẳng vào nút. */
#lv-them { position:relative; }

@media (max-width:720px) {
  /* Điện thoại: ngăn chat trải gần hết bề ngang, nằm sát trên thanh công cụ để
     ngón cái với tới. Không dùng position:fixed — bàn phím ảo đẩy khung lên và
     fixed sẽ nằm sai chỗ. */
  .live__chat { right:8px; left:8px; bottom:70px; width:auto;
    max-height:min(56vh, 380px);
    /* 🔴 Điện thoại: KHÔNG kéo, KHÔNG đổi kích thước. Khung đã trải gần hết bề
       ngang nên kéo đi chỉ làm nó lọt ra ngoài, mà tay nắm resize thì đè lên ô
       nhập tin. Nút phóng to vẫn còn — đó mới là thứ cần trên màn hình hẹp. */
    resize:none; max-width:none; min-width:0; }
  .live__chat-dau { cursor:default; }
  /* Vị trí do JS đặt (kéo trên máy tính) không được theo sang điện thoại khi
     xoay máy hoặc thu cửa sổ — nếu không khung nằm chết ngoài màn hình. */
  .live__chat[style] { left:8px !important; right:8px !important; top:auto !important;
    bottom:70px !important; width:auto !important; height:auto !important; }
  .live__chat.is-to[style] { inset:8px !important; width:auto !important; height:auto !important; }
}

/* ── Giơ tay (os-app.js → veTay) ────────────────────────────────────────
   Huy hiệu ✋ trên ô người đang giơ tay. Đặt góc TRÊN-TRÁI vì góc dưới đã có
   tên người và ô báo micro — chồng lên nhau thì cái sau vẽ đè cái trước và
   người dạy mất một trong hai thông tin (bài học 21/08). */
.live__tile.is-gio-tay::before {
  content:"✋"; position:absolute; top:7px; left:7px; z-index:3;
  width:26px; height:26px; border-radius:8px;
  display:flex; align-items:center; justify-content:center;
  background:var(--accent, #cc6600); color:#fff; font-size:14px; line-height:1;
  box-shadow:0 1px 4px rgba(0,0,0,.35);
}
/* Viền cam quanh ô để nhìn từ xa cũng thấy — huy hiệu 26px dễ lọt thỏm khi
   lớp đông và mỗi ô chỉ còn bằng con tem. */
.live__tile.is-gio-tay { box-shadow:inset 0 0 0 2px var(--accent, #cc6600); }

/* Nút đang bật — dùng chung kiểu với các nút khác của thanh công cụ. */
.live__btn.is-on { background:var(--accent, #cc6600); border-color:var(--accent, #cc6600); color:#fff; }
.live__btn.is-on svg { stroke:#fff; }

/* =====================================================================
   HỘP NỔI XEM BÀI VIẾT (2026-08-26)
   Founder: "bấm vào card xem bài đăng phải hiện card xem đầy đủ nội dung và
   hình ảnh bài đăng" — và trước đó: "bấm mãi ko ra".
   ===================================================================== */

/* Cả thẻ là một nút bấm ⇒ con trỏ phải NÓI ra điều đó (`cursor:pointer` gộp
   thẳng vào lần khai `.post--m` ở dòng ~1269).
   🔴 KHÔNG khai `.post--m{}` lần nữa ở đây: phép kiểm "hai khối @media cùng gác
   một selector" đã bắt đúng em lúc thử — `.post--m` vốn đã có 2 lần khai (bản
   nền + bản trong @media), thêm lần thứ ba là chỗ để một luật âm thầm đè luật
   kia, và nhìn màn hình thì không thấy gì sai. */
/* Phản hồi khi rê chuột.
   🔴 Bản đầu của em đổi `border-color` — VÔ TÁC DỤNG, và em chỉ biết khi đọc
   lại `.post--m`: nó mang `border:0`, chỉ còn đúng `border-bottom`. Đổi màu
   viền ở đó thì mỗi đường kẻ đáy đổi màu, đọc như lỗi vẽ chứ không như phản hồi.
   Nay đổi NỀN bằng token có sẵn `--surface-muted` (#F3F3F1 trên nền #F7F7F5) —
   khác vừa đủ để mắt bắt được, không đủ để chói.
   Bọc trong `hover:hover` để trên điện thoại không kẹt trạng thái rê sau khi
   chạm — màn cảm ứng không có sự kiện "rời chuột". */
@media (hover:hover){
  .post--m:hover{background:var(--surface-muted)}
}
/* Con trỏ mặc định trở lại ở những chỗ KHÔNG mở bài — nếu để nguyên bàn tay,
   người ta tưởng bôi đen chữ cũng sẽ nhảy trang. */
.post--m .pm-excerpt{cursor:auto}

/* Hộp: rộng hơn hộp thoại thường nhiều, vì đây là chỗ ĐỌC chứ không phải chỗ
   điền form. 880px ≈ bề ngang một trang sách mở — dài hơn nữa thì mắt phải quét
   ngang quá xa và dễ nhảy dòng. */
.modal--baiviet{max-width:880px}
/* Đầu hộp dính trên: bài dài vài nghìn chữ mà nút ✕ trôi mất theo thì người đọc
   phải cuộn ngược lên đầu mới đóng được. */
.modal--baiviet .bv-head{position:sticky;top:0;z-index:2;background:var(--surface)}
.bv-head__t{font-size:14px;color:var(--text-muted);font-weight:600}
.bv-head__mo{margin-left:auto}
.bv-body{padding:20px}
/* Khối bài + khối bình luận bên trong hộp: KHÔNG mang viền thẻ. Hộp đã là một
   tấm thẻ rồi — lồng thêm thẻ nữa là hai lần viền, hai lần bóng (anti-pattern
   R11: card lồng trong card). */
.bv-khoi{background:transparent;border:0;padding:0}
.bv-khoi--cmt{margin-top:22px;padding-top:18px;border-top:1px solid var(--border)}

@media (max-width:640px){
  /* Trên điện thoại, hộp chiếm gần trọn màn hình: viền và bo góc lúc này chỉ ăn
     mất chỗ đọc chứ không nói thêm điều gì.

     🔴 `:has()` chứ KHÔNG phải `.overlay{padding:0}` trơn. Bản đầu của em viết
     trơn, và nó áp cho MỌI hộp thoại trong app — hộp xác nhận xoá, hộp sửa
     bình luận, hộp mời thành viên… tất cả mất lề trên điện thoại. Một dòng CSS
     viết cho một màn hình đi phá mười màn hình khác, và không test nào bắt được
     vì chẳng test nào nói về lề của hộp xác nhận.
     `.overlay` không mang class riêng nào (hàm `modal()` chỉ gắn `opts.cls` vào
     `.modal` bên trong), nên `:has()` là cách khoanh đúng mà không phải sửa
     `modal()` — một hàm đang phục vụ hàng chục chỗ khác.
     Trình duyệt cũ không hiểu `:has()` thì luật này im lặng không chạy: hộp giữ
     lề 20px như cũ. Hụt một chút chỗ đọc, KHÔNG vỡ gì. */
  .overlay:has(.modal--baiviet){padding:0}
  /* `dvh` trước, `vh` sau làm nền: trên Safari/Chrome điện thoại, `100vh` tính
     theo màn hình lúc thanh công cụ ĐÃ THU — nên đáy hộp (chỗ có ô gõ bình
     luận) bị thanh công cụ che mất. `dvh` co giãn theo thanh đó. */
  .modal--baiviet{max-height:100vh;max-height:100dvh;height:100%;border:0;border-radius:0}
  .bv-body{padding:14px}
}


/* ===== CHĂM SÓC CỘNG ĐỒNG =================================================
   Dùng lại token và component sẵn có (.card .btn .pill .stat .empty .skeleton).
   Nhịp khoảng cách theo bội số 8px. Không đặt màu cứng — mọi màu đi qua token,
   để đổi theme một lần là đổi cả trang.

   🔴 Sắc ĐỎ chỉ dành cho "quá hạn" và việc phá huỷ. Việc GẤP dùng sắc cam của
      thương hiệu. Nếu mọi thứ đều đỏ thì không còn gì là gấp — mắt sẽ học cách
      bỏ qua màu đỏ, đúng lúc ta cần nó nhất. */

.csoc {max-width:1100px;margin:0 auto;padding:0 0 40px}

/* --- Header --- */
.csoc-h{margin-bottom:24px}
.csoc-h h1{margin:0 0 4px;font-size:var(--fs-xl);line-height:var(--lh-tight)}
.csoc-h__phu{margin:0;color:var(--text-secondary);font-size:var(--fs-sm)}

/* --- Bốn thẻ số liệu --- */
.csoc-kpi{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(148px,1fr));margin-bottom:24px}
.csoc-kpi .stat{display:flex;flex-direction:column;gap:2px;position:relative;overflow:hidden}
.csoc-kpi__so{font-size:var(--fs-2xl);font-weight:700;line-height:1.1;color:var(--text-primary);
  font-variant-numeric:tabular-nums}
.csoc-kpi__ten{font-size:var(--fs-xs);color:var(--text-muted);font-weight:500}
/* Một vạch mảnh ở mép trái nói ý nghĩa của con số — đủ để phân biệt, không đủ
   để biến bảng số liệu thành đèn giao thông. */
.csoc-kpi .stat::before{content:'';position:absolute;left:0;top:0;bottom:0;width:3px;background:transparent}
.csoc-kpi__gap::before{background:var(--accent)}
.csoc-kpi__qua::before{background:var(--danger)}
.csoc-kpi__hoan::before{background:var(--text-disabled)}
.csoc-kpi__can::before{background:var(--text-secondary)}

/* --- Thanh bộ lọc --- */
.csoc-bar{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:16px}
.csoc-search{
  flex:1 1 240px;min-width:0;max-width:360px;display:flex;align-items:center;gap:8px;
  background:var(--surface);border:1px solid var(--border-strong);border-radius:var(--radius-md);
  padding:9px 12px;transition:.14s;
}
.csoc-search:focus-within{border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-soft)}
.csoc-search__ic{color:var(--text-muted);display:grid;place-items:center;flex:0 0 auto}
.csoc-search input{flex:1;min-width:0;background:none;border:none;outline:none;
  color:var(--text-primary);font-size:var(--fs-sm);font-family:inherit}
.csoc-search input::placeholder{color:var(--text-muted)}
.csoc-search input::-webkit-search-cancel-button{-webkit-appearance:none;appearance:none}

/* Ô chọn: bỏ mũi tên mặc định của trình duyệt, tự vẽ để mọi máy giống nhau. */
.csoc-sel{position:relative;flex:0 0 auto}
.csoc-sel select{
  -webkit-appearance:none;appearance:none;
  background:var(--surface);border:1px solid var(--border-strong);border-radius:var(--radius-md);
  padding:9px 30px 9px 12px;color:var(--text-primary);font-size:var(--fs-sm);font-family:inherit;
  outline:none;cursor:pointer;transition:.14s;max-width:190px;
}
.csoc-sel select:hover{background:var(--surface-muted)}
.csoc-sel select:focus{border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-soft)}
.csoc-sel__mui{position:absolute;right:9px;top:50%;transform:translateY(-50%);
  pointer-events:none;color:var(--text-muted);display:grid;place-items:center}
.csoc-bar__reset{margin-left:auto}
.csoc-bar__loc{display:none}

/* --- Danh sách --- */
.csoc-ds{display:flex;flex-direction:column;gap:12px}

/* --- Một việc cần xử lý --- */
.csoc-item{
  padding:16px;display:grid;gap:8px;position:relative;transition:box-shadow .14s,border-color .14s;
  grid-template-columns:1fr auto;
}
.csoc-item:hover{box-shadow:var(--shadow-card)}
.csoc-item:focus-within{box-shadow:0 0 0 3px var(--accent-soft),var(--shadow-card)}
.csoc-item.dang-chon{border-color:var(--accent-border);box-shadow:0 0 0 2px var(--accent-soft)}
.csoc-item.dang-xu-ly{opacity:.6;pointer-events:none}
.csoc-item.xong{opacity:.55}
.csoc-item__top{grid-column:1/-1;display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.csoc-item__h{
  grid-column:1/2;margin:0;font-size:var(--fs-md);font-weight:650;line-height:1.35;
  color:var(--text-primary);
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;
}
.csoc-item__xt{
  grid-column:1/2;margin:0;color:var(--text-secondary);font-size:var(--fs-sm);
  line-height:var(--lh-normal);
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;
}
.csoc-item__meta{grid-column:1/2;display:flex;align-items:center;gap:8px;flex-wrap:wrap;
  font-size:var(--fs-xs);color:var(--text-muted)}
.csoc-item__cham{opacity:.5}
.csoc-ava{
  width:22px;height:22px;border-radius:50%;flex:0 0 auto;display:grid;place-items:center;
  background:var(--surface-muted);color:var(--text-secondary);
  font-size:10px;font-weight:700;border:1px solid var(--border-card);
}
.csoc-item__act{grid-column:2/3;grid-row:2/5;display:flex;align-items:flex-start;gap:6px;
  align-self:start;flex:0 0 auto}

/* Nhãn độ gấp — dùng .pill, chỉ đổi sắc. */
.csoc-gap--cao{background:var(--accent-soft);color:var(--accent-hover);border-color:var(--accent-border)}
.csoc-gap--vua{background:var(--surface-muted);color:var(--text-secondary)}
.csoc-gap--thap{background:transparent;color:var(--text-muted);border-color:var(--border-card)}
.csoc-tt--open{background:var(--surface-muted);color:var(--text-secondary)}
.csoc-tt--in_progress{background:var(--accent-soft);color:var(--accent-hover);border-color:var(--accent-border)}
.csoc-tt--resolved{background:var(--success-soft);color:var(--success-strong);border-color:var(--success-border)}
.csoc-tt--snoozed{background:var(--surface-muted);color:var(--text-muted)}
.csoc-qua{background:var(--danger-soft);color:var(--danger);border-color:var(--danger)}
.csoc-loai{color:var(--text-muted);font-size:var(--fs-xs)}

/* --- Menu ⋯ --- */
.csoc-menu{position:relative}
.csoc-menu__nut{
  width:34px;height:34px;border-radius:10px;border:1px solid var(--border);background:var(--surface);
  color:var(--text-primary);font-size:17px;display:grid;place-items:center;transition:.14s;
}
.csoc-menu__nut:hover{background:var(--surface-muted)}
.csoc-menu__nut:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.csoc-menu__ds{
  position:absolute;right:0;top:calc(100% + 6px);min-width:210px;z-index:40;
  background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-md);
  box-shadow:var(--shadow-pop);padding:6px;display:none;
}
.csoc-menu.mo .csoc-menu__ds{display:block}
.csoc-menu__muc{
  display:flex;align-items:center;gap:9px;width:100%;text-align:left;padding:9px 11px;
  border-radius:9px;font-size:var(--fs-sm);font-weight:600;color:var(--text-primary);
  background:none;border:none;transition:.12s;
}
.csoc-menu__muc:hover{background:var(--surface-muted)}
.csoc-menu__muc:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}
.csoc-menu__muc--xong{color:var(--success-strong)}
.csoc-menu__muc--xong:hover{background:var(--success-soft)}
.csoc-menu__vach{height:1px;background:var(--border-card);margin:5px 4px}

/* --- Ngăn kéo chi tiết --- */
.csoc-nen{
  position:fixed;inset:0;background:rgba(0,0,0,.28);z-index:80;opacity:0;pointer-events:none;
  transition:opacity .18s;
}
.csoc-nen.mo{opacity:1;pointer-events:auto}
.csoc-ngan{
  position:fixed;top:0;right:0;bottom:0;width:min(560px,100vw);z-index:81;
  background:var(--surface);border-left:1px solid var(--border);box-shadow:var(--shadow-pop);
  display:flex;flex-direction:column;transform:translateX(100%);transition:transform .2s;
}
.csoc-ngan.mo{transform:none}
.csoc-ngan__dau{
  display:flex;align-items:flex-start;gap:12px;padding:16px 20px;
  border-bottom:1px solid var(--border-card);flex:0 0 auto;
}
.csoc-ngan__ten{margin:0;font-size:var(--fs-lg);line-height:var(--lh-tight);flex:1;min-width:0}
.csoc-ngan__dong{
  width:34px;height:34px;border-radius:10px;border:1px solid var(--border);background:var(--surface);
  color:var(--text-primary);display:grid;place-items:center;flex:0 0 auto;transition:.14s;
}
.csoc-ngan__dong:hover{background:var(--surface-muted)}
.csoc-ngan__than{flex:1;overflow-y:auto;padding:16px 20px;-webkit-overflow-scrolling:touch}
.csoc-ngan__chan{
  display:flex;align-items:center;gap:8px;padding:14px 20px;flex:0 0 auto;
  border-top:1px solid var(--border-card);background:var(--surface);flex-wrap:wrap;
}
.csoc-ngan__chan .btn--primary{flex:1;justify-content:center;min-width:150px}
.csoc-ngan__tt{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:14px}
.csoc-ngan__nd{
  font-size:var(--fs-sm);line-height:var(--lh-relaxed);color:var(--text-primary);
  white-space:pre-wrap;word-break:break-word;
}
.csoc-ngan__muc{margin:20px 0 8px;font-size:var(--fs-sm);font-weight:650;color:var(--text-secondary)}

/* Dòng thời gian: việc đã xảy ra với mục này. */
.csoc-tl{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:10px}
.csoc-tl li{display:flex;gap:10px;align-items:flex-start;font-size:var(--fs-xs);color:var(--text-secondary)}
.csoc-tl__cham{width:8px;height:8px;border-radius:50%;background:var(--border-strong);
  margin-top:5px;flex:0 0 auto}
.csoc-tl li.nay .csoc-tl__cham{background:var(--accent)}

/* --- Bình luận trong ngăn kéo --- */
.csoc-bl{padding:10px 0;border-bottom:1px solid var(--border-card)}
.csoc-bl:last-child{border-bottom:none}
.csoc-bl--go{opacity:.55}
.csoc-bl__meta{font-size:var(--fs-xs);color:var(--text-muted);margin-bottom:4px}
.csoc-bl__than{font-size:var(--fs-sm);line-height:var(--lh-normal);white-space:pre-wrap;
  word-break:break-word}
.csoc-bl__act{margin-top:6px}
.csoc-dago{margin-top:18px}
.csoc-dago h3{font-size:var(--fs-sm);color:var(--text-muted);margin:0 0 8px}

/* --- Trang đầy đủ của một luồng (đường dẫn đã lưu vẫn sống) --- */
.csoc--luong{max-width:860px}
.csoc-bai{margin:14px 0}
.csoc-bai h1{margin:0 0 8px;font-size:var(--fs-2xl);line-height:var(--lh-tight)}
.csoc-bai__than{margin-top:12px;font-size:var(--fs-base);line-height:var(--lh-relaxed);
  white-space:pre-wrap;word-break:break-word}
.csoc-h2{margin:22px 0 10px;font-size:var(--fs-lg)}
.csoc-soan{margin-top:18px}
.csoc-soan h3{margin:0 0 10px;font-size:var(--fs-base)}
.csoc-soan__act{display:flex;gap:8px;margin-top:10px;flex-wrap:wrap}
.csoc-nhap{width:100%;resize:vertical;background:var(--surface);
  border:1px solid var(--border-strong);border-radius:var(--radius-md);padding:11px 13px;
  color:var(--text-primary);font-size:var(--fs-base);font-family:inherit;outline:none}
.csoc-nhap:focus{border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-soft)}
.csoc-xt {margin-top:12px;padding:12px;border-radius:var(--radius-md);
  /* Viền ĐỨT là cố ý: khối xem trước phải nhìn khác hẳn ô soạn, nếu không người
     ta tưởng đang đọc lại chỗ vừa gõ rồi bấm Đăng mà chưa thật sự xem. */
  background:var(--surface-muted);border:1px dashed var(--border-strong)}
.csoc-xt__nhan{font-size:var(--fs-xs);font-weight:600;color:var(--text-muted);margin-bottom:6px}
.csoc-ghi{margin-top:10px;font-size:var(--fs-xs);color:var(--text-muted)}

/* --- Phân trang --- */
.csoc-trang{display:flex;align-items:center;justify-content:center;gap:12px;margin-top:20px;
  font-size:var(--fs-sm);color:var(--text-secondary)}

/* --- Trạng thái: đang tải --- */
.csoc-tai{display:flex;flex-direction:column;gap:12px}
.csoc-tai__the{border:1px solid var(--border-card);border-radius:var(--radius-md);
  background:var(--surface);padding:16px;display:flex;flex-direction:column;gap:9px}
.csoc-tai__d{height:12px}
.csoc-tai__d--ngan{width:38%}
.csoc-tai__d--dai{width:82%}
.csoc-loi{border-left:3px solid var(--danger);background:var(--danger-soft)}

/* --- Máy tính bảng và điện thoại --- */
@media (max-width:900px){
  .csoc-bar__loc{display:inline-flex}
  .csoc-bar__nhom{display:none;width:100%;gap:8px;flex-wrap:wrap}
  .csoc-bar__nhom.mo{display:flex}
  .csoc-sel,.csoc-sel select{width:100%;max-width:none}
  .csoc-search{max-width:none}
  .csoc-bar__reset{margin-left:0}
}
@media (max-width:640px){
  .csoc-item{grid-template-columns:1fr}
  .csoc-item__h,.csoc-item__xt,.csoc-item__meta{grid-column:1/-1}
  .csoc-item__act{grid-column:1/-1;grid-row:auto;padding-top:4px}
  .csoc-item__act .btn{flex:1;justify-content:center}
  /* Điện thoại: ngăn kéo chiếm trọn màn hình — nửa vời trên màn nhỏ thì
     vừa không đọc được nội dung, vừa không thấy hàng đợi. */
  .csoc-ngan{width:100vw;border-left:none}
  /* Trên màn hẹp: việc chính chiếm trọn một hàng, ba việc phụ chia đều hàng
     dưới — thay vì để một nút rơi lẻ xuống dòng thứ ba trông như bị bỏ quên. */
  .csoc-ngan__chan{gap:6px}
  .csoc-ngan__chan .btn--primary{flex:1 1 100%;min-width:0}
  .csoc-ngan__chan .btn--ghost{flex:1 1 0;min-width:0;justify-content:center;padding:8px 6px}
}
@media (prefers-reduced-motion:reduce){
  .csoc-ngan,.csoc-nen,.csoc-item{transition:none}
}

/* ── Học tập (Phase 4) ─────────────────────────────────────────────────────
   Dùng lại token và component có sẵn (.card .btn .pill .empty .skeleton).
   Không đặt màu cứng, không tạo ngôn ngữ thị giác thứ hai: trang này phải
   trông như cùng một sản phẩm với Feed và Chăm sóc, không phải một trang quản
   trị dán thêm. */

/* --- Header trang --- */
.hoct-hero{margin-bottom:20px}
.hoct-hero h1{margin:0 0 4px;font-size:var(--fs-xl);line-height:var(--lh-tight)}
.hoct-hero__phu{margin:0;color:var(--text-secondary);font-size:var(--fs-sm)}

/* --- Thanh công cụ: tìm + lọc --- */
.hoct-bar{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-bottom:18px}
.hoct-search{
  flex:1 1 260px;min-width:0;max-width:420px;display:flex;align-items:center;gap:9px;
  background:var(--surface);border:1px solid var(--border-strong);border-radius:var(--radius-md);
  padding:9px 13px;transition:.14s;
}
.hoct-search:focus-within{border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-soft)}
.hoct-search__ic{color:var(--text-muted);display:grid;place-items:center;flex:0 0 auto}
.hoct-search input{
  flex:1;min-width:0;background:none;border:none;outline:none;
  color:var(--text-primary);font-size:var(--fs-sm);font-family:inherit;
}
.hoct-search input::placeholder{color:var(--text-muted)}
/* Bỏ nút "x" mặc định của trình duyệt trên input[type=search] — nó không theo
   design system và mỗi trình duyệt vẽ một kiểu. */
.hoct-search input::-webkit-search-cancel-button{-webkit-appearance:none;appearance:none}
.hoct-loc{display:flex;gap:6px;flex-wrap:wrap}
/* 🔴 :not(.is-active) là bắt buộc, không phải cho gọn. Thiếu nó thì luật này
   (cùng độ đặc hiệu, đứng sau) đè mất nền accent của .pill.is-active nhưng
   KHÔNG đè color:#fff — ra chữ trắng trên nền trắng, chip biến mất khỏi màn
   hình. Đã thấy thật trong ảnh chụp 27/08. */
.hoct-loc .pill:not(.is-active){cursor:pointer;background:var(--surface);border-color:var(--border);transition:.14s}
.hoct-loc .pill{cursor:pointer}
.hoct-loc .pill:not(.is-active):hover{background:var(--surface-muted)}
.hoct-loc .pill:focus-visible{outline:2px solid var(--accent);outline-offset:2px}

/* --- Lưới thẻ khoá học --- */
.hoct-grid{display:grid;gap:16px;grid-template-columns:repeat(auto-fill,minmax(260px,1fr))}
.hoct-card{
  display:flex;flex-direction:column;padding:0;overflow:hidden;position:relative;
  transition:transform .14s,box-shadow .14s;
}
.hoct-card:hover{transform:translateY(-2px);box-shadow:var(--shadow-card)}
.hoct-card:focus-within{box-shadow:0 0 0 3px var(--accent-soft),var(--shadow-card)}

/* Ảnh bìa. Có `cover_url` thì vẽ ảnh (28/08/2026); không có thì rơi về mảng màu
   tĩnh lấy sắc từ chính id khoá — mỗi khoá một sắc ổn định, không phải màu ngẫu
   nhiên đổi mỗi lần tải. Chữ cái đầu làm mốc nhận diện thay cho ảnh. */
.hoct-cover{
  position:relative;aspect-ratio:16/9;display:grid;place-items:center;
  background:linear-gradient(135deg,var(--hoct-c1,var(--surface-muted)),var(--hoct-c2,var(--border-strong)));
  flex:0 0 auto;
}
.hoct-cover__chu{
  font-size:2.5rem;font-weight:700;line-height:1;letter-spacing:-.02em;
  color:rgba(23,23,23,.42);user-select:none;
}
/* Có ảnh thì bỏ nền chuyển sắc đi: để lại thì mép ảnh trong suốt (PNG) ăn màu
   nền, mỗi khoá một tông — trông như lỗi hiển thị. */
.hoct-cover--anh{background:var(--surface-muted)}
.hoct-cover__img{width:100%;height:100%;object-fit:cover;display:block}
.hoct-cover__tt{position:absolute;top:10px;left:10px}
.hoct-cover__tien{position:absolute;top:10px;right:10px}

.hoct-card__than{padding:14px 15px 15px;display:flex;flex-direction:column;gap:9px;flex:1}

/* ---- Đầu trang khoá học: bìa + tên + tiến độ -----------------------------
   Máy tính: hai cột (bìa trái 150px). Điện thoại: MỘT cột, bìa nằm trên.
   Ở 390px, hai cột bóp cột chữ còn ~180px và tên khoá vỡ thành từng dòng một
   hai chữ — đọc như một danh sách chứ không như một tiêu đề.

   `min-width:0` KHÔNG phải cho đẹp: mặc định `min-width:auto` của flex item
   khiến một từ dài (URL, tên khoá không dấu cách) đẩy tràn cả hàng ngang. */
.khoa-dau__bia{width:150px;aspect-ratio:16/9;height:auto;border-radius:14px;flex:0 0 auto}
.khoa-dau__than{flex:1;min-width:0}
@media (max-width:560px){
  .khoa-dau{flex-direction:column;gap:12px}
  .khoa-dau__bia{width:100%}
}
.hoct-card__ten{
  margin:0;font-size:var(--fs-md);font-weight:650;line-height:1.35;color:var(--text-primary);
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;
}
.hoct-card__meta{display:flex;align-items:center;gap:8px;flex-wrap:wrap;
  font-size:var(--fs-xs);color:var(--text-muted)}
.hoct-card__meta .hoct-cham{opacity:.55}
.hoct-card__cta{margin-top:auto;padding-top:4px}
.hoct-card__cta .btn{width:100%;justify-content:center}

/* --- Trang chi tiết: hero --- */
.hoct-khoa{position:relative;margin-bottom:20px;display:flex;gap:16px;align-items:flex-start;flex-wrap:wrap}
.hoct-khoa__anh{
  width:104px;height:104px;border-radius:var(--radius-lg);flex:0 0 auto;display:grid;place-items:center;
  background:linear-gradient(135deg,var(--hoct-c1,var(--surface-muted)),var(--hoct-c2,var(--border-strong)));
}
.hoct-khoa__anh span{font-size:2.5rem;font-weight:700;line-height:1;color:rgba(23,23,23,.42)}
.hoct-khoa__noi{flex:1 1 260px;min-width:0}
.hoct-khoa__ten{margin:0 0 8px;font-size:var(--fs-2xl);line-height:var(--lh-tight);word-break:break-word}
.hoct-khoa__tt{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:8px}
.hoct-khoa__mo{margin:0;color:var(--text-secondary);font-size:var(--fs-sm);line-height:var(--lh-normal);
  max-width:62ch}
.hoct-khoa__act{margin-left:auto;display:flex;align-items:center;gap:8px;flex:0 0 auto}

/* Menu ⋯ cho việc quản trị — không để nút thô nằm giữa trang. */
.hoct-menu{position:relative}
.hoct-menu__nut{
  width:38px;height:38px;border-radius:11px;border:1px solid var(--border);background:var(--surface);
  color:var(--text-primary);font-size:18px;display:grid;place-items:center;transition:.14s;
}
.hoct-menu__nut:hover{background:var(--surface-muted)}
.hoct-menu__nut:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.hoct-menu__ds{
  position:absolute;right:0;top:calc(100% + 6px);min-width:216px;z-index:40;
  background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-md);
  box-shadow:var(--shadow-pop);padding:6px;display:none;
}
.hoct-menu.mo .hoct-menu__ds{display:block}
.hoct-menu__muc{
  display:flex;align-items:center;gap:9px;width:100%;text-align:left;
  padding:9px 11px;border-radius:9px;font-size:var(--fs-sm);font-weight:600;
  color:var(--text-primary);background:none;border:none;transition:.12s;
}
.hoct-menu__muc:hover{background:var(--surface-muted)}
.hoct-menu__muc:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}
.hoct-menu__muc--nguy{color:var(--danger)}
.hoct-menu__muc--nguy:hover{background:var(--danger-soft)}

/* --- Thẻ số liệu --- */
.hoct-kpi{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));margin-bottom:22px}
.hoct-kpi .stat{display:flex;flex-direction:column;gap:2px}
.hoct-kpi__so{font-size:var(--fs-2xl);font-weight:700;line-height:1.1;color:var(--text-primary)}
.hoct-kpi__ten{font-size:var(--fs-xs);color:var(--text-muted);font-weight:500}

/* --- Mục lớn trong trang --- */
.hoct-muc{margin-bottom:24px}
.hoct-muc__dau{display:flex;align-items:baseline;gap:10px;margin-bottom:10px}
.hoct-muc__dau h2{margin:0;font-size:var(--fs-lg);line-height:var(--lh-tight)}
.hoct-muc__dem{font-size:var(--fs-xs);color:var(--text-muted)}

/* --- Chương: thẻ mở/gập --- */
.hoct-chuong{padding:0;overflow:hidden;margin-bottom:10px}
.hoct-chuong__dau{
  display:flex;align-items:center;gap:10px;width:100%;text-align:left;
  padding:13px 15px;background:none;border:none;transition:.12s;
}
.hoct-chuong__dau:hover{background:var(--surface-muted)}
.hoct-chuong__dau:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}
.hoct-chuong__mui{color:var(--text-muted);display:grid;place-items:center;transition:transform .16s;flex:0 0 auto}
.hoct-chuong.mo .hoct-chuong__mui{transform:rotate(90deg)}
.hoct-chuong__ten{font-weight:650;font-size:var(--fs-base);color:var(--text-primary);flex:1;min-width:0}
.hoct-chuong__dem{font-size:var(--fs-xs);color:var(--text-muted);flex:0 0 auto}
.hoct-chuong__than{display:none;border-top:1px solid var(--border-card)}
.hoct-chuong.mo .hoct-chuong__than{display:block}

/* --- Bài học: hàng có số thứ tự --- */
.hoct-bai{display:flex;align-items:center;gap:12px;padding:11px 15px;
  border-bottom:1px solid var(--border-card)}
.hoct-bai:last-child{border-bottom:none}
.hoct-bai__stt{
  width:26px;height:26px;border-radius:8px;flex:0 0 auto;display:grid;place-items:center;
  background:var(--surface-muted);color:var(--text-secondary);
  font-size:12px;font-weight:700;font-variant-numeric:tabular-nums;
}
.hoct-bai__ten{flex:1;min-width:0;font-size:var(--fs-sm);color:var(--text-primary);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.hoct-bai__loai{flex:0 0 auto;color:var(--text-muted);display:grid;place-items:center}

/* --- Bảng ghi danh --- */
.hoct-bang{width:100%;border-collapse:collapse;font-size:var(--fs-sm)}
.hoct-bang th{
  text-align:left;padding:9px 14px;font-size:var(--fs-xs);font-weight:600;
  color:var(--text-muted);border-bottom:1px solid var(--border-card);white-space:nowrap;
}
.hoct-bang td{padding:11px 14px;border-bottom:1px solid var(--border-card);
  color:var(--text-primary);white-space:nowrap}
.hoct-bang tr:last-child td{border-bottom:none}
.hoct-bang__cuon{overflow-x:auto;-webkit-overflow-scrolling:touch}
.hoct-bang__act{text-align:right}

/* --- Trạng thái rỗng / đang tải / lỗi --- */
.hoct-tai{display:grid;gap:16px;grid-template-columns:repeat(auto-fill,minmax(260px,1fr))}
.hoct-tai__the{border-radius:var(--radius-md);overflow:hidden;border:1px solid var(--border-card);
  background:var(--surface)}
.hoct-tai__anh{aspect-ratio:16/9}
.hoct-tai__d{height:13px;margin:14px 15px 0}
.hoct-tai__d2{height:11px;width:60%;margin:9px 15px 16px}
.hoct-loi{border-left:3px solid var(--danger);background:var(--danger-soft)}

/* --- Máy nhỏ --- */
@media (max-width:640px){
  .hoct-grid,.hoct-tai{grid-template-columns:1fr}
  .hoct-khoa__anh{width:72px;height:72px}
  .hoct-khoa__anh span{font-size:1.75rem}
  .hoct-khoa__ten{font-size:var(--fs-xl)}
  /* Trên máy nhỏ, hàng flex bị xuống dòng nên nút ⋯ rơi xuống một dòng riêng,
     lơ lửng bên trái — trông như bị bỏ quên. Ghim nó vào góc trên phải của
     khối, đúng chỗ mắt tìm việc quản trị. Thấy trong ảnh chụp 27/08. */
  .hoct-khoa__act{position:absolute;top:0;right:0;margin-left:0}
  .hoct-khoa__noi{padding-right:46px}
  .hoct-kpi{grid-template-columns:repeat(auto-fit,minmax(120px,1fr))}
  .hoct-search{max-width:none;flex-basis:100%}
}
/* Người tắt hiệu ứng chuyển động thì đừng ép họ xem. */
@media (prefers-reduced-motion:reduce){
  .hoct-card,.hoct-chuong__mui{transition:none}
  .hoct-card:hover{transform:none}
}

/* ═══════════════════════════════════════════════════════════════════════════
   MÀN HÌNH CHUẨN BỊ TRƯỚC KHI VÀO PHÒNG (Ưu tiên 1 · P1.1 · 03/09/2026)

   Đặt trong `.live__cho` sẵn có nên thừa hưởng nền và canh giữa của lớp đó —
   không dựng một khung nổi thứ hai chồng lên.

   🔴 `.cb__video` KHÔNG dùng `object-fit: cover`. Cắt mép ở màn xem trước là
   nói dối: người dùng canh khuôn mặt vào giữa khung này, rồi vào phòng thấy
   mình bị cắt mất trán. `contain` cho đúng khuôn hình sẽ gửi đi.
   ═══════════════════════════════════════════════════════════════════════════ */
.live__cho--cb{max-width:900px;width:100%}
.cb{display:flex;flex-direction:column;gap:14px;text-align:left}
.cb__tieu{margin:0;font-size:19px;font-weight:700}
.cb__phu{margin:0;font-size:13px;color:var(--muted)}
.cb__khung{position:relative;width:100%;aspect-ratio:16/9;border-radius:14px;
  overflow:hidden;background:var(--live-o-nen)}
.cb__video{width:100%;height:100%;object-fit:contain;display:block;background:var(--live-o-nen)}
/* Lật gương CHỈ ở màn hình của chính mình — track gửi đi không hề bị lật. */
.cb__video.is-guong{transform:scaleX(-1)}
.cb__cho{position:absolute;inset:0;display:grid;place-items:center;
  color:var(--live-o-chu);font-size:13px;pointer-events:none}
.cb__cot{display:grid;grid-template-columns:1fr 1fr;gap:18px}
.cb__nhom{display:flex;flex-direction:column;gap:8px;min-width:0}
.cb__nhom h3{margin:0 0 2px;font-size:12px;font-weight:700;letter-spacing:.06em;
  text-transform:uppercase;color:var(--muted)}
.cb__hang{display:grid;grid-template-columns:1fr auto;gap:2px 10px;align-items:center}
.cb__hang input[type=range]{grid-column:1;width:100%}
.cb__nhan{font-size:13px;font-weight:500}
.cb__so{grid-column:2;grid-row:2;font-size:12px;color:var(--muted);
  font-variant-numeric:tabular-nums;min-width:2.4em;text-align:right}
.cb__ghi{margin:0 0 4px;font-size:11.5px;line-height:1.45;color:var(--muted)}
.cb__cong{display:flex;align-items:center;gap:8px;font-size:13px;cursor:pointer}
.cb__chon{width:100%;padding:7px 9px;border-radius:9px;border:1px solid var(--border);
  background:var(--surface);color:inherit;font-size:13px;max-width:100%}
/* Điện thoại: một cột. Hai cột ở 390px bóp thanh trượt xuống còn ~120px —
   kéo không nổi bằng ngón cái. */
@media (max-width:640px){
  .cb__cot{grid-template-columns:1fr;gap:14px}
  .cb__khung{aspect-ratio:4/3}
}

/* Trong lúc CHUẨN BỊ, lưới không còn là lưới ô người nữa — nó là một trang.
   Nới đúng hai ràng buộc dành cho ô người (trần cao + bó rộng theo số hàng) và
   thôi canh giữa dọc; giữ nguyên mọi luật khác của phòng họp. */
.live__grid.is-chuan-bi{max-height:none;min-height:0;align-content:start}
.live__grid.is-chuan-bi:not(.is-chia-se){max-width:none;margin-left:0;margin-right:0}
.live__cho--cb{padding:18px 14px 22px;margin:0 auto}
/* 🔴 CHỮ SÁNG TRÊN NỀN TỐI. Bản đầu em đặt `color:inherit` — mà `.live__grid`
   là nền gần đen, nên tiêu đề thành chữ tối trên nền tối, gần như không đọc
   được (thấy trên Production 03/09/2026). `.live__cho` vốn đã có màu sáng;
   phần chuẩn bị chỉ cần đừng ghi đè nó, và nói rõ màu cho từng vai chữ. */
.live__cho--cb .cb__tieu{color:var(--live-o-chu)}
.live__cho--cb .cb__nhan,
.live__cho--cb .cb__cong{color:var(--live-o-chu)}
.live__cho--cb .cb__nhom h3{color:var(--live-o-chu);opacity:.72}
.live__cho--cb .cb__phu,
.live__cho--cb .cb__ghi,
.live__cho--cb .cb__so{color:var(--live-o-chu);opacity:.66}
/* Khung xem trước KHÔNG được cao tới mức đẩy hai nút xuống dưới màn hình:
   người ta phải THẤY nút "Vào phòng" mà không cần cuộn, nếu không họ tưởng
   trang bị treo. Bó CHIỀU RỘNG theo chiều cao cho phép — tỉ lệ 16:9 giữ nguyên. */
.cb__khung{width:min(100%, calc(40vh * 16 / 9));max-width:100%;margin:0 auto}

/* ═══════════════════════════════════════════════════════════════════════════
   MENU "THÊM" CỦA THANH CÔNG CỤ PHÒNG HỌC (04/09/2026)

   Gom những nút ĐANG CÓ mà ít bấm hơn, để hàng nút chính không trải dài. Không
   một nút mới nào, không một tính năng mới nào — chỉ đổi chỗ hiển thị.

   🔴 Popover mở LÊN TRÊN (`bottom:100%`). Thanh nút nằm ở đáy khung phòng, mở
   xuống dưới là rơi ra ngoài màn hình trên laptop 13".
   ═══════════════════════════════════════════════════════════════════════════ */
.live__them{position:relative;display:inline-flex}
.live__them-menu{
  position:absolute;bottom:calc(100% + 8px);left:50%;transform:translateX(-50%);
  display:flex;flex-direction:column;gap:6px;padding:8px;min-width:210px;
  background:var(--surface);border:1px solid var(--border);border-radius:12px;
  box-shadow:0 10px 30px rgba(0,0,0,.16);z-index:40}
/* Trong menu, nút trải hết bề ngang và canh TRÁI — đọc như một danh sách, không
   như một hàng nút thứ hai. */
.live__them-menu .live__btn{width:100%;justify-content:flex-start}
/* Trên máy tính, "Camera sau" vẫn bị ẩn — luật cũ ở dòng 2647 dùng
   `.live__btn--mat`, và nút này giữ nguyên lớp đó nên không phải sửa gì. */
@media (max-width:720px){
  .live__them-menu{left:auto;right:0;transform:none;min-width:min(240px,72vw)}
}

/* ═══════════════════════════════════════════════════════════════════════════
   HỘP CÀI ĐẶT PHÒNG HỌP — HAI CỘT, XEM TRƯỚC SỐNG (04/09/2026)

   Trước bản này hộp cài đặt che gần hết khung hình: người dùng kéo thanh Làm
   mịn / Làm nét mà không nhìn được mặt mình để đánh giá. Nay hình là trọng tâm,
   chữ lùi lại.

   🔴 Ô xem trước DÍNH (`sticky`) ở cột trái: cột phải dài và phải cuộn được,
   nhưng lúc cuộn thì vẫn phải NHÌN THẤY camera — đó là toàn bộ mục đích.
   ═══════════════════════════════════════════════════════════════════════════ */
.modal--form:has(.tbcd){max-width:min(1100px, 78vw)}
.tbcd{display:grid;grid-template-columns:minmax(0,1.15fr) minmax(320px,.85fr);
  gap:20px;align-items:start}
.tbcd__xem{position:sticky;top:0;display:flex;flex-direction:column;gap:6px}
.tbcd__khung{position:relative;width:100%;aspect-ratio:16/9;border-radius:12px;
  overflow:hidden;background:var(--live-o-nen)}
.tbcd__khung video{width:100%;height:100%;object-fit:contain;display:block}
/* Lật gương chỉ đổi hình mình tự nhìn — track gửi đi không hề bị lật. */
.tbcd__khung video.is-guong{transform:scaleX(-1)}
.tbcd__cho{position:absolute;inset:0;display:grid;place-items:center;
  color:var(--live-o-chu);font-size:13px;pointer-events:none}
/* 🔴 `display:grid` THẮNG thuộc tính `hidden` (mặc định của trình duyệt chỉ là
   `[hidden]{display:none}`, cùng độ ưu tiên nhưng khai sau thì lớp này thắng).
   Không có dòng dưới thì chữ "Đang lấy hình…" nằm đè lên mặt người dùng vĩnh
   viễn dù JS đã bật `hidden` — thấy trên Production 04/09/2026. */
.tbcd__cho[hidden]{display:none}
.tbcd__ghi{margin:0;font-size:11.5px;color:var(--muted)}
/* Chỉ CỘT PHẢI cuộn. Cột trái đứng yên nên camera không bao giờ trôi khỏi mắt. */
.tbcd__dieu{min-width:0;max-height:min(70vh,560px);overflow-y:auto;padding-right:4px}
.tbcd__dieu .field{margin-bottom:12px}

/* Màn hẹp: một cột, xem trước lên trên và DÍNH ở đỉnh khi cuộn phần điều khiển. */
@media (max-width:820px){
  .modal--form:has(.tbcd){max-width:96vw}
  .tbcd{grid-template-columns:1fr;gap:12px}
  .tbcd__xem{position:sticky;top:0;z-index:2;background:var(--surface);
    padding-bottom:6px}
  .tbcd__dieu{max-height:none;overflow:visible}
}
