/* Font HỆ THỐNG, không tải font ngoài, và CHỈ MỘT font cho cả giao diện.

   Lý do không phải thẩm mỹ: ứng dụng chạy trong mạng bệnh viện, và
   `fonts.googleapis.com` chặn được là mọi thứ rơi về font mặc định mà không ai biết
   - đã xảy ra thật với v2, nơi thẻ <link> chưa từng được thêm nên `document.fonts`
   rỗng suốt.
   
   Font hệ thống dựng dấu tiếng Việt đúng vì Windows và macOS đều kèm sẵn font có
   đủ dấu chồng; không cần tải một byte nào, và không có nhịp chữ nhảy khi font về
   muộn.

   KHÔNG còn font máy chữ. Bản trước dùng nó cho tên cột, huy hiệu, ngày tháng, số
   đếm - 25 trên 167 phần tử - và trên Windows nó rơi vào `Cascadia Mono`, font dành
   cho lập trình. Không chỗ nào trong số đó cần các ký tự rộng bằng nhau: chúng là
   chữ để ĐỌC, không phải cột số phải gióng hàng. Một font cho cả giao diện, và đó là
   font người dùng đã quen nhìn trên chính máy họ. */
:root{
  --font-sans:system-ui,-apple-system,'Segoe UI',Roboto,'Helvetica Neue',Arial,sans-serif;
}
/* app.css - hệ thống thị giác giữ nguyên từ Phase 1, bổ sung phần Phase 2:
   thanh tiến độ, bộ lọc phát hiện, màn hình đối chiếu đề xuất sửa. */
:root{
  --navy:#233E50; --navy-dark:#1A2E3C; --pink:#DF4C6C; --cream:#F7F5EF;
  --line:#E1DED4; --ink:#1D2A32; --ink-soft:#5F6B72; --navy-tint:#E7ECEF; --pink-tint:#FBE8ED;
  --ok:#1F8A5A; --warn:#B9852B; --danger:#C1443C; --amber-tint:#FBF0DD;
  /* Nền rê chuột trung tính. Hai luật đã dùng `var(--wash)` từ trước mà biến chưa
     bao giờ được khai, nên hover của dòng bảng và của danh sách cách viết không hiện
     gì - `background` nhận giá trị không hợp lệ rồi rơi về trong suốt, im lặng. */
  --wash:#F4F2EB;
}
/* Chừa sẵn chỗ cho thanh cuộn dọc. Vòng hỏi 5 giây làm chiều cao bảng đổi liên tục
   (thanh tiến độ, dòng ghi chú); nếu chiều cao trang lúc vượt lúc không vượt màn hình
   thì thanh cuộn hiện rồi tắt, và toàn bộ nội dung căn giữa nhảy ngang ~15px mỗi nhịp. */
html{scrollbar-gutter:stable;}
*{box-sizing:border-box;}
body{margin:0;background:var(--cream);color:var(--ink);font-family:var(--font-sans);}
input,button,select,textarea{font-family:inherit;}
::selection{background:var(--pink-tint);}

/* ---------- LOGIN ---------- */
#login-screen{min-height:100vh;display:flex;align-items:center;justify-content:center;
  background:linear-gradient(160deg,var(--navy) 0%, var(--navy-dark) 100%);}
.login-card{background:#fff;border-radius:16px;padding:40px 36px;width:380px;max-width:90vw;
  box-shadow:0 30px 60px -20px rgba(0,0,0,.4);}
.login-logo{width:44px;height:44px;margin:0 auto 18px;display:block;}
.login-card h1{font-size:20px;text-align:center;margin:0 0 4px;color:var(--navy);font-weight:800;}
.login-card .sub{text-align:center;font-size:13px;color:var(--ink-soft);margin-bottom:24px;}
.field{margin-bottom:14px;}
.field label{display:block;font-size:12.5px;font-weight:600;color:var(--navy);margin-bottom:5px;}
.field input,.field select,.field textarea{width:100%;padding:10px 12px;border:1.5px solid var(--line);
  border-radius:8px;font-size:14px;}
.field input:focus,.field select:focus{outline:none;border-color:var(--pink);}
.field .hint{font-size:11.5px;color:var(--ink-soft);margin-top:4px;}
.btn{width:100%;padding:11px;border:none;border-radius:8px;background:var(--navy);color:#fff;
  font-weight:700;font-size:14.5px;cursor:pointer;transition:background .15s;}
.btn:hover{background:var(--navy-dark);}
.btn.pink{background:var(--pink);}
.btn.pink:hover{background:#c73f5c;}
.btn.small{width:auto;padding:7px 14px;font-size:13px;}
.btn.ghost{background:var(--navy-tint);color:var(--navy);}
.btn.ghost:hover{background:#dbe3e7;}
.btn.danger{background:var(--danger);}
.btn:disabled{opacity:.55;cursor:progress;}
.login-error{background:#FCEAEA;color:var(--danger);font-size:13px;padding:9px 11px;border-radius:8px;margin-bottom:14px;}

/* ---------- APP SHELL ---------- */
#app{display:none;min-height:100vh;}
.topbar{background:var(--navy);color:#fff;padding:12px 26px;display:flex;align-items:center;gap:14px;
  position:sticky;top:0;z-index:10;}
.topbar .title{font-weight:800;font-size:16px;letter-spacing:.01em;}
.topbar-logo{width:26px;height:26px;object-fit:contain;border-radius:4px;}
.unit-logo-thumb{width:32px;height:32px;object-fit:contain;border-radius:4px;background:#f2f4f6;}
.topbar .role-badge{font-size:10.5px;background:var(--pink);color:#fff;
  padding:2px 9px;border-radius:100px;font-weight:600;text-transform:uppercase;}
.topbar .spacer{flex:1;}
.topbar .who{font-size:13px;color:#cfd8dd;}
.topbar .logout{background:rgba(255,255,255,.12);color:#fff;border:none;padding:7px 14px;border-radius:7px;
  font-size:13px;cursor:pointer;}
.topbar .logout:hover{background:rgba(255,255,255,.22);}
.topbar .logout.icon-btn{padding:7px;display:inline-flex;align-items:center;justify-content:center;}
.topbar .logout.icon-btn svg{width:17px;height:17px;}
.topbar .running-chip{font-size:12px;background:var(--pink);color:#fff;padding:3px 10px;border-radius:100px;display:none;cursor:pointer;}
.topbar .running-chip.show{display:inline-block;}

.tabs{display:flex;gap:6px;padding:16px 26px 0;border-bottom:1px solid var(--line);background:#fff;flex-wrap:wrap;}
.tab{padding:11px 16px;font-size:13.5px;font-weight:700;color:var(--ink-soft);cursor:pointer;
  border-bottom:2.5px solid transparent;}
.tab.active{color:var(--navy);border-bottom-color:var(--pink);}
.content{max-width:96vw;margin:0 auto;padding:26px clamp(16px, 2vw, 34px);}
.panel{display:none;}
.panel.active{display:block;animation:fadein .25s ease;}
@keyframes fadein{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:translateY(0)}}

.card{background:#fff;border:1px solid var(--line);border-radius:12px;padding:20px 22px;margin-bottom:18px;}
.card h2{font-size:16px;margin:0 0 4px;color:var(--navy);font-weight:800;}
.card .desc{font-size:13px;color:var(--ink-soft);margin:0 0 16px;}

/* "Tài liệu của tôi" / "Tất cả" (`specs/tiny/documents-mine-all-scope.md`, R1) -
   cùng ngôn ngữ hình ảnh với `.fd-tabs` (gạch chân hồng khi đang chọn), nhưng nhỏ
   hơn vì đây chỉ là một bộ lọc bên trong thẻ, không phải điều hướng cấp trang. */
.scope-toggle{display:flex;gap:16px;margin-bottom:14px;}
.scope-toggle button{border:none;background:none;padding:0 0 7px;cursor:pointer;
  font-size:14.5px;font-weight:800;color:var(--ink-soft);border-bottom:2.5px solid transparent;}
.scope-toggle button.on{color:var(--navy);border-bottom-color:var(--pink);}

.table-wrap{overflow-x:auto;}
table{width:100%;border-collapse:collapse;font-size:13.5px;}
th{text-align:left;font-size:10.5px;text-transform:uppercase;
  letter-spacing:.04em;color:var(--ink-soft);padding:8px 10px;border-bottom:1.5px solid var(--line);font-weight:600;}
td{padding:9px 10px;border-bottom:1px solid #EEECE3;vertical-align:top;}
tr:last-child td{border-bottom:none;}

/* Tên cột là một nút bấm để sắp xếp. Kế thừa nguyên kiểu chữ của `th` để nó vẫn là
   tên cột, không phải một nút trông như nút. Mũi ⇅ mờ sẵn để nói "bấm được"; thành
   ↑ hoặc ↓ đậm khi bảng đang xếp theo cột này. */
.th-sort{border:none;background:none;padding:0;cursor:pointer;font:inherit;
  color:inherit;text-transform:inherit;letter-spacing:inherit;white-space:nowrap;}
.th-sort:hover{color:var(--ink);}
.th-arrow{margin-left:4px;opacity:.3;}
.th-sort:hover .th-arrow{opacity:.7;}
.th-sort.on{color:var(--pink);}
.th-sort.on .th-arrow{opacity:1;font-weight:700;}
/* Cột số: hẹp, canh phải, chữ mảnh - nó để định hướng chứ không phải để đọc. */
.fd-num-col{width:38px;text-align:right;color:var(--ink-soft);
  font-size:11.5px;}
/* Cột tích chọn. Hẹp hết mức, và ô tích phóng to hơn mặc định một chút vì đây là
   thứ người dùng bấm hàng chục lần liên tiếp. */
.fd-pick-col{width:34px;text-align:center;padding-right:0;}
.fd-pick-col input{width:15px;height:15px;cursor:pointer;accent-color:var(--pink);
  margin:0;vertical-align:middle;}

/* Thanh chip lọc phía trên bảng. Chip chưa lọc thì viền nhạt; đang lọc thì mang màu
   nhấn và hiện luôn giá trị, nên không phải mở ra mới biết. */
.fd-chips{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin:14px 0 4px;}
.fd-chip{display:inline-flex;align-items:center;gap:6px;padding:6px 12px;
  border:1.5px solid var(--line);border-radius:999px;background:#fff;cursor:pointer;
  font-size:12.5px;color:var(--ink);}
.fd-chip:hover{border-color:var(--ink-soft);}
.fd-chip.on{border-color:var(--pink);color:var(--pink);background:var(--pink-tint);
  font-weight:600;}
.fd-chip-caret{opacity:.5;font-size:10px;}
.fd-chip-clear{border:none;background:none;cursor:pointer;font-size:12.5px;
  color:var(--ink-soft);text-decoration:underline;padding:6px 4px;}
.fd-chip-clear:hover{color:var(--danger);}

/* Dòng tên bảng: số đếm bên trái, lệnh bên phải. */
.fd-head{display:flex;align-items:center;gap:10px;margin:14px 0 10px;}
.fd-head-title{display:flex;align-items:center;gap:8px;font-weight:700;
  color:var(--navy);font-size:15px;}
.fd-count{padding:2px 9px;border-radius:999px;background:var(--navy-tint);
  color:var(--ink-soft);font-size:11.5px;font-weight:600;
  }
/* Lệnh nằm NGAY CẠNH tên bảng, không dạt sang mép phải.

   Trên màn hình rộng, `margin-left:auto` đẩy nút đi cả ngàn pixel khỏi con số nó
   nói tới ("4 mục" ... khoảng trống ... "Sửa 4 mục vào tệp"), nên mắt phải đi hai
   quãng mới nối được hai thứ. Nút ba chấm vẫn ra mép phải: nó không nói về con số
   nào, và để nó dính vào lệnh chính thì hai thứ khác hẳn nhau trông thành một cụm. */
.fd-head-actions{display:flex;align-items:center;gap:8px;flex:1;}
.fd-more{margin-left:auto;width:30px;height:30px;border:1.5px solid var(--line);
  border-radius:8px;background:#fff;cursor:pointer;color:var(--ink-soft);
  font-size:15px;line-height:1;flex:none;}
.fd-more:hover{border-color:var(--ink-soft);color:var(--ink);}

/* Menu bật ra, dựng ngoài bảng (xem `openMenuAt`) nên `position:fixed` và toạ độ do
   JS đặt. `text-transform:none` vì nó có thể mở từ trong `<thead>`, nơi chữ bị viết
   hoa toàn bộ. */
.fd-menu{position:fixed;z-index:60;min-width:190px;max-width:250px;padding:5px;
  background:#fff;border:1.5px solid var(--line);border-radius:10px;
  box-shadow:0 8px 24px rgba(20,30,50,.14);text-transform:none;letter-spacing:0;
  font-family:inherit;font-size:13px;max-height:60vh;overflow-y:auto;}
.fd-menu button{display:block;width:100%;text-align:left;padding:7px 9px;border:none;
  background:none;cursor:pointer;border-radius:6px;font-size:13px;color:var(--ink);}
.fd-menu button:hover{background:var(--wash);}
.fd-menu button.on{background:var(--pink-tint);color:var(--pink);font-weight:600;}
.fd-menu-head{padding:7px 9px 3px;font-size:10.5px;text-transform:uppercase;
  letter-spacing:.04em;color:var(--ink-soft);}
.fd-menu-clear{margin-top:4px;border-top:1px solid var(--line)!important;
  border-radius:0 0 6px 6px!important;color:var(--ink-soft)!important;}

/* Ký tự đổi giữa phần sai và dạng đúng (`App.diffPair`). Đỏ là chữ mất, xanh là chữ
   thay vào - cùng quy ước với `<del>`/`<ins>` mà mắt đã quen từ git.

   `mark` mặc định của trình duyệt là nền vàng chói; ghi đè cả nền lẫn màu chữ. */
mark.d-del{background:#FBE0E3;color:#8E2233;border-radius:3px;padding:0 1px;}
mark.d-ins{background:#DCF0E4;color:#155C38;border-radius:3px;padding:0 1px;}

.fd-empty-row td{text-align:center;color:var(--ink-soft);padding:26px 10px;}
tr.clickable{cursor:pointer;}
tr.clickable:hover{background:var(--navy-tint);}
/* Dòng của chính người dùng khi đang xem "Tất cả" (R5) - nhạt hơn `.navy-tint`
   của hover để hai trạng thái không lẫn vào nhau khi dòng vừa của mình vừa mở được. */
tr.own-row{background:var(--pink-tint);}
tr.own-row.clickable:hover{background:var(--navy-tint);}
/* Dòng chưa có lượt rà soát nào - tô vàng để dễ tìm việc cần làm, ở cả hai tab
   (`specs/tiny/documents-table-gui-polish.md`, R4). Đứng SAU `.own-row` trong
   bảng nên thắng khi một dòng trùng cả hai lớp. */
tr.unreviewed-row{background:var(--amber-tint);}
tr.unreviewed-row.clickable:hover{background:var(--navy-tint);}

.badge{font-size:10.5px;font-weight:600;padding:2px 8px;border-radius:100px;
  display:inline-block;}
.badge.role-superadmin{background:#EFE3F5;color:#6A3B99;}
.badge.role-manager{background:var(--pink-tint);color:#B23A5A;}
.badge.role-clerk{background:var(--navy-tint);color:var(--navy);}
.badge.status-completed,.badge.status-approved{background:#E4F3EB;color:var(--ok);}
.badge.status-queued,.badge.status-pending{background:#FBF0DD;color:var(--warn);}
.badge.status-running{background:#E7ECEF;color:var(--navy);}
.badge.status-failed,.badge.status-interrupted,.badge.status-rejected{background:#FCEAEA;color:var(--danger);}
.badge.status-cancelled,.badge.status-dismissed{background:#EFEFEA;color:var(--ink-soft);}
.badge.status-new{background:var(--navy-tint);color:var(--navy);}
.badge.status-seen{background:#EFEFEA;color:var(--ink-soft);}
.badge.status-accepted{background:#E4F3EB;color:var(--ok);}
.badge.status-fixed{background:#E4F3EB;color:var(--ok);}
.badge.status-written{background:#E4F3EB;color:var(--ok);}
.badge.sev-high{background:#FCEAEA;color:var(--danger);}
.badge.sev-medium{background:#FBF0DD;color:var(--warn);}
.badge.sev-low{background:#E7ECEF;color:var(--ink-soft);}
.badge.group-grammar{background:var(--navy-tint);color:var(--navy);}
.badge.group-consistency{background:#EFE3F5;color:#6A3B99;}
.badge.confirm{background:#FBF0DD;color:var(--warn);}

.range-switch{display:flex;gap:6px;margin-bottom:16px;flex-wrap:wrap;}
.range-switch button{padding:7px 14px;border:1.5px solid var(--line);background:#fff;border-radius:100px;
  font-size:13px;font-weight:600;color:var(--ink-soft);cursor:pointer;}
.range-switch button.active{background:var(--navy);color:#fff;border-color:var(--navy);}

.stat-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));gap:12px;margin-bottom:6px;}
.stat-box{background:var(--navy-tint);border-radius:10px;padding:14px 16px;}
.stat-box .num{font-size:26px;font-weight:800;color:var(--navy);}
.stat-box .label{font-size:12px;color:var(--ink-soft);margin-top:2px;}

.toolbar{display:flex;gap:10px;align-items:center;margin-bottom:16px;flex-wrap:wrap;}
.toolbar select,.toolbar input[type=text]{padding:8px 10px;border:1.5px solid var(--line);border-radius:8px;font-size:13px;}
/* Gom nhóm thay vì dùng một `.spacer` co giãn: thanh công cụ có wrap, mà `flex:1` chỉ
   đẩy được trong phạm vi một dòng - các nút rơi xuống dòng dưới sẽ bị bỏ lại bên trái. */
.toolbar-actions{display:flex;gap:8px;flex-wrap:wrap;margin-left:auto;}

.modal-backdrop{display:none;position:fixed;inset:0;background:rgba(26,46,60,.55);z-index:50;
  align-items:flex-start;justify-content:center;padding:40px 20px;overflow:auto;}
.modal-backdrop.show{display:flex;}
.modal{background:#fff;border-radius:14px;max-width:860px;width:100%;padding:26px 28px;}
/* Biến thể rộng cho màn hình đối chiếu hai cột (danh sách lỗi cạnh ảnh trang). */
.modal.wide{max-width:1180px;}
.modal h3{margin:0 0 4px;color:var(--navy);font-size:18px;}
/* Gấp đôi kích cỡ so với trước (20px) - dùng chung cho MỌI popup vì chỉ có một
   `#modal-close` (`index.html`) (`specs/tiny/documents-review-source-and-filters.md`, R9). */
.modal .close{float:right;background:none;border:none;font-size:40px;cursor:pointer;color:var(--ink-soft);}
.empty{text-align:center;padding:40px 10px;color:var(--ink-soft);font-size:13.5px;}
.upload-row{display:flex;gap:10px;flex-wrap:wrap;align-items:flex-end;margin-bottom:8px;}
.upload-row .field{margin-bottom:0;min-width:180px;flex:1;}
/* Chọn/Loại/Tệp cùng chiều cao 44px để hàng thẳng nhau - trước đây select (~39px,
   đệm 10px, không lồng nút) và ô Chọn tệp (~48px, đệm 8px cộng nút lồng bên trong)
   khác chiều cao nhau, và nút Tải lên (đứng riêng, không nhãn phía trên) chỉ cao
   ~29px nên trôi lệch khỏi dải nút/ô phía trên nó. */
.upload-row .field select,.upload-row .field input{height:44px;}
.upload-row>.btn{height:44px;}
/* Ô "Chọn tệp" tự vẽ, thay chữ Anh mặc định của trình duyệt (R5). Input thật ẩn
   theo kiểu "sr-only" (vẫn bắt được sự kiện `change` và bấm được qua `<label>`),
   không dùng `display:none` vì vài trình duyệt cũ bỏ qua input đó khi submit. */
.file-choose{display:flex;align-items:center;gap:10px;padding:0 12px;height:44px;
  border:1.5px solid var(--line);border-radius:8px;}
/* `.field input` (đầu tệp) có đặc hiệu CAO HƠN `.file-choose-input` - một lớp cộng
   một thẻ so với một lớp - nên `width:100%` của nó thắng, và input "ẩn" thật ra rộng
   bằng cả hàng (đo được 1442px). Chỉ có `clip` che nó lại; bỏ `clip` đi là ô chọn
   tệp mặc định của trình duyệt hiện ra đè lên nút. Thêm `.field` vào đây để đặc hiệu
   ngang nhau và luật đứng sau thắng. */
.field .file-choose-input{position:absolute;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0;}
.field .file-choose-btn{display:inline-block;margin-bottom:0;flex-shrink:0;}
.file-choose-name{font-size:13px;color:var(--ink-soft);overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap;}
/* Nhãn + mô tả của cột "Loại rà soát" trong bảng Tài liệu (R1) - cùng kiểu chữ phụ
   nhỏ với `.block-ref` đã dùng ở các cột khác, chỉ khác `scan-type-label` là dòng
   đậm phía trên. */
.scan-type-label{font-weight:600;color:var(--navy);}
.toast{position:fixed;bottom:22px;right:22px;background:var(--navy);color:#fff;padding:12px 18px;border-radius:10px;
  font-size:13.5px;box-shadow:0 10px 30px rgba(0,0,0,.25);display:none;z-index:60;max-width:420px;}
.toast.show{display:block;animation:fadein .2s ease;}
.toast.err{background:var(--danger);}
.search-box{position:relative;flex:1;min-width:200px;}
/* Phải kèm [type=text] để thắng `.toolbar input[type=text]` ở trên - bộ chọn thuộc tính
   tính ngang một lớp, thiếu nó thì đệm trái bị kéo về 10px và chữ chui xuống dưới icon. */
.search-box input[type=text]{width:100%;padding:8px 12px 8px 32px;border:1.5px solid var(--line);
  border-radius:8px;font-size:13px;}
.search-box svg{position:absolute;left:10px;top:50%;transform:translateY(-50%);width:14px;height:14px;
  color:var(--ink-soft);}

/* Chip chữ cái đầu của dự án - để phân biệt nhanh bằng mắt khi lướt bảng tài liệu. */
.proj-cell{display:flex;align-items:center;}
.proj-icon{display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;
  border-radius:7px;color:#fff;font-size:10px;font-weight:800;flex:none;margin-right:7px;
  letter-spacing:-.02em;}
.pagination{display:flex;align-items:center;gap:6px;justify-content:flex-end;margin-top:14px;font-size:13px;}
.pagination button{border:1.5px solid var(--line);background:#fff;border-radius:7px;padding:5px 10px;cursor:pointer;color:var(--ink);}
.pagination button:disabled{opacity:.4;cursor:default;}
.pagination button.active{background:var(--navy);color:#fff;border-color:var(--navy);}
.pagination .info{color:var(--ink-soft);margin-right:8px;}

/* ---------- PHASE 2: tiến độ, phát hiện, đề xuất sửa ---------- */
.progress{height:8px;background:var(--navy-tint);border-radius:100px;overflow:hidden;min-width:120px;}
.progress > span{display:block;height:100%;background:var(--pink);transition:width .4s ease;}
.progress-note{font-size:11.5px;color:var(--ink-soft);margin-top:4px;}

.notice{padding:10px 13px;border-radius:9px;font-size:13px;margin-bottom:14px;}
.notice.warn{background:#FBF0DD;color:#7a5a12;}
.notice.info{background:var(--navy-tint);color:var(--navy);}
.notice.err{background:#FCEAEA;color:var(--danger);}
.notice.ok{background:#E4F3EB;color:#12603c;}

.block-ref{font-size:11px;color:var(--ink-soft);}

/* Ô "Thời gian / Chi phí": hai giá trị xếp chồng, không xuống dòng giữa số và đơn
   vị. Chữ số dùng bảng chiều rộng cố định để các dòng thẳng cột nhau khi đọc dọc. */
td.run-cost{white-space:nowrap;font-variant-numeric:tabular-nums;}
td.run-cost .block-ref{margin-top:2px;}

/* Cột thao tác của dòng tài liệu: các nút xếp DỌC và rộng bằng nhau. Xếp ngang thì
   bốn nút hoặc đẩy bảng tràn ngang, hoặc bóp các cột nội dung lại. `width:min-content`
   giữ cột hẹp đúng bằng nút dài nhất thay vì ăn phần thừa của bảng. */
.row-actions{display:flex;flex-direction:column;align-items:stretch;gap:6px;width:min-content;}
.row-actions .btn.small{width:100%;white-space:nowrap;}
.excerpt{font-size:13px;line-height:1.55;}
.excerpt mark{background:var(--pink-tint);color:#7a2740;padding:0 2px;border-radius:3px;}

.diff{font-size:13.5px;line-height:1.7;background:var(--cream);border:1px solid var(--line);
  border-radius:9px;padding:11px 13px;word-break:break-word;}
.diff .op-delete{background:#FCEAEA;color:var(--danger);text-decoration:line-through;}
.diff .op-insert{background:#E4F3EB;color:#12603c;}

.proposal{border:1px solid var(--line);border-radius:11px;padding:16px 18px;margin-bottom:14px;background:#fff;}
.proposal.needs-confirm{border-color:var(--warn);background:#FFFDF7;}
.proposal .head{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin-bottom:10px;}
.proposal .why{font-size:13px;color:var(--ink-soft);margin:10px 0;}
.proposal .actions{display:flex;gap:8px;flex-wrap:wrap;}

.variant-list{margin:8px 0 0;padding-left:18px;font-size:13px;}
.variant-list li{margin-bottom:3px;}
.counts{display:flex;gap:8px;flex-wrap:wrap;font-size:12px;color:var(--ink-soft);margin-bottom:12px;}
.checkcell{width:28px;}

/* =========================================================
   Tính năng 003 - áp dụng sửa trực tiếp và khung xem trong app
   ========================================================= */

/* FR-024a - ba trạng thái của luồng áp dụng phân biệt được bằng mắt.
   `pending_confirmation` cố tình dùng màu cảnh báo: nó là việc còn dang dở của
   người dùng, không phải một kết quả. */
.badge.status-pending_confirmation{background:#FBF0DD;color:#7a5a12;}
/* `.badge.status-fixed` đã khai ở phần trạng thái phía trên - không lặp lại. */
.badge.status-revision_rejected{background:#EFEFEA;color:var(--ink-soft);}
.await-note{margin-top:5px;font-size:11.5px;color:#7a5a12;}


.skip-list{margin:6px 0 0;padding-left:18px;font-size:12.5px;color:var(--ink-soft);}
.skip-list li{margin-bottom:3px;}
.modal-actions{display:flex;gap:8px;justify-content:flex-end;margin-top:18px;flex-wrap:wrap;}

/* FR-041a - hộp thoại rộng 1180px chia hai cột: danh sách lỗi trái, tài liệu phải.
   Bề rộng do `.modal.wide` lo (biến thể đã có sẵn từ bản GUI tham chiếu). */
.viewer{display:grid;grid-template-columns:340px 1fr;gap:18px;align-items:start;}
.viewer-side{max-height:66vh;overflow-y:auto;padding-right:6px;}
.viewer-summary{font-size:13px;color:var(--ink-soft);margin-bottom:10px;}
.mark-group{margin:14px 0 6px;font-size:12px;text-transform:uppercase;
  letter-spacing:.04em;color:var(--ink-soft);}
.mark-list{list-style:none;margin:0;padding:0;}
.mark-item{border:1px solid var(--line);border-radius:9px;padding:9px 11px;
  margin-bottom:7px;cursor:pointer;}
.mark-item:hover{border-color:var(--navy);}
/* Dấu vết không có neo trong khung xem: không mời bấm, và nói rõ vì sao. */
.mark-item.not-locatable{cursor:default;border-style:dashed;}
.mark-item.not-locatable:hover{border-color:var(--line);}
.mark-note{font-size:12px;color:var(--warn);margin:4px 0 0;}
.mark-body{font-size:13px;margin:5px 0;word-break:break-word;}
/* Chỗ tô sáng không đổi chữ nào, nên thẻ của nó nói "cần xem gì": nội dung phát
   hiện, dạng chuẩn đề xuất, rồi lời giải thích - nhỏ dần theo mức quan trọng. */
.mark-suggest{font-size:12.5px;margin-top:4px;}
.mark-why{font-size:12px;color:var(--ink-soft);margin-top:4px;line-height:1.5;}
.mark-meta{font-size:10.5px;color:var(--ink-soft);}
.mark-actions{display:flex;gap:6px;margin-top:7px;}
.badge.markkind-revision{background:var(--navy-tint);color:var(--navy);}
.badge.markkind-highlight{background:#FBF0DD;color:#7a5a12;}
.badge.markstate-pending{background:#FBF0DD;color:#7a5a12;}
.badge.markstate-accepted{background:#E4F3EB;color:#12603c;}
.badge.markstate-rejected{background:#EFEFEA;color:var(--ink-soft);}

.viewer-doc{min-width:0;}
.viewer-bar{font-size:11px;color:var(--ink-soft);
  margin-bottom:10px;display:flex;align-items:center;justify-content:space-between;gap:12px;}
/* FR-033 - khung chỉ đọc. Không có contenteditable ở đâu; `user-select` để cho
   phép sao chép, còn sửa thì không có đường nào. */
.viewer-content{max-height:60vh;overflow-y:auto;border:1px solid var(--line);
  border-radius:10px;padding:20px 24px;background:#fff;font-size:14px;line-height:1.7;}
.viewer-content .docx-p{margin:0 0 10px;}
.viewer-content .docx-empty{height:6px;margin:0;}
.viewer-content .docx-table{border-collapse:collapse;width:100%;margin:12px 0;}
.viewer-content .docx-td{border:1px solid var(--line);padding:7px 9px;vertical-align:top;}

/* FR-034 - chỗ ĐÃ SỬA và chỗ CHỈ TÔ SÁNG phải khác nhau bằng mắt.
   Chỗ sửa hiện cả phần cũ (gạch bỏ, đỏ) lẫn phần mới (gạch chân, xanh); chỗ tô
   sáng là nền vàng, không đổi chữ - đúng như trong tệp Word. */
.viewer-content del{background:#FCEAEA;color:var(--danger);text-decoration:line-through;
  padding:0 2px;border-radius:3px;}
.viewer-content ins{background:#E4F3EB;color:#12603c;text-decoration:underline;
  padding:0 2px;border-radius:3px;}
.viewer-content .mark-highlight{background:#FFF3B0;padding:0 2px;border-radius:3px;
  box-shadow:inset 0 -2px 0 #E0B400;}
/* Chỗ đã chốt. Ba việc khác nhau thì ba màu khác nhau, và cùng bảng màu với chỗ chờ
   chốt ngay trên: đã chấp nhận trông như phần <ins>, đã từ chối thì lơ đi. */
.viewer-content .mark-accepted{background:#E4F3EB;color:#12603c;padding:0 2px;
  border-radius:3px;box-shadow:inset 0 -2px 0 #12603c;}
.viewer-content .mark-rejected{background:#EDF1F5;color:var(--ink-soft);padding:0 2px;
  border-radius:3px;box-shadow:inset 0 -2px 0 #9AA7B4;}
/* Neo của một chỗ ĐÃ CHỐT: trong tệp không còn revision nào để neo vào, nên neo
   là một thẻ rỗng đặt ở đầu khối. Không được chiếm chỗ, kẻo nó đẩy chữ đi. */
.viewer-content .mark-anchor{display:inline;width:0;height:0;overflow:hidden;}
/* FR-035 - chỗ vừa được cuộn tới phải nổi bật rõ. */
.viewer-content .mark-focus{outline:2px solid var(--pink);outline-offset:3px;
  border-radius:4px;transition:outline-color .3s;}

@media (max-width:900px){
  .viewer{grid-template-columns:1fr;}
  .viewer-side{max-height:none;}
}

/* AIT-458 - gom nhóm cột trái theo trạng thái / mức độ / loại lỗi. */
.group-toggle{display:flex;gap:6px;margin-bottom:12px;flex-wrap:wrap;}
.group-toggle button{font-size:11.5px;padding:4px 10px;border-radius:100px;
  border:1px solid var(--line);background:#fff;color:var(--ink-soft);cursor:pointer;}
.group-toggle button:hover{border-color:var(--navy);}
.group-toggle button.on{background:var(--navy);border-color:var(--navy);color:#fff;
  font-weight:600;}
.mark-group-head{display:flex;align-items:baseline;justify-content:space-between;gap:8px;}
.mark-group-head .mark-group{margin:14px 0 6px;}
.group-accept{background:none;border:none;padding:0;cursor:pointer;font-size:10.5px;
  font-weight:600;letter-spacing:.03em;color:var(--pink);}
.group-accept:hover{text-decoration:underline;}
.group-accept:disabled{color:var(--ink-soft);cursor:default;text-decoration:none;}
.mark-cat{font-size:11px;color:var(--ink-soft);margin-left:auto;}
.mark-head{display:flex;align-items:center;gap:4px;flex-wrap:wrap;}

/* AIT-458 - tab tách mục đã ghi vào tệp khỏi danh sách chính.
   Lớp riêng của màn hình Phát hiện; không chạm lớp dùng chung. */
.fd-tabs{display:flex;gap:20px;border-bottom:1px solid var(--line);margin-bottom:14px;}
.fd-tabs button{border:none;background:none;padding:9px 0;cursor:pointer;
  color:var(--ink-soft);font-weight:600;border-bottom:2px solid transparent;}
.fd-tabs button.on{color:var(--navy);border-bottom-color:var(--pink);}
.fd-tabs button span{font-size:11px;
  margin-left:6px;color:var(--ink-soft);}

/* AIT-458 - bảng gọn lại và khung xem tài liệu gốc bên phải.
   Toàn bộ tiền tố `fd-` là của riêng màn hình Phát hiện. */
.fd-split{display:flex;gap:16px;align-items:flex-start;}
.fd-split .fd-list{flex:1 1 auto;min-width:0;}
.fd-split.open .fd-list{flex:0 1 56%;}
.fd-preview{flex:1 1 44%;min-width:0;position:sticky;top:16px;
  border:1px solid var(--line);border-radius:8px;background:#fff;
  max-height:calc(100vh - 60px);display:flex;flex-direction:column;}

.fd-list tbody tr{cursor:pointer;}
.fd-list tbody tr:hover{background:var(--wash);}
.fd-list tbody tr.on{background:#FDEEF3;}
/* `width:1%` là mẹo CSS quen dùng cho bảng `auto` layout: ép cột này co về đúng
   độ rộng nội dung thay vì ăn phần trống dư ra, để phần đó dồn sang hai cột chữ
   dài bên cạnh (`.fd-wrong`, `.fd-suggest`) - đúng chỗ đang cần khoảng rộng hơn
   là "Vị trí". Mẹo này không tự đủ: `nowrap` (bản trước) vẫn buộc trình duyệt
   dành đủ chỗ cho giá trị DÀI NHẤT trong toàn bộ 98 dòng - kể cả dòng có "(dòng
   N)" đang cuộn ngoài màn hình - nên cả cột vẫn rộng ra theo dòng đó. Bỏ nowrap,
   giới hạn `max-width`: dòng dài hiếm gặp xuống hai dòng, còn cột vẫn hẹp. */
.fd-pos,.fd-pos-th{width:1%;max-width:90px;}
.fd-pos{color:var(--ink-soft);font-size:12px;}
.fd-wrong,.fd-suggest{max-width:230px;overflow-wrap:anywhere;}
.fd-wrong{color:#9B1C31;}
.fd-suggest{color:#12603c;}
.fd-none{color:var(--ink-soft);}
/* Cột "Thao tác" trên bảng Phát hiện - hẹp hết mức, nút xếp dọc rộng bằng nhau,
   cùng cách `.row-actions` đang dùng cho bảng Tài liệu. */
.fd-act-col{width:min-content;white-space:nowrap;}
.fd-row-actions{display:flex;flex-direction:column;align-items:stretch;gap:3px;width:min-content;}
/* Ba nút xếp dọc (Sửa/Không sửa/Vào từ điển) - nhỏ hơn `.btn.small` mặc định
   (padding 7px 14px) vì đây là NHIỀU nút chồng nhau trong một cột hẹp, không
   phải một nút đứng riêng; giữ nguyên cỡ mặc định thì cột "Thao tác" cao và to
   hơn hẳn các cột còn lại. */
.fd-row-actions .btn.small{width:100%;white-space:nowrap;padding:4px 10px;font-size:12px;}
/* Đoạn khác nhau giữa "sai" và "đề xuất" - một dấu thanh hay một khoảng trắng
   lẫn vào chữ đồng màu cùng cột thì không ai nhìn ra sự khác biệt là gì.
   `.fd-pv-variants` là danh sách RIÊNG, không nằm trong `.fd-pv-title` - phải
   liệt kê thêm, không phải con của nó. */
.fd-wrong mark,.fd-suggest mark,.fd-pv-title mark,.fd-pv-variants mark{
  background:#FFF3B0;color:inherit;font-weight:700;padding:0 1px;border-radius:2px;}
/* Dấu cho phát hiện không chắc chắn - lệnh nhiều mục bỏ qua nhóm này (FR-009). */
.fd-unsure{display:inline-block;width:15px;height:15px;line-height:15px;
  text-align:center;border-radius:50%;background:#FBF0DD;color:#7a5a12;
  font-size:10px;font-weight:700;cursor:help;}

.fd-pv-head{padding:12px 14px;border-bottom:1px solid var(--line);position:relative;}
.fd-pv-close{position:absolute;top:8px;right:10px;border:none;background:none;
  font-size:18px;line-height:1;cursor:pointer;color:var(--ink-soft);}
.fd-pv-title{font-size:14px;padding-right:22px;}
.fd-pv-title del{color:#9B1C31;}
.fd-pv-title ins{color:#12603c;text-decoration:none;font-weight:600;}
.fd-pv-meta{font-size:11px;color:var(--ink-soft);margin-top:4px;}
.fd-pv-why{font-size:12px;color:var(--ink-soft);margin-top:6px;}
.fd-pv-variants{margin:6px 0 0;padding-left:18px;font-size:12px;}
.fd-note{font-size:12px;color:var(--ink-soft);margin-top:8px;}

.fd-doc{overflow:auto;padding:14px;font-size:12.5px;line-height:1.65;flex:1 1 auto;}
.fd-doc .docx-p{margin:0 0 7px;}
.fd-doc .docx-table{border-collapse:collapse;margin:8px 0;width:100%;}
.fd-doc .docx-td{border:1px solid var(--line);padding:4px 6px;vertical-align:top;}
.fd-doc mark.finding-hit{background:#FFF1B8;padding:0 1px;border-radius:2px;}
.fd-doc mark.fd-hit-on{background:#FFC53D;box-shadow:0 0 0 2px #FFC53D;}
.fd-variants{margin:0;padding-left:15px;}
.fd-variants li{margin:1px 0;}
.fd-pv-variants li{cursor:pointer;padding:1px 4px;border-radius:3px;}
.fd-pv-variants li:hover{background:var(--wash);}
.fd-pv-variants li.on{background:#FFF1B8;}
/* Danh sách có nút chọn dạng đúng: bỏ dấu đầu dòng vì mỗi dòng đã có một nút
   tròn, và hai ký hiệu cạnh nhau thì không rõ cái nào bấm được. */
.fd-pv-variants.picking{list-style:none;padding-left:2px;}
/* `cursor:default` ghi đè luật chung ở trên: ở danh sách có nút chọn, cả dòng
   KHÔNG phải một vùng bấm - chữ và nút tròn làm hai việc khác nhau và tự khai
   con trỏ của mình. */
.fd-pv-variants.picking li{display:flex;align-items:baseline;gap:6px;cursor:default;}
/* Vùng bấm để XEM. Nút tròn nằm ngoài vùng này, nên con trỏ nói đúng: chữ thì
   xem được, nút tròn thì chọn được. */
.fd-pv-variants .fd-v-text{cursor:pointer;flex:1 1 auto;}
.fd-pv-variants.picking input{cursor:pointer;flex:0 0 auto;}
.fd-pv-hint{font-size:11.5px;color:var(--ink-soft);margin-top:4px;}

/* ================= Lớp chỉ v2 dùng =================
   Tệp này phục vụ CẢ HAI giao diện (`/` là v2, `/old` là v1). v1 dựng modal từ một
   khung duy nhất trong `index.html` nên nó chỉ cần `.modal` với `.close` nổi phải;
   v2 dựng mỗi hộp thoại thành một component, và mỗi cái có phần đầu và phần thân
   riêng. Không lớp nào dưới đây có mặt trong `gui/js/`, nên thêm vào đây không đụng
   tới v1. */

/* Đầu hộp thoại: tiêu đề bên trái, nút đóng bên phải.
   `position:relative` là BẮT BUỘC, không phải trang trí: v2 dùng lại `.fd-pv-close`
   (`position:absolute`) làm nút ×, và không có mốc neo ở đây thì nó nhảy ra góc
   trên bên phải của cả lớp phủ, cách hộp thoại một quãng. */
.modal-head{position:relative;display:flex;align-items:flex-start;gap:12px;
  margin-bottom:12px;}
.modal-head h3{margin:0;flex:1 1 auto;}
/* Nút đóng dạng chữ ("Đóng") của khung xem tự đứng cuối hàng. */
.modal-head .btn{flex:0 0 auto;}
/* Không đặt `overflow` ở đây: khung xem đã có hai vùng tự cuộn bên trong
   (`.viewer-side` 66vh, `.viewer-content` 60vh), thêm một thanh cuộn thứ ba bọc
   ngoài là hai thanh chồng nhau trên cùng một nội dung. */
.modal-body{min-width:0;}

/* Hàng phân trang của bảng Tài liệu. v1 gọi là `.pagination` và dựng bằng chuỗi
   HTML; v2 đặt tên `.pager` và dùng `.btn` thật cho hai nút, nên chỉ cần phần bố
   cục - màu và viền nút đã có ở `.btn`. */
.pager{display:flex;align-items:center;gap:8px;margin-top:12px;font-size:12.5px;
  color:var(--ink-soft);}
.pager span{margin-right:auto;}

/* Ba nút gom nhóm ở cột trái khung xem (v1: `.group-toggle`). */
.viewer-modes{display:flex;gap:6px;flex-wrap:wrap;margin:10px 0;}

/* Hàng nút quyết định trong một thẻ dấu vết, và các cụm nút thưa khác của v2. */
.fd-actions{display:flex;gap:6px;flex-wrap:wrap;margin-top:8px;}
