/* ============================================================
   KHO TÀI LIỆU — Minimalist document storage
   Design system: "Endurance & Clarity" (đồng bộ /web)
   Paper × slate × terracotta · Apple system font · glass · aurora
   ------------------------------------------------------------
   MỤC LỤC (Ctrl+F theo số mục)
      1. Tokens (màu · bo góc · bóng · easing)      13. Modal · xem trước
      2. Reset & base                               14. Toasts
      3. Nền: aurora + background-paths             15. Responsive — nền tảng
      4. Liquid glass (vật liệu kính)               16. Giảm chuyển động
      5. Shell: header · brand · icon button        17. Xác thực Supabase
      6. Buttons                                    18. Responsive nâng cao
      7. Toolbar: đếm·tìm·gợi ý·lọc·sắp·xem         19. Cảm ứng (vùng chạm)
      8. Dropzone (kéo-thả tải lên)                 20. Khách / Thành viên
      9. Hàng tài liệu (.row) + nút hành động       21. Môn học (thẻ · breadcrumb)
     10. Taskbar loại tài liệu (chip · đèn trượt)   22. Hiệu ứng "liquid"
     11. Chọn nhiều + thanh thao tác đáy            23. Subject-first (dashboard/workspace)
     12. Trạng thái trống · đang tải · lỗi          24. Responsive toàn diện

   QUY ƯỚC KHI SỬA
     • Màu/bo góc/bóng LUÔN lấy từ token ở mục 1 — đừng viết mã màu thẳng vào rule.
     • Các mục 15/18/24 nằm SAU phần base là CỐ Ý: chúng override bằng thứ tự cascade,
       nên đừng đổi vị trí khối, và đừng thêm !important để "chữa" thứ tự.
     • Không dùng selector sâu quá 3 cấp; đặt tên theo BEM: .khối__phần--biến-thể.
   ============================================================ */

/* ---------------------------------------------------------------
   1. Tokens — KHOÁ theo /web (KHÔNG đổi palette)
--------------------------------------------------------------- */
:root {
  --bg:#FAF9F6;                                   /* alabaster như giấy thật */
  --text:#334155; --text-2:#64748B; --text-3:#94A3B8;   /* slate 700 / 500 / 400 */
  --line:rgba(51,65,85,.10); --line-2:rgba(51,65,85,.06);
  --glass:rgba(255,255,255,.86);
  --glass-2:rgba(255,255,255,.66);
  --glass-strong:rgba(255,255,255,.95);
  --blur:saturate(112%) blur(18px);
  --blur-lite:saturate(108%) blur(9px);
  --glass-bf:saturate(180%) blur(15px);          /* liquid-glass backdrop (port web-react) */
  --apple:#3B4D61; --apple-press:#32414F;         /* deep slate — neo điểm nhìn */
  --on-slate:#FFFFFF;                             /* chữ trên nền --apple (đảo màu ở chế độ Tối) */
  --accent:#D97757; --accent-press:#C9684A; --on-accent:#FFFFFF;   /* terracotta — hành động tiến tới */
  --accent-soft:rgba(217,119,87,.10);
  --ok:#10B981;
  --bad:#E17055; --bad-bg:#FEF2F2;                /* TRẠNG THÁI hỏng (toast lỗi, ô báo lỗi, thẻ error) */
  /* HÀNH ĐỘNG PHÁ HUỶ (xoá) — đỏ THẬT, tách hẳn khỏi terracotta: --bad (#E17055) gần như trùng
     --accent (#D97757) nên nút/chấm xoá từng bị nhìn nhầm thành màu nhấn, không ra ý "nguy hiểm". */
  --danger:#D6453B; --danger-press:#BE362D; --on-danger:#FFFFFF;
  --ring:#3B4D61;
  /* Vòng focus MỀM: --ring đặc trông như viền đen dày. 68% vẫn ~3.5:1 với nền giấy
     (đạt WCAG 1.4.11 cho chỉ báo focus) nhưng nhẹ mắt hơn hẳn. */
  --ring-soft:color-mix(in srgb, var(--ring) 68%, transparent);
  --grad-avada:linear-gradient(135deg,#3B4D61 0%,#46607a 55%,#6E8095 100%);
  --grad-soft:linear-gradient(120deg,rgba(59,77,97,.06),rgba(217,119,87,.08));
  --r-lg:26px; --r-md:18px; --r-sm:12px; --pill:980px;
  --shadow-1:0 1px 2px rgba(51,65,85,.06), 0 12px 30px rgba(51,65,85,.08);
  --shadow-2:0 26px 60px rgba(51,65,85,.14);
  --hl:inset 0 1px 0 rgba(255,255,255,.7), inset 0 0 0 .5px rgba(255,255,255,.4);
  /* Viên kính "đèn" (tubelight) — nền + bóng DÙNG CHUNG cho .tagbar__lamp-pill (mục 10)
     và hover của nút icon/hành động/dropdown (mục 22): một nguồn, hai theme, hết lặp giá trị. */
  --lamp-bg:linear-gradient(180deg, rgba(255,255,255,.92), rgba(255,255,255,.72));
  --lamp-shadow:inset 0 1px 0 rgba(255,255,255,.75), inset 0 0 0 .5px rgba(255,255,255,.35), 0 2px 9px rgba(20,20,28,.14);
  --nav-h:60px; --pill-h:56px; --maxw:1180px;
  /* LỀ TRANG — một con số duy nhất cho .wrap và cho mọi khối "tràn viền" (vd thanh loại cuộn ngang).
     Đổi lề theo cỡ máy = đổi ĐÚNG token này ở mục 15/18, không phải đi sửa từng chỗ. */
  --gutter:24px;
  --font:-apple-system,BlinkMacSystemFont,"SF Pro Display","SF Pro Text","Segoe UI",Roboto,Helvetica,Arial,sans-serif;
  --mono:ui-monospace,"SF Mono",Menlo,Consolas,monospace;
  --ease:cubic-bezier(.2,.7,.2,1);
  --spring:cubic-bezier(.34,1.45,.5,1);        /* overshoot nhẹ, thay spring của framer-motion */
  color-scheme:light;
}

:root[data-theme="dark"] {
  --bg:#1E293B;                                   /* than chì, không đen tuyền */
  --text:#E2E8F0; --text-2:#94A3B8; --text-3:#64748B;
  --line:rgba(148,163,184,.14); --line-2:rgba(148,163,184,.08);
  --glass:rgba(39,53,72,.72); --glass-2:rgba(39,53,72,.5); --glass-strong:rgba(39,53,72,.94);
  --apple:#8FA6BF; --apple-press:#A6BAD0;
  --on-slate:#1E293B;                             /* nền --apple sáng ở Tối -> chữ than chì cho đủ tương phản */
  --accent:#E08B6E; --accent-press:#E89C82; --on-accent:#1E293B;
  --accent-soft:rgba(224,139,110,.14);
  --ok:#34D399;
  --bad:#F0876B; --bad-bg:rgba(225,112,85,.16);
  --danger:#F2705F; --danger-press:#F98878; --on-danger:#2A1512;   /* nền tối -> đỏ sáng hơn, chữ than chì */
  --ring:#8FA6BF;
  --ring-soft:color-mix(in srgb, var(--ring) 62%, transparent);
  --grad-avada:linear-gradient(135deg,#A6BAD0 0%,#8FA6BF 60%,#6f86a0 100%);
  --grad-soft:linear-gradient(120deg,rgba(143,166,191,.12),rgba(224,139,110,.10));
  --shadow-1:0 1px 2px rgba(0,0,0,.4), 0 16px 40px rgba(0,0,0,.5);
  --shadow-2:0 28px 64px rgba(0,0,0,.6);
  --hl:inset 0 1px 0 rgba(255,255,255,.08), inset 0 0 0 .5px rgba(255,255,255,.05);
  --lamp-bg:linear-gradient(180deg, rgba(143,166,191,.3), rgba(143,166,191,.16));
  --lamp-shadow:inset 0 1px 0 rgba(255,255,255,.2), inset 0 0 0 .5px rgba(255,255,255,.1), 0 2px 9px rgba(0,0,0,.3);
  color-scheme:dark;
}

/* ---------------------------------------------------------------
   2. Reset & base
--------------------------------------------------------------- */
*,*::before,*::after { box-sizing:border-box; }
* { margin:0; }
html { -webkit-text-size-adjust:100%; }

body {
  font-family:var(--font);
  background:var(--bg);
  color:var(--text);
  font-size:16px;
  line-height:1.55;
  min-height:100dvh;
  display:flex; flex-direction:column;            /* cột dọc: main giãn hết chiều cao còn lại */
  overflow-x:clip;                                 /* chống cuộn ngang, không phá sticky */
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
  transition:background .3s var(--ease), color .3s var(--ease);
}

h1,h2,h3,h4 { line-height:1.25; font-weight:700; letter-spacing:-.02em; }
button { font:inherit; color:inherit; cursor:pointer; border:none; background:none; }
input,select,textarea { font:inherit; color:inherit; }
a { color:var(--apple); text-decoration:none; }
svg { display:block; flex-shrink:0; }
img { max-width:100%; }
::selection { background:var(--accent-soft); color:var(--accent-press); }

:focus-visible {
  outline:none;
  box-shadow:0 0 0 3px var(--ring-soft);
  border-radius:var(--r-sm);
}
/* High Contrast (Windows): box-shadow bị bỏ qua -> cần outline thật */
@media (forced-colors:active){
  :focus-visible{ outline:2px solid Highlight; outline-offset:2px; }
}

/* Scrollbar tiết chế */
*{ scrollbar-width:thin; scrollbar-color:var(--text-3) transparent; }
*::-webkit-scrollbar{ width:10px; height:10px; }
*::-webkit-scrollbar-thumb{ background:var(--line); border-radius:999px; border:3px solid transparent; background-clip:padding-box; }

.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; }

.skip-link{
  position:fixed; top:8px; left:50%; transform:translate(-50%,-160%);
  z-index:300; padding:10px 18px; border-radius:var(--pill);
  background:var(--apple); color:var(--on-slate); font-weight:650; font-size:14px;
  box-shadow:var(--shadow-1); transition:transform .2s var(--ease);
}
.skip-link:focus{ transform:translate(-50%,0); }

/* ---------------------------------------------------------------
   3. Aurora background (port từ /web — slate × đất nung)
--------------------------------------------------------------- */
.aurora{
  position:fixed; inset:0; z-index:-1; overflow:hidden;
  clip-path:inset(0); pointer-events:none;
  --au:repeating-linear-gradient(100deg,#3b4d61 8%,#4f6a86 13%,#6e8095 18%,#93a7c0 23%,#e0a98e 28%,#d97757 33%,#c2694b 38%,#46607a 45%);
  --stripe:repeating-linear-gradient(100deg,var(--bg) 0%,var(--bg) 7%,transparent 10%,transparent 14%,var(--bg) 17%);
  -webkit-mask-image:radial-gradient(125% 100% at 60% -6%,#000 30%,transparent 78%);
  mask-image:radial-gradient(125% 100% at 60% -6%,#000 30%,transparent 78%);
}
.aurora span{
  position:absolute; inset:-55% -32%;
  background-image:var(--stripe),var(--au);
  background-size:170% 150%,150% 135%;
  background-position:50% 50%,28% 50%;
  filter:blur(30px) saturate(1.1);
  opacity:.6;
  will-change:transform; transform:translateZ(0);
}
.aurora span.b{
  inset:-65% -38%;
  background-image:var(--au);
  background-size:165% 140%;
  filter:blur(48px) saturate(1.12);
  opacity:.38;
}
:root[data-theme="dark"] .aurora span{ opacity:.5; }
:root[data-theme="dark"] .aurora span.b{ opacity:.4; mix-blend-mode:screen; }
/* mặc định aurora tĩnh -> kính cache được blur -> mượt; chỉ chạy khi bật hiệu ứng cao */
:root[data-fx="high"] .aurora span,
:root[data-fx="max"] .aurora span{ animation:auA 34s ease-in-out infinite alternate; }
:root[data-fx="high"] .aurora span.b,
:root[data-fx="max"] .aurora span.b{ animation:auB 46s ease-in-out infinite alternate; }
:root[data-fx="off"] .aurora{ display:none; }
/* CHỈ translate, KHÔNG scale: texture blur được raster 1 lần rồi chỉ DI CHUYỂN
   (scale từng khiến GPU phải raster lại lớp mờ khổng lồ liên tục — audit hiệu năng). */
@keyframes auA{ from{transform:translate3d(-9%,-4%,0);} to{transform:translate3d(9%,5%,0);} }
@keyframes auB{ from{transform:translate3d(8%,4%,0);} to{transform:translate3d(-8%,-5%,0);} }

/* ---------------------------------------------------------------
   3b. Nền "Background Paths" (port kokonutd) — chế độ data-fx="paths"
       Chỉ hiện khi chọn Hiệu ứng nền = Đường nét; khi đó ẩn aurora.
--------------------------------------------------------------- */
.bgpaths{
  position:fixed; inset:0; z-index:-1; overflow:hidden; pointer-events:none;
  display:none; color:var(--apple); opacity:.68;              /* --apple tự đổi slate↔sáng theo theme */
}
:root[data-fx="paths"] .aurora{ display:none; }               /* "Đường nét": ẩn aurora, chỉ paths */
:root[data-fx="paths"] .bgpaths,
:root[data-fx="max"] .bgpaths{ display:block; }               /* "max" = Động + Đường nét: giữ CẢ aurora lẫn paths */
:root[data-theme="dark"] .bgpaths{ opacity:.55; }
.bgpaths__svg{ width:100%; height:100%; display:block; }
/* Chảy: pathLength=1 -> dash theo đơn vị 0..1; dịch dashoffset 1 vòng = liền mạch */
.bgpaths path{ stroke-dasharray:.35 .65; animation-name:bgFlow; animation-timing-function:linear; animation-iteration-count:infinite; }
@keyframes bgFlow{ from{ stroke-dashoffset:1; } to{ stroke-dashoffset:0; } }
:root[data-fx="off"] .bgpaths{ display:none; }
/* Giảm chuyển động: đường liền không chạy + aurora đứng yên */
@media (prefers-reduced-motion:reduce){
  .bgpaths path{ stroke-dasharray:none; animation:none; }
  .aurora span, .aurora span.b{ animation:none !important; }
}

/* ĐIỆN THOẠI/TABLET (pointer thô) — audit hiệu năng: 72 path stroke-dashoffset = repaint
   toàn màn hình mỗi khung hình trên main thread + phá cache blur của mọi lớp kính phía trên.
   Mobile: tắt paths + aurora ĐỨNG YÊN (vẫn giữ gradient nền) + kính nhẹ tay hơn.
   Desktop giữ nguyên "Động + Đường nét" như đã chọn. */
@media (pointer:coarse){
  .bgpaths{ display:none !important; }
  .aurora span, .aurora span.b{ animation:none !important; will-change:auto; }
  :root{ --glass-bf:saturate(140%) blur(9px); }   /* blur 15→9px, bỏ saturate nặng: kernel rẻ ~1/3 */
}

/* ---------------------------------------------------------------
   4. LIQUID GLASS — vật liệu kính dùng cho header · taskbar · dock
--------------------------------------------------------------- */
/* (port y hệt web-react) — kính mờ + bão hoà + viền sáng + inset highlight đặc trưng */
.liquid-glass{
  position:relative;
  background:linear-gradient(177deg, rgba(255,255,255,.48), rgba(255,255,255,.24));
  backdrop-filter:var(--glass-bf); -webkit-backdrop-filter:var(--glass-bf);
  border:1px solid rgba(255,255,255,.55);
  box-shadow:
    0 8px 26px rgba(20,20,28,.13),
    0 1px 2px rgba(20,20,28,.06),
    inset 0 1px 0 rgba(255,255,255,.9),
    inset 0 0 0 .5px rgba(255,255,255,.3);
  transform:translateZ(0);                          /* layer riêng -> blur không re-raster mỗi frame */
}
:root[data-theme="dark"] .liquid-glass{
  background:linear-gradient(177deg, rgba(74,96,124,.5), rgba(40,56,76,.42));
  border-color:rgba(255,255,255,.14);
  box-shadow:
    0 8px 26px rgba(0,0,0,.42),
    inset 0 1px 0 rgba(255,255,255,.16),
    inset 0 0 0 .5px rgba(255,255,255,.06);
}
:root[data-fx="off"] .liquid-glass{ background:var(--glass-strong); backdrop-filter:none; -webkit-backdrop-filter:none; }
/* (Đã BỎ vệt sáng specular quét động trên pill — không còn hiệu ứng "bóng bóng".) */

/* ---------------------------------------------------------------
   5. Shell
--------------------------------------------------------------- */
.wrap{ max-width:var(--maxw); margin:0 auto; padding-left:max(var(--gutter),env(safe-area-inset-left)); padding-right:max(var(--gutter),env(safe-area-inset-right)); }

/* Nav nổi (glass pill) — giống /web */
.header{ position:sticky; top:calc(12px + env(safe-area-inset-top)); z-index:50; padding-left:max(16px,env(safe-area-inset-left)); padding-right:max(16px,env(safe-area-inset-right)); margin-bottom:2px; }
.brand__name, .brand__sub{ overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }

/* Thanh header = 3 PILL KÍNH riêng biệt: [thương hiệu] · [taskbar] · [điều khiển]
   (không còn một pill lớn bọc tất cả — giống web-react) */
.header-row{                                     /* 2 pill: [thương hiệu] ......... [điều khiển] */
  max-width:1240px; margin:0 auto;
  display:flex; flex-wrap:wrap; align-items:center; justify-content:space-between; gap:12px;
}
.brand, .header-tools{ border-radius:var(--pill); }

.brand{
  flex:0 1 auto; min-width:0;
  display:flex; align-items:center; gap:11px;
  height:var(--pill-h); padding:0 20px 0 12px;
}
.header-tools{
  flex:0 0 auto;
  display:flex; align-items:center; gap:6px;
  height:var(--pill-h); padding:0 8px;
}
.brand__mark{
  width:36px; height:36px; border-radius:11px;
  background:var(--grad-avada); color:var(--on-slate);
  display:grid; place-items:center; box-shadow:var(--shadow-1);
}
.brand__mark svg{ width:20px; height:20px; }
.brand__name{ font-size:16.5px; font-weight:750; letter-spacing:-.02em; }
/* display:block ở ĐÂY (trước nằm inline trong index.html -> thắng mọi @media, nên màn hẹp không ẩn được) */
.brand__sub{ display:block; font-size:12.5px; color:var(--text-2); font-weight:600; margin-top:-1px; }

/* Icon buttons in header */
.iconbtn{
  width:40px; height:40px; display:grid; place-items:center;
  border-radius:12px; color:var(--text-2);
  transition:background .18s var(--ease), color .18s var(--ease);
}
.iconbtn svg{ width:19px; height:19px; }
.iconbtn:hover{ background:var(--glass-2); color:var(--text); }
.iconbtn:active{ transform:scale(.94); }

/* ---------------------------------------------------------------
   6. Buttons
--------------------------------------------------------------- */
.btn{
  position:relative; overflow:hidden;
  display:inline-flex; align-items:center; justify-content:center; gap:8px;
  height:44px; padding:0 20px; border-radius:var(--pill);
  font-size:15px; font-weight:650; white-space:nowrap;
  border:1px solid transparent;
  transition:background .18s var(--ease), color .18s var(--ease), border-color .18s var(--ease), transform .12s var(--ease), box-shadow .18s var(--ease);
}
/* (Đã BỎ lớp gloss "bóng bóng" phủ nửa trên nút — nút giờ PHẲNG, màu đặc.) */
.btn svg{ width:17px; height:17px; }
.btn:active{ transform:scale(.97); }

.btn-accent{ background:var(--accent); color:var(--on-accent); box-shadow:0 2px 6px rgba(217,119,87,.16); }
.btn-accent:hover{ background:var(--accent-press); }
:root[data-theme="dark"] .btn-accent{ box-shadow:0 2px 8px rgba(0,0,0,.28); }

.btn-slate{ background:var(--apple); color:var(--on-slate); }
.btn-slate:hover{ background:var(--apple-press); }

.btn-ghost{ color:var(--text-2); }
.btn-ghost:hover{ background:var(--glass-2); color:var(--text); }

.btn-outline{ background:var(--glass); border-color:var(--line); color:var(--text); }
.btn-outline:hover{ border-color:var(--text-3); }

/* Di CHUỘT VÀO nút: nhấc nhẹ + bóng rõ hơn (chỉ máy có chuột; khi bấm xuống thì nhấn lại nhờ :active đặt SAU) */
@media (hover:hover){
  .btn:hover{ transform:translateY(-2px); }
  .btn-accent:hover{ box-shadow:0 8px 18px rgba(217,119,87,.30); }
  .btn-slate:hover{ box-shadow:0 8px 18px rgba(59,77,97,.26); }
  .btn-outline:hover{ transform:translateY(-2px); box-shadow:var(--shadow-1); }
  .iconbtn:hover{ transform:translateY(-1px); }
  .subject-card__act:hover{ transform:translateY(-1px); }
  .btn:active{ transform:translateY(0) scale(.97); }
}

.btn-danger{ background:var(--danger); color:var(--on-danger); }   /* HÀNH ĐỘNG xoá -> đỏ, không dùng terracotta */
.btn-danger:hover{ background:var(--danger-press); }

/* DISABLED nhất quán cho mọi nút pill + chip: bulkbar "Gắn loại/Xóa" khi CHƯA chọn gì, nút modal
   đang lưu ("Đang xóa…")… — trước đây trông Y HỆT nút bấm được. Mờ đi + không nhận hover/active.
   (.auth-submit.is-busy đặt SAU trong cascade nên vẫn giữ opacity .7 riêng của nó.) */
.btn:disabled, .tagchip:disabled{ opacity:.5; pointer-events:none; }

/* ---------------------------------------------------------------
   7. Content — toolbar tài liệu · ô tìm + khay gợi ý · dropdown lọc/sắp xếp · danh sách↔lưới
--------------------------------------------------------------- */
.main{ flex:1 0 auto; padding:30px 0 64px; }   /* chừa chỗ thở dưới header nổi */

/* TOOLBAR TÀI LIỆU — [số đếm] [ô tìm] [sắp xếp] [chọn nhiều]
   Một hàng flex duy nhất; ô tìm là phần co giãn, các control khác giữ nguyên cỡ.
   Màn hẹp: ô tìm nhảy lên chiếm trọn hàng đầu (order:-1) rồi mới tới các nút. */
.ws-toolbar{
  display:flex; align-items:center; flex-wrap:wrap; gap:10px;
  margin:0 0 16px;
}
.ws-toolbar__count{
  flex-shrink:0; font-size:14px; font-weight:650; color:var(--text-2);
  font-variant-numeric:tabular-nums; white-space:nowrap;
  padding:9px 15px; border-radius:var(--pill);
  background:var(--glass-2); border:1px solid var(--line); box-shadow:var(--hl);
}
.ws-toolbar__sel{ flex-shrink:0; }   /* trạng thái disabled đã có chung ở .btn:disabled (mục 6) */
.ws-toolbar__new{ flex-shrink:0; }
/* Đang BẬT: tô đặc slate. Không chỉ đổi màu chữ — nút bật/tắt phải nhìn ra ngay là đang bật. */
.ws-toolbar__new[aria-pressed="true"]{
  background:var(--apple); border-color:var(--apple); color:var(--on-slate);
}
.ws-toolbar__new[aria-pressed="true"]:hover{ background:var(--apple-press); color:var(--on-slate); }

/* Ô TÌM — icon trái, nút xoá phải; nút xoá tự ẩn khi ô rỗng bằng :placeholder-shown (không cần JS) */
.search{ position:relative; flex:1 1 220px; min-width:0; max-width:420px; }
.search__icon{
  position:absolute; left:14px; top:50%; transform:translateY(-50%);
  color:var(--text-3); pointer-events:none; display:grid;
}
.search__icon svg{ width:17px; height:17px; }
.search__input{
  width:100%; height:44px; padding:0 42px 0 40px;
  font-size:16px;                                       /* ≥16px: iOS không tự phóng to trang khi bấm vào ô */
  border:1px solid var(--line); border-radius:var(--pill);
  background:linear-gradient(180deg,var(--glass-strong),var(--glass)); color:var(--text);
  backdrop-filter:var(--blur-lite); -webkit-backdrop-filter:var(--blur-lite);
  box-shadow:var(--hl);
  transition:border-color .18s var(--ease), box-shadow .18s var(--ease);
}
:root[data-fx="off"] .search__input{ background:var(--glass-strong); backdrop-filter:none; -webkit-backdrop-filter:none; }
.search__input::placeholder{ color:var(--text-3); }
/* Ô TÌM là ngoại lệ có chủ đích: gõ chữ thì phải thấy ô đang nhận chữ, kể cả khi bấm chuột.
   Nhưng chỉ tô ĐƯỜNG VIỀN, không bắn vòng 3px -> không bị nặng như .select. */
.search__input:focus{ outline:none; border-color:var(--apple); box-shadow:var(--hl); }
.search__input:focus-visible{ box-shadow:0 0 0 3px var(--ring-soft), var(--hl); }
.search__input::-webkit-search-cancel-button{ -webkit-appearance:none; appearance:none; }   /* dùng nút xoá của mình */
.search__clear{
  position:absolute; right:4px; top:50%; transform:translateY(-50%);
  width:36px; height:36px; display:grid; place-items:center; cursor:pointer;
  border-radius:50%; color:var(--text-2); background:transparent;
  transition:background .16s var(--ease), color .16s var(--ease), opacity .12s var(--ease);
}
.search__clear svg{ width:15px; height:15px; }
.search__clear:hover{ background:var(--glass-2); color:var(--text); }
.search__input:placeholder-shown ~ .search__clear{ opacity:0; pointer-events:none; }   /* ô rỗng -> ẩn */

/* TÔ SÁNG đoạn khớp từ khoá (dùng ở hàng tài liệu, nhãn loại, khay gợi ý).
   Không đổi màu CHỮ — chỉ nền mờ + đậm hơn, nên vẫn đọc được ở cả Sáng và Tối. */
mark{
  background:color-mix(in srgb, var(--accent) 24%, transparent);
  color:inherit; font-weight:750; border-radius:5px; padding:0 2px;
  box-decoration-break:clone; -webkit-box-decoration-break:clone;
}

/* KHAY GỢI Ý (combobox) — nổi ngay dưới ô tìm, không đẩy layout, tự cuộn khi dài.
   .search đã position:relative nên khay neo đúng vào ô; is-open nâng z-index để không bị hàng dưới che. */
.search.is-open{ z-index:30; }
.search__pop{
  position:absolute; left:0; right:0; top:calc(100% + 8px); z-index:1;
  max-height:min(56vh,400px); overflow-y:auto; overscroll-behavior:contain;
  padding:6px; border-radius:var(--r-md);
  background:var(--glass-strong); border:1px solid var(--line);
  box-shadow:var(--shadow-2), var(--hl);
  backdrop-filter:var(--blur); -webkit-backdrop-filter:var(--blur);
  animation:sugIn .16s var(--ease) both;
}
.search__pop[hidden]{ display:none; }
:root[data-fx="off"] .search__pop{ backdrop-filter:none; -webkit-backdrop-filter:none; }
@keyframes sugIn{ from{ opacity:0; transform:translateY(-5px); } to{ opacity:1; transform:none; } }

.sug{
  display:flex; align-items:center; gap:11px;
  padding:8px 10px; border-radius:12px; cursor:pointer;
  transition:background .14s var(--ease);
}
.sug:hover{ background:var(--glass-2); }
/* Đang trỏ bằng bàn phím: nền + viền trong, KHÔNG chỉ dựa vào màu (đủ tín hiệu khi mù màu) */
.sug.is-active{
  background:color-mix(in srgb, var(--apple) 12%, transparent);
  box-shadow:inset 0 0 0 1.5px color-mix(in srgb, var(--apple) 34%, transparent);
}
.sug .ficon{ width:34px; height:34px; border-radius:10px; flex-shrink:0; }
.sug .ficon svg{ width:17px; height:17px; }
.sug__body{ flex:1; min-width:0; display:flex; flex-direction:column; }
.sug__name{ font-size:14.5px; font-weight:650; color:var(--text); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.sug__meta{ font-size:12px; color:var(--text-2); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; font-variant-numeric:tabular-nums; }
/* "Vì sao khớp" — chỉ hiện khi lý do KHÔNG nằm ở tên tệp (vd khớp loại, khớp người tải) */
.sug__why{
  flex-shrink:0; max-width:40%; font-size:11.5px; font-weight:600; color:var(--text-2);
  padding:3px 9px; border-radius:var(--pill);
  background:var(--glass-2); border:1px solid var(--line);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}
.sug--all{
  justify-content:center; gap:8px; margin-top:3px; padding-top:11px;
  font-size:13.5px; font-weight:650; color:var(--apple);
  border-top:1px solid var(--line-2); border-radius:0 0 12px 12px;   /* = bo góc .sug, khỏi lệch tông */
}
.sug--all svg{ width:15px; height:15px; }
.sug-empty{ display:flex; align-items:center; gap:10px; padding:15px 12px; font-size:14px; color:var(--text-2); }
.sug-empty svg{ width:18px; height:18px; flex-shrink:0; color:var(--text-3); }

/* DANH SÁCH ↔ LƯỚI — cặp nút phân đoạn; tổng cao 44px để thẳng hàng với ô tìm và dropdown */
.viewtog{
  flex-shrink:0; display:inline-flex; gap:2px; padding:3px;
  border-radius:var(--pill); background:var(--glass-2); border:1px solid var(--line); box-shadow:var(--hl);
}
.viewtog__b{
  width:38px; height:36px; display:grid; place-items:center; cursor:pointer;
  border-radius:var(--pill); color:var(--text-2); background:transparent;
  transition:background .16s var(--ease), color .16s var(--ease);
}
.viewtog__b svg{ width:17px; height:17px; }
.viewtog__b:hover{ color:var(--text); }
.viewtog__b.is-on{ background:var(--glass-strong); color:var(--apple); box-shadow:var(--shadow-1); }

/* "Xoá lọc" — chỉ xuất hiện khi thật sự có bộ lọc đang bật (JS bật/tắt thuộc tính hidden) */
.ws-toolbar__clear{ flex-shrink:0; }
.ws-toolbar__clear[hidden]{ display:none; }

/* DROPDOWN sắp xếp / lọc định dạng */
.select{
  /* Đệm ĐỀU 2 bên + text-align:center -> chữ "Mới nhất" nằm CHÍNH GIỮA viên thuốc
     (trước: 15px trái / 36px phải nên chữ dạt hẳn sang trái). Chevron nằm đè lên phần đệm phải. */
  flex-shrink:0; height:44px; padding:0 36px;
  text-align:center; text-align-last:center;
  /* Không dùng min-width:max-content — Chrome KHÔNG tính bề rộng nội tại đúng cho <select>
     có appearance:none, đo ra vẫn bị bóp. Sàn px đặt ở 2 khối responsive bên dưới (mục 24). */
  border:1px solid var(--line); border-radius:var(--pill);
  background:var(--glass) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='none' stroke='%2364748b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E") no-repeat right 12px center;
  color:var(--text); font-size:16px; font-weight:600; cursor:pointer;   /* 16px = cùng cỡ ô tìm & chip loại */
  box-shadow:var(--hl);
  -webkit-appearance:none; appearance:none; transition:border-color .18s var(--ease);
}
/* Danh sách xổ xuống: khai báo đúng font của app cho <option>. (Menu này do trình duyệt/HĐH vẽ —
   Chrome/Edge tôn trọng font-family/size; menu native macOS có thể bỏ qua, không hỏng gì.) */
.select option{ font-family:var(--font); font-size:15px; font-weight:500; }
.select:hover{ border-color:var(--text-3); }
/* :focus-visible chứ KHÔNG phải :focus — bấm bằng chuột xong, vòng slate 3px sẽ DÍNH lại trên
   viên thuốc trông như lỗi vẽ; chỉ bàn phím (Tab) mới cần chỉ báo tiêu điểm. */
.select:focus-visible{ outline:none; border-color:var(--apple); box-shadow:0 0 0 3px var(--ring-soft), var(--hl); }
/* Chế độ Tối: chevron #64748B chìm hẳn vào nền kính tối -> sáng lên thành #94A3B8 (= --text-2 dark).
   Mã màu buộc phải nằm thẳng trong data-URI vì url() không nội suy var(). */
:root[data-theme="dark"] .select{
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='none' stroke='%2394A3B8' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
}

/* ---------------------------------------------------------------
   8. Dropzone (terracotta — hành động tiến tới)
--------------------------------------------------------------- */
.dropzone{
  position:relative;
  border:1.5px dashed color-mix(in srgb,var(--accent) 55%,var(--line));
  border-radius:var(--r-lg);
  background:var(--glass);
  padding:38px 24px; text-align:center; cursor:pointer;
  margin-bottom:24px;
  transition:border-color .2s var(--ease), background .2s var(--ease), transform .2s var(--ease);
}
.dropzone:hover{ border-color:var(--accent); }
/* Kéo tệp vào (spec): PHỒNG nhẹ + viền đổi sang NÉT LIỀN đậm + hiện "Thả để tải lên ngay" */
.dropzone__title--drop{ display:none; color:var(--accent); font-weight:750; }
.dropzone.is-drag{ border-style:solid; border-width:2px; border-color:var(--accent); background:var(--accent-soft); transform:scale(1.014); }
.dropzone.is-drag .dropzone__title:not(.dropzone__title--drop){ display:none; }
.dropzone.is-drag .dropzone__title--drop{ display:block; }
.dropzone.is-drag .dropzone__hint{ visibility:hidden; }      /* giữ chỗ -> không giật chiều cao */
.dropzone__icon{
  width:56px; height:56px; margin:0 auto 16px; border-radius:16px;
  background:var(--accent-soft); color:var(--accent);
  display:grid; place-items:center; transition:transform .2s var(--spring);
}
.dropzone.is-drag .dropzone__icon{ transform:translateY(-5px) scale(1.06); }
.dropzone__icon svg{ width:27px; height:27px; }
.dropzone__title{ font-size:16.5px; font-weight:700; text-wrap:balance; }
.dropzone__title b{ color:var(--accent); }
.dropzone__hint{ font-size:13px; color:var(--text-2); margin-top:4px; text-wrap:balance; }

/* Trạng thái ĐANG TẢI LÊN — khoá thao tác + thanh tiến trình KHÔNG xác định (indeterminate) */
.dropzone.is-uploading{ pointer-events:none; border-color:var(--accent); background:var(--accent-soft); }
.upstatus{ margin-top:16px; display:flex; flex-direction:column; align-items:center; gap:9px; }
.upstatus__txt{ font-size:13.5px; font-weight:700; color:var(--accent); }
.upstatus__bar{ position:relative; width:min(300px,84%); height:5px; border-radius:999px; background:var(--accent-soft); overflow:hidden; }
.upstatus__bar::before{ content:""; position:absolute; top:0; bottom:0; left:0; width:38%; border-radius:inherit; background:var(--accent); animation:upIndet 1.05s var(--ease) infinite; }
@keyframes upIndet{ 0%{ transform:translateX(-130%);} 100%{ transform:translateX(360%);} }
:root[data-fx="off"] .upstatus__bar::before{ animation:none; width:100%; opacity:.55; }
/* Tiến độ THẬT: bề rộng = số tệp đã xong / tổng. (Không có % từng tệp — xem ghi chú ở upProgress
   trong app.js: sb.storage.upload() chạy trên fetch nên không phát sự kiện progress.) */
.upstatus__bar.is-determinate::before{
  animation:none; width:var(--p,0%); transition:width .28s var(--ease);
}

/* ---------------------------------------------------------------
   9. File grid / list
--------------------------------------------------------------- */
/* icon file — monochrome slate (không thêm màu thứ 3) */
.ficon{ width:46px; height:46px; border-radius:13px; display:grid; place-items:center; background:var(--grad-soft); color:var(--apple); border:1px solid var(--line); }
.ficon svg{ width:23px; height:23px; }
.act{
  width:36px; height:36px; display:grid; place-items:center; border-radius:10px;
  background:var(--glass-strong); border:1px solid var(--line); color:var(--text-2);
  box-shadow:var(--shadow-1); transition:.16s var(--ease);
}
.act svg{ width:16px; height:16px; }
/* Cảm ứng: vùng chạm to hơn cho ngón tay (nút hành động luôn hiện trên thiết bị touch) */
@media (hover:none){ .act{ width:40px; height:40px; border-radius:12px; } .act svg{ width:18px; height:18px; } }
.act:hover{ background:var(--glass-2); color:var(--text); }
.act--danger:hover{ background:color-mix(in srgb,var(--danger) 12%,transparent); color:var(--danger); border-color:var(--danger); }

/* list row */
.row{
  display:flex; align-items:center; gap:16px;
  padding:14px 18px; border:1px solid var(--line); border-radius:var(--r-md);
  background:var(--glass); cursor:pointer;
  transition:border-color .18s var(--ease), background .18s var(--ease);
}
.row:hover{ border-color:var(--text-3); background:var(--glass-strong); }   /* spec: hàng sáng nhẹ khi rê */
.row:focus-visible{ box-shadow:0 0 0 3px var(--ring-soft); border-color:var(--apple); }
.row .ficon{ width:44px; height:44px; border-radius:12px; }
.row .ficon svg{ width:22px; height:22px; }
.row__thumb{ width:44px; height:44px; border-radius:12px; object-fit:cover; flex-shrink:0; border:1px solid var(--line); }
.row__body{ flex:1; min-width:0; }
.row__name{ font-size:16px; font-weight:650; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.row__meta{ font-size:13px; color:var(--text-2); margin-top:2px; font-variant-numeric:tabular-nums; }
.row__owner{ display:inline-flex; align-items:center; gap:3px; color:var(--text-2); vertical-align:middle; }
.row__owner::before{ content:"·"; margin:0 6px; }
.row__owner svg{ width:12px; height:12px; }
.row__actions{ display:flex; gap:4px; flex-shrink:0; }
.row .act{ box-shadow:none; }
/* BẪY ĐẶC HIỆU: `.row .act` (0,2,0) đè `:focus-visible` toàn cục (0,1,0) -> nút hành động
   trên hàng từng KHÔNG hiện vòng focus khi đi bằng Tab. Khai báo lại ở mức (0,3,0) cho chắc. */
.act:focus-visible,
.row .act:focus-visible{ outline:none; box-shadow:0 0 0 3px var(--ring-soft); }
@media (hover:hover){
  .row__actions{ opacity:0; transition:opacity .18s var(--ease); }
  .row:hover .row__actions,.row:focus-within .row__actions{ opacity:1; }
}

/* ---------------------------------------------------------------
   10. TAG (loại tài liệu) · GHIM · đổi tên INLINE — trong Workspace
       Typography: chip lọc & ô nhập ≥16px, line-height 1.5, tương phản mềm.
--------------------------------------------------------------- */
/* Thanh chip lọc theo loại = TASKBAR web-react nguyên bản:
   vật liệu kính lấy từ class .liquid-glass (đúng port), khung theo DOM gốc
   `flex items-center gap-1 sm:gap-3 py-1 px-1 rounded-full`.
   Bọc VỪA nội dung (thêm loại tới đâu, thanh dài tới đó), tự xuống dòng khi chạm mép. */
.tagbar-scroll{ margin:0 0 20px; }                             /* khung ngoài: giữ khoảng thở, màn hẹp thì cho cuộn ngang */
.tagbar{
  display:flex; flex-wrap:wrap; align-items:center; gap:4px;   /* gap-1 */
  width:fit-content; max-width:100%;
  margin:0; padding:4px; border-radius:9999px;                 /* py-1 px-1 rounded-full */
}
@media (min-width:640px){ .tagbar{ gap:12px; } }               /* sm:gap-3 */

/* ĐÈN TRƯỢT (port tubelight-navbar): viên kính DUY NHẤT trượt giữa các phím + đèn tuýp phía trên.
   Chip active KHÔNG tự tô nền — nền là viên đèn này (giống layoutId của framer-motion). */
.tagbar{ position:relative; }
/* Easing = ĐÚNG spring của web-react: framer-motion { stiffness:230, damping:19, mass:0.9 }.
   Giải phương trình lò xo m·x″ + c·x′ + k·x = k cho ra: ω₀ = √(230/0,9) = 15,986 rad/s,
   hệ số tắt dần ζ = 19/(2√(230·0,9)) = 0,660 -> DAO ĐỘNG (ζ<1): chạm đích ở 0,19s, vọt lố
   6,32% ở 0,262s, lún nhẹ 0,4% rồi tắt. 46 mốc × 16ms = mỗi khung hình một mốc.
   (Bản cũ ζ=0,80 chỉ vọt lố 1,5% và tới đích rất muộn -> đó là cảm giác "cứng".) */
:root{
  --lamp-dur:.72s;
  --lamp-ease:linear(0, 0.0292, 0.1036, 0.2062, 0.3232, 0.444, 0.5609, 0.6685, 0.7636, 0.8445, 0.9108, 0.963, 1.0023, 1.0302, 1.0484, 1.0588, 1.0629, 1.0624, 1.0585, 1.0526, 1.0454, 1.0378, 1.0303, 1.0233, 1.017, 1.0115, 1.007, 1.0034, 1.0006, 0.9986, 0.9973, 0.9965, 0.9961, 0.996, 0.9962, 0.9965, 0.997, 0.9974, 0.9979, 0.9984, 0.9988, 0.9992, 0.9995, 0.9997, 0.9999, 1);
  /* Đường cong ÊM (không nảy) — dành cho hàng tài liệu trượt chỗ khi lọc: giữ nguyên như trước,
     không để chúng nảy lây theo đèn. */
  --flip-ease:linear(0, 0.0554, 0.1816, 0.3344, 0.4865, 0.6228, 0.7366, 0.8264, 0.8938, 0.942, 0.9746, 0.9953, 1.0072, 1.0131, 1.0151, 1.0147, 1.0129, 1.0107, 1.0083, 1.0062, 1.0044, 1.0029, 1.0018, 1.001, 1.0005);
}
@supports not (transition-timing-function:linear(0,1)){    /* trình duyệt cũ: bezier khớp đỉnh vọt lố nhất */
  :root{ --lamp-ease:cubic-bezier(.38,1.51,.1,.95); --flip-ease:cubic-bezier(.3,1.04,.4,1); }
}
.tagbar__lamp{
  position:absolute; top:0; left:0; z-index:0; pointer-events:none;
  opacity:0; border-radius:var(--pill);
  transition:transform var(--lamp-dur) var(--lamp-ease), width var(--lamp-dur) var(--lamp-ease),
             height var(--lamp-dur) var(--lamp-ease), opacity .2s var(--ease);
  will-change:transform;          /* width không phải thuộc tính hợp thành -> gợi ý nó vô nghĩa */
}
.tagbar__lamp.is-on{ opacity:1; }
.tagbar__lamp-pill{
  position:absolute; inset:0; border-radius:var(--pill); will-change:transform;
  background:var(--lamp-bg);
  box-shadow:var(--lamp-shadow);
  /* (Bản Tối tự đổi qua token --lamp-bg/--lamp-shadow ở mục 1 — không cần rule riêng.) */
}

/* ĐÈN TUÝP — dựng đúng như bản React: thanh 32×4 (bo trên) + 3 quầng mờ.
   Màu = slate (--apple), khớp `bg-primary` (#3B4D61) của web-react. */
.tagbar__glow{
  position:absolute; top:0; left:0; z-index:0; pointer-events:none; opacity:0;
  width:32px; height:4px; margin-left:-16px;      /* margin âm = canh giữa phím */
  border-radius:999px 999px 0 0; background:var(--apple);
  transition:transform var(--lamp-dur) var(--lamp-ease), opacity .2s var(--ease);
  will-change:transform;
}
.tagbar__glow.is-on{ opacity:1; }
.tagbar__glow span{ position:absolute; display:block; border-radius:999px; background:color-mix(in srgb,var(--apple) 20%,transparent); }
.tagbar__glow-h1{ width:48px; height:24px; top:-8px; left:-8px; filter:blur(12px); }
.tagbar__glow-h2{ width:32px; height:24px; top:-4px; left:0;    filter:blur(12px); }
.tagbar__glow-h3{ width:16px; height:16px; top:0;    left:8px;  filter:blur(4px); }
/* Giãn ngang "gooey" theo hướng đi — Y HỆT web-react: scaleX [1 → 1,3 → 1] trong 0,42s với
   cubic-bezier(.34,1.45,.5,1). Số 1,45 > 1 nên mỗi CHẶNG tự vọt lố: phình quá 1,3 một chút rồi
   hút về, và khi co lại thì lún nhẹ dưới 1 — đó mới là cảm giác "chất lỏng".
   (CSS áp timing-function cho TỪNG chặng keyframe, đúng như framer-motion -> khớp 1:1.) */
.tagbar__lamp-pill.is-stretch{ animation:navStretch .42s var(--spring); }
@keyframes navStretch{ 0%{ transform:scaleX(1); } 50%{ transform:scaleX(1.3); } 100%{ transform:scaleX(1); } }
:root[data-fx="off"] .tagbar__lamp, :root[data-fx="off"] .tagbar__glow{ transition:none; }
:root[data-fx="off"] .tagbar__glow{ display:none; }
@media (prefers-reduced-motion:reduce){
  .tagbar__lamp, .tagbar__glow{ transition:none; }
  .tagbar__lamp-pill.is-stretch{ animation:none; }
}

/* Mỗi loại = một "phím" — Y HỆT tab gốc:
   `text-sm font-semibold px-5 sm:px-6 py-2 rounded-full transition-colors duration-300
    text-foreground/80 hover:text-primary` · active = text-primary (cả 2 theme). */
.tagchip{
  position:relative; z-index:1;
  font-size:14px; line-height:20px; font-weight:600;           /* text-sm font-semibold */
  padding:8px 20px; border-radius:9999px; cursor:pointer;      /* py-2 px-5 rounded-full */
  background:transparent; border:0;
  color:color-mix(in srgb,var(--text) 80%,transparent);        /* text-foreground/80 */
  transition:color .3s var(--ease);                            /* transition-colors duration-300 */
}
@media (min-width:640px){ .tagchip{ padding:8px 24px; } }      /* sm:px-6 */
.tagchip:hover{ color:var(--apple); }                          /* hover:text-primary */
.tagchip.is-active{ color:var(--apple); }                      /* text-primary (dark: --apple sáng = y hệt) */
.tagchip:focus-visible{ outline:none; box-shadow:0 0 0 3px var(--ring-soft); }

/* Loại TỰ TẠO: phím GIỐNG HỆT loại mặc định, ✕ là HUY HIỆU nổi ở GÓC trên-phải.
   Ẩn sẵn (opacity:0 + pointer-events:none -> không nuốt cú bấm vào phím), chỉ hiện khi rê vào phím.
   KHÔNG kẹt hover: rê vào chính huy hiệu thì tổ tiên .tagchip-wrap cũng :hover -> nó vẫn hiện để bấm.

   VÌ SAO KHÔNG DÙNG NỀN KÍNH NỮA: phím đang chọn có viên đèn TRẮNG nằm dưới, huy hiệu kính trắng
   đặt lên đó thì chìm nghỉm thành một cục mờ. Giờ: chấm ĐỎ ĐẶC + vành mỏng màu mặt kính của thanh
   -> luôn tách khỏi thứ nằm sau (đèn trắng hay nền kính, Sáng lẫn Tối) mà không cần rule riêng cho
   từng theme (--danger/--on-danger/--glass-strong đều tự đổi theo theme).

   VỊ TRÍ: GÓC TRÊN-PHẢI, lệch -3px mỗi chiều. Phím bo tròn hoàn toàn (bán kính = nửa chiều cao)
   nên điểm 45° trên cung nằm ở đúng (-3,-3) so với góc hộp: đặt tâm huy hiệu ở đó thì nó TIẾP
   TUYẾN với cung — ngồi trên mép phím chứ không bay lơ lửng ngoài góc như bản -5px.
   (Đã thử neo giữa cạnh phải; chủ dự án chọn quay lại góc.) */
.tagchip-wrap{ position:relative; display:inline-flex; }
.tagchip__x{
  position:absolute; top:-3px; right:-3px; z-index:3;
  width:18px; height:18px; display:grid; place-items:center; cursor:pointer;
  border-radius:50%;
  background:var(--danger); color:var(--on-danger);
  border:1.5px solid var(--glass-strong);
  box-shadow:0 1px 4px color-mix(in srgb, var(--danger) 45%, transparent);
  opacity:0; pointer-events:none;
  transform:scale(.4); transform-origin:35% 65%;                    /* bung RA TỪ trong góc phím */
  transition:opacity .14s var(--ease), transform .22s var(--spring),
             background .14s var(--ease), box-shadow .14s var(--ease);
}
.tagchip__x svg{ width:10px; height:10px; stroke-width:3; }    /* nét dày: 10px vẫn đọc rõ là dấu ✕ */
/* Vòng tròn chỉ 18px cho gọn mắt, nhưng ::after nới VÙNG BẤM lên 36×36 (ngưỡng tối thiểu).
   ::after trong suốt nên không đổi gì về thị giác. */
.tagchip__x::after{ content:""; position:absolute; inset:-9px; border-radius:50%; }
.tagchip-wrap:hover .tagchip__x,
.tagchip-wrap:focus-within .tagchip__x{ opacity:1; transform:none; pointer-events:auto; }
/* Rê THẲNG vào huy hiệu: đỏ đậm hơn + nhỉnh lên. Phải đặc hiệu HƠN rule hiện-ra ở trên (0,3,0),
   không thì `transform:none` của nó đè mất — đúng cái bẫy đã dính ở bản trước. */
.tagchip-wrap:hover .tagchip__x:hover,
.tagchip-wrap:focus-within .tagchip__x:hover{
  background:var(--danger-press); transform:scale(1.12);
  box-shadow:0 2px 9px color-mix(in srgb, var(--danger) 55%, transparent);
}
.tagchip-wrap:hover .tagchip__x:active{ transform:scale(.94); }
.tagchip__x:focus-visible{ outline:none; opacity:1; transform:none; pointer-events:auto; box-shadow:0 0 0 3px var(--ring-soft); }
/* Đèn tuýp mọc ngay ĐỈNH phím đang chọn -> đúng chỗ huy hiệu vừa hiện ra. Khi rê vào phím tự tạo
   ĐANG CHỌN thì cho đèn lùi lại, khỏi chồng hai thứ sáng-tối lên nhau ở cùng một góc.
   (:has không hỗ trợ -> rule bị bỏ qua, đèn giữ nguyên; không hỏng gì.) */
.tagbar:has(.tagchip-wrap:hover .tagchip.is-active) .tagbar__glow{ opacity:.16; }

/* Cảm ứng (không có chuột): không rê được -> LUÔN hiện. To hơn chút và ::after nới VÙNG CHẠM ra
   ~36px (ngón tay bấm trúng mà huy hiệu vẫn nhỏ gọn trên màn hình). */
@media (hover:none){
  .tagchip__x{ opacity:1; transform:none; pointer-events:auto; width:22px; height:22px; top:-5px; right:-5px; }
  .tagchip__x svg{ width:11px; height:11px; }
  .tagchip__x::after{ inset:-7px; }                             /* 22 + 7×2 = 36px vùng chạm */
}

/* Phím "+ Thêm loại" — luôn ở CUỐI taskbar, tạo loại mới bất cứ lúc nào (chỉ thành viên) */
.tagchip--add{
  display:inline-flex; align-items:center; gap:7px;
  margin-left:4px; color:var(--accent);
}
.tagchip--add::before{                                  /* vạch ngăn: bên trái là BỘ LỌC, bên phải là HÀNH ĐỘNG */
  content:""; position:absolute; left:-4px; top:50%; transform:translateY(-50%);
  width:1px; height:19px; background:color-mix(in srgb,var(--text) 16%,transparent);
}
.tagchip--add svg{ width:16px; height:16px; }
.tagchip--add:hover{ color:var(--accent-press); }
/* Ô nhập tên loại mới — hiện TẠI CHỖ phím "+", không cần mở hộp thoại */
.tagbar__add{ position:relative; z-index:1; display:inline-flex; align-items:center; gap:5px; padding-left:5px; }
.tagbar__input{
  width:min(190px,44vw); height:36px; padding:0 13px; border-radius:var(--pill);
  font-size:16px; font-weight:600;                      /* ≥16px: iOS không tự phóng to trang khi bấm vào ô */
  color:var(--text); background:var(--glass-strong);
  border:1px solid color-mix(in srgb,var(--accent) 45%,var(--line));
}
.tagbar__input:focus{ outline:none; border-color:var(--accent); box-shadow:0 0 0 3px var(--ring-soft); }
.tagbar__ok, .tagbar__cancel{
  width:34px; height:34px; display:grid; place-items:center; border-radius:50%; cursor:pointer;
  transition:background .16s var(--ease), color .16s var(--ease);
}
.tagbar__ok svg, .tagbar__cancel svg{ width:16px; height:16px; }
.tagbar__ok{ background:var(--accent); color:var(--on-accent); }
.tagbar__ok:hover{ background:var(--accent-press); }
.tagbar__cancel{ background:var(--glass-2); color:var(--text-2); }
.tagbar__cancel:hover{ color:var(--text); }

/* Nhãn loại trên mỗi hàng tài liệu */
.row__tag{
  flex-shrink:0; font-size:16px; line-height:1.5; font-weight:600; white-space:nowrap;
  padding:3px 13px; border-radius:var(--pill);
  background:var(--accent-soft); color:var(--accent-press); border:1px solid transparent;
}
@media (max-width:560px){ .row__tag{ display:none; } }   /* màn hẹp: ưu tiên tên + nút, tag đã có ở thanh lọc */

/* Huy hiệu MỚI — tệp người khác tải lên sau lần bạn ghé gần nhất.
   KHÔNG ẩn ở màn hẹp như .row__tag: nhãn này nhỏ hơn nhiều, và nó chính là thứ người ta mở app để tìm. */
.row__new{
  flex-shrink:0; font-size:12px; line-height:1.5; font-weight:700; white-space:nowrap;
  padding:3px 10px; border-radius:var(--pill); letter-spacing:.01em;
  background:var(--apple); color:var(--on-slate); border:1px solid transparent;
}
.doclist.is-grid .row__new{ align-self:flex-start; }

/* Hàng ĐÃ GHIM: viền + nền nhấn nhẹ; huy hiệu ghim đứng trước tên */
.row.is-pinned{ border-color:color-mix(in srgb,var(--accent) 42%,var(--line)); background:color-mix(in srgb,var(--accent-soft) 55%,var(--glass)); }
.row__pinbadge{ display:inline-flex; vertical-align:-2px; color:var(--accent); margin-right:6px; }
.row__pinbadge svg{ width:15px; height:15px; }
.act--pinned{ color:var(--accent); background:var(--accent-soft); }
.act--pinned:hover{ color:var(--accent-press); background:var(--accent-soft); }

/* Ô đổi tên INLINE (thay chỗ tên ngay trong hàng) */
.row__rename{
  width:100%; min-width:0; font-size:16px; line-height:1.5; font-weight:650;
  padding:6px 10px; border-radius:var(--r-sm);
  border:1px solid var(--apple); background:var(--glass-strong); color:var(--text);
}
.row__rename:focus{ outline:none; box-shadow:0 0 0 3px var(--ring-soft); }

/* Chip chọn/quản lý loại khi upload (trong modal) — active dùng terracotta để phân biệt với thanh lọc */
/* Danh sách tệp trùng trong hộp thoại cảnh báo */
.duplist{
  margin:12px 0 14px; padding-left:20px; display:flex; flex-direction:column; gap:7px;
  font-size:14px; line-height:1.5; color:var(--text-2);
}
.duplist b{ color:var(--text); font-weight:650; overflow-wrap:anywhere; }

.tagpickbar{ display:flex; flex-wrap:wrap; align-items:center; gap:10px; margin-top:14px; }
.tagpick.is-active{ background:var(--accent); border-color:var(--accent); color:var(--on-accent); }
.tagpick-item{ position:relative; display:inline-flex; }
/* nút ✕ xoá loại — góc trên-phải chip; hiện khi rê chuột / trên cảm ứng luôn hiện */
.tagpick-del{
  position:absolute; top:-7px; right:-7px; width:22px; height:22px; z-index:2;
  display:grid; place-items:center; border-radius:50%; cursor:pointer;
  background:var(--danger); color:var(--on-danger); border:2px solid var(--glass-strong);
  opacity:0; transition:opacity .14s var(--ease);
}
.tagpick-del svg{ width:12px; height:12px; }
.tagpick-item:hover .tagpick-del, .tagpick-del:focus-visible{ opacity:1; }
.tagpick-del:focus-visible{ outline:none; box-shadow:0 0 0 3px var(--ring-soft); }
@media (hover:none){ .tagpick-del{ opacity:1; } }
/* chip "+ Thêm loại" (nét đứt) + ô nhập tên loại mới */
.tagpick-new{ display:inline-flex; align-items:center; gap:6px; border-style:dashed; color:var(--accent); }
.tagpick-new svg{ width:16px; height:16px; }
.tagpick-add{ display:inline-flex; align-items:center; gap:8px; }
.tagpick-add .input{ width:min(200px,60vw); }
/* nút "Tạo": đồng bộ cỡ/chữ với "Tải lên" (.modal__foot .btn) — giữ màu slate (.btn-slate) */
.btn-sm{ height:50px; padding:0 24px; font-size:16px; }

/* --- THÙNG RÁC ---------------------------------------------------
   Dùng lại .row nguyên vẹn (icon · tên · metadata · hành động) nên không phát sinh
   đường render thứ hai; chỉ thêm huy hiệu đếm ngược và làm hàng nhạt đi một chút
   để nhìn là biết "đây không phải kho, đây là chỗ chờ xoá". */
.hdr-trash{ display:none; }                        /* khách không xoá/khôi phục được -> ẩn hẳn */
body.is-member .hdr-trash{ display:grid; }

.row--trash{ background:var(--glass-2); }
/* Ở kho, cụm nút ẩn đến khi rê chuột cho danh sách sạch. Nhưng vào Thùng rác thì "Khôi phục"
   CHÍNH LÀ việc người ta tới đây để làm — ẩn nó đi là bắt đoán. Luôn hiện. */
.row--trash .row__actions{ opacity:1; }
.row--trash .ficon{ opacity:.72; }
.row--trash .row__name{ color:var(--text-2); }
.row--trash:hover .row__name{ color:var(--text); }

.trashleft{
  flex-shrink:0; font-size:12.5px; font-weight:650; white-space:nowrap;
  padding:4px 11px; border-radius:var(--pill);
  background:var(--glass-strong); border:1px solid var(--line); color:var(--text-2);
  font-variant-numeric:tabular-nums;
}
/* Sắp hết hạn: đỏ + CHỮ đổi luôn ("còn 6 giờ"/"sắp bị xoá") — không chỉ dựa vào màu. */
.trashleft.is-urgent{
  background:color-mix(in srgb, var(--danger) 12%, transparent);
  border-color:color-mix(in srgb, var(--danger) 34%, transparent);
  color:var(--danger);
}

/* ---------------------------------------------------------------
   11. CHỌN NHIỀU (bulk) — nút bật · checkbox trên hàng · thanh thao tác đáy
--------------------------------------------------------------- */
.row__check{
  /* dấu ✓ dùng --on-accent (không phải #fff cứng): nền tick là --accent, ở chế độ Tối
     accent SÁNG lên nên chữ trắng mất tương phản — --on-accent tự đảo đúng theo theme */
  flex-shrink:0; width:26px; height:26px; border-radius:8px; color:var(--on-accent);
  border:2px solid var(--text-3); background:var(--glass); display:grid; place-items:center;
  transition:background .14s var(--ease), border-color .14s var(--ease);
}
.row__check svg{ width:16px; height:16px; }
.row__check.is-on{ background:var(--accent); border-color:var(--accent); }
.row--sel{ cursor:pointer; }
.row.is-selected{ border-color:var(--accent); background:color-mix(in srgb,var(--accent-soft) 65%,var(--glass)); }
/* (.row--locked đã bỏ: chế độ chọn giờ cho chọn MỌI tệp — xem ghi chú ở selIdsAll() trong app.js) */
.doclist.is-selmode{ padding-bottom:110px; }         /* chừa chỗ cho thanh bulk cố định */

/* Thanh thao tác hàng loạt — DOCK kính mờ nổi ở đáy (hiệu ứng giống taskbar cũ):
   nền trong mờ + bão hoà, viền sáng specular, inset highlight, trượt lên khi hiện. */
.bulkbar{
  position:fixed; left:50%; bottom:calc(20px + env(safe-area-inset-bottom)); transform:translateX(-50%);
  z-index:150; display:flex; align-items:center; gap:10px; flex-wrap:wrap; justify-content:center;
  /* `width:max-content` KHÔNG phải cho đẹp: thiếu nó thì hộp `position:fixed` này co vừa nội dung
     trong khoảng từ `left:50%` tới mép phải — tức CHỈ NỬA màn — nên dock gãy làm 2 hàng dù màn
     1280px còn thừa cả trăm pixel. (.toasts bên dưới đã dùng đúng mẹo này từ trước.) */
  width:max-content; max-width:calc(100vw - 24px); padding:11px 15px; border-radius:26px;
  background:linear-gradient(177deg, rgba(255,255,255,.6), rgba(255,255,255,.36));
  backdrop-filter:var(--glass-bf); -webkit-backdrop-filter:var(--glass-bf);
  border:1px solid rgba(255,255,255,.6);
  box-shadow:
    0 14px 38px rgba(20,20,28,.18),
    0 3px 8px rgba(20,20,28,.08),
    inset 0 1px 0 rgba(255,255,255,.92),
    inset 0 0 0 .5px rgba(255,255,255,.32);
  animation:dockIn .34s var(--spring) both;
}
:root[data-theme="dark"] .bulkbar{
  background:linear-gradient(177deg, rgba(74,96,124,.58), rgba(40,56,76,.5));
  border-color:rgba(255,255,255,.14);
  box-shadow:
    0 14px 38px rgba(0,0,0,.5),
    inset 0 1px 0 rgba(255,255,255,.16),
    inset 0 0 0 .5px rgba(255,255,255,.06);
}
:root[data-fx="off"] .bulkbar{ background:var(--glass-strong); backdrop-filter:none; -webkit-backdrop-filter:none; border-color:var(--line); animation:none; }
@keyframes dockIn{ from{ opacity:0; transform:translateX(-50%) translateY(16px); } to{ opacity:1; transform:translateX(-50%) translateY(0); } }
.bulkbar__count{ font-size:16px; font-weight:700; color:var(--text); padding:0 6px; white-space:nowrap; }
.bulkbar__spacer{ width:1px; height:26px; background:color-mix(in srgb,var(--text-3) 40%,transparent); margin:0 2px; }
@media (max-width:560px){
  /* width:auto để trả lại quyền cho cặp left/right — max-content ở trên sẽ giữ dock co lại, không giãn hết bề ngang. */
  .bulkbar{ left:12px; right:12px; width:auto; transform:none; max-width:none; gap:8px; padding:10px; border-radius:22px; animation:dockInM .34s var(--spring) both; }
  .bulkbar__spacer{ display:none; }
  .bulkbar__count{ width:100%; text-align:center; padding:2px 0; }
  /* KHÔNG dùng lưới 2 cột cứng ở đây (đã thử và ĐO ĐƯỢC là sai): ô nửa hàng chỉ còn ~92px chữ,
     mà "Xoá vĩnh viễn (3)" cần 118px -> cụt mất dấu ")" ngay từ 390px. Nhãn cụt trên một nút
     XOÁ KHÔNG HOÀN TÁC ĐƯỢC là thứ tuyệt đối không đánh đổi lấy sự thẳng cột.
       flex-basis:0 + flex-grow:1 -> các nút CÙNG HÀNG chia đều bề ngang (hết ragged);
       min-width:max-content     -> nhưng không bao giờ co nhỏ hơn chữ (hết cụt).
     Nút nào chữ dài quá thì tự xuống hàng riêng và chiếm trọn — đúng thứ tự ưu tiên. */
  .bulkbar .btn{ flex:1 1 0; min-width:max-content; padding:0 14px; }
  .doclist.is-selmode{ padding-bottom:150px; }
}
@media (max-width:360px){
  .bulkbar .btn{ padding:0 10px; }
}
@keyframes dockInM{ from{ opacity:0; transform:translateY(16px); } to{ opacity:1; transform:none; } }
@media (prefers-reduced-motion:reduce){ .bulkbar{ animation:none; } }

@keyframes cardIn{ from{opacity:0; transform:translateY(9px);} to{opacity:1; transform:none;} }

/* Bảng phím tắt + gợi ý "Bấm ? …" (chỉ máy có bàn phím mới thấy) */
.keylist{ list-style:none; margin:14px 0 16px; padding:0; display:flex; flex-direction:column; gap:10px; }
.keylist li{ display:flex; align-items:center; gap:14px; font-size:15px; color:var(--text-2); }
kbd{
  min-width:34px; padding:5px 9px; text-align:center;
  font-family:var(--mono); font-size:13px; font-weight:700; color:var(--text);
  background:var(--glass-strong); border:1px solid var(--line);
  border-bottom-width:2px; border-radius:8px; box-shadow:var(--hl);
}
/* Dòng dung lượng — nằm ngay trong .page-sub sẵn có, không phải widget riêng */
/* Xuống hẳn dòng riêng: để nguyên trong câu thì câu bị ngắt giữa cụm ("Kho / đang giữ") và
   con số tranh chỗ với lời hướng dẫn chính. Cùng màu, chỉ nhấn nhẹ bằng độ đậm. */
.usage{ display:block; color:inherit; font-weight:600; margin-top:4px; }
.usage.is-hot{ color:var(--danger); font-weight:700; }

.kbdhint{ color:var(--text-3); }
.kbdhint kbd{ min-width:0; padding:2px 6px; font-size:12px; border-bottom-width:1px; }
/* Điện thoại/máy tính bảng không có phím -> gợi ý này chỉ làm rối. */
@media (pointer:coarse){ .kbdhint{ display:none; } }

/* ---------------------------------------------------------------
   12. Trạng thái trống · đang tải · lỗi
--------------------------------------------------------------- */
.empty{
  width:100%; max-width:540px; margin:0 auto;
  text-align:center; padding:48px 36px;
  border:1px solid var(--line); border-radius:var(--r-lg); background:var(--glass); box-shadow:var(--shadow-1),var(--hl);
}
.empty__icon{
  width:74px; height:74px; margin:0 auto 20px; border-radius:22px;
  background:var(--glass-2); color:var(--text-3); display:grid; place-items:center; border:1px solid var(--line);
}
.empty__icon svg{ width:38px; height:38px; stroke-width:1.2; }   /* icon to, nét MẢNH (spec: Lucide stroke-1 mềm mại) */
.empty__title{ font-size:21px; font-weight:750; letter-spacing:-.02em; }
.empty__text{ font-size:15.5px; line-height:1.6; color:var(--text-2); margin:9px auto 0; max-width:400px; }
.empty__actions{ margin-top:24px; display:inline-flex; gap:12px; flex-wrap:wrap; justify-content:center; }
.empty--error .empty__icon{ background:var(--bad-bg); color:var(--bad); border-color:transparent; }

@keyframes shimmer{ to{ transform:translateX(100%); } }

/* ---------------------------------------------------------------
   13. Modal · xem trước
--------------------------------------------------------------- */
.scrim{
  position:fixed; inset:0; z-index:200; display:grid; place-items:center; padding:16px;
  background:rgba(15,23,42,.5);                   /* bỏ blur(3px) toàn màn hình: đắt nhất file mà gần như vô hình dưới lớp tối 50% */
  opacity:0; transition:opacity .2s var(--ease);
}
.scrim.on{ opacity:1; }
.scrim[hidden]{ display:none; }
.modal{
  width:100%; max-width:520px; border-radius:var(--r-lg);
  max-height:calc(100dvh - 32px); overflow-y:auto;   /* nội dung cao thì cuộn, không tràn màn hình */
  background:var(--glass-strong); border:1px solid var(--line);
  box-shadow:var(--shadow-2);                     /* bỏ backdrop-filter: nền đã đặc 95% -> blur phía sau vô nghĩa mà phải tính mỗi frame khi modal trượt vào */
  transform:translateY(10px) scale(.98); opacity:0;
  transition:transform .2s var(--spring), opacity .2s var(--ease);
}
.scrim.on .modal{ transform:none; opacity:1; }
.modal--wide{ max-width:820px; }
.modal__head{ display:flex; align-items:center; gap:15px; padding:28px 28px 0; }
.modal__title{ font-size:21px; font-weight:750; flex:1; letter-spacing:-.02em; }
.modal__head .ficon{ width:50px; height:50px; }
.modal__head .ficon svg{ width:24px; height:24px; }
.modal__head--danger .ficon{ background:color-mix(in srgb,var(--danger) 12%,transparent); color:var(--danger); border-color:transparent; }
.modal__body{ padding:20px 28px; }
.modal__text{ font-size:16.5px; color:var(--text-2); line-height:1.65; overflow-wrap:anywhere; }
.modal__text b{ color:var(--text); }
/* 3 nút (Sao chép link · Tải xuống · Đóng) không lọt một hàng ở màn hẹp -> cho xuống dòng.
   Nút PHỤ ("Sao chép link") dạt hẳn sang trái để 2 nút chính vẫn đứng cạnh nhau bên phải. */
.modal__foot{ display:flex; flex-wrap:wrap; justify-content:flex-end; gap:12px; padding:0 28px 28px; }
.modal__foot [data-copy]{ margin-right:auto; }
@media (max-width:480px){
  /* Màn hẹp: bỏ việc đẩy nút phụ sang trái (mục 18/24 đã cho các nút tự chia đều bề ngang,
     ra đúng bố cục mong muốn: hàng 1 "Sao chép link" + "Tải xuống", hàng 2 "Đóng" trọn hàng). */
  .modal__foot [data-copy]{ margin-right:0; }
  .modal__foot .btn{ padding:0 18px; }
}
/* Modal: nút + ô nhập to hơn cho dễ đọc/bấm (chỉ trong modal, không đụng header) */
.modal__foot .btn{ height:50px; font-size:16px; padding:0 24px; }
.modal .input{ height:50px; font-size:16px; }
.modal .field label{ font-size:14.5px; }
.field{ display:flex; flex-direction:column; gap:8px; }
.field label{ font-size:13px; font-weight:650; color:var(--text-2); }
.input{
  height:44px; padding:0 14px; width:100%;
  border:1px solid var(--line); border-radius:var(--r-sm);
  background:var(--glass); color:var(--text);
  transition:border-color .18s var(--ease), box-shadow .18s var(--ease);
}
.input:focus{ outline:none; border-color:var(--apple); box-shadow:0 0 0 3px var(--ring-soft); }

/* Dòng thông tin đầu preview: .pdf · 500 KB · 29/05/2026 · Bạn · Đề thi · Kế toán tài chính
   Ngăn cách bằng dấu chấm VẼ BẰNG CSS -> khi xuống dòng không còn dấu chấm mồ côi đầu dòng. */
.preview__info{
  display:flex; flex-wrap:wrap; align-items:center; gap:5px 9px;
  margin:0 0 14px; font-size:13.5px; color:var(--text-2);
}
.preview__info > span:not(:last-child)::after{ content:"·"; margin-left:9px; color:var(--text-3); }
.preview__info-warn{ color:var(--danger); font-weight:650; }

.preview{ background:var(--glass-2); border-radius:var(--r-md); overflow:hidden; display:grid; place-items:center; min-height:220px; max-height:64vh; border:1px solid var(--line); }
.preview img{ max-width:100%; max-height:64vh; object-fit:contain; }
.preview iframe{ width:100%; height:64vh; border:0; background:#fff; }
.preview pre{ width:100%; max-height:64vh; overflow:auto; margin:0; padding:18px; font-family:var(--mono); font-size:13px; line-height:1.6; white-space:pre-wrap; word-break:break-word; text-align:left; color:var(--text); }
.preview__fallback{ text-align:center; padding:40px; color:var(--text-2); }
.preview__fallback svg{ width:42px; height:42px; margin:0 auto 12px; color:var(--text-3); }

/* ---------------------------------------------------------------
   14. Toasts (aria-live) — có Hoàn tác
--------------------------------------------------------------- */
.toasts{ position:fixed; left:50%; bottom:28px; transform:translateX(-50%); z-index:250; display:flex; flex-direction:column; gap:8px; align-items:center; width:max-content; max-width:calc(100vw - 32px); pointer-events:none; }
.toast{
  pointer-events:auto; display:flex; align-items:center; gap:12px;
  padding:11px 16px; border-radius:14px;
  background:var(--text); color:var(--bg); font-size:14px; font-weight:600;
  box-shadow:var(--shadow-2);
  animation:toastIn .26s var(--spring) both;
}
.toast.out{ animation:toastOut .22s var(--ease) forwards; }
.toast svg{ width:18px; height:18px; }
.toast--ok svg{ color:var(--ok); } .toast--bad svg{ color:var(--bad); }
/* dùng chính màu chữ của toast (var(--bg)) -> luôn đủ tương phản ở cả 2 theme; nền tint terracotta + gạch chân để nhận biết là hành động */
.toast__act{ margin-left:4px; padding:5px 11px; border-radius:9px; font-weight:750; color:var(--bg); background:color-mix(in srgb,var(--accent) 34%,transparent); text-decoration:underline; text-underline-offset:2px; }
.toast__act:hover{ background:color-mix(in srgb,var(--accent) 50%,transparent); }
@keyframes toastIn{ from{opacity:0; transform:translateY(14px);} to{opacity:1; transform:none;} }
@keyframes toastOut{ to{opacity:0; transform:translateY(8px);} }

/* (Mục 13 "macOS DOCK" đã gỡ — thay bằng TASK BAR tubelight ở đầu trang, xem mục 20.) */

/* ---------------------------------------------------------------
   15. Responsive — nền tảng
--------------------------------------------------------------- */
@media (max-width:720px){
  :root{ --gutter:16px; }
  .main{ padding:20px 0 44px; }
  .btn-label{ display:none; }
  /* .btn.hdr (không phải .btn-accent.hdr — nút Đăng nhập giờ là btn-outline): chữ đã ẩn
     ở trên thì thu về nút vuông icon, khỏi thành viên pill rỗng dài 60px */
  .btn.hdr{ width:42px; padding:0; }
}

/* ---------------------------------------------------------------
   16. Giảm chuyển động — bắt buộc theo /web
--------------------------------------------------------------- */
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{ animation-duration:.001ms !important; animation-iteration-count:1 !important; transition-duration:.001ms !important; scroll-behavior:auto !important; }
}

/* ---------------------------------------------------------------
   17. Xác thực Supabase — cổng đăng nhập + chip tài khoản
--------------------------------------------------------------- */
body.locked{ overflow:hidden; }

.authgate{
  position:fixed; inset:0; z-index:400;
  display:grid; place-items:center; padding:24px;
  background:var(--glass-strong);                 /* nền đặc thay blur toàn màn hình (audit): nhìn gần như cũ, rẻ hơn hẳn */
  overflow:auto;
}
.authgate[hidden]{ display:none; }

.auth-card{
  position:relative;
  width:100%; max-width:400px; margin:auto;
  background:var(--glass-strong); border:1px solid var(--line);
  border-radius:var(--r-lg); box-shadow:var(--shadow-2), var(--hl);
  padding:34px 30px; text-align:center;
  animation:authpop .32s var(--spring) both;
}
@keyframes authpop{ from{ opacity:0; transform:translateY(10px) scale(.98); } to{ opacity:1; transform:none; } }
@media (prefers-reduced-motion:reduce){ .auth-card{ animation:none; } }

.auth-brand{ display:inline-flex; align-items:center; gap:10px; font-weight:750; font-size:15px; color:var(--text); margin-bottom:20px; letter-spacing:-.01em; }
.auth-mark{ width:34px; height:34px; display:grid; place-items:center; border-radius:11px; background:var(--grad-avada); color:var(--on-slate); box-shadow:var(--hl); }
.auth-mark svg{ width:19px; height:19px; }

.auth-title{ font-size:24px; letter-spacing:-.03em; margin-bottom:7px; }
.auth-sub{ font-size:14px; color:var(--text-2); line-height:1.6; margin-bottom:22px; }
.auth-sub code{ font-family:var(--mono); font-size:.88em; background:var(--glass-2); padding:1px 6px; border-radius:6px; border:1px solid var(--line); color:var(--text); overflow-wrap:anywhere; }
.auth-sub b{ color:var(--text); font-weight:650; }

.auth-form{ display:flex; flex-direction:column; gap:14px; text-align:left; }
.auth-form .field label{ margin-left:2px; }
.auth-submit{ width:100%; height:46px; margin-top:4px; }
.auth-submit.is-busy{ opacity:.7; pointer-events:none; }

.auth-msg{ font-size:13px; line-height:1.5; padding:10px 12px; border-radius:var(--r-sm); border:1px solid var(--line); background:var(--glass-2); color:var(--text-2); }
.auth-msg[hidden]{ display:none; }
.auth-msg--bad{ background:var(--bad-bg); border-color:transparent; color:var(--bad); }
.auth-msg--ok{ background:rgba(16,185,129,.12); border-color:transparent; color:var(--ok); }

.auth-switch{ margin-top:20px; font-size:14px; color:var(--text-2); }
.linkbtn{ color:var(--accent); font-weight:650; padding:2px 4px; border-radius:8px; }
.linkbtn:hover{ text-decoration:underline; }

/* Chip tài khoản trên header */
.userchip{ display:inline-flex; align-items:center; gap:8px; height:42px; padding:0 6px 0 12px; border-radius:var(--pill); background:var(--glass); border:1px solid var(--line); }
.userchip[hidden]{ display:none; }
.userchip__avatar{ width:22px; height:22px; color:var(--apple); }
.userchip__avatar svg{ width:22px; height:22px; }
.userchip__email{ font-size:13px; font-weight:600; color:var(--text-2); max-width:180px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.userchip__out{ width:36px; height:36px; }
.userchip__out svg{ width:17px; height:17px; }
@media (max-width:640px){ .userchip__email{ display:none; } .userchip{ padding:0 4px 0 8px; } }

/* ===============================================================
   18. Responsive nâng cao — phủ mọi cỡ máy
       Thang: desktop >1080 · tablet ≤1080 · phone ≤720 · phone thường ≤560
       · phone hẹp ≤430 · phone nhỏ ≤360 · landscape thấp
   =============================================================== */

/* Điện thoại thường (≤560): brand gọn, lưới CỐ ĐỊNH 2 cột (không bao giờ sập 1 cột),
   CTA hero xếp dọc, toolbar hàng 2 lấp đầy. */
@media (max-width:560px){
  .header-row{ gap:8px; }
  .brand{ padding:0 14px 0 10px; }
  .brand__sub{ display:none; }
  .dropzone{ padding:26px 16px; }
  .dropzone__title{ font-size:16px; }               /* spec typography: không tụt dưới 16px */
  .authgate{ padding:16px; }
  .auth-card{ padding:28px 22px; }

  /* Modal (vừa phóng to) + trạng thái trống — base nằm TRÊN khối này nên override tại đây có hiệu lực */
  .modal__title{ font-size:19px; }
  .modal__head .ficon{ width:46px; height:46px; }
  .modal__text{ font-size:16px; }
  .modal__foot .btn{ height:48px; font-size:16px; }
  .modal .input{ height:48px; }
  .empty{ padding:40px 24px; }
  .empty__title{ font-size:19px; }
  .empty__text{ font-size:16px; }                   /* spec typography: không tụt dưới 16px */
}

/* Điện thoại hẹp (≤430): thu nhỏ nút header, ẩn avatar chip, modal gọn lại */
@media (max-width:430px){
  .header-row{ gap:6px; }
  .iconbtn{ width:38px; height:38px; }
  .iconbtn svg{ width:18px; height:18px; }
  .btn.hdr{ width:40px; height:40px; }
  .userchip__avatar{ display:none; }
  .userchip{ height:40px; padding:0 4px 0 6px; }
  .userchip__out{ width:30px; height:30px; }

  .toasts{ bottom:24px; }

  .modal__head{ padding:18px 18px 0; }
  .modal__body{ padding:14px 18px; }
  .modal__foot{ padding:0 18px 18px; }
  .modal__title{ font-size:18.5px; }
}

/* Điện thoại nhỏ (≤360, vd iPhone SE): chỉ icon thương hiệu, nút modal xếp dọc */
@media (max-width:360px){
  :root{ --gutter:12px; }
  .tagchip{ padding:8px 15px; }                     /* phím taskbar gọn lại -> đỡ tràn */
  .brand__name{ display:none; }
  .iconbtn{ width:36px; height:36px; }
  .toasts{ bottom:22px; }
  .modal__foot{ flex-wrap:wrap; }
  .modal__foot .btn{ flex:1 1 auto; }
}

/* Màn THẤP & xoay ngang (landscape phone): nén theo chiều cao */
@media (max-height:500px) and (orientation:landscape){
  .main{ padding:12px 0 36px; }
  .dropzone{ padding:18px 16px; margin-bottom:16px; }
  .toasts{ bottom:20px; }
  .preview iframe{ height:56vh; }
  .authgate{ align-items:start; }
}

/* ---------------------------------------------------------------
   19. Cảm ứng (vùng chạm) (không có chuột): vùng chạm ≥40px + giãn nút xoá
       Trên máy cảm ứng, nút thao tác thẻ LUÔN hiện (không ẩn-đến-hover)
       nên 31px dễ bấm nhầm Xoá — phóng to & giãn khoảng cách.
--------------------------------------------------------------- */
@media (pointer:coarse){
  .act{ width:40px; height:40px; border-radius:11px; }
  .act svg{ width:17px; height:17px; }
  .row__actions{ gap:8px; }
  .userchip__out{ width:40px; height:40px; }
  .userchip__out svg{ width:18px; height:18px; }
  .linkbtn{ display:inline-block; padding:6px 8px; }
  .toast__act{ padding:8px 13px; }
}

/* ---------------------------------------------------------------
   20. Khách / Thành viên + Auth mở rộng (Google · quên/đặt lại mật khẩu)
--------------------------------------------------------------- */
/* Hiện/ẩn theo trạng thái: Khách thấy "Đăng nhập"; Thành viên thấy chip tài khoản */
body.is-member #signInBtn{ display:none; }

/* Nút "Tiếp tục với Google" — nền kính trung tính, logo 4 màu giữ nguyên */
.btn-google{
  width:100%; background:var(--glass-strong); color:var(--text); border:1px solid var(--line);
  box-shadow:var(--shadow-1),var(--hl); font-weight:600;
}
.btn-google:hover{ border-color:var(--text-3); }
.btn-google svg{ width:18px; height:18px; }

/* Dải "hoặc" giữa Google và form email */
.auth-or{ display:flex; align-items:center; gap:12px; margin:16px 0; color:var(--text-3); font-size:12.5px; }
.auth-or::before, .auth-or::after{ content:""; height:1px; flex:1; background:var(--line); }

/* Nút đóng cổng đăng nhập (quay về xem kho ở chế độ Khách) */
.auth-close{
  position:absolute; top:12px; right:12px; width:36px; height:36px;
  display:grid; place-items:center; border-radius:10px; color:var(--text-2);
  background:var(--glass-2); border:1px solid var(--line);
  transition:background .16s var(--ease), color .16s var(--ease);
}
.auth-close:hover{ background:var(--glass-strong); color:var(--text); }
.auth-close svg{ width:17px; height:17px; }

/* Thẻ tài liệu ở chế độ Khách: nút "Đăng nhập để tải xuống" (icon khoá) */
.act--login{ color:var(--accent); }
.act--login:hover{ background:var(--accent-soft); color:var(--accent-press); border-color:var(--accent); }

/* ===============================================================
   21. Môn học — chip phân loại (thẻ/hàng) + spacing modal + danh sách tệp upload
   =============================================================== */
/* Hai field trong modal (Sửa tài liệu / Tải lên) tách dòng — không đụng auth-form (ngoài .modal__body) */
.modal__body .field + .field{ margin-top:14px; }

/* ===============================================================
   22. Hiệu ứng "liquid" (đồng bộ TASK BAR) cho MỌI nút + dropdown
       - Bấm: NẢY gooey theo spring (1 lần/bấm, .liquid-press gắn bằng JS) — như viên pill trượt/giãn
       - Hover: control kính trung tính lên KÍNH BÓNG đúng chất .tagbar__lamp-pill
   =============================================================== */
@keyframes liquidPop{ 0%{ transform:scale(.94); } 42%{ transform:scale(1.035); } 100%{ transform:scale(1); } }
.liquid-press{ animation:liquidPop .42s var(--spring); }
/* Nổi lên khi phóng to -> không bị nút cạnh che.
   TUYỆT ĐỐI KHÔNG đặt `position` ở đây: `button.liquid-press` (0,1,1) thắng `.auth-close` (0,1,0)
   nên nó từng ép position:absolute -> relative ngay lúc pointerdown; nút ✕ văng khỏi góc, con trỏ
   không còn nằm trên nó, click không bao giờ tới -> "bấm vào là chạy đi chỗ khác".
   Không cần position: `transform` của liquidPop tự tạo stacking context nên nút đã được vẽ nổi
   trên mọi anh em tĩnh. z-index:2 chỉ là lớp bảo hiểm, và nó chỉ ăn khi nút đã positioned
   (.btn/.tagchip: relative · .auth-close/.tagpick-del: absolute) hoặc là flex item
   (.act/.iconbtn). Riêng .linkbtn trong .auth-switch (div block) không thoả cả hai
   -> z-index bị bỏ qua, nhưng transform vẫn đủ để nổi lên. */
button.liquid-press, select.liquid-press{ z-index:2; }

/* Kính bóng liquid khi hover — ĐÚNG vật liệu viên đèn, lấy từ token --lamp-bg/--lamp-shadow
   (mục 1, tự đổi theo theme -> không cần cặp rule dark riêng như trước). */
.iconbtn:hover,
.act:hover:not(.act--danger):not(.act--login){
  background:var(--lamp-bg);
  box-shadow:var(--lamp-shadow);
  color:var(--apple);
}
/* Dropdown: GIỮ mũi tên (không đổi background) — chỉ thêm viền sáng + đổ bóng như pill khi hover */
.select:hover{
  border-color:rgba(255,255,255,.55);
  box-shadow:var(--lamp-shadow);
}
:root[data-theme="dark"] .select:hover{ border-color:rgba(255,255,255,.14); }

/* ===============================================================
   23. Subject-first — Dashboard (lưới môn) + Workspace (breadcrumb + danh sách)
   =============================================================== */
a.brand{ text-decoration:none; color:inherit; transition:transform .12s var(--ease); }
a.brand:hover{ transform:translateY(-1px); }
a.brand:active{ transform:scale(.99); }

/* Trạng thái trống/lỗi -> căn giữa trong khoảng còn lại của viewport (không dồn lên đầu, dưới trống hoác) */
.state{ min-height:clamp(300px,56vh,600px); display:grid; place-items:center; }

/* Đầu mỗi màn: tiêu đề + nút/đếm */
/* Đầu trang căn GIỮA (Dashboard + Workspace): tiêu đề · mô tả · nút/đếm xếp dọc, giữa cho cân đối */
.page-head{ display:flex; flex-direction:column; align-items:center; text-align:center; gap:14px; margin:6px 0 26px; }
.page-title{ font-size:clamp(28px,3.8vw,40px); font-weight:800; letter-spacing:-.03em; overflow-wrap:anywhere; }
.page-sub{ color:var(--text-2); font-size:16px; margin-top:6px; max-width:62ch; margin-inline:auto; }
.page-count{ font-size:14px; font-weight:650; color:var(--text-2); background:var(--glass-2); border:1px solid var(--line); padding:9px 16px; border-radius:var(--pill); white-space:nowrap; box-shadow:var(--hl); }

/* Lưới môn học */
/* auto-fit: thẻ GIÃN ra lấp đầy chiều ngang (ít thẻ -> mỗi thẻ rộng/bè hơn, 1 thẻ -> gần full hàng) */
.subjects{ display:grid; gap:18px; grid-template-columns:repeat(auto-fit,minmax(320px,1fr)); }
.subject-card{
  position:relative;
  display:flex; align-items:center; gap:18px; padding:26px; border-radius:var(--r-md);
  background:var(--glass); border:1px solid var(--line); color:var(--text);
  box-shadow:var(--shadow-1),var(--hl);
  transition:border-color .18s var(--ease), transform .18s var(--ease), box-shadow .18s var(--ease);
}
.subject-card:hover{ border-color:var(--text-3); transform:translateY(-2px); box-shadow:var(--shadow-2); }
.subject-card:focus-visible{ outline:none; box-shadow:0 0 0 3px var(--ring-soft); border-color:var(--apple); }
.subject-card.sk{ pointer-events:none; }
.subject-card__icon{ width:60px; height:60px; flex-shrink:0; border-radius:16px; display:grid; place-items:center; background:var(--grad-soft); color:var(--apple); border:1px solid var(--line); }
.subject-card__icon svg{ width:29px; height:29px; }
.subject-card__body{ flex:1; min-width:0; display:flex; flex-direction:column; gap:4px; }
.subject-card__name{ font-size:20px; font-weight:750; letter-spacing:-.01em; overflow-wrap:anywhere; }
.subject-card__meta{ font-size:14px; color:var(--text-2); }
/* Chữ, không phải chấm màu: người mù màu và trình đọc màn hình đều nhận được thông tin. */
.subject-card__new{ color:var(--accent-press); font-weight:700; white-space:nowrap; }
.subject-card__go{ color:var(--text-3); flex-shrink:0; transition:transform .18s var(--ease), color .18s var(--ease); }
.subject-card__go svg{ width:24px; height:24px; }
.subject-card:hover .subject-card__go{ transform:translateX(3px); color:var(--accent); }
.subjects.anim .subject-card{ animation:cardIn .34s var(--ease) both; }

/* Cụm nút Sửa/Xoá môn — NẰM TRONG hàng (thay mũi tên), không đè lên tên. Luôn hiện (mờ), rõ khi rê/nhấn. Chỉ chủ môn. */
.subject-card__acts{ display:flex; gap:4px; flex-shrink:0; }
.subject-card__act{
  width:36px; height:36px; display:grid; place-items:center; border-radius:10px; cursor:pointer;
  color:var(--text-3); background:transparent; border:1px solid transparent;
  transition:background .16s var(--ease), color .16s var(--ease), border-color .16s var(--ease);
}
.subject-card__act svg{ width:16px; height:16px; }
.subject-card__act:hover{ background:var(--glass-2); color:var(--text); border-color:var(--line); }
.subject-card__act:focus-visible{ outline:none; box-shadow:0 0 0 3px var(--ring-soft); }
.subject-card__act--del:hover{ background:color-mix(in srgb,var(--danger) 12%,transparent); color:var(--danger); border-color:var(--danger); }
.subject-card__act--del:focus-visible{ color:var(--danger); }

/* Breadcrumb Workspace */
.crumb{ display:flex; justify-content:center; align-items:center; gap:8px; font-size:15px; color:var(--text-2); margin:4px 0 12px; flex-wrap:wrap; }
.crumb__link{ color:var(--text-2); font-weight:600; padding:4px 8px; border-radius:8px; transition:background .16s var(--ease), color .16s var(--ease); }
.crumb__link:hover{ background:var(--glass-2); color:var(--apple); }
.crumb__sep{ color:var(--text-3); }
.crumb__cur{ color:var(--text); font-weight:700; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; max-width:60vw; }

/* Danh sách tài liệu (Workspace) — kích thước hàng nằm ở base .row (mục 9); .row chỉ render trong .doclist */
.doclist{ display:flex; flex-direction:column; gap:12px; }
.doclist.anim .row{ animation:cardIn .34s var(--ease) both; }

/* LƯỚI — CÙNG một .row, chỉ đổi cách bày: JS không có nhánh render thứ hai, nên chọn nhiều /
   FLIP / thumbnail lười vẫn chạy y nguyên. Hợp với môn nhiều ẢNH (thumbnail to, nhìn là nhận ra). */
.doclist.is-grid{ display:grid; gap:14px; grid-template-columns:repeat(auto-fill,minmax(212px,1fr)); }
/* flex-wrap:nowrap là BẮT BUỘC, không phải cho đẹp: ở ≤640 .row có flex-wrap:wrap. Cột + wrap
   nghĩa là con được phép TRÀN SANG CỘT MỚI — cụm 5 nút hành động (tối thiểu 232px khi chạm)
   tự tách thành cột riêng rồi bị align-content:center đẩy LÒI RA HAI BÊN thẻ. */
.doclist.is-grid .row{ position:relative; flex-direction:column; flex-wrap:nowrap; align-items:stretch; gap:11px; padding:12px; }
.doclist.is-grid .ficon,
.doclist.is-grid .row__thumb{ width:100%; height:106px; border-radius:13px; }
.doclist.is-grid .ficon svg{ width:30px; height:30px; }
.doclist.is-grid .row__body{ flex:none; }
.doclist.is-grid .row__name{
  font-size:15px; white-space:normal; text-overflow:clip;
  display:-webkit-box; -webkit-line-clamp:2; line-clamp:2; -webkit-box-orient:vertical; overflow:hidden;
}
.doclist.is-grid .row__meta{ white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.doclist.is-grid .row__tag{ align-self:flex-start; max-width:100%; overflow:hidden; text-overflow:ellipsis; }
/* Thẻ hẹp hơn tổng bề ngang 5 nút -> cho XUỐNG DÒNG trong thẻ, thay vì tràn ra ngoài. */
.doclist.is-grid .row__actions{ flex-wrap:wrap; justify-content:flex-end; gap:6px; }
/* Ô tick nổi lên góc ảnh (ở dạng hàng nó nằm trong dòng, ở dạng thẻ sẽ chiếm nguyên 1 dòng) */
.doclist.is-grid .row__check{ position:absolute; top:20px; left:20px; z-index:2; box-shadow:var(--shadow-1); }
.row.sk{ pointer-events:none; }

/* Skeleton cho môn + hàng tài liệu (shimmer dùng chung) */
.subject-card.sk .subject-card__icon,
.subject-card.sk .subject-card__name,
.subject-card.sk .subject-card__meta,
.row.sk .ficon, .row.sk .row__name, .row.sk .row__meta{
  background:var(--glass-2); color:transparent; border-radius:var(--r-sm); position:relative; overflow:hidden;
}
.subject-card.sk .subject-card__name{ height:15px; width:70%; }
.subject-card.sk .subject-card__meta{ height:11px; width:40%; }
.row.sk .row__name{ height:14px; width:52%; } .row.sk .row__meta{ height:11px; width:32%; }
.subject-card.sk .subject-card__icon::after, .subject-card.sk .subject-card__name::after,
.subject-card.sk .subject-card__meta::after,
.row.sk .ficon::after, .row.sk .row__name::after, .row.sk .row__meta::after{
  content:""; position:absolute; inset:0;
  background:linear-gradient(90deg,transparent,color-mix(in srgb,var(--glass-strong) 70%,transparent),transparent);
  transform:translateX(-100%); animation:shimmer 1.3s infinite;
}

/* ===============================================================
   RESPONSIVE — Dashboard/Workspace (subject-first). ĐẶT SAU phần base
   ở trên để override có hiệu lực (cascade). Thang: tablet ≤900 · phone
   ≤560 · phone hẹp ≤430 · nhỏ ≤360 · cảm ứng.
   =============================================================== */
@media (max-width:900px){
  .subjects{ grid-template-columns:repeat(auto-fit,minmax(220px,1fr)); gap:16px; }
}
@media (max-width:560px){
  .subjects{ grid-template-columns:1fr; gap:14px; }
  .page-head{ align-items:stretch; margin-bottom:20px; }
  .page-head [data-add-subject]{ width:100%; justify-content:center; }
  .page-count{ align-self:center; }                 /* badge đếm không bị kéo giãn full hàng */
  .subject-card{ padding:20px; gap:15px; }
  .subject-card__icon{ width:52px; height:52px; border-radius:14px; }
  .subject-card__icon svg{ width:26px; height:26px; }
  .subject-card__name{ font-size:18px; }
  .subject-card__meta{ font-size:13px; }
  .page-sub{ font-size:16px; }                      /* spec typography: không tụt dưới 16px */
}
@media (max-width:430px){
  .subject-card{ padding:18px; }
  .subject-card__name{ font-size:17.5px; }
  .crumb{ font-size:14px; }
}
@media (max-width:360px){
  .subject-card{ padding:16px; gap:13px; }
  .subject-card__icon{ width:46px; height:46px; }
  .subject-card__icon svg{ width:23px; height:23px; }
  .subject-card__name{ font-size:17px; }
}
@media (pointer:coarse){
  /* Sửa/xoá môn: nút to hơn cho dễ chạm trên màn cảm ứng */
  .subject-card__act{ width:38px; height:38px; }
  .subject-card__act svg{ width:18px; height:18px; }
}

/* ===============================================================
   24. Responsive toàn diện — mọi loại thiết bị, KHÔNG bỏ tính năng nào
   ---------------------------------------------------------------
   Thang máy (đặt CUỐI file để override chắc chắn):
     ≥1600 màn rộng · ≤1080 laptop nhỏ/tablet ngang · ≤900 tablet DỌC (thanh loại thành
     băng cuộn ngang) · ≤720 phone ngang · ≤640 phone (hàng tài liệu tự xuống dòng)
     · ≤560 phone dọc (hộp thoại thành BOTTOM SHEET) · ≤430 phone hẹp · ≤360 phone nhỏ
     · màn thấp nằm ngang · pointer:coarse (vùng chạm)
   Nguyên tắc: mọi chức năng đều còn đủ ở mọi cỡ — chỉ ĐỔI CÁCH BÀY, không cắt.
   =============================================================== */

/* --- Màn rộng (≥1600): dùng thêm chiều ngang thay vì để hai bên trống hoác.
   Vùng đọc vẫn có trần (--maxw) để dòng chữ không dài quá tầm mắt. --- */
@media (min-width:1600px){
  :root{ --maxw:1320px; --gutter:32px; }
  .subjects{ grid-template-columns:repeat(auto-fit,minmax(340px,1fr)); gap:20px; }
  .doclist.is-grid{ grid-template-columns:repeat(auto-fill,minmax(232px,1fr)); gap:16px; }
  .search{ max-width:520px; }
}

/* --- Laptop nhỏ / tablet nằm ngang (≤1080) --- */
@media (max-width:1080px){
  .subjects{ grid-template-columns:repeat(auto-fit,minmax(280px,1fr)); }
  .doclist{ gap:11px; }
  .doclist.is-grid{ grid-template-columns:repeat(auto-fill,minmax(196px,1fr)); }
}

/* --- TABLET DỌC (≤900, vd iPad 768): chỗ hẹp lại nhưng ngón tay vẫn to ---
   • Thanh loại: XUỐNG DÒNG (không cuộn ngang). Bản cuộn ngang giấu mất loại ở cuối — người dùng
     không biết còn gì phía sau, phím cuối lại bị CẮT CỤT trông như lỗi vẽ. Xuống dòng thì thấy
     hết mọi loại cùng lúc, đổi lại thanh cao thêm vài chục px — đáng.
     Đèn trượt nằm TRONG .tagbar và được JS đo theo offsetTop/offsetLeft nên tự bám đúng hàng.
   • Toolbar: ô tìm CHIẾM TRỌN hàng đầu, cụm lọc/sắp xếp/xem xuống hàng dưới. */
@media (max-width:900px){
  .tagbar-scroll{ margin-bottom:16px; }
  .tagbar{
    flex-wrap:wrap;                                 /* <- thứ làm nên việc xuống dòng */
    width:100%; max-width:100%;
    gap:6px; row-gap:8px;                           /* 6px: đủ chỗ cho chấm ✕ neo giữa (thò 5px) */
    justify-content:flex-start;
    /* Nhiều hàng mà vẫn bo tròn hoàn toàn thì thành cục bầu dục khổng lồ -> bo như một TẤM. */
    border-radius:22px; padding:6px;
  }
  .tagchip{ padding:9px 16px; font-size:15px; }     /* gọn lại -> xuống dòng ít lần hơn */
  /* Gạch phân cách trước "+ Thêm loại" chỉ có nghĩa khi mọi thứ nằm CÙNG một hàng. Đã xuống dòng
     thì bản thân hàng mới đã là ranh giới — để lại gạch sẽ thành nét trơ ở đầu hàng. */
  .tagchip--add::before{ display:none; }
  /* SÀN 180px = "Mọi định dạng" (107px @16px) + đệm 2 bên 72px. Thiếu sàn là flex bóp cụt chữ;
     có sàn thì control nào không đủ chỗ sẽ TỰ XUỐNG HÀNG — thà cao thêm còn hơn mất chữ. */
  .select{ flex:1 1 150px; min-width:180px; }

  .subjects{ grid-template-columns:repeat(auto-fit,minmax(240px,1fr)); gap:14px; }
  .ws-toolbar{ gap:9px; }
  .search{ order:-1; flex:1 1 100%; max-width:none; }
  .ws-toolbar__count{ order:-2; }                   /* số kết quả đứng TRÊN ô tìm, không chen ngang */
  .select{ flex:1 1 auto; min-width:0; }
  .doclist.is-grid{ grid-template-columns:repeat(auto-fill,minmax(172px,1fr)); gap:12px; }
}

/* --- Phone nằm ngang & tablet nhỏ (≤720) --- */
@media (max-width:720px){
  .tagbar__input{ width:min(190px,46vw); }
  .page-head{ margin-bottom:20px; gap:12px; }
  .ws-toolbar{ gap:8px; margin-bottom:14px; }
  .doclist{ gap:10px; }
  .row{ padding:13px 15px; gap:13px; }
  .dropzone{ margin-bottom:20px; }
  .toasts{ bottom:calc(22px + env(safe-area-inset-bottom)); }
  /* Khay gợi ý: bám sát ô tìm, cao tối đa nửa màn để bàn phím ảo không đè mất */
  .search__pop{ max-height:min(48vh,340px); }
  .sug__why{ display:none; }                        /* hẹp rồi thì tên + metadata là đủ */
}

/* --- Phone: HÀNG TÀI LIỆU TỰ XUỐNG DÒNG KHI CHẬT ---
   Cho .row xuống dòng được, và cho phần thân một BỀ RỘNG SÀN (flex-basis 150px) —
   đủ chỗ thì mọi thứ vẫn nằm 1 dòng như cũ (khách chỉ có 1 nút), chật thì cụm nút
   tự rơi xuống dòng dưới và dạt phải. Không ép cứng 2 dòng nên không thừa khoảng trắng.
     Dòng 1: [icon] [tên · dung lượng · ngày · người tải] [loại]
     Dòng 2:                                    [tải · ghim · loại · sửa · xoá] */
@media (max-width:640px){
  .row{ flex-wrap:wrap; align-content:center; column-gap:12px; row-gap:10px; padding:12px 14px; }
  .row .ficon, .row__thumb{ width:40px; height:40px; border-radius:11px; }
  .row .ficon svg{ width:20px; height:20px; }
  .row__body{ flex:1 1 150px; min-width:0; }        /* 150px = ngưỡng "hết chỗ" -> đẩy cụm nút xuống dòng */
  .row__name{
    font-size:15.5px; white-space:normal; text-overflow:clip;
    display:-webkit-box; -webkit-line-clamp:2; line-clamp:2; -webkit-box-orient:vertical; overflow:hidden;
  }
  /* Dòng phụ: nén nhẹ + cắt bằng "…" thay vì xuống dòng (tránh dấu "·" mồ côi đầu dòng) */
  .row__meta{ font-size:12px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
  .row__owner::before{ margin:0 4px; }
  .trashleft{ font-size:11.5px; padding:3px 9px; }
  /* Nhãn loại QUAY LẠI trên điện thoại (trước đây bị ẩn hẳn ≤560 vì hết chỗ) */
  .row__tag{ display:inline-flex; font-size:13px; padding:3px 11px; max-width:50%; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .row__actions{ margin-left:auto; }
  .row__check{ width:24px; height:24px; }
  .row__check svg{ width:15px; height:15px; }
}

/* --- Phone dọc: header gọn + HỘP THOẠI THÀNH BOTTOM SHEET (trong tầm ngón cái) --- */
@media (max-width:560px){
  :root{ --pill-h:50px; }
  .header{ top:calc(8px + env(safe-area-inset-top)); }
  .brand{ height:var(--pill-h); }
  .brand__mark{ width:32px; height:32px; border-radius:10px; }
  .brand__mark svg{ width:18px; height:18px; }
  .brand__name{ font-size:15.5px; }
  .header-tools{ height:var(--pill-h); }

  /* (Trước đây ẩn chữ "Thêm loại" vì thanh cuộn ngang chật. Nay thanh XUỐNG DÒNG nên hàng cuối
     luôn đủ chỗ — để trơ mỗi dấu "+" thì không ai đoán ra nó làm gì.) */
  /* Toolbar gói gọn 2 hàng: [đếm][ô tìm] / [định dạng][sắp xếp][xem][xoá lọc][chọn — chỉ icon].
     Các nút chỉ còn icon nhưng aria-label/title vẫn đầy đủ (xem wsToolbarHTML). */
  /* Số kết quả bỏ vỏ "viên thuốc" -> thành NHÃN nhỏ, tụt xuống đứng cùng hàng với sắp xếp/kiểu xem.
     Trước đó nó chiếm trọn một hàng 44px chỉ để nói "1 tài liệu" — ba hàng điều khiển trên một
     màn dọc là quá nhiều; giờ còn hai. Chữ vẫn ≥13px và vẫn là mốc "N / tổng" khi đang lọc. */
  .ws-toolbar__count{
    order:0; padding:0 2px; font-size:13.5px;
    background:none; border:none; box-shadow:none;
  }
  /* LƯỚI 2 CỘT thay cho flex-wrap.
     ĐO ĐƯỢC (tests/newbadge.js) khi có đủ 3 dropdown: flex-wrap cho ra 6 hàng ở 320px, mỗi hàng
     một bề rộng khác nhau — nhìn như nút rơi vãi. Lưới 2 cột giữ nguyên số hàng nhưng mọi thứ
     THẲNG CỘT, đọc ra ngay là một bảng điều khiển. Và vì mỗi ô rộng ~140px nên CHỮ trên các nút
     được TRẢ LẠI (trước đây phải giấu đi để nhét vừa một hàng flex). */
  .ws-toolbar{
    display:grid; grid-template-columns:repeat(2,minmax(0,1fr));
    align-items:center; gap:10px;
  }
  .ws-toolbar__count, .search{ grid-column:1 / -1; }   /* 2 thứ này luôn chiếm trọn hàng */
  .viewtog{ width:100%; }
  .ws-toolbar__sel, .ws-toolbar__clear, .ws-toolbar__new{ width:100%; padding:0 12px; }
  /* Hai nút hành động luôn đi CÙNG một hàng cuối, không rơi rớt mỗi cái một dòng. */
  .ws-toolbar__clear{ grid-column:1; }
  .ws-toolbar__sel{ grid-column:2; }
  /* Không lọc gì -> "Xoá lọc" biến mất; "Chọn nhiều" mà đứng một mình ở nửa phải trông như bị
     bỏ quên -> cho chiếm trọn hàng. Thùng rác KHÔNG có nút "Xoá lọc" -> cùng cảnh, cùng cách xử. */
  .ws-toolbar:has(.ws-toolbar__clear[hidden]) .ws-toolbar__sel,
  .ws-toolbar:not(:has(.ws-toolbar__clear)) .ws-toolbar__sel{ grid-column:1 / -1; }
  .ws-toolbar__new{ grid-column:1 / -1; }              /* Dashboard chỉ có 1 nút -> trọn hàng */
  /* .btn-ghost trong suốt nằm giữa các control có nền trông như chữ trôi nổi.
     Cho mượn đúng vật liệu kính của hàng xóm -> nhìn ra ngay là nút bấm được. */
  .ws-toolbar__sel, .ws-toolbar__clear, .ws-toolbar__new{
    background:var(--glass-2); border:1px solid var(--line); box-shadow:var(--hl);
  }
  /* …trừ khi đang BẬT: giữ nền đặc để trạng thái không biến mất theo cái nền kính. */
  .ws-toolbar__new[aria-pressed="true"]{ background:var(--apple); border-color:var(--apple); }
  /* Đệm đối xứng 36px (để căn giữa) ăn 72px bề ngang -> ở màn hẹp chữ bị CẮT CỤT ("Mọi địn…").
     Thu đệm + hạ 1px cỡ chữ, chevron nhích vào; chữ vẫn ở giữa mà đủ chỗ hiện trọn.
     ĐÃ BỎ `min-width:168px`: giờ thanh công cụ là LƯỚI 2 cột, sàn 168px làm 2 ô = 346px > 288px
     dùng được ở 320px -> TRÀN NGANG (đo bằng tests/newbadge.js). Ô lưới tự chia đều là đủ. */
  .select{
    width:100%; min-width:0; flex:none;
    font-size:15px; padding:0 28px;
    background-position:right 8px center;
  }
  .tagchip--add{ padding:8px 14px; }
  /* SÀN 200px chứ không phải 148px: dưới 430px máy chỉ vừa 1 cột, mà cột 194px thì 5 nút chạm
     (40px + khe) KHÔNG đủ chỗ -> bị bẻ thành 3+2 trông lộn xộn. Một cột rộng cho thẻ đàng hoàng:
     dải xem trước to, tên đọc thoải mái, hàng nút gọn trong một dòng. Máy ~560px vẫn ra 2 cột. */
  .doclist.is-grid{ grid-template-columns:repeat(auto-fill,minmax(200px,1fr)); gap:12px; }
  .doclist.is-grid .ficon,
  .doclist.is-grid .row__thumb{ height:120px; }
  /* Câu "kéo thả để tải lên" LẶP LẠI đúng nội dung ô kéo-thả ngay bên dưới -> bỏ trên màn dọc.
     CHỈ ở workspace: ngoài Trang chủ không có ô kéo-thả nên câu mô tả ở đó vẫn cần thiết.
     (body[data-route] do render() gán — xem app.js mục 4.) */
  body[data-route="workspace"] .page-sub{ display:none; }
  .page-head{ margin-bottom:16px; }

  /* Hộp thoại trượt lên từ ĐÁY: dễ với tay, chừa safe-area, có "tay nắm" như sheet iOS */
  .scrim{ padding:0; place-items:end stretch; }
  .modal, .modal--wide{
    width:100%; max-width:none;
    border-radius:24px 24px 0 0; max-height:92dvh;
    transform:translateY(26px) scale(1);
    padding-bottom:env(safe-area-inset-bottom);
  }
  .modal::before{
    content:""; display:block; width:40px; height:5px; margin:9px auto 0;
    border-radius:999px; background:color-mix(in srgb,var(--text-3) 55%,transparent);
  }
  .modal__head{ padding:14px 20px 0; }
  .modal__body{ padding:16px 20px; }
  .modal__foot{ padding:0 20px 20px; }
  .modal__foot .btn{ flex:1 1 auto; }               /* nút to bằng ngón tay, chia đều bề ngang */
  .preview{ max-height:52vh; min-height:170px; }
  .preview img{ max-height:52vh; }
  .preview iframe{ height:52vh; }
  .preview pre{ max-height:52vh; }
}

/* --- Phone hẹp --- */
@media (max-width:430px){
  .dropzone{ padding:22px 14px; }
  .dropzone__icon{ width:48px; height:48px; border-radius:14px; margin-bottom:12px; }
  .dropzone__icon svg{ width:24px; height:24px; }
  .tagbar__input{ width:min(150px,38vw); }
  .row{ padding:11px 13px; }
  .empty{ padding:34px 20px; }
  .empty__icon{ width:64px; height:64px; border-radius:19px; margin-bottom:16px; }
  .empty__icon svg{ width:32px; height:32px; }
}

/* --- Phone nhỏ (iPhone SE…) --- */
@media (max-width:360px){
  /* Ô lưới còn ~139px: giảm đệm ngang để nhãn dài nhất vẫn hiện TRỌN.
     Số đo thật ở 320px (tests/newbadge.js): "Mọi định dạng" cần 101px @15px nhưng chỉ còn 87px
     -> hạ còn 14px chữ (≈94px) và thu đệm 28→18px (chỗ trống 103px). Chevron nằm ở right:8px
     nên vẫn thừa khoảng hở. */
  .ws-toolbar__sel, .ws-toolbar__clear, .ws-toolbar__new{ padding:0 8px; gap:6px; font-size:14.5px; }
  .ws-toolbar .select{ font-size:14px; padding:0 18px; }
  .brand{ padding:0 10px; }                         /* ≤360 chỉ còn icon thương hiệu -> bỏ lề thừa bên phải */
  .row{ column-gap:10px; }
  .row__body{ flex-basis:130px; }
  .row .ficon, .row__thumb{ width:36px; height:36px; border-radius:10px; }
  .row__tag{ max-width:44%; }
  .modal__head{ gap:11px; }
  .modal__head .ficon{ width:42px; height:42px; }
  .modal__title{ font-size:17.5px; }
}

/* --- Màn THẤP nằm ngang (điện thoại xoay ngang) ---
   Chiều cao là thứ khan hiếm: nén đầu trang và ĐỔI ô kéo-thả sang nằm NGANG
   (icon trái · chữ phải) -> tiết kiệm ~80px, thấy ngay danh sách tài liệu mà không phải cuộn.
   Hộp thoại giữ ở giữa màn (sheet đáy sẽ chỉ còn một khe hẹp). */
@media (max-height:520px) and (orientation:landscape){
  .main{ padding:12px 0 32px; }
  .crumb{ margin:0 0 6px; }
  .page-head{ margin:0 0 16px; gap:8px; }   /* gộp: rule margin-bottom:16px lặp ở cuối khối cũ đã đè 12px */
  .page-title{ font-size:24px; }
  .page-sub{ font-size:14px; margin-top:2px; }
  .page-count{ padding:6px 13px; }
  .dropzone{
    display:grid; grid-template-columns:auto auto; justify-content:center; align-items:center;
    column-gap:14px; row-gap:2px; text-align:left; padding:13px 18px; margin-bottom:14px;
  }
  .dropzone__icon{ grid-row:1 / span 2; width:40px; height:40px; margin:0; border-radius:12px; }
  .dropzone__icon svg{ width:20px; height:20px; }
  .dropzone__title, .dropzone__title--drop, .dropzone__hint{ grid-column:2; }
  .dropzone__title{ font-size:15.5px; }

  .scrim{ padding:10px; place-items:center; }
  .modal, .modal--wide{ border-radius:var(--r-lg); max-height:calc(100dvh - 20px); transform:translateY(10px) scale(.98); }
  .modal::before{ display:none; }
  .modal__head{ padding:16px 20px 0; }
  .modal__body{ padding:12px 20px; }
  .modal__foot{ padding:0 20px 16px; }
  .preview, .preview img, .preview pre{ max-height:46vh; }
  .preview iframe{ height:46vh; }
  .tagbar-scroll{ margin-bottom:12px; }
}

/* --- CẢM ỨNG: mọi thứ bấm được đều ≥40px, kể cả taskbar loại --- */
@media (pointer:coarse){
  .tagchip{ padding:11px 20px; }                    /* 20px chữ + 22px đệm ≈ 42px cao */
  .tagchip--add{ padding:11px 16px; }
  .tagbar__input{ height:40px; }
  .tagbar__ok, .tagbar__cancel{ width:40px; height:40px; }
  .tagbar__ok svg, .tagbar__cancel svg{ width:18px; height:18px; }
  .crumb__link{ padding:8px 10px; }
  .row__check{ width:28px; height:28px; }
  .empty__actions .btn, .page-head .btn{ min-height:46px; }
  .viewtog__b{ width:44px; height:40px; }           /* 44x40 — đủ cho đầu ngón tay */
  .sug{ min-height:52px; }                          /* gợi ý cũng là thứ bấm được */
  .sug--all{ min-height:48px; }
  .search__clear{ width:40px; height:40px; }
}

/* --- Khoá cuộn nền khi mở hộp thoại (chỉ màn nhỏ: desktop có thanh cuộn, khoá sẽ gây giật layout) --- */
@media (max-width:720px){
  body.modal-open{ overflow:hidden; }
}
