/*
 * Vinpack — global.css
 * Nạp trên mọi trang. Xem spec mục 5 và 7.
 *
 * TOKEN LOẠI A (màu, cỡ chữ, khoảng cách biên tập viên chọn được trong editor)
 *   → nguồn duy nhất là theme.json. Ở đây CHỈ đặt bí danh.
 *   → muốn đổi thì sửa theme.json, đừng sửa ở đây.
 *
 * TOKEN LOẠI B (chỉ dùng nội bộ trong CSS của theme)
 *   → khai thẳng ở đây.
 *
 * Sửa typography của .art-content thì phải sửa cả assets/css/editor.css.
 * Test tests/test-editor-sync.php sẽ báo hỏng nếu quên.
 */

/* ============================================================
   1. Bí danh token loại A — nguồn: theme.json
   ============================================================ */
:root{
  --navy:       var(--wp--preset--color--navy, #001BB7);
  --navy-dark:  var(--wp--preset--color--navy-dark, #001291);
  --cobalt:     var(--wp--preset--color--cobalt, #5C90F5);
  /*
   * ĐỊNH NGHĨA: màu xanh dùng cho MỌI chữ dưới 18px, trên MỌI nền sáng của
   * theme — không riêng nền trắng.
   *
   * Định nghĩa cũ ngầm hiểu là "xanh chữ nhỏ trên nền trắng", và đúng bốn lần
   * có thứ vẽ trên --bg-alt rơi lọt qua nó: .btn-secondary:hover, dòng
   * .vp-table đang hover, link trong blockquote, link trong code. #3A6ED9 cũ
   * đạt 4.76:1 trên trắng nhưng chỉ 4.17:1 trên --bg-alt.
   *
   * #3366CC đạt 5.37:1 trên trắng, 4.70:1 trên --bg-alt, 5.23:1 trên nền hàng
   * chẵn #FBFCFE và 4.96:1 trên --img-bg. Cùng sắc 220° như bản cũ, chỉ tối hơn
   * 4 điểm độ sáng, nên ô màu trong trình soạn thảo vẫn đọc ra cùng một họ.
   *
   * Đổi màu này thì phải đo lại CẢ BỐN nền sáng, đừng chỉ đo trên trắng.
   */
  --cobalt-ink: var(--wp--preset--color--cobalt-ink, #3366CC);
  --bg-alt:     var(--wp--preset--color--bg-alt, #EAF0FF);
  --white:      var(--wp--preset--color--white, #FFFFFF);
  --text:       var(--wp--preset--color--text, #1A1A1A);
  --text-muted: var(--wp--preset--color--text-muted, #6B7280);

  /* Mockup dùng tên này; giữ làm bí danh để CSS chép sang không phải sửa. */
  --cobalt-light: var(--bg-alt);

  --sp-1: var(--wp--preset--spacing--sp-1, 4px);
  --sp-2: var(--wp--preset--spacing--sp-2, 8px);
  --sp-3: var(--wp--preset--spacing--sp-3, 12px);
  --sp-4: var(--wp--preset--spacing--sp-4, 16px);
  --sp-5: var(--wp--preset--spacing--sp-5, 24px);
  --sp-6: var(--wp--preset--spacing--sp-6, 32px);
  --sp-7: var(--wp--preset--spacing--sp-7, 48px);
  --sp-8: var(--wp--preset--spacing--sp-8, 96px);

  --font-head: 'Manrope', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-body: 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
}

/* ============================================================
   2. Token loại B — chỉ dùng trong CSS của theme
   ============================================================ */
:root{
  --border:         #E2E8F0;
  --disabled:       #C4CEE0;
  --img-bg:         #F4F6FA;
  --footer-text:    #9AA8CC;
  --on-navy-accent: #A9C4FF;
  --on-navy-text:   #C3CDE8;
  --on-navy-text-2: #C7D2EE;
  --danger:         #DD3429;   /* 4.57:1 trên trắng; #E0453B cũ chỉ 4.13:1, trượt AA */
  --video-bg:       #0A1440;
  --decor:          #D7E0F7;
  --icon-muted:     #C2CAD8;

  /*
   * Bốn màu thương hiệu kênh liên hệ .vp-fab-btn--* (26/08/2026, khách: "giữ
   * đúng màu như web hiện tại https://vinpack.vn/") — ĐO TRỰC TIẾP trên web
   * cũ (không đoán): web cũ dùng plugin Chaty, mỗi kênh một icon SVG/ảnh
   * RIÊNG mang sẵn màu nền trong chính file, không qua CSS. Bốn giá trị dưới
   * lấy nguyên văn từ đó (getComputedStyle + fetch trực tiếp file .svg).
   *
   * NGOẠI LỆ TƯƠNG PHẢN CÓ TÀI LIỆU: --fab-call/--fab-whatsapp chỉ 1.64:1 với
   * icon trắng — DƯỚI CẢ 3:1 (WCAG 1.4.11, đồ hoạ không phải chữ) lẫn 4.5:1
   * (chữ thường). Đây là màu nguyên bản của chính web cũ đang chạy thật (đo
   * được, không phải theme tự chọn) — khách yêu cầu khớp màu, không yêu cầu
   * đổi màu thương hiệu kênh. Mỗi nút đã có nhãn a11y thật qua
   * .screen-reader-text (xem template-parts/global/contact-fab.php), không
   * phụ thuộc độ tương phản màu của icon để hiểu được nội dung nút.
   */
  --fab-call:      #03E78B;   /* icon trắng: 1.64:1 — xem "NGOẠI LỆ" trên */
  --fab-whatsapp:  #49E670;   /* icon trắng: 1.64:1 — cùng lý do trên */
  --fab-zalo:      #0068FF;   /* icon trên nền trắng: 4.75:1, đạt AA chữ thường */
  --fab-map:       #EA4335;   /* icon trên nền trắng: 3.92:1, đạt AA đồ hoạ (3:1), không đạt AA chữ (4.5:1) */

  /*
   * Màu vòng focus. CỐ Ý không dùng lại --cobalt.
   *
   * Vòng focus là ranh giới thành phần giao diện nên cần 3:1 (WCAG 1.4.11 và
   * 2.4.11) so với MỌI nền mà theme có thể đặt một phần tử nhận focus lên.
   * --cobalt đạt trên trắng (3.11:1) và trên --navy (3.67:1) nhưng trượt trên
   * --bg-alt: 2.72:1. Nền đó có thật — blockquote, code, khối xen kẽ, dòng bảng
   * đang hover, và chính .btn-secondary lúc hover.
   *
   * Cửa sổ độ chói khả dĩ rất hẹp và có hai đầu: sáng hơn thì trượt trên
   * --bg-alt, tối hơn thì trượt trên --navy. Điểm cân bằng cho tỷ số tốt nhất
   * có thể đạt được là 3.16:1 ở cả hai đầu; #5183EC nằm gần đúng điểm đó.
   * Đừng chỉnh màu này theo cảm giác — đo lại cả ba nền trước.
   *
   * CÒN LẠI CHO PHASE B: trên nền của .on-navy blockquote (navy pha 8% trắng)
   * vòng này chỉ đạt 2.71:1. Hiện không template nào phát ra .on-navy nên đây
   * là ràng buộc phải giải khi dựng các khối nền navy, không phải lỗi đang sống.
   */
  --focus-ring:     #5183EC;

  --gap-card:   24px;
  --gap-inline: 12px;
  --wrap-x:     32px;
  --wrap-max:   1180px;

  --r-btn:     8px;
  --r-input:   9px;
  --r-sm:      10px;
  --r-card:    12px;
  --r-card-lg: 14px;
  --r-lg:      16px;
  /*
   * --r-xl là bậc CUỐI của thang bo góc bề mặt. Mockup dùng đúng 20px cho hai
   * bề mặt lớn (.cta-box và .feat-visual); .feat-visual chưa được dựng trong
   * theme này, nên hiện chỉ .cta-box tiêu thụ nó. Khai ở đây chứ không ở
   * home.css vì home.css BỊ CẤM khai custom property — một token nằm ngoài
   * global.css thì editor.css và theme.json không có cách nào rơi về.
   */
  --r-xl:      20px;
  --r-pill:    100px;
  --r-full:    50%;

  --sh-1: 0 4px 16px rgba(0, 27, 183, .05);
  --sh-2: 0 6px 22px rgba(0, 27, 183, .06);
  --sh-3: 0 18px 40px rgba(0, 27, 183, .13);
  --sh-4: 0 24px 48px rgba(0, 27, 183, .14);

  --z-header: 50;
  --z-mega:   60;
  --z-dd:     70;
  --z-fab:    100;

  --ease:      cubic-bezier(.25, .1, .25, 1);
  --dur-micro: .2s;
  --dur-state: .3s;
}

/* ============================================================
   3. Reset
   ============================================================ */
*{ margin:0; padding:0; box-sizing:border-box; }

/* Thanh admin của WordPress không chịu được box-sizing:border-box. */
#wpadminbar, #wpadminbar *{ box-sizing:content-box; }

:where(html){ scroll-behavior:smooth; -webkit-text-size-adjust:100%; }

/*
 * overflow-x:hidden tren body (ngay duoi day) khong du de chan
 * document.documentElement.scrollWidth khoi phinh ra theo noi dung tran cua
 * .faq - do that: chi dat tren body, scrollWidth cua <html> van do duoc
 * 1273px thay vi 1265px (dat lai tren san-pham/tui-hot-xoai-trang-25x40cm/
 * sau khi them dong body). Phai dat CA hai (html va body) thi
 * documentElement.scrollWidth moi ve dung clientWidth.
 */
html{
  /*
   * `clip` CHU KHONG PHAI `hidden` — xem khoi giai thich o body ngay duoi.
   * Khai `hidden` truoc lam ban du phong cho trinh duyet cu chua ho tro
   * `clip` (Safari < 16): dong sau ghi de dong truoc o trinh duyet moi.
   */
  overflow-x:hidden;
  overflow-x:clip;
}

body{
  font-family:var(--font-body);
  font-size:15.5px;
  color:var(--text);
  background:var(--white);
  line-height:1.6;
  -webkit-font-smoothing:antialiased;
  -moz-osx-font-smoothing:grayscale;
  /*
   * .faq (taxonomy-danhmuc.css) dung ky thuat full-bleed `width:100vw;
   * margin-left:calc(50% - 50vw)` de tran het chieu rong VIEWPORT THAT.
   * Theo spec, 100vw tinh CA be rong thanh cuon doc, con % (co so tinh 50%)
   * thi khong - tren trang co thanh cuon, lech dung mot nua be rong thanh
   * cuon (do that: 8px tren desktop 1280). Chan tran o day la NUA CON LAI
   * bat buoc cua chinh ky thuat full-bleed do.
   *
   * PHAI la `clip`, KHONG duoc dung `hidden`: `hidden` bien body thanh mot
   * KHUNG CUON (scroll container), va khi do moi `position:sticky` nam trong
   * body deu mat cho bam -> chet sticky toan site. Do that tren
   * /san-pham/tui-dung-rac-day-rut/ khi con dung `hidden`: cuon xuong 1800px
   * thi .art-toc troi len -932px (dang le ghim +100px); doi sang `clip` thi
   * ghim dung +100px, ma van chan tran ngang 0px. `clip` kep tran MA KHONG
   * tao khung cuon - dung cho truong hop nay.
   *
   * Khai `hidden` truoc lam ban du phong cho trinh duyet cu chua ho tro
   * `clip` (Safari < 16): o do sticky khong an nhung it nhat khong tran ngang.
   */
  overflow-x:hidden;
  overflow-x:clip;
}

/*
 * (0,0,2) - KHONG (0,0,0). Do tren trinh duyet that, khong suy ra tu file.
 *
 * WordPress core in mot stylesheet NOI TUYEN (id global-styles-inline-css) sinh
 * tu theme.json, va trong do co:
 *
 *   a:where(:not(.wp-element-button)){ color:var(--wp--preset--color--navy) }
 *
 * Do uu tien cua no la (0,0,1): chu `a` tinh 1, `:where()` dong gop 0. Mot
 * `:where(a)` o (0,0,0) THUA no, nen reset nay chua tung co hieu luc tren
 * production: moi <a> ra mau --navy. Tren nen sang khong ai thay; trong chan
 * trang (nen --navy-dark) thi navy-tren-navy-dark = 1.23:1, tuc vo hinh. Dau
 * hieu chan doan: `.site-footer a:hover` o (0,1,1) THANG duoc, nen hover dung
 * mau con luc nghi thi sai.
 *
 * `body a` cho (0,0,2) - vua du thang core, van thua MOI rule cap class cua
 * theme, nen y dinh "link ke thua mau, cho nao can mau rieng thi khai bang
 * class" giu nguyen. `:where(:not(.wp-element-button))` chep dung ngoai le cua
 * core (dong gop 0 vao do uu tien) de khong cuop mau cua nut block editor.
 *
 * tests/test-css-cascade.php muc 12 giu danh sach selector cua core ma theme
 * phai thang, va so bang do uu tien - bo giai MOT MINH khong du, no chi doc CSS
 * cua theme.
 */
body a:where(:not(.wp-element-button)){ color:inherit; text-decoration:none; }
:where(img, svg, video, canvas, iframe){ max-width:100%; height:auto; display:block; }
:where(button, input, select, textarea){ font:inherit; color:inherit; }
:where(ul, ol){ list-style:none; }
:where(table){ border-collapse:collapse; width:100%; }

/* ============================================================
   4. Thang chữ h1–h6 — spec mục 5.7
   Reset của mockup chỉ có h1–h4; h5 và h6 bổ sung tại đây.
   ============================================================ */
h1, h2, h3, h4, h5{
  font-family:var(--font-head);
  font-weight:800;
  color:var(--navy);
  /*
   * text-wrap:balance (01/09/2026) -- khach: "check tat ca title xuong
   * dong tum lum" phat hien lech o CA .section-head h2 (trang chu) LAN
   * .intro-copy h2/.contact-cta-box h2 (Ve chung toi, chua tung kiem toi
   * truoc do) -- moi tieu de rieng deu co the co truong hop lech tuong tu,
   * khong biet truoc het duoc. Dat o RULE NEN h1-h6 dung chung toan site
   * thay vi vá tung selector rieng: phu MOI trang/tieu de la the h1-h6
   * that, khong con phai do tung trang moi tim ra. Trinh duyet chua ho
   * tro (Chrome/Safari/Firefox deu co tu 2023-2024) don gian bo qua
   * thuoc tinh -- khong co rui ro giam cap.
   */
  text-wrap:balance;
}

/*
 * Tieu de RONG + CAN TRAI: pretty thay cho balance (03/09/2026).
 * ---------------------------------------------------------------------------
 * Rule nen ngay tren dat `text-wrap:balance` cho moi h1-h6. Balance CHIA DEU
 * do dai cac dong — dung cho tieu de NGAN CAN GIUA (khe ho doi xung, nhin can
 * doi), nhung SAI cho tieu de DAI CAN TRAI: hai dong ngan bang nhau de lai mot
 * mang trong ben phai, dung trieu chung khach bao "chua full width ma da rot
 * dong roi".
 *
 * Do that o be rong 1440px (be rong khung / do rong dong dai nhat / phan thua):
 *
 *   .detail-title (H1 chi tiet du an, san pham)   820px / 495 / thua 325 = 40%
 *   .cta-copy h2 (Tuyen dung)                     420px / 239 / thua 181 = 43%
 *   .feat-main .body h3 (Tin tuc, bai noi bat)    557px / 316 / thua 241 = 43%
 *   .section-head h2 (Trang chu, ban can trai)    640px / 381 / thua 259 = 40%
 *   .au-media-copy h2 (Tac gia)                   530px / 374 / thua 156 = 29%
 *     ^ sua trong page-tacgia.css chu KHONG o day: file do khai bao
 *       text-wrap tuong minh va nap SAU global.css nen se ghi de.
 *   .certs-text-container h2 (Trang chu)          524px / 379 / thua 145 = 28%
 *
 * CO Y KHONG dung cho tieu de THE (.job-card h3, .proj-card-body h3, .hj-card):
 * khung chi 213-343px, hai dong can nhau trong the lai gon mat hon.
 *
 * `pretty` chu khong phai `wrap`: pretty van chong chu mo coi o dong cuoi —
 * dung thu khach can hom 01/09 — ma khong co ngan cac dong tren.
 */
/*
 * TIEU DE SAN PHAM "KHONG FULL RA" (04/09/2026, khach gui anh chup
 * /san-pham/tui-bau-uom-cay-tu-huy-sinh-hoc/ tren mobile, khoanh do quanh
 * tieu de xuong dong). Do that: .pd-info h1 can trai (text-align:start),
 * ke thua text-wrap:balance tu rule nen ben tren — xuong 2 dong nhung dong
 * dai nhat chi 187px trong khung 327px, thua 140px (43%) khong dung toi.
 * DUNG loai loi da sua cho 6 tieu de khac ben tren (balance chia deu do dai
 * dong, hop voi tieu de CAN GIUA ngan, nhung phan tac dung voi tieu de
 * RONG CAN TRAI) — day la tieu de thu 7 bi bo sot trong lan ra soat truoc.
 * .pd-info h1 khong nam trong file nay (o product-single.css) nen gop
 * chung vao day, dung 1 diem sua duy nhat cho toan bo nhom pretty.
 */
.pd-info h1,
.detail-title,
.section-head h2,
.certs-text-container h2,
.cta-copy h2,
.feat-main .body h3{
  text-wrap:pretty;
}

/*
 * Trong so tren, CHI `.section-head` la lop dung chung ca hai kieu can le.
 * Sau day la TOAN BO bien the duoc CAN GIUA (grep 'section-head' + 'center'
 * tren toan bo assets/css) — chung giu nguyen balance vi can giua thi hai dong
 * can nhau moi dep. Them bien the can giua moi thi phai them vao day.
 */
.gallery .section-head h2,
.vmv .section-head h2,
.org .section-head h2,
.timeline .section-head h2,
.fields .section-head h2,
.faq-box .section-head h2{
  text-wrap:balance;
}

h1{ font-size:46px;   line-height:1.15; letter-spacing:-.5px; }
h2{ font-size:32px;   line-height:1.25; }
h3{ font-size:24px;   line-height:1.3; }
h4{ font-size:17px;   line-height:1.4; }
h5{ font-size:14px;   line-height:1.45; letter-spacing:.3px; }
h6{
  font-family:var(--font-body);
  font-weight:700;
  font-size:12.5px;
  line-height:1.5;
  text-transform:uppercase;
  letter-spacing:.5px;
  color:var(--cobalt-ink);
  text-wrap:balance;
}

/* ============================================================
   5. Container và section
   :where() cho độ ưu tiên 0 — markup của plugin ghi đè được dễ dàng.
   ============================================================ */
.wrap{
  max-width:var(--wrap-max);
  margin-inline:auto;
  padding-inline:var(--wrap-x);
}

:where(section){ padding-block:var(--sp-8); }

/* Mockup dùng chung <section class="wrap">; khai lại để không mất padding dọc. */
section.wrap{ padding:var(--sp-8) var(--wrap-x); }

/*
 * SỬA — khách (25/08/2026, ảnh /san-pham/tui-hot-xoai-hd/, khoanh đỏ khoảng
 * trắng lớn giữa dải nút CTA và khối "NỘI DUNG BÀI VIẾT"): "check luôn
 * spacing lớn quá".
 *
 * `<section class="wrap"><div class="art-wrap">...` (TOC + nội dung dài) là
 * markup DÙNG CHUNG cho BỐN template — single-vp_product.php,
 * single-vp_project.php, page-templates/dich-vu-chi-tiet.php,
 * page-templates/chinh-sach-chi-tiet.php (đều bare `<section class="wrap">`,
 * không class riêng nào khác) — nên đây là lỗi CHUNG cả bốn trang, không chỉ
 * trang sản phẩm khách gửi ảnh. Sửa MỘT rule ở đây, không phải bốn PHP +
 * bốn CSS.
 *
 * KHÔNG PHẢI lỗi specificity như `.cat-seo` (SỬA LẦN 3 taxonomy-danhmuc.css)
 * — section này KHÔNG có override nào cả, nó dùng ĐÚNG mặc định
 * `section.wrap{padding-top:96px}` chưa từng bị ai chỉnh. Nhưng cộng với
 * khối phía TRÊN nó (`.pd-top`/tương đương của 4 template) đã có sẵn
 * padding-bottom riêng (64px trên trang sản phẩm — xem `.pd-top` trong
 * product-single.css), tổng khoảng trắng giữa nút CTA cuối cùng và khối TOC
 * là 64+96=160px — một dải trống thấy rõ, đúng ảnh khách khoanh.
 *
 * Giảm padding-top riêng cho đúng nhóm section này còn --sp-6 (32px, khác
 * --sp-8 mặc định), để TỔNG khoảng trắng còn 64+32=96px — ĐÚNG bằng tổng đã
 * chốt cho trang danh mục (80px shop + 16px cat-seo = 96px, SỬA LẦN 3
 * taxonomy-danhmuc.css) — cùng một nhịp trống "cuối khối tương tác → đầu
 * khối TOC" xuyên suốt site, không phải hai con số tuỳ hứng ở hai nơi.
 *
 * `:has(> .art-wrap)` giữ nguyên markup PHP ở cả bốn template (không thêm
 * class mới) — cùng kỹ thuật `.footer-grid:has(> :nth-child(4))` đã dùng
 * trong layout.css, không phải công cụ mới lạ với dự án này. Chỉ ăn CHÍNH
 * `<section class="wrap">` bọc TRỰC TIẾP `.art-wrap` (child combinator `>`),
 * không đụng các `<div class="wrap">`/`<section class="wrap">` khác trên
 * cùng trang bọc nội dung không liên quan.
 *
 * padding-BOTTOM của section này GIỮ NGUYÊN 96px (--sp-8, không đổi) —
 * khoảng cách xuống khối tiếp theo (FAQ/đánh giá/dự án liên quan) chưa có
 * feedback nào nói lớn quá, không tự ý đổi ngoài phạm vi được yêu cầu.
 */
.wrap:has(> .art-wrap){ padding-top:var(--sp-6); }

/*
 * max-width 640px -> 1240px (03/09/2026, khach yeu cau doi truc tiep
 * '.section-head{ max-width:1240px; margin-bottom:var(--sp-7); }').
 *
 * `.section-head` la khoi TIEU DE + MO TA (h2 + p) dung chung o 14 NOI
 * khac nhau tren toan site (trang chu: Thong ke/Video/San pham/Bao
 * chi/Gallery/Doi tac; Ve chung toi: VMV/To chuc/Timeline/Lanh
 * dao/Linh vuc; FAQ danh muc; 3 trang chi tiet). SAU DAY LA MOT TRONG
 * SAU DIEM co max-width:640px TUONG MINH (do uu tien cao hon rule goc
 * nay) - phai sua CA SAU cho dong bo, khong chi rule goc: khach da
 * chon 'Tat ca 14 noi, dong bo' khi duoc hoi ro pham vi (base rule +
 * .vmv/.org/.timeline/.fields trong page-vechungtoi.css, .faq-box
 * trong taxonomy-danhmuc.css). Sua chi RULE GOC ma bo sot 5 cho kia se
 * KHONG CO TAC DUNG GI o do (do uu tien selector ghep cao hon thang).
 *
 * KHONG dung `.pd-related .section-head{max-width:var(--wrap-max)}`
 * (product-single.css): gia tri do la 1180px (token --wrap-max), KHAC
 * 640px va nam NGOAI pham vi cau hoi da hoi khach - giu nguyen.
 */
.section-head{ max-width:1240px; margin-bottom:var(--sp-7); }
.section-head h2{ margin-bottom:var(--sp-4); }
.section-head p{ color:var(--text-muted); font-size:15.5px; line-height:1.65; }

.grid-cards{ display:grid; grid-template-columns:repeat(3, 1fr); gap:var(--gap-card); }
.actions{ display:flex; gap:var(--gap-inline); flex-wrap:wrap; }

/* ============================================================
   6. Nút — spec mục 7.2
   ============================================================ */

/*
 * WordPress phát sẵn :root :where(.wp-element-button, .wp-block-button__link)
 * ở độ ưu tiên 0-1-0 — bằng đúng .btn. Hai bên chỉ đụng nhau khi một phần tử
 * mang cả hai class, chuyện không xảy ra trong theme này. Nếu về sau cần đặt
 * .btn lên nút của block editor thì phải nâng độ ưu tiên, đừng dùng !important.
 */
.btn{
  display:inline-flex;
  align-items:center;
  justify-content:center;
  gap:var(--sp-2);
  padding:12px 26px;
  border:2px solid transparent;
  border-radius:var(--r-btn);
  font-family:var(--font-head);
  font-weight:700;
  font-size:14.5px;
  line-height:1.2;
  cursor:pointer;
  text-align:center;
  transition:background var(--dur-micro) ease,
             color var(--dur-micro) ease,
             border-color var(--dur-micro) ease,
             transform var(--dur-micro) ease;
}

.btn-primary{ background:var(--navy); color:var(--white); }
.btn-primary:hover{ background:var(--navy-dark); transform:translateY(-2px); }

/*
 * Viền dùng --cobalt (viền không phải chữ), nhưng CHỮ phải dùng --cobalt-ink:
 * .btn là 14.5px, dưới ngưỡng 18px, mà --cobalt chỉ đạt 3.11:1 trên nền trắng.
 * --cobalt-ink đạt 5.37:1 — xem định nghĩa token ở mục 1.
 */
.btn-secondary{ background:transparent; border-color:var(--cobalt); color:var(--cobalt-ink); }
/*
 * Đây là chỗ đầu tiên phát hiện ra rằng "--cobalt-ink đạt 4.76:1" là một lý lẽ
 * chỉ đúng trên nền TRẮNG: trên nền hover --bg-alt bản cũ #3A6ED9 chỉ còn
 * 4.17:1. Cách chữa lúc đó là đổi chữ sang --navy (10.00:1 trên --bg-alt).
 *
 * Token nay đã được hiệu chỉnh (#3366CC, 4.70:1 trên --bg-alt) nên chỗ này
 * KHÔNG còn là bắt buộc về tương phản. Giữ --navy là quyết định thị giác: nút
 * đặc lại rõ rệt khi trỏ vào, và 10:1 thì dư dả. Đừng đổi ngược về --cobalt-ink
 * chỉ vì bây giờ nó cũng đạt chuẩn.
 */
.btn-secondary:hover{ background:var(--bg-alt); color:var(--navy); }

.btn-outline-light{ background:transparent; border-color:var(--white); color:var(--white); }
.btn-outline-light:hover{ background:rgba(255, 255, 255, .14); }

/*
 * Trên nền navy, nút chính đổi sang cobalt cho nổi — nhưng là --cobalt-ink,
 * không phải --cobalt. Chữ trắng 14.5px/700 trên --cobalt chỉ đạt 3.11:1;
 * trên --cobalt-ink đạt 5.37:1. Đây đúng là thiếu hụt mà --cobalt-ink sinh ra
 * để chặn, chỉ khác là lần này nó nằm ở phía NỀN chứ không phải phía chữ.
 *
 * Hover CỐ Ý giữ nguyên nền; nút vẫn nhấc lên nhờ transform của
 * .btn-primary:hover. Phải viết rõ :hover chứ không được bỏ trống: .btn-primary:hover
 * cũng là (0,2,0) y hệt .on-navy .btn-primary, bỏ trống thì kết quả chỉ do thứ tự
 * dòng quyết định — đảo khối một cái là nền rơi về --navy-dark, 1.23:1 so với nền
 * navy, tức nút tàng hình vì viền .btn vốn trong suốt.
 *
 * Đổi nền sang --cobalt-ink kéo tương phản CHỮ lên 5.37:1 nhưng lại kéo tương phản
 * giữa NỀN NÚT và nền section navy xuống 2.13:1 (bản --cobalt cũ là 3.67:1). Viền
 * .btn vốn trong suốt nên hình dạng nút chỉ do mảng nền vẽ ra — dưới 3:1 là trượt
 * WCAG 1.4.11. Trả lại đường viền bằng --cobalt: viền không phải chữ nên --cobalt
 * dùng được, và 3.67:1 so với nền navy là đạt.
 *
 * ĐÂY LÀ CHỖ DUY NHẤT --cobalt-ink nằm trên nền tối, và nó nằm ở phía NỀN chứ
 * không phải phía chữ. Hiệu chỉnh token xuống #3366CC làm mảng nền tối thêm
 * (2.40 -> 2.13 so với section navy) nhưng con số đó không phải chốt chặn:
 * đường bao của nút do viền --cobalt vẽ, và viền đó không đổi, vẫn 3.67:1.
 */
.on-navy .btn-primary,
.on-navy .btn-primary:hover{ background:var(--cobalt-ink); border-color:var(--cobalt); }

.btn[disabled],
.btn:disabled,
.btn.is-disabled{
  background:transparent;
  border-color:var(--disabled);
  color:var(--disabled);
  cursor:not-allowed;
  transform:none;
  pointer-events:none;
}

/* ============================================================
   7. Form — spec mục 7.2
   ============================================================ */
label{
  display:block;
  font-size:13px;
  font-weight:600;
  color:var(--text);
  margin-bottom:6px;
}

label .req{ color:var(--danger); }

/*
 * RỦI RO ĐÃ CÂN NHẮC VÀ CHẤP NHẬN — đừng rà lại từ đầu.
 * Viền nghỉ --border #E2E8F0 trên nền trắng chỉ đạt 1.23:1, dưới ngưỡng 3:1 của
 * WCAG 1.4.11 nếu đọc theo nghĩa chặt. Chấp nhận vì ô nhập được nhận ra bằng
 * NHÃN và vị trí chứ không bằng đường viền, và trạng thái focus đã có vòng
 * --focus-ring đạt chuẩn. Đổi --border sang màu đậm hơn sẽ kéo theo mọi đường
 * kẻ, viền thẻ và viền bảng của cả hệ thiết kế.
 */
input[type="text"],
input[type="email"],
input[type="tel"],
input[type="url"],
input[type="number"],
input[type="search"],
input[type="password"],
input[type="date"],
select,
textarea{
  width:100%;
  padding:11px 14px;
  border:1px solid var(--border);
  border-radius:var(--r-input);
  background:var(--white);
  font-family:var(--font-body);
  font-size:14px;
  color:var(--text);
  transition:border-color var(--dur-micro) ease;
}

/*
 * KHÔNG đặt `outline:none` ở đây. Đã từng có, và nó nuốt vòng focus của mọi ô
 * nhập trong suốt Phase A mà không test nào thấy.
 *
 * Số học: rule này là (0,1,1) — một thẻ cộng một pseudo-class. Vòng focus dùng
 * chung ở mục 10 là `:where(a,button,input,textarea,select,summary,[tabindex])
 * :focus-visible`, chỉ (0,1,0), vì :where() cộng 0. Khi một ô nhập nhận focus
 * bàn phím thì CẢ HAI cùng khớp, nên (0,1,1) thắng và vòng focus biến mất.
 *
 * Tệ hơn một bậc: `outline` là shorthand, nên `outline:none` không chỉ đổi kiểu
 * nét mà đặt lại cả outline-width về medium và outline-color về currentColor.
 * Đo trên trình duyệt: ô nhập lúc focus ra outline-style:none trong khi nút và
 * link vẫn có vòng 2px — chênh lệch chỉ thấy khi đo, không thấy khi đọc file.
 *
 * Đổi màu viền là hiệu ứng phụ THỨ HAI và cố ý giữ lại, nhưng một mình nó
 * không đủ: --cobalt trên nền trắng chỉ 3.11:1.
 *
 * Ô nhập hiện vòng focus cả khi bấm chuột là ĐÚNG Ý, khác với nút. Không thêm
 * phạm vi :focus-visible riêng cho ô nhập để "sửa" chuyện đó.
 *
 * tests/test-css-cascade.php khoá lại bằng cascade thật, không bằng regex.
 */
input:focus,
select:focus,
textarea:focus{
  border-color:var(--cobalt);
}

textarea{ resize:vertical; min-height:100px; }

::placeholder{ color:var(--text-muted); opacity:1; }

.contact-field{ display:flex; flex-direction:column; margin-bottom:var(--sp-4); }

/*
 * Danh sách selector có kiểu phải LẶP LẠI đầy đủ trong media query.
 * Media query KHÔNG cộng thêm độ ưu tiên: `input` trần là (0,0,1), thua
 * `input[type="text"]` (0,1,1) của khối gốc, nên bản viết tắt là rule chết —
 * đo ở viewport 800px vẫn ra 11px 14px. Viết tắt còn rò padding sang
 * input[type="file"] và input[type="submit"], hai thứ khối gốc cố ý không đụng.
 */
@media (max-width:900px){
  .btn{ padding:12px 22px; min-height:44px; }
  input[type="text"],
  input[type="email"],
  input[type="tel"],
  input[type="url"],
  input[type="number"],
  input[type="search"],
  input[type="password"],
  input[type="date"],
  select,
  textarea{ padding:12px 14px; }
}

/* ============================================================
   8. .art-content — vùng nội dung biên tập viên nhập
   Sửa ở đây thì PHẢI sửa cả assets/css/editor.css.
   Test tests/test-editor-sync.php sẽ báo hỏng nếu quên.
   ============================================================ */
/*
 * text-wrap:pretty (03/09/2026) — khách: "chưa full width mà đã rớt dòng rồi".
 *
 * Rule nền h1–h6 ở mục 4 đặt `text-wrap:balance` (01/09/2026, cũng theo yêu
 * cầu khách: "check tất cả title xuống dòng tùm lum"). Balance CHIA ĐỀU độ dài
 * các dòng, rất hợp với tiêu đề NGẮN căn giữa (.section-head h2, .intro-copy
 * h2...) — đúng chỗ khách nhắm tới hôm đó.
 *
 * Nhưng trong CỘT THÂN BÀI rộng 752px thì nó phản tác dụng: tiêu đề dài bị bẻ
 * thành hai dòng ngắn bằng nhau, chừa trống gần nửa bề ngang. Đo thật trên
 * /san-pham/tui-bau-uom-cay-tu-huy-sinh-hoc/ (khung 752px, dòng dài nhất):
 *
 *   "Đơn vị sản xuất túi bầu ươm cây tự hủy..."  balance 424px | pretty 700px
 *   "Kích thước túi bầu ươm cây tự hủy..."       balance 397px | pretty 647px
 *   "Vinpack có nhận đục sẵn lỗ thoát nước..."   balance 394px | pretty 672px
 *
 * SỐ DÒNG KHÔNG ĐỔI (đều 2 dòng ở cả ba chế độ) — balance không làm rớt dòng
 * thêm, chỉ làm hai dòng ngắn lại nên trông như rớt dòng sớm.
 *
 * Chọn `pretty` chứ KHÔNG phải `wrap`: pretty vẫn chống chữ mồ côi ở dòng
 * cuối — đúng thứ khách cần hôm 01/09 — mà không co ngắn các dòng trên. Bỏ
 * hẳn về `wrap` là làm sống lại đúng vấn đề cũ.
 *
 * CHỈ ĐÈ TRONG .art-content: rule nền h1–h6 giữ nguyên balance cho toàn site,
 * vì ngoài thân bài không có khối nào bị (đã đo mọi h1–h6 trên trang: 3/24
 * tiêu đề lệch, cả 3 đều nằm trong .art-content).
 */
.art-content h2{
  font-size:24px;
  color:var(--navy);
  margin:38px 0 16px;
  scroll-margin-top:100px;
  text-wrap:pretty;
}
.art-content h2:first-child{ margin-top:0; }

.art-content h3{ font-size:21px; color:var(--navy); margin:28px 0 12px; text-wrap:pretty; }
.art-content h3:first-child{ margin-top:0; }

/*
 * text-align:justify (03/09/2026) — khách: "mặc định cho css text align
 * justify mấy cái description detail".
 *
 * Áp cho CẢ <p> lẫn <li> của thân bài: danh sách ở đây phần lớn là câu đầy
 * đủ dài 2-3 dòng ("80gsm: Vải mỏng và nhẹ hơn, giúp tối ưu..."), để đoạn
 * căn đều mà mục danh sách căn trái thì hai khối cạnh nhau lệch nhau thấy rõ.
 *
 * Dòng CUỐI của mỗi đoạn KHÔNG bị kéo giãn — đó là hành vi chuẩn của
 * justify, không cần khai báo thêm.
 *
 * Tiếng Việt không ngắt từ được (hyphens không dùng cho tiếng Việt), nên
 * justify nới khoảng cách GIỮA CÁC TỪ. Trong cột 752px ở cỡ chữ 15.5px thì
 * mức nới nhỏ; nếu sau này thu hẹp cột hoặc tăng cỡ chữ thì cần đo lại —
 * cột càng hẹp, khe hở càng lộ.
 */
.art-content p{
  font-size:15.5px;
  line-height:1.85;
  color:var(--text);
  margin-bottom:16px;
  text-align:justify;
}

.art-content ul,
.art-content ol{
  margin:0 0 18px;
  padding-left:22px;
}
.art-content ul{ list-style:disc; }
.art-content ol{ list-style:decimal; }

.art-content li{
  font-size:15.5px;
  line-height:1.85;
  margin-bottom:8px;
  text-align:justify;
}

/*
 * SỬA (26/08/2026, khách): "bold thì tô đậm không đổi màu" — chỉ độ đậm
 * font-weight, KHÔNG đổi màu chữ (trước đây ép var(--navy), khiến chữ in
 * đậm giữa đoạn văn --text thường bị nhảy màu ngoài ý muốn biên tập viên).
 */
.art-content strong,
.art-content b{ font-weight:700; }

.art-content em,
.art-content i{ font-style:italic; }

/*
 * SỬA (26/08/2026, khách): "link trong bài màu xanh nhưng không gạch chân"
 * — bỏ text-decoration:underline (và text-underline-offset đi kèm, vô nghĩa
 * khi không còn gạch chân). Giữ nguyên màu var(--navy) — đã là xanh (navy),
 * khách không yêu cầu đổi tông màu, chỉ bỏ gạch chân.
 */
.art-content a{
  color:var(--navy);
  transition:color var(--dur-micro) ease;
}
.art-content a:hover{ color:var(--cobalt-ink); }

.art-content img{
  width:100%;
  border-radius:var(--r-card);
  margin:20px 0;
  background:var(--img-bg);
}

.art-content figure{ margin:24px 0; }
.art-content figure img{ margin:0; }

/*
 * Chú thích ảnh của trình soạn thảo CŨ (shortcut [caption], không phải khối
 * Gutenberg): WordPress tự in style="width:NNNpx" THẲNG lên <figure
 * class="wp-caption">, bằng đúng bề rộng ảnh gốc — đo được 1200px trên ảnh
 * đồng bộ từ vinpack.vn. Không CSS ngoài nào (dù độ ưu tiên cao đến đâu, trừ
 * !important — mà cả file này CỐ Ý không dùng) thắng được width TRÊN CÙNG một
 * phần tử khi nó được set bằng style nội tuyến, vì đó là hai NGUỒN khác nhau
 * của CÙNG một thuộc tính và nguồn nội tuyến luôn thắng.
 *
 * max-width lại là chuyện khác: nó là một THUỘC TÍNH riêng, không cạnh tranh
 * với width qua cascade — trình duyệt luôn tính width trước rồi kẹp lại bằng
 * max-width sau, bất kể width đến từ đâu. Nên .art-content .wp-caption{
 * max-width:100% } kẹp được 1200px về vừa cột nội dung mà không cần
 * !important. Thiếu rule này, ảnh 1200px tự phá khung .art-wrap
 * (max-width:1080px) dù .art-layout đã dùng minmax(0,1fr) — track co đúng
 * nhưng nội dung bên trong vẫn tràn ra ngoài track đó.
 */
.art-content .wp-caption{ max-width:100%; }

/* SỬA (26/08/2026, khách): "cap image text căn giữa" — thêm text-align:center. */
.art-content figcaption{
  font-size:13px;
  color:var(--text-muted);
  line-height:1.6;
  margin-top:10px;
  text-align:center;
}
.art-content figcaption cite{
  font-size:13.5px;
  font-weight:600;
  color:var(--navy);
  font-style:normal;
}

.art-content blockquote{
  background:var(--bg-alt);
  border-radius:var(--r-card);
  padding:22px 26px;
  margin:24px 0;
  font-size:16px;
  font-style:italic;
  color:var(--navy);
  line-height:1.7;
}
/*
 * Trình soạn thảo khối bọc nội dung trích dẫn trong <p>:
 *     <blockquote class="wp-block-quote"><p>…</p><cite>…</cite></blockquote>
 *
 * `.art-content p` ở (0,1,1) đặt font-size, line-height và color THẲNG lên chính
 * thẻ <p> đó, nên bốn khai báo tương ứng của rule blockquote ngay trên chỉ còn
 * là THỪA KẾ — mà khai báo trực tiếp luôn thắng thừa kế, bất kể độ ưu tiên.
 * Đo trên trang thật trước khi thêm rule này: chữ trong trích dẫn ra 15.5px màu
 * #1A1A1A, không phải 16px navy như spec mục 7.2 quy định. Ba khai báo đó là
 * rule chết với MỌI trích dẫn do biên tập viên chèn; chỉ font-style sống sót vì
 * không có gì tranh nó.
 *
 * Rule này ở (0,1,2) — một class, hai thẻ — nên thắng `.art-content p` ở (0,1,1)
 * bằng độ ưu tiên, không phụ thuộc thứ tự dòng.
 *
 * CỐ Ý KHÔNG thắng kiểu khối "Lớn" của core. `.wp-block-quote.is-large p` và
 * `.is-style-large p` ở (0,2,1) vẫn đè rule này, và điều đó được giữ nguyên:
 * đó là một kiểu khối biên tập viên CHỌN, nên vô hiệu hoá nó lặng lẽ sẽ tạo ra
 * một control bấm vào không có gì xảy ra. Cùng lý lẽ với việc inc/theme-json.php
 * cố ý GIỮ dimensions.aspectRatios thay vì làm control đó tắt câm. Không muốn
 * kiểu đó thì gỡ hẳn bằng unregisterBlockStyle, đừng nâng độ ưu tiên ở đây.
 */
.art-content blockquote p{
  font-size:16px;
  font-style:italic;
  color:var(--navy);
  line-height:1.7;
}

/*
 * Đoạn cuối không được cộng thêm 16px vào phần đệm dưới của khung trích dẫn —
 * nếu không, khung có 22px đệm trên và 38px đệm dưới.
 */
.art-content blockquote p:last-of-type{ margin-bottom:0; }

.art-content blockquote cite{
  display:block;
  margin-top:12px;
  font-size:13.5px;
  font-weight:600;
  color:var(--navy);
  font-style:normal;
}

.art-content code{
  font-family:ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size:14px;
  color:var(--navy);
  background:var(--bg-alt);
  border-radius:6px;
  padding:2px 6px;
}

.art-content small{ font-size:12.5px; color:var(--text-muted); }

.art-content hr{
  border:none;
  border-top:1px solid var(--border);
  margin:32px 0;
}

/* Biến thể khi cả khối đặt trên nền navy. */
.on-navy blockquote{
  background:rgba(255, 255, 255, .08);
  color:var(--white);
}
.on-navy blockquote cite{ color:var(--on-navy-accent); }

/* Khung tỷ lệ cố định — bốn tỷ lệ duy nhất của hệ thiết kế. */
.media-16x10,
.media-16x9,
.media-1x1,
.media-hero{
  overflow:hidden;
  border-radius:var(--r-card);
  background:var(--img-bg);
}
.media-16x10{ aspect-ratio:16 / 10; }
.media-16x9{ aspect-ratio:16 / 9; }
.media-1x1{ aspect-ratio:1 / 1; }
.media-hero{ aspect-ratio:4 / 3.1; }

/*
 * Bản có tiền tố .art-content là (0,2,1), thắng .art-content img (0,1,1) bằng độ
 * ưu tiên. Không có nó thì hai bên bằng nhau (0,1,1) và chỉ hơn nhau vì khối này
 * đứng sau — mà Task 12 sắp chép mục 8 sang editor.css, chép thiếu hoặc đảo thứ
 * tự là ảnh trong khung lặng lẽ bo góc hai lần và ăn lại margin 20px, phá object-fit.
 * Bản không tiền tố giữ lại cho khung nằm ngoài .art-content.
 */
.art-content .media-16x10 img,
.art-content .media-16x9 img,
.art-content .media-1x1 img,
.art-content .media-hero img,
.media-16x10 img,
.media-16x9 img,
.media-1x1 img,
.media-hero img{
  width:100%;
  height:100%;
  object-fit:cover;
  margin:0;
  border-radius:0;
}

/*
 * Video nhúng (YouTube/Vimeo...) do biên tập viên dán — ép khung 16:9.
 *
 * Reset ở mục 1 có `:where(img, svg, video, canvas, iframe){ height:auto }`.
 * Với <img>/<video> thì đúng: chúng CÓ tỉ lệ nội tại nên `height:auto` giữ
 * đúng tỉ lệ khi bị co ngang. Nhưng <iframe> KHÔNG có tỉ lệ nội tại — nó chỉ
 * có thuộc tính width/height trong HTML, mà `height:auto` lại thắng thuộc
 * tính đó, nên iframe sập về chiều cao mặc định 150px của trình duyệt.
 *
 * Đo thật trên /dich-vu-in-bao-bi-theo-yeu-cau/ trước khi sửa: iframe
 * width="1200" height="650" render ra 752x150 — tỉ lệ 5.01 thay vì 1.78,
 * video bị bẹp thành một dải ngang.
 *
 * `aspect-ratio:16/9` trả lại tỉ lệ chuẩn của video, và vì đi cùng
 * `width:100%` nên khung tự co đúng tỉ lệ ở mọi bề rộng — không cần lớp bọc
 * padding-top:56.25% kiểu cũ, cũng không cần JS.
 */
.art-content iframe{
  width:100%;
  height:auto;
  aspect-ratio:16 / 9;
  border:0;
  border-radius:var(--r-lg);
  margin:24px 0;
  background:var(--video-bg);
}

/*
 * Bảng do biên tập viên chèn.
 *
 * KHÔNG đặt display:block lên chính <table>. Khuôn mẫu đó phổ biến nhưng sai:
 * width:100% chỉ định cỡ cho hộp block, còn hộp bảng bên trong vẫn co về nội
 * dung — đo được ba cột tổng 33px trong khung 1280px, hẹp gấp 40 lần. Và
 * overflow-x hầu như không kích hoạt vì văn xuôi bình thường chỉ xuống dòng.
 *
 * Trình soạn thảo khối bọc mọi bảng trong <figure class="wp-block-table">,
 * nên cho figure cuộn và giữ table là table.
 */
.art-content .wp-block-table{
  overflow-x:auto;
  overscroll-behavior-x:contain;
  -webkit-overflow-scrolling:touch;
  margin:24px 0;
}

/* Bọc sàn 520px trong min(...,100%) để một bảng hai cột vốn đã vừa khung không
   bị kéo lên 520px rồi sinh thanh cuộn thừa. Đo ở figure 352px: cũ bảng 520px và
   CÓ cuộn, mới bảng 352px và HẾT cuộn.
   Bảng thật sự rộng vẫn cuộn — nhưng nhờ min-content của chính nội dung, không
   nhờ dòng này: đo được 1709px trong figure 352px.
   NÓI THẲNG: cùng với `.art-content table{width:100%}` ngay bên dưới, min-width
   này luôn ≤ bề rộng figure nên hiện KHÔNG ép gì cả. Giữ lại làm lưới an toàn
   cho trường hợp width:100% bị bỏ — khi ấy nó chặn đúng ở mép figure thay vì
   520px. Ở màn rộng cũ và mới đo giống hệt nhau. */
.art-content .wp-block-table > table{ margin:0; min-width:min(520px, 100%); }

/*
 * Bảng dán thô, không có figure bọc: co giãn bình thường, không ép min-width
 * kẻo tràn ngang cả trang trên mobile.
 *
 * `border:0` — khách (25/08/2026, ảnh khoanh đỏ mép dưới cùng của bảng thông
 * số /san-pham/tui-dung-rac-day-rut/): "check luôn các table global sao
 * bottom ko có line border".
 *
 * NGUYÊN NHÂN: bảng dán từ Word/Excel mang theo thuộc tính HTML thô
 * `<table border="1">` (đã đo trên đúng bảng khách gửi — get Attribute
 * 'border' === '1', không phải điều tôi đoán). Trình duyệt tự map thuộc
 * tính đó thành `border:1px outset rgb(128,128,128)` qua UA stylesheet —
 * MỘT viền xám 3D hoàn toàn khác token --border (xám xanh nhạt) mà rule
 * `.art-content th, .art-content td{ border-bottom:... }` ngay dưới đang
 * dùng. Với `border-collapse:collapse`, viền CỦA CHÍNH BẢNG và viền của
 * DÒNG CUỐI CÙNG cạnh tranh đúng ở mép dưới ngoài cùng — nơi duy nhất
 * không có ô nào bên dưới để "thắng hộ". Ba dòng thẻ pasted <tr>/<td>
 * còn mang `style="height:…"` từ nguồn dán, khiến chiều cao dòng cuối
 * lệch phân-pixel (đo được 0.5px) so với khung bảng — mép dưới rơi vào
 * đúng vùng tranh chấp phân-pixel đó, có trình duyệt bỏ qua không vẽ.
 *
 * `border:0` xoá hẳn viền lạ từ thuộc tính HTML, để CHỈ CÒN viền của
 * chính theme (--border) tại mọi cạnh — không còn hai nguồn viền tranh
 * chấp nhau nữa.
 */
/*
 * MỘT khối duy nhất, không tách hai rule cùng selector `.art-content table` —
 * tests/test-editor-sync.php mục vp_css_rule_map() suy bản đồ selector=>khai
 * báo bằng cách GHI ĐÈ theo selector khi quét CSS phẳng (không gộp), nên hai
 * khối cùng tên chỉ còn khối SAU được so với editor.css — một khối biến mất
 * khỏi phép so sánh mà không có gì báo lỗi. Đã đo lỗi thật khi tách hai khối.
 *
 * `border-bottom` VIẾT LẠI sau `border:0` trong CÙNG một khối, cố ý theo
 * đúng thứ tự đó — longhand `border-bottom` khai SAU thắng đúng cạnh dưới,
 * `border:0` xử lý ba cạnh còn lại (trên/trái/phải, nơi bảng dán thô không
 * cần viền). Cùng bề rộng/kiểu/màu với viền mỗi ô (`.art-content th,
 * .art-content td` ngay dưới) nên không tạo viền đúp nhìn thấy được — nó chỉ
 * đảm bảo khung ngoài của <table> luôn khép kín tại mép dưới, không phụ
 * thuộc việc dòng cuối có lệch phân-pixel vì style dán thô hay không (xem
 * chú thích "NGUYÊN NHÂN" ngay trên).
 */
.art-content table{ width:100%; border-collapse:collapse; border:0; border-bottom:1px solid var(--border); font-size:14.5px; }

/*
 * Bảng dán thô không có <figure class="wp-block-table"> bọc sẵn — cùng lý lẽ
 * với khối ngay trên: KHÔNG đặt overflow-x lên chính <table>, bọc bằng div.
 * vinpack_render_art_toc_content() (inc/template-tags.php) tự chèn
 * .art-table-scroll quanh mọi <table> không có tổ tiên .wp-block-table.
 */
.art-content .art-table-scroll{
  overflow-x:auto;
  overscroll-behavior-x:contain;
  -webkit-overflow-scrolling:touch;
  margin:24px 0;
}
.art-content .art-table-scroll > table{ margin:0; }

/*
 * Bảng dán thô "chuẩn" về mặt hình ảnh: trước rule này bảng chỉ có
 * width:100%, không viền/nền header/đệm ô — nhìn như bảng mặc định trình
 * duyệt. Viết bộ riêng, đơn giản hơn .vp-table (biến thể pin/stack/hint của
 * .vp-table dành cho bảng thiết kế tay, không hợp bảng biên tập viên dán tự
 * do), cùng ngôn ngữ hình ảnh: nền --bg-alt/chữ --navy cho header, viền dưới
 * --border giữa các dòng, vằn ngựa vằn hàng chẵn.
 *
 * Header dán thô từ trình soạn thảo cũ thường KHÔNG dùng <th> thật — đo được
 * trên bảng báo giá thật của trang dịch-vu-in-tem-nhan: <thead><tr><td>
 * <strong>...</strong></td>. Nên style riêng cho header phải bắt CẢ hai hình
 * dạng: <th> chuẩn lẫn <td> nằm trong <thead>, không chỉ mỗi th.
 *
 * `vertical-align:top` + `line-height:1.5` (khách 26/08/2026, ảnh chụp bảng
 * giá túi sinh học: "mấy cái bẳng UI Ux cho dễ nhìn được ko") — đo trên
 * /tui-sinh-hoc/ thật: cột "Kích thước" chứa tới 20 kích cỡ cách nhau bằng
 * dấu phẩy, xuống dòng nhiều lần trong một ô; mặc định trình duyệt
 * `vertical-align:middle` khiến ô ngắn cùng dòng (vd "Độ dày") trôi nổi giữa
 * khoảng trắng thay vì thẳng hàng với đầu nội dung ô dài bên cạnh — nhìn rời
 * rạc. `top` cho mọi ô bắt đầu ngay hàng trên, đúng cách đọc bảng dữ liệu.
 * `line-height:1.5` thay vì kế thừa 1.6 mặc định của khối văn bản — bảng dữ
 * liệu cần đọc dày/gọn hơn văn xuôi, nhất là với ô đã nhiều dòng sẵn.
 */
.art-content th,
.art-content td{ padding:12px 16px; text-align:left; border-bottom:1px solid var(--border); vertical-align:top; line-height:1.5; }
/*
 * `white-space:nowrap` CHỈ header (không phải ô dữ liệu) — đo trên
 * /tui-sinh-hoc/ thật TRƯỚC khi sửa: khổ 375px, dòng header cao tới 184.5px
 * vì "Giá in túi sinh học theo yêu cầu" bị ép xuống dòng 5-6 lần trong cột
 * 67px. Giữ header MỘT dòng buộc trình duyệt chừa đủ bề rộng cột cho tiêu đề
 * — bảng có thể rộng hơn khung và cần cuộn ngang, nhưng .art-table-scroll/
 * .wp-block-table (hai khối ngay trên) đã xử lý cuộn sẵn, đúng triết lý
 * "cho khung cuộn, giữ table là table" đã ghi ở đầu mục 8 — không nới min-width
 * lên .art-content table (vẫn cấm, xem chốt phủ định ở tests/test-css-artcontent.php).
 * KHÔNG áp cho ô dữ liệu: cột "Kích thước" vẫn cần xuống dòng ở dấu phẩy,
 * nếu không một hàng 20 kích cỡ sẽ thành một dòng ngang cả nghìn pixel.
 */
.art-content th,
.art-content thead td{
  background:var(--bg-alt);
  color:var(--navy);
  font-family:var(--font-head);
  font-weight:800;
  font-size:12.5px;
  letter-spacing:.6px;
  text-transform:uppercase;
  white-space:nowrap;
}
.art-content tbody tr:nth-child(even){ background:#FBFCFE; }

/* ============================================================
   9. Bảng — spec mục 7.2, tài liệu hệ thiết kế mục 07
   Ba cách xử lý mobile: cuộn ngang (mặc định), ghim cột đầu,
   xếp thành thẻ.
   ============================================================ */
.vp-table-wrap{
  border:1px solid var(--border);
  border-radius:var(--r-lg);
  overflow:hidden;
}

/* Cách 1 — cuộn ngang, áp cho mọi bảng. */
.vp-table-scroll{
  overflow-x:auto;
  overscroll-behavior-x:contain;
  -webkit-overflow-scrolling:touch;
}

.vp-table{
  width:100%;
  min-width:640px;
  border-collapse:collapse;
  font-size:14.5px;
}

.vp-table th{
  background:var(--bg-alt);
  color:var(--navy);
  text-align:left;
  font-family:var(--font-head);
  font-weight:800;
  font-size:12.5px;
  letter-spacing:.6px;
  text-transform:uppercase;
  padding:14px 20px;
  white-space:nowrap;
}

.vp-table td{
  padding:13px 20px;
  color:var(--text-muted);
  white-space:nowrap;
}

.vp-table td:first-child{ color:var(--text); font-weight:600; }
.vp-table td.wrap-text{ white-space:normal; min-width:220px; }

.vp-table tbody tr{ border-top:1px solid var(--border); }
.vp-table tbody tr:nth-child(even){ background:#FBFCFE; }
.vp-table tbody tr:hover{ background:var(--bg-alt); }

/*
 * Dòng đổi nền thì chữ phải đậm thêm. --text-muted trên --bg-alt chỉ 4.24:1 ở
 * cỡ 14.5px, trượt AA; --text trên --bg-alt là 15.25:1.
 *
 * Đây đúng cái bẫy đã sửa ở .btn-secondary:hover, lần này ở một token khác:
 * lý lẽ "--text-muted đạt 4.83:1" chỉ đúng trên nền TRẮNG, tức đúng lúc nghỉ
 * và sai ngay khi nền hover đáp xuống.
 *
 * (0,2,3) nên thắng cả .vp-table td (0,1,2) lẫn .vp-table td:first-child (0,2,1).
 */
.vp-table tbody tr:hover td{ color:var(--text); }

.vp-table-hint{
  display:none;
  font-size:13px;
  color:var(--text-muted);
  margin-top:10px;
}

/* Cách 2 — ghim cột đầu, dùng khi bảng từ 5 cột trở lên. */
.vp-table--pin th:first-child,
.vp-table--pin td:first-child{
  position:sticky;
  left:0;
  z-index:1;
  background:var(--white);
  box-shadow:6px 0 12px rgba(0, 27, 183, .06);
}
.vp-table--pin tbody tr:nth-child(even) td:first-child{ background:#FBFCFE; }
.vp-table--pin thead th:first-child{ background:var(--bg-alt); z-index:2; }

@media (max-width:900px){
  .vp-table{ font-size:14px; }
  .vp-table th,
  .vp-table td{ padding:11px 14px; }
  .vp-table-hint{ display:block; }
}

/* Cách 3 — xếp thành thẻ, chỉ cho bảng 2–3 cột kiểu thông số. */
@media (max-width:560px){
  .vp-table--stack{ min-width:0; }
  .vp-table--stack thead{ display:none; }
  .vp-table--stack tr{
    display:block;
    border:1px solid var(--border);
    border-radius:var(--r-card);
    padding:6px 14px;
    margin-bottom:12px;
  }
  .vp-table--stack td{
    display:flex;
    justify-content:space-between;
    gap:16px;
    white-space:normal;
    padding:9px 0;
    border-top:1px solid var(--border);
  }
  .vp-table--stack tr td:first-child{ border-top:none; }
  .vp-table--stack td::before{
    content:attr(data-label);
    color:var(--text-muted);
    font-size:13.5px;
    flex-shrink:0;
  }
}

/* ============================================================
   10. Khả năng tiếp cận — spec mục 12
   Tài liệu hệ thiết kế ghi rõ: nhiều nơi đang outline:none mà
   chưa có gì thay thế. Đây là phần vá.
   ============================================================ */
/*
 * Màu là --focus-ring chứ không phải --cobalt — xem chú thích ở mục 2.
 * outline-offset 2px cũng có vai trò tương phản: vòng nằm NGOÀI phần tử nên nó
 * đối chiếu với nền của khối chứa, không phải với nền của chính nút.
 */
:where(a, button, input, textarea, select, summary, [tabindex]):focus-visible{
  outline:2px solid var(--focus-ring);
  outline-offset:2px;
}

.screen-reader-text{
  position:absolute;
  width:1px;
  height:1px;
  padding:0;
  margin:-1px;
  overflow:hidden;
  clip:rect(0, 0, 0, 0);
  clip-path:inset(50%);
  white-space:nowrap;
  border:0;
}

.skip-link{
  position:absolute;
  top:-100px;
  left:var(--sp-4);
  z-index:calc(var(--z-fab) + 1);
  border-radius:var(--r-btn);
  font-family:var(--font-head);
  font-weight:700;
  font-size:14px;
  transition:top var(--dur-micro) ease;
}

/*
 * `padding` PHẢI nằm ở đây, không được để lại ở rule .skip-link (0,1,0).
 * .screen-reader-text:focus của core cũng khai padding và đứng ở (0,2,0), nên
 * nó thắng rule nghỉ và ép link lúc focus về 15px 23px 14px — đo được trên
 * trình duyệt thật. Link lúc nghỉ bị clip nên không cần padding ở đó.
 *
 * Chọn cả thẻ `a` để đạt độ ưu tiên (0,2,1). WordPress core có sẵn
 * .screen-reader-text:focus ở (0,2,0) và sẽ chiếm background, color, left
 * nếu ta chỉ dùng .skip-link:focus — vốn cũng (0,2,0) nên chỉ thắng nhờ thứ
 * tự nạp. Đo được: nền xám #ddd, chữ #444, left 5px thay vì thiết kế của theme.
 */
a.skip-link:focus{
  top:var(--sp-4);
  left:var(--sp-4);
  padding:12px 20px;
  background:var(--navy);
  color:var(--white);
  clip:auto;
  clip-path:none;
  width:auto;
  height:auto;
  margin:0;
  overflow:visible;
  white-space:normal;
}

/* ============================================================
   11. Responsive — mốc chính 900px, spec mục 7.3
   ============================================================ */
@media (max-width:1024px){
  .grid-cards{ grid-template-columns:repeat(2, 1fr); }
}

@media (max-width:900px){
  :root{
    --wrap-x:24px;
    --sp-8:64px;
    --sp-7:36px;
    --gap-card:16px;
    --gap-inline:10px;
  }

  h1{ font-size:32px; }
  h2{ font-size:25px; }
  h3{ font-size:21px; }
  h4{ font-size:16px; }

  .section-head{ margin-bottom:var(--sp-7); }

  .art-content img{ border-radius:10px; margin:16px 0; }
  .art-content blockquote{ padding:18px 20px; font-size:15px; }
  /*
   * Phải lặp lại cho <p>. Media query KHÔNG cộng độ ưu tiên, mà
   * `.art-content blockquote p` ở mục 8 là (0,1,2) — mạnh hơn (0,1,1) của dòng
   * trên. Thiếu dòng này thì chữ trích dẫn kẹt ở 16px trên điện thoại còn khung
   * vẫn co lại, đúng kiểu rule chết mà không assertion văn bản nào thấy.
   */
  .art-content blockquote p{ font-size:15px; }
  .art-content h2{ margin:30px 0 14px; }

  /*
   * Bảng ở mobile (khách 26/08/2026 — xem chú thích đầy đủ ở mục 8): giữ
   * `white-space:nowrap` của header + không min-width trên .art-content
   * table (vẫn cấm) khiến bảng nhiều cột buộc phải cuộn ngang ở khổ hẹp —
   * đúng ý, nhưng bớt đệm/cỡ chữ một chút để cần cuộn ít hơn mà chữ vẫn đọc
   * được (đo /tui-sinh-hoc/ ở 375px: 12px viền mỗi bên × 5 cột = 40px thu
   * lại được, không đổi gì ở desktop ≥900px).
   */
  .art-content th,
  .art-content td{ padding:10px 12px; }
  .art-content td{ font-size:13.5px; }
  .art-content th,
  .art-content thead td{ font-size:12px; }
}

@media (max-width:560px){
  .grid-cards{ grid-template-columns:1fr; }
}

/* ============================================================
   12. Tôn trọng lựa chọn của người dùng
   ============================================================ */
@media (prefers-reduced-motion: reduce){
  *,
  *::before,
  *::after{
    animation-duration:.01ms !important;
    animation-iteration-count:1 !important;
    transition-duration:.01ms !important;
    scroll-behavior:auto !important;
  }
  html{ scroll-behavior:auto; }
}
