:root{--nen:#eef1ee;--the:#fff;--muc:#15201b;--muc2:#41514a;--muc3:#767c78;--nhan:#1c6b4a;--nhan-nh:#e3efe8;--sai:#ac3a2b;--sai-nh:#fbeceb;--vang:#8a6a1e;--vang-nh:#f7efd9;--vien:#d4dad5;--vien2:#e8ebe8;--chon:#1c6b4a;--bong:0 1px 2px rgba(21,32,27,.06),0 10px 28px -14px rgba(21,32,27,.18)}
@media (prefers-color-scheme:dark){:root:not([data-theme="light"]){--nen:#101514;--the:#181e1b;--muc:#e8eeea;--muc2:#a9b5af;--muc3:#7d8b85;--nhan:#5cc294;--nhan-nh:#163024;--sai:#f08b7c;--sai-nh:#331c19;--vang:#d9b45e;--vang-nh:#3a3016;--vien:#2b3430;--vien2:#222a26;--chon:#5cc294;--bong:0 1px 2px rgba(0,0,0,.45),0 12px 32px -16px rgba(0,0,0,.8)}}
:root[data-theme="dark"]{--nen:#101514;--the:#181e1b;--muc:#e8eeea;--muc2:#a9b5af;--muc3:#7d8b85;--nhan:#5cc294;--nhan-nh:#163024;--sai:#f08b7c;--sai-nh:#331c19;--vang:#d9b45e;--vang-nh:#3a3016;--vien:#2b3430;--vien2:#222a26;--chon:#5cc294;--bong:0 1px 2px rgba(0,0,0,.45),0 12px 32px -16px rgba(0,0,0,.8)}
*{box-sizing:border-box}
body{background:var(--nen);color:var(--muc);font-family:"Be Vietnam Pro",system-ui,sans-serif;font-size:14px;line-height:1.55;padding-block:0 40px;padding-left:16px;padding-right:16px}
.bao{max-width:1300px;margin:0 auto}
h1{font-size:clamp(22px,3.4vw,30px);line-height:1.15;letter-spacing:-.02em;margin:0 0 4px;font-weight:700}
.eb{display:inline-flex;align-items:center;gap:8px;font-size:11.5px;letter-spacing:.14em;text-transform:uppercase;color:var(--nhan);font-weight:600;margin:26px 0 12px}
.eb::before{content:"";width:20px;height:2px;background:var(--nhan)}
.dat{color:var(--muc2);margin:0 0 16px;max-width:76ch}
code,.mono{font-family:"IBM Plex Mono",monospace;font-variant-numeric:tabular-nums}
.app{display:grid;grid-template-columns:300px 1fr;gap:14px;align-items:start}
@media(max-width:960px){.app{grid-template-columns:1fr}.san{order:-1}.bang-dk{position:static;max-height:none}}
.bang-dk{background:var(--the);border:1px solid var(--vien);border-radius:14px;padding:14px;box-shadow:var(--bong);position:sticky;top:12px;max-height:calc(100vh - 24px);overflow-y:auto}
.san{background:var(--the);border:1px solid var(--vien);border-radius:14px;box-shadow:var(--bong);overflow:hidden;position:relative}
canvas{display:block;width:100%;height:auto;touch-action:none}
.hud{position:absolute;left:12px;bottom:10px;right:12px;font-family:"IBM Plex Mono",monospace;font-size:11px;color:#fff;background:rgba(0,0,0,.58);padding:4px 9px;border-radius:5px;pointer-events:none}
.kyhieu{position:absolute;left:12px;top:12px;display:flex;align-items:center;gap:8px;font-size:12px;font-weight:600;color:#fff;background:rgba(16,22,20,.82);padding:6px 11px;border-radius:8px;pointer-events:none;opacity:0;transition:opacity .12s}
.kyhieu.hien{opacity:1}.kyhieu .bt{font-family:"IBM Plex Mono",monospace;font-size:15px;line-height:1}.kyhieu.ve{background:rgba(28,107,74,.92)}.kyhieu.sau{background:rgba(120,80,20,.9)}
.nh{font-size:10.5px;text-transform:uppercase;letter-spacing:.1em;color:var(--muc3);font-weight:600;margin:14px 0 7px}.nh:first-child{margin-top:0}
.hang{display:flex;gap:6px;flex-wrap:wrap}
button{font-family:inherit;font-size:12.5px;font-weight:500;color:var(--muc);background:var(--nen);border:1px solid var(--vien);border-radius:8px;padding:7px 10px;cursor:pointer;transition:.12s}
button:hover:not(:disabled){border-color:var(--nhan);color:var(--nhan)}button.ch{background:var(--nhan);border-color:var(--nhan);color:#fff}button:disabled{opacity:.38;cursor:not-allowed}
button.ph{color:var(--sai)}button.ph:hover:not(:disabled){border-color:var(--sai)}button.to{width:100%;text-align:left}
input[type=number]{font-family:"IBM Plex Mono",monospace;font-size:12.5px;width:100%;padding:6px 8px;border:1px solid var(--vien);border-radius:7px;background:var(--nen);color:var(--muc)}
.kt2{display:grid;grid-template-columns:1fr auto 1fr;gap:6px;align-items:center}.kt2 span{color:var(--muc3);font-size:12px}
.o-mau{display:grid;grid-template-columns:repeat(6,1fr);gap:5px}.o-mau i{display:block;aspect-ratio:1;border-radius:5px;cursor:pointer;border:2px solid transparent;background-size:cover}.o-mau i:hover{border-color:var(--muc3)}.o-mau i.ch{border-color:var(--chon);box-shadow:0 0 0 2px var(--the) inset}
.tt{font-size:12px;color:var(--muc2);margin:6px 0 0}
input[type=range]{width:100%;accent-color:var(--nhan);margin:4px 0 0}.so{font-family:"IBM Plex Mono",monospace;font-size:12px;color:var(--muc2);display:flex;justify-content:space-between}
.cd{background:var(--nen);border-radius:9px;padding:9px 10px;font-size:12px;color:var(--muc2)}.cd b{color:var(--muc)}.cd.bac{background:var(--vang-nh);color:var(--vang)}.cd.bac b{color:var(--vang)}
.the-nc{display:none;border:1px solid var(--vien);border-radius:11px;padding:11px 12px;margin-top:12px;background:var(--the)}.the-nc.mo{display:block}
.the-nc .nh:first-child{margin-top:0}
.chon-nep{display:flex;flex-direction:column;gap:6px}.chon-nep .vai{font-size:11px;color:var(--muc3);text-transform:uppercase;letter-spacing:.04em;margin-top:4px}
.chon-nep .hang button{display:inline-flex;align-items:center;gap:5px;padding:4px 7px}.chon-nep .hang button svg{width:30px;height:20px;flex:none}.chon-nep .hang button.ch svg *{stroke:#fff}
.chon-nep .hang button.ch svg .to{fill:#fff}
.mau-nep{display:flex;gap:6px}.mau-nep button{width:30px;height:24px;padding:0;border-radius:6px;border:2px solid var(--vien)}.mau-nep button.ch{outline:2px solid var(--nhan);outline-offset:1px;border-color:#fff}
.mau-nep button:disabled{opacity:.25}
#popMach{max-height:calc(100% - 64px);overflow:auto}#popMach .chon-nep .hang button span{max-width:120px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.chua{background:var(--nhan-nh);border-left:3px solid var(--nhan);border-radius:0 9px 9px 0;padding:9px 11px;font-size:12.5px;margin-top:12px}
.bo-mau{display:grid;grid-template-columns:1fr 1fr;gap:6px}
.mau-khoi{text-align:left;padding:0 0 6px;border-radius:9px;line-height:1.25;overflow:hidden}.mau-khoi .hinh{display:block;aspect-ratio:12/7;background-size:cover;background-position:center;border-bottom:1px solid var(--vien);margin-bottom:5px}.mau-khoi b{display:block;font-size:11.5px;padding:0 7px}i.stt{display:inline-block;font-style:normal;font-family:ui-monospace,Menlo,monospace;font-size:10.5px;background:var(--nhan);color:#fff;border-radius:4px;padding:0 5px;margin-right:5px;vertical-align:1px}summary i.stt{margin-right:7px}.mau-khoi small{display:block;font-size:10.5px;color:var(--muc3);margin-top:2px}.mau-khoi em{display:inline-block;font-style:normal;font-size:9.5px;color:var(--muc3);border:1px solid var(--vien);border-radius:4px;padding:0 4px;margin:4px 7px 0}.nh .dem,summary .dem{font-weight:400;color:var(--muc3);font-size:11px}
.tw{overflow-x:auto;border:1px solid var(--vien);border-radius:10px;margin-top:14px;background:var(--the)}
table{border-collapse:collapse;width:100%;font-size:12px}th,td{padding:5px 8px;text-align:left;border-bottom:1px solid var(--vien2)}th{font-size:10px;text-transform:uppercase;letter-spacing:.06em;color:var(--muc3);font-weight:600;white-space:nowrap}tbody tr:last-child td{border-bottom:none}
td.n,th.n{text-align:right;font-family:"IBM Plex Mono",monospace;font-variant-numeric:tabular-nums;white-space:nowrap}
.do{background:var(--the);border:1px solid var(--vien);border-radius:14px;padding:18px 20px;margin-top:14px;box-shadow:var(--bong)}.do h2{font-size:16px;margin:0 0 12px}
.do-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(126px,1fr));gap:10px}.do-grid>div{background:var(--nen);border-radius:10px;padding:11px 12px}
.do-grid b{display:block;font-family:"IBM Plex Mono",monospace;font-size:21px;font-weight:600;line-height:1.15;font-variant-numeric:tabular-nums;letter-spacing:-.02em}.do-grid small{display:block;font-size:11.5px;color:var(--muc3);margin-top:3px;line-height:1.3}
.do .ct{font-family:"IBM Plex Mono",monospace;font-size:12.5px;color:var(--muc2);margin:11px 0 0}
.canh{background:var(--sai-nh);border-left:3px solid var(--sai);border-radius:0 9px 9px 0;padding:12px 14px;margin:14px 0;font-size:13px}.canh b{color:var(--sai)}
#khungAnh{display:none;margin-top:14px;background:var(--the);border:1px solid var(--vien);border-radius:14px;padding:16px;box-shadow:var(--bong)}#khungAnh img{width:100%;border-radius:9px;border:1px solid var(--vien);display:block}
.dt-an{display:none}@media(max-width:960px){.dt-an{display:block;background:var(--sai-nh);border-left:3px solid var(--sai);border-radius:0 9px 9px 0;padding:10px 12px;font-size:12.5px;margin-bottom:12px}.chi-pc{display:none}}
:focus-visible{outline:2px solid var(--nhan);outline-offset:2px}

details.nhom{border:1px solid var(--vien);border-radius:11px;background:var(--the);margin-top:10px;overflow:hidden}
details.nhom>summary{list-style:none;cursor:pointer;padding:10px 12px;font-weight:600;font-size:13px;display:flex;align-items:center;gap:8px}
details.nhom>summary::-webkit-details-marker{display:none}
details.nhom>summary .buoc{font-family:"IBM Plex Mono",monospace;font-size:11px;color:#fff;background:var(--nhan);border-radius:5px;padding:1px 6px}
details.nhom>summary .tomtat{margin-left:auto;font-weight:400;font-size:11.5px;color:var(--muc3);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:46%}
details.nhom>summary::after{content:"▸";color:var(--muc3);margin-left:6px;transition:.15s}
details.nhom[open]>summary::after{transform:rotate(90deg)}
details.nhom>.than{padding:2px 12px 12px}
details.con{margin-top:10px;border-top:1px dashed var(--vien);padding-top:6px}
details.con>summary{list-style:none;cursor:pointer;font-size:12px;color:var(--nhan);font-weight:600;padding:4px 0}
details.con>summary::-webkit-details-marker{display:none}
details.con>summary::before{content:"▸ ";color:var(--muc3)}
details.con[open]>summary::before{content:"▾ "}
.thanh-nhanh{position:absolute;right:12px;top:12px;display:flex;gap:6px;z-index:3}
.thanh-nhanh button{padding:6px 9px;font-size:12px;background:rgba(255,255,255,.92);border-color:rgba(0,0,0,.12);color:#15201b;box-shadow:0 2px 8px rgba(0,0,0,.18)}
.thanh-nhanh button.ch{background:var(--nhan);color:#fff}
.thanh-nhanh button:disabled{opacity:.45}
.pop{position:absolute;z-index:4;background:var(--the);border:1px solid var(--vien);border-radius:12px;box-shadow:0 12px 32px -10px rgba(0,0,0,.35);padding:8px;display:none;min-width:200px;max-width:280px}
.pop.mo{display:block}
.pop .ten{font-size:11px;color:var(--muc3);padding:2px 4px 6px;font-weight:600;letter-spacing:.06em;text-transform:uppercase}
.pop .hang{gap:4px}.pop button{padding:6px 8px;font-size:12px}
.pop .o-mau{grid-template-columns:repeat(6,1fr);gap:4px;margin-top:6px}.pop .o-mau i{border-radius:4px}
.pop input[type=range]{margin:6px 0 0}
.pop .dong{display:none;padding-top:6px}.pop .dong.mo{display:block}
.goiy{position:absolute;left:50%;top:44%;transform:translate(-50%,-50%);z-index:2;background:rgba(16,22,20,.86);color:#fff;border-radius:12px;padding:14px 18px;font-size:13.5px;line-height:1.7;pointer-events:none;text-align:left;box-shadow:0 12px 30px rgba(0,0,0,.35)}
.goiy b{color:#8fe3bd}
.goiy.an{display:none}
.bo-lam{display:flex;flex-direction:column;gap:6px}
.nhom-lam{border:1px solid var(--vien);border-radius:9px;padding:6px 7px 7px;background:var(--nen)}
.nhom-lam .dau{display:grid;grid-template-columns:64px 1fr;gap:8px;align-items:center}
.nhom-lam svg{width:64px;height:18px;display:block;color:var(--muc2)}.nhom-lam svg path{fill:currentColor}
.nhom-lam b{font-size:11.5px;font-weight:600;display:block;line-height:1.2}.nhom-lam small{font-size:10.5px;color:var(--muc3)}
.chip-lam{display:flex;flex-wrap:wrap;gap:5px;margin-top:6px}
.chip-lam button{display:flex;align-items:center;gap:5px;padding:3px 7px 3px 3px;font-size:10.5px;font-family:"IBM Plex Mono",monospace;border-radius:6px;background:var(--the)}
.chip-lam button i{width:18px;height:18px;border-radius:4px;background-size:cover;background-position:center;box-shadow:inset 0 0 0 1px rgba(0,0,0,.15);flex:none}
.chip-lam button.ch{background:var(--nhan);border-color:var(--nhan);color:#fff}.chip-lam button.ch:hover{color:#fff}

/* ── KHUNG TRANG TRÊN WEBSITE ─────────────────────────────────────────────────
   Bản chạy thử là một tệp đứng riêng, không có thanh đầu trang và chân trang của
   site. Bốn lớp dưới là phần nối công cụ vào khung trang chung.
   ⚠ Để ở `vach.css` chứ không ở `eb.css`: chỉ trang này nạp nó. Nhét 11 KB kiểu
     dáng của một công cụ vào bảng kiểu chung là bắt 297 trang còn lại tải thứ
     chúng không bao giờ dùng. `kiem_lop_css()` đọc cả hai tệp nên vẫn được canh. */
.vach-trang{padding-top:18px}
.vach-h1{font-size:clamp(1.5rem,1.1rem + 1.4vw,2rem);line-height:1.2;margin:0 0 6px}
.vach-phu{margin:0 0 16px;color:var(--ink-600);max-width:62ch}
/* Dòng nói rõ ảnh là dựng 3D — thay khối cảnh báo đỏ của bản chạy thử. Luật lệnh
   23/09: mọi ảnh xuất ra phải ghi rõ, không để khách hiểu là ảnh chụp công trình. */
.vach-ghichu{margin:10px 0 0;font-size:.86rem;color:var(--ink-600)}
.vach-ghichu a{color:var(--green-700);font-weight:600}
@media (max-width:899px){
  .vach-trang{padding-top:10px}
  .vach-phu{margin-bottom:10px;font-size:.92rem}
}

/* ── TẦNG ĐIỆN THOẠI ────────────────────────────────────────────────────────
   Lệnh 23/09 mục 2.2. Bật bằng lớp `dt-on` trên <html> do `dt.js` đặt theo bề
   rộng thật, KHÔNG bằng `@media` một mình: `dt.js` còn phải đặt trần
   devicePixelRatio và chiều cao khung 3D, nên hai bên phải bật cùng một lúc theo
   cùng một điều kiện. Hai điều kiện song song là hai chỗ để lệch nhau.
   ⚠ ĐẶT Ở CUỐI TỆP: `@media` không cộng độ đặc hiệu, mà nhiều quy tắc dưới đây
   ghi đè các quy tắc cùng độ đặc hiệu ở trên (bài học đã ghi trong CLAUDE.md —
   khối mobile đặt giữa tệp thì hỏng đúng một nửa). */
html.dt-on .bang-dk, html.dt-on .do, html.dt-on .tw, html.dt-on #khungAnh,
html.dt-on .dt-an, html.dt-on #hud{ display:none }
html.dt-on .app{ display:block }
html.dt-on .san{ position:sticky; top:0; z-index:3; height:56svh; min-height:240px;
  background:var(--nen); padding:0; border-radius:0 }
html.dt-on .san canvas{ display:block; width:100%; border-radius:0 }
html.dt-on .bao{ padding-bottom:calc(112px + env(safe-area-inset-bottom,0px)) }
html.dt-on #kyhieu, html.dt-on #popMang, html.dt-on #popMach{ display:none !important }

/* nút nổi trên khung 3D — chỉ ba nút, không thêm (mục 2.2) */
/* 0.3 — nhắc nổi giữa khung 3D khi chưa chọn gì (Bổ sung 7 §0.3) */
.dt-nhac{ display:none }
html.dt-on .dt-nhac{ display:block; position:absolute; left:50%; top:46%;
  transform:translate(-50%,-50%); z-index:4; pointer-events:none;
  padding:9px 14px; border-radius:999px; font-size:13.5px; font-weight:600;
  color:#fff; background:rgba(20,26,23,.78); backdrop-filter:blur(3px);
  opacity:0; transition:opacity .25s }
html.dt-on .dt-nhac.hien{ opacity:1 }
@media (prefers-reduced-motion:reduce){ html.dt-on .dt-nhac{ transition:none } }
.dt-noi{ display:none }
html.dt-on .dt-noi{ display:flex; gap:8px; position:absolute; top:10px; z-index:4 }
html.dt-on .dt-noi-t{ left:10px } html.dt-on .dt-noi-p{ right:10px }
.dt-tron{ width:40px; height:40px; border-radius:50%; border:1px solid var(--vien);
  background:rgba(255,255,255,.86); color:var(--muc); font-size:17px; line-height:1;
  display:grid; place-items:center; backdrop-filter:blur(6px) }
.dt-tron:disabled{ opacity:.38 }
@media (prefers-color-scheme:dark){ :root:not([data-theme="light"]) .dt-tron{ background:rgba(24,30,27,.86) } }

/* thanh việc theo ngữ cảnh, cao 56px */
.dt-viec{ display:none }
html.dt-on .dt-viec{ display:flex; gap:8px; align-items:center; height:56px;
  padding:0 10px; overflow-x:auto; overflow-y:hidden; -webkit-overflow-scrolling:touch;
  position:sticky; top:56svh; z-index:3; background:var(--the);
  border-bottom:1px solid var(--vien); scrollbar-width:none }
html.dt-on .dt-viec::-webkit-scrollbar{ display:none }
.dt-viec button{ flex:0 0 auto; min-height:44px; padding:0 14px; border-radius:22px;
  border:1px solid var(--vien); background:var(--nen); color:var(--muc); font-size:14px }
.dt-viec button[aria-pressed="true"]{ background:var(--nhan-nh); border-color:var(--nhan);
  color:var(--nhan); font-weight:600 }

/* tấm đáy: cao tối đa 40% màn hình để vách vẫn thấy ở trên */
.dt-tam{ display:none }
html.dt-on .dt-tam{ display:flex; flex-direction:column; position:fixed; left:0; right:0;
  bottom:calc(56px + env(safe-area-inset-bottom,0px)); z-index:40; max-height:40svh;
  background:var(--the); border-top:1px solid var(--vien);
  border-radius:14px 14px 0 0; box-shadow:var(--bong);
  transform:translateY(102%); transition:transform .18s ease-out }
html.dt-on .dt-tam.mo{ transform:none }
.dt-tam-dau{ display:flex; align-items:center; justify-content:space-between; gap:10px;
  padding:10px 12px; border-bottom:1px solid var(--vien2); font-size:14px }
.dt-tam-dau button{ width:36px; height:36px; border-radius:10px; border:1px solid var(--vien);
  background:var(--nen); color:var(--muc) }
.dt-tam-than{ overflow-y:auto; -webkit-overflow-scrolling:touch; padding:10px 12px 14px }
/* Khối dời vào tấm đáy: bỏ khung ngoài của nó, tấm đáy đã là khung.
   Và mở lại các khối vốn chỉ dành cho desktop — chúng nay CÓ đường dùng trên
   điện thoại (nút ±, chia, bo), nên `.chi-pc` không còn đúng khi đã ở trong tấm. */
.dt-tam-than>.the-nc, .dt-tam-than>details, .dt-tam-than>div{ border:0; padding:0; margin:0 0 6px;
  background:none; box-shadow:none; max-height:none }
.dt-tam-than>.the-nc{ display:block }
.dt-tam-than .chi-pc{ display:block }
.dt-tam-than .hang.chi-pc, .dt-tam-than .kt2.chi-pc{ display:flex }
.dt-tam-than summary{ cursor:default }
.dt-hang{ display:flex; gap:8px; flex-wrap:wrap; margin:6px 0 }
.dt-hang button{ flex:1 1 auto; min-height:44px; min-width:64px; border-radius:10px;
  border:1px solid var(--vien); background:var(--nen); color:var(--muc); font-size:14px }
.dt-hang input[type=number]{ flex:1 1 84px; min-height:44px; text-align:center;
  border-radius:10px; border:1px solid var(--vien); background:var(--the); color:var(--muc);
  font-size:15px; font-variant-numeric:tabular-nums }
.dt-tam-than input[type=range]{ width:100%; margin:4px 0 2px }
.dt-nh{ font-size:12px; color:var(--muc3); margin-top:10px }
.dt-tt{ font-size:12.5px; color:var(--muc2); margin:8px 0 0; line-height:1.5 }

/* thanh tổng cố định sát đáy — thay chỗ .mbar trên trang này */
.dt-tong{ display:none }
html.dt-on .dt-tong{ display:flex; align-items:center; justify-content:space-between; gap:10px;
  position:fixed; left:0; right:0; bottom:0; z-index:45; height:56px;
  padding:0 12px calc(0px + env(safe-area-inset-bottom,0px));
  box-sizing:content-box; background:var(--the); border-top:1px solid var(--vien) }
.dt-tong #dtSo{ font-size:13.5px; color:var(--muc); font-variant-numeric:tabular-nums }
.dt-tong #dtSo i{ color:var(--muc3); margin:0 6px; font-style:normal }
.dt-cta{ flex:0 0 auto; min-height:44px; padding:0 16px; border-radius:10px; border:0;
  background:var(--nhan); color:#fff; font-size:14px; font-weight:600 }
/* Nút phụ trên thanh đáy — lối vào "Xuất ảnh & bản vẽ" (Bổ sung 5 điểm ⑨).
   ⚠ Viền chứ không nền đặc: nền đặc thì nó tranh mắt với "Nhận báo giá", mà đó
     mới là đường ra lead chính. Vẫn giữ 44px chiều cao chạm.
   ⚠ `#dtSo` nhường chỗ khi hẹp: ba thứ trên một thanh 390px thì con số tóm tắt là
     thứ bỏ được, nút thì không. */
.dt-phu{ flex:0 0 auto; min-height:44px; padding:0 12px; border-radius:10px;
  border:1px solid var(--vien); background:var(--the); color:var(--muc);
  font-size:13.5px; font-weight:600; white-space:nowrap }
@media (max-width:400px){ .dt-tong #dtSo{ display:none } }

/* ngang màn hình: khung 3D bên trái, tấm đáy thành cột phải (mục 2.2) */
@media (orientation:landscape) and (max-height:560px){
  html.dt-on .san{ position:fixed; left:0; top:0; width:60vw; height:100svh }
  html.dt-on .bao{ padding-left:60vw; padding-bottom:0 }
  html.dt-on .dt-viec{ position:fixed; top:0; left:60vw; right:0; width:auto }
  html.dt-on .dt-tam{ left:60vw; bottom:56px; max-height:calc(100svh - 112px) }
  html.dt-on .dt-tong{ left:60vw }
}

/* ── LƯỚI CHỌN MÃ THẬT (mục 3) ──────────────────────────────────────────────
   101 ô thay 13 vật liệu tạm. Ô nền là MÀU ĐẠI DIỆN đo từ tấm ô mẫu lúc dựng, ảnh
   nhỏ nằm trên nó và tải lười — nên lưới hiện ra đủ màu ngay, ảnh về sau. */
.o-mau i{ position:relative; overflow:hidden }
.o-mau i>img{ position:absolute; inset:0; width:100%; height:100%; object-fit:cover;
  display:block; border:0 }
.o-mau i>b{ position:absolute; left:0; right:0; bottom:0; z-index:2;
  font:600 8.5px/1.5 ui-monospace,SFMono-Regular,Menlo,monospace; text-align:center;
  color:#fff; background:rgba(0,0,0,.42); letter-spacing:.2px;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap }
.o-mau i[hidden]{ display:none !important }
.loc-van{ display:flex; gap:6px; flex-wrap:wrap; margin:2px 0 8px }
.loc-van button{ min-height:30px; padding:0 9px; border-radius:15px; font-size:11.5px;
  border:1px solid var(--vien); background:var(--nen); color:var(--muc2) }
.loc-van button b{ color:var(--muc3); font-weight:600 }
.loc-van button[aria-pressed="true"]{ background:var(--nhan-nh); border-color:var(--nhan);
  color:var(--nhan) } .loc-van button[aria-pressed="true"] b{ color:var(--nhan) }
html.dt-on .loc-van button{ min-height:36px; padding:0 12px; font-size:12.5px }

/* ── BẢNG KHỐI LƯỢNG (mục 4) ────────────────────────────────────────────────
   Hai phần: vật liệu Eco Bamboo bán, và thứ thợ chuẩn bị. Sale chỉ báo giá phần
   trên (Bổ sung 3, 23/09). */
.bl-nh{ margin:14px 0 6px; font-size:12px; font-weight:700; letter-spacing:.3px;
  text-transform:uppercase; color:var(--muc3) }
.bl-nh:first-child{ margin-top:4px }
table.bl{ width:100%; border-collapse:collapse; font-size:13px }
table.bl th{ text-align:left; font-weight:600; font-size:11.5px; color:var(--muc3);
  padding:4px 8px 4px 0; border-bottom:1px solid var(--vien) }
table.bl td{ padding:5px 8px 5px 0; border-bottom:1px solid var(--vien2);
  vertical-align:top }
table.bl td.sl, table.bl th.sl{ text-align:right; white-space:nowrap;
  font-variant-numeric:tabular-nums; font-weight:600 }
table.bl td.dv{ color:var(--muc2); white-space:nowrap }
table.bl td.gc{ color:var(--muc3); font-size:12px }
.bl-nut{ margin-top:12px }
.nut-phu{ display:inline-block; min-height:44px; line-height:42px; padding:0 16px;
  border-radius:10px; border:1px solid var(--nhan); color:var(--nhan);
  background:var(--nhan-nh); font-size:14px; font-weight:600; text-decoration:none }
/* Trên điện thoại bảng nằm trong tấm đáy: cột ghi chú xuống dòng chứ không cuộn. */
html.dt-on table.bl td.gc{ font-size:11.5px }
html.dt-on table.bl{ font-size:12.5px }

/* ── VÁCH CỦA TÔI (mục 5.1) ─────────────────────────────────────────────────
   Xác nhận xoá làm NGAY TRÊN NÚT (bấm lần nữa), không dùng confirm(): hộp của
   trình duyệt chặn mọi sự kiện, kể cả vòng vẽ WebGL của khung 3D. */
.lv{ margin-top:18px; padding-top:14px; border-top:1px solid var(--vien) }
.lv-dau{ display:flex; align-items:center; gap:10px; flex-wrap:wrap; margin-bottom:10px }
.lv-dau b{ font-size:14px }
.lv-dem{ font-size:12px; color:var(--muc3); font-variant-numeric:tabular-nums }
.lv-nho{ min-height:36px; padding:0 12px; border-radius:9px; font-size:13px;
  border:1px solid var(--vien); background:var(--nen); color:var(--muc2) }
.lv-hoi{ border-color:var(--sai) !important; background:var(--sai-nh) !important;
  color:var(--sai) !important; font-weight:600 }
.lv-ds{ display:grid; gap:12px; grid-template-columns:repeat(auto-fill,minmax(180px,1fr)) }
.lv-o{ border:1px solid var(--vien); border-radius:10px; padding:8px; background:var(--the) }
.lv-o img{ display:block; width:100%; height:auto; border-radius:6px; background:var(--nen) }
.lv-trong{ aspect-ratio:5/3; display:grid; place-items:center; border-radius:6px;
  background:var(--nen); color:var(--muc3); font-size:12px }
.lv-o input{ width:100%; margin:8px 0 6px; min-height:36px; padding:0 8px; font-size:13px;
  border:1px solid var(--vien); border-radius:8px; background:var(--nen); color:var(--muc) }
.lv-nut{ display:flex; gap:5px; flex-wrap:wrap }
.lv-nut button{ flex:1 1 auto; min-height:36px; padding:0 8px; font-size:12px;
  border:1px solid var(--vien); border-radius:8px; background:var(--nen); color:var(--muc2) }
.lv-o small{ display:block; margin-top:6px; font-size:11.5px; color:var(--muc3) }
html.dt-on .lv-ds{ grid-template-columns:repeat(auto-fill,minmax(150px,1fr)) }
html.dt-on .lv-nut button{ min-height:44px }

/* ── LƯU ẢNH · BẢN VẼ · GỬI LINK (mục 5.2) ─────────────────────────────────── */
.gu{ display:flex; gap:8px; flex-wrap:wrap; align-items:center; margin-top:14px }
.gu .tt{ flex:1 1 100%; margin:2px 0 0 }
#guLink{ flex:1 1 100%; min-height:40px; padding:0 10px; font-size:12.5px;
  border:1px solid var(--vien); border-radius:9px; background:var(--nen); color:var(--muc) }
html.dt-on .gu button{ flex:1 1 40% }

/* ── NHẬN BÁO GIÁ CHO VÁCH (mục 5.3) ────────────────────────────────────────── */
.bg-lead{ max-width:760px; margin:26px auto 0; padding:18px 16px 20px;
  border:1px solid var(--vien); border-radius:12px; background:var(--the) }
.bg-lead h2{ margin:0 0 4px; font-size:17px }
.bg-hang{ display:grid; gap:10px; grid-template-columns:repeat(auto-fit,minmax(180px,1fr));
  margin:10px 0 }
.bg-form label{ display:block; font-size:12.5px; color:var(--muc2) }
.bg-form input[type=text], .bg-form input:not([type]), .bg-form textarea{
  width:100%; margin-top:4px; min-height:44px; padding:8px 10px; font-size:15px;
  border:1px solid var(--vien); border-radius:9px; background:var(--nen); color:var(--muc) }
.bg-form textarea{ min-height:64px; resize:vertical }
.bg-ghi{ display:block; margin-top:10px }
.bg-form button[type=submit]{ margin-top:12px; min-height:48px; padding:0 22px;
  border:0; border-radius:10px; background:var(--nhan); color:#fff;
  font-size:15px; font-weight:600 }
.bg-form .hp{ position:absolute; left:-9999px; width:1px; height:1px }
.bg-xong{ margin-top:14px; padding:14px; border-radius:10px;
  border:1px solid var(--nhan); background:var(--nhan-nh); font-size:14px }
.bg-ma{ margin:10px 0 }
.bg-ma span{ display:block; font-size:12px; color:var(--muc3); margin-bottom:4px }
.bg-ma input{ width:100%; min-height:40px; padding:0 10px; font-size:12.5px;
  border:1px solid var(--vien); border-radius:9px; background:var(--nen); color:var(--muc) }
.bg-nut{ display:flex; gap:8px; flex-wrap:wrap; margin-top:10px }

/* Loé nhẹ khối xuất ảnh khi tới từ nút trên khung 3D — cuộn tới mà không có
   dấu gì thì khách không biết mình vừa được đưa tới đâu. */
.gu-loe{ animation:guLoe 1.4s ease-out }
@keyframes guLoe{ 0%,60%{ box-shadow:0 0 0 3px var(--nhan) } 100%{ box-shadow:none } }
@media (prefers-reduced-motion:reduce){ .gu-loe{ animation:none; box-shadow:0 0 0 3px var(--nhan) } }

/* ── ⑧ CỬA SỔ NỔI "NHẬN BÁO GIÁ" + BẢNG TẠM TÍNH ─────────────────────────────
   ⚠ Bảng cuộn ngang trong khối riêng: bốn cột tiền trên khung 390px là đúng chỗ
     số tiền bị bẻ đôi, mà số tiền ngắt giữa chừng thì đọc sai còn dễ hơn đọc đúng
     (bài học đã ghi cho bảng giá trang mã màu). Cột số giữ `nowrap`. */
/* ⚠⚠ `[hidden]` THUA MỘT BỘ CHỌN LỚP. `.bg-hop{display:flex}` có độ đặc hiệu
   (0,1,0) còn `[hidden]{display:none}` mặc định của trình duyệt là (0,0,1) — nên
   hộp vẫn hiện dù đã đặt `hidden`, và biểu mẫu nằm chình ình trên trang đúng thứ
   lệnh ⑧ bảo phải giấu. Đo được: `bgKhoiHien: true` trước khi bấm.
   Khai lại tường minh cho HAI lớp này thay vì đặt `[hidden]{…!important}` toàn
   tệp — `!important` toàn cục là thứ lần sau có người phải đi gỡ. */
.bg-nen[hidden],.bg-hop[hidden]{ display:none }
.bg-nen{ position:fixed; inset:0; z-index:70; background:#0007 }
.bg-hop{ position:fixed; z-index:71; left:50%; top:50%; transform:translate(-50%,-50%);
  width:min(680px,calc(100vw - 24px)); max-height:min(86svh,900px);
  display:flex; flex-direction:column; background:var(--the);
  border:1px solid var(--vien); border-radius:14px; overflow:hidden }
.bg-hop-dau{ display:flex; align-items:center; justify-content:space-between; gap:10px;
  padding:12px 14px; border-bottom:1px solid var(--vien); font-size:15px }
.bg-x{ min-width:44px; min-height:44px; border:0; background:none; color:var(--muc);
  font-size:18px; line-height:1 }
.bg-hop-than{ overflow:auto; padding:12px 14px 16px }
.bg-bang{ width:100%; border-collapse:collapse; font-size:13.5px; margin-bottom:10px }
.bg-bang th,.bg-bang td{ padding:7px 8px; border-bottom:1px solid var(--vien); text-align:left }
.bg-bang th:nth-child(2),.bg-bang td:nth-child(2),
.bg-bang th:nth-child(3),.bg-bang td:nth-child(3),
.bg-bang th:nth-child(4),.bg-bang td:nth-child(4){ text-align:right; white-space:nowrap;
  font-variant-numeric:tabular-nums }
.bg-bang tfoot th{ border-bottom:0; font-size:15px }
.bg-rieng,.bg-tho,.bg-nhan{ font-size:13px; color:var(--muc2); margin:6px 0 }
.bg-nhan{ padding:8px 10px; background:var(--nen2); border-radius:8px; color:var(--muc) }
.q-cta{ background:var(--nhan); color:#fff; border:0; font-weight:600 }
@media (max-width:520px){
  .bg-hop{ left:0; right:0; top:auto; bottom:0; transform:none; width:100%;
    max-height:92svh; border-radius:14px 14px 0 0 }
  .bg-bang{ font-size:12.5px }
  .bg-bang th,.bg-bang td{ padding:6px 5px }
}

/* ⚠⚠ HAI NÚT CHỮ CHỈ DÀNH CHO DESKTOP. Lệnh Bổ sung 5 đặt lối vào ở HAI chỗ khác
   nhau: thanh công cụ khung 3D (desktop) và thanh đáy (điện thoại). Đặt cả hai vào
   cả hai chỗ là thừa, và ở đây nó còn HỎNG THẬT:
   `.thanh-nhanh` là `position:absolute` NẰM ĐÈ lên khung 3D và nó KHÔNG được ẩn ở
   khổ hẹp (lớp `chi-pc` không có quy tắc nào). Thêm hai nút chữ làm thanh đó xuống
   ba dòng — đo ở 390×844: 366×126 px, che 27% khung 3D — và nó NUỐT CÚ CHẠM.
   Đo được: chạm chọn mạch tụt từ 22/22 xuống 2/22.
   ⚠ Chỉ ẩn HAI nút mới, không ẩn cả thanh: các nút còn lại (vẽ mạch · quét LED ·
     số đo · xem ảnh) vốn đã ở đó từ trước và điện thoại đang dùng chúng. */
/* ⚠⚠ 0.1/§1 (Bổ sung 7): TRÊN ĐIỆN THOẠI ẨN CẢ THANH CÔNG CỤ DESKTOP, không chỉ
   hai nút chữ. Đo 25/09 ở 390×664: `.thanh-nhanh` (absolute, right/top 12) và bộ
   nút tròn RIÊNG của tầng điện thoại (`#dtUndo` ↶ · `#dtRedo` ↷ · `#dtVua` ⤢, dựng
   trong `dt.js`) cùng nằm góc trên khung 3D và ĐÈ LÊN NHAU — đúng ảnh `soat-dt-1`
   mà lệnh nêu. Tức không phải thanh desktop co lại cho xấu, mà là HAI BỘ NÚT CHO
   CÙNG MỘT VIỆC cùng hiện.
   ⚠ Ghi chú cũ ngay dưới nói "các nút còn lại điện thoại đang dùng chúng" — SAI:
     tầng điện thoại có bộ tròn của riêng nó, và Bổ sung 9 bỏ hẳn việc sửa bố cục
     trên điện thoại nên ✏ Vẽ mạch · 💡 Quét LED không còn chỗ dùng ở khổ hẹp.
   Giữ lại ghi chú cũ bên dưới vì số đo trong đó (27% khung 3D, 22/22 → 2/22) vẫn
   là bằng chứng của lần trước. */
@media (max-width:899px){ .thanh-nhanh{ display:none } }

/* ── KHUNG MỘT MÀN HÌNH (Bổ sung 8) ─────────────────────────────────────────
   Header 56 · Thanh bước 44 · Khung 3D · Thanh việc 52 · Tầng nội dung · Đáy 64.

   ⚠⚠ ẨN CHROME CỦA SITE trên trang này ở khổ điện thoại. Đo 25/09 ở 390px:
     topbar 49 + header 83 = 132px, tức MỘT MÌNH nó đã vượt trần "đỉnh khung 3D
     ≤ 130px" của Bổ sung 7 §1. Không có cách nào đạt mà vẫn giữ cả hai, và
     Bổ sung 8 khai "Header 56" nghĩa là công cụ có thanh đầu RIÊNG.
     Đảo lại: bỏ lớp `dt-app` trong dt.js — một chỗ, không phải đi tìm từng dòng.
   ⚠ Chỉ ẩn dưới `html.dt-app`, KHÔNG ẩn bằng `@media` một mình: `dt.js` bật lớp
     đó theo bề rộng thật cùng lúc với `dt-on`, nên không có hai điều kiện song
     song để lệch nhau. Máy tính và máy in không đụng tới.
   ⚠ ĐẶT CUỐI TỆP — `@media` không cộng độ đặc hiệu. */
html.dt-app .topbar, html.dt-app .hdr,
html.dt-app .vach-h1, html.dt-app .vach-phu{ display:none }
html.dt-app .vach-trang{ padding-top:0 }
html.dt-app .vach-trang>.wrap-wide{ padding:0 }
html.dt-app, html.dt-app body{ overscroll-behavior-y:none }

.dt-head{ display:none }
html.dt-app .dt-head{ display:flex; align-items:center; gap:8px;
  position:sticky; top:0; z-index:6; height:56px; padding:0 8px;
  padding-top:env(safe-area-inset-top,0px);
  background:var(--nen); border-bottom:1px solid var(--vien) }
html.dt-app .dt-head>b{ font-size:15px; font-weight:650 }
html.dt-app .dt-head-p{ margin-left:auto; font-size:12px; color:var(--muc3) }
.dt-ve{ display:flex; align-items:center; justify-content:center;
  width:40px; height:40px; border-radius:50%; text-decoration:none;
  font-size:24px; line-height:1; color:var(--muc2) }

.dt-buoc{ display:none }
html.dt-app .dt-buoc{ display:flex; gap:6px; align-items:stretch;
  position:sticky; top:calc(56px + env(safe-area-inset-top,0px)); z-index:6;
  height:44px; padding:0 8px 6px; background:var(--nen) }
.dt-buoc button{ flex:1 1 0; display:flex; align-items:center; justify-content:center;
  gap:6px; min-width:0; min-height:38px; padding:0 6px; border-radius:10px;
  border:1px solid var(--vien); background:var(--the); font-size:13px;
  color:var(--muc2); white-space:nowrap; overflow:hidden }
.dt-buoc button>i{ flex:0 0 auto; width:18px; height:18px; border-radius:50%;
  display:grid; place-items:center; font-style:normal; font-size:11px;
  background:var(--vien); color:var(--muc2) }
.dt-buoc button[aria-selected="true"]{ background:var(--nhan-nh);
  border-color:var(--nhan); color:var(--nhan); font-weight:650 }
.dt-buoc button[aria-selected="true"]>i{ background:var(--nhan); color:#fff }
/* Khung 3D bám dưới hai thanh trên, không bám mép màn hình. */
html.dt-app .san{ top:calc(100px + env(safe-area-inset-top,0px)); z-index:3 }

/* Thẻ "mở trên máy tính" — lối ra cho việc cần chuột (Bổ sung 9 §1) */
.dt-may{ border:1px solid var(--vien); border-left:3px solid var(--nhan);
  border-radius:0 10px 10px 0; padding:12px; margin-top:12px; background:var(--the) }
.dt-may>b{ display:block; font-size:14px; margin-bottom:4px }
.dt-may>p{ margin:0 0 10px; font-size:12.5px; color:var(--muc3); line-height:1.5 }
.dt-may .dt-cta{ width:100% }

/* Chiều cao hai thanh theo ĐÚNG số của Bổ sung 8: thanh việc 52 · thanh đáy 64.
   Trước đó là 56 và 56 — đo ở 390px ra 56/57. Không phải sửa cho đẹp mắt: hai con
   số này quyết định chiều cao còn lại của khung 3D, và trần "đỉnh 3D ≤ 130px" của
   Bổ sung 7 §1 đo được hay không phụ thuộc vào chúng. */
html.dt-app .dt-viec{ height:52px }
html.dt-app .dt-tong{ height:64px }

/* ⚠ Đáy tấm nội dung phải bám ĐÚNG chiều cao thanh đáy. Nâng thanh đáy 56 → 64 mà
   để `bottom:56px` là tấm che mất 8px trên cùng của thanh CTA — ca 4c bắt được
   ngay. Hai con số ở hai chỗ thì lần sau đổi một chỗ lại lệch, nên khai một biến. */
html.dt-app{ --dt-day:64px }
html.dt-app .dt-tam{ bottom:calc(var(--dt-day) + env(safe-area-inset-bottom,0px)) }

/* ── "Không tải được công cụ" (Bổ sung 7 §5) ────────────────────────────────
   Ẩn sẵn; chỉ hiện khi bó JS không tải được hoặc `window.VACH` không có thật.
   ⚠ Dùng `[hidden]` của HTML chứ không dùng một lớp `.an`: thuộc tính đó là thứ
     `soi()` bật/tắt, và `[hidden]{display:none}` trong reset chỉ (0,0,1) nên bất
     kỳ lớp nào cũng thắng nó — nên khối này KHÔNG được mang thêm lớp đặt display. */
.vach-hong{ max-width:520px; margin:28px auto; padding:18px;
  border:1px solid var(--vien); border-left:3px solid var(--sai);
  border-radius:0 12px 12px 0; background:var(--the); text-align:left }
.vach-hong>b{ display:block; font-size:16px; margin-bottom:6px }
.vach-hong>p{ margin:0 0 12px; font-size:13.5px; color:var(--muc3); line-height:1.55 }
.vach-hong>button{ min-height:44px; padding:0 20px; border-radius:10px;
  border:0; background:var(--nhan); color:#fff; font-size:15px; font-weight:600 }

/* ── HỘP BÁO GIÁ TRÊN ĐIỆN THOẠI (Bổ sung 7 §4) ─────────────────────────────
   Đo 25/09 ở 390×844 và 360×640: hộp là modal `position:fixed` đúng, thân cuộn
   được đúng — nhưng thứ tự nội dung là *bảng tạm tính rồi mới tới biểu mẫu*, và
   bảng đó cao 1.104px trong khung thấy được 705px. Hệ quả đo được:
     ô Họ tên  y = 799  (đáy khung là 844 — tức nằm sát mép, bàn phím lên là mất)
     nút Gửi   y = 1113 (390px) · 672 (360px) — NGOÀI khung, phải cuộn mới thấy
   Khách mở "Nhận báo giá" mà không thấy chỗ điền lẫn nút gửi thì đó là một cái
   phễu bị bịt ngay ở miệng, và nó không báo gì cả.

   ⚠ Đổi thứ tự bằng `order` của flex, KHÔNG đổi DOM: `gui.js` chuyển node
     `#bgKhoi` thật vào hộp (không dựng biểu mẫu thứ hai), nên đụng vào DOM ở đây
     là đụng vào chính cái node đang mang mọi trình nghe của `eb.js`.
   ⚠ Chỉ đổi ở khổ điện thoại. Trên máy tính hộp cao 776px chứa đủ cả hai, và đọc
     bảng số trước rồi mới điền là thứ tự đúng ở đó. */
.bg-hop .bg-lead>h2{ display:none }   /* thanh đầu của hộp đã in đúng câu này */
@media (max-width:899px){
  .bg-hop .bg-hop-than{ display:flex; flex-direction:column }
  .bg-hop .bg-hop-than>#bgKhoi{ order:1 }
  .bg-hop .bg-hop-than>#bgTamTinh{ order:2 }
}

/* Thanh đầu và thanh bước phải TRÀN HẾT BỀ NGANG. Đo 25/09: `#dtHead` ra x=16 w=358
   trên khổ 390 — vì nó nằm trong `.app`, mà khối đó có lề hai bên. Một thanh chrome
   thụt vào hai bên trông như một cái thẻ, không như thanh đầu của ứng dụng. */
html.dt-app .dt-head, html.dt-app .dt-buoc{ margin-inline:calc(-1 * var(--gut, 16px)) }
html.dt-app .dt-head{ padding-inline:14px }
html.dt-app .dt-buoc{ padding-inline:14px }
/* Nút mở menu — gọi đúng `#burger` thật, xem chú thích trong dt.js */
.dt-menu{ margin-left:auto; width:40px; height:40px; border-radius:50%;
  border:1px solid var(--vien); background:var(--the); font-size:17px; line-height:1;
  color:var(--muc2) }
/* Khung 3D cũng tràn hết bề ngang: đo được x=17 w=356 trên khổ 390 — mất 34px cho
   lề của `.app`, tức gần 9% bề ngang vách, chỉ để giữ một lề mà tầng này không dùng. */
html.dt-app .san{ margin-inline:calc(-1 * var(--gut, 16px)) }
