/* Bộ chữ chọn được ở Cài đặt → Giao diện. Nhúng thẳng trong site (không gọi
   Google Fonts) nên trang không phụ thuộc máy chủ ngoài và không rò địa chỉ IP
   khách sang bên thứ ba. Ba tập con theo đúng bản Google cắt sẵn: trình duyệt
   chỉ tải tập nào có chữ đang hiện — trang tiếng Việt thường chỉ tải hai tệp
   latin + vietnamese (~50KB mỗi bộ chữ). Khai @font-face ở đây KHÔNG làm trang
   nào tải thêm: chỉ bộ chữ mà --font-body đang trỏ tới mới được lấy về.
   Một tệp biến thiên cho cả dải đậm 400–700, không phải mỗi độ đậm một tệp. */
@font-face{font-family:"Noto Sans";font-style:normal;font-weight:400 700;font-display:swap;
  src:url(../fonts/noto-sans-latin.woff2) format("woff2");
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:"Noto Sans";font-style:normal;font-weight:400 700;font-display:swap;
  src:url(../fonts/noto-sans-vietnamese.woff2) format("woff2");
  unicode-range:U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1EA0-1EF9,U+20AB}
@font-face{font-family:"Noto Sans";font-style:normal;font-weight:400 700;font-display:swap;
  src:url(../fonts/noto-sans-latin-ext.woff2) format("woff2");
  unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}

@font-face{font-family:"Roboto";font-style:normal;font-weight:400 700;font-display:swap;
  src:url(../fonts/roboto-latin.woff2) format("woff2");
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:"Roboto";font-style:normal;font-weight:400 700;font-display:swap;
  src:url(../fonts/roboto-vietnamese.woff2) format("woff2");
  unicode-range:U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1EA0-1EF9,U+20AB}
@font-face{font-family:"Roboto";font-style:normal;font-weight:400 700;font-display:swap;
  src:url(../fonts/roboto-latin-ext.woff2) format("woff2");
  unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}

/* EB Garamond: chỉ giấy chứng nhận mẫu ở trang Đào tạo (.dtc-paper) dùng, chép từ
   cert.cfdways.com. Georgia thiếu chữ hoa có dấu (Ấ vỡ thành A´) nên không thay được. */
@font-face{font-family:"EB Garamond";font-style:normal;font-weight:400 800;font-display:swap;
  src:url(../fonts/eb-garamond-latin.woff2) format("woff2");
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:"EB Garamond";font-style:normal;font-weight:400 800;font-display:swap;
  src:url(../fonts/eb-garamond-vietnamese.woff2) format("woff2");
  unicode-range:U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1EA0-1EF9,U+20AB}
@font-face{font-family:"EB Garamond";font-style:italic;font-weight:400 800;font-display:swap;
  src:url(../fonts/eb-garamond-italic-latin.woff2) format("woff2");
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:"EB Garamond";font-style:italic;font-weight:400 800;font-display:swap;
  src:url(../fonts/eb-garamond-italic-vietnamese.woff2) format("woff2");
  unicode-range:U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1EA0-1EF9,U+20AB}

:root{
  /* Bộ chữ toàn site. Chọn bộ khác ở Cài đặt → Giao diện thì máy chủ chèn một
     thẻ <style> cuối <head> đặt lại đúng biến này (xem lib/ui.js) — file này
     không bị sửa, bỏ lựa chọn là quay về nguyên bản.
     Danh sách dự phòng KHÔNG còn tên "Roboto" (trước đây có): từ lúc Roboto được
     khai @font-face ngay trên kia, để tên đó trong danh sách nghĩa là máy nào
     không có system-ui lẫn Segoe UI sẽ lẳng lặng TẢI bộ chữ về — đúng thứ mà
     lựa chọn "Mặc định của máy" hứa là không làm. Máy Android vốn lấy Roboto
     làm system-ui nên bỏ tên này ra không đổi mặt chữ ở đâu cả. */
  /* Noto Sans chứ không phải chữ hệ điều hành. Lý do là ĐỘ ĐẬM, không phải mặt
     chữ: Segoe UI mà Chrome lấy cho system-ui chỉ có Regular và Bold — đặt
     font-weight 500 hay 600 lên nó ra chữ y hệt 400 (đo bằng thang 400/500/600/700
     trên chính máy Windows). Cả hệ thiết kế này cần một nấc TRUNG GIAN cho chữ
     trong thẻ: 400 thì nhạt, 700 thì bết dấu tiếng Việt ở cỡ 15px. @font-face của
     Noto Sans ở đầu file khai `font-weight: 400 700` — font biến thiên, có đủ dải.
     Ba tập con (latin, latin-ext, vietnamese) đã tự lưu trong src/assets/fonts/. */
  --font-body:"Noto Sans",system-ui,-apple-system,"Segoe UI","Helvetica Neue",Arial,sans-serif;
  /* --brand LÀ màu trong logo (#2B65B0 của khối bình hành trong cfdways-logo.svg),
     không phải một màu xanh khác cùng họ. */
  --brand:#2B65B0; --brand-mid:#1F4E88;
  /* Nền tối của trang KHÔNG còn là navy. Footer và thanh menu lúc cuộn dùng đen
     trung tính ấm #1A1918 — cùng họ với --ink, nên trang chỉ có đúng một màu
     (xanh logo) và một thang xám, không có màu thứ ba. */
  --brand-dark:#1A1918;
  /* màu logo trên nền tối: #2B65B0 đặt trên #1A1918 chưa đủ 3:1 cho mảng đồ hoạ,
     khối "CFD" ở footer đọc ra như vệt sáng mờ. Nâng sáng một nấc cùng hue. */
  --brand-lite:#4C86CE;
  /* KHÔNG còn màu nhấn thứ hai. Bộ --accent giờ trỏ thẳng về xanh logo: trang chỉ
     dùng một màu, đúng như hệ mà bản tham chiếu dựng (họ có duy nhất #236192).
     Giữ nguyên tên biến để 40+ chỗ đang gọi --accent không phải sửa. */
  --accent:#2B65B0; --accent-dark:#1F4E88; --accent-lite:#9DC2E8;
  --accent-wash:#E4E9EF; --accent-ink:#1F4E88;
  --accent-rgb:43,101,176;
  /* Chữ đen trung tính ẤM, không ngả xanh như bản cũ (#16202b). Trên nền xám
     trung tính thì chữ ngả xanh đọc ra hơi lạnh và lệch tông với ảnh. */
  --ink:#2C2A29; --muted:#6E6B69; --line:#E0E0DF;
  /* Nền trang #F7F7F7, tấm nội dung #EDEDED — chênh nhau đúng một nấc sáng. ĐÂY LÀ
     TOÀN BỘ cơ chế phân tách của hệ này: không viền, không bóng, chỉ chênh nền.
     --bg-soft không còn là "nền section xen kẽ" mà là nền của TẤM. */
  --bg:#F7F7F7; --bg-soft:#EDEDED; --panel-hi:#E6E6E5; --fill:#E0E0DF;
  --max:1360px;
  --hdr:74px;
  /* Chiều cao thanh menu SAU khi cuộn (header.stuck). Là biến chứ không phải số
     rời, vì thanh tab ở trang Tài nguyên/Công bố bám đúng vào mép dưới của nó. */
  --hdr-stuck:58px;
  /* Bóng đổ bị bỏ hẳn khỏi hệ. Giữ tên biến và cho chúng bằng `none` để mọi
     `box-shadow:var(--lift)` rải khắp file tự tắt theo, không phải đi sửa từng
     chỗ — và bật lại được bằng một dòng nếu đổi ý. */
  --shadow:none;
  --r:8px; --r-sm:4px;
  --lift:none; --lift-hi:none;
  /* Rê chuột: thẻ dịch lên --rise và đổ bóng --lift-hover. Đây là ngoại lệ DUY
     NHẤT của luật "không bóng đổ" ngay trên: bóng chỉ sống trong lúc con trỏ đặt
     lên thẻ, trạng thái nghỉ vẫn phẳng tuyệt đối.
     Bóng là thứ BẮT BUỘC phải có, không phải trang trí thêm: mép thẻ ở site này là
     ranh giới #EDEDED trên #F7F7F7 — chênh 10 đơn vị sáng, không viền. Cạnh mờ như
     vậy thì dịch trơn 8px mắt vẫn đọc ra "đứng yên" (đã dựng cả bản 4px lẫn 8px
     không bóng và đều không nhận ra). Bóng vẽ ra một cạnh đậm ngay dưới thẻ, cạnh
     đó mới là cái mắt bám vào để thấy thẻ rời khỏi mặt trang.
     Số lấy theo creaform-engineering.com (trang tham chiếu): thẻ lớn -10px kèm bóng
     0 10px 20px đen 15%, thẻ nhỏ -5px kèm 0 5px 10px đen 10%. Ở đây dùng -8px cho
     thẻ lưới, còn ô logo tự hạ xuống một nửa. Bóng MỘT lớp, blur ngắn, đục — bản
     trước hai lớp blur 24px nên loang thành quầng xám, không ra "thẻ nâng lên".
     rgba(26,25,24) = --brand-dark, đen ấm cùng họ với --ink, không phải đen thuần. */
  --rise:-8px;
  --lift-hover:0 10px 20px rgba(26,25,24,.15);
}
*{box-sizing:border-box}
/* header dính ở đỉnh nên mọi cú nhảy tới #id (mục lục, liên kết trong bài, mở
   trang sẵn kèm hash) phải chừa đúng chiều cao header, không tiêu đề chui xuống
   dưới nó. Đặt ở khung cuộn nên ăn cho cả link lẫn scrollIntoView. */
html{-webkit-text-size-adjust:100%;overflow-x:clip;
  scroll-padding-top:calc(var(--hdr) + 16px)}
@media(prefers-reduced-motion:no-preference){html{scroll-behavior:smooth}}
/* ---------- chuyển trang: hoà hình thay vì chớp trắng ----------
   Cái làm người ta thấy "bị refresh" khi đổi ngôn ngữ không phải thời gian tải
   (bản dịch đã được dựng sẵn, xem thẻ speculationrules trong base.njk) mà là
   khoảnh khắc TRẮNG giữa hai tài liệu. Khai báo này bảo trình duyệt giữ ảnh
   trang cũ lại và hoà sang trang mới, nên cú đổi nhìn như chữ đổi tại chỗ.
   Ăn cho MỌI liên kết trong site chứ không riêng nút ngôn ngữ — không khai
   riêng cho một liên kết được, mà một pha hoà 160ms ở các cú chuyển trang khác
   cũng chỉ có lợi. Trình duyệt chưa hỗ trợ bỏ qua cả khối, trang chạy y như cũ. */
@view-transition{navigation:auto}
/* Mặc định 250ms: dài, thành ra thấy "mờ đi rồi hiện lại". */
::view-transition-old(root),
::view-transition-new(root){animation-duration:160ms}
/* Header hai trang giống hệt nhau: đặt tên riêng cho nó ĐỨNG YÊN trong lúc thân
   trang hoà, thay vì mờ đi rồi hiện lại cùng mọi thứ khác — mắt bám vào thanh
   menu đứng im nên không đọc pha chuyển là một lần tải lại.
   KHÔNG dùng selector trần "header": hai tên trùng nhau trên cùng một trang là
   trình duyệt huỷ toàn bộ pha chuyển, mà src/settings.html có cả chục
   <header class="card2-head"> lồng trong thân và cũng nạp file này. */
body:not(.adminpage) > header{view-transition-name:site-header}
/* … TRỪ lúc drawer mobile đang mở — mà đó chính là lúc người dùng bấm nút đổi
   ngôn ngữ trên điện thoại: nút nằm TRONG drawer. Drawer là .navwrap phủ kín
   màn hình nằm bên trong <header>, nên ảnh chụp của thẻ "site-header" lúc ấy là
   cả màn hình; sang trang mới nó chỉ còn thanh 64px và trình duyệt sẽ diễn hoạt
   cú co lại đó. Bỏ tên đi thì cả trang (kèm drawer) hoà thẳng sang trang mới. */
body.nav-open > header{view-transition-name:none}
@media(prefers-reduced-motion:reduce){
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*){animation:none!important}
}
body{margin:0;font-family:var(--font-body);
  color:var(--ink);background:var(--bg);line-height:1.65;font-size:16px}
/* Khu quản trị có ngôn ngữ thị giác riêng (bộ --ad-* trong admin.css) nhưng vẫn
   nạp cả style.css. Ghim nền trắng ở đây để bảng màu của site — vốn vừa đổi sang
   nền xám #F7F7F7 — không lặng lẽ đổi nền trang Cài đặt và Đăng nhập theo. */
body.adminpage{background:#fff}
img{max-width:100%;display:block}
a{color:var(--brand);text-decoration:none}
a:hover{text-decoration:underline}
:focus-visible{outline:3px solid var(--accent);outline-offset:2px;border-radius:2px}
.wrap{max-width:var(--max);margin:0 auto;padding:0 20px}
/* Thang độ đậm của cả site — chỉ bốn nấc, mỗi nấc có việc riêng:
     400 thân bài · 500 chữ trong thẻ · 600 tiêu đề và nút · 700 chỉ thẻ <b>.
   Không có 750/800 nữa: hệ này không dùng chữ rất đậm ở đâu cả. */
h1,h2,h3,h4{line-height:1.22;margin:0 0 .5em;font-weight:700;letter-spacing:-.01em}
h1{font-size:clamp(1.8rem,3.2vw,2.5rem);letter-spacing:-.02em}
h2{font-size:clamp(1.25rem,1.9vw,1.6rem);letter-spacing:-.012em}
h3{font-size:1.02rem}
p{margin:0 0 1em}
/* Đệm trên/dưới của khối là BIẾN --sec-pad (mặc định ở đây, bản mobile ở cuối
   file). Người sửa kéo thanh dưới khối để đổi KHOẢNG CÁCH tới khối kế tiếp: một
   con số, lib/render.js chia đều rồi đặt inline --sec-pb cho khối trên và --sec-pt
   (+ --sec-wt cho phần dưới vạch tóc trang chủ) cho khối dưới. Không đặt gì thì
   cả ba rơi về --sec-pad. Lưu ở layout.sec, xem lib/content.js. */
.sec{--sec-pad:clamp(32px,4.2vw,52px);padding:var(--sec-pt,var(--sec-pad)) 0 var(--sec-pb,var(--sec-pad))}
/* .sec-soft KHÔNG còn tô nền. Hệ này bỏ hẳn kiểu "section trắng / section xám xen
   kẽ": cả trang là một nền #F7F7F7 liền mạch, phân tách do TẤM nội dung nổi lên
   khỏi nền chứ không do dải section. Giữ lại lớp để 50+ trang không phải sửa. */
.sec-soft{background:transparent}
/* Trang chủ (body.home): các section tách nhau bằng VẠCH TÓC theo mẫu x.ai —
   vạch nằm trong .wrap, thẳng mép nội dung (lùi 20px = padding ngang của .wrap),
   không chạy hết màn. Không tô nền xen kẽ, KHÔNG đổi nhịp dọc: padding của .sec
   giữ nguyên làm khoảng TRÊN vạch; khoảng DƯỚI vạch là padding-top của .wrap,
   đúng bằng padding .sec (kể cả bản 44px dưới 620px ở cuối file) để hai bên cân.
   Chỉ .wrap ĐẦU của section mang vạch: khối Phạm vi có dải logo nằm ngoài .wrap
   rồi tới .wrap khác, không được kẻ lại giữa chừng. Muốn áp cả site: bỏ tiền tố
   body.home. */
/* Vạch phải nằm CHÍNH GIỮA khe: phía trên vạch có hai lớp đệm (dưới khối trên +
   trên khối dưới), phía dưới chỉ có padding của .wrap — nên mỗi lớp trên lấy 3/4
   và .wrap lấy 3/2 đệm chuẩn: 39+39 = 78 trên, 78 dưới, tổng vẫn 156 như cũ.
   :has() chọn khối ĐỨNG TRƯỚC một .sec; trình duyệt cũ không hiểu thì khối trên
   giữ đệm 52, vạch lệch nhẹ chứ không vỡ. */
body.home .sec:has(+ .sec){padding-bottom:var(--sec-pb,calc(var(--sec-pad)*.75))}
body.home .sec + .sec{padding-top:var(--sec-pt,calc(var(--sec-pad)*.75))}
body.home .sec + .sec > .wrap:first-child{position:relative;padding-top:var(--sec-wt,calc(var(--sec-pad)*1.5))}
body.home .sec + .sec > .wrap:first-child::before{content:"";position:absolute;left:20px;right:20px;top:0;height:1px;background:var(--line)}
/* Đầu section: tiêu đề rồi MỘT dòng dẫn gần đen, trải hết bề ngang — không phải
   đoạn xám nhạt bó trong 62ch. Chữ nhạt ở đây làm dòng dẫn tụt xuống ngang chú
   thích, trong khi nó là câu định khung cho cả section. */
.sec-head{margin-bottom:26px;max-width:none}
.sec-head p{color:var(--ink);margin:0;font-size:1rem;line-height:1.6;max-width:78ch}
/* Vạch màu trước eyebrow bỏ đi: hệ này giảm số dấu hiệu trên trang xuống mức tối
   thiểu, và eyebrow đã tự tách bạch nhờ chữ nhỏ in hoa giãn ký tự. */
.eyebrow{font-size:.72rem;letter-spacing:.12em;text-transform:uppercase;color:var(--brand);font-weight:600;margin-bottom:10px}
.lead{font-size:1.02rem;color:var(--muted);max-width:68ch}

/* ================= HEADER =================
   Băng sáng trải hết bề ngang, KHÔNG viền dưới. Khi cuộn, nền tối đặt lên chính
   <header> nên nó cũng trải hết bề ngang — cùng một kiểu với footer.
   Trước đây nền tối đặt trên .nav (max-width:1280px) để dải tối bó trong khung nội
   dung. Bỏ vì .nav có padding:0 20px và nền tô trùm cả phần padding: mép dải tối
   thò ra 20px mỗi bên so với MỌI thứ bên dưới, đọc ra như body và footer bị hẹp
   hơn header. Chữ trong mảng màu thì cần lề, chữ body thì không, nên hai mép đó
   không bao giờ vừa trùng nhau vừa đúng — cách thoát là đẩy mép ra khỏi màn hình.
   Class .stuck do assets/js/site.js gắn ở ngưỡng cuộn 40px và gỡ ở 16px — hai
   ngưỡng lệch nhau vì chênh lệch --hdr/--hdr-stuck tự làm scrollY xê dịch. */
header{position:sticky;top:0;z-index:100;background:var(--hdr-bg);border-bottom:0;
  transition:background .22s ease}
.nav{max-width:var(--max);margin:0 auto;padding:0 20px;height:var(--hdr);display:flex;align-items:center;gap:10px;
  transition:height .22s ease}
header.stuck:not(:where([data-hdr=keep])){background:var(--brand-dark)}
header.stuck .nav{height:var(--hdr-stuck)}
/* Cài đặt → Giao diện → "Thanh menu khi cuộn: giữ nguyên" (lib/ui.js): máy chủ gắn
   data-hdr="keep" lên <header>, và mọi luật ĐỔI MÀU của .stuck bỏ qua header đó
   qua :not(:where(...)) — :where giữ nguyên độ ưu tiên cũ của luật. Luật đổi
   CHIỀU CAO thì vẫn áp: các dải bám dưới header (.rtabs, .ev-nav…) tính theo
   --hdr-stuck. Header vốn trong suốt, nên lúc cuộn phải có nền trang + một vạch tóc
   để chữ bên dưới không lộ qua. Thêm luật màu .stuck mới thì nhớ cùng kiểu neo. */
header.stuck[data-hdr=keep]{background:var(--bg);box-shadow:0 1px 0 var(--line)}
/* Nút menu nằm ngay trên dải tối ở mọi bề ngang -> luật này KHÔNG bọc media. */
header.stuck:not(:where([data-hdr=keep])) .burger span{background:#fff}

/* CHỮ SÁNG CHO NỀN TỐI: CHỈ TỪ 1025px TRỞ LÊN.
   Dưới ngưỡng đó .mlist, .lang và .acct-id không còn nằm trên dải tối nữa — chúng
   chui vào menu trượt, mà nền menu trượt LUÔN TRẮNG (.menu{background:#fff}) dù
   header có .stuck hay không. Để các luật này ở phạm vi chung thì hễ người dùng
   cuộn quá 40px là toàn bộ chữ trong menu mobile thành trắng trên trắng: menu mở
   ra trông như rỗng, chỉ còn thấy mấy vạch ngăn.
   Cùng một cái bẫy đã gặp ở logo (xem chú thích "Phải neo vào `.nav >`" bên dưới):
   drawer nằm TRONG <header> nên mọi luật `header.stuck <thẻ trần>` đều với tới nó.
   Thêm luật .stuck mới thì tự hỏi: thẻ đó lúc màn hẹp có còn trên nền tối không? */
@media(min-width:1025px){
  header.stuck:not(:where([data-hdr=keep])) .mlist > li > a{color:#fff}
  header.stuck:not(:where([data-hdr=keep])) .mlist > li > a:hover,
  header.stuck:not(:where([data-hdr=keep])) .mlist > li > a.active{color:var(--accent-lite)}
  header.stuck:not(:where([data-hdr=keep])) .mlist > li > a.active::after{background:var(--accent-lite)}
  header.stuck:not(:where([data-hdr=keep])) .lang{color:rgba(255,255,255,.72);border-color:rgba(255,255,255,.24)}
  /* Nền tối: hover của .lang ở khối chung tô nền --brand, gần như trùng dải tối
     nên không còn thấy phản hồi — ở đây lật sang lớp trắng mờ cho cùng họ với
     các mục menu khác. */
  header.stuck:not(:where([data-hdr=keep])) .lang:hover{color:#fff;background:rgba(255,255,255,.14);
    border-color:rgba(255,255,255,.6)}
  /* Khối tài khoản bám mép PHẢI MÀN HÌNH, nên từ lúc nền tối trải hết bề ngang nó
     nằm hẳn trên nền tối — trước đó nó còn thò ra ngoài dải tối 1280px. Chữ #25313e
     và nút viền màu --brand đều không đọc được ở đó. */
  header.stuck:not(:where([data-hdr=keep])) .acct-id b{color:#fff}
  header.stuck:not(:where([data-hdr=keep])) .acct-id span{color:rgba(240,240,240,.6)}
  header.stuck:not(:where([data-hdr=keep])) .acct-id:hover b{color:var(--accent-lite)}
  header.stuck:not(:where([data-hdr=keep])) .acct .btn-line{border-color:rgba(255,255,255,.38);color:#fff}
  header.stuck:not(:where([data-hdr=keep])) .acct .btn-line:hover{background:rgba(255,255,255,.14);color:#fff}
}
/* Trên nền tối dùng bản logo assets/img/cfdways-logo-dark.svg — chính là bản mono
   chính thức của thương hiệu: toàn hình trắng, chữ "CFD" khoét rỗng cho nền tối lộ
   qua. Bản sáng không dùng được ở đây vì khối #2B65B0 chỉ đạt 2,97:1 và chữ "WAYS"
   #3C3C3D đạt 1,6:1 trên #1A1918. Đổi bằng display, không đổi src: không JS vẫn đúng
   và không có nhịp trắng lúc cuộn qua ngưỡng .stuck.
   Phải neo vào `.nav >` chứ không để `header.stuck .logo` trần: logo trong drawer
   (.mhead) cũng nằm trong <header>, mà nền drawer luôn trắng — bản nền tối lọt vào
   đó là chữ sáng trên nền sáng. */
header.stuck:not(:where([data-hdr=keep])) .nav > .logo img.lt{display:none}
header.stuck:not(:where([data-hdr=keep])) .nav > .logo img.dk{display:inline-block}
header.stuck .nav > .logo img{height:28px}

.logo{display:inline-flex;align-items:center;flex:0 0 auto;text-decoration:none}
.logo:hover{text-decoration:none}
.logo img{height:34px;width:auto}
.logo img.dk{display:none}
footer .logo img{height:30px}
footer .logo img.dk{display:inline-block}
/* .logotext là bản chữ dự phòng, chỉ hiện khi ảnh logo tải hỏng (onerror gắn
   .nologo). Ở nền tối phải đổi màu theo, nếu không rơi vào đúng vấn đề tương phản
   mà bản logo nền tối vừa giải quyết. */
.logotext{display:none;align-items:center;font-weight:700;font-size:1.26rem;letter-spacing:.02em;line-height:1}
.logotext .l1{background:var(--brand);color:#fff;padding:5px 7px;border-radius:4px}
.logotext .l2{color:#3C3C3D;padding-left:4px}
.logo.nologo img{display:none}
.logo.nologo .logotext{display:inline-flex}
header.stuck .nav > .logo.nologo .logotext{font-size:1.1rem}
header.stuck:not(:where([data-hdr=keep])) .nav > .logo .logotext .l1,
footer .logotext .l1{background:var(--brand-lite)}
header.stuck:not(:where([data-hdr=keep])) .nav > .logo .logotext .l2,
footer .logotext .l2{color:#f0f0f0}

.navwrap{display:contents}
.menu{margin-left:auto;display:flex;flex-direction:row;align-items:center}
.mhead,.mfoot{display:none}
.mlist{display:flex;list-style:none;margin:0;padding:0;align-items:center;gap:2px}
.mlist > li{position:relative}
.mlist > li > a{display:flex;align-items:center;gap:7px;padding:10px 13px;color:var(--ink);font-size:.9rem;
  font-weight:500;white-space:nowrap;border-radius:8px;position:relative;transition:color .15s}
.mlist > li > a:hover{color:var(--brand);text-decoration:none}
.mlist > li > a.active{color:var(--brand)}
.mlist > li > a.active::after{content:'';position:absolute;left:13px;right:13px;bottom:2px;height:2.5px;
  border-radius:2px;background:var(--brand)}
.chev{width:7px;height:7px;border-right:1.8px solid currentColor;border-bottom:1.8px solid currentColor;
  transform:rotate(45deg) translateY(-1px);transition:transform .2s;opacity:.55;flex:0 0 auto}
.mlist > li:hover > a .chev,.mlist > li:focus-within > a .chev{transform:rotate(225deg);opacity:1}

/* dropdown desktop */
.sub{position:absolute;top:calc(100% + 10px);left:0;min-width:308px;background:#fff;
  border:1px solid var(--line);border-radius:14px;padding:10px;margin:0;list-style:none;
  box-shadow:0 18px 36px rgba(16,45,61,.10);
  opacity:0;visibility:hidden;transform:translateY(8px);transition:opacity .18s ease, transform .18s ease, visibility .18s}
.sub::before{content:'';position:absolute;top:-12px;left:0;right:0;height:12px}
.mlist > li:hover .sub,.mlist > li:focus-within .sub{opacity:1;visibility:visible;transform:none}
.sub a{display:flex;align-items:flex-start;gap:11px;padding:10px 14px;border-radius:9px;
  color:var(--ink);font-size:.89rem;line-height:1.4}
.sub a b{display:block;font-weight:700}
.sub a span{display:block}
.sub .nvt span{font-size:.78rem;color:var(--muted);margin-top:1px}
.sub a:hover{background:var(--bg-soft);text-decoration:none}
.sub a:hover b{color:var(--brand)}
.sub .grp{padding:12px 14px 5px;font-size:.68rem;letter-spacing:.13em;text-transform:uppercase;
  color:var(--muted);font-weight:800}
.sub .sep{height:1px;background:var(--line);margin:8px 6px}

/* Biểu tượng của mục con (lib/navicons.js). Nét vẽ để hết ở đây: 30 hình trong
   bộ chỉ có <path>, không hình nào tự mang màu — đổi màu nhấn sửa đúng chỗ này. */
.nvi{width:19px;height:19px;flex:0 0 auto;margin-top:1px;fill:none;stroke:#7d90a6;
  stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round;transition:stroke .15s}
.sub a:hover .nvi{stroke:var(--brand)}
.sub .nvt{min-width:0;flex:1} /* nhãn dài phải xuống dòng chứ không đẩy rộng cả cột */

/* Dòng "Xem tất cả →" đóng một cột lại: tách khỏi danh sách bằng khoảng trống
   và một vạch mảnh, chữ nhỏ hơn — nó là lối ra, không phải một mục ngang hàng. */
.sub .more{margin-top:6px;padding-top:8px;border-top:1px solid var(--line)}
.sub .more a{font-size:.83rem;font-weight:700;color:var(--brand);gap:7px;align-items:center}
.sub .more a:hover{background:transparent;text-decoration:underline}
.arw{width:6px;height:6px;border-right:1.9px solid currentColor;border-bottom:1.9px solid currentColor;
  transform:rotate(-45deg);transition:transform .18s}
.sub .more a:hover .arw{transform:rotate(-45deg) translate(2px,2px)}

/* ---- mega menu: panel rộng nhiều cột ----
   Mục cha bỏ position:relative để gốc định vị lùi ra <header> (sticky = đã là
   phần tử positioned). Nhờ vậy panel căn giữa MÀN HÌNH và rộng đúng bằng cột
   nội dung, thay vì bám mép trái của một mục menu rồi tràn ra ngoài màn hình. */
.mlist > li.mg{position:static}
/* Panel DÁN LIỀN đáy header, không chừa khe. Gốc định vị đã lùi ra <header> (nhờ
   position:static ngay trên) nên top:100% rơi đúng đáy thanh menu, kể cả lúc cuộn
   khi header co từ 74px xuống 58px. Chừa khe thì lúc cuộn — header là dải đen tràn
   viền, panel trắng — vệt nền trang lọt giữa hai mảng đọc ra như lỗi render, đúng
   lý do .pageband không có margin-top. Bo góc chỉ còn hai đỉnh dưới, bỏ viền trên
   và bỏ bóng (hệ đã đặt --lift:none): panel là phần nối dài của thanh menu chứ
   không phải một tấm nổi. */
.sub.mega{left:50%;top:100%;transform:translate(-50%,8px);
  width:min(var(--max),calc(100vw - 40px));min-width:0;
  display:grid;gap:0 10px;padding:18px 16px;
  border-top:0;border-radius:0 0 16px 16px;box-shadow:none}
/* Cầu nối hover cao 12px của .sub sinh ra để bắc qua khe. Hết khe thì nó chỉ còn là
   một mảng vô hình đè lên đáy header — lúc cuộn nó ăn mất 5px cuối của chính mục
   menu đang mở, bấm vào đó không ra liên kết nào. */
.sub.mega::before{display:none}
.mlist > li.mg:hover .sub.mega,.mlist > li.mg:focus-within .sub.mega{transform:translate(-50%,0)}
.sub.mega.cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}
.sub.mega.cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}
.sub.mega.cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}
/* Cột cuối là tấm promo (.haspro do lib/menuhtml.js gắn): promo giữ bề ngang cố
   định 268px, phần còn lại chia đều cho các cột chữ — nhờ vậy bảng 3 cột + promo
   (Giải pháp) và 4 cột + promo (Lĩnh vực, Dự án) có tấm promo y hệt nhau. */
.sub.mega.cols-2.haspro{grid-template-columns:minmax(0,1fr) 268px}
.sub.mega.cols-3.haspro{grid-template-columns:repeat(2,minmax(0,1fr)) 268px}
.sub.mega.cols-4.haspro{grid-template-columns:repeat(3,minmax(0,1fr)) 268px}
/* Bảng MỘT cột (Phần mềm Siemens) vẫn dùng khung 3 cột + promo của bảng bên cạnh
   (Giải pháp): cột duy nhất rơi đúng vào ô đầu, cùng bề ngang và cùng mép với cột
   đầu của bảng kia, nên rê qua lại giữa hai mục chỉ thấy ruột đổi chứ khung không
   nhảy. Chiều cao bằng nhau do --mega-h lo (xem dưới). */
.sub.mega.cols-1{grid-template-columns:repeat(3,minmax(0,1fr)) 268px}
/* Hàng cột là hàng co giãn: khi panel bị min-height (--mega-h) kéo cao hơn nội
   dung, phần dư dồn hết vào hàng cột — "Xem tất cả" (margin-top:auto) và tấm
   promo (flex:1) tụt theo xuống đáy — chứ không chia đôi cho hàng chân. Lúc không
   có phần dư, 1fr co về đúng nội dung như auto. */
.sub.mega{grid-template-rows:minmax(0,1fr)}
.sub.mega.hasfr{grid-template-rows:minmax(0,1fr) auto}
.sub.mega .mcol{display:flex;flex-direction:column}
.sub.mega .mcol > ul{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;flex:1}
/* Vạch ngăn giữa các cột: chỉ vẽ ở cột thứ hai trở đi, không có vạch thừa ở rìa */
.sub.mega .mcol + .mcol{padding-left:11px;border-left:1px solid var(--line)}
/* "Xem tất cả" luôn tụt xuống đáy cột, nên ba cột dài ngắn khác nhau vẫn có
   ba lối ra thẳng hàng nhau ở chân panel. */
.sub.mega .more{margin-top:auto}
/* Tiêu đề nhóm dài ("Digital twin & Engineering AI") xuống hai dòng và đẩy cả
   cột đó tụt xuống so với các cột bên cạnh. Chừa sẵn chỗ cho hai dòng để hàng
   đầu tiên của mọi cột luôn thẳng nhau, bất kể nhãn dài ngắn. */
.sub.mega .grp{padding-top:2px;min-height:2.6em;display:flex;align-items:flex-end}
/* Mục nổi bật trong panel rộng: nền dịu để tách khỏi các dòng liên kết thường */
.sub.mega .ft a{background:var(--bg-soft);margin-bottom:6px;align-items:flex-start}
.sub.mega .ft a:hover{background:#e9f2fb}
.sub.mega.cols-5{grid-template-columns:repeat(4,minmax(0,1fr)) 268px}

/* --- cột thẻ ảnh (.ccol: mục con "card" / "latest", lib/menuhtml.js) -------
   Phần mềm và Tài nguyên chỉ có 5–6 liên kết: nhét vào khung 3 cột + promo của
   bảng Giải pháp thì bỏ trống 3/4 panel. Bố cục cho hai bảng đó: cột liên kết
   1 phần, hàng thẻ 3 phần — cùng bề ngang, cùng chiều cao (--mega-h) với các
   bảng khác nên rê qua lại khung vẫn không nhảy. Mẫu khác ngoài [chữ | thẻ]
   rơi về luật cols-N chia đều ở trên. nc-N = số thẻ trong cột. */
.sub.mega.cols-2.hascards{grid-template-columns:minmax(0,1fr) minmax(0,3fr)}
.sub.mega .mcol.ccol{padding-left:22px}
.sub.mega .ccol > ul{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:0 16px;align-content:start}
.sub.mega .ccol.nc-1 > ul{grid-template-columns:minmax(0,1fr)}
.sub.mega .ccol.nc-2 > ul{grid-template-columns:repeat(2,minmax(0,1fr))}
.sub.mega .ccol.nc-4 > ul{grid-template-columns:repeat(4,minmax(0,1fr))}
.sub.mega .ccol .grp,.sub.mega .ccol .more{grid-column:1/-1}
.sub .mcard a{display:flex;flex-direction:column;gap:3px;padding:0 0 4px;border-radius:0;color:var(--ink)}
.sub .mcard a:hover{background:none}
/* Khung ảnh giữ tỷ lệ khi ảnh chưa tải (ảnh chỉ tải lúc bảng mở, xem site.js):
   chiều cao bảng đo được ngay từ đầu, --mega-h không lệch. */
.sub .mcimg{display:block;aspect-ratio:16/10;border-radius:10px;overflow:hidden;background:var(--bg-soft);margin-bottom:9px}
.sub .mcimg img{display:block;width:100%;height:100%;object-fit:cover;transition:transform .35s ease-out}
.sub .mcard a:hover .mcimg img{transform:scale(1.03)}
.sub .mcard b{font-size:.9rem;line-height:1.3;font-weight:700}
.sub .mcd{font-size:.78rem;line-height:1.4;color:var(--muted)}
@media(prefers-reduced-motion:reduce){.sub .mcimg img{transition:none}}

/* --- tấm promo ở cột cuối --------------------------------------------------
   Cột promo KHÔNG có vạch ngăn bên trái: nó đã là một mảng màu đặc, thêm vạch
   nữa thành hai đường phân cách chồng nhau. */
.sub.mega .pcol{padding-left:11px;border-left:0}
.sub.mega .pro{display:flex;flex:1}
.sub.mega .pro a{flex:1;flex-direction:column;justify-content:flex-end;gap:0;
  padding:20px;border-radius:12px;color:#fff;
  background:linear-gradient(145deg,var(--brand-dark) 0%,var(--brand-mid) 62%,var(--brand) 100%)}
.sub.mega .pro a:hover{background:linear-gradient(145deg,var(--brand-dark) 0%,var(--brand-mid) 40%,var(--brand) 100%)}
.sub.mega .pro b{font-size:1.02rem;line-height:1.25;color:#fff;margin-bottom:8px}
.sub.mega .pro a:hover b{color:#fff}
.sub.mega .pro .pd{font-size:.79rem;line-height:1.45;color:#c7dcec;margin-bottom:16px}
.sub.mega .pro .pbtn{display:inline-flex;align-items:center;gap:8px;align-self:flex-start;
  background:#fff;color:var(--ink);font-size:.76rem;font-weight:700;
  padding:9px 13px;border-radius:7px}
.sub.mega .pro .pbtn .arw{border-color:var(--brand)}

/* --- hàng chân mega --------------------------------------------------------
   Trục phụ của panel ("Theo ngành", "Theo kết quả"): một dải ngang vắt hết bề
   ngang lưới, nên phải grid-column:1/-1 chứ không nằm trong cột nào. */
.sub.mega .mfr{grid-column:1/-1;display:flex;flex-wrap:wrap;align-items:baseline;gap:10px 26px;
  margin-top:14px;padding:13px 6px 2px;border-top:1px solid var(--line)}
.sub.mega .mfr-lbl{font-size:.68rem;letter-spacing:.13em;text-transform:uppercase;
  font-weight:800;color:var(--muted);flex:0 0 auto}
.sub.mega .mfr-links{display:flex;flex-wrap:wrap;gap:6px 22px}
.sub.mega .mfr-links a{display:inline-flex;align-items:center;gap:7px;padding:5px 0;
  font-size:.86rem;font-weight:700;color:var(--ink);background:none}
.sub.mega .mfr-links a::before{content:"";width:5px;height:5px;border-radius:1px;
  background:var(--accent);flex:0 0 auto}
.sub.mega .mfr-links a:hover{background:none;color:var(--brand);text-decoration:none}

/* ---- lớp phủ mờ dưới panel mega (desktop) ----
   Panel mega che gần hết chiều ngang nhưng nội dung trang phía dưới (nút CTA
   đậm, carousel ảnh) vẫn hiện nguyên độ tương phản và tranh sự chú ý với menu.
   Lớp phủ này đặt menu thành tầng trên cùng rõ ràng, cùng màu/blur với .scrim
   của drawer mobile. Là ::after của <body> (body không phải stacking context nên
   z-index:99 xếp ngay DƯỚI header z-index:100 trong ngữ cảnh gốc, trên mọi
   section tĩnh). Bắt đầu từ ĐÁY header (top = --hdr / --hdr-stuck) chứ không
   inset:0: header không có nền đục (--hdr-bg chưa định nghĩa → trong suốt) nên
   phủ từ mép trên là thanh menu cũng tối và nhòe theo. Cuộn là panel tự đóng
   (site.js) nên mốc top đổi giữa hai trạng thái không thấy được lúc đang mở.
   KHÔNG đặt vào header::after z-index:-1: lớp đó tối được trang
   nhưng backdrop-filter không "nhìn" thấy nội dung ngoài stacking context của
   header — chỉ phần mờ mất tác dụng, đo mới thấy. pointer-events:none — rời
   chuột khỏi panel là đóng nên không cần bắt click. Chỉ kích hoạt cho li.mg:
   bảng thả nhỏ (.has thường) mà tối cả trang là quá tay. Hai nhánh: không JS mở
   theo :hover; có JS (.js-nav) theo lớp .on để đi cùng độ trễ của panel — :hover
   thuần bị tắt lại, nếu không lớp phủ sẽ hiện trước panel 130ms lúc con trỏ mới
   lướt ngang qua. */
@media(min-width:1025px){
  body::after{content:'';position:fixed;top:var(--hdr);left:0;right:0;bottom:0;z-index:99;
    background:rgba(7,30,48,.34);-webkit-backdrop-filter:blur(3px);backdrop-filter:blur(3px);
    opacity:0;visibility:hidden;pointer-events:none;transition:opacity .22s ease, visibility .22s}
  body:has(> header.stuck)::after{top:var(--hdr-stuck)}
  body:has(.mlist > li.mg:hover)::after,
  body:has(.mlist > li.mg:focus-within)::after{opacity:1;visibility:visible}
  .js-nav body:has(.mlist > li.mg:hover)::after{opacity:0;visibility:hidden}
  .js-nav body:has(.mlist > li.mg.on)::after,
  .js-nav body:has(.mlist > li.mg:focus-within)::after{opacity:1;visibility:visible}
}

/* ---- mở bảng thả xuống có ĐỘ TRỄ (chỉ khi có JS) ----
   Mặc định bảng mở bằng :hover thuần, không JS vẫn dùng được. Khi site.js chạy
   nó gắn .js-nav lên <html>, và từ đó quyền mở chuyển sang lớp .on do JS đặt
   sau một nhịp trễ ngắn. Cần thiết vì panel mega rộng cả màn hình: bật ngay lúc
   con trỏ mới lướt ngang qua trên đường tới mục khác là chói mắt và che nội
   dung. Bàn phím (:focus-within) thì mở tức thì — người dùng Tab tới là có ý.
   Bọc trong min-width:1025px vì dưới ngưỡng đó bảng là accordion trong drawer,
   dùng max-height chứ không dùng opacity. */
@media(min-width:1025px){
  /* Mọi bảng mega cao BẰNG NHAU: site.js đo bảng cao nhất rồi ghi --mega-h lên
     .mlist; bảng thấp hơn được kéo lên bằng min-height. Chỉ ở desktop — trong
     drawer mobile bảng đóng/mở bằng max-height:0, một min-height ở đó là bảng
     đóng vẫn lòi ra. Không JS thì biến không có, bảng cao theo nội dung như cũ. */
  .sub.mega{min-height:var(--mega-h,0px)}
  .js-nav .mlist > li.has:hover > .sub{opacity:0;visibility:hidden;transform:translateY(8px)}
  .js-nav .mlist > li.mg:hover > .sub.mega{transform:translate(-50%,8px)}
  .js-nav .mlist > li.has.on > .sub,
  .js-nav .mlist > li.has:focus-within > .sub{opacity:1;visibility:visible;transform:none}
  .js-nav .mlist > li.mg.on > .sub.mega,
  .js-nav .mlist > li.mg:focus-within > .sub.mega{transform:translate(-50%,0)}
  /* Đang mở bảng này rê sang mục khác (site.js gắn .swap lên .mlist): bảng cũ và
     bảng mới chỉ đổi chỗ bằng một nhịp mờ nhanh, KHÔNG trượt dọc 8px — hai bảng
     cùng trượt ngược chiều lúc chồng lên nhau là cái "nhảy" thấy được. Chiều cao
     bốn bảng lệch nhau tới ~50px nên site.js còn đặt height tạm để chuyển mượt từ
     cao độ bảng cũ sang bảng mới; height .22s ở đây là cho việc đó. Gỡ .swap khi
     không còn bảng nào mở để lần đóng hẳn vẫn trượt xuống như thường. */
  .js-nav .mlist.swap > li.mg > .sub.mega{transform:translate(-50%,0);
    transition:opacity .14s ease, visibility .14s, height .22s ease}
  /* Bảng mới nằm TRÊN (z-index) và mờ dần vào; bảng cũ giữ nguyên đục thêm .14s
     rồi tắt ngay (delay, không fade). Nếu cả hai cùng fade thì giữa chừng hai
     tấm đều nửa trong suốt, lớp phủ tối lộ xuyên qua — thấy như nháy xám. */
  .js-nav .mlist.swap > li.mg.on > .sub.mega{z-index:1}
  .js-nav .mlist.swap > li.mg:not(.on) > .sub.mega{transition:opacity 0s .14s, visibility 0s .14s, height .22s ease}
  /* mũi tên chỉ lật khi bảng THẬT SỰ mở, không lật lúc mới rê qua */
  .js-nav .mlist > li.has:hover > a .chev{transform:rotate(45deg) translateY(-1px);opacity:.55}
  .js-nav .mlist > li.has.on > a .chev,
  .js-nav .mlist > li.has:focus-within > a .chev{transform:rotate(225deg);opacity:1}
}

/* đổi ngôn ngữ bằng MỘT nút chữ — nút in mã ngôn ngữ SẼ chuyển sang, kèm quả
   địa cầu để mã hai chữ cái ấy không bị đọc nhầm là một mục menu.
   Chữ chứ không phải cờ: cờ đánh đồng ngôn ngữ với quốc gia (tiếng Anh đâu chỉ
   của Anh), và ở cỡ 25×17px thì hai lá cờ đọc ra hai vệt màu na ná nhau. */
.langs{display:flex;align-items:center;gap:3px;padding:10px 11px}
.langlbl{display:none;font-size:.8rem;font-weight:650;color:var(--muted)} /* chỉ hiện trong drawer mobile */
.lang{display:inline-flex;align-items:center;justify-content:center;gap:5px;
  padding:5px 9px;border:1px solid var(--line);border-radius:999px;line-height:1;
  font-size:.78rem;font-weight:700;letter-spacing:.05em;color:var(--muted);
  transition:color .15s, background .15s, border-color .15s}
.lang svg{width:14px;height:14px;flex:0 0 auto;fill:none;stroke:currentColor;
  stroke-width:1.8;stroke-linecap:round}
.lang b{font-weight:700}
/* Hover CHỈ đổi chữ + viền, không tô đầy: nút này đứng sát nút tìm kiếm, mà nút
   tìm kiếm hover cũng chỉ đổi chữ+viền (.srch-btn:hover). Tô nền xanh đặc làm
   cả góc phải header nháy thành một mảng xanh — nặng hơn hẳn cái nó báo. */
.lang:hover{text-decoration:none;color:var(--brand);border-color:var(--brand)}
/* huỷ padding/bo góc của mục menu thường áp lên thẻ <a> của nút ngôn ngữ */
.mlist > li.langs > a.lang{padding:5px 9px;border-radius:999px}

/* ---------- nút tìm kiếm trong header ----------
   Là con trực tiếp của .nav, đứng SAU .navwrap trong DOM. Trên desktop .menu
   có margin-left:auto nên cả cụm menu bị đẩy sang phải và nút này rơi ngay sau
   cụm VI/EN — đúng chỗ muốn đặt, mà không phải nhét thêm một <li> vào .mlist
   (xem chú thích trong partials/header.njk).
   Ô vuông biểu tượng cùng cỡ và cùng kiểu viền với hai nút của khối tài khoản,
   để góc phải header chỉ có MỘT ngôn ngữ hình khối.
   Ẩn khi không có JS: tìm kiếm chạy trọn vẹn ở trình duyệt (tải chỉ mục về rồi
   tra), không JS thì bấm vào không có gì xảy ra — thà đừng hiện nút. */
.srch-btn{display:none;align-items:center;justify-content:center;flex:0 0 auto;
  width:34px;height:34px;padding:0;background:none;color:#33414e;
  border:1.5px solid var(--line);border-radius:8px;cursor:pointer;
  transition:color .15s, border-color .15s, background .15s}
.js-nav .srch-btn{display:inline-flex}
.srch-btn svg{width:17px;height:17px;fill:none;stroke:currentColor;stroke-width:1.9;
  stroke-linecap:round;stroke-linejoin:round}
.srch-btn:hover{color:var(--brand);border-color:var(--brand)}
header.stuck:not(:where([data-hdr=keep])) .srch-btn{color:#fff;border-color:rgba(255,255,255,.38)}
header.stuck:not(:where([data-hdr=keep])) .srch-btn:hover{background:rgba(255,255,255,.14);border-color:rgba(255,255,255,.6)}

/* ---------- bảng tìm kiếm ----------
   Toàn bộ khối này do assets/js/site.js dựng lúc mở lần đầu, không nằm sẵn
   trong 56 trang tĩnh. Đóng/mở bằng opacity + visibility như .scrim, không bằng
   display:none — visibility:hidden vừa gỡ khỏi luồng tab vừa gỡ khỏi cây trợ
   năng, mà vẫn còn đường để chuyển động mờ dần.
   z-index phải trên 120 của .navwrap: trên màn hẹp menu trượt là lớp cao nhất
   của header, bảng tìm kiếm mở ra từ đó phải nằm đè lên nó. */
.srch-ov{position:fixed;inset:0;z-index:200;display:flex;justify-content:center;
  align-items:flex-start;padding:clamp(12px,9vh,96px) 16px 16px;
  opacity:0;visibility:hidden;transition:opacity .18s ease, visibility 0s .18s}
/* visibility đổi TỨC THÌ lúc mở (0s, không trễ) và chỉ hoãn tới cuối lúc đóng.
   Không được để nó chạy transition như opacity: phần tử còn visibility:hidden
   thì .focus() rơi vào khoảng không, và bảng mở ra với con trỏ nằm ngoài ô nhập
   — người dùng gõ mà không có chữ nào hiện. */
.srch-ov.on{opacity:1;visibility:visible;transition:opacity .18s ease, visibility 0s 0s}
body.srch-open{overflow:hidden}
.srch-scrim{position:absolute;inset:0;background:rgba(7,30,48,.5);
  -webkit-backdrop-filter:blur(3px);backdrop-filter:blur(3px)}
/* Tấm trắng nổi trên nền tối: đây là một trong vài chỗ hệ này CÓ bóng đổ, cùng
   lý do với .sub — nó là lớp nổi thật sự, không phải một mảng trong trang. */
.srch-box{position:relative;display:flex;flex-direction:column;width:min(680px,100%);
  max-height:min(74vh,620px);background:#fff;border-radius:14px;overflow:hidden;
  box-shadow:0 24px 60px rgba(7,30,48,.28);
  transform:translateY(-10px);transition:transform .18s ease}
.srch-ov.on .srch-box{transform:none}

.srch-top{display:flex;align-items:center;gap:11px;padding:13px 14px;
  border-bottom:1px solid var(--line);flex:0 0 auto}
.srch-top > svg{width:19px;height:19px;flex:0 0 auto;fill:none;stroke:var(--muted);
  stroke-width:1.9;stroke-linecap:round;stroke-linejoin:round}
/* Ô nhập KHÔNG có viền riêng: cả hàng trên cùng đã là ô nhập, viền lồng trong
   viền chỉ vẽ thêm một cái hộp thứ hai. */
.srch-q{flex:1;min-width:0;border:0;outline:0;background:none;padding:4px 0;
  font-family:inherit;font-size:1.02rem;color:var(--ink);line-height:1.4}
.srch-q::placeholder{color:var(--muted)}
.srch-x{flex:0 0 auto;background:none;border:1.5px solid var(--line);border-radius:7px;
  padding:5px 9px;font-family:inherit;font-size:.72rem;font-weight:700;letter-spacing:.04em;
  color:var(--muted);cursor:pointer;transition:color .15s, border-color .15s}
.srch-x:hover{color:var(--brand);border-color:var(--brand)}

.srch-res{overflow-y:auto;overscroll-behavior:contain;-webkit-overflow-scrolling:touch;
  padding:6px;flex:1}
.srch-grp{padding:11px 12px 4px;font-size:.68rem;letter-spacing:.13em;text-transform:uppercase;
  color:var(--muted);font-weight:800}
.srch-it{display:block;padding:9px 12px;border-radius:9px;color:var(--ink)}
.srch-it b{display:block;font-size:.95rem;font-weight:600;line-height:1.35}
.srch-it .srch-sn{display:block;margin-top:2px;font-size:.82rem;line-height:1.5;color:var(--muted)}
/* Một trạng thái "đang chọn" duy nhất cho cả chuột lẫn bàn phím: lớp .on do JS
   đặt, và con trỏ rê tới đâu thì JS dời .on tới đó. Nếu để :hover vẽ riêng thì
   khi vừa dùng phím vừa vô tình chạm chuột sẽ có HAI dòng cùng sáng, mà chỉ một
   dòng trong đó là dòng Enter sẽ mở. */
.srch-it.on{background:var(--bg-soft);text-decoration:none}
.srch-it.on b{color:var(--brand)}
.srch-it mark{background:var(--accent-lite);color:inherit;border-radius:2px;padding:0 1px}
/* Mở kết quả tìm kiếm là mở trang ở đúng chỗ có chữ đó (Text Fragment, xem
   neo() trong site.js). Trình duyệt tự tô — đặt cùng màu với <mark> trong bảng
   để chữ người ta vừa thấy ở bảng và chữ sáng trên trang là một. */
::target-text{background:var(--accent-lite);color:inherit}
.srch-hint{padding:30px 18px;text-align:center;color:var(--muted);font-size:.9rem;line-height:1.6}
.srch-hint b{display:block;color:var(--ink);font-weight:600;margin-bottom:4px}

.srch-foot{display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding:9px 14px;border-top:1px solid var(--line);background:var(--bg-soft);
  font-size:.75rem;color:var(--muted);flex:0 0 auto}
.srch-foot kbd{display:inline-block;min-width:18px;padding:1px 5px;margin:0 1px;
  border:1px solid var(--line);border-bottom-width:2px;border-radius:4px;background:#fff;
  font-family:inherit;font-size:.72rem;line-height:1.5;text-align:center;color:#33414e}
/* Màn cảm ứng không có phím nào để nhắc; chỗ đó dành hết cho số kết quả. */
@media(max-width:620px){
  .srch-keys{display:none}
  .srch-box{max-height:82vh}
  .srch-ov{padding:10px}
}

/* Khối tài khoản — chỉ do JS chèn vào khi đã đăng nhập, khách không thấy gì.
   Nổi tuyệt đối so với <header> (thẻ sticky = đã là positioned), nên bám mép phải
   MÀN HÌNH chứ không phải mép cột nội dung 1180px, và nằm ngoài luồng flex của .nav
   => logo, menu, nút CTA giữ nguyên đúng vị trí cũ, lề trái không suy suyển. */
.acct{position:absolute;right:20px;top:50%;transform:translateY(-50%);
  display:flex;align-items:center;gap:10px}
/* Tên rút còn hai chữ cái (site.js: initials()) nên khối căn giữa chứ không căn
   phải nữa — "DP" ngắn hơn "Admin" bên dưới, căn phải là hai dòng lệch trục. */
.acct-id{display:block;line-height:1.25;text-align:center}
.acct-id:hover{text-decoration:none}
.acct-id b{display:block;font-size:.88rem;font-weight:700;letter-spacing:.03em;color:#25313e}
.acct-id span{display:block;font-size:.71rem;color:var(--muted)}
.acct-id:hover b{color:var(--brand)}

/* Hai nút của khối tài khoản là ô vuông biểu tượng. Nhãn chữ vẫn nằm trong DOM
   (site.js dựng .acct-lbl) — ẩn bằng CSS chứ không bỏ đi, để trình đọc màn hình
   và menu trượt còn dùng. */
.acct .btn{width:34px;height:34px;padding:0;flex:0 0 auto;
  display:inline-flex;align-items:center;justify-content:center}
.acct .btn .acct-lbl{display:none}
.acct-ic{width:17px;height:17px;flex:0 0 auto;fill:none;stroke:currentColor;
  stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}
.acct-m{display:none}

@media(min-width:1025px){
  /* Khối nổi không chiếm chỗ, nên phải tự chừa: kéo mép phải của nội dung .nav vào
     đủ xa để menu không bao giờ chui xuống dưới khối tài khoản. Công thức lấy từ
     mép phải cột nội dung (50vw + 590px) trừ đi mép trái khối (100vw − 20 − bề rộng).
     --acctw do JS đo bề rộng thật rồi đặt vào — tên người dùng dài ngắn khác nhau.
     Chỉ padding-PHẢI, nên lề trái và vị trí logo không đổi. */
  body.logged .nav{padding-right:max(20px, calc(610px + var(--acctw, 230px) + 24px - 50vw))}

  /* .cw-compact do JS bật sau khi ĐO thật (hàm refit() trong site.js), không đoán
     theo mốc bề rộng màn hình: menu chạm khối tài khoản thì bỏ nốt khối tên, chỉ
     còn hai nút (tên và vai trò xem ở trang Cài đặt).
     Trước đây mức này còn phải thu nút về ô vuông và vẽ ký tự bằng ::after — nay
     nút vốn đã là ô vuông biểu tượng ở mọi bề rộng nên không còn việc gì. */
  body.cw-compact .acct .acct-id{display:none}
}
.burger{display:none;margin-left:auto;background:none;border:1.5px solid var(--line);border-radius:9px;
  width:44px;height:44px;cursor:pointer;position:relative;flex:0 0 auto}
.burger span{position:absolute;left:11px;right:11px;height:2px;background:#33414e;border-radius:2px;
  transition:transform .2s, opacity .2s}
.burger span:nth-child(1){top:15px}
.burger span:nth-child(2){top:21px}
.burger span:nth-child(3){top:27px}
.scrim{position:fixed;inset:0;background:rgba(7,30,48,.5);
  -webkit-backdrop-filter:blur(3px);backdrop-filter:blur(3px);
  opacity:0;visibility:hidden;transition:opacity .25s, visibility .25s}

/* ---------- buttons ---------- */
/* viền trong suốt 1.5px: .btn-ghost/.btn-line có viền thật, để .btn không viền
   thì hai biến thể lệch nhau 3px chiều cao và chữ trong nút đặc bị lệch tâm */
.btn{display:inline-flex;align-items:center;background:var(--accent);color:#fff;padding:12px 22px;border-radius:4px;
  font-weight:600;font-size:.88rem;border:1.5px solid transparent;cursor:pointer;font-family:inherit;
  box-shadow:none;transition:background .15s}
.btn:hover{background:var(--accent-dark);text-decoration:none;color:#fff}
/* Mũi tên nằm TRONG nút — dấu hiệu nhận diện của bộ nút trong hệ này. Dựng bằng
   ::after nên không phải sửa chữ trong 56 trang.
   Chỉ áp cho a.btn, KHÔNG cho button.btn: mũi tên nghĩa là "đi tới đâu đó", đặt
   lên nút gửi biểu mẫu là sai nghĩa. Và trên thực tế mọi .btn của site đều là
   <a>, còn mọi .btn của khu quản trị (Đăng nhập, Lưu…) đều là <button> — nên
   luật này cũng chính là hàng rào giữ tông nút của site không tràn sang admin. */
a.btn::after{content:"→";margin-left:12px;font-weight:400}
.btn-sm{padding:9px 16px;font-size:.82rem}
a.btn-sm::after{margin-left:9px}
/* .btn ở trên đặt nền đặc, nên hai biến thể viền phải trả nền về rỗng — nếu
   không chữ xanh nằm trên nền xanh và nút đọc ra một khối đặc không có chữ. */
.btn-ghost{background:transparent;border-color:rgba(44,42,41,.45);color:var(--ink);box-shadow:none}
.btn-ghost:hover{background:rgba(44,42,41,.07);color:var(--ink)}
.btn-line{background:transparent;border-color:var(--brand);color:var(--brand);box-shadow:none}
.btn-line:hover{background:var(--brand);color:#fff;box-shadow:none}
.btn:disabled{opacity:.5;cursor:not-allowed;transform:none}
/* ---------- hàng nhiều nút ----------
   Thay cho lối cũ: hai thẻ <a class="btn"> nằm trong một <p>, cách nhau bằng
   `style="margin-left:8px"` đặt tay trên cái thứ hai. Lối đó hỏng ở khổ hẹp —
   hai nút xuống hai dòng nhưng margin-left vẫn còn, nút dưới thụt vào 8px so với
   nút trên (đo ở 390px: x=20 và x=28), đọc ra như căn lề lỗi.
   flex + gap thì khoảng cách chỉ tồn tại GIỮA hai nút cùng dòng, xuống dòng là
   tự mất. Dưới 620px hai nút kéo hết bề ngang: nút chữ dài ngắn khác nhau
   (205px và 226px) xếp dọc so le còn khó coi hơn cả việc thụt lề. */
.btnrow{display:flex;flex-wrap:wrap;align-items:center;gap:10px}
@media(max-width:620px){
  .btnrow .btn{width:100%;justify-content:center}
}

/* ---------- sửa nội dung trực tiếp trên trang (admin & editor) ---------- */
.cw-toggle{background:var(--brand);white-space:nowrap}
.cw-toggle:hover{background:var(--brand-mid)}
.cw-toggle.on{background:#c8392b}
.cw-toggle.on:hover{background:#a92e22}

/* Viền báo ô sửa được. Cố ý KHÔNG đổi màu nền chữ: các ô này nằm cả trên nền
   trắng lẫn nền xanh đậm (hero, pageband, finalcta) — đổi nền là mất chữ. */
.cw-editing [data-cw]{outline:1px dashed rgba(43,101,176,.55);outline-offset:3px;
  border-radius:3px;cursor:text}
.cw-editing [data-cw]:hover{outline-style:solid;background:rgba(43,101,176,.10)}
.cw-editing [data-cw]:focus{outline:2px solid var(--accent);outline-offset:3px;
  background:rgba(43,101,176,.10)}
.cw-editing [data-cw].cw-saving{opacity:.5}
[data-cw].cw-ok{outline:2px solid #1a9e5f !important;outline-offset:3px}
[data-cw].cw-err{outline:2px solid #c8392b !important;outline-offset:3px}

/* Núm kéo cỡ ảnh — chỉ hiện trong chế độ sửa. Vạch kéo nới cột đã bỏ: cột bài
   viết nay luôn chiếm hết bề rộng lưới cho được, không còn gì để nới. */
.artmain{position:relative}

.artmain figure{position:relative}
.cw-imgdrag{display:none;position:absolute;right:6px;bottom:6px;width:20px;height:20px;
  border-radius:50%;background:var(--accent);border:2.5px solid #fff;
  box-shadow:0 1px 5px rgba(0,0,0,.35);cursor:nwse-resize;z-index:60;touch-action:none}
.cw-imgdrag:hover{background:var(--accent-dark)}
body.cw-editing .cw-imgdrag{display:block}

/* Núm kéo khoảng cách khối — thanh ngang ở mép dưới mỗi <section data-cw-sec>,
   chỉ hiện trong chế độ sửa; kéo dọc đổi khoảng cách tới khối kế tiếp, nháy đúp
   về mặc định. position:relative chỉ đặt khi đang sửa để không đụng bố cục khách. */
body.cw-editing section[data-cw-sec]{position:relative}
.cw-secdrag{display:none;position:absolute;left:50%;bottom:-7px;transform:translateX(-50%);
  min-width:56px;height:14px;padding:0 8px;border-radius:7px;background:var(--accent);
  border:2px solid #fff;box-shadow:0 1px 5px rgba(0,0,0,.35);cursor:ns-resize;z-index:60;
  touch-action:none;font:600 10px/10px var(--font-body);color:#fff;text-align:center;
  white-space:nowrap;user-select:none}
.cw-secdrag:hover,.cw-secdrag.on{background:var(--accent-dark)}
body.cw-editing .cw-secdrag{display:block}

/* Núm chỉnh cỡ TỪNG logo trong dải đối tác. Cùng kiểu với .cw-secdrag (pill có
   số) vì cũng là kéo một con số, chỉ khác là kéo NGANG.
   Đang sửa thì dải phải đứng yên và cuộn tay được: núm gắn vào bản gốc, còn dải
   chạy là các bản nhân đôi trôi ngang — kéo trên nền đang trôi thì không trúng. */
body.cw-editing .logomar .lm-track{animation:none !important}
/* .logomar.is-run{overflow:hidden} nằm SAU trong file và cùng độ đặc hiệu, nên
   phải kèm .is-run ở đây mới thắng — thiếu nó thì logo ngoài khung không kéo tới
   được, và lỗi trông như "núm chỉ hiện cho vài logo đầu". */
body.cw-editing .logomar.is-run{overflow-x:auto}
body.cw-editing .lm-item{position:relative}
/* Bản nhân đôi (aria-hidden) không mang núm; ẩn cả phần đệm chỗ cho chắc. */
body.cw-editing .lm-item[aria-hidden] .cw-logodrag{display:none}
.cw-logodrag{display:none;position:absolute;left:50%;bottom:2px;transform:translateX(-50%);
  min-width:44px;height:14px;padding:0 7px;border-radius:7px;background:var(--accent);
  border:2px solid #fff;box-shadow:0 1px 5px rgba(0,0,0,.35);cursor:ew-resize;z-index:60;
  touch-action:none;font:600 10px/10px var(--font-body);color:#fff;text-align:center;
  white-space:nowrap;user-select:none}
.cw-logodrag:hover,.cw-logodrag.on{background:var(--accent-dark)}
body.cw-editing .cw-logodrag{display:block}
/* Đang sửa thì bỏ xám hóa: người chỉnh cỡ cần thấy logo đúng như khách rê chuột
   vào, và cả dải xám thì khó ước lượng logo nào đang nặng mắt hơn logo nào. */
body.cw-editing .lm-item img{filter:none}

/* Ba nút của khung ảnh (chọn / dán / xóa) — một thanh biểu tượng nhỏ ở góc phải
   trên, luôn hiện trên mọi khung khi đang sửa, kể cả khung đã có ảnh. */
.cw-imgtools{display:none;position:absolute;top:6px;right:6px;z-index:61;gap:1px;padding:2px;
  border-radius:7px;background:rgba(15,44,69,.86);box-shadow:0 1px 5px rgba(0,0,0,.28)}
body.cw-editing .cw-imgtools{display:flex}
.cw-imgtools button{display:grid;place-items:center;width:24px;height:24px;padding:0;border:none;
  border-radius:5px;background:transparent;color:#fff;cursor:pointer}
.cw-imgtools svg{width:14px;height:14px;fill:none;stroke:currentColor;stroke-width:2;
  stroke-linecap:round;stroke-linejoin:round}
.cw-imgtools button:hover{background:rgba(255,255,255,.18)}
/* Khung đang là đích dán: nút dán sáng lên để thấy Ctrl+V sẽ rơi vào đâu */
body.cw-editing .imgbox.cw-pick .cw-imgpaste{background:var(--accent)}
.cw-imgtools .cw-imgdel:hover,.imgbox.cw-del .cw-imgdel{background:#c8392b}
/* Khung đang chờ máy chủ trả lời: mờ đi và không bấm thêm được */
.imgbox.cw-saving{opacity:.5;pointer-events:none}
/* Đang kéo file ảnh lơ lửng trên khung */
body.cw-editing .imgbox.cw-drop{outline:3px dashed var(--accent);outline-offset:-3px}
/* Khung đang chọn — Ctrl+V sẽ rơi vào đây. Vòng sáng phải khác kiểu với lúc kéo
   thả để hai trạng thái không lẫn vào nhau. */
body.cw-editing .imgbox{cursor:pointer}
body.cw-editing .imgbox.cw-pick{outline:3px solid var(--accent);outline-offset:-3px;
  box-shadow:0 0 0 6px rgba(43,101,176,.18)}
/* Đã có .cw-pick làm dấu hiệu rồi, vòng focus mặc định chồng lên chỉ thêm rối */
body.cw-editing .imgbox:focus{outline:none}
.imgbox.cw-ok{outline:3px solid #1a9e5f;outline-offset:-3px}
.imgbox.cw-err{outline:3px solid #c8392b;outline-offset:-3px}
/* Khung đang giữ ảnh CHƯA xuất bản — khách vẫn thấy ảnh cũ ở đây. Nhãn hiện cả
   khi đã tắt Live edit (class do site.js gắn, mà site.js chỉ dựng phần sửa cho
   admin/editor nên khách không bao giờ thấy): tắt chế độ sửa đi xem lại trang
   mà không còn dấu nào thì tưởng đã xuất bản rồi. Nhãn góc chứ không tô viền cả
   khung — khung ảnh nằm giữa bố cục thật, viền lạ làm đọc sai cả trang. */
.imgbox.cw-pend::after,.imgbox.cw-del::after{content:"Ảnh chờ xuất bản";position:absolute;left:0;top:0;z-index:60;
  background:#8a5a06;color:#fff;font-size:.68rem;font-weight:700;letter-spacing:.02em;
  padding:3px 8px;border-radius:0 0 6px 0;pointer-events:none}
.imgbox.cw-del::after{content:"Chờ xóa khi xuất bản";background:#a3302a}
/* Bộ ảnh xoay vòng vừa sửa, chưa xuất bản. Ô vừa có ảnh chính chờ vừa có bộ chờ
   thì nhãn ảnh chính thắng — một nhãn đã đủ báo "trang này còn thứ chưa lên". */
.imgbox.cw-altpend:not(.cw-pend):not(.cw-del)::after{content:"Bộ ảnh chờ xuất bản";position:absolute;left:0;top:0;
  z-index:60;background:#8a5a06;color:#fff;font-size:.68rem;font-weight:700;letter-spacing:.02em;
  padding:3px 8px;border-radius:0 0 6px 0;pointer-events:none}
/* Dải ảnh của bộ xoay vòng: đáy trái khung, chỉ khi đang sửa. Tấm đầu (ảnh chính)
   viền nét đứt để tách khỏi các ảnh thêm; × hiện khi rê chuột lên ảnh thêm. */
.cw-alts{display:none;position:absolute;left:6px;bottom:6px;z-index:61;gap:4px;padding:3px;max-width:calc(100% - 12px);
  overflow-x:auto;border-radius:7px;background:rgba(15,44,69,.86);box-shadow:0 1px 5px rgba(0,0,0,.28)}
body.cw-editing .cw-alts{display:flex}
.cw-altth{position:relative;flex:0 0 auto}
.cw-altth > button{display:block;width:44px;height:33px;padding:0;border:2px solid transparent;border-radius:4px;
  background:#fff;cursor:pointer;overflow:hidden}
.cw-altth > button img{width:100%;height:100%;object-fit:cover;display:block}
.cw-altth.main > button{border-style:dashed;border-color:rgba(255,255,255,.55)}
.cw-altth.on > button{border:2px solid var(--accent-lite)}
/* × nằm TRONG góc ảnh nhỏ chứ không thò ra ngoài: dải có overflow-x:auto (bộ
   nhiều ảnh trên khung hẹp thì cuộn ngang) nên phần thò ra sẽ bị cắt mất. */
.cw-altx{display:none;position:absolute;top:2px;right:2px;width:16px;height:16px;padding:0;border:none;
  border-radius:50%;background:#c8392b;color:#fff;font:700 12px/16px var(--font-body);cursor:pointer;
  box-shadow:0 1px 3px rgba(0,0,0,.35)}
.cw-altth:hover .cw-altx,.cw-altx:focus-visible{display:block}
/* Máy chỉ có cảm ứng không rê chuột được: hiện × thường trực. */
@media(any-hover:none){.cw-altx{display:block}}
/* Ô đã trống sẵn (file không có) thì không còn gì để xóa */
.imgbox.failed:not(.cw-del) .cw-imgdel{display:none}

/* Thanh trạng thái nổi dưới màn hình khi đang ở chế độ sửa */
.cw-bar{position:fixed;left:50%;bottom:-120px;transform:translateX(-50%);z-index:200;
  display:flex;align-items:center;justify-content:center;gap:11px;flex-wrap:wrap;
  background:#0f2c45;color:#dbe7f0;padding:11px 13px 11px 19px;border-radius:12px;
  box-shadow:0 18px 44px rgba(7,30,48,.42);transition:bottom .25s ease;
  max-width:calc(100vw - 28px)}
.cw-bar.show{bottom:18px}
.cw-bar-txt{font-size:.87rem;font-weight:650}
.cw-bar .btn-line{border-color:rgba(255,255,255,.45);color:#fff}
.cw-bar .btn-line:hover{background:rgba(255,255,255,.15);color:#fff}

/* ---------- page hero band ----------
   Từ dải gradient navy tràn viền → một TẤM xám bo góc. Tấm tràn gần hết bề ngang
   (chừa 8px mỗi bên) nhưng CHỮ bên trong vẫn nằm trên đúng lưới .wrap — padding
   ngang phải là 20px y hệt .wrap, nếu không mép trái của chữ trong tấm lệch với
   logo và với tiêu đề section bên dưới.
   Không có margin-top: 8px ở trên làm lộ một vệt nền trang kẹp giữa header và
   tấm, ba sắc xám sát nhau và vệt ở giữa đọc ra như lỗi render. */
.pageband{background:var(--bg-soft);color:var(--ink);margin:0 8px;border-radius:var(--r);
  padding:clamp(30px,4.5vw,52px) 0}
.pageband > .wrap{padding-left:20px;padding-right:20px}
.pageband h1{color:var(--ink);margin-bottom:.3em}
.pageband p{color:var(--ink);max-width:78ch;margin:0;font-size:1rem;line-height:1.6}
/* Breadcrumb: biểu tượng nhà (về trang chủ) › cấp cha › trang đang xem.
   Dấu phân cách do CSS vẽ ở ::before của mọi phần tử TRỪ cái đầu, nên markup mỗi
   trang chỉ còn đúng danh sách các cấp — thêm hay bớt một cấp không phải sửa dấu,
   và không bao giờ thừa một dấu lửng ở hai đầu. Cùng cách vẽ với .chev và .arw:
   hai cạnh viền xoay 45°, không thêm ký tự hay tệp hình nào. */
.crumb{display:flex;align-items:center;flex-wrap:wrap;
  font-size:.92rem;line-height:1.45;margin-bottom:16px}
.crumb > *{display:inline-flex;align-items:center;min-width:0}
.crumb > * + *::before{content:'';width:6px;height:6px;flex:0 0 auto;margin:0 13px;
  border-right:2px solid rgba(44,42,41,.4);border-bottom:2px solid rgba(44,42,41,.4);
  transform:rotate(-45deg)}
.crumb a{color:var(--brand);font-weight:600}
.crumb a:hover{color:var(--brand-mid)}
/* Trang đang xem: đậm và dùng màu chữ thường chứ không phải màu liên kết — mắt
   tách ngay nó khỏi những cấp còn bấm được. */
.crumb b{color:var(--ink);font-weight:700}
.crumb-home svg{width:19px;height:19px;flex:0 0 auto;fill:none;stroke:var(--brand);
  stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round;transition:stroke .15s}
.crumb-home:hover svg{stroke:var(--brand-mid)}
/* Eyebrow trong dải đầu trang ẩn trên MỌI trang (12/10/2026, người dùng: "thừa
   thãi"): nó đứng ngay dưới breadcrumb và phần lớn chỉ lặp lại cấp vừa đọc
   ("Giải pháp" dưới "› Giải pháp"). Ẩn bằng CSS chứ không xóa khỏi src/ và
   layout: bỏ một phần tử anh em trước h1 là đổi đường dẫn băm data-cw của h1 và
   câu dẫn, mọi bản sửa tại chỗ đã lưu cho hai ô đó im lặng mất. */
.pageband .eyebrow{display:none}

/* ---------- pageband hai cột (chữ | hình) ----------
   Biến thể cho trang nào có một tấm hình minh hoạ ngay trên dải đầu trang.
   Breadcrumb ở NGOÀI lưới, vẫn là con trực tiếp của .wrap: nó thuộc cả tấm chứ
   không thuộc cột chữ — đẩy vào trong cột trái thì trên màn hẹp nó bị bó vào
   nửa bề ngang và phần cuộn ngang cụt mất một nửa.
   1.15fr/1fr chứ không 1fr/1fr: cột trái mang H1 và một đoạn văn, chia đều thì
   tiêu đề vỡ dòng sớm còn đoạn văn kéo thành sáu bảy dòng hẹp. */
.pb-grid{display:grid;grid-template-columns:1.15fr 1fr;
  column-gap:clamp(28px,4vw,56px);align-items:center}
/* Bỏ trần 78ch của .pageband p: trong cột hẹp chính cột đã là trần rồi, để
   nguyên thì trên màn rộng đoạn văn dừng trước mép cột và cột phải trông lệch. */
.pb-txt > p{max-width:none}
/* Hình thu còn 70% bề ngang cột và dán vào mép phải: cột phải rộng hơn tấm hình
   cần đến, để hình tràn hết cột thì logo phình to hơn cả H1 bên trái. Đè
   .arbox{width:100%} nên phải đủ đậm hơn về specificity, không phải nhờ thứ tự.
   margin-left:auto chứ không justify-items ở lưới — cột trái vẫn phải căng
   hết chỗ của nó. */
.pb-grid > .imgbox{width:50%;margin-left:auto}
@media(max-width:860px){
  .pb-grid{grid-template-columns:1fr;row-gap:22px}
  /* Một cột thì "mép phải" mất nghĩa: hình trả về full width, canh giữa. */
  .pb-grid > .imgbox{width:100%;margin-left:0}
}

/* ---------- pageband trên điện thoại ----------
   Breadcrumb KHÔNG bẻ dòng: màn hẹp thì chuỗi cấp cha + tên trang dài hơn bề
   ngang, wrap làm nó chiếm hai ba dòng và đẩy H1 xuống quá nửa màn hình. Cho nó
   cuộn ngang trong chính nó (một dòng, tràn thì kéo tay) — không dòng nào của
   trang bị đẩy, và cấp cuối vẫn đọc được bằng cách vuốt. overflow-x nằm ở chính
   .crumb chứ không ở .wrap, nếu không cả tấm trang cuộn ngang theo.
   Ẩn thanh cuộn: dải xám dưới breadcrumb đọc ra như một vạch kẻ lạ.
   Câu mô tả dưới H1 ẩn hẳn: nội dung ấy lặp lại ý của tiêu đề và trên màn hẹp
   nó đẩy phần thân bài xuống dưới màn hình đầu tiên. Vẫn còn trong <meta
   description> nên máy tìm kiếm không mất gì. */
@media(max-width:620px){
  .crumb{flex-wrap:nowrap;overflow-x:auto;scrollbar-width:none;
    -webkit-overflow-scrolling:touch}
  .crumb::-webkit-scrollbar{display:none}
  /* flex:0 0 auto để các cấp không bị co lại (mặc định .crumb > * có
     min-width:0 cho phép co, chữ sẽ chồng lên nhau khi không còn chỗ) */
  .crumb > *{white-space:nowrap;flex:0 0 auto}
  .crumb > * + *::before{margin:0 9px}
  /* .pb-txt > p đi kèm: ở biến thể hai cột đoạn văn không còn là con trực tiếp
     của .wrap, chỉ liệt kê selector cũ là nó hiện lại trên điện thoại. */
  .pageband > .wrap > p,.pageband .pb-txt > p{display:none}
}

/* ---------- hero (homepage) ----------
   Khác .pageband: tấm hero tràn kín bề ngang, không chừa 8px và không bo góc.
   Nhờ vậy mép trái của chữ trong .hero-inner (padding 20px, giống .wrap) trùng
   đúng lưới trang ở mọi bề ngang, kể cả khi màn hẹp hơn --max. */
.hero{background:var(--bg-soft);color:var(--ink);margin:0;border-radius:0}
.hero-inner{max-width:var(--max);margin:0 auto;padding:clamp(40px,5.5vw,64px) 20px;display:grid;
  grid-template-columns:1.06fr 1fr;column-gap:48px;row-gap:0;align-items:center}
/* Ba ô theo thứ tự DOM: đầu (eyebrow + h1) — hình — thân (câu dẫn + nút + ghi
   chú). Ở đây hai ô chữ xếp chồng trong cột trái, hình chiếm trọn cột phải.
   Hình cao hơn khối chữ, phần dôi ra được lưới chia ĐỀU cho hai hàng; dán ô đầu
   vào mép dưới hàng 1 và ô thân vào mép trên hàng 2 thì hai khối chữ vẫn liền
   nhau, đồng thời cả cụm nằm giữa theo chiều dọc so với hình. */
.hero-head{grid-area:1/1;align-self:end}
.hero-body{grid-area:2/1;align-self:start}
.hero .herovis{grid-area:1/2/3/3;align-self:center}
.hero h1{color:var(--ink);margin-bottom:.36em}
.hero .lead{color:rgba(44,42,41,.7);font-size:1.02rem;max-width:52ch}
.hero .cta-row{display:flex;gap:12px;flex-wrap:wrap;margin-top:30px}
.hero .sub-note{font-size:.85rem;color:var(--muted);margin-top:18px}
.hero .eyebrow{color:var(--brand)}
/* Bốn ảnh hero là WebP NỀN TRONG SUỐT, mép trường dòng tự mờ dần: thiết bị đặt
   thẳng lên nền --bg-soft của dải hero. Tô --fill ở đây là hiện lại một tấm xám
   đậm hơn sau hình — đúng cái khung chữ nhật mà ảnh trong suốt sinh ra để bỏ. */
.hero-img{border-radius:var(--r);overflow:hidden;box-shadow:none;background:transparent}
.hero-img img{width:100%;height:100%;object-fit:cover}

/* ---------- hero: khung ảnh xoay vòng ----------
   Chỉ HÌNH xoay, chữ trong hero đứng yên. Các tấm chồng lên nhau và mờ chồng
   chéo; dùng visibility kèm opacity để tấm ẩn không nhận được tiêu điểm bàn phím
   (opacity:0 một mình vẫn tab vào được). */
.hs-track{position:relative;aspect-ratio:4/3}
.hs-slide{position:absolute;inset:0;opacity:0;visibility:hidden;
  transition:opacity .55s ease, visibility .55s}
.hs-slide.on{opacity:1;visibility:visible}
/* Trong hero, ảnh trong suốt nằm thẳng trên nền dải hero. Để .imgbox tự tô nền
   --fill của nó là hiện lại khung xám sau hình (xem .hero-img ở trên). */
.hs-slide .imgbox{position:absolute;inset:0;background:transparent}
/* Video động đè lên ảnh tĩnh cùng tấm; chỉ hiện khi đã thật sự chạy (.on do
   site.js gắn ở sự kiện "playing"), nên lúc đang tải vẫn thấy ảnh tĩnh chứ không
   thấy khung đen. Đang Live edit thì ẩn hẳn: các nút đặt/xóa ảnh làm việc trên
   ẢNH TĨNH bên dưới, để video che là sửa mà không thấy mình sửa gì. */
.hs-vid{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;opacity:0;
  transition:opacity .4s ease;pointer-events:none}
.hs-vid.on{opacity:1}
body.cw-editing .hs-vid{display:none}
/* Slide đã ẩn (chỉ người có quyền sửa còn nhận nó, xem applyHide ở lib/render.js):
   trong Live edit hiện mờ kèm nhãn để còn bấm "Hiện slide" lại. */
body.cw-editing .hs-slide[data-cw-hidden] .imgbox img{opacity:.35}
body.cw-editing .hs-slide[data-cw-hidden]::after{content:"Slide đang ẩn — khách không thấy";position:absolute;
  left:50%;top:50%;transform:translate(-50%,-50%);z-index:62;background:#a3302a;color:#fff;font-size:.78rem;
  font-weight:700;padding:5px 12px;border-radius:6px;pointer-events:none;white-space:nowrap}
.hs-dot[hidden]{display:none}
/* Video của slide đang chờ thay / chờ bỏ: nhãn riêng, nằm dưới nhãn ảnh (::after)
   để ô vừa đổi ảnh vừa đổi video vẫn đọc được cả hai. */
.imgbox.cw-vpend::before,.imgbox.cw-vdel::before{content:"Video chờ xuất bản";position:absolute;left:0;top:22px;
  z-index:60;background:#8a5a06;color:#fff;font-size:.68rem;font-weight:700;letter-spacing:.02em;
  padding:3px 8px;border-radius:0 6px 6px 0;pointer-events:none}
.imgbox.cw-vdel::before{content:"Chờ bỏ video";background:#a3302a}
.hs-bar{display:flex;align-items:center;gap:16px;padding:12px 2px 0}
/* Các chú thích chồng lên nhau ở cùng một chỗ: nếu để chúng đẩy nhau theo chiều
   dọc thì mỗi lần đổi tấm cả khối dưới hero lại nhảy một nấc. */
.hs-caps{position:relative;flex:1;min-width:0;min-height:2.6em}
.hs-cap{position:absolute;inset:0;font-size:.84rem;color:var(--muted);line-height:1.4;
  opacity:0;transition:opacity .45s ease}
.hs-cap.on{opacity:1}
/* gap:0 vì mỗi chấm đã tự mang 24px ô chạm; nút tạm dừng tự tách bằng margin */
.hs-ctl{display:flex;align-items:center;gap:0;flex:0 0 auto}
/* Chấm vẽ ra chỉ 9px và cách nhau 16px tâm-đến-tâm. WCAG 2.5.8 đòi ô chạm 24px;
   ngoại lệ "đủ thưa" cũng không cứu được vì vòng 24px của hai chấm cạnh nhau đè
   lên nhau. Nút phình ra đủ 24px NHƯNG trong suốt, hình tròn vẽ bằng ::before —
   ô chạm to gấp 2,7 lần diện tích cũ mà nhìn không khác gì. */
.hs-dot{width:24px;height:24px;padding:0;border:0;cursor:pointer;background:none;
  position:relative;flex:0 0 auto}
.hs-dot::before{content:"";position:absolute;left:50%;top:50%;width:9px;height:9px;
  margin:-4.5px 0 0 -4.5px;border-radius:50%;background:rgba(44,42,41,.26);
  transition:background .2s, transform .2s}
.hs-dot:hover::before{background:rgba(44,42,41,.45)}
.hs-dot[aria-current="true"]::before{background:var(--brand);transform:scale(1.25)}
.hs-pause{width:24px;height:24px;margin-left:5px;padding:0;border:0;border-radius:50%;cursor:pointer;
  background:rgba(44,42,41,.10);color:var(--ink);display:inline-flex;align-items:center;
  justify-content:center;font-size:.62rem;line-height:1}
.hs-pause:hover{background:rgba(44,42,41,.18)}
/* Không có JS thì bốn tấm chồng lên nhau và chỉ tấm đầu hiện — trang vẫn đúng,
   chỉ mất phần xoay. Thanh điều khiển do JS dựng nên cũng không có nút chết. */
@media(prefers-reduced-motion:reduce){
  .hs-slide,.hs-cap{transition:none}
}

/* ---------- stats ---------- */
/* Dải số liệu cũng là một tấm, không phải một dải trắng có viền dưới. */
.stats{background:transparent;border-bottom:0}
.stats .wrap{display:grid;grid-template-columns:repeat(4,1fr);gap:20px;
  background:var(--bg-soft);border-radius:var(--r);margin-top:30px;
  padding:34px 24px;text-align:center}
.stat{position:relative}
.stat + .stat::before{content:"";position:absolute;left:-10px;top:8px;bottom:8px;width:1px;background:rgba(44,42,41,.16)}
.stat .n{font-size:1.6rem;font-weight:600;color:var(--brand);line-height:1.05;letter-spacing:-.03em}
/* text-wrap:balance chia đều chữ cho các dòng: chú thích 3 dòng không còn bỏ
   lại một từ lẻ ở dòng cuối ("… một mô | hình"), thứ lộ ra rõ nhất khi bốn ô
   đứng cạnh nhau và mỗi ô lẻ một kiểu. Trình duyệt cũ không hiểu thì xuống dòng
   như cũ, không hỏng gì. */
.stat .l{font-size:.88rem;color:rgba(44,42,41,.7);margin-top:4px;text-wrap:balance}

/* ---------- công bố khoa học ----------
   Danh mục công bố không phải một cái bảng: bảng bắt người đọc quét ngang qua ba
   cột để ghép lại một mục, mà cột "Công bố" thì dài gấp năm cột "Năm". Ở đây mỗi
   công bố là MỘT MỤC — năm nằm cột trái hẹp, tên bài là dòng nặng nhất, tạp chí
   và chỉ số ảnh hưởng thành dòng phụ ngay dưới. Đúng lối một danh mục công bố
   của nhóm nghiên cứu, và xuống màn hẹp thì tự xếp dọc chứ không phải kéo ngang.
   Danh sách sửa ở Cài đặt → Công bố (data/pubs.json, lib/pubrender.js). */
.pubstat{display:grid;grid-template-columns:repeat(4,1fr);gap:20px;
  background:var(--bg-soft);border-radius:var(--r);padding:26px 24px;
  text-align:center;margin-bottom:34px}
.pubstat-i{position:relative}
.pubstat-i + .pubstat-i::before{content:"";position:absolute;left:-10px;top:6px;bottom:6px;
  width:1px;background:rgba(44,42,41,.16)}
.pubstat-i b{display:block;font-size:1.9rem;font-weight:600;color:var(--brand);
  line-height:1.05;letter-spacing:-.03em}
.pubstat-i span{display:block;font-size:.84rem;color:rgba(44,42,41,.7);margin-top:4px}

/* Danh mục chia tab theo năm (.rtabs/.rpane dùng chung với tab Tài nguyên):
   gạch chân của thanh tab CHÍNH LÀ đường kẻ trên của danh sách, nên bỏ
   margin-bottom mặc định — thêm 26px trống giữa hai thứ là tách rời chúng ra
   thành hai khối, mà đây là một. Danh mục chỉ có một năm thì không có thanh tab,
   lúc ấy mục đầu tiên tự mang đường kẻ trên. */
.pubtabs{margin-bottom:0}
.publist > .pub:first-child{border-top:1px solid var(--line)}
/* Ba cột: năm · nội dung · trích dẫn. Cột trích dẫn rộng cố định để mọi con số
   thẳng một mép, và nằm bên phải vì đó là số liệu đi kèm chứ không phải thứ đọc
   trước. */
.pub{display:grid;grid-template-columns:76px minmax(0,1fr) 86px;gap:0 22px;
  padding:18px 0;border-bottom:1px solid var(--line)}
/* Số năm dùng chữ số đều bề ngang (tabular-nums) để cột năm thẳng hàng tăm tắp. */
.pub-y{font-size:.95rem;font-weight:700;color:var(--muted);
  font-variant-numeric:tabular-nums;padding-top:2px}
.pub-b{min-width:0}
.pub-t{font-size:1.02rem;line-height:1.45;font-weight:600;color:var(--ink);margin:0 0 5px}
.pub-t a{color:inherit;text-decoration:none;border-bottom:1px solid rgba(43,101,176,.35)}
.pub-t a:hover{color:var(--brand);border-bottom-color:var(--brand)}
/* Danh sách tác giả: cỡ nhỏ hơn tên bài một nấc, xám — có mặt để tra cứu chứ
   không phải để đọc trước. Tên viết tắt nên không cắt dòng giữa chừng được. */
.pub-a{font-size:.84rem;color:var(--muted);line-height:1.5;margin-bottom:4px}
.pub-m{display:flex;flex-wrap:wrap;align-items:center;gap:8px;font-size:.88rem;color:var(--muted)}
/* Số trích dẫn: con số là thứ đọc được từ xa, chữ "trích dẫn" chỉ để không ai
   phải đoán con số ấy là gì. Ô để TRỐNG khi chưa có số (xem pubrender.pubHtml). */
.pub-c{text-align:right;font-variant-numeric:tabular-nums;padding-top:1px}
.pub-c b{display:block;font-size:1.12rem;font-weight:600;color:var(--brand);line-height:1.15}
.pub-c span{display:block;font-size:.72rem;color:var(--muted);margin-top:1px}
/* Tên tạp chí in nghiêng — quy ước của giới học thuật, và cũng là cách tách nó
   khỏi tên bài mà không cần thêm màu thứ hai. */
.pub-j{font-style:italic}
.pub-if{font-style:normal;font-size:.74rem;font-weight:700;color:var(--brand);
  border:1px solid rgba(43,101,176,.3);border-radius:4px;padding:1px 6px;
  letter-spacing:.02em;white-space:nowrap}
@media(max-width:620px){
  .pubstat{grid-template-columns:repeat(2,1fr);gap:18px 12px;padding:22px 16px}
  .pubstat-i:nth-child(odd)::before{display:none}
  .pubstat-i b{font-size:1.5rem}
  /* Màn hẹp: năm và số trích dẫn về CÙNG MỘT DÒNG trên đầu mục — hai con số
     đứng hai đầu một dòng, tên bài chiếm trọn bề ngang bên dưới. Giữ ba cột như
     desktop thì cột trích dẫn ăn mất 86px của cột chữ vốn đã chỉ còn 350px. */
  /* Đặt ô TƯỜNG MINH: thứ tự trong DOM là năm → nội dung → trích dẫn, để lưới
     tự xếp thì khối nội dung (chiếm cả hàng) đẩy ô trích dẫn xuống hàng ba. */
  .pub{grid-template-columns:1fr auto;gap:3px 12px;padding:15px 0}
  .pub-y{grid-row:1;grid-column:1;font-size:.78rem;padding-top:0}
  .pub-c{grid-row:1;grid-column:2;justify-self:end}
  .pub-b{grid-row:2;grid-column:1 / -1}
  .pub-t{font-size:.98rem}
  .pub-c{display:flex;align-items:baseline;gap:5px;padding-top:0}
  .pub-c b{font-size:.86rem}
  .pub-c span{font-size:.72rem;margin-top:0}
}

/* Bể chọn ở trang chủ: HTML nhúng sẵn cả bể (tám công bố mới nhất ở .pubpick,
   bảy dự án ở .projpick), JS bốc ngẫu nhiên ba mục (một mục trên màn hẹp).
   Không có JS thì các luật dưới đây để lộ đúng ba mục đầu — trang vẫn đủ nghĩa,
   chỉ là không đổi mỗi lần tải.
   Hai lớp đi chung luật nhưng KHÔNG gộp thành một tên: lib/pubrender.js tìm đúng
   chuỗi ".pubpick" để dựng lại khối công bố lúc phục vụ. */
.pubpick > *:nth-child(n+4),.projpick > *:nth-child(n+4){display:none}
.pubpick.js > *,.projpick.js > *{display:none}
.pubpick.js > .on,.projpick.js > .on{display:flex}
.pubpick h3{font-size:.97rem}
@media(max-width:620px){
  .pubpick > *:nth-child(n+2),.projpick > *:nth-child(n+2){display:none}
}

/* ---------- grids & cards ---------- */
.g2{display:grid;grid-template-columns:repeat(2,1fr);gap:26px}
.g2>*,.g3>*,.g4>*,.steps>*{min-width:0}
/* .g2.diagram: hàng "sơ đồ + chú giải". Cột hình hẹp hơn nửa hàng vì sơ đồ ở
   đây là hình VUÔNG — để nó rộng 1fr thì khối cao hơn 500px và át cả cột chữ
   bên cạnh. 380px là bề ngang đọc rõ mọi nhãn quanh vòng tròn. */
.g2.diagram{grid-template-columns:minmax(0,380px) 1fr;gap:44px;align-items:center}
/* Hàng "cột chữ + ảnh" của trang ngành và năng lực. Ảnh cao đúng bằng cột chữ
   thay vì thả nổi giữa hàng: mép trên ảnh thẳng với eyebrow, mép dưới thẳng với
   dòng link — hai cột khóa vào cùng một khung ngang. Ảnh phải absolute, nếu không
   khung không lấy được chiều cao từ hàng (cùng lý do như .arbox bên dưới).
   Dưới 620px lưới xếp dọc, không còn hàng để bám nên .h260 trả lại chiều cao cố định. */
@media(min-width:621px){
  .g2.rowmedia{align-items:stretch}
  .g2.rowmedia>.imgbox{height:auto;min-height:230px}
  .g2.rowmedia>.imgbox>img{position:absolute;inset:0}
}
.g3{display:grid;grid-template-columns:repeat(3,1fr);gap:26px}
.g4{display:grid;grid-template-columns:repeat(4,1fr);gap:22px}
/* Thẻ: nền xám phẳng, KHÔNG viền, KHÔNG bóng — phân tách hoàn toàn bằng chênh
   lệch nền so với nền trang.
   Thứ tự ảnh/chữ giữ nguyên (ảnh trên): đảo bằng column-reverse trên .card nói
   chung sẽ lật cả thẻ case study, tin tức và bài viết — nơi ảnh đại diện phải
   đọc trước tiêu đề. Kiểu "tiêu đề trên, ảnh dưới" chỉ áp cho lưới thẻ ngành,
   và làm bằng lưới ở cuối khối này chứ không bằng flex. */
.card{background:var(--bg-soft);border:0;border-radius:var(--r);overflow:hidden;
  display:flex;flex-direction:column}
.card:hover{background:var(--panel-hi)}
.card .imgbox{flex:0 0 auto;background:var(--fill)}
.card .body{padding:20px 22px 18px;flex:1;display:flex;flex-direction:column}
.card h3{margin-bottom:.45em;color:var(--brand);font-size:1.16rem}
/* Thẻ case study (meta · tiêu đề · ô kết quả · link) đứng cạnh nhau trong lưới
   (.projpick trang chủ, Bằng chứng ở Giải pháp, trang Kết quả): tiêu đề giữ chỗ
   2 dòng (2 × line-height 1.22) và ô kết quả nở ra lấp phần dư, nên các thẻ có ô
   kết quả cùng mép trên/mép dưới và link cùng một hàng dù chữ dài ngắn khác nhau
   (người dùng yêu cầu 04/09/2026). */
.card .body h3:has(+ .result){min-height:2.44em}
.card .body .result{flex:1 0 auto}
/* Dòng meta ("Hiệu quả năng lượng · Nhà máy gạch ceramic · Việt Nam · 2022–2024")
   có khi xuống 2 dòng, đẩy cả tiêu đề lẫn ô kết quả xuống 1 dòng so với thẻ bên
   cạnh — giữ chỗ 2 dòng luôn (lh = line-height của chính nó). */
.card .body .meta:has(+ h3 + .result){min-height:2lh}
/* Thẻ dự án ở TRANG CHỦ bỏ ô kết quả (05/09/2026: quá chi tiết cho trang chủ),
   nên hai luật giữ chỗ ở trên không còn bám vào đâu — nhắc lại cho .projpick để
   ba thẻ vẫn cùng mép trên tiêu đề và cùng hàng link. */
.projpick .card .body .meta{min-height:2lh}
.projpick .card .body h3{min-height:2.44em}
/* chữ trong thẻ nặng hơn thân bài một nấc và gần đen — 500 chỉ dùng được nhờ
   Noto Sans, xem chú thích --font-body ở đầu file */
.card p{color:var(--ink);font-size:.94rem;font-weight:500;margin-bottom:.85em}
.card ul{margin:0 0 14px;padding-left:18px;color:var(--ink);font-size:.94rem;font-weight:500}
.card ul li{margin-bottom:4px}
.card .more{font-size:.86rem;font-weight:600;margin-top:auto;color:var(--brand)}
/* Thẻ ngành ở trang chủ: tiêu đề → ẢNH → bullet → link.
   Markup có h3 nằm TRONG .body còn .imgbox là anh em NGOÀI .body, flex không xen
   kẽ được hai cấp đó. Bật lưới trên .card rồi cho .body `display:contents`: .body
   biến mất khỏi cây bố cục, ba đứa con của nó thành ô lưới trực tiếp, ngang cấp
   với .imgbox. Không phải sửa một chữ HTML nào.
   Đổi lại padding của .body mất theo nên phải trả về cho từng đứa con — và đó
   đúng ý: ảnh cần tràn sát mép thẻ, chữ thì không. */
#linh-vuc .card{display:grid;grid-template-rows:auto auto 1fr;position:relative}
#linh-vuc .card .body{display:contents;padding:0}
/* min-height = 2 dòng: "HVAC & Thiết kế công trình" xuống dòng còn ba tiêu đề kia
   một dòng. Không ghim thì ảnh thẻ thứ tư tụt thấp hơn ba thẻ còn lại. */
/* Dải tiêu đề 22px trên / 22px dưới — cùng số với thẻ Năng lực (#nang-luc).
   min-height giữ chỗ 2 dòng để ảnh bốn thẻ thẳng hàng khi một tiêu đề xuống
   dòng; tiêu đề một dòng thì CĂN GIỮA trong dải đó, không dồn lên trên. */
#linh-vuc .card h3{grid-row:1;margin:0;padding:22px 22px;min-height:calc(2.44em + 44px);
  display:flex;align-items:center}
#linh-vuc .card .imgbox{grid-row:2;height:200px}
#linh-vuc .card ul{grid-row:3;margin:0;padding:16px 22px 22px 40px} /* 22 lề + 18 thụt bullet */
/* Không còn dòng "Chi tiết →": link phủ kín thẻ (cùng cách với #nang-luc .path
   .more — font-size:0 giấu chữ, tên link vẫn còn cho trình đọc màn hình), chạm
   đâu trên thẻ cũng sang trang ngành. Rê chuột: tiêu đề đậm màu, không gạch chân. */
#linh-vuc .card .more{position:absolute;inset:0;margin:0;padding:0;font-size:0}
#linh-vuc .card:hover h3{color:var(--brand-mid)}
body.cw-editing #linh-vuc .card{grid-template-rows:auto auto 1fr auto}
body.cw-editing #linh-vuc .card .more{position:static;font-size:.86rem;padding:0 22px 20px}
.meta{font-size:.76rem;color:var(--muted);margin-bottom:.5em}
.result{background:rgba(43,101,176,.09);border-left:3px solid var(--accent);padding:11px 15px;font-size:.89rem;
  color:#2b4a70;margin:0 0 14px;font-weight:500;border-radius:0 4px 4px 0}
/* nhãn nhỏ: bỏ vàng, về trung tính — hệ chỉ có một màu và một thang xám */
.chip{background:transparent;border:1px solid rgba(44,42,41,.28);color:var(--muted);font-size:.7rem;
  padding:1px 7px;border-radius:3px;font-weight:600;display:inline-block;vertical-align:1px;line-height:1.5}
/* Thẻ của trang đang ẩn — chỉ người đăng nhập sửa mới thấy (lib/hidden.js mark) */
.chip.chip-an{background:#3d4757;border-color:#3d4757;color:#fff}

/* ---------- rê chuột: thẻ dịch lên ----------
   MỘT luật cho tất cả các loại thẻ trong lưới, không phải mỗi trang một kiểu:
     .card    thẻ ngành / dịch vụ / case study      .pcard  thẻ bài viết, tin, sự kiện
     .path    ô hướng đi ở trang giải pháp          .step   ô bước quy trình
     .logostrip .cl  ô tên khách hàng, đối tác
   Dịch bằng transform chứ không phải margin/top: transform không tính vào bố cục
   nên thẻ dịch lên KHÔNG đẩy các thẻ bên cạnh hay làm trang giật một dòng.
   .3s ease-out: creaform để .36s ease-in-out cho cùng hiệu ứng này. Nhanh hơn nữa
   (bản .2s trước đây) thì cú dịch xong trước khi mắt kịp bám vào thẻ.
   Không đặt will-change: một trang có tới hơn hai chục thẻ, ghim sẵn ngần ấy lớp
   hợp thành trên GPU tốn hơn phần được. */
.card,.pcard,.path,.step,.logostrip .cl{
  transition:transform .3s ease-out, box-shadow .3s ease-out, background .18s}
/* Chỉ từ 621px trở lên — đúng khổ mà lưới thẻ còn là LƯỚI. Dưới ngưỡng đó thẻ
   xếp thành một cột (và trong .mstack thì thành các dòng của một khối liền):
   một dòng nhấc lên đổ bóng giữa danh sách là hỏng hình, mà ngón tay cũng chẳng
   rê được để thấy. Cắt ở đây thì bóng nghỉ của .step cũng không bị chớp tắt —
   cách khác là ghi đè `box-shadow:none` lúc hover, làm vậy thì hover một cái là
   bóng có sẵn của nó biến mất.
   Đây là câu hỏi BỀ RỘNG, không phải câu hỏi con trỏ: xem chú thích
   @media(any-hover:none) ngay dưới về việc vì sao không dùng hover:hover. */
@media(min-width:621px){
  .card:hover,.path:hover,.step:hover,.logostrip .cl:hover{
    transform:translateY(var(--rise));box-shadow:var(--lift-hover)}
  /* Ngoại lệ .pcard (bài viết, tin, sự kiện): CHỈ sáng lên, không nhấc lên.
     Danh sách tin là một dòng chảy đọc lướt từ trên xuống — mỗi lần rê qua mà
     thẻ bật khỏi hàng thì mắt phải bám lại vị trí, trong khi thẻ ngành/dịch vụ
     là các ô rời để CHỌN nên nhấc lên mới đúng. Nền sáng thêm một nấc
     (.pcard:hover) cộng bóng đổ đã đủ chỉ rõ con trỏ đang ở đâu. */
  .pcard:hover{box-shadow:var(--lift-hover)}
}
/* Luật trên KHÔNG bọc trong @media(hover:hover) — bọc như vậy là mất hiệu ứng ở
   đúng những máy vẫn có chuột: máy có màn cảm ứng hoặc bảng vẽ cắm kèm bị Chrome
   khai con trỏ CHÍNH là loại thô, `hover:hover` thành sai và cả khối bị bỏ qua.
   Đảo lại: mặc định luôn bật, chỉ tắt khi trình duyệt khẳng định KHÔNG có thiết bị
   nào rê được (`any-hover:none` — điện thoại, máy tính bảng thuần cảm ứng). Ở đó
   chạm vào thẻ cũng bắn ra :hover và trạng thái đó dính lại tới lần chạm sau.
   Vẫn cần dù đã cắt theo bề rộng: máy tính bảng nằm ngang rộng hơn 620px. */
@media(any-hover:none){
  .card:hover,.pcard:hover,.path:hover,.step:hover,.logostrip .cl:hover{
    transform:none;box-shadow:none}
}
/* Khổ hẹp không còn gì để chuyển động: bỏ luôn phần transform/box-shadow khỏi
   danh sách transition, giữ mỗi nền (dùng cho .mrow-btn:active khi chạm). */
@media(max-width:620px){
  .card,.pcard,.path,.step,.logostrip .cl{transition:background .18s}
}
/* Người tắt hiệu ứng chuyển động vẫn cần biết chuột đang ở thẻ nào: nền sáng thêm
   một nấc và bóng đổ đều không phải chuyển động nên giữ nguyên, chỉ bỏ phần dịch. */
@media(prefers-reduced-motion:reduce){
  .card,.pcard,.path,.step,.logostrip .cl{transition:box-shadow .3s ease-out, background .18s}
  .card:hover,.pcard:hover,.path:hover,.step:hover,.logostrip .cl:hover{transform:none}
}

/* ---------- images ---------- */
/* Nền chờ của khung ảnh. Trước đây là #f0f4f7 — một màu xám ám xanh viết cứng,
   sót lại từ bảng màu cũ: nó SÁNG HƠN cả dải nền ngoài cùng (#EDEDED) nên khung
   ảnh nổi lên như một mảng vá, lại ám xanh 7 đơn vị giữa toàn xám trung tính.
   Dùng token --fill để nó nằm cùng hệ với mọi mảng nền khác. */
.imgbox{position:relative;background:var(--fill)}
.imgbox img{width:100%;height:100%;object-fit:cover}
.imgbox.contain img{object-fit:contain;background:#fff}
.imgbox .ph{display:none}
.imgbox.failed img{display:none}
.imgbox.failed .ph{display:flex}
.ph{background:repeating-linear-gradient(45deg,#eef2f5,#eef2f5 10px,#e7ecf1 10px,#e7ecf1 20px);
  border:1px dashed #b9c5d0;display:flex;align-items:center;justify-content:center;
  text-align:center;color:#6b7a89;font-size:.74rem;padding:12px;line-height:1.45;width:100%;height:100%}
.imgbox .ph{position:absolute;inset:0;width:auto;height:auto}
.arbox{width:100%}
.ph b{display:block;font-weight:600;color:#4a5a68;margin-bottom:2px}
.h180{height:180px}.h220{height:220px}.h260{height:260px}.h320{height:320px}
/* Khung ảnh theo TỶ LỆ thay vì chiều cao cứng: ảnh cao theo bề ngang cột nên
   lưới 3 cột và lưới 1 cột trên điện thoại đều giữ đúng khuôn hình. Ảnh gốc của
   kho thiết bị phần lớn ~1.4:1, nên 4:3 chỉ xén rất nhẹ hai mép (object-fit:cover),
   khác hẳn khung 2:1 cũ vốn cắt mất phần trên–dưới của trường dòng chảy. */
.r43{aspect-ratio:4/3}
figure{margin:0}
figcaption{font-size:.78rem;color:var(--muted);padding:8px 2px 0;line-height:1.5}
.frame{border:0;border-radius:var(--r);overflow:hidden;background:var(--bg-soft)}
/* Bài blog & tin tức: ảnh minh họa đứng trần giữa dòng chữ, không đóng khung —
   khung viền hợp với thẻ trong lưới, chèn vào bài đọc thì rối mắt */
.postsec .frame{border:none;border-radius:0;background:transparent}
/* …và tấm nền của Ô ẢNH bên trong cũng vậy. Luật trên chỉ gỡ nền của .frame,
   nên ảnh nào có nền trong suốt vẫn lộ ra một mảng var(--fill) — còn ảnh .contain
   thì lộ tấm #fff mà luật ảnh chung đắp dưới <img>. Trong bài đọc KHÔNG có ô ảnh
   nào cần nền chờ: ảnh đặc thì tự che kín, ảnh trong suốt thì phải thấy nền trang.
   Nhờ luật này mọi ảnh trong bài blog/tin tức tự đúng, không phải gắn .plain từng cái. */
.postsec .imgbox,.postsec .imgbox.contain img{background:transparent}
/* Ảnh trong bài luôn nằm giữa cột — kể cả ảnh đã thu nhỏ bằng núm kéo, và kể cả
   cột tin tức vốn không có luật căn giữa nào của riêng nó. */
.postsec figure{margin-inline:auto}

/* ---------- misc blocks ---------- */
.path{border:0;border-radius:var(--r);padding:28px 26px;background:var(--bg-soft);display:flex;flex-direction:column}
.path:hover{background:var(--panel-hi)}
/* Không đánh số ở .path: ba trụ là thực đơn để khách tự chọn ô khớp với vấn đề
   của mình, không phải trình tự phải đọc từ 1. Số chỉ dùng ở .steps — nơi thứ tự
   là thông tin thật (xem khối .steps bên dưới). */
.path h3{font-size:1.14rem;margin-bottom:.5em;color:var(--brand)}
.path p{color:var(--ink);font-size:.94rem;font-weight:500;margin-bottom:1.3em}
/* Ảnh thay cho đoạn mô tả (khối Năng lực ở trang chủ), trải hết bề ngang thẻ.
   -26px đúng bằng padding ngang của .path ở trên — sửa padding thì phải sửa cả
   số này. Chỉ có một chỗ khai báo padding cho .path, không có bản ghi đè theo bề
   rộng màn, nên một cặp số là đủ cho mọi khổ.
   KHÔNG cần overflow:hidden trên .path: --r chỉ 8px và ảnh nằm dưới h3 nên mép
   ảnh chạm phần THẲNG của cạnh thẻ, không chạm khúc bo góc.
   Cũng không bo góc ảnh — bo thì lại thành khung nổi giữa thẻ, đúng thứ vừa bỏ.
   width:auto ghi đè `width:100%` của .arbox — phải có, nếu không thì 100% vẫn đo
   theo bề rộng TRONG padding, lề âm chỉ đẩy ảnh lệch sang trái chứ không nong ra:
   mép trái tràn đúng, mép phải hụt lại 26px. Để auto thì ảnh là ô co giãn theo
   thẻ và lề âm mới cộng vào bề rộng.
   flex:0 0 auto để aspect-ratio không bị lưới kéo giãn khi thẻ bên cạnh cao hơn. */
.path .imgbox{flex:0 0 auto;width:auto;margin:2px -26px 20px}
.path .more{margin-top:auto;font-weight:600;font-size:.86rem}
/* Thẻ Năng lực ở trang chủ, MỌI bề rộng (09/2026): không còn dòng "Chi tiết →".
   Link giãn ra phủ kín thẻ — chạm/bấm đâu trên thẻ cũng sang trang trụ;
   font-size:0 giấu chữ chứ không display:none nên link vẫn có tên cho trình đọc
   màn hình. Không bọc thẻ trong <a>: đổi cấu trúc là bản sửa tại chỗ của tiêu đề
   thành mồ côi (lib/editable.js). Ảnh chạm mép dưới nên thẻ cần overflow:hidden
   để góc vuông của ảnh không thò khỏi bo góc. Khổ điện thoại bên dưới đã làm
   đúng cách này từ trước, giờ desktop theo; tín hiệu "bấm được" là thẻ nhấc
   lên, đổi nền và tiêu đề đậm màu lúc rê chuột. */
#nang-luc .path{position:relative;overflow:hidden;padding-top:22px;padding-bottom:0}
/* Dải tiêu đề: 22px trên và 22px dưới chữ, bằng nhau. Mặc định của .path là
   padding-top 28px + margin-bottom .5em của h3 + 2px của ảnh → trên 28, dưới 13,
   dải nhìn lệch lên (người dùng chỉ ra 04/09/2026). Khổ điện thoại có luật riêng
   bên dưới (h3 margin 16px 0, ảnh sát mép) nên không ảnh hưởng. */
#nang-luc .path h3{margin:0}
#nang-luc .path .imgbox{margin:22px -26px 0}
#nang-luc .path .more{position:absolute;inset:0;margin:0;font-size:0}
/* Rê chuột: chỉ đậm màu tiêu đề, không gạch chân (người dùng bỏ 04/09/2026);
   thẻ nhấc lên + đổi nền đã đủ báo bấm được. */
#nang-luc .path:hover h3{color:var(--brand-mid)}
/* Đang sửa tại chỗ: lớp phủ nuốt cú bấm vào tiêu đề và ô ảnh — trả link về dạng dòng. */
body.cw-editing #nang-luc .path{padding-bottom:28px}
body.cw-editing #nang-luc .path .more{position:static;font-size:.86rem;margin-top:12px}
/* Dòng "bạn nhận được gì" (.nl-out) + mũi tên sau tiêu đề (06/10/2026).
   .nl-out đứng cuối thẻ trong mã (giữ đường dẫn cấu trúc, xem chú thích trong
   src/vi/index.html); order đưa nó lên dưới h3. Subgrid: ba thẻ chung ba hàng
   tiêu đề / dòng chữ / ảnh, nên dòng chữ dài ngắn khác nhau mà ảnh vẫn thẳng
   hàng. Mũi tên là tín hiệu "bấm được" duy nhất trên điện thoại (không có rê
   chuột) — link phủ thẻ không để lại dấu vết nào khác. */
#nang-luc .g3{grid-template-rows:auto auto auto}
#nang-luc .path{display:grid;grid-row:span 3;grid-template-rows:subgrid;row-gap:0}
#nang-luc .path h3{display:flex;align-items:baseline;gap:12px}
#nang-luc .path h3::after{content:"\2192";margin-left:auto;flex:none;font-weight:600;color:var(--brand);transition:transform .2s ease-out}
#nang-luc .path:hover h3::after{transform:translateX(5px);color:var(--brand-mid)}
#nang-luc .path .nl-out{order:1;margin:8px 0 0;font-size:.92rem;line-height:1.5;color:var(--muted);font-weight:400}
#nang-luc .path .nl-out b{color:var(--ink);font-weight:600}
#nang-luc .path .imgbox{order:2}
/* Đang sửa: link quay về dòng chảy thành phần tử thứ tư — bỏ subgrid, xếp dọc. */
body.cw-editing #nang-luc .g3{grid-template-rows:none}
body.cw-editing #nang-luc .path{display:flex;grid-row:auto}
body.cw-editing #nang-luc .path .more{order:3}
/* Khổ điện thoại: mỗi trụ thu về MỘT HÀNG — chữ bên trái, ảnh một phần ba bên
   phải. Giữ nguyên kiểu xếp dọc thì riêng ba ảnh 4:3 tràn hết bề ngang đã ăn hơn
   một màn hình rưỡi, mà đây mới là khối thứ hai của trang.
   KHÔNG bọc h3 + link vào một thẻ chung dù làm vậy dễ canh hơn: thêm một lớp div
   là đổi đường dẫn cấu trúc của h3, và bản sửa tại chỗ của tiêu đề thẻ (data-cw,
   xem lib/editable.js) thành mồ côi. Ba con vẫn nằm thẳng trong lưới, đặt tay.
   Bó trong #nang-luc: .path còn dùng ở trang Giải pháp và khối Đào tạo, những
   chỗ đó không có ảnh nên kéo sang hàng ngang là thành thẻ rỗng một bên. */
@media(max-width:620px){
  #nang-luc .path{
    /* mốc cho link phủ toàn thẻ ở dưới */
    position:relative;
    display:grid;
    /* Một hàng thôi: dòng "Chi tiết →" đã ra khỏi dòng chảy nên chỉ còn tiêu đề
       và ảnh đứng cạnh nhau. */
    grid-template-columns:minmax(0,1fr) 33%;
    align-items:center;
    column-gap:16px;
    /* CHỈ còn padding trái: ảnh phải chạm cả mép trên, phải và dưới, mà padding
       của thẻ thì nằm ngoài vùng lưới nên ô nào cũng không với tới được.
       Khoảng thở của cụm chữ chuyển thành margin của chính h3 — margin ấy vẫn
       tính vào chiều cao hàng, nên ảnh vẫn phủ hết chiều cao thẻ. */
    padding:0 0 0 20px;
    /* Ảnh chạm bốn mép nên góc vuông của nó thò ra ngoài khúc bo 8px của thẻ. */
    overflow:hidden;
  }
  #nang-luc .path h3{grid-area:1/1;margin:16px 0}
  /* "Chi tiết →" biến mất khỏi mắt nhưng KHÔNG bị gỡ: nó giãn ra phủ kín thẻ,
     nên chạm chỗ nào trên hàng cũng sang được trang trụ đó. Bỏ hẳn thì ba trụ
     mất đường vào duy nhất ở khổ điện thoại — thẻ không phải là link, tiêu đề
     cũng không.
     font-size:0 giấu chữ chứ không display:none, nhờ vậy link vẫn còn tên đọc
     được cho trình đọc màn hình. Không bọc thẻ trong <a> vì như thế là đổi cấu
     trúc và bản sửa tại chỗ của tiêu đề thành mồ côi. */
  #nang-luc .path .more{position:absolute;inset:0;margin:0;font-size:0}
  /* stretch đè lên align-items:center của thẻ, nên ảnh cao bằng đúng thẻ. Tiêu đề
     một dòng thì chiều cao thẻ do tỷ lệ 4:3 của ảnh quyết định và ảnh hiện đúng
     4:3; tiêu đề hai dòng thì thẻ cao hơn, ảnh giãn theo và object-fit:cover xén
     bớt — không bao giờ hở lề. */
  #nang-luc .path .imgbox{grid-area:1/2;align-self:stretch;margin:0}
  /* Khung chờ ảnh phải co theo: cỡ chữ mặc định của .ph tính cho ô rộng cả thẻ,
     nhét vào ô ~105px thì tên file tràn khỏi khung. Chỉ là giàn giáo — có ảnh
     thật thì .ph không hiện nữa. */
  #nang-luc .path .ph{font-size:.58rem;padding:6px;line-height:1.35;overflow:hidden}
  /* Hai hàng bên trái (tiêu đề, dòng chữ), ảnh phủ cả hai hàng bên phải. */
  #nang-luc .path{grid-row:auto;grid-template-rows:auto auto}
  #nang-luc .path h3{grid-area:1/1;margin:16px 0 0;align-self:end}
  #nang-luc .path .nl-out{grid-area:2/1;margin:4px 0 16px;align-self:start;font-size:.86rem}
  #nang-luc .path .imgbox{grid-area:1/2/3/3}
}
/* Trích dẫn: từ thẻ trắng có vạch màu → TẤM XANH ĐẶC, chữ trắng cỡ lớn. Trong hệ
   chỉ có xám và một màu, đây là chỗ màu được dùng thành mảng — và cũng đúng thứ
   tự ưu tiên: chứng thực khách hàng xứng đáng nặng ký hơn thẻ giới thiệu. */
.quote{background:var(--brand);border:0;border-left:0;color:#fff;
  padding:clamp(28px,3.6vw,40px);border-radius:var(--r);box-shadow:none;display:flex;flex-direction:column}
.quote p{font-size:1.22rem;line-height:1.55;color:#fff;font-weight:400;margin-bottom:22px}
/* margin-top:auto — hai trích dẫn dài ngắn khác nhau, phần ghi danh vẫn thẳng hàng đáy */
.quote .who{margin-top:auto;padding-top:16px;border-top:1px solid rgba(255,255,255,.3)}
.quote .who b{display:block;font-size:.94rem;color:#fff;font-weight:700}
.quote .who span{font-size:.84rem;color:rgba(255,255,255,.78)}
/* Logo công ty ở góc dưới phải: tên + chức vụ cột trái, logo cột phải canh giữa
   theo cụm hai dòng đó — đối trọng với khối chữ dồn trái. Tô trắng đặc
   (brightness 0 → invert) vì logo màu đặt trên nền xanh brand thì chìm hoặc
   chọi màu; cần PNG nền trong suốt (xem ô Logo ở Cài đặt → Chứng thực). */
.quote .who{display:grid;grid-template-columns:minmax(0,1fr) auto;column-gap:24px;align-items:center}
.quote .who b,.quote .who span{grid-column:1}
.quote .who-logo{grid-column:2;grid-row:1 / span 2;justify-self:end;display:block;
  height:24px;width:auto;max-width:140px;object-fit:contain;filter:brightness(0) invert(1);opacity:.92}
@media(max-width:620px){.quote .who-logo{height:20px;max-width:110px}}

/* ---------- băng chứng thực ----------
   Khối .quotes vẫn là lưới .g2 bình thường; site.js bọc nó thành băng chuyền
   khi có JS (và chỉ khi có từ 2 tấm trở lên). Không có JS thì mọi tấm nằm
   nguyên đó, hai cột như trước — nên toàn bộ phần dưới đây chỉ có tác dụng sau
   khi lớp .qrun được gắn vào.
   Danh sách tấm sửa ở Cài đặt → Chứng thực (data/quotes.json). */
.qbox{position:relative} /* mốc cho IntersectionObserver + vùng rê chuột để treo */
.qview{overflow:hidden}
/* Từ lưới sang MỘT hàng ngang. grid-template-columns của .g2 phải bị vô hiệu:
   để nguyên thì hai tấm đầu vẫn chia đôi khung còn tấm thứ ba rơi xuống hàng
   dưới, và cả băng chuyền trượt vào chỗ trống. */
.quotes.qrun{display:flex;flex-wrap:nowrap;grid-template-columns:none;
  transition:transform .5s cubic-bezier(.33,1,.68,1);will-change:transform}
/* Hai tấm một lượt, trừ đúng một khoảng gap 26px của .g2. */
.quotes.qrun>.quote{flex:0 0 calc((100% - 26px)/2)}
/* Cùng ngưỡng với .g2 rơi về một cột (@media 620px ở cuối file): dưới đó mỗi
   lượt đúng MỘT tấm, không có tấm hé bên cạnh. */
@media(max-width:620px){.quotes.qrun>.quote{flex:0 0 100%}}
@media(prefers-reduced-motion:reduce){.quotes.qrun{transition:none}}

/* ---------- cụm mũi tên ----------
   Đặt ở GÓC PHẢI DẢI TIÊU ĐỀ, không đè lên tấm chứng thực. Kiểu nút tròn nổi
   bám mép tấm đã bỏ: trên màn hẹp tấm chỉ rộng ~350px nên hai nút ấy nằm chồng
   lên chữ, và cái bóng đổ của chúng lạc hẳn khỏi hệ — thẻ trong site này không
   có bóng, chỉ có viền tóc và một màu.
   Hai nút dính liền thành MỘT khối viền: đó là một cặp điều khiển, không phải
   hai nút rời — cùng ngôn ngữ với thanh điều khiển băng hình ở hero.
   site.js gắn lớp .qhead vào .sec-head rồi thả cụm nút vào đó; không có JS thì
   cả hai thứ đều không tồn tại, dải tiêu đề y như mọi mục khác. */
.qctl{display:flex;width:max-content;margin:0 0 14px auto;
  background:#fff;border:1px solid var(--line);border-radius:9px;overflow:hidden}
/* Có dải tiêu đề thì cụm nút ngồi hẳn vào đó, canh đáy với chữ H2. */
.sec-head.qhead{position:relative;padding-right:112px;min-height:54px}
.sec-head.qhead .qctl{position:absolute;right:0;bottom:2px;margin:0}
/* display:flex ở trên thắng [hidden] của trình duyệt (cùng độ ưu tiên, luật của
   tác giả đứng sau) — thiếu dòng này thì cụm nút vẫn hiện khi không có gì để
   chuyển. */
.qctl[hidden]{display:none}
/* Mũi tên để mức xám chữ phụ lúc nghỉ: thẻ chứng thực là mảng xanh đặc nặng
   nhất trang, cụm điều khiển mà cũng đen đậm thì hai thứ tranh nhau. Màu đậm
   để dành cho lúc rê chuột. #6E6B69 trên nền trắng vẫn hơn 5:1, thừa ngưỡng
   3:1 của biểu tượng. */
.qnav{width:46px;height:40px;padding:0;border:0;background:none;cursor:pointer;
  color:var(--muted);display:flex;align-items:center;justify-content:center;
  transition:background .16s,color .16s}
.qnav + .qnav{border-left:1px solid var(--line)}
.qnav svg{width:17px;height:17px;fill:none;stroke:currentColor;stroke-width:1.9;
  stroke-linecap:round;stroke-linejoin:round}
.qnav:hover{background:var(--brand);color:#fff}
.qnav:active{background:var(--brand-mid);color:#fff}
.qnav:focus-visible{outline:2px solid var(--brand);outline-offset:2px;z-index:1}
/* Máy cảm ứng không có con trỏ: trạng thái hover dính lại sau khi chạm, nút cứ
   xanh mãi cho tới lần chạm chỗ khác. */
@media(any-hover:none){.qnav:hover{background:none;color:var(--muted)}}
@media(max-width:620px){
  .sec-head.qhead{padding-right:100px}
  .qnav{width:42px;height:38px}
}
/* ---------- nhóm thẻ gập lại trên màn hẹp: .mstack ----------
   Bốn thẻ chữ xếp dọc trên điện thoại thành một cột dài phải cuộn hai ba màn
   mới hết, mà đúng thứ để CHỌN — dòng tiêu đề — lại nằm rải rác giữa các đoạn
   văn. Dưới 620px, nhóm mang lớp .mstack gộp thành MỘT khối: mỗi thẻ còn lại
   một dòng tiêu đề, chạm mới mở phần chữ; mở thẻ này thì thẻ đang mở đóng lại,
   nên cả nhóm luôn nằm gọn trong một màn.
   Trên màn rộng lớp này KHÔNG làm gì — thẻ giữ nguyên như cũ.
   site.js dựng nút bấm và hai lớp bọc; không có JS thì không có lớp nào cả,
   mọi thẻ mở sẵn như hiện nay. Muốn dùng cho một lưới thẻ khác: thêm .mstack
   vào lưới đó, không phải sửa gì thêm. */

/* Nút bọc chữ tiêu đề. Ở mọi bề rộng nó phải trông đúng như chữ tiêu đề cũ —
   dưới 620px mới thành một hàng bấm được. */
.mrow-btn{display:block;width:100%;margin:0;padding:0;border:0;background:none;
  font:inherit;color:inherit;text-align:left;cursor:default}

@media(max-width:620px){
  /* Vỏ của từng thẻ tan ra, cả nhóm thành một khối liền chia bằng vạch tóc. */
  .mstack{display:block;background:#fff;border:1px solid var(--line);
    border-radius:var(--r);overflow:hidden}
  .mstack > *{display:block;padding:0;background:none;border:0;border-radius:0;box-shadow:none}
  .mstack > * + *{border-top:1px solid var(--line)}
  .mstack > *:hover{background:none} /* .card:hover / .path:hover đổi nền cả khối */
  .mstack > .mrow.on{background:var(--bg-soft)} /* thẻ đang mở: một mảng nền để neo mắt */
  .mstack .body{display:block;padding:0}
  /* h4 đi kèm h3: thẻ .step đặt tiêu đề ở h4 (xem TIEUDE trong site.js) */
  .mstack h3,.mstack h4{margin:0;font-size:1.02rem;line-height:1.35}

  .mrow-btn{display:flex;align-items:center;gap:14px;padding:16px;cursor:pointer;
    -webkit-tap-highlight-color:transparent}
  .mrow-btn:active{background:rgba(0,0,0,.03)}
  /* Mũi tên vẽ bằng ::after chứ KHÔNG phải thẻ thật: chữ tiêu đề là ô sửa trực
     tiếp được (data-cw), nhét thêm một thẻ vào trong h3 là nó bị lưu theo mỗi
     lần biên tập viên sửa dòng đó. */
  .mrow-btn::after{content:'';flex:0 0 auto;margin-left:auto;width:8px;height:8px;
    border-right:2px solid var(--muted);border-bottom:2px solid var(--muted);
    transform:rotate(-45deg);transition:transform .25s}
  .mrow.on .mrow-btn::after{transform:rotate(45deg)}

  /* 0fr -> 1fr: mở đúng theo chiều cao thật của chữ, không phải đoán max-height
     rồi chịu một quãng nghỉ ở cuối. */
  .mrow-body{display:grid;grid-template-rows:0fr;
    transition:grid-template-rows .3s cubic-bezier(.33,1,.68,1)}
  .mrow.on .mrow-body{grid-template-rows:1fr}
  /* visibility: chữ bị kẹp chiều cao về 0 vẫn NHẬN ĐƯỢC TIÊU ĐIỂM — không tắt
     thì phím Tab đi lạc vào mấy đường link đang không nhìn thấy. Hoãn tắt đúng
     bằng thời gian đóng để không cắt ngang hoạt ảnh. */
  .mrow-in{overflow:hidden;min-height:0;visibility:hidden;transition:visibility 0s .3s}
  .mrow.on .mrow-in{visibility:visible;transition:visibility 0s}
  /* Lề trong đặt ở CON của .mrow-in: bản thân .mrow-in bị kẹp chiều cao về 0
     nhưng padding của nó thì không co lại — lúc đóng sẽ còn một dải trắng. */
  .mstack .mrow-in > *{margin-left:16px;margin-right:16px}
  .mstack .mrow-in p{margin-top:0;margin-bottom:12px;font-size:.94rem}
  .mstack .mrow-in .more{display:inline-block;margin-bottom:16px}

  /* Đang bật Live edit: mở hết và tắt nút, để bấm vào chữ là sửa được ngay chứ
     không phải mở thẻ trước. */
  body.cw-editing .mrow-body{grid-template-rows:1fr}
  body.cw-editing .mrow-in{visibility:visible}
  body.cw-editing .mrow-btn{pointer-events:none}
}
/* TRẢ LẠI CỘT FLEX Ở KHỔ RỘNG.
   site.js dựng khung xương .mrow-body > .mrow-in ở MỌI bề rộng, nên từ lúc một
   lưới được gắn .mstack thì mọi thứ dưới tiêu đề tụt xuống sâu thêm hai cấp.
   Hệ quả: `.card .more`/`.path .more{margin-top:auto}` — luật kéo dòng "Chi tiết →"
   xuống đáy thẻ cho cả hàng thẳng nhau — mất tác dụng, vì margin auto chỉ đẩy được
   khi phần tử là con TRỰC TIẾP của một cột flex, mà cha nó giờ là .mrow-in (block).
   Đo ở 1280px trước khi sửa: ba thẻ .path của trang chủ có đáy link 4919/4944/4944.
   Chữa bằng cách cho hai lớp bọc trong suốt với cột flex (nối tiếp flex:1 xuống
   dưới) chứ không bỏ luật margin-top:auto ở 5 chỗ.
   CHỈ từ 621px: dưới ngưỡng đó .mrow-body là lưới 0fr↔1fr đóng/mở, đặt display:flex
   lên nó là hỏng hẳn phần gập. */
@media(min-width:621px){
  .mstack .mrow-body,.mstack .mrow-in{display:flex;flex-direction:column;flex:1;min-height:0}
}
@media(prefers-reduced-motion:reduce){
  .mrow-body,.mrow-btn::after{transition:none}
}

.steps{counter-reset:st;display:grid;grid-template-columns:repeat(4,1fr);gap:18px}
.step{background:var(--bg-soft);border:0;border-radius:var(--r);padding:22px 22px 24px;position:relative;
  box-shadow:var(--lift)}
.step::before{counter-increment:st;content:counter(st,decimal-leading-zero);font-weight:800;color:var(--accent);font-size:.92rem;letter-spacing:.08em}
.step h4{font-size:1.02rem;margin:.45em 0 .35em}
.step p{font-size:.9rem;color:var(--muted);margin:0}
/* ---- .steps gập lại trên màn hẹp ----
   Dùng chung cơ chế .mstack ở trên (site.js dựng nút, khối @media 620px vẽ
   hàng); ở đây chỉ là phần .steps cần nói thêm.
   Phải NHẮC LẠI vài luật thay vì trông vào khối .mstack: .steps/.step được khai
   SAU khối đó nên ở thế cân bằng độ ưu tiên chúng thắng — `.mstack{display:block}`
   thua `.steps{display:grid}`, `.mstack > *{padding:0}` thua `.step{padding:22px}`,
   `.mstack > * + *{border-top}` thua `.step{border:0}`. Viết kèm `.steps`/`.step`
   là lên một nấc độ ưu tiên, không phải !important. */
@media(max-width:620px){
  .steps.mstack{display:block;gap:0}
  .steps.mstack > .step{padding:0;background:none;border-radius:0;box-shadow:none}
  .steps.mstack > .step + .step{border-top:1px solid var(--line)}
  .steps.mstack > .step.mrow.on{background:var(--bg-soft)}
  /* Cùng một cái bẫy độ ưu tiên: `.mstack h3,.mstack h4{margin:0}` (0,1,1) thua
     `.step h4{margin:.45em 0 .35em}` vì .step khai sau. Lề ấy sống sót vào trong
     hàng gập và đội mỗi hàng lên ~13px — thấy ra thành một vệt trắng phía trên
     mỗi tiêu đề, còn số thứ tự (neo tuyệt đối, không nhúc nhích theo) thì tụt
     lên trên dòng chữ. Đo ở 430px trước khi sửa: hàng cao 68px, chữ bắt đầu ở
     y=24 trong khi số ở y=19. */
  .steps.mstack > .step h4{margin:0}
  /* Số thứ tự về CÙNG HÀNG với tiêu đề. Ở dạng gập, một hàng = một bước, nên số
     phải nằm trong hàng ấy chứ không đứng thành một dòng riêng phía trên. Neo
     tuyệt đối (.step vốn đã position:relative) rồi chừa chỗ bằng lề trái của
     nút — để số trong luồng thì nó đẩy chữ tiêu đề xuống dòng dưới.
     top/line-height dựng đúng bằng hộp dòng của tiêu đề (padding-top 16px của
     .mrow-btn, rồi 1.02rem × 1.35 ≈ 22px) thay vì một con số dò tay: hai hộp
     dòng trùng nhau thì số và chữ thẳng hàng, không phải canh lại mỗi lần đổi
     cỡ chữ. */
  .steps.mstack > .step::before{position:absolute;left:16px;top:16px;
    line-height:22px;font-size:.85rem}
  .steps.mstack .mrow-btn{padding-left:46px}
  /* Chữ trong phần thân thụt vào thẳng mép chữ tiêu đề, không thẳng mép số. */
  .steps.mstack .mrow-in > *{margin-left:46px}
}
/* .btn là con trực tiếp của flex-column nên bị kéo giãn suốt bề ngang thẻ —
   nút tải tài liệu ở trang Tài nguyên đang là một thanh đặc chạy hết thẻ */
.card .body > .btn,.path > .btn{align-self:flex-start}
/* ---------- tab Tài nguyên: Blog / Tin tức / Sự kiện ---------- */
/* Bám dưới thanh menu khi cuộn: danh sách bài dài hơn một màn hình nhiều lần,
   đọc tới giữa chừng vẫn đổi được tab mà không phải cuộn ngược lên đầu.
   top = đúng chiều cao thanh menu lúc đã cuộn (header.stuck) nên hai dải dính
   liền nhau, không hở một vệt nền ở giữa. Bám trong phạm vi khối cha, nên qua
   hết danh sách là thanh tab trôi đi theo trang chứ không đeo bám cả trang.
   z-index: ảnh trong thẻ là position:relative, đứng sau trong markup nên vẽ đè
   lên thanh tab nếu thanh không được nâng lên trên. Nền phải tô: nội dung cuộn
   qua BÊN DƯỚI thanh. */
.rtabs{position:sticky;top:var(--hdr-stuck);z-index:5;background:var(--bg);
  display:flex;gap:4px;border-bottom:1px solid var(--line);margin-bottom:26px;
  overflow-x:auto;scrollbar-width:none}
.rtabs::-webkit-scrollbar{display:none}
.rtab{position:relative;background:none;border:none;cursor:pointer;font-family:inherit;
  font-size:.95rem;font-weight:700;color:var(--muted);padding:12px 16px 13px;
  white-space:nowrap;display:inline-flex;align-items:center;gap:8px;transition:color .15s}
.rtab:hover{color:var(--ink)}
.rtab.on{color:var(--ink)}
.rtab.on::after{content:'';position:absolute;left:12px;right:12px;bottom:-1px;height:2.5px;
  border-radius:3px 3px 0 0;background:var(--accent)}
.rnum{font-size:.72rem;font-weight:800;color:var(--muted);background:var(--bg-soft);
  border:1px solid var(--line);min-width:20px;height:20px;border-radius:10px;
  padding:0 6px;display:inline-flex;align-items:center;justify-content:center}
.rtab.on .rnum{background:var(--accent);border-color:var(--accent);color:#fff}
/* position: mốc cho thẻ nổi "Được xem nhiều nhất" đứng ở lề phải (xem .toppost) */
.rpane{position:relative}
.rpane[hidden]{display:none}

/* ---------- thẻ bài viết trên trang danh sách ---------- */
.postgrid{display:grid;grid-template-columns:repeat(3,1fr);gap:24px}
.postgrid.lead{grid-template-columns:1.6fr 1fr;gap:26px;margin-bottom:26px;align-items:start}

.pcard{display:flex;flex-direction:column;background:var(--bg-soft);border:0;
  border-radius:var(--r);overflow:hidden;text-decoration:none;color:inherit;
  box-shadow:var(--lift)}
.pcard:hover{text-decoration:none;
  background:var(--panel-hi)}
.pcard .imgbox{aspect-ratio:16/9;background:#eef2f6;flex:0 0 auto}
/* aspect-ratio chỉ là chiều cao ƯU TIÊN: ảnh trong luồng cao hơn khung sẽ kéo giãn
   khung theo tỷ lệ gốc của nó. Đặt ảnh absolute để khung luôn giữ đúng tỷ lệ khai báo
   — áp cho cả .arbox (khung ảnh của case study, sản phẩm, ngành). */
.pcard .imgbox,.arbox{overflow:hidden}
.pcard .imgbox img,.arbox img{position:absolute;inset:0}
.pcard-body{padding:18px 20px 20px;display:flex;flex-direction:column;flex:1}
.pcard h3{font-size:1.06rem;line-height:1.35;margin:0 0 auto;color:var(--ink)}
.pcard:hover h3{color:var(--brand)}
.pcard-top{display:flex;align-items:center;gap:9px;margin-bottom:9px;flex-wrap:wrap}
.pcard-foot{display:flex;align-items:center;gap:9px;margin-top:12px;
  font-size:.78rem;color:var(--muted)}
.tag{display:inline-block;font-size:.7rem;font-weight:700;letter-spacing:.02em;
  padding:2px 9px;border-radius:20px;background:#e9f2fb;color:#0b4a86;white-space:nowrap}
.tag-hvac{background:var(--accent-wash);color:var(--accent-ink)}
.tag-thiet-bi{background:#fff4e3;color:#8a5a06}
.pcard-date{font-size:.78rem;color:var(--muted)}

/* bài nổi bật: ảnh lớn hơn, chữ to hơn */
.pcard.big .imgbox{aspect-ratio:2/1}
.pcard.big .pcard-body{padding:20px 24px 24px}
.pcard.big h3{font-size:1.35rem;line-height:1.28;letter-spacing:-.01em}
.pcard.big .pcard-sum{font-size:.9rem;color:var(--muted);margin:10px 0 0;line-height:1.6}

/* bảng đọc nhiều nhất */
.toplist{background:var(--bg-soft);border:0;border-radius:var(--r);padding:20px 22px 22px;box-shadow:var(--lift)}
.toplist h3{font-size:.72rem;letter-spacing:.13em;text-transform:uppercase;color:var(--muted);
  font-weight:800;margin:0 0 12px}
.toplist ol{list-style:none;counter-reset:tl;margin:0;padding:0}
.toplist li{counter-increment:tl;display:flex;gap:11px;padding:9px 0;
  border-bottom:1px solid var(--line);font-size:.88rem;line-height:1.45}
.toplist li:last-child{border-bottom:none}
.toplist li::before{content:counter(tl);flex:0 0 auto;width:20px;font-weight:800;
  color:var(--accent);font-size:.8rem;padding-top:2px}
.toplist a{color:var(--ink)}
.toplist a:hover{color:var(--brand)}
.toplist .n{display:block;font-size:.76rem;color:var(--muted);margin-top:2px}

@media(max-width:1024px){
  .postgrid{grid-template-columns:repeat(2,1fr)}
  .postgrid.lead{grid-template-columns:1fr}
}
@media(max-width:620px){
  .postgrid{grid-template-columns:1fr}
}

/* ---------- .split — ba bài mới nhất là thẻ, các bài cũ hơn là dòng ----------
   VẪN MỘT LƯỚI, không tách làm hai khối. Thứ tự trong lưới do máy chủ xếp theo
   ngày (lib/pagerender.js: sortByDate), nên "ba con đầu" luôn đúng là ba bài mới
   nhất — kể cả sau khi thêm bài. CSS chỉ đổi HÌNH DẠNG theo vị trí, không ai
   phải nhớ chuyển thẻ từ khối này sang khối kia, và máy chủ không phải biết gì
   về chuyện thẻ hay dòng.

   Giữ 3 cột xuống tận 620px (chỗ khác rơi về 2 cột): hàng đầu phải đúng ba thẻ,
   hai cột thì hàng đầu hụt một ô và bài thứ ba đứng trơ giữa khoảng trống.
   Dưới 620px thì đổi hẳn bố cục — xem khối "điện thoại" cuối phần này.
   row-gap:0 để các dòng dính liền nhau; khe 24px dưới ba thẻ đặt bằng margin. */
.postgrid.split{row-gap:0}
.postgrid.split>.pcard:nth-child(-n+3){margin-bottom:24px}
@media(max-width:1024px){.postgrid.split{grid-template-columns:repeat(3,1fr)}}

/* Dòng: bỏ nền và bo góc của thẻ, ảnh thu nhỏ nằm trái, chữ dồn thành hai dòng
   (tiêu đề / chuyên mục · ngày · thời gian đọc). Vạch ngăn đặt ở MÉP TRÊN nên
   vừa tách các dòng với nhau, vừa tách cả khối dòng khỏi ba thẻ bên trên, mà
   cuối danh sách không thừa một vạch cụt. */
.postgrid.split>.pcard:nth-child(n+4){grid-column:1/-1;flex-direction:row;align-items:center;
  gap:16px;padding:12px 6px;background:none;box-shadow:none;border-radius:0;
  border-top:1px solid var(--line)}
.postgrid.split>.pcard:nth-child(n+4):hover{background:var(--bg-soft);box-shadow:none}
.postgrid.split>.pcard:nth-child(n+4) .imgbox{flex:0 0 300px;border-radius:4px}
.postgrid.split>.pcard:nth-child(n+4) .pcard-body{flex-flow:row wrap;align-items:center;
  padding:0;gap:3px 14px}
/* order: trong thẻ, chuyên mục + ngày đứng TRÊN tiêu đề — đúng cho một tấm ảnh
   lớn, nhưng thành dòng danh sách thì thứ cần đọc trước là tiêu đề. Đảo bằng
   order để markup của thẻ và của dòng vẫn là một (xem lib/pagerender.js: pcard).
   flex 0 0 100% ở tiêu đề bẻ dòng, nên chuyên mục · ngày · thời gian đọc dồn
   hết xuống dòng thứ hai. margin:0 0 auto của tiêu đề trong thẻ dọc sẽ đẩy chữ
   lệch khi xoay ngang. */
.postgrid.split>.pcard:nth-child(n+4) h3{order:1;flex:0 0 100%;margin:0;font-size:1.02rem}
.postgrid.split>.pcard:nth-child(n+4) .pcard-sum{order:2;flex:0 0 100%;margin:0}
.postgrid.split>.pcard:nth-child(n+4) .pcard-top{order:3;margin:0}
.postgrid.split>.pcard:nth-child(n+4) .pcard-foot{order:4;margin:0}

/* Mô tả: câu dẫn của bài, do máy chủ lấy từ front matter (lib/pagerender.js:
   fillSums) nên thẻ trong src/ không phải chép lại. Cắt ở 2 dòng — câu dẫn viết
   cho đoạn trích Google nên dài ngắn không đều, để tự do thì mỗi dòng một chiều
   cao. Ba thẻ đầu KHÔNG hiện: chỗ đó đã có ảnh lớn làm phần nhìn, thêm chữ vào
   là ba thẻ cao ngắn khác nhau theo độ dài câu dẫn. */
.postgrid.split>.pcard:nth-child(-n+3) .pcard-sum{display:none}
.postgrid.split>.pcard:nth-child(n+4) .pcard-sum{display:-webkit-box;-webkit-box-orient:vertical;
  -webkit-line-clamp:2;overflow:hidden;font-size:.88rem;line-height:1.55;color:var(--muted)}
/* ---------- điện thoại: một bài lớn, hai bài nhỏ, còn lại là dòng ----------
   Ba thẻ ngang hàng ở khổ 390px thì mỗi thẻ rộng chưa tới 110px — ảnh bằng con
   tem, tiêu đề rơi bốn năm dòng. Đổi thành: bài mới nhất chiếm trọn bề ngang,
   hai bài kế đứng cạnh nhau, các bài cũ hơn thành dòng ảnh nhỏ bên trái.
   Mô tả TẮT ở khổ này: cột chữ cạnh ảnh chỉ còn hơn 200px, thêm hai ba dòng
   chữ nhạt vào là mỗi mục cao gấp rưỡi mà vẫn không đọc trọn được câu nào. */
@media(max-width:620px){
  .postgrid.split{grid-template-columns:repeat(2,1fr);column-gap:14px}
  .postgrid.split>.pcard:nth-child(1){grid-column:1/-1}
  /* Thẻ nhỏ: chữ và đệm lùi một nấc cho vừa nửa bề ngang màn hình */
  .postgrid.split>.pcard:nth-child(2) .pcard-body,
  .postgrid.split>.pcard:nth-child(3) .pcard-body{padding:12px 13px 14px}
  .postgrid.split>.pcard:nth-child(2) h3,
  .postgrid.split>.pcard:nth-child(3) h3{font-size:.93rem}

  /* Dòng: ảnh bên trái, tiêu đề và dòng thông tin xếp ở cột phải — ảnh cao
     bằng đúng tiêu đề + chuyên mục nên không còn mảng trắng treo lơ lửng.
     display:contents ở .pcard-body để mấy phần chữ thành ô của chính lưới
     .pcard, nhờ vậy thẻ và dòng vẫn dùng chung một markup. */
  .postgrid.split>.pcard:nth-child(n+4){display:grid;grid-template-columns:144px 1fr;
    column-gap:12px;row-gap:5px;align-items:start;padding:12px 2px}
  .postgrid.split>.pcard:nth-child(n+4) .pcard-body{display:contents}
  /* Ảnh cắt về 3:2 chứ không giữ 16:9: ở bề ngang này khung 16:9 chỉ cao 81px
     trong khi khối chữ bên phải cao gần 100px, nhìn ra một tấm ảnh bé tí nằm
     cạnh ba dòng chữ. 3:2 cao 96px — ngang tầm khối chữ, mà chỉ cắt ~8% mỗi
     mép nên hình vẽ trong thumbnail vẫn còn đủ. */
  .postgrid.split>.pcard:nth-child(n+4) .imgbox{grid-column:1;grid-row:1/span 3;
    align-self:start;flex-basis:auto;aspect-ratio:3/2}
  .postgrid.split>.pcard:nth-child(n+4) h3{grid-column:2;grid-row:1;font-size:.93rem}
  .postgrid.split>.pcard:nth-child(n+4) .pcard-sum{display:none}
  .postgrid.split>.pcard:nth-child(n+4) .pcard-top{grid-column:2;grid-row:2}
  .postgrid.split>.pcard:nth-child(n+4) .pcard-foot{grid-column:2;grid-row:3}
}

/* ---------- "Được xem nhiều nhất": thẻ nổi ở lề phải tab Blog ----------
   Máy chủ chèn <aside class="toppost"> vào cuối khung tab lúc phục vụ
   (lib/pagerender.js: topCard). Nằm trong #pane-blog nên đổi tab là mất theo cả
   khung — không cần một dòng JS nào.

   Thẻ đứng NGOÀI lưới, trong khoảng trắng bên phải trang, nên không thẻ bài viết
   nào bị bóp hẹp lại. Chỗ ấy chỉ có ở màn rộng: dưới ngưỡng thì ẩn hẳn, vì chen
   được vào cũng là đè lên lưới.

   Khối bọc cao bằng cả khung tab (top:0;bottom:0) để tấm .toplist bên trong
   sticky bám theo suốt chiều dài lưới; bọc là khối rỗng nên không che gì. */
.toppost{display:none}
@media(min-width:1660px){
  /* Neo CẢ HAI mép, không đặt bề rộng: trái cách lưới 24px (bằng khe giữa hai
     cột thẻ bài viết), phải thẳng hàng với dải hero — thẻ tự giãn ra lấp trọn
     khoảng lề, màn càng rộng thẻ càng rộng.

     .pageband cách mép trang đúng 8px. 636px = 620 (nửa bề ngang lưới) + 8 (lề
     của dải) + 8 (nửa thanh cuộn, vì 50vw tính cả thanh cuộn). Máy không có
     thanh cuộn thì thẻ lùi vào 8px — lệch về phía an toàn, không bao giờ chồi
     ra ngoài dải. */
  .toppost{display:block;position:absolute;top:0;bottom:0;
    left:calc(100% + 24px);right:calc(636px - 50vw)}
  .toppost .toplist{position:sticky;top:calc(var(--hdr) + 16px);padding:18px 18px 20px}
  .toppost .toplist li{font-size:.84rem;padding:8px 0;line-height:1.4}
  .toppost .toplist a{display:block}
}

/* ---------- trang Dự án: thanh lọc hai trục + danh mục case study ----------
   Hai trục lọc là hai cách phân loại đã có sẵn của site, không phải bộ mới:
   GIẢI PHÁP là ba trụ ở giai-phap.html, LĨNH VỰC là bốn nhóm ở linh-vuc.html.
   Mỗi thẻ mang data-gp/data-lv (nhiều giá trị cách nhau bằng dấu cách) và JS chỉ
   bật/tắt thuộc tính hidden — nội dung vẫn là HTML tĩnh nên vẫn sửa được ở khu
   quản trị và vẫn vào chỉ mục tìm kiếm.
   Thanh lọc ẩn cho tới khi JS gắn .on: không có JS thì nút bấm sẽ chết, mà danh
   mục thì vẫn hiện đủ — thà không có thanh lọc còn hơn có một thanh không bấm được. */
.pjbar{display:none;border-bottom:1px solid var(--line);padding-bottom:16px;margin-bottom:26px}
.pjbar.on{display:block}
.pjrow{display:flex;align-items:flex-start;gap:18px;padding:5px 0}
/* Nhãn trục rộng cố định để hai hàng chip thẳng mép trái với nhau. padding-top
   canh chữ nhãn với dòng chữ trong chip chứ không với mép trên của chip. */
.pjlab{flex:0 0 84px;padding-top:9px;font-size:.72rem;letter-spacing:.12em;
  text-transform:uppercase;color:var(--muted);font-weight:600;line-height:1.2}
.pjchips{display:flex;flex-wrap:wrap;gap:8px;min-width:0}
.pjchip{display:inline-flex;align-items:center;gap:8px;cursor:pointer;font-family:inherit;
  font-size:.87rem;font-weight:600;line-height:1.2;color:var(--ink);white-space:nowrap;
  background:var(--bg-soft);border:1px solid transparent;border-radius:20px;padding:8px 14px;
  transition:background .18s, color .18s, border-color .18s}
.pjchip:hover{background:var(--panel-hi)}
.pjchip.on{background:var(--accent);border-color:var(--accent);color:#fff}
.pjchip.on:hover{background:var(--accent-dark);border-color:var(--accent-dark)}
/* Chip không còn dự án nào KHÔNG bị khóa: bấm vào vẫn được, và khung rỗng bên
   dưới mới là chỗ nói rõ đi đâu tiếp. Nút khóa thì người ta chỉ biết là hết,
   không biết vì sao.
   :not(.on) là bắt buộc chứ không phải cho gọn: luật này nằm SAU .pjchip.on và
   cùng độ ưu tiên, không loại trừ thì chính cái chip vừa bấm — nền xanh đặc —
   bị trả chữ về màu xám nhạt và đọc ra như đang bị khóa. */
.pjchip.zero:not(.on){color:var(--muted)}
.pjn{font-size:.72rem;font-weight:700;font-variant-numeric:tabular-nums;color:var(--muted);
  background:var(--bg);border-radius:9px;min-width:19px;height:19px;padding:0 5px;
  display:inline-flex;align-items:center;justify-content:center}
.pjchip.on .pjn{background:rgba(255,255,255,.22);color:#fff}
.pjfoot{display:flex;align-items:center;gap:16px;flex-wrap:wrap;margin-top:12px;padding-left:102px}
.pjcount{margin:0;font-size:.86rem;color:var(--muted)}
.pjcount b{color:var(--ink);font-weight:700;font-variant-numeric:tabular-nums}
.pjclear{background:none;border:0;padding:0;cursor:pointer;font-family:inherit;
  font-size:.86rem;font-weight:600;color:var(--brand);text-decoration:underline;
  text-underline-offset:3px}
.pjclear:hover{color:var(--brand-mid)}

/* Một dự án = một THẺ DỌC trong lưới BỐN CỘT ở khổ desktop: ảnh trên · meta +
   tên dự án · dải hai con số ở chân thẻ (người dùng yêu cầu 04/09/2026).
   Trước đó đây là hàng ngang ảnh | chữ | số, đọc theo lối quét dọc cột số. Cái
   giá của nó: mỗi hàng cao ~200px nên 11 case study trải hơn ba màn hình, và
   trang danh mục đọc ra như một bảng. Khuôn thẻ dọc này KHÔNG phải phát minh
   mới — nó chính là khuôn mà khổ điện thoại vẫn dùng (ảnh 16/10 fit:contain,
   câu mô tả và dải nhãn ẩn, cả thẻ bấm được); giờ nó thành khuôn duy nhất cho
   mọi khổ, chỉ khác số cột. Cột số vẫn quét dọc được, nhưng theo từng HÀNG
   thẻ: .pjcard-kpi ghim ở chân thẻ bằng margin-top:auto nên mọi dải số của một
   hàng luôn cùng mép dưới.
   Bốn cột trong .wrap 1240px ra ô rộng ~296px — cỡ chữ tiêu đề và dải KPI bên
   dưới đo theo bề ngang ĐÓ, không phải theo ô 400px của bản ba cột.
   Câu mô tả bài toán và dải nhãn vẫn nằm trong HTML, chỉ ẩn bằng CSS — lý do
   đầy đủ ở hai luật display:none bên dưới. */
.pjgrid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:18px;align-items:stretch}
.pjcard{position:relative}
/* Thẻ rê chuột phải nằm TRÊN thẻ kế tiếp. transform của luật hover chung có tạo
   ngữ cảnh xếp lớp, nhưng anh em đứng sau trong DOM vẫn vẽ đè lên — bóng đổ 20px
   của thẻ đang nhấc bị thẻ sau cắt mất một nửa, trông như bóng bị xén. */
.pjcard:hover{z-index:1}
/* .card đặt display:flex nên luật display:none mặc định của [hidden] thua về
   độ ưu tiên — phải ghi lại, nếu không lọc xong thẻ vẫn nằm nguyên đó. */
.pjcard[hidden]{display:none}
/* Ảnh thẻ là SƠ ĐỒ kỹ thuật, chữ nhãn nằm ngay trong hình. Khung cao cố định
   trên bề ngang cả thẻ ra tỷ lệ ~2.3, trong khi ảnh thật là 1.4–2.0 —
   object-fit:cover xén mất 15–40% chiều cao, đúng vào dải mang tiêu đề hình.
   Khung 16/10 + fit:contain: thấy trọn hình, phần thừa là nền trắng ở hai bên. */
.pjcard > .imgbox{height:auto;min-height:0;aspect-ratio:16/10;background:#fff}
.pjcard > .imgbox img{object-fit:contain}
.pjcard-body{padding:16px 18px 14px;display:flex;flex-direction:column;flex:1;min-width:0}
/* Dòng meta GIỮ CHỖ 2 dòng dù chỉ chiếm 1: đo trên bản live có 2 trong 11 thẻ
   xuống dòng ("Case study · Môi trường – năng lượng · Hàn Quốc · 2024"), và một
   dòng lệch ở đây đẩy tiêu đề của cả thẻ đó xuống thấp hơn ba thẻ bên cạnh —
   đúng cái làm lưới trông xô lệch. Giữ chỗ thì mọi tiêu đề khởi đầu cùng một
   cao độ. Cắt ở 2 dòng luôn: meta dài hơn thế là dữ liệu sai, không phải bố cục.
   line-clamp cần -webkit-box; -webkit-line-clamp nay là chuẩn ở mọi trình duyệt
   hiện hành, `line-clamp` không tiền tố vẫn chưa đủ phủ nên khai cả hai. */
.pjcard-body .meta{margin-bottom:.5em;min-height:2.8em;
  display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;line-clamp:2;overflow:hidden}
/* Tiêu đề phải NHỈNH HƠN giá trị KPI (1.05rem, đặt ở khối thang sắc độ cuối
   file): xếp chồng nhau trong một thẻ hẹp thì thứ to nhất đọc ra là tiêu đề —
   để con số to hơn là thẻ lộn ngược, cụm giá trị thành tên dự án.
   Cắt ở 3 dòng: đo trên cả hai ngôn ngữ thì tên dài nhất ("Chốt cấu hình phun
   SNCR trước lắp đặt cho lò đốt rác phát điện 30 MW") vừa đúng 3 dòng, nên đây
   là trần an toàn chứ không cắt mất chữ của thẻ nào. */
.pjcard h3{font-size:1.14rem;line-height:1.32;margin-bottom:0;color:var(--brand);
  display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3;line-clamp:3;overflow:hidden}
/* Tiêu đề bấm được để mở case study — site.js gắn lớp .pjtitle-tap cho thẻ nào
   có sẵn <a class="more"> để lấy đích. Đây CHỈ là tiện tay cho chuột: <h3> vẫn
   là heading thuần (không role, không tabindex), còn đường đi cho bàn phím và
   trình đọc màn hình là chính thẻ <a> — ở khổ điện thoại nó thành lớp phủ trong
   suốt trùm cả thẻ chứ không bị display:none (xem khối @media bên dưới).
   KHÔNG bọc <a> vào trong <h3>: lib/editable.js bỏ qua mọi ô có link bên trong,
   bọc vào là tiêu đề mất luôn khả năng sửa tại chỗ. */
.pjcard h3.pjtitle-tap{cursor:pointer}
.pjcard h3.pjtitle-tap:hover{text-decoration:underline;text-underline-offset:3px}
/* Chạm cũng bắn ra :hover và trạng thái dính lại tới lần chạm sau — gạch chân
   một tiêu đề rồi để đó thì trông như lỗi. Bọc ngược bằng any-hover:none, KHÔNG
   bọc luật trên trong hover:hover (xem chú thích ở khối rê chuột chung). */
@media(any-hover:none){.pjcard h3.pjtitle-tap:hover{text-decoration:none}}
/* Câu mô tả bài toán KHÔNG hiện trên thẻ: ở cột hẹp nó thành 4–5 dòng và đẩy
   hai con số KPI — thứ đáng đọc nhất của thẻ — xuống dưới mép màn hình, đúng
   thứ đã bỏ ở khổ điện thoại từ trước. Câu đó là chữ mở đầu của chính case
   study, đọc đủ khi mở trang.
   display:none chứ KHÔNG bỏ khỏi HTML: chữ vẫn nằm trong trang cho chỉ mục tìm
   kiếm, ô vẫn sửa được tại chỗ (gỡ thẻ ra là mọi bản đè đã lưu theo mã đường
   dẫn phần tử thành mồ côi), và bật lại chỉ là xóa một dòng ở đây. */
.pjcard-body p{color:var(--ink);font-size:.93rem;font-weight:500;line-height:1.6;
  margin:0 0 16px;max-width:62ch;display:none}
/* Dải nhãn cũng đi: nó chỉ chép lại đúng thứ vừa chọn trên thanh lọc ngay phía
   trên. Bộ lọc chạy trên data-gp/data-lv của thẻ chứ không trên dải nhãn này,
   nên ẩn nó không đụng gì tới việc lọc. */
.pjtags{display:flex;flex-wrap:wrap;gap:6px;margin-top:auto}
.pjcard .pjtags{display:none}
/* Dòng "Đọc case study →" KHÔNG dùng display:none: ẩn kiểu đó là gỡ luôn đường
   link duy nhất của thẻ khỏi cây trợ năng và khỏi phím Tab. Thay vào đó cho nó
   phủ trong suốt lên cả thẻ (font-size:0 nên chữ biến mất, .pjcard đã có
   position:relative) — đúng lối đã dùng ở #nang-luc .path .more. Chữ vẫn còn
   nguyên cho trình đọc màn hình, bấm chỗ nào trên thẻ cũng mở case study, và
   <h3> giữ nguyên là heading. */
.pjcard-body .more{position:absolute;inset:0;margin:0;font-size:0}
/* Đang sửa tại chỗ thì lớp phủ nuốt mọi cú bấm vào chữ: nhấc nó ra khỏi đường
   đi, chữ vẫn tàng hình vì font-size:0. */
body.cw-editing .pjcard-body .more{position:static;inset:auto}
.pjtag{font-size:.72rem;font-weight:600;line-height:1.5;padding:2px 9px;border-radius:3px;
  white-space:nowrap}
/* Hai trục phân loại phải nhìn ra khác nhau ngay trên thẻ: giải pháp tô nền xanh
   nhạt, lĩnh vực chỉ viền trung tính. Vẫn đúng luật một-màu của hệ. */
.pjtag-gp{background:var(--accent-wash);color:var(--accent-ink)}
.pjtag-lv{background:transparent;border:1px solid rgba(44,42,41,.28);color:var(--muted)}
/* Hai ô KPI nằm ngang ở CHÂN thẻ. Để chúng là hai hộp flex rời thì giá trị bên
   này xuống hai dòng còn bên kia một dòng là hai câu mô tả lệch nhau đúng một
   dòng — nhìn như hai thẻ chồng hụt. Trải cả dải thành LƯỚI 2 cột × 2 hàng: mọi
   giá trị ở hàng 1, mọi mô tả ở hàng 2, hàng tự cao theo ô cao nhất nên hai cột
   luôn khởi đầu cùng một mức. .pjkpi phải display:contents để bốn phần tử con
   rơi thẳng vào lưới của dải, không bị lớp bọc chặn lại.
   margin-top:auto ghim dải xuống đáy: ba thẻ trong một hàng lưới cao bằng nhau
   nên ba dải số cùng mép, quét ngang một hàng là so được. */
/* Hai HÀNG của dải đều GIỮ CHỖ CỐ ĐỊNH, không co theo chữ: hàng giá trị 2 dòng,
   hàng nhãn 3 dòng. Đo trên bản live ở khổ 4 cột, dải này cao từ 68px tới 141px
   tùy thẻ — mỗi thẻ một mép trên khác nhau, và vì dải ghim ở đáy thẻ nên chênh
   lệch dồn hết vào khoảng trắng dưới tiêu đề. Đó chính là cái làm lưới trông xô
   lệch dù mọi thẻ cao bằng nhau.
   Ghim cả hai hàng: MỌI dải cao đúng như nhau ở mọi thẻ, mọi hàng, cả hai ngôn
   ngữ — mép trên của dải thành một đường ngang liên tục suốt lưới.
   Giá trị canh ĐÁY hàng của nó (align-self:end) nên giá trị một dòng vẫn nằm sát
   ngay trên nhãn của mình; phần dư dồn lên trên, nhập vào khoảng trắng dưới tiêu
   đề chứ không thành lỗ hổng giữa hai dòng chữ. */
.pjcard-kpi{margin-top:auto;border-top:1px solid var(--line);
  display:grid;grid-template-columns:1fr 1fr;
  grid-template-rows:calc(2 * 1.05rem * 1.18) calc(4 * .76rem * 1.4);
  column-gap:16px;row-gap:3px;padding:12px 18px 14px}
.pjcard .pjkpi{display:contents}
.pjkpi b{display:block;font-size:1.0rem;font-weight:600;color:var(--brand);
  line-height:1.12;letter-spacing:-.025em}
.pjcard .pjkpi b{grid-row:1;align-self:end;
  display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;line-clamp:2;overflow:hidden}
.pjkpi span{display:block;font-size:.79rem;color:var(--muted);line-height:1.4;margin-top:4px}
/* Nhãn hạ xuống .76rem (từ .8rem): ở ô 4 cột rộng ~122px, cỡ cũ đẩy 5 trong 22
   nhãn của hai ngôn ngữ sang dòng thứ tư — muốn dải cao đều thì hoặc cắt bớt
   chữ của 5 nhãn đó, hoặc hạ nửa nấc cỡ chữ để chúng vừa 3 dòng. Chọn cách sau:
   không nhãn nào mất chữ. Cắt ở 3 dòng vẫn giữ làm trần cho nhãn nhập sau này. */
.pjcard .pjkpi span{grid-row:2;margin-top:0;font-size:.76rem;
  display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:4;line-clamp:4;overflow:hidden}
/* Đang sửa tại chỗ thì bỏ mọi luật cắt dòng: chữ dài hơn khung sẽ bị giấu ngay
   trong lúc gõ, người sửa tưởng vừa mất chữ. */
body.cw-editing .pjcard h3,
body.cw-editing .pjcard-body .meta,
body.cw-editing .pjcard .pjkpi b,
body.cw-editing .pjcard .pjkpi span{display:block;-webkit-line-clamp:none;line-clamp:none;overflow:visible}
/* MỌI giá trị KPI dùng chung một cỡ và một màu — kể cả giá trị là chữ
   ("Toàn tuyến", "Đa pha"). Ở đây từng có lớp .w hạ cụm chữ xuống 1.06rem vì sợ
   "một cụm ba từ chiếm bốn dòng"; đo lại trên cả hai ngôn ngữ thì không giá trị
   nào vượt quá HAI dòng, còn cái giá phải trả thì thấy ngay: cột số đọc thành
   hai loại thẻ khác nhau khi quét dọc danh mục — đúng thứ cột này sinh ra để
   làm. Giá trị dài nhất hiện nay ("Government project", "2 injection systems")
   xuống 2 dòng, line-height 1.12 ở trên là để hai dòng đó không dính nhau. */

.pjempty{background:var(--bg-soft);border-radius:var(--r);padding:36px 30px;text-align:center}
.pjempty h3{font-size:1.14rem;color:var(--ink);margin-bottom:.55em}
.pjempty p{margin:0 auto 8px;max-width:64ch;color:var(--muted);font-size:.94rem}
.pjempty .pjempty-t{color:var(--ink);font-weight:500}
.pjempty .btnrow{justify-content:center;margin-top:20px}

/* ── Khối "Các dự án khác theo giai đoạn" (#khac) ────────────────────────────
   Trước đây là <table> bốn cột. Ở khổ điện thoại nó phải ghim min-width:580px
   rồi cuộn ngang (xem .tbl-min) — nghĩa là hai cột Ngành và Phạm vi nằm ngoài
   màn hình, không ai thấy. Còn ở khổ rộng, cột NĂM lặp lại "2025" mười lần
   trong khi tiêu đề mục hứa "theo giai đoạn": cột tốn diện tích nhất của bảng
   lại là cột không mang tin.
   Bản này gộp theo năm — năm viết MỘT lần ở rãnh trái và dính theo lúc cuộn,
   mỗi dự án là một dòng hai tầng (tên / ngành + phạm vi) tự xuống dòng. Không
   còn ô bảng nào nên không còn gì để cuộn ngang.
   Vẫn là HTML tĩnh mang data-pj/data-gp/data-lv nên thanh lọc ở trên chạy y
   như với hàng bảng cũ; site.js đếm lại số dưới mỗi năm và giấu cả nhóm khi
   lọc hết dòng (khối "rãnh năm" trong file đó). */
.yrlist{background:#fff;border:1px solid var(--line);border-radius:var(--r);overflow:clip}
/* overflow:CLIP chứ không phải overflow:hidden. Cả hai đều cắt nền xám của rãnh
   năm cho khớp góc bo, nhưng `hidden` biến khối này thành một khung cuộn và
   position:sticky của rãnh năm chết câm ngay trong đó — `clip` thì không tạo
   khung cuộn nên dính vẫn ăn theo cửa sổ.
   Hai luật bo góc bên dưới vẫn giữ: Safari trước bản 16 không hiểu overflow:clip,
   ở đó chúng là đường lui. Chỉ có chúng thôi thì chưa đủ — lọc mà nhóm năm đầu
   bị ẩn thì :first-child vẫn trỏ vào nhóm đã ẩn, góc trên trái hở ra. */
.yrgrp{display:grid;grid-template-columns:116px minmax(0,1fr)}
.yrgrp + .yrgrp{border-top:1px solid var(--line)}
/* .yrgrp là display:grid nên [hidden] mặc định thua độ ưu tiên — cùng lý do đã
   ghi ở .pjcard[hidden]. */
.yrgrp[hidden]{display:none}
.yrtag{background:var(--bg-soft);border-right:1px solid var(--line);padding:16px 18px}
.yrgrp:first-child .yrtag{border-radius:calc(var(--r) - 1px) 0 0 0}
.yrgrp:last-child .yrtag{border-radius:0 0 0 calc(var(--r) - 1px)}
/* Nhóm 2025 có mười dự án, cao hơn một màn hình: cuộn tới giữa nhóm mà năm đã
   trôi mất thì danh sách quay lại đúng thứ mà bảng cũ làm sai — không biết
   đang đọc năm nào. Dính vào ngay dưới thanh menu lúc cuộn, cùng số với .rtabs. */
.yrtagin{position:sticky;top:calc(var(--hdr-stuck) + 16px);display:block}
.yrtagin b{display:block;font-size:clamp(1.5rem,2.1vw,2rem);font-weight:800;line-height:1;
  letter-spacing:-.03em;color:var(--ink);font-variant-numeric:tabular-nums}
.yrc{display:block;margin-top:7px;font-size:.74rem;font-weight:600;letter-spacing:.05em;
  text-transform:uppercase;color:var(--muted)}
.yrc i{font-style:normal}
.yritems{list-style:none;margin:0;padding:0;min-width:0}
/* Ba cột: [ngành] [phạm vi] [mũi tên]. Tên dự án nằm hàng trên và trùm hai cột
   đầu, mũi tên trùm cả hai hàng ở mép phải.
   Cột ngành GHIM 168px chứ không auto: để auto thì mỗi dòng một mép, hai mươi
   hai dòng phạm vi thành một rìa răng cưa và mất luôn cái để quét dọc. 168px
   vừa chuỗi dài nhất của cả hai ngôn ngữ ("Công nghiệp quá trình",
   "Refrigeration equipment") ở cỡ chữ này. Canh cột rồi thì KHÔNG cần dấu chấm
   ngăn cách — bản thân chuỗi phạm vi đã dùng "·" bên trong, thêm một dấu nữa là
   không đọc ra ngành hết ở đâu. */
.yritem{position:relative;display:grid;grid-template-columns:168px 104px minmax(0,1fr) 20px;
  column-gap:18px;row-gap:3px;padding:12px 20px;transition:background .18s}
.yritem + .yritem{border-top:1px solid var(--line)}
.yritem[hidden]{display:none}
.yritem:hover{background:var(--bg-soft)}
.yrt{grid-column:1/4;grid-row:1;color:var(--brand);font-weight:600;font-size:1rem;line-height:1.45}
/* Cả dòng bấm được: lớp phủ trong suốt của chính thẻ <a>, đúng lối đã dùng ở
   .pjcard-body .more khổ dọc. Ngón tay không phải nhắm trúng chữ. */
.yrt::before{content:"";position:absolute;inset:0}
/* Đang sửa tại chỗ thì lớp phủ nuốt mọi cú bấm vào hai span bên dưới nó. */
body.cw-editing .yrt::before{content:none}
/* Tên dự án màu thương hiệu, cùng màu với h3 của thẻ .pjcard ở trên: từng để
   màu mực cho nhẹ, nhưng khi hàng dưới đã nhạt hết thì tiêu đề màu mực vẫn
   chìm — không có gì nói "đây là mục chính của dòng". Mũi tên đặt trên <li>
   chứ không trên <a> để nét gạch chân lúc rê chuột không ăn vào nó. */
.yritem::after{content:"→";grid-column:4;grid-row:1/3;align-self:center;justify-self:end;
  color:var(--muted);opacity:0;line-height:1;
  transition:opacity .18s,color .18s,transform .18s}
.yritem:hover .yrt{color:var(--brand-mid);text-decoration:underline;text-underline-offset:3px}
.yritem:hover::after{opacity:1;color:var(--brand);transform:translateX(3px)}
/* Chạm cũng bắn ra :hover và trạng thái dính lại tới lần chạm sau — một dòng tô
   nền xám giữa danh sách trông như đang chọn. Bọc ngược bằng any-hover:none,
   KHÔNG bọc luật trên trong hover:hover (xem chú thích ở khối rê chuột chung). */
@media(any-hover:none){
  .yritem:hover{background:transparent}
  .yritem:hover .yrt{color:var(--brand);text-decoration:none}
  .yritem::after,.yritem:hover::after{opacity:.5;color:var(--muted);transform:none}
}
/* Hàng dưới tiêu đề là MỘT tầng phụ, toàn bộ màu nhạt: chỉ tiêu đề mang màu mực.
   Đã thử ngành dạng huy hiệu có viền và nền — nó tranh mắt với tiêu đề ngay bên
   trên (22 ô tô liền nhau nặng hơn 22 dòng chữ). Ngành giờ là chữ hoa nhỏ giãn
   cách, đủ khác giọng để quét dọc theo cột mà không thành khối. Quốc gia tách
   khỏi tên dự án thành cột riêng (trước nằm cuối tiêu đề trong ngoặc, dòng
   nào cũng dài thêm một đuôi giống nhau). Mũi tên chỉ hiện khi rê chuột — 22
   mũi tên mờ xếp dọc là một cột nhiễu. */
.yrind{grid-column:1;grid-row:2;font-size:.72rem;font-weight:600;letter-spacing:.06em;
  text-transform:uppercase;color:var(--muted);white-space:nowrap;align-self:baseline}
.yrloc{grid-column:2;grid-row:2;font-size:.82rem;color:var(--muted);white-space:nowrap;align-self:baseline}
.yrloc:empty{display:none}
.yrsc{grid-column:3;grid-row:2;font-size:.82rem;color:var(--muted);min-width:0;align-self:baseline}

/* Khổ hẹp: rãnh năm lật thành thanh ngang dính ở đỉnh, dòng dự án xếp ba tầng.
   Đây là chỗ bảng cũ hỏng — giờ mọi chữ đều nằm trong bề ngang màn hình. */
@media(max-width:720px){
  .yrgrp{grid-template-columns:minmax(0,1fr)}
  .yrtag{border-right:0;border-bottom:1px solid var(--line);padding:8px 16px;
    position:sticky;top:var(--hdr-stuck);z-index:2}
  .yrgrp:first-child .yrtag{border-radius:calc(var(--r) - 1px) calc(var(--r) - 1px) 0 0}
  .yrgrp:last-child .yrtag{border-radius:0}
  .yrtagin{position:static;display:flex;align-items:baseline;justify-content:space-between;gap:12px}
  .yrtagin b{font-size:1.16rem}
  .yrc{margin-top:0}
  .yritem{grid-template-columns:auto minmax(0,1fr) 20px;column-gap:10px;padding:11px 16px}
  /* Tên dự án và phạm vi lấy TRỌN bề ngang; mũi tên nép vào mép phải của dòng
     ngành — dòng ngắn nhất trong ba tầng. Để mũi tên chiếm một cột riêng suốt cả
     ba tầng thì ở 390px nó ăn mất 32px của tên dự án, đủ để đẩy thêm một dòng. */
  .yrt{grid-column:1/-1;grid-row:1}
  .yrind{grid-column:1;grid-row:2;margin-top:2px}
  .yrloc{grid-column:2;grid-row:2;margin-top:2px}
  .yrsc{grid-column:1/-1;grid-row:3}
  .yritem::after{grid-column:3;grid-row:2;align-self:center}
}

/* Số cột theo bề ngang. Khuôn thẻ KHÔNG đổi giữa các khổ — chỉ lưới đổi.
   Ngưỡng đặt theo bề ngang MỘT Ô chứ không theo mốc thiết bị: dưới ~280px thì
   nhãn hai chữ dưới mỗi con số KPI vỡ thành bốn dòng, nên bớt một cột ngay
   trước lúc đó (4 cột tới 1200px, 3 cột tới 1000px, 2 cột tới 720px). */
@media(max-width:1200px){
  .pjgrid{grid-template-columns:repeat(3,minmax(0,1fr))}
  /* Ô rộng ra thì nhãn KPI ngắn lại đúng một dòng: đo ở 1119px và 929px, không
     nhãn nào của hai ngôn ngữ quá 3 dòng. Giữ chỗ 4 dòng ở đây chỉ là chừa
     trắng, nên hạ một nấc — vẫn cố định, nên dải vẫn cao đều khắp lưới. */
  .pjcard-kpi{grid-template-rows:calc(2 * 1.05rem * 1.18) calc(3 * .76rem * 1.4)}
  .pjcard .pjkpi span{-webkit-line-clamp:3;line-clamp:3}
}
@media(max-width:1000px){
  .pjgrid{grid-template-columns:repeat(2,minmax(0,1fr))}
}
@media(max-width:720px){
  .pjgrid{grid-template-columns:minmax(0,1fr)}
  /* Một cột thì thẻ rộng bằng cả màn hình — tiêu đề lên lại một nấc cho cân với
     bề ngang đó. Giá trị KPI đi kèm một nấc ở cuối file (media query không cộng
     độ ưu tiên nên .pjkpi b phải đặt sau khối thang sắc độ). */
  .pjcard h3{font-size:1.28rem}
  .pjcard-body{padding:18px 20px 16px}
  /* Một cột thì thẻ rộng bằng màn hình: meta luôn gọn một dòng, nhãn KPI một tới
     hai dòng. Giữ chỗ 2 dòng meta / 3 dòng nhãn ở đây chỉ là đục ba lỗ trắng
     trong mỗi thẻ — trả các hàng về co theo chữ. Thẻ xếp dọc nên chẳng có thẻ
     nào bên cạnh để so le với. */
  .pjcard-body .meta{min-height:0}
  .pjcard-kpi{grid-template-rows:auto auto;column-gap:22px;padding:14px 20px 16px}
  .pjcard .pjkpi span{font-size:.79rem}
  .pjrow{flex-direction:column;gap:7px;padding:6px 0}
  .pjlab{flex:none;padding-top:0}
  .pjfoot{padding-left:0}
}
/* Khổ điện thoại: chip nhỏ lại một nấc. KHÔNG cho hàng chip cuộn ngang như .rtabs
   — tab thì mở tab đầu là đủ dùng, còn bộ lọc mà giấu bớt lựa chọn thì người ta
   không biết là lọc được theo cái đó. Thà chịu vài hàng cao hơn còn hơn giấu.
   Đo ở 390px: bộ lọc từ 381px xuống còn ~285px, mọi lựa chọn vẫn thấy hết.
   Chip vẫn cao 34px — trên mức 24px mà WCAG 2.5.8 đòi cho ô chạm. */
@media(max-width:620px){
  .pjchips{gap:7px}
  .pjchip{font-size:.82rem;padding:8px 12px;gap:7px}
  .pjn{font-size:.68rem;min-width:18px;height:18px}
}

/* ---------- trang case study: mạch kể + dải bằng chứng ----------
   Cột trái kể chuyện, cột phải giữ bằng chứng trong tầm mắt suốt lúc đọc. Khác
   .artgrid của bài viết ở chỗ cột phải rộng 400px chứ không 300px: thứ nằm đó
   là ảnh trường vận tốc/nhiệt độ, 300px thì nhìn ra màu chứ không nhìn ra cái
   gì. */
.csgrid{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,400px);
  gap:clamp(30px,3.6vw,54px);counter-reset:cssec}
/* sticky đặt trên phần tử BÊN TRONG ô lưới, không phải trên chính ô: ô lưới cao
   bằng cả hàng (align-items mặc định là stretch) nên bên trong mới có chỗ trượt.
   Đặt sticky thẳng lên ô lưới thì ô cao đúng bằng nội dung và không trượt gì cả. */
.csrail-in{position:sticky;top:calc(var(--hdr) + 18px)}
.csrail-in > *{margin-top:0}
.csrail-in > * + *{margin-top:16px}

/* Số mục do CSS đếm, không khai trong layout: trang không có mục "Giá trị" vẫn
   chạy 01–02–03 liền mạch.
   counter-reset nằm ở .csgrid chứ KHÔNG ở .csbody: dưới 1024px .csbody là
   display:contents, mà phần tử không sinh hộp thì counter-reset bị bỏ qua. Khi
   đó `counter-increment` ở mỗi h2 không thấy bộ đếm nào trong tầm, nên tự tạo
   một bộ đếm riêng phạm vi ĐÚNG CÁI H2 ẤY — bốn mục cùng in "01". .csgrid sinh
   hộp ở cả hai bố cục (grid ở desktop, flex ở màn hẹp) nên là chỗ neo an toàn. */
.cssec + .cssec{margin-top:clamp(28px,3.2vw,42px);padding-top:clamp(28px,3.2vw,42px);
  border-top:1px solid var(--line)}
/* Cùng thang chữ với tiêu đề mục giữa bài viết (.artmain h2): h2 toàn cục tới
   37px, dùng ở đây là mỗi mục thành một đầu section rời rạc. */
.cssec > h2{counter-increment:cssec;display:flex;align-items:baseline;gap:14px;
  font-size:clamp(1.4rem,2.1vw,1.75rem);margin:0 0 14px}
.cssec > h2::before{content:counter(cssec,decimal-leading-zero);flex:0 0 auto;
  font-size:.76rem;font-weight:800;letter-spacing:.1em;color:var(--brand)}
.cssec p{line-height:1.75}
.cssec > :last-child{margin-bottom:0}
.csnote{color:var(--muted);font-size:.88rem;margin-top:16px}

/* Bảng thông tin dự án: nhãn cột trái, giá trị cột phải — cùng lối trình bày
   với .tbl nhưng gọn trong thẻ hẹp. */
.csfacts dl{margin:0}
/* 92px = đủ cho nhãn dài nhất ("ĐỐI TƯỢNG") nằm gọn một dòng ở cả hai ngôn ngữ;
   hẹp hơn là nhãn xuống dòng còn giá trị thì không, hai cột lệch nhau. */
.csfacts dl > div{display:grid;grid-template-columns:minmax(0,92px) minmax(0,1fr);
  gap:14px;padding:9px 0;border-top:1px solid rgba(44,42,41,.14)}
.csfacts dl > div:first-child{border-top:0;padding-top:0}
.csfacts dl > div:last-child{padding-bottom:0}
.csfacts dt{font-size:.72rem;letter-spacing:.06em;text-transform:uppercase;
  color:var(--muted);font-weight:700;padding-top:2px}
.csfacts dd{margin:0;font-size:.92rem;line-height:1.55}

.csfig-more > * + *{margin-top:16px}

/* ---------- lưới ảnh dự án ----------
   Bốn ô một hàng; dưới 900px là 2×2 chứ không phải bốn ô teo lại còn 160px.
   Ngưỡng 900 chứ không phải 620 như các lưới khác của site: bốn ô 4:3 xếp
   ngang ở 800px chỉ còn ~185px mỗi ô, nhỏ hơn cả thẻ ảnh nhỏ nhất đang có. */
.csgal{display:grid;grid-template-columns:repeat(4,1fr);gap:16px}
.csgal figure{margin:0}
/* Phóng nhẹ khi rê chuột: .imgbox đã overflow:hidden nên ảnh nở ra trong khung.
   KHÔNG bọc trong @media(hover:hover) — nhiều máy để bàn khai any-pointer thô
   và sẽ mất sạch hiệu ứng (xem ghi chú ở .card). */
.csgal .imgbox img{transition:transform .45s ease}
.csgal figure:hover .imgbox img{transform:scale(1.045)}
@media(max-width:900px){
  .csgal{grid-template-columns:repeat(2,1fr);gap:12px}
}

/* ---------- một cột: xen ảnh vào giữa mạch kể ----------
   Dưới 1024px cột phải hết chỗ đứng. Đổ nguyên dải bằng chứng xuống sau mạch kể
   là điện thoại mở trang ra chỉ thấy chữ, cuộn hết bốn mục mới tới tấm ảnh đầu
   tiên — với case study thì ảnh CHÍNH LÀ bằng chứng, để ở đáy coi như không có.

   display:contents gỡ ba lớp bọc (.csbody, .csrail, .csrail-in) khỏi cây hộp,
   nên mọi mục chữ và mọi cụm ảnh thành con trực tiếp của .csgrid và xếp lại
   được bằng order. Nhờ vậy chỉ có MỘT bản HTML cho cả hai bố cục — không có
   khối nào lặp lại để rồi ẩn đi một bản.

   Thứ tự đọc trên màn hẹp:
     ảnh dẫn → thông tin dự án → bối cảnh → cách tiếp cận → kết quả
     → ảnh còn lại → giá trị → ghi chú bảo mật
   Ảnh đứng TRƯỚC bảng thông tin: dải bốn con số phía trên đã cao gần 400px trên
   điện thoại, đặt bảng trước nữa là ảnh bị đẩy khỏi màn thứ hai.
   Cùng ngưỡng với .artgrid để hai loại trang dài của site gãy ở một chỗ. */
@media(max-width:1024px){
  /* 860px = bề rộng ảnh trong bài viết: trên tablet cột chữ không kéo dài hết
     trang, ảnh cũng không phình theo. */
  /* Khoảng cách bằng gap chứ không bằng margin: gap tính theo thứ tự NHÌN THẤY
     nên không phải đi tìm "phần tử nào đang đứng đầu" để bỏ lề trên — mà phần
     tử đó thì đổi theo việc trang có ảnh hay không. */
  .csgrid{display:flex;flex-direction:column;gap:clamp(26px,6vw,34px);
    max-width:860px;margin-inline:auto}
  .csbody,.csrail,.csrail-in{display:contents}
  .csrail-in{position:static}

  .csfig-lead{order:1}
  .csfacts{order:2}
  .cs-context{order:3}
  .cs-approach{order:4}
  .cs-results{order:5}
  .csfig-more{order:6}
  .cs-value{order:7}
  .csrail-in > .notecard{order:8}

  /* order đổi thứ tự NHÌN THẤY chứ không đổi thứ tự DOM, nên `.cssec + .cssec`
     ở trên không còn chỉ đúng chỗ nữa — đặt vạch ngăn thẳng lên từng mục. Mục
     nào cũng có vạch: mục đầu tiên đứng ngay sau bảng thông tin nên vẫn cần. */
  .csbody > .cssec,.csrail-in > *{margin-top:0}
  .csbody > .cssec{padding-top:clamp(26px,6vw,34px);border-top:1px solid var(--line)}
}

/* ---------- câu chuyện khách hàng (customer-story.njk) ----------
   TRANG DUY NHẤT ĐƯỢC PHÉP RA NGOÀI HỆ PHẲNG một-màu của site. Ngôn ngữ thị
   giác lấy theo bản tham chiếu cfdways.com/vi/khach-hang/cau-chuyen-khach-hang
   và được người dùng chọn sau khi xem ba phương án (23/08/2026): GRADIENT xanh
   thương hiệu → lục lam, chữ trắng canh giữa, icon nét trắng trong hero, tấm
   con số trắng nổi có bóng. Lý do trang này được phá hệ: nó là tài liệu bán
   hàng gửi cho khách tiềm năng đọc, không phải trang tra cứu kỹ thuật.
   Mọi luật dưới đây bó trong tiền tố .cst-, không luật nào dùng selector trần,
   nên bố cục này không rò sang trang khác. */

/* Hai màu và một gradient CHỈ trang này có. Lục lam #14A8A8 là màu thứ hai
   duy nhất của site, sống ở đây và không đi đâu khác. Khai ở .cst-hero và các
   khối dùng nó chứ không ở :root, để biến không lọt ra ngoài. */
.cst-hero,.cst-cta,.cst-tm{
  --cst-teal:#14A8A8;
  --cst-grad:linear-gradient(100deg,rgba(31,78,136,.95) 0%,rgba(43,101,176,.88) 46%,rgba(20,168,168,.78) 100%);
  --cst-grad-solid:linear-gradient(100deg,#1F4E88 0%,#2B65B0 46%,#14A8A8 100%)}

/* ---- hero: gradient phủ ảnh, chữ trắng CANH TRÁI, hai cột ----
   Breadcrumb ở góc trên trái như mọi trang, rồi cột trái (logo, eyebrow, H1,
   câu dẫn) và cột phải (ba lợi ích xếp dọc). Bản canh giữa trước đó bị bác vì
   breadcrumb canh giữa đọc ra như một dòng tiêu đề phụ. */
.cst-hero{position:relative;isolation:isolate;background:var(--brand-mid);color:#fff;
  overflow:hidden;padding:clamp(26px,3.2vw,40px) 0 clamp(56px,6.5vw,88px)}
/* Có tấm số đi sau thì chừa đáy cho nó đè lên (margin âm ở .cst-statwrap). */
.cst-hero:has(+ .cst-statwrap){padding-bottom:clamp(110px,12vw,160px)}
/* Ảnh nền: .imgbox để ô ảnh này sửa được từ khu quản trị như mọi ảnh khác.
   Nền của .imgbox (xám nhạt) phải bị đè, không thì lúc ảnh chưa tải nó nháy
   một mảng sáng dưới chữ trắng. Giảm bão hoà để ảnh không đánh nhau với gradient. */
.cst-hero-bg{position:absolute;inset:0;z-index:-2;background:var(--brand-mid)}
.cst-hero-bg img{width:100%;height:100%;object-fit:cover;display:block;filter:saturate(.6)}
/* Ảnh hỏng/thiếu: .failed đã ẩn ảnh, ô giữ chỗ kẻ sọc ẩn nốt — còn lại gradient. */
.cst-hero-bg .ph{display:none}
.cst-hero::after{content:"";position:absolute;inset:0;z-index:-1;background:var(--cst-grad)}
.cst-hero-in{position:relative}
.cst-crumb{color:rgba(255,255,255,.82);margin-bottom:clamp(30px,4vw,52px)}
.cst-crumb a,.cst-crumb b{color:#fff}
.cst-crumb a:hover{color:#fff}
.cst-crumb > * + *::before{border-right-color:rgba(255,255,255,.5);border-bottom-color:rgba(255,255,255,.5)}
.cst-crumb .crumb-home svg,.cst-crumb .crumb-home:hover svg{stroke:#fff}
.cst-herogrid{display:grid;grid-template-columns:minmax(0,7fr) minmax(0,5fr);
  gap:clamp(30px,5vw,84px);align-items:center}
/* Logo khách trên tấm trắng nhỏ: giữ nguyên màu thật của logo. */
.cst-hero-logo{display:inline-block;background:#fff;border-radius:var(--r);padding:10px 16px;margin:0 0 22px}
.cst-hero-logo img{display:block;height:28px;width:auto}
/* eyebrow toàn cục màu thương hiệu — trên gradient xanh nó biến mất. */
.cst-hero .eyebrow{color:rgba(255,255,255,.86);margin:0 0 14px}
.cst-hero h1{color:#fff;font-size:clamp(2rem,3.6vw,2.9rem);letter-spacing:-.025em;line-height:1.12;
  margin:0 0 18px;max-width:22ch;text-wrap:balance}
.cst-hero-sub{color:rgba(255,255,255,.9);font-size:clamp(1rem,1.25vw,1.08rem);line-height:1.6;
  max-width:56ch;margin:0}

/* ---- ba lợi ích: cột phải, xếp dọc, icon nét trắng + một câu, vạch tóc ngăn ---- */
.cst-ben{display:flex;flex-direction:column}
.cst-ben-i{display:flex;align-items:center;gap:18px;padding:18px 0}
.cst-ben-i + .cst-ben-i{border-top:1px solid rgba(255,255,255,.28)}
.cst-ben-ic{display:flex;align-items:center;justify-content:center;flex:0 0 auto;
  width:56px;height:56px;border-radius:50%;background:rgba(255,255,255,.14)}
.cst-ben-ic svg{width:30px;height:30px;fill:none;stroke:#fff;stroke-width:1.4;
  stroke-linecap:round;stroke-linejoin:round}
.cst-ben-i h3{color:#fff;font-size:1.04rem;font-weight:500;line-height:1.45;margin:0;text-wrap:balance}

/* ---- tấm con số: trắng, NỔI, đè lên mép dưới hero ----
   Bóng đổ ở trạng thái nghỉ — ngoại lệ của site, có lý do: tấm bắc qua ranh
   giới gradient/nền sáng, không bóng thì nửa trên chìm vào gradient. Bóng pha
   xanh thương hiệu chứ không đen để hợp với dải gradient phía trên. */
.cst-statwrap{position:relative;z-index:1;margin-top:clamp(-80px,-7vw,-56px)}
.cst-stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));
  background:#fff;border-radius:10px;padding:clamp(24px,3vw,32px) clamp(16px,2.2vw,24px);
  box-shadow:0 18px 44px rgba(31,78,136,.22)}
.cst-stat{position:relative;text-align:center;padding:4px 14px}
.cst-stat + .cst-stat::before{content:"";position:absolute;left:0;top:6px;bottom:6px;width:1px;
  background:var(--line)}
.cst-stat .n{font-size:clamp(1.7rem,2.5vw,2.15rem);font-weight:600;color:var(--brand);
  line-height:1.05;letter-spacing:-.03em}
.cst-stat .l{font-size:.86rem;color:var(--muted);margin-top:6px;line-height:1.45;text-wrap:balance}

/* ---- chung cho các mục ---- */
.cst-kicker{font-size:.74rem;letter-spacing:.14em;text-transform:uppercase;
  color:var(--brand);font-weight:700;margin-bottom:10px}
/* Tiêu đề mục to hơn h2 giữa bài viết (1.75rem): ba mục là ba chương. */
.cst-text h2{font-size:clamp(1.5rem,2.4vw,2rem);margin:0 0 16px;letter-spacing:-.02em}
.cst-text p{line-height:1.8;font-size:1.02rem}
.cst-text > :last-child{margin-bottom:0}

/* ---- khách hàng: logo lớn canh giữa, đoạn giới thiệu in nghiêng ---- */
.cst-customer{--sec-pt:clamp(46px,5.6vw,72px)}
.cst-cust{text-align:center}
.cst-cust-logo img{display:inline-block;height:clamp(44px,4.2vw,58px);width:auto}
.cst-cust-name{margin:0}
.cst-cust-meta{font-size:.78rem;letter-spacing:.1em;text-transform:uppercase;color:var(--muted);
  font-weight:600;margin-top:16px}
.cst-cust-desc{font-style:italic;color:var(--muted);line-height:1.75;font-size:1.02rem;
  max-width:74ch;margin:16px auto 0}
.cst-cust-link{display:inline-block;margin-top:12px;font-size:.88rem;font-weight:600;color:var(--brand)}

/* ---- hàng hai cột của từng mục ----
   Cột ảnh rộng hơn cột chữ một chút (1.1fr / 1fr): hình ở đây là sơ đồ có chữ
   chú thích bên trong, cần bề ngang để đọc. Ảnh là tấm trắng có bóng — đứng
   trên nền trang #F7F7F7 nó nổi hẳn lên. */
.cst-grid{display:grid;align-items:center;gap:clamp(28px,4.4vw,64px)}
.cst-has-aside{grid-template-columns:minmax(0,1fr) minmax(0,1.1fr)}
.cst-aside-left .cst-text{order:2}
.cst-aside-left .cst-aside{order:1}
.cst-aside figure{margin:0}
.cst-aside .frame{background:#fff;box-shadow:0 16px 40px rgba(26,25,24,.12);border-radius:10px}
.cst-aside .imgbox{background:#fff}
/* Nền xanh nhạt tràn viền cho mục Giải pháp — nhịp sáng/nhạt/sáng như bản
   tham chiếu, nhưng là sắc xanh rất nhạt chứ không phải xám, để nối với hero. */
.cst-tint{background:#EDF1F6} /* sắc xanh nhấn chung của site (09/10/2026), xem .dt-band */

/* ---- lời khách hàng: thẻ GRADIENT với dấu ngoặc kép lớn ---- */
.cst-quotes{display:grid;gap:18px}
.cst-tm{position:relative;margin:0;background:var(--cst-grad-solid);color:#fff;border-radius:10px;
  padding:clamp(24px,2.8vw,32px) clamp(24px,3vw,34px) clamp(20px,2.4vw,26px);
  display:flex;flex-direction:column;box-shadow:0 16px 40px rgba(31,78,136,.22)}
.cst-tm-mark{position:absolute;right:22px;top:-6px;font-size:6rem;line-height:1;font-weight:700;
  color:rgba(255,255,255,.22);font-family:Georgia,"Times New Roman",serif;pointer-events:none}
.cst-tm blockquote{margin:0;position:relative}
.cst-tm p{color:#fff;font-size:1.04rem;line-height:1.65;margin:0 0 20px;font-weight:400}
.cst-tm-who{margin-top:auto;display:flex;align-items:center;gap:14px;padding-top:14px;
  border-top:1px solid rgba(255,255,255,.28)}
/* Logo khách trên gradient: tấm trắng nhỏ để giữ màu thật. */
.cst-tm-logo{display:block;height:18px;width:auto;background:#fff;border-radius:4px;
  padding:5px 8px;box-sizing:content-box;flex:0 0 auto}
.cst-tm-who b{display:block;font-size:.94rem;color:#fff;font-weight:700}
.cst-tm-who i{display:block;font-style:normal;font-size:.82rem;color:rgba(255,255,255,.8)}

/* ---- CTA: dải gradient tràn viền ---- */
.cst-cta{background:var(--cst-grad-solid);color:#fff;padding:clamp(34px,4.4vw,54px) 0}
.cst-cta-in{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:30px;align-items:center}
.cst-cta h2{color:#fff;font-size:clamp(1.3rem,2vw,1.7rem);letter-spacing:-.015em;margin:0 0 6px}
.cst-cta p{color:rgba(255,255,255,.88);margin:0;max-width:70ch}
.cst-cta-btn{background:#fff;color:var(--brand-mid);border-color:#fff;font-weight:700;
  padding:14px 26px;white-space:nowrap}
.cst-cta-btn:hover{background:#fff;color:var(--brand);box-shadow:0 10px 24px rgba(0,0,0,.18)}

/* ---- webinar: nền trang, khung video 16:9 có bóng ---- */
.cst-video .cst-text p{max-width:56ch}
.cst-frame{position:relative;aspect-ratio:16/9;border-radius:10px;overflow:hidden;background:#000;
  box-shadow:0 16px 40px rgba(26,25,24,.16)}
.cst-frame iframe{position:absolute;inset:0;width:100%;height:100%;border:0;display:block}

/* ---- màn hẹp ---- */
@media(max-width:900px){
  .cst-hero{padding:clamp(18px,4vw,26px) 0 clamp(40px,7vw,56px)}
  .cst-hero:has(+ .cst-statwrap){padding-bottom:clamp(76px,11vw,96px)}
  .cst-crumb{margin-bottom:22px}
  .cst-herogrid{grid-template-columns:1fr;gap:26px}
  .cst-hero h1{max-width:none}
  .cst-ben{border-top:1px solid rgba(255,255,255,.28);padding-top:6px}
  .cst-ben-i{gap:14px;padding:13px 0}
  .cst-ben-ic{width:44px;height:44px}
  .cst-ben-ic svg{width:24px;height:24px}
  .cst-ben-i h3{font-size:.98rem}
  .cst-statwrap{margin-top:clamp(-48px,-7vw,-36px)}
  .cst-stats{grid-template-columns:repeat(2,1fr);gap:18px 0}
  /* Vạch ngăn dọc chỉ đúng khi các ô cùng hàng; xếp 2×2 thì bỏ. */
  .cst-stat + .cst-stat::before{display:none}
  .cst-has-aside{grid-template-columns:1fr;max-width:860px;margin-inline:auto}
  /* Ảnh đứng TRƯỚC chữ — hình là bằng chứng, không đẩy xuống đáy mục. */
  .cst-aside-left .cst-text,.cst-aside-right .cst-text{order:2}
  .cst-aside-left .cst-aside,.cst-aside-right .cst-aside{order:1}
  /* Riêng mục Kết quả thì ngược lại: lời khách hàng là phần kết, không đọc trước. */
  .cst-results .cst-text{order:1}
  .cst-results .cst-aside{order:2}
  .cst-cta-in{grid-template-columns:1fr;gap:18px}
  .cst-cta-btn{justify-self:start}
}


/* ---------- trang bài viết: cột chữ + thanh bên phải ---------- */
.artgrid{display:grid;grid-template-columns:minmax(0,1fr) 300px;gap:56px;align-items:start}
/* Cột bài viết chiếm hết bề rộng lưới cho được: có cột phải thì 1fr, không có
   thì .artwide mở bằng đúng H1. Không còn giới hạn bề rộng đọc, cũng không còn
   vạch kéo để nới — một bề rộng duy nhất, giống nhau ở mọi bài. */
.artmain p{line-height:1.75}
/* h2 toàn cục nay tới 37px — đúng cho đầu section trang chủ, nhưng làm tiêu đề
   mục GIỮA BÀI ĐỌC nặng gấp hơn hai lần thân chữ, chặt bài thành từng mảnh rời.
   Cột bài dùng thang riêng, nhỏ hơn nhưng vẫn cách xa cỡ thân chữ. */
.artmain h2,.artcol h2{font-size:clamp(1.4rem,2.1vw,1.75rem);margin-top:42px}
.artmain h3,.artcol h3{font-size:1.18rem;margin-top:28px}
.artmain figure{margin:22px auto} /* ảnh thu nhỏ vẫn nằm chính giữa cột */
.artlead > p:first-of-type{font-size:1.05rem}
/* ---------- công thức trong bài ----------
   Bài không nạp KaTeX/MathJax: công thức viết thẳng bằng sub/sup rồi mượn font
   toán CÓ SẴN TRONG MÁY để lấy đúng dáng chữ sách giáo khoa. Cambria Math và
   STIX Two Math là hai font toán chuẩn có sẵn trên Windows/macOS; không có thì
   rơi về Times — vẫn serif, vẫn khác hẳn thân bài Noto Sans nên vẫn đọc ra ngay
   là phép tính. Đây là chỗ DUY NHẤT của site dùng serif, và đó là chủ ý.
   Quy ước đánh dấu: <i> bọc ký hiệu chữ (biến, đơn vị) để in nghiêng; chữ số và
   dấu phép tính để trần nên đứng thẳng — đúng lối sắp chữ toán. */
.artmain .eq,.artcol .eq{margin:22px 0;text-align:center;overflow-x:auto;
  font-family:"Cambria Math","STIX Two Math",Cambria,"Times New Roman",serif;
  font-size:1.22rem;line-height:1.85}
.artmain .eq i,.artcol .eq i{font-style:italic}
/* sub/sup mặc định của trình duyệt là .83em — quá to so với thân công thức đã
   phóng lên 1.22rem, chỉ số trông như ký tự chính.
   padding-right = "italic correction": chữ nghiêng nhô sang phải quá bề rộng ô
   chữ của nó, nên chỉ số nghiêng đâm vào ký tự đứng liền sau (p_tQ_v dính thành
   một cục). Máy sắp chữ toán tự chèn khoảng bù này; HTML thì phải tự thêm. */
.artmain .eq sub,.artmain .eq sup,.artcol .eq sub,.artcol .eq sup{
  font-size:.68em;padding-right:.1em}

/* dòng tác giả · ngày · lượt xem, kẻ ngăn trên dưới như bản in */
.byline{display:flex;align-items:center;justify-content:space-between;gap:14px;flex-wrap:wrap;
  border-top:1px solid var(--line);border-bottom:1px solid var(--line);
  padding:12px 2px;margin-bottom:26px}
.byline .who{margin:0;font-size:.9rem;color:var(--muted)}
.byline .who b{color:var(--ink);font-weight:700}
/* tin tức: cùng hàng nhưng không kẻ vạch, dòng meta đã đủ nhẹ */
.byline-plain{border:none;padding:0;margin-bottom:16px}
.byline-plain .meta{margin-bottom:0}
.views{display:inline-flex;align-items:center;gap:7px;font-size:.88rem;
  color:var(--muted);font-weight:500;white-space:nowrap}
.views svg{width:17px;height:17px;stroke:currentColor;fill:none;stroke-width:1.7;flex:0 0 auto}

/* mục lục ở thanh bên, sáng mục đang đọc khi cuộn */
/* max-width 300px = đúng bề rộng cột phải của bài blog (.artgrid). Thẻ mục lục
   còn nằm ở cột phải của tin tức nữa, mà cột đó là .g2 rộng nửa trang — không
   chặn thì cùng một thẻ lại to gấp đôi ở hai loại bài.
   margin-left:auto để thẻ ép sát mép phải của cột: mép phải thẻ thẳng hàng với
   mép phải H1 ở dải tiêu đề. Bài blog cột vốn đúng 300px nên không đổi gì. */
.toc{background:var(--bg-soft);border:0;border-radius:var(--r);padding:18px 18px 14px;
  max-width:300px;margin-left:auto;box-shadow:var(--lift)}
.toc h3{font-size:.72rem;letter-spacing:.13em;text-transform:uppercase;color:var(--muted);
  font-weight:800;margin:0 0 10px;display:flex;align-items:center;gap:8px}
.toc h3::before{content:'';width:16px;height:3px;border-radius:2px;background:var(--accent)}
.toc ol{list-style:none;margin:0;padding:0;counter-reset:toc}
.toc li{counter-increment:toc}
.toc a{display:flex;gap:9px;padding:7px 8px;font-size:.87rem;color:#33414e;
  border-radius:7px;line-height:1.45}
.toc a::before{content:counter(toc,decimal-leading-zero);font-weight:800;font-size:.7rem;
  color:var(--muted);padding-top:3px;flex:0 0 auto}
.toc a:hover{background:var(--bg-soft);color:var(--brand);text-decoration:none}
.toc a.on{color:var(--brand);font-weight:700;background:var(--bg-soft)}
.toc a.on::before{color:var(--accent)}

/* nút chia sẻ */
.sharebox{display:flex;align-items:center;gap:8px;margin-top:14px;flex-wrap:wrap}
.sharebox .lbl{font-size:.68rem;letter-spacing:.13em;text-transform:uppercase;
  color:var(--muted);font-weight:800;margin-right:2px}
.share{width:34px;height:34px;border-radius:50%;border:1px solid var(--line);background:#fff;
  display:inline-flex;align-items:center;justify-content:center;color:#33414e;
  font-size:.82rem;transition:background .15s,color .15s,border-color .15s}
.share b{font-weight:800}
.share svg{width:15px;height:15px;stroke:currentColor;fill:none;stroke-width:1.9;stroke-linecap:round}
.share:hover{background:var(--brand);border-color:var(--brand);color:#fff;text-decoration:none}
.share.done{background:#1a9e5f;border-color:#1a9e5f;color:#fff}

.railcard{background:var(--bg-soft);border:0;border-radius:var(--r);
  padding:17px 20px 18px;margin-top:14px;box-shadow:var(--lift)}

@media(max-width:1024px){
  .artgrid{grid-template-columns:1fr;gap:30px}
  .artgrid .sidesticky{position:static}
  .toc{display:none} /* màn hẹp: bài đọc tuần tự, mục lục bên phải không còn chỗ đứng */
}

/* Cột chữ của bài viết khi không có cột phụ: căn giữa, giới hạn bề rộng đọc.
   Ảnh và bảng trong bài được phép rộng hơn cột chữ để không bị bóp nhỏ. */
.artcol{max-width:74ch;margin-inline:auto;width:100%}
.artcol > figure,.artcol .tblwrap{width:min(100%,860px);margin-inline:auto}
/* Bài không có cột phải (không mục lục, không ảnh bìa, không bảng thông tin):
   cột chữ rộng đúng bằng H1 của dải tiêu đề phía trên, cho hai thứ thẳng hàng
   thay vì chữ nằm thụt vào giữa trang. */
.artcol.artwide{max-width:none}
@media(min-width:1100px){
  .artcol > figure,.artcol .tblwrap{width:860px;margin-left:calc((74ch - 860px) / 2)}
}
/* Lề âm ở trên tính theo cột 74ch — cột rộng thì phải bỏ, không ảnh sẽ thò hẳn
   ra ngoài mép trái. Đặt sau @media để thắng luật trong đó. */
.artcol.artwide > figure,.artcol.artwide .tblwrap{width:min(100%,860px);margin-inline:auto}

/* Cột phụ bám theo khi cuộn — bài dài thì cột phải không bị trống hoác.
   Cần .g2 có align-items:start, nếu không phần tử bị kéo cao bằng cột kia. */
.sidesticky{position:sticky;top:calc(var(--hdr) + 18px)}
@media(max-width:620px){.sidesticky{position:static}}
/* Ảnh cột phải tụt xuống ngang DÒNG CHỮ ĐẦU TIÊN của cột trái, không dính lên
   đỉnh <h2>. Đúng bằng chiều cao một dòng h2 (1.22) cộng lề dưới của nó (.5em),
   tính theo chính cỡ chữ h2 nên co giãn cùng thang chữ. Dưới 620px .g2 rơi về
   một cột và ảnh xuống dưới chữ — lúc đó không còn gì để căn. */
.figdrop{margin-top:calc(clamp(1.25rem,1.9vw,1.6rem) * 1.72)}
@media(max-width:620px){.figdrop{margin-top:0}}
.listclean{list-style:none;padding:0;margin:0}
.listclean li{padding:9px 0 9px 26px;position:relative;border-bottom:1px solid var(--line);font-size:.94rem}
.listclean li::before{content:"";position:absolute;left:2px;top:17px;width:9px;height:9px;border-radius:2px;background:var(--accent)}
/* Gạch dưới mục cuối không ngăn cách gì cả — để lại thì danh sách đọc như bảng bị cắt cụt */
.listclean li:last-child{border-bottom:none}
/* .listclean nằm trong tấm .toplist: trả <li> về block. `.toplist li` là flex —
   đúng cho danh sách ĐÁNH SỐ của chính nó (ô số | nội dung), nhưng khi ruột là
   .listclean thì <b> tên mục thành một ô flex còn phần "— mô tả" thành ô thứ
   hai: hai cột hẹp cùng xuống dòng, đọc ra như bảng hai cột bị vỡ chứ không
   phải một dòng chữ. Chỉ cần trả display, các luật còn lại của .listclean
   (đệm, vạch ngăn, ô vuông ::before) đều đã thắng nhờ đứng sau trong file. */
.toplist .listclean li{display:block}
/* Dòng link phụ dưới khối ngành: nhỏ và nhạt hơn link chính, để hai dòng liền nhau
   không đọc thành hai hàng nút ngang cấp */
.sublinks{margin-top:6px;font-size:.87rem;color:var(--muted)}
.sublinks .more{color:var(--muted);font-weight:600}
.sublinks .more:hover{color:var(--brand)}
.tbl{width:100%;border-collapse:collapse;font-size:.93rem;background:#fff}
.tbl th{background:var(--bg-soft);text-align:left;font-size:.75rem;letter-spacing:.08em;text-transform:uppercase;
  color:var(--muted);font-weight:800}
.tbl th,.tbl td{padding:13px 16px;border:1px solid var(--line);vertical-align:top}
.tblwrap{overflow-x:auto;border-radius:var(--r);border:1px solid var(--line);box-shadow:var(--lift)}
.tblwrap .tbl{border:none}
/* .tblwrap có overflow-x:auto sẵn, nhưng nó KHÔNG bao giờ chạy: .tbl là width:100%
   nên bảng tự co lại vừa khung thay vì tràn ra. Ở 390px, bảng 4 cột co thành bốn
   dải chữ dựng đứng — một ô "Điều phối dự án · tối ưu thiết kế" vỡ thành 6 dòng,
   cả bảng 3 hàng cao tới 617px. Ghim bề rộng tối thiểu thì bảng mới thật sự tràn
   và cuộn ngang được.
   Đặt trên lớp .tbl-min chứ không lên .tbl: cùng lỗi này còn ở doi-ngu, phan-mem,
   dich-vu và khối bảng của trình soạn thảo — sửa chung là đổi bố cục bốn trang
   chưa xem, nên chỉ bật cho bảng đã kiểm ở đây.
   HIỆN KHÔNG TRANG NÀO GẮN .tbl-min: hai chỗ từng dùng (du-an, projects) đã đổi
   sang danh sách gộp theo năm (.yrlist ở trên) — cuộn ngang là thứ bản đó bỏ đi
   chứ không phải thứ nó cần. Giữ luật lại vì bốn trang kể trên vẫn còn nguyên
   lỗi và đây là cách vá đã kiểm; gắn class vào là chạy. */
@media(max-width:720px){
  .tblwrap .tbl-min{min-width:580px}
}
/* Cột SỐ trong bảng: hẹp lại, căn phải, chữ số đều bề ngang. Không có luật này
   thì con số nằm dính mép trái của một cột rộng bằng cả cái tiêu đề cột ("Lượt
   trích dẫn"), và hàng chục con số không thẳng được một mép nào để so sánh —
   mà so sánh chính là việc duy nhất người ta làm với một cột số. Cùng cách với
   .pub-y/.pub-c ở danh mục công bố. Gắn class vào CẢ <th> lẫn <td> của cột đó. */
.tbl .num{text-align:right;font-variant-numeric:tabular-nums;white-space:nowrap;width:120px}
/* ---------- bảng XẾP HẠNG (.tbl-rank): mười tạp chí ở Đội ngũ, VI+EN ----------
   Danh sách để đọc lướt chứ không phải lưới để tra ô: bỏ khung, bóng, kẻ dọc và
   nền tô của .tbl; còn vạch tóc ngang, một vạch đậm dưới tiêu đề và dưới hàng
   cuối. Số thứ hạng vẽ bằng counter (không thêm cột trong HTML). Cột trích dẫn
   là khóa xếp hạng nên đậm, cột số bài nhạt.
   .rankrow: bảng một cột, ghi chú nguồn số liệu một cột hẹp bên phải — bảng trải
   cả 1300px thì tên tạp chí và con số cách nhau cả màn, còn bảng hẹp đứng một
   mình thì bỏ trống nửa phải. Dưới 900px ghi chú tụt xuống dưới bảng. */
.rankrow{display:grid;grid-template-columns:minmax(0,1fr) 300px;gap:64px;align-items:start}
.rank-note{margin:0;padding-top:30px;color:var(--muted);font-size:.88rem;line-height:1.65}
.rank-note .more{display:inline-block;margin-top:6px}
@media(max-width:900px){
  .rankrow{grid-template-columns:minmax(0,1fr);gap:16px}
  .rank-note{padding-top:0}
}
.tblwrap-rank{border:0;border-radius:0;box-shadow:none}
.tbl-rank{background:none;font-size:.94rem;counter-reset:rk}
.tbl-rank th,.tbl-rank td{border:0;border-bottom:1px solid var(--line);padding:11px 14px}
.tbl-rank th{background:none;padding-top:0;padding-bottom:9px;font-size:.72rem;letter-spacing:.1em;font-weight:700;
  border-bottom-color:var(--ink)}
.tbl-rank tr:last-child td{border-bottom-color:var(--ink)}
/* Thụt treo: tên dài xuống dòng thì dòng sau thẳng mép tên, không chui dưới số hạng. */
.tbl-rank th:first-child,.tbl-rank td:first-child{padding-left:34px;text-indent:-34px}
.tbl-rank th:last-child,.tbl-rank td:last-child{padding-right:0}
.tbl-rank td:first-child::before,.tbl-rank th:first-child::before{display:inline-block;width:34px;
  text-indent:0;font-size:.82rem;color:var(--muted);font-variant-numeric:tabular-nums}
.tbl-rank th:first-child::before{content:"#"}
.tbl-rank td:first-child::before{counter-increment:rk;content:counter(rk,decimal-leading-zero)}
.tbl-rank td.num{color:var(--muted)}
.tbl-rank td.num:last-child{color:var(--ink);font-weight:700}
@media(max-width:620px){
  .tbl-rank .num{width:auto}
  .tbl-rank th.num{white-space:normal;line-height:1.35}
  .tbl-rank th.num:last-child{width:84px} /* "LƯỢT TRÍCH DẪN" một dòng ăn mất cột tên */
  .tbl-rank th,.tbl-rank td{padding-left:8px;padding-right:8px}
  .tbl-rank th:first-child,.tbl-rank td:first-child{padding-left:28px;text-indent:-28px}
  .tbl-rank td:first-child::before,.tbl-rank th:first-child::before{width:28px}
}
/* Khối Simcenter X (#simcenter-x) nằm chung section với License & Dịch vụ đi kèm,
   trước hàng nút báo giá — để nhịp sec/sec-soft của trang không bị hai dải cùng
   màu đứng liền nhau. Một vạch tóc tách nó khỏi hai cột phía trên. Danh sách
   trong thẻ: nhãn đậm đầu dòng là chỗ mắt bám, nên bỏ chấm tròn và thụt lề. */
.sx{margin-top:56px;padding-top:48px;border-top:1px solid var(--line);scroll-margin-top:90px}
.sx .card ul{list-style:none;padding:0;margin:4px 0 0;border-top:1px solid var(--line)}
.sx .card li{margin:0;padding:9px 0;border-bottom:1px solid var(--line);line-height:1.55}
.sx .card li:last-child{border-bottom:0;padding-bottom:0}
/* Hai gói Simcenter X là khối gập .mstack trên điện thoại (08/10/2026, người dùng
   chọn A). `.sx .card ul{margin:4px 0 0}` ở trên đè lề 16px của .mrow-in > * —
   nhắc lại lề cho ul, không thì gạch đầu dòng dính sát mép trái khối. */
@media(max-width:620px){
  .sx .mstack .mrow-in > p{margin-bottom:8px}
  .sx .mstack .mrow-in > ul{margin:0 16px 16px}
}
/* ---------- bảng MA TRẬN gói × dịch vụ (.tbl-mx): Phần mềm Siemens, VI+EN ----------
   Cùng lối kẻ với .tbl-rank (vỏ .tblwrap-rank: không khung, không bóng). Ô "có"
   là dấu tích vẽ bằng ảnh nền, chữ "Trong gói" giữ lại cho trình đọc màn hình;
   ô tùy chọn ghi thẳng chữ nên không cần chú giải ký hiệu ●/○ bên dưới nữa.
   Tiêu đề cột viết thường, không giãn chữ: bản in hoa giãn 0.08em bẻ "PHẦN MỀM"
   thành hai dòng trong cột 17%. */
.tbl-mx{background:none;font-size:.93rem}
.tbl-mx th,.tbl-mx td{border:0;border-bottom:1px solid var(--line);padding:13px 10px;vertical-align:middle}
.tbl-mx th{background:none;padding-top:0;padding-bottom:10px;vertical-align:bottom;text-align:center;
  text-transform:none;letter-spacing:0;font-size:.82rem;line-height:1.35;font-weight:700;color:var(--muted);
  border-bottom-color:var(--ink)}
.tbl-mx th:first-child{text-align:left}
.tbl-mx th:first-child,.tbl-mx td:first-child{padding-left:0}
.tbl-mx th:last-child,.tbl-mx td:last-child{padding-right:0}
.tbl-mx td:first-child{font-weight:600}
.tbl-mx tr:last-child td{border-bottom-color:var(--ink)}
.tbl-mx .mk-y,.tbl-mx .mk-o{text-align:center;width:17%}
.tbl-mx .mk-y span{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
.tbl-mx .mk-y::before{content:"";display:inline-block;width:18px;height:18px;vertical-align:middle;
  background:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%232B65B0' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m4.5 12.5 5 5 10-11'/%3E%3C/svg%3E") no-repeat center/contain}
.tbl-mx .mk-o{font-size:.8rem;color:var(--muted)}
@media(max-width:620px){
  .tbl-mx th,.tbl-mx td{padding-left:6px;padding-right:6px}
  .tbl-mx td:first-child{font-size:.86rem}
  /* EN: "Deployment", "Maintenance" là một từ dài, không ngắt thì bảng tràn 405px.
     hyphens:auto không đủ (Chrome Windows thiếu từ điển ngắt) nên HTML có thêm &shy;. */
  .tbl-mx th{font-size:.74rem;hyphens:auto;-webkit-hyphens:auto}
  .tbl-mx th,.tbl-mx td{padding-left:4px;padding-right:4px}
}
/* ---------- bảng SO SÁNH (.tbl-cmp): bốn câu hỏi × ba dịch vụ ----------
   Bảng bốn cột trên điện thoại là bản vỡ nặng nhất của site này. Đo ở 390px
   trước khi sửa: ba cột nội dung còn ~85px mỗi cột, một ô "Nhà máy tiêu hao cao
   nhưng chưa xác định được khâu nào" vỡ thành MƯỜI dòng, mỗi dòng một hai chữ,
   cả bảng cao 1241px. Đọc theo hàng thì mắt phải nhảy qua ba dải chữ dựng đứng
   lệch nhau; đọc theo cột thì mất luôn câu hỏi ở đầu hàng.
   Cuộn ngang (.tbl-min ở trên) không cứu được: giấu hai phần ba bảng ra ngoài
   màn hình đúng chỗ người ta cần SO SÁNH ba dịch vụ với nhau.
   Dưới 860px bảng bỏ dạng lưới: mỗi HÀNG (một câu hỏi) thành một thẻ, trong thẻ
   là ba câu trả lời xếp dọc, mỗi câu mang tên dịch vụ của nó. Vẫn đúng một câu
   hỏi một thẻ nên so sánh vẫn nằm gọn trong tầm mắt, mà mỗi câu trả lời được
   trọn bề ngang màn hình — hai dòng thay vì mười.
   Tên dịch vụ lấy từ data-svc của chính ô đó (viết sẵn trong HTML nên không có
   JS vẫn đọc được; site.js chép lại từ hàng tiêu đề để bản sửa tại chỗ không
   làm nhãn lạc hậu). Hàng tiêu đề thật bị ẩn ở khổ này — tên cột đã nằm ngay
   trên từng câu trả lời rồi.
   Ngưỡng 860px chứ không phải 620px như .mstack: ba cột chữ cần nhiều bề ngang
   hơn ba thẻ, ở 768px (máy bảng dựng đứng) mỗi cột mới có ~200px và đã vỡ 5 dòng. */
@media(min-width:861px){
  /* Ba cột dịch vụ bằng nhau: table-layout:fixed chia đều phần còn lại sau cột
     nhãn. Để auto thì bề rộng cột chạy theo chữ trong ô — cột 1 rộng hơn cột 3
     tới 30px chỉ vì câu trả lời dài hơn, đọc ra như ba cột không ngang hàng. */
  .tbl-cmp{table-layout:fixed}
  .tbl-cmp tr:first-child th:first-child{width:17%}
  /* Tên dịch vụ là danh tính của cột, không phải chú thích: trả về màu chữ chính.
     Nhãn hàng (cột đầu) vẫn xám để hai trục của bảng không đọc ngang cấp nhau. */
  .tbl-cmp tr:first-child th{color:var(--ink)}
}
@media(max-width:860px){
  /* Vỏ bảng tan ra: viền/bo góc chuyển xuống từng thẻ, và bỏ overflow-x để thẻ
     không bị cắt mép. Lấy class .tblwrap-cmp trên vỏ chứ không phải :has() — cả
     file này không dùng :has ở đâu khác, và một class là thứ đọc ra ngay trong HTML. */
  .tblwrap-cmp{overflow:visible;border:0;border-radius:0}
  .tbl-cmp,.tbl-cmp tbody{display:block;background:none}
  /* Hàng tiêu đề: tên ba dịch vụ đã lặp lại ở data-svc của từng ô bên dưới. */
  .tbl-cmp tr:first-child{display:none}
  .tbl-cmp tr{display:block;background:#fff;border:1px solid var(--line);
    border-radius:var(--r);overflow:hidden}
  .tbl-cmp tr + tr{margin-top:12px}
  /* Câu hỏi = thanh tiêu đề của thẻ. Nền --bg-soft giữ đúng tín hiệu "đây là
     tiêu đề của một bảng" mà .tbl th vẫn dùng ở khổ rộng, nhưng cỡ chữ nhích
     lên và về màu chữ chính vì ở đây nó là TIÊU ĐỀ THẺ chứ không phải nhãn phụ. */
  .tbl-cmp tr > th{display:block;border:0;border-bottom:1px solid var(--line);
    padding:11px 16px;font-size:.8rem;letter-spacing:.07em;color:var(--ink)}
  .tbl-cmp td{display:block;border:0;padding:12px 16px 14px;font-size:.94rem;line-height:1.5}
  .tbl-cmp td + td{border-top:1px solid var(--line)}
  /* Tên dịch vụ đứng trên câu trả lời của nó. Màu nhấn: trong một thẻ có ba câu
     trả lời liền nhau, đây là thứ duy nhất phân biệt chúng nên nó phải bắt mắt
     trước phần chữ. */
  .tbl-cmp td::before{content:attr(data-svc);display:block;margin-bottom:3px;
    font-size:.72rem;font-weight:800;letter-spacing:.07em;text-transform:uppercase;
    color:var(--accent)}
}
/* Khoảng máy bảng (621–860px): thẻ vẫn là thẻ, nhưng tên dịch vụ về NẰM CẠNH
   câu trả lời chứ không đứng thành một dòng riêng. Ở 800px câu trả lời chỉ dài
   một dòng, để nhãn ở trên là mỗi ô ăn hai dòng cho một dòng chữ — thẻ dài gấp
   đôi mà bề ngang bỏ trống quá nửa. Ngưỡng 620px lấy đúng chỗ .mstack đổi bố
   cục, dưới đó cột nhãn 190px sẽ ăn mất nửa màn hình. */
@media(min-width:621px) and (max-width:860px){
  .tbl-cmp td{display:grid;grid-template-columns:190px 1fr;gap:18px;align-items:baseline;
    padding:13px 16px}
  .tbl-cmp td::before{margin-bottom:0}
}
.dot{color:var(--accent);font-weight:800}
/* CTA cuối trang: từ tấm gradient xanh → TẤM XÁM, và nút mới là chỗ có màu. Nếu
   cả tấm đã xanh thì nút xanh trên nền xanh không còn nổi, phải đổi sang nút
   trắng — tức là mất luôn màu hành động thống nhất của cả site. */
.finalcta{background:var(--bg-soft);color:var(--ink);border-radius:var(--r);padding:clamp(30px,5vw,50px) clamp(24px,5vw,46px);
  display:grid;grid-template-columns:1.4fr auto;gap:30px;align-items:center;box-shadow:none}
.finalcta h2{color:var(--ink);margin-bottom:.3em}
.finalcta p{color:var(--ink);margin:0;font-weight:500}
.finalcta a[href^="tel"]{color:var(--brand)}
.notecard{border:0;background:var(--bg-soft);border-radius:var(--r);padding:20px 24px;display:flex;align-items:center;gap:18px;flex-wrap:wrap}
.notecard p{margin:0;flex:1;min-width:250px;font-size:.96rem}
/* flex-wrap cho ô rộng theo độ dài tên, hàng cuối thiếu ô là rách một mảng lớn.
   Lưới ô đều nhau thì hàng cuối hụt vẫn đọc ra là lưới, không phải chỗ vỡ. */
.logostrip{display:grid;grid-template-columns:repeat(auto-fill,minmax(186px,1fr));gap:12px}
/* Ô logo chỉ cao bằng một phần tư thẻ trong lưới, dịch đủ 8px thì cả dải nhấp nhô
   như sóng — hạ xuống một nửa, bóng cũng rút theo đúng tỷ lệ đó (creaform cũng
   chia hai mức y hệt cho thẻ lớn và thẻ nhỏ). */
.logostrip .cl{--rise:-4px;--lift-hover:0 5px 10px rgba(26,25,24,.12);border:0;border-radius:var(--r);padding:14px 16px;font-size:.86rem;
  font-weight:600;color:var(--ink);background:var(--bg-soft)}
.logostrip .cl:hover{background:var(--panel-hi)}
.logostrip .cl span{display:block;font-size:.7rem;color:var(--muted);font-weight:400}
/* Ô đối tác mang huy hiệu thật thay cho tên gõ tay. Nền TRẮNG chứ không phải
   --bg-soft: nửa phải của huy hiệu Siemens vốn là nền trắng, đặt lên tấm xám thì
   nó hiện ra như một hình chữ nhật trắng dán đè chứ không phải một dấu chứng nhận.
   Chữ tên vẫn nằm trong markup nhưng ẩn; ảnh hỏng thì .noimg (do onerror gắn) bật
   lại đúng ô chữ cũ — cùng cách dự phòng với .lm-item ở dải logo trang chủ. */
.logostrip .cl-logo{background:#fff;box-shadow:inset 0 0 0 1px var(--line)}
.logostrip .cl-logo:hover{background:#fff}
/* Huy hiệu Siemens khóa theo bề ngang, các huy hiệu .cl-mark khóa theo băng cao
   42px: trong một hàng lưới, ảnh cao thấp khác nhau thì dòng chú thích dưới mỗi
   ô cũng nằm mỗi nơi một kiểu. Ô là flex cột, chú thích đẩy xuống ĐÁY — lưới kéo
   mọi ô trong hàng bằng nhau nên cả hàng chú thích về chung một đường. */
.logostrip .cl-logo{display:flex;flex-direction:column}
.logostrip .cl-logo span{margin-top:auto}
/* Huy hiệu rộng gấp đôi chiều cao và mang hai dòng chữ nhỏ: khóa theo chiều CAO
   (kiểu 50px như dải logo trang chủ) thì nó chỉ còn ~127px ngang và hai dòng chữ
   trong huy hiệu nhòe hẳn. Khóa theo bề ngang ô, cao tự tính. */
.logostrip .cl-logo img{display:block;width:100%;max-width:220px;height:auto;
  margin-bottom:10px}
.logostrip .cl-logo b{display:none;font-weight:600}
.logostrip .cl-logo.noimg img{display:none}
.logostrip .cl-logo.noimg b{display:block}
/* .cl-mark — huy hiệu trường/đối tác, KHÁC huy hiệu chứng thực Siemens ở trên.
   Bốn logo này có tỷ lệ 1,4 đến 4,6 (TOMECO là khối vuông, TLU là dải rất dẹt):
   khóa theo bề ngang như Siemens thì cái dẹt nhất chỉ cao 34px còn cái dày nhất
   47px — cùng một dải mà chữ trong logo ra ba cỡ khác nhau. Nên cho một BĂNG cao
   cố định, ảnh contain trong băng: mọi ô cùng chiều cao quang học, logo nào quá
   rộng tự thu theo bề ngang. --mk-k nhân riêng cho logo dạng khối (biểu tượng
   chồng lên chữ) vì ở cùng chiều cao nó đọc ra nhỏ hơn logo dàn ngang. */
.logostrip .cl-mark img{flex:none;width:100%;max-width:none;height:calc(42px * var(--mk-k,1));
  object-fit:contain;object-position:left center;margin-bottom:12px}
.logo-label{font-size:.72rem;letter-spacing:.12em;text-transform:uppercase;color:var(--muted);font-weight:600;margin-bottom:14px}

/* ---------- bản đồ phạm vi hoạt động (trang chủ) ----------
   Bảy quốc gia trên một bản đồ thế giới thì bản đồ KHÔNG phải chỗ để đọc: bốn
   nước Đông/Đông Nam Á dồn trong 11% bề rộng, Pháp và Bỉ cách nhau chưa tới 1%.
   Nên chia việc: bản đồ lo hình dạng và độ trải, .gm-list lo tên. Ai cần đọc thì
   đọc cột phải; ai chỉ liếc thì thấy ngay ba cụm — Đông Á, Tây Âu, Bắc Mỹ.
   Cột trái 1.55fr chứ không phải 1fr: bản đồ tỷ lệ 18:7 mà chia đôi tấm thì nó
   thấp hơn cột chữ bên cạnh, khối đọc ra như một tấm ảnh minh hoạ bị kẹp. */
.gmap{display:grid;grid-template-columns:minmax(0,1.55fr) minmax(0,1fr);gap:30px;align-items:center;
  background:var(--bg-soft);border-radius:var(--r);padding:24px}
.gm-art{position:relative}
/* Đại dương trong file SVG tô đúng --bg-soft, nên bản đồ không có mép: lục địa
   nổi thẳng trên nền tấm, không khung không viền — đúng luật "chỉ chênh nền" của
   hệ này. Nền chờ của .imgbox (--fill) phải tắt đi, không thì lúc ảnh chưa tải
   xong có một hình chữ nhật xám nhấp nháy. ĐỔI --bg-soft thì phải sửa màu nền
   trong image/ban-do-pham-vi.svg theo, hai chỗ này buộc phải bằng nhau. */
.gm-art .imgbox{background:transparent}
/* Vành 2px màu nền: chấm Pháp và chấm Bỉ cách nhau ~7px nên hai hình tròn chạm
   nhau. Có vành thì chúng đọc ra là hai điểm cạnh nhau, không có vành thì thành
   một vệt dài. Vành cũng tách chấm khỏi mảng xanh nhạt của quốc gia bên dưới. */
.gm-pin{position:absolute;width:9px;height:9px;margin:-4.5px 0 0 -4.5px;border-radius:50%;
  background:var(--brand);box-shadow:0 0 0 2px var(--bg-soft)}
/* Nhãn chỉ hiện lúc rê chuột — mỗi lúc đúng một cái, nên bảy cái nhãn không bao
   giờ phải tránh nhau. Nâng z-index cả chấm để nhãn không chui xuống dưới chấm
   hàng xóm. */
.gm-pin b{position:absolute;left:50%;bottom:calc(100% + 8px);transform:translateX(-50%);
  white-space:nowrap;font-size:.74rem;font-weight:600;line-height:1.55;background:var(--brand);
  color:#fff;padding:2px 8px;border-radius:var(--r-sm);opacity:0;pointer-events:none;
  transition:opacity .12s ease}
.gm-pin:hover{z-index:3}
.gm-pin:hover b{opacity:1}
.gm-list{list-style:none;margin:0;padding:0}
/* flex-wrap chứ không phải xếp dọc theo breakpoint: dòng nào ĐỦ CHỖ thì giữ
   nguyên một hàng, dòng nào không đủ mới nhả cột phải xuống dòng riêng. Ở màn
   360px chỉ mỗi dòng Việt Nam (ba khách hàng) phải xuống, sáu dòng còn lại vẫn
   một hàng. Không có nó thì cột phải tự ngắt chữ bên trong và bỏ lại một chữ mồ
   côi ("TONA") nằm một mình — trông như lỗi chứ không như thiết kế.
   margin-left:auto thay cho justify-content:space-between: space-between chỉ đẩy
   được khi hai món CÙNG một dòng; lúc cột phải xuống dòng riêng nó thành món duy
   nhất của dòng đó và bị dồn về trái, gãy mất mép phải của cả cột. */
.gm-list li{display:flex;flex-wrap:wrap;align-items:baseline;gap:2px 14px;
  padding:9px 2px;border-bottom:1px solid var(--line);font-size:.94rem}
.gm-list li:last-child{border-bottom:0}
.gm-list b{font-weight:600;white-space:nowrap}
.gm-list span{margin-left:auto;color:var(--muted);font-size:.8rem;text-align:right}
/* Nhãn của dải logo ngay bên dưới: nó là chú thích của DẢI, không phải đầu đề
   của cả section nữa (section đã có .sec-head riêng), nên phải có khoảng thở
   tách hẳn khỏi tấm bản đồ. */
.gm-cap{margin-top:38px}
/* Máy cảm ứng thuần không rê được, mà :hover trên đó còn dính lại sau khi chạm —
   một cái nhãn treo giữa bản đồ không tự tắt. Bỏ hẳn nhãn ở đó: tên nước đã nằm
   đủ trong .gm-list ngay bên dưới. (Bọc ngược bằng any-hover:none, KHÔNG bọc
   phần hover trong hover:hover — xem chú thích dài ở khối .card phía trên.) */
@media(any-hover:none){.gm-pin b{display:none}}
@media(max-width:1024px){.gmap{grid-template-columns:1fr;gap:22px}}
@media(max-width:620px){
  .gmap{padding:16px;gap:16px}
  /* Bản đồ còn ~320px thì bốn chấm Đông Nam Á cách nhau vài pixel. Thu chấm và
     vành theo để cụm ấy vẫn đọc ra là nhiều điểm, không thành một vết mực. */
  .gm-pin{width:7px;height:7px;margin:-3.5px 0 0 -3.5px;box-shadow:0 0 0 1.5px var(--bg-soft)}
  /* Danh sách nước + khách hàng ẩn trên điện thoại (08/10/2026, theo yêu cầu
     người dùng): tiêu đề đã nói "6 quốc gia", bản đồ đủ cho cái liếc. Chỉ ẩn
     với MẮT — bản đồ mang aria-hidden nên danh sách là nguồn duy nhất cho trình
     đọc màn hình. position:absolute đưa nó ra khỏi lưới, không để lại gap 16px. */
  .gmap{position:relative}
  .gm-list{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);
    clip-path:inset(50%);white-space:nowrap}
  .gm-cap{margin-top:30px}
}

/* ---------- dải logo chạy ngang (trang chủ) ----------
   Mẫu chuyển động lấy từ creaform-engineering.com: bên họ jQuery nhích
   margin-left của <ul> đúng MỘT ô mỗi 3 giây theo đường thẳng rồi chuyển ô đầu
   xuống cuối — nhìn ra là một dải trôi đều, không giật nấc. Ở đây làm cùng
   chuyển động ấy bằng MỘT keyframe translateX(-50%): không có vòng lặp JS nào
   chạy 60 khung hình/giây, và trình duyệt đẩy hẳn nó xuống luồng hợp thành.
   Vòng lặp chỉ liền mạch khi dải gồm đúng HAI lượt giống hệt nhau và một lượt
   rộng hơn khung nhìn; site.js nhân bản cho đủ nên HTML chỉ viết mỗi logo một
   lần (xem "dải logo chạy ngang" trong site.js).
   Dải cố ý KHÔNG bó trong .wrap: logo trôi ra khỏi mép màn mới đọc ra là băng
   chuyền, bó trong lề thì thành một dải cụt hai đầu. */
.logomar{
  /* Chưa có JS (hoặc JS hỏng): dải vẫn kéo ngang xem hết được. Ẩn thanh cuộn vì
     ngay sau đó JS đổi overflow thành hidden — hiện rồi ẩn là trang giật một nấc.
     Cùng lý do, .lm-track để nowrap ngay từ đầu: lần vẽ đầu tiên trông đúng như
     lúc đã chạy, không có cảnh xếp hai hàng rồi rút lại một hàng. */
  /* KHÔNG mờ dần hai đầu dải. Mask gradient làm mấy logo ngoài rìa nhạt dần đi
     thành một vệt trắng chạy dọc hai bên — logo phải hiện nguyên bản, kể cả cái
     đang trôi ra khỏi mép. Cắt phẳng ở mép cũng đúng như creaform làm. */
  overflow-x:auto;scrollbar-width:none}
.logomar::-webkit-scrollbar{display:none}
.logomar.is-run{overflow:hidden}
.lm-track{display:flex;flex-wrap:nowrap;width:max-content;list-style:none;margin:0;padding:0}
/* --n là số logo trong MỘT lượt, do site.js đặt. 3s mỗi logo là đúng nhịp
   creaform (data-autoplayspeed="3000"), không phụ thuộc dải dài bao nhiêu. */
.logomar.is-run .lm-track{animation:lm-chay calc(var(--n,10) * 3s) linear infinite}
@keyframes lm-chay{to{transform:translateX(-50%)}}
/* WCAG 2.2.2 — thứ tự chuyển động quá 5 giây phải dừng được: rê chuột hoặc đưa
   tiêu điểm vào dải là dừng. Máy đặt prefers-reduced-motion thì site.js không
   nhân bản và không gắn .is-run, dải nằm yên ngay từ đầu. */
.logomar:hover .lm-track,.logomar:focus-within .lm-track{animation-play-state:paused}
@media(prefers-reduced-motion:reduce){
  .logomar.is-run .lm-track{animation:none}
}
/* Ô CO THEO LOGO chứ không rộng cố định: mọi logo cao đúng --lm-h, bề ngang tự
   theo tỷ lệ ảnh. Ô rộng cố định thì logo ngang (Siemens 6.3:1) chạm mép ô rồi bị
   max-width kéo tụt còn 26px cao, trong khi logo vuông (Viglacera) vẫn đủ 50px —
   nhìn ra một hàng cao thấp so le. Đây là lý do phải bỏ bề rộng cố định.
   Đổi lại, bề rộng một lượt chỉ đo đúng KHI ĐÃ BIẾT tỷ lệ ảnh (site.js đọc
   track.scrollWidth để nhân bản dải). Nên mỗi <img> trong dải BẮT BUỘC có thuộc
   tính width/height bằng kích thước thật của file: trình duyệt giữ sẵn đúng chỗ
   từ trước khi ảnh tải xong, đo lúc nào cũng ra cùng một số. Thêm logo mới mà
   quên hai thuộc tính đó thì dải sẽ hụt một mảng trống ở cuối mỗi vòng. */
.lm-item{--lm-h:34px;flex:0 0 auto;min-height:80px;
  display:flex;align-items:center;justify-content:center;padding:10px 26px}
.lm-item > a{display:flex;align-items:center;justify-content:center}
.lm-item > a:hover{text-decoration:none}
/* height cứng, width:auto — đây là điều làm cả hàng cao bằng nhau. max-width:none
   để logo ngang không bị ô kéo tụt xuống. Các file trong image/logo/ đã cắt sạch
   lề trắng thừa, nếu không thì lề ấy tính vào chiều cao và logo đó sẽ nhỏ hơn.
   --lm-k là hệ số chỉnh tay CHO RIÊNG một logo, người sửa kéo núm trên trang rồi
   lưu (layout.logo trong data/content.json, xem applyLayout ở lib/render.js).
   Cần nó vì cao bằng nhau về SỐ ĐO chưa chắc bằng nhau về mắt: logo có khung bao
   quanh hay chữ dày trông to hơn hẳn logo chỉ có chữ mảnh ở cùng chiều cao. */
.lm-item img{height:calc(var(--lm-h) * var(--lm-k,1));width:auto;max-width:none;object-fit:contain;
  /* Mặc định đơn sắc xám cho cả dải đọc như MỘT khối, rê chuột vào mới trả lại
     màu thật của thương hiệu. Cùng lúc đó .logomar:hover dừng dải chạy, nên logo
     đang xem vừa đứng yên vừa lên màu.
     CHỈ grayscale(1), không kèm opacity hay brightness: hạ độ mờ làm logo trông
     như bị làm trong suốt, còn đây chỉ cần rút màu. Logo giữ nguyên độ đậm nhạt
     vốn có của nó. */
  filter:grayscale(1);
  transition:filter .28s ease}
.lm-item:hover img,.lm-item:focus-within img{filter:grayscale(0)}
/* Máy KHÔNG rê chuột được (điện thoại, bảng vẽ): không bao giờ chạm được trạng
   thái hover nên phải thấy màu thật ngay. Bọc chiều ngược lại — bọc luật hover
   trong (hover:hover) thì máy có chuột nhưng khai báo thiếu sẽ mất sạch hiệu ứng. */
@media (any-hover:none){
  .lm-item img{filter:none}
}
/* Chưa có file logo trong image/logo/: onerror gắn .noimg, ô hiện lại đúng tên và
   dòng chú như bản lưới cũ. Dải chạy được ngay hôm nay và tự đẹp dần theo từng
   file logo được thả vào, không phải sửa HTML lần nào. */
.lm-item .lm-txt{display:none;font-size:.84rem;font-weight:600;color:var(--ink);
  text-align:center;line-height:1.3}
.lm-item .lm-txt small{display:block;font-size:.7rem;color:var(--muted);font-weight:400;
  margin-top:3px}
.lm-item.noimg img{display:none}
.lm-item.noimg .lm-txt{display:block}
/* Ô đã co theo logo nên khi KHÔNG có ảnh, ô phải tự lấy lại bề rộng — không thì
   tên dài xuống bốn dòng, cả dải cao vọt lên theo ô ấy. */
.lm-item.noimg{width:clamp(148px,15vw,200px)}
/* Điện thoại: hạ chiều cao và thu khoảng cách, vì logo ngang nhất (Siemens 6.3:1)
   ở 48px đã rộng hơn cả màn hình. */
@media (max-width:640px){
  .lm-item{--lm-h:25px;padding:10px 18px;min-height:64px}
}
.lm-more{margin:22px 0 0}

/* ---------- forms ---------- */
.form{display:grid;grid-template-columns:1fr 1fr;gap:16px}
.form .full{grid-column:1/-1}
.form label{font-size:.86rem;font-weight:700;display:block;margin-bottom:7px}
.form label small{color:var(--muted);font-weight:500}
.form input,.form textarea,.form select{width:100%;padding:13px 14px;border:1.5px solid var(--line);border-radius:var(--r-sm);
  font-family:inherit;font-size:16px;background:#fff;transition:border-color .15s, box-shadow .15s}
/* vòng sáng thay cho chỉ đổi màu viền: ô đang nhập nhận ra được ngay cả khi liếc */
.form input:focus,.form textarea:focus,.form select:focus{border-color:var(--accent);outline:none;
  box-shadow:0 0 0 3px rgba(43,101,176,.16)}
.req::after{content:" *";color:#c8392b}

/* ---------- trang Liên hệ ----------
   Trang này là ĐÍCH ĐẾN của mọi nút CTA trên site, nên biểu mẫu phải là thứ nặng
   nhất trang. Cách làm theo đúng cơ chế phân tách của hệ (chênh nền, không viền
   không bóng): biểu mẫu ngồi trong một TẤM --bg-soft, mà ô nhập thì nền trắng —
   trắng trên xám nổi rõ hơn trắng trên nền trang, nên các ô tự đọc ra là chỗ để
   gõ mà không cần thêm nét kẻ nào. Cột phải cũng là tấm cùng loại nhưng chữ nhỏ
   hơn một nấc: hai cột cùng ngôn ngữ, khác trọng lượng.
   Tiền tố "ct" cho cả cụm — style.css nạp chung với admin.css ở trang Cài đặt,
   tên trần kiểu .panel hay .chips là đụng nhau. */

/* Ba lời hứa dưới dải tiêu đề: chỗ trả lời ba câu người ta hỏi thầm trước khi gõ
   chữ đầu tiên (bao lâu có trả lời · có mất tiền không · dữ liệu của tôi đi đâu).
   Nằm trong .pageband nên vạch ngăn lấy theo --ink chứ không phải --line: --line
   quá nhạt để đọc ra trên nền #EDEDED. */
.ctpromise{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:16px 28px;
  margin-top:26px;padding-top:22px;border-top:1px solid rgba(44,42,41,.16)}
.ctpromise-i{display:flex;gap:12px;align-items:flex-start}
.ctpromise svg{width:22px;height:22px;flex:0 0 auto;margin-top:2px;fill:none;stroke:var(--brand);
  stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}
.ctpromise b{display:block;font-size:.98rem;font-weight:600;color:var(--ink);line-height:1.35}
.ctpromise span{display:block;font-size:.85rem;color:var(--muted);line-height:1.5;margin-top:3px}
@media(max-width:860px){
  .ctpromise{grid-template-columns:1fr;gap:14px;margin-top:22px;padding-top:18px}
}

/* Biểu mẫu rộng hơn cột liên hệ đúng một nấc rưỡi — đủ để hai ô nhập nằm cạnh
   nhau vẫn thoải mái, mà cột phải không thành một dải hẹp. */
.ctgrid{display:grid;grid-template-columns:minmax(0,1.45fr) minmax(0,1fr);gap:26px;align-items:start}
@media(max-width:1024px){.ctgrid{grid-template-columns:1fr}}
/* Hai cột bằng đáy: cột nào ngắn hơn thì tấm cuối của nó giãn ra. */
@media(min-width:1025px){
  .ctgrid{align-items:stretch}
  .ctgrid > div:last-child{display:flex;flex-direction:column}
  .ctgrid > div:last-child > .ctpanel:last-child{flex:1}
}

.ctpanel{background:var(--bg-soft);border-radius:var(--r);padding:clamp(22px,2.4vw,32px)}
.ctpanel + .ctpanel{margin-top:20px}
.ctpanel > h2{margin-bottom:.3em}
.ctsub{color:var(--muted);font-size:.95rem;margin-bottom:22px;max-width:60ch}
/* Nhãn của tấm phụ: chữ nhỏ in hoa giãn ký tự, cùng kiểu với .toplist h3 và
   .toc h3 — không phải một H3 thường, để nó không tranh cấp với H2 của biểu mẫu. */
.ctpanel-t{font-size:.72rem;letter-spacing:.13em;text-transform:uppercase;color:var(--muted);
  font-weight:800;margin:0 0 4px}

/* Ô nhập nằm trên tấm xám: viền --line (#E0E0DF) chỉ chênh nền 13 đơn vị sáng nên
   gần như tàng hình ở đó. Lấy màu viền theo --ink pha loãng để giữ đúng một thang
   xám, không đẻ thêm mã màu viết cứng. */
.ctpanel .form input,.ctpanel .form textarea,.ctpanel .form select{border-color:rgba(44,42,41,.2)}
.ctpanel .form input:focus,.ctpanel .form textarea:focus,.ctpanel .form select:focus{border-color:var(--accent)}

/* Nhóm chọn loại yêu cầu: từ <select> đổ xuống thành hàng chip hiện hết lựa chọn.
   Sáu nhãn này cũng chính là danh mục việc CFDWAYS nhận — để chúng nằm sau một cú
   bấm mở là giấu mất một mẩu thông tin. Radio thật nằm dưới nhãn, ẩn bằng
   clip chứ không display:none để bàn phím còn Tab tới được. */
.ctfield{border:0;padding:0;margin:0;min-width:0}
.ctfield legend{padding:0;font-size:.86rem;font-weight:700;margin-bottom:9px}
.ctchips{display:flex;flex-wrap:wrap;gap:8px}
.ctchips input{position:absolute;width:1px;height:1px;opacity:0;pointer-events:none}
.form .ctchips label{display:inline-flex;align-items:center;margin:0;padding:9px 15px;
  border:1.5px solid rgba(44,42,41,.2);border-radius:20px;background:#fff;
  font-size:.85rem;font-weight:600;color:var(--ink);line-height:1.35;cursor:pointer;
  transition:background .15s,border-color .15s,color .15s}
.form .ctchips label:hover{border-color:var(--brand);color:var(--brand)}
.form .ctchips input:checked + label{background:var(--brand);border-color:var(--brand);color:#fff}
.form .ctchips input:focus-visible + label{outline:3px solid var(--accent);outline-offset:2px}
@media(any-hover:none){
  .form .ctchips label:hover{border-color:rgba(44,42,41,.2);color:var(--ink)}
  .form .ctchips input:checked + label{border-color:var(--brand);color:#fff}
}
/* Ô chạm: đệm 9px cho chip cao 38px — vừa với con trỏ chuột, hụt sàn 44px của
   đầu ngón tay. Nới đệm dọc ở khổ hẹp thay vì ghim min-height: chip nhãn dài
   xuống hai dòng thì vẫn tự cao thêm theo. Nhớ rằng bộ chữ đổi được ở Cài đặt →
   Giao diện, bộ nào dòng thấp hơn Noto Sans là ô chạm tụt xuống dưới sàn 44px,
   nên chừa dư một nhịp. */
@media(max-width:620px){
  .form .ctchips label{padding:12px 16px}
}

.cthelp{margin:9px 0 0;font-size:.82rem;color:var(--muted);line-height:1.55}
/* Nút gửi và dòng cam kết đứng CÙNG một hàng: dòng chữ ấy là điều kiện của cú
   bấm, đặt nó thành một đoạn rời phía dưới thì đọc ra như chú thích cuối trang. */
.ctfoot{display:flex;align-items:center;flex-wrap:wrap;gap:14px 20px;
  margin-top:6px;padding-top:22px;border-top:1px solid rgba(44,42,41,.14)}
.ctfoot .btn{flex:0 0 auto}
.ctfoot p{flex:1;min-width:250px;margin:0;font-size:.82rem;color:var(--muted);line-height:1.6}
.ctfoot p b{color:var(--ink);font-weight:600}

/* Một kênh liên hệ = một hàng: biểu tượng · nhãn nhỏ in hoa · giá trị bấm được.
   Nhãn tách khỏi giá trị nên không phải đoán "+82 10…" là số gì, và bốn hàng
   quét dọc được bằng một cột biểu tượng thẳng hàng. */
.ctch{display:flex;gap:13px;align-items:flex-start;padding:14px 0;
  border-top:1px solid rgba(44,42,41,.14)}
.ctch:last-child{padding-bottom:0}
.ctch-ic{width:21px;height:21px;flex:0 0 auto;margin-top:3px;fill:none;stroke:var(--brand);
  stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}
.ctch-b{flex:1;min-width:0}
.ctch-l{font-size:.7rem;letter-spacing:.1em;text-transform:uppercase;color:var(--muted);
  font-weight:700;margin-bottom:3px}
/* Giá trị để màu chữ thường chứ không phải màu liên kết — bốn dòng xanh xếp
   chồng trong một tấm hẹp thành một mảng màu, mà cột này là thông tin tra cứu
   chứ không phải chỗ để nhấn. Cùng cách với .mcontact ở đáy menu trượt: màu chỉ
   xuất hiện lúc rê chuột, còn biểu tượng bên trái đã gánh phần màu nhấn. */
.ctch-v{display:block;font-size:.98rem;font-weight:600;color:var(--ink);line-height:1.45;
  overflow-wrap:anywhere}
a.ctch-v:hover{color:var(--brand)}
.ctch-s{display:block;font-size:.8rem;color:var(--muted);line-height:1.5;margin-top:2px}
/* Hai liên kết mạng xã hội nằm CÙNG một dòng, ngăn bằng dấu chấm giữa do CSS vẽ —
   để mỗi cái một dòng thì hàng này cao gấp đôi ba hàng kia mà chẳng thêm nghĩa gì. */
.ctsoc{display:flex;flex-wrap:wrap;align-items:baseline;gap:0 9px}
.ctsoc a{color:var(--ink)}
.ctsoc a:hover{color:var(--brand)}
.ctsoc a + a::before{content:"·";margin-right:9px;color:var(--muted);font-weight:400}
.ctmap{margin-top:6px}
/* Ảnh văn phòng nằm trong tấm cột phải chứ không đứng cạnh một cột chữ. Lý do là
   TỈ LỆ: van-phong-01.jpg xuất ở 2:1, đặt cạnh khối chữ dài thì cột ảnh hụt hơn
   300px so với cột chữ, mà đổi sang tỉ lệ cao hơn thì phải xuất thêm một bản
   nữa của cùng một tấm ảnh (xem "Tỷ lệ khung ảnh" trong README). Trong cột hẹp
   ~380px thì 2:1 cao ~190px — vừa đúng một nhịp của tấm. */
.ctpic{border-radius:var(--r-sm);overflow:hidden;margin:2px 0 4px}

/* Vạch ngăn của .listclean lấy màu --line, chỉ chênh nền tấm xám 13 đơn vị sáng
   nên gần như mất hút khi danh sách nằm trong .ctpanel. Cùng cách chữa với viền
   ô nhập ở trên: --ink pha loãng, không thêm mã màu mới. */
.ctpanel .listclean li{border-bottom-color:rgba(44,42,41,.14)}

/* ---------- footer ---------- */
footer{background:var(--brand-dark);color:rgba(240,240,240,.68);padding:56px 0 0;font-size:.9rem;margin-top:0}
footer h4{color:#fff;font-size:.76rem;letter-spacing:.12em;text-transform:uppercase;margin-bottom:14px}
footer a{color:rgba(240,240,240,.75)}
footer ul{list-style:none;padding:0;margin:0}
footer li{margin-bottom:8px}
.fgrid{display:grid;grid-template-columns:1.6fr 1fr 1fr 1.1fr;gap:36px}
.fbot{border-top:1px solid rgba(255,255,255,.14);margin-top:42px;padding:18px 0;font-size:.82rem;
  display:flex;justify-content:space-between;gap:16px;flex-wrap:wrap}

/* ---------- responsive ---------- */
@media(max-width:1180px) and (min-width:1025px){
  .mlist > li > a{padding:10px 9px;font-size:.85rem}
}
@media(max-width:1024px){
  /* Cụm menu chui vào drawer nên nút tìm kiếm không còn cụm VI/EN để đứng cạnh:
     cho nó về cuối hàng, ngay trước nút menu. Khoảng trống phải nằm TRƯỚC cả
     hai nút, nên margin-left:auto chuyển sang nút đầu của cặp — để nguyên trên
     .burger thì nút tìm kiếm dính vào logo còn nút menu bay sang mép phải.
     Cỡ nâng lên 44px cho bằng nút menu và đạt ô chạm cỡ ngón tay. */
  .srch-btn{order:2;margin-left:auto;width:44px;height:44px;border-radius:9px}
  .srch-btn svg{width:19px;height:19px}
  .burger{display:block;order:3;margin-left:0}
  /* drawer trong lớp cắt riêng — trạng thái đóng không tạo tràn ngang */
  .navwrap{display:block;position:fixed;inset:0;overflow:hidden;pointer-events:none;z-index:120}
  /* Drawer CHIẾM TRỌN màn hình ở mọi bề ngang dưới 1025px. Trước đây nó rộng
     min(86vw,360px) và chừa một dải hé bên trái để bấm ra ngoài mà đóng; bỏ dải
     đó thì lối thoát chỉ còn nút ✕ góc trên (và phím Escape) — vẫn đủ, và đổi lại
     mega menu ba cột có nguyên bề ngang màn hình thay vì bị nhồi vào 360px. */
  .menu{position:absolute;inset:0;background:#fff;
    transform:translateX(108%);
    transition:transform .32s cubic-bezier(.32,.72,.28,1), box-shadow .32s ease;
    /* Drawer đóng vẫn nằm trong lớp cắt, nên bóng của nó hắt ngược vào mép phải
       màn hình thành một vệt xám. Tắt bóng bằng alpha (không phải box-shadow:none)
       để lúc đóng/mở bóng mờ dần theo, không biến mất đột ngột. */
    box-shadow:-24px 0 64px rgba(7,30,48,0);
    display:flex;flex-direction:column;margin:0;overflow:hidden;pointer-events:auto;
    /* desktop đặt align-items:center cho hàng ngang — cột dọc mà giữ nguyên thì
       đầu và đáy drawer co theo nội dung, không kín bề ngang */
    align-items:stretch}
  body.nav-open .menu{transform:none;box-shadow:-24px 0 64px rgba(7,30,48,.3)}
  body.nav-open .scrim{opacity:1;visibility:visible}
  /* KHÓA CUỘN NỀN. Phải là position:fixed trên <body>, KHÔNG được rút gọn về
     mỗi overflow:hidden — đó chính là bản cũ và nó không chặn được gì cả.
     `body{overflow:hidden}` chỉ có tác dụng khi trình duyệt CHUYỂN giá trị
     overflow của <body> lên khung nhìn, mà theo CSS Overflow 3 việc chuyển đó chỉ
     xảy ra khi overflow của <html> là `visible` ở CẢ HAI trục. Đầu file này đặt
     `html{overflow-x:clip}` để chặn tràn ngang, thế là điều kiện hỏng: <body>
     thành khung cuộn của riêng nó, còn khung nhìn vẫn cuộn như chưa có gì.
     Đo 17/08/2026 (Chrome 150, khung 390px): mở menu ở scrollY=600, lăn chuột
     một cái ra 1000, đóng menu thì lạc hẳn khỏi chỗ đang đọc.
     position:fixed thì chắc chắn ở mọi trình duyệt, kể cả Safari iOS — nơi
     overflow:hidden đặt trên <html> cũng vẫn cuộn được. Cái giá của nó là trang
     nhảy về đầu, nên assets/js/site.js cất scrollY vào body.style.top lúc mở và
     trả lại lúc đóng. HAI CHỖ ĐÓ ĐI LIỀN NHAU: bỏ position:fixed ở đây mà quên
     gỡ phần JS thì mỗi lần mở menu trang lại tự nhảy lên đầu. */
  body.nav-open{position:fixed;left:0;right:0;overflow:hidden}
  .mhead{display:flex;align-items:center;justify-content:space-between;padding:14px 14px 14px 18px;
    border-bottom:1px solid var(--line);flex:0 0 auto}
  .mhead .logo img{height:30px}
  .mclose{background:none;border:1.5px solid var(--line);border-radius:10px;width:40px;height:40px;
    font-size:1.1rem;cursor:pointer;color:#33414e;line-height:1;
    display:flex;align-items:center;justify-content:center;transition:background .15s,color .15s}
  .mclose:hover,.mclose:active{background:var(--bg-soft);color:var(--brand)}
  /* ---- DANH SÁCH TRONG DRAWER: kiểu gọn ----
     Bỏ hết đồ trang trí mà bản trước mượn của desktop — nền bo góc cho mục đang
     xem, vạch dọc chạy suốt bên trái bảng con, vạch ngang ngăn giữa các nhóm.
     Còn lại đúng MỘT loại đường kẻ: hairline vắt hết bề ngang, chỉ giữa hai mục
     cấp một. Mọi tầng bên dưới phân cấp bằng thụt lề và cỡ chữ, không bằng nét vẽ.
     Biểu tượng thì GIỮ — đây là chỗ cố ý khác bản tham chiếu (x.ai không có mục
     con nào có biểu tượng): bảng "Giải pháp" là 12 dòng chữ dài na ná nhau, biểu
     tượng là thứ duy nhất cho mắt bắt lại dòng đang đọc dở sau khi cuộn.
     Mực bỏ đi phải bù bằng thang chữ chứ không bằng khoảng trống: mục cấp một lên
     1.08rem/600 (bản cũ 1rem/500). */
  .mlist{flex-direction:column;align-items:stretch;gap:0;overflow-y:auto;
    overscroll-behavior:contain;-webkit-overflow-scrolling:touch;padding:0 18px 12px;flex:1}
  .mlist > li{width:100%}
  /* Vạch chia CHỈ nằm giữa hai mục. Mép trên đã có viền đáy của .mhead, mép dưới
     đã có viền trên của .mfoot — kẻ thêm ở hai đầu là hai nét chồng nhau. */
  .mlist > li + li{border-top:1px solid var(--line)}
  /* line-height phải đặt tay: 1.7 của body cộng với đệm 14px cho ra hàng cao 57px,
     thừa một nấc so với nhịp của bản tham chiếu (~50px). Cắt ở dòng chứ không cắt
     ở đệm — đệm mới là thứ giữ ô chạm đủ rộng cho ngón tay. */
  .mlist > li > a{padding:14px 0;font-size:1.08rem;font-weight:600;line-height:1.35;
    border-radius:0;justify-content:space-between}
  /* Chạm vào thì đổi MÀU CHỮ chứ không tô nền. Nền tô sẽ dừng ở lề 18px của danh
     sách trong khi vạch chia trên dưới vắt hết bề ngang — đọc ra như một tấm thẻ
     lọt vào giữa hai vạch, chứ không phải một dòng đang được nhấn. */
  .mlist > li > a:active,.mlist > li.open > a{color:var(--brand)}
  /* Trang đang xem: vạch nhấn dán MÉP TRÁI drawer (thò ra khỏi lề 18px của .mlist
     bằng left âm) thay cho nền xanh nhạt phủ kín dòng của bản cũ. Cùng một tín
     hiệu, một phần mười lượng mực. Luật desktop ngay trên đã đặt content/position/
     background — ở đây chỉ đổi hình dạng từ gạch chân ngang sang vạch dọc. */
  .mlist > li > a.active{color:var(--brand)}
  .mlist > li > a.active::after{left:-18px;right:auto;top:8px;bottom:8px;
    width:3px;height:auto;border-radius:0 2px 2px 0}
  .chev{width:9px;height:9px;transform:rotate(45deg)}
  .mlist > li:hover > a .chev{transform:rotate(45deg);opacity:.55}
  .mlist > li.open > a .chev,.mlist > li.open:hover > a .chev{transform:rotate(225deg);opacity:1}
  /* Submenu = accordion trượt mượt bằng max-height. Đóng = max-height:0 + overflow
     hidden, nên kể cả khi luật :hover/:focus-within của desktop bật opacity lên
     thì vẫn kín — VỚI ĐIỀU KIỆN đệm đáy KHÔNG nằm trên chính .sub. box-sizing là
     border-box, nên max-height:0 chỉ ép được HỘP VIỀN về 0; đệm 8px vẫn chống hộp
     cao 8px và cửa sổ cắt ấy để lọt 8px đầu của bảng đang đóng. Trên màn cảm ứng
     lỗi này lộ ra mỗi lần: chạm mục cha để gập bảng lại là tiêu điểm ở nguyên trên
     thẻ <a> đó, tức li:focus-within đúng nghĩa, opacity bị bật lên 1 và một lát
     chữ của tiêu đề nhóm đầu tiên ("KỸ THUẬT HIỆU SUẤT") hiện ra dưới dòng menu,
     trông như chữ bị cắt ngang. Nên đệm đáy chuyển sang ::after — nó là NỘI DUNG,
     bị cắt cùng phần còn lại, và hộp đóng cao đúng 0.
     Không còn vạch dọc bên trái: bảng con đã nằm trọn giữa hai vạch chia của mục
     cha, thêm một nét dọc nữa chỉ để nói lại đúng điều đó. Thụt lề chỉ 2px vì cột
     biểu tượng mới là thứ tạo bậc — đo được chữ mục con lùi vào 32px so với chữ
     mục cha, đúng khoảng thụt của bản tham chiếu. */
  .sub{position:static;min-width:0;box-shadow:none;border:none;
    border-radius:0;margin:0;padding:0 0 0 2px;display:block;overflow:hidden;
    max-height:0;opacity:0;visibility:visible;transform:none;
    transition:max-height .3s ease,opacity .22s ease}
  /* Mega menu ba cột có thể tới hơn hai chục dòng — trần 600px của bảng thả
     xuống thường sẽ cắt cụt mất phần đuôi. */
  .mlist > li.open .sub{max-height:600px;opacity:1}
  /* TRẦN NÀY LÀ CON SỐ CHẾT: max-height không nhận được chiều cao nội dung, nên
     bảng nào cao hơn trần sẽ bị cắt cụt phần đuôi mà KHÔNG báo gì. Đo lại
     17/08/2026 ở bề rộng 390px, sau khi làm gọn và ẩn tấm promo: Giải pháp 1104px,
     Dự án 1104px, Ngành 1067px, CFDWAYS 630px (bản trước lần lượt 1418/–/1398/909
     — bỏ vạch ngăn cột và thu đệm dòng bớt ~11%, ẩn promo bớt thêm ~160px/bảng).
     Thêm mục vào menu (kể cả từ khu quản trị) thì phải ngó lại số này. */
  .mlist > li.mg.open .sub{max-height:2800px}
  .sub::before{display:none}
  /* Đệm đáy của bảng con: đặt ở đây chứ không phải padding-bottom của .sub — xem
     chú thích dài phía trên. Đọc ra vẫn là khoảng thở giữa mục cuối của bảng và
     vạch chia của mục cấp một kế tiếp. */
  .sub::after{content:"";display:block;height:8px}
  /* Dòng mục con: căn giữa theo trục dọc (bản desktop căn mép trên vì ở đó mục
     nổi bật có thêm dòng mô tả — trong drawer dòng mô tả đã bị ẩn, xem .nvt span
     bên dưới, nên mọi dòng đều chỉ còn một hàng chữ cạnh một biểu tượng). */
  .sub a{padding:8px 0;border-radius:0;font-size:.95rem;gap:12px;align-items:center}
  .sub a:active{background:transparent;color:var(--brand)}
  .sub a:active .nvi{stroke:var(--brand)}
  .nvi{width:18px;height:18px;margin-top:0}
  /* Tiêu đề nhóm là thứ DUY NHẤT còn lại để mở đầu một cột — nhẹ bớt giãn chữ và
     bỏ đệm ngang, nhưng giữ in hoa: nó phải đọc ra là nhãn, không phải một mục
     bấm được nằm lẫn trong danh sách. */
  .sub .grp{padding:16px 0 5px;letter-spacing:.1em}
  .sub .sep{margin:8px 0}

  /* Mega menu trong drawer: lưới cột duỗi thẳng thành một cột, các cột nối đuôi
     nhau. Phải hủy cả left/transform của bản desktop — kể cả luật :hover, vì màn
     cảm ứng vẫn bắn ra hover. */
  .mlist > li.mg{position:relative}
  .sub.mega,
  .mlist > li.mg:hover .sub.mega,
  .mlist > li.mg:focus-within .sub.mega{left:auto;transform:none;width:auto;min-width:0;
    display:block;padding:0 0 0 2px;border-radius:0}
  /* Phải nhắc lại kèm .cols-N: luật cột của desktop có độ ưu tiên cao hơn
     ".sub.mega" trần nên gỡ ở trên là không đủ. */
  .sub.mega.cols-1,.sub.mega.cols-2,.sub.mega.cols-3,.sub.mega.cols-4,.sub.mega.cols-5{grid-template-columns:none;grid-template-rows:none}
  .sub.mega{margin-left:0}
  /* Ranh giới giữa hai cột duỗi ra KHÔNG cần vạch: cột nào cũng mở đầu bằng một
     tiêu đề nhóm in hoa, mà nhãn ấy đã là dấu ngắt rồi. Vạch thêm vào là nói hai
     lần cùng một việc — và trên màn hẹp nó rơi đúng cạnh vạch chia mục cấp một,
     thành hai đường kẻ cùng kiểu cách nhau vài chục pixel. */
  .sub.mega .mcol + .mcol{padding-left:0;border-left:none;margin-top:0;padding-top:0;
    border-top:none}
  /* "Xem tất cả →" ở desktop bị margin-top:auto đẩy xuống chân cột cho ba cột có
     ba lối ra thẳng hàng; duỗi thành một cột thì không còn hàng nào để thẳng.
     Vạch ngăn phía trên cũng bỏ luôn — chữ xanh đậm kèm mũi tên đã đủ tách nó
     khỏi các dòng thường mà không tốn thêm một nét kẻ. */
  .sub .more,.sub.mega .more{margin:5px 0 3px;padding-top:0;border-top:0}
  .sub .more a{padding:9px 0}
  /* Chỗ chừa sẵn cho tiêu đề nhóm hai dòng chỉ có nghĩa khi các cột nằm cạnh
     nhau. Trong drawer chúng xếp dọc: không còn gì để căn thẳng, chỗ chừa
     thành khoảng trống thừa nhân với số nhóm. */
  .sub.mega .grp{min-height:0;display:block}
  .sub.mega .ft a{background:transparent;margin-bottom:0}
  /* Hàng chân là dải ngang ở desktop; nhét vào drawer thì flex-wrap bẻ nó thành
     ba dòng so le (hai mục một dòng, một mục một dòng) — trông như lỗi dựng chứ
     không ra một danh sách.
     Đã thử lưới hai cột: đều hơn, nhưng ô rộng ~162px trong khi nhãn dài nhất
     ("Năng lượng & Tiện ích") cần hơn thế, nên nó gãy dòng bỏ lại chữ mồ côi.
     Một cột tốn thêm 74px chiều cao bảng và đổi lại KHÔNG nhãn nào gãy, bất kể
     sau này đặt tên dài tới đâu. Đệm dọc nâng lên cho ô chạm đạt cỡ ngón tay.
     Hàng chân GIỮ vạch ngăn phía trên — đây là nét kẻ duy nhất còn sót lại bên
     trong bảng con, và nó gánh việc thật: các mục dưới vạch là một TRỤC KHÁC
     ("Theo ngành"), không phải cột thứ tư của cùng danh sách. */
  .sub.mega .mfr{display:block;margin-top:8px;padding:12px 0 2px}
  .sub.mega .mfr-lbl{display:block;margin-bottom:2px}
  /* Phải đổi display của chính thẻ <a>: bản desktop để inline-flex, nên dù hộp
     chứa đã là block thì chúng vẫn chảy ngang và dính sát nhau. */
  .sub.mega .mfr-links{display:block}
  .sub.mega .mfr-links a{display:flex;padding:8px 0}
  /* Trong drawer hẹp, mô tả của mục nổi bật ăn hết chỗ mà không thêm thông tin
     nào so với tiêu đề — bỏ đi, danh sách ngắn lại gần một nửa. */
  .sub .nvt span{display:none}
  /* Tấm promo ở cột cuối: ẨN trên màn hẹp. Trên desktop nó là cột thứ năm nằm
     CẠNH bốn cột chữ, không tốn dòng nào của ai. Duỗi thành một cột thì nó thành
     ~150px chắn ngang đường xuống của người đang cuộn tìm mục menu. (Lý do cũ —
     trùng đích với nút "Gửi thông tin dự án" ghim ở đáy drawer — hết hiệu lực từ
     18/08/2026 khi nút ấy bị bỏ; nhưng chỗ nó chiếm thì vẫn nguyên như thế.)
     Phải kể cả `.sub.mega .pro`: luật desktop đặt display:flex ở đúng độ ưu tiên
     đó, `.sub .pro` trần thua nó và tấm promo vẫn hiện. `.pcol` là cột bọc ngoài,
     ẩn luôn để không còn cái hộp rỗng mang lề của cột. */
  .sub .pro,.sub.mega .pro,.sub.mega .pcol{display:none}
  /* Thẻ ảnh trong drawer: ảnh nhỏ bên trái, tiêu đề + dòng phụ bên phải — hàng
     thẻ ba cột của desktop duỗi thành danh sách, mỗi thẻ cao chừng một dòng đôi. */
  .sub.mega .mcol.ccol{padding-left:0}
  .sub.mega .ccol > ul{display:block}
  .sub .mcard a{display:grid;grid-template-columns:76px minmax(0,1fr);column-gap:12px;row-gap:1px;
    align-items:center;padding:7px 0}
  .sub .mcimg{grid-row:span 2;margin:0;border-radius:7px}
  .sub .mcard b{font-size:.92rem;font-weight:600;align-self:end}
  .sub .mcd{align-self:start}
  /* mở drawer: các mục lướt vào lần lượt cho có nhịp */
  @media(prefers-reduced-motion:no-preference){
    .mlist > li{opacity:0;transform:translateX(18px);transition:opacity .25s ease,transform .25s ease}
    body.nav-open .mlist > li{opacity:1;transform:none}
    body.nav-open .mlist > li:nth-child(1){transition-delay:.05s}
    body.nav-open .mlist > li:nth-child(2){transition-delay:.08s}
    body.nav-open .mlist > li:nth-child(3){transition-delay:.11s}
    body.nav-open .mlist > li:nth-child(4){transition-delay:.14s}
    body.nav-open .mlist > li:nth-child(5){transition-delay:.17s}
    body.nav-open .mlist > li:nth-child(6){transition-delay:.2s}
    body.nav-open .mlist > li:nth-child(n+7){transition-delay:.23s}
  }
  /* Vạch trên của cụm ngôn ngữ đã do .mlist > li + li vẽ — ở đây chỉ còn đệm. */
  .langs{margin-top:0;padding:15px 0}
  .langs .langlbl{display:block;margin-right:auto}
  /* ---- đáy drawer: liên hệ nhanh ----
     Khối này GHIM cố định, không cuộn theo danh sách, nên mỗi pixel nó chiếm là
     một pixel vĩnh viễn không bao giờ dùng để hiện mục menu. Bản đầu cao 167px
     trên khung 844px — một phần năm màn hình cho hai dòng chữ và một cái nút.
     Rút còn 104px (17/08/2026) bằng cách xếp số điện thoại và email NGANG thay
     vì dọc (–36px), hạ nút CTA về cỡ .btn-sm (–5px) và thu đệm trên/dưới
     14/16 → 11/11 (–8px).
     18/08/2026 bỏ hẳn nút "Gửi thông tin dự án" — xem partials/header.njk. Đo
     ở khung 390×844: khối đáy 104px → 48.7px, danh sách menu 631px → 726px, tức
     gần hai mục cấp một nữa lọt vào khung nhìn. Đích đến ấy vẫn nằm trong menu
     và ở chân trang nên không mất lối nào.
     Chừa safe-area cho iPhone tai thỏ.
     Bóng hắt lên trên: khối đáy nổi hẳn so với danh sách, nên khi mục cuối bị
     cắt ngang ở mép này người dùng đọc ra là "còn cuộn được", không phải lỗi. */
  .mfoot{display:block;padding:11px 18px calc(11px + env(safe-area-inset-bottom));
    border-top:1px solid var(--line);background:var(--bg-soft);flex:0 0 auto;
    box-shadow:0 -10px 18px -10px rgba(7,30,48,.16)}
  /* Hai mục liên hệ nằm cùng một hàng. space-between chứ không phải chia đôi chỗ
     trống: cách này ghim mép trái của số điện thoại và mép phải của email đúng
     vào hai mép trong của khối đáy, nên cả dải đọc ra một hàng gọn thay vì hai
     mảnh trôi nổi giữa chỗ trống.
     flex-wrap + white-space:nowrap là chỗ mấu chốt: bề rộng cơ sở của mỗi mục
     CHÍNH LÀ bề rộng chữ của nó, nên hễ số điện thoại hay email bị sửa dài ra (cả
     hai đều nhập được ở khu quản trị) thì hàng tự gãy, mỗi mục về lại một dòng —
     đo thử với "phong.kinhdoanh@cfdways-vietnam.com.vn": gãy đúng, khối đáy cao
     132px thay vì 104px, không tràn ngang. Không dùng ellipsis: cắt cụt một số
     điện thoại thì thà xuống dòng còn hơn. */
  .mcontact{display:flex;flex-direction:row;flex-wrap:wrap;
    justify-content:space-between;gap:2px 14px}
  .mcontact a{flex:0 1 auto;min-width:0;white-space:nowrap;
    display:flex;align-items:center;gap:7px;padding:2px 0;font-size:.82rem;
    color:#33414e;font-weight:600}
  .mcontact a:hover{color:var(--brand);text-decoration:none}
  .mcontact svg{width:15px;height:15px;flex:0 0 auto;fill:none;stroke:var(--brand);
    stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}
  /* Header hẹp chỉ còn logo + burger — khối tài khoản chuyển xuống đáy menu trượt */
  .acct{display:none}
  .acct-m{display:flex;align-items:center;gap:12px;
    margin-bottom:13px;padding-bottom:13px;border-bottom:1px solid var(--line)}
  .acct-m .acct-id{flex:1;min-width:0;text-align:left}
  /* Trong menu trượt hai nút GIỮ chữ, chỉ thêm biểu tượng vào trước. Màn cảm ứng
     không có hover nên không có tooltip — biểu tượng trần ở đây là bắt đoán mò. */
  .acct-m .btn{width:auto;flex:0 0 auto;display:inline-flex;align-items:center;gap:7px}

  /* Một cột: bỏ hết vị trí đặt tay, ba ô tự xếp theo đúng thứ tự DOM
     (đầu → hình → thân) — chính là bố cục muốn có, không cần `order`. */
  .hero-inner{grid-template-columns:1fr}
  .hero-head,.hero-body,.hero .herovis{grid-area:auto;align-self:auto}
  .hero .herovis{margin:14px 0 18px}
  .g3,.g4,.steps{grid-template-columns:repeat(2,1fr)}
  /* còn 2 cột: ô thứ 3 mở đầu hàng dưới nhưng vẫn là "ô đứng sau một ô", vạch
     ngăn của nó rơi ra ngoài mép trái lưới — chỉ giữ vạch ở ô cột phải */
  .stats .wrap{grid-template-columns:repeat(2,1fr);gap:24px}
  .stat:nth-child(odd)::before{display:none}
  .fgrid{grid-template-columns:1fr 1fr;gap:28px}
  .finalcta{grid-template-columns:1fr}
}
@media(max-width:620px){
  .g2,.g3,.g4,.steps,.form{grid-template-columns:1fr}
  .g2.diagram{grid-template-columns:1fr;gap:26px}
  /* mobile: luôn chữ trước, hình sau */
  .g2 > figure,.g2 > .imgbox,.g2 > .gfx{order:2}

  /* .rowmedia là NGOẠI LỆ của luật ngay trên. Đo ở 390px: xếp chữ-rồi-ảnh đẩy
     tấm ảnh xuống 547px dưới chính <h2> của nó — 1,5 màn hình — và nằm SAU cả dòng
     link thoát trang, nên ai bấm link thì không bao giờ thấy ảnh. Thêm nữa .sec-soft
     không còn tô nền, nên ảnh đứng cuối mục chỉ cách eyebrow của mục SAU 88px trong khi
     cách chữ của chính nó 40px — tỉ lệ 1:2,2, mỏng, dễ đọc nhầm sang nhóm kế.
     Đưa ảnh về đúng chỗ hero đã dùng từ đầu (.hero-head = eyebrow + h1, rồi .herovis,
     rồi .hero-body): eyebrow → tiêu đề → ảnh → thân.

     Cột chữ là một <div> trơn KHÔNG mang data-cw (đã kiểm trong _site), nên
     display:contents hoà các con của nó thành ô lưới để `order` với tới — thuần CSS,
     không đụng một chữ HTML nào, băm đường dẫn của bản live-edit giữ nguyên.
     Lưu ý khi sửa: display:contents đổi cách sinh hộp chứ KHÔNG đổi cây DOM, nên
     selector vẫn phải đi qua `> div >`, không rút gọn thành `.g2.rowmedia > .eyebrow`.

     row-gap về 0 vì gap 26px của .g2 vốn chỉ để ngăn hai CỘT; giờ nó sẽ chen vào
     giữa từng đoạn văn. Bỏ đi thì nhịp dọc trả về đúng margin sẵn có của
     eyebrow/h2/p/ul — y nguyên như khi chúng còn nằm trong div. Riêng .imgbox
     không có margin nào nên phải cấp tay. min-width:0 chuyển xuống theo, vì
     `.g2>*` ở trên giờ bám vào cái div không còn sinh hộp nữa. */
  .g2.rowmedia{row-gap:0}
  .g2.rowmedia > div:not(.imgbox){display:contents}
  .g2.rowmedia > div:not(.imgbox) > *{order:4;min-width:0}
  .g2.rowmedia > div:not(.imgbox) > .eyebrow{order:1}
  .g2.rowmedia > div:not(.imgbox) > h2{order:2}
  .g2.rowmedia > .imgbox{order:3;margin:6px 0 22px}
  .fgrid{grid-template-columns:1fr}
  .hero .cta-row .btn{width:100%;text-align:center}
  /* Khối đã kéo tay (style inline) thắng luật này: giá trị kéo áp mọi bề ngang. */
  .sec{--sec-pad:44px}

}

/* ============================================================
   BÌNH LUẬN BÀI VIẾT  (macro `comments` ở partials/blocks.njk,
   danh sách do lib/commentrender.js dựng vào lúc phục vụ)

   Giữ đúng cơ chế phân tách của hệ: KHÔNG viền, KHÔNG bóng — mỗi bình luận là
   một tấm --bg-soft trên nền trang --bg, chênh nhau một nấc sáng. Không có màu
   thứ hai: bình luận của CFDWAYS lấy xanh logo, "chờ duyệt" chỉ là một vạch xám
   bên trái cộng một nhãn chữ.

   Tiền tố "cmt" cho cả cụm — style.css nạp chung với admin.css ở trang Cài đặt,
   tên trần kiểu .card hay .list là đụng nhau.
   ============================================================ */

/* Lưới y hệt .artgrid của bài viết (1fr + 300px + 56px): khối bình luận vì vậy
   thẳng hàng với CỘT CHỮ phía trên chứ không trải hết bề rộng trang — chỗ nghỉ
   bên phải là cái giữ cho phần thảo luận vẫn đọc như phần đọc. */
.cmt-wrap{display:grid;grid-template-columns:minmax(0,1fr) 300px;gap:0 56px;align-items:start}
.cmt-wrap > *{grid-column:1;min-width:0}
@media(max-width:1024px){.cmt-wrap{grid-template-columns:1fr}}

/* Vạch ngăn với bài viết: cùng cách các mục lớn khác của site tự tách nhau. */
.cmt-h2{font-size:clamp(1.25rem,1.9vw,1.5rem);margin:0 0 20px;
  padding-top:clamp(24px,3vw,34px);border-top:1px solid var(--line)}
.cmt-n{color:var(--muted);font-weight:600}
.cmt-n::before{content:"("}
.cmt-n::after{content:")"}

.cmt-list{list-style:none;margin:0;padding:0;display:grid;gap:14px}
.cmt-empty{color:var(--muted);font-size:.95rem;background:var(--bg-soft);
  border-radius:var(--r);padding:18px 20px}
.cmt-item{min-width:0}
.cmt-card{background:var(--bg-soft);border-radius:var(--r);padding:15px 20px 17px}
/* Chờ duyệt: chỉ admin/editor mới nhận được bản dựng có nó (lib/render.js gọi
   variant "draft"). Nền trắng viền nét đứt — "chưa chính thức" — thay cho vạch
   màu bên trái (vạch dày trên thẻ bo góc bị cong hai đầu, xem ghi chú ở .ev-feat). */
.cmt-item.is-wait > .cmt-card{background:#fff;border:1px dashed rgba(44,42,41,.3)}

.cmt-top{display:flex;align-items:center;gap:9px;flex-wrap:wrap;margin-bottom:9px}
.cmt-av{width:30px;height:30px;flex:0 0 auto;border-radius:50%;background:var(--fill);
  display:grid;place-items:center;font-weight:700;font-size:.85rem;color:var(--ink)}
.cmt-av.is-staff{background:var(--brand);color:#fff}
.cmt-name{font-size:.95rem;font-weight:700}
.cmt-tag{font-size:.66rem;letter-spacing:.09em;text-transform:uppercase;font-weight:800;
  padding:3px 8px;border-radius:999px;line-height:1.5}
.cmt-tag-staff{background:var(--accent-wash);color:var(--accent-ink)}
.cmt-tag-wait{background:var(--fill);color:var(--muted)}
/* Đẩy giờ sang mép phải; màn hẹp thì .cmt-top xuống dòng và nó tự về đầu dòng mới. */
.cmt-when{margin-left:auto;color:var(--muted);font-size:.8rem;white-space:nowrap}

.cmt-body p{margin:0 0 .6em;line-height:1.72;font-size:.97rem}
.cmt-body p:last-child{margin-bottom:0}

/* "@Tên" mở đầu một trả lời — thay cho cấp thụt thứ hai (xem lib/comments.js).
   Đậm vừa đủ để mắt bắt được ngay đầu dòng, không tô nền: nó là một tiếng gọi
   tên giữa câu chuyện chứ không phải một cái nhãn. */
.cmt-at{font-weight:700;color:var(--brand);text-decoration:none}
.cmt-at:hover{text-decoration:underline}

/* Hàng nút dưới mỗi bình luận: Thích và Trả lời. */
.cmt-acts{display:flex;align-items:center;gap:18px;margin-top:11px}
.cmt-like,.cmt-replybtn{padding:0;border:0;background:none;font:inherit;
  font-size:.85rem;font-weight:700;cursor:pointer}
.cmt-replybtn{color:var(--brand)}
.cmt-replybtn:hover{text-decoration:underline}
.cmt-like:focus-visible,.cmt-replybtn:focus-visible{
  outline:3px solid var(--accent);outline-offset:3px;border-radius:2px}

/* Nút Thích để MÀU CHÌM khi chưa bấm: mặc định nó là một lời mời nhỏ, chỉ khi
   đã bấm mới sáng lên màu thương hiệu — nhờ vậy liếc qua một danh sách dài là
   thấy ngay mình đã thích những cái nào. */
.cmt-like{display:inline-flex;align-items:center;gap:6px;color:var(--muted)}
.cmt-likei{fill:currentColor;flex:0 0 auto;transition:transform .18s ease}
.cmt-like:hover{color:var(--brand)}
.cmt-like.is-liked{color:var(--brand)}
.cmt-like.is-liked .cmt-likei{transform:translateY(-1px) scale(1.08)}
/* Trống khi chưa ai thích: :empty giấu cả khoảng gap, không để lại số "0". */
.cmt-liken{font-weight:600;font-variant-numeric:tabular-nums}
.cmt-liken:empty{display:none}
.cmt-liken:not(:empty)::before{content:"·";margin-right:6px;color:var(--line)}
@media(prefers-reduced-motion:reduce){.cmt-likei{transition:none}}

/* Trả lời: thụt vào một cấp DUY NHẤT (lib/comments.js không cho sâu hơn). */
.cmt-sub{list-style:none;display:grid;gap:12px;margin:12px 0 0 clamp(14px,2.4vw,30px);
  padding-left:18px;border-left:2px solid var(--line)}
.cmt-sub .cmt-card{padding:13px 17px 15px}
.cmt-sub .cmt-av{width:26px;height:26px;font-size:.78rem}

/* ---------- ô soạn bình luận ----------
   Bấm "Trả lời" là site.js CHUYỂN nguyên biểu mẫu này xuống dưới bình luận đó,
   nên nó phải trông đúng ở cả hai chỗ: đứng riêng cuối danh sách, và nằm lồng
   trong một mục. Khác biệt duy nhất là khoảng cách trên. */
.cmt-form{margin-top:24px;background:var(--bg-soft);border-radius:var(--r);
  padding:clamp(18px,2.2vw,26px)}
.cmt-item > .cmt-form{margin-top:12px}
.cmt-formh{font-size:1.02rem;margin:0 0 14px}

.cmt-to{margin:0 0 14px;font-size:.88rem;color:var(--muted)}
.cmt-cancel{margin-left:8px;padding:0;border:0;background:none;font:inherit;
  font-size:.85rem;font-weight:700;color:var(--brand);cursor:pointer}
.cmt-cancel:hover{text-decoration:underline}

.cmt-two{display:grid;grid-template-columns:1fr 1fr;gap:14px}
@media(max-width:620px){.cmt-two{grid-template-columns:1fr}}
.cmt-field{margin-top:14px}
.cmt-form label{display:block;font-size:.86rem;font-weight:700;margin-bottom:7px}
.cmt-form label small{color:var(--muted);font-weight:500}
/* Ô nhập trắng trên tấm xám — cùng cách trang Liên hệ làm, và cùng lý do: viền
   --line trên nền --bg-soft gần như tàng hình nên nền trắng mới là thứ nói "gõ
   vào đây". 16px để iOS không phóng to trang khi đặt con trỏ. */
.cmt-form input[type=text],.cmt-form input[type=email],.cmt-form textarea{
  width:100%;padding:12px 13px;border:1.5px solid rgba(44,42,41,.2);border-radius:var(--r-sm);
  font-family:inherit;font-size:16px;background:#fff;transition:border-color .15s, box-shadow .15s}
.cmt-form textarea{line-height:1.65;resize:vertical;min-height:110px}
.cmt-form input:focus,.cmt-form textarea:focus{border-color:var(--accent);outline:none;
  box-shadow:0 0 0 3px rgba(43,101,176,.16)}

.cmt-check{display:flex;align-items:center;gap:9px;margin:13px 0 0;
  font-size:.88rem;font-weight:500;cursor:pointer}
.cmt-check input{width:16px;height:16px;flex:0 0 auto;accent-color:var(--brand)}

.cmt-foot{display:flex;align-items:center;gap:18px;flex-wrap:wrap;margin-top:16px}
.cmt-rule{margin:0;max-width:46ch;color:var(--muted);font-size:.82rem;line-height:1.55}

/* Thông báo sau khi bấm gửi. Ẩn hẳn khi rỗng để không chừa một dòng trắng. */
.cmt-msg{display:none;margin:14px 0 0;font-size:.9rem;font-weight:600}
.cmt-msg.show{display:block}
.cmt-msg.ok{color:#1a7a4a}
.cmt-msg.err{color:#c8392b}

/* Bẫy máy gửi rác (ô "website"). Đưa ra ngoài màn hình chứ KHÔNG display:none:
   vài loại máy bỏ qua ô ẩn hẳn, nhưng vẫn điền ô chỉ nằm ngoài khung nhìn.
   .cthp là bản dùng cho form liên hệ, do site.js cắm vào lúc chạy. */
.cmt-hp,.cthp{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}

/* Thông báo của form liên hệ — cùng bảng màu với .cmt-msg, nằm đầu .ctfoot. */
.ctmsg{display:none;margin:0 0 12px;font-size:.92rem;font-weight:600;grid-column:1/-1}
.ctmsg.show{display:block}
.ctmsg.ok{color:#1a7a4a}
.ctmsg.err{color:#c8392b}

/* ---------- lightbox: bấm vào ảnh trong lưới ảnh (.gal) để xem to ----------
   Lớp .gal do layout đặt lên lưới ảnh cuối trang (case-study / sự kiện / tin);
   site.js dựng hộp xem và chuyển ảnh. Ở chế độ sửa (.cw-editing) bấm vào khung
   ảnh là CHỌN Ô để đặt ảnh (xem initImageSlots) — lightbox nhường, nên con trỏ
   cũng không hiện kính lúp. */
.gal .imgbox{cursor:zoom-in}
.gal .imgbox.failed,.cw-editing .gal .imgbox{cursor:default}
.gal .imgbox:focus-visible{outline:2px solid var(--brand);outline-offset:3px}
/* z-index trên 200 của .srch-ov / .cw-bar: khi đang xem ảnh thì đây là lớp cao
   nhất của trang. Ẩn bằng visibility như .srch-ov (gỡ khỏi luồng tab, vẫn có
   chuyển động mờ dần). */
.lb{position:fixed;inset:0;z-index:210;display:flex;align-items:center;justify-content:center;
  opacity:0;visibility:hidden;transition:opacity .2s ease, visibility 0s .2s}
.lb.on{opacity:1;visibility:visible;transition:opacity .2s ease, visibility 0s 0s}
body.lb-open{overflow:hidden}
.lb-scrim{position:absolute;inset:0;background:rgba(7,30,48,.94)}
.lb-fig{position:relative;margin:0;display:flex;flex-direction:column;align-items:center;
  max-width:calc(100vw - 140px);padding:56px 0 40px;pointer-events:none}
.lb-fig img{display:block;max-width:100%;max-height:calc(100vh - 128px);width:auto;height:auto;
  object-fit:contain;border-radius:6px;box-shadow:0 24px 60px rgba(0,0,0,.55);
  pointer-events:auto;transform:scale(.97);transition:transform .2s ease}
.lb.on .lb-fig img{transform:none}
.lb-cap{margin-top:12px;color:rgba(255,255,255,.85);font-size:.9rem;line-height:1.5;text-align:center;
  max-width:640px;pointer-events:auto}
.lb-cap[hidden]{display:none}
.lb-n{position:absolute;top:18px;left:50%;transform:translateX(-50%);color:rgba(255,255,255,.7);
  font-size:.8rem;letter-spacing:.08em;font-variant-numeric:tabular-nums}
/* Nút tròn nổi trên nền tối: không theo .btn của site (nền trắng/xanh) vì ở đây
   chúng phải lùi lại sau tấm ảnh. Vùng bấm 46px đủ cho ngón tay. */
.lb-btn{position:absolute;display:flex;align-items:center;justify-content:center;width:46px;height:46px;
  border-radius:50%;border:1.5px solid rgba(255,255,255,.35);background:rgba(255,255,255,.08);
  color:#fff;cursor:pointer;padding:0;transition:background .15s, border-color .15s}
.lb-btn svg{width:22px;height:22px;fill:none;stroke:currentColor;stroke-width:2;
  stroke-linecap:round;stroke-linejoin:round}
.lb-btn:hover{background:rgba(255,255,255,.2);border-color:rgba(255,255,255,.7)}
.lb-btn:focus-visible{outline:2px solid #fff;outline-offset:2px}
.lb-x{top:14px;right:14px}
.lb-prev{left:16px;top:50%;transform:translateY(-50%)}
.lb-next{right:16px;top:50%;transform:translateY(-50%)}
/* Chỉ một ảnh thì không có gì để chuyển: giấu mũi tên và bộ đếm. */
.lb.lb-one .lb-prev,.lb.lb-one .lb-next,.lb.lb-one .lb-n{display:none}
@media(max-width:720px){
  /* Màn hẹp: ảnh lấy hết bề ngang, mũi tên xuống đáy để không đè lên ảnh.
     Vuốt ngang cũng chuyển được (site.js). */
  .lb-fig{max-width:100vw;padding:56px 12px 84px}
  .lb-fig img{max-height:calc(100vh - 150px)}
  .lb-prev,.lb-next{top:auto;bottom:18px;transform:none}
  .lb-prev{left:calc(50% - 60px)}
  .lb-next{right:calc(50% - 60px)}
}
@media(prefers-reduced-motion:reduce){
  .lb,.lb.on,.lb-fig img{transition:none}
}

/* ================= tiện ích cuối bảng =================
   .plain — ảnh PNG/SVG có nền trong suốt: tắt mọi tấm nền tô (khung, ô ảnh, và
   tấm trắng mà .contain đắp dưới img) cùng đổ bóng của khung, để màu nền của
   section xuyên qua đúng như file gốc.

   ĐẶT Ở CUỐI FILE là có chủ ý: nhiều khu có luật riêng cùng độ đặc hiệu (0,2,0)
   tô nền cho .frame/.imgbox — .cst-aside chẳng hạn. Cùng độ đặc hiệu thì luật
   đứng sau thắng, nên .plain phải nằm sau tất cả mới có tác dụng ở mọi khu.

   Chỉ đặt khi ảnh THỰC SỰ trong suốt: PNG nền trắng đặc mà bỏ nền thì chính nó
   vẫn là mảng trắng, chỉ khác là mất bo góc của khung. Kiểm bằng cách mở ảnh
   trên một nền màu chói — còn thấy màu đó xuyên qua thì mới là ảnh trong suốt. */
.imgbox.plain,.imgbox.plain img,.frame.plain{background:transparent}
.frame.plain{box-shadow:none}

/* ---------- trang Sự kiện (su-kien.html / events.html) ----------
   Tiền tố "ev" cho cả cụm — cùng lý do với "ct" ở trang Liên hệ. Ba trạng thái
   (sắp diễn ra · đang mở · đã diễn ra) được phân biệt bằng một chấm màu và một
   nhãn .tag, không bằng nền: trang vẫn chỉ có xanh logo + một thang xám.
   Bố cục cố ý GỌN: biểu mẫu đăng ký nằm ngay trong tấm sự kiện gần nhất, các
   sự kiện khác là dòng một hàng, webinar theo yêu cầu không có ảnh, sự kiện cũ
   gấp trong <details>. */

/* Thanh trạng thái dính dưới header, thay cho .rtabs (ở đây là NEO cuộn, không
   ẩn/hiện khối). */
.ev-nav{position:sticky;top:var(--hdr-stuck);z-index:5;background:var(--bg);
  border-bottom:1px solid var(--line);margin-bottom:-1px}
.ev-nav .wrap{display:flex;align-items:center;gap:4px;overflow-x:auto;scrollbar-width:none}
.ev-nav .wrap::-webkit-scrollbar{display:none}
.ev-nav a{display:inline-flex;align-items:center;gap:8px;padding:14px 12px;font-size:.92rem;
  font-weight:600;color:var(--muted);white-space:nowrap;flex:0 0 auto}
.ev-nav a:hover{color:var(--ink);text-decoration:none}
.ev-nav .rnum{margin-left:-2px}
.ev-nav-cta{margin-left:auto;color:var(--brand)!important}
.ev-dot{width:9px;height:9px;border-radius:50%;flex:0 0 auto}
.ev-dot-up{background:var(--brand)}
.ev-dot-on{background:#1a9e5f;box-shadow:0 0 0 3px rgba(26,158,95,.18)}
.ev-dot-past{background:#b5b3b1}

/* Nhãn trạng thái/loại. Loại sự kiện dùng xanh logo ở các độ đậm; "đang mở" là
   màu duy nhất khác họ (lục) vì nó báo TRẠNG THÁI SỐNG, giống chấm trên thanh. */
.ev-tag-webinar{background:var(--accent-wash);color:var(--accent-ink)}
.ev-tag-workshop{background:var(--brand);color:#fff}
.ev-tag-seminar,.ev-tag-user{background:#E0E0DF;color:var(--ink)}
.ev-tag-expo{background:#fff4e3;color:#8a5a06}
.ev-tag-up{background:#fff;color:var(--brand);border:1px solid var(--brand)}
.ev-tag-on{background:#e3f4ea;color:#156b40}

/* Ô ngày: số to, tháng/năm nhỏ — thứ mắt tìm đầu tiên ở một lịch. */
.ev-date{flex:0 0 auto;width:72px;text-align:center;border-radius:var(--r);background:var(--bg-soft);
  padding:10px 4px 9px;line-height:1;align-self:flex-start}
.ev-date b{display:block;font-size:2rem;font-weight:800;color:var(--brand);letter-spacing:-.02em}
.ev-date span{display:block;font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;
  color:var(--muted);margin-top:5px;line-height:1.25}
.ev-date.sm{width:62px;padding:8px 4px 7px}
.ev-date.sm b{font-size:1.6rem}

/* Sự kiện nổi bật: tấm hai cột — nội dung trái, BIỂU MẪU ĐĂNG KÝ phải. Khách
   thấy sự kiện và ô đăng ký trong cùng một khung nhìn, không phải cuộn tìm. */
/* Thang sắc độ của trang: tấm nổi bật TRẮNG, cột biểu mẫu xám nhạt, các dòng
   thường chỉ kẻ viền không tô — nhìn lướt là biết đâu là việc chính.
   KHÔNG dùng vạch màu dày một cạnh (border-top/left 3px) trên thẻ bo góc ở bất
   kỳ đâu trên site: vạch bị uốn cong hai đầu theo góc bo, người dùng thấy ngay
   là kiểu giao diện AI sinh ra (10/2026). Nhấn bằng cỡ chữ và bố cục. */
.ev-feat{display:grid;grid-template-columns:minmax(0,1.35fr) minmax(320px,1fr);gap:0;background:#fff;
  border:1px solid var(--line);border-radius:var(--r);overflow:hidden;box-shadow:var(--lift)}
.ev-feat-main{display:flex;gap:22px;padding:clamp(22px,2.6vw,32px)}
.ev-feat-body{min-width:0;flex:1}
.ev-feat-body h3{font-size:clamp(1.2rem,1.8vw,1.45rem);line-height:1.28;letter-spacing:-.01em;margin:8px 0 12px;color:var(--ink)}
/* Cột biểu mẫu là flex dọc: lưới .form chiếm hết chiều cao, hàng ô "Câu hỏi"
   (hàng 5) là 1fr nên textarea nở ra lấp phần dư thay vì để trống dưới nút.
   Dưới 1024px cột xếp chồng, chiều cao tự nhiên nên 1fr = nội dung. */
.ev-feat-form{display:flex;flex-direction:column;padding:clamp(20px,2.4vw,30px);background:var(--bg-soft);border-left:1px solid var(--line)}
.ev-feat-form .form{gap:11px;flex:1;grid-template-rows:repeat(4,auto) minmax(0,1fr) auto}
.ev-feat-form .form .full:has(textarea){display:flex;flex-direction:column}
.ev-feat-form .form textarea{flex:1;min-height:64px;resize:vertical}
.ev-feat-form .form label{margin-bottom:5px;font-size:.82rem}
.ev-feat-form .form input,.ev-feat-form .form textarea,.ev-feat-form .form select{padding:10px 12px;font-size:15px;border-color:rgba(44,42,41,.18)}
.ev-feat-form .ctfoot{margin-top:4px;gap:10px 16px}
.ev-feat-form .ctfoot p{font-size:.78rem;min-width:180px}
.ev-spkline{font-size:.86rem;color:var(--muted);margin:0;line-height:1.5}
.ev-spkline b{color:var(--ink);font-weight:700}

/* Dòng thông tin có biểu tượng nét mảnh (giờ · nơi · đối tượng). */
.ev-facts{list-style:none;padding:0;margin:0 0 14px;display:grid;gap:6px}
.ev-facts li{display:flex;align-items:flex-start;gap:10px;font-size:.9rem;color:var(--ink);line-height:1.45}
.ev-facts svg{width:18px;height:18px;flex:0 0 auto;margin-top:2px;fill:none;stroke:var(--brand);
  stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}

/* Chương trình: danh sách giờ — chữ nhỏ, không kẻ bảng. */
.ev-agenda{background:var(--bg);border:1px solid var(--line);border-radius:var(--r-sm);padding:12px 16px 10px;margin-bottom:12px}
.ev-agenda h4{font-size:.72rem;letter-spacing:.12em;text-transform:uppercase;color:var(--muted);margin:0 0 6px}
/* Là <details>: desktop luôn mở (không có dấu mũi tên, không bấm được); dưới
   620px site.js đóng lại, summary thành nút có mũi tên. */
.ev-agenda summary{list-style:none;pointer-events:none;display:flex;align-items:center;gap:8px}
.ev-agenda summary::-webkit-details-marker{display:none}
.ev-agenda summary::after{content:"";width:6px;height:6px;border-right:1.5px solid var(--muted);border-bottom:1.5px solid var(--muted);
  transform:rotate(45deg) translateY(-3px);margin-left:auto;display:none}
.ev-agenda[open] summary::after{transform:rotate(-135deg) translateY(-2px)}
.ev-agenda ol{list-style:none;margin:0;padding:0}
.ev-agenda li{display:flex;gap:12px;font-size:.9rem;line-height:1.45;padding:5px 0;border-top:1px solid var(--line)}
.ev-agenda li:first-child{border-top:0}
.ev-agenda li b{flex:0 0 46px;font-variant-numeric:tabular-nums;color:var(--brand)}

/* Các sự kiện còn lại: một hàng — ngày · nhãn+giờ+nơi · tên · nút. */
.ev-list{display:grid;gap:10px}
.ev-row{display:flex;gap:18px;align-items:center;background:transparent;border:1px solid var(--line);border-radius:var(--r);
  padding:14px 20px}
.ev-row-body{flex:1;min-width:0}
.ev-row-body .pcard-top{margin-bottom:0}
.ev-row-body h3{font-size:1.02rem;line-height:1.35;margin:4px 0 0;color:var(--ink)}
.ev-row-act{flex:0 0 auto}

/* Webinar theo yêu cầu: bốn DÒNG (số thứ tự · tên · tóm tắt · nút), cả dòng là
   liên kết chọn sẵn sự kiện trong biểu mẫu. Ảnh thumbnail không thêm thông tin
   nào nên bỏ — tiết kiệm nửa màn hình. */
.ev-od{gap:8px}
.ev-odrow{color:inherit;text-decoration:none;padding:12px 18px}
.ev-odrow:hover{background:var(--bg-soft);text-decoration:none}
.ev-odrow:hover b{color:var(--brand)}
.ev-odno{flex:0 0 40px;font-size:1.05rem;font-weight:800;color:var(--brand)}
.ev-odrow .ev-row-body b{display:block;font-size:.98rem;line-height:1.35}
.ev-odrow .ev-psum{margin-top:2px}

/* Đã diễn ra: dòng thời gian. Ngày ở cột trái cố định, tên đậm, "Xem tổng kết"
   bên phải. Dòng là <a> khi có bài, là <div> khi không. 4 dòng cũ nhất gấp trong
   <details> — không JS. */
.ev-past{display:grid;gap:0}
.ev-prow{display:flex;gap:18px;align-items:center;padding:13px 8px;border-bottom:1px solid var(--line);
  color:inherit;text-decoration:none;border-radius:var(--r-sm)}
a.ev-prow:hover{background:var(--bg-soft);text-decoration:none}
a.ev-prow:hover b{color:var(--brand)}
.ev-pdate{flex:0 0 108px;font-weight:800;font-size:.92rem;color:var(--brand);font-variant-numeric:tabular-nums}
.ev-pbody{flex:1;min-width:0;display:block}
.ev-pbody .pcard-top{margin-bottom:4px}
.ev-pbody > b{display:block;font-size:1rem;line-height:1.35;font-weight:700}
.ev-psum{display:block;font-size:.86rem;color:var(--muted);line-height:1.5}
.ev-pmore{flex:0 0 auto;font-size:.86rem;font-weight:600;color:var(--brand);white-space:nowrap}
.ev-pmuted{color:var(--muted);font-weight:500}
.ev-fold summary{list-style:none;cursor:pointer;padding:12px 8px;font-size:.88rem;font-weight:600;color:var(--brand);
  display:flex;align-items:center;gap:10px}
.ev-fold summary::-webkit-details-marker{display:none}
.ev-fold summary::before{content:"";width:7px;height:7px;border-right:2px solid currentColor;border-bottom:2px solid currentColor;
  transform:rotate(45deg);margin:0 2px 3px 2px;flex:0 0 auto}
.ev-fold[open] summary{display:none}

/* Nút "Đăng ký" ở thẻ sự kiện vừa chọn sẵn ô này (site.js) — nháy viền một nhịp. */
.form select.ev-picked{border-color:var(--accent);box-shadow:0 0 0 3px rgba(43,101,176,.16)}

@media(max-width:1024px){
  .ev-feat{grid-template-columns:1fr}
  .ev-feat-form{border-left:0;border-top:1px solid var(--line)}
  .ev-feat-form .form{grid-template-rows:none}
}
@media(max-width:860px){
  .ev-row{flex-wrap:wrap}
  .ev-row-act{flex:0 0 100%}
  .ev-odrow .ev-pmore{flex:0 0 100%;padding-left:58px}
  .ev-prow .ev-pmore{flex:0 0 100%;padding-left:126px}
}
@media(max-width:620px){
  .ev-nav a{padding:12px 9px;font-size:.86rem}
  .ev-feat-main{flex-direction:column;gap:12px;padding:18px}
  .ev-date,.ev-date.sm{width:auto;display:inline-flex;align-items:baseline;gap:6px;padding:6px 10px}
  .ev-date b,.ev-date.sm b{font-size:1.3rem}
  .ev-date span{margin:0}.ev-date span br{display:none}
  .ev-row{flex-direction:column;align-items:flex-start;gap:8px;padding:14px 16px}
  .ev-row-act{flex:0 0 auto}
  .ev-odrow{flex-direction:row;flex-wrap:wrap;gap:6px 12px}
  .ev-odrow .ev-row-body{flex:1 1 calc(100% - 52px)}
  .ev-prow{flex-wrap:wrap;gap:6px 14px;padding:12px 4px}
  .ev-pdate{flex:0 0 100%}
  .ev-odrow .ev-pmore,.ev-prow .ev-pmore{padding-left:0}
  /* Dòng meta chỉ còn ngày · giờ; nơi/phí đã có ở trang chi tiết. */
  .ev-row .ev-meta-x{display:none}
  /* Chương trình gấp được: summary thành nút, có mũi tên. */
  .ev-agenda summary{pointer-events:auto;cursor:pointer}
  .ev-agenda summary::after{display:block}
  .ev-agenda:not([open]){padding-bottom:12px}
  .ev-agenda:not([open]) h4{margin-bottom:0}
}

/* Tên sự kiện là liên kết tới trang chi tiết (từ khi sự kiện quản lý được ở khu
   quản trị): màu chữ như tiêu đề, rê chuột mới xanh. */
.ev-feat-body h3 a,.ev-row-body h3 a{color:inherit;text-decoration:none}
.ev-feat-body h3 a:hover,.ev-row-body h3 a:hover{color:var(--brand)}
.ev-feat-sum{color:var(--ink);font-size:.95rem;line-height:1.55;margin:0 0 12px}
.ev-odrow .ev-row-body h3{font-size:.98rem;margin:0}
.ev-odrow .ev-odno{align-self:center}

/* ===================== Thang sắc độ của thẻ (09/2026) =====================
   Trước đây mọi thẻ đều tô --bg-soft: một trang có 5–6 lưới thẻ xám xếp chồng
   thì mắt không phân biệt được khối chính với khối phụ (soát 04/09/2026). Chia
   lại HAI mức, ghi đè các luật khai ở trên — sửa màu thẻ thì sửa Ở ĐÂY:
   · TÔ NỀN (--bg-soft): dải trang .pageband/.hero, dải số liệu, .finalcta,
     .ctpanel, cột biểu mẫu sự kiện — mỗi trang chỉ vài tấm, là chỗ cần "nặng".
   · KẺ VIỀN (nền trắng, viền --line): mọi thẻ trong lưới — .card .path .step
     .pcard .toplist .railcard .notecard .logostrip .cl. Rê chuột mới đổ nền xám.
   Trang Sự kiện đã đi trước theo đúng thang này (.ev-feat trắng, .ev-row viền). */
.card,.path,.step,.pcard,.toplist,.railcard,.notecard,.logostrip .cl{
  background:#fff;border:1px solid var(--line)}
.card:hover,.path:hover,.step:hover,.pcard:hover,.logostrip .cl:hover{background:var(--bg-soft)}
.logostrip .cl-logo{box-shadow:none}
/* Dòng bài viết (từ thẻ thứ 4 trong .postgrid.split) vốn không phải thẻ. */
.postgrid.split>.pcard:nth-child(n+4){background:none;border:0;border-top:1px solid var(--line)}
/* Dưới 620px các nhóm .mstack tan thành MỘT khối chia vạch (xem khối .mstack ở
   trên); luật viền vừa thêm có cùng độ ưu tiên và khai sau nên phải nhắc lại. */
@media(max-width:620px){
  .mstack > *{border:0;background:none}
  .mstack > * + *{border-top:1px solid var(--line)}
  .mstack > *:hover{background:none}
  .mstack > .mrow.on{background:var(--bg-soft)}
  .steps.mstack > .step{border:0}
  .steps.mstack > .step + .step{border-top:1px solid var(--line)}
  .steps.mstack > .step.mrow.on{background:var(--bg-soft)}
}

/* Trang Dự án: thẻ case study trắng viền theo luật trên; cột KPI tô nền nhạt và
   số to hơn để quét dọc danh mục là đọc ra kết quả; rãnh năm ở phụ lục bớt
   nặng (số nhỏ hơn, màu xám) vì nó chỉ là mốc, không phải nội dung. */
.pjgrid{gap:14px}
.pjcard-kpi{background:var(--bg);border-top:1px solid var(--line)}
/* Giá trị KPI phải NHỎ HƠN tiêu đề thẻ (1.14rem = 18.2px ở lưới bốn cột). Thẻ
   dọc xếp tiêu đề ngay trên dải số, mà thứ to nhất trong một khối chồng đọc ra
   là tiêu đề của khối đó — để 1.5rem như hàng ngang cũ thì cụm giá trị thành
   tên dự án, tên dự án thành phụ đề. 1.05rem giữ lại phần lớn sức nặng mà khối
   thang sắc độ cố ý thêm cho dải này, vẫn đứng dưới tiêu đề.
   Luật này bắt buộc nằm Ở ĐÂY, trong khối thang sắc độ — nó là tầng ngoài cùng,
   viết .pjkpi b ở giữa file là viết một luật chết. Cùng lý do với luật một cột
   ngay dưới: ở đó tiêu đề lên 1.28rem nên con số theo lên 1.15rem. */
.pjkpi b{font-size:1.05rem;font-weight:700;line-height:1.18}
.pjkpi span{font-size:.8rem}
@media(max-width:720px){
  .pjkpi b{font-size:1.15rem}
}
.yrtag{background:transparent}
.yrtagin b{font-size:1.35rem;font-weight:700;color:var(--muted)}

/* ---------- bước quy trình có biểu tượng + mũi tên nối (.steps.flow) ----------
   Trang Giải pháp (10/2026), rồi mọi khối bốn bước: Dịch vụ, Liên hệ, ba trang
   trụ (solution.njk) và năm trang ngành (industry.njk — khóa "ic" trong front
   matter steps). Bốn bước đọc thành MỘT CHUỖI chứ không phải bốn thẻ rời. Biểu tượng chọn bằng thuộc tính data-ic trên .step — vẽ bằng ảnh nền SVG
   chứ không chèn thẻ <svg>: thêm phần tử con là đổi đường dẫn băm data-cw của
   h4/p bên cạnh, bản sửa tại chỗ đã lưu của chúng mồ côi (lib/editable.js).
   Specificity (0,3,0) để thắng `.step:hover{background:…}` (shorthand xóa ảnh nền).
   Thêm biểu tượng mới: một dòng data-ic nữa, nét 1.6, màu --brand (#2B65B0). */
.steps .step[data-ic]{background-repeat:no-repeat;background-position:right 20px top 20px;background-size:30px 30px}
.steps .step[data-ic="do"]{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%232B65B0' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3.3 19a10 10 0 1 1 17.4 0'/%3E%3Cpath d='m12 14 4-4'/%3E%3Ccircle cx='12' cy='14' r='1.2'/%3E%3C/svg%3E")}
.steps .step[data-ic="mo-hinh"]{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%232B65B0' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M21 8 12 3 3 8v8l9 5 9-5z'/%3E%3Cpath d='m3 8 9 5 9-5M12 13v8'/%3E%3C/svg%3E")}
.steps .step[data-ic="so-sanh"]{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%232B65B0' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 20h18'/%3E%3Cpath d='M7 16V9'/%3E%3Cpath d='M12 16V5'/%3E%3Cpath d='M17 16v-5'/%3E%3C/svg%3E")}
.steps .step[data-ic="kiem-chung"]{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%232B65B0' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='m8 12.5 3 3 5-6'/%3E%3C/svg%3E")}
.steps .step[data-ic="ho-so"]{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%232B65B0' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z'/%3E%3C/svg%3E")}
.steps .step[data-ic="chan-doan"]{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%232B65B0' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='m20 20-4-4'/%3E%3Cpath d='M7 11h2l1-2.5 2 5 1-2.5h1'/%3E%3C/svg%3E")}
.steps .step[data-ic="ban-giao"]{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%232B65B0' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M14 3H7a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8z'/%3E%3Cpath d='M14 3v5h5'/%3E%3Cpath d='m9 14.5 2 2 4-4'/%3E%3C/svg%3E")}
.steps .step[data-ic="y-tuong"]{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%232B65B0' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9 18h6M10 21h4'/%3E%3Cpath d='M12 3a6 6 0 0 0-3.5 10.9c.6.5 1 1.2 1 2V16h5v-.1c0-.8.4-1.5 1-2A6 6 0 0 0 12 3z'/%3E%3C/svg%3E")}
.steps .step[data-ic="thiet-ke"]{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%232B65B0' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 20h16'/%3E%3Cpath d='m6 16 9.5-9.5 2.5 2.5L8.5 18.5H6z'/%3E%3Cpath d='m13.5 8.5 2.5 2.5'/%3E%3C/svg%3E")}
.steps .step[data-ic="theo-doi"]{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%232B65B0' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 12h4l3-7 4 14 3-7h4'/%3E%3C/svg%3E")}
.steps .step[data-ic="giao-dien"]{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%232B65B0' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='12' rx='2'/%3E%3Cpath d='M8 20h8M12 16v4'/%3E%3Cpath d='m7 12 3-3 2 2 4-4'/%3E%3C/svg%3E")}
.steps .step[data-ic="ranh-gioi"]{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%232B65B0' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 8V4h4M16 4h4v4M20 16v4h-4M8 20H4v-4'/%3E%3Ccircle cx='12' cy='12' r='2.5'/%3E%3C/svg%3E")}
.steps .step[data-ic="dao-tao"]{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%232B65B0' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m2 9 10-5 10 5-10 5z'/%3E%3Cpath d='M6 11v5c0 1.5 3 3 6 3s6-1.5 6-3v-5'/%3E%3C/svg%3E")}
.steps .step[data-ic="thu"]{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%232B65B0' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='5' width='18' height='14' rx='2'/%3E%3Cpath d='m3 7 9 6 9-6'/%3E%3C/svg%3E")}
.steps .step[data-ic="ky-su"]{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%232B65B0' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='8' r='4'/%3E%3Cpath d='M4 21a8 8 0 0 1 16 0'/%3E%3C/svg%3E")}
.steps .step[data-ic="trao-doi"]{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%232B65B0' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M21 12a8 8 0 0 1-11.6 7.1L4 20l1-4.6A8 8 0 1 1 21 12z'/%3E%3C/svg%3E")}
.steps .step[data-ic="pham-vi"]{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%232B65B0' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M14 3H7a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8z'/%3E%3Cpath d='M14 3v5h5'/%3E%3Cpath d='M9 13h6M9 17h6'/%3E%3C/svg%3E")}
/* Chừa chỗ cho biểu tượng: tiêu đề dài không chạy xuống dưới nó. */
.steps .step[data-ic] h4{padding-right:34px}
/* Mũi tên nối: chỉ khi bốn bước nằm trên MỘT hàng (trên 1024px; dưới đó lưới
   2 cột, mũi tên ô thứ hai sẽ chỉ ra khoảng trống). Nằm giữa khe 18px. */
@media(min-width:1025px){
  .steps.flow .step:not(:last-child)::after{content:"";position:absolute;top:50%;right:-14px;width:9px;height:9px;
    border-top:2px solid var(--accent);border-right:2px solid var(--accent);transform:translateY(-50%) rotate(45deg);opacity:.55}
}
/* Dưới 620px .mstack gập bốn bước thành các dòng bấm mở, góc phải là mũi tên
   mở dòng — biểu tượng sẽ đè lên nó. */
@media(max-width:620px){
  .steps.mstack .step[data-ic]{background-image:none}
  .steps.mstack .step[data-ic] h4{padding-right:0}
}

/* Biểu tượng ba thẻ Tầm nhìn / Sứ mệnh / Giá trị cốt lõi (Về CFDWAYS, VI+EN).
   Cùng lý do với data-ic của .step ở trên: không chèn thẻ <svg>, vẽ bằng giả phần
   tử — nó không tính vào đường dẫn băm data-cw. Ảnh khai một lần vào biến --ic,
   hai chỗ vẽ dùng chung. Khổ rộng: ô 34px đứng trên tiêu đề (.body là cột flex).
   Dưới 620px site.js biến thẻ thành dòng bấm mở (.mrow, nút .mrow-btn nằm TRONG
   h3): biểu tượng chuyển xuống đầu dòng, mũi tên mở vẫn ở cuối dòng. */
.card[data-ic="tam-nhin"]{--ic:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%232B65B0' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2 12s3.6-7 10-7 10 7 10 7-3.6 7-10 7S2 12 2 12z'/%3E%3Ccircle cx='12' cy='12' r='3'/%3E%3C/svg%3E")}
.card[data-ic="su-menh"]{--ic:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%232B65B0' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='m15.5 8.5-2 5-5 2 2-5z'/%3E%3C/svg%3E")}
.card[data-ic="gia-tri"]{--ic:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%232B65B0' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 3h12l4 6-10 12L2 9z'/%3E%3Cpath d='M2 9h20'/%3E%3Cpath d='m10 3-2 6 4 12 4-12-2-6'/%3E%3C/svg%3E")}
.card[data-ic] .body::before{content:"";flex:0 0 auto;width:34px;height:34px;margin-bottom:14px;
  background:var(--ic) no-repeat center/contain}
@media(max-width:620px){
  .mstack > .mrow[data-ic] .body::before{display:none}
  .card[data-ic] .mrow-btn::before{content:"";flex:0 0 22px;height:22px;
    background:var(--ic) no-repeat center/contain}
}

/* Vòng Simcenter cạnh tiêu đề "Phần mềm Siemens" ở trang Giải pháp. */
.sw-wheel{float:right;width:132px;height:auto;margin:-6px 0 8px 18px}
@media(max-width:620px){.sw-wheel{width:96px}}

/* Ba thẻ đầu trang Phần mềm (VI+EN, 10/2026): mỗi thẻ có một sơ đồ nét định
   tính phía trên chữ — hỗ trợ (hội thoại + ghim Hà Nội), benchmark (mô hình →
   kết quả & thời gian tính), đào tạo (đường cong làm chủ). Không có số liệu.
   SVG nằm thẳng trong HTML; lib/editable.js bỏ qua <svg> nên chữ nhãn trong hình
   không thành ô sửa. Dưới 620px nhóm là .mstack (dòng bấm mở) — hình bị ẩn để
   mỗi dòng vẫn chỉ còn tiêu đề. */
.swart{flex:0 0 auto;height:150px;display:grid;place-items:center;
  background:linear-gradient(180deg,#EEF2F7,#F7F8FA);border-bottom:1px solid var(--line)}
.card:hover .swart{background:linear-gradient(180deg,#E4EAF2,#EEF1F5)}
.swart svg{width:min(260px,86%);height:auto;overflow:visible}
.swart text{font-family:var(--font-body);font-size:10.5px;fill:var(--muted)}
@media(max-width:620px){.mstack .swart{display:none}}

/* ---------- lưới ảnh trượt ngang (.gal-slide) ----------
   Tối đa 3 ảnh: vẫn là lưới .g3 bình thường. Từ 4 ảnh: site.js gắn .is-slider,
   lưới thành dải cuộn ngang bắt điểm theo từng ảnh, kèm hai nút ←/→ và tự chuyển.
   Số ảnh trong khung theo đúng số cột của .g3: 3 / 2 (≤1024px) / 1 (≤620px). */
.gal-slide{position:relative}
.gal-slide.is-slider .gs-track{grid-template-columns:none;grid-auto-flow:column;
  grid-auto-columns:calc((100% - 52px)/3);overflow-x:auto;scroll-snap-type:x mandatory;
  scrollbar-width:none;overscroll-behavior-x:contain}
.gal-slide.is-slider .gs-track::-webkit-scrollbar{display:none}
.gal-slide.is-slider .gs-track>*{scroll-snap-align:start}
.gs-btn{position:absolute;top:var(--gs-mid,40%);transform:translateY(-50%);z-index:2;
  display:flex;align-items:center;justify-content:center;width:44px;height:44px;padding:0;
  border-radius:50%;border:1px solid var(--line,#d9e0e6);background:#fff;color:var(--ink);
  box-shadow:0 6px 18px rgba(7,30,48,.16);cursor:pointer;transition:background .15s,color .15s,border-color .15s}
.gs-btn:hover{background:var(--brand);border-color:var(--brand);color:#fff}
.gs-btn:focus-visible{outline:2px solid var(--brand);outline-offset:3px}
.gs-btn svg{width:20px;height:20px;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.gs-prev{left:-22px}
.gs-next{right:-22px}
@media(max-width:1024px){
  .gal-slide.is-slider .gs-track{grid-auto-columns:calc((100% - 26px)/2)}
}
@media(max-width:620px){
  .gal-slide.is-slider .gs-track{grid-auto-columns:100%}
  .gs-prev{left:8px}
  .gs-next{right:8px}
}

/* ---------- Trang Hợp tác (/vi/hop-tac): khuôn hai tấm cho mỗi hình thức ----------
   Trái: tấm ví dụ thật (đối tác / đề tài / khóa thực tập). Phải: danh sách đánh số.
   Hai cột BẰNG NHAU, cùng padding, và cả hai tấm kết thúc bằng một dải chân .rsx-foot
   cao như nhau, đẩy xuống đáy (margin-top:auto) — vạch kẻ chân của hai tấm luôn
   thẳng hàng. Chip trong chân phải giữ một hàng ở bề rộng máy tính, nên chip
   trường chỉ ghi viết tắt (tên đủ ở title). Không vạch màu một cạnh: xem .ev-feat. */
.rsx{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:22px;align-items:stretch}
.rsx-feat,.rsx-dirs{display:flex;flex-direction:column;background:#fff;border:1px solid var(--line);
  border-radius:var(--r);box-shadow:var(--lift);padding:clamp(22px,2.4vw,30px)}
.rsx-feat{align-items:flex-start}
.rsx-feat h3{font-size:clamp(1.2rem,1.7vw,1.42rem);line-height:1.3;letter-spacing:-.01em;color:var(--ink);margin:2px 0 10px}
.rsx-feat p{color:var(--muted);font-size:.95rem;margin:0 0 20px}
.rsx-lbl{font-size:.72rem;letter-spacing:.12em;text-transform:uppercase;color:var(--muted);font-weight:600}
.rsx-dirs ol{list-style:none;margin:8px 0 20px;padding:0}
.rsx-dirs li{display:grid;grid-template-columns:38px 1fr;align-items:baseline;padding:11px 0;
  border-top:1px solid var(--line);font-size:.95rem;font-weight:500;color:var(--ink)}
.rsx-dirs li:first-child{border-top:0}
.rsx-dirs li b{color:var(--brand);font-size:.82rem;font-variant-numeric:tabular-nums;letter-spacing:.04em}
.rsx-dirs li a{color:var(--brand)}
.rsx-foot{margin-top:auto;width:100%;box-sizing:border-box;min-height:58px;padding-top:18px;display:flex;flex-wrap:wrap;
  align-items:center;justify-content:space-between;gap:10px 12px;border-top:1px solid var(--line)}
.rsx-partners{justify-content:flex-start}
.rsx-partners .rsx-lbl{margin-right:6px}
.rsx-chip{display:inline-flex;align-items:baseline;gap:8px;padding:7px 14px;border:1px solid var(--line);
  border-radius:999px;background:#fff;font-size:.88rem;font-weight:500;color:var(--ink);line-height:1.3}
.rsx-chip b{color:var(--brand);font-size:.78rem;letter-spacing:.06em}
@media(max-width:900px){
  .rsx{grid-template-columns:1fr}
}
/* Tấm ví dụ tô xanh thương hiệu rất loãng, chữ tối: cột trái thường ít chữ hơn
   danh sách bên phải, để trắng thì khoảng trống giữa tiêu đề và chân trông như
   thiếu nội dung; tô nhạt thì nó đọc ra là ô nhấn có chủ ý. Người dùng chọn bản
   này (10/2026) sau khi thấy bản xanh đậm chữ trắng quá nặng. */
.rsx-feat{background:#EDF1F6;border-color:#DCE3EC}
.rsx-feat h3{color:var(--ink)}
.rsx-feat p{color:#4F5B69}
.rsx-feat .rsx-foot{border-top-color:#DCE3EC}
.rsx-feat .rsx-chip{border-color:#DCE3EC}

/* ============================================================
   SOÁT MOBILE 08/10/2026 — ĐỢT 2: các luật dùng chung
   Đo trên cả 154 trang ở khung 390px. Mỗi luật dưới đây sửa một lỗi lặp lại
   ở nhiều trang cùng khuôn; khối nằm cuối file để thắng các luật cũ cùng độ đặc.
   ============================================================ */

/* Ô kết quả: bỏ vạch màu 3px cạnh trái — cùng quy tắc với .ev-feat (vạch dày một
   cạnh trên khối bo góc là dấu hiệu giao diện sinh hàng loạt). Nền nhạt + viền
   1px đều bốn cạnh vẫn đủ tách nó khỏi đoạn văn. Áp mọi bề ngang. */
.result{border-left:0;border:1px solid rgba(43,101,176,.2);border-radius:var(--r)}

/* Thanh tab cuộn ngang (Tài nguyên, Công bố, Sự kiện): tab cuối bị mép màn hình
   cắt cụt ("Sự ki", "2023") mà không có dấu hiệu là còn tab để vuốt. Làm mờ dần
   mép phải trong lúc còn chỗ cuộn; cuộn tới cuối thì vệt mờ tự tắt. Trình duyệt
   chưa có scroll-timeline thì giữ như cũ. */
@property --tabfade{syntax:'<length>';inherits:false;initial-value:0px}
@keyframes cw-tabfade{from,92%{--tabfade:40px}to{--tabfade:0px}}

@media(max-width:620px){
  /* Tiêu đề không bỏ một chữ lẻ ở dòng cuối ("…bạn / cần", "…kỹ / sư?");
     đoạn văn tránh dòng cuối chỉ một từ. */
  h1,h2,h3,h4{text-wrap:balance}
  p,li,dd,figcaption{text-wrap:pretty}

  /* Tiêu đề trang: 28.8px làm tiêu đề dài chiếm 5–7 dòng, đẩy đoạn đầu xuống
     quá nửa màn hình. Hạ một nấc; tiêu đề ngắn vẫn là chữ lớn nhất trang. */
  .pageband h1{font-size:1.62rem;line-height:1.22}
  .cst-hero h1{font-size:1.75rem}

  /* Lề trái một mức: tấm tiêu đề cách mép 8px (chữ ở 28px), dải số liệu tràn
     mép mà vẫn bo góc (lộ khía ở bốn góc màn hình), thân bài ở 20px. Cả hai tấm
     tràn mép, không bo — chữ của mọi khối cùng đứng ở 20px như hero trang chủ. */
  .pageband{margin:0;border-radius:0}
  .stats .wrap{border-radius:0}

  /* Số liệu: giá trị dạng cụm ("870–1100°C", "Toàn tuyến") ở 25.6px rơi xuống
     hai dòng, để lại đơn vị mồ côi. Trang chủ giữ cỡ lớn vì chỉ có số ngắn. */
  body:not(.home) .stats .n{font-size:1.35rem;line-height:1.15;text-wrap:balance}

  /* Breadcrumb: cấp cuối bị mép màn hình xén giữa chữ ("Simcenter Amesi").
     Cấp cuối co lại và kết thúc bằng "…"; các cấp cha giữ nguyên. Không còn
     gì để vuốt nên bỏ cuộn ngang. */
  .crumb{overflow:hidden}
  .crumb > b:last-child{display:block;flex:0 1 auto;min-width:0;
    overflow:hidden;text-overflow:ellipsis}
  .crumb > b:last-child::before{display:inline-block;vertical-align:.12em}

  /* Vệt mờ báo còn tab bên phải (xem @keyframes ở trên). */
  @supports (animation-timeline:scroll()){
    .rtabs,.ev-nav .wrap{
      -webkit-mask-image:linear-gradient(to right,#000 calc(100% - var(--tabfade)),transparent);
              mask-image:linear-gradient(to right,#000 calc(100% - var(--tabfade)),transparent);
      animation:cw-tabfade linear both;animation-timeline:scroll(self inline)}
  }

  /* Footer: mọi nhóm xếp một cột làm footer dài ~1.100px. Giữ hai nhóm link
     cạnh nhau; khối giới thiệu và khối liên hệ trải hết bề ngang. */
  .fgrid{grid-template-columns:1fr 1fr;gap:28px 20px}
  .fgrid > :first-child,.fgrid > :last-child{grid-column:1 / -1}

  /* Ảnh dự án: lưới 2×2 chỉ còn ô ~168px — thang màu, trục biểu đồ không đọc
     được, và 5 ảnh thì ảnh cuối đứng một mình. Thành dải vuốt ngang, mỗi ảnh
     ~84% bề ngang, ảnh kế ló ra ở mép phải để báo còn ảnh. Chạm vẫn mở phóng to. */
  .csgal{display:flex;gap:12px;overflow-x:auto;scroll-snap-type:x mandatory;
    margin:0 -20px;padding:0 20px 4px;scroll-padding:0 20px;scrollbar-width:none}
  .csgal::-webkit-scrollbar{display:none}
  .csgal > figure{flex:0 0 84%;scroll-snap-align:start}

  /* Bảng nhãn–giá trị trong cột hẹp: nhãn gãy dòng ("THỜI / GIAN", "PHƯƠNG /
     PHÁP", "ĐƠN VỊ / TỔ CHỨC") mà giá trị cũng gãy. Cả hai loại xếp nhãn nằm
     trên giá trị, giá trị có trọn bề ngang. Bảng th[scope=row] trên site đều
     là cặp một th + một td (đã kiểm cả 28 trang), nên tách hàng an toàn.
     !important: cột nhãn mang width:34% inline. */
  .csfacts dl > div{grid-template-columns:1fr;gap:3px}
  .tbl:has(th[scope=row]),.tbl:has(th[scope=row]) tbody,
  .tbl:has(th[scope=row]) tr{display:block}
  .tbl th[scope=row],.tbl th[scope=row] + td{display:block;width:auto!important;border:0}
  .tbl th[scope=row]{background:none;padding:11px 16px 2px}
  .tbl th[scope=row] + td{padding:0 16px 11px;border-bottom:1px solid var(--line)}
  .tbl:has(th[scope=row]) tr:last-child > td{border-bottom:0}
  /* Bảng chương trình: tiêu đề cột đầu ("Thời gian") không gãy. Chỉ cột ĐẦU:
     bảng ma trận nhiều cột (phần mềm) mà cấm gãy mọi tiêu đề là tràn ngang. */
  .tbl thead th:first-child{white-space:nowrap}

  /* Khoảng trắng chết trước hộp kêu gọi cuối trang: 44px đáy section trước +
     44px đỉnh section chứa hộp = 88px, cộng phần đệm của hộp thành 120–165px.
     Bỏ đỉnh của section chứa hộp. Tương tự cho khối bình luận sau bài viết và
     mục ảnh dự án sau mạch kể của case study. */
  .sec:has(> .wrap > .finalcta){--sec-pt:0px}
  .sec.cmt{--sec-pt:8px}
  .sec:has(> .wrap > .csgal){--sec-pt:8px}
}

/* ============================================================
   SOÁT MOBILE 08/10/2026 — ĐỢT 1: bảng dựng lại từ ảnh chụp bảng
   Ba bảng trong blog (xi măng, dàn nóng, tiêu chí HVAC) và bảng IAQI trước là
   ảnh: thu về 350px thì chữ còn 4–5px. Giờ là bảng HTML.
   ============================================================ */

/* Bảng so sánh có nhãn hàng là câu (xi măng): giữ chữ thường, không viết hoa
   giãn chữ như nhãn ngắn "Dành cho" ở trang Dịch vụ. Hàng đầu vẫn là tiêu đề cột. */
.tbl-rowtxt tr + tr > th{text-transform:none;letter-spacing:0;font-size:.92rem;
  color:var(--ink);font-weight:700;line-height:1.4}
.tbl-cmp td ul{margin:0;padding-left:1.1em}
.tbl-cmp td li + li{margin-top:4px}
/* Dàn nóng: ảnh cắt từ bảng cũ đứng đầu ô "Đặc thù". */
.tbl-dn td img{display:block;width:100%;height:auto;border-radius:6px;margin:0 0 10px;
  aspect-ratio:16/10;object-fit:cover}

/* Bảng IAQI: bốn mức là bốn cột, chất ô nhiễm là hàng — đủ hẹp để giữ lưới ở 390px. */
.tbl-iaqi{font-variant-numeric:tabular-nums}
.tbl-iaqi th,.tbl-iaqi td{text-align:center;vertical-align:middle}
.tbl-iaqi th:first-child,.tbl-iaqi td.k{text-align:left}
.tbl-iaqi td.k{font-weight:700}
.tbl-iaqi th span,.tbl-iaqi td.k span{display:block;font-weight:500;font-size:.78em;
  color:var(--muted);text-transform:none;letter-spacing:0;margin-top:2px}
.tbl-iaqi .lv{display:inline-block;width:8px;height:8px;border-radius:50%;margin-right:6px;vertical-align:1px}
.tbl-iaqi .lv-1{background:#1d9fd8}
.tbl-iaqi .lv-2{background:#1a9e5f}
.tbl-iaqi .lv-3{background:#e2b10f}
.tbl-iaqi .lv-4{background:#d8392b}

/* Bảng sao (tiêu chí HVAC): cột sao căn giữa, màu thương hiệu. */
.tbl-stars td{vertical-align:middle}
.tbl-stars th + th,.tbl-stars td + td{text-align:center}
.tbl-stars td + td{color:var(--brand);white-space:nowrap;letter-spacing:.06em}
.tbl-stars td.no{color:var(--muted)}
.tblnote{font-size:.86rem;color:var(--muted);margin-top:10px}

@media(max-width:620px){
  .tbl-iaqi,.tbl-stars{font-size:.8rem}
  .tbl-iaqi th,.tbl-iaqi td,.tbl-stars th,.tbl-stars td{padding:9px 6px}
  .tbl-iaqi th{font-size:.66rem;letter-spacing:.04em}
  .tbl-stars th{font-size:.66rem;letter-spacing:.04em}
  .tbl-stars td + td{font-size:.7rem;letter-spacing:0}
}
/* Bảng trong bài viết cách đoạn văn như ảnh (.artmain figure: 22px). */
.artmain .tblwrap,.artcol .tblwrap{margin-top:22px;margin-bottom:22px}
.artmain .tblwrap + .tblnote,.artcol .tblwrap + .tblnote{margin-top:-12px}

/* ============================================================
   SOÁT MOBILE 08/10/2026 — ĐỢT 3: bố cục riêng từng trang
   (người dùng duyệt qua xem-truoc-mobile-dot-3.html; chọn phương án A cho
   khối Ngành trang chủ và thẻ Dự án). Trên 620px không đổi, trừ khối bài
   liên quan cuối bài blog.
   ============================================================ */
@media(max-width:620px){
  /* Trang chủ · bốn ngành: lưới 2×2, mỗi ô chỉ ảnh + tên ngành. Danh sách bốn
     mục đã có ở trang ngành; ở đây nó làm mỗi thẻ cao ~450px, cả khối ~1.850px
     (giờ ~390px). Cả thẻ vẫn là link (.more phủ kín thẻ). */
  #linh-vuc .g4{grid-template-columns:1fr 1fr;gap:12px}
  #linh-vuc .card{grid-template-rows:auto auto}
  #linh-vuc .card .imgbox{grid-row:1;height:auto;aspect-ratio:4/3}
  #linh-vuc .card h3{grid-row:2;min-height:0;padding:10px 12px 12px;font-size:.95rem;line-height:1.3;display:block}
  #linh-vuc .card ul{display:none}

  /* Danh mục dự án: thẻ gọn — ảnh nhỏ bên trái cạnh tiêu đề, hai số liệu ở
     dưới. 16 thẻ ~7.200px → ~3.450px. */
  .pjcard{display:grid;grid-template-columns:118px minmax(0,1fr);align-items:start}
  .pjcard > .imgbox{grid-column:1;grid-row:1;aspect-ratio:4/3;margin:14px 0 0 14px;border-radius:6px}
  .pjcard-body{grid-column:2;grid-row:1;padding:12px 14px 12px 12px}
  .pjcard-body .meta{min-height:0;font-size:.72rem;margin-bottom:.35em}
  .pjcard h3{font-size:.98rem}
  .pjcard-kpi{grid-column:1 / -1;grid-row:2;padding:10px 14px 12px}

  /* Trang sự kiện: thẻ Thông tin + nút đăng ký nằm sau cả chương trình
     (y≈1.800–2.000). Lên ngay dưới tiêu đề. */
  .g2 > .sidesticky{order:-1}

  /* Webinar xem lại: số "#1" lên đầu thẻ thay vì đứng riêng một cột 40px. */
  .ev-odrow{display:block}
  .ev-odno{display:inline-block;font-size:.8rem;margin-bottom:2px}
  .ev-odrow .ev-row-act{margin-top:10px}

  /* Phần mềm: vòng tròn Simcenter ~350px → 230px, căn giữa. */
  .g2.diagram > figure:has(img[src*="simcenter-vong-tron"]){width:230px;justify-self:center}

  /* Blog: mục lục từng bị ẩn dưới 1024px (.toc{display:none} ở trên) — bài dài
     8.000–15.000px không có lối tắt nào. Hiện lại ở ĐẦU bài; nút chia sẻ, thẻ
     tác giả vẫn ở cuối. display:contents cho cột phải tan ra để mục lục đứng
     riêng được trong lưới .artgrid. */
  .artgrid > .artrail,.artgrid > .artrail > div{display:contents}
  .artgrid > .artrail .toc{display:block;order:-1;max-width:none;margin:0;box-shadow:none;padding:14px 14px 10px}
  .artgrid > .artrail .toc a{padding:6px 4px}

  /* Tài nguyên: hai thẻ nửa bề ngang làm dòng thông tin rơi chữ ("1.265 lượt /
     xem"). Từ bài thứ hai trở đi đều là dòng ảnh nhỏ bên trái. */
  .postgrid.split{grid-template-columns:1fr}
  .postgrid.split>.pcard:nth-child(1){margin-bottom:12px}
  .postgrid.split>.pcard:nth-child(2),.postgrid.split>.pcard:nth-child(3){margin-bottom:0;
    display:grid;grid-template-columns:144px 1fr;column-gap:12px;row-gap:5px;align-items:start;
    padding:12px 2px;background:none;box-shadow:none;border:0;border-radius:0;border-top:1px solid var(--line)}
  .postgrid.split>.pcard:nth-child(2) .pcard-body,.postgrid.split>.pcard:nth-child(3) .pcard-body{display:contents}
  .postgrid.split>.pcard:nth-child(2) .imgbox,.postgrid.split>.pcard:nth-child(3) .imgbox{grid-column:1;grid-row:1/span 3;
    align-self:start;aspect-ratio:3/2;border-radius:4px}
  .postgrid.split>.pcard:nth-child(2) h3,.postgrid.split>.pcard:nth-child(3) h3{grid-column:2;grid-row:1;margin:0}
  .postgrid.split>.pcard:nth-child(2) .pcard-top,.postgrid.split>.pcard:nth-child(3) .pcard-top{grid-column:2;grid-row:2;margin:0}
  .postgrid.split>.pcard:nth-child(2) .pcard-foot,.postgrid.split>.pcard:nth-child(3) .pcard-foot{grid-column:2;grid-row:3;margin:0}
}

/* Blog · bài liên quan (lib/relrender.js dựng từ trang danh sách). Máy tính:
   ba thẻ một hàng, ảnh trên. Điện thoại: ba dòng, ảnh nhỏ bên trái — cùng
   kiểu dòng ở trang Tài nguyên. Thẻ trắng + viền như các thẻ khác của site. */
.relposts h2{font-size:clamp(1.15rem,1.6vw,1.35rem);margin:0 0 16px}
.relgrid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:20px}
.relcard{display:flex;flex-direction:column;gap:6px;background:#fff;border:1px solid var(--line);
  border-radius:var(--r);overflow:hidden;color:var(--ink);text-decoration:none;padding-bottom:14px}
.relcard:hover{text-decoration:none;background:var(--bg-soft)}
.relcard:hover b{color:var(--brand)}
.relimg{display:block;aspect-ratio:16/9;background:var(--bg-soft);margin-bottom:6px}
.relimg img{display:block;width:100%;height:100%;object-fit:cover}
.relimg.failed img{display:none}
.relcard b{font-size:1rem;line-height:1.35;padding:0 16px}
.relmeta{font-size:.8rem;color:var(--muted);padding:0 16px}
.relall{font-size:.9rem;margin:16px 0 0}
@media(max-width:620px){
  .relgrid{grid-template-columns:1fr;gap:0}
  .relcard{display:grid;grid-template-columns:120px 1fr;column-gap:12px;row-gap:3px;align-items:start;
    background:none;border:0;border-radius:0;border-top:1px solid var(--line);padding:12px 0}
  .relcard:hover{background:none}
  .relimg{grid-row:1/span 2;aspect-ratio:3/2;border-radius:4px;overflow:hidden;margin:0}
  .relcard b,.relmeta{padding:0}
  .relcard b{font-size:.95rem}
}

/* Trang chủ · ba trụ (ĐỢT 3, bản thứ hai sau khi người dùng chê bản "contain"
   trong ô cao bằng thẻ). Ô ảnh mang aspect-ratio:4/3 inline mà lại bị kéo cao
   bằng hàng (align-self:stretch), nên bề ngang suy từ tỷ lệ (133–162px) vượt
   cột 33% và bị mép thẻ xén — "412 kW" còn "41", "−37 %" mất hẳn. Giờ: cột ảnh
   44%, ô ảnh căn giữa theo chiều dọc và giữ đúng 4:3 (không stretch), cách mép
   thẻ 10px như một ảnh thu nhỏ — hình hiện trọn, không có dải nền thừa. */
@media(max-width:620px){
  #nang-luc .path{grid-template-columns:minmax(0,1fr) 44%;column-gap:14px}
  #nang-luc .path .imgbox{align-self:center;width:auto;min-width:0;margin:10px 10px 10px 0;border-radius:6px}
  #nang-luc .path .imgbox img{object-fit:contain}
}

/* Danh mục dự án trên điện thoại (08/10/2026, theo yêu cầu người dùng):
   1. Bộ lọc gọn lại: mỗi trục MỘT dòng — nhãn trục nhỏ bên trái, hàng chip vuốt
      ngang bên phải, mép phải mờ dần khi còn chip (cùng cơ chế vệt mờ của
      .rtabs ở khối ĐỢT 2). Đảo ghi chú cũ "KHÔNG cho hàng chip cuộn ngang":
      người dùng chọn gọn hơn là thấy hết — bộ lọc ~300px → ~130px.
   2. Ẩn dải KPI của thẻ: thẻ chỉ còn ảnh nhỏ + chuyên mục + tên dự án; số liệu
      đọc ở trang case study. */
@media(max-width:620px){
  .pjbar{padding-bottom:12px;margin-bottom:18px}
  .pjrow{flex-direction:row;align-items:center;gap:10px;padding:4px 0}
  .pjlab{flex:0 0 66px;padding-top:0;font-size:.64rem;letter-spacing:.1em}
  .pjchips{flex:1 1 auto;flex-wrap:nowrap;overflow-x:auto;scrollbar-width:none;gap:6px;
    margin-right:-20px;padding:2px 20px 2px 0;scroll-padding-right:20px}
  .pjchips::-webkit-scrollbar{display:none}
  .pjchip{flex:0 0 auto;font-size:.8rem;padding:7px 11px;gap:6px}
  .pjn{font-size:.66rem;min-width:17px;height:17px;padding:0 4px}
  .pjfoot{margin-top:8px}
  @supports (animation-timeline:scroll()){
    .pjchips{
      -webkit-mask-image:linear-gradient(to right,#000 calc(100% - var(--tabfade)),transparent);
              mask-image:linear-gradient(to right,#000 calc(100% - var(--tabfade)),transparent);
      animation:cw-tabfade linear both;animation-timeline:scroll(self inline)}
  }
  .pjcard-kpi{display:none}
  .pjcard > .imgbox{margin:14px 0 14px 14px}
}

/* ============================================================
   Hero trang chủ trên điện thoại (08/10/2026 — người dùng chọn "khối chữ
   vuông" qua xem-truoc-hero-mobile.html). Hình trải hết bề ngang mà khối chữ
   chỉ chiếm ~70% nên phía phải trống hơn phía trái.
   ============================================================ */
@media(max-width:620px){
  /* Tiêu đề VI phóng theo bề ngang: cỡ = (bề ngang − 40px lề) / 12,6 cho dòng
     dài nhất chạm mép phải của hình. Tiêu đề (10/10/2026) "Giảm tiêu hao &
     phát thải, / kiểm chứng thiết kế / trước khi chế tạo" xuống ba dòng theo vế
     câu — các từ trong một vế nối bằng &nbsp; trong index.html; dòng đầu rộng
     12,43 lần cỡ chữ (≈ 28px ở 390px). Đổi câu tiêu đề thì đo lại số chia, nếu
     không vế dài nhất bị ngắt giữa chừng. Dưới ~320px chạm mức sàn 22px, dòng
     đầu tự xuống thành "Giảm tiêu hao & / phát thải,". Bản EN 1.62rem.
     text-wrap:wrap đè balance của khối ĐỢT 2: balance cố ý rút ngắn dòng,
     ngược đúng thứ cần ở đây. */
  html[lang=vi] .hero h1{font-size:clamp(22px,calc((100vw - 40px) / 12.6),36px);
    line-height:1.12;letter-spacing:-.025em;text-wrap:wrap}
  html[lang=en] .hero h1{font-size:1.62rem}
  /* Câu dẫn căn đều hai bên cho mép phải thẳng với hình. */
  .hero .lead{text-align:justify;text-justify:inter-word;hyphens:none;text-wrap:wrap}
  .hero .sub-note{text-align:center}
  /* Video có nền xám dựng sẵn, lệch nền dải hero một mức màu — trên vài màn hình
     lộ thành viền hộp nhạt quanh hình. Mép canvas mờ dần vào nền. */
  .hs-vid{-webkit-mask-image:radial-gradient(ellipse 72% 70% at 50% 50%,#000 78%,transparent 100%);
          mask-image:radial-gradient(ellipse 72% 70% at 50% 50%,#000 78%,transparent 100%)}
}

/* Hero (08/10/2026): ảnh động AVIF thay video khi trình duyệt chặn tự phát
   (site.js: hienDong), và vuốt ngang để chuyển tấm. */
.hs-dong{object-fit:cover}
.hs-track.hs-swipe{touch-action:pan-y}

/* ============================================================
   Cặp nút trên điện thoại (08/10/2026 — người dùng chọn "hai nút song song"
   qua xem-truoc-nut-hero-mobile.html, rồi bảo áp cho mọi chỗ cùng kiểu).
   Trước: hai nút cùng trải hết bề ngang, xếp chồng, chữ + mũi tên dồn trái nên
   nửa phải mỗi nút trống. Giờ: hai nút đứng cạnh nhau một hàng, chữ căn giữa,
   bỏ mũi tên; chữ dài thì xuống hai dòng, hai nút luôn cao bằng nhau (lưới).
   Áp cho: hero trang chủ (.cta-row), mọi .btnrow có ĐÚNG hai nút (trang trụ cột,
   dịch vụ, phần mềm, khối phần mềm ở trang chủ), và hai nút của .notecard trang
   Liên hệ. .btnrow của khung "không có dự án" (.pjempty) giữ nguyên: một trong
   hai nút của nó thường ẩn.
   ============================================================ */
@media(max-width:620px){
  .hero .cta-row,
  .btnrow:has(> .btn + .btn):not(:has(> .btn + .btn + .btn)):not(.pjempty .btnrow){
    display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:10px;align-items:stretch}
  .hero .cta-row{margin-top:22px}
  .hero .cta-row .btn,
  .btnrow:has(> .btn + .btn):not(:has(> .btn + .btn + .btn)):not(.pjempty .btnrow) > .btn,
  .notecard > .btn{
    width:auto;justify-content:center;text-align:center;padding:13px 8px;
    font-size:clamp(.78rem,3.6vw,.86rem);line-height:1.25;border-radius:6px}
  .hero .cta-row a.btn::after,
  .btnrow:has(> .btn + .btn):not(:has(> .btn + .btn + .btn)):not(.pjempty .btnrow) > a.btn::after,
  .notecard > a.btn::after{display:none}
  /* Nút phụ (viền) lấy nền trắng: trên dải xám nó mới đọc ra là một nút. */
  .hero .cta-row .btn-ghost,
  .btnrow > .btn-ghost,.btnrow > .btn-line,.notecard > .btn-line{background:#fff}
  .hero .cta-row .btn-ghost{border-color:rgba(44,42,41,.22)}
  /* .notecard: đoạn chữ trải hết hàng trên, hai nút chia đôi hàng dưới. */
  .notecard:has(> .btn + .btn){display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:14px 10px;align-items:stretch}
  .notecard:has(> .btn + .btn) > p{grid-column:1 / -1;min-width:0}
}

/* ============================================================
   Dự án tiêu biểu ở trang chủ (08/10/2026, theo yêu cầu người dùng): 4 cột
   trên máy tính, 2 cột trên điện thoại. site.js bốc 4 thẻ ở mọi khổ. Không có
   JS thì lộ đúng 4 thẻ đầu (đè luật 3/1 của bể chọn ở trên).
   ============================================================ */
.g3.projpick{grid-template-columns:repeat(4,minmax(0,1fr));gap:20px}
.projpick > *:nth-child(-n+4){display:flex}
.projpick.js > *:not(.on){display:none}
.projpick .card .body{padding:18px 18px 16px}
.projpick .card h3{font-size:1.05rem}
@media(max-width:1024px){
  .g3.projpick{grid-template-columns:repeat(2,minmax(0,1fr))}
}
@media(max-width:620px){
  .g3.projpick{grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}
  /* 2 thẻ một hàng (người dùng: "bản mobile chỉ hiện 2 dự án"). */
  .projpick > *:nth-child(n+3){display:none}
  .projpick.js > *:not(.on){display:none}
  .projpick.js > .on{display:flex}
  .projpick .card .body{padding:12px 12px 14px}
  /* Ẩn dòng meta cho gọn: tên dự án là đủ, chi tiết đọc ở trang case study. */
  .projpick .card .body .meta{display:none!important}
  /* Dòng meta dài ("Hiệu quả quá trình · Xử lý môi trường · Hoa Kỳ · 2025–2026")
     trong nửa bề ngang thành 4 dòng: cắt còn 2, chữ nhỏ một nấc. */
  .projpick .card .body .meta{font-size:.7rem;line-height:1.4;min-height:2lh;
    display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;line-clamp:2;overflow:hidden}
  .projpick .card h3{font-size:.92rem;line-height:1.3;min-height:3.9em}
  .projpick .card .more{font-size:.8rem}
}
/* "Kết quả đo được" ở trang Giải pháp trên điện thoại (08/10/2026, người dùng:
   "hai cột, 1 hàng giống như ở trang chủ"): 2 thẻ cạnh nhau, thẻ thứ ba ẩn,
   bỏ dòng meta như .projpick. Ô kết quả giữ lại — đó là nội dung của khối này —
   nhưng thu chữ và đệm cho vừa nửa bề ngang. */
@media(max-width:620px){
  .g3.proofrow{grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}
  .proofrow > *:nth-child(n+3){display:none}
  .proofrow .card .body{padding:12px 12px 14px}
  .proofrow .card .body .meta{display:none}
  .proofrow .card h3{font-size:.92rem;line-height:1.3;min-height:3.9em}
  .proofrow .card .result{font-size:.76rem;line-height:1.45;padding:8px 9px;margin-bottom:10px}
  .proofrow .card .more{font-size:.8rem}
}

/* ============================================================
   Trang Liên hệ trên điện thoại (08/10/2026, người dùng: "cho gọn gàng").
   Gọn = bỏ khung lồng khung và đồ trang trí, giữ nguyên nội dung chính:
   · tấm xám .ctpanel tan vào trang, ngăn nhau bằng một vạch tóc — biểu mẫu
     rộng thêm ~44px, hết cảnh ô nhập nằm trong tấm nằm trong trang;
   · ba lời hứa chỉ còn dòng đậm;
   · sáu chip "Bạn quan tâm tới" xếp lưới hai cột thẳng hàng thay vì sáu hàng
     so le;
   · kênh liên hệ thành bảng hai cột nhãn | giá trị, bỏ biểu tượng (nhãn đã
     nói rõ là gì);
   · đoạn dẫn của mục "Chuẩn bị" ẩn — câu "không cần đủ dữ liệu" đã có ngay
     dưới tiêu đề biểu mẫu.
   Bó trong body.ctpage (front matter của vi/lien-he.html và en/contact.html)
   để không lấn sang biểu mẫu trang Sự kiện, vốn cũng dùng .form/.ctfoot.
   ============================================================ */
@media(max-width:620px){
  .ctpage .sec{--sec-pad:26px}
  .ctpage .ctpromise{gap:9px;margin-top:16px;padding-top:14px}
  .ctpage .ctpromise-i{align-items:center;gap:10px}
  .ctpage .ctpromise svg{width:19px;height:19px;margin-top:0}
  .ctpage .ctpromise b{font-size:.92rem}
  .ctpage .ctpromise span{display:none}

  .ctpage .ctpanel{background:none;border-radius:0;padding:0}
  .ctpage .ctgrid{gap:0}
  .ctpage .ctgrid > div:last-child > .ctpanel{margin-top:26px;padding-top:22px;border-top:1px solid var(--line)}
  .ctpage .ctpanel > h2{font-size:1.32rem}
  .ctpage .ctsub{font-size:.9rem;margin-bottom:16px}

  .ctpage .form{gap:13px}
  .ctpage .form label,.ctpage .ctfield legend{margin-bottom:5px}
  .ctpage .form input,.ctpage .form textarea{padding:11px 12px}
  .ctpage .form textarea{height:8.5em}
  .ctpage .ctchips{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:8px}
  .ctpage .form .ctchips label{justify-content:center;text-align:center;min-height:46px;
    padding:8px 10px;border-radius:10px;font-size:.8rem}
  .ctpage .ctfoot{padding-top:16px;gap:12px}
  .ctpage .ctfoot .btn{width:100%;justify-content:center}
  .ctpage .ctfoot p{min-width:0;font-size:.78rem}

  .ctpage .ctch{display:grid;grid-template-columns:6.2rem minmax(0,1fr);gap:0 12px;align-items:baseline;padding:11px 0}
  .ctpage .ctpanel-t + .ctch{border-top:0;padding-top:6px}
  .ctpage .ctch-ic{display:none}
  .ctpage .ctch-b{display:contents}
  .ctpage .ctch-l{grid-column:1;margin:0}
  .ctpage .ctch-v,.ctpage .ctch-s{grid-column:2}
  .ctpage .ctch-v{font-size:.94rem}
  .ctpage .ctpic{margin:10px 0 2px}
  .ctpage .ctmap{margin-top:10px}

  .ctpage .ctpanel:has(> .listclean) > .ctsub{display:none}
  .ctpage .ctpanel:has(> .listclean) > h2{margin-bottom:10px}
  .ctpage .ctpanel .listclean li{font-size:.9rem;padding-top:10px;padding-bottom:10px}
}

/* Trang chủ · khối Công bố trên điện thoại (08/10/2026, người dùng chọn phương án
   C trong ba bản dựng thử): một thẻ tên bài báo tiếng Anh dài 6 dòng + dòng link
   4 dòng → dải bốn con số + cặp nút. Hai khối mới (.pubstat-m, .pubbtn-m) nằm
   cuối .wrap trong src/{vi,en}/index.html; màn rộng giữ nguyên bản cũ.
   Cặp nút tự ăn kiểu "hai nút song song" của .btnrow có đúng 2 nút. */
/* 10/10/2026: dải số hiện cả trên màn rộng, và điện thoại hiện lại MỘT dòng công
   bố — xem khối "Bốn khối cuối trang chủ" cuối file. */
.pubsec .pubstat-m,.pubsec .pubbtn-m{display:none}
@media(max-width:620px){
  .pubsec .pubpick + p{display:none!important}
  .pubsec .pubstat-m{display:grid;margin-top:4px}
  .pubsec .pubbtn-m{display:grid;margin-top:16px}
}

/* ============================================================
   Dải Đào tạo trang chủ (09/10/2026 — người dùng chọn phương án B qua
   xem-truoc-dao-tao-trang-chu.html, đặt ngay sau khối Năng lực).
   <section class="dt-band"> KHÔNG phải .sec: nền xanh rất nhạt tràn viền và đệm
   là của riêng nó, nên luật vạch tóc `body.home .sec + .sec` không chạm tới.
   Đây là khối có màu duy nhất ở nửa trên trang chủ — đừng tô thêm khối nào
   gần nó. Thẻ trắng viền 1px bốn cạnh, không vạch màu một cạnh (xem .ev-feat).
   ============================================================ */
/* Nền phẳng #EDF1F6 = đúng màu nền ba ảnh Năng lực ngay trên (09/10/2026, phương án A
   qua xem-truoc-nen-dao-tao.html): cùng họ màu với khối kề nên mép dải mềm, không đọc
   ra như một mảng lạnh dán vào thang xám ấm. Khối nhấn màu — MỘT khối mỗi trang. */
.dt-band{background:#EDF1F6;padding:clamp(48px,5.4vw,76px) 0}
.dt-top{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.04fr);gap:clamp(28px,4.4vw,64px);
  align-items:center;margin-bottom:clamp(30px,3.4vw,46px)}
/* Tiêu đề và câu dẫn theo đúng thang chung của đầu section (h2 toàn cục, .sec-head p):
   dải nổi nhờ nền và ảnh, không nhờ chữ to hơn các khối khác. */
.dt-band h2{text-wrap:balance}
.dt-band .lead{font-size:1rem;line-height:1.6;max-width:50ch;margin:0;color:var(--ink)}
.dt-band .btnrow{margin-top:28px}
/* Ảnh là .imgbox (ô ảnh sửa được ở Live edit); khung bo góc có bóng để nổi khỏi
   nền xanh. Cắt dịch xuống dưới để giữ người học, bớt trần nhà. */
.dt-photo{margin:0;position:relative;border-radius:10px;overflow:hidden;box-shadow:0 8px 22px rgba(26,25,24,.10)}
.dt-photo .imgbox img{object-position:50% 62%}
.dt-photo figcaption{position:absolute;left:12px;bottom:12px;background:rgba(26,25,24,.64);color:#fff;
  font-size:.78rem;padding:5px 11px;border-radius:999px;pointer-events:none}

/* Thẻ đối tượng: biểu tượng nét (cùng quy ước lib/navicons.js), tiêu đề, một câu,
   dòng bằng chứng. Link phủ kín thẻ như #nang-luc .path; mũi tên là ::after. */
.dt-aud{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:22px}
.dt-card{position:relative;display:flex;flex-direction:column;background:#fff;border:1px solid #DCE3EC;
  border-radius:var(--r);padding:26px 26px 22px;transition:transform .3s ease-out,box-shadow .3s ease-out}
.dt-card-hd{display:flex;align-items:center;gap:14px;margin-bottom:14px}
.dt-card-hd::after{content:"\2192";margin-left:auto;flex:none;font-weight:600;color:var(--brand);transition:transform .2s ease-out}
.dt-ic{display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;width:46px;height:46px;
  border-radius:50%;background:#EDF1F6}
.dt-ic svg{width:24px;height:24px;fill:none;stroke:var(--brand);stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}
.dt-card h3{font-size:1.14rem;line-height:1.25;color:var(--ink);margin:0;letter-spacing:-.012em}
.dt-card p{font-size:.95rem;font-weight:500;color:var(--ink);line-height:1.55;margin:0 0 18px}
.dt-proof{margin-top:auto;padding-top:14px;border-top:1px solid var(--line);font-size:.86rem;line-height:1.45;
  color:var(--ink);font-weight:600}
.dt-proof small{display:block;font-size:.68rem;letter-spacing:.1em;text-transform:uppercase;color:var(--muted);
  font-weight:600;margin-bottom:4px}
.dt-card .more{position:absolute;inset:0;margin:0;font-size:0}
.dt-card:hover h3{color:var(--brand-mid)}
.dt-card:hover .dt-card-hd::after{transform:translateX(5px);color:var(--brand-mid)}
body.cw-editing .dt-card .more{position:static;font-size:.86rem;margin-top:12px}
@media(min-width:621px){.dt-card:hover{transform:translateY(var(--rise));box-shadow:var(--lift-hover)}}
@media(any-hover:none){.dt-card:hover{transform:none;box-shadow:none}}
@media(prefers-reduced-motion:reduce){.dt-card:hover{transform:none}}
@media(max-width:900px){
  .dt-top{grid-template-columns:1fr}
  .dt-aud{grid-template-columns:1fr}
}
@media(max-width:620px){
  .dt-band{padding:40px 0}
  .dt-top{gap:24px;margin-bottom:24px}
  /* Điện thoại (09/10/2026, người dùng chọn M1 qua xem-truoc-dao-tao-mobile-gon.html):
     ba thẻ gộp thành MỘT tấm trắng chia vạch, mỗi đối tượng một dòng — tên +
     dòng bằng chứng; câu mô tả ẩn, chạm cả dòng sang trang chi tiết. */
  .dt-aud{gap:0;background:#fff;border:1px solid #DCE3EC;border-radius:var(--r);overflow:hidden}
  .dt-card{border:0;border-radius:0;padding:14px 16px 13px}
  .dt-card + .dt-card{border-top:1px solid var(--line)}
  .dt-card-hd{gap:12px;margin-bottom:2px}
  .dt-ic{width:34px;height:34px}
  .dt-ic svg{width:19px;height:19px}
  .dt-card h3{font-size:1.04rem}
  .dt-card p{display:none}
  .dt-proof{margin:0 0 0 46px;padding:0;border:0;font-weight:500;color:var(--muted);font-size:.86rem}
  .dt-proof small{display:none}
  body.cw-editing .dt-card p{display:block}
}

/* ============================================================
   Trang Đào tạo trên điện thoại (09/10/2026, người dùng chọn phương án A qua
   xem-truoc-trang-dao-tao-mobile.html). body.dtpage = /vi/dao-tao, /en/training.
   Ba thẻ đối tượng gập lại (.mstack, như Hình thức và Lộ trình); khối Đối tác chỉ
   còn tên đơn vị + chip; ba ảnh thành dải vuốt ngang; ẩn ghi chú dưới lộ trình.
   ============================================================ */
@media(max-width:620px){
  .dtpage #doi-tac .rsx-feat p,.dtpage #doi-tac .rsx-dirs ol,
  .dtpage #doi-tac .rsx-dirs > .rsx-lbl{display:none}
  .dtpage #doi-tac .rsx-dirs .rsx-foot{border-top:0;padding-top:0;margin-top:0}
  .dtpage #lo-trinh .wrap > p{display:none}
  .dtpage .gal-slide .gs-track{display:flex;gap:12px;overflow-x:auto;scroll-snap-type:x mandatory;
    margin:0 -20px;padding:0 20px 4px;scroll-padding:0 20px;scrollbar-width:none}
  .dtpage .gal-slide .gs-track::-webkit-scrollbar{display:none}
  .dtpage .gal-slide .gs-track > figure{flex:0 0 82%;scroll-snap-align:start}
}

/* ---- Trang Đào tạo › Thi & chứng nhận (#chung-nhan), 12/10/2026 theo trang chủ
   daotao.cfdways.com và cert.cfdways.com: bên trái ba lối tắt (phòng thi, phiếu kết quả,
   tra cứu giấy chứng nhận) — thẻ trắng viền 1px, không vạch màu một cạnh; bên phải hình
   chồng ba văn bản MẪU, giấy chứng nhận nền kem viền đôi vàng đồng như tờ thật. ---- */
.dtc{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:clamp(28px,4vw,56px);align-items:center}
.dtc-links{display:flex;flex-direction:column;gap:12px}
.dtc-l{display:flex;align-items:center;gap:16px;background:#fff;border:1px solid var(--line);border-radius:12px;
  padding:16px 20px;color:var(--ink);text-decoration:none;transition:border-color .2s,box-shadow .2s,transform .2s}
.dtc-l:hover{border-color:#B9CBE3;box-shadow:0 10px 28px rgba(31,78,136,.12);transform:translateY(-2px);text-decoration:none}
.dtc-ri{width:44px;height:44px;flex:none;display:grid;place-items:center;border-radius:12px;background:#EDF1F6;color:var(--brand)}
.dtc-ri svg{width:22px;height:22px;fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}
.dtc-lt{display:flex;flex-direction:column;gap:2px;min-width:0;flex:1}
.dtc-lt b{font-weight:700;font-size:1.02rem}
.dtc-lt span{font-size:.92rem;color:var(--muted)}
.dtc-go{width:18px;height:18px;flex:none;fill:none;stroke:var(--muted);stroke-width:2;stroke-linecap:round;stroke-linejoin:round;transition:stroke .2s,transform .2s}
.dtc-l:hover .dtc-go{stroke:var(--brand);transform:translate(2px,-2px)}
.dtc-hv{display:flex;justify-content:center}
.dtc-stack{position:relative;height:310px;max-width:540px;width:100%}
.dtc-doc{position:absolute;width:62%;display:flex;flex-direction:column;border-radius:6px;background:#fff;border:1px solid #DFE4EA;
  box-shadow:0 1px 2px rgba(16,24,40,.06),0 16px 40px rgba(16,24,40,.12);padding:16px 16px 12px;font-size:12px}
.dtc-doc i{display:block;height:8px;border-radius:4px;background:#EEF1F5;margin-top:9px}
.dtc-dt{font-weight:700;font-size:11px;letter-spacing:.12em;text-transform:uppercase;color:var(--brand)}
.dtc-dt2{font-size:8px;letter-spacing:.2em;text-transform:uppercase;color:var(--muted)}
.dtc-d1{left:0;top:18px;transform:rotate(-6deg)}
.dtc-d2{right:0;top:0;transform:rotate(5deg)}
.dtc-paper{left:19%;top:70px;z-index:2;background:#FBF9F4;border:1px solid #9C7A3C;outline:3px double #9C7A3C;outline-offset:-7px;
  border-radius:4px;padding:18px 16px 12px;text-align:center;align-items:center}
.dtc-pt{font-family:"EB Garamond",Georgia,"Times New Roman",serif;font-weight:600;font-size:17px;letter-spacing:.12em;text-transform:uppercase;color:var(--brand)}
.dtc-pt2{font-size:8.5px;letter-spacing:.24em;text-transform:uppercase;color:var(--muted);margin-top:1px}
.dtc-pn{font-family:"EB Garamond",Georgia,"Times New Roman",serif;font-style:italic;font-weight:600;font-size:24px;line-height:1.2;margin-top:10px;color:var(--ink)}
.dtc-pc{font-size:12px;font-weight:600;color:var(--brand);margin-top:4px}
.dtc-pf{display:flex;align-items:center;gap:10px;margin-top:12px;text-align:left;align-self:stretch}
.dtc-paper .dtc-pf{margin-top:14px}
.dtc-qr{width:36px;height:36px;flex:none;fill:var(--ink);background:#fff;padding:3px;border-radius:2px}
.dtc-paper .dtc-qr{width:44px;height:44px}
.dtc-code small{display:block;font-size:10px;color:var(--muted);line-height:1.3}
.dtc-code b{display:block;font-size:12.5px;letter-spacing:.06em;color:var(--ink)}
.dtc-badge{position:absolute;z-index:3;right:-18px;bottom:-18px;white-space:nowrap;display:flex;align-items:center;gap:8px;background:#fff;
  border:1px solid #DFE4EA;border-radius:99px;padding:6px 14px 6px 8px;box-shadow:0 1px 2px rgba(16,24,40,.06),0 16px 40px rgba(16,24,40,.12);
  font-size:13px;font-weight:700;color:#1a7f4b}
.dtc-ok{width:20px;height:20px;border-radius:50%;background:#1a7f4b;display:grid;place-items:center;flex:none}
.dtc-ok svg{width:12px;height:12px;fill:none;stroke:#fff;stroke-width:3;stroke-linecap:round;stroke-linejoin:round}
@media(max-width:1100px) and (min-width:901px){.dtc-stack{transform:scale(.88)}}
@media(max-width:900px){.dtc{grid-template-columns:1fr}.dtc-hv{margin-top:8px}}
@media(max-width:620px){
  /* Điện thoại: hình minh họa chỉ để trang trí — bỏ, còn ba lối tắt. */
  .dtc-hv{display:none}
  .dtc-l{padding:14px 16px;gap:14px}
  .dtc-ri{width:40px;height:40px;border-radius:10px}
}

/* ============================================================
   Trang Đào tạo › "Theo đối tượng" (.dta) và "Hình thức" (.dtf) — phương án V1
   (09/10/2026, xem-truoc-dao-tao-doi-tuong-hinh-thuc.html): thẻ có ảnh thật, biểu
   tượng tròn đè mép ảnh, ba ý có dấu ✓; hình thức là dải xanh nhạt bốn ô đánh số.
   Cả hai lưới mang .mstack: luật `.mstack .mrow-body/.mrow-in` (từ 621px) đã kéo khung
   site.js dựng thành cột flex nên chân thẻ dính đáy — đừng đặt display ở đây, dưới
   620px nó là lưới 0fr/1fr đóng mở.
   ============================================================ */
.dta{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:24px}
.dta-c{display:flex;flex-direction:column;background:#fff;border:1px solid var(--line);border-radius:10px;
  overflow:hidden;transition:transform .3s ease-out,box-shadow .3s ease-out}
.dta-media{position:relative}
.dta-media .imgbox{background:#EDF1F6}
.dta-badge{position:absolute;left:16px;bottom:-22px;width:48px;height:48px;border-radius:50%;background:var(--brand);
  display:flex;align-items:center;justify-content:center;box-shadow:0 6px 16px rgba(31,78,136,.3)}
.dta-badge svg{width:24px;height:24px;fill:none;stroke:#fff;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}
.dta-b{padding:34px 24px 22px;display:flex;flex-direction:column;flex:1}
.dta-b h3{font-size:1.2rem;color:var(--ink);margin:0 0 6px;letter-spacing:-.01em}
.dta-b p{font-size:.95rem;color:var(--muted);margin:0 0 16px}
.dta-li{list-style:none;margin:0 0 18px;padding:0;display:grid;gap:10px}
.dta-li li{display:grid;grid-template-columns:22px 1fr;gap:10px;font-size:.94rem;font-weight:500;color:var(--ink);line-height:1.45}
.dta-li svg{width:22px;height:22px;padding:4px;border-radius:50%;background:#EDF1F6;fill:none;stroke:var(--brand);
  stroke-width:2.4;stroke-linecap:round;stroke-linejoin:round}
.dta-f{margin-top:auto;display:flex;align-items:center;justify-content:space-between;gap:12px;padding-top:14px;border-top:1px solid var(--line)}
.dta-f small{display:block;font-size:.66rem;letter-spacing:.1em;text-transform:uppercase;color:var(--muted);font-weight:600}
.dta-f span{font-size:.84rem;font-weight:600;color:var(--ink)}
.dta-go{flex:none;width:36px;height:36px;border-radius:50%;border:1px solid #DCE3EC;display:flex;align-items:center;
  justify-content:center;color:var(--brand);font-weight:700;text-decoration:none}
.dta-go:hover{text-decoration:none}
.dta-c:hover .dta-go{background:var(--brand);color:#fff;border-color:var(--brand)}
@media(min-width:621px){.dta-c:hover{transform:translateY(var(--rise));box-shadow:var(--lift-hover)}}
@media(any-hover:none){.dta-c:hover{transform:none;box-shadow:none}}
.dtf{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));background:#EDF1F6;border-radius:12px;padding:8px}
.dtf-i{position:relative;padding:26px 24px;display:flex;flex-direction:column}
.dtf-i + .dtf-i::before{content:"";position:absolute;left:0;top:26px;bottom:26px;width:1px;background:#DCE3EC}
.dtf-h{display:flex;align-items:center;justify-content:space-between;margin-bottom:18px}
.dtf-n{font-size:2.4rem;font-weight:700;color:var(--brand);letter-spacing:-.03em;line-height:1}
.dtf-h svg{width:44px;height:44px;padding:10px;border-radius:50%;background:#fff;fill:none;stroke:var(--brand);
  stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}
.dtf-i h3{font-size:1.06rem;color:var(--ink);margin:0 0 6px}
.dtf-i p{font-size:.92rem;color:#44505E;margin:0}
.dtf-i .more{margin-top:10px;font-size:.86rem;font-weight:600;color:var(--brand)}
@media(max-width:1024px){
  .dta{grid-template-columns:1fr 1fr}
  .dtf{grid-template-columns:1fr 1fr}
  .dtf-i:nth-child(3)::before{display:none}
}
/* Điện thoại: giữ kiểu gập (.mstack) đã chọn — ẩn ảnh, số và biểu tượng; mỗi thẻ
   còn một dòng tiêu đề, chạm mới mở chữ. */
@media(max-width:620px){
  .dta-media,.dtf-h,.dtf-i + .dtf-i::before{display:none}
  .dta.mstack,.dtf.mstack{display:block}
  .dta-c{border:0;border-radius:0}
  .dta-c + .dta-c{border-top:1px solid var(--line)}
  .dtf.mstack{background:#fff;padding:0;border-radius:var(--r)}
  .dta-b,.dtf-i{padding:0}
  .dta-b h3,.dtf-i h3{font-size:1.02rem;margin:0}
  .dta-b p{margin:0 0 12px}
}

/* ============================================================
   Trang Sự kiện (body.evpage) — phương án 2 "Thẻ ảnh + khối đăng ký ngang"
   (09/10/2026, qua xem-truoc-su-kien-bo-cuc.html). Tiền tố evr-.
   Khuôn HTML dựng ở lib/pagerender.js (injectEvents) và viết tay trong
   src/vi/su-kien.html — đổi một bên thì đổi bên kia. Khối đăng ký nền #EDF1F6 là
   khối nhấn màu DUY NHẤT của trang (xem .dt-band).
   ============================================================ */
.evr-band{padding-top:clamp(24px,3.4vw,40px);padding-bottom:clamp(24px,3.4vw,40px)}
.evr-bandg{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:40px;align-items:end;margin-top:14px}
.evr-bandg h1{margin-bottom:.25em}
.evr-stats{display:flex;background:#fff;border:1px solid var(--line);border-radius:10px}
.evr-stats a{display:block;padding:14px 22px;min-width:124px;color:var(--ink);text-decoration:none}
.evr-stats a + a{border-left:1px solid var(--line)}
.evr-stats a:hover{text-decoration:none;background:var(--bg)}
.evr-stats b{display:block;font-size:1.6rem;color:var(--brand);line-height:1.1;letter-spacing:-.02em}
.evr-stats span{font-size:.8rem;color:var(--muted)}
.evr-date{display:inline-flex;flex-direction:column;align-items:center;justify-content:center;flex:none;width:64px;height:68px;border-radius:10px;background:#fff;border:1px solid var(--line);line-height:1}
.evr-date b{font-size:1.6rem;color:var(--brand);letter-spacing:-.02em}
.evr-date span{font-size:.62rem;text-transform:uppercase;letter-spacing:.08em;font-weight:700;color:var(--ink);margin-top:5px}
.evr-meta{display:flex;flex-direction:column;gap:4px;font-size:.86rem;color:var(--muted);margin-top:8px}
.evr-mi{display:inline-flex;align-items:center;gap:7px}
.evr-mi svg,.evr-ph svg,.evr-libi svg,.evr-gets svg{width:16px;height:16px;flex:none;fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}
.evr-more{font-size:.86rem;font-weight:600;color:var(--brand)}
/* Thẻ ảnh sự kiện sắp diễn ra. */
.evr-cards{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:22px}
/* Không còn sự kiện sắp diễn ra: thẻ báo lịch trống thay lưới (lib/pagerender.js
   evrNoUpcoming, 11/10/2026 phương án B trong xem-truoc-su-kien-lich-trong.html). */
.evr-empty{display:flex;align-items:center;gap:22px;background:#fff;border:1px solid var(--line);border-radius:10px;padding:26px 28px}
.evr-eic{flex:none;width:56px;height:56px;border-radius:50%;background:#EDF1F6;display:flex;align-items:center;justify-content:center}
.evr-eic svg{width:26px;height:26px;fill:none;stroke:var(--brand);stroke-width:1.6;stroke-linecap:round;stroke-linejoin:round}
.evr-etx{flex:1;min-width:0}
.evr-etx b{display:block;font-size:1.08rem;color:var(--ink);margin-bottom:4px}
.evr-etx p{margin:0;font-size:.93rem;color:var(--muted);max-width:62ch}
.evr-eac{flex:none;display:flex;gap:18px;align-items:center}
.evr-elk{font-size:.9rem;font-weight:600}
@media(max-width:620px){
  .evr-empty{flex-direction:column;align-items:flex-start;gap:14px;padding:20px}
  .evr-eac{flex-wrap:wrap}
}
.evr-card{display:flex;flex-direction:column;background:#fff;border:1px solid var(--line);border-radius:10px;transition:transform .3s ease-out,box-shadow .3s ease-out}
.evr-cimg{position:relative;display:block;aspect-ratio:16/9;background:#EDF1F6;border-radius:10px 10px 0 0}
.evr-cimg img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;border-radius:10px 10px 0 0}
.evr-cimg .evr-ph{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;color:#9AA8BA}
.evr-cimg .evr-ph svg{width:36px;height:36px;stroke-width:1.3}
.evr-cimg .evr-date{position:absolute;left:16px;bottom:-26px;box-shadow:0 4px 12px rgba(26,25,24,.12)}
.evr-cb{display:flex;flex-direction:column;align-items:flex-start;padding:38px 22px 4px;flex:1}
.evr-cb .tag{margin-bottom:8px}
.evr-cb h3{font-size:1.08rem;line-height:1.35;margin:0}
.evr-cb h3 a{color:var(--ink)}
.evr-cf{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:16px 22px 20px}
@media(min-width:621px){.evr-card:hover{transform:translateY(var(--rise));box-shadow:var(--lift-hover)}}
@media(any-hover:none){.evr-card:hover{transform:none;box-shadow:none}}
/* Khối đăng ký: trái tóm tắt + "bạn sẽ nhận được", phải form hai cột. */
.evr-regband{background:#EDF1F6;padding:clamp(40px,5vw,64px) 0;margin-top:clamp(16px,2.6vw,32px)}
.evr-reg2{display:grid;grid-template-columns:minmax(0,.85fr) minmax(0,1.15fr);gap:clamp(28px,4vw,56px);align-items:start}
.evr-reginfo h2{margin:0 0 4px}
.evr-sum{display:flex;gap:14px;align-items:center;background:#fff;border:1px solid #DCE3EC;border-radius:10px;padding:12px 14px;margin:14px 0 6px}
.evr-sum .evr-date{width:56px;height:60px;border-radius:8px}
.evr-sum .evr-date b{font-size:1.4rem}
.evr-sum b{display:block;font-size:.98rem;line-height:1.35;color:var(--ink)}
.evr-sum span{font-size:.82rem;color:var(--muted)}
.evr-sum .evr-sumic{width:44px;height:44px;flex:none;fill:none;stroke:var(--brand);stroke-width:1.5}
.evr-gets{list-style:none;margin:22px 0 0;padding:0;display:grid;gap:16px}
.evr-gets li{display:flex;gap:14px;align-items:flex-start;font-size:.86rem;color:var(--muted)}
.evr-gets svg{width:40px;height:40px;padding:9px;border-radius:50%;background:#fff;color:var(--brand);stroke-width:1.7}
.evr-gets b{display:block;font-size:.95rem;color:var(--ink)}
.evr-formcard{background:#fff;border:1px solid #DCE3EC;border-radius:12px;padding:clamp(22px,2.6vw,32px)}
.evr-regd > .evr-regsum{display:none}
.evr-form{margin:0;gap:14px 16px}
.evr-form label{font-size:.82rem;margin-bottom:6px}
.evr-form input,.evr-form select,.evr-form textarea{padding:11px 12px}
.evr-form input::placeholder,.evr-form textarea::placeholder{color:#A3A6AA}
.evr-form .ctfoot{display:block}
.evr-submit{width:100%;justify-content:center;padding:13px}
.evr-priv{font-size:.78rem;color:var(--muted);margin:10px 0 0;text-align:center}
/* Đã diễn ra: dòng thời gian theo năm. */
.evr-tl{display:grid}
.evr-yr{display:grid;grid-template-columns:90px minmax(0,1fr);gap:20px;padding:18px 0;border-top:1px solid var(--line)}
.evr-y{font-size:1.6rem;font-weight:700;color:var(--brand);letter-spacing:-.02em;line-height:1}
.evr-yi{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:14px 24px}
.evr-ti{display:grid;grid-template-columns:120px minmax(0,1fr);gap:14px;align-items:center;color:var(--ink);text-decoration:none}
a.evr-ti:hover{text-decoration:none;color:var(--ink)}
a.evr-ti:hover b{color:var(--brand)}
.evr-ti img,.evr-ti .evr-ph{width:120px;height:72px;object-fit:cover;border-radius:6px;background:#EDF1F6;display:flex;align-items:center;justify-content:center;color:#9AA8BA}
.evr-ti .evr-ph svg{width:26px;height:26px;stroke-width:1.4}
.evr-ti small{display:block;font-size:.74rem;color:var(--muted)}
.evr-ti b{display:block;font-size:.95rem;line-height:1.35}
.evr-tlmore{display:none;margin-top:6px;padding:0;background:none;border:0;font:inherit;font-size:.86rem;font-weight:600;color:var(--brand);cursor:pointer}
/* Thư viện webinar. */
.evr-lib{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:16px}
.evr-libi{display:flex;flex-direction:column;gap:10px;background:#fff;border:1px solid var(--line);border-radius:10px;padding:18px 18px 16px;color:var(--ink);text-decoration:none}
.evr-libi:hover{text-decoration:none;color:var(--ink);border-color:var(--brand)}
.evr-libi svg{width:30px;height:30px;color:var(--brand);stroke-width:1.5}
.evr-libi small{display:block;font-size:.72rem;color:var(--muted);text-transform:uppercase;letter-spacing:.08em;font-weight:600}
.evr-libi b{font-size:1rem;line-height:1.35}
.evr-libi i{font-style:normal;font-size:.84rem;font-weight:600;color:var(--brand);margin-top:auto}
/* Hai ô cuối trang. */
.evr-cta{display:grid;grid-template-columns:1fr 1fr;gap:20px}
.evr-ctai{display:flex;flex-direction:column;gap:6px;background:var(--bg-soft);border-radius:var(--r);padding:26px 28px;color:var(--ink);text-decoration:none}
.evr-ctai:hover{text-decoration:none;color:var(--ink);background:var(--panel-hi)}
.evr-ctai .eyebrow{margin:0}
.evr-ctai b{font-size:1.15rem}
.evr-ctai > span:last-child{color:var(--brand);font-weight:600;font-size:.9rem}
@media(max-width:1024px){
  .evr-cards{grid-template-columns:1fr 1fr}
}
@media(max-width:900px){
  .evr-bandg,.evr-reg2{grid-template-columns:1fr}
  .evr-yi{grid-template-columns:1fr}
  .evr-lib{grid-template-columns:1fr 1fr}
}
/* Điện thoại: thẻ vuốt ngang, form gập sau một nút, ẩn ba con số và "bạn sẽ nhận
   được", dòng thời gian chỉ ba năm gần nhất, thư viện + hai ô cuối thành dòng. */
@media(max-width:620px){
  .evr-bandg p,.evr-stats{display:none}
  .evr-bandg{margin-top:10px}
  #sap-dien-ra{--sec-pt:20px}
  .evr-cards{display:flex;gap:12px;overflow-x:auto;scroll-snap-type:x mandatory;margin:0 -20px;padding:0 20px 6px;scroll-padding:0 20px;scrollbar-width:none}
  .evr-cards::-webkit-scrollbar{display:none}
  .evr-card{flex:0 0 84%;scroll-snap-align:start}
  .evr-cb{padding:34px 16px 2px}
  .evr-cb h3{font-size:1rem}
  .evr-cf{padding:12px 16px 16px}
  .evr-regband{padding:28px 0;margin-top:8px}
  .evr-gets,.evr-reginfo .eyebrow{display:none}
  .evr-reginfo h2{font-size:1.2rem}
  .evr-reg2{gap:12px}
  details.evr-regd:not([open]){padding:0;background:none;border:0}
  .evr-regd > .evr-regsum{display:block;list-style:none;cursor:pointer}
  .evr-regsum::-webkit-details-marker{display:none}
  .evr-regsum .btn{width:100%;justify-content:center}
  details.evr-regd[open] > .evr-regsum{display:none}
  .evr-formcard{padding:16px}
  .evr-tl:not(.all) .evr-yr:nth-child(n+4){display:none}
  .evr-tlmore{display:inline-block}
  .evr-yr{grid-template-columns:1fr;gap:8px;padding:12px 0}
  .evr-y{font-size:1.2rem}
  .evr-ti{grid-template-columns:72px minmax(0,1fr);gap:10px}
  .evr-ti img,.evr-ti .evr-ph{width:72px;height:46px}
  .evr-ti b{font-size:.88rem}
  #dang-mo .sec-head p{display:none}
  .evr-lib{display:block;background:#fff;border:1px solid var(--line);border-radius:var(--r)}
  .evr-libi{flex-direction:row;align-items:center;gap:12px;border:0;border-radius:0;padding:12px 14px}
  .evr-libi + .evr-libi{border-top:1px solid var(--line)}
  .evr-libi svg{width:24px;height:24px}
  .evr-libi > span{flex:1}
  .evr-libi small{display:none}
  .evr-libi b{font-size:.94rem}
  .evr-libi i{margin:0;font-size:.8rem;white-space:nowrap}
  .evr-cta{display:block;background:var(--bg-soft);border-radius:var(--r)}
  .evr-ctai{flex-direction:row;align-items:center;justify-content:space-between;background:none;padding:14px 16px}
  .evr-ctai + .evr-ctai{border-top:1px solid var(--line)}
  .evr-ctai .eyebrow,.evr-ctai > span:last-child{display:none}
  .evr-ctai b{font-size:.95rem}
  .evr-ctai::after{content:"\2192";color:var(--brand);font-weight:700}
}

/* ============================================================
   Trang chủ trọng tâm giá trị (10/10/2026, phương án A1 qua
   xem-truoc-phuong-an-a-nang-luc.html): dải số liệu dưới hero thành dải KẾT QUẢ
   (.stats.rband — bốn ô là link tới case study), và dòng kết quả .hkpi trong thẻ
   Dự án tiêu biểu (viết tay trong index.html; thẻ tự sinh lấy ô stats đầu tiên,
   lib/projrender.js).
   ============================================================ */
.rband .wrap{align-items:stretch}
a.rb{display:flex;flex-direction:column;align-items:center;text-align:center;color:var(--ink);text-decoration:none;padding:4px 6px}
a.rb:hover{text-decoration:none;color:var(--ink)}
a.rb:hover .rb-m{text-decoration:underline;text-underline-offset:3px}
.rb-k{font-size:.68rem;letter-spacing:.12em;text-transform:uppercase;font-weight:700;color:var(--muted);margin-bottom:8px}
.rband .stat .n{font-size:2rem}
.rband .stat .l{max-width:24ch}
.rb-m{margin-top:8px;font-size:.8rem;font-weight:600;color:var(--brand)}
/* Số trên, nhãn dưới: số dài ("Từng hàng ống", "64,4 → 53,5 °C") không chèn ép nhãn. */
.card .hkpi{margin:2px 0 14px;padding-top:10px;border-top:1px solid var(--line)}
.card .hkpi b{display:block;font-size:1.5rem;color:var(--brand);letter-spacing:-.02em;line-height:1.15}
.card .hkpi span{display:block;font-size:.84rem;color:var(--muted);line-height:1.4;margin-top:3px}
@media(max-width:620px){
  .rband .stat .n{font-size:1.5rem}
  .rb-k{font-size:.6rem;margin-bottom:4px}
  .rb-m{display:none}
  .card .hkpi{margin:0 0 10px}
  .card .hkpi b{font-size:1.3rem}
  .card .hkpi span{font-size:.76rem;margin-top:2px}
}
/* KPI dạng chữ trên thẻ dự án ("Trước khi chế tạo", "Khớp băng thử"): nhỏ hơn KPI số. */
.card .hkpi.t b{font-size:1.08rem;line-height:1.3}
/* Soát điện thoại 10/10/2026. Bốn ô dải kết quả chia chung hàng lưới (subgrid):
   nhãn "Kiểm chứng trước khi chế tạo" xuống hai dòng ở một ô thì số của ô bên cạnh
   vẫn thẳng hàng — nhãn bám đáy hàng của nó, số và chú thích bắt đầu cùng một đường.
   Ô là lưới bốn hàng (nhãn · số · chú thích · "Case study →"); điện thoại ẩn dòng
   link nên còn ba. row-gap:0 để các phần trong ô sát nhau, khoảng cách giữa hai
   hàng ô vẫn là gap của .stats .wrap. Trình duyệt chưa có subgrid giữ lối cũ. */
@supports (grid-template-rows:subgrid){
  a.rb{display:grid;grid-row:span 4;grid-template-rows:subgrid;row-gap:0;justify-items:center;align-items:start}
  .rb-k{align-self:end}
}
/* Nhãn xuống hai dòng thì chia đều ("Hiệu quả / năng lượng", không "Hiệu quả năng / lượng"). */
.rb-k{text-wrap:balance}
/* KPI trong thẻ dự án chia đều chữ cho các dòng ("Trước kỳ / bảo dưỡng", không
   "Trước kỳ bảo / dưỡng"); số đi liền đơn vị nhờ &nbsp; trong index.html. */
.card .hkpi b{text-wrap:balance}
@media(max-width:620px){
  @supports (grid-template-rows:subgrid){a.rb{grid-row:span 3}}
  /* Câu dẫn hero bản EN: căn đều hai bên ở bề ngang ~350px để lại khoảng trống
     lớn giữa các từ tiếng Anh ("Every   option   is") — căn trái. */
  html[lang=en] .hero .lead{text-align:left;text-wrap:pretty}
}

/* ---- Thẻ KPI trên hình hero (10/10/2026, qua xem-truoc-hero-kpi.html) ----
   Đặt vào CHỖ TRỐNG của từng hình (đo theo kênh alpha của ảnh): lò hơi góc dưới-phải,
   lọc bụi góc dưới-trái — sườn loe của thiết bị ở x ≈ 0,27 bề ngang nên thẻ lọc bụi
   chỉ rộng 150px. Thẻ nằm trong .hs-slide nên mờ/hiện cùng slide và đè lên cả video.
   Số liệu lấy từ case study cùng hiện tượng với hình, viết cho người đọc thông thường.
   Đổi ảnh hero thì kiểm lại vị trí. Điện thoại: hình chỉ ~350px, thẻ sẽ che mô phỏng — ẩn.
   Cập nhật 10/10 (xem-truoc-hero-kpi-desktop.html, phương án 1): bỏ khung và nền trắng,
   chữ đặt thẳng lên nền hero. Lò hơi: chuyển sang khoảng trống bên phải buồng lửa, dưới
   ống ra (mép trái khối ≈ 0,765 bề ngang, ngoài vòi đốt). Lọc bụi: đáy khối ngang cạnh
   dưới thân thiết bị — đáy vỏ ở 91,5 % chiều cao ảnh, nên bottom:8,5 %. */
.hs-kpi{position:absolute;z-index:3;display:flex;flex-direction:column;gap:3px;color:var(--ink);text-decoration:none}
.hs-kpi:hover{text-decoration:none;color:var(--ink)}
.hs-kpi:hover i{text-decoration:underline;text-underline-offset:3px}
.hs-kpi b{font-size:1.7rem;line-height:1.05;color:var(--brand);letter-spacing:-.02em;white-space:nowrap}
.hs-kpi span{font-size:.8rem;line-height:1.4;color:var(--ink)}
.hs-kpi i{font-style:normal;font-size:.76rem;font-weight:600;color:var(--brand);margin-top:5px;white-space:nowrap}
.hs-kpi.k-br{right:0;top:46%;width:23.5%}
.hs-kpi.k-bl{left:.5%;bottom:8.5%;width:150px;max-width:24%}
/* Màn ~1000–1240px: hình hero chỉ còn ~460px, chỗ trống hẹp lại — chữ nhỏ một nấc,
   tên dự án được xuống dòng thay vì bị mép hình cắt. */
@media(max-width:1240px){
  .hs-kpi b{font-size:1.35rem}
  .hs-kpi span{font-size:.72rem;line-height:1.35}
  .hs-kpi i{font-size:.7rem;white-space:normal;margin-top:3px}
  .hs-kpi.k-bl{width:120px}
}
body.cw-editing .hs-kpi{pointer-events:none}
.hs-kpi span em{font-style:normal}
/* Ngắt dòng chỉ dùng trên điện thoại ("bụi trong / khí thải"); máy tính đọc liền. */
.hs-kpi span br{display:none}
/* Điện thoại (10/10, M1 qua xem-truoc-hero-kpi-mobile-tren-hinh.html): KPI vẫn nằm
   trên hình như bản máy tính. Hình chỉ ~350px nên chỗ trống hẹp; để chữ đủ lớn mà
   đọc (nhãn ~12,5px) thì nhãn rút còn vế đầu — phần sau nằm trong <em> ở index.html
   và ẩn ở đây ("amoniac đốt kèm than", "bụi trong khí thải"); tên dự án vẫn là link.
   Thay cho dòng KPI dưới chú thích (.hs-mk) dùng trước đó. */
@media(max-width:620px){
  .hs-kpi{gap:2px}
  .hs-kpi b{font-size:1.4rem}
  .hs-kpi span{font-size:.78rem;line-height:1.3}
  .hs-kpi span em{display:none}
  .hs-kpi i{font-size:.74rem;white-space:normal;margin-top:4px}
  .hs-kpi.k-br{top:44%;width:25%}
  .hs-kpi span br{display:inline}
  /* Lọc bụi: khối trải từ mép dưới ống vào (58,5 % chiều cao ảnh) tới đáy hình và
     căn GIỮA theo chiều dọc — khoảng cách tới ống và tới đáy luôn bằng nhau ở mọi
     bề ngang, số không sát hình. */
  .hs-kpi.k-bl{width:120px;max-width:34%;top:58.5%;bottom:0;justify-content:center}
  .hs-kpi b{line-height:1}
  /* EN "dust in flue gas" một dòng, rộng hơn: đẩy lên là chạm sườn loe — giữ sát đáy. */
  html[lang=en] .hs-kpi.k-bl{top:auto;bottom:3%}
  .hs-kpi.k-bl i{white-space:nowrap}
}
/* Slide lò hơi trên điện thoại lệch phải (ống ra chạy tới mép phải, thang màu cách
   mép trái 4,9 %): dời riêng HÌNH sang trái 4 %, thẻ KPI đứng yên — chỉ cắt phần
   trong suốt bên trái;
   ống ra kết thúc trước mép phải, không kéo dài (người dùng 10/10/2026). */
@media(max-width:620px){
  .hs-slide:has(img[src*="hero-truong-nhiet-do"]) .imgbox{transform:translateX(-4%)}
}
@media(max-width:380px){
  .hs-kpi b{font-size:1.25rem}
  .hs-kpi span{font-size:.72rem}
  .hs-kpi i{font-size:.7rem}
}
@media(max-width:340px){
  .hs-kpi b{font-size:1.1rem}
  .hs-kpi span{font-size:.66rem}
  .hs-kpi i{font-size:.64rem}
}

/* ============================================================
   Bốn khối cuối trang chủ (10/10/2026 — người dùng chọn trong
   xem-truoc-bon-khoi-trang-chu.html: Ngành B, Chứng thực B nền nhạt, Công bố C, Hợp tác B).
   Trước đó cả bốn cùng một khuôn "tiêu đề + hàng thẻ trắng" nên đọc ra đơn điệu;
   giờ mỗi khối một nhịp: ảnh · dải nền · con số · tấm liền.
   Ngành và Hợp tác KHÔNG đổi HTML (chỉ thêm lớp .coop vào section — lớp không
   tính vào đường dẫn data-cw, xem lib/editable.js pathOf), nên bản sửa tại chỗ
   giữ nguyên. Chứng thực/Công bố đổi markup ở lib/quoterender.js và
   lib/pubrender.js (span .qm, .pj/.pif/.py).
   ============================================================ */

/* ---- Ngành: ảnh đứng, chữ trắng trên lớp tối ----
   Lớp tối là ::before của THẺ (không phải của .imgbox: ::after của .imgbox dành
   cho nhãn "Ảnh chờ xuất bản" khi sửa tại chỗ), pointer-events:none để bấm vào
   ảnh lúc sửa vẫn tới được ô ảnh. Link "Chi tiết →" giấu chữ (font-size:0, tên
   link vẫn còn cho trình đọc màn hình), phủ cả thẻ bằng ::after của chính nó; chỉ
   còn mũi tên ở góc trên phải (::before) — cùng kiểu mũi tên của thẻ Năng lực
   (#nang-luc .path h3::after), rê chuột thì dịch sang phải. Lớp tối có thêm một
   dải mỏng ở mép trên để mũi tên trắng không chìm vào trời/trần sáng. */
#linh-vuc .g4{counter-reset:ng;gap:20px}
/* Thẻ là flex cột dồn đáy: .body KHÔNG định vị (z-index vẫn ăn vì là flex item),
   nên ::before/::after của link lấy chính THẺ làm khung — mũi tên ở góc thẻ,
   lớp phủ link phủ kín thẻ. */
#linh-vuc .card{display:flex;flex-direction:column;justify-content:flex-end;position:relative;aspect-ratio:15/16;overflow:hidden; /* 3/4 thấp đi 20% (11/10/2026) */
  border:0;background:#2a2928;color:#fff;counter-increment:ng}
#linh-vuc .card:hover{background:#2a2928}
#linh-vuc .card .imgbox{position:absolute;inset:0;height:100%;aspect-ratio:auto;margin:0;border-radius:0}
#linh-vuc .card .imgbox img{width:100%;height:100%;object-fit:cover;transition:transform .7s ease}
#linh-vuc .card:hover .imgbox img{transform:scale(1.06)}
#linh-vuc .card::before{content:"";position:absolute;inset:0;z-index:1;pointer-events:none;
  background:linear-gradient(to bottom,rgba(18,20,24,.32) 0,rgba(18,20,24,0) 22%),
    linear-gradient(to top,rgba(18,20,24,.92) 0%,rgba(18,20,24,.78) 34%,rgba(18,20,24,.18) 62%,rgba(18,20,24,0) 76%)}
#linh-vuc .card .body{display:block;position:static;flex:none;z-index:2;padding:24px 24px 22px}
#linh-vuc .card h3{display:block;min-height:0;padding:0;margin:0 0 12px;font-size:1.32rem;line-height:1.25;
  letter-spacing:-.01em;color:#fff}
#linh-vuc .card h3::before{content:counter(ng,decimal-leading-zero);display:block;margin-bottom:6px;
  font-size:.74rem;letter-spacing:.14em;font-weight:700;color:rgba(255,255,255,.7)}
#linh-vuc .card:hover h3{color:#fff}
#linh-vuc .card ul{list-style:none;margin:0;padding:0;font-size:.88rem;line-height:1.5;color:rgba(255,255,255,.86)}
#linh-vuc .card li{padding:3px 0}
/* Danh sách ngành chỉ mở ra khi rê chuột (11/10/2026): mặc định thẻ chỉ còn số +
   tên ngành ở đáy; hover/focus thì danh sách trượt lên. Máy không có chuột
   (any-hover:none) và lúc sửa tại chỗ thì luôn hiện. */
#linh-vuc .card h3{margin:0}
#linh-vuc .card ul{max-height:0;opacity:0;overflow:hidden;margin-top:0;
  transition:max-height .45s ease,opacity .3s ease,margin-top .45s ease}
#linh-vuc .card:hover ul,#linh-vuc .card:focus-within ul{max-height:12em;opacity:1;margin-top:12px}
/* Danh sách mở ra lấn lên vùng ảnh còn sáng → thêm một lớp tối hiện cùng lúc. */
#linh-vuc .card::after{content:"";position:absolute;inset:0;z-index:1;pointer-events:none;opacity:0;
  background:linear-gradient(to top,rgba(18,20,24,.45) 0,rgba(18,20,24,.4) 45%,rgba(18,20,24,0) 78%);
  transition:opacity .4s ease}
#linh-vuc .card:hover::after,#linh-vuc .card:focus-within::after{opacity:1}
@media(any-hover:none){#linh-vuc .card ul{max-height:none;opacity:1;margin-top:12px}}
body.cw-editing #linh-vuc .card ul{max-height:none;opacity:1;margin-top:12px}
#linh-vuc .card .more{position:static;display:block;font-size:0;margin:0;padding:0}
#linh-vuc .card .more::after{content:"";position:absolute;inset:0;z-index:3}
#linh-vuc .card .more::before{content:"\2192";position:absolute;top:18px;right:22px;z-index:3;
  font-size:1.4rem;line-height:1;font-weight:600;color:#fff;transition:transform .2s ease-out}
#linh-vuc .card:hover .more::before{transform:translateX(5px)}
body.cw-editing #linh-vuc .card .more::after{display:none}
body.cw-editing #linh-vuc .card .more{position:static;font-size:0;padding:0}
@media(max-width:620px){
  #linh-vuc .g4{gap:12px}
  #linh-vuc .card{aspect-ratio:4/5}
  #linh-vuc .card::before{background:linear-gradient(to bottom,rgba(18,20,24,.3) 0,rgba(18,20,24,0) 24%),
    linear-gradient(to top,rgba(18,20,24,.85) 0%,rgba(18,20,24,.4) 35%,rgba(18,20,24,0) 60%)}
  #linh-vuc .card .body{padding:14px}
  #linh-vuc .card h3{font-size:1rem;line-height:1.28;margin:0}
  #linh-vuc .card h3::before{font-size:.66rem;margin-bottom:3px}
  #linh-vuc .card ul{display:none}
  #linh-vuc .card .more::before{top:12px;right:14px;font-size:1.1rem}
  /* Chạm vào thẻ thì mở/gập danh sách ngành ngay trên thẻ; mũi tên góc phải
     đứng yên chỗ cũ và là chỗ duy nhất dẫn sang trang ngành (site.js, 11/10/2026).
     Thẻ giữ nguyên 4:5: mỗi ngành một dòng, dài quá thì cắt bằng dấu ba chấm —
     không bẻ dòng cho thẻ khỏi giãn. */
  #linh-vuc .card.open::after{opacity:1;background:rgba(18,20,24,.5)}
  #linh-vuc .card.open ul{display:block;max-height:none;opacity:1;margin-top:8px;font-size:.78rem;line-height:1.4;
    animation:lvMo .25s ease}
  #linh-vuc .card.open li{padding:1px 0;margin:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
}
@keyframes lvMo{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}

/* ---- Chứng thực: dải nền nhạt tràn viền, hai lời trích ngăn bằng vạch dọc ----
   10/10/2026: bản đầu dùng nền --brand đặc, người dùng thấy đậm quá → nền xanh
   nhấn nhạt #EDF1F6 (cùng mã với dải Đào tạo, xem .dt-band — người dùng chọn
   giữ HAI khối xanh trên trang chủ, xem xem-truoc-nen-chung-thuc.html), chữ màu mực, ngoặc
   kép và vạch ngăn theo sắc xanh xám #DCE3EC. Hai lời trích không khung; vạch dọc
   là .qview::after đứng yên giữa khung băng chuyền — băng trượt từng tấm nên lúc
   nghỉ khe giữa hai tấm luôn nằm đúng giữa. Dấu nháy mở (.qm đầu,
   lib/quoterender.js) thành ký hiệu lớn, dấu đóng ẩn. */
/* 11/10/2026: người dùng thêm nền xanh nhạt cho Ngành (#linh-vuc) và Hợp tác
   (.coop) — trang chủ giờ có bốn khối xanh, xen kẽ khối trắng, không khối nào kề nhau. */
body.home .sec.qband,body.home #linh-vuc,body.home .sec.coop{background:#EDF1F6;padding:clamp(56px,6vw,84px) 0}
body.home .sec.qband > .wrap:first-child,body.home #linh-vuc > .wrap:first-child,
body.home .sec.coop > .wrap:first-child{padding-top:0}
body.home .sec.qband > .wrap:first-child::before,
body.home .sec.qband + .sec > .wrap:first-child::before,
body.home #linh-vuc > .wrap:first-child::before,body.home #linh-vuc + .sec > .wrap:first-child::before,
body.home .sec.coop > .wrap:first-child::before,body.home .sec.coop + .sec > .wrap:first-child::before{display:none}
body.home .sec.qband + .sec,body.home #linh-vuc + .sec,body.home .sec.coop + .sec{padding-top:0}
.qband .quotes{gap:96px}
.qband .quotes.qrun > .quote{flex:0 0 calc((100% - 96px)/2)}
.qband .qview{position:relative}
.qband .quote{background:none;color:var(--ink);padding:6px 0 0;border-radius:0}
.qband .quote p{color:var(--ink);font-size:1.4rem;line-height:1.5;font-weight:500;letter-spacing:-.005em;margin:0 0 30px}
.qband .quote .qm:first-child{display:block;height:46px;font:700 84px/.8 Georgia,"Times New Roman",serif;color:var(--brand)}
.qband .quote .qm:last-child{display:none}
.qband .quote .who{border-top:0;padding-top:0}
.qband .quote .who b{font-size:.98rem;color:var(--ink)}
.qband .quote .who span{font-size:.85rem;color:var(--muted)}
.qband .quote .who-logo{height:30px;filter:none;opacity:1}
@media(min-width:621px){
  .qband .qview::after,.qband .quotes:not(.qrun)::after{content:"";position:absolute;left:50%;top:0;bottom:0;
    width:1px;background:#DCE3EC}
  .qband .quotes:not(.qrun){position:relative}
}
@media(max-width:620px){
  .qband .quotes{gap:26px}
  .qband .quotes.qrun > .quote{flex:0 0 100%}
  .qband .quote p{font-size:1.16rem}
  .qband .quote .qm:first-child{height:38px;font-size:70px}
  .qband .quote .who-logo{height:22px}
}

/* ---- Công bố: dải bốn con số rồi danh sách dạng bảng ----
   Dải số (.pubstat-m, máy chủ tính lại) nằm CUỐI .wrap trong HTML để không đổi
   đường dẫn data-cw của phần đứng trước; `order` đưa nó lên ngay dưới tiêu đề.
   Mỗi công bố là một dòng: năm | tên bài + tạp chí | IF — .meta `display:contents`
   để ba span của nó thành ô lưới của .body. */
.pubsec > .wrap{display:flex;flex-direction:column}
.pubsec > .wrap > .sec-head{order:0}
.pubsec .pubstat-m{order:1;display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:0;
  background:none;border-radius:0;padding:0;margin:0 0 8px;text-align:left;
  border-top:1px solid var(--line);border-bottom:1px solid var(--line)}
.pubsec .pubpick{order:2}
.pubsec .pubpick + p{order:3}
.pubsec .pubbtn-m{order:4}
.pubsec .pubstat-m .pubstat-i{padding:18px 0 16px 28px}
.pubsec .pubstat-m .pubstat-i:first-child{padding-left:0}
.pubsec .pubstat-m .pubstat-i + .pubstat-i::before{left:0;top:0;bottom:0;background:var(--line)}
/* 1.7rem: 2.7rem bị chê to quá (10/10/2026); vẫn nhỉnh hơn KPI thẻ dự án (1.4rem). */
.pubsec .pubstat-m .pubstat-i b{font-size:1.7rem;font-weight:700;line-height:1.1;letter-spacing:-.02em}
.pubsec .pubstat-m .pubstat-i span{font-size:.86rem;color:var(--muted);margin-top:6px}
.pubsec .pubpick{display:block}
.pubsec .pubpick > .card{background:none;border:0;border-bottom:1px solid var(--line);border-radius:0;
  padding:20px 0;box-shadow:none;transform:none}
.pubsec .pubpick > .card:hover{background:none;box-shadow:none;transform:none}
.pubsec .pubpick > .card .body{flex:1;display:grid;grid-template-columns:72px minmax(0,1fr) auto;
  column-gap:24px;align-items:baseline;padding:0}
.pubsec .pubpick .meta{display:contents}
.pubsec .pubpick .py{grid-column:1;grid-row:1 / 3;font-size:.86rem;font-weight:700;color:var(--muted)}
.pubsec .pubpick h3{grid-column:2;grid-row:1;margin:0 0 4px;font-size:1.06rem;line-height:1.45;font-weight:600;color:var(--ink)}
.pubsec .pubpick .pj{grid-column:2;grid-row:2;font-size:.84rem;color:var(--muted)}
.pubsec .pubpick .pif{grid-column:3;grid-row:1 / 3;font-size:.78rem;font-weight:700;color:var(--brand);white-space:nowrap}
.pubsec .pubpick + p{margin-top:22px!important}
@media(max-width:620px){
  .pubsec .pubstat-m{grid-template-columns:1fr 1fr;margin-top:4px}
  .pubsec .pubstat-m .pubstat-i{padding:14px 0 12px 16px}
  .pubsec .pubstat-m .pubstat-i:nth-child(odd){padding-left:0}
  .pubsec .pubstat-m .pubstat-i:nth-child(odd)::before{display:none}
  .pubsec .pubstat-m .pubstat-i:nth-child(n+3){border-top:1px solid var(--line)}
  .pubsec .pubstat-m .pubstat-i b{font-size:1.3rem}
  .pubsec .pubpick > .card .body{grid-template-columns:minmax(0,1fr);row-gap:4px}
  .pubsec .pubpick .py{grid-row:1}
  .pubsec .pubpick h3{grid-column:1;grid-row:2;margin:0}
  .pubsec .pubpick .pj{grid-column:1;grid-row:3}
  .pubsec .pubpick .pif{display:none}
}

/* ---- Hợp tác: MỘT tấm ba cột, chân tấm là dòng hồ sơ năng lực ----
   Lưới .g3 và .notecard là hai phần tử anh em; ghép thành một tấm bằng viền và
   bo góc nối tiếp. Biểu tượng là ::before của .body (nền #EDF1F6 + SVG nét xanh,
   cùng kiểu .dt-ic của dải Đào tạo) — không thêm phần tử nào vào HTML.
   Chỉ từ 621px: điện thoại giữ nguyên các dòng .mstack bấm mở. */
@media(min-width:621px){
  .coop .g3{gap:0;background:#fff;border:1px solid var(--line);border-radius:var(--r) var(--r) 0 0;overflow:hidden}
  .coop .g3 > .card{position:relative;border:0;border-radius:0;background:none}
  .coop .g3 > .card + .card{border-left:1px solid var(--line)}
  .coop .g3 > .card:hover{background:var(--bg);transform:none;box-shadow:none}
  .coop .g3 > .card .body{padding:32px 32px 28px}
  .coop .g3 > .card .body::before{content:"";display:block;width:46px;height:46px;border-radius:50%;
    background:#EDF1F6 no-repeat center/24px 24px}
  .coop .g3 > .card:nth-child(1) .body::before{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%232B65B0' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3.5 4.5h17v11h-17z'/%3E%3Cpath d='M8 20h8M12 15.5V20'/%3E%3Cpath d='M6.5 12c2-4 3.8 0 5.6-2.4S15.6 7 17.5 9'/%3E%3C/svg%3E")}
  .coop .g3 > .card:nth-child(2) .body::before{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%232B65B0' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='8' cy='15' r='4.2'/%3E%3Cpath d='m11 12 9-9M16.5 6.5l2.2 2.2M14.3 8.7l2.2 2.2'/%3E%3C/svg%3E")}
  .coop .g3 > .card:nth-child(3) .body::before{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%232B65B0' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m12 4 10 5-10 5L2 9l10-5Z'/%3E%3Cpath d='M6 11.5V17c0 1.7 2.7 3 6 3s6-1.3 6-3v-5.5'/%3E%3C/svg%3E")}
  .coop .g3 > .card h3{font-size:1.24rem;margin:20px 0 8px;color:var(--ink)}
  .coop .g3 > .card p{color:var(--muted);font-size:.95rem;margin:0 0 20px}
  .coop .g3 > .card .more{font-size:.9rem}
  .coop .g3 > .card .more::after{content:"";position:absolute;inset:0}
  body.cw-editing .coop .g3 > .card .more::after{display:none}
  .coop .notecard{margin-top:0!important;border:1px solid var(--line);border-top:0;
    border-radius:0 0 var(--r) var(--r);background:var(--bg);padding:18px 32px}
  .coop .notecard .btn{background:var(--brand);border-color:var(--brand);color:#fff}
  .coop .notecard .btn:hover{background:var(--brand-mid);border-color:var(--brand-mid);color:#fff}
}
/* 621–1024px: .g3/.g4 rơi về hai cột. Thẻ ngành đứng 3:4 ở hai cột cao gần 600px
   → nằm ngang 4:3; tấm hợp tác giữ đủ ba cột, không để cột thứ ba rớt hàng. */
@media(min-width:621px) and (max-width:1024px){
  #linh-vuc .card{aspect-ratio:4/3}
  .coop .g3{grid-template-columns:repeat(3,minmax(0,1fr))}
  .coop .g3 > .card .body{padding:24px 22px 22px}
  .coop .notecard{padding:16px 22px}
}

/* ---- Dự án tiêu biểu: kết quả lên đầu (10/10/2026, phương án A trong
   xem-truoc-du-an-tieu-bieu.html; người dùng bỏ dòng phân loại ở đáy thẻ) ----
   Không đổi HTML: `order` đưa .hkpi lên ngay dưới ảnh và thành dòng to nhất thẻ,
   tên dự án đứng sau; .meta ẩn. Link "Đọc case study" giấu chữ (vẫn là tên link
   cho trình đọc màn hình), phủ cả thẻ. Không có mũi tên — người dùng gỡ nút
   tròn ở góc ảnh (10/10/2026). */
#du-an .projpick > .card{position:relative;overflow:hidden;flex-direction:column}
#du-an .projpick .imgbox{aspect-ratio:16/10}
#du-an .projpick .imgbox img{transition:transform .6s ease}
#du-an .projpick > .card:hover .imgbox img{transform:scale(1.04)}
#du-an .projpick .card .body{display:flex;flex-direction:column;flex:1;padding:22px 24px 24px}
#du-an .projpick .card .hkpi{order:-1;margin:0 0 14px;padding:0 0 14px;border-top:0;border-bottom:1px solid var(--line)}
/* Một cỡ cho mọi kết quả, số hay chữ (người dùng 10/10: "0" 2.3rem cạnh
   "Khớp vết ăn mòn" 1.4rem trông lệch — lấy cỡ của dạng chữ). */
#du-an .projpick .card .hkpi b,#du-an .projpick .card .hkpi.t b{font-size:1.4rem;line-height:1.2;font-weight:700;letter-spacing:-.015em}
#du-an .projpick .card .hkpi span{font-size:.88rem;margin-top:6px}
#du-an .projpick .card .body h3{min-height:0;font-size:1.06rem;line-height:1.38;color:var(--ink);margin:0}
#du-an .projpick .card .body .meta{display:none}
#du-an .projpick .card .more{font-size:0;position:static;margin:0}
#du-an .projpick .card .more::after{content:"";position:absolute;inset:0;z-index:2}
body.cw-editing #du-an .projpick .card .more::after{display:none}
/* Thân thẻ cùng nền #EDF0F5 với hình (mọi ảnh thiet-bi-*-01 đều nền này), để ảnh
   và chữ liền một khối thay vì hình xám trên thẻ trắng (12/10/2026, thử). Viền và
   vạch dưới kết quả lấy tông lạnh theo nền. Hover giữ nguyên nền (không đổi sang
   --bg-soft như thẻ chung) — đổi là thân thẻ lệch màu với hình; thẻ vẫn nhấc lên
   và hình vẫn phóng. */
#du-an .projpick > .card{background:#EDF0F5;border-color:#DFE4EC}
#du-an .projpick > .card:hover{background:#EDF0F5}
#du-an .projpick .card .hkpi{border-bottom-color:#D7DDE7}
/* Vạch ngăn hình–chữ cùng kiểu vạch dưới kết quả: thụt theo lề chữ,
   cách hình 12px (người dùng 12/10: sát hình quá) — margin âm ăn bớt padding-top. */
#du-an .projpick .card .body::before{content:"";order:-2;border-top:1px solid #D7DDE7;margin:-10px 0 18px}
@media(max-width:620px){
  #du-an .g3.projpick{gap:12px}
  #du-an .projpick .card .body{padding:12px 12px 14px}
  #du-an .projpick .card .body::before{margin:-5px 0 10px}
  #du-an .projpick .card .hkpi{margin:0 0 10px;padding:0 0 10px}
  #du-an .projpick .card .hkpi b,#du-an .projpick .card .hkpi.t b{font-size:1.08rem}
  #du-an .projpick .card .hkpi span{font-size:.74rem}
  #du-an .projpick .card .body h3{font-size:.9rem}
}

/* ---- Phần mềm Simcenter: thẻ có hình minh họa (11/10/2026, phương án A trong
   xem-truoc-phan-mem-trang-chu.html; hình do Claude vẽ lại thành SVG theo đặc
   trưng từng phần mềm — image/phan-mem/mh-*.svg, không phải ảnh chụp kết quả) ----
   .imgbox nằm SAU .body trong HTML để đường dẫn data-cw của chữ trong thẻ giữ
   nguyên (lib/editable.js pathOf); `order:-1` đưa nó lên đầu thẻ. Bỏ lớp .mstack
   khỏi lưới: điện thoại là lưới 2×2 hình + tên, không còn các dòng bấm mở.
   Link "Chi tiết" giấu chữ, phủ cả thẻ; mũi tên cạnh tên như thẻ Năng lực. */
#phan-mem .g4{gap:20px}
#phan-mem .g4 > .card{display:flex;flex-direction:column;position:relative;overflow:hidden}
#phan-mem .g4 > .card .imgbox{order:-1;aspect-ratio:16/10;height:auto;margin:0;border-radius:0;
  background:#EDF0F5;border-bottom:1px solid var(--line)}
#phan-mem .g4 > .card .imgbox img{width:100%;height:100%;object-fit:cover;transition:transform .6s ease}
#phan-mem .g4 > .card:hover .imgbox img{transform:scale(1.04)}
#phan-mem .g4 > .card .body{padding:20px 22px 22px}
#phan-mem .g4 > .card h3{display:flex;align-items:baseline;gap:10px;font-size:1.08rem;margin:0 0 8px;color:var(--ink)}
#phan-mem .g4 > .card h3::after{content:"\2192";margin-left:auto;flex:none;font-weight:600;color:var(--brand);transition:transform .2s ease-out}
#phan-mem .g4 > .card:hover h3::after{transform:translateX(5px)}
#phan-mem .g4 > .card p{margin:0;font-size:.92rem;color:var(--muted)}
#phan-mem .g4 > .card .more{font-size:0;position:static;margin:0;padding:0}
#phan-mem .g4 > .card .more::after{content:"";position:absolute;inset:0;z-index:2}
body.cw-editing #phan-mem .g4 > .card .more::after{display:none}
@media(max-width:620px){
  #phan-mem .g4{grid-template-columns:1fr 1fr;gap:12px}
  #phan-mem .g4 > .card .body{padding:12px 12px 14px}
  #phan-mem .g4 > .card h3{font-size:.92rem;line-height:1.3;margin:0}
  #phan-mem .g4 > .card h3::after{display:none}
  #phan-mem .g4 > .card p{display:none}
}

/* Huy hiệu Siemens Software Partner ở dải đầu trang Phần mềm (11/10/2026).
   <img> đặt CUỐI .wrap để không đổi đường dẫn data-cw của tiêu đề/câu dẫn; màn
   rộng thì treo bên phải, căn giữa theo chiều cao dải; dưới 900px rơi xuống dưới
   câu dẫn. */
.pageband > .wrap:has(> .pb-badge){position:relative}
.pageband .pb-badge{position:absolute;right:20px;top:50%;transform:translateY(-50%);
  height:112px;width:auto;display:block}
@media(min-width:901px){.pageband > .wrap:has(> .pb-badge) > p{max-width:min(78ch,calc(100% - 280px))}}
@media(max-width:900px){
  .pageband .pb-badge{position:static;transform:none;height:64px;margin-top:20px}
}

/* Dải đầu trang Đào tạo (11/10/2026): ảnh lớp học thay bằng hình minh họa tự vẽ
   image/dao-tao-minh-hoa.svg (dữ liệu đơn vị → mô hình CFD → kiểm chứng, lộ trình
   4 bước). Hình nền trong suốt, hòa thẳng vào nền dải — không khung, không bóng
   (người dùng bỏ tấm nền xanh nhạt + viền, 11/10/2026). */
.dt-hero-art,.dt-hero-art .imgbox{background:none;border:0;box-shadow:none;border-radius:0}
.dt-hero-art img{object-fit:contain}
/* Dải Đào tạo trang chủ dùng cùng hình (11/10/2026, thay ảnh lớp học + chú thích
   đè ảnh): nền trong suốt hòa vào nền xanh nhạt #EDF1F6 của dải. */
.dt-photo.dt-art{border-radius:0;overflow:visible;box-shadow:none}
.dt-photo.dt-art .imgbox{background:none}
.dt-photo.dt-art .imgbox img{object-fit:contain;object-position:50% 50%}
/* Thu hình (12/10/2026): ở cột 1.04fr hình cao ~305px so với khối chữ ~230px, chữ trôi
   giữa vùng cao hơn nó nên đệm trên trông dày gấp đôi đệm dưới. Trần 520px → hình
   ~250px, ngang khối chữ; dạt phải cho mép hình thẳng mép thẻ thứ ba. */
@media(min-width:901px){
  .dt-top{grid-template-columns:minmax(0,1.15fr) minmax(0,1fr)}
  .dt-photo.dt-art{width:100%;max-width:520px;justify-self:end}
}

/* ---- Drawer menu: hai tầng gập (11/10/2026, phương án B không icon trong
   xem-truoc-menu-mobile.html) ----
   Mở một mục cấp một chỉ hiện TÊN CÁC NHÓM; chạm tên nhóm mới mở các mục của
   nhóm đó, mỗi lần một nhóm (site.js). Bảng "Giải pháp" từ 848px còn 165px khi
   chưa mở nhóm, nên các mục cấp một không bị đẩy khỏi màn hình.
   Tiêu đề nhóm thôi là nhãn in hoa nhỏ: nó thành một dòng bấm được, cùng thang
   chữ với mục, kèm mũi tên gập. Mục con bỏ icon, thụt 16px dưới tên nhóm — tên
   nhóm đã làm việc định vị mà icon từng gánh trong danh sách dài liền mạch.
   Hàng chân "Theo ngành" ẩn trong drawer: trùng mục Lĩnh vực ở cấp một.
   Thẻ ảnh (.mcard) giữ ảnh nhỏ — đó là ảnh bài/sản phẩm, không phải icon. */
.gchev{display:none}
@media(max-width:1024px){
  .mlist .sub.mega .mfr{display:none}
  .mlist .sub .nvi{display:none}
  .mlist .sub.mega .mcol > ul > li.grp{display:flex;align-items:center;justify-content:space-between;gap:12px;
    min-height:0;padding:13px 0 13px 2px;font-size:1rem;font-weight:600;letter-spacing:0;text-transform:none;
    line-height:1.35;color:var(--ink);cursor:pointer;-webkit-tap-highlight-color:transparent}
  .mlist .sub.mega .mcol.gopen > ul > li.grp{color:var(--brand)}
  .gchev{display:block;flex:none;width:8px;height:8px;margin-right:6px;border-right:1.6px solid currentColor;
    border-bottom:1.6px solid currentColor;transform:rotate(45deg);opacity:.5;transition:transform .2s ease}
  .mcol.gopen .gchev{transform:rotate(225deg);opacity:1}
  .mlist .sub.mega .mcol:not(.gopen) > ul > li:not(.grp){display:none}
  .mlist .sub.mega .mcol > ul > li:not(.grp):not(.more) > a{padding:11px 0 11px 16px}
  .mlist .sub.mega .mcol > ul > li.more > a{padding:6px 0 14px 16px;font-size:.9rem}
  .mlist .sub.mega .mcol.ccol > ul > li.mcard > a{padding-left:16px}
  /* Mục nổi bật (.ft) đậm ở desktop vì có dòng mô tả bên dưới; trong drawer mô
     tả đã ẩn, để đậm thì nhóm "Theo đối tượng" trông như một loại dòng khác. */
  .mlist .sub.mega li.ft .nvt b{font-weight:400}
}

/* ============================================================
   Trang chủ trên máy tính bảng dọc (12/10/2026, đo ở Galaxy Tab S8 800px và
   iPad Pro 1024px). Ở 621–1024px trang rơi về bố cục điện thoại kéo giãn: hình
   hero 4:3 tràn cả bề ngang (570px ở 800, 740px ở 1024), ba trụ Năng lực xếp
   2 + 1 để thẻ thứ ba mồ côi, dải Đào tạo có hình cao 430px và ba thẻ một cột.
   Ngang (1280px) đã dùng bố cục máy tính, không đụng.
   ============================================================ */
@media(min-width:621px) and (max-width:1024px){
  /* Hero: tiêu đề trải trọn bề ngang, dưới là chữ + nút bên trái, hình bên phải.
     Đặt ô bằng grid-area nên thứ tự DOM (đầu → hình → thân) giữ nguyên. */
  .hero-inner{grid-template-columns:minmax(0,.85fr) minmax(0,1.15fr);column-gap:32px}
  .hero-head{grid-area:1/1/2/3}
  .hero-body{grid-area:2/1;align-self:center}
  .hero .herovis{grid-area:2/2;align-self:center;margin:8px 0 0}
  .hero .cta-row{margin-top:24px}
  .hero .cta-row .btn{flex:1 1 100%;justify-content:center;text-align:center}

  /* Năng lực: đủ ba cột như máy tính, đệm thẻ hẹp lại cho ảnh còn rộng. */
  #nang-luc .g3{grid-template-columns:repeat(3,minmax(0,1fr));gap:16px}
  #nang-luc .path{padding-left:18px;padding-right:18px}
  #nang-luc .path .imgbox{margin:18px -18px 0}
  #nang-luc .path h3{font-size:1.05rem}
  #nang-luc .path .nl-out{font-size:.86rem}

  /* Trích dẫn: 1.4rem là cỡ cho cột ~570px; cột tablet chỉ 330–440px. */
  .qband .quotes{gap:56px}
  .qband .quotes.qrun > .quote{flex:0 0 calc((100% - 56px)/2)}
  .qband .quote p{font-size:1.18rem}
}
/* Đào tạo 621–900px (trên 900 đã là hai cột). Cùng lối với hero tablet: tiêu đề
   trải trọn bề ngang, dưới là câu dẫn + hai nút xếp dọc (trái) | hình (phải).
   Bản đầu (hình một cột, căn giữa dưới chữ) để trống nửa phải khối chữ và hình
   trôi lơ lửng giữa dải — người dùng chê 12/10/2026.
   display:contents trên cột chữ: <div> trơn không mang data-cw (đã kiểm _site),
   nên đường dẫn bản sửa tại chỗ không đổi. Ba thẻ đứng cạnh nhau với biểu tượng
   nằm trên tên — tên dài ("Tổ chức & viện nghiên cứu") không bị ép vào 140px. */
@media(min-width:621px) and (max-width:900px){
  .dt-top{grid-template-columns:minmax(0,.85fr) minmax(0,1.15fr);column-gap:32px;row-gap:0;align-items:start}
  .dt-top > div:first-child{display:contents}
  .dt-top > div:first-child > *{grid-column:1/-1;min-width:0}
  .dt-top > div:first-child > .lead{grid-column:1;grid-row:3;align-self:end;margin-top:14px;text-wrap:pretty}
  .dt-top > div:first-child > .btnrow{grid-column:1;grid-row:4;align-self:start;margin-top:24px}
  .dt-band .btnrow .btn{flex:1 1 100%;justify-content:center;text-align:center}
  .dt-photo.dt-art{grid-column:2;grid-row:3/5;align-self:center;width:100%;margin-top:14px}
  /* Cột chữ ~240px ở 640: "Lịch workshop & webinar →" gãy hai dòng nếu giữ đệm 22px. */
  .dt-band .btnrow .btn{white-space:nowrap;padding-left:12px;padding-right:12px}
  .dt-aud{grid-template-columns:repeat(3,minmax(0,1fr));gap:16px}
  .dt-card{padding:22px 20px 20px}
  .dt-card-hd{flex-wrap:wrap;row-gap:14px}
  .dt-card-hd::after{order:1}
  .dt-card h3{order:2;flex:1 1 100%;font-size:1.05rem}
}

/* ---------- Thanh sự kiện sắp diễn ra (trang chủ) ----------
   12/10/2026, phương án A qua xem-truoc-tin-noi-bat.html. Máy chủ chèn
   <aside class="evbar"> ngay trước <header> (lib/eventbar.js): dải tối mảnh cuộn
   đi cùng trang, header vẫn dính như cũ. Nền là --brand-dark (cùng màu footer)
   để không thêm màu thứ ba; nhãn dùng --accent-lite như chữ xanh trên nền tối
   ở footer. Điện thoại: bỏ nhãn và ngày dài, chỉ còn tên gọn + ngày ngắn. */
.evbar{background:var(--brand-dark);color:#D9D8D6;font-size:.84rem;line-height:1.35}
.evbar[hidden]{display:none}
.evbar-in{display:flex;align-items:center;justify-content:center;gap:14px;min-height:40px;position:relative;padding-right:52px}
.evbar-k{color:var(--accent-lite);font-weight:600;font-size:.72rem;letter-spacing:.1em;text-transform:uppercase;white-space:nowrap}
.evbar a{color:#fff;text-decoration:none}
.evbar-t{font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0}
.evbar-t:hover{text-decoration:underline;text-underline-offset:3px}
.evbar-d{color:#A9A7A4;white-space:nowrap}
.evbar-go{font-weight:600;white-space:nowrap;text-decoration:underline !important;text-underline-offset:3px;text-decoration-color:#6E6B69 !important}
.evbar-go:hover{text-decoration-color:#fff !important}
.evbar-x{position:absolute;right:var(--evbar-xr,20px);top:50%;transform:translateY(-50%);background:none;border:0;color:#A9A7A4;font:inherit;font-size:1.15rem;line-height:1;padding:8px;cursor:pointer}
.evbar-x:hover{color:#fff}
.evbar a:focus-visible,.evbar-x:focus-visible{outline:2px solid var(--accent-lite);outline-offset:2px}
.evbar-s{display:none}
@media(max-width:900px){.evbar-d{display:none}}
@media(max-width:620px){
  .evbar-in{justify-content:flex-start;gap:12px;font-size:.8rem;padding-right:56px}
  .evbar-k,.evbar-l{display:none}
  .evbar-s{display:inline}
  .evbar-t{flex:1}
}

/* ---------- Công cụ tính toán (/vi/cong-cu-tinh-toan ↔ /en/calculators) ----------
   12/10/2026. Phép tính, hình SVG và tab ở /assets/js/calc.js; mọi lớp mang tiền
   tố .ct-. Tấm công cụ theo thang thẻ trắng + viền; hình minh họa nằm trên nền
   trang --bg. Hai màu chức năng duy nhất: xanh logo (đạt) và hổ phách #C9822B
   (cần chú ý: vùng đệm y+, ô bị bỏ qua khi CFL > 1, nón Mach, đường δ). */
.ct-page [hidden]{display:none!important}
/* Thẻ dẫn sang trang công cụ, ở mục #tai-lieu trang Tài nguyên. Là <a> chứ không
   phải <div> để không đổi chỉ số div0/div1… của các khối data-cw phía sau. */
.ct-promo{display:flex;align-items:center;gap:20px;background:#fff;border:1px solid var(--line);border-radius:var(--r);
  padding:20px 24px;margin-bottom:26px;color:var(--ink);text-decoration:none;transition:transform .2s ease,box-shadow .2s ease,background .2s}
.ct-promo:hover{transform:translateY(var(--rise));box-shadow:var(--lift-hover);text-decoration:none}
.ct-promo > svg{flex:0 0 auto;width:42px;height:42px;fill:none;stroke:var(--brand);stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round}
.ct-promo-t{flex:1;display:flex;flex-direction:column;gap:3px;min-width:0}
.ct-promo-t b{font-size:1.16rem;color:var(--brand);font-weight:600;line-height:1.3}
.ct-promo-t span{font-size:.94rem;font-weight:500}
.ct-promo-go{font-size:.86rem;font-weight:600;color:var(--brand);white-space:nowrap}
@media(any-hover:none){.ct-promo:hover{transform:none;box-shadow:none}}
@media(max-width:620px){.ct-promo{flex-wrap:wrap;gap:12px 16px;padding:16px 18px}.ct-promo-go{width:100%}}
/* Tab hai cấp. Cấp 1 — nhóm công cụ: cùng dáng .rtabs của trang Tài nguyên (gạch
   chân xanh, số đếm .rnum) nhưng không dính và không dùng lớp .rtab, vì site.js gắn
   tay nghe cho mọi .rtab. Cấp 2 — công cụ trong nhóm: một tấm trắng, các tab gom theo
   bước thiết lập (nhãn nhỏ phía trên), tab đang mở tô xanh. Điện thoại: hàng tab
   công cụ vuốt ngang. */
.ct-hub{padding-top:clamp(22px,3vw,34px)}
.ct-cats{display:flex;gap:4px;border-bottom:1px solid var(--line);margin-bottom:16px;overflow-x:auto;scrollbar-width:none}
.ct-cats::-webkit-scrollbar{display:none}
.ct-cat{position:relative;background:none;border:none;cursor:pointer;font-family:inherit;font-size:1rem;font-weight:700;
  color:var(--muted);padding:12px 16px 13px;white-space:nowrap;display:inline-flex;align-items:center;gap:9px;transition:color .15s}
.ct-cat:hover,.ct-cat.on{color:var(--ink)}
.ct-cat.on::after{content:'';position:absolute;left:12px;right:12px;bottom:-1px;height:2.5px;border-radius:3px 3px 0 0;background:var(--accent)}
.ct-cat svg{width:20px;height:20px;fill:none;stroke:currentColor;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}
.ct-cat.on svg{stroke:var(--brand)}
.ct-cat.on .rnum{background:var(--accent);border-color:var(--accent);color:#fff}
.ct-catlead{margin:0 0 16px;font-size:1rem;line-height:1.6}
.ct-tabs{display:flex;background:#fff;border:1px solid var(--line);border-radius:var(--r);padding:8px 6px;margin:0 0 30px;
  overflow-x:auto;scrollbar-width:none}
.ct-tabs::-webkit-scrollbar{display:none}
.ct-grp{flex:0 0 auto;display:flex;flex-direction:column;gap:5px;padding:2px 10px}
.ct-grp + .ct-grp{border-left:1px solid var(--line)}
.ct-grp-l{font-size:.68rem;letter-spacing:.08em;text-transform:uppercase;color:var(--muted);font-weight:600;padding:0 8px;white-space:nowrap}
.ct-grp-b{display:flex;gap:4px}
.ct-tab{display:inline-flex;align-items:center;gap:8px;border:0;background:none;font:inherit;font-size:.9rem;font-weight:600;
  color:var(--ink);padding:8px 13px 8px 10px;border-radius:6px;cursor:pointer;white-space:nowrap;transition:background .15s,color .15s}
.ct-tab svg{width:20px;height:20px;flex:0 0 auto;fill:none;stroke:var(--brand);stroke-width:1.6;stroke-linecap:round;stroke-linejoin:round}
.ct-tab:hover{background:var(--bg-soft)}
.ct-tab.on{background:var(--brand);color:#fff}
.ct-tab.on svg{stroke:#fff}
.ct-tab:focus-visible,.ct-cat:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}
.ct-pane > .sec-head{margin-bottom:18px}
/* Biểu đồ tính chất (nhóm lưu chất): hàng nút chọn tính chất nằm trên SVG. */
.ct-chips{display:flex;flex-wrap:wrap;gap:6px;margin:0 0 10px}
.ct-chip{font:inherit;font-size:.86rem;font-weight:600;min-width:40px;padding:5px 12px;border-radius:999px;border:1px solid #C9D6E6;
  background:#fff;color:var(--brand);cursor:pointer;transition:background .15s,color .15s,border-color .15s}
.ct-chip:hover{border-color:var(--brand)}
.ct-chip.on{background:var(--brand);border-color:var(--brand);color:#fff}
.ct-area{fill:rgba(43,101,176,.08)}
@media(max-width:620px){
  .ct-cat{font-size:.95rem;padding:10px 12px 11px}
  .ct-catlead{font-size:.94rem}
  .ct-tabs{margin:0 -20px 24px;border-radius:0;border-left:0;border-right:0;padding:8px 10px}
  .ct-grp{padding:2px 6px}
  .ct-tab{font-size:.86rem;padding:7px 11px 7px 8px}
  .ct-tab svg{width:18px;height:18px}
}
/* Giải thích của từng công cụ: Là gì? · Vì sao cần? · Cách dùng — ba cột chia vạch. */
.ct-intro{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:0;margin:0 0 22px}
.ct-intro > div{padding:0 26px;border-left:1px solid var(--line);min-width:0}
.ct-intro > div:first-child{padding-left:0;border-left:0}
.ct-intro h3{font-size:.8rem;letter-spacing:.06em;text-transform:uppercase;color:var(--brand);font-weight:600;margin:0 0 .5em}
.ct-intro p{font-size:.95rem;line-height:1.65;margin:0}
@media(max-width:760px){
  .ct-intro{grid-template-columns:1fr;gap:16px}
  .ct-intro > div{padding:0;border-left:0}
}

.ct-tool{display:grid;grid-template-columns:minmax(0,5fr) minmax(0,7fr);gap:clamp(20px,3vw,36px);background:#fff;
  border:1px solid var(--line);border-radius:var(--r);padding:clamp(18px,2.4vw,28px)}
.ct-form{display:flex;flex-direction:column;gap:16px;min-width:0}
.ct-fields{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px 14px}
.ct-wide{grid-column:1/-1}
.ct-f{display:flex;flex-direction:column;gap:5px;margin:0;min-width:0}
.ct-l{font-size:.8rem;color:var(--muted);font-weight:500;line-height:1.3}
.ct-u{display:flex;align-items:center;border:1px solid #CFCDCB;border-radius:var(--r-sm);background:#fff;transition:border-color .15s,box-shadow .15s}
.ct-u:focus-within{border-color:var(--brand);box-shadow:0 0 0 3px rgba(var(--accent-rgb),.14)}
.ct-u input,.ct-u select{flex:1;min-width:0;width:100%;border:0;background:transparent;font:inherit;font-size:.95rem;color:var(--ink);
  padding:8px 10px;outline:none;font-variant-numeric:tabular-nums}
.ct-u select{cursor:pointer}
.ct-u i{font-style:normal;font-size:.82rem;color:var(--muted);padding-right:10px;white-space:nowrap}
.ct-range{width:100%;accent-color:var(--brand);margin:4px 0 0;cursor:pointer}
.ct-seg{display:inline-flex;flex-wrap:wrap;gap:3px;padding:3px;background:var(--bg-soft);border-radius:6px;align-self:flex-start;justify-self:start}
.ct-seg label{position:relative;cursor:pointer}
.ct-seg input{position:absolute;opacity:0;pointer-events:none}
.ct-seg span{display:block;padding:6px 14px;border-radius:4px;font-size:.85rem;font-weight:500;color:var(--muted);transition:background .15s,color .15s}
.ct-seg input:checked + span{background:#fff;color:var(--ink);box-shadow:0 1px 2px rgba(26,25,24,.14)}
.ct-seg input:focus-visible + span{outline:2px solid var(--accent);outline-offset:1px}
.ct-fluid{display:flex;flex-direction:column;gap:6px}
.ct-props{margin:0;font-size:.8rem;color:var(--muted)}
.ct-pull{justify-content:flex-end}
.ct-pull .btn{white-space:normal;text-align:left;line-height:1.3;justify-content:center}
.ct-sug{margin:0;font-size:.82rem;color:var(--muted);display:flex;flex-wrap:wrap;align-items:center;gap:6px 10px}
.ct-sug button{font:inherit;font-size:.8rem;font-weight:600;color:var(--brand);background:none;border:1px solid var(--brand);border-radius:4px;padding:2px 10px;cursor:pointer}
.ct-sug button:hover{background:var(--brand);color:#fff}
.ct-res{border-top:1px solid var(--line);padding-top:16px;display:flex;flex-direction:column;gap:14px}
.ct-main{display:flex;flex-direction:column;gap:2px}
.ct-main b{font-size:clamp(1.5rem,2.4vw,1.9rem);font-weight:600;color:var(--brand);line-height:1.2;font-variant-numeric:tabular-nums;letter-spacing:-.01em}
.ct-main small{font-size:.82rem;color:var(--muted)}
.ct-main small:empty{display:none}
.ct-list{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px 18px;margin:0}
.ct-list > div{min-width:0}
.ct-list dt{font-size:.78rem;color:var(--muted);line-height:1.3}
.ct-list dd{margin:2px 0 0;font-size:.95rem;font-weight:600;font-variant-numeric:tabular-nums}
.ct-msg{margin:0;font-size:.86rem;line-height:1.55}
.ct-msg:empty{display:none}
.ct-dot{display:inline-block;width:8px;height:8px;border-radius:50%;margin:0 8px 1px 0;background:var(--brand)}
.ct-dot.is-warn{background:#C9822B}

.ct-viz{margin:0;background:var(--bg);border-radius:var(--r);padding:clamp(10px,1.6vw,18px);display:flex;flex-direction:column;justify-content:center;min-width:0}
.ct-svg{width:100%;height:auto;display:block;overflow:hidden;--ct-fs:11.5px}
.ct-svg text{font-family:var(--font-body);font-size:var(--ct-fs)}
.ct-viz figcaption{font-size:.8rem;color:var(--muted);line-height:1.45;margin-top:10px}
.ct-hbg{fill:var(--bg-soft)}
.ct-hln{stroke:#A9A7A4;stroke-width:1.3}
.ct-wall{stroke:var(--ink);stroke-width:1.6}
.ct-z1{fill:rgba(43,101,176,.12)}
.ct-z2{fill:rgba(201,130,43,.11)}
.ct-z3{fill:rgba(43,101,176,.06)}
.ct-z4{fill:rgba(44,42,41,.025)}
.ct-zl{fill:var(--muted);font-weight:600}
.ct-onwall{fill:var(--ink);paint-order:stroke;stroke:var(--bg-soft);stroke-width:3px}
.ct-grid{stroke:rgba(44,42,41,.13);stroke-width:1}
.ct-ax{fill:var(--muted)}
.ct-axt{fill:var(--ink);font-weight:600;font-style:italic}
.ct-asym{fill:none;stroke:#8F8C89;stroke-width:1.2;stroke-dasharray:4 4}
.ct-note{fill:#8F8C89;font-style:italic}
.ct-vec{stroke:rgba(43,101,176,.38);stroke-width:1.2}
.ct-vech{fill:none;stroke:rgba(43,101,176,.55);stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round}
.ct-curve{fill:none;stroke:var(--brand);stroke-width:2.6;stroke-linejoin:round;stroke-linecap:round}
.ct-pt{fill:var(--brand);opacity:.5}
.ct-cell{fill:rgba(43,101,176,.13);stroke:var(--brand);stroke-width:1.4}
.ct-layer{stroke:rgba(43,101,176,.42);stroke-width:.8}
.ct-mk{stroke:var(--brand-mid);stroke-width:1.3;stroke-dasharray:5 4}
.ct-mkdot{fill:var(--brand);stroke:#fff;stroke-width:2}
.ct-lblbg{fill:var(--ink)}
.ct-lbl{fill:#fff;font-weight:600}
.ct-brk{fill:none;stroke:var(--ink);stroke-width:1.2}
.ct-lbl2{fill:var(--ink);font-weight:600;paint-order:stroke;stroke:var(--bg);stroke-width:4px;stroke-linejoin:round}
.ct-lay{fill:var(--brand)}
.ct-core{fill:#fff;stroke:#AEBBCB;stroke-width:.9}
.ct-delta{stroke:#C9822B;stroke-width:1.5;stroke-dasharray:6 4}
.ct-streak{stroke:var(--brand);stroke-width:1.7;stroke-linecap:round;opacity:.6}
.ct-b1{fill:rgba(43,101,176,.25)}
.ct-b2{fill:rgba(201,130,43,.5)}
.ct-b3{fill:var(--brand)}
.ct-duct{fill:#fff}
.ct-ductw{fill:none;stroke:var(--ink);stroke-width:2}
.ct-eddy{fill:rgba(43,101,176,.07);stroke:rgba(43,101,176,.25);stroke-width:.8}
.ct-eddyarc{fill:none;stroke:var(--brand);stroke-width:1.3;stroke-linecap:round}
.ct-plotbg{fill:#fff}
.ct-band{fill:rgba(43,101,176,.12)}
.ct-mean{stroke:var(--ink);stroke-width:1;stroke-dasharray:4 3}
.ct-trace{fill:none;stroke:var(--brand);stroke-width:1.8;stroke-linejoin:round}
.ct-cc{fill:#fff;stroke:#B9B7B5;stroke-width:1;transition:fill .2s,stroke .2s}
.ct-cc.is-here{fill:rgba(43,101,176,.16);stroke:var(--brand)}
.ct-cc.is-skip{fill:rgba(201,130,43,.16);stroke:#C9822B}
.ct-skip{fill:#A4661C;font-weight:600}
.ct-parcel{fill:var(--brand);stroke:#fff;stroke-width:2}
.ct-trail{fill:none;stroke:var(--brand);stroke-width:1.5;opacity:.55}
.ct-jump{fill:none;stroke:var(--brand);stroke-width:1.4;stroke-dasharray:3 4}
.ct-vec2{stroke:var(--ink);stroke-width:2}
.ct-vech2{fill:none;stroke:var(--ink);stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.ct-wave{fill:none;stroke:var(--brand);stroke-width:1.5}
.ct-cone{fill:none;stroke:#C9822B;stroke-width:2.2}

.ct-math{margin-top:12px;border:1px solid var(--line);border-radius:var(--r);background:#fff}
.ct-math summary{cursor:pointer;padding:12px 18px;font-size:.9rem;font-weight:600;color:var(--brand);list-style:none;display:flex;align-items:center;gap:10px}
.ct-math summary::-webkit-details-marker{display:none}
.ct-math summary::before{content:"";width:6px;height:6px;border-right:2px solid currentColor;border-bottom:2px solid currentColor;transform:rotate(-45deg);transition:transform .2s}
.ct-math[open] summary::before{transform:rotate(45deg)}
.ct-math ul{margin:0;padding:0 18px 16px 38px;font-size:.88rem;line-height:1.65}
.ct-math li{margin-bottom:4px}

@media(max-width:1020px){
  .ct-tool{grid-template-columns:1fr}
  .ct-viz{order:-1}
}
@media(max-width:620px){
  .ct-tool{padding:14px;gap:18px}
  .ct-viz{padding:6px}
  .ct-svg{--ct-fs:20px}
  .ct-fields{gap:10px}
  .ct-seg span{padding:6px 11px}
  .ct-math summary{padding:12px 14px}
  .ct-math ul{padding:0 14px 14px 30px}
}
