/* =====================================================================
   app.css — Lớp style riêng của app quản lý mật khẩu
   Đặt SAU styles.css (Metronic). Chỉ dùng token màu của Metronic
   (var(--background), var(--foreground), var(--primary)...) nên tự động
   theo theme sáng/tối. Không đụng tới file vendor.
   ===================================================================== */

/* ---------------------------------------------------------------------
   1. Khung nội dung tối thiểu (view ngắn vẫn phủ hết chiều cao)
   --------------------------------------------------------------------- */
.kt-content {
  min-height: calc(100dvh - var(--header-height));
}

/* Nền + chữ mặc định bám token (phòng khi utility trên body bị override) */
body.demo1 {
  background-color: var(--background);
  color: var(--foreground);
}

/* Header hơi mờ nền cho cảm giác "dính" */
.kt-header {
  background-color: color-mix(in oklab, var(--background) 88%, transparent);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}

/* ---------------------------------------------------------------------
   2. Trạng thái CHƯA MỞ KHÓA — ẩn sidebar + header, bỏ padding khung
   --------------------------------------------------------------------- */
body.pm-locked .kt-sidebar,
body.pm-locked .kt-header {
  display: none !important;
}
/* Khi khóa, router đã gỡ class kt-sidebar-fixed/kt-header-fixed nên template
   không còn chừa khoảng đệm. Chỉ cần bỏ padding nội dung để màn phủ trọn. */
body.pm-locked .kt-wrapper { padding: 0; }
body.pm-locked .kt-content {
  min-height: 100dvh;
  padding: 0;
}

/* ---------------------------------------------------------------------
   3. Drawer mobile — dùng đúng "hợp đồng" .kt-drawer của styles.css.
      layout.js gắn/tháo .kt-drawer .kt-drawer-start ở <1024px.
      Xếp lớp: sidebar(60) > backdrop(55) > header(20).
   --------------------------------------------------------------------- */
.kt-sidebar.kt-drawer {
  z-index: 60;
}
.pm-backdrop {
  z-index: 55;
}
/* Khóa cuộn nền khi drawer đang mở */
body.pm-drawer-open {
  overflow: hidden;
}

/* ---------------------------------------------------------------------
   4. Điều hướng sidebar (scope dưới .kt-sidebar để chắc chắn thắng
      độ ưu tiên so với mặc định Metronic)
   --------------------------------------------------------------------- */
.kt-sidebar .kt-menu-link {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.625rem 0.75rem;
  border-radius: var(--radius);
  color: var(--muted-foreground);
  font-size: 0.9375rem;
  font-weight: 500;
  line-height: 1.25rem;
  transition: background-color 0.15s ease, color 0.15s ease;
}
.kt-sidebar .kt-menu-link:hover {
  background-color: color-mix(in oklab, var(--foreground) 6%, transparent);
  color: var(--foreground);
}
.kt-sidebar .kt-menu-link.pm-active {
  background-color: color-mix(in oklab, var(--primary) 12%, transparent);
  color: var(--primary);
}
.kt-sidebar .kt-menu-icon {
  display: inline-flex;
  width: 1.5rem;
  justify-content: center;
  flex-shrink: 0;
}
.kt-sidebar .kt-menu-icon i {
  font-size: 1.25rem;
  line-height: 1;
}
.kt-sidebar .kt-menu-title {
  flex: 1 1 auto;
}
.kt-sidebar .kt-menu-heading {
  padding: 0.75rem 0.75rem 0.25rem;
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted-foreground);
}

/* ---------------------------------------------------------------------
   5. Nút icon trên header (ghost) — tự định nghĩa để tránh xung đột
   --------------------------------------------------------------------- */
.pm-hbtn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.5rem;
  height: 2.5rem;
  border: 0;
  border-radius: var(--radius);
  background: transparent;
  color: var(--muted-foreground);
  cursor: pointer;
  transition: background-color 0.15s ease, color 0.15s ease;
}
.pm-hbtn:hover {
  background-color: color-mix(in oklab, var(--foreground) 8%, transparent);
  color: var(--foreground);
}
.pm-hbtn:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}
.pm-hbtn i {
  font-size: 1.25rem;
  line-height: 1;
}
/* Chỉ hiện ở mobile: khi >=64rem thì ẩn (thắng .pm-hbtn vì !important + unlayered) */
@media (min-width: 64rem) {
  .pm-mobile-only { display: none !important; }
}
/* Nút chrome do JS bật/tắt (đặc hiệu cao hơn .pm-hbtn nên override được) */
.pm-hbtn.pm-hide { display: none; }

/* ---------------------------------------------------------------------
   6. Form control theo theme (dùng cho các view placeholder)
   --------------------------------------------------------------------- */
.pm-field {
  display: flex;
  flex-direction: column;
  gap: 0.375rem;
}
.pm-label {
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--foreground);
}
.pm-hint {
  font-size: 0.8125rem;
  color: var(--muted-foreground);
}
.pm-control {
  width: 100%;
  height: 2.625rem;
  padding: 0 0.75rem;
  background-color: var(--background);
  color: var(--foreground);
  border: 1px solid var(--input);
  border-radius: var(--radius);
  font-size: 0.9375rem;
  line-height: 1.5;
  outline: none;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.pm-control::placeholder {
  color: var(--muted-foreground);
}
.pm-control:focus-visible {
  border-color: var(--primary);
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--primary) 20%, transparent);
}
select.pm-control {
  appearance: none;
  -webkit-appearance: none;
  padding-inline-end: 2rem;
  background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="%23999" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M6 9l6 6 6-6"/></svg>');
  background-repeat: no-repeat;
  background-position: right 0.7rem center;
}

/* Ô nhập có nút phụ (vd nút hiện/ẩn mật khẩu) */
.pm-affix {
  position: relative;
}
.pm-affix .pm-control {
  padding-inline-end: 3rem;
}
.pm-affix-btn {
  position: absolute;
  inset-inline-end: 0.375rem;
  top: 50%;
  transform: translateY(-50%);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  border: 0;
  border-radius: calc(var(--radius) - 2px);
  background: transparent;
  color: var(--muted-foreground);
  cursor: pointer;
}
.pm-affix-btn:hover {
  color: var(--foreground);
  background-color: color-mix(in oklab, var(--foreground) 8%, transparent);
}
.pm-affix-btn:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 1px;
}

/* Thanh trượt độ dài (generator — placeholder) */
.pm-range {
  width: 100%;
  accent-color: var(--primary);
}

/* ---------------------------------------------------------------------
   7. Bố cục trang & tiêu đề view
   --------------------------------------------------------------------- */
.pm-page {
  max-width: 72rem;
  margin-inline: auto;
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}
.pm-page-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
}
.pm-page-title {
  font-size: 1.375rem;
  font-weight: 600;
  color: var(--foreground);
  line-height: 1.2;
}
.pm-page-sub {
  margin-top: 0.25rem;
  font-size: 0.9375rem;
  color: var(--muted-foreground);
}

/* Nhãn "placeholder" nhỏ nhắc trạng thái Phiên 1 */
.pm-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  padding: 0.25rem 0.625rem;
  border-radius: 999px;
  font-size: 0.75rem;
  font-weight: 500;
  color: var(--muted-foreground);
  background-color: color-mix(in oklab, var(--foreground) 6%, transparent);
  border: 1px solid var(--border);
}

/* Trạng thái rỗng */
.pm-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 0.75rem;
  padding: 3rem 1.5rem;
  color: var(--muted-foreground);
}
.pm-empty-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 3.5rem;
  height: 3.5rem;
  border-radius: 999px;
  background-color: color-mix(in oklab, var(--primary) 10%, transparent);
  color: var(--primary);
}
.pm-empty-icon i {
  font-size: 1.75rem;
}

/* Thẻ thống kê nhỏ (health) */
.pm-stat {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  padding: 1.125rem 1.25rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background-color: var(--card, var(--background));
}
.pm-stat-value {
  font-size: 1.75rem;
  font-weight: 700;
  line-height: 1;
  color: var(--foreground);
}
.pm-stat-label {
  font-size: 0.8125rem;
  color: var(--muted-foreground);
}

/* Ô mật khẩu sinh ra (generator — placeholder) */
.pm-passbox {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.875rem 1rem;
  border: 1px dashed var(--input);
  border-radius: var(--radius);
  background-color: color-mix(in oklab, var(--foreground) 3%, transparent);
  font-family: var(--default-mono-font-family, ui-monospace, monospace);
  font-size: 1.05rem;
  letter-spacing: 0.06em;
  color: var(--foreground);
  overflow-wrap: anywhere;
}

/* ---------------------------------------------------------------------
   8. Sàn chất lượng: focus rõ ràng + tôn trọng reduced-motion
   --------------------------------------------------------------------- */
a:focus-visible,
button:focus-visible {
  outline-offset: 2px;
}
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}

/* ---------------------------------------------------------------------
   9. Huy hiệu thương hiệu — mark "The Silent Vault" (Phiên 11)
   Nguồn hình: assets/media/logo.svg (đã chứa nền gradient + cửa két).
   Phần tử để RỖNG, aria-hidden — đây là trang trí, tên app nằm ở <span>
   kế bên. Không còn <i class="ki-duotone ki-shield-tick"> ở đây.
   --------------------------------------------------------------------- */
.pm-brand-badge {
  display: inline-flex;
  flex-shrink: 0;
  width: 3.5rem;
  height: 3.5rem;
  border-radius: 1rem;
  background-image: url('../media/logo.svg');
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  box-shadow: 0 8px 20px -6px color-mix(in oklab, #4f46e5 60%, transparent);
}
/* Huy hiệu nhỏ trong sidebar / header mobile */
.pm-brand-badge.pm-brand-sm {
  width: 2.25rem;
  height: 2.25rem;
  border-radius: 0.625rem;
}

/* ---------------------------------------------------------------------
   10. Nút phân đoạn (segmented control) — dùng cho chọn giao diện
   --------------------------------------------------------------------- */
.pm-seg-group {
  display: inline-flex;
  padding: 0.25rem;
  gap: 0.25rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background-color: color-mix(in oklab, var(--foreground) 4%, transparent);
  flex-wrap: wrap;
}
.pm-seg {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.45rem 0.85rem;
  border: 0;
  border-radius: calc(var(--radius) - 2px);
  background: transparent;
  color: var(--muted-foreground);
  font-size: 0.875rem;
  font-weight: 500;
  cursor: pointer;
  transition: background-color 0.15s ease, color 0.15s ease;
}
.pm-seg:hover { color: var(--foreground); }
.pm-seg.pm-seg-active {
  background-color: var(--background);
  color: var(--foreground);
  box-shadow: 0 1px 2px rgb(0 0 0 / 0.08);
}
.pm-seg:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}
.pm-seg i { font-size: 1rem; }

/* ---------------------------------------------------------------------
   11. Toast nhỏ gọn (thông báo placeholder cho các nút chưa hoạt động)
   --------------------------------------------------------------------- */
.pm-toast-wrap {
  position: fixed;
  inset-inline: 0;
  bottom: 1.25rem;
  display: flex;
  justify-content: center;
  padding: 0 1rem;
  z-index: 80;
  pointer-events: none;
}
.pm-toast {
  max-width: 90vw;
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.6rem 0.9rem;
  border-radius: var(--radius);
  background-color: var(--foreground);
  color: var(--background);
  font-size: 0.875rem;
  box-shadow: 0 10px 25px -8px rgb(0 0 0 / 0.35);
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 0.2s ease, transform 0.2s ease;
}
.pm-toast.pm-show { opacity: 1; transform: translateY(0); }
.pm-toast i { font-size: 1rem; }

/* =====================================================================
   12. Lớp nền do app tự lo (một số utility Tailwind không được biên dịch
       trong bản build của template, nên định nghĩa tường minh ở đây).
   ===================================================================== */

/* Định vị sidebar/header cố định (base). Bản build thiếu inset-y-0/z-30… */
.kt-sidebar {
  position: fixed;
  inset-block: 0;
  inset-inline-start: 0;
  z-index: 30;
  display: flex;
  flex-direction: column;
}
.kt-header {
  position: fixed;
  inset-block-start: 0;
  inset-inline-end: 0;
  inset-inline-start: 0;
  z-index: 20;
  display: flex;
  align-items: center;
}
/* Khi thành drawer (mobile) đã set z-index:60 ở mục 3; giữ nguyên. */

/* Vùng danh sách menu cuộn được trong sidebar (thiếu overflow-y-auto) */
.pm-sidebar-scroll {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
}

/* Màn mở khóa toàn màn hình, căn giữa (thiếu min-h-dvh) */
.pm-unlock-screen {
  min-height: 100dvh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 2.5rem 1rem;
}

/* Lưới thẻ thống kê health (thiếu sm:grid-cols-3) */
.pm-stat-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.75rem;
}
@media (min-width: 640px) {
  .pm-stat-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* Bề rộng tối đa hay dùng (thiếu max-w-xs/sm) */
.pm-w-xs { width: 100%; max-width: 20rem; }
.pm-w-sm { width: 100%; max-width: 24rem; }

/* Cuộn ngang cho bảng (thiếu overflow-x-auto) */
.pm-scroll-x { overflow-x: auto; }

/* Chặn bôi đen chữ trên nhãn công tắc (thiếu select-none) */
.pm-noselect { user-select: none; -webkit-user-select: none; }

/* Bề mặt sidebar/header (không dùng được utility giá trị tùy biến bg-[...]) */
.kt-sidebar {
  background-color: var(--background);
  border-inline-end: 1px solid var(--border);
}
.kt-header {
  border-block-end: 1px solid var(--border);
}
/* Khu vực logo đầu sidebar cao bằng header */
.pm-sidebar-brand {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  height: var(--header-height);
  padding-inline: 1.25rem;
  flex-shrink: 0;
  border-block-end: 1px solid var(--border);
}
.pm-sidebar-foot {
  padding: 0.75rem 1.25rem;
  font-size: 0.75rem;
  color: var(--muted-foreground);
  border-block-start: 1px solid var(--border);
  flex-shrink: 0;
}

/* ---------------------------------------------------------------------
   Phiên 2 — Màn thiết lập master password
   --------------------------------------------------------------------- */
/* Ẩn chung (Phiên 1 mới chỉ định nghĩa cho .pm-hbtn) */
.pm-hide { display: none !important; }

/* Thanh đo độ mạnh mật khẩu */
.pm-strength {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-top: -0.5rem; /* nép sát ô mật khẩu phía trên */
}
.pm-strength-bar {
  flex: 1;
  height: 0.375rem;
  border-radius: 999px;
  background: var(--muted);
  overflow: hidden;
}
.pm-strength-bar span {
  display: block;
  height: 100%;
  width: 0;
  border-radius: 999px;
  transition: width 0.25s ease, background-color 0.25s ease;
}
.pm-strength-bar span.pm-str-0 { background: transparent; }
.pm-strength-bar span.pm-str-1 { background: #ef4444; }
.pm-strength-bar span.pm-str-2 { background: #f59e0b; }
.pm-strength-bar span.pm-str-3 { background: #22c55e; }
.pm-strength-bar span.pm-str-4 { background: #16a34a; }
.pm-strength-label {
  font-size: 0.75rem;
  min-width: 5.5rem;
  text-align: right;
  color: var(--muted-foreground);
}

/* Hộp cảnh báo "quên là mất kho" */
.pm-warn {
  display: flex;
  gap: 0.625rem;
  padding: 0.75rem 0.875rem;
  border-radius: 0.625rem;
  font-size: 0.8125rem;
  line-height: 1.5;
  color: var(--foreground);
  background: color-mix(in srgb, #f59e0b 12%, transparent);
  border: 1px solid color-mix(in srgb, #f59e0b 35%, transparent);
}
.pm-warn i {
  font-size: 1.125rem;
  color: #d97706;
  flex-shrink: 0;
  margin-top: 0.0625rem;
}

/* Checkbox xác nhận */
.pm-check {
  display: flex;
  align-items: flex-start;
  gap: 0.625rem;
  font-size: 0.8125rem;
  color: var(--foreground);
  cursor: pointer;
  user-select: none;
}
.pm-check input {
  margin-top: 0.1875rem;
  width: 1rem;
  height: 1rem;
  accent-color: var(--primary);
  flex-shrink: 0;
}

/* =====================================================================
   PHIÊN 3 — Kho mật khẩu: bảng/thẻ, modal, nút thao tác
   ===================================================================== */

/* ---------------------------------------------------------------------
   14. Modal (bổ trợ cho .kt-modal của Metronic)
   --------------------------------------------------------------------- */
.kt-modal.pm-modal {
  z-index: 100; /* trên sidebar-drawer (60); backdrop của ktui tự đặt z-1 */
}
.pm-modal-md,
.pm-modal-sm {
  width: 100%;
  margin-top: 3rem;
  margin-bottom: 3rem;
}
.pm-modal-md { max-width: 34rem; }
.pm-modal-sm { max-width: 26rem; }
@media (max-width: 40rem) {
  .pm-modal-md, .pm-modal-sm { margin-top: 1rem; margin-bottom: 1rem; }
}
/* Footer: chỗ báo lỗi bên trái, nút bên phải */
.pm-err { color: var(--destructive, #ef4444); }
.pm-req { color: var(--destructive, #ef4444); }
.pm-textarea { min-height: 4.5rem; resize: vertical; }

/* Ô nhập có NHÓM nút bên phải (ẩn/hiện + copy + sinh) */
.pm-affix-3 .pm-control { padding-inline-end: 7rem; }
.pm-affix-btns {
  position: absolute;
  inset-inline-end: 0.375rem;
  top: 50%;
  transform: translateY(-50%);
  display: inline-flex;
  gap: 0.125rem;
}
.pm-affix-btns .pm-affix-btn {
  position: static;
  transform: none;
}

/* ---------------------------------------------------------------------
   15. Nút thao tác nhỏ trong hàng / danh mục
   --------------------------------------------------------------------- */
.pm-mini-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  border: 0;
  border-radius: calc(var(--radius) - 2px);
  background: transparent;
  color: var(--muted-foreground);
  cursor: pointer;
  flex-shrink: 0;
  transition: background-color 0.15s ease, color 0.15s ease;
}
.pm-mini-btn:hover {
  background-color: color-mix(in oklab, var(--foreground) 8%, transparent);
  color: var(--foreground);
}
.pm-mini-btn:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 1px;
}
.pm-mini-btn i { font-size: 1rem; line-height: 1; }
.pm-mini-btn.pm-mini-danger:hover {
  background-color: color-mix(in oklab, var(--destructive, #ef4444) 12%, transparent);
  color: var(--destructive, #ef4444);
}
.pm-mini-btn.pm-armed {
  width: auto;
  padding: 0 0.5rem;
  background-color: color-mix(in oklab, var(--destructive, #ef4444) 14%, transparent);
  color: var(--destructive, #ef4444);
  font-size: 0.75rem;
  font-weight: 600;
  white-space: nowrap;
}
.pm-row-actions {
  display: inline-flex;
  gap: 0.125rem;
  justify-content: flex-end;
}

/* Sao yêu thích */
.pm-star {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 1.75rem;
  border: 0;
  border-radius: calc(var(--radius) - 2px);
  background: transparent;
  color: var(--muted-foreground);
  cursor: pointer;
  flex-shrink: 0;
}
.pm-star:hover { color: #f59e0b; }
.pm-star.pm-star-on { color: #f59e0b; }
.pm-star i { font-size: 1rem; line-height: 1; }

/* ---------------------------------------------------------------------
   16. Bảng kho — desktop bảng, mobile thẻ (một DOM duy nhất)
   --------------------------------------------------------------------- */
.pm-vault-table th {
  padding: 0.625rem 1rem;
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted-foreground);
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
}
.pm-vault-table td {
  padding: 0.625rem 1rem;
  border-bottom: 1px solid var(--border);
  vertical-align: middle;
}
.pm-vault-table tbody tr[data-id] { cursor: pointer; }
.pm-vault-table tbody tr[data-id]:hover {
  background-color: color-mix(in oklab, var(--foreground) 3%, transparent);
}
.pm-title-cell {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  min-width: 0;
}
.pm-entry-title {
  font-weight: 500;
  color: var(--foreground);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 22rem;
}
.pm-entry-url {
  display: inline-block;
  font-size: 0.75rem;
  color: var(--muted-foreground);
  text-decoration: none;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 22rem;
}
a.pm-entry-url:hover { color: var(--primary); text-decoration: underline; }
.pm-user {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  min-width: 0;
}
.pm-user-text {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 16rem;
}
.pm-dim { color: var(--muted-foreground); }
.pm-w-2xs { width: 100%; max-width: 11.5rem; }

/* Mobile (<64rem): mỗi hàng thành một THẺ, nhãn cột lấy từ data-th */
@media (max-width: 63.98rem) {
  .pm-vault-table thead { display: none; }
  .pm-vault-table, .pm-vault-table tbody { display: block; width: 100%; }
  .pm-vault-table tbody { padding: 0.75rem; }
  .pm-vault-table tbody tr {
    display: block;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--background);
    margin-bottom: 0.75rem;
    padding: 0.375rem 0;
  }
  .pm-vault-table tbody tr:last-child { margin-bottom: 0; }
  .pm-vault-table td {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    border: 0;
    padding: 0.375rem 0.875rem;
  }
  .pm-vault-table td[data-th]::before {
    content: attr(data-th);
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--muted-foreground);
    flex-shrink: 0;
  }
  .pm-vault-table td[data-th="Tên"] { padding-top: 0.625rem; }
  .pm-vault-table td[data-th="Tên"]::before { display: none; } /* tiêu đề tự nói lên */
  .pm-vault-table td[data-th="Tên"] .pm-title-cell { flex: 1 1 auto; }
  .pm-vault-table td[data-th="Thao tác"] {
    border-top: 1px solid var(--border);
    margin-top: 0.25rem;
    padding-top: 0.5rem;
  }
  /* Hàng "trạng thái rỗng" chiếm trọn, không viền thẻ */
  .pm-vault-table tbody tr:has(.pm-empty) {
    border: 0;
    padding: 0;
  }
  .pm-vault-table tbody tr:has(.pm-empty) td { display: block; padding: 0; }
  .pm-vault-table tbody tr:has(.pm-empty) td::before { display: none; }
  /* Nút thao tác to hơn chút cho ngón tay */
  .pm-row-actions .pm-mini-btn { width: 2.5rem; height: 2.25rem; }
}

/* Hàng trong modal Danh mục */
.pm-folder-row {
  display: flex;
  align-items: center;
  gap: 0.375rem;
}
.pm-folder-row .pm-control { flex: 1 1 auto; min-width: 0; }
.pm-folder-count { flex-shrink: 0; }

/* ---------------------------------------------------------------------
   PHIÊN 4 — Generator & Health
   --------------------------------------------------------------------- */

/* Thanh đo độ mạnh (dùng chung: generator, form entry, Phiên 5) */
.pm-meter {
  display: flex;
  flex-direction: column;
  gap: 0.375rem;
}
.pm-meter-track {
  height: 0.375rem;
  border-radius: 999px;
  background-color: color-mix(in oklab, var(--foreground) 8%, transparent);
  overflow: hidden;
}
.pm-meter-bar {
  height: 100%;
  width: 0;
  border-radius: 999px;
  transition: width 0.2s ease, background-color 0.2s ease;
}
.pm-meter-0 { background-color: var(--color-red-600, #dc2626); }
.pm-meter-1 { background-color: var(--color-orange-500, #f97316); }
.pm-meter-2 { background-color: var(--color-yellow-500, #eab308); }
.pm-meter-3 { background-color: var(--color-green-500, #22c55e); }
.pm-meter-4 { background-color: var(--color-emerald-600, #059669); }

/* Ô hiển thị mật khẩu sinh ra: phân màu số / ký tự đặc biệt */
.pm-passout { overflow-wrap: anywhere; min-height: 1.4em; }
/* .pm-affix-btn mặc định position:absolute (cho ô input) — trong passbox
   các nút nằm trong flex, phải về static kẻo chồng lên nhau. */
.pm-passbox .pm-affix-btn { position: static; transform: none; flex-shrink: 0; }
.pm-ch-d { color: var(--color-blue-500, #3b82f6); }
.pm-ch-s { color: var(--color-orange-500, #f97316); }

/* Ô số nhỏ cạnh slider độ dài */
.pm-num { width: 5rem; text-align: center; }
.pm-w-fit { width: fit-content; }

/* Lưới 4 thẻ thống kê (health) */
.pm-stat-grid-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (min-width: 48rem) {
  .pm-stat-grid-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* Dòng vấn đề trong health: cả dòng là nút bấm → mở sửa entry */
.pm-issue {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  width: 100%;
  padding: 0.625rem 0.75rem;
  border: 0;
  border-radius: calc(var(--radius) - 2px);
  background: transparent;
  text-align: left;
  cursor: pointer;
  font: inherit;
}
.pm-issue:hover {
  background-color: color-mix(in oklab, var(--foreground) 5%, transparent);
}
.pm-issue:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 1px;
}
.pm-issue-main {
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
  min-width: 0;
}
.pm-issue-title {
  font-weight: 500;
  color: var(--foreground);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.pm-issue-sub {
  font-size: 0.8125rem;
  color: var(--muted-foreground);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.pm-issue-go { color: var(--muted-foreground); font-size: 1rem; }

/* Badge trạng thái vấn đề */
.pm-badge {
  display: inline-flex;
  align-items: center;
  padding: 0.125rem 0.5rem;
  border-radius: 999px;
  font-size: 0.75rem;
  font-weight: 500;
  white-space: nowrap;
}
.pm-badge-red {
  color: var(--color-red-600, #dc2626);
  background-color: color-mix(in oklab, var(--color-red-500, #ef4444) 12%, transparent);
}
.pm-badge-orange {
  color: var(--color-orange-600, #ea580c);
  background-color: color-mix(in oklab, var(--color-orange-500, #f97316) 12%, transparent);
}
.pm-badge-yellow {
  color: var(--color-yellow-600, #ca8a04);
  background-color: color-mix(in oklab, var(--color-yellow-500, #eab308) 14%, transparent);
}
.pm-badge-gray {
  color: var(--muted-foreground);
  background-color: color-mix(in oklab, var(--foreground) 7%, transparent);
}

/* Thanh tiến độ HIBP */
.pm-progress {
  height: 0.375rem;
  border-radius: 999px;
  background-color: color-mix(in oklab, var(--foreground) 8%, transparent);
  overflow: hidden;
}
.pm-progress-bar {
  height: 100%;
  width: 0;
  border-radius: 999px;
  background-color: var(--primary);
  transition: width 0.2s ease;
}

/* ===== Phiên 5.1 — Tinh chỉnh UI Cài đặt ===== */

/* Bó chiều rộng form (pm-w-xs đã có ở trên) */
.pm-w-md { width: 100%; max-width: 30rem; }

/* Bố cục 2 cột cho trang Cài đặt trên màn rộng.
   Dùng media query RIÊNG (không dựa lg:grid-cols của Tailwind) —
   theo bài học @layer từ Phiên 1. */
.pm-settings-grid,
.pm-settings-main,
.pm-settings-side {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
  min-width: 0;
}
@media (min-width: 1024px) {
  .pm-settings-grid {
    display: grid;
    grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
    align-items: start;
  }
}

/* File picker tùy biến: input gốc ẩn nhưng vẫn trong DOM
   (giữ id cho test jsdom/Playwright), nút + tên file thay mặt. */
.pm-file {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
}
.pm-file-input {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}
.pm-file-name {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  max-width: 100%;
  padding: 0.3rem 0.65rem;
  border-radius: 0.5rem;
  border: 1px dashed var(--border);
  color: var(--muted-foreground);
  font-size: 0.8125rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.pm-file-name.pm-file-has {
  border-style: solid;
  color: var(--foreground);
  background-color: color-mix(in oklab, var(--primary) 8%, transparent);
}
.pm-file-clear {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.6rem;
  height: 1.6rem;
  border-radius: 999px;
  border: 0;
  background: transparent;
  color: var(--muted-foreground);
  cursor: pointer;
}
.pm-file-clear:hover {
  color: var(--destructive, #ef4444);
  background-color: color-mix(in oklab, var(--destructive, #ef4444) 10%, transparent);
}

/* ============ Banner cập nhật PWA (Phiên 7) ============
   Ghim đáy màn hình, KHÔNG che nội dung chính; nằm ngoài @layer của
   Metronic nên thắng cascade mà không cần !important. */
.pm-update-banner {
  position: fixed;
  left: 50%;
  bottom: 1rem;
  transform: translateX(-50%);
  z-index: 1000;
  display: flex;
  align-items: center;
  gap: 0.6rem;
  max-width: calc(100vw - 2rem);
  padding: 0.55rem 0.75rem 0.55rem 1rem;
  border-radius: 0.75rem;
  border: 1px solid var(--border, #e5e7eb);
  background-color: var(--background, #fff);
  color: var(--foreground);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);
  font-size: 0.875rem;
}
.pm-update-banner > i {
  color: var(--primary, #4f46e5);
}
.pm-update-dismiss {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.6rem;
  height: 1.6rem;
  border-radius: 999px;
  border: 0;
  background: transparent;
  color: var(--muted-foreground);
  cursor: pointer;
}
.pm-update-dismiss:hover {
  color: var(--foreground);
  background-color: color-mix(in oklab, var(--foreground) 8%, transparent);
}

/* =====================================================================
   PHIÊN 7.2 — Vùng an toàn iOS (PWA standalone, viewport-fit=cover)
   Nguyên tắc: CỘNG DỒN env(safe-area-inset-*) vào padding/offset sẵn có
   bằng calc(); trên nền không hỗ trợ, inset = 0px → layout y hệt cũ.
   Đặt cuối file: cùng specificity thì rule sau thắng, và app.css nằm
   NGOÀI @layer của Metronic nên thắng cascade của template.
   ===================================================================== */

/* --- Mép TRÊN: header dính --------------------------------------------
   Metronic dùng --header-height cho cả chiều cao header lẫn padding-top
   của .kt-wrapper, nên phải nới CẢ HAI cùng một lượng inset.
   box-sizing: border-box → padding-top nằm TRONG height: phần nội dung
   (nút menu, logo) tụt xuống dưới thanh trạng thái, còn NỀN header
   (color-mix + blur, khai báo ở mục 1) phủ kín vùng đệm — không lộ
   khoảng trong suốt sau đồng hồ hệ thống. */
.demo1 .kt-header {
  height: calc(var(--header-height) + env(safe-area-inset-top, 0px));
  padding-top: env(safe-area-inset-top, 0px);
  /* px-4 (1rem) sẵn có trong HTML — cộng thêm inset ngang cho xoay ngang */
  padding-left: calc(1rem + env(safe-area-inset-left, 0px));
  padding-right: calc(1rem + env(safe-area-inset-right, 0px));
}
.demo1.kt-header-fixed .kt-wrapper {
  padding-top: calc(var(--header-height) + env(safe-area-inset-top, 0px));
}
/* Khung nội dung tối thiểu (mục 1) trừ thêm inset cho khớp */
.kt-content {
  min-height: calc(100dvh - var(--header-height) - env(safe-area-inset-top, 0px));
}

/* --- Sidebar / drawer mobile -------------------------------------------
   Drawer phủ toàn chiều cao màn hình: khu logo cần tụt khỏi thanh trạng
   thái (đồng bộ chiều cao với header), chân sidebar né home indicator,
   mép trái né tai thỏ khi xoay ngang. */
.pm-sidebar-brand {
  height: calc(var(--header-height) + env(safe-area-inset-top, 0px));
  padding-top: env(safe-area-inset-top, 0px);
}
.kt-sidebar {
  padding-left: env(safe-area-inset-left, 0px);
}
.pm-sidebar-foot {
  padding-bottom: calc(0.75rem + env(safe-area-inset-bottom, 0px));
}

/* --- Vùng nội dung chính -----------------------------------------------
   p-4 (1rem) sẵn có — cộng inset đáy để hàng cuối không bị home
   indicator che, và inset ngang cho xoay ngang. */
.kt-content {
  padding-bottom: calc(1rem + env(safe-area-inset-bottom, 0px));
  padding-left: calc(1rem + env(safe-area-inset-left, 0px));
  padding-right: calc(1rem + env(safe-area-inset-right, 0px));
}
/* Lưu ý: body.pm-locked .kt-content (mục 2) có specificity cao hơn nên
   màn khóa vẫn padding: 0 — vùng đệm của màn khóa nằm ở .pm-unlock-screen
   bên dưới. */

/* --- Màn khóa / thiết lập (toàn màn hình, không header) ----------------- */
.pm-unlock-screen {
  padding: calc(2.5rem + env(safe-area-inset-top, 0px))
           calc(1rem   + env(safe-area-inset-right, 0px))
           calc(2.5rem + env(safe-area-inset-bottom, 0px))
           calc(1rem   + env(safe-area-inset-left, 0px));
}

/* --- Mép DƯỚI: banner "Có bản mới — Tải lại" (Phiên 7) ------------------ */
.pm-update-banner {
  bottom: calc(1rem + env(safe-area-inset-bottom, 0px));
  max-width: calc(100vw - 2rem
                  - env(safe-area-inset-left, 0px)
                  - env(safe-area-inset-right, 0px));
}

/* --- Toast gần đáy ------------------------------------------------------ */
.pm-toast-wrap {
  bottom: calc(1.25rem + env(safe-area-inset-bottom, 0px));
  padding: 0 calc(1rem + env(safe-area-inset-right, 0px))
           0 calc(1rem + env(safe-area-inset-left, 0px));
}

/* --- Modal trên mobile (margin 1rem đang sát mép khi cuộn hết cỡ) ------- */
@media (max-width: 40rem) {
  .pm-modal-md,
  .pm-modal-sm {
    margin-top: calc(1rem + env(safe-area-inset-top, 0px));
    margin-bottom: calc(1rem + env(safe-area-inset-bottom, 0px));
  }
}

/* =====================================================================
   PHIÊN 9 — Sinh trắc học
   Không nằm trong @layer (giống mọi khối app.css) → thắng specificity
   của utility Tailwind đã layer hóa. Banner mời ghi danh dùng lại đúng
   khung .pm-update-banner (đã có đệm safe-area đáy từ Phiên 7.2), chỉ
   thêm màu nhấn riêng.
   ===================================================================== */

.pm-bio-banner > i {
  color: var(--primary, #4f46e5);
}

/* Dải "hoặc" giữa nút sinh trắc và ô mật khẩu ở màn Mở khóa */
.pm-or {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  color: var(--muted-foreground);
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.pm-or::before,
.pm-or::after {
  content: "";
  flex: 1;
  height: 1px;
  background-color: var(--border, #e5e7eb);
}

/* =====================================================================
   PHIÊN 13 — Nâng giao diện ba màn không-đăng-nhập (Mở khóa / Thiết lập /
   banner sinh trắc). CHỈ trình bày: markup ba view đổi sang pattern
   Metronic (.kt-input wrapper + .kt-form-label + .kt-card p-8). Các lớp
   .pm-affix/.pm-control/.pm-label/.pm-field CŨ giữ nguyên (view khác dùng).
   Khối này ngoài @layer → thắng cascade. Không token mạng, không byte ảnh.
   ===================================================================== */

/* Nền màn khóa: gradient CSS thuần thay .page-bg PNG của demo (Q8). Rất
   nhẹ, tự hợp sáng/tối qua --primary + --background. Đệm safe-area giữ
   nguyên ở hai rule .pm-unlock-screen phía trên. */
.pm-unlock-screen {
  background:
    radial-gradient(1100px 620px at 50% -12%,
      color-mix(in oklab, var(--primary) 9%, transparent), transparent 72%),
    radial-gradient(900px 500px at 92% 108%,
      color-mix(in oklab, var(--primary) 6%, transparent), transparent 70%),
    var(--background);
}

/* Chiều cao ô nhập dễ chịu (Metronic .kt-input mặc định hơi thấp cho màn
   đăng nhập). min-height luôn thắng height cố định nếu lớn hơn. Chỉ trong
   màn khóa — không đụng ô nhập ở view khác. */
.pm-unlock-screen .kt-input { min-height: 2.625rem; }
.pm-unlock-screen .kt-card { box-shadow: 0 1px 2px rgba(0,0,0,.04),
                                         0 8px 24px -12px rgba(0,0,0,.12); }

/* Nút con mắt hiện/ẩn mật khẩu, đặt TRONG .kt-input wrapper. Tự vẽ (không
   phụ thuộc KTUI) — handler data-pm-reveal trong view là cơ chế nền duy
   nhất; chạy y hệt trong jsdom lẫn Chromium (§2.3). */
.pm-eye {
  flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center;
  width: 1.75rem; height: 1.75rem; padding: 0;
  border: 0; border-radius: calc(var(--radius) - 4px);
  background: transparent; color: var(--muted-foreground); cursor: pointer;
  margin-inline-end: -0.125rem;
  transition: color .15s ease, background-color .15s ease;
}
.pm-eye:hover  { color: var(--foreground);
                 background: color-mix(in oklab, var(--foreground) 8%, transparent); }
.pm-eye:focus-visible { outline: 2px solid var(--primary); outline-offset: 1px; }
.pm-eye i { font-size: 1.0625rem; color: inherit; }

/* Liên kết phụ dạng chữ (kt-btn-link KHÔNG tồn tại trong styles.css — grep
   0 hit). Dùng cho các nút mở/thu panel (khôi phục file / mây / tạo kho). */
.pm-link {
  display: inline-flex; align-items: center; gap: 0.375rem;
  background: transparent; border: 0; padding: 0.25rem 0.375rem;
  font-size: 0.875rem; font-weight: 500; color: var(--primary);
  cursor: pointer; border-radius: calc(var(--radius) - 2px);
  transition: color .15s ease, background-color .15s ease;
}
.pm-link:hover { text-decoration: underline; }
.pm-link:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.pm-link i { font-size: 1rem; }
/* §4 (10.B): "Tạo kho mới" phải MỜ/PHỤ hơn — màn NO_VAULT-mây trông như kho
   cá nhân, không như trang mời đăng ký. "Khôi phục từ file" KHÔNG bị làm mờ
   (phao cứu khi mất mây). */
.pm-link-muted { color: var(--muted-foreground); font-size: 0.8125rem; font-weight: 400; }
.pm-link-muted:hover { color: var(--foreground); text-decoration: underline; }

/* Chấm tròn keenicon (0 byte ảnh) thay illustration cho accent sinh trắc —
   ngân sách illustration 10 tệp = 619 KB ≫ trần 60 KB nên KHÔNG ship tệp
   nào; dùng vòng tròn tint + keenicon (§ báo cáo). */
.pm-badge-round {
  display: inline-flex; align-items: center; justify-content: center;
  width: 2.75rem; height: 2.75rem; border-radius: 999px;
  background: color-mix(in oklab, var(--primary) 12%, transparent);
  color: var(--primary); flex: 0 0 auto;
}
.pm-badge-round i { font-size: 1.375rem; }

/* =====================================================================
   PHIÊN 14 — Nối logo mục vào Kho + đồng bộ toolbar/kho-rỗng theo Metronic.
   CHỈ trình bày. Khối NGOÀI @layer → thắng cascade (Metronic ở @layer).
   Không token mạng, không byte ảnh: kho rỗng dùng keenicon + gradient;
   logo mục là <img> CÙNG NGUỒN hoặc monogram tất định (0 asset ship).
   Selector/hành vi giữ nguyên tuyệt đối — đây chỉ là lớp trình bày.
   ===================================================================== */

/* --- Toolbar Kho: căn chiều cao đồng nhất 2.625rem. .kt-input mặc định
   ~2.125rem (spacing*8.5) hơi thấp so với <select>/nút cạnh bên; min-height
   luôn thắng nếu lớn hơn. CHỈ trong thanh công cụ Kho — không đụng .kt-input
   ở view khác (Mở khóa/Thiết lập dùng rule riêng của Phiên 13). --- */
.pm-toolbar .kt-input { min-height: 2.625rem; font-size: 0.875rem; }

/* --- <select> GỐC mang .kt-select: Metronic .kt-select vốn cho component
   KTSelect (wrapper flex, không chiều cao). Trên <select> gốc ta CHỈ mượn
   khung (viền/nền/bo góc từ rule layered) rồi ép display:block + chiều cao +
   mũi chevron nền. GIỮ NATIVE (không data-kt-select) để Playwright
   select_option chạy — Q7. appearance:none đã có sẵn trong .kt-select. --- */
select.kt-select {
  display: block;
  height: 2.625rem;
  padding-inline: 0.75rem;
  padding-inline-end: 2rem;
  font-size: 0.875rem;
  background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="%23999" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M6 9l6 6 6-6"/></svg>');
  background-repeat: no-repeat;
  background-position: right 0.7rem center;
}
select.kt-select:focus-visible {
  border-color: var(--primary);
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--primary) 20%, transparent);
  outline: none;
}

/* --- Logo mục (bậc 1 ảnh / bậc 3 monogram) — ô 32px bo tròn, nền TRUNG TÍNH
   var(--muted) (tự hợp sáng/tối, khỏi bản -dark). Đặt GIỮA sao yêu thích và
   khối chữ trong .pm-title-cell; flex-shrink:0 để không bị bóp. Khối chữ giữ
   min-w-0 nên tiêu đề ELLIPSIS, KHÔNG bị logo đẩy xuống dòng (kể cả 390px). */
.pm-logo {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  border-radius: calc(var(--radius) - 2px);
  background: var(--muted);
  overflow: hidden;
}
img.pm-logo { object-fit: contain; }

/* Monogram TẤT ĐỊNH: màu suy từ --mono-hue (FNV-1a domain — cùng domain LUÔN
   cùng màu). Sáng: nền tint nhạt + chữ đậm cùng tông. Tối: đảo độ sáng cho đủ
   tương phản (.dark trên <html>, unlayered → thắng). */
.pm-mono {
  background: hsl(var(--mono-hue, 220) 55% 90%);
  color: hsl(var(--mono-hue, 220) 42% 34%);
  font-weight: 600;
  font-size: 0.875rem;
  line-height: 1;
}
.pm-mono-icon { color: hsl(var(--mono-hue, 220) 42% 42%); }
.pm-mono-icon i { font-size: 1rem; line-height: 1; }
.dark .pm-mono {
  background: hsl(var(--mono-hue, 220) 30% 26%);
  color: hsl(var(--mono-hue, 220) 68% 80%);
}
.dark .pm-mono-icon { color: hsl(var(--mono-hue, 220) 60% 78%); }

/* --- Kho rỗng: vòng tròn keenicon dùng GRADIENT (thay nền phẳng). Scope
   vào .pm-vault-table → KHÔNG đụng kho-rỗng của view Health (dùng chung
   .pm-empty-icon). Bo tròn (border-radius:999px) kế thừa từ rule gốc. --- */
.pm-vault-table .pm-empty-icon {
  width: 4rem;
  height: 4rem;
  background: linear-gradient(135deg,
    color-mix(in oklab, var(--primary) 20%, transparent),
    color-mix(in oklab, var(--primary) 6%, transparent));
  border: 1px solid color-mix(in oklab, var(--primary) 14%, transparent);
}
.pm-vault-table .pm-empty-icon i { font-size: 2rem; }

/* =====================================================================
   PHIÊN 15 — Màn XEM chỉ-đọc (#pm-view-modal). Tách XEM khỏi SỬA: chạm
   hàng mở màn này (copy nhanh + hiện mật khẩu), Sửa là hành động riêng.
   CHỈ trình bày, selector MỚI data-pm-view-* (không đụng hợp đồng cũ).
   Khối NGOÀI @layer → thắng cascade. Không token mạng, không byte ảnh:
   logo dùng LẠI engine .pm-logo/.pm-mono; giá trị copy dùng .pm-mini-btn.
   ===================================================================== */

/* Đầu màn: ô logo (to hơn hàng một chút) + tiêu đề ellipsis, nút sao/đóng. */
.pm-view-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
}
.pm-view-id {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  min-width: 0;
}
.pm-view-logo { flex: 0 0 auto; display: inline-flex; }
.pm-view-logo .pm-logo { width: 2.5rem; height: 2.5rem; }
.pm-view-logo .pm-mono { font-size: 1.0625rem; }
.pm-view-logo .pm-mono-icon i { font-size: 1.25rem; }
.pm-view-title {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 1.0625rem;
}
.pm-view-head-btns {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
}

/* Thân màn: các trường theo cột. */
.pm-view-body {
  display: flex;
  flex-direction: column;
  gap: 0.875rem;
}
.pm-view-row {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  min-width: 0;
}
.pm-view-field-label {
  font-size: 0.75rem;
  font-weight: 500;
  color: var(--muted-foreground);
}
.pm-view-field-static {
  font-size: 0.9375rem;
  color: var(--foreground);
  overflow-wrap: anywhere;
}
.pm-view-dim { color: var(--muted-foreground); }
.pm-view-notes {
  white-space: pre-wrap;
  word-break: break-word;
  line-height: 1.5;
}

/* Dòng giá trị + nút. Nút giá trị chạm-để-copy (1Password); biểu tượng copy
   ở cuối là gợi ý tường minh. Nút Hiện là ANH EM (không lồng) để bấm mắt
   không kích hoạt copy. min-height 2.75rem = 44px: đủ lớn để chạm mọi cỡ. */
.pm-view-field-line {
  display: flex;
  align-items: stretch;
  gap: 0.375rem;
  min-width: 0;
}
.pm-view-field-btn {
  flex: 1 1 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  min-width: 0;
  min-height: 2.75rem;
  padding: 0.4375rem 0.75rem;
  text-align: start;
  background: var(--background);
  color: var(--foreground);
  border: 1px solid var(--input);
  border-radius: var(--radius);
  cursor: pointer;
  transition: border-color 0.15s ease, background-color 0.15s ease;
}
.pm-view-field-btn:hover {
  border-color: var(--primary);
  background: color-mix(in oklab, var(--primary) 5%, transparent);
}
.pm-view-field-btn:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 1px;
}
.pm-view-val {
  min-width: 0;
  overflow-wrap: anywhere;
  font-size: 0.9375rem;
}
.pm-view-mono {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  letter-spacing: 0.02em;
}
.pm-view-copy-ico {
  flex: 0 0 auto;
  font-size: 1rem;
  color: var(--muted-foreground);
}
.pm-view-field-btn:hover .pm-view-copy-ico { color: var(--primary); }

/* Nút Hiện (con mắt): khớp chiều cao ô giá trị, viền nhẹ, 44px chạm tốt. */
.pm-view-eye {
  flex: 0 0 auto;
  width: 2.75rem;
  height: auto;
  min-height: 2.75rem;
  border: 1px solid var(--input);
  border-radius: var(--radius);
}
.pm-view-eye:hover { border-color: var(--primary); }

/* =====================================================================
   PHIÊN 17.B — Chống iOS auto-zoom: mọi ô nhập ≥16px trên MOBILE.
   Safari phóng to toàn màn khi focus vào <input> có font-size < 16px
   (thấy rõ ở ảnh thật 17.A: mép tiêu đề bị cắt khi focus ô Mở khóa /
   ô Tìm). 16px là ngưỡng; chỉ áp ≤40rem (= breakpoint sm của Metronic)
   nên DESKTOP GIỮ NGUYÊN cỡ cũ (14/15px). Khối NGOÀI @layer + đặt CUỐI
   file → thắng cascade: rule sau thắng rule trước cùng specificity, và
   unlayered thắng .kt-input layered của Metronic (0.8125rem).
   Cũng chuẩn hóa .pm-control (vốn 15px) về 16px trên mobile → trả nốt
   nợ "dọn" khác biệt thị giác so với .kt-input mà KHÔNG đổi tên class.
   CHỈ trình bày: 0 đổi id / data-* / DOM / hành vi. Bằng chứng cơ học:
   computed font-size ô Tìm 390px=16px, 1280px=14px (tools/measure17b.py). */
@media (max-width: 40rem) {
  .pm-toolbar .kt-input,
  select.kt-select,
  .pm-control,
  .kt-input,
  .kt-input input,
  input.kt-input,
  textarea.kt-input {
    font-size: 16px;
  }
}
/* =====================================================================
   PHIÊN 17.C — Thẻ Kho "gọn tối đa" (ii) trên MOBILE (một DOM; desktop
   giữ đủ 5 cột). Cùng breakpoint thẻ hiện có (max-width:63.98rem). CHỈ ẩn
   4 <td> qua [data-th] bằng display:none (KHÔNG xóa DOM/dữ liệu — chứng
   minh ở tests/repro_phien17c.js). Nút copy gọn: ẩn desktop, hiện mobile.
   KHÔNG đổi id / data-* / DOM / hành vi — chỉ trình bày. Đổi byte app.css
   ⇒ bump cache-name SW + version. */
.pm-compact-copy { display: none; }               /* desktop: ẩn (đã có hàng Thao tác) */
@media (max-width: 63.98rem) {
  /* Thẻ chỉ còn hàng "Tên": ẩn Tài khoản/Danh mục/Cập nhật/Thao tác. */
  .pm-vault-table td[data-th="Tài khoản"],
  .pm-vault-table td[data-th="Danh mục"],
  .pm-vault-table td[data-th="Cập nhật"],
  .pm-vault-table td[data-th="Thao tác"] { display: none; }
  /* Nút copy gọn hiện ra, tap tốt cho ngón tay, không co. */
  .pm-vault-table td[data-th="Tên"] .pm-compact-copy {
    display: inline-flex;
    width: 2.5rem; height: 2.25rem;
    flex-shrink: 0;
  }
  /* Khối chữ (tiêu đề/URL) NỞ để đẩy nút copy sát MÉP PHẢI; min-w-0 (đã có)
     cho ellipsis. Scope vào ô "Tên" của bảng kho → không đụng .min-w-0 khác. */
  .pm-vault-table td[data-th="Tên"] .pm-title-cell > .min-w-0 { flex: 1 1 auto; }
  /* Thẻ mỏng lại: bỏ đệm dư của hàng đơn (đè riêng thuộc tính padding). */
  .pm-vault-table tbody tr { padding: 0.25rem 0; }
}
/* =====================================================================
   PHIÊN 17.E — Toolbar Kho theo social.html: đệm trên/dưới đều, ô Tìm chiếm
   trọn hàng, 2 dropdown (Danh mục + Sắp xếp) CẠNH NHAU cho gọn chiều cao,
   "Yêu thích" là NÚT OUTLINE. Đếm mục đã dời lên phụ đề (data-pm-count trên
   .pm-page-sub). Một DOM; KHÔNG đổi selector/hành vi — chỉ trình bày + bọc
   thêm .pm-toolbar-filters (không mang data-*). Đổi byte → bump version. */
.pm-toolbar {
  padding: 1rem;                 /* đệm đều mọi phía — ô Tìm không dính mép card */
  column-gap: 0.75rem;
  row-gap: 0.75rem;
  align-items: center;
}
.pm-toolbar-filters {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem;
  flex: 1 1 auto;
}
/* "Yêu thích" outline; trạng thái BẬT (pm-seg-active) tô primary nhạt để phân biệt */
.pm-fav-btn.pm-seg-active {
  border-color: var(--primary);
  color: var(--primary);
  background-color: color-mix(in oklab, var(--primary) 10%, transparent);
}
.pm-fav-btn.pm-seg-active i { color: var(--primary); }

@media (max-width: 63.98rem) {
  .pm-toolbar > .kt-input { flex: 1 1 100%; max-width: none; }        /* ô Tìm trọn hàng */
  .pm-toolbar-filters { flex-basis: 100%; }                            /* nhóm lọc xuống hàng riêng */
  .pm-toolbar-filters > .kt-select {                                   /* 2 dropdown chia đôi, cạnh nhau */
    flex: 1 1 0;
    min-width: 0;
    max-width: none;
  }
  .pm-toolbar-filters > .pm-fav-btn {                                  /* "Yêu thích" hàng riêng, canh giữa */
    flex: 1 1 100%;
    justify-content: center;
  }
}
/* =====================================================================
   PHIÊN 17.F — "Truy cập nhanh": thẻ ghim mục ★ (tối đa 4) ở ĐẦU màn Kho.
   Nguồn = cờ favorite (KHÔNG đụng dữ liệu). Lưới 2 cột mobile / 4 cột desktop.
   Chạm thẻ → Xem; nút copy → chép mật khẩu (không mở Xem). Đổi byte → bump. */
.pm-pins { margin-bottom: 1rem; }
.pm-pins[hidden] { display: none; }
.pm-pins-head {
  margin: 0 0 0.5rem;
  display: flex; align-items: center; gap: 0.375rem;
  font-size: 0.8125rem; font-weight: 600; letter-spacing: 0.02em;
  color: var(--muted-foreground);
}
.pm-pins-head i { color: var(--primary); font-size: 1rem; }
.pm-pins-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 0.5rem; }
.pm-pin {
  display: flex; align-items: center; gap: 0.5rem; min-width: 0;
  padding: 0.5rem 0.625rem;
  border: 1px solid var(--border);
  border-radius: calc(var(--radius) - 2px);
  background: var(--background);
  cursor: pointer;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.pm-pin:hover {
  border-color: color-mix(in oklab, var(--primary) 40%, var(--border));
  box-shadow: 0 1px 3px rgb(0 0 0 / 0.06);
}
.pm-pin:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.pm-pin .pm-logo { flex: 0 0 auto; width: 1.75rem; height: 1.75rem; font-size: 0.8125rem; }
.pm-pin-title {
  flex: 1 1 auto; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: 0.875rem; font-weight: 500; color: var(--foreground);
}
.pm-pin-copy {
  flex: 0 0 auto; width: 2rem; height: 2rem;
  border: 0; background: transparent; color: var(--muted-foreground);
  border-radius: 0.5rem; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
}
.pm-pin-copy:hover {
  background: color-mix(in oklab, var(--primary) 10%, transparent);
  color: var(--primary);
}
.pm-pin-copy i { font-size: 1.05rem; }
@media (min-width: 64rem) { .pm-pins-grid { grid-template-columns: repeat(4, 1fr); } }
/* =====================================================================
   PHIÊN 17.G — Ghim THỦ CÔNG cho "Truy cập nhanh" (thay "4 mục ★ đầu").
   Nút ghim ở hàng Thao tác (desktop) + header màn Xem (đường ghim mobile).
   Trạng thái ĐÃ GHIM tô primary để phân biệt với ★ (vàng). */
.pm-pin-btn.pm-pinned,
.pm-view-pin.pm-pin-on { color: var(--primary); }
.pm-pin-btn.pm-pinned i,
.pm-view-pin.pm-pin-on i { color: var(--primary); }
.pm-pin-btn.pm-pinned:hover,
.pm-view-pin.pm-pin-on:hover {
  background-color: color-mix(in oklab, var(--primary) 12%, transparent);
}
/* =====================================================================
   PHIÊN 17.H — Copy nhanh URL.
   (a) Modal Sửa: ô URL nay nằm trong .pm-affix nhưng input dùng class
       `kt-input` (không phải `.pm-control`), mà rule cũ
       `.pm-affix .pm-control{padding-inline-end:3rem}` không phủ → THÊM rule
       cho .kt-input để nút copy không đè lên chữ. Chỉ THÊM, không sửa rule cũ.
   (b) Modal Xem: hàng Website về cùng khuôn ô + nút copy như Tên đăng nhập. */
.pm-affix .kt-input { padding-inline-end: 3rem; }

.pm-view-url-copy { flex: 0 0 auto; }
.pm-view-field-line > .pm-view-field-static.pm-view-grow {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* =====================================================================
   PHIÊN 17.I — SỬA LỖI: cột "Thao tác" bị cắt trên desktop.

   Triệu chứng (TB2 báo, ảnh 2026-07-24): header hiện "THAO T…", nút Xóa mất
   một nửa. ĐO ĐƯỢC: bảng đòi 1198px trong wrapper 1126px (viewport 1440) ⇒
   tràn ở MỌI viewport 1024–1920. Wrapper `.pm-scroll-x` có overflow-x:auto
   nên về kỹ thuật cuộn được, nhưng thanh cuộn overlay gần như vô hình ⇒ người
   dùng thấy như bị "nuốt mất".

   NGUYÊN NHÂN GỐC: `.pm-entry-title{max-width:22rem}` (352px) và
   `.pm-user-text{max-width:16rem}` (256px) là số CỨNG — cột không co theo
   không gian còn lại, nên tổng bề rộng cột luôn > wrapper. (Nút ghim thêm ở
   17.G làm cột Thao tác rộng thêm ~32px, khiến lỗi lộ rõ chứ không phải gốc.)

   CÁCH SỬA (đã đo 6 biến thể, chọn cái duy nhất vừa ở mọi viewport mà cột Tên
   vẫn đọc được): cho 2 cột chữ CO ĐƯỢC (`max-width:0` trên td là thủ thuật
   chuẩn của table-layout:auto) + trần mềm theo % + chặn dưới min-width; cột
   Thao tác `width:1%` để chỉ chiếm đúng nội dung, không giãn.
   Chỉ CSS — 0 đổi markup, 0 đổi selector, mobile (≤63.98rem) không đụng tới. */
/* ⚠️ TOÀN BỘ khối dưới CHỈ áp cho chế độ BẢNG (≥64rem). Bản đầu quên bọc
   media query ⇒ `max-width:0` áp cả mobile, làm nút copy trên thẻ tràn ra
   ngoài td 78px (smoke 17.C bắt được). Mobile là thẻ block — không được đụng. */
@media (min-width: 64rem) {
  .pm-vault-table td[data-th="Tên"],
  .pm-vault-table td[data-th="Tài khoản"] { max-width: 0; }
  .pm-vault-table td[data-th="Tên"] .pm-entry-title,
  .pm-vault-table td[data-th="Tài khoản"] .pm-user-text { max-width: 100%; }
  /* Thao tác: co về đúng nội dung, không bao giờ bị bóp cụt */
  .pm-vault-table td[data-th="Thao tác"],
  .pm-vault-table th:last-child { width: 1%; white-space: nowrap; }
  /* Phân bổ phần dư cho 2 cột chữ (th theo thứ tự: Tên, Tài khoản, Danh mục,
     Cập nhật, Thao tác — thead không có data-* nên dùng nth-child) */
  .pm-vault-table th:nth-child(1) { width: 44%; min-width: 15rem; }
  .pm-vault-table th:nth-child(2) { width: 24%; min-width: 8rem; }
}
/* Dải hẹp của chế độ bảng (64rem–80rem): nới chặn dưới để vẫn KHÔNG tràn —
   thà tiêu đề ngắn hơn còn hơn mất cột Thao tác. */
@media (min-width: 64rem) and (max-width: 80rem) {
  .pm-vault-table th:nth-child(1) { min-width: 10rem; }
  .pm-vault-table th:nth-child(2) { min-width: 6rem; }
}
/* =====================================================================
   PHIÊN 17.J — Sticky hàng tiêu đề + sắp xếp theo cột (CHỈ chế độ bảng).

   ⚠️ CẠM BẪY ĐÃ ĐO: `.pm-scroll-x` đặt `overflow-x:auto`, mà CSS ép
   `overflow-y` từ `visible` → `auto` ⇒ nó thành SCROLL CONTAINER. `position:
   sticky` bám ancestor cuộn GẦN NHẤT, tức bám vào wrapper này — nhưng wrapper
   KHÔNG cuộn dọc (trang cuộn ở document) nên sticky sẽ "chết". Sau 17.I bảng
   luôn vừa wrapper ở 1024–1920 nên desktop KHÔNG còn cần cuộn ngang ⇒ trả
   `overflow: visible` để sticky bám document. Mobile (thẻ) không đụng tới. */
@media (min-width: 64rem) {
  /* `.pm-scroll-x` chỉ dùng cho bảng Kho (đã grep xác nhận) nên nhắm thẳng —
     không cần `:has()` (tránh phụ thuộc tính năng CSS mới). */
  .pm-scroll-x { overflow: visible; }

  .pm-vault-table thead th {
    position: sticky;
    top: 0;
    z-index: 5;
    background: var(--background);
    /* viền dưới vẽ bằng shadow: border trên <th> sticky bị "rơi" khi cuộn */
    box-shadow: inset 0 -1px 0 var(--border);
  }

  /* Đầu cột bấm được */
  .pm-sort-th {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    padding: 0;
    border: 0;
    background: transparent;
    font: inherit;
    color: inherit;
    letter-spacing: inherit;
    text-transform: inherit;
    cursor: pointer;
    user-select: none;
  }
  .pm-sort-th:hover { color: var(--primary); }
  .pm-sort-th:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; border-radius: 0.25rem; }
  .pm-sort-ico { font-size: 0.75rem; opacity: 0.45; }
  .pm-sort-th:hover .pm-sort-ico { opacity: 0.9; }
  /* Cột đang sắp: nhấn mạnh + mũi tên rõ */
  .pm-sort-th.pm-sort-on { color: var(--primary); }
  .pm-sort-th.pm-sort-on .pm-sort-ico { opacity: 1; color: var(--primary); }
}
/* 17.J — dải hẹp của chế độ bảng: icon mũi tên trên 4 đầu cột làm min-content
   của thead tăng, ép cột Tên co thêm (~10px — smoke 17.I bắt: 75px < 80px).
   Ở dải này chỉ hiện mũi tên cho cột ĐANG sắp; các cột khác hiện icon khi rê
   chuột (hover) nên vẫn khám phá được chức năng. */
@media (min-width: 64rem) and (max-width: 80rem) {
  .pm-sort-th:not(.pm-sort-on) .pm-sort-ico { display: none; }
  .pm-sort-th:not(.pm-sort-on):hover .pm-sort-ico { display: inline-block; }
}
/* =====================================================================
   PHIÊN 17.K — Nút copy cho Ghi chú (màn Xem + modal Sửa).
   Ghi chú NHIỀU DÒNG nên nút đặt ở HÀNG NHÃN (góc phải), không dùng affix
   giữa dòng như URL/Tài khoản. Chỉ THÊM, không đổi selector/CSS cũ. */
.pm-view-notes-head,
.pm-e-notes-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
}
/* nút copy trong hàng nhãn: nhỏ gọn, không chiếm chiều cao dòng nhãn */
.pm-e-notes-copy { margin-inline-start: auto; }
.pm-view-notes-copy { flex: 0 0 auto; }
