/* ============================================================
   Font: Inter (self-hosted, xem vendor/fonts/ — không load qua CDN để
   giữ app chạy được cả khi mất mạng, cùng nguyên tắc với vendor/*.js)
   ============================================================ */
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("../vendor/fonts/Inter-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("../vendor/fonts/Inter-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("../vendor/fonts/Inter-vietnamese.woff2") format("woff2");
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}

/* ============================================================
   Design tokens
   ============================================================ */
:root {
  --red-h: 356;
  --red: hsl(var(--red-h) 78% 51%);
  --red-dark: hsl(var(--red-h) 78% 43%);
  --red-darker: hsl(var(--red-h) 78% 36%);
  --red-tint: hsl(var(--red-h) 90% 96%);
  --red-tint-border: hsl(var(--red-h) 80% 88%);

  --bg: #f5f6f8;
  --surface: #ffffff;
  --surface-2: #f2f3f5;
  --surface-hover: #eceef1;
  --text: #1a2233;
  --text-light: #667085;
  --text-faint: #98a1ae;
  --border: #e3e6eb;
  --border-strong: #cfd4dc;

  --success: #16a34a;
  --success-tint: #eefbf2;
  --success-border: #c9edd6;
  /* "Xong, nhưng không trọn vẹn" — chuyển hàng loạt có file bị bỏ qua. Cố ý
     tách khỏi cả --success lẫn --red: xanh sẽ giấu mất phần thất bại, còn đỏ
     lại làm người dùng tưởng không có file nào chuyển được. */
  --warn: #b45309;
  --warn-tint: #fdf4e8;
  --warn-border: #f2dcba;
  --info: #2563eb;
  --info-tint: #eef4ff;
  --info-border: #cddefb;
  --purple: #7c3aed;
  --purple-tint: #f4eefe;
  --teal: #0d9488;
  --teal-tint: #eafbf9;

  --radius-sm: 7px;
  --radius: 12px;
  --radius-lg: 18px;
  --radius-pill: 999px;

  --shadow-sm: 0 1px 2px rgba(20, 24, 33, 0.06);
  --shadow-md: 0 4px 14px rgba(20, 24, 33, 0.08);
  --shadow-lg: 0 14px 34px rgba(20, 24, 33, 0.14);
  --shadow-focus: 0 0 0 3px hsl(var(--red-h) 78% 51% / 0.22);

  --ease: cubic-bezier(0.22, 0.9, 0.32, 1);
  --font-ui: "Inter", "Segoe UI", system-ui, -apple-system, Roboto, Helvetica, Arial, sans-serif;
}

:root[data-theme="dark"] {
  --bg: #0f1115;
  --surface: #181b21;
  --surface-2: #20242c;
  --surface-hover: #262b34;
  --text: #eaecef;
  --text-light: #9aa3b2;
  --text-faint: #6b7382;
  --border: #2b3038;
  --border-strong: #3a4049;

  --success: #34d17c;
  --success-tint: #10261a;
  --success-border: #204a30;
  --warn: #f0a33c;
  --warn-tint: #2a1d0c;
  --warn-border: #4d3718;
  --info: #5b9dff;
  --info-tint: #101d33;
  --info-border: #22375d;

  --red-tint: hsl(var(--red-h) 45% 18%);
  --red-tint-border: hsl(var(--red-h) 45% 30%);

  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3);
  --shadow-md: 0 6px 18px rgba(0, 0, 0, 0.35);
  --shadow-lg: 0 18px 40px rgba(0, 0, 0, 0.5);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #0f1115;
    --surface: #181b21;
    --surface-2: #20242c;
    --surface-hover: #262b34;
    --text: #eaecef;
    --text-light: #9aa3b2;
    --text-faint: #6b7382;
    --border: #2b3038;
    --border-strong: #3a4049;

    --success: #34d17c;
    --success-tint: #10261a;
    --success-border: #204a30;
    /* Giữ khớp với khối [data-theme="dark"] ở trên — khối này là bản dự phòng
       cho khoảnh khắc trước khi applyTheme() của app.js kịp chạy. */
    --warn: #f0a33c;
    --warn-tint: #2a1d0c;
    --warn-border: #4d3718;
    --info: #5b9dff;
    --info-tint: #101d33;
    --info-border: #22375d;

    --red-tint: hsl(var(--red-h) 45% 18%);
    --red-tint-border: hsl(var(--red-h) 45% 30%);

    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3);
    --shadow-md: 0 6px 18px rgba(0, 0, 0, 0.35);
    --shadow-lg: 0 18px 40px rgba(0, 0, 0, 0.5);
  }
}

/* ============================================================
   Base
   ============================================================ */
* { box-sizing: border-box; }

html { color-scheme: light dark; }
html[data-theme="dark"] { color-scheme: dark; }
html[data-theme="light"] { color-scheme: light; }

body {
  margin: 0;
  font-family: var(--font-ui);
  background: var(--bg);
  color: var(--text);
  -webkit-font-smoothing: antialiased;
  transition: background 0.2s var(--ease), color 0.2s var(--ease);
}

::selection { background: hsl(var(--red-h) 78% 51% / 0.25); }

a { color: var(--red); }

/* ============================================================
   App shell: sidebar + main area
   ============================================================ */
.app-shell {
  display: flex;
  align-items: stretch;
  min-height: 100vh;
}

.sidebar {
  width: 248px;
  flex-shrink: 0;
  background: var(--surface);
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  padding: 20px 14px;
  position: sticky;
  top: 0;
  height: 100vh;
  overflow-y: auto;
}

.sidebar-brand {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 2px 8px 20px;
}
.sidebar-logo { line-height: 1; display: flex; }

/* Icon tự vẽ (không phải emoji) — xem sprite ẩn đầu index.html + mục "Icon
   emoji -> SVG tự vẽ" trong docs/CHANGELOG.md. stroke:currentColor nên ăn
   theo màu chữ/nền của thẻ cha (mỗi danh mục 1 màu, xem 5 rule bên dưới).
   Icon nào cần TÔ ĐẶC thay vì viền (vd icon-redact, icon-sidebar-logo) tự
   khai `fill`/`stroke` ngay trên path — presentation attribute trên phần tử
   con luôn thắng giá trị kế thừa từ rule dùng chung này. */
.icon-badge .icon,
svg.cat-icon,
.vti-icon-svg,
.sidebar-logo-icon,
.sidebar-nav-icon,
.theme-icon,
.tab-icon-svg {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.icon-badge .icon { width: 28px; height: 28px; }
svg.cat-icon { width: 16px; height: 16px; flex-shrink: 0; vertical-align: -3px; }
.sidebar-logo-icon { width: 26px; height: 26px; flex-shrink: 0; color: var(--red); }
.sidebar-nav-icon { width: 17px; height: 17px; flex-shrink: 0; vertical-align: -3px; }
.theme-icon { width: 18px; height: 18px; flex-shrink: 0; vertical-align: -3px; }
.tab-icon-svg { width: 15px; height: 15px; flex-shrink: 0; vertical-align: -2px; }
.sidebar-title { font-weight: 700; font-size: 15px; letter-spacing: -0.01em; color: var(--text); }
.sidebar-subtitle { font-size: 11px; color: var(--text-light); margin-top: 1px; }

.sidebar-nav { display: flex; flex-direction: column; gap: 2px; margin-bottom: 20px; }
.sidebar-nav-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  border-radius: var(--radius-sm);
  border: none;
  background: none;
  color: var(--text);
  font-size: 13.5px;
  font-weight: 650;
  cursor: pointer;
  text-align: left;
  transition: background 0.15s var(--ease), color 0.15s var(--ease);
}
.sidebar-nav-item:hover { background: var(--surface-2); }
.sidebar-nav-item.active { background: var(--red-tint); color: var(--red-dark); }

.sidebar-section-label {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-faint);
  margin: 6px 12px 8px;
}

.sidebar-categories { display: flex; flex-direction: column; gap: 1px; }
.sidebar-cat {
  display: block;
  width: 100%;
  text-align: left;
  padding: 8px 12px;
  border: none;
  background: none;
  color: var(--text-light);
  font-size: 13px;
  font-weight: 600;
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: background 0.15s var(--ease), color 0.15s var(--ease);
}
.sidebar-cat:hover { background: var(--surface-2); color: var(--text); }
.sidebar-cat.active { background: var(--red-tint); color: var(--red-dark); }

.sidebar-footer {
  margin-top: auto;
  font-size: 11px;
  color: var(--text-faint);
  line-height: 1.5;
  padding: 14px 8px 0;
  border-top: 1px solid var(--border);
}

.main-area {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
}

/* ============================================================
   Header (inside main area)
   ============================================================ */
header.topbar {
  position: sticky;
  top: 0;
  z-index: 20;
  background: var(--bg);
  border-bottom: 1px solid var(--border);
  padding: 16px 28px;
  display: flex;
  align-items: center;
  gap: 14px;
  transition: background 0.2s var(--ease), border-color 0.2s var(--ease);
}

header.topbar .tool-search { flex: 1; margin-bottom: 0; max-width: 480px; }

.theme-toggle {
  flex-shrink: 0;
  width: 36px;
  height: 36px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  font-size: 16px;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background 0.15s var(--ease), transform 0.15s var(--ease), border-color 0.15s var(--ease);
}
.theme-toggle:hover { border-color: var(--red-tint-border); background: var(--red-tint); transform: translateY(-1px); }
.theme-toggle:active { transform: translateY(0); }

/* ============================================================
   Layout
   ============================================================ */
main {
  max-width: 1200px;
  padding: 28px 28px 60px;
  width: 100%;
}

/* ============================================================
   Search
   ============================================================ */
.tool-search {
  position: relative;
  margin-bottom: 26px;
}
.tool-search input {
  width: 100%;
  padding: 12px 16px 12px 40px;
  font-size: 14px;
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  background: var(--surface);
  color: var(--text);
  box-shadow: var(--shadow-sm);
  transition: border-color 0.15s var(--ease), box-shadow 0.15s var(--ease);
}
.tool-search input:focus {
  outline: none;
  border-color: var(--red);
  box-shadow: var(--shadow-focus);
}
.tool-search::before {
  content: "🔍";
  position: absolute;
  left: 14px;
  top: 50%;
  transform: translateY(-50%);
  font-size: 14px;
  opacity: 0.6;
  pointer-events: none;
}
.tool-search-empty {
  display: none;
  text-align: center;
  color: var(--text-light);
  padding: 40px 16px;
  font-size: 14px;
}
.tool-search input { padding-right: 62px; }
.cmdk-hint {
  position: absolute;
  right: 12px;
  top: 50%;
  transform: translateY(-50%);
  padding: 2px 6px;
  border: 1px solid var(--border-strong);
  border-radius: 5px;
  background: var(--surface-2);
  color: var(--text-faint);
  font-size: 11px;
  font-family: var(--font-ui);
  font-style: normal;
  pointer-events: none;
}

/* ============================================================
   Command palette (Ctrl+K) — mở tool từ bất kỳ đâu, không riêng trang chủ
   ============================================================ */
.cmdk-overlay {
  position: fixed;
  inset: 0;
  z-index: 100;
  background: rgba(15, 20, 28, 0.45);
  display: flex;
  justify-content: center;
  padding: 12vh 16px 16px;
}
.cmdk-overlay.hidden { display: none; }
.cmdk-panel {
  width: 100%;
  max-width: 560px;
  max-height: 66vh;
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
  height: fit-content;
}
.cmdk-inputwrap { position: relative; flex-shrink: 0; border-bottom: 1px solid var(--border); }
.cmdk-input {
  width: 100%;
  height: 52px;
  padding: 0 16px 0 46px;
  border: none;
  background: transparent;
  color: var(--text);
  font-family: var(--font-ui);
  font-size: 15px;
  box-sizing: border-box;
}
.cmdk-input:focus { outline: none; }
.cmdk-search-icon {
  position: absolute;
  left: 16px;
  top: 50%;
  transform: translateY(-50%);
  width: 18px;
  height: 18px;
  fill: none;
  stroke: var(--text-faint);
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.cmdk-list { overflow-y: auto; padding: 8px; }
.cmdk-item {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 9px 10px;
  border: none;
  background: none;
  border-radius: var(--radius-sm);
  text-align: left;
  cursor: pointer;
  color: var(--text);
}
.cmdk-item.active,
.cmdk-item:hover { background: var(--red-tint); }
.cmdk-item-icon {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  fill: none;
  stroke: var(--text-light);
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.cmdk-item.active .cmdk-item-icon,
.cmdk-item:hover .cmdk-item-icon { stroke: var(--red-dark); }
.cmdk-item-text { display: flex; flex-direction: column; min-width: 0; }
.cmdk-item-name { font-size: 13.5px; font-weight: 650; }
.cmdk-item-desc {
  font-size: 12px;
  color: var(--text-light);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.cmdk-empty { padding: 32px 16px; text-align: center; color: var(--text-light); font-size: 13px; }
.cmdk-empty.hidden { display: none; }
.cmdk-footer {
  display: flex;
  gap: 14px;
  padding: 8px 14px;
  border-top: 1px solid var(--border);
  font-size: 11px;
  color: var(--text-faint);
  flex-shrink: 0;
}
.cmdk-footer kbd {
  display: inline-block;
  padding: 1px 5px;
  margin-right: 2px;
  border: 1px solid var(--border-strong);
  border-radius: 4px;
  background: var(--surface-2);
  font-family: var(--font-ui);
  font-size: 10.5px;
}

/* ============================================================
   Category sections (collapsible <details>) + grid of tool cards
   ============================================================ */
.tool-category { margin-bottom: 22px; }
.tool-category.hidden { display: none; }
.tool-category[open] { margin-bottom: 30px; }

.tool-category-title {
  font-size: 13.5px;
  font-weight: 700;
  letter-spacing: 0.01em;
  color: var(--text);
  margin: 0 0 12px 2px;
  padding: 4px 2px;
  display: flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
  list-style: none;
  user-select: none;
}
.tool-category-title::-webkit-details-marker { display: none; }
.tool-category-title .chevron {
  margin-left: auto;
  color: var(--text-faint);
  font-size: 15px;
  transition: transform 0.18s var(--ease);
}
.tool-category[open] > .tool-category-title .chevron { transform: rotate(180deg); }
.tool-category-title:hover { color: var(--red-dark); }

/* Per-category accent color for icon badges */
.tool-category[data-category="organize"] .icon-badge { background: var(--red-tint); color: var(--red); }
.tool-category[data-category="optimize"] .icon-badge { background: var(--success-tint); color: var(--success); }
.tool-category[data-category="convert"] .icon-badge { background: var(--info-tint); color: var(--info); }
.tool-category[data-category="edit"] .icon-badge { background: var(--purple-tint); color: var(--purple); }
.tool-category[data-category="security"] .icon-badge { background: var(--teal-tint); color: var(--teal); }

#homeGrid { display: block; }
#homeGrid.hidden { display: none; }

.tool-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
  gap: 14px;
}

.tool-card {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 20px 16px;
  text-align: center;
  cursor: pointer;
  box-shadow: var(--shadow-sm);
  transition: transform 0.18s var(--ease), box-shadow 0.18s var(--ease), border-color 0.18s var(--ease);
}
.tool-card:hover {
  transform: translateY(-3px);
  box-shadow: var(--shadow-lg);
  border-color: var(--red-tint-border);
}
.tool-card:active { transform: translateY(-1px); }
.tool-card.filtered-out { display: none; }

.tool-card .icon-badge {
  width: 52px;
  height: 52px;
  margin: 0 auto 12px;
  border-radius: var(--radius);
  background: var(--red-tint);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: transform 0.18s var(--ease);
}
.tool-card:hover .icon-badge { transform: scale(1.06) rotate(-2deg); }

.tool-card .name { font-weight: 650; font-size: 14.5px; letter-spacing: -0.01em; }
.tool-card .desc { font-size: 12px; color: var(--text-light); margin-top: 4px; line-height: 1.4; }

.badge-new {
  position: absolute;
  top: 10px;
  right: 10px;
  background: var(--info-tint);
  color: var(--info);
  font-size: 10px;
  font-weight: 700;
  padding: 2px 8px;
  border-radius: var(--radius-pill);
}

/* ============================================================
   Tool panel
   ============================================================ */
.tool-panel {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
  padding: 28px;
  animation: panel-in 0.22s var(--ease);
}
.tool-panel.hidden { display: none; }

@keyframes panel-in {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: translateY(0); }
}

.panel-header {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-bottom: 20px;
  padding-bottom: 16px;
  border-bottom: 1px solid var(--border);
}

.back-btn, .btn-secondary {
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  border-radius: var(--radius-sm);
  padding: 7px 13px;
  cursor: pointer;
  font-size: 13px;
  font-weight: 600;
  transition: border-color 0.15s var(--ease), color 0.15s var(--ease), background 0.15s var(--ease);
}
.back-btn:hover, .btn-secondary:hover { border-color: var(--red); color: var(--red); background: var(--red-tint); }
.back-btn:disabled, .btn-secondary:disabled { opacity: 0.45; cursor: not-allowed; }
.back-btn:disabled:hover, .btn-secondary:disabled:hover { border-color: var(--border); color: var(--text); background: var(--surface); }

.panel-header h2 { margin: 0; font-size: 19px; font-weight: 700; letter-spacing: -0.01em; }

.tool-panel h3 {
  font-size: 14px;
  font-weight: 700;
  margin: 0 0 12px;
  color: var(--text);
}

/* ============================================================
   Settings view
   ============================================================ */
.settings-tabs {
  display: flex;
  gap: 20px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 20px;
}
.settings-tab {
  border: none;
  background: none;
  color: var(--text-light);
  font-weight: 650;
  font-size: 14px;
  padding: 10px 2px;
  margin-bottom: -1px;
  cursor: pointer;
  position: relative;
  transition: color 0.15s var(--ease);
}
.settings-tab:hover { color: var(--text); }
.settings-tab.active { color: var(--red); }
.settings-tab.active::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  height: 2px;
  background: var(--red);
  border-radius: 2px;
}

.settings-panel.hidden { display: none; }

.settings-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 16px 2px;
  border-bottom: 1px solid var(--border);
}
.settings-row-title { font-weight: 650; font-size: 14px; color: var(--text); }
.settings-value { font-size: 13.5px; font-weight: 600; color: var(--text-light); }
.settings-input {
  flex: none;
  width: 230px;
  max-width: 45%;
  /* 7px cho chiều cao 33px, khớp đúng nút .btn-secondary đứng ngay dưới nó
     trong cùng bảng Lựa chọn — lệch 4px giữa hai control xếp chồng nhìn ra
     ngay. */
  padding: 7px 12px;
  font-family: var(--font-ui);
  font-size: 13.5px;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  transition: border-color 0.12s var(--ease), box-shadow 0.12s var(--ease);
}
.settings-input:focus { outline: none; border-color: var(--red); box-shadow: var(--shadow-focus); }
.settings-input::placeholder { color: var(--text-faint); }

.settings-list {
  margin: 16px 0 0;
  padding-left: 20px;
  font-size: 13.5px;
  line-height: 1.8;
  color: var(--text-light);
}
.settings-list li { margin-bottom: 6px; }
.settings-list code {
  background: var(--surface-2);
  border-radius: 4px;
  padding: 1px 5px;
  font-size: 12.5px;
}

.toggle-switch { position: relative; display: inline-block; width: 42px; height: 24px; flex-shrink: 0; }
.toggle-switch input { opacity: 0; width: 0; height: 0; position: absolute; }
.toggle-slider {
  position: absolute;
  inset: 0;
  cursor: pointer;
  background: var(--border-strong);
  border-radius: var(--radius-pill);
  transition: background 0.15s var(--ease);
}
.toggle-slider::before {
  content: "";
  position: absolute;
  width: 18px;
  height: 18px;
  left: 3px;
  top: 3px;
  background: white;
  border-radius: 50%;
  transition: transform 0.15s var(--ease);
  box-shadow: var(--shadow-sm);
}
.toggle-switch input:checked + .toggle-slider { background: var(--red); }
.toggle-switch input:checked + .toggle-slider::before { transform: translateX(18px); }
.toggle-switch input:focus-visible + .toggle-slider { box-shadow: var(--shadow-focus); }

/* ============================================================
   Dropzone
   ============================================================ */
.dropzone {
  border: 2px dashed var(--border-strong);
  border-radius: var(--radius);
  padding: 32px 16px;
  text-align: center;
  color: var(--text-light);
  cursor: pointer;
  font-size: 13.5px;
  background: var(--surface-2);
  transition: border-color 0.15s var(--ease), background 0.15s var(--ease), transform 0.1s var(--ease);
}
.dropzone:hover { border-color: var(--red-tint-border); background: var(--red-tint); }
.dropzone.dragover {
  border-color: var(--red);
  background: var(--red-tint);
  color: var(--red-dark);
  transform: scale(1.01);
}
.dropzone strong { color: var(--red); }

/* ============================================================
   File list
   ============================================================ */
.file-list {
  margin-top: 14px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.file-row {
  display: flex;
  align-items: center;
  gap: 10px;
  background: var(--surface-2);
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  padding: 9px 12px;
  font-size: 13px;
  transition: border-color 0.15s var(--ease);
}
.file-row:hover { border-color: var(--border); }
.file-row .fname { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.file-row .fsize { color: var(--text-faint); font-variant-numeric: tabular-nums; }
.file-row button.remove {
  border: none;
  background: none;
  color: var(--text-faint);
  cursor: pointer;
  font-size: 16px;
  line-height: 1;
  width: 22px;
  height: 22px;
  border-radius: var(--radius-pill);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background 0.15s var(--ease), color 0.15s var(--ease);
}
.file-row button.remove:hover { color: var(--red); background: var(--red-tint); }
.file-row .handle { cursor: grab; color: var(--text-faint); }

/* ============================================================
   Options / form fields
   ============================================================ */
.options {
  margin-top: 18px;
  display: flex;
  flex-wrap: wrap;
  gap: 16px 22px;
  padding: 16px;
  background: var(--surface-2);
  border-radius: var(--radius);
}

.option-field { display: flex; flex-direction: column; gap: 6px; font-size: 13px; }
.option-field label { font-weight: 600; color: var(--text); }

.option-field input[type="text"],
.option-field input[type="number"],
.option-field input[type="password"],
.option-field input[type="file"],
.option-field select,
.option-field textarea {
  padding: 8px 11px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  font-size: 13px;
  min-width: 170px;
  background: var(--surface);
  color: var(--text);
  font-family: inherit;
  transition: border-color 0.15s var(--ease), box-shadow 0.15s var(--ease);
}
.option-field textarea { resize: vertical; line-height: 1.5; }
.option-field input:focus, .option-field select:focus, .option-field textarea:focus {
  outline: none;
  border-color: var(--red);
  box-shadow: var(--shadow-focus);
}
.option-field input[type="color"] {
  width: 44px;
  height: 34px;
  padding: 2px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  cursor: pointer;
}
.option-field.checkbox { flex-direction: row; align-items: center; }
.option-field input[type="checkbox"] { accent-color: var(--red); width: 15px; height: 15px; cursor: pointer; }

/* ============================================================
   Actions / buttons
   ============================================================ */
.actions { margin-top: 22px; display: flex; align-items: center; flex-wrap: wrap; gap: 14px; }

button.primary,
label.btn-file.primary {
  background: linear-gradient(135deg, var(--red), var(--red-dark));
  color: white;
  border: none;
  border-radius: var(--radius-sm);
  padding: 11px 26px;
  font-size: 14px;
  font-weight: 650;
  cursor: pointer;
  box-shadow: var(--shadow-sm);
  transition: transform 0.12s var(--ease), box-shadow 0.12s var(--ease), filter 0.12s var(--ease);
}
button.primary:hover:not(:disabled),
label.btn-file.primary:hover { filter: brightness(1.06); box-shadow: var(--shadow-md); transform: translateY(-1px); }
button.primary:active:not(:disabled) { transform: translateY(0); }
button.primary:disabled { background: var(--border-strong); color: var(--text-faint); cursor: not-allowed; box-shadow: none; }
button.primary:focus-visible { outline: none; box-shadow: var(--shadow-focus); }

.status { font-size: 13px; color: var(--text-light); }
.status.error { color: var(--red); font-weight: 600; }
.status.error::before { content: "⚠ "; }
.status.success { color: var(--success); font-weight: 600; }
.status.success::before { content: "✓ "; }
.status.warn { color: var(--warn); font-weight: 600; }
.status.warn::before { content: "! "; }

/* ============================================================
   Progress bar
   ============================================================ */
.progress-bar {
  height: 7px;
  background: var(--surface-2);
  border-radius: var(--radius-pill);
  overflow: hidden;
  margin-top: 12px;
  display: none;
  border: 1px solid var(--border);
}
.progress-bar.active { display: block; }
.progress-bar > div {
  height: 100%;
  width: 0%;
  background: linear-gradient(90deg, var(--red), var(--red-dark));
  border-radius: var(--radius-pill);
  transition: width 0.25s var(--ease);
}

/* ============================================================
   Result box
   ============================================================ */
.result-box {
  margin-top: 20px;
  padding: 18px;
  border-radius: var(--radius);
  background: var(--success-tint);
  border: 1px solid var(--success-border);
  display: none;
  font-size: 13.5px;
  color: var(--text);
  animation: result-in 0.25s var(--ease);
}
.result-box.active { display: block; }
@keyframes result-in {
  from { opacity: 0; transform: translateY(4px); }
  to { opacity: 1; transform: translateY(0); }
}
.result-box a.download-link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-top: 10px;
  margin-right: 10px;
  background: var(--success);
  color: white;
  padding: 9px 18px;
  border-radius: var(--radius-sm);
  text-decoration: none;
  font-size: 13px;
  font-weight: 650;
  box-shadow: var(--shadow-sm);
  transition: filter 0.12s var(--ease), transform 0.12s var(--ease);
}
.result-box a.download-link::before { content: "⬇"; }
.result-box a.download-link:hover { filter: brightness(1.08); transform: translateY(-1px); }
/* Only added for PDF results (see setPdfOpener/showResult in utils.js).
   Deliberately the quieter sibling of the download button: reading the result
   is the shortcut, downloading it is still the main outcome. */
.result-box button.open-in-reader {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-top: 10px;
  background: var(--surface);
  color: var(--text);
  padding: 9px 18px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  font-family: var(--font-ui);
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  box-shadow: var(--shadow-sm);
  transition: background 0.12s var(--ease), border-color 0.12s var(--ease), transform 0.12s var(--ease);
}
.result-box button.open-in-reader::before { content: "📄"; }
.result-box button.open-in-reader:hover:not(:disabled) {
  background: var(--surface-hover);
  border-color: var(--text-light);
  transform: translateY(-1px);
}
.result-box button.open-in-reader:disabled { opacity: 0.6; cursor: not-allowed; }

.hint { font-size: 12px; color: var(--text-light); margin-top: 8px; line-height: 1.5; }

/* ============================================================
   Báo cáo kiểm định (Kiểm định file)
   Ba mức nghiêm trọng dùng đúng 3 cặp token đã có sẵn của hệ thống màu
   (red / warn / info) thay vì màu rời, nên tự đúng ở cả 2 chế độ sáng-tối.
   ============================================================ */
#inspect-report:empty { display: none; }

.audit-summary {
  margin-top: 20px;
  padding: 16px 18px;
  border-radius: var(--radius);
  background: var(--surface-2);
  border: 1px solid var(--border);
  font-size: 14px;
  color: var(--text);
}
.audit-summary.clean { background: var(--success-tint); border-color: var(--success-border); }
.audit-summary.danger { background: var(--red-tint); border-color: var(--red-tint-border); }
.audit-summary .hint { margin-top: 6px; }

.audit-item {
  margin-top: 10px;
  padding: 14px 16px;
  border-radius: var(--radius);
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 3px solid var(--border-strong);
}
.audit-item.sev-high { border-left-color: var(--red); }
.audit-item.sev-medium { border-left-color: var(--warn); }
.audit-item.sev-low { border-left-color: var(--info); }

.audit-item-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.audit-title { font-size: 14px; font-weight: 650; color: var(--text); }

.audit-sev {
  flex: none;
  padding: 2px 10px;
  border-radius: var(--radius-pill);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.02em;
  border: 1px solid transparent;
}
.audit-sev.sev-high { background: var(--red-tint); border-color: var(--red-tint-border); color: var(--red-dark); }
.audit-sev.sev-medium { background: var(--warn-tint); border-color: var(--warn-border); color: var(--warn); }
.audit-sev.sev-low { background: var(--info-tint); border-color: var(--info-border); color: var(--info); }
/* Ở nền tối, `--red` nguyên bản trên nền `--red-tint` chỉ đạt tương phản 3.27
   — dưới chuẩn AA, và trớ trêu là rơi đúng vào chip QUAN TRỌNG NHẤT. Đẩy sáng
   lên 66% cho ~5.1 (hai chip còn lại vốn đã 7,8 và 6,2). */
:root[data-theme="dark"] .audit-sev.sev-high { color: hsl(var(--red-h) 85% 66%); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .audit-sev.sev-high { color: hsl(var(--red-h) 85% 66%); }
}

.audit-detail {
  margin-top: 7px;
  font-size: 13px;
  line-height: 1.65;
  color: var(--text-light);
  word-break: break-word;
}
.audit-manual {
  margin-top: 9px;
  padding: 9px 12px;
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  border: 1px solid var(--border);
  font-size: 12.5px;
  line-height: 1.6;
  color: var(--text);
}

.inspect-clean {
  margin-top: 22px;
  padding: 18px;
  border-radius: var(--radius);
  background: var(--surface-2);
  border: 1px solid var(--border);
}
.inspect-clean.hidden { display: none; }
.inspect-clean-title { font-size: 14px; font-weight: 650; color: var(--text); margin-bottom: 12px; }
.inspect-clean-options { display: flex; flex-direction: column; gap: 10px; }
.inspect-clean-options .option-field.checkbox { gap: 9px; cursor: pointer; }
.inspect-clean-options .option-field.checkbox span { font-size: 13px; line-height: 1.5; }
.inspect-clean .actions { margin-top: 16px; }

/* ============================================================
   Page picker (Cắt trang / Bôi đen / Ký PDF)
   Drag a rectangle straight on a rendered page.
   ============================================================ */
.page-picker { margin-top: 14px; }
.pp-toolbar {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  margin-bottom: 10px;
}
.pp-toolbar[hidden] { display: none; }
.pp-nav {
  width: 32px;
  height: 32px;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--text);
  font-size: 12px;
  cursor: pointer;
}
.pp-nav:hover { background: var(--surface-hover); }
.pp-pageinfo { font-size: 13px; color: var(--text-light); }
.pp-sep { width: 1px; height: 20px; background: var(--border); margin: 0 2px; }
.pp-clear { padding: 7px 12px; font-size: 12.5px; }
.pp-hint { font-size: 12px; color: var(--text-light); flex: 1; min-width: 180px; }
.pp-stage {
  display: flex;
  justify-content: center;
  padding: 14px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}
.pp-empty { font-size: 13px; color: var(--text-light); padding: 26px 0; }
.pp-page {
  position: relative;
  background: white;
  box-shadow: var(--shadow-lg);
  border-radius: 2px;
  line-height: 0;
}
.pp-page[hidden] { display: none; }
.pp-page canvas { display: block; border-radius: 2px; }
.pp-overlay {
  position: absolute;
  inset: 0;
  cursor: crosshair;
  /* Without this the drag can start a native image/text drag instead. */
  touch-action: none;
  user-select: none;
}
.pp-rect {
  position: absolute;
  border: 2px solid var(--red);
  background: rgba(229, 50, 45, 0.16);
  box-sizing: border-box;
}
.pp-rect-preview { border-style: dashed; }
/* Vùng do QUÉT THEO MẪU sinh ra (tool Bôi đen): nét đứt + màu cảnh báo để phân
   biệt ngay với vùng người dùng tự kéo — hai loại có vòng đời khác nhau (vùng
   quét dựng lại theo danh sách kết quả), và người dùng cần thấy đâu là chỗ máy
   đoán, đâu là chỗ mình tự quyết. */
.pp-rect-scan {
  border-color: var(--warn);
  border-style: dashed;
  background: rgba(180, 83, 9, 0.16);
}
.pp-rect-scan .pp-rect-del { background: var(--warn); }
.pp-rect-del {
  position: absolute;
  top: -11px;
  right: -11px;
  width: 22px;
  height: 22px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: var(--red);
  color: white;
  font-size: 15px;
  line-height: 1;
  cursor: pointer;
  box-shadow: var(--shadow-sm);
}
.pp-rect-del:hover { background: var(--red-dark); }

/* ---- Sửa mục lục (tools/outline.js) ---- */
.ol-editor {
  margin-top: 14px;
  max-height: 460px;
  /* Khai cả hai trục — xem Bẫy #13. */
  overflow: hidden auto;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
}
.ol-editor[hidden] { display: none; }
/* Thụt lề theo cấp bằng padding-left tính từ biến --ol-depth do JS đặt: mỗi cấp
   22px. Dùng padding chứ không margin để dải nền/viền dưới của dòng vẫn kéo hết
   bề rộng, nhìn ra được đây là một danh sách liền mạch chứ không phải các khối
   rời bị đẩy lệch. */
.ol-row {
  display: flex;
  align-items: center;
  /* wrap để .ol-problem (flex-basis 100%) xuống hàng riêng dưới các ô nhập —
     thiếu nó thì dòng báo lỗi bị nhồi vào cùng hàng và bóp hết ô tiêu đề. */
  flex-wrap: wrap;
  gap: 8px;
  padding: 8px 12px 8px calc(12px + var(--ol-depth, 0) * 22px);
  border-bottom: 1px solid var(--border);
}
.ol-row:last-child { border-bottom: none; }
.ol-row.invalid { background: var(--warn-tint); }
.ol-title {
  flex: 1 1 auto;
  min-width: 0;
  padding: 6px 9px;
  font-family: inherit;
  font-size: 13px;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
}
.ol-title:focus { outline: none; border-color: var(--red); box-shadow: 0 0 0 3px var(--red-tint); }
.ol-page {
  flex: 0 0 auto;
  width: 66px;
  padding: 6px 8px;
  font-family: inherit;
  font-size: 13px;
  font-variant-numeric: tabular-nums;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
}
.ol-tools { display: flex; gap: 3px; flex: 0 0 auto; }
.ol-btn {
  width: 26px;
  height: 26px;
  padding: 0;
  font-family: inherit;
  font-size: 12px;
  line-height: 1;
  color: var(--text-light);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  cursor: pointer;
}
.ol-btn:hover:not(:disabled) { color: var(--red); border-color: var(--red); background: var(--red-tint); }
.ol-btn:disabled { opacity: 0.35; cursor: not-allowed; }
/* Dòng báo lỗi chiếm cả hàng riêng bên dưới các ô nhập của cùng dòng mục. */
.ol-problem {
  flex: 1 0 100%;
  margin-top: 2px;
  font-size: 11.5px;
  font-weight: 600;
  color: var(--warn);
}

/* ---- Quét theo mẫu trong tool Bôi đen (redact-patterns.js) ---- */
.rp-types { display: flex; flex-wrap: wrap; gap: 8px 18px; margin-top: 8px; }
.rp-type {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  color: var(--text);
  cursor: pointer;
}
.rp-type input { accent-color: var(--red); width: 15px; height: 15px; cursor: pointer; }
.rp-actions { margin-top: 10px; }
.rp-findings {
  margin-top: 10px;
  max-height: 300px;
  /* Khai cả hai trục — xem Bẫy #13. */
  overflow: hidden auto;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
}
.rp-findings[hidden] { display: none; }
.rp-head {
  padding: 10px 12px;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--text);
  background: var(--warn-tint);
  border-bottom: 1px solid var(--warn-border);
}
.rp-bulk { display: flex; gap: 8px; margin-top: 8px; }
.rp-group {
  position: sticky;
  top: 0;
  z-index: 1;
  padding: 6px 12px;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--text-light);
  background: var(--surface-2);
  border-bottom: 1px solid var(--border);
}
.rp-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 7px 12px;
  border-bottom: 1px solid var(--border);
  cursor: pointer;
}
.rp-row:last-child { border-bottom: none; }
.rp-row input { accent-color: var(--red); width: 15px; height: 15px; cursor: pointer; flex: 0 0 auto; }
.rp-badge {
  flex: 0 0 auto;
  padding: 2px 7px;
  font-size: 11px;
  font-weight: 700;
  color: var(--warn);
  background: var(--warn-tint);
  border: 1px solid var(--warn-border);
  border-radius: 999px;
}
/* Chuỗi tìm được hiện nguyên văn, cắt bớt nếu quá dài để một email dài không đẩy
   nút "Xem trên trang" ra ngoài. Chữ số cùng bề rộng (tabular-nums) cho dễ soi
   dãy số — KHÔNG đổi sang font đơn cách: cả app không có chỗ nào dùng monospace,
   thêm ở đúng một chỗ này là lạc khỏi hệ thiết kế. */
.rp-text {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 12.5px;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.01em;
  color: var(--text);
}
.rp-jump {
  flex: 0 0 auto;
  padding: 3px 8px;
  font-family: inherit;
  font-size: 11.5px;
  color: var(--text-light);
  background: var(--surface-2);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  cursor: pointer;
}
.rp-jump:hover { color: var(--red); border-color: var(--red); }

/* Signature pad */
.sign-pad-wrap {
  margin-top: 6px;
  padding: 10px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}
.sign-pad {
  display: block;
  width: 100%;
  max-width: 520px;
  height: 180px;
  background: white;
  /* A ruled baseline makes it obvious this is a place to sign. */
  background-image: linear-gradient(to right, var(--border) 0 100%);
  background-size: calc(100% - 48px) 1px;
  background-position: 24px 132px;
  background-repeat: no-repeat;
  border: 1px dashed var(--border);
  border-radius: var(--radius-sm);
  cursor: crosshair;
  touch-action: none;
}

/* ============================================================
   Điền biểu mẫu (fillform) — danh sách ô bên trái, trang xem trước bên phải
   ============================================================ */
.ff-empty {
  margin-top: 14px;
  padding: 22px 16px;
  text-align: center;
  font-size: 13px;
  color: var(--text-light);
  line-height: 1.6;
  background: var(--surface-2);
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius);
}
.ff-empty[hidden] { display: none; }

/* Hai cột chia theo TỈ LỆ, không phải "trang xem trước lấy bao nhiêu cũng được"
   (`auto`). Đo ở cửa sổ 1280px: khung xem trước ăn 590px cứng làm cột nhập chỉ
   còn 298px — hẹp tới mức khó điền, mà đây mới là chỗ người dùng gõ. */
.ff-layout {
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
  gap: 16px;
  align-items: start;
  margin-top: 14px;
}
.ff-layout[hidden] { display: none; }

.ff-fields {
  max-height: 560px;
  /* Khai báo CẢ HAI trục: chỉ đặt overflow-y thì trình duyệt tự suy overflow-x
     thành auto và bố cục co lại một cách khó hiểu — xem Bẫy #13. */
  overflow: hidden auto;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
}
.ff-group {
  position: sticky;
  top: 0;
  z-index: 1;
  padding: 7px 14px;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--text-light);
  background: var(--surface-2);
  border-bottom: 1px solid var(--border);
}
.ff-field {
  padding: 11px 14px;
  border-bottom: 1px solid var(--border);
  border-left: 3px solid transparent;
}
.ff-field:last-child { border-bottom: none; }
.ff-field.active { border-left-color: var(--red); background: var(--red-tint); }
.ff-label {
  display: block;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--text);
  margin-bottom: 5px;
}
.ff-required { color: var(--red); margin-left: 3px; }
.ff-note { font-size: 11.5px; color: var(--text-light); margin-top: 5px; line-height: 1.45; }
.ff-input {
  width: 100%;
  padding: 7px 10px;
  font-family: inherit;
  font-size: 13px;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
}
.ff-input:focus { outline: none; border-color: var(--red); box-shadow: 0 0 0 3px var(--red-tint); }
.ff-input:disabled { background: var(--surface-2); color: var(--text-faint); }
textarea.ff-input { resize: vertical; line-height: 1.5; }
.ff-check { display: flex; align-items: center; gap: 7px; font-size: 13px; color: var(--text); cursor: pointer; }
.ff-check input { accent-color: var(--red); width: 15px; height: 15px; cursor: pointer; }

.ff-preview-bar { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; }
.ff-stage {
  display: flex;
  justify-content: center;
  padding: 14px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}
/* Canvas được vẽ ở đúng kích thước tính lúc render, nhưng vẫn co lại được khi
   người dùng đổi cỡ cửa sổ sau đó — khung các ô đặt theo phần trăm nên vẫn
   nằm đúng chỗ ở mọi tỉ lệ. */
.ff-page { position: relative; max-width: 100%; background: white; box-shadow: var(--shadow-lg); border-radius: 2px; line-height: 0; }
.ff-page canvas { display: block; max-width: 100%; height: auto; border-radius: 2px; }
.ff-overlay { position: absolute; inset: 0; }
.ff-box {
  position: absolute;
  box-sizing: border-box;
  border: 1px solid var(--info);
  background: rgba(37, 99, 235, 0.1);
  border-radius: 1px;
  cursor: pointer;
}
.ff-box:hover { background: rgba(37, 99, 235, 0.2); }
.ff-box.active { border: 2px solid var(--red); background: rgba(229, 50, 45, 0.16); }
.ff-box.readonly { border-style: dashed; border-color: var(--text-faint); background: transparent; cursor: default; }

/* Xếp dọc sớm hơn breakpoint 860px quen thuộc của app, và đây là con số ĐO chứ
   không phải chọn cho tròn: panel công cụ hẹp hơn cửa sổ khoảng 319px (sidebar
   + lề), nên ở cửa sổ 900px hai cột chỉ còn 271px cho ô nhập và 206px cho trang
   xem trước — cả hai đều vô dụng. Ở 1100px, panel còn ~780px, chia ra vẫn được
   ~409px/~356px là dùng được. */
@media (max-width: 1100px) {
  .ff-layout { grid-template-columns: minmax(0, 1fr); }
  .ff-fields { max-height: 420px; }
}

/* ============================================================
   Tạo ô điền (prepareform) — phần riêng, phần khung dùng chung .ff-*
   ============================================================
   Tool này và Điền biểu mẫu là hai nửa của cùng một việc (tạo ô ↔ điền ô) nên
   dùng CHUNG bộ .ff-* phía trên cho khung 2 cột / danh sách / trang xem trước:
   sửa bố cục 1 lần là cả hai theo, thay vì 2 bản gần-giống-nhau rồi lệch dần.
   Chỉ những gì tool này có mà tool kia không có mới đặt tên .pf-*. */
.pf-type-label { display: flex; align-items: center; gap: 6px; font-size: 12.5px; color: var(--text-light); }
.pf-type {
  padding: 5px 8px;
  font-family: inherit;
  font-size: 12.5px;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
}
.pf-draw-hint { margin-top: 8px; font-size: 11.5px; color: var(--text-light); line-height: 1.45; }

/* Con trỏ chữ thập trên cả lớp overlay: ở đây kéo-để-vẽ là việc CHÍNH, khác
   fillform (overlay chỉ để bấm chọn ô có sẵn). */
.pf-overlay { cursor: crosshair; }

.pf-box {
  position: absolute;
  box-sizing: border-box;
  border: 1.5px solid var(--info);
  background: rgba(37, 99, 235, 0.12);
  border-radius: 1px;
  cursor: pointer;
}
.pf-box:hover { background: rgba(37, 99, 235, 0.22); }
.pf-box.active { border: 2px solid var(--red); background: rgba(229, 50, 45, 0.16); }
/* Ô chưa dùng được (thiếu lựa chọn, trùng giá trị...) phải nhìn ra ngay trên
   trang, không chỉ báo ở dòng trong danh sách — người dùng đang nhìn trang. */
.pf-box.invalid { border-color: var(--warn); border-style: dashed; background: rgba(180, 83, 9, 0.14); }
.pf-box-preview { border-style: dashed; background: rgba(37, 99, 235, 0.08); pointer-events: none; }
/* Nhãn nằm NGOÀI khung, phía trên: ô đánh dấu/nút chọn chỉ 14pt nên nhãn đặt
   bên trong sẽ tràn kín ô và che luôn nội dung trang bên dưới. */
.pf-box-tag {
  position: absolute;
  left: -1.5px;
  bottom: 100%;
  max-width: 220px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  padding: 1px 4px;
  font-size: 10px;
  line-height: 1.35;
  color: white;
  background: var(--info);
  border-radius: 2px 2px 0 0;
  pointer-events: none;
}
.pf-box.active .pf-box-tag { background: var(--red); }
.pf-box.invalid .pf-box-tag { background: var(--warn); }

.pf-row-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 7px; }
/* MỘT kiểu badge cho cả 5 loại ô, cố ý không tô màu riêng từng loại: bộ token
   của app chỉ có 4 màu mang nghĩa (red/success/warn/info) và 3 trong số đó đã
   có nghĩa khác (lỗi / xong / cảnh báo) — gán chúng cho "loại ô" sẽ đọc thành
   trạng thái, còn bịa thêm màu thứ 5 thì vỡ hệ màu và vỡ luôn dark mode. Chữ
   trong badge đã nói rõ loại; màu ở đây dành cho TRẠNG THÁI (đang chọn / chưa
   dùng được), giống đúng cách .ff-box phía trên đang làm. */
.pf-badge {
  padding: 2px 7px;
  font-size: 11px;
  font-weight: 700;
  color: var(--info);
  background: var(--info-tint);
  border: 1px solid var(--info-border);
  border-radius: 999px;
}
.pf-row-del {
  padding: 2px 6px;
  font-size: 13px;
  line-height: 1;
  color: var(--text-light);
  background: none;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  cursor: pointer;
}
.pf-row-del:hover { color: var(--red); border-color: var(--border-strong); background: var(--surface-2); }

.pf-inline { display: flex; align-items: center; gap: 8px; margin-bottom: 7px; }
.pf-inline > label { flex: 0 0 auto; min-width: 88px; font-size: 12px; color: var(--text-light); }
.pf-inline-block { display: block; }
.pf-inline-block > label { display: block; margin-bottom: 4px; min-width: 0; }
.pf-flags { display: flex; flex-wrap: wrap; gap: 6px 14px; margin-top: 8px; }
.pf-flags .ff-check { font-size: 12px; }
.pf-problem { color: var(--warn); font-weight: 600; }
.pf-list-empty { padding: 18px 14px; text-align: center; }

/* ============================================================
   Page thumbnails (rotate / split / organize)
   ============================================================ */
.page-thumbs {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 14px;
}
.page-thumb {
  border: 2px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 5px;
  text-align: center;
  font-size: 11px;
  color: var(--text-light);
  cursor: pointer;
  user-select: none;
  width: 96px;
  background: var(--surface);
  transition: border-color 0.15s var(--ease), background 0.15s var(--ease), transform 0.1s var(--ease);
}
.page-thumb:hover { border-color: var(--border-strong); transform: translateY(-2px); }
.page-thumb.selected { border-color: var(--red); background: var(--red-tint); color: var(--red-dark); }
.page-thumb canvas, .page-thumb img { width: 100%; display: block; border-radius: 4px; }

.organize-empty {
  border: 2px dashed var(--border);
  border-radius: var(--radius);
  padding: 40px 16px;
  text-align: center;
  color: var(--text-light);
  margin-top: 14px;
  font-size: 13.5px;
}
.organize-card {
  width: 132px;
  cursor: grab;
  position: relative;
  padding-bottom: 32px;
}
.organize-card:active { cursor: grabbing; }
.organize-card img { width: 100%; display: block; border-radius: 4px; transition: transform 0.15s var(--ease); }
.organize-label {
  font-size: 10px;
  color: var(--text-faint);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  margin-top: 4px;
}
.organize-toolbar {
  position: absolute;
  bottom: 4px;
  left: 4px;
  right: 4px;
  display: flex;
  justify-content: space-between;
  gap: 4px;
}
.organize-toolbar button {
  flex: 1;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  border-radius: var(--radius-sm);
  font-size: 12px;
  padding: 3px 0;
  cursor: pointer;
  transition: border-color 0.15s var(--ease), color 0.15s var(--ease);
}
.organize-toolbar button:hover { border-color: var(--red); color: var(--red); }

/* ============================================================
   Compare PDF
   ============================================================ */
.compare-columns {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
}
.compare-columns .option-field { width: 100%; }
.compare-columns label { font-weight: 700; font-size: 13px; margin-bottom: 6px; display: block; }
@media (max-width: 640px) {
  .compare-columns { grid-template-columns: 1fr; }
}

#compare-summary {
  margin-top: 14px;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--text);
}

#compare-viewer {
  margin-top: 14px;
}
#compare-viewer .diff-body {
  max-height: 480px;
  overflow: auto;
  white-space: pre-wrap;
  word-break: break-word;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 18px;
  font-size: 13.5px;
  line-height: 1.7;
  background: var(--surface);
}
#compare-viewer ins {
  background: var(--success-tint);
  color: var(--success);
  text-decoration: none;
  border-radius: 3px;
  padding: 0 1px;
}
#compare-viewer del {
  background: var(--red-tint);
  color: var(--red-dark);
  border-radius: 3px;
  padding: 0 1px;
}

/* ============================================================
   Footer
   ============================================================ */
footer {
  text-align: center;
  font-size: 12px;
  color: var(--text-faint);
  padding: 24px 20px;
}

/* ============================================================
   Responsive
   ============================================================ */
@media (max-width: 860px) {
  .app-shell { flex-direction: column; }
  .sidebar {
    width: 100%;
    height: auto;
    position: relative;
    flex-direction: row;
    align-items: center;
    overflow-x: auto;
    padding: 10px 14px;
    gap: 16px;
    scrollbar-width: thin;
  }
  .sidebar-brand { padding: 0; flex-shrink: 0; }
  .sidebar-subtitle { display: none; }
  .sidebar-nav { flex-direction: row; margin-bottom: 0; flex-shrink: 0; }
  .sidebar-nav-item span { display: none; }
  .sidebar-section-label { display: none; }
  .sidebar-categories { flex-direction: row; gap: 6px; flex-shrink: 0; }
  .sidebar-cat { white-space: nowrap; }
  .sidebar-footer { display: none; }
}

@media (max-width: 640px) {
  header.topbar { padding: 12px 16px; flex-wrap: wrap; }
  main { padding: 18px 12px 40px; }
  .tool-grid { grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 10px; }
  .tool-card { padding: 14px 10px; }
  .tool-card .icon-badge { width: 42px; height: 42px; }
  .tool-card .icon-badge .icon { width: 22px; height: 22px; }
  .tool-panel { padding: 18px; }
  .options { padding: 12px; gap: 12px 16px; }
  .option-field input, .option-field select { min-width: 140px; }
}

/* ============================================================
   Tab bar (top-level) + tab views
   ============================================================ */
html, body { height: 100%; }
body { display: flex; flex-direction: column; }

.tab-bar {
  display: flex;
  align-items: center;
  gap: 4px;
  height: 44px;
  flex-shrink: 0;
  padding: 0 10px;
  background: var(--surface-2);
  border-bottom: 1px solid var(--border);
  overflow: hidden;
}
.tab-list {
  display: flex;
  align-items: stretch;
  gap: 2px;
  flex: 1;
  min-width: 0;
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: thin;
  height: 100%;
  padding-top: 6px;
}
.tab-list::-webkit-scrollbar { height: 6px; }
.tab-list::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 3px; }

.app-tab {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 0 14px 0 12px;
  height: 100%;
  max-width: 220px;
  min-width: 80px;
  background: transparent;
  border: 1px solid transparent;
  border-bottom: none;
  border-top-left-radius: 8px;
  border-top-right-radius: 8px;
  color: var(--text-light);
  font-family: var(--font-ui);
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  transition: background 0.12s var(--ease), color 0.12s var(--ease);
  position: relative;
}
.app-tab:hover { background: var(--surface-hover); color: var(--text); }
.app-tab.active {
  background: var(--surface);
  color: var(--text);
  border-color: var(--border);
  z-index: 1;
}
.app-tab.active::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -1px;
  height: 1px;
  background: var(--surface);
}
.app-tab .tab-icon { font-size: 15px; flex-shrink: 0; }
.app-tab .tab-title {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  flex: 1;
  min-width: 0;
}
.app-tab .tab-close {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  border-radius: 4px;
  border: none;
  background: transparent;
  color: var(--text-faint);
  font-size: 14px;
  line-height: 1;
  cursor: pointer;
  padding: 0;
  flex-shrink: 0;
}
.app-tab .tab-close:hover { background: var(--red-tint); color: var(--red); }
.app-tab[data-tab-type="home"] .tab-close { display: none; }
/* Drag to reorder: the dragged tab fades, and a bar marks where it will land. */
.app-tab.dragging { opacity: 0.45; }
.app-tab.drop-before::before,
.app-tab.drop-after::after {
  content: "";
  position: absolute;
  top: 4px;
  bottom: 4px;
  width: 2px;
  border-radius: 1px;
  background: var(--red);
}
.app-tab.drop-before::before { left: -1px; }
.app-tab.drop-after::after { right: -1px; }

.tab-add {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  margin-top: 6px;
  border-radius: 6px;
  border: none;
  background: transparent;
  color: var(--text-light);
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
  flex-shrink: 0;
}
.tab-add:hover { background: var(--surface-hover); color: var(--text); }

.tab-body {
  flex: 1;
  overflow: hidden;
  position: relative;
  min-height: 0;
}
.tab-view {
  position: absolute;
  inset: 0;
  overflow-y: auto;
  display: none;
  background: var(--bg);
}
.tab-view.active { display: block; }
.tab-view .app-shell { min-height: 100%; }
.tab-view .sidebar { height: 100%; }

/* ============================================================
   "Mở Tệp" (open-file) view
   ============================================================ */
.openfile-view {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100%;
  padding: 40px 24px;
}
.openfile-card {
  width: 100%;
  max-width: 560px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
  padding: 36px 32px;
  text-align: center;
}
.openfile-card h2 {
  margin: 0 0 6px;
  font-size: 22px;
  font-weight: 700;
  letter-spacing: -0.01em;
}
.openfile-card .openfile-sub {
  color: var(--text-light);
  font-size: 13.5px;
  margin: 0 0 22px;
}
.openfile-drop {
  border: 2px dashed var(--border-strong);
  border-radius: var(--radius);
  padding: 40px 24px;
  cursor: pointer;
  background: var(--surface-2);
  color: var(--text-light);
  transition: background 0.12s var(--ease), border-color 0.12s var(--ease), color 0.12s var(--ease);
}
.openfile-drop:hover, .openfile-drop.dragover {
  border-color: var(--red);
  background: var(--red-tint);
  color: var(--red-dark);
}
.openfile-drop .of-icon { font-size: 42px; line-height: 1; margin-bottom: 10px; }
.openfile-drop strong { color: var(--red); font-weight: 600; }
.openfile-status { margin-top: 14px; font-size: 13px; color: var(--text-light); min-height: 18px; }
.openfile-status.error { color: var(--red); }

/* ============================================================
   PDF Viewer layout
   ============================================================ */
.viewer-layout {
  display: grid;
  grid-template-columns: 200px 1fr 300px;
  height: 100%;
  min-height: 100%;
  background: var(--bg);
}

.viewer-thumbs {
  background: var(--surface);
  border-right: 1px solid var(--border);
  overflow: hidden;
  padding: 0;
  display: flex;
  flex-direction: column;
  min-height: 0;
}
.viewer-thumbs-body {
  display: grid;
  grid-template-columns: 48px 1fr;
  flex: 1;
  min-height: 0;
}
.viewer-side-rail {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 10px 6px;
  border-right: 1px solid var(--border);
  background: var(--surface);
  align-items: center;
}
.rail-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border: 1px solid transparent;
  background: transparent;
  color: var(--text-light);
  cursor: pointer;
  border-radius: 8px;
  padding: 0;
  transition: background 0.12s var(--ease), color 0.12s var(--ease), border-color 0.12s var(--ease);
}
.rail-btn:hover { background: var(--surface-hover); color: var(--text); }
.rail-btn.active {
  background: var(--surface);
  color: var(--red);
  border-color: var(--red-tint-border);
}
.rail-btn svg { display: block; }
.viewer-side-content {
  overflow-y: auto;
  /* No top padding — .viewer-panel-header sits flush at the top so its
     border-bottom lines up with the main toolbar's (both 48px + border). */
  padding: 0 8px 12px;
  min-width: 0;
  /* Same fix as .viewer-tools: a visible scrollbar reserves width via the
     implied overflow-x: auto, shrinking content narrower than the panel. */
  scrollbar-width: none;
}
.viewer-side-content::-webkit-scrollbar { display: none; }
.viewer-side-view { display: none; }
.viewer-side-view.active { display: block; }

.viewer-info { display: flex; flex-direction: column; gap: 14px; padding: 4px 4px 20px; }
.viewer-info-item .viewer-info-label {
  font-size: 12px;
  font-weight: 700;
  color: var(--text);
  margin-bottom: 2px;
}
.viewer-info-item .viewer-info-value {
  font-size: 12.5px;
  color: var(--text-light);
  word-break: break-word;
  line-height: 1.4;
}
.viewer-thumbs-title {
  font-size: 14px;
  font-weight: 600;
  color: var(--text);
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  text-align: center;
}
.viewer-panel-header {
  display: flex;
  align-items: center;
  gap: 8px;
  height: 48px;
  box-sizing: border-box;
  padding: 0 8px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 10px;
}
.viewer-panel-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text-light);
  border-radius: 8px;
  line-height: 1;
  cursor: pointer;
  padding: 0;
  flex-shrink: 0;
  transition: background 0.12s var(--ease), color 0.12s var(--ease), border-color 0.12s var(--ease), box-shadow 0.12s var(--ease), transform 0.12s var(--ease);
}
.viewer-panel-toggle:hover {
  background: var(--red-tint);
  border-color: var(--red-tint-border);
  color: var(--red-dark);
  box-shadow: var(--shadow-sm);
}
.viewer-panel-toggle:active { transform: scale(0.92); }
/* Chevron direction: when the panel is expanded the arrow points toward the
   edge (left panel points left, collapsing it; right panel points right,
   collapsing it); once collapsed it flips to point inward (expand me). */
.viewer-panel-toggle .toggle-chevron { transition: transform 0.16s var(--ease); }
.viewer-panel-toggle[data-toggle-left] .toggle-chevron { transform: rotate(180deg); }
.viewer-thumbs.collapsed .viewer-panel-toggle[data-toggle-left] .toggle-chevron { transform: rotate(0deg); }
.viewer-panel-toggle[data-toggle-right] .toggle-chevron { transform: rotate(0deg); }
.viewer-tools.collapsed .viewer-panel-toggle[data-toggle-right] .toggle-chevron { transform: rotate(180deg); }
.viewer-thumb {
  position: relative;
  margin: 0 auto 12px;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  padding: 4px;
  border-radius: 6px;
  transition: background 0.12s var(--ease);
}
.viewer-thumb:hover { background: var(--surface-hover); }
.viewer-thumb.active { background: var(--red-tint); }
.viewer-thumb canvas {
  max-width: 140px;
  width: 100%;
  height: auto;
  border: 2px solid var(--border);
  border-radius: 4px;
  box-shadow: var(--shadow-sm);
  background: white;
  transition: border-color 0.12s var(--ease);
}
.viewer-thumb.active canvas { border-color: var(--red); }
.viewer-thumb-num { font-size: 12px; color: var(--text-light); }

.viewer-main {
  display: flex;
  flex-direction: column;
  min-width: 0;
  overflow: hidden;
  /* Anchor for the floating find bar. It must NOT anchor to
     .viewer-canvas-area — that one scrolls, and the bar would scroll away. */
  position: relative;
}
.viewer-toolbar {
  display: flex;
  align-items: center;
  /* 4px chứ không 6: với ~30 phần tử thì mỗi 2px chênh lệch là 60px bề ngang —
     nhiều hơn cả một cái nút. Xem mục "Thanh công cụ trình đọc" trong
     docs/ARCHITECTURE.md về ngân sách bề ngang của thanh này. */
  gap: 4px;
  padding: 8px 12px;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
  /* Never wrap to a second row — that would grow the toolbar's height past
     the 48px side rails and break the corner alignment when collapsed.
     Scroll horizontally instead so the height always stays one row tall. */
  flex-wrap: nowrap;
  overflow-x: auto;
  /* Hidden, not disabled — wheel/trackpad scroll still works. A visible
     scrollbar would add height and break the 48px corner alignment. */
  scrollbar-width: none;
}
.viewer-toolbar::-webkit-scrollbar { display: none; }
.viewer-toolbar button {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 32px;
  min-width: 32px;
  padding: 0 8px;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 6px;
  color: var(--text);
  font-size: 14px;
  cursor: pointer;
  flex-shrink: 0;
}
.viewer-toolbar button:hover:not(:disabled) { background: var(--surface-hover); border-color: var(--border); }
.viewer-toolbar button:disabled { opacity: 0.4; cursor: not-allowed; }
.viewer-toolbar button.active { background: var(--red-tint); border-color: var(--red-tint-border); color: var(--red-dark); }
/* These Unicode glyphs carry less visual weight than +/−/◀/▶ at the same size,
   so they get bumped up to look optically equal next to them. */
.viewer-toolbar button[data-rotate-left],
.viewer-toolbar button[data-rotate-right],
.viewer-toolbar button[data-print],
.viewer-toolbar button[data-fullscreen] {
  font-size: 19px;
}
/* Vạch ngăn nhóm. Quy tắc: KHÔNG đặt vạch cạnh một điều khiển đã có viền
   (select, input) — viền của chính nó đã tách nhóm rồi, thêm vạch chỉ tốn
   9px mỗi cái mà không thêm thông tin. */
.viewer-toolbar .vt-sep {
  width: 1px;
  height: 20px;
  background: var(--border);
  margin: 0 2px;
  flex-shrink: 0;
}
.viewer-toolbar .vt-pagenum {
  display: flex;
  align-items: center;
  gap: 4px;
  font-size: 13px;
  color: var(--text-light);
  flex-shrink: 0;
}
.viewer-toolbar .vt-pagenum input {
  width: 44px;
  height: 28px;
  border: 1px solid var(--border);
  border-radius: 5px;
  background: var(--surface-2);
  color: var(--text);
  text-align: center;
  font-family: var(--font-ui);
  font-size: 13px;
}
.viewer-toolbar .vt-zoom {
  display: flex;
  align-items: center;
  gap: 2px;
  font-size: 13px;
  color: var(--text-light);
  flex-shrink: 0;
}
.viewer-toolbar .vt-zoom input {
  width: 46px;
  height: 28px;
  border: 1px solid var(--border);
  border-radius: 5px;
  background: var(--surface-2);
  color: var(--text);
  text-align: center;
  font-family: var(--font-ui);
  font-size: 13px;
  /* Hide the native up/down spinner — clutters a field this narrow and the
     zoom in/out buttons already cover that role. */
  -moz-appearance: textfield;
}
.viewer-toolbar .vt-zoom input::-webkit-outer-spin-button,
.viewer-toolbar .vt-zoom input::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

.viewer-toolbar .vt-page-layout {
  height: 32px;
  padding: 0 8px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--surface);
  color: var(--text);
  font-family: var(--font-ui);
  font-size: 13px;
  cursor: pointer;
  flex-shrink: 0;
}
/* Chế độ đọc vô hiệu hoá select/input không áp dụng được (bố cục trang, chỉnh
   vừa kích thước, zoom, màu chú thích) — button:disabled đã có style riêng ở
   trên, đây là phần còn lại (input/select không phải button). */
.viewer-toolbar select:disabled,
.viewer-toolbar input:disabled,
.viewer-toolbar .vt-annot-color:disabled { opacity: 0.4; cursor: not-allowed; }

/* ⚠️ `[hidden]` của HTML chỉ là `display: none` trong bảng kiểu mặc định của
   trình duyệt, nên bất kỳ rule `display` nào của chính phần tử cũng đè mất nó
   — đúng cái bẫy đã làm vỏ điện thoại che kín trang (xem CHANGELOG 2026-08-21).
   `.vt-sep` không đặt `display` nên hiện tại không dính, nhưng khai báo tường
   minh để lần sau thêm rule không âm thầm làm vạch ngăn hiện lại. */
.viewer-toolbar .vt-sep[hidden] { display: none; }

/* Nút tràn "»" — xem js/viewer-overflow.js. */
.viewer-toolbar .vt-overflow-btn {
  font-size: 18px;
  font-weight: 700;
  /* Luôn ở cuối thanh và không bao giờ bị co lại: nó chính là đường vào phần
     đang không nhìn thấy. */
  margin-left: auto;
}
.viewer-toolbar .vt-overflow-btn[aria-expanded="true"] {
  background: var(--surface-hover);
  border-color: var(--border);
}

/* Menu là ANH EM của thanh công cụ chứ không phải con — thanh có
   `overflow-x: auto` nên con absolute sẽ bị cắt cụt. Mốc định vị là
   `.viewer-main`, đúng chỗ ô tìm kiếm nổi đang neo. */
.vt-overflow-menu {
  position: absolute;
  top: 48px;
  right: 8px;
  z-index: 40;
  display: grid;
  grid-template-columns: max-content 1fr;
  align-items: center;
  gap: 2px 10px;
  padding: 6px;
  max-width: min(320px, calc(100% - 16px));
  max-height: min(60vh, 420px);
  overflow-y: auto;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.16);
}
.vt-overflow-menu.hidden { display: none; }
.vt-overflow-menu .vt-of-label {
  font-size: 13px;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* Ô chọn mang sẵn chữ của nó nên chiếm trọn hàng, không cần cột nhãn. */
.vt-overflow-menu select {
  grid-column: 1 / -1;
  width: 100%;
}
/* Nút trong menu giữ nguyên kiểu của thanh công cụ (kể cả trạng thái .active
   của các chế độ chú thích) — chỉ đổi chỗ, không đổi diện mạo. */
.vt-overflow-menu button {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 32px;
  min-width: 32px;
  padding: 0 8px;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 6px;
  color: var(--text);
  font-size: 14px;
  cursor: pointer;
}
.vt-overflow-menu button:hover:not(:disabled) { background: var(--surface-hover); border-color: var(--border); }
.vt-overflow-menu button:disabled { opacity: 0.4; cursor: not-allowed; }
.vt-overflow-menu button.active { background: var(--red-tint); border-color: var(--red-tint-border); color: var(--red-dark); }
.vt-overflow-menu button[data-rotate-left],
.vt-overflow-menu button[data-rotate-right],
.vt-overflow-menu button[data-print],
.vt-overflow-menu button[data-fullscreen] { font-size: 19px; }
/* Hàng nào bị vô hiệu hoá (Chế độ đọc tắt bớt điều khiển) thì nhãn mờ theo,
   nếu không chữ vẫn đậm trong khi nút đã xám. */
.vt-overflow-menu button:disabled + .vt-of-label,
.vt-overflow-menu input:disabled + .vt-of-label { opacity: 0.4; }


.viewer-canvas-area.pan-mode { cursor: grab; }
.viewer-canvas-area.pan-mode.panning { cursor: grabbing; }
/* While panning, a plain click-drag over text/canvas must move the page,
   not start a text selection — see wirePanTool() in viewer.js. */
.viewer-canvas-area.pan-mode { user-select: none; }

.viewer-canvas-area {
  flex: 1;
  overflow: auto;
  padding: 22px;
  background: var(--surface-2);
  /* Block (not flex) + the fit-content/min-width trick on .viewer-pages: with
     `display:flex; align-items:center` a page zoomed wider than the area gets
     its overflowing left half clipped and unreachable by scrolling. */
  display: block;
}
/* Chế độ đọc bật => vùng canvas nhường chỗ. Không có dòng này thì `display:block`
   ở trên thắng (cùng độ đặc hiệu, khai báo sau) và cả hai panel cùng hiện. */
.viewer-canvas-area.hidden { display: none; }
/* min-width:100% keeps pages centred while they fit; width:fit-content lets the
   scroll extent grow with them once they don't. */
.viewer-pages {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 26px;
  width: fit-content;
  min-width: 100%;
  margin: 0 auto;
}
/* "Hai trang" (two-page) mode: layoutPages() in viewer.js groups pages into
   one of these per row (page 1+2, 3+4, ...) instead of appending them
   straight to .viewer-pages. Gap here MUST match .viewer-pages' own gap —
   fitWidth()/fitPage() add the same number in as PAGE_GAP when sizing a pair. */
.viewer-page-row {
  display: flex;
  flex-direction: row;
  align-items: flex-start;
  gap: 26px;
}
.viewer-page {
  position: relative;
  background: white;
  box-shadow: var(--shadow-lg);
  border-radius: 3px;
  /* The canvas used to round its own corners; a partial (sliced) canvas can't,
     so the box clips instead — same visual result for both cases. */
  overflow: hidden;
  flex-shrink: 0;
  /* pdf.js sizes the text layer with round(down, var(--total-scale-factor) * Npx,
     var(--scale-round-x)); without these it falls back to `auto` and every span
     lands in the wrong place. --total-scale-factor is set per page from JS. */
  --scale-round-x: 1px;
  --scale-round-y: 1px;
}
/* Absolute + 100%/100% is identical to the old in-flow `display:block` fill for
   a whole-page canvas (the box always has an explicit width/height from
   applyPageBox()), but it also lets renderPage() place a PARTIAL canvas: an
   oversized page is rasterized one viewport slice at a time and the slice's
   left/top/width/height are set inline. The box's own white background shows
   through wherever no slice has been drawn yet, which reads as blank paper
   rather than a hole. See sliceFor() in viewer.js. */
.viewer-page canvas {
  position: absolute;
  left: 0;
  top: 0;
  display: block;
  width: 100%;
  height: 100%;
}
/* ---- Tông màu trang khi đọc (data-page-tint trên <html>, xem utils.js) ----
   KHÁC chế độ tối của app (đổi vỏ giao diện) và khác Chế độ đọc (thay canvas
   bằng HTML). Đây chỉ là lớp màu phủ lên chính trang PDF, để đọc lâu đỡ chói.

   Dùng `filter` trên canvas chứ không phủ một lớp màu đè lên: filter chạy ở
   khâu ghép hình (GPU), không buộc vẽ lại trang, nên đổi tông màu ở tài liệu
   1000 trang cũng không tốn gì. Quan trọng hơn: nó KHÔNG đụng vào lớp chữ và
   lớp annotation nằm trên canvas, nên bôi đen chọn chữ, ô tìm kiếm tô sáng và
   nét chú thích giữ nguyên màu thật.

   `.viewer-page` phải đổi nền theo: chỗ chưa vẽ tới của trang khổ lớn (rasterize
   theo từng vùng khung nhìn — xem sliceFor() trong viewer.js) để lộ chính nền
   này, mà nền trắng cạnh canvas ngả vàng thì thành hai mảng màu khác nhau trên
   cùng một tờ giấy. */
/* ⚠️ THỨ TỰ trong chuỗi filter quyết định có thấy gì hay không: `brightness()`
   phải đứng TRƯỚC `sepia()`. Ma trận sepia làm kênh đỏ/lục của màu trắng vượt
   mức tối đa rồi bị chặn lại, nên `sepia(0.42)` một mình để nguyên trang gần
   như trắng. Đã đo bằng cách chạy đúng chuỗi filter này qua ctx.filter của
   canvas rồi đọc pixel:
     sepia(0.42) brightness(0.98)  ->  trang trắng thành rgb(249,249,243)  (vô hình)
     brightness(0.87) sepia(0.42)  ->  trang trắng thành rgb(254,240,215)  (giấy ngà thật)
   Cả hai chuỗi đều để CHỮ ĐEN nguyên rgb(0,0,0) — phép biến đổi là tuyến tính,
   không cộng thêm nền, nên độ tương phản chữ/giấy không giảm.
   Màu nền hộp trang bên dưới đặt ĐÚNG bằng con số đo được, không phải ước lượng
   bằng mắt: lệch là thấy 2 mảng màu trên trang khổ lớn vẽ theo từng vùng. */
:root[data-page-tint="sepia"] .viewer-page { background: rgb(254, 240, 215); }
:root[data-page-tint="sepia"] .viewer-page canvas { filter: brightness(0.87) sepia(0.42); }
:root[data-page-tint="warm"] .viewer-page { background: rgb(250, 245, 236); }
:root[data-page-tint="warm"] .viewer-page canvas { filter: brightness(0.93) sepia(0.16) grayscale(0.1); }

/* Chế độ đọc (văn bản chảy) không có canvas nào để lọc — ở đó chính khung HTML
   là "trang giấy", nên tô thẳng nền/màu chữ cho khớp với bản canvas. Không làm
   chỗ này thì bật tông màu rồi chuyển sang Chế độ đọc là trắng chói trở lại. */
:root[data-page-tint="sepia"] .viewer-flow-inner { background: rgb(254, 240, 215); color: #40372a; }
:root[data-page-tint="warm"] .viewer-flow-inner { background: rgb(250, 245, 236); color: #3a3a38; }

.viewer-page-label {
  position: absolute;
  right: 2px;
  bottom: -20px;
  font-size: 11px;
  color: var(--text-light);
  pointer-events: none;
  user-select: none;
}
/* The text and annotation layers are laid out in unrotated page space (pdf.js
   positions their contents from the raw viewBox), so a rotated page needs the
   whole layer rotated into place — same rules the stock pdf.js viewer uses.
   pdf.js sets data-main-rotation on each layer itself. */
.viewer-page .textLayer[data-main-rotation="90"],
.viewer-page .annotationLayer[data-main-rotation="90"] { transform: rotate(90deg) translateY(-100%); }
.viewer-page .textLayer[data-main-rotation="180"],
.viewer-page .annotationLayer[data-main-rotation="180"] { transform: rotate(180deg) translate(-100%, -100%); }
.viewer-page .textLayer[data-main-rotation="270"],
.viewer-page .annotationLayer[data-main-rotation="270"] { transform: rotate(270deg) translateX(-100%); }

/* ============================================================
   Chú thích khi đọc (viewer-annotate.js) — highlight / ghi chú / vẽ tay / thêm chữ
   ============================================================ */
.viewer-toolbar .vt-annot-color {
  width: 28px;
  height: 28px;
  padding: 2px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--surface);
  cursor: pointer;
  flex-shrink: 0;
}
/* Không toạ độ theo % như .textLayer/.annotationLayer (đã tính sẵn rotation
   khi đổi toạ độ trong JS, không cần transform bù như 2 lớp đó của pdf.js —
   xem toPdfRect() trong page-picker.js, cùng kỹ thuật) — nên KHÔNG có khối
   [data-main-rotation] transform ở đây, cố ý. */
.annotateLayer {
  position: absolute;
  inset: 0;
  pointer-events: none;
  touch-action: none;
}
/* Layer chỉ thật sự "auto" (bắt được click đặt mới) lúc đang ở 1 trong 3 chế
   độ đặt-điểm; 3 chế độ đánh dấu chữ (Highlight/Gạch chân/Gạch ngang) KHÔNG nằm
   trong danh sách này — chúng phải để trống trang bôi đen chọn chữ được bình
   thường (uỷ việc bắt sự kiện cho document "mouseup" ở wireAnnotateToolbar(),
   không cần layer chặn click). */
.viewer-canvas-area[data-annotate-mode="note"] .annotateLayer,
.viewer-canvas-area[data-annotate-mode="ink"] .annotateLayer,
.viewer-canvas-area[data-annotate-mode="freetext"] .annotateLayer {
  pointer-events: auto;
  cursor: crosshair;
}

/* Highlight / Gạch chân / Gạch ngang: cùng 1 hộp phủ đúng ô chữ (QuadPoints),
   chỉ khác cách vẽ bên trong — xem _renderTextMarkup() trong viewer-annotate.js.
   Vị trí + độ dày nét gạch do JS tính theo tỉ lệ chiều cao ô chữ (dùng chung
   hằng số với bản ghi vào file), không đặt cứng ở đây. */
.annot-textmark {
  position: absolute;
  pointer-events: none;
}
.annot-highlight {
  mix-blend-mode: multiply;
  border-radius: 1px;
}
.annot-textmark-line {
  position: absolute;
  left: 0;
  right: 0;
  border-radius: 1px;
}
/* Chỉ annotation CÙNG kiểu với chế độ đang bật mới bấm được để xoá — giữ đúng
   quy ước đã có của highlight (đang đọc bình thường thì mọi đánh dấu trong suốt
   với chuột, không cản việc chọn chữ bên dưới). */
.viewer-canvas-area[data-annotate-mode="highlight"] .annot-highlight,
.viewer-canvas-area[data-annotate-mode="underline"] .annot-underline,
.viewer-canvas-area[data-annotate-mode="strikeout"] .annot-strikeout {
  pointer-events: auto;
  cursor: pointer;
}

.annot-note {
  position: absolute;
  width: 18px;
  height: 18px;
  padding: 0;
  border: 1px solid rgba(0, 0, 0, 0.25);
  border-radius: 4px 4px 4px 0;
  font-size: 11px;
  line-height: 18px;
  text-align: center;
  cursor: pointer;
  pointer-events: auto;
  box-shadow: var(--shadow-sm);
}

.annot-freetext {
  position: absolute;
  max-width: 260px;
  padding: 2px 4px;
  font-family: var(--font-ui);
  font-size: 13px;
  line-height: 1.25;
  white-space: pre-wrap;
  word-break: break-word;
  cursor: pointer;
  pointer-events: auto;
  background: rgba(255, 255, 255, 0.55);
  border-radius: 3px;
}
:root[data-theme="dark"] .annot-freetext { background: rgba(0, 0, 0, 0.4); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .annot-freetext { background: rgba(0, 0, 0, 0.4); }
}

.annot-ink-preview,
.annot-ink-stroke {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  pointer-events: none;
}
.annot-ink-preview path,
.annot-ink-stroke path {
  fill: none;
  stroke-width: 2px;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.viewer-canvas-area[data-annotate-mode="ink"] .annot-ink-stroke path {
  pointer-events: stroke;
  cursor: pointer;
}

/* ---- Trang khổ lớn: lời mời phóng to (viewer-largepage.js) ---- */
/* Neo bên TRÁI, khác ô tìm / thanh Đo / thanh Đọc to (neo phải): ba cái kia là
   bộ điều khiển người dùng vừa chủ động mở ra và biết đi tìm ở đâu; cái này tự
   hiện ra nên phải nằm ở chỗ mắt đọc tới đầu tiên. */
.viewer-largepage {
  left: 18px;
  right: auto;
  max-width: calc(100% - 36px);
  flex-wrap: wrap;
  gap: 10px;
}
.viewer-largepage-text {
  font-size: 12.5px;
  line-height: 1.4;
  color: var(--text-light);
  max-width: 420px;
}
.viewer-largepage-btn {
  width: auto;
  padding: 0 12px;
  white-space: nowrap;
  border-color: var(--border);
  color: var(--red-dark);
  font-weight: 600;
}
.viewer-largepage-btn:hover { background: var(--red-tint); border-color: var(--red-tint-border); }

/* ---- Quét bằng camera (tools/scan.js) ---- */
.scan-stage {
  margin-top: 18px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  padding: 14px;
}
.scan-empty {
  padding: 34px 12px;
  text-align: center;
  color: var(--text-light);
  font-size: 13.5px;
}
.scan-empty[hidden], .scan-editor[hidden] { display: none; }
.scan-editor { display: flex; justify-content: center; }
/* `position: relative` + con `absolute` là thứ giữ 4 tay nắm bám đúng ảnh: toạ
   độ góc được lưu chuẩn hoá 0..1 rồi nhân với kích thước HIỂN THỊ của <img>, nên
   ảnh co lại theo bề rộng panel thì tay nắm vẫn nằm đúng chỗ trên tờ giấy. */
.scan-frame { position: relative; display: inline-block; max-width: 100%; line-height: 0; }
.scan-frame img { max-width: 100%; max-height: 62vh; display: block; border-radius: 4px; }
.scan-svg { position: absolute; inset: 0; pointer-events: none; }
.scan-svg polygon { fill: rgba(228, 33, 46, 0.14); stroke: var(--red); stroke-width: 2; }
.scan-overlay { position: absolute; inset: 0; }
.scan-handle {
  position: absolute;
  width: 30px;
  height: 30px;
  margin: -15px 0 0 -15px;
  border-radius: 50%;
  border: 2px solid #fff;
  background: var(--red);
  box-shadow: var(--shadow-md);
  cursor: grab;
  /* Chặn cuộn/zoom của trình duyệt khi ngón tay bắt đầu kéo trên tay nắm —
     không có nó thì trên điện thoại kéo góc sẽ cuộn cả trang thay vì dời góc. */
  touch-action: none;
}
.scan-handle.dragging { cursor: grabbing; transform: scale(1.12); }
.scan-handle:focus-visible { outline: none; box-shadow: var(--shadow-focus); }
.scan-pages {
  margin-top: 16px;
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}
.scan-pages[hidden] { display: none; }
.scan-page {
  position: relative;
  width: 112px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
  padding: 6px;
}
.scan-page img { width: 100%; display: block; border-radius: 3px; }
.scan-page-no {
  display: block;
  text-align: center;
  font-size: 12px;
  color: var(--text-light);
  margin-top: 4px;
}
.scan-page-del {
  position: absolute;
  top: -8px;
  right: -8px;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text-light);
  font-size: 12px;
  line-height: 1;
  cursor: pointer;
}
.scan-page-del:hover { border-color: var(--red); color: var(--red); }

/* ---- Đo lường (viewer-measure.js) ---- */
/* Lớp overlay nhận chuột trong chế độ Đo. KHÔNG dùng data-annotate-mode như 3
   chế độ đặt-điểm: Đo là chế độ riêng, loại trừ lẫn nhau với chú thích chứ không
   phải một kiểu chú thích, nên nó có cờ riêng trên canvasArea. */
.viewer-canvas-area.measure-mode .annotateLayer {
  pointer-events: auto;
  cursor: crosshair;
}
/* Cùng khuôn với .annot-ink-stroke phía trên: SVG phủ đúng hộp trang, khai cả
   width/height (chỉ `inset:0` thì SVG lấy kích thước nội tại 300×150 chứ không
   giãn theo hộp) và overflow:visible cho nhãn tràn ra ngoài đường đo. */
.annot-measure {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  pointer-events: none;
}
.annot-measure path {
  fill: none;
  stroke-width: 1.5px;
  stroke-linecap: round;
}
/* Đo diện tích: ruột tô rất nhạt để thấy vùng nào đang được đo mà vẫn đọc được
   bản vẽ bên dưới (đặc lại là che mất đúng thứ người ta đang đo). Cùng độ mờ
   với bản ghi vào file PDF — xem MEASURE_AREA_FILL_ALPHA ở viewer-annotate.js. */
.annot-measure-area .annot-measure-fill {
  fill-opacity: 0.12;
  stroke-width: 1.5px;
  stroke-linejoin: round;
}
.annot-measure-vertex { pointer-events: none; }

/* Đường bắt chuột: dày, trong suốt, và chỉ bấm được khi đang ở chế độ Đo — cùng
   quy ước với nét vẽ tay (.annot-ink-stroke) ở trên. */
.annot-measure-hit { stroke: transparent; stroke-width: 12px; }
.viewer-canvas-area.measure-mode .annot-measure-hit {
  pointer-events: stroke;
  cursor: pointer;
}
/* Bản xem trước (đang chờ điểm thứ hai): nét đứt để phân biệt rõ với phép đo đã
   chốt, nếu không người dùng không biết mình đã bấm xong chưa. */
.annot-measure-preview path { stroke-dasharray: 5 4; }
/* Viền trắng quanh chữ (paint-order) để số đo đọc được cả khi nằm đè lên vùng
   nét dày của bản vẽ — không cần vẽ hộp nền che mất nội dung bên dưới. */
.annot-measure-label {
  font: 700 11px var(--font-ui);
  paint-order: stroke;
  stroke: white;
  stroke-width: 3px;
  stroke-linejoin: round;
  text-anchor: middle;
}
.viewer-measure { gap: 6px; }
/* Nhãn + ô chọn của thanh Đo lường và thanh Đọc to dùng chung một bộ style: cùng
   là "nhãn nhỏ đứng cạnh select" trong cùng kiểu hộp nổi. Thêm selector vào đây
   thay vì chép lại khối rule cho .viewer-speak-field. */
.viewer-measure-unit,
.viewer-speak-field {
  display: flex;
  align-items: center;
  gap: 4px;
  font-size: 12px;
  color: var(--text-light);
  white-space: nowrap;
}
.viewer-measure-unit select,
.viewer-speak-field select {
  height: 28px;
  padding: 0 4px;
  font-family: inherit;
  font-size: 12.5px;
  color: var(--text);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 6px;
}
.viewer-measure-status {
  max-width: 260px;
  font-size: 11.5px;
  line-height: 1.35;
  color: var(--text-light);
}
.viewer-measure-calib { display: flex; align-items: center; gap: 4px; }
.viewer-measure-calib[hidden] { display: none; }
.viewer-measure-input { width: 86px; }

/* ---- Đọc to (viewer-speak.js) ---- */
/* Thanh này có nhiều thứ hơn ô tìm và thanh Đo (4 nút + 2 ô chọn + dòng trạng
   thái), nên phải xuống dòng được: hộp neo ở góc phải (right: 18px) nên nếu cứ
   giãn ra một hàng thì trên màn hình hẹp nó tràn ra NGOÀI mép trái khung nhìn —
   mất luôn nút ▶, không cuộn tới được. */
.viewer-speak {
  gap: 6px;
  flex-wrap: wrap;
  max-width: calc(100% - 36px);
}
/* Tên giọng của hệ điều hành có thể rất dài ("Microsoft HoaiMy Online (Natural)
   - Vietnamese (Vietnam)") — chặn bề rộng để một ô chọn không chiếm cả thanh. */
.viewer-speak-field select { max-width: 190px; }
.viewer-speak [data-speak-status] { max-width: 100%; }
@media (max-width: 860px) {
  .viewer-speak-field select { max-width: 120px; }
}
/* Hai trạng thái KHÁC nhau trên cùng cái nút, cố ý phân biệt được từ xa:
   `.active` (nhạt, quy ước chung của toolbar) = thanh Đọc to đang mở;
   `.speaking` (đặc) = đang thật sự phát tiếng. Nút luôn có cả 2 class khi đang
   đọc, nên bản đặc phải đứng SAU để thắng. Nhờ vậy nhìn nút là biết đang đọc hay
   đang tạm dừng, không phải đọc dòng trạng thái. */
.viewer-toolbar button[data-speak].speaking {
  background: var(--red);
  border-color: var(--red);
  color: #fff;
}

.annot-editor {
  position: absolute;
  z-index: 8;
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 8px;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-lg);
}
.annot-editor textarea {
  width: 100%;
  min-height: 56px;
  resize: vertical;
  padding: 6px 8px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--surface-2);
  color: var(--text);
  font-family: var(--font-ui);
  font-size: 13px;
  box-sizing: border-box;
}
.annot-editor-actions {
  display: flex;
  justify-content: flex-end;
  gap: 6px;
}
.annot-editor-actions button {
  height: 26px;
  padding: 0 9px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--surface-2);
  color: var(--text);
  font-size: 12px;
  cursor: pointer;
}
.annot-editor-save { border-color: var(--red-tint-border); color: var(--red-dark); background: var(--red-tint); }
.annot-editor-delete:hover { border-color: var(--red-tint-border); color: var(--red-dark); }

/* ============================================================
   Chế độ đọc (viewer-flow.js) — văn bản chảy, thay canvas trang bằng HTML
   thuần dựng từ cùng pipeline suy luận cấu trúc của PDF -> Markdown.
   ============================================================ */
.viewer-flow {
  flex: 1;
  overflow: auto;
  padding: 40px 24px;
  background: var(--surface-2);
}
/* Chưa bật chế độ đọc thì panel này phải biến mất hẳn — thiếu dòng này nó vẫn
   chiếm nửa khung nhìn và hiện ra một thẻ trắng rỗng ngay dưới trang PDF. */
.viewer-flow.hidden { display: none; }
.viewer-flow-inner {
  max-width: 720px;
  margin: 0 auto;
  padding: 48px clamp(20px, 6vw, 56px);
  background: var(--surface);
  border-radius: 8px;
  box-shadow: var(--shadow-lg);
  color: var(--text);
  font-family: var(--font-ui);
  line-height: 1.7;
  /* Cỡ chữ tự co giãn theo bề rộng khung nhìn — đúng ý "Liquid Mode": rộng
     hơn thì chữ lớn hơn (trong giới hạn), hẹp lại (điện thoại) thì chữ nhỏ lại
     nhưng không bao giờ dưới mức đọc được. */
  font-size: clamp(15px, 1.1vw + 11px, 18px);
  overflow-wrap: break-word;
}
.viewer-flow-inner h1, .viewer-flow-inner h2, .viewer-flow-inner h3 {
  margin: 1.4em 0 0.6em;
  line-height: 1.3;
  color: var(--text);
}
.viewer-flow-inner h1 { font-size: 1.8em; }
.viewer-flow-inner h2 { font-size: 1.4em; }
.viewer-flow-inner h3 { font-size: 1.15em; }
.viewer-flow-inner h1:first-child,
.viewer-flow-inner h2:first-child,
.viewer-flow-inner h3:first-child { margin-top: 0; }
.viewer-flow-inner p { margin: 0 0 1em; }
.viewer-flow-inner ul, .viewer-flow-inner ol { margin: 0 0 1em; padding-left: 1.6em; }
.viewer-flow-inner li { margin: 0.3em 0; }
.viewer-flow-inner a { color: var(--red); text-decoration: underline; }
.viewer-flow-inner table { width: 100%; border-collapse: collapse; margin: 0 0 1.4em; font-size: 0.92em; }
.viewer-flow-inner th, .viewer-flow-inner td { border: 1px solid var(--border); padding: 6px 10px; text-align: left; vertical-align: top; }
.viewer-flow-inner th { background: var(--surface-2); font-weight: 600; }
.viewer-flow-inner .flow-image { margin: 0 0 1.4em; }
.viewer-flow-inner .flow-image img { max-width: 100%; height: auto; border-radius: 4px; display: block; margin: 0 auto; }
/* Mốc phân trang — chỉ để định vị cuộn (gotoPage()/syncFlowCurrentPage() ở
   viewer-flow.js) và cho người đọc biết đang ở trang nào của bản gốc, không
   mang ý nghĩa ngắt trang thật (đây là văn bản chảy liên tục). */
.viewer-flow-inner .flow-page-marker {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 2.2em 0;
  color: var(--text-light);
  font-size: 0.6em;
  user-select: none;
}
.viewer-flow-inner .flow-page-marker::before,
.viewer-flow-inner .flow-page-marker::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--border);
}

@media (max-width: 860px) {
  .viewer-flow { padding: 16px 8px; }
  .viewer-flow-inner { padding: 28px 20px; border-radius: 6px; }
}

/* Search hits. Painted by the browser's highlight registry over the (invisible)
   text layer spans, so the glyphs on the canvas below stay untouched. */
::highlight(pdf-find) {
  background-color: rgba(255, 196, 0, 0.42);
}
::highlight(pdf-find-current) {
  background-color: rgba(255, 138, 0, 0.75);
}
/* Câu đang được đọc to (viewer-speak.js) — cùng sổ đăng ký highlight với kết quả
   tìm, nên phải là màu KHÁC HẲN họ vàng/cam ở trên: hai thứ dễ cùng hiện một
   lúc (vừa tìm vừa nghe đọc) và không được lẫn vào nhau. */
::highlight(pdf-speak) {
  background-color: rgba(45, 140, 255, 0.32);
}

.viewer-loading {
  color: var(--text-light);
  padding: 40px;
  font-size: 14px;
}

/* Shown only once the layout is too narrow for side columns (see the 860px
   block at the end of this file), where the panels turn into overlay drawers. */
.viewer-narrow-only { display: none !important; }
.viewer-backdrop {
  display: none;
  position: absolute;
  inset: 0;
  z-index: 15;
  background: rgba(15, 20, 28, 0.45);
}

/* Find bar — floats over the top-right of the page area like a browser's own */
.viewer-find {
  position: absolute;
  /* Just below the 48px toolbar + its 1px border. */
  top: 58px;
  right: 18px;
  z-index: 6;
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 6px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: var(--shadow-lg);
}
.viewer-find.hidden { display: none; }
.viewer-find-input {
  width: 190px;
  height: 30px;
  padding: 0 10px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--surface-2);
  color: var(--text);
  font-family: var(--font-ui);
  font-size: 13px;
}
.viewer-find-input:focus {
  outline: none;
  border-color: var(--red);
  box-shadow: 0 0 0 3px var(--red-tint);
}
.viewer-find-input::-webkit-search-cancel-button { display: none; }
.viewer-find-count {
  min-width: 62px;
  padding: 0 2px;
  font-size: 12px;
  color: var(--text-light);
  text-align: center;
  white-space: nowrap;
}
.viewer-find-count.no-match { color: var(--red); }
.viewer-find-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  padding: 0;
  border: 1px solid transparent;
  border-radius: 6px;
  background: transparent;
  color: var(--text);
  font-size: 13px;
  font-family: var(--font-ui);
  cursor: pointer;
  flex-shrink: 0;
}
.viewer-find-btn:hover { background: var(--surface-hover); border-color: var(--border); }
.viewer-find-btn.active { background: var(--red-tint); border-color: var(--red-tint-border); color: var(--red-dark); }

/* Outline (bookmarks) panel */
.viewer-outline { padding: 4px 0 20px; }
.viewer-outline-empty {
  padding: 8px 4px;
  font-size: 12.5px;
  color: var(--text-light);
  line-height: 1.5;
}
.viewer-outline-list {
  list-style: none;
  margin: 0;
  padding: 0;
}
.viewer-outline-list .viewer-outline-list {
  padding-left: 14px;
}
.viewer-outline-list.collapsed { display: none; }
.viewer-outline-row {
  display: flex;
  align-items: flex-start;
  gap: 2px;
}
.viewer-outline-toggle {
  flex-shrink: 0;
  width: 16px;
  height: 22px;
  padding: 0;
  border: none;
  background: transparent;
  color: var(--text-light);
  font-size: 10px;
  line-height: 22px;
  cursor: pointer;
  transition: transform 0.15s var(--ease);
}
.viewer-outline-toggle.collapsed { transform: rotate(-90deg); }
.viewer-outline-toggle.empty { cursor: default; visibility: hidden; }
.viewer-outline-item {
  flex: 1;
  min-width: 0;
  padding: 3px 6px;
  border: none;
  border-radius: 5px;
  background: transparent;
  color: var(--text);
  font-family: var(--font-ui);
  font-size: 12.5px;
  line-height: 1.35;
  text-align: left;
  cursor: pointer;
  transition: background 0.12s var(--ease), color 0.12s var(--ease);
}
.viewer-outline-item:hover { background: var(--surface-hover); color: var(--red-dark); }

.viewer-layers { padding: 4px 0 20px; }
.viewer-layers-empty {
  padding: 8px 4px;
  font-size: 12.5px;
  color: var(--text-light);
  line-height: 1.5;
}
.viewer-layers-list {
  list-style: none;
  margin: 0;
  padding: 0;
}
.viewer-layers-list .viewer-layers-list {
  padding-left: 14px;
}
.viewer-layers-heading {
  padding: 5px 6px 2px;
  font-size: 11.5px;
  font-weight: 600;
  color: var(--text-light);
  text-transform: uppercase;
  letter-spacing: 0.02em;
}
.viewer-layers-item {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 3px 6px;
  border-radius: 5px;
  font-family: var(--font-ui);
  font-size: 12.5px;
  line-height: 1.35;
  color: var(--text);
  cursor: pointer;
  transition: background 0.12s var(--ease);
}
.viewer-layers-item:hover { background: var(--surface-hover); }
.viewer-layers-item input[type="checkbox"] { flex-shrink: 0; cursor: pointer; }
.viewer-layers-item span { flex: 1; min-width: 0; overflow-wrap: break-word; }

.viewer-tools {
  background: var(--surface);
  border-left: 1px solid var(--border);
  overflow-y: auto;
  /* No top padding — .viewer-panel-header sits flush at the top so its
     border-bottom lines up with the main toolbar's (both 48px + border). */
  padding: 0 12px 14px;
  /* A visible scrollbar reserves width from the content box (via the implied
     overflow-x: auto that comes with setting only overflow-y), which makes
     the header/border-bottom fall short of the panel's true right edge.
     Hide it — wheel/trackpad scroll still works. */
  scrollbar-width: none;
}
.viewer-tools::-webkit-scrollbar { display: none; }
.viewer-tools-title {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 15px;
  font-weight: 700;
  color: var(--text);
  flex: 1;
  min-width: 0;
}
.viewer-tools-group {
  margin-top: 4px;
}
.viewer-tools-group summary {
  cursor: pointer;
  list-style: none;
  padding: 10px 8px;
  border-radius: 6px;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-light);
  display: flex;
  justify-content: space-between;
  align-items: center;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}
.viewer-tools-group summary::-webkit-details-marker { display: none; }
.viewer-tools-group summary:hover { background: var(--surface-hover); color: var(--text); }
.viewer-tools-group summary .chev { transition: transform 0.15s var(--ease); font-size: 11px; }
.viewer-tools-group[open] summary .chev { transform: rotate(180deg); }
.viewer-tool-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border-radius: 6px;
  cursor: pointer;
  font-size: 13.5px;
  color: var(--text);
  transition: background 0.1s var(--ease);
  border: none;
  background: transparent;
  width: 100%;
  text-align: left;
  font-family: var(--font-ui);
}
.viewer-tool-item:hover { background: var(--surface-hover); }
.viewer-tool-item:disabled { opacity: 0.45; cursor: not-allowed; }
.viewer-tool-item:disabled:hover { background: transparent; }
.viewer-tool-item .vti-icon {
  width: 28px;
  height: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--surface-2);
  border-radius: 6px;
  flex-shrink: 0;
}
.viewer-tool-item .vti-icon-svg { width: 16px; height: 16px; }
.viewer-tool-item .vti-label { flex: 1; }
.viewer-tool-item .vti-badge {
  font-size: 10.5px;
  color: var(--text-faint);
  background: var(--surface-2);
  padding: 2px 6px;
  border-radius: 999px;
}

/* Inline tool form inside the viewer's right panel */
.viewer-tools-form-mount { padding: 4px 2px 16px; }
.vt-form { display: flex; flex-direction: column; gap: 12px; }
.vt-form-header {
  display: flex;
  align-items: center;
  gap: 6px;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 4px;
}
.vt-back {
  display: inline-flex;
  align-items: center;
  height: 26px;
  padding: 0 8px;
  border: 1px solid var(--border);
  background: transparent;
  color: var(--text-light);
  border-radius: 5px;
  font-size: 12px;
  cursor: pointer;
  font-family: var(--font-ui);
}
.vt-back:hover { background: var(--surface-hover); color: var(--text); }
.vt-form-title {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 14px;
  font-weight: 700;
  color: var(--text);
  margin-left: 4px;
}
.vt-form-body { display: flex; flex-direction: column; gap: 10px; }
.vt-form-field { display: flex; flex-direction: column; gap: 4px; }
.vt-form-field.hidden { display: none; }
.vt-form-field > label {
  font-size: 12px;
  color: var(--text-light);
  font-weight: 500;
}
.vt-form-field input[type="text"],
.vt-form-field input[type="password"],
.vt-form-field input[type="number"],
.vt-form-field select {
  width: 100%;
  height: 32px;
  padding: 0 10px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--surface-2);
  color: var(--text);
  font-family: var(--font-ui);
  font-size: 13px;
  outline: none;
  transition: border-color 0.12s var(--ease), box-shadow 0.12s var(--ease);
}
.vt-form-field input:focus, .vt-form-field select:focus {
  border-color: var(--red);
  box-shadow: var(--shadow-focus);
}
.vt-form-field input[type="color"] {
  width: 44px;
  height: 30px;
  padding: 2px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: transparent;
}
.vt-form-field input[type="file"] { font-size: 12px; color: var(--text-light); }
.vt-form-check {
  flex-direction: row;
  align-items: center;
  gap: 8px;
}
.vt-form-check > label {
  font-size: 12.5px;
  color: var(--text);
  font-weight: 400;
  cursor: pointer;
}
.vt-form-check input[type="checkbox"] {
  width: 15px;
  height: 15px;
  accent-color: var(--red);
  cursor: pointer;
}

.vt-form-actions { margin-top: 4px; }
.vt-run {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 36px;
  padding: 0 16px;
  background: var(--red);
  color: white;
  border: none;
  border-radius: 8px;
  font-family: var(--font-ui);
  font-size: 13.5px;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.12s var(--ease), transform 0.05s var(--ease);
}
.vt-run:hover:not(:disabled) { background: var(--red-dark); }
.vt-run:active:not(:disabled) { transform: translateY(1px); }
.vt-run:disabled { opacity: 0.6; cursor: not-allowed; }

.vt-status {
  font-size: 12.5px;
  min-height: 16px;
  color: var(--text-light);
}
.vt-status.running { color: var(--info); }
.vt-status.success { color: var(--success); }
.vt-status.error { color: var(--red); }

.vt-progress {
  height: 6px;
  background: var(--surface-2);
  border-radius: 3px;
  overflow: hidden;
  display: none;
}
.vt-progress.active { display: block; }
.vt-progress > div {
  height: 100%;
  width: 0;
  background: var(--red);
  transition: width 0.2s var(--ease);
}

.vt-result {
  display: none;
  flex-direction: column;
  gap: 8px;
  padding: 12px;
  border: 1px solid var(--success-border);
  background: var(--success-tint);
  border-radius: 8px;
  font-size: 12.5px;
  color: var(--text);
}
.vt-result.active { display: flex; }
.vt-download {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 32px;
  padding: 0 12px;
  background: var(--success);
  color: white;
  text-decoration: none;
  border-radius: 6px;
  font-size: 13px;
  font-weight: 600;
}
.vt-download:hover { filter: brightness(1.05); }

/* "Chain the result back in" actions, shown only for PDF output */
.vt-result-actions {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.vt-open {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  height: 32px;
  padding: 0 12px;
  border: 1px solid var(--red);
  border-radius: 6px;
  background: var(--red);
  color: white;
  font-family: var(--font-ui);
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.12s var(--ease), filter 0.12s var(--ease), transform 0.05s var(--ease);
}
.vt-open:hover:not(:disabled) { background: var(--red-dark); border-color: var(--red-dark); }
.vt-open:active:not(:disabled) { transform: translateY(1px); }
.vt-open:disabled { opacity: 0.6; cursor: not-allowed; }
.vt-open.secondary {
  background: var(--surface);
  color: var(--text);
  border-color: var(--border);
  font-weight: 500;
}
.vt-open.secondary:hover:not(:disabled) { background: var(--surface-hover); border-color: var(--text-light); }
.vt-result-note {
  font-size: 11.5px;
  line-height: 1.45;
  color: var(--text-light);
}

/* Collapsed side panels: left panel keeps only its icon rail; right panel
   still shows tool icons stacked vertically (see right-side rules below). */
.viewer-layout.left-collapsed { grid-template-columns: 48px 1fr 300px; }
.viewer-layout.right-collapsed { grid-template-columns: 200px 1fr 48px; }
.viewer-layout.left-collapsed.right-collapsed { grid-template-columns: 48px 1fr 48px; }

/* Left panel collapsed → hide the content column, only rail remains */
.viewer-thumbs.collapsed .viewer-thumbs-body { grid-template-columns: 48px; }
.viewer-thumbs.collapsed .viewer-side-content { display: none; }
.viewer-thumbs.collapsed .viewer-panel-header {
  padding: 0 0 8px;
  justify-content: center;
}
.viewer-thumbs.collapsed .viewer-thumbs-title { display: none; }

/* Right panel (tools) collapsed → icon-only rail */
.viewer-tools.collapsed {
  padding: 0 6px 10px;
}
.viewer-tools.collapsed .viewer-panel-header {
  padding: 0 0 8px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 10px;
  justify-content: center;
}
.viewer-tools.collapsed .viewer-tools-title { display: none; }
.viewer-tools.collapsed > [data-tools-form] { display: none; }
.viewer-tools.collapsed [data-tools-list] {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  width: 100%;
}
.viewer-tools.collapsed .viewer-tools-group {
  width: 100%;
  border-top: 1px solid var(--border);
  margin-top: 6px;
  padding-top: 8px;
}
.viewer-tools.collapsed .viewer-tools-group:first-child {
  border-top: none;
  margin-top: 0;
  padding-top: 0;
}
.viewer-tools.collapsed .viewer-tools-group summary { display: none; }
.viewer-tools.collapsed .viewer-tools-group > *:not(summary) { display: block; }
.viewer-tools.collapsed .viewer-tool-item {
  padding: 6px 0;
  justify-content: center;
  gap: 0;
}
.viewer-tools.collapsed .viewer-tool-item .vti-icon {
  width: 36px;
  height: 36px;
  border-radius: 8px;
}
.viewer-tools.collapsed .viewer-tool-item .vti-icon-svg { width: 19px; height: 19px; }
.viewer-tools.collapsed .viewer-tool-item .vti-label,
.viewer-tools.collapsed .viewer-tool-item .vti-badge { display: none; }

@media (max-width: 1024px) {
  .viewer-layout { grid-template-columns: 200px 1fr 260px; }
  .viewer-layout.left-collapsed { grid-template-columns: 48px 1fr 260px; }
  .viewer-layout.right-collapsed { grid-template-columns: 200px 1fr 48px; }
  .viewer-layout.left-collapsed.right-collapsed { grid-template-columns: 48px 1fr 48px; }
  .viewer-thumb canvas { max-width: 120px; }
}
/* Narrow layout: 200 + 300px of side chrome doesn't fit, and stacking the
   panels above/below the page eats the little height there is. So both panels
   become overlay drawers opened from the toolbar (.viewer-narrow-only buttons)
   and the page gets the full width. Same 860px breakpoint as the home sidebar.
   The collapsed-column rules must be neutralised here — they are written with
   two classes, so these overrides need the same weight to win. */
@media (max-width: 860px) {
  .viewer-layout,
  .viewer-layout.left-collapsed,
  .viewer-layout.right-collapsed,
  .viewer-layout.left-collapsed.right-collapsed {
    grid-template-columns: 1fr;
    position: relative;
  }
  .viewer-narrow-only { display: flex !important; }

  .viewer-thumbs,
  .viewer-tools {
    position: absolute;
    top: 0;
    bottom: 0;
    width: min(300px, 84vw);
    z-index: 20;
    box-shadow: var(--shadow-lg);
    transition: transform 0.2s var(--ease);
  }
  .viewer-thumbs { left: 0; transform: translateX(-101%); }
  .viewer-tools { right: 0; transform: translateX(101%); }
  .viewer-layout.left-open .viewer-thumbs,
  .viewer-layout.right-open .viewer-tools { transform: none; }
  .viewer-layout.left-open .viewer-backdrop,
  .viewer-layout.right-open .viewer-backdrop { display: block; }

  /* In drawer mode a panel is either open at full width or off-screen — the
     icon-only collapsed state has no meaning and would show a 48px sliver. */
  .viewer-thumbs.collapsed,
  .viewer-tools.collapsed { width: min(300px, 84vw); padding: 0 12px 14px; }
  .viewer-thumbs.collapsed .viewer-thumbs-body { grid-template-columns: 48px 1fr; }
  .viewer-thumbs.collapsed .viewer-side-content { display: block; }
  .viewer-thumbs.collapsed .viewer-thumbs-title,
  .viewer-tools.collapsed .viewer-tools-title { display: block; }
  .viewer-tools.collapsed .viewer-tool-item .vti-label { display: inline; }

  .viewer-canvas-area { padding: 12px; }
  .viewer-toolbar { padding: 8px; gap: 4px; }
}
/* ============================================================
   Vỏ điện thoại — điều hướng kiểu app (Zalo/Facebook)
   ============================================================

   Mốc chuẩn khi làm: iPhone XS Max, 414 × 896pt, có tai thỏ và vạch Home.

   Đặt Ở CUỐI FILE là có chủ ý: nhiều rule ở đây phải thắng các rule desktop có
   cùng độ đặc hiệu (ví dụ `.sidebar` trong khối @media 860px). Xếp cuối thì
   thắng theo THỨ TỰ NGUỒN, không phải đi đua độ đặc hiệu bằng cách chồng thêm
   class — cùng bài học đã ghi trong ARCHITECTURE ở mục ngăn kéo panel trình đọc.

   Ba khối này ẩn hẳn trên máy tính nên không ảnh hưởng bố cục cũ. */
.mobile-nav,
.bottom-sheet,
.sheet-backdrop {
  display: none;
}

/* Điều kiện thứ hai bắt luôn điện thoại nằm ngang (896×414): không có nó thì
   quay ngang máy là rơi về bố cục desktop, vỏ app biến mất giữa lúc dùng. */
@media (max-width: 640px), (orientation: landscape) and (max-height: 500px) and (pointer: coarse) {
  /* ---------- 1. Nền tảng ---------- */

  /* iOS Safari TỰ PHÓNG TO cả trang khi focus vào ô nhập có cỡ chữ < 16px, rồi
     để trang bị phóng luôn ở đó. Đo được 112/112 ô nhập của app đều dưới 16px,
     nên đây không phải chi tiết nhỏ — nó làm mọi tool có ô nhập bị lệch khung
     ngay khi người dùng chạm vào. 16px là ngưỡng cứng của Safari, không phải
     lựa chọn thẩm mỹ. */
  /* `!important` ở đây là cần thật, không phải cho nhanh: cỡ chữ của ô nhập
     được đặt bởi hàng chục rule có CLASS (`.settings-input`, `.tool-search
     input`, `.cmdk-input`…), mà bộ chọn theo TÊN THẺ luôn thua class bất kể
     xếp sau. Đo được: không có `!important` thì `#outputNameInput` vẫn giữ
     13,5px và Safari vẫn phóng trang. Đây là ngưỡng cứng của nền tảng, không
     phải lựa chọn thẩm mỹ — cùng loại lý do như `.viewer-narrow-only` ở trên. */
  input,
  select,
  textarea {
    font-size: 16px !important;
  }

  /* Đừng để iOS tự phóng chữ khi quay ngang máy. */
  html {
    -webkit-text-size-adjust: 100%;
  }

  /* ---------- 2. Thanh tab trên cùng nhường chỗ cho thanh dưới ---------- */
  .tab-bar {
    display: none;
  }

  /* Chừa chỗ cho thanh dưới. Phải đặt trên .tab-view chứ KHÔNG phải .tab-body:
     .tab-view là `position:absolute; inset:0`, mà khối chứa của phần tử
     absolute là HỘP PADDING của cha — nên padding của .tab-body không đẩy nó,
     thanh dưới sẽ che mất phần cuối nội dung. */
  .tab-view {
    padding-bottom: calc(56px + env(safe-area-inset-bottom));
  }

  /* ---------- 3. Đầu trang kiểu app: tên app + dải danh mục cuộn ngang ---------- */
  .app-shell {
    flex-direction: column;
  }
  .sidebar {
    position: sticky;
    top: 0;
    z-index: 30;
    flex-direction: column;
    align-items: stretch;
    gap: 10px;
    width: 100%;
    height: auto;
    padding: calc(10px + env(safe-area-inset-top)) 0 10px;
    overflow: visible;
    background: var(--surface-2);
    border-bottom: 1px solid var(--border);
  }
  .sidebar-brand {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 0 16px;
  }
  .sidebar-title {
    font-size: 17px;
  }
  /* Hai nút này đã có mặt trong thanh dưới — để lại là hai đường dẫn tới cùng
     một chỗ, đúng kiểu làm người dùng phải đoán chúng có khác nhau không. */
  .sidebar-nav,
  .sidebar-section-label,
  .sidebar-footer {
    display: none;
  }
  .sidebar-categories {
    flex-direction: row;
    gap: 8px;
    overflow-x: auto;
    padding: 0 16px 2px;
    /* Dừng đúng vào từng chip khi vuốt, như dải tab của app điện thoại. */
    scroll-snap-type: x proximity;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }
  .sidebar-categories::-webkit-scrollbar {
    display: none;
  }
  .sidebar-cat {
    flex-shrink: 0;
    scroll-snap-align: start;
    min-height: 40px;
    padding: 0 16px;
    border-radius: 999px;
    display: inline-flex;
    align-items: center;
    gap: 6px;
  }

  /* Ô tìm ở đầu trang bỏ đi: đã có nút "Tìm" ở thanh dưới, mở đúng bảng tìm
     Ctrl+K (tìm được từ mọi tab, không chỉ trang chủ). Nút đổi giao diện
     sáng/tối nằm trong "Lựa chọn". */
  header.topbar {
    display: none;
  }

  main {
    padding: 14px 12px 28px;
  }
  footer {
    padding: 18px 20px 8px;
    font-size: 11.5px;
  }

  /* ---------- 4. Lưới công cụ: thẻ đủ to cho ngón tay ---------- */
  .tool-grid {
    grid-template-columns: repeat(2, 1fr);
    gap: 10px;
  }
  .tool-card {
    min-height: 116px;
    padding: 16px 12px;
    /* Phản hồi khi chạm: điện thoại không có :hover nên nếu không có :active
       thì bấm vào thẻ cảm giác như app bị treo. */
    transition: transform 0.09s ease, background-color 0.09s ease;
    -webkit-tap-highlight-color: transparent;
  }
  .tool-card:active {
    transform: scale(0.97);
    background: var(--surface-2);
  }
  .tool-category-title {
    min-height: 44px;
    display: flex;
    align-items: center;
  }

  /* ---------- 5. Panel công cụ = một "trang" toàn màn hình ---------- */
  .tool-panel {
    padding: 0 12px 16px;
  }
  /* Đầu panel dính trên, nút quay lại to đúng cỡ ngón tay. */
  .tool-panel .panel-header {
    position: sticky;
    top: 0;
    z-index: 20;
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 0 -12px 12px;
    padding: 8px 12px;
    background: var(--surface);
    border-bottom: 1px solid var(--border);
  }
  .tool-panel .panel-header h2 {
    font-size: 17px;
    margin: 0;
    /* Tên tool dài thì cắt bằng dấu … chứ không đẩy nút quay lại ra khỏi màn
       hình — "Kiểm tra khả năng tiếp cận" là ca thật. */
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .tool-panel .back-btn {
    flex-shrink: 0;
    min-width: 44px;
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0 10px;
  }

  .dropzone {
    padding: 26px 16px;
    min-height: 128px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
  }

  /* Ô tuỳ chọn xếp DỌC: hai ô cạnh nhau ở 414px thì mỗi ô còn ~180px, select
     nào cũng bị cắt chữ. */
  .options {
    padding: 12px;
    gap: 12px;
  }
  .option-field {
    flex-direction: column;
    align-items: stretch;
    gap: 6px;
    min-width: 0;
  }
  .option-field input,
  .option-field select,
  .option-field textarea {
    width: 100%;
    min-width: 0;
    min-height: 44px;
  }
  /* Trừ ô tích: nhãn phải nằm cạnh, không nằm dưới. */
  .option-field.checkbox {
    flex-direction: row;
    align-items: center;
    min-height: 44px;
  }
  .option-field.checkbox input[type="checkbox"] {
    width: 22px;
    height: 22px;
    min-height: 22px;
    flex-shrink: 0;
  }

  /* ĐÃ THỬ VÀ BỎ: ghim khối nút xuống đáy màn hình (`position: sticky;
     bottom: 0`) cho ra cảm giác app nhất. Bỏ vì đo được **4 trong 35 panel có
     NHIỀU khối `.actions`** — `watermark` và `scan` mỗi cái 3 khối, `redact` và
     `outline` mỗi cái 2 — do chúng là vài tool con xếp chồng trong một panel.
     Ghim thì 2–3 thanh tranh nhau cùng một chỗ ở đáy, và người dùng không biết
     nút đang thấy thuộc phần nào. Nên khối nút để chảy theo nội dung, chỉ làm
     nó rộng hết bề ngang và cao 48px cho dễ bấm; nền + đường kẻ trên giữ lại
     vì nó vạch ranh giới giữa các phần, thứ càng cần khi có 3 phần. */
  .tool-panel .actions {
    flex-wrap: wrap;
    gap: 8px;
    margin: 12px -12px 0;
    padding: 10px 12px;
    background: var(--surface-2);
    border-top: 1px solid var(--border);
  }
  .tool-panel .actions button {
    min-height: 48px;
    flex: 1 1 auto;
  }
  .tool-panel .actions .status {
    flex-basis: 100%;
  }

  .hint {
    font-size: 13px;
    line-height: 1.6;
  }

  /* ---------- 6. Thanh điều hướng dưới ---------- */
  .mobile-nav {
    display: flex;
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 120;
    align-items: stretch;
    /* Vạch Home của iPhone nằm trong dải này — không cộng thêm là ngón tay
       chạm vào vạch Home thay vì chạm nút. */
    padding-bottom: env(safe-area-inset-bottom);
    background: var(--surface);
    border-top: 1px solid var(--border);
    /* Chữ/hình của trang cuộn qua dưới thanh; làm mờ nhẹ cho ra chất app. */
    backdrop-filter: saturate(150%) blur(12px);
  }
  .mnav-item {
    position: relative;
    flex: 1;
    min-height: 56px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 3px;
    border: 0;
    background: none;
    color: var(--text-faint);
    font: inherit;
    font-size: 11px;
    font-weight: 600;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
  }
  .mnav-item .mnav-icon {
    width: 23px;
    height: 23px;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.7;
    stroke-linecap: round;
    stroke-linejoin: round;
  }
  .mnav-item.active {
    color: var(--red);
  }
  .mnav-item:active {
    background: var(--surface-2);
  }
  .mnav-badge {
    position: absolute;
    top: 6px;
    left: 50%;
    margin-left: 4px;
    min-width: 17px;
    height: 17px;
    padding: 0 4px;
    border-radius: 999px;
    background: var(--red);
    color: #fff;
    font-size: 10.5px;
    font-weight: 700;
    line-height: 17px;
    text-align: center;
  }

  /* Trong một panel công cụ, thanh dưới ẩn đi: đó là "trang việc", có nút quay
     lại riêng ở đầu panel. Zalo ẩn thanh dưới khi vào một cuộc trò chuyện vì
     cùng lý do — đang làm một việc thì đừng mời đi chỗ khác. */
  body.panel-open .mobile-nav {
    display: none;
  }
  body.panel-open .tab-view {
    padding-bottom: env(safe-area-inset-bottom);
  }
  /* Đầu trang của app (tên app + dải danh mục) cũng ẩn: panel đã có đầu riêng
     với nút quay lại và tên tool, để cả hai là hai thanh xếp lên nhau ăn 160px
     chiều cao trên máy chỉ có 896px, và người dùng thấy hai chỗ để bấm cho
     cùng một việc "đi ra khỏi đây". */
  body.panel-open .sidebar {
    display: none;
  }

  /* Đã thử và BỎ: `min-height: 100%` + flex + `margin-top: auto` để ghim khối
     nút xuống đáy kể cả khi panel ngắn. Không ăn — `100%` tính theo `main`, mà
     `main` cao tự động nên không có gì để lấy 100% của. Muốn ăn thì phải dùng
     `100dvh` trừ đi lề của mấy lớp cha, tức một hằng số phải sửa lại mỗi lần
     đổi padding — đắt và dễ mục. Panel ngắn thì khối nút nằm ngay sau nội dung,
     đúng cách biểu mẫu trên điện thoại vẫn làm; panel dài thì `sticky` bên trên
     đã ghim nó vào đáy khung nhìn, và đó mới là ca cần giải. */

  /* ---------- 7. Ngăn "Tệp đang mở" trượt lên từ đáy ---------- */

  /* ⚠️ PHẢI có hai rule này, và phải đặt TRƯỚC hay SAU đều được miễn là đặc
     hiệu hơn. Thuộc tính `hidden` của HTML chỉ là `[hidden] { display: none }`
     trong bảng kiểu mặc định của trình duyệt — **rule của mình đặt `display`
     sẽ đè mất nó**. Bỏ hai rule này thì ngăn và nền mờ HIỆN NGAY LÚC MỞ TRANG
     dù thuộc tính `hidden` vẫn còn đó: nền mờ phủ kín 414×896, và MỌI cú chạm
     rơi vào nó thay vì vào thẻ công cụ — app không dùng được trên điện thoại.
     Đây là lỗi đã lọt ra bản phát hành: bài test lúc đó chỉ kiểm THUỘC TÍNH
     `hidden` chứ không kiểm `display` thật, nên không thấy gì. */
  .bottom-sheet[hidden],
  .sheet-backdrop[hidden] {
    display: none;
  }

  .sheet-backdrop {
    display: block;
    /* iOS Safari không phát sự kiện `click` trên <div> thường nếu nó không có
       dấu hiệu bấm được. Thiếu `cursor: pointer` là chạm ra ngoài ngăn không
       đóng được ngăn — người dùng bị kẹt. */
    cursor: pointer;
    position: fixed;
    inset: 0;
    z-index: 130;
    background: rgba(0, 0, 0, 0.4);
  }
  .bottom-sheet {
    display: flex;
    flex-direction: column;
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 140;
    max-height: 72vh;
    padding: 6px 16px calc(16px + env(safe-area-inset-bottom));
    background: var(--surface);
    border-radius: 16px 16px 0 0;
    box-shadow: 0 -8px 30px rgba(0, 0, 0, 0.22);
  }
  .sheet-grip {
    width: 38px;
    height: 4px;
    margin: 6px auto 10px;
    border-radius: 999px;
    background: var(--border);
  }
  .sheet-head {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 8px;
  }
  .sheet-title {
    flex: 1;
    font-size: 15px;
    font-weight: 700;
  }
  .sheet-close {
    flex-shrink: 0;
    width: 44px;
    height: 44px;
    border: 0;
    border-radius: 999px;
    background: var(--surface-2);
    color: var(--text);
    font-size: 22px;
    line-height: 1;
    cursor: pointer;
  }
  .sheet-close:active {
    background: var(--border);
  }
  .sheet-list {
    overflow-y: auto;
    margin: 0 -4px;
  }
  .sheet-row {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    min-height: 52px;
    padding: 6px 4px;
    border: 0;
    border-radius: 10px;
    background: none;
    color: var(--text);
    font: inherit;
    text-align: left;
    cursor: pointer;
  }
  .sheet-row:active {
    background: var(--surface-2);
  }
  .sheet-row.active {
    color: var(--red);
    font-weight: 700;
  }
  .sheet-row-name {
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .sheet-row-close {
    flex-shrink: 0;
    width: 40px;
    height: 40px;
    border: 0;
    border-radius: 999px;
    background: none;
    color: var(--text-faint);
    font-size: 19px;
    line-height: 1;
    cursor: pointer;
  }
  .sheet-row-close:active {
    background: var(--surface-2);
  }
  .sheet-empty {
    padding: 14px 4px 18px;
    color: var(--text-faint);
    font-size: 13.5px;
  }
  .sheet-cta {
    margin-top: 10px;
    min-height: 50px;
    width: 100%;
  }

  /* ---------- 8. Điểm chạm còn lại ---------- */
  .theme-toggle,
  .tab-add {
    min-width: 44px;
    min-height: 44px;
  }
  .result-box .btn-secondary,
  .result-box .primary,
  .result-box a.primary {
    min-height: 46px;
  }
}
/* Điện thoại NẰM NGANG (iPhone XS Max quay ngang = 896 × 414).
   Chiều cao còn 414px nên chrome phải gọn lại: đo được ở khối dọc bên trên,
   đầu trang 108px + thanh dưới 57px chỉ để lại 249px cho nội dung. Và bề ngang
   896px thì 2 cột là bỏ trống nửa màn hình. */
@media (orientation: landscape) and (max-height: 500px) and (pointer: coarse) {
  /* Tên app bỏ đi: đang nằm ngang thì mỗi pixel chiều cao đáng giá hơn một
     dòng nhãn mà người dùng đã biết mình đang ở app nào. */
  .sidebar-brand {
    display: none;
  }
  .sidebar {
    padding: calc(6px + env(safe-area-inset-top)) 0 6px;
  }
  .tool-grid {
    grid-template-columns: repeat(4, 1fr);
  }
  .tool-card {
    min-height: 96px;
  }
  /* Icon và nhãn nằm CẠNH nhau để thanh dưới thấp hơn. */
  .mnav-item {
    flex-direction: row;
    gap: 7px;
    min-height: 46px;
    font-size: 12px;
  }
  .mnav-badge {
    top: 3px;
  }
  .bottom-sheet {
    max-height: 88vh;
  }
  main {
    padding: 10px 12px 20px;
  }
}
