/*
 * PHÔNG CHỮ — tự chứa, không gọi CDN.
 *
 * Bitter cho tiêu đề, Be Vietnam Pro cho thân bài. Lý do chọn và giấy phép:
 * xem public/gd/phong/GIAY-PHEP.md.
 *
 * 🪤 `unicode-range` phải khai ĐÚNG, không được bỏ. Thiếu khối `vietnamese`
 * thì trình duyệt vẫn hiện chữ — bằng phông dự phòng của hệ điều hành — nên
 * nhìn qua tưởng chạy tốt, chỉ có điều mỗi chữ có dấu lại nhảy sang một phông
 * khác. Lỗi ấy lộ rõ nhất ở đúng thứ sản phẩm này đầy: tên người Việt.
 *
 * `font-display: swap` để chữ hiện ngay bằng phông dự phòng rồi đổi — thà
 * nhấp nháy một cái còn hơn trang trắng trên mạng 3G ở quê.
 */

@font-face {
  font-family: 'Bitter'; font-style: normal; font-weight: 600; font-display: swap;
  src: url('phong/bitter-600-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;
}
@font-face {
  font-family: 'Bitter'; font-style: normal; font-weight: 600; font-display: swap;
  src: url('phong/bitter-600-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Bitter'; font-style: normal; font-weight: 700; font-display: swap;
  src: url('phong/bitter-700-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;
}
@font-face {
  font-family: 'Bitter'; font-style: normal; font-weight: 700; font-display: swap;
  src: url('phong/bitter-700-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Be Vietnam Pro'; font-style: normal; font-weight: 400; font-display: swap;
  src: url('phong/bvp-400-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;
}
@font-face {
  font-family: 'Be Vietnam Pro'; font-style: normal; font-weight: 400; font-display: swap;
  src: url('phong/bvp-400-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Be Vietnam Pro'; font-style: normal; font-weight: 600; font-display: swap;
  src: url('phong/bvp-600-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;
}
@font-face {
  font-family: 'Be Vietnam Pro'; font-style: normal; font-weight: 600; font-display: swap;
  src: url('phong/bvp-600-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

/*
 * Giao diện phả đồ. Mobile-first: viết cho màn hình hẹp trước, máy tính là
 * phần mở rộng — không phải web desktop rồi co lại.
 *
 * Bảng màu lấy tinh thần giấy phả cũ: nền ngà, mực nâu đen, son đỏ cho dấu
 * nhấn. Tránh xanh dương mặc định của trình duyệt vì nó làm bản in trông như
 * ảnh chụp màn hình phần mềm, mà cuối cùng dòng họ nào cũng in ra treo.
 */

/*
 * BẢNG MÀU — sơn son thếp vàng trên giấy dó.
 *
 * Một màu nhấn duy nhất trên nền kem là thứ làm trang trông như bản nháp: mọi
 * thứ cùng một sắc độ thì không gì nổi lên, và mắt không biết nhìn đâu trước.
 * Nên có BA tầng:
 *
 *   · SƠN  — đỏ sơn son, dành cho hành động chính và chỗ đang mở. Dùng ít.
 *   · THẾP — vàng thếp, dành cho thứ đáng chú ý mà KHÔNG phải hành động:
 *            giỗ sắp tới, việc chờ duyệt. Tách hẳn khỏi "bấm được".
 *   · MỰC  — thang trung tính ấm, năm bậc, cho toàn bộ phần còn lại.
 *
 * Sắc trung tính đều ngả ấm (hue ~35°), không phải xám máy tính. Xám thuần
 * cạnh đỏ son thì trông bẩn.
 */
:root {
  --giay:      #FAF7F0;   /* nền chính */
  --giay-sau:  #F2EDE2;   /* nền lún, ô nhập */
  --giay-nang: #FFFFFF;   /* thẻ nổi lên trên nền */

  /* Thang mực: mỗi bậc ĐỀU ĐẠT ngưỡng đọc được trên nền giấy, đo bằng
     App\Theme\Theme::doTuongPhan chứ không ướm bằng mắt.
     🪤 Bản trước `--muc-mo` chỉ đạt 2,93 mà vẫn dùng cho nhãn "CÔNG CỤ",
     "SẮP TỚI" và chữ trong khung ảnh trống — dưới ngưỡng 4,5 của WCAG. */
  /* 🔴 SỐ ĐO PHẢI LẤY TRÊN NỀN THẬT, KHÔNG PHẢI TRÊN `--giay`.
     `--giay` bị GIAO DIỆN CỦA DÒNG HỌ ghi đè lúc chạy — ba nền dựng sẵn ở
     `Theme::NEN_UNG_DUNG` là #f6f1e7 · #eef0ea · #eceef2, không cái nào là
     #FAF7F0. Bảng cũ đo trên #FAF7F0 nên mọi con số đều cao hơn thực tế, và
     `--muc-mo` thực đo chỉ 4,32 chứ không phải 4,54.
     Số trong ngoặc dưới đây là ngưỡng THẤP NHẤT trong ba nền ấy. */
  --muc:       #211C16;   /* 14,55 */
  --muc-dam:   #4A4136;   /*  8,61 */
  --muc-nhat:  #6E6455;   /*  5,00 */
  --muc-mo:    #736A5F;   /*  4,57 — trước là #797065, thực đo 4,32 */

  /* 🪤 Viền cũ chỉ 1,29 — gần như vô hình trên nền kem, và đó chính là thứ
     làm cả trang trông nhạt: thẻ không có mép, mắt không thấy ranh giới nào.
     WCAG 1.4.11 đòi 3,0 cho ranh giới của phần tử BẤM ĐƯỢC. */
  --vien:      #A5A095;   /*  2,43 — đường phân cách, mép thẻ */
  --vien-dam:  #8F887B;   /*  3,28 — mép nút, ô nhập */

  --son:       #9E2B18;
  --son-toi:   #7E2011;
  --son-sang:  #C4462C;
  --son-nhat:  #FAEDE8;

  --thep:      #8E631D;   /*  4,57 — trước là #976920, thực đo 4,15 */
  --thep-nhat: #FBF2DE;

  --nam:       #2F5D74;
  --nam-nen:   #E7EFF3;
  --nu:        #8A4A6B;
  --nu-nen:    #F5E9F0;
  --song:      #2C7361;
  --an:        #B8B0A3;

  /* Bóng nhiều tầng: một tầng sát để tách khỏi nền, một tầng xa để tạo độ
     nổi. Một tầng duy nhất thì hoặc cứng như viền, hoặc mờ như vết bẩn. */
  --bong-1: 0 1px 2px rgba(33,28,22,.06);
  --bong-2: 0 1px 2px rgba(33,28,22,.05), 0 4px 12px -6px rgba(33,28,22,.18);
  --bong-3: 0 2px 4px rgba(33,28,22,.06), 0 14px 32px -18px rgba(33,28,22,.42);
  --bong:   var(--bong-2);

  --chu-than: 'Be Vietnam Pro', -apple-system, BlinkMacSystemFont, 'Segoe UI',
              Roboto, sans-serif;
  --chu-de:   'Bitter', Georgia, 'Times New Roman', serif;

  --cao-thanh: 60px;
  --cao-hang2: 52px;
  /* 🔴 LỀ TRÁI CỦA MỌI THỨ NEO CỨNG, để tránh một loại lỗi đã trả giá.
     Từ 880px có thanh điều hướng DỌC bên trái, nên khung cây, các màn và
     hàng 2 đều phải bắt đầu sau nó. Trước đây việc ấy làm bằng ba luật
     `left: var(--rong-ben)` đặt trong khối @media — mà luật NỀN của
     `.thanh-hai` lại nằm SAU khối ấy trong tệp và dùng `inset: … 0 auto 0`,
     tức là gồm cả `left: 0`. Đặc hiệu bằng nhau thì luật sau thắng, nên hàng
     2 tụt về mép trái và NẰM DƯỚI thanh dọc: ô tìm người bị che mất một
     nửa. David 02/09: *"thanh tìm kiếm ở pc bị lệch sang trái bị menu dọc
     che mất rồi."*
     Biến thì giải ở lúc DÙNG, nên thứ tự khai báo trong tệp không còn quyết
     định được gì nữa. */
  --le-trai: 0px;

  /* =====================================================================
     THANG KHOẢNG CÁCH VÀ THANG CHỮ
     =====================================================================
     🔴 TRƯỚC 02/09/2026 KHÔNG CÓ HAI THANG NÀY. Bộ áo có đủ token màu, nhưng
     mọi khoảng cách và cỡ chữ đều là số gõ thẳng tại chỗ. Đo ra: 24 giá trị
     khoảng cách khác nhau (có cả 5, 7, 9, 11, 13, 17px) và 26 cỡ chữ (có cả
     9,5 · 10,5 · 11,5 · 12,5 · 13,5 · 14,5 · 15,5px — NỬA PIXEL). Không nhịp
     nào cả, nên mỗi màn lệch nhau một chút và người dùng thấy được cái lệch ấy
     dù không gọi tên ra được. David 02/09: *"mày không dùng skill design nào
     để làm hay sao?"*

     Nhịp 4px, thang lấy từ `design-md/kho/intercom` — bộ có nền kem, chữ than
     và MỘT màu nhấn, tức gần nhất với bộ áo sẵn có của giapha. Chỉ lấy NHỊP
     và THANG; màu, phông, bo góc vẫn là của dự án (luật ③ của skill: dự án đã
     có hệ thì hệ ấy thắng).

     🪤 THÊM TOKEN KHÔNG TỰ SỬA GÌ CẢ. Hơn ba nghìn dòng CSS vẫn đang gõ số
     thẳng; ép hết về thang trong một lượt là đổi hàng trăm chỗ mà không đo lại
     được chỗ nào. Áp dần từng tệp, đo sau mỗi tệp. `bin/soi-thang.sh` liệt kê
     số nào còn lạc ngoài thang. */
  --k1: 4px;    /* khe rất hẹp: giữa biểu tượng và chữ */
  --k2: 8px;    /* khe trong một cụm */
  --k3: 12px;   /* đệm ô nhập, khe giữa các cụm nhỏ */
  --k4: 16px;   /* đệm thẻ, khe giữa các khối */
  --k5: 24px;   /* đệm khối lớn, khe giữa các nhóm */
  --k6: 32px;
  --k7: 48px;   /* tách hẳn hai phần của một trang */

  /* Thang chữ. Bỏ hẳn nửa pixel: mắt không thấy 0,5px, mà nó làm mọi thứ
     quanh nó lệch nhịp. 16px là cỡ thân — cũng là ngưỡng iOS thôi tự phóng to
     khi bấm vào ô nhập, nên ô nhập KHÔNG BAO GIỜ nhỏ hơn cỡ này. */
  --c1: 11px;   /* nhãn viết hoa, chữ rất phụ */
  --c2: 12px;   /* chú thích, meta */
  --c3: 14px;   /* chữ phụ, thân trong thẻ */
  --c4: 16px;   /* thân mặc định, và mọi ô nhập */
  --c5: 18px;   /* dẫn nhập */
  --c6: 22px;   /* tiêu đề thẻ */
  --c7: 28px;   /* tiêu đề màn */
  --bo-nho: 8px;
  --bo-vua: 12px;
  --bo-lon: 16px;
}

/* Tông tối do HỌ chọn, đặt bằng `data-tong` trên <html>.
   Phải là một khối riêng chứ không gộp với media query: người dùng có thể
   đang ở máy tông sáng mà dòng họ chọn tông tối, và ngược lại. */
:root[data-tong="toi"] {
  --giay-sau: #1C1813; --giay-nang: #221D17;
  --muc-dam: #CFC5B5; --muc-mo: #978B7A;   /* 4,74 — trước #7C7263 chỉ 3,95 */
  --vien: #322B22; --vien-dam: #463D31;
  --son-toi: #C4553C; --son-sang: #F09076; --son-nhat: #331C16;
  --thep: #D6A85A; --thep-nhat: #2A2113;
  --bong-1: 0 1px 2px rgba(0,0,0,.5);
  --bong-2: 0 1px 2px rgba(0,0,0,.5), 0 4px 14px -6px rgba(0,0,0,.7);
  --bong-3: 0 2px 6px rgba(0,0,0,.5), 0 16px 34px -18px rgba(0,0,0,.9);
}

/* Họ chọn tông SÁNG thì giữ sáng, dù máy đang ở chế độ tối. */
:root[data-tong="sang"] {
  --giay-sau: #F2EDE2; --giay-nang: #FFFFFF;
  /* 🪤 KHỐI NÀY MỚI LÀ KHỐI THẮNG — mọi cây đều mang `data-tong`. Sửa token
     ở `:root` mà quên đây là sửa chỗ không ai nhìn thấy: `--muc-mo` từng
     giữ #9B9081 (thực đo 2,78) suốt trong khi bảng trên ghi 4,54. */
  --muc-dam: #4A4136; --muc-mo: #736A5F;
  --vien: #E2DBCC; --vien-dam: #CFC5B2;
  --son-toi: #7E2011; --son-sang: #C4462C; --son-nhat: #FAEDE8;
  --thep: #8D631B; --thep-nhat: #FBF2DE;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-tong="sang"]) {
    --giay: #15120E; --giay-sau: #1C1813; --giay-nang: #221D17;
    --muc: #EFE8DC; --muc-dam: #CFC5B5; --muc-nhat: #A99E8E; --muc-mo: #978B7A;
    --vien: #322B22; --vien-dam: #463D31;

    /* Đỏ son nguyên bản trên nền tối thì tối quá, gần như đen. Kéo sáng lên
       cho đủ tương phản — cùng luật đã viết cho bản in ở App\Theme\Theme. */
    --son: #E27358; --son-toi: #C4553C; --son-sang: #F09076; --son-nhat: #331C16;
    --thep: #D6A85A; --thep-nhat: #2A2113;

    --nam: #8FC0D8; --nam-nen: #16242C; --nu: #D69CBC; --nu-nen: #2A1A24;
    --song: #6CBFA3; --an: #4A4237;
    --bong-1: 0 1px 2px rgba(0,0,0,.5);
    --bong-2: 0 1px 2px rgba(0,0,0,.5), 0 4px 14px -6px rgba(0,0,0,.7);
    --bong-3: 0 2px 6px rgba(0,0,0,.5), 0 16px 34px -18px rgba(0,0,0,.9);
    --bong: var(--bong-2);
  }
}

* { box-sizing: border-box; }

/*
 * BẮT BUỘC PHẢI CÓ, ĐỪNG XOÁ.
 *
 * Thuộc tính `hidden` của HTML chỉ là `display: none` trong bảng kiểu mặc định
 * của trình duyệt, mà bảng kiểu của TÁC GIẢ luôn thắng bảng kiểu mặc định —
 * bất kể độ đặc hiệu. Nên chỉ cần một dòng `display: grid` ở `.lop-mo` là hộp
 * đăng nhập hiện đè lên cả trang ngay từ lúc mở, dù JavaScript đã đặt
 * `hidden = true`.
 *
 * Đúng loại lỗi jsdom không bắt được: jsdom trả về `display: none` nên bộ kiểm
 * thử vẫn xanh, chỉ trình duyệt thật mới lộ.
 */
[hidden] { display: none !important; }

html, body {
  /* 🪤 `100%` neo theo khung nhìn BỐ CỤC, vốn cao bằng lúc thanh địa chỉ đã
     thu lại. Trong trình duyệt NHÚNG (Zalo, Facebook) và Safari iOS, phần
     NHÌN THẤY thấp hơn thế, nên thanh dưới `bottom: 0` tụt xuống dưới mép màn
     hình — David 02/09: *"menu bottom không dính đáy màn hình thiết bị"*.
     `100dvh` bám theo phần nhìn thấy và co giãn theo thanh công cụ. Giữ dòng
     `100%` đứng trước làm bản lùi cho trình duyệt cũ chưa biết `dvh`. */
  margin: 0; height: 100%; height: 100dvh; overflow: hidden;
  background: var(--giay); color: var(--muc);
  font: 15px/1.55 var(--chu-than);
  -webkit-font-smoothing: antialiased;
  overscroll-behavior: none;
}

/* ---------- Thanh trên ---------- */

/* 🔴 MŨ CÓ NỀN MÀU — David chốt 01/09: "header nên là nền màu cho chắc chắn",
   nhắc lại 02/09. Khác hẳn cái "cục màu nặng nề" đã bị gạt hồi tháng 8: cái ấy
   là một MẢNG đỏ cao gần một phần ba màn hình nằm trong thân trang; cái này là
   một THANH mỏng ghim trên đỉnh, đúng vai của một thanh ứng dụng.

   🪤 Nền ĐẶC, không còn `backdrop-filter`. Ngoài chuyện nền màu thì mờ nền là
   vô nghĩa, dòng ấy còn là một cái bẫy đã ghi trong skill: `backdrop-filter`
   biến phần tử thành KHUNG NEO cho mọi con `position: fixed` — y như
   `transform` — nên cụm nút đặt trong header tính `bottom` theo cái thanh cao
   60px và treo ngược lên trên màn hình.

   🪤 Màu lấy từ `--son`, và đó là chỗ an toàn: `Theme::nhanManHinh()` đã KÉO
   màu nhấn của dòng họ cho đủ tương phản với nền SÁNG, tức nó luôn đủ tối —
   nên chữ trắng đặt lên luôn đọc được, kể cả khi họ tự chọn màu. */
/* 🔴 CHIỀU CAO DO NỘI DUNG QUYẾT, KHÔNG ĐÓNG CỨNG.
   Bản trước đặt `height: var(--cao-thanh)` rồi cộng thêm
   `padding-top: env(safe-area-inset-top)`. Với `box-sizing: border-box` thì
   phần đệm ấy ĂN VÀO TRONG chiều cao đã chốt, nên dấu hiệu và tên dòng họ bị
   đẩy xuống rồi cắt cụt ở mép dưới thanh. Trên trình duyệt thường inset bằng 0
   nên không thấy gì; chỉ trong trình duyệt NHÚNG của Zalo/Facebook và trên
   iPhone tai thỏ mới lộ — David chụp được 02/09.

   🪤 VÀ `.thanh` KHÔNG ĐƯỢC ĐỌC `--cao-thanh`. `doThanhTren()` đo chiều cao
   thật rồi ghi ngược vào biến ấy; nếu chiều cao lại tính từ chính biến đó thì
   mỗi lần đo là một vòng cộng dồn — thanh tự nở ra mãi. `min-height` là con số
   trần, cố ý viết cứng. */
.thanh {
  position: fixed; inset: 0 0 auto 0; z-index: 20;
  min-height: 60px;
  display: flex; align-items: center; gap: 12px;
  padding: env(safe-area-inset-top, 0px) 12px 0;
  background: var(--son);
  color: #fff;
  border-bottom: 0;
}
.thanh h1 { color: #fff; }
.thanh .phu, .thanh-trai .phu { color: rgba(255, 255, 255, .78); }
.thanh .dau-hieu { color: #fff; }
/* Con dấu đứng TRẮNG TRƠN trên nền son, không khối nền (David 02/09: "sao logo
   không dùng màu trắng luôn, bỏ nền làm gì"). Khối vuông kia sinh ra để tách
   hình đỏ khỏi nền kem; nền son thì nó thành một cái hộp thừa quanh chính thứ
   nó định làm nổi bật. */
.thanh .dh-nen { fill: none; }
/* 🔴 PHẢI GHI ĐÈ CẢ KHUNG CỦA `.nut`, KHÔNG CHỈ MÀU CHỮ. Hai nút này mang
   `class="nut mu-nut"`, mà `.nut` đứng SAU trong tệp với cùng độ đặc hiệu nên
   nó thắng: nền `--giay-nang` (trắng) + viền + bóng. Ba gạch trắng trên nền
   trắng là VÔ HÌNH — trên mũ son nó hiện ra thành một ô vuông trắng đặc, đúng
   cái David chụp lại sáng 02/09. Không lỗi nào báo; chỉ nhìn ảnh mới thấy. */
.thanh .mu-nut, .thanh .mu-avatar {
  background: none; border: 0; box-shadow: none; padding: 0;
}
/* 🪤 Avatar phải THẤY ĐƯỢC LÀ MỘT VÒNG TRÒN ngay từ đầu, không đợi rê chuột:
   trên điện thoại không có chuột để mà rê. Nền đứng yên một kiểu, bấm là bấm. */
.thanh .mu-avatar { background: rgba(255, 255, 255, .18); }
.thanh .mu-nut { color: #fff; }

/* Dấu hiệu CÂN GIỮA thanh ở màn hẹp (David 02/09) — ba gạch một bên, avatar
   bên kia, cùng 38px, nên cho khối giữa giãn ra là nó tự cân. Đo được lệch 0px
   ở cả 320 lẫn 390.
   🪤 Ngưỡng phải TRÙNG với chỗ tên dòng họ bị ẩn (720px), không phải chỗ hàng
   điều hướng ngang xuất hiện (880px). Ở khoảng giữa hai con số ấy thanh vẫn
   mang tên dòng họ, mà ép dấu hiệu ra giữa khi còn thứ khác trong hàng thì nó
   không ra giữa được, chỉ bóp tên dòng họ lại — đúng kiểu "chữ bị bóp thành
   mảnh vụn" mà tệp này đã trả giá một lần. */
@media (max-width: 720px) {
  .thanh .dau-hieu { flex: 1 1 auto; justify-content: center; min-width: 0; }
}

/* Điều hướng ngang nằm TRONG mũ, nên cũng phải đổi sang mực trắng. */
.thanh-ngang .mucd { color: rgba(255, 255, 255, .85); }
.thanh-ngang .mucd.dang { color: #fff; }
.thanh-ngang .mucd::before { background: #fff; }
.thanh-ngang .mucd:focus-visible { outline-color: #fff; }
.thanh-trai { min-width: 0; flex: 0 1 auto; }
.thanh h1 {
  margin: 0; font-size: 15px; font-weight: 650; letter-spacing: -.01em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 42vw;
}
.phu { margin: 0; font-size: 11.5px; color: var(--muc-nhat); }
.thanh-trai .phu { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 42vw; }
.thanh-giua { flex: 1 1 auto; min-width: 0; display: flex; justify-content: center; }
/* 🪤 `margin-left: auto` là thứ ĐẨY AVATAR SÁT MÉP PHẢI. Không có nó thì mọi
   phần tử của thanh dồn về trái — trên 390px avatar dừng ở 234 trong khi mép
   thanh ở 390, thừa 156px trống bên phải. Không phần tử nào trong thanh có
   `flex-grow`, nên chẳng có gì tự đẩy nó đi cả. */
.thanh-phai { display: flex; gap: 6px; align-items: center; flex: 0 0 auto; margin-left: auto; }

/* ---- Ba gạch, avatar và tấm menu — bộ của bản B, David chốt 01/09 ----
   Hai nút này KHÔNG mang khung của `.nut` (viền + nền trắng + bóng): trên
   thanh tiêu đề chúng phải nhẹ như biểu tượng, không phải hai cái hộp. */
.mu-nut, .mu-avatar {
  width: 38px; height: 38px; flex: 0 0 auto; padding: 0;
  display: grid; place-items: center;
  border: 0; border-radius: 19px; box-shadow: none;
  background: none; color: var(--muc-dam); cursor: pointer;
}
.mu-nut .bt { width: 22px; height: 22px; }

/* Avatar TRÒN — David chốt 02/09. Đặc hiệu phải cao hơn `.nut` (cùng một
   lớp, nên thứ tự trong tệp mới quyết định) — không thì nó ăn `border-radius`
   8px của `.nut` và ra một ô vuông bo góc. */
.thanh .mu-avatar { border-radius: 50%; position: relative; }
.mu-chu-dau { display: grid; place-items: center; width: 100%; height: 100%; }
.mu-chu-dau .bt { width: 22px; height: 22px; }
/* Trên mũ son, avatar đảo màu: nền trắng, chữ son. Đó là chỗ SÁNG NHẤT thanh
   tiêu đề — đúng vai của thứ người ta phải tìm thấy ngay. */
.thanh .mu-avatar.co-chu {
  background: #fff; color: var(--son);
  font-weight: 700; font-size: 14px; line-height: 1; letter-spacing: -.01em;
}

/* Chấm báo chưa đọc, nay nằm trên AVATAR chứ không trên cái chuông riêng.
   🪤 Viền cùng màu nền mũ để tách con số khỏi vòng tròn trắng bên dưới — thiếu
   nó thì trắng đè trắng và chấm báo tan vào avatar. */
/* Cùng con số ấy, nhưng nằm TRONG hàng "Thông báo" ở màn Tôi — nên phải gỡ
   `position: absolute` của luật gốc, không thì nó bay ra khỏi hàng. */
.chuong-so.trong-hang {
  position: static; display: inline-block; margin-left: 6px; border: 0;
  min-width: 18px; height: 18px; padding: 0 6px; border-radius: 999px;
  background: var(--son); color: #fff;
  font-size: 11px; font-weight: 700; line-height: 18px; text-align: center;
}

.thanh .mu-avatar .chuong-so {
  position: absolute; top: -2px; right: -2px;
  min-width: 18px; height: 18px; padding: 0 4px;
  border-radius: 999px; border: 2px solid var(--son);
  background: #fff; color: var(--son);
  font-size: 10.5px; font-weight: 700; line-height: 14px; text-align: center;
  font-variant-numeric: tabular-nums;
}

/* Tấm menu trượt từ TRÁI, vì nút mở nó nằm bên trái — tấm trượt từ phía khác
   là mất mối liên hệ giữa cái bấm và cái mở ra. */
.mu-lop { position: fixed; inset: 0; z-index: 60; background: rgba(33, 28, 22, .45); }
.mu-tam {
  width: min(310px, 84vw); height: 100%; overflow-y: auto;
  padding: calc(14px + env(safe-area-inset-top)) 12px 14px;
  background: var(--giay);
  box-shadow: 0 0 0 1px var(--vien), 12px 0 40px rgba(0, 0, 0, .18);
}
.mu-muc {
  display: flex; align-items: center; gap: 12px; width: 100%;
  padding: 13px 12px; border: 0; border-radius: var(--bo-nho);
  background: none; color: var(--muc); cursor: pointer; text-align: left;
  font: inherit; font-size: 15px; box-shadow: none;
}
.mu-muc:hover { background: var(--giay-sau); }
.mu-muc-hinh { width: 21px; height: 21px; flex: 0 0 auto; color: var(--muc-nhat); }
.mu-ngan { margin: 8px 12px; border: 0; border-top: 1px solid var(--vien); }

/*
 * NÚT — ba bậc, và mỗi bậc có đủ bốn trạng thái.
 *
 * Nút cũ chỉ khác nhau ở màu nền và đổi đúng một thứ khi rê chuột. Thiếu
 * trạng thái là thứ khiến giao diện "trông như bản nháp" mà khó gọi tên: mắt
 * người đọc độ nổi và độ lún để biết cái gì bấm được, và một mặt phẳng không
 * đổi thì đọc ra là hình vẽ, không phải nút.
 */
.nut {
  display: inline-flex; align-items: center; gap: 6px;
  font: inherit; font-size: 13px; font-weight: 500; line-height: 1;
  padding: 8px 12px; border-radius: var(--bo-nho);
  border: 1px solid var(--vien-dam);
  background: var(--giay-nang); color: var(--muc-dam);
  box-shadow: var(--bong-1);
  cursor: pointer; white-space: nowrap;
  transition: background .12s, border-color .12s, box-shadow .12s, transform .06s;
}
.nut:hover { background: var(--giay-sau); border-color: var(--muc-mo); color: var(--muc); }
.nut:active { transform: translateY(1px); box-shadow: none; }
.nut:focus-visible { outline: 2px solid var(--son); outline-offset: 2px; }
.nut .bt { width: 16px; height: 16px; }

/* Bậc CHÍNH: một hành động mỗi màn hình. Nhiều nút chính là không nút nào
   chính. Dốc màu rất nhẹ để mặt nút không phẳng lì. */
.nut-chinh {
  background: linear-gradient(180deg, var(--son-sang), var(--son));
  border-color: var(--son-toi); color: #fff;
  box-shadow: var(--bong-2);
}
.nut-chinh:hover {
  background: linear-gradient(180deg, var(--son), var(--son-toi));
  border-color: var(--son-toi); color: #fff;
}

/* Bậc NHẸ: hành động phụ, hoặc thứ có thể lùi lại được. */
.nut-nhe {
  background: transparent; border-color: transparent;
  box-shadow: none; color: var(--muc-nhat);
}
.nut-nhe:hover { background: var(--giay-sau); border-color: var(--vien); }

/* ---------- Ô tìm ---------- */

.o-tim { position: relative; width: min(420px, 100%); }
.o-tim input {
  width: 100%; font: inherit; font-size: 13.5px;
  padding: 8px 12px; border-radius: 999px;
  border: 1px solid var(--vien); background: var(--giay-sau); color: var(--muc);
}
.o-tim input:focus { outline: 2px solid var(--son); outline-offset: 1px; }

.kq-tim {
  position: absolute; top: calc(100% + 6px); left: 0; right: 0; z-index: 30;
  max-height: 60vh; overflow-y: auto;
  background: var(--giay); border: 1px solid var(--vien);
  border-radius: 12px; box-shadow: var(--bong); padding: 4px;
}
.kq-tim button {
  display: block; width: 100%; text-align: left; font: inherit;
  padding: 8px 10px; border: 0; border-radius: 8px;
  background: transparent; color: var(--muc); cursor: pointer;
}
.kq-tim button:hover { background: var(--giay-sau); }
.kq-tim .nho { font-size: 11.5px; color: var(--muc-nhat); }
.kq-tim .trong { padding: 10px; color: var(--muc-nhat); font-size: 13px; }

/* ---------- Khung vẽ ---------- */

.khung { position: fixed; inset: var(--cao-thanh) 0 var(--cao-duoi) var(--le-trai); }
#phado {
  width: 100%; height: 100%; display: block;
  touch-action: none;                 /* tự xử lý chạm–kéo–chụm */
  cursor: grab;
  /* 🪤 Nền chấm đã bỏ. Lưới chấm là ngôn ngữ của Figma và Miro — bảng vẽ vô
     tận, chưa có gì trên đó. Một cuốn gia phả thì ngược lại: nó là tờ giấy đã
     có chữ. Nền giấy phẳng, và cấu trúc do DẢI ĐỜI nói ra. */
  background: var(--giay);
}

/* Dải đời: xen kẽ hai sắc giấy rất nhạt. Đủ để mắt tách được hàng, không đủ
   để tranh chú ý với tên người. */
.dai-doi { fill: none; }
.dai-doi.le { fill: var(--giay-sau); }

.nhan-doi {
  font-family: var(--chu-de);
  font-size: 12.5px; font-weight: 700;
  fill: var(--son);
  letter-spacing: .06em;
  paint-order: stroke;
  stroke: var(--giay); stroke-width: 4; stroke-linejoin: round;
}
#phado.dang-keo { cursor: grabbing; }

/* Cạnh */
.canh { fill: none; stroke: var(--muc-mo); stroke-width: 1.4; }
.canh-vo-chong { stroke: var(--muc-nhat); stroke-width: 1.8; }
.canh-nuoi { stroke-dasharray: 4 3; }
.canh-phu { stroke: var(--son); stroke-dasharray: 2 4; marker-end: url(#mui-ten); }
.mui-ten { fill: var(--son); }

/* Thẻ người */
/* Ô người: nền GIẤY cho mọi người, không tô màu theo giới.
 *
 * 🪤 Xanh-trai / hồng-gái vừa sáo vừa KHÔNG phải quy ước của phả Việt — phả đồ
 * chép tay không tô màu theo giới bao giờ. Tệ hơn, tô nền màu làm tương phản
 * của chữ tụt xuống: chữ đen trên nền hồng nhạt đọc mệt hơn hẳn trên nền giấy.
 *
 * Giới tính chuyển thành VỆT MÉP TRÁI — đọc ra ngay, không đụng vào nền chữ. */
.the-nen { fill: var(--giay-nang); stroke: var(--vien-dam); stroke-width: 1.2; }
/* Ảnh nhỏ trong ô. Chữ đầu tên nằm DƯỚI ảnh chứ không thay ảnh: đường tải ảnh
   tự canh điều 7 nên có thể trả 404, và khi ấy ô vẫn phải có gì đó để đọc. */
.o-anh-nen { fill: var(--giay-sau); stroke: var(--vien-dam); stroke-width: 1; }
.o-anh-chu { font-size: 15px; font-weight: 700; fill: var(--muc-mo); text-anchor: middle; }
/* Dải băng tang vắt chéo góc trên phải ô người đã mất. Đen thật, không phải
   xám — dải băng tang không có sắc độ trung gian. */
.bang-tang { fill: #1A1613; stroke: none; }
.nguoi.an   .the-nen { fill: var(--giay-sau); stroke-dasharray: 5 3; stroke: var(--an); }
.nguoi.tam  .the-nen { stroke: var(--son); stroke-width: 2.4; }
.nguoi.chon .the-nen { stroke: var(--son); stroke-width: 2.4; }

.nguoi { cursor: pointer; }
.nguoi text { pointer-events: none; }
.ten  { font-size: 13px; font-weight: 700; fill: var(--muc); }
.ho   { font-size: 10.5px; fill: var(--muc-nhat); }
.nam-thang { font-size: 10px; fill: var(--muc-nhat); font-variant-numeric: tabular-nums; }

/* Giới tính bằng CHỮ, nghiêng và nhỏ. Một vệt màu bắt người ta học bảng chú
   dẫn rồi nhớ; chữ "(nam)" thì đọc là hiểu. */
.gioi { font-size: 9.5px; font-style: italic; fill: var(--muc-mo); }
/* Chấm "còn sống": viền giấy quanh chấm để nó tách khỏi mép ô, không lẫn vào
   đường bao. Không dùng viền chạy quanh cả ô nữa — xem lý do ở veNguoi(). */
.cham-song { fill: var(--song); stroke: var(--giay-nang); stroke-width: 1.6; }

.dai-chi { }
.cham-hon { fill: var(--muc-nhat); stroke: var(--giay); stroke-width: 1.5; }
.cham-hon.hai { fill: var(--son); }

.nut-bung {
  fill: var(--giay); stroke: var(--muc-mo); stroke-width: 1.2; cursor: pointer;
}
.nut-bung:hover { fill: var(--son-nhat); stroke: var(--son); }
.dau-bung { font-size: 12px; font-weight: 700; fill: var(--muc-nhat); pointer-events: none; }
.so-an { font-size: 10.5px; fill: var(--son); }

.dang-tai {
  position: absolute; top: 12px; left: 50%; transform: translateX(-50%);
  background: var(--muc); color: var(--giay); font-size: 12.5px;
  padding: 6px 14px; border-radius: 999px; z-index: 10;
}

/* ---------- Bảng chỉ dẫn ---------- */
/* Mở cây ra mà không biết bấm gì thì tấm phả đồ đẹp cũng vô dụng. Bảng này
   hiện ở lần mở đầu, tắt đi thì nhớ (localStorage), bấm "?" là mở lại. */
.chi-dan {
  position: absolute; left: 12px; bottom: calc(12px + env(safe-area-inset-bottom));
  width: min(370px, calc(100vw - 24px)); max-height: 62vh; overflow-y: auto;
  background: var(--giay); border: 1px solid var(--vien);
  border-radius: 12px; box-shadow: var(--bong); padding: 14px 16px; z-index: 15;
}
.chi-dan .dong {
  position: absolute; top: 2px; right: 4px;
  /* 🪤 Ô chạm tối thiểu 24px (WCAG 2.2 AA). Trước đây nút này cao 22px — vừa
     đủ để ngón tay bấm trượt ra ngoài bảng chỉ dẫn. */
  width: 32px; height: 32px; display: grid; place-items: center;
  font-size: 20px; line-height: 1; background: none; border: 0; padding: 0;
  color: var(--muc-nhat); cursor: pointer;
}
.chi-dan h2 {
  margin: 0 0 6px; font-size: 11px; text-transform: uppercase;
  letter-spacing: .07em; color: var(--muc-nhat); font-weight: 600;
}
.chi-dan h2 + * { margin-top: 0; }
.chi-dan .cach-dung {
  margin: 0 0 14px; padding-left: 17px; font-size: 13px; line-height: 1.55;
}
.chi-dan .cach-dung li { margin-bottom: 4px; }
.chi-dan .vd-nut {
  display: inline-block; min-width: 16px; text-align: center;
  border: 1px solid var(--muc-mo); border-radius: 50%; background: var(--giay-sau);
}
.chi-dan .phu { margin-top: 8px; font-style: italic; }

.chu-dan {
  display: flex; gap: 6px 12px; flex-wrap: wrap;
  font-size: 11.5px; color: var(--muc-nhat);
}

/* Thanh vai vế: nổi trên đầu khung vẽ, không đẩy cây dịch đi. */
.thanh-vai-ve {
  position: absolute; top: 12px; left: 50%; transform: translateX(-50%);
  z-index: 16; display: flex; align-items: center; gap: 12px;
  max-width: min(560px, calc(100vw - 24px));
  background: var(--giay); border: 1px solid var(--son);
  border-radius: 10px; box-shadow: var(--bong); padding: 9px 10px 9px 14px;
  font-size: 14px;
}
.thanh-vai-ve b { color: var(--son) }
.thanh-vai-ve .chua-chac {
  display: block; font-size: 11.5px; color: var(--muc-nhat); margin-top: 2px;
}
.chu-dan .oo {
  display: inline-block; width: 9px; height: 9px; border-radius: 2px;
  margin-right: 4px; vertical-align: -1px; border: 1px solid var(--vien);
}
/* Chú dẫn phải nói ĐÚNG thứ đang vẽ trên cây: giới tính là vệt mép trái,
   không phải nền tô màu. Chú dẫn lệch với bản vẽ còn tệ hơn không có. */
.oo.nam { background: var(--giay-nang); border-color: var(--vien-dam);
          border-left: 4px solid var(--nam); }
.oo.nu  { background: var(--giay-nang); border-color: var(--vien-dam);
          border-left: 4px solid var(--nu); }
.oo.song { background: var(--song); border-color: var(--song); border-radius: 50%;
           width: 10px; height: 10px; }
.oo.tang {
  background: var(--giay-nang); border-color: var(--vien-dam);
  background-image: linear-gradient(225deg, #1A1613 0 34%, transparent 34%);
}
.oo.an  { background: var(--giay-sau); border-style: dashed; border-color: var(--an); }
.oo.cham  { background: var(--muc-nhat); border-color: var(--muc-nhat); border-radius: 50%; }
.oo.cham2 { background: var(--son); border-color: var(--son); border-radius: 50%; }

/* Đang xem quanh ai — không có dòng này thì kéo vài cái là mất phương hướng. */
.dang-o { color: var(--son); font-weight: 600; }

/* ---------- Thẻ chi tiết ---------- */

/* 🪤 THẺ NGƯỜI PHẢI NẰM TRÊN CÁC BẢNG. Cả ba tấm (`the-nguoi`, `lich-gio`,
   `su-kien`) cùng lớp `.the` nên cùng z-index, và khi ấy THỨ TỰ TRONG DOM
   quyết định: `the-nguoi` khai trước nên bị hai bảng kia che. Mở một người từ
   lịch giỗ ra sẽ thấy… vẫn là lịch giỗ. */
#the-nguoi { z-index: 30; }

.the {
  position: fixed; z-index: 25; background: var(--giay);
  border: 1px solid var(--vien); box-shadow: var(--bong);
  overflow-y: auto;
}
/* Điện thoại: bottom-sheet */
@media (max-width: 720px) {
  .the {
    left: 0; right: 0; bottom: 0;

    /* 🔴 TRÀN HẲN LÊN TRÊN, CHE CẢ MŨ (David 02/09). Trước đây tấm dừng dưới
       thanh tiêu đề, nên trên màn 844px nó chỉ còn ~600px cho một thẻ người có
       ảnh, ba hàng quan hệ và danh sách con — vừa mở ra đã phải cuộn. Che luôn
       mũ thì được thêm gần một phần mười chiều cao, và không lẫn với nền phía
       sau nữa.
       Nút ✕ ở góc trên phải là đường thoát; bấm ra ngoài và phím Esc vẫn chạy. */
    top: 0;
    max-height: 100vh; max-height: 100dvh;
    border-radius: 0; padding: 14px 16px;
    padding-top: calc(14px + env(safe-area-inset-top));
    padding-bottom: calc(16px + env(safe-area-inset-bottom));
    z-index: 40;
  }
  #the-nguoi { z-index: 42; }
}
/* Máy tính: cột bên phải */
@media (min-width: 721px) {
  .the {
    top: calc(var(--cao-thanh) + 12px); right: 12px; bottom: 12px;
    width: 340px; border-radius: 14px; padding: 16px 18px;
  }
}
/* Lịch giỗ dùng chung khung thẻ nhưng rộng hơn: nó là một danh sách, không
   phải một hồ sơ. */
@media (min-width: 721px) {
  .the-rong { width: 420px; }
}
.chon-khoang { display: flex; gap: 6px; flex-wrap: wrap; margin: 10px 0 6px; }
.chon-khoang .nut { font-size: 12px; padding: 6px 9px; }
.chon-khoang .nut[aria-pressed="true"] {
  background: var(--son); border-color: var(--son); color: #fff;
}

.ngay-gio { display: flex; flex-direction: column; gap: 2px; margin: 0 0 4px; }
.mot-gio {
  display: grid; grid-template-columns: 62px minmax(0,1fr); gap: 10px;
  padding: 9px 0; border-bottom: 1px solid var(--vien); align-items: baseline;
}
.mot-gio .o-ngay {
  text-align: center; line-height: 1.15;
}
.mot-gio .o-ngay b { display: block; font-size: 18px; font-weight: 700; }
.mot-gio .o-ngay span { font-size: 10.5px; color: var(--muc-nhat); }
.mot-gio .ten-gio { font-size: 14.5px; font-weight: 600; }
.mot-gio button.ten-gio {
  background: none; border: 0; padding: 0; font: inherit; font-weight: 600;
  color: var(--muc); cursor: pointer; text-align: left;
}
.mot-gio button.ten-gio:hover { color: var(--son); }
.mot-gio .phu-gio { font-size: 12px; color: var(--muc-nhat); }
.mot-gio.sap-toi .o-ngay b { color: var(--son); }
.canh-bao-nhuan {
  display: inline-block; font-size: 11px; padding: 1px 6px; border-radius: 999px;
  background: var(--son-nhat); color: var(--son); margin-left: 6px;
}

.the .dong {
  position: absolute; top: 8px; right: 10px;
  font-size: 22px; line-height: 1; background: none; border: 0;
  color: var(--muc-nhat); cursor: pointer;
}
.the h2 { margin: 0 28px 2px 0; font-size: 18px; letter-spacing: -.01em; }
.the .duoi-ten { margin: 0 0 12px; font-size: 12.5px; color: var(--muc-nhat); }

.the .nhan {
  display: inline-block; font-size: 11px; padding: 2px 7px; border-radius: 999px;
  border: 1px solid var(--vien); background: var(--giay-sau); margin: 0 4px 4px 0;
}
.nhan.song { border-color: var(--song); color: var(--song); }
.nhan.chi  { border-color: var(--son); color: var(--son); }

.the dl { display: grid; grid-template-columns: 92px 1fr; gap: 5px 10px; margin: 12px 0; font-size: 13.5px; }
.the dt { color: var(--muc-nhat); }
.the dd { margin: 0; }

/* Chỉ đường bằng lời — thứ dùng được thật với mộ không có địa chỉ. */
.the .chi-duong {
  margin: 8px 0 0; padding: 9px 11px; font-size: 13.5px;
  background: var(--giay-sau); border-left: 3px solid var(--muc-mo);
  border-radius: 0 8px 8px 0; color: var(--muc);
}
.the .dia-chi { margin: 0; font-size: 14.5px; }
.the .phu { font-size: 12px; }

.canh-bao-rieng-tu {
  margin: 10px 0; padding: 9px 11px; font-size: 12.5px;
  background: var(--son-nhat); border-left: 3px solid var(--son); border-radius: 0 8px 8px 0;
  color: var(--muc);
}
@media (prefers-color-scheme: dark) { /* Chỉ đường bằng lời — thứ dùng được thật với mộ không có địa chỉ. */
.the .chi-duong {
  margin: 8px 0 0; padding: 9px 11px; font-size: 13.5px;
  background: var(--giay-sau); border-left: 3px solid var(--muc-mo);
  border-radius: 0 8px 8px 0; color: var(--muc);
}
.the .dia-chi { margin: 0; font-size: 14.5px; }
.the .phu { font-size: 12px; }

.canh-bao-rieng-tu { color: var(--muc); } }

.the .hang-nut { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 12px; }
.the .hang-sua {
  padding-top: 10px; margin-top: 10px; border-top: 1px dashed var(--vien);
}

/* Form sửa: nhãn nhỏ nằm trên ô nhập, ô nhập rộng hết cột — đọc nhanh trên
   điện thoại, và không phải căn hai cột. */
.form-sua { display: flex; flex-direction: column; gap: 10px; margin-top: 12px; }
.form-sua label { display: block; }
.form-sua .nhan-o {
  display: block; font-size: 11.5px; color: var(--muc-nhat); margin-bottom: 3px;
}
/* 🪤 Ô nhập để 14,5px là Safari iOS TỰ PHÓNG TO cả trang khi người ta bấm vào
   — ngưỡng của nó là 16px. Và ô cao 39px thì dưới mức bấm trúng ngay lần đầu.
   Cả app dùng 16px / ~48px; riêng khối này còn sót lại mức cũ, nên màn Quỹ
   trông lệch hẳn so với các form khác. */
.form-sua input[type="text"],
.form-sua input[type="number"],
.form-sua input[type="date"],
.form-sua input[type="tel"],
.form-sua input[type="email"],
.form-sua select,
.form-sua textarea {
  width: 100%; font: inherit; font-size: 16px;
  padding: 12px 14px; border-radius: var(--bo-nho);
  border: 1px solid var(--vien); background: var(--giay-sau); color: var(--muc);
}
.form-sua textarea { resize: vertical; }
.form-sua input:focus, .form-sua select:focus, .form-sua textarea:focus {
  outline: 2px solid var(--son); outline-offset: 1px;
}
.form-sua .o-co {
  display: flex; align-items: center; gap: 7px; font-size: 14.5px;
}
.form-sua .o-co input { width: auto; }

/* Danh sách thành viên và lời mời */
.ds-tv { list-style: none; margin: 8px 0 0; padding: 0; }
.ds-tv li {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 9px 0; border-bottom: 1px solid var(--vien);
}
.ds-tv .phu { font-size: 11.5px; }
.ds-tv .nhan { flex: 0 0 auto; }
.ds-tv .nho { color: var(--muc-nhat); font-size: 12px; }

/* Hồ sơ họ */
.di-tich {
  border: 1px solid var(--son); background: var(--son-nhat);
  border-radius: 8px; padding: 10px 12px; margin: 12px 0;
}
.di-tich a { font-size: 14px; font-weight: 600; }

/* Sự kiện của họ */
.mot-sk {
  padding: 12px 0; border-bottom: 1px solid var(--vien);
}
.mot-sk.da-qua { opacity: .6; }
.sk-dau { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.sk-dau b { font-size: 15px; }
.mot-sk .phu { font-size: 12px; margin: 3px 0 0; }
.mot-sk .hang-nut { margin-top: 8px; }
.mot-sk .nut { font-size: 12px; padding: 6px 9px; }
.ds-dule { margin-top: 8px; }

/* Sổ quỹ */
.tong-quy {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 1px;
  background: var(--vien); border: 1px solid var(--vien);
  border-radius: 10px; overflow: hidden; margin: 10px 0 14px;
}
/* 🪤 Ô số phải là CỘT. Bản đầu để mặc định nên nhãn và số dính liền thành
   "Đã thu0đ" — mắt đọc lướt qua thành một chữ vô nghĩa, mà không có lỗi nào
   báo vì cả hai phần tử đều đúng chỗ. */
.tong-quy > div {
  background: var(--giay); padding: 9px 11px;
  display: flex; flex-direction: column; gap: 2px;
}
.tong-quy .nhan-o { font-size: 11.5px; color: var(--muc-nhat); }
.tong-quy b { font-size: 15px; font-variant-numeric: tabular-nums; }
.tong-quy .thu { color: var(--song); }
.tong-quy .chi { color: var(--son); }

.mo-ghi { margin-bottom: 12px; }
.mo-ghi summary { cursor: pointer; font-size: 13.5px; color: var(--son); }

.ds-quy { list-style: none; margin: 0; padding: 0; }
.ds-quy li {
  display: grid; grid-template-columns: auto minmax(0,1fr) auto;
  gap: 10px; align-items: start;
  padding: 10px 0; border-bottom: 1px solid var(--vien);
}
.o-quy-tien {
  font-variant-numeric: tabular-nums; font-weight: 700; font-size: 14px;
  white-space: nowrap;
}
.o-quy-tien.thu { color: var(--song); }
.o-quy-tien.chi { color: var(--son); }
.o-quy-mo-ta .phu { font-size: 11.5px; }
/* Khoản đã bị đảo: gạch ngang số tiền, nhưng KHÔNG xoá khỏi sổ. */
.ds-quy li.da-dao .o-quy-tien { text-decoration: line-through; opacity: .55; }
.ds-quy li.but-dao { background: var(--giay-sau); }

/* Đường dẫn mời chỉ hiện MỘT LẦN nên phải bày thật rõ. */
.link-moi {
  border: 1px solid var(--son); background: var(--son-nhat);
  border-radius: 10px; padding: 12px 14px; margin-bottom: 14px;
}
.link-moi h3 { margin-top: 0; color: var(--son); }
.link-moi input {
  width: 100%; font: inherit; font-size: 13px; margin: 4px 0;
  padding: 8px 10px; border-radius: 8px;
  border: 1px solid var(--vien); background: var(--giay); color: var(--muc);
}
.the h3 { font-size: 12px; text-transform: uppercase; letter-spacing: .06em;
          color: var(--muc-nhat); margin: 14px 0 6px; font-weight: 600; }
.ds-nguoi { list-style: none; margin: 0; padding: 0; }
.ds-nguoi li { margin-bottom: 3px; }
.ds-nguoi button {
  font: inherit; font-size: 13.5px; background: none; border: 0; padding: 2px 0;
  color: var(--muc); cursor: pointer; text-align: left; border-bottom: 1px dotted var(--vien);
}
.ds-nguoi button:hover { color: var(--son); border-color: var(--son); }
.ds-nguoi .nho { color: var(--muc-nhat); font-size: 11.5px; }

/* ---------- Lớp mờ + đăng nhập ---------- */

.lop-mo {
  position: fixed; inset: 0; z-index: 40; display: grid; place-items: center;
  background: rgba(38,32,26,.42); backdrop-filter: blur(2px); padding: 16px;
}
.hop {
  width: min(400px, 100%); background: var(--giay); border-radius: 14px;
  border: 1px solid var(--vien); box-shadow: var(--bong);
  /* Đệm ĐỀU bốn phía. Thang của nhóm này: 24 ngoài · 20 giữa các khối ·
     16 giữa các hàng · 8 trong một hàng. */
  padding: 24px;
  max-height: 92vh; overflow-y: auto;
}
.hop h2 { margin: 0 0 4px; font-size: 19px; }

/* Đầu hộp: logo to, tiêu đề và lời dẫn CĂN GIỮA (David 02/09). Đây là màn đầu
   tiên người lạ nhìn thấy, nên dấu hiệu sản phẩm phải đủ to để nhận ra. */
/* 🔴 MỌI TẤM PHỦ PHẢI CÓ ĐƯỜNG THOÁT NHÌN THẤY ĐƯỢC. Trên điện thoại không có
   phím Esc, và người ta không đoán được là bấm ra nền tối thì đóng — không có
   nút này thì họ mắc kẹt trong hộp và thoát bằng cách tắt trình duyệt. */
.hop { position: relative; }
.hop-dong {
  position: absolute; top: 10px; right: 10px;
  width: 40px; height: 40px; display: grid; place-items: center;
  border: 0; border-radius: 20px; background: none; padding: 0;
  color: var(--muc-nhat); cursor: pointer;
}
.hop-dong:hover { background: var(--giay-sau); color: var(--muc); }

.hop-dau { text-align: center; margin-bottom: 20px; }
/* Dấu hiệu trong hộp đứng trên ĐĨA TRÒN TRẮNG, không thả trơn trên nền kem —
   thả trơn thì nó lẫn vào đúng cái dấu hiệu đang nằm trên thanh tiêu đề ngay
   phía sau tấm phủ. Đĩa trắng tách nó ra thành một vật riêng.
   🪤 Hình ĐẶC (fill), khác cả bộ biểu tượng của dự án vốn là hình NÉT
   (`.bt` đặt fill:none + stroke) — không khai riêng thì luật chung tô nó
   thành một khối bôi kín. */
.hop-dia {
  width: 88px; height: 88px; margin: 0 auto 14px;
  display: grid; place-items: center;
  background: #fff; border-radius: 50%;
  box-shadow: 0 1px 2px rgba(33,28,22,.06), 0 8px 20px -10px rgba(33,28,22,.35);
}
.hop-logo {
  width: 56px; height: 56px; display: block;
  color: var(--son); fill: currentColor; stroke: none;
}
.hop-dau h2 { margin: 0 0 6px; font-size: 22px; }
.hop-dau .phu { margin: 0; }

/* Nút chính rộng hết bề ngang VÀ cao 48px: một việc chính mỗi màn, và ngón
   tay bác bảy mươi tuổi phải bấm trúng ngay lần đầu. `.nut` gốc chỉ cao 31px —
   đủ cho nút phụ trong thanh công cụ, không đủ cho nút chính của một màn. */
.nut-suot {
  width: 100%; justify-content: center; margin-top: 16px;
  min-height: 48px; font-size: 15px;
}
.hop .nut-suot + .nut-suot { margin-top: 10px; }

/* Chữ nhỏ dưới cùng — đường phụ (đăng ký, quên mật khẩu, quay lại). */
.hop .doi-mat { text-align: center; margin-top: 16px; }

/* 🪤 `.lien` trước đây chỉ có kiểu trong ba ngữ cảnh riêng (.qt-ds, .la-toi,
   .dv-dau), nên trong hộp đăng nhập nó rơi về NÚT MẶC ĐỊNH của trình duyệt:
   viền xám, nền trắng, bo góc lạ — đứng cạnh nút son thì như của một phần mềm
   khác dán vào. Khai một luật chung, không phụ thuộc ngữ cảnh. */
.lien {
  border: 0; background: none; padding: 0; margin: 0;
  font: inherit; font-size: inherit; font-weight: 600;
  color: var(--son); cursor: pointer; text-decoration: underline;
  text-underline-offset: 2px;
}
.lien:hover { color: var(--son-toi); }
.hop .doi-mat .lien { font-size: 13px; }

/* Nút Hiện mật khẩu: gõ mật khẩu dài trên bàn phím điện thoại mà không nhìn
   được là nguồn gốc phần lớn lần "sai mật khẩu". */
.hop label { position: relative; }
.hien-mk {
  position: absolute; right: 8px; bottom: 10px;
  border: 0; background: none; cursor: pointer; padding: 4px 6px;
  font: inherit; font-size: 12px; font-weight: 600; color: var(--son);
}

/* Sáu ô mã, mỗi ô một chữ số. */
.o-ma-6 { display: flex; gap: 8px; margin-top: 6px; }
.o-ma-6 input {
  flex: 1 1 0; min-width: 0; width: auto;
  text-align: center; font-size: 22px; font-weight: 700;
  padding: 10px 0; font-variant-numeric: tabular-nums;
}
.ma-chan { display: flex; align-items: center; gap: 8px; margin-top: 16px; }
.ma-chan .phu { margin: 0; font-variant-numeric: tabular-nums; }
.ma-chan .nut { margin-left: auto; }
.ma-chan .nut[disabled] { opacity: .45; cursor: default; }
.hop label { display: block; margin: 16px 0 0; font-size: 12.5px; color: var(--muc-nhat); }
/* 🪤 PHẢI KHAI CẢ `select` VÀ `textarea`, KHÔNG CHỈ `input`. Thiếu chúng thì
   hai thẻ ấy rơi về mặc định trình duyệt: viền xám, chữ monospace, và vì là
   inline nên chúng NẰM CÙNG DÒNG với nhãn — nhãn "Loại" dính vào ô chọn, còn
   "Kể rõ hơn" tụt xuống dưới ô nhập. Một form trông như trang chưa ai làm
   xong, giữa những form khác đã đẹp. `.form-sua` và `.nhac-form` khai đủ ba
   thẻ từ đầu; chỉ `.hop` sót lại. */
.hop input, .hop select, .hop textarea {
  display: block;
  width: 100%; font: inherit; font-size: 16px; margin-top: 6px;
  padding: 12px 14px; border-radius: var(--bo-nho); border: 1px solid var(--vien);
  background: var(--giay-sau); color: var(--muc);
}
.hop textarea { resize: vertical; min-height: 96px; line-height: 1.5; }
.hop input:focus, .hop select:focus, .hop textarea:focus {
  outline: 2px solid var(--son); outline-offset: 1px; border-color: var(--son);
}
/* Ô tích không được ăn `width: 100%` — nó phình thành một khối rộng cả hộp và
   đẩy nhãn xuống dòng dưới. */
.hop input[type="checkbox"], .hop input[type="radio"] {
  display: inline-block; width: auto; margin: 0 8px 0 0;
}
.hop .hang-nut { display: flex; gap: 8px; justify-content: flex-end; margin-top: 16px; }
.loi { color: var(--son); font-size: 13px; margin: 10px 0 0; }

.bao {
  position: fixed; left: 50%; bottom: 24px; transform: translateX(-50%); z-index: 50;
  background: var(--muc); color: var(--giay); font-size: 13px;
  padding: 9px 16px; border-radius: 10px; max-width: 90vw;
}

@media (max-width: 720px) {
  /* Chiều cao do JS đo và ghi vào `--cao-thanh` — xem doThanhTren().
     Không đặt con số cứng ở đây: thanh cao bao nhiêu là tuỳ số nút và độ dài
     tên dòng họ. */
  .thanh { flex-wrap: wrap; height: auto; padding: 8px 10px; gap: 8px; }
  .thanh-trai { order: 1; flex: 1 1 auto; }

  /* 🪤 LUẬT CHẾT SAU KHI DỜI CHỖ. Trước đây ô tìm nằm TRONG thanh trên và
     `order: 3` đẩy nó xuống hàng dưới cùng — đúng lúc ấy. Dời ô tìm sang
     hàng 2 mà để nguyên luật cũ thì `order: 3` áp vào chỗ mới và đẩy ô tìm
     ra SAU mấy nút điều khiển: trên điện thoại hiện ra "⌂ − + ⛶  Tìm người",
     nút trước ô tìm sau. Không lỗi nào báo, và ở màn rộng thì không thấy.
     Đổi chỗ một phần tử thì phải soi lại mọi luật đang trỏ vào nó. */
  .thanh-hai .thanh-giua { order: 0; flex: 1 1 auto; }

  /* Hàng nút TRƯỢT NGANG thay vì xuống dòng hay bị cắt.
     🪤 Bản trước để `flex: 0 0 auto` nên nút cuối bị mép màn hình cắt cụt —
     ảnh chụp của David cho thấy "Cây củ…". Cho xuống dòng thì thanh trên cao
     ba hàng, ăn hết màn hình điện thoại. Trượt ngang giữ đúng một hàng và
     không nút nào biến mất. */
  .thanh-phai {
    order: 2;
    /* 🪤 Từng để `1 1 100%` để hàng nút xuống dòng riêng — hồi ấy có tám nút.
       Nay điều hướng đã chuyển xuống thanh dưới nên chỉ còn hai nút, mà luật
       cũ vẫn ép chúng chiếm trọn một hàng: mất một hàng của màn hình 844px
       cho hai cái nút. Co lại theo nội dung, vẫn trượt được nếu về sau dài ra. */
    flex: 0 1 auto;
    max-width: 100%;
    overflow-x: auto;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
    padding-bottom: 2px;
  }
  .thanh-phai::-webkit-scrollbar { display: none; }
  .thanh-phai > * { flex: 0 0 auto; }
  .thanh h1, .thanh-trai .phu { max-width: 100%; }
  .nut { padding: 7px 9px; }
  #nut-vua, #nut-goc { font-size: 12px; padding: 7px 8px; }
  /* Chỉ dẫn KHÔNG ẩn trên điện thoại: người cần nó nhất là người mở bằng
     điện thoại lần đầu. Chỉ thu gọn lại cho vừa. */
  .chi-dan { width: calc(100vw - 24px); max-height: 46vh; font-size: 13px; }
}


/* Đầu thẻ: ảnh bên trái, tên và nhãn bên phải.
   `align-items: start` để tên bám mép trên ảnh; căn giữa thì tên trôi xuống
   giữa khung và mất liên hệ với dòng đầu. */
.dau-the {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  margin-bottom: 10px;
}
.dau-the { align-items: center; }
.dau-chu { min-width: 0; flex: 1 1 auto; display: flex;
           flex-direction: column; gap: 8px; align-items: flex-start; }
.dau-the .duoi-ten { margin: 0; font-size: 14px; }
.hang-nhan { display: flex; flex-wrap: wrap; gap: 6px; }

/* Ảnh chân dung trong thẻ người.
   Khung 3:4 cố định và `object-fit: cover` để ảnh nào cũng vừa: người ta tải
   lên đủ kiểu tỉ lệ, và ảnh méo trong gia phả trông rất tệ. */
.chan-dung {
  display: block;
  width: 84px;
  aspect-ratio: 3 / 4;
  object-fit: cover;
  border-radius: 3px;
  border: 1px solid var(--vien);
  margin: 0;
  flex: 0 0 auto;
  background: var(--giay-sau);
}

/* Ảnh thờ của người đã mất là ảnh trắng đen — đúng lệ, không phải hiệu ứng. */
img.chan-dung.da-mat { filter: grayscale(1); }

/* Khung CHỜ SẴN khi chưa có ảnh.
   Không để trống: khung rỗng lặp ở mọi thẻ trông như lỗi in. Nó mang chữ đầu
   tên người ấy — đúng lối ảnh đại diện quen thuộc — nên đọc ra là "chưa có
   ảnh", không phải "hỏng". */
.chan-dung-trong {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  border-style: dashed;
  color: var(--muc-mo);
  user-select: none;
}

.chan-dung-trong .chu-dau {
  font-size: 30px;
  font-weight: 600;
  line-height: 1;
  color: var(--muc-mo);
}

/* Lời mời chỉ hiện khi người xem THẬT SỰ thêm được ảnh. Mời người không có
   quyền là mời họ bấm vào một nút máy chủ sẽ từ chối. */
.chan-dung-trong .moi {
  font-size: 11px;
  letter-spacing: .02em;
  color: var(--son);
}

.chan-dung-trong.moi-them {
  cursor: pointer;
  border-color: var(--son);
  background: var(--son-nhat);
}

.chan-dung-trong.moi-them:hover,
.chan-dung-trong.moi-them:focus-visible {
  border-style: solid;
}


/* Danh sách cạnh ghép cây. Mỗi mục là một quyết định của con người, không phải
   một dòng dữ liệu — nên để rộng và tách bạch, đừng nén thành bảng. */
.ds-ghep { list-style: none; padding: 0; margin: 0; }
.ds-ghep > li {
  padding: 10px 0;
  border-bottom: 1px solid var(--vien, #e6e1d9);
}
.ds-ghep > li:last-child { border-bottom: 0; }
.ds-gon { list-style: none; padding: 0; margin: 0 0 8px; }
.ds-gon > li { padding: 4px 0; }


/* Ô đồng ý cho chép nhánh. Để rộng và rõ: đây là người ta đang cho phép chép
   dữ liệu vợ con mình sang cây khác, không phải một tuỳ chọn hiển thị. */
.dong-chon {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 8px 0;
  font-size: 14px;
  color: var(--muc-nhat);
}
