/* Gốc Xanh — hệ giao diện sáng, một chủ đề cho toàn hệ thống. HAI MÀU theo ảnh mẫu, dùng ngang nhau: xanh dương hoàng gia + xanh bạc hà.
   Phần đầu trang / dải màu: khối xanh dương lớn (mang chữ trắng, ≤ #1570ef) chồng lên trường bạc hà, bo cong như ảnh, chỗ gặp nhau pha xanh trời,
   vòng tròn trắng trong mờ trên phần bạc hà; panel kính mờ trắng pha bạc hà trên dải màu; thẻ trắng bo 20–24px trên nền trang phối xanh dương / bạc hà.
   Nút chính viên thuốc xanh dương chữ trắng; nút phụ bạc hà chữ xanh đen; liên kết chữ xanh lá đậm; ô biểu tượng xanh dương / bạc hà xen kẽ;
   thanh điều hướng trắng, mục đang mở nền bạc hà. Màu trạng thái (--ok, --warn, --danger, --info) và màu cấp tin cậy là hệ riêng, luôn kèm chữ / biểu tượng.
   Mọi màu khai báo ở :root — các tệp daily/devices/env/ndvi/plausibility.css chỉ dùng biến. */

:root {
  color-scheme: light;
  /* nền trang và bề mặt */
  --bg: #eef6ff;
  --bg-2: #f4f9ff;
  --panel: #ffffff;
  --panel-2: #f3f8ff;
  --panel-3: #e4effd;
  --panel-solid: #ffffff;
  --tint: #e7f1ff;
  --tint-2: #e3f9ee;
  --glass: rgba(255, 255, 255, .72);
  --glass-strong: rgba(255, 255, 255, .96);
  --glass-line: rgba(255, 255, 255, .78);
  --glass-dark: rgba(10, 30, 90, .32);
  --glass-mint: linear-gradient(160deg, rgba(255, 255, 255, .84) 0%, rgba(240, 253, 246, .72) 100%);
  --field: #ffffff;
  --line: #dfeaf8;
  --line-2: #c9dbf2;
  /* chữ: xanh đen, phụ, mờ (đều ≥ 4.5:1 trên nền trang); --faint chỉ cho biểu tượng / trang trí */
  --text: #0f1b3d;
  --text-2: #3f4d6e;
  --muted: #515f7b;
  --faint: #7f8fb0;
  --placeholder: #7c8aa8;
  /* nhấn chính: xanh dương (chữ trắng trên nền nhấn ≥ 4.57:1) */
  --accent: #1268e0;
  --accent-2: #1062d8;
  --accent-text: #0f5bcc;
  --accent-rgb: 21, 112, 239;
  --accent-soft: #e6f0ff;
  --accent-line: #c2d7fb;
  /* nút chính: xanh dương, mọi điểm của nút (kể cả góc sáng #1570ef) cho chữ trắng ≥ 4.57:1; độ tươi đến từ viền sáng phía trên và quầng xanh dương bên dưới */
  --accent-grad: linear-gradient(135deg, #1570ef 0%, #1268e0 55%, #1062d8 100%);
  --on-accent: #ffffff;
  /* HAI MÀU THƯƠNG HIỆU (theo ảnh mẫu): xanh dương hoàng gia + xanh bạc hà, dùng ngang nhau; xanh trời chỉ là chỗ pha nơi hai khối gặp nhau.
     Chữ trắng CHỈ đặt trên xanh dương ≤ #1570ef (≥ 4.57:1). Xanh bạc hà luôn đi với chữ xanh đen (#0f1b3d trên #4cd98f: 9.3:1) — không bao giờ chữ trắng.
     Chữ / liên kết màu xanh lá trên nền trắng dùng --mint-text (#0d7040: 6.1:1). Màu trạng thái --ok* là màu riêng, không dùng cho trang trí. */
  --blue: #1570ef; --blue-2: #1062d8; --blue-bright: #1890ff; --blue-rgb: 21, 112, 239;
  --cyan: #18a8ff; --cyan-2: #60d8f0; --cyan-rgb: 24, 168, 255;
  --mint: #4cd98f; --mint-2: #48d890; --mint-hi: #7ee6b0; --mint-rgb: 76, 217, 143;
  --mint-soft: #dcf8e9; --mint-line: #aeeccb; --mint-text: #0d7040; --on-mint: #0f1b3d;
  --mint-grad: linear-gradient(135deg, #86e9b6 0%, #4cd98f 55%, #3fd0a6 100%);
  --link: var(--mint-text);
  /* tên cũ vẫn dùng trong các tệp tính năng */
  --green: var(--mint); --green-2: var(--mint-2); --green-rgb: var(--mint-rgb);
  --leaf: var(--mint); --leaf-rgb: var(--mint-rgb); --lime-rgb: var(--mint-rgb);
  --aqua-rgb: 44, 194, 208;
  --sky: var(--cyan); --sky-rgb: var(--cyan-rgb); --sky-soft: #e2f2ff;
  /* Khối màu lớn kiểu ảnh mẫu: khối xanh dương (mang chữ trắng, ≤ #1570ef ở mọi điểm) đặt chồng lên trường xanh bạc hà;
     mép khối xanh dương có quầng xanh trời (bóng mờ ra phía ngoài — không bao giờ nằm dưới chữ) nên chỗ gặp nhau pha màu như ảnh */
  --blue-shape: linear-gradient(160deg, #0f5fd4 0%, #1062d8 40%, #1268e0 80%, #1570ef 100%);
  --duo-glow: 0 0 0 9px rgba(var(--cyan-rgb), .3), 0 0 60px 26px rgba(var(--cyan-rgb), .55);
  --mint-field: radial-gradient(70% 60% at 100% 100%, rgba(96, 216, 240, .42), transparent 100%),
    linear-gradient(165deg, #6fe3a7 0%, #4cd98f 40%, #45d596 70%, #3fd0a6 100%);
  /* dải chữ trắng tràn cả khối (phiếu giao hàng…): chỉ xanh dương an toàn cho chữ, vòng tròn tối nhẹ ở góc */
  --hero-bg: radial-gradient(circle 120px at 100% 0%, rgba(8, 40, 120, .16) 99%, transparent 100%), radial-gradient(circle 60px at 0% 100%, rgba(8, 40, 120, .12) 99%, transparent 100%), var(--blue-shape);
  /* nền trang phối màu: một lớp cố định theo khung nhìn (body::before) nên trang dài cuộn vẫn giữ đủ các góc màu, kể cả trên iOS.
     Nửa trên xanh dương nhạt, nửa dưới bạc hà; góc trên trái và dưới phải bạc hà đậm hơn, góc trên phải xanh dương, hai vòng tròn lớn mờ nhắc lại khối màu của ảnh mẫu.
     Màu đậm nhất vẫn đủ sáng để chữ phụ --muted ≥ 4.5:1 ngay trên nền */
  --page-bg: radial-gradient(56% 40% at 50% 48%, rgba(255, 255, 255, .5), transparent 100%),
    radial-gradient(circle 300px at 104% 34%, rgba(var(--mint-rgb), .16) 99%, transparent 100%),
    radial-gradient(circle 220px at -6% 72%, rgba(var(--cyan-rgb), .1) 99%, transparent 100%),
    radial-gradient(80% 50% at 0% 0%, rgba(var(--mint-rgb), .3), rgba(var(--mint-rgb), .1) 55%, transparent 100%),
    radial-gradient(70% 46% at 100% 0%, rgba(var(--cyan-rgb), .22), rgba(24, 120, 240, .06) 55%, transparent 100%),
    radial-gradient(72% 48% at 0% 100%, rgba(var(--cyan-rgb), .16), transparent 100%),
    radial-gradient(84% 56% at 100% 100%, rgba(var(--mint-rgb), .34), rgba(var(--mint-rgb), .12) 55%, transparent 100%),
    linear-gradient(172deg, #e6f1ff 0%, #eaf6fb 40%, #e2f7eb 100%);
  --page-base: #e8f5f4;
  /* dải hai màu (ô biểu tượng emoji, trang trí): xanh dương → xanh trời → bạc hà — KHÔNG đặt chữ trắng lên */
  --brand-grad: linear-gradient(135deg, #1570ef 0%, #1890ff 38%, #2cc2d0 66%, #4cd98f 100%);
  /* ô tròn biểu tượng nét trắng (camera, đồng hồ…): nét trắng ≥ 3:1 ở mọi điểm; bản bạc hà dùng nét xanh đen */
  --icon-grad: linear-gradient(135deg, #1268e0 0%, #1a86fb 55%, #1996f0 100%);
  --icon-grad-mint: linear-gradient(135deg, #7ee6b0 0%, #4cd98f 60%, #3fd0a6 100%);
  /* khối rộng mà thấp có chữ trắng (thanh trên cùng, thẻ lô nổi bật): xanh dương an toàn dưới chữ; khối bạc hà lớn bo cong ở phía phải
     (viền trong xanh trời để hai khối pha vào nhau), vòng tròn trắng trong mờ chỉ nằm trên phần bạc hà */
  --brand-grad-x: linear-gradient(90deg, #0e5ccf 0%, #1062d8 35%, #1268e0 70%, #1570ef 100%);
  --hero-bg-x: var(--brand-grad-x);
  /* dải sáng không có chữ trắng (màn hình điện thoại minh họa): khối xanh dương góc trên trái chồng lên bạc hà, vòng tròn trắng trong mờ */
  --hero-bright: radial-gradient(circle 70px at 88% 26%, rgba(255, 255, 255, .24) 99%, transparent 100%), radial-gradient(circle 40px at 8% 78%, rgba(255, 255, 255, .2) 99%, transparent 100%),
    radial-gradient(ellipse 74% 58% at 0% 0%, #1570ef 0%, #1890ff 70%, #18a8ff 97%, transparent 100%),
    radial-gradient(ellipse 86% 70% at 0% 0%, rgba(var(--cyan-rgb), .9) 80%, rgba(var(--cyan-rgb), 0) 100%),
    var(--mint-field);
  --on-grad: #ffffff;
  --on-grad-2: #f3f7ff;
  --on-grad-hi: #8ef5bf;
  --grad-text-shadow: 0 1px 2px rgba(10, 30, 90, .28);
  /* ô biểu tượng: xanh dương nhạt / bạc hà xen kẽ (đủ đậm để thấy rõ hai màu) */
  --tile-bg: linear-gradient(160deg, #f2f7ff 0%, #d9e8ff 100%);
  --tile-bg-mint: linear-gradient(160deg, #eefcf4 0%, #c9f2dc 100%);
  --tile-line: #d3e3fa;
  --tile-line-mint: #b9ebd0;
  --progress-grad: linear-gradient(90deg, #18a8ff 0%, #2cc2d0 30%, #4cd98f 70%, #48d890 100%);
  /* trạng thái: màu nền, chữ, viền (chữ ≥ 4.5:1 trên nền tương ứng) */
  --ok: #16a34a; --ok-fg: #0f7a43; --ok-bg: #e6f7ee; --ok-line: #b5e5c9; --ok-grad: linear-gradient(135deg, #15803d 0%, #0f6b3a 100%);
  --warn: #b45309; --warn-fg: #8a5300; --warn-bg: #fff4db; --warn-line: #f1d38e;
  --danger: #c62828; --danger-fg: #b42318; --danger-bg: #fdecec; --danger-line: #f5c2c2;
  --info: #1d6fd8; --info-fg: #1d4ed8; --info-bg: #e8f0ff; --info-line: #c4d6fb;
  /* tên cũ vẫn được các trang dùng: trỏ về bảng màu sáng */
  --ink: var(--text);
  --ink-2: var(--text-2);
  --ink-3: var(--muted);
  --paper: #ffffff;
  --line-light: var(--line);
  --cream: var(--bg);
  --lime: var(--on-grad-hi);
  /* nhãn nguồn số liệu môi trường (env.css): ok = ký số / LoRaWAN, info = dịch vụ thời tiết / vệ tinh, plain = chưa ký số, self = tự khai */
  --src-ok-fg: #0f6b3a; --src-ok-bg: #e3f6ea; --src-ok-line: #a8dcb9;
  --src-info-fg: #1450a8; --src-info-bg: #e8f0ff; --src-info-line: #b8cff5;
  --src-plain-fg: #3f4d6e; --src-plain-bg: #f1f4fa; --src-plain-line: #d3dcec;
  --src-self-fg: #7a4a00; --src-self-bg: #fff4d9; --src-self-line: #dc9f2e;
  --src-card: #ffffff; --src-chip: #f4f7fe;
  /* thang màu dữ liệu NDVI (ndvi.css, ndvi.js đọc lại): cát → vàng → xanh lá đậm, độ sáng giảm đều (đọc được khi mù màu đỏ–lục) */
  --ndvi-c0: #ebd3b4; --ndvi-c1: #ebcf7a; --ndvi-c2: #b5ca4e; --ndvi-c3: #5fab42; --ndvi-c4: #257c3a; --ndvi-c5: #0c532f;
  --ndvi-water: #2d86c8; --ndvi-cloud: #d5dbe0; --ndvi-cloud-line: #6f7a84; --ndvi-grid-line: rgba(15, 27, 61, .13);
  /* biểu đồ (validate_palette --mode light): mưa, nhiệt, NDVI trên nền trắng #fff và nền thẻ QR #f5fbf8 —
     đạt dải sáng, độ bão hòa, mù màu (ΔE ≥ 9.5 cặp kề), tương phản ≥ 3:1 — kiểm lại trên #fff, #f5fbf8, #e6f6ed, #e5f3fb */
  --chart-rain: #2a78d6; --chart-temp: #e0602c; --chart-ndvi: #169a6b;
  --chart-grid: #e6edf8; --chart-axis: #c9d5ea; --chart-label: #1f2d4f;
  /* ô môi trường trong dòng thời gian hai luồng, khung điện thoại minh họa */
  --env-line: #9fc0f2;
  --device: #0b1430; --device-rim: #26324f;
  --r-xl: 32px;
  --r-lg: 24px;
  --r: 20px;
  --r-sm: 14px;
  --r-xs: 10px;
  --r-field: 16px;
  --shadow: 0 24px 50px -22px rgba(21, 94, 210, .34);
  --shadow-soft: 0 12px 30px -14px rgba(21, 112, 239, .26);
  --shadow-card: 0 1px 2px rgba(15, 27, 61, .04), 0 12px 30px -18px rgba(21, 112, 239, .24);
  /* nút chính: quầng xanh lá tươi phía dưới + viền sáng phía trên cho cảm giác bóng, tươi */
  --shadow-btn: 0 10px 22px -10px rgba(16, 98, 216, .6);
  --font: 'Be Vietnam Pro', system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', sans-serif;
  /* cấp độ tin cậy: chỉnh cho nền sáng — chữ màu cấp trên nền pha 10% đạt ≥ 4.9:1; luôn đi kèm số cấp / chữ.
     Cấp 3 màu mận (không dùng xanh ngọc) để không lẫn với cấp 4; cấp 4 xanh lá ngả ngọc để khác màu đỏ “vi phạm” cả khi mù màu đỏ–lục
     (validate_palette: bình thường ΔE ≥ 19 giữa các cấp kề; đỏ ↔ cấp 4 ΔE 8.5 deutan, kèm dấu “!” và chữ) */
  --lv-0: #56657f;
  --lv-1: #95560a;
  --lv-2: #1a5fc8;
  --lv-3: #9a3aa6;
  --lv-4: #0b7a5a;
  --lv-red: #b91c1c;
}

/* ============================================================================================
   HỆ KÍCH THƯỚC — MỘT THANG DUY NHẤT CHO CẢ HỆ THỐNG  (lấy điện thoại 320–430px làm gốc)
   Mọi tệp CSS tính năng (daily, delivery, devices, env, ndvi, entry, glossary, roadmap, zalo, anchor…)
   và mọi trang .ejs chỉ dùng các biến / lớp dưới đây — không đặt px tự do, không đặt style="font-size:…" trong view.
   Khối này CHỈ nói về kích thước – tỷ lệ – nhịp khoảng cách; màu vẫn ở khối :root phía trên (xanh dương + bạc hà).

   1) KHOẢNG CÁCH — 7 bậc: 4 · 6 · 8 · 12 · 16 · 20 · 24 (--sp4 … --sp24). Không dùng 2/5/7/9/10/14/18/22/26px nữa.
      khe trong chip/badge --sp4/--sp6 · nhãn → ô nhập --sp6 · khe giữa nút, chip, ô lưới --sp8 (--gap-grid)
      tiêu đề thẻ → nội dung --sp12 (--title-gap) · đệm trong thẻ --card-pad (16px ≤639px, 20px ≥640px)
      · thẻ lồng / dải thông báo / ô nhật ký --card-pad-dense (12px trên dưới, 16px hai bên) · ô số liệu nhỏ --sp12 đều bốn phía
      khoảng cách giữa hai thẻ --gap-card (16px) · giữa hai khối lớn --gap-block (24px) · lề trang 16px (.container, giữ nguyên).
   2) CHỮ — ĐÚNG 6 BẬC (thang 13 · 15,2 · 17,4 · 20 · 24 · 30 ở cỡ “Thường”, tỉ lệ 1,14–1,25 giữa hai bậc liền nhau).
      Trước đây cả hệ thống có 61 cỡ chữ khác nhau, 52 cặp cách nhau dưới 0,5px — mắt không thấy cấp bậc, chỉ thấy lộn xộn.
      Nay mỗi bậc phải cách bậc dưới ít nhất một bậc rõ; muốn phân biệt “chính / phụ” thì đổi MÀU và ĐỘ ĐẬM, KHÔNG đổi cỡ.
      ĐỢT “gọn hơn, chuyên nghiệp hơn” ĐÃ HẠ CẢ THANG MỘT BẬC: 15,5→15,2 · 18→17,4 · 22→20 · 27→24 · 33→30.
      Bậc 1 giữ 13px vì đã ở SÀN. Hai sàn không bao giờ được vượt: thân bài ≥15px, chữ phụ ≥13px (cỡ “Thường”),
      và chiều cao ô bấm ≥44px KHÔNG đi theo cỡ chữ.
      Bậc 6  --fs-hero    30→57,6px/700 CHỈ dòng tiêu đề lớn của trang chủ “/” (.hero-title) — một chỗ duy nhất trong cả hệ thống.
      Bậc 5  --fs-display 24→39px/700   tiêu đề trang tiếp thị / trang đứng một mình: /huong-dan · /tra-cuu (.hero-title-sm),
                                        /dang-nhap · /dang-ky (.auth-box h1), trang lỗi (.err-page h1).
             --fs-section 24→30,4px/700 tiêu đề mục của trang tiếp thị / trang chữ dài (.section-head h2, .section-h2, .prose h1).
             --fs-stat    24px/600      CON SỐ lớn (.stat-num, .nm-big…). Ba biến này cùng một bậc trên điện thoại,
                                        chỉ nở khác nhau trên màn rộng. Trong khu làm việc (/app, /admin) KHÔNG dùng bậc này cho CHỮ.
      Bậc 4  --fs-page    20→22px/600   tiêu đề trang — h1 của MỌI trang, kể cả /app/viec (.ex-h1) và tiêu đề hộp thoại (.ex-sh-title);
                                        và đoạn dẫn dưới tiêu đề lớn (.hero-lead, .section-head p). Không mở bậc 18px riêng.
      Bậc 3  --fs-h2      17,4px/600    tiêu đề thẻ (.card-title h2, .section-title, .dl-h2…).
                                        KHÔNG dùng cho tên món trong danh sách: TÊN VIỆC (.ex-task-t b) là --fs-body đậm —
                                        một dòng trong danh sách không được cùng bậc với tiêu đề của mục chứa nó.
      Bậc 2  --fs-body    15,2px/400    chữ thân bài (body) VÀ chữ trên mọi nút (.btn, .ex-btn, .ex-go…),
                                        và tên món trong danh sách (đậm 600–700 để nổi, không to hơn).
                                        SÀN: không bao giờ dưới 15px ở cỡ “Thường” — người lớn tuổi phải đọc được.
      Bậc 1  --fs-sm      13px          dòng phụ, nhãn trường, chip, badge chữ, .small, .hint
             --fs-xs      13px/600      nhãn ô lưới, số đếm, chú thích, .tiny — CÙNG một bậc với --fs-sm,
                                        khác nhau ở màu (--muted) và độ đậm, không ở cỡ. SÀN: không dưới 13px.
      Ai cần chữ to hơn đã có sẵn mục “Lớn” và “Rất lớn” trong Tuỳ chọn (public/css/prefs.css) — cả thang nhân lên theo,
      giữ nguyên tỉ lệ 6 bậc. Mục “Nhỏ” hạ cả thang xuống nhưng không bao giờ đụng tới chiều cao ô bấm.
      NGOẠI LỆ CÓ CHỦ Ý — không phải bậc mới, chỉ là bù theo nét chữ / theo ô:
        ô nhập chữ (input, textarea, select, .ex-text, .ex-numin input) = tối thiểu 16px — dưới 16px iOS Safari
        tự phóng to cả trang khi đặt con trỏ vào ô, người dùng phải chụm tay thu lại; đây là ràng buộc của máy, không phải bậc chữ;
        code, .mono = .88em của chữ xung quanh (chữ đơn cách rộng hơn nên phải nhỏ lại để cùng cao quang học);
        emoji trong ô = --fs-emoji* (mục 4) — là cỡ Ô BIỂU TƯỢNG, không phải cỡ chữ;
        <option> của <select> và chữ trong <svg> do trình duyệt / bản vẽ quyết định;
        .phone-screen (ảnh minh họa một màn hình điện thoại thu nhỏ trong trang chủ) là một BẢN VẼ theo tỉ lệ máy thật,
        chữ trong đó là nét vẽ chứ không phải chữ để đọc — giữ px riêng, không tính vào thang.
   3) VÙNG CHẠM — 4 chiều cao, hết: chip / nút nhỏ 44px (--h-chip) · nút thường và ô nhập 48px (--h-btn, --h-field)
      · nút lớn 54px (--h-btn-lg) · nút biểu tượng tròn 48px. Trên máy tính sàn là 40px để các nút cùng hàng thẳng nhau.
      Nhãn vỡ hai dòng KHÔNG được sinh bậc mới: đệm dọc của nút trải hàng / nút trong lưới là --sp4 nên vẫn rơi vào 44/48/54.
      NGOẠI LỆ CÓ CHỦ Ý — ba thứ, hết, đã đo và chốt; lần đo sau KHÔNG đếm lại:
        (a) <summary> của <details> là một DÒNG CHỮ bấm được, không phải nút — cao tối thiểu --h-btn
            và nở thêm khi nhãn dài xuống 2 dòng (cắt chữ để ép 48px sẽ mất nghĩa);
        (b) a.term — thuật ngữ gạch chân NẰM GIỮA DÒNG VĂN (public/css/glossary.css). Cao 27,7–33,9px theo
            cỡ chữ. Không nâng lên 44px được: một dòng văn có 3–4 thuật ngữ thì vùng chạm 44px sẽ chồng lên nhau
            và lên cả dòng trên / dòng dưới, bấm vào chữ thường lại mở chú giải. Ai không trúng vẫn còn trang
            /thuat-ngu tra được đủ;
        (c) <input type="checkbox"> và <input type="radio"> — ô vẽ 24px do trình duyệt quyết định;
            vùng chạm thật là cả <label> bọc ngoài (.chip, .ex-chip, .qi-mark…) và cái đó ≥44px;
        (d) <label for="…"> ĐỨNG TRÊN một ô nhập — là một dòng CHỮ (20px), không phải nút.
            Ô bấm thật là chính ô nhập ngay dưới nó (48px). Nâng nhãn lên 44px chỉ làm biểu mẫu dài thêm
            mà không thêm chỗ bấm nào.
   4) BIỂU TƯỢNG — 3 cỡ ô: 40px (--ico-sm, đứng cạnh một dòng chữ) · 52px (--ico, ô trong lưới / thẻ lô) · 64px (--ico-lg, đầu trang).
      Emoji ăn theo ô: 1,15rem trong dòng chữ (--fs-emoji-inline) · 1,75rem trong ô 40–52px (--fs-emoji) · 2rem trong ô 64px (--fs-emoji-lg).
      Biểu tượng nét (.i 20px, .i-sm 16px, .i-lg 26px) giữ nguyên.
   5) Ô LƯỚI (tiles) — điện thoại LUÔN 4 cột chẵn (hoặc đặt --cols cho khớp số ô: 3 ô → --cols:3, 5 ô → --cols:5…),
      gap --gap-grid, mọi hàng cao bằng nhau (grid-auto-rows: 1fr), nhãn kẹp 2 dòng (.tile-name).
      BỀ RỘNG Ô KHÔNG PHỤ THUỘC SỐ Ô: --tile-w tính theo bề rộng THẺ trên cơ sở 4 cột, nên thẻ 3 ô và thẻ 8 ô
      nằm cạnh nhau vẫn có ô bằng nhau; số cột chỉ quyết định hàng nào có mấy ô. Máy tính: ô không nở quá --tile-max-w (120px).
      Chiều cao ô: --tile-min-h 100px cho .tile của app.css; ô việc hằng ngày .dl-tile cố tình thấp hơn (88px, xem daily.css)
      vì một thẻ lô có tới 8 ô và phải nhìn thấy trọn thẻ trên một màn điện thoại.
   6) HÀNG NÚT / CHIP — hai khuôn, không có khuôn thứ ba:
      (a) .btn-grid — lưới 2 cột ô bằng nhau, món lẻ cuối trải hết hàng (.btn-grid > :last-child:nth-child(odd));
      (b) .scroll-row — một dải cuộn ngang (thanh lọc, dải ngày).
      Cấm flex-wrap thuần cho hàng nút/chip (sinh ra dòng cuối trơ một món).
   7) THẺ — đệm --card-pad, bo --r-lg (24px) cho thẻ ngoài, --r (20px) cho thẻ lồng (.card-2, .tl-body, .dl-lot bên trong một thẻ),
      --r-tile (18px) cho ô lưới / ô biểu tượng, --r-field (16px) cho ô nhập, 999px cho viên thuốc. Không lồng .card trong .card quá một bậc.
   8) DÒNG PHỤ — .meta-line: tối đa 2 dòng trên điện thoại, phân cách bằng “·”; mục ít giá trị nhất đánh .meta-drop để ẩn ở ≤430px.
   9) VIỆC ÍT DÙNG — gập vào <details class="fold"> thay vì xếp một bức tường nút giống nhau.
  10) MÀN RỘNG — khối thẻ độc lập dùng .flow (thay .stack): app.js đo bề ngang THẬT của khối và chia cột sao cho
      mỗi cột ≥ 300px (máy tính bảng 768px đã có 2 cột), thẻ ngắn TRÔI LÊN lấp chỗ trống; .flow-3 cho tối đa 3 cột.
      Cột của từng thẻ cố định nên mở / đóng <details> không làm thẻ nhảy cột. Thẻ phải chiếm trọn bề ngang
      (đầu trang, cảnh báo, bảng rộng, dòng thời gian, bản đồ, trang in) đặt NGOÀI .flow (phía trên hoặc phía dưới).
      Bố cục điện thoại không đổi.
  11) BẤT BIẾN — 320–430px: không tràn ngang, vùng chạm ≥44px, chữ trên ảnh, thanh nút dưới chia đều trong lề, không gì bị che hay cắt.
   ============================================================================================ */
:root {
  /* khoảng cách */
  --sp4: 4px; --sp6: 6px; --sp8: 8px; --sp12: 12px; --sp16: 16px; --sp20: 20px; --sp24: 24px;
  --gap-grid: var(--sp8);
  --gap-card: var(--sp16);
  --gap-block: var(--sp24);
  --title-gap: var(--sp12);
  --card-pad: var(--sp16);
  --card-pad-dense: var(--sp12) var(--sp16);
  /* chữ — thang HẠ MỘT BẬC so với bản trước (13 · 15,5 · 18 · 22 · 27 · 33 → 13 · 15,2 · 17,4 · 20 · 24 · 30).
     Lý do: trên điện thoại tiêu đề 22px và tên việc 18px đọc ra “to và tràn”; trang trông như bản thử,
     không như một sản phẩm. Hạ một bậc thì cùng một màn thấy nhiều việc hơn và khối chữ rộng hơn
     nên bớt vỡ dòng. SÀN KHÔNG ĐỔI: thân bài ≥15px, chữ phụ ≥13px, ô bấm ≥44px. Ai cần to hơn
     đã có “Lớn” (17,4px thân bài) và “Rất lớn” (19,4px) trong Tuỳ chọn. */
  --fs-hero: clamp(1.875rem, 5.1vw, 3.6rem);
  --fs-display: clamp(1.5rem, .93rem + 1.87vw, 2.44rem);
  --fs-section: clamp(1.5rem, 1.2rem + .98vw, 1.9rem);
  --fs-page: clamp(1.25rem, 1.1rem + .47vw, 1.375rem);
  --fs-h2: 1.09rem;
  --fs-body: .95rem;
  --fs-sm: .8125rem;
  --fs-xs: .8125rem;
  --fs-stat: 1.5rem;
  /* vùng chạm */
  --h-chip: 44px;
  --h-btn: 48px;
  --h-btn-lg: 54px;
  --h-field: 48px;
  --h-tap-desktop: 40px;
  /* ô biểu tượng + emoji */
  --ico-sm: 40px; --ico: 52px; --ico-lg: 64px;
  --fs-emoji-inline: 1.15rem; --fs-emoji: 1.75rem; --fs-emoji-lg: 2rem;
  /* ô lưới */
  --tile-min-h: 100px; --tile-max-w: 120px;
  /* bo góc ô lưới / ô biểu tượng (thẻ dùng --r-lg, thẻ lồng --r, ô nhập --r-field) */
  --r-tile: 18px;
}
@media (min-width: 640px) { :root { --card-pad: var(--sp20); } }

/* Hàng nút / chip: lưới ô bằng nhau, món lẻ cuối trải hết hàng (khuôn của .lot-actions và .dl-more-list, nâng lên dùng chung) */
.btn-grid { display: grid; grid-template-columns: repeat(var(--cols, 2), minmax(0, 1fr)); gap: var(--gap-grid); align-items: stretch; grid-auto-rows: 1fr; }
.btn-grid > * { width: 100%; min-width: 0; }
.btn-grid > :last-child:nth-child(odd) { grid-column: 1 / -1; }
.btn-grid :is(.btn, .chip) { white-space: normal; text-align: center; line-height: 1.25; padding-inline: var(--sp12); }
/* Hàng cuộn ngang: thanh lọc, dải ngày, dải chip dài — luôn một hàng, không bao giờ xuống dòng lởm chởm */
.scroll-row { display: flex; gap: var(--gap-grid); overflow-x: auto; overscroll-behavior-x: contain; scrollbar-width: none; scroll-snap-type: x proximity; scroll-padding-inline: var(--sp16); padding-bottom: var(--sp4); }
.scroll-row::-webkit-scrollbar { display: none; }
.scroll-row > * { flex: none; scroll-snap-align: center; }
/* Dòng phụ dưới tiêu đề: dấu “·” nằm trong khe, mục nào rơi xuống dòng thì dấu bị cắt đi (không lơ lửng đầu dòng) */
.meta-line { display: flex; flex-wrap: wrap; gap: var(--sp4) var(--sp16); font-size: var(--fs-sm); color: var(--muted); overflow: hidden; min-width: 0; }
.meta-line > * { position: relative; min-width: 0; }
.meta-line > * + *::before { content: '·'; position: absolute; left: -10px; }
@media (max-width: 430px) { .meta-line > .meta-drop { display: none; } }
/* Nhãn ô lưới: kẹp 2 dòng để mọi ô cao bằng nhau (màn rất hẹp cho 3 dòng); thẻ bọc vẫn có title=… nên đọc được đủ chữ */
.tile-name { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2; overflow: hidden; overflow-wrap: anywhere; }
/* Điện thoại: cho nhãn 3 dòng. Ở bậc chữ mới nhãn ô lưới là 13px (bằng chữ phụ), kẹp 2 dòng thì
   “Đóng gói & in tem”, “Điểm nhận đã nhận”, “Hồ sơ trường học” bị CẮT MẤT chữ trong ô rộng 58–73px. */
@media (max-width: 430px) { .tile-name { -webkit-line-clamp: 3; line-clamp: 3; } }
/* Màn rộng: các thẻ độc lập tự trôi lên lấp chỗ trống thay vì để một cột dài cạnh khoảng trắng.
   Dùng THAY .stack ở khối thẻ ngoài cùng; thứ tự đọc (và tab) vẫn là thứ tự trong HTML, thẻ không bị cắt đôi giữa hai cột. */
.flow { display: flex; flex-direction: column; gap: var(--gap-card); }
/* Bản không có JS (hoặc trước khi app.js chạy): chia cột sẵn có của trình duyệt — vẫn trôi lên, chỉ kém ổn định khi mở <details>. */
@media (min-width: 1024px) {
  .flow:not(.flow-grid), .stack.flow:not(.flow-grid), .grid.flow:not(.flow-grid) { display: block; columns: 2; column-gap: var(--gap-card); }
  .flow:not(.flow-grid) > * { break-inside: avoid; -webkit-column-break-inside: avoid; margin: 0 0 var(--gap-card); }
  .flow:not(.flow-grid) > :last-child { margin-bottom: 0; }
}
@media (min-width: 1400px) { .flow-3:not(.flow-grid), .stack.flow-3:not(.flow-grid) { columns: 3; } }
/* Bản có JS (app.js đặt lớp .flow-grid, --flow-cols, grid-column và grid-row cho từng thẻ):
   lưới masonry — CỘT của mỗi thẻ cố định theo bề rộng màn hình, nên mở / đóng một mục gập chỉ đẩy các thẻ
   phía dưới CÙNG cột, thẻ không bao giờ nhảy sang cột khác. Số cột do JS tính theo bề ngang thật của khối
   (mỗi cột ≥ 300px) nên máy tính bảng 768px cũng có 2 cột, còn điện thoại vẫn một cột như cũ. */
.flow.flow-grid { display: grid; grid-template-columns: repeat(var(--flow-cols, 2), minmax(0, 1fr));
  column-gap: var(--gap-card); row-gap: 0; grid-auto-rows: 1px; grid-auto-flow: row dense; align-items: start; }
.flow.flow-grid > * { margin: 0; align-self: start; break-inside: auto; }
/* Lưới ô nằm trong một thẻ HẸP (thẻ minh họa trang chủ): số cột đã ấn định bằng --cols-lg nên bỏ sàn 104px,
   ô co theo bề ngang thẻ thay vì đẩy thẻ tràn ngang ở 768px. */
@media (min-width: 640px) { .tiles.tiles-fit { grid-template-columns: repeat(var(--cols-lg, 4), minmax(0, 1fr)); } }
/* Bổ sung (nhóm công khai + quản trị): khối vốn đã là lưới .grid-2/3/4 thì GIỮ lưới ở 640–1023px (máy tính bảng chưa có
   thanh bên, một cột sẽ rộng gần 1000px — quá rộng cho một thẻ nhỏ), từ 1024px mới đổi sang cột .flow để thẻ ngắn trôi lên. */
@media (min-width: 1024px) { :is(.grid-2, .grid-3, .grid-4).flow:not(.flow-grid) { display: block; columns: 2; column-gap: var(--gap-card); } }
@media (min-width: 1400px) { :is(.grid-2, .grid-3, .grid-4).flow-3:not(.flow-grid) { columns: 3; } }

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body { margin: 0; font-family: var(--font); font-size: var(--fs-body); line-height: 1.55; color: var(--text); background: var(--bg); -webkit-font-smoothing: antialiased; }
/* nền phối màu: lớp cố định bằng khung nhìn nằm dưới mọi nội dung (position: fixed chạy cả trên iOS, khác background-attachment: fixed) —
   trang dài cuộn tới đâu cũng thấy đủ các góc màu, không bị kéo giãn theo chiều cao trang */
:is(body.app, body.site, body.trace, body.auth-page) { background: var(--page-base); }
:is(body.app, body.site, body.trace, body.auth-page)::before { content: ''; position: fixed; left: 0; top: 0; width: 100%; height: 100vh; height: 100lvh; z-index: -1; pointer-events: none; background: var(--page-bg); }
img, svg { max-width: 100%; }
a { color: inherit; }
h1, h2, h3, h4 { margin: 0 0 .4em; line-height: 1.2; font-weight: 600; letter-spacing: -.01em; }
/* quy tắc 2: KHÔNG h1/h2 nào rơi về cỡ mặc định của trình duyệt (2em / 1.5em) — mỗi thẻ đều nằm đúng một bậc của thang */
h1 { font-size: var(--fs-page); }
h2, h3 { font-size: var(--fs-h2); }
h4 { font-size: var(--fs-body); }
p { margin: 0 0 .8em; }
code, .mono { font-family: ui-monospace, 'SF Mono', Menlo, Consolas, monospace; font-size: .88em; overflow-wrap: anywhere; }
hr { border: 0; border-top: 1px solid var(--line); margin: 20px 0; }
.i { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; flex: none; vertical-align: middle; }
.i-sm { width: 16px; height: 16px; }
.i-lg { width: 26px; height: 26px; }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
.muted { color: var(--muted); }
.small { font-size: var(--fs-sm); }
.tiny { font-size: var(--fs-xs); }
.center { text-align: center; }
.nowrap { white-space: nowrap; }
.hidden { display: none !important; }
.mt-0 { margin-top: 0 } .mt-1 { margin-top: 8px } .mt-2 { margin-top: 16px } .mt-3 { margin-top: 24px } .mt-4 { margin-top: 40px }
.mb-0 { margin-bottom: 0 } .mb-1 { margin-bottom: 8px } .mb-2 { margin-bottom: 16px } .mb-3 { margin-bottom: 24px }
.c-danger { color: var(--danger); }
.c-warn { color: var(--warn); }
.c-accent { color: var(--accent-text); }

/* ---------- Bố cục ---------- */
.container { width: 100%; max-width: 1180px; margin: 0 auto; padding: 0 16px; }
/* Điện thoại: lề hai bên rộng hơn một chút cho thoáng và đều nhau */
@media (max-width: 560px) { .container { padding: 0 20px; } }
.stack { display: flex; flex-direction: column; gap: var(--gap-card); }
.row { display: flex; align-items: center; gap: var(--gap-grid); flex-wrap: wrap; }
.row-between { display: flex; align-items: center; justify-content: space-between; gap: var(--sp12); flex-wrap: wrap; }
.grow { flex: 1; min-width: 0; }
.grid { display: grid; gap: var(--gap-card); }
.grid-2, .grid-3, .grid-4 { display: grid; gap: var(--gap-card); grid-template-columns: minmax(0, 1fr); }
/* ô lưới được co nhỏ hơn nội dung (dải cuộn ngang, bảng…) — không đẩy cả trang tràn ngang */
:is(.grid-2, .grid-3, .grid-4, .grid) > * { min-width: 0; }
@media (min-width: 640px) { .grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); } .grid-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); } .grid-3 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 960px) { .grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); } .grid-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
/* Cột chính + cột phụ (tỉ lệ riêng từng trang qua --cols): điện thoại xếp một cột, không ép cột chính còn vài chục px */
.grid-side { grid-template-columns: minmax(0, 1fr); }
@media (min-width: 640px) { .grid-side { grid-template-columns: var(--cols, minmax(0, 1.6fr) minmax(280px, 1fr)); } }

/* ---------- Nút: chính = viên thuốc xanh dương chữ trắng; phụ = viên thuốc bạc hà chữ xanh đen; mặc định = trắng chữ xanh dương ---------- */
.btn { display: inline-flex; align-items: center; justify-content: center; gap: var(--sp8); min-height: var(--h-btn); padding: var(--sp12) var(--sp20); border-radius: 999px; border: 1px solid var(--accent-line);
  font: 600 var(--fs-body)/1.2 var(--font); text-decoration: none; cursor: pointer; transition: transform .12s ease, filter .15s ease, background .15s ease, border-color .15s ease, box-shadow .15s ease; white-space: nowrap;
  color: var(--accent-text); background: var(--panel); box-shadow: 0 1px 2px rgba(15, 27, 61, .05); }
.btn:hover { border-color: var(--accent); }
.btn:active { transform: scale(.97); }
.btn:focus-visible, a:focus-visible, input:focus-visible, select:focus-visible, textarea:focus-visible, summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.btn-primary { background: var(--accent-grad); color: var(--on-accent); border-color: transparent; box-shadow: var(--shadow-btn), inset 0 1px 0 rgba(255, 255, 255, .3), inset 0 -2px 6px rgba(8, 40, 120, .2); }
/* nút bạc hà: hành động thứ hai bên cạnh nút chính, chữ xanh đen (≥ 8.6:1 ở mọi điểm của dải) — như nút xanh lá của ảnh mẫu */
.btn-mint, .btn-sage, .btn-onleaf { background: var(--mint-grad); color: var(--on-mint); border-color: rgba(255, 255, 255, .6); box-shadow: 0 10px 22px -12px rgba(18, 129, 74, .6), inset 0 1px 0 rgba(255, 255, 255, .55); }
.btn-primary:hover, .btn-mint:hover, .btn-sage:hover, .btn-onleaf:hover { filter: brightness(1.05); border-color: rgba(255, 255, 255, .6); }
.btn-primary:hover { border-color: transparent; }
.btn-glass { background: var(--glass); border-color: var(--line); color: var(--accent-text); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); }
/* nút trắng nổi (trên dải màu hoặc thẻ nhạt) */
.btn-light, .btn-lime { background: var(--panel); color: var(--accent-text); border-color: transparent; box-shadow: var(--shadow-soft); }
.btn-outline { background: transparent; border-color: var(--line-2); color: var(--text); }
.btn-danger { background: var(--danger-bg); color: var(--danger-fg); border-color: var(--danger-line); }
.btn-danger:hover { border-color: var(--danger); }
.btn-sm { min-height: var(--h-tap-desktop); padding: var(--sp6) var(--sp12); font-size: var(--fs-sm); }
.btn-lg { min-height: var(--h-btn-lg); padding: var(--sp12) var(--sp24); font-size: var(--fs-h2); }
.btn-block { width: 100%; white-space: normal; text-align: center; }
.btn-icon { width: var(--h-btn); height: var(--h-btn); min-height: 0; padding: 0; border-radius: 50%; flex: none; }
.btn-square { width: 56px; height: 56px; min-height: 0; padding: 0; border-radius: 18px; }
/* nút khóa: vẫn phải đọc được (≥ 3:1) — mờ quá thì trông như lỗi hiển thị chứ không ra “đang khóa” */
.btn[disabled], .btn.disabled { opacity: .6; pointer-events: none; }
/* liên kết chữ: xanh lá đậm (kiểu “View All” / “Create an account” của ảnh mẫu) */
.link { color: var(--link); text-decoration: none; font-weight: 600; }
.link:hover { text-decoration: underline; }

/* ---------- Thẻ ---------- */
.card { background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-lg); padding: var(--card-pad); position: relative; box-shadow: var(--shadow-card); }
/* thẻ lồng trong một thẻ: bo nhỏ hơn thẻ ngoài đúng một bậc (quy tắc 7) */
.card-2 { background: var(--panel-2); box-shadow: none; border-radius: var(--r); }
.card-glow { background: radial-gradient(120% 90% at 100% 0%, rgba(var(--accent-rgb), .1), transparent 55%), radial-gradient(90% 80% at 0% 100%, rgba(var(--mint-rgb), .2), transparent 62%), var(--panel); }
.card-light { background: var(--panel); color: var(--text); border: 1px solid var(--line); border-radius: var(--r-lg); padding: var(--card-pad); box-shadow: var(--shadow-card); }
.card-tint { background: var(--bg-2); box-shadow: none; }
/* tiêu đề thẻ + chữ phụ / nút bên phải: không đủ chỗ thì phần bên phải xuống dòng dưới, không ép cả hai thành cột hẹp */
.card-title { display: flex; align-items: center; justify-content: space-between; gap: var(--sp4) var(--sp12); margin-bottom: var(--title-gap); flex-wrap: wrap; }
.card-title h2, .card-title h3 { margin: 0; font-size: var(--fs-h2); }
.card-link { text-decoration: none; display: block; transition: transform .15s ease, border-color .15s, box-shadow .15s; }
.card-link:hover { border-color: var(--accent-line); transform: translateY(-2px); box-shadow: var(--shadow-soft); }
.section-title { font-size: var(--fs-h2); margin: var(--gap-block) 0 var(--title-gap); display: flex; align-items: center; gap: var(--sp12); }
.eyebrow { font-size: var(--fs-xs); letter-spacing: .12em; text-transform: uppercase; font-weight: 700; color: var(--mint-text); }

/* Ô biểu tượng: xanh dương nhạt / bạc hà xen kẽ; ô đang chọn / gợi ý dùng dải hai màu */
/* điện thoại: 4 cột chẵn (đặt --cols cho khớp số ô); mọi hàng cao bằng nhau; máy tính: ô không nở quá --tile-max-w */
.tiles { display: grid; grid-template-columns: repeat(var(--cols, 4), minmax(0, 1fr)); gap: var(--gap-grid); grid-auto-rows: 1fr; justify-items: center; }
@media (min-width: 640px) { .tiles { grid-template-columns: repeat(var(--cols-lg, auto-fill), minmax(104px, 1fr)); } }
.tile { display: flex; flex-direction: column; align-items: center; justify-content: flex-start; gap: var(--sp6); width: 100%; max-width: var(--tile-max-w); min-height: var(--tile-min-h); text-decoration: none; color: var(--text-2); font-size: var(--fs-xs); text-align: center; line-height: 1.25; padding: var(--sp8) var(--sp4); border-radius: var(--r-tile); position: relative; }
.tile-ico { width: var(--ico); height: var(--ico); border-radius: var(--r-tile); display: grid; place-items: center; font-size: var(--fs-emoji); color: var(--accent); background: var(--tile-bg); border: 1px solid var(--tile-line);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .9), 0 8px 18px -12px rgba(var(--accent-rgb), .45); transition: transform .15s; }
.tile:nth-child(even) .tile-ico { background: var(--tile-bg-mint); border-color: var(--tile-line-mint); box-shadow: inset 0 1px 0 rgba(255, 255, 255, .9), 0 8px 18px -12px rgba(18, 129, 74, .45); }
.tile:hover .tile-ico { transform: translateY(-2px); }
.tile.active .tile-ico, .tile.suggest .tile-ico { background: var(--brand-grad); border-color: transparent; color: #fff; box-shadow: 0 10px 22px -10px rgba(var(--accent-rgb), .75); }
.tile.active, .tile.suggest { color: var(--text); font-weight: 600; }
.tile.locked .tile-ico { background: var(--warn-bg); border-color: var(--warn-line); }
.tile-ico.is-danger { background: var(--danger-bg); border-color: var(--danger-line); }
.tile.done .tile-ico::after { content: '✓'; position: absolute; top: 2px; right: calc(50% - 31px); width: 20px; height: 20px; border-radius: 50%; background: var(--ok); color: #fff; font-size: var(--fs-xs); display: grid; place-items: center; font-weight: 700; box-shadow: 0 0 0 2px var(--panel); }
.tile .count { position: absolute; top: 0; right: calc(50% - 33px); min-width: 22px; height: 22px; padding: 0 6px; border-radius: 99px; background: var(--accent-grad); color: #fff; font-size: var(--fs-xs); font-weight: 700; display: grid; place-items: center; box-shadow: 0 0 0 2px var(--panel); }
.tile.disabled { opacity: .4; pointer-events: none; }

/* Số liệu */
.stat { display: flex; flex-direction: column; gap: var(--sp4); }
.stat-num { font-size: var(--fs-stat); font-weight: 600; letter-spacing: -.02em; line-height: 1.05; }
.stat-num small { font-size: var(--fs-sm); font-weight: 500; color: var(--muted); margin-left: var(--sp4); }
.stat-label { color: var(--muted); font-size: var(--fs-sm); }
.stat-ico { width: var(--ico-sm); height: var(--ico-sm); border-radius: var(--r-sm); display: grid; place-items: center; background: var(--tint); color: var(--accent-text); border: 1px solid var(--tile-line); margin-bottom: var(--sp12); font-weight: 700; }
/* bước đã xong: ô bạc hà, dấu ✓ xanh đen */
.stat-ico.green { background: var(--icon-grad-mint); color: var(--on-mint); border: 0; box-shadow: 0 6px 14px -8px rgba(18, 129, 74, .6); }
.kpis { display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px; }
@media (min-width: 900px) { .kpis { grid-template-columns: repeat(4, 1fr); } }
/* ô số liệu: xanh dương nhạt / bạc hà nhạt xen kẽ (bàn cờ 2 cột trên điện thoại, xen kẽ trên hàng 4 ô của máy tính) */
.kpis > .card { background: linear-gradient(160deg, #ffffff 30%, #e9f2ff 100%); }
.kpis > .card:nth-child(4n+2), .kpis > .card:nth-child(4n+3) { background: linear-gradient(160deg, #ffffff 30%, #e2f8ec 100%); border-color: var(--tile-line-mint); }
@media (min-width: 900px) {
  .kpis > .card:nth-child(4n+3) { background: linear-gradient(160deg, #ffffff 30%, #e9f2ff 100%); border-color: var(--line); }
  .kpis > .card:nth-child(4n) { background: linear-gradient(160deg, #ffffff 30%, #e2f8ec 100%); border-color: var(--tile-line-mint); }
}

/* Thanh tiến độ: phần đã đạt là dải xanh trời → bạc hà, phần còn lại có vạch */
.progress { height: 26px; border-radius: 99px; background: repeating-linear-gradient(90deg, rgba(var(--accent-rgb), .13) 0 3px, transparent 3px 7px), var(--panel-2); border: 1px solid var(--line); overflow: hidden; position: relative; }
.progress > span { display: block; height: 100%; border-radius: 99px; background: var(--progress-grad); box-shadow: 0 4px 14px -4px rgba(18, 129, 74, .5); }
.progress-sm { height: 10px; }
.progress-plain { background: var(--panel-3); border: 0; }

/* Nhãn, huy hiệu */
.badge { display: inline-flex; align-items: center; gap: var(--sp6); min-height: 24px; padding: var(--sp4) var(--sp8); border-radius: 99px; font-size: var(--fs-xs); font-weight: 600; background: var(--panel-2); border: 1px solid var(--line); color: var(--text-2); white-space: nowrap; }
.badge .dot { width: 8px; height: 8px; border-radius: 50%; background: currentColor; box-shadow: 0 0 0 3px color-mix(in srgb, currentColor 18%, transparent); }
.badge-ok { color: var(--ok-fg); background: var(--ok-bg); border-color: var(--ok-line); }
.badge-warn { color: var(--warn-fg); background: var(--warn-bg); border-color: var(--warn-line); }
.badge-err { color: var(--danger-fg); background: var(--danger-bg); border-color: var(--danger-line); }
.badge-info { color: var(--info-fg); background: var(--info-bg); border-color: var(--info-line); }
/* nhãn trang trí bạc hà (số đếm, chú thích) — khác nhãn trạng thái .badge-ok (nền nhạt, chữ xanh lá) */
.badge-mint { color: var(--on-mint); background: var(--mint-soft); border-color: var(--mint-line); }
:where(.lv, .lv-ring) { --c: var(--lv-0); }
.lv { color: var(--c); background: color-mix(in srgb, var(--c) 10%, var(--panel)); border-color: color-mix(in srgb, var(--c) 32%, var(--panel)); }
.badge.lv { max-width: 100%; white-space: normal; border-radius: 14px; }
.lv-0 { --c: var(--lv-0); } .lv-1 { --c: var(--lv-1); } .lv-2 { --c: var(--lv-2); } .lv-3 { --c: var(--lv-3); } .lv-4 { --c: var(--lv-4); } .lv-red { --c: var(--lv-red); }
.lv-ring { width: 58px; height: 58px; border-radius: 50%; display: grid; place-items: center; font-weight: 700; font-size: var(--fs-page); color: var(--c);
  background: radial-gradient(circle, var(--panel) 58%, transparent 59%), conic-gradient(var(--c) calc(var(--p, 0) * 1%), var(--panel-3) 0); }
.chip { display: inline-flex; align-items: center; justify-content: center; gap: var(--sp6); min-height: var(--h-tap-desktop); padding: var(--sp6) var(--sp12); border-radius: 99px; background: var(--panel); border: 1px solid var(--line-2); font-size: var(--fs-sm); cursor: pointer; color: var(--text); text-decoration: none; font-family: var(--font); }
.chip:hover { border-color: var(--mint-2); background: var(--mint-soft); }
.chip.on { background: var(--accent-grad); color: var(--on-accent); border-color: transparent; font-weight: 600; box-shadow: var(--shadow-btn); }

/* ---------- Biểu mẫu: ô trắng bo tròn, viền nhạt, vòng sáng xanh khi chọn ---------- */
.field { display: flex; flex-direction: column; gap: var(--sp6); margin-bottom: var(--sp16); }
.field > label, .label { font-size: var(--fs-sm); font-weight: 500; color: var(--text-2); }
.field .req { color: var(--danger); }
.hint { font-size: var(--fs-sm); color: var(--muted); }
/* Ô NHẬP = 16px CỨNG, không đi theo --fs-body: dưới 16px iOS Safari tự phóng to cả trang khi đặt con trỏ
   vào ô, người dùng phải chụm tay thu lại. Đây là ràng buộc của máy, không phải một bậc chữ. */
input[type=text], input[type=tel], input[type=password], input[type=email], input[type=number], input[type=date], input[type=datetime-local], input[type=search], select, textarea {
  width: 100%; min-height: var(--h-field); padding: var(--sp12) var(--sp16); border-radius: var(--r-field); border: 1px solid var(--line-2); background: var(--field); color: var(--text);
  font: 400 max(16px, var(--fs-body))/1.4 var(--font); transition: border-color .15s, box-shadow .15s; appearance: none; -webkit-appearance: none; }
textarea { min-height: 96px; resize: vertical; }
select { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='none' stroke='%231062d8' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 14px center; padding-right: 40px; max-width: 100%; min-width: 0; text-overflow: ellipsis; }
select option { background: var(--panel); color: var(--text); }
/* ô chọn nhỏ trong hàng bảng; trên điện thoại vẫn cao 44px để dễ bấm */
.select-sm { min-height: 36px; padding: var(--sp4) 30px var(--sp4) var(--sp8); font-size: var(--fs-sm); background-position: right 8px center; }
@media (max-width: 560px) { .select-sm { min-height: 44px; } }
input:focus, select:focus, textarea:focus { border-color: var(--accent); outline: none; box-shadow: 0 0 0 4px rgba(var(--accent-rgb), .15); }
::selection { background: rgba(var(--mint-rgb), .45); color: var(--text); }
input::placeholder, textarea::placeholder { color: var(--placeholder); }
input[type=checkbox], input[type=radio] { width: 20px; height: 20px; accent-color: var(--accent); }
.input-unit { position: relative; }
.input-unit input { padding-right: 64px; }
.input-unit span { position: absolute; right: 16px; top: 50%; transform: translateY(-50%); color: var(--muted); font-size: var(--fs-sm); pointer-events: none; }
/* ô nhập có biểu tượng xanh ở đầu */
.input-ico { position: relative; display: block; min-width: 0; }
.input-ico > .i { position: absolute; left: 16px; top: 50%; transform: translateY(-50%); color: var(--accent); pointer-events: none; }
.input-ico > input { padding-left: 46px; }
/* ô đánh dấu: cả dòng nhãn là vùng bấm, cao tối thiểu như mọi vùng chạm khác (40px máy tính, 44px khi chạm) */
.check { display: flex; gap: var(--gap-grid); align-items: center; min-height: var(--h-tap-desktop); font-size: var(--fs-body); color: var(--text-2); }
@media (max-width: 640px), (pointer: coarse) { .check { min-height: var(--h-chip); } }
/* thanh nút cuối biểu mẫu: hai ô bằng nhau, nút lẻ cuối trải hết bề ngang (cùng khuôn .btn-grid) */
.form-actions { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--gap-grid); align-items: stretch; grid-auto-rows: 1fr; margin-top: var(--sp8); }
.form-actions > * { width: 100%; min-width: 0; }
.form-actions > :last-child:nth-child(odd) { grid-column: 1 / -1; }
@media (max-width: 374px) { .form-actions .btn { padding-inline: var(--sp8); gap: var(--sp4); } }
.form-actions .btn { white-space: normal; text-align: center; line-height: 1.25; padding-inline: var(--sp12); }
.radio-cards { display: grid; gap: var(--gap-grid); grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
.radio-card { position: relative; }
.radio-card input { position: absolute; opacity: 0; }
.radio-card label { display: flex; flex-direction: column; gap: var(--sp4); padding: var(--card-pad); min-height: var(--h-btn-lg); justify-content: center; border-radius: var(--r); background: var(--panel); border: 1px solid var(--line-2); cursor: pointer; height: 100%; }
.radio-card label b { font-size: var(--fs-body); }
.radio-card label .emo { font-size: var(--fs-emoji); }
.radio-card input:checked + label { border-color: var(--accent); background: var(--accent-soft); box-shadow: 0 0 0 1px var(--accent) inset; }
.radio-card input:focus-visible + label { outline: 2px solid var(--accent); outline-offset: 2px; }

.photo-drop { display: flex; align-items: center; gap: var(--sp12); padding: var(--sp16); border-radius: var(--r); border: 1.5px dashed var(--mint-2); background: linear-gradient(135deg, var(--mint-soft), #f1fbf6); cursor: pointer; color: var(--text); }
.photo-drop:hover { border-color: var(--mint-text); }
.photo-drop input { display: none; }
.photo-prev { display: flex; gap: var(--gap-grid); flex-wrap: wrap; margin-top: var(--sp12); }
.photo-prev:empty { display: none; }
.photo-prev img { width: 76px; height: 76px; object-fit: cover; border-radius: 14px; border: 1px solid var(--line); }
.gps-line { display: flex; align-items: center; gap: var(--gap-grid); font-size: var(--fs-sm); color: var(--text-2); padding: var(--card-pad-dense); border-radius: var(--r-sm); background: var(--panel-2); border: 1px solid var(--line); }
.gps-line .i { color: var(--accent); }
.gps-line.ok { color: var(--ok-fg); background: var(--ok-bg); border-color: var(--ok-line); }
.gps-line.ok .i { color: var(--ok-fg); }

/* ---------- Thông báo ---------- */
.alert { display: flex; gap: var(--sp12); align-items: flex-start; padding: var(--card-pad-dense); border-radius: var(--r); border: 1px solid var(--line); background: var(--panel); color: var(--text); margin-bottom: var(--gap-card); font-size: var(--fs-body); }
.alert .i { margin-top: var(--sp4); }
.alert-ok { background: var(--ok-bg); border-color: var(--ok-line); color: var(--ok-fg); }
.alert-err { background: var(--danger-bg); border-color: var(--danger-line); color: var(--danger-fg); }
.alert-warn { background: var(--warn-bg); border-color: var(--warn-line); color: var(--warn-fg); }
.alert-info { background: var(--info-bg); border-color: var(--info-line); color: var(--text); }
.alert-info > .i { color: var(--info-fg); }
.alert ul { margin: var(--sp4) 0 0; padding-left: var(--sp20); }

/* ---------- Bảng ---------- */
.table-wrap { overflow-x: auto; border-radius: var(--r); border: 1px solid var(--line); background: var(--panel); }
/* dải cuộn ngang: bóng mờ ở mép còn nội dung phía sau — người dùng biết là vuốt được; cuộn hết thì bóng tự tắt
   (hai lớp “local” màu nền che hai lớp bóng “scroll”, kỹ thuật bóng cuộn thuần CSS) */
.table-wrap, .prose .table-scroll, .scroll-hint, .scroll-shadow { background-color: var(--scroll-bg, var(--panel));
  background-image: linear-gradient(90deg, var(--scroll-bg, var(--panel)) 40%, rgba(255, 255, 255, 0)), linear-gradient(270deg, var(--scroll-bg, var(--panel)) 40%, rgba(255, 255, 255, 0)),
    radial-gradient(farthest-side at 0 50%, rgba(15, 27, 61, .2), rgba(15, 27, 61, 0)), radial-gradient(farthest-side at 100% 50%, rgba(15, 27, 61, .2), rgba(15, 27, 61, 0));
  background-position: 0 0, 100% 0, 0 0, 100% 0; background-size: 34px 100%, 34px 100%, 13px 100%, 13px 100%;
  background-repeat: no-repeat; background-attachment: local, local, scroll, scroll; }
.table { width: 100%; border-collapse: collapse; font-size: var(--fs-sm); }
.table th, .table td { padding: var(--sp12) var(--sp16); text-align: left; border-bottom: 1px solid var(--line); vertical-align: top; }
.table th { font-weight: 600; color: var(--muted); font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: .04em; white-space: nowrap; background: var(--bg-2); }
.table tr:last-child td { border-bottom: 0; }
.table td.num, .table th.num { text-align: right; font-variant-numeric: tabular-nums; }
.table a { text-decoration: none; }
.table a:not(.btn):hover { color: var(--accent-text); }

/* ---------- Khu làm việc (app shell) ---------- */
body.app { min-height: 100vh; }
.shell { position: relative; z-index: 1; display: flex; min-height: 100vh; }
.side { display: none; }
.main { flex: 1; min-width: 0; padding: var(--sp16) 0 120px; }
.main > .container { max-width: 1120px; }
/* thanh trên cùng (điện thoại) kiểu ảnh mẫu: khối xanh dương mang chữ trắng, khối bạc hà tròn lớn ở góc phải sau nút chuông
   (viền trong xanh trời, không có quầng ra ngoài: chữ luôn cách mép phải ≥ 82px, khối bạc hà chỉ tới 78px), vòng tròn trắng trong mờ nằm trên phần bạc hà;
   ảnh đại diện có vòng bạc hà */
.topbar { display: flex; align-items: center; gap: var(--sp12); margin-bottom: var(--sp16); padding: var(--sp8) var(--sp8) var(--sp8) var(--sp12); border-radius: var(--r-lg); color: var(--on-grad); box-shadow: var(--shadow-soft), 0 14px 30px -20px rgba(18, 129, 74, .5);
  background: radial-gradient(circle 20px at calc(100% - 16px) 8px, rgba(255, 255, 255, .34) 99%, transparent 100%),
    radial-gradient(circle 11px at calc(100% - 64px) calc(100% - 7px), rgba(255, 255, 255, .3) 99%, transparent 100%),
    radial-gradient(circle 80px at calc(100% + 2px) 50%, var(--mint-hi) 0, var(--mint) 45%, var(--mint-2) 80%, #3fd0b4 90%, #2cc2d0 97%, #1a9af5 99.5%, transparent 100%),
    var(--hero-bg-x); }
.avatar { width: 46px; height: 46px; border-radius: 50%; display: grid; place-items: center; font-weight: 700; background: var(--accent-grad); color: #fff; flex: none; box-shadow: 0 0 0 3px rgba(var(--accent-rgb), .14); }
/* trên dải màu: ô tròn kính trắng, chữ xanh */
.topbar .avatar { background: var(--glass-strong); box-shadow: 0 0 0 3px var(--mint), 0 0 0 7px rgba(var(--mint-rgb), .28); color: var(--accent-text); }
.topbar .hello { line-height: 1.3; min-width: 0; margin-right: var(--sp12); text-shadow: var(--grad-text-shadow); }
.topbar .hello small { color: var(--on-grad-2); font-size: var(--fs-sm); display: block; }
.topbar .hello b { font-weight: 600; font-size: var(--fs-body); display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.topbar .bell { margin-left: auto; position: relative; }
.topbar .btn-glass { border-color: var(--glass-line); background: rgba(255, 255, 255, .8); }
.topbar .bell .pip { position: absolute; top: 9px; right: 11px; width: 8px; height: 8px; border-radius: 50%; background: var(--danger); box-shadow: 0 0 0 2px #fff; }
.page-head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--gap-grid) var(--sp12); flex-wrap: wrap; margin: var(--sp4) 0 var(--gap-card); }
/* thanh lọc / tìm kiếm trên đầu danh sách (trang quản trị): điện thoại mỗi ô một hàng trọn bề ngang, cao 48px như mọi ô nhập;
   từ 640px trở lại thành một hàng ngang ôm sát nội dung — không còn ô nhập bị bóp còn vài chục px */
.filter-bar { display: grid; gap: var(--gap-grid); grid-template-columns: minmax(0, 1fr); width: 100%; }
.filter-bar > * { width: 100%; min-width: 0; }
@media (min-width: 640px) {
  .filter-bar { display: flex; flex-wrap: wrap; align-items: center; width: auto; }
  .filter-bar > * { width: auto; }
  .filter-bar > :is(input, .input-ico) { width: 240px; }
}
.page-head h1 { font-size: var(--fs-page); margin: 0; }
.page-head .sub { color: var(--muted); font-size: var(--fs-sm); margin-top: var(--sp4); }
/* Điện thoại: việc chính của trang (“+ Tạo lô mới”) trải hết bề ngang như mọi nút chính trong thẻ —
   không để nút quan trọng nhất lại là nút nhỏ nhất trên màn hình */
@media (max-width: 559px) { .page-head > .btn-primary { width: 100%; } }
/* đầu trang Tổng quan (máy tính): dải hai khối màu như thanh trên cùng của điện thoại — chữ trắng trong 62% bên trái trên xanh dương,
   khối bạc hà bo cong bên phải (mép trái nhất 70%) mang nút “Tạo lô mới” */
@media (min-width: 1024px) {
  .dash-head { position: relative; overflow: hidden; align-items: center; padding: var(--sp24); border-radius: var(--r-lg); color: var(--on-grad);
    box-shadow: var(--shadow-soft), 0 18px 36px -24px rgba(18, 129, 74, .55);
    background: radial-gradient(circle 60px at calc(100% - 40px) 0%, rgba(255, 255, 255, .26) 99%, transparent 100%), radial-gradient(circle 22px at 76% 88%, rgba(255, 255, 255, .3) 99%, transparent 100%),
      radial-gradient(ellipse 34% 150% at 104% 50%, var(--mint-hi) 0, var(--mint) 50%, var(--mint-2) 82%, #3fd0b4 91%, #2cc2d0 97%, #1a9af5 99.5%, transparent 100%),
      radial-gradient(circle 90px at 0% 100%, rgba(8, 40, 120, .14) 99%, transparent 100%), var(--hero-bg-x); }
  .dash-head > div { max-width: 62%; text-shadow: var(--grad-text-shadow); }
  .dash-head h1 { color: var(--on-grad); }
  .dash-head .sub { color: var(--on-grad-2); }
}
.back { display: inline-flex; align-items: center; gap: var(--sp6); min-height: var(--h-tap-desktop); color: var(--accent-text); text-decoration: none; font-size: var(--fs-sm); font-weight: 500; margin-bottom: var(--sp8); }
.back:hover { color: var(--accent-2); }

/* Thanh điều hướng nổi (điện thoại): thanh trắng bo tròn, biểu tượng xanh dương; mục đang mở: nền bạc hà + vạch chỉ báo xanh lá; nút giữa là nút ghi */
/* HÀNG DƯỚI CÙNG: menu giữ viên thuốc của nó, nút tin nhắn là một VÒNG TRÒN XANH đứng riêng
   bên cạnh — không có nền trắng phía sau. Cả hàng canh giữa màn hình nên thêm nút thì menu dịch
   sang trái mà cụm vẫn cân. */
.bnav-hang { position: fixed; left: 50%; bottom: max(14px, env(safe-area-inset-bottom)); transform: translateX(-50%);
  z-index: 50; display: flex; align-items: center; gap: var(--sp8); max-width: calc(100vw - 16px); }
/* Menu giữ nguyên viên thuốc trắng của nó; chỉ thôi tự canh giữa (việc ấy do .bnav-hang lo). */
.bnav { position: static; transform: none; bottom: auto; left: auto; z-index: auto; display: flex;
  align-items: center; gap: var(--sp6); padding: var(--sp8); border-radius: 99px;
  background: var(--panel); border: 1px solid var(--accent-line);
  backdrop-filter: blur(18px) saturate(1.4); -webkit-backdrop-filter: blur(18px) saturate(1.4);
  box-shadow: 0 1px 2px rgba(15, 27, 61, .06), 0 6px 14px -6px rgba(15, 27, 61, .18), 0 22px 44px -16px rgba(16, 90, 200, .55); }
.bnav a { width: 50px; height: 50px; border-radius: 50%; display: grid; place-items: center; color: var(--text-2); text-decoration: none; position: relative; background: transparent; transition: color .15s, background .15s; }
.bnav a:hover { color: var(--accent); }
.bnav a.on { color: var(--on-mint); background: var(--mint-grad); box-shadow: inset 0 1px 0 rgba(255, 255, 255, .55), 0 6px 14px -8px rgba(18, 129, 74, .8); }
.bnav a.on::after { content: ''; position: absolute; bottom: 5px; left: 50%; width: 14px; height: 4px; margin-left: -7px; border-radius: 4px; background: var(--mint-text); }
.bnav a.bnav-add { background: var(--accent-grad); color: #fff; box-shadow: var(--shadow-btn), inset 0 1px 0 rgba(255, 255, 255, .3); }
.bnav a.bnav-add .i { width: 24px; height: 24px; }
.bnav a.bnav-add.on::after { background: #fff; }
.bnav a .i { width: 22px; height: 22px; }
.bnav a span { position: absolute; bottom: -22px; font-size: var(--fs-xs); color: var(--muted); white-space: nowrap; display: none; }

@media (min-width: 1024px) {
  .bnav { display: none; }
  .side { display: flex; flex-direction: column; gap: 4px; width: 264px; flex: none; position: sticky; top: 0; height: 100vh; padding: 20px 16px; border-right: 1px solid var(--line); overflow-y: auto;
    background: radial-gradient(circle 120px at 100% 100%, rgba(var(--mint-rgb), .22) 99%, transparent 100%), linear-gradient(180deg, rgba(255, 255, 255, .92) 0%, rgba(244, 252, 248, .92) 100%); backdrop-filter: blur(12px); }
  .main { padding: var(--sp24) 0 60px; }
  .topbar.mobile-only { display: none; }
}
.brand { display: flex; align-items: center; gap: var(--gap-grid); text-decoration: none; font-weight: 700; font-size: var(--fs-h2); letter-spacing: -.01em; color: var(--text); }
.brand img { width: 36px; height: 36px; }
.brand small { display: block; font-weight: 400; font-size: var(--fs-xs); color: var(--muted); letter-spacing: 0; }
.side .brand { padding: var(--sp4) var(--sp8) var(--sp16); }
.side nav { display: flex; flex-direction: column; gap: var(--sp4); }
.side .nav-label { font-size: var(--fs-xs); letter-spacing: .12em; text-transform: uppercase; color: var(--mint-text); padding: 16px 12px 6px; font-weight: 700; }
.side nav a { display: flex; align-items: center; gap: var(--sp12); padding: var(--sp8) var(--sp12); min-height: var(--h-tap-desktop); border-radius: var(--r-sm); text-decoration: none; color: var(--text-2); font-size: var(--fs-body); }
.side nav a .i { color: var(--accent); }
.side nav a:hover { background: var(--mint-soft); color: var(--text); }
.side nav a.on { background: var(--accent-grad); color: #fff; font-weight: 500; box-shadow: var(--shadow-btn); }
.side nav a.on .i { color: #fff; }
.side nav a .count { margin-left: auto; font-size: var(--fs-xs); background: var(--danger); color: #fff; border-radius: 99px; padding: 1px var(--sp6); }
.side .side-foot { margin-top: auto; padding-top: 16px; border-top: 1px solid var(--line); }
.tenant-switch { display: flex; align-items: center; gap: var(--sp8); padding: var(--sp8); border-radius: 16px; background: linear-gradient(135deg, var(--mint-soft), #f1fbf6); border: 1px solid var(--mint-line); }
.tenant-switch select { min-height: 36px; padding: var(--sp6) 30px var(--sp6) var(--sp8); font-size: var(--fs-sm); background-position: right 8px center; border-radius: 12px; }

/* Nút ghi nhanh nổi (desktop cũng có) */
.fab { position: fixed; right: 22px; bottom: 26px; z-index: 40; display: none; }
@media (min-width: 1024px) { .fab { display: inline-flex; } }

/* ---------- Thẻ lô ---------- */
.lot-card { display: flex; flex-direction: column; gap: 12px; text-decoration: none; overflow: hidden; }
.lot-card .top { display: flex; gap: 12px; align-items: flex-start; }
.lot-emo { width: var(--ico); height: var(--ico); border-radius: var(--r-tile); display: grid; place-items: center; font-size: var(--fs-emoji); background: var(--tile-bg); border: 1px solid var(--tile-line); flex: none; }
.lot-card h3 { font-size: var(--fs-h2); margin: 0 0 var(--sp4); }
:is(.grid-2, .grid-3, .grid-4, .grid, .stack) > .lot-card:nth-child(even) .lot-emo, .hero-panel .grid-2 > .pick:nth-child(even) .pick-emo { background: var(--tile-bg-mint); border-color: var(--tile-line-mint); }
.lot-card .code { font-size: var(--fs-xs); color: var(--muted); font-family: ui-monospace, Menlo, monospace; }
.lot-card .meta { display: flex; gap: var(--sp8); flex-wrap: wrap; }
.lot-card .foot { display: flex; justify-content: space-between; align-items: center; font-size: var(--fs-sm); color: var(--muted); }

/* Thẻ nổi bật (lô đang làm): nửa trái khối xanh dương mang chữ trắng (chữ ≤ 56% bề ngang), nửa phải khối bạc hà bo cong từ trên xuống dưới
   (mép trái nhất ở 60% — viền trong xanh trời), vòng tròn trắng trong mờ và lá cây trên phần bạc hà; nhãn, nút và bong bóng là kính mờ chữ tối */
.feature-lot { overflow: hidden; min-height: 250px; padding: var(--card-pad); display: flex; flex-direction: column; justify-content: space-between; }
.card.feature-lot { color: var(--on-grad); border-color: transparent; box-shadow: var(--shadow), 0 20px 40px -26px rgba(18, 129, 74, .55);
  background: radial-gradient(circle 34px at 88% 16%, rgba(255, 255, 255, .26) 99%, transparent 100%),
    radial-gradient(circle 16px at 70% 90%, rgba(255, 255, 255, .3) 99%, transparent 100%),
    radial-gradient(ellipse 46% 96% at 106% 70%, var(--mint-hi) 0%, var(--mint) 55%, var(--mint-2) 84%, #3fd0b4 93%, #2cc2d0 99%, transparent 100%),
    var(--hero-bg-x); }
/* lá cây chỉ hiện trong khối bạc hà (mặt nạ trùng hình khối) → không bao giờ nằm dưới chữ trắng */
.feature-lot::after { content: ''; position: absolute; inset: 0; pointer-events: none; opacity: .85;
  background: url('/static/img/monstera.svg') no-repeat right -34px bottom -30px / 240px auto;
  -webkit-mask-image: radial-gradient(ellipse 46% 96% at 106% 70%, #000 96%, transparent 99%); mask-image: radial-gradient(ellipse 46% 96% at 106% 70%, #000 96%, transparent 99%); }
.feature-lot > * { position: relative; z-index: 1; }
/* tên lô nổi bật: cùng bậc tiêu đề thẻ — nổi bật nhờ nền hai màu, không nhờ cỡ chữ to hơn cả tiêu đề trang */
.feature-lot h2 { font-size: var(--fs-h2); font-weight: 600; line-height: 1.2; text-shadow: var(--grad-text-shadow); }
.feature-lot :is(h2, .muted) { max-width: 56%; }
.feature-lot .muted { color: var(--on-grad-2); }
.feature-lot .badge { background: var(--glass-strong); border-color: var(--glass-line); }
.feature-lot .badge:not(.lv) { color: var(--text-2); }
/* trên dải màu: nút chính thành nút trắng chữ xanh để nổi lên */
.feature-lot .btn-primary { background: var(--panel); color: var(--accent-text); box-shadow: var(--shadow-soft); }
.bubble { display: inline-flex; align-items: center; gap: var(--gap-grid); padding: var(--sp8) var(--sp12); border-radius: 99px; background: var(--glass); border: 1px solid var(--glass-line); backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px); font-size: var(--fs-sm); color: var(--text); box-shadow: 0 8px 20px -12px rgba(10, 30, 90, .4); }
.bubble .i { color: var(--accent); }
a.bubble { text-decoration: none; }

/* ---------- Dòng thời gian ---------- */
.tl { position: relative; display: flex; flex-direction: column; gap: var(--sp12); }
.tl::before { content: ''; position: absolute; left: 19px; top: var(--sp8); bottom: var(--sp8); width: 2px; background: linear-gradient(var(--blue), var(--mint) 60%, rgba(var(--mint-rgb), .2)); opacity: .55; }
.tl-item { display: flex; gap: var(--sp12); position: relative; }
.tl-dot { width: var(--ico-sm); height: var(--ico-sm); border-radius: var(--r-sm); flex: none; display: grid; place-items: center; font-size: var(--fs-emoji-inline); background: var(--panel); border: 1px solid var(--line-2); z-index: 1; box-shadow: 0 6px 14px -10px rgba(var(--accent-rgb), .5); }
.tl-item.is-verify .tl-dot { background: var(--brand-grad); border: 0; }
.tl-item.is-dist .tl-dot { background: var(--info-bg); border-color: var(--info-line); }
.tl-item.is-void { opacity: .55; }
.tl-item.is-void .tl-body h4 { text-decoration: line-through; }
.tl-body { flex: 1; min-width: 0; background: var(--panel); border: 1px solid var(--line); border-radius: var(--r); padding: var(--card-pad-dense); }
.tl-body h4 { margin: 0; font-size: var(--fs-body); }
.tl-when { font-size: var(--fs-xs); color: var(--muted); }
.tl-fields { display: grid; grid-template-columns: auto 1fr; gap: var(--sp4) var(--sp12); font-size: var(--fs-sm); margin: var(--sp8) 0 0; }
.tl-fields dt { color: var(--muted); }
.tl-fields dd { margin: 0; color: var(--text); }
.tl-tags { display: flex; gap: var(--sp6); flex-wrap: wrap; margin-top: var(--sp8); }
.tl-photos { display: flex; gap: var(--gap-grid); margin-top: var(--sp12); overflow-x: auto; }
.tl-photos img { width: 108px; height: 80px; object-fit: cover; border-radius: 12px; border: 1px solid var(--line); flex: none; background: var(--panel-2); }
.tl-by { font-size: var(--fs-xs); color: var(--muted); margin-top: var(--sp8); }
.tl-actions { display: flex; gap: var(--gap-grid); flex-wrap: wrap; margin-top: var(--sp12); }
.tl-actions details { position: relative; }
.tl-actions summary { list-style: none; }
.tl-actions summary::-webkit-details-marker { display: none; }

/* Tabs: mục đang chọn là viên thuốc trắng chữ xanh dương, số đếm bạc hà */
/* thanh tab xuống dòng ở MỌI cỡ màn: trên điện thoại không còn mục nào bị cắt cụt hay khuất ngoài mép.
   Thanh lọc thật dài mới thêm .scroll-row để cuộn ngang (quy tắc riêng ở dưới). */
.tabs { display: flex; flex-wrap: wrap; gap: var(--sp6); padding: var(--sp4); margin: 0 0 var(--sp16); scrollbar-width: none; }
.tabs::-webkit-scrollbar { display: none; }
/* mọi mục đều là một viên thuốc (kính mờ trắng) nên cả hàng đọc ra là một bộ điều khiển, không phải dòng chữ xám rời rạc */
.tabs a { position: relative; padding: var(--sp12) var(--sp16); border-radius: 99px; text-decoration: none; color: var(--muted); font-weight: 500; white-space: nowrap; font-size: var(--fs-sm); min-height: var(--h-tap-desktop); display: inline-flex; align-items: center; background: var(--glass); box-shadow: inset 0 0 0 1px var(--glass-line); }
.tabs a:hover { color: var(--text); }
.tabs a.on { background: var(--panel); color: var(--accent-text); font-weight: 600; box-shadow: var(--shadow-card); }
.tabs a sup { display: inline-grid; place-items: center; min-width: 20px; height: 20px; border-radius: 99px; background: var(--panel-3); color: var(--text-2); font-size: var(--fs-xs); margin-left: var(--sp6); padding: 0 var(--sp6); top: -1px; }
.tabs a.on { box-shadow: var(--shadow-card), inset 0 -3px 0 var(--mint); }
.tabs a.on sup { background: var(--mint); color: var(--on-mint); }
/* thanh tab trên màn rộng: xuống dòng thay vì cuộn ngang nên không mục nào bị khuất; menu nhiều mục (quản trị) xuống dòng ở mọi cỡ màn, khoảng cách gọn hơn */
@media (min-width: 761px) { .tabs { flex-wrap: wrap; overflow: visible; } }
/* Thanh nhiều mục KHÔNG giấu mục nào (thanh quản trị 12 mục, thanh lọc phiếu giao): lưới ô BẰNG NHAU
   thay cho flex-wrap thuần — mọi hàng đều đặn, không còn mục đứng trơ một mình ở hàng cuối.
   Số cột tăng dần theo bề rộng: 2 (điện thoại) → 3 → 4 → 6; mục lẻ cuối trải hết hàng khi chỉ có 2 cột. */
.tabs-wrap { display: grid; grid-template-columns: repeat(var(--tab-cols, 2), minmax(0, 1fr)); gap: var(--gap-grid); grid-auto-rows: 1fr; overflow: visible; padding: 0; }
.tabs-wrap a { justify-content: center; text-align: center; white-space: normal; padding: var(--sp8); line-height: 1.25; }
.tabs-wrap > :last-child:nth-child(odd) { grid-column: 1 / -1; }
@media (min-width: 480px) { .tabs-wrap { --tab-cols: 3; } .tabs-wrap > :last-child:nth-child(odd) { grid-column: auto; } }
@media (min-width: 768px) { .tabs-wrap { --tab-cols: 4; } }
@media (min-width: 1024px) { .tabs-wrap { --tab-cols: 6; } }
/* ĐIỆN THOẠI (≤479px): mọi thanh tab xuống dòng đều thành lưới 2 ô BẰNG NHAU, mục lẻ cuối trải hết hàng.
   Vẫn đúng ý “không giấu mục nào” của .tabs, nhưng hết kiểu xuống dòng lởm chởm mỗi mục một bề rộng
   (trước: /admin/lo 7 mục = [3,3,1], /app/lo 5 mục = [2,2,1] với 5 bề rộng khác nhau). */
@media (max-width: 479px) {
  .tabs:not(.scroll-row) { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--gap-grid); grid-auto-rows: 1fr; padding: 0; }
  /* thanh lọc nằm trong một hàng .row-between (trang /app/lo, /admin/lo): lưới co theo nội dung nên trước đây
     chỉ rộng 288px cạnh thẻ rộng 382px. Cho nó xuống hàng riêng và trải hết bề ngang để thẳng mép với ô tìm kiếm và các thẻ dưới. */
  .row-between > .tabs:not(.scroll-row) { flex: 1 1 100%; min-width: 0; }
  .tabs:not(.scroll-row) a { justify-content: center; text-align: center; white-space: normal; padding: var(--sp8); line-height: 1.25; }
  .tabs:not(.scroll-row) > :last-child:nth-child(odd) { grid-column: 1 / -1; }
}
/* MỘT hệ tab cho cả app: thanh lọc nhiều mục dùng .tabs.scroll-row — luôn một hàng cuộn ngang, không bao giờ
   xuống dòng để lại một mục trơ trọi ở dòng cuối (kể cả trên máy tính, nơi .tabs vốn cho phép xuống dòng) */
.tabs.scroll-row { flex-wrap: nowrap; overflow-x: auto; overflow-y: hidden; padding: var(--sp4); }
/* mép mờ hai bên cho thấy hàng còn cuộn được tiếp (cùng cách dải ngày của /app/hom-nay đang dùng) */
.tabs.scroll-row { -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 14px, #000 calc(100% - 14px), transparent 100%);
  mask-image: linear-gradient(90deg, transparent 0, #000 14px, #000 calc(100% - 14px), transparent 100%); }

.list { display: flex; flex-direction: column; }
.list-item { display: flex; align-items: center; gap: 12px; padding: 12px 0; border-bottom: 1px solid var(--line); text-decoration: none; }
.list-item:last-child { border-bottom: 0; }
a.list-item:hover { color: var(--accent-text); }
.list-ico { width: var(--ico-sm); height: var(--ico-sm); border-radius: var(--r-sm); display: grid; place-items: center; background: var(--tile-bg); border: 1px solid var(--tile-line); flex: none; font-size: var(--fs-emoji-inline); }
:is(.list-item, .demo-acc):nth-child(even) .list-ico { background: var(--tile-bg-mint); border-color: var(--tile-line-mint); }
/* màn hẹp: nhãn cuối dòng (hạn chứng nhận, trạng thái…) xuống dòng dưới, thẳng hàng với chữ — cột chữ không bị ép còn vài chục px */
@media (max-width: 400px) {
  .list-item:has(> .grow + .badge:last-child) { flex-wrap: wrap; row-gap: 6px; }
  .list-item:has(> .grow + .badge:last-child) > .grow { flex: 1 1 calc(100% - 52px); }
  .list-item:has(> .list-ico) > .grow + .badge:last-child { margin-left: 52px; }
}

.check-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--gap-grid); }
.check-list li { display: flex; gap: var(--sp12); align-items: flex-start; font-size: var(--fs-body); }
.check-list .ok, .check-list .no { width: 22px; height: 22px; border-radius: 50%; display: grid; place-items: center; flex: none; font-size: var(--fs-xs); font-weight: 700; margin-top: 1px; }
/* MỘT kiểu dấu tích cho cả hệ: vòng tròn nền nhạt cùng màu với dấu (y như .pl-ic của “Kiểm tra tính hợp lý”,
   hai danh sách này nằm chung một thẻ ở /app/lo/:id nên trước đây trông như hai phần của hai trang khác nhau).
   “Bắt buộc” hay “hợp lý” phân biệt bằng tiêu đề mục, không bằng hai kiểu biểu tượng. */
.check-list .ok { background: color-mix(in srgb, var(--ok-fg) 18%, transparent); color: var(--ok-fg); }
.check-list .no { background: color-mix(in srgb, var(--muted) 14%, transparent); color: var(--muted); }
.check-list .bad, .tr-checks .bad { background: color-mix(in srgb, var(--danger) 18%, transparent); color: var(--danger-fg); }

.empty { text-align: center; padding: 36px 16px; color: var(--muted); }
.empty .emo { font-size: var(--fs-emoji-lg); margin-bottom: var(--sp8); }

details.fold { border-radius: var(--r); background: var(--panel); border: 1px solid var(--line); }
.card details.fold { background: var(--bg-2); }
details.fold > summary { cursor: pointer; padding: var(--sp12) var(--sp16); min-height: var(--h-btn); font-weight: 500; list-style: none; display: flex; justify-content: space-between; align-items: center; gap: var(--sp12); }
details.fold > summary::-webkit-details-marker { display: none; }
/* dấu “+” không được kéo cao cả dòng tiêu đề (line-height: 1) ⇒ mọi đầu khối gập cao đúng 48px khi nhãn một dòng */
details.fold > summary::after { content: '+'; font-size: var(--fs-h2); line-height: 1; color: var(--mint-text); transition: transform .2s; }
details.fold[open] > summary::after { transform: rotate(45deg); }
details.fold > .fold-body { padding: 0 var(--sp16) var(--sp16); }

.qr-box { background: #fff; border-radius: 18px; padding: var(--sp12); display: inline-block; line-height: 0; border: 1px solid var(--line); }
.qr-box svg { width: 100%; height: auto; display: block; }

.toast-stack { position: fixed; top: 14px; left: 50%; transform: translateX(-50%); z-index: 100; width: min(560px, calc(100% - 24px)); }
.toast-stack .alert { box-shadow: var(--shadow); animation: drop .3s ease; }
@keyframes drop { from { transform: translateY(-10px); opacity: 0; } }

/* ============================================================
   TRANG CÔNG KHAI: thanh điều hướng trắng kính mờ, phần đầu dải màu, khối nội dung trắng
   ============================================================ */
body.site { color: var(--text); }
/* chữ trên khối xanh dương của dải màu: trắng hết (chữ phụ phân cấp bằng cỡ chữ — mọi màu nhạt hơn trắng đều < 4.5:1 ở phần #1570ef) */
:is(.hero, .section-sage) .muted { color: var(--on-grad); }
:is(.hero, .section-sage) .eyebrow { color: var(--on-grad); }
:is(.hero, .section-sage) .link { color: #fff; text-decoration: underline; }
.site-nav { position: sticky; top: 0; z-index: 60; background: rgba(255, 255, 255, .88); backdrop-filter: blur(14px) saturate(1.3); -webkit-backdrop-filter: blur(14px) saturate(1.3); color: var(--text); border-bottom: 1px solid var(--line); }
.site-nav .container { display: flex; align-items: center; gap: 16px; height: 68px; }
.site-nav .brand { color: var(--text); }
.site-nav .brand small { color: var(--muted); }
.site-nav .links { display: none; gap: 4px; margin-left: 20px; }
.site-nav .links a { color: var(--text-2); text-decoration: none; display: inline-flex; align-items: center; min-height: var(--h-tap-desktop); padding: var(--sp8) var(--sp12); border-radius: 99px; font-size: var(--fs-body); font-weight: 500; }
.site-nav .links a:hover, .site-nav .links a.on { background: var(--accent-soft); color: var(--accent-text); }
.site-nav .actions { margin-left: auto; display: flex; gap: 8px; align-items: center; }
.site-nav .menu-btn { color: var(--accent-text); background: var(--accent-soft); border-color: transparent; box-shadow: none; }
.mobile-menu { display: none; padding: var(--sp8) var(--sp16) var(--sp16); background: var(--panel); border-top: 1px solid var(--line); }
.mobile-menu.open { display: block; }
.mobile-menu a { display: block; padding: 12px 6px; color: var(--text); text-decoration: none; border-bottom: 1px solid var(--line); font-weight: 500; }
.mobile-menu a:hover { color: var(--accent-text); }
@media (min-width: 900px) { .site-nav .links { display: flex; } .site-nav .menu-btn { display: none; } }
/* Điện thoại ưu tiên "Đăng nhập": ẩn nút "Đăng ký" ở thanh trên và cho nút đăng nhập mang dáng nút chính.
   Người chưa có tài khoản bấm "Đăng nhập" rồi đăng ký ngay dưới ô mật khẩu (views/auth/login.ejs). */
@media (max-width: 520px) {
  .site-nav .actions .btn-signup { display: none; }
  .site-nav .actions .btn-login {
    background: var(--accent-grad); color: var(--on-accent); border-color: transparent; font-weight: 600;
    box-shadow: var(--shadow-btn), inset 0 1px 0 rgba(255, 255, 255, .3), inset 0 -2px 6px rgba(8, 40, 120, .2);
  }
}
.site-nav .brand { min-width: 0; }
.site-nav .brand span { white-space: nowrap; }
@media (max-width: 400px) {
  .site-nav .container { gap: var(--sp12); }
  .site-nav .brand img { width: 32px; height: 32px; }
  .site-nav .brand small { display: none; }
  .site-nav .actions { gap: 6px; }
  .site-nav .actions .btn-sm { padding: 6px 12px; }
}
/* đã đăng nhập: nút "Vào khu làm việc" dài hơn — màn rất hẹp chỉ giữ biểu tượng thương hiệu */
@media (max-width: 369px) { .site-nav.authed .brand span { display: none; } }

/* Phần đầu trang (trang chủ, tra cứu, neo hash, hướng dẫn) và các dải màu giữa trang — hai khối màu lớn chồng lên nhau như ảnh mẫu.
   Nền dải là trường xanh bạc hà (kèm vòng tròn trắng trong mờ); khối xanh dương (::before của khối chữ .hero-copy / .section-head / .cta-copy,
   ≤ #1570ef ở mọi điểm) nằm đè lên, mang toàn bộ chữ trắng, bo vừa ở góc trên phải và bo cong lớn ở góc dưới phải; quầng xanh trời mờ ra phía ngoài
   mép (box-shadow chỉ vẽ bên ngoài khối) nên chỗ hai khối gặp nhau pha màu như ảnh mà không bao giờ nằm dưới chữ.
   Điện thoại: chữ trải hết bề ngang → khối xanh dương phủ trọn bề ngang, bạc hà ở góc trên phải (trên dòng chữ đầu) và toàn bộ phần dưới.
   Máy tính: khối xanh dương rộng hơn cột chữ 180–220px rồi cong xuống; bán kính tính sẵn để đường cong luôn nằm ngoài khung chữ (đã đo tương phản). */
.hero { --band-pt: 56px; color: var(--on-grad); position: relative; overflow: hidden; isolation: isolate; padding: var(--band-pt) 0 0;
  background: radial-gradient(circle 150px at right -40px top -30px, rgba(255, 255, 255, .22) 99%, transparent 100%), var(--mint-field); }
.hero > .container { position: relative; display: grid; gap: 28px; isolation: isolate; }
/* trang chủ: nổi trên tấm thẻ trắng bên dưới — khung điện thoại minh họa chồng lên mép thẻ mà không bị che.
   Chỉ trang chủ: ở trang tra cứu / neo hash, khối xanh dương kéo dài dưới chữ phải nằm DƯỚI tấm thẻ trắng */
.hero-home > .container { z-index: 2; }
:is(.hero-copy, .section-sage .section-head, .cta-copy) { position: relative; }
:is(.hero-copy, .section-sage .section-head, .cta-copy)::before { content: ''; position: absolute; z-index: -1; pointer-events: none;
  top: calc(-1 * var(--band-pt)); left: var(--bs-left, -16px); right: var(--bs-right, -16px); bottom: calc(-1 * var(--bs-ext, 90px));
  border-top-right-radius: var(--bs-tr, 58% 50px); border-bottom-right-radius: var(--bs-br, 88% 110px);
  background: radial-gradient(circle 90px at 0% 100%, rgba(8, 40, 120, .14) 99%, transparent 100%), var(--blue-shape); box-shadow: var(--duo-glow); }
/* điện thoại, phần đầu không có hình minh họa (tra cứu, neo hash, hướng dẫn): chỉ còn ~40px trước tấm thẻ trắng → đường cong ngắn để vẫn thấy;
   trang tra cứu kết thúc bằng ô nhập + nút trắng (không phải chữ trắng) nên đường cong quét rộng qua đó */
@media (max-width: 959px) {
  .hero:not(.hero-home) .hero-copy { --bs-ext: 50px; --bs-br: 88% 70px; }
  .hero:not(.hero-home) .hero-copy:has(> form) { --bs-ext: 30px; --bs-br: 92% 150px; }
}
/* điện thoại (trang phụ): hai màu rõ như ảnh mẫu — khối xanh dương dừng ngay dưới chữ, cong rộng ở góc trên phải và dưới phải;
   dải bạc hà (có vòng tròn trắng trong mờ) hiện rõ trước tấm thẻ trắng. Đường cong đã tính để luôn nằm ngoài khung chữ trắng */
@media (max-width: 600px) {
  .hero:not(.hero-home) { --band-pt: 64px; }
  .hero:not(.hero-home) > .container { padding-bottom: 56px; }
  .hero:not(.hero-home) .hero-copy { --bs-ext: 40px; --bs-br: 100% 64px; --bs-tr: 70% 100px; }
  .hero:not(.hero-home) .hero-copy:has(> form) { --bs-ext: 24px; --bs-br: 100% 170px; }
  .hero:not(.hero-home) .hero-copy::after { content: ''; position: absolute; z-index: -1; pointer-events: none; right: 8px; bottom: calc(-1 * var(--bs-ext) - 50px);
    width: 58px; height: 58px; border-radius: 50%; background: rgba(255, 255, 255, .3); }
}
@media (min-width: 960px) {
  .hero { --band-pt: 64px; }
  .hero > .container { grid-template-columns: 1.1fr .9fr; align-items: center; gap: 40px; }
  .hero-main { align-self: start; }
  :is(.hero-copy, .section-sage .section-head, .cta-copy) { --bs-left: -50vw; --bs-right: -220px; --bs-ext: 90px; --bs-tr: 240px 90px; --bs-br: 460px 250px; }
  .hero-home .hero-copy { --bs-right: -180px; --bs-ext: 150px; --bs-tr: 260px 120px; --bs-br: 560px 420px; }
}
.hero-title { font-size: var(--fs-hero); line-height: 1.02; font-weight: 700; color: var(--on-grad); letter-spacing: -.035em; margin: var(--sp8) 0 var(--sp16); text-shadow: var(--grad-text-shadow); }
.hero-title em { font-style: normal; color: var(--on-grad-hi); }
.hero-title-sm { font-size: var(--fs-display); }
/* Đoạn dẫn (dưới tiêu đề lớn): MỘT cỡ duy nhất cho cả .hero-lead và .section-head p — đúng bậc 4
   (--fs-page), tức 20px trên điện thoại sau khi cả thang hạ một bậc, 22px từ màn 1024px trở lên.
   KHÔNG mở bậc riêng cho đoạn dẫn. Trước đợt này bậc 4 là 22px nên đoạn dẫn của trang chủ cao
   tới 273px / 8 dòng ở màn 390px — gấp bốn lần chiều cao tiêu đề, gần một phần ba màn hình đầu
   chỉ để đọc 60 chữ. Ở 20px và tiêu đề 30px, tỉ lệ dẫn/tiêu đề về 1:1,5 và đoạn dẫn còn 6 dòng.
   text-wrap: balance để dòng cuối không trơ một hai chữ. */
.hero-lead { font-size: var(--fs-page); color: var(--on-grad); max-width: 46ch; text-shadow: var(--grad-text-shadow); margin-bottom: 0; text-wrap: pretty; }
/* hàng nút của phần đầu trang: lưới ô bằng nhau như .btn-grid (điện thoại hai nút bằng nhau, nút lẻ trải hết hàng);
   máy tính ≥ 640px trở lại thành hàng ngang ôm sát chữ */
.hero .cta { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--gap-grid); margin: var(--gap-block) 0 var(--gap-card); }
.hero .cta .btn { width: 100%; }
@media (min-width: 640px) { .hero .cta { display: flex; flex-wrap: wrap; } .hero .cta .btn { width: auto; } }
/* Nút tài khoản ở đầu trang chủ: điện thoại hiện "Đăng nhập", máy tính hiện "Đăng ký miễn phí" */
.hero .cta .cta-login, .hero .cta-note { display: none; }
@media (max-width: 639px) {
  .hero .cta .cta-login { display: inline-flex; }
  .hero .cta .cta-signup { display: none; }
  /* Nút "Quét thử" nằm trên dải bạc hà nên nền bạc hà của nó chìm hẳn vào nền.
     Đổi sang xanh mực đậm: bật khỏi cả dải bạc hà lẫn khối xanh dương, và khác hẳn
     nút "Đăng nhập" nền trắng ngay trên nó. */
  .hero .cta .btn-mint {
    background: linear-gradient(135deg, #1f7ae0, #1360c8 58%, #0e53b4);
    color: #fff; border-color: rgba(255, 255, 255, .3);
    box-shadow: 0 2px 4px rgba(13, 62, 140, .16), 0 14px 28px -12px rgba(13, 62, 140, .7);
  }
  .hero .cta .btn-mint .i, .hero .cta .btn-mint svg { color: var(--mint) }
  /* dòng này nằm trên dải bạc hà, không phải trên khối xanh dương — nên dùng chữ đậm màu tối */
  .hero .cta-note { display: block; margin: calc(-1 * var(--gap-card)) 0 var(--gap-card); color: var(--text-2); font-size: var(--fs-sm); }
  .hero .cta-note a { color: var(--accent-text); font-weight: 600; text-underline-offset: 3px; }
}
/* Lối đăng ký dưới nút đăng nhập */
.signup-cta { display: grid; gap: var(--sp8); justify-items: center; text-align: center; }
.signup-cta .muted { font-size: var(--fs-sm); }
/* nhãn nhỏ của phần đầu trang: điện thoại xếp lưới 2 cột ô bằng nhau (nhãn lẻ cuối trải hết hàng) thay vì
   xuống dòng lởm chởm mỗi nhãn một bề rộng; từ 640px trở lại thành một hàng ngang */
.hero-pills { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--gap-grid); align-items: stretch; grid-auto-rows: 1fr; }
.hero-pills > :last-child:nth-child(odd) { grid-column: 1 / -1; }
/* quy tắc 6: LUÔN là lưới hai ô bằng nhau. Trước đây từ 640px trở lên là flex-wrap thuần nên ở 1280px
   bốn viên xếp [3,1] — một viên trơ trọi ở dòng cuối, đúng kiểu “hàng chip vỡ lởm chởm” cần tránh. */
.hero-pills span { display: inline-flex; align-items: center; justify-content: center; text-align: center; font-size: var(--fs-sm); padding: var(--sp6) var(--sp12); border-radius: 99px; background: rgba(255, 255, 255, .82); border: 1px solid var(--glass-line); color: var(--text); backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px); box-shadow: 0 8px 18px -14px rgba(10, 30, 90, .5); }
.hero-art { position: relative; display: flex; justify-content: center; align-items: flex-end; min-height: 420px; }
/* quanh điện thoại minh họa (máy tính): vòng tròn trắng trong mờ lớn sau điện thoại + khối xanh dương sáng tròn chồng ở góc dưới trái (viền xanh trời) */
.hero-art::before { content: ''; position: absolute; z-index: -1; inset: -40px -70px -80px; pointer-events: none;
  background: radial-gradient(circle 190px at 64% 34%, rgba(255, 255, 255, .24) 99%, transparent 100%), radial-gradient(circle 46px at 94% 70%, rgba(255, 255, 255, .3) 99%, transparent 100%),
    radial-gradient(circle 96px at 26% calc(100% - 170px), #1890ff 0, #18a8ff 74%, #60d8f0 97%, transparent 100%),
    radial-gradient(circle 124px at 26% calc(100% - 170px), rgba(var(--cyan-rgb), .45) 76%, rgba(var(--cyan-rgb), 0) 100%); }
/* khối tròn xanh đặt theo mép dưới (không theo %): quầng của nó dừng trước tấm thẻ trắng — khung chứa điện thoại nằm trên tấm thẻ (z-index 2) nên phần tràn xuống sẽ phủ lên thẻ */
/* điện thoại / máy tính bảng: vùng hình minh họa trải hết bề ngang trên nền bạc hà; khối xanh dương sáng tròn ló ra ở mép trái, vòng tròn trắng trong mờ */
@media (max-width: 959px) {
  .hero-art::before { inset: -40px -50vw -100px;
    background: radial-gradient(circle 64px at calc(50% + 150px) 30%, rgba(255, 255, 255, .26) 99%, transparent 100%),
      radial-gradient(circle 150px at calc(50% + 60px) 18%, rgba(255, 255, 255, .18) 99%, transparent 100%),
      radial-gradient(circle 130px at calc(50% - 190px) 62%, #1890ff 0, #18a8ff 74%, #60d8f0 97%, transparent 100%),
      radial-gradient(circle 160px at calc(50% - 190px) 62%, rgba(var(--cyan-rgb), .5) 78%, rgba(var(--cyan-rgb), 0) 100%); }
}
.hero-art .rosette { position: absolute; width: 300px; top: 0; right: -30px; filter: drop-shadow(0 30px 30px rgba(10, 30, 90, .25)); animation: spin 90s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .hero-art .rosette { animation: none; } html { scroll-behavior: auto; } }
.hero-panel { background: var(--panel); color: var(--text); border-radius: var(--r-xl) var(--r-xl) 0 0; margin-top: 40px; padding: var(--sp24) 0 var(--sp8); position: relative; }
/* Điện thoại: chừa chỗ để hai chấm số trên hàng tab không dính vào đáy ảnh điện thoại phía trên */
@media (max-width: 760px) { .hero-panel { margin-top: 48px; padding-top: var(--sp24); } .hero-panel .tabs-light a { padding-top: 32px; } }
.hero-panel .muted { color: var(--muted); }
.hero-panel .link { color: var(--accent-text); text-decoration: none; }
.hero-panel .tabs-light { display: flex; gap: var(--sp24); align-items: flex-end; overflow-x: auto; padding-bottom: 4px; }
.hero-panel .tabs-light a { text-decoration: none; font-size: var(--fs-page); font-weight: 500; color: var(--muted); white-space: nowrap; position: relative; padding-top: 28px; }
.hero-panel .tabs-light a.on { color: var(--text); font-weight: 700; }
.hero-panel .tabs-light a.on::after { content: ''; position: absolute; left: 0; right: 0; bottom: -4px; height: 3px; border-radius: 3px; background: var(--progress-grad); }
.hero-panel .tabs-light a sup { position: absolute; top: 0; left: 50%; transform: translateX(-50%); display: grid; place-items: center; width: 22px; height: 22px; border-radius: 50%; background: var(--panel-3); color: var(--text-2); font-size: var(--fs-xs); font-weight: 600; }
.hero-panel .tabs-light a.on sup { background: var(--mint); color: var(--on-mint); }
/* màn hẹp: ba thẻ chia đều bề ngang, chữ nhỏ hơn, số đếm căn giữa trên nhãn — không nhãn nào bị cắt ở mép phải */
@media (max-width: 400px) {
  .hero-panel .tabs-light { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 6px; overflow: visible; }
  .hero-panel .tabs-light a { font-size: var(--fs-h2); text-align: center; min-height: var(--h-chip); }
}

/* Điện thoại minh họa */
.phone { width: 290px; height: 590px; border-radius: 46px; background: var(--device); padding: 10px; box-shadow: 0 30px 50px -30px rgba(10, 30, 90, .42), inset 0 0 0 2px var(--device-rim); position: relative; z-index: 1; margin-bottom: -60px; }
.phone-screen { width: 100%; height: 100%; border-radius: 38px; overflow: hidden; background: var(--bg); position: relative; color: var(--text); font-size: 12px; }
.phone-screen .ph-img { height: 55%; background: var(--hero-bright); position: relative; overflow: hidden; }
.phone-screen .ph-img img { position: absolute; width: 130%; max-width: none; left: -15%; top: 6%; }
.phone-screen .ph-status { position: absolute; top: 12px; left: 22px; right: 22px; display: flex; justify-content: space-between; font-weight: 600; font-size: 12px; z-index: 2; color: #fff; }
.phone-screen .ph-status span { padding: 1px 7px; border-radius: 99px; background: var(--glass-dark); }
.phone-screen .ph-frame { position: absolute; inset: 70px 50px auto 50px; height: 150px; z-index: 2; }
.phone-screen .ph-frame i { position: absolute; width: 26px; height: 26px; border: 2.5px solid #fff; }
.phone-screen .ph-frame i:nth-child(1) { top: 0; left: 0; border-right: 0; border-bottom: 0; border-radius: 10px 0 0 0; }
.phone-screen .ph-frame i:nth-child(2) { top: 0; right: 0; border-left: 0; border-bottom: 0; border-radius: 0 10px 0 0; }
.phone-screen .ph-frame i:nth-child(3) { bottom: 0; left: 0; border-right: 0; border-top: 0; border-radius: 0 0 0 10px; }
.phone-screen .ph-frame i:nth-child(4) { bottom: 0; right: 0; border-left: 0; border-top: 0; border-radius: 0 0 10px 0; }
.phone-screen .ph-sheet { position: absolute; left: 8px; right: 8px; bottom: 8px; background: #fff; color: var(--text); border-radius: 26px; padding: 16px; }
.phone-screen .ph-sheet h5 { font-size: 15px; margin: 0 0 2px; }
.phone-screen .ph-sheet p { font-size: 10.5px; color: var(--muted); margin: 0 0 10px; }
.phone-screen .ph-stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; }
.phone-screen .ph-stats div { background: var(--tint); border-radius: 14px; padding: 8px; }
.phone-screen .ph-stats b { display: block; font-size: 15px; }
.phone-screen .ph-stats small { font-size: 9px; color: var(--muted); }
.phone-screen .ph-badge { position: absolute; top: 14px; right: 14px; width: 34px; height: 34px; border-radius: 50%; background: var(--mint-grad); display: grid; place-items: center; color: var(--on-mint); font-weight: 700; }
/* chừa chỗ cho huy hiệu cấp (34px + khoảng hở) để chữ không nằm dưới huy hiệu */
.phone-screen .ph-sheet h5, .phone-screen .ph-sheet p { padding-right: 42px; }
.phone-screen .ph-pill { position: absolute; left: 18px; bottom: 212px; z-index: 2; background: var(--glass); border: 1px solid var(--glass-line); backdrop-filter: blur(8px); color: var(--text); border-radius: 99px; padding: 7px 12px; font-size: 10.5px; display: flex; gap: 6px; align-items: center; }

.section { padding: 64px 0; }
/* Nhảy tới một mục bằng liên kết "#..." (Tính năng, Cách hoạt động): thanh đầu trang dính ở trên
   cao 68px, không chừa thì tiêu đề mục nhảy tới nằm LẤP sau thanh ấy. */
.section[id] { scroll-margin-top: 80px; }
.section-white { background: var(--panel); }
.section-sage { --band-pt: 64px; color: var(--on-grad); position: relative; overflow: hidden; isolation: isolate;
  background: radial-gradient(circle 220px at right -60px bottom -80px, rgba(255, 255, 255, .2) 99%, transparent 100%),
    radial-gradient(circle 70px at 8% 92%, rgba(255, 255, 255, .22) 99%, transparent 100%),
    radial-gradient(circle 150px at right -50px top -40px, rgba(255, 255, 255, .2) 99%, transparent 100%), var(--mint-field); }
/* dải kêu gọi cuối trang: khối xanh dương chỉ sau đoạn chữ; nút (trắng + xanh dương) nằm được trên cả hai màu */
.section-cta { --band-pt: 56px; }
.section-cta .cta-copy { --bs-ext: 36px; --bs-br: 70% 80px; }
@media (min-width: 960px) { .section-cta .cta-copy { --bs-right: -120px; --bs-ext: 56px; --bs-tr: 160px 60px; --bs-br: 300px 160px; } }
.section-dark { background: radial-gradient(900px 500px at 90% 0%, rgba(var(--accent-rgb), .12), transparent 60%), radial-gradient(760px 460px at 0% 100%, rgba(var(--mint-rgb), .26), transparent 62%), var(--bg); color: var(--text); }
.section-head { max-width: 720px; margin-bottom: var(--gap-block); }
.section-head h2, .section-h2, .prose h1 { font-size: var(--fs-section); letter-spacing: -.02em; font-weight: 700; }
.section-head p { font-size: var(--fs-page); }
.section-sage .section-head, .lime { text-shadow: var(--grad-text-shadow); }
.section-sage .section-head h2, .lime { color: var(--on-grad); }
.section-sage code { color: var(--accent-text); background: var(--panel); padding: 1px 6px; border-radius: 6px; }

/* Thẻ mẫu quy trình / đối tượng: thẻ xanh nhạt; trên dải màu thành panel kính mờ */
.pick { display: flex; align-items: center; gap: var(--sp16); background: var(--bg-2); color: var(--text); border: 1px solid var(--line); border-radius: var(--r-lg); padding: var(--card-pad); position: relative; }
.pick .pick-emo { width: var(--ico-lg); height: var(--ico-lg); border-radius: var(--r-tile); display: grid; place-items: center; font-size: var(--fs-emoji-lg); background: var(--tile-bg); border: 1px solid var(--tile-line); flex: none; }
.pick h3 { font-size: var(--fs-h2); margin: 0 0 var(--sp4); color: var(--text); }
.pick p { margin: 0; font-size: var(--fs-sm); color: var(--text-2); }
.pick .mini-icons { display: flex; flex-wrap: wrap; gap: var(--sp6); margin-top: var(--sp8); }
.pick .mini-icons span { width: 28px; height: 28px; border-radius: var(--r-xs); border: 1px solid var(--line-2); background: var(--panel); display: grid; place-items: center; font-size: var(--fs-xs); }
.pick .plus { margin-left: auto; width: var(--h-btn-lg); height: var(--h-btn-lg); border-radius: var(--r-tile); background: var(--accent-grad); color: #fff; display: grid; place-items: center; flex: none; box-shadow: var(--shadow-btn); text-decoration: none; }
/* điện thoại hẹp: ô biểu tượng và nút “+” ở hàng trên, chữ xuống dòng dưới trải hết bề ngang — không còn cột chữ 130px */
@media (max-width: 430px) {
  .pick { flex-wrap: wrap; align-items: center; gap: var(--sp12); }
  .pick .pick-emo { width: var(--ico); height: var(--ico); border-radius: var(--r-tile); font-size: var(--fs-emoji); }
  .pick .plus { order: 2; }
  .pick > :not(.pick-emo):not(.plus) { order: 3; flex: 1 0 100%; min-width: 0; }
}
/* kính mờ trên dải màu: trắng trong pha bạc hà, viền trắng — trên khối xanh dương thành kính xanh nhạt, trên bạc hà thành kính bạc hà */
.section-sage :is(.pick, .step-card), .stats-band div { background: var(--glass-mint); border-color: var(--glass-line); backdrop-filter: blur(14px) saturate(1.3); -webkit-backdrop-filter: blur(14px) saturate(1.3); box-shadow: 0 16px 36px -22px rgba(10, 50, 60, .5); }
.section-sage .pick .pick-emo { background: rgba(255, 255, 255, .85); }
.section-sage .grid-3 > .pick:nth-child(even) .pick-emo { background: rgba(220, 248, 233, .95); border-color: var(--tile-line-mint); }

.feature { background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-lg); padding: var(--card-pad); box-shadow: var(--shadow-card); height: 100%; }
.feature .f-ico { width: var(--ico); height: var(--ico); border-radius: var(--r-tile); display: grid; place-items: center; font-size: var(--fs-emoji); background: var(--tile-bg); border: 1px solid var(--tile-line); margin-bottom: var(--title-gap); }
.grid-3 > .feature:nth-child(even) .f-ico, .grid-4 > .feature:nth-child(even) .f-ico { background: var(--tile-bg-mint); }
.feature h3 { font-size: var(--fs-h2); margin-bottom: var(--sp6); }
.feature p { color: var(--text-2); font-size: var(--fs-body); margin: 0; }
.feature-flat { box-shadow: none; background: var(--bg-2); }
.feature-env { box-shadow: none; background: var(--info-bg); border-color: var(--info-line); }
.feature-dark { background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-lg); padding: var(--card-pad); height: 100%; }
.feature-dark .f-ico { width: var(--ico); height: var(--ico); border-radius: var(--r-tile); display: grid; place-items: center; font-size: var(--fs-emoji); background: var(--brand-grad); color: #fff; margin-bottom: var(--title-gap); }
.feature-dark p { color: var(--text-2); font-size: var(--fs-body); margin: 0; }

.steps-row { display: grid; gap: var(--gap-card); grid-template-columns: 1fr; counter-reset: s; }
@media (min-width: 760px) { .steps-row { grid-template-columns: repeat(4, 1fr); } }
.step-card { background: var(--glass); border: 1px solid var(--glass-line); border-radius: var(--r-lg); padding: var(--card-pad); position: relative; color: var(--text); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); box-shadow: 0 16px 36px -22px rgba(10, 30, 90, .5); }
.step-card::before { counter-increment: s; content: counter(s); position: absolute; top: 18px; right: 18px; width: 34px; height: 34px; border-radius: 50%; background: var(--accent-grad); color: #fff; display: grid; place-items: center; font-weight: 700; box-shadow: var(--shadow-btn); }
.step-card:nth-child(even)::before { background: var(--icon-grad-mint); color: var(--on-mint); box-shadow: 0 10px 22px -10px rgba(18, 129, 74, .6); }
.step-card .emo { font-size: var(--fs-emoji-lg); margin-bottom: var(--sp8); }
.step-card h3 { color: var(--text); font-size: var(--fs-h2); }
.step-card p { color: var(--text-2); font-size: var(--fs-body); margin: 0; }

.level-grid { display: grid; gap: var(--gap-card); grid-template-columns: 1fr; }
@media (min-width: 760px) { .level-grid { grid-template-columns: repeat(4, 1fr); } }
.level-card { border-radius: var(--r-lg); padding: var(--card-pad); background: var(--panel); border: 1px solid var(--line); border-top: 5px solid var(--c); box-shadow: var(--shadow-card); }
.level-card .n { font-size: var(--fs-stat); font-weight: 700; color: var(--c); line-height: 1; }
/* cấp 4: viền bạc hà như ảnh mẫu; chữ số giữ màu cấp đậm (đủ tương phản) */
.level-card.lv-4 { border-top-color: var(--mint); }
.level-card h3 { font-size: var(--fs-h2); margin: var(--sp8) 0 var(--sp6); }
.level-card p { font-size: var(--fs-sm); color: var(--text-2); margin: 0; }

.compare { width: 100%; border-collapse: separate; border-spacing: 0; background: var(--panel); border-radius: var(--r-lg); overflow: hidden; box-shadow: var(--shadow-card); font-size: var(--fs-body); }
.compare th, .compare td { padding: var(--sp12) var(--sp16); border-bottom: 1px solid var(--line); text-align: left; vertical-align: top; }
.compare th { background: var(--bg-2); font-weight: 600; }
.compare th.us { background: var(--accent-grad); color: #fff; }
.compare td.us { background: var(--accent-soft); font-weight: 500; }
.compare tr:last-child td { border-bottom: 0; }
.compare-wrap { overflow-x: auto; border-radius: var(--r-lg); border: 1px solid var(--line); }
.compare-wrap .compare { box-shadow: none; }
/* Bảng neo hash: màn hẹp chuyển mỗi dòng thành thẻ, gốc Merkle chiếm trọn bề ngang */
@media (max-width: 600px) {
  .anchors-table thead { display: none; }
  .anchors-table, .anchors-table tbody { display: block; }
  .anchors-table tr { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: var(--sp12); padding: var(--sp12) var(--sp16); border-bottom: 1px solid var(--line); }
  .anchors-table tr:last-child { border-bottom: 0; }
  .anchors-table td { display: block; padding: 0; border: 0; }
  .anchors-table td:nth-child(2), .anchors-table td:nth-child(4) { grid-column: 1 / -1; }
  .anchors-table td.num { grid-column: 2; grid-row: 1; text-align: right; }
  .anchors-table td[data-label]::before { content: attr(data-label); display: block; font-size: var(--fs-xs); font-weight: 500; color: var(--muted); margin-bottom: 2px; }
}
/* ô tra cứu: trắng, bo tròn lớn, chữ in hoa, biểu tượng kính lúp xanh */
.lookup-input { flex: 1 1 220px; min-width: 0; }
.lookup-input input, input.lookup-input { min-height: var(--h-btn-lg); border-radius: 999px; border-color: transparent; font-size: var(--fs-h2); text-transform: uppercase; box-shadow: var(--shadow-soft); }
.lookup-input::placeholder, .lookup-input input::placeholder { text-transform: none; }
.lookup-btn { flex: 1 0 auto; }
@media (min-width: 521px) { .lookup-btn { flex-grow: 0; } }

.faq details { background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-lg); margin-bottom: var(--gap-grid); box-shadow: var(--shadow-card); }
.faq summary { padding: var(--sp12) var(--card-pad); min-height: var(--h-btn); box-sizing: border-box; align-items: center; cursor: pointer; font-weight: 600; list-style: none; display: flex; justify-content: space-between; gap: var(--sp12); }
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after { content: '+'; width: 30px; height: 30px; border-radius: var(--r-xs); background: var(--icon-grad-mint); color: var(--on-mint); font-weight: 700; display: grid; place-items: center; flex: none; transition: transform .2s; }
.faq details[open] summary::after { transform: rotate(45deg); }
.faq details > div { padding: 0 var(--card-pad) var(--card-pad); color: var(--text-2); }

.stats-band { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--gap-card); }
@media (min-width: 760px) { .stats-band { grid-template-columns: repeat(4, 1fr); } }
.stats-band div { border: 1px solid var(--glass-line); border-radius: var(--r-lg); padding: var(--card-pad); }
.stats-band b { display: block; font-size: var(--fs-stat); color: var(--accent-text); line-height: 1.1; }
.stats-band div:nth-child(even) b { color: var(--mint-text); }
.stats-band span { font-size: var(--fs-sm); color: var(--text-2); }

.chain { display: flex; gap: var(--gap-grid); overflow-x: auto; padding: var(--sp6) 2px var(--sp12); }
.chain .blk { flex: none; width: 180px; border-radius: var(--r-tile); padding: var(--sp12); background: var(--panel-2); border: 1px solid var(--line); font-size: var(--fs-sm); position: relative; color: var(--text-2); }
.chain .blk:not(:last-child)::after { content: '→'; position: absolute; right: -14px; top: 50%; transform: translateY(-50%); color: var(--mint-text); font-weight: 700; }
.chain .blk b { display: block; font-size: var(--fs-body); margin-bottom: var(--sp6); color: var(--text); }
.chain .blk code { color: var(--accent-text); font-size: var(--fs-xs); }
/* điện thoại: chuỗi khối xếp dọc, mũi tên quay xuống — người mua đọc được cả chuỗi, không khối nào bị cắt ngoài mép thẻ */
@media (max-width: 559px) {
  .chain { flex-direction: column; overflow-x: visible; gap: 24px; padding: var(--sp6) 0 var(--sp4); }
  .chain .blk { width: auto; }
  .chain .blk:not(:last-child)::after { content: '↓'; right: auto; left: 50%; top: auto; bottom: -21px; transform: translateX(-50%); }
}

.site-foot { background: var(--panel); color: var(--text-2); padding: 48px 0 110px; font-size: var(--fs-body); border-top: 1px solid var(--line); }
.site-foot a { color: var(--text-2); text-decoration: none; }
.site-foot a:hover { color: var(--accent-text); }
.site-foot .brand { color: var(--text); }
.site-foot .cols { display: grid; gap: var(--gap-block); grid-template-columns: 1fr; }
@media (min-width: 760px) { .site-foot .cols { grid-template-columns: 1.4fr 1fr 1fr 1fr; } .site-foot { padding-bottom: 48px; } }
.site-foot h4 { color: var(--text); font-size: var(--fs-body); margin-bottom: var(--title-gap); }
.site-foot ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0; }
/* liên kết chân trang đủ cao để bấm bằng ngón tay (≥ 44px), không dính nhau */
.site-foot li > a { display: inline-flex; align-items: center; min-height: 44px; }
.site-foot li > span { display: block; padding: var(--sp8) 0; }
/* tiêu đề của thẻ gập (details.card) đủ cao để bấm (≥ 44px) mà thẻ không cao thêm */
details.card > summary { padding-block: var(--sp8); margin-block: calc(var(--sp8) * -1); cursor: pointer; }

/* Hướng dẫn */
.guide { display: grid; gap: var(--gap-block); grid-template-columns: 1fr; padding: var(--gap-block) 0 60px; }
@media (min-width: 960px) { .guide { grid-template-columns: 250px 1fr; } }
.guide-single { grid-template-columns: 1fr; max-width: 860px; margin: 0 auto; }
@media (min-width: 960px) { .guide-single { grid-template-columns: 1fr; } }
.toc { position: sticky; top: 86px; align-self: start; background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-lg); padding: var(--card-pad); box-shadow: var(--shadow-card); display: none; }
@media (min-width: 960px) { .toc { display: block; } }
/* mục lục: mỗi mục là một vùng bấm đủ cao (sàn máy tính 40px) nên cột trái thẳng nhịp với chữ bên phải */
.toc a { display: flex; align-items: center; min-height: var(--h-tap-desktop); padding: var(--sp6) var(--sp8); border-radius: var(--r-xs); text-decoration: none; color: var(--text-2); font-size: var(--fs-sm); }
.toc a:hover { background: var(--accent-soft); color: var(--accent-text); }
.prose { background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-xl); padding: clamp(20px, 4vw, 44px); box-shadow: var(--shadow-card); min-width: 0; }
.prose h2 { font-size: var(--fs-page); margin-top: 44px; padding-top: var(--sp8); scroll-margin-top: 90px; }
.prose h2:first-child { margin-top: 0; }
.prose h3 { font-size: var(--fs-h2); margin-top: var(--gap-block); }
.prose p, .prose li { color: var(--text-2); }
.prose ol, .prose ul { padding-left: var(--sp24); }
.prose li { margin-bottom: 6px; }
.prose .tip { background: var(--accent-soft); border-left: 4px solid var(--accent); border-radius: 0 var(--r-field) var(--r-field) 0; padding: var(--sp12) var(--sp16); margin: var(--gap-card) 0; color: var(--text); }
.prose .warn { background: var(--warn-bg); border-left-color: var(--warn); }
.prose table { width: 100%; border-collapse: collapse; margin: var(--gap-card) 0; font-size: var(--fs-sm); }
.prose th, .prose td { border: 1px solid var(--line); padding: var(--sp8) var(--sp12); text-align: left; vertical-align: top; }
.prose th { background: var(--bg-2); }
.prose .table-scroll { overflow-x: auto; }
/* Bảng xếp thành thẻ trên điện thoại (.table-stack): mỗi hàng một khối, ô đầu là tiêu đề, các ô sau “tên cột — giá trị”
   (tên cột ở data-label, app.js tự điền theo hàng tiêu đề); ô không có tên cột (nút thao tác) trải hết bề ngang */
@media (max-width: 560px) {
  .table-stack thead, .table-stack tr:not(:has(> td)) { display: none; }
  .table-stack, .table-stack tbody, .table-stack tr, .table-stack td { display: block; width: 100%; }
  .table-stack { border-collapse: separate; }
  .table-stack tr { padding: var(--card-pad-dense); border-bottom: 1px solid var(--line); }
  .table-stack tr:last-child { border-bottom: 0; }
  .table-stack td { border: 0; padding: 3px 0; text-align: left; overflow-wrap: anywhere; white-space: normal; }
  .table-stack td.num { text-align: left; }
  /* tên cột trôi sang lề trái (38% bề ngang ô = 61.3% phần nội dung); flow-root giữ ô đủ cao khi tên cột dài hai dòng */
  .table-stack td[data-label] { display: flow-root; padding-left: 38%; }
  .table-stack td[data-label]::before { content: attr(data-label); float: left; width: calc(61.3% - 10px); margin: 3px 0 0 -61.3%; color: var(--muted); font-size: var(--fs-xs); font-weight: 600; line-height: 1.3; overflow-wrap: normal; }
  .table-stack td:first-child { padding: 0 0 var(--sp6); font-size: var(--fs-body); }
  .table-stack td:first-child::before { content: none; }
  .table-stack td:not([data-label]):not(:first-child) { padding-top: 8px; }
  .table-stack td:empty { display: none; }
  .table-stack .btn-sm { min-height: var(--h-chip); }
  .table-stack select { min-height: var(--h-field); }
  /* liên kết trong ô thao tác và tên ở dòng đầu: đủ cao để bấm bằng ngón tay */
  .table-stack td:not([data-label]) > .link, .table-stack td:first-child > a { display: inline-flex; align-items: center; min-height: 44px; }
  .table-stack td.actions { padding: 8px 0 0; }
  .table-stack td.actions::before { content: none; }
  .table-stack :is(td.actions, td:not([data-label])) .row > .btn { flex: 1 1 calc(50% - 6px); }
  /* bảng so sánh trang chủ: mỗi dòng một thẻ, giá trị của Gốc Xanh nổi bật */
  .compare.table-stack td.us { background: var(--accent-soft); border-radius: var(--r-sm); padding: var(--sp8) var(--sp8) var(--sp8) 38%; margin-top: var(--sp4); }
  .compare.table-stack td.us::before { color: var(--accent-text); }
}
.prose kbd { background: var(--tint); border-radius: 6px; padding: var(--sp4) var(--sp6); font-family: var(--font); font-size: var(--fs-sm); border: 1px solid var(--line-2); }

/* ============================================================
   TRANG QUÉT QR: phần đầu dải màu có lá cây + tấm thẻ trắng bo tròn bên dưới
   ============================================================ */
body.trace { color: var(--text); }
/* khung dọc lấp đầy màn hình: trang ngắn thì tấm thẻ trắng kéo dài tới đáy, không lộ dải nền */
/* padding-bottom chừa chỗ cho thanh lối tắt đang fixed ở đáy: 62px thân thanh + khoảng hở trên
   và dưới. Không chừa thì cuộn tới cuối trang là thanh đè mất dòng chữ cuối cùng. */
.tr-wrap { max-width: 560px; margin: 0 auto; min-height: 100vh; min-height: 100dvh; position: relative; display: flex; flex-direction: column;
  padding-bottom: calc(62px + 2 * max(12px, calc(env(safe-area-inset-bottom) + 6px))); }
/* đầu trang QR (không có chữ trắng): khối xanh dương lớn từ góc trên trái chồng lên trường bạc hà, mép pha xanh trời, vòng tròn trắng trong mờ, lá cây bạc hà */
.tr-hero { position: relative; flex: none; height: 360px; overflow: hidden;
  background: radial-gradient(circle 96px at 92% 20%, rgba(255, 255, 255, .26) 99%, transparent 100%), radial-gradient(circle 52px at 6% 74%, rgba(255, 255, 255, .22) 99%, transparent 100%),
    radial-gradient(circle 150px at 104% 104%, rgba(255, 255, 255, .16) 99%, transparent 100%),
    radial-gradient(ellipse 74% 62% at 0% 0%, #1268e0 0%, #1570ef 52%, #1890ff 88%, #18a8ff 98%, transparent 100%),
    radial-gradient(ellipse 86% 74% at 0% 0%, rgba(var(--cyan-rgb), .85) 80%, rgba(var(--cyan-rgb), 0) 100%),
    var(--mint-field); }
.tr-hero-sm { height: 250px; }
.tr-hero-xs { height: 240px; }
.tr-hero .cover { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; opacity: .5; mix-blend-mode: luminosity; }
.tr-hero .plant { position: absolute; width: 118%; max-width: none; left: -9%; top: 26px; opacity: .92; }
/* đáy ảnh tối nhẹ (xanh đen) để tấm thẻ trắng tách khỏi ảnh */
.tr-hero::after { content: ''; position: absolute; inset: 0; background: linear-gradient(180deg, rgba(8, 30, 70, 0) 55%, rgba(8, 30, 70, .2)); }
.tr-top { position: absolute; top: 14px; left: 14px; right: 14px; z-index: 3; display: flex; justify-content: space-between; align-items: center; }
.tr-top .btn-icon { background: var(--glass); border: 1px solid var(--glass-line); backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px); color: var(--accent-text); box-shadow: 0 8px 20px -12px rgba(10, 30, 90, .45); }
.tr-top { gap: 8px; }
.tr-top .bubble { min-width: 0; white-space: nowrap; }
.tr-top-gap { width: 46px; flex: none; }
@media (max-width: 374px) { .tr-top-lbl { display: none; } }
.tr-frame { position: absolute; left: 50%; top: 80px; transform: translateX(-50%); width: 210px; height: 170px; z-index: 2; }
.tr-frame i { position: absolute; width: 34px; height: 34px; border: 3px solid rgba(255, 255, 255, .92); }
.tr-frame i:nth-child(1) { top: 0; left: 0; border-right: 0; border-bottom: 0; border-radius: 14px 0 0 0; }
.tr-frame i:nth-child(2) { top: 0; right: 0; border-left: 0; border-bottom: 0; border-radius: 0 14px 0 0; }
.tr-frame i:nth-child(3) { bottom: 0; left: 0; border-right: 0; border-top: 0; border-radius: 0 0 0 14px; }
.tr-frame i:nth-child(4) { bottom: 0; right: 0; border-left: 0; border-top: 0; border-radius: 0 0 14px 0; }
.tr-bubble { position: absolute; left: 16px; right: 16px; bottom: 60px; z-index: 3; }
/* nhãn trên ảnh: bo 18px (vẫn là viên thuốc khi một dòng, thành thẻ bo tròn khi phải xuống dòng) */
.tr-bubble .bubble { border-radius: 18px; max-width: 100%; }
.tr-sheet { position: relative; z-index: 4; margin-top: -44px; background: var(--panel); color: var(--text); border-radius: 30px 30px 0 0; padding: var(--sp24) var(--sp16) calc(120px + env(safe-area-inset-bottom)); flex: 1 0 auto;
  box-shadow: 0 -12px 30px -18px rgba(21, 94, 210, .45); }
.tr-head { display: flex; gap: var(--sp12); align-items: flex-start; }
.tr-head h1 { font-size: var(--fs-page); margin: 0 0 var(--sp4); font-weight: 700; }
.tr-head h1.mono { font-size: var(--fs-page); }
.tr-head p { margin: 0; color: var(--muted); font-size: var(--fs-sm); }
/* huy hiệu cấp độ: màu lấy từ --c của lớp .lv-N (chữ trắng trên màu cấp ≥ 4.9:1), điểm sáng pha trắng */
/* mặc định cấp 4 bằng :where (độ ưu tiên 0) để .lv-N / .lv-red luôn thắng; điểm sáng nhỏ ở góc, không nằm dưới chữ số */
:where(.tr-badge) { --c: var(--lv-4); }
.tr-badge { width: 54px; height: 54px; border-radius: 50%; display: grid; place-items: center; flex: none; margin-left: auto; font-size: var(--fs-page); font-weight: 700; color: #fff;
  background: radial-gradient(circle at 28% 24%, color-mix(in srgb, var(--c) 72%, #fff), var(--c) 42%); box-shadow: 0 10px 24px -8px color-mix(in srgb, var(--c) 65%, transparent); }
/* cấp 4 tô bạc hà như ảnh mẫu, chữ số xanh đen (không bao giờ chữ trắng trên bạc hà) */
.tr-badge.lv-4 { background: var(--mint-grad); color: var(--on-mint); box-shadow: 0 10px 24px -8px rgba(18, 129, 74, .6), inset 0 1px 0 rgba(255, 255, 255, .55); }
.tr-level { font-size: var(--fs-xs); padding: var(--sp4) var(--sp8); }
.tr-stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--gap-grid); margin: var(--sp16) 0; }
.tr-stat { background: var(--tile-bg); border: 1px solid var(--tile-line); border-radius: 20px; padding: var(--sp12); position: relative; min-height: 96px; min-width: 0; display: flex; flex-direction: column; justify-content: flex-start; }
.tr-stat:nth-child(2) { background: var(--tile-bg-mint); border-color: var(--tile-line-mint); }
.tr-stat:nth-child(2) .ic { background: var(--icon-grad-mint); color: var(--on-mint); box-shadow: 0 6px 14px -6px rgba(18, 129, 74, .6); }
/* biểu tượng nằm trong luồng (hàng trên cùng) → số → nhãn: mọi ô bắt đầu cùng độ cao nên các con số thẳng hàng */
.tr-stat .ic { align-self: flex-end; flex: none; margin: -2px -2px 6px 0; width: 30px; height: 30px; border-radius: 50%; background: var(--icon-grad); display: grid; place-items: center; color: #fff; box-shadow: 0 6px 14px -6px rgba(var(--accent-rgb), .6); }
.tr-stat .ic .i { width: 16px; height: 16px; }
.tr-stat b { font-size: var(--fs-page); line-height: 1.1; letter-spacing: -.02em; margin-top: 4px; }
.tr-stat small { font-size: var(--fs-xs); color: var(--muted); line-height: 1.25; }
@media (max-width: 374px) { .tr-stats { gap: var(--sp6); } .tr-stat { padding: var(--sp8); border-radius: var(--r-tile); } }
.tr-card { background: var(--bg-2); border: 1px solid var(--line); border-radius: var(--r-lg); padding: var(--card-pad); margin-bottom: var(--gap-card); }
.tr-card h2 { font-size: var(--fs-h2); margin: 0 0 var(--title-gap); display: flex; align-items: flex-start; gap: var(--gap-grid); }
/* flex-start chứ không center: tiêu đề dài (“Môi trường thực tế tại khu sản xuất”) xuống hàng
   trên màn hình 320 px thì align-items: center đẩy biểu tượng xuống giữa hai dòng, trông như nó
   lạc ra khỏi dòng chữ. margin-top .03em bù lại nửa khoảng trống dòng để tiêu đề một dòng vẫn cân như cũ. */
.tr-card h2 > .i, .tr-card h2 > svg { margin-top: .03em; flex: none; }
.tr-card h2 > .i { color: var(--accent); }
.tr-sheet > .tr-card:nth-of-type(even) h2 > .i { color: var(--mint-text); }
details.tr-card > summary { gap: var(--sp12); align-items: center; min-height: var(--h-chip); margin: calc(var(--sp8) * -1) 0; cursor: pointer; font-weight: 600; list-style: none; display: flex; justify-content: space-between; }
/* khi mở: bỏ lề âm phía dưới để danh sách không đè lên dòng thứ hai của tiêu đề (màn 320px tiêu đề xuống 2 dòng) */
details.tr-card[open] > summary { margin-bottom: var(--sp12); }
details.tr-card > summary::-webkit-details-marker { display: none; }
details.tr-card > summary > span { flex: none; white-space: nowrap; color: var(--accent-text); }
.tr-kv { display: grid; grid-template-columns: fit-content(42%) minmax(0, 1fr); gap: var(--sp6) var(--sp12); font-size: var(--fs-sm); margin: 0; }
.tr-kv dt { color: var(--muted); }
.tr-kv dd { margin: 0; font-weight: 500; overflow-wrap: anywhere; }
/* Giấy tờ: HAI cột — biểu tượng và nội dung. Nhãn Đạt/Không đạt nằm trong nội dung, ngay
   dưới tiêu đề (xem views/public/trace.ejs). Trước đây nó là cột thứ ba ở mép phải: cột chữ
   bị bóp hẹp nên tiêu đề gãy ba dòng, mà giữa ảnh và nhãn lại hở một mảng trống. */
.tr-doc { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 4px 12px; align-items: start; }
.tr-doc .ic { font-size: var(--fs-emoji); line-height: 1.2; }
.tr-doc-chu > div:first-of-type { margin: 4px 0 2px; }
.tr-alert { border-radius: var(--r); padding: var(--sp12) var(--sp16); margin-bottom: var(--sp12); display: flex; gap: var(--sp12); font-size: var(--fs-sm); border: 1px solid transparent; }
.tr-alert > div { min-width: 0; overflow-wrap: break-word; }
.tr-alert a { color: inherit; font-weight: 600; }
.tr-alert.red { background: var(--danger-bg); color: var(--danger-fg); border-color: var(--danger-line); }
.tr-alert.amber { background: var(--warn-bg); color: var(--warn-fg); border-color: var(--warn-line); }
.tr-alert.ok { background: var(--ok-bg); color: var(--ok-fg); border-color: var(--ok-line); }
.tr-alert b { display: block; margin-bottom: 2px; }
.tr-checks { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 8px; }
.tr-checks li { display: flex; gap: var(--gap-grid); font-size: var(--fs-sm); }
.tr-checks .ok, .tr-checks .no { width: 22px; height: 22px; border-radius: 50%; flex: none; display: grid; place-items: center; font-size: var(--fs-xs); font-weight: 700; }
.tr-checks .ok { background: var(--mint); color: var(--on-mint); }
.tr-checks .no { background: var(--panel-3); color: var(--muted); }
.tr-tl { position: relative; display: flex; flex-direction: column; gap: var(--sp12); }
.tr-tl::before { content: ''; position: absolute; left: 19px; top: 10px; bottom: 10px; width: 2px; background: var(--line-2); }
.tr-ev { display: flex; gap: 12px; position: relative; }
.tr-ev .d { width: var(--ico-sm); height: var(--ico-sm); border-radius: var(--r-sm); background: var(--panel); border: 1px solid var(--line-2); display: grid; place-items: center; font-size: var(--fs-emoji-inline); flex: none; z-index: 1; }
.tr-ev.verify .d { background: var(--brand-grad); border: 0; }
.tr-ev.void { opacity: .5; }
.tr-ev.void h3 { text-decoration: line-through; }
.tr-ev .b { flex: 1; min-width: 0; background: var(--panel); border: 1px solid var(--line); border-radius: 18px; padding: var(--card-pad-dense); }
.tr-ev h3 { font-size: var(--fs-body); margin: 0; }
.tr-ev .w { font-size: var(--fs-xs); color: var(--muted); }
.tr-ev dl { display: grid; grid-template-columns: fit-content(40%) minmax(0, 1fr); gap: var(--sp4) var(--gap-grid); font-size: var(--fs-sm); margin: var(--sp6) 0 0; }
.tr-ev dt { color: var(--muted); }
.tr-ev dd { margin: 0; overflow-wrap: anywhere; }
@media (max-width: 420px) {
  .tr-ev dt { font-size: var(--fs-xs); }
}
.tr-ev .ph { display: flex; gap: 6px; margin-top: 8px; overflow-x: auto; }
.tr-ev .ph img { width: 96px; height: 72px; border-radius: 12px; object-fit: cover; flex: none; cursor: zoom-in; }
.tr-ev .by { font-size: var(--fs-xs); color: var(--muted); margin-top: var(--sp6); }
.tr-ev .by a { color: inherit; }
.tr-tags { display: flex; gap: var(--sp4); flex-wrap: wrap; margin-top: var(--sp6); }
.tag { font-size: var(--fs-xs); padding: 2px 8px; border-radius: 99px; background: var(--panel-3); color: var(--text-2); font-weight: 500; }
.tag.g { background: var(--ok-bg); color: var(--ok-fg); }
.tag.a { background: var(--warn-bg); color: var(--warn-fg); }
.tag.r { background: var(--danger-bg); color: var(--danger-fg); }
a.tag { text-decoration: none; }
.tr-sheet .btn-verify { width: 100%; }
/* nút kiểm tra khóa lại khi đang tính / đã có kết quả: giữ màu đậm để chữ kết quả vẫn đọc rõ */
.btn-verify[disabled] { opacity: 1; }
.tr-verify-out { margin-top: var(--gap-grid); font-size: var(--fs-sm); display: flex; flex-direction: column; gap: var(--sp6); }
.tr-verify-out div { display: flex; gap: 8px; align-items: flex-start; }
.tr-foot { color: var(--muted); line-height: 2.4; }
/* vùng chạm cao hơn chữ (chữ nhỏ vẫn đủ 44px) mà không làm dòng chữ giãn thêm */
.tr-foot a { color: inherit; padding-block: 15px; }
/* Thanh lối tắt: hai mép cách đều (lấy vùng an toàn lớn hơn), gần trọn bề ngang, tối đa bằng cột 560px;
   ba nút bằng nhau (lưới 3 cột), chữ không xuống dòng, nằm trên vùng an toàn phía dưới */
/* VỪ FIXED, VỪ CHỪ CHỖ SẴN Ở CUỐI TRANG.
   Đã thử sticky: trên máy thật nó bám vào KHUNG NHÌN BỐ CỤC, mà vụt lên ẩn thanh công cụ
   trình duyệt thì khung ấy không còn khớp vùng nhìn thật — thanh trôi lềnh bềnh giữa nội dung,
   cách đáy màn hình cả trăm điểm. Chụp trên iPhone Safari thấy rõ.
   fixed thì trình duyệt neo theo vùng nhìn THẬT nên luôn đúng đáy; cái giá của fixed là nó đè lên
   nội dung ở cuối trang — trả bằng padding-bottom chừa sẵn chỗ đúng bằng thanh (xem .tr-wrap).
   --bar-h là chiều cao thật: 48 (nút) + 2×6 (đệm) + 2×1 (viền). */
.tr-bar { --bar-x: max(10px, env(safe-area-inset-left), env(safe-area-inset-right));
  --bar-y: max(12px, calc(env(safe-area-inset-bottom) + 6px));
  position: fixed; left: var(--bar-x); right: var(--bar-x); z-index: 30;
  /* --vv-lech do public/js/app.js đo từ visualViewport; tắt JavaScript thì là 0, về đúng nếp cũ. */
  bottom: calc(var(--bar-y) + var(--vv-lech, 0px));
  max-width: 536px; margin: 0 auto;
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 6px; padding: 6px; border-radius: 99px;
  background: var(--glass-strong); border: 1px solid var(--line); backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px); box-shadow: 0 18px 40px -12px rgba(21, 94, 210, .38); }
/* nút phụ: viên thuốc bạc hà nhạt chữ xanh lá đậm; nút giữa: xanh dương chữ trắng */
.tr-bar a { min-width: 0; display: flex; align-items: center; justify-content: center; gap: 6px; height: 48px; padding: 0 6px; white-space: nowrap; overflow: hidden;
  border-radius: 99px; color: var(--mint-text); text-decoration: none; font-size: var(--fs-sm); font-weight: 600; background: var(--mint-soft); box-shadow: inset 0 0 0 1px var(--mint-line); }
.tr-bar a.main { background: var(--accent-grad); color: var(--on-accent); box-shadow: var(--shadow-btn); }
.tr-ev.verify .d, .tl-item.is-verify .tl-dot { box-shadow: 0 6px 14px -8px rgba(18, 129, 74, .6); }
@media (max-width: 359px) { .tr-bar { gap: 4px; padding: 5px; } .tr-bar a { gap: var(--sp4); height: 46px; padding: 0 var(--sp4); font-size: var(--fs-xs); } }
.lightbox { position: fixed; inset: 0; background: rgba(6, 14, 34, .92); z-index: 200; display: grid; place-items: center; padding: 16px; cursor: zoom-out; }
.lightbox img { max-height: 90vh; max-height: 90dvh; max-width: 100%; object-fit: contain; border-radius: 16px; }
.lightbox button { position: absolute; top: max(12px, env(safe-area-inset-top)); right: 12px; width: 46px; height: 46px; border-radius: 50%; border: 1px solid rgba(255, 255, 255, .35);
  background: rgba(255, 255, 255, .16); color: #fff; font-size: var(--fs-h2); cursor: pointer; }

/* Đăng nhập / đăng ký kiểu ảnh mẫu: khối xanh dương (thương hiệu + lời chào chữ trắng) chồng lên trường bạc hà, khung biểu mẫu là tấm kính mờ trắng
   đè lên phần màu; ô nhập trắng hình viên thuốc, nút chính xanh dương, liên kết “Đăng ký” xanh lá.
   Điện thoại: lời chào chỉ chiếm 72% bề ngang, khối xanh dương rộng 78% (mép cong cách chữ ≥ 13px ở 320–414px), phần phải là bạc hà có cây sen đá.
   Máy tính: khối xanh dương phủ góc trên trái (62% × 68%), bán kính theo % nên đường cong luôn nằm ngoài lời chào ở mọi cỡ màn. */
.auth { min-height: 100vh; display: grid; grid-template-columns: 1fr; grid-template-rows: auto 1fr; position: relative; isolation: isolate; }
.auth-art { position: relative; overflow: hidden; isolation: isolate; display: flex; flex-direction: column; gap: var(--sp16); padding: max(var(--sp20), env(safe-area-inset-top)) var(--sp20) 100px; color: var(--on-grad); border-radius: 0 0 36px 36px;
  background: radial-gradient(circle 46px at calc(100% - 26px) 26px, rgba(255, 255, 255, .28) 99%, transparent 100%), radial-gradient(circle 20px at 84% 78%, rgba(255, 255, 255, .3) 99%, transparent 100%), var(--mint-field); }
.auth-art::before { content: ''; position: absolute; z-index: -1; pointer-events: none; top: 0; left: 0; right: 22%; bottom: 40px; border-radius: 0 110px 140px 0 / 0 70px 110px 0;
  background: radial-gradient(circle 70px at 0% 100%, rgba(8, 40, 120, .14) 99%, transparent 100%), var(--blue-shape); box-shadow: var(--duo-glow); }
.auth-art .brand { color: var(--on-grad); position: relative; z-index: 1; }
.auth-art .brand small { color: var(--on-grad-2); }
.auth-art .rosette { position: absolute; width: 160px; right: -70px; bottom: 18px; opacity: .95; filter: drop-shadow(0 16px 20px rgba(10, 30, 90, .25)); }
.auth-art h2 { position: relative; z-index: 1; font-size: var(--fs-display); color: var(--on-grad); line-height: 1.1; font-weight: 700; letter-spacing: -.03em; max-width: 72%; margin: 0; text-shadow: var(--grad-text-shadow); }
/* đoạn chữ phía dưới (máy tính) nằm trên panel kính mờ bạc hà (chữ xanh đen) để không lẫn với hình cây */
.auth-art > p, .auth-art > .check-list { display: none; position: relative; z-index: 1; max-width: 400px; margin: 0; padding: var(--card-pad-dense); border-radius: 20px; color: var(--text); background: var(--glass-mint);
  border: 1px solid var(--glass-line); backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px); box-shadow: 0 16px 36px -22px rgba(10, 50, 60, .5); }
.auth-box { position: relative; z-index: 1; margin: -52px var(--sp12) var(--sp24); padding: var(--sp24) var(--sp20); border-radius: 30px; color: var(--text); display: flex; flex-direction: column;
  background: rgba(255, 255, 255, .86); border: 1px solid rgba(255, 255, 255, .9); backdrop-filter: blur(18px) saturate(1.3); -webkit-backdrop-filter: blur(18px) saturate(1.3);
  box-shadow: 0 24px 50px -26px rgba(10, 40, 110, .45), 0 10px 30px -20px rgba(18, 129, 74, .4); }
.auth-box .inner { width: 100%; max-width: 440px; margin: 0 auto; }
.auth-box h1 { font-size: var(--fs-display); margin: var(--sp12) 0 var(--sp6); }
.auth-box :is(input[type=tel], input[type=password], input[type=text], input[type=email]) { border-radius: 999px; padding-left: 20px; padding-right: 20px; }
.auth-box .input-ico > input { padding-left: 48px; }
.auth-box .input-ico > .i { left: 18px; }
@media (min-width: 960px) {
  .auth { grid-template-columns: 1fr 1fr; grid-template-rows: none; background: radial-gradient(circle 260px at 100% 0%, rgba(255, 255, 255, .22) 99%, transparent 100%), radial-gradient(circle 80px at 44% 92%, rgba(255, 255, 255, .24) 99%, transparent 100%), var(--mint-field); }
  .auth::before { content: ''; position: absolute; z-index: -1; pointer-events: none; top: 0; left: 0; width: 62%; height: 68%; border-radius: 0 50% 60% 0 / 0 30% 50% 0;
    background: radial-gradient(circle 160px at 0% 100%, rgba(8, 40, 120, .14) 99%, transparent 100%), var(--blue-shape); box-shadow: var(--duo-glow); }
  .auth-art { display: flex; justify-content: space-between; padding: 48px; background: none; isolation: auto; border-radius: 0; }
  .auth-art::before { display: none; }
  .auth-art h2 { line-height: 1.05; max-width: 420px; }
  .auth-art > p, .auth-art > .check-list { display: block; }
  .auth-art .rosette { width: 460px; right: -120px; bottom: -80px; }
  .auth-box { margin: 28px 28px 28px 0; border-radius: 36px; padding: 48px 64px; justify-content: center; }
}
/* Lỗi */
/* Trang báo lỗi / cổng QR nhập liệu: cùng bộ hai màu như các trang khác — trường bạc hà bo cong ở mép trên,
   khối xanh dương lệch trái chồng lên. Hai khối chỉ nằm sau ô biểu tượng (cao 150px), KHÔNG bao giờ nằm dưới chữ xanh đen. */
.err-page { min-height: 70vh; display: grid; place-items: center; text-align: center; padding: 40px 16px; position: relative; overflow: hidden; isolation: isolate; }
.err-page::before, .err-page::after { content: ''; position: absolute; z-index: -1; pointer-events: none; top: 0; }
.err-page::before { left: -14%; right: -14%; height: 150px; border-bottom-left-radius: 50% 60px; border-bottom-right-radius: 74% 110px; background: var(--mint-field); }
.err-page::after { left: -20%; width: 64%; height: 104px; border-bottom-right-radius: 92% 90px; background: var(--blue-shape); box-shadow: var(--duo-glow); }
.err-page .big { position: relative; font-size: 4rem; width: 112px; height: 112px; margin: 0 auto 12px; border-radius: 32px; display: grid; place-items: center; background: var(--glass-strong); border: 1px solid var(--glass-line); box-shadow: var(--shadow-soft); backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px); }
/* hai nút bằng nhau trong lề, nút lẻ trải hết bề ngang (cùng khuôn .btn-grid) */
.err-page h1 { font-size: var(--fs-display); }
.err-page .btn-grid { width: 100%; max-width: 380px; margin: var(--gap-card) auto 0; }
.err-page .alert { text-align: left; }

/* In ấn: ẩn khung khi in trang thường */
@media print {
  .bnav, .side, .topbar, .fab, .site-nav, .site-foot, .tr-bar, .no-print { display: none !important; }
  body { background: #fff !important; color: #000 !important; }
}

/* ============================================================
   BIỂU ĐỒ (thời tiết, NDVI, quản trị) — bảng màu cho nền sáng
   ============================================================ */
/* Màu chuỗi số liệu khai báo ở :root (--chart-*); chú giải, nhãn và bảng số liệu luôn đi kèm biểu đồ. */
.viz, .viz-table { --viz-rain: var(--chart-rain); --viz-temp: var(--chart-temp); --viz-ndvi: var(--chart-ndvi); --viz-grid: var(--chart-grid); --viz-axis: var(--chart-axis);
  --viz-text: var(--muted); --viz-label: var(--chart-label); --viz-mark: rgba(15, 27, 61, .22); --viz-surface: var(--panel); position: relative; }
.tr-card .viz, .tr-card .viz-table { --viz-surface: var(--bg-2); }
.viz-svg { width: 100%; height: auto; display: block; overflow: visible; }
.viz-grid { stroke: var(--viz-grid); stroke-width: 1; }
.viz-axis { stroke: var(--viz-axis); stroke-width: 1; }
.viz-tick { fill: var(--viz-text); font-size: 10.5px; font-family: var(--font); font-variant-numeric: tabular-nums; }
.viz-label { fill: var(--viz-label); font-size: 11px; font-weight: 600; font-family: var(--font); }
.viz-emo { font-size: 11px; }
.viz-mark { stroke: var(--viz-mark); stroke-width: 1; }
.viz-rain, .viz-bar { fill: var(--viz-rain); }
.viz-band { fill: var(--viz-temp); opacity: .13; }
.viz-line { fill: none; stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.viz-temp-line { stroke: var(--viz-temp); }
.viz-ndvi-line { stroke: var(--viz-ndvi); }
.viz-dot { stroke: var(--viz-surface); stroke-width: 2; }
.viz-temp-dot { fill: var(--viz-temp); }
.viz-ndvi-dot { fill: var(--viz-ndvi); }
.viz-cloud { fill: none; stroke: var(--viz-text); stroke-width: 1.5; }
.viz-x { stroke: var(--viz-label); stroke-width: 1; }
.viz-hit { cursor: crosshair; outline: none; touch-action: pan-y; }
.viz-hit:focus-visible { outline: 2px solid var(--accent); }
.viz-tip { position: absolute; pointer-events: none; z-index: 5; background: var(--glass-strong); color: var(--text); border: 1px solid var(--line); border-radius: 12px;
  padding: var(--sp8) var(--sp12); font-size: var(--fs-sm); min-width: 160px; box-shadow: var(--shadow); }
.viz-tip b { display: block; margin-bottom: 4px; }
.viz-tip div { display: flex; justify-content: space-between; gap: 12px; }
.viz-tip span { color: var(--muted); }
/* Khung hẹp (điện thoại): ô số liệu thành dải gọn ghim ngay trên biểu đồ (che phần chú giải), không đè lên cột, đường dóng hay ngón tay */
.viz-tip.pin { right: 0; min-width: 0; display: flex; flex-wrap: wrap; gap: 1px var(--sp12); padding: var(--sp6) var(--sp12); font-size: var(--fs-xs); line-height: 1.35; }
.viz-tip.pin b { width: 100%; margin: 0; }
.viz-tip.pin div { display: inline-flex; gap: 4px; }
.viz-legend { display: flex; gap: var(--sp6) var(--sp12); flex-wrap: wrap; font-size: var(--fs-xs); margin: var(--sp4) 0 var(--sp6); color: var(--text-2); }
.viz-legend i { display: inline-block; width: 14px; height: 10px; border-radius: 3px; margin-right: 6px; vertical-align: middle; }
.tr-sheet .viz-legend { font-size: var(--fs-xs); }
.key-rain { background: var(--viz-rain); }
.key-temp { background: color-mix(in srgb, var(--viz-temp) 22%, transparent); border-top: 2px solid var(--viz-temp); }
.key-ndvi { height: 2px !important; background: var(--viz-ndvi); border-radius: 0 !important; }
.key-mark { width: 1px !important; height: 12px !important; background: var(--viz-text); border-radius: 0 !important; }
.viz-table summary { cursor: pointer; font-size: var(--fs-sm); color: var(--accent-text); font-weight: 500; margin-top: 0; min-height: var(--h-chip); display: flex; align-items: center; padding: var(--sp8) 0; }
.viz-table .scroll { max-height: 260px; overflow: auto; margin-top: 6px; }
.viz-table table { font-size: var(--fs-xs); width: 100%; border-collapse: collapse; font-variant-numeric: tabular-nums; }
.viz-table td, .viz-table th { padding: var(--sp4) var(--sp6); border-bottom: 1px solid var(--line); text-align: right; white-space: nowrap; }
/* tiêu đề cột dính trên cùng khi cuộn trong khung bảng */
.viz-table th { font-weight: 600; line-height: 1.2; vertical-align: bottom; position: sticky; top: 0; z-index: 1; background: var(--viz-surface); }
.viz-table th small { display: block; font-size: var(--fs-xs); font-weight: 400; color: var(--viz-text); white-space: normal; }
.viz-table td:first-child, .viz-table th:first-child { text-align: left; padding-left: 0; }
.viz-table td:last-child, .viz-table th:last-child { padding-right: 0; }
@media (max-width: 420px) { .viz-table table { font-size: var(--fs-xs); } .viz-table td, .viz-table th { padding: 4px; } }
/* Hai bản biểu đồ (rộng 640 / gọn 360): khung dưới 480px dùng bản gọn. Cỡ chữ SVG được nhân với tỉ lệ
   viewBox / bề rộng khung (tan(atan2(a, b)) = a / b) nên chữ trên màn hình luôn ~11–12px dù biểu đồ co giãn. */
.viz { container-type: inline-size; }
.viz-sm { display: none; }
@container (max-width: 479px) { .viz-wide { display: none; } .viz-sm { display: block; } }
@supports not (container-type: inline-size) { @media (max-width: 560px) { .viz-wide { display: none; } .viz-sm { display: block; } } }
.viz-sm .viz-tick { font-size: 14px; }
.viz-sm .viz-label, .viz-sm .viz-emo { font-size: 15px; }
@supports (font-size: calc(1px * tan(atan2(1px, 100cqw)))) {
  .viz-wide { --viz-k: tan(atan2(640px, 100cqw)); }
  .viz-sm { --viz-k: tan(atan2(360px, 100cqw)); }
  :is(.viz-wide, .viz-sm) .viz-tick { font-size: calc(11px * var(--viz-k)); }
  :is(.viz-wide, .viz-sm) :is(.viz-label, .viz-emo) { font-size: calc(12px * var(--viz-k)); }
}
.env-verdict { display: flex; flex-wrap: wrap; gap: 6px 8px; align-items: flex-start; }
.env-verdict > .badge { flex: none; }
.env-verdict > span:last-child { flex: 1 1 260px; min-width: 0; }
.admin-levels { display: flex; flex-direction: column; gap: var(--sp12); }
.admin-levels .row { flex-wrap: nowrap; }
.admin-levels .track { flex: 1; height: 12px; border-radius: 99px; background: var(--panel-3); overflow: hidden; }
.admin-levels .track span { display: block; height: 100%; background: var(--viz-rain); border-radius: 0 4px 4px 0; }

/* ============================================================
   DÒNG THỜI GIAN HAI LUỒNG: nông hộ ghi ↔ môi trường thực tế
   ============================================================ */
.lanes { container: lanes / inline-size; --ln-card: var(--panel); --ln-env: var(--info-bg); --ln-env-line: var(--env-line); --ln-line: var(--line); --ln-muted: var(--muted); --ln-chip: var(--panel); --ln-head: var(--panel); }
.tr-card .lanes { --ln-head: var(--bg-2); }
.lanes-head { display: grid; grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr); gap: 8px; position: sticky; top: 0; z-index: 3; background: var(--ln-head); padding: 8px 0; border-radius: 0 0 10px 10px; }
/* Hai nhãn cột phải XUỐNG DÒNG ĐƯỢC, không đẩy rộng cả trang: nhãn tiếng Anh ("Measured
   conditions") dài hơn tiếng Việt, mà flex mặc định không cho ngắt dòng nên nó nong cột ra
   quá khung và cả trang cuộn ngang được ở 390px. */
.lanes-head div { font-size: var(--fs-xs); letter-spacing: .08em; text-transform: uppercase; font-weight: 700; color: var(--ln-muted); display: flex; align-items: center; gap: 6px; flex-wrap: wrap; min-width: 0; }
.lane-date { display: flex; align-items: center; gap: var(--gap-grid); font-size: var(--fs-xs); font-weight: 700; color: var(--ln-muted); margin: 12px 0 6px; }
.lane-date::after { content: ''; flex: 1; height: 1px; background: var(--ln-line); }
.lane-row { display: grid; grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr); gap: 8px; align-items: start; }
.lane-f { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.lane-card { background: var(--ln-card); border: 1px solid var(--ln-line); border-radius: 16px; padding: var(--sp8); min-width: 0; box-shadow: 0 6px 16px -14px rgba(var(--accent-rgb), .5); }
.lane-card h4 { margin: 0; font-size: var(--fs-sm); display: flex; gap: 6px; align-items: center; }
.lane-card .w { font-size: var(--fs-xs); color: var(--ln-muted); }
.lane-card dl { display: grid; grid-template-columns: fit-content(45%) minmax(0, 1fr); gap: 1px var(--gap-grid); font-size: var(--fs-xs); margin: var(--sp4) 0 0; }
.lane-card dt { color: var(--ln-muted); }
.lane-card dd { margin: 0; overflow-wrap: anywhere; }
.lane-card .ph { display: flex; gap: var(--sp4); margin-top: var(--sp6); overflow-x: auto; }
.lane-card .ph img { width: 64px; height: 48px; object-fit: cover; border-radius: 10px; flex: none; cursor: zoom-in; }
.lane-card .lane-flag + .ph { margin-top: 8px; }
.lane-card.void { opacity: .5; }
.lane-card.void h4 { text-decoration: line-through; }
.lane-card.verify { border-color: var(--ok-line); background: linear-gradient(180deg, var(--ok-bg), var(--ln-card) 60%); }
.lane-env { background: var(--ln-env); border-left: 3px solid var(--ln-env-line); border-radius: var(--sp12) var(--r-field) var(--r-field) var(--sp12); padding: var(--sp8); font-size: var(--fs-xs); min-width: 0; overflow-wrap: anywhere; }
.lane-env .big { font-size: var(--fs-body); font-weight: 600; display: flex; align-items: center; gap: 6px; }
/* mưa to: mỗi ngày một dòng “11/09 · 42 mm” — không bao giờ tràn khỏi ô xanh */
.lane-env .heavy span { display: block; }
.env-chips { display: flex; gap: var(--sp4); flex-wrap: wrap; margin-top: var(--sp4); }
.env-chips span { font-size: var(--fs-xs); padding: 2px var(--sp6); border-radius: 99px; background: var(--ln-chip); border: 1px solid var(--ln-line); white-space: nowrap; }
.lane-env .sat { margin-top: var(--sp6); font-size: var(--fs-xs); }
.lane-env .none { color: var(--ln-muted); font-style: italic; }
.lane-gap { display: grid; grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr); gap: var(--gap-grid); margin: var(--sp8) 0; align-items: center; }
.lane-gap .quiet { font-size: var(--fs-xs); color: var(--ln-muted); text-align: center; border: 1px dashed var(--line-2); border-radius: 12px; padding: 8px; }
.lane-flag { font-size: var(--fs-xs); padding: var(--sp6) var(--sp8); border-radius: var(--r-xs); background: var(--warn-bg); color: var(--warn-fg); margin-top: 6px; }
@media (max-width: 420px) {
  .lane-row, .lanes-head, .lane-gap { grid-template-columns: minmax(0, 1.1fr) minmax(0, .9fr); gap: 6px; }
  .lanes-head div { letter-spacing: .04em; gap: 4px; align-items: flex-start; }
  .lane-card { padding: var(--sp8); }
  .lane-card h4 { align-items: flex-start; overflow-wrap: anywhere; }

  .lane-env { padding: var(--sp8); }
  .lane-env .big { flex-wrap: wrap; }
  .env-chips span { padding: 2px var(--sp6); }
}
/* luồng hẹp (điện thoại, nhất là trong khu làm việc): tiêu đề cột rút gọn, số nhiệt độ nhỏ lại */
@container lanes (max-width: 340px) {
  .lanes-head .hide-xs { display: none; }
  .lane-env .big { font-size: var(--fs-body); gap: var(--sp4); }
  /* cột hẹp (máy 320px): chip thời tiết dài được xuống dòng bên trong thay vì bị mép khối gọt mất phần trăm */
  .env-chips { min-width: 0; }
  .env-chips span { white-space: normal; max-width: 100%; }
}
@container lanes (max-width: 260px) {
  .lane-env { padding: var(--sp6); font-size: var(--fs-xs); }
  .lane-card { padding: var(--sp6); }
}
@media (min-width: 1024px) { .mobile-menu-card { display: none; } }

@media (max-width: 1023px) { .desktop-only { display: none !important; } }
.demo-acc { display: flex; align-items: center; gap: var(--sp12); width: 100%; padding: var(--sp12); border-radius: var(--r); border: 1px solid var(--line); background: var(--panel); color: var(--text); font: inherit; cursor: pointer; transition: border-color .15s, background .15s, box-shadow .15s; box-shadow: var(--shadow-card); }
/* số điện thoại + mật khẩu mẫu: máy tính nằm bên phải; điện thoại xuống dòng riêng thụt bằng ô biểu tượng,
   để cột chữ đủ rộng — tên không còn vỡ thành “Nguyễn Văn / Nam” */
.demo-acc .demo-cred { text-align: right; flex: none; }
@media (max-width: 430px) {
  .demo-acc { flex-wrap: wrap; row-gap: var(--sp4); }
  .demo-acc .demo-cred { flex: 1 0 100%; text-align: left; padding-left: calc(var(--ico-sm) + var(--sp12)); }
  .demo-acc .demo-cred > .tiny { display: inline !important; margin-left: var(--sp8); }
}
.demo-acc:hover { border-color: var(--accent-line); }
.demo-acc.on { border-color: var(--accent); background: var(--accent-soft); box-shadow: 0 0 0 1px var(--accent) inset; }

/* ============================================================
   ẢNH BẰNG CHỨNG TRONG THẺ NÔNG HỘ GHI
   Điện thoại (và cột trang QR luôn hẹp): chữ ở trên, ảnh bên dưới gần trọn bề ngang thẻ, khung 4:3;
   nhiều ảnh thì vuốt ngang (scroll-snap), ảnh sau ló ra một chút; chạm để phóng to. Máy tính trong khu làm việc giữ ảnh nhỏ.
   ============================================================ */
.tr-sheet .lane-card .ph, .tr-ev .ph, .ev-photos {
  display: flex; gap: var(--gap-grid); margin-top: var(--sp12); overflow-x: auto; scroll-snap-type: x mandatory; overscroll-behavior-x: contain; scrollbar-width: thin; border-radius: 12px; }
.tr-sheet .lane-card .ph img, .tr-ev .ph img, .ev-photos img {
  flex: 0 0 100%; width: 100%; height: auto; aspect-ratio: 4 / 3; object-fit: cover; border-radius: 12px; scroll-snap-align: start; cursor: zoom-in; background: var(--panel-2); }
.tr-sheet .lane-card .ph.multi img, .tr-ev .ph.multi img, .ev-photos.multi img { flex-basis: calc(100% - 26px); }
.tr-sheet .lane-card .ph { gap: 6px; }
.tr-sheet .lane-card .ph img { border-radius: 10px; }
.tr-sheet .lane-card .ph.multi img { flex-basis: calc(100% - 18px); }
@media (max-width: 640px) {
  .lane-card .ph, .tl-photos { gap: 6px; overflow-x: auto; scroll-snap-type: x mandatory; overscroll-behavior-x: contain; scrollbar-width: thin; border-radius: 12px; }
  .lane-card .ph img, .tl-photos img { flex: 0 0 100%; width: 100%; height: auto; aspect-ratio: 4 / 3; object-fit: cover; border-radius: 12px; scroll-snap-align: start; cursor: zoom-in; }
  .lane-card .ph.multi img { flex-basis: calc(100% - 18px); }
  .tl-photos.multi img { flex-basis: calc(100% - 26px); }
}
.tl-photos img { cursor: zoom-in; }

/* ============================================================
   ĐIỆN THOẠI: vùng chạm ≥ 44px, thẻ đỡ chật, các chỗ xuống dòng khó coi
   ============================================================ */
@media (max-width: 640px), (pointer: coarse) {
  .btn-sm { min-height: var(--h-chip); }
  .chip { min-height: var(--h-chip); }
  .tabs a { min-height: var(--h-chip); display: inline-flex; align-items: center; }
}
@media (max-width: 420px) {
  .card { padding: var(--card-pad); }
  details.fold > summary { padding: var(--sp12) var(--sp16); min-height: var(--h-btn); }
  details.fold > .fold-body { padding: 0 var(--sp12) var(--sp12); }
}
.tr-ev .by a { white-space: nowrap; }

/* Đầu trang lô (khu làm việc): biểu tượng – nội dung – vòng cấp độ; điện thoại ẩn biểu tượng để phần chữ đủ rộng */
.lot-head { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: var(--sp16); align-items: start; }
.lot-head h1 { font-size: var(--fs-page); margin: 0 0 var(--sp4); overflow-wrap: anywhere; }
/* dấu “·” nằm trong khe giữa hai mục; mục nào bắt đầu dòng mới thì dấu rơi ra ngoài mép trái và bị cắt đi */
.lot-meta { display: flex; flex-wrap: wrap; gap: var(--sp4) var(--sp16); font-size: var(--fs-sm); color: var(--muted); overflow: hidden; }
.lot-meta > span { position: relative; min-width: 0; }
.lot-meta > span + span::before { content: '·'; position: absolute; left: -10px; }
.lot-meta .mono { font-size: var(--fs-sm); }
@media (max-width: 480px) {
  .lot-head { grid-template-columns: minmax(0, 1fr) auto; gap: var(--sp12); }
  .lot-head > .lot-emo { display: none; }
  .lot-head .lv-ring { width: 50px; height: 50px; font-size: var(--fs-h2); }
  /* nút đầu trang lô: ô bằng nhau, cao bằng nhau kể cả khi nhãn vỡ 2 dòng */
  .lot-actions { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--gap-grid); align-items: stretch; grid-auto-rows: 1fr; }
  .lot-actions .btn { padding: var(--sp8); white-space: normal; text-align: center; line-height: 1.2; }
  /* nút lẻ cuối hàng trải hết bề ngang thay vì đứng trơ một nửa */
  .lot-actions > .btn:last-child:nth-child(odd) { grid-column: 1 / -1; }
}

/* ===== NHÓM TRANG NÔNG DÂN — tỷ lệ & nhịp (chỉ dùng biến của HỆ KÍCH THƯỚC ở đầu tệp) =====
   Dùng cho /app, /app/lo, /app/lo/:id, /app/lo/moi, form ghi, /app/su-co. */
/* biểu tượng đầu trang lô = cỡ ô đầu trang (64px), khác hẳn ô 52px trong lưới và ô 40px cạnh một dòng chữ */
.lot-head > .lot-emo { width: var(--ico-lg); height: var(--ico-lg); font-size: var(--fs-emoji-lg); }
/* Lưới ô khi số cột được đặt cứng (--cols-lg): ô co được, bỏ sàn 104px của auto-fill
   ⇒ trong cột hẹp của màn rộng, lưới không bao giờ tràn ra ngoài thẻ. */
@media (min-width: 640px) { .tiles.tiles-cols { grid-template-columns: repeat(var(--cols-lg, 4), minmax(0, 1fr)); } }
/* dải nhãn trạng thái dưới tiêu đề lô: coi như dòng phụ — xuống dòng gọn, tối đa 2 dòng, không cắt mất nhãn nào */
.lot-badges { display: flex; flex-wrap: wrap; gap: var(--sp6); }
@media (max-width: 430px) { .lot-badges > .meta-drop { display: none; } }
/* tiêu đề khối nằm ngoài thẻ (“Nhật ký”, …): cùng bậc với tiêu đề thẻ, không tự đặt cỡ riêng trong view */
.block-h2 { font-size: var(--fs-h2); margin: 0; }
/* lưới ô số liệu: ô bằng nhau tuyệt đối, một cỡ con số duy nhất (khuôn của /app/phieu-giao/:id) */
.stat-grid { display: grid; grid-template-columns: repeat(var(--cols, 2), minmax(0, 1fr)); gap: var(--gap-grid); grid-auto-rows: 1fr; }
.stat-grid .stat-num { font-size: var(--fs-page); }
/* nhãn ô lưới luôn chiếm đúng 2 dòng ⇒ mọi lưới ô trong app cao bằng nhau, dù nhãn dài ngắn khác nhau */
.tile > .tile-name { min-height: 2.5em; }
/* Tổng quan: hai ô số liệu nhỏ cao bằng nhau; màn rất hẹp thì nhãn xuống dòng dưới con số để không vỡ 3 dòng */
.dash-stat { display: flex; gap: var(--gap-card); align-items: center; }
.dash-mini { display: grid; gap: var(--gap-grid); grid-auto-rows: 1fr; flex: 1; min-width: 0; }
.dash-mini > .row { padding: var(--sp8) var(--sp12); border-radius: var(--r-sm); border: 1px solid var(--line); gap: var(--gap-grid); }
.dash-total { margin-left: auto; text-align: right; flex: none; }
@media (max-width: 374px) { .dash-mini > .row > .small { flex: 1 0 100%; } }
/* khối rỗng nằm trong thẻ: đệm theo thang, không đặt riêng trong view */
.empty-sm { padding: var(--sp20) var(--sp16); }
/* ô tìm lô cạnh thanh lọc: cao bằng ô nhập chung, màn hẹp thì trải hết hàng thay vì đứng lẻ 220px */
.lots-search { flex: 1 1 200px; min-width: 0; max-width: 320px; }
/* biểu tượng công đoạn ở đầu form ghi: cỡ ô đầu trang, nền hai màu */
.step-ico { width: var(--ico-lg); height: var(--ico-lg); font-size: var(--fs-emoji-lg); background: var(--brand-grad); border: 0; color: #fff; }

/* Hủy / hoàn tác bản ghi: khi mở, khung xác nhận chiếm trọn hàng thay vì ép bề rộng tối thiểu */
.tl-actions details[open] { flex-basis: 100%; }
.tl-void-form { padding: var(--sp12); width: 100%; max-width: 420px; }
.tl-void-form .btn { margin-top: 4px; }

/* Ô công đoạn: 4 cột co được (minmax 0) để 320px không tràn; biểu tượng nhỏ lại trên màn rất hẹp */
@media (max-width: 639px) { .tiles { grid-template-columns: repeat(var(--cols, 4), minmax(0, 1fr)); } }
.tile { min-width: 0; overflow-wrap: anywhere; }
/* dấu đếm và dấu ✓ bám mép phải ô biểu tượng 52px (26px + nửa dấu) — ô hẹp thì lùi về mép ô */
.tile .count { right: max(0px, calc(50% - 30px)); }
.tile.done .tile-ico::after { right: max(0px, calc(50% - 28px)); }
@media (max-width: 374px) {
  .tiles { gap: var(--sp6); }
  .tile { padding: var(--sp8) 0; }
}

/* Trường của bản ghi (khu làm việc): nhãn không chiếm quá nửa; điện thoại xếp nhãn nhỏ phía trên giá trị */
.tl-fields { grid-template-columns: fit-content(45%) minmax(0, 1fr); }
.tl-fields dd { overflow-wrap: anywhere; }
@media (max-width: 420px) {
  .tl-fields dt { font-size: var(--fs-xs); }
}
/* Nhãn – giá trị: dòng nào nội dung (hoặc nhãn) dài quá một dòng thì nhãn nằm trên, nội dung xuống dưới trải hết bề ngang
   (app.js đo và gắn .kv-stack); dòng ngắn giữ nhãn và nội dung cùng hàng. Nhãn và nội dung vẫn khác màu để dễ nhận ra */
:is(.tl-fields, .tr-kv, .tr-ev dl, .lane-card dl) > .kv-stack { grid-column: 1 / -1; }
:is(.tl-fields, .tr-kv, .tr-ev dl, .lane-card dl) > dt.kv-stack:not(:first-child) { margin-top: 5px; }
:is(.tl-fields, .tr-kv, .tr-ev dl, .lane-card dl) > dd.kv-stack { margin-bottom: 3px; }

/* Liên kết đứng RIÊNG một dòng giữa thẻ (“Chưa có tài khoản? Đăng ký”, “Xem thử một lô hàng mẫu →”):
   là nút thật chứ không phải chữ trong câu, nên luôn có vùng bấm đủ cao — 40px trên máy tính, 44px khi chạm. */
p.center > .link, .card-title .link { display: inline-flex; align-items: center; justify-content: center; min-height: var(--h-tap-desktop); padding-block: var(--sp8); margin-block: calc(var(--sp8) * -1); }
@media (max-width: 640px), (pointer: coarse) { p.center > .link, .card-title .link { min-height: var(--h-chip); } }
/* Vùng chạm ≥ 44px cho các liên kết nhỏ đứng riêng (không đổi bố cục: nới vùng bấm bằng padding + margin âm) */
@media (max-width: 640px), (pointer: coarse) {
  .back { min-height: var(--h-chip); margin: calc(var(--sp8) * -1) 0 var(--sp4); }
  .site-nav .brand { min-height: 44px; }
  .topbar .brand { min-width: 44px; justify-content: center; }
  a.bubble { min-height: 44px; }
  /* ô tick / ô chọn: to hơn cho ngón tay (ô nào bị ẩn đi vẫn nằm ngoài bố cục nên không ảnh hưởng) */
  input[type=checkbox], input[type=radio] { width: 24px; height: 24px; }
  /* mũi tên gập/mở cũng là một nút bấm */
  summary { min-height: var(--h-chip); }
  .tr-doc a.tag { display: inline-flex; align-items: center; min-height: var(--h-chip); padding: 0 var(--sp12); font-size: var(--fs-xs); }
}

/* ============================================================================================
   NHÓM TRANG CÔNG CỤ — /app/khu · /app/thiet-bi · /app/ban-do-ndvi · /app/moi-truong/nhap ·
   /app/thanh-vien · /app/ho-so-truong · /app/qms · /app/qms/kiem-tra/moi · /app/khac-phuc
   Chỉ KÍCH THƯỚC – TỶ LỆ – NHỊP, lấy từ thang ở đầu tệp (--sp*, --fs-*, --h-*, --ico*, --r*).
   Không màu mới, không đổi tên lớp cũ, không đụng khối HỆ KÍCH THƯỚC.
   ============================================================================================ */

/* Lưới trường nhập: khe ngang theo thang, khe dọc để .field tự lo (margin 16px) — trước đây mỗi biểu mẫu một giá trị gap */
:is(.grid-2, .grid-3).fields { column-gap: var(--sp16); row-gap: 0; }

/* Ô nhập + nút đứng cùng hàng (thêm thành viên, mời hộ): hai ô cao bằng nhau, nút không bao giờ bị bóp */
.row-add { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: var(--gap-grid); align-items: stretch; }
.row-add > * { min-width: 0; }
.row-add .btn { min-height: var(--h-field); }

/* Danh sách người / hộ: ảnh đại diện bằng đúng cỡ ô biểu tượng cạnh một dòng chữ (--ico-sm) */
.list-item > .avatar { width: var(--ico-sm); height: var(--ico-sm); font-size: var(--fs-sm); }

/* Hộp chụp ảnh: ô biểu tượng trong hộp không mang khoảng cách dưới của .stat-ico */
.photo-drop > .stat-ico { margin-bottom: 0; }

/* Chấm điểm kiểm tra nội bộ (/app/qms/kiem-tra/moi): một dòng = lưới chip đều nhau + ô ghi nhận.
   3 chip chia 3 cột; màn rất hẹp về 2 cột, chip lẻ cuối trải hết hàng (khuôn .btn-grid). */
.qi-list { display: flex; flex-direction: column; gap: var(--sp12); }
.qi-item { padding: var(--sp12); }
.qi-row { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--gap-grid); align-items: center; }
.qi-marks { --cols: 3; }
.qi-marks .chip { min-height: var(--h-field); padding: var(--sp6) var(--sp8); }
.qi-marks .chip input { flex: none; }
.qi-note { width: 100%; }
/* điện thoại: 2 ô bằng nhau + ô lẻ cuối trải hết hàng (nhãn “Không áp dụng” đủ chỗ); từ 480px chia đúng 3 cột
   (3 món chia hết cho 3 nên bỏ luật “món lẻ cuối trải hết hàng”, nếu không món thứ 3 lại rơi xuống hàng riêng) */
@media (max-width: 479px) { .qi-marks { --cols: 2; } }
@media (min-width: 480px) { .qi-marks > :last-child:nth-child(odd) { grid-column: auto; } }
@media (min-width: 900px) { .qi-row { grid-template-columns: minmax(280px, 400px) minmax(0, 1fr); } }

/* Chip chọn nhiều (hộ tham dự buổi tập huấn): ô bằng nhau thay vì xuống dòng lởm chởm */
.chip-grid .chip { justify-content: flex-start; text-align: left; }

/* Khắc phục điểm không phù hợp (/app/khac-phuc): xếp dọc — ô nhập trải hết bề ngang (trước bị bóp còn 56–70px),
   ô chọn tệp cao bằng ô nhập, nút chính trải hết thẻ. */
.nc-form { display: grid; gap: var(--gap-grid); }
.nc-form > * { min-width: 0; }
.nc-form input[type=file] { width: 100%; min-height: var(--h-field); padding: var(--sp12) var(--sp16); border-radius: var(--r-field);
  border: 1.5px dashed var(--mint-2); background: linear-gradient(135deg, var(--mint-soft), #f1fbf6); color: var(--text); font: 500 var(--fs-sm)/1.4 var(--font); cursor: pointer; }
.nc-form input[type=file]::file-selector-button { min-height: 32px; margin-right: var(--sp12); padding: 0 var(--sp12); border-radius: 99px;
  border: 1px solid var(--line-2); background: var(--panel); color: var(--accent-text); font: 600 var(--fs-sm) var(--font); cursor: pointer; }
/* một cột ở MỌI bề rộng: thẻ nay tự trôi lên thành 2–3 cột nên biểu mẫu bên trong luôn hẹp, xếp dọc là gọn nhất */

/* ============================================================================================
   LƯỢT GỌN GÀNG 2 — TỶ LỆ & NHỊP (chỉ kích thước, không màu, không đổi hành vi)
   Mọi quy tắc dưới đây bám đúng HỆ KÍCH THƯỚC ở đầu tệp. Đặt cuối tệp để ghi đè các khai báo cũ
   mà không phải viết lại chúng (các workflow khác đang sửa cùng tệp).
   ============================================================================================ */

/* — Quy tắc 5: BỀ RỘNG Ô LƯỚI KHÔNG PHỤ THUỘC SỐ Ô —
   Trước đây ô co theo số ô (repeat(--cols, 1fr)) nên thẻ 3 ô có ô 94px còn thẻ 8 ô ngay cạnh chỉ 69px.
   Nay bề rộng ô tính theo bề rộng THẺ trên cơ sở 4 cột; số cột vẫn quyết định hàng nào mấy ô,
   ô thừa chỗ thì căn giữa trong ô lưới. Ô không bao giờ rộng hơn ô lưới nên không tràn. */
.tiles {
  /* cơ sở 4 cột theo bề rộng THẺ; hai vế sau chỉ để lưới nhiều cột hơn 4 không tràn ra ngoài thẻ */
  --tile-w: min(var(--tile-max-w), calc((100% - 3 * var(--gap-grid)) / 4), calc((100% - (var(--cols, 4) - 1) * var(--gap-grid)) / var(--cols, 4)));
  /* căn TRÁI: thẻ 3 ô và thẻ 8 ô nằm chồng nhau phải cùng mép trái, nếu căn giữa thì thẻ ít ô trông như rỗng nửa */
  grid-template-columns: repeat(var(--cols, 4), var(--tile-w)); justify-content: start;
}
.tiles > .tile { width: 100%; max-width: 100%; }
@media (min-width: 640px) {
  .tiles, .tiles.tiles-cols, .tiles.tiles-fit {
    --tile-w: min(var(--tile-max-w), calc((100% - 3 * var(--gap-grid)) / 4), calc((100% - (var(--cols-lg, 4) - 1) * var(--gap-grid)) / var(--cols-lg, 4)));
    grid-template-columns: repeat(var(--cols-lg, 4), var(--tile-w));
  }
}

/* — Quy tắc 6: HÀNG NÚT TRONG BẢN GHI NHẬT KÝ —
   .tl-actions từng là flex-wrap thuần ⇒ 3 nút xuống dòng [2,1] với nút thứ ba trơ trọi, và ba nút lệch bề rộng.
   Điện thoại: lưới 2 ô bằng nhau, nút lẻ cuối trải hết hàng; khung “Hủy bản ghi” mở ra cũng trải hết hàng.
   Máy tính vẫn là một hàng flex (đủ chỗ cho 3 nút nên không sinh dòng lởm chởm). */
@media (max-width: 640px), (pointer: coarse) {
  .tl-actions { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--gap-grid); align-items: stretch; }
  .tl-actions > * { width: 100%; min-width: 0; }
  .tl-actions > :last-child:nth-child(odd), .tl-actions > details[open] { grid-column: 1 / -1; }
  .tl-actions :is(.btn, summary.btn) { width: 100%; white-space: normal; text-align: center; line-height: 1.25; padding-inline: var(--sp8); }
}

/* — Quy tắc 8 áp cho cặp nhãn–giá trị: MỘT BỀ RỘNG CỘT NHÃN DÙNG CHUNG —
   Trước đây mỗi thẻ nhật ký tự tính bề rộng cột nhãn (66 / 80 / 85px) nên cuộn dọc thấy cột giá trị nhảy trái–phải.
   clamp() cho ra một con số CỐ ĐỊNH theo bề rộng thẻ ⇒ mọi thẻ cùng bề rộng thì cột nhãn thẳng hàng tuyệt đối.
   Nhãn thật dài vẫn được app.js đánh .kv-stack để xuống dòng riêng. */
:is(.tl-fields, .tr-ev dl) { grid-template-columns: clamp(84px, 38%, 180px) minmax(0, 1fr); }

/* — Quy tắc 6 cho LƯỚI THẺ: 4 thẻ trong lưới 3 cột thành [3,1] với thẻ thứ tư mồ côi và 2/3 hàng bỏ trống.
   Đúng 4 thẻ ⇒ 2 cột × 2 hàng. Với 7 / 10 thẻ vẫn giữ 3 cột: chuyển sang 4 cột sẽ làm thẻ hẹp dưới 300px. */
@media (min-width: 960px) {
  .grid-3:has(> :nth-child(4):last-child) { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* — Quy tắc 5 cho Ô SỐ LIỆU: mọi hàng cao bằng nhau (nhãn dài xuống 2 dòng không còn làm lệch hàng) — */
.kpis { gap: var(--gap-card); grid-auto-rows: 1fr; }
.kpis > .card { display: flex; }

/* — /t/:serial — ba ô số liệu tin cậy: con số về đúng bậc --fs-page (trước 20,16px, cách --fs-page 0,66px),
   màn rất hẹp xếp dọc 1 cột để nhãn 3 dòng không còn chiếm 3/4 chiều cao ô. */
.tr-stats { gap: var(--gap-grid); margin: var(--gap-card) 0; }
.tr-stat { padding: var(--sp12); border-radius: var(--r); min-height: 0; }
@media (max-width: 374px) {
  .tr-stats { grid-template-columns: minmax(0, 1fr); }
  .tr-stat { flex-direction: row; align-items: center; gap: var(--sp12); padding: var(--sp8) var(--sp12); }
  .tr-stat .ic { order: 3; align-self: center; margin: 0 0 0 auto; }
  .tr-stat b { margin: 0; flex: none; }
  .tr-stat small { flex: 1; min-width: 0; }
}

/* — /app/khu — 4 nút của một khu: ở điện thoại mỗi nhãn vỡ thành hai dòng ngắn trong ô 143px.
   Một cột ⇒ nhãn một dòng, nút cao đúng --h-btn, dễ bấm cho người không rành công nghệ. */
@media (max-width: 480px) { .site-links { --cols: 1; } }
/* mọi nút trên trang khu nằm trong thang chiều cao 44 / 48 / 54 — không còn bậc 55 / 59 do nhãn vỡ dòng */
.site-links > .btn { min-height: var(--h-btn); }
.site-cols .btn-block, .site-cols .btn-lg { min-height: var(--h-btn-lg); }

/* — /app/lo/moi — 4 thẻ chọn loại sản phẩm cao ~136px xếp dọc chiếm 544px màn hình chỉ để chọn 1 trong 4.
   Điện thoại: lưới 2 cột, emoji nằm trong ô biểu tượng --ico (52px) như mọi ô khác, nhãn kẹp 2 dòng. */
@media (max-width: 430px) {
  .radio-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .radio-card label { align-items: center; text-align: center; gap: var(--sp6); padding: var(--sp12) var(--sp8); min-height: 104px; justify-content: flex-start; }
  .radio-card label .emo { width: var(--ico); height: var(--ico); border-radius: var(--r-tile); display: grid; place-items: center;
    background: var(--tile-bg); border: 1px solid var(--tile-line); font-size: var(--fs-emoji); }
  .radio-card:nth-child(even) label .emo { background: var(--tile-bg-mint); border-color: var(--tile-line-mint); }
  .radio-card label b { font-size: var(--fs-sm); line-height: 1.25; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2; overflow: hidden; }
  .radio-card label .tiny { line-height: 1.2; }
}
/* chip gợi ý tên lô: ở điện thoại mỗi gợi ý một hàng ⇒ nhãn một dòng, chip cao đúng 44px (trước vỡ 3 dòng, 68px) */
@media (max-width: 430px) { [data-name-suggest] { --cols: 1; } }
[data-name-suggest] .chip { min-height: var(--h-chip); padding-block: var(--sp4); line-height: 1.25; }

/* — Quy tắc 3: NHÃN VỠ DÒNG KHÔNG ĐƯỢC SINH BẬC CHIỀU CAO MỚI —
   Nút trải hết hàng / nút trong lưới nút: đệm dọc nhỏ lại để nhãn hai dòng vẫn nằm trong 44 / 48 / 54
   (trước: 51px ở đầu trang lô, 55px ở trang khu, 59px cho “Lấy GPS nơi tôi đang đứng”). */
.btn-block, .lot-actions .btn, .btn-grid > .btn { padding-block: var(--sp4); }
.lot-actions .btn { min-height: var(--h-btn); }

/* — Quy tắc 9 (liên kết tải bằng chứng .ots đứng riêng trong câu): vùng bấm đủ cao khi chạm — */
@media (max-width: 640px), (pointer: coarse) {
  a[href$=".ots"] { display: inline-flex; align-items: center; min-height: var(--h-chip); padding-inline: var(--sp4); }
}

/* — Quy tắc 10: MÀN RỘNG, CÁC THẺ TỰ TRÔI LÊN — QUYẾT ĐỊNH TỪNG TRANG
   DÙNG .flow (≥1024px chia 2 cột, thẻ ngắn trôi lên; .flow-3 thêm cột thứ ba ở ≥1400px):
     /app          — ô bấm nhanh + Tuân thủ + Nhắc việc + Vừa ghi gộp vào MỘT .flow (cần ≥3 thẻ thì cột mới lấp được chỗ trống)
     /app/lo/:id   — 4 thẻ tóm tắt (Cấp độ tin cậy · Sản lượng & tem · Phân phối · Thông tin lô · Phản ánh)
     /app/ho-so    — 6 thẻ độc lập, CHỈ 2 cột (thẻ chứa biểu mẫu: ở .flow-3 ô nhập chỉ còn ~133px và cột 3 hở 866px)
     /app/thanh-vien, /app/qms, /app/su-co, /app/khac-phuc, /admin/*  — danh sách thẻ độc lập
   PHẢI CHIẾM TRỌN BỀ NGANG, đặt NGOÀI .flow:
     dòng thời gian nhật ký (/app/lo/:id #nhat-ky — cao 6.000px, nằm trong cột sẽ để trống 3.600px bên cạnh),
     đầu trang, cảnh báo, bảng rộng, bản đồ, trang in, lưới thẻ lô (.grid-3 đã có luật riêng cho 4 thẻ).
   GIỮ HAI CỘT CỐ ĐỊNH (có lý do, đừng đổi thành .flow ở lượt sau):
     /app/hom-nay  — cột chính phải ≥636px thì thẻ lô mới xếp 2 cột (container query trong daily.css);
                     cột phụ nhận thêm “Ghi cùng lúc cho nhiều lô” để lấp phần trống bên dưới.
     /app/khu      — mỗi thẻ khu chứa trọn một biểu mẫu sửa; chia cột làm ô nhập còn ~111px (xem env.css).
     /app/thiet-bi — khối “Cổng LoRaWAN” chỉ có 2 thẻ: 2 thẻ thì cột nào cũng chỉ chứa 1 thẻ, .flow không giúp gì.
   Bố cục điện thoại của mọi trang trên đều KHÔNG đổi: .flow là một cột dưới 1024px. */
.flow > .card, .flow > section, .flow > article { break-inside: avoid; }

/* viên thuốc có ô tick bên trong (chọn hộ dự kiểm tra…): ô tick 24px khi chạm ⇒ đệm nhỏ lại để chip vẫn đúng 44px */
.chip:has(> input) { padding-block: var(--sp4); }

/* ============================================================================================
   PHỤ LỤC — VÁ LỀ CHO TRANG CÔNG KHAI · QUẢN TRỊ · MINI APP (đợt “font + lề”, nhóm C)
   Đặt CUỐI TỆP để ghi đè đúng chỗ, không đụng vào khối “HỆ KÍCH THƯỚC” và các luật ở trên.
   Không mở bậc chữ mới: chỉ dùng --fs-xs/--fs-sm · --fs-body · --fs-h2 · --fs-page · --fs-section · --fs-hero.
   Đích của cả khối: ở 320–414px không chữ nào cách mép màn hình dưới 16px, không chữ nào bị cắt.
   ============================================================================================ */

/* 1) Trang chủ ở 320px — điện thoại minh họa không được đẩy cột chữ ra mép.
   .phone rộng CỨNG 290px trong khi lòng .container chỉ 280px (320 − 2×20), nên cột lưới nở thành 290px
   và mọi chữ dải đầu trang chỉ còn cách mép PHẢI 10–14px. Cho nó co lại vừa lòng khung. */
.phone { width: min(290px, 100%); }

/* 2) Thanh đầu trang công khai — chữ thương hiệu KHÔNG được đè lên nút bên phải.
   Ở cỡ “Rất lớn” @390–414px dòng “Truy xuất nguồn gốc” đè lên nút “Vào khu làm việc”; ở 320px
   chữ “Gốc Xanh” đè nút “Đăng nhập” ngay cả cỡ “Thường”. Hai bên đều phải biết co lại. */
@media (max-width: 430px) {
  .site-nav .brand small { display: none; }          /* trước chỉ ẩn ở ≤400px */
  .site-nav .brand { flex: 0 1 auto; min-width: 0; }
  .site-nav .brand span { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
  .site-nav .actions { flex: none; }
}
/* 320–359px: chỗ chỉ đủ cho biểu tượng thương hiệu + nút. Trước đây mới làm cho trang đã đăng nhập. */
@media (max-width: 359px) { .site-nav .brand span { display: none; } }
/* Cỡ chữ “Lớn” / “Rất lớn” trên điện thoại: chữ “Gốc Xanh” cần 109px mà chỗ chỉ còn 81px.
   Cắt bằng dấu … một cái tên thương hiệu thì xấu hơn là bỏ hẳn — giữ lại biểu tượng, chữ nhường chỗ cho nút. */
@media (max-width: 430px) {
  body.sz-2 .site-nav .brand span, body.sz-3 .site-nav .brand span { display: none; }
}

/* 2b) Trang chủ, dải thẻ “Trồng trọt · Chăn nuôi · Chế biến” ở ≤400px — ba ô chia đều 89px,
   nhãn 18px cần 91px nên bị cắt mất 2px. Nhãn của thẻ là chữ trên NÚT ⇒ bậc 2, và cho phép xuống dòng. */
@media (max-width: 400px) {
  .hero-panel .tabs-light a { font-size: var(--fs-body); white-space: normal; }
}

/* 2c) Nhãn ngắn dưới con số (trang QR công khai /l/<mã>, /t/<mã>, /demo và thẻ số liệu nói chung):
   “bước có ảnh bằng chứng” đang vỡ 3 dòng với một chữ trơ lại ở dòng cuối. Cân dòng cho đều,
   không đổi cỡ chữ và không đổi chữ nghĩa. Trình duyệt cũ không hiểu thì bỏ qua, xuống dòng như cũ. */
.tr-stat small, .stat-label { text-wrap: balance; }

/* 3) /admin ở cỡ “Rất lớn” @320px — thẻ “Lô theo cấp độ tin cậy” rộng 337px trong khung 278px.
   KHÔNG đặt overflow lên .viz: .viz-svg cố tình vẽ tràn ra ngoài khung và .viz-tip (bóng chú thích khi
   chạm vào biểu đồ) là position:absolute — biến .viz thành khung cuộn là cắt mất cả hai ở /app/khu, /l/<mã>. */
.admin-levels .row { flex-wrap: nowrap; }
.admin-levels .row .track { min-width: 0; }
/* nhãn cấp độ: 92px đặt thẳng trong view là bề rộng của cỡ “Thường” — cỡ lớn hơn thì cho nở, đừng ép vỡ chữ */
.admin-levels .badge.lv { width: auto !important; min-width: 92px; white-space: nowrap; }

/* 4) Chú giải bản đồ độ phủ xanh (/demo, /l/<mã>, /app/ban-do-ndvi…) — từ 390px lưới chuyển 2 cột
   nên mỗi ô chỉ còn 71–93px, “Đang phát triển” cần 134px và bị cắt mất 63px.
   Giữ MỘT cột tới 430px; từ 431px mới chia đôi. Bản đồ vẫn một khổ 500 × 500 m như đã chốt.
   (Luật gốc ở public/css/ndvi.css:34 — thêm một bậc đặc trưng “body” để thắng bất kể thứ tự nạp tệp.) */
@media (max-width: 430px) {
  body :is(.ndvi-scope, .ndvi-mini) .nx-classes { grid-template-columns: minmax(0, 1fr); }
}
body :is(.ndvi-scope, .ndvi-mini) .nx-classes li span { white-space: normal; overflow: visible; text-overflow: clip; overflow-wrap: break-word; }

/* 5) Phiếu giao hàng /g/<mã> ở ≤359px — đệm hai bên bị hạ xuống 12px nên cả phiếu chạm mép.
   Trả về 16px như phần còn lại của tệp. (Luật gốc ở public/css/delivery.css:106.) */
@media (max-width: 359px) {
  body .dn-wrap { padding-left: var(--sp16); padding-right: var(--sp16); }
}

/* ============================================================
   NHÓM B — TÊN TỔ CHỨC Ở ĐẦU TRANG, HÀNG DANH SÁCH CÓ NÚT, VÀ DÒNG LẺ
   (thêm vào cuối tệp, sau khi HỆ KÍCH THƯỚC đã chốt; không đổi bậc chữ nào)
   ============================================================ */

/* 1. Tên tổ chức trong thanh đầu trang bị CẮT ở mọi bề rộng.
   Hàng .topbar chiếm cứng 150px (đệm 12 + ảnh đại diện 46 + khe 12 + lề phải 12 + khe 12 + chuông 48 + đệm 8),
   nên ô tên chỉ còn 130px @320 · 224px @414 trong khi “HTX Nông nghiệp Xuân An (mẫu)” cần 253px:
   cắt 123px @320, vẫn cắt 29px @414 — ở CẢ bốn cỡ chữ, trên 24 trang dùng vỏ “Form đầy đủ”.
   Chữa bằng hai việc, không đụng cỡ chữ: bỏ lề phải thừa (đã có khe 12px của flex) và cho tên XUỐNG DÒNG
   thay vì cắt bằng dấu “…”. Tên dài nhất thành 2 dòng ở cỡ Thường, 3 dòng ở cỡ Rất lớn — không mất chữ nào. */
.topbar .hello { margin-right: 0; }
.topbar .hello b { white-space: normal; overflow: visible; text-overflow: clip; overflow-wrap: anywhere; text-wrap: pretty; }

/* 2. Hàng danh sách có nút ở cuối (/app/qms “Kiểm tra”, /app/ho-so “Chuyển sang”, /app/thanh-vien “Gỡ”,
   /app/thiet-bi “Thu hồi”): nút không xuống dòng được nên nó ép khối chữ còn 87–99px, tên hộ vỡ 2 dòng
   và dòng phụ “Chưa kiểm tra lần nào · hạn 23/09/2026” vỡ 3 dòng, ở cỡ Rất lớn thì bị cắt hẳn.
   Cho khối chữ một bề rộng sàn 150px: còn đủ chỗ thì nút vẫn nằm cùng hàng (390px trở lên),
   không đủ thì NÚT xuống hàng dưới — chữ chính không bao giờ bị vỡ vụn nữa. Cùng cách đã dùng cho .badge ở trên. */
@media (max-width: 479px) {
  .list-item:has(> .grow + :is(.btn, form):last-child) { flex-wrap: wrap; row-gap: var(--sp8); }
  .list-item:has(> .grow + :is(.btn, form):last-child) > .grow { flex: 1 1 150px; }
  .list-item > .grow + :is(.btn, form):last-child { margin-left: auto; }
}

/* 3. DÒNG LẺ: cấm dòng cuối của một đoạn chỉ còn một hai ký tự (“…kiểu cũ” → “cũ”, “…về lô” → “lô”).
   text-wrap chỉ đổi CHỖ NGẮT DÒNG, không đổi cỡ chữ, không đổi kích thước khối nào; trình duyệt cũ bỏ qua.
   pretty: cho chữ thân bài và dòng phụ. balance: cho tiêu đề và nhãn nút (ít dòng, chia đều đẹp hơn). */
body { text-wrap: pretty; }
h1, h2, h3, h4, .card-title h2, .page-head h1, .btn, .chip, .tile-name, .badge { text-wrap: balance; }

/* 4. Chấm điểm kiểm tra nội bộ (/app/qms/kiem-tra/moi) ở màn 320px: hai cột cho ô chip chỉ 106px,
   trừ ô tròn 24px và đệm thì nhãn “✗ Không đạt” còn 58px và vỡ hai dòng (14 lần trên một trang).
   Dưới 360px cho MỘT cột: ba lựa chọn thành ba ô bấm trọn bề ngang, nhãn nào cũng một dòng. */
@media (max-width: 359px) { .qi-marks { --cols: 1; } }

/* 5. Cùng chuyện đó với NHÃN cuối dòng: luật sẵn có chỉ chạy tới 400px, nên ở 414px cỡ “Rất lớn”
   nhãn “đến 05/03/2027” rộng 156px ép khối chữ còn 120px (tên chứng nhận vỡ 3 dòng).
   Khoảng 401–479px cũng cho khối chữ sàn 150px: đủ chỗ thì nhãn ở lại cùng hàng, không đủ thì nhãn xuống hàng. */
@media (min-width: 401px) and (max-width: 479px) {
  .list-item:has(> .grow + .badge:last-child) { flex-wrap: wrap; row-gap: var(--sp6); }
  .list-item:has(> .grow + .badge:last-child) > .grow { flex: 1 1 150px; }
  .list-item:has(> .grow) > .badge:last-child { margin-left: auto; }
}

/* ---------- Đợt “gọn hơn, chuyên nghiệp hơn”: hai chỗ chữ vượt QUA mép phải màn hình ----------
   Đo ở cỡ “Rất lớn” @320px trên /app/lo/:id bằng Range.getClientRects (chữ thật, không phải hộp):
   dòng “Nguồn: thời tiết theo tọa độ khu từ (lưới mô hình ~10 km)…” trong <details class="viz-table">
   có right = 322,9px trong màn 320px — vượt 2,9px, và tràn 40px ra khỏi thẻ chứa nó (283px).
   Không tổ tiên nào cuộn ngang được nên đây là tràn thật, phần thò ra bị màn hình cắt mất. */
.viz-table p.tiny, .viz-table > p, .viz-table figcaption { min-width: 0; max-width: 100%; overflow-wrap: anywhere; }
.viz-table .term { overflow-wrap: anywhere; }

/* ---------- Nhãn ô lưới ở cỡ chữ “Lớn” / “Rất lớn”: THÀ Ô CAO HƠN CÒN HƠN MẤT CHỮ ----------
   Đo trên /app/lo/:id @320px (ô lưới rộng 55px, mỗi dòng chứa đúng MỘT từ):
     cỡ “Thường”  — 0 nhãn bị cắt
     cỡ “Lớn”     — 2 nhãn bị cắt: “Ghi chú / quan sát”, “Điểm nhận đã nhận” (cần 74px, chỗ 55px)
     cỡ “Rất lớn” — 4 nhãn bị cắt, nặng nhất là “Kết quả xét nghiệm” cần 102px trong 61px
                     (mất gần 2 trong 4 dòng — người chọn cỡ to nhất lại là người mất chữ)
   Kẹp 3 dòng + min-height 2,5em là để MỌI Ô CAO BẰNG NHAU; ở hai cỡ chữ lớn thì cái giá là mất chữ.
   Bỏ kẹp và bỏ chiều cao cố định cho riêng hai cỡ đó: ô tự cao theo nhãn dài nhất, và vì
   .tiles vẫn có grid-auto-rows: 1fr nên MỌI HÀNG TRONG CÙNG MỘT LƯỚI vẫn cao bằng nhau —
   chỉ lưới của thẻ này cao hơn lưới của thẻ kia, không ô nào lệch trong cùng một lưới. */
@media (max-width: 430px) {
  body.sz-2 .tile-name, body.sz-3 .tile-name { -webkit-line-clamp: none; line-clamp: none; display: block; }
  body.sz-2 .tile > .tile-name, body.sz-3 .tile > .tile-name { min-height: 0; }
  body.sz-2 .tiles > .tile, body.sz-3 .tiles > .tile { height: auto; }
}

/* TÍCH XANH của cơ sở (src/lib/verify.js). Bấm vào mở ra đúng những mục đã được đối chiếu —
   một dấu tích trơn là lời tuyên bố không kèm bằng chứng, đúng thứ nền tảng này sinh ra để thay.
   Dùng <details> nên tắt JavaScript vẫn mở được. */
.xm { display: inline-block; margin-left: 6px; vertical-align: -.15em; }
.xm > summary { display: inline-flex; align-items: center; gap: 4px; cursor: pointer; list-style: none;
  padding: 1px 9px 1px 6px; border-radius: 99px; font-size: var(--fs-xs); font-weight: 700;
  background: var(--mint-soft); color: var(--mint-text); box-shadow: inset 0 0 0 1px var(--mint-line); }
.xm > summary::-webkit-details-marker { display: none; }
.xm > summary:hover { background: rgba(var(--mint-rgb), .28); }
.xm > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* Viên tích dùng chung: trong huy hiệu .xm và trong chuỗi nguồn gốc .tr-nguon. Không khoá vào
   .xm nữa — chỗ nào cần dấu đã-xác-minh cũng dùng được đúng một hình. */
.xm-tick { display: inline-grid; place-items: center; width: 15px; height: 15px; border-radius: 50%;
  background: var(--mint-text); color: #fff; font-size: 10px; line-height: 1; vertical-align: .05em; }
.xm .xm-in { margin-top: 8px; padding: 10px 12px; border-radius: var(--r-sm); background: var(--mint-soft);
  font-size: var(--fs-sm); line-height: 1.5; font-weight: 400; color: var(--text); }
/* Trong thẻ định nghĩa của trang công khai, mở ra thì cho nó xuống hàng riêng cho dễ đọc. */
.tr-kv .xm[open] { display: block; margin-left: 0; margin-top: 6px; }

/* Chuỗi nguồn gốc của lô con (kho tách ra từ lô mẹ). Mỗi bậc là một nấc đi ngược về ruộng. */
.tr-nguon { list-style: none; margin: 0; padding: 0; }
.tr-nguon li { position: relative; padding: 0 0 12px 22px; }
.tr-nguon li::before { content: ''; position: absolute; left: 4px; top: 6px; width: 9px; height: 9px;
  border-radius: 50%; background: var(--mint); box-shadow: 0 0 0 3px var(--mint-soft); }
.tr-nguon li:not(:last-child)::after { content: ''; position: absolute; left: 8px; top: 18px; bottom: 0;
  width: 2px; background: var(--mint-line); }
.tr-nguon li:last-child { padding-bottom: 0; }

/* HÀNG ĐANG Ở ĐÂU — bốn ô số trên trang QR công khai (views/public/trace.ejs).
   Bốn con số này suy ra từ nhật ký, không phải lời khai: còn ở nơi sản xuất, đang trên đường,
   còn trên kệ, đã tới tay người mua. Xếp lưới 2×2 trên điện thoại, một hàng trên máy tính. */
.tr-odau { display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px; margin-top: 12px; }
.tr-odau .od { padding: 10px 12px; border-radius: var(--r-sm); background: var(--mint-soft);
  box-shadow: inset 0 0 0 1px var(--mint-line); }
.tr-odau .od b { display: block; font-size: var(--fs-h2); line-height: 1.1; color: var(--mint-text); }
.tr-odau .od span { display: block; font-size: var(--fs-xs); color: var(--text-2); margin-top: 2px; }
/* Ô “đã tới tay người mua” là đích của cả chuỗi — cho nó màu đậm hơn để mắt dừng lại ở đó. */
.tr-odau .od[data-od="ban"] { background: var(--accent-soft, #e6f0ff); box-shadow: inset 0 0 0 1px var(--line); }
.tr-odau .od[data-od="ban"] b { color: var(--accent); }
@media (min-width: 620px) { .tr-odau { grid-template-columns: repeat(4, 1fr); } }
.tr-diem > summary { cursor: pointer; font-size: var(--fs-sm); font-weight: 600; color: var(--accent); }
.tr-diem ul { list-style: none; margin: 8px 0 6px; padding: 0; }
.tr-diem li { padding: 8px 0; border-top: 1px solid var(--line); }

/* Ảnh giấy tờ trên trang QR công khai — hiện luôn ảnh, bấm vào mở hộp thoại (public/js/app.js).
   Trước đây chỉ là một chip chữ “🖼️ Ảnh 1” mở tab mới: người mua mất trang đang đọc, mà bằng
   chứng thì vẫn chưa thấy. Đây là thứ đáng xem nhất trên cả trang. */
.tr-anhs { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.tr-anh { display: block; width: 84px; height: 84px; border-radius: var(--r-sm); overflow: hidden;
  background: var(--panel-2, #f1f5fb); box-shadow: 0 0 0 1px var(--line); cursor: zoom-in; }
.tr-anh img { width: 100%; height: 100%; object-fit: cover; display: block; }
.tr-anh:hover { box-shadow: 0 0 0 2px var(--accent); }
.tr-anh:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
@media (min-width: 560px) { .tr-anh { width: 104px; height: 104px; } }

/* Giấy tờ: CHỮ BÊN TRÁI, ẢNH BÊN PHẢI trên cùng một hàng.
   Ảnh nằm dưới chữ thì mỗi giấy tờ cao gấp đôi, cả thẻ “Giấy tờ” bị kéo dài ra; đặt cạnh nhau
   thì đọc một lượt là thấy cả hai. Ảnh không co (flex: none) để luôn đủ to mà nhận ra. */
.tr-doc-in { display: flex; align-items: flex-start; gap: var(--sp12); }
.tr-doc-chu { min-width: 0; flex: 1; }
.tr-doc-in .tr-anhs { flex: none; }
/* Màn rất hẹp: ảnh nhỏ lại một nấc để cột chữ còn đủ chỗ, vẫn giữ bên phải chứ không tụt xuống. */
@media (max-width: 419px) {
  .tr-doc-in .tr-anh { width: 68px; height: 68px; }
  .tr-doc-in { gap: var(--sp8); }
}

/* ĐỢT THU của lô mẹ (đợt trứng, đợt sữa…) và lô con đã tách.
   Dòng tóm tắt phải đọc được ở 320px nên xếp hai hàng: ngày + số lượng + tình trạng ở trên,
   mã lô ở dưới. Cột tình trạng cao trọn hai hàng để badge luôn thẳng lề phải. */
.dot-kho { display: grid; gap: var(--sp8); }
details.dot { border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--bg-2); overflow: hidden; }
details.dot > summary { cursor: pointer; list-style: none; padding: var(--sp12); display: grid;
  grid-template-columns: auto auto 1fr auto; grid-template-areas: "cai ngay so tag" "cai ma ma tag";
  column-gap: var(--sp8); row-gap: 2px; align-items: center; }
details.dot > summary::-webkit-details-marker { display: none; }
details.dot > summary::before { grid-area: cai; content: '›'; font-size: var(--fs-h2); line-height: 1;
  color: var(--mint-text); transition: transform .2s; }
details.dot[open] > summary::before { transform: rotate(90deg); }
.dot-ngay { grid-area: ngay; font-weight: 600; }
.dot-so { grid-area: so; color: var(--muted); font-size: var(--fs-sm); }
.dot-ma { grid-area: ma; font-size: var(--fs-xs); color: var(--faint); }
details.dot > summary > .badge { grid-area: tag; justify-self: end; align-self: center; }
/* Đợt đang thu: vạch màu bên trái để mắt tìm thấy ngay giữa một danh sách dài */
details.dot.dang-nhat { border-left: 3px solid var(--mint); }
details.dot.het > summary { opacity: .68; }
details.dot[open] > summary { border-bottom: 1px solid var(--line); }
.dot-in { padding: var(--sp12); }

.dot-so4 { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--sp8); margin-bottom: var(--sp12); }
.dot-so4 > div { background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-sm);
  padding: var(--sp8) var(--sp6); text-align: center; }
.dot-so4 b { display: block; font-size: var(--fs-h2); }
.dot-so4 span { display: block; font-size: var(--fs-xs); color: var(--muted); }

.dot-tl { list-style: none; margin: 0 0 var(--sp12); padding: 0; display: grid; gap: var(--sp8); }
.dot-tl > li { display: flex; gap: var(--sp8); align-items: flex-start; }
.dot-tl-ic { flex: none; width: 1.5em; text-align: center; }
.dot-nut { display: flex; gap: var(--sp8); flex-wrap: wrap; }

/* DÒNG ĐỜI trên trang QR công khai: mua giống → nuôi → đợt thu của gói đang cầm.
   Hai đầu (đợt cũ hơn, đợt mới hơn) rút thành hàng nút bấm chứ không đổ hết ra — một đàn gà đẻ
   18 tháng có hơn 500 đợt, đổ hết thì điện thoại cũ không mở nổi trang. */
.dd { list-style: none; margin: 12px 0 0; padding: 0; }
.dd > li { position: relative; padding: 0 0 14px 24px; }
.dd > li::before { content: ''; position: absolute; left: 4px; top: 6px; width: 9px; height: 9px;
  border-radius: 50%; background: var(--mint); box-shadow: 0 0 0 3px var(--mint-soft); }
.dd > li:not(:last-child)::after { content: ''; position: absolute; left: 8px; top: 18px; bottom: 0;
  width: 2px; background: var(--mint-line); }
.dd > li:last-child { padding-bottom: 0; }
.dd-nuoi { display: flex; gap: 8px; align-items: flex-start; }
.dd-ic { flex: none; width: 1.4em; text-align: center; }
.dd-bot { font-size: var(--fs-sm); color: var(--muted); }
.dd-bot::before { background: var(--mint-line); box-shadow: none; }

/* Hàng đợt bị ẩn: nhãn nhỏ rồi tới các nút. Cuộn ngang khi nhiều nút, không đẩy vỡ khung. */
.dd-nhan { display: block; font-size: var(--fs-xs); color: var(--muted); margin-bottom: 6px; }
.dd-chips { display: flex; gap: 8px; overflow-x: auto; padding-bottom: 4px;
  scrollbar-width: thin; -webkit-overflow-scrolling: touch; }
.dd-chip { flex: none; display: flex; flex-direction: column; gap: 1px; text-decoration: none;
  padding: 8px 12px; min-height: 44px; justify-content: center;
  border: 1px solid var(--mint-line); border-radius: var(--r-sm); background: var(--panel); color: inherit; }
.dd-chip b { font-size: var(--fs-sm); }
.dd-chip span { font-size: var(--fs-xs); color: var(--muted); }
.dd-chip:hover, .dd-chip:focus-visible { background: var(--mint-soft); }

/* Đợt của gói đang cầm: mở sẵn, viền màu để mắt dừng lại đúng chỗ */
.dd-nay::before { width: 13px; height: 13px; left: 2px; top: 4px; box-shadow: 0 0 0 4px var(--mint-soft); }
.dd-nhan-nay { display: block; font-weight: 600; color: var(--mint-text); margin-bottom: 8px; }
.dd-trong { margin: 0; padding: 10px 12px; border: 1px solid var(--mint-line); border-radius: var(--r-sm);
  background: var(--mint-soft); }
.dd-trong > li { padding-left: 0; padding-bottom: 8px; }
.dd-trong > li::before, .dd-trong > li::after { display: none; }
.dd-trong > li:last-child { padding-bottom: 0; }
.dd-nhay { display: inline-block; margin-top: 8px; font-size: var(--fs-sm); color: var(--mint-text); }

/* LÁ CỜ ĐỔI NGÔN NGỮ. Hai nút nhỏ, cao đủ 44px cho ngón tay, cờ vẽ bằng SVG nên máy nào cũng
   hiện. Nút đang chọn có nền đậm để nhìn một cái là biết mình đang đọc thứ tiếng nào. */
.co-nn { display: inline-flex; gap: 4px; padding: 3px; border-radius: 999px;
  background: var(--bg-2); border: 1px solid var(--line); }
.co-nn a { display: inline-flex; align-items: center; gap: 6px; padding: 5px 10px; min-height: 38px;
  border-radius: 999px; text-decoration: none; color: var(--muted); font-size: var(--fs-sm); font-weight: 600; }
.co-nn a.on { background: var(--panel); color: var(--ink); box-shadow: 0 1px 3px rgba(16, 32, 64, .12); }
.co-nn svg { width: 21px; height: 14px; border-radius: 2px; display: block; flex: none;
  box-shadow: 0 0 0 1px rgba(16, 32, 64, .14); }
/* Một nút cờ trên thanh đầu trang QR: cùng cỡ, cùng kiểu kính mờ với nút quay lại và chia sẻ.
   Lá cờ lấp gần kín nút (không có chữ VI/EN) nên bo tròn theo nút và cắt gọn ở mép. */
.tr-top-r { display: flex; align-items: center; gap: 8px; }
.co-nut { overflow: hidden; }
.co-nut svg { width: 26px; height: 18px; border-radius: 3px; display: block;
  box-shadow: 0 0 0 1px rgba(16, 32, 64, .18); }

/* Trang mã GS1 trong khu làm việc */
.gs1-row { display: flex; align-items: center; gap: var(--sp12); padding: var(--sp12);
  border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--bg-2); flex-wrap: wrap; }
.gs1-vd { background: var(--bg-2); border: 1px solid var(--line); border-radius: var(--r-sm);
  padding: var(--sp12); overflow-x: auto; font-size: var(--fs-sm); margin: 0 0 var(--sp12); }
.gs1-vd code { white-space: pre; }
.gs1-hl { color: var(--mint-text); font-weight: 700; }
/* Ví dụ dưới tên loại sản phẩm: cho xuống dòng thoải mái, không ép một dòng như chữ "N công đoạn" */
.radio-card .rc-vd { display: block; margin: 2px 0 4px; line-height: 1.3; }

/* CHỢ NÔNG SẢN — danh bạ hàng đang có. Thẻ xếp lưới tự co, một cột trên điện thoại. */
.cho-wrap { padding-bottom: 40px; }
.cho-luoi { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: var(--gap-grid); }
.cho-the { background: var(--panel); border: 1px solid var(--line); border-radius: var(--r); padding: var(--card-pad); display: flex; flex-direction: column; gap: var(--sp8); }
.cho-dau { display: flex; align-items: flex-start; gap: var(--sp8); }
.cho-dau h2 { margin: 0; font-size: var(--fs-h2); }
.cho-emo { font-size: var(--fs-emoji-inline); flex: none; }
.cho-kv { display: grid; grid-template-columns: auto 1fr; gap: 2px var(--sp8); margin: 0; font-size: var(--fs-sm); }
.cho-kv dt { color: var(--muted); }
.cho-kv dd { margin: 0; }
.cho-nut { display: flex; gap: var(--sp8); flex-wrap: wrap; }
.cho-hoi > summary { list-style: none; cursor: pointer; }
.cho-hoi > summary::-webkit-details-marker { display: none; }
.cs-dau { display: flex; gap: var(--sp16); align-items: flex-start; flex-wrap: wrap; }
.cs-anh { border-radius: var(--r-sm); object-fit: cover; flex: none; }
.don-the.don-moi { border-color: var(--mint); box-shadow: 0 0 0 3px rgba(var(--mint-rgb), .14); }
/* Số đơn chưa xử trên menu */
.nav-dem { display: inline-flex; align-items: center; justify-content: center; min-width: 20px; height: 20px;
  padding: 0 6px; margin-left: auto; border-radius: 999px; background: var(--mint); color: var(--on-mint);
  font-size: var(--fs-xs); font-weight: 700; }

/* TIN NHẮN — dùng chung cho cả trang người mua lẫn khu làm việc của hộ. */
.tn-hang { display: flex; align-items: center; gap: var(--sp12); padding: var(--sp12);
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-sm);
  text-decoration: none; color: inherit; }
.tn-hang.chua-doc { border-color: var(--mint); background: var(--mint-soft); }
.tn-anh { width: 44px; height: 44px; border-radius: 50%; object-fit: cover; flex: none; }
.tn-chu { display: grid; place-items: center; background: var(--bg-2); border: 1px solid var(--line);
  font-weight: 700; color: var(--muted); }
.tn-hang .grow { min-width: 0; display: block; }
.tn-cuoi { display: block; font-size: var(--fs-sm); color: var(--muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tn-phai { display: flex; flex-direction: column; align-items: flex-end; gap: 4px; flex: none; }
.tn-phai .nav-dem { margin-left: 0; }

.chat { display: flex; flex-direction: column; gap: var(--sp8); padding: var(--sp12);
  background: var(--bg-2); border: 1px solid var(--line); border-radius: var(--r);
  max-height: 60vh; overflow-y: auto; }
.chat-d { max-width: 78%; }
.chat-d.toi { align-self: flex-end; text-align: right; }
.chat-b { display: inline-block; padding: 8px 12px; border-radius: 16px; white-space: pre-wrap;
  word-break: break-word; background: var(--panel); border: 1px solid var(--line); text-align: left; }
.chat-d.toi .chat-b { background: var(--mint-soft); border-color: var(--mint-line); }
.chat-w { font-size: var(--fs-xs); color: var(--muted); margin-top: 2px; }
.chat-gui { display: flex; gap: var(--sp8); align-items: flex-end; margin-top: var(--sp12); }
.chat-gui textarea { flex: 1; resize: vertical; min-height: 44px; }
.chat-gui .btn { flex: none; height: var(--h-btn); width: var(--h-btn); padding: 0; border-radius: 50%; }

/* NÚT TIN NHẮN — vòng tròn xanh dương đứng một mình, KHÔNG nền trắng phía sau.
   Xanh dương (không phải xanh lá của nút "ghi việc") để mắt phân biệt ngay: một bên là việc
   đồng áng, một bên là khách. */
.bnav-chat-cum { display: flex; align-items: center; gap: 4px; flex: none; }
.bnav-chat { width: 52px; height: 52px; border-radius: 50%; display: grid; place-items: center; position: relative;
  color: #fff; background: var(--accent-grad); text-decoration: none; flex: none;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .3), 0 1px 2px rgba(15, 27, 61, .06),
    0 6px 14px -6px rgba(15, 27, 61, .18), 0 22px 44px -16px rgba(16, 90, 200, .55); }
.bnav-chat .i { width: 24px; height: 24px; }
.bnav-chat .dem { position: absolute; top: -3px; right: -3px; min-width: 20px; height: 20px; padding: 0 5px;
  border-radius: 999px; background: var(--danger); color: #fff; font-size: var(--fs-xs); font-weight: 700;
  display: grid; place-items: center; border: 2px solid var(--bg); }
/* Cần gạt ẩn/hiện: nhỏ, nhạt, tròn — là cần gạt chứ không phải đích đến */
.bnav-an { width: 26px; height: 26px; padding: 0; border: 1px solid var(--line); cursor: pointer;
  background: var(--panel); color: var(--muted); font-size: 15px; line-height: 1; border-radius: 50%;
  position: relative; flex: none; display: grid; place-items: center;
  box-shadow: 0 2px 6px -2px rgba(15, 27, 61, .25); }
.bnav-an:hover { color: var(--ink); }
.bnav-an .mui { display: block; transition: transform .2s; }
.bnav-chat-cum.da-an .bnav-chat { display: none; }
.bnav-chat-cum.da-an .bnav-an .mui { transform: rotate(180deg); }
/* Ẩn đi không có nghĩa là mất tin: cần gạt mang chấm đỏ khi còn tin chưa đọc */
.bnav-chat-cum.da-an .bnav-an.co-tin::after { content: ''; position: absolute; top: -2px; right: -2px;
  width: 9px; height: 9px; border-radius: 50%; background: var(--danger); border: 1.5px solid var(--bg); }

/* TRÊN TRANG GHI VIỆC (.ex-nav): nút đứng NGAY TRÊN thanh menu, canh đúng cột "Lô" bên phải.
   Cột thứ ba của .ex-nav: thanh cách mép 12px, đệm 6px, ba cột đều nhau, hai khe 6px
   ⇒ tâm cột phải cách mép phải 18px + (100vw − 48px)/6. Tính thẳng bằng CSS nên không phụ
   thuộc JavaScript và không lệch khi xoay máy. Ở đây không có cần gạt: nút chỉ nổi lên khi có
   tin chưa đọc, ẩn một thứ vốn đã hiếm khi xuất hiện là vô nghĩa. */
.bnav-hang.tren-viec { left: auto; right: calc(18px + (100vw - 48px) / 6 - 26px); transform: none;
  bottom: calc(12px + 74px + 10px); max-width: none; }
.bnav-hang.tren-viec .bnav { display: none; }
.bnav-hang.tren-viec .bnav-an { display: none; }
/* Màn hẹp: thu nhỏ đều cả menu và nút tin nhắn, thay vì để trình duyệt tự bóp méo từng ô.
   Đo được ở 390px: menu 292px + khe 8 + nút 52 = 352, khung còn 374 ⇒ chỉ hở 11px mỗi bên. */
@media (max-width: 400px) {
  .bnav-hang { gap: var(--sp6); }
  .bnav { gap: 4px; padding: var(--sp6); }
  .bnav a { width: 46px; height: 46px; }
  .bnav a .i { width: 20px; height: 20px; }
  .bnav a.bnav-add .i { width: 22px; height: 22px; }
  .bnav-chat { width: 48px; height: 48px; }
  .bnav-chat .i { width: 22px; height: 22px; }
}
@media (max-width: 344px) {
  .bnav a { width: 42px; height: 42px; }
  .bnav-chat { width: 44px; height: 44px; }
}
@media (min-width: 1024px) { .bnav-chat-cum { display: none; } }

/* Ô NHẬP TIN NHẮN NỔI — nằm trên thanh menu dưới, như mọi trình nhắn tin. */
.tn-dau { display: flex; align-items: center; gap: var(--sp12); flex-wrap: wrap; }
.tn-dau h1 { margin: 0; font-size: var(--fs-h2); }
.tn-goi { flex: none; }
.chat-noi { position: fixed; left: 50%; transform: translateX(-50%); z-index: 45;
  width: min(720px, calc(100vw - 24px));
  /* đẩy lên khỏi thanh menu: chiều cao thanh (66px) + khoảng hở dưới cùng */
  bottom: calc(max(14px, env(safe-area-inset-bottom)) + 78px);
  padding: var(--sp8); border-radius: 22px; background: var(--panel); border: 1px solid var(--accent-line);
  backdrop-filter: blur(18px) saturate(1.4); -webkit-backdrop-filter: blur(18px) saturate(1.4);
  box-shadow: 0 1px 2px rgba(15, 27, 61, .06), 0 10px 26px -10px rgba(15, 27, 61, .28); }
.chat-noi textarea { border-radius: 18px; max-height: 40vh; }
/* Chừa chỗ cho ô nhập nổi + thanh menu, nếu không tin cuối bị che khuất hẳn */
.chat-noi ~ .tn-luuy { margin-bottom: 0; }
body:has(.chat-noi) .app-main, body:has(.chat-noi) main { padding-bottom: 170px; }
@media (min-width: 1024px) { .chat-noi { bottom: 18px; } body:has(.chat-noi) .app-main { padding-bottom: 120px; } }

/* HỘP THOẠI NỔI trên trang Chợ (đặt đơn / nhắn tin). Dùng thẻ <dialog> của trình duyệt nên có
   sẵn phím Esc, bẫy tiêu điểm và lớp nền mờ — không phải dựng lại bằng tay. */
.hop { width: min(520px, calc(100vw - 24px)); max-height: min(86vh, 760px); padding: 0; border: 0;
  border-radius: var(--r); background: var(--panel); color: var(--ink); overflow: visible;
  box-shadow: 0 24px 60px -20px rgba(15, 27, 61, .5); }
.hop::backdrop { background: rgba(9, 22, 52, .5); backdrop-filter: blur(3px); }
.hop-trong { padding: var(--card-pad); max-height: min(86vh, 760px); overflow-y: auto; }
.hop-dau { margin-bottom: var(--sp12); padding-right: 32px; }
.hop-dau h2 { margin: 0; font-size: var(--fs-h2); }
.hop-dong { position: absolute; top: 10px; right: 10px; width: 34px; height: 34px; border-radius: 50%;
  border: 1px solid var(--line); background: var(--panel); color: var(--muted); font-size: 20px;
  line-height: 1; cursor: pointer; z-index: 1; }
.hop-dong:hover { color: var(--ink); background: var(--bg-2); }
/* Trên điện thoại: dán xuống đáy như tấm trượt, ngón cái với tới được */
@media (max-width: 560px) {
  .hop { width: 100vw; max-width: none; margin: 0; position: fixed; left: 0; right: 0; bottom: 0; top: auto;
    border-radius: var(--r) var(--r) 0 0; max-height: 88vh; }
  .hop-trong { max-height: 88vh; padding-bottom: max(var(--card-pad), env(safe-area-inset-bottom)); }
}
