/* ==========================================================================
   ฟอนต์ประจำแบรนด์ — DB Adman X (ไฟล์อยู่ในระบบเอง ไม่พึ่งเน็ตนอก)
   font-display:swap = ขึ้นฟอนต์สำรองก่อนแล้วสลับเมื่อโหลดเสร็จ ไม่มีจอค้างรอฟอนต์
   ========================================================================== */
@font-face{font-family:'DB Adman X';src:url('fonts/dbadmanx-light.ttf') format('truetype');
  font-weight:300;font-style:normal;font-display:swap;size-adjust:118%}
@font-face{font-family:'DB Adman X';src:url('fonts/dbadmanx.ttf') format('truetype');
  font-weight:400;font-style:normal;font-display:swap;size-adjust:118%}
@font-face{font-family:'DB Adman X';src:url('fonts/dbadmanx-bold.ttf') format('truetype');
  font-weight:700;font-style:normal;font-display:swap;size-adjust:118%}

/* ==========================================================================
   ชุดสี — โหมดสว่าง/มืด
   หลักการ: ทุกสีที่ "พลิกตามธีม" ต้องอยู่ใน token เท่านั้น ห้ามเขียนโค้ดสีลงในกฎ
   ไม่งั้นพอสลับธีมจะเหลือจุดสว่างค้างอยู่กลางพื้นมืดทีละจุดโดยไม่มีใครรู้
   แบ่ง token เป็น 4 กลุ่ม:
     1) แบรนด์      — น้ำเงินเข้ม #1E3A5F + ขาว · เท่ากันทั้งสองธีม
     2) chrome      — พื้นผิวกรมท่าที่มืดอยู่แล้วทั้งสองธีม (แถบบน แถบเครื่องมือลอย toast)
     3) พื้นผิว/ตัวอักษร — พลิกตามธีม
     4) canvas      — สีบนผืนแบบ อ่านจาก JS ผ่าน getComputedStyle
   ========================================================================== */
:root{
  color-scheme:light;

  /* --- 1) แบรนด์ · คงที่ทั้งสองธีม --- */
  --navy:#132B46; --navy2:#1E3A5F; --navy-hov:#27507F;
  /* สีสัญลักษณ์ในแบบก่อสร้าง เป็นเรื่องการอ่านแบบ ไม่ใช่สีแบรนด์ ประตูกับหน้าต่างต้องแยกจากกันและจากผนัง */
  --door:#C9A227; --door-deep:#8A6E14; --win:#7FB5D5; --win-deep:#2E6E96;

  /* --- 2) chrome · พื้นกรมท่าที่มืดทั้งสองธีม --- */
  --chrome-a:#0F2138; --chrome-b:#1E3A5F;   /* ไล่สีแถบบน */
  --float:#132B46;                          /* กล่องลอยพื้นเข้ม: seltool · toast · lockbadge */
  --on-navy:#FFFFFF;                        /* ตัวอักษรหลักบนกรมท่า */
  --on-navy-2:#C7D3E8;                      /* รอง */
  --on-navy-3:#93A6C4;                      /* ป้ายกำกับ/หน่วย */
  --accent-on-navy:#8FBEEF;                 /* เน้นบนพื้นเข้ม — ต้องใช้โทนอ่อนถึงจะอ่านออก */
  --hair:rgba(255,255,255,.11);             /* เส้นคั่นบนพื้นเข้ม */
  --hair-2:rgba(255,255,255,.18);

  /* --- 3) พื้นผิว · ตัวอักษร · เส้น (พลิกตามธีม) --- */
  --paper:#EFF2F7;      /* พื้นหลังหน้า */
  --card:#FFFFFF;       /* การ์ด/กล่องหลัก */
  --surf:#FAFBFD;       /* แถวย่อยในการ์ด: รายการคลัง เวอร์ชัน ไฟล์ CAD */
  --surf2:#F4F7FB;      /* หัวตาราง · พื้นตอนชี้ */
  --surf3:#E8EDF5;      /* รางของปุ่มแบบแบ่งช่อง · swatch */
  --tint:#F1F7FD;       /* พื้นจาง ๆ สีเน้น ตอนชี้/เลือก */
  --tintbg:#EDF1F8;     /* ป้ายตัวเลขในหัวข้อพับ */
  --ink:#1B2A44;
  --muted:#5E6C86;
  --line:#D8DFEB;
  --line-soft:#EDF1F7;  /* เส้นคั่นแถวในตาราง — บางกว่า --line */

  --accent:#2E7FCC;         /* ขอบ/พื้น/สถานะที่เลือกอยู่ */
  --accent-ink:#1E3A5F;     /* ตัวอักษรสีเน้น บนพื้นการ์ด — โหมดมืดจะพลิกเป็นโทนอ่อน */
  --accent-fade:rgba(46,127,204,.14);   /* วงแหวนโฟกัส */
  --accent-line:rgba(46,127,204,.34);


  /* ===== ระบบดีไซน์ =====
     ก่อนหน้านี้ขอบมนถูกใช้ 9 ค่าปนกัน (6/7/8/9/10/11/12) เงาเขียนสด 51 จุด
     และ transition ตั้งเวลาเองทุกที่ — ผลคือแต่ละหน้ารู้สึกคนละงาน
     ต่อไปนี้ทุกอย่างอ้างสเกลชุดเดียว */

  /* ขอบมน — ไล่ตามขนาดของก้อน ไม่ใช่ตามใจตอนเขียน */
  --r-xs:8px; --r-sm:10px; --r-md:12px; --r-lg:16px; --r-xl:20px; --r-pill:999px;

  /* ระยะห่าง — ฐาน 4px */
  --sp-1:4px; --sp-2:8px; --sp-3:12px; --sp-4:16px; --sp-5:20px; --sp-6:24px; --sp-8:32px;

  /* ความสูงของวัตถุ (elevation) — โหมดสว่างใช้เงา โหมดมืดจะสลับไปพึ่งเส้นขอบแทน
     เพราะเงาดำบนพื้นดำมองไม่เห็น ต้องยกด้วยแสงที่ขอบ */
  --e1:0 1px 2px rgba(11,24,48,.08), 0 1px 1px rgba(11,24,48,.04);
  --e2:0 6px 16px -8px rgba(11,24,48,.22), 0 2px 4px rgba(11,24,48,.06);
  --e3:0 18px 38px -22px rgba(11,24,48,.34), 0 4px 10px rgba(11,24,48,.08);
  --e4:0 34px 70px -30px rgba(6,14,30,.55), 0 8px 20px rgba(6,14,30,.22);

  /* จังหวะเคลื่อนไหว — โค้งชะลอตัวแบบเดียวทั้งระบบ ให้ทุกอย่างรู้สึกเป็นของชิ้นเดียวกัน */
  --t-fast:120ms; --t-base:180ms; --t-slow:280ms;
  --ease:cubic-bezier(.2,.7,.3,1);
  --ease-out:cubic-bezier(.16,1,.3,1);

  --scrim:rgba(11,24,48,.55);
  --sh:rgba(11,24,48,.15);       /* เงาตื้น */
  --sh-lg:rgba(11,24,48,.30);    /* เงากล่องลอย */
  --sh-xl:rgba(6,14,30,.50);     /* เงา modal */

  /* --- สถานะ --- */
  --ok:#15803D; --ok-bg:#EAF6EE;
  --ok-line:rgba(46,160,90,.45); --ok-line-strong:rgba(46,160,90,.6);
  --ok-bg-soft:rgba(46,160,90,.16); --ok-on-card:#2EA05A;
  --warn:#B45309; --warn-bg:#FBF3E6; --warn-line:#EBDFB8;
  --bad:#B91C1C; --bad-bg:#FBEDED; --bad-line:#F3C6C6;
  --info:#3730A3; --info-bg:#EEF2FF;

  /* --- 4) canvas · ผืนแบบ (JS อ่านค่าไปวาด SVG) --- */
  --cv-bg:#FFFFFF;
  --cv-grid1:#EDF1F7; --cv-grid2:#DEE5EF;
  --cv-wall:#1E3A5F;
  --cv-room:rgba(30,58,95,.06); --cv-room-sel:rgba(46,127,204,.13);
  --cv-sel:#2E7FCC;
  --cv-name:#1E3A5F; --cv-sub:#5E6C86; --cv-label:#8B99AF;
  --cv-dim:#B45309;
  --cv-ghost:#B6C2D6; --cv-ghost-text:#AEBACE;
  --cv-wm:rgba(14,31,61,.05);
  --cv-stair:#8FA0BC;
  --cv-knob:#FFFFFF;
  --cv-bad:#B91C1C; --cv-bad-fill:rgba(185,28,28,.13);
  --cv-ul:#9AA8BE; --cv-ul-text:#8B99AF;
  /* สัญลักษณ์ช่องเปิดบนผืนแบบ — โหมดสว่างใช้ค่าเริ่มต้นใน opening-symbol.js (แหล่งเดียวกับ server) */
  --cv-door:#C9A227; --cv-door-line:#8A6E14;
  --cv-win:#7FB5D5; --cv-win-line:#2E6E96;
  --cv-doorsw-bg:#FFFCF2; --cv-doorsw-line:#E7DAB0;
  --cv-winsw-bg:#F3F9FD; --cv-winsw-line:#C2DCEC;

  /* --- แถบเลื่อน --- */
  --sb:rgba(94,108,134,.55); --sb-on:rgba(22,48,94,.78);

  /* --- ไอคอนปุ่มสลับธีม (ใช้เป็น mask จึงรับสีจาก currentColor) --- */
  --ic-light:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='4'/%3E%3Cpath d='M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4'/%3E%3C/svg%3E");
  --ic-dark:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8z'/%3E%3C/svg%3E");
}

/* ==========================================================================
   โหมดมืด — ไม่ใช่ "กลับสี" แต่เป็นชุดสีของตัวเอง
   พื้นไล่จากเข้มไปอ่อนตามระดับความสูงของชั้น (paper < card < surf < surf2 < surf3)
   ตัวอักษรไม่ใช้ขาวสนิทบนดำสนิท — ตาจะล้าและตัวหนังสือไทยหัวกลมจะเบลอ
   ========================================================================== */
:root[data-theme="dark"]{
  color-scheme:dark;

  --chrome-a:#0C1828; --chrome-b:#1A3352;
  --float:#1E2B3F;
  --hair:rgba(255,255,255,.10);
  --hair-2:rgba(255,255,255,.16);

  --paper:#0B1420;
  --card:#141E2C;
  --surf:#1A2434;
  --surf2:#1F2A3B;
  --surf3:#26334A;
  --tint:#17304F;
  --tintbg:#1B2C45;
  --ink:#E6EDF7;
  --muted:#9AABC4;
  --line:#2C3A4F;
  --line-soft:#222E40;

  --accent:#4A93DC;
  --accent-ink:#8FBEEF;
  --accent-fade:rgba(74,147,220,.20);
  --accent-line:rgba(74,147,220,.42);

  /* น้ำเงินหลักของธีมสว่างคือสีเข้ม — พอเอามาวางบนพื้นมืดมันจมหายไปกับพื้น
     ธีมมืดจึงต้องยกโทนขึ้น ไม่ใช่ใช้ค่าเดียวกันทั้งสองธีม */
  --navy:#2A4E7C; --navy2:#33608F; --navy-hov:#3F76AE;

  --scrim:rgba(3,8,15,.72);
  --sh:rgba(0,0,0,.40);
  --sh-lg:rgba(0,0,0,.55);
  --sh-xl:rgba(0,0,0,.68);


  /* เงาบนพื้นมืดแทบมองไม่เห็น — ลดเงาลงแล้วเพิ่มเส้นแสงที่ขอบบนแทน (inset ด้านบน) */
  --e1:0 1px 2px rgba(0,0,0,.40), inset 0 1px 0 rgba(255,255,255,.045);
  --e2:0 8px 20px -10px rgba(0,0,0,.62), inset 0 1px 0 rgba(255,255,255,.06);
  --e3:0 20px 44px -24px rgba(0,0,0,.75), inset 0 1px 0 rgba(255,255,255,.07);
  --e4:0 38px 78px -32px rgba(0,0,0,.85), inset 0 1px 0 rgba(255,255,255,.08);

  --ok:#6EE7A0; --ok-bg:#123021;
  /* สถานะผ่านแล้วบนพื้นการ์ด — โหมดมืดต้องยกโทนขึ้น ไม่งั้นเขียวเข้มจมพื้น */
  --ok-line:rgba(110,231,160,.42); --ok-line-strong:rgba(110,231,160,.6);
  --ok-bg-soft:rgba(110,231,160,.16); --ok-on-card:#6EE7A0;
  --warn:#F0B45E; --warn-bg:#332510; --warn-line:#54401C;
  --bad:#F98C8C; --bad-bg:#361A1A; --bad-line:#5C2A2A;
  --info:#A9B4F5; --info-bg:#1E2140;

  /* ผืนแบบเป็นโต๊ะเขียนแบบสีเข้ม เส้นผนังกลับเป็นโทนสว่าง (เหมือน model space ของ CAD)
     ภาพ export กับหน้าพิมพ์ยังเป็นกระดาษขาวเสมอ — คนละเส้นทางโค้ดกัน */
  --cv-bg:#0F1A28;
  --cv-grid1:#172334; --cv-grid2:#213047;
  --cv-wall:#B9CDE6;
  --cv-room:rgba(143,190,239,.07); --cv-room-sel:rgba(74,147,220,.20);
  --cv-sel:#5AA3E8;
  --cv-name:#DCE7F5; --cv-sub:#93A3BC; --cv-label:#7E8DA6;
  --cv-dim:#E8A54B;
  --cv-ghost:#44577A; --cv-ghost-text:#5C7295;
  --cv-wm:rgba(255,255,255,.055);
  --cv-stair:#6E809E;
  --cv-knob:#0F1A28;
  --cv-bad:#F87171; --cv-bad-fill:rgba(248,113,113,.16);
  --cv-ul:#6F8098; --cv-ul-text:#8697AE;
  /* บนพื้นเข้ม เส้นทองเข้ม #8A6E14 กับฟ้าเข้ม #2E6E96 มืดเกินจะอ่านออก — ยกโทนขึ้นทั้งคู่
     ยังคงคู่สีเดิม (ทอง=ประตู ฟ้า=หน้าต่าง) เพื่อให้อ่านแบบได้เหมือนกระดาษ */
  --cv-door:#E3C24E; --cv-door-line:#C9A227;
  --cv-win:#A9D2EA; --cv-win-line:#7FB5D5;
  --cv-doorsw-bg:#2A2415; --cv-doorsw-line:#4E4222;
  --cv-winsw-bg:#152836; --cv-winsw-line:#2B4B61;

  --sb:rgba(154,171,196,.38); --sb-on:rgba(143,190,239,.62);
}

*{margin:0;padding:0;box-sizing:border-box}
html,body{background:var(--paper)}
body{font-family:'DB Adman X','Leelawadee UI','Sarabun','Noto Sans Thai',Tahoma,sans-serif;color:var(--ink);-webkit-font-smoothing:antialiased}
button{font-family:inherit;cursor:pointer;border:none;background:none;color:inherit}
button:focus-visible,select:focus-visible,input:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
select,input{font-family:inherit}

/* สลับธีมแล้วให้พื้นค่อย ๆ เปลี่ยน — ใส่คลาสนี้เฉพาะช่วงสั้น ๆ ตอนกดสลับ
   ถ้าเปิดทิ้งไว้ตลอด การลากห้องบนผ้าใบจะหน่วงตาม transition ไปด้วย
   ต้องครอบด้วย no-preference ไม่ใช่ปล่อยให้กฎ prefers-reduced-motion ด้านล่างมาปิดทีหลัง —
   `html.theming *` มี specificity สูงกว่า `*` ต่อให้ทั้งคู่เป็น !important กฎนี้ก็ยังชนะ */
@media (prefers-reduced-motion:no-preference){
  html.theming,html.theming *,html.theming *::before,html.theming *::after{
    transition:background-color var(--t-base) var(--ease),border-color var(--t-base) var(--ease),color var(--t-base) var(--ease),fill var(--t-base) var(--ease),stroke var(--t-base) var(--ease)!important;
  }
}

/* ---------- แถบเลื่อน ----------
   ค่าเริ่มต้นของเบราว์เซอร์เป็นแท่งเทาทึบ พาดผ่านพื้นกรมท่าแล้วดูเป็นรอยแยกกลางงานออกแบบ
   ใช้สีกลาง ๆ กึ่งโปร่ง จึงอ่านออกทั้งบนพื้นขาวและพื้นเข้ม โดยไม่แย่งสายตาจากตัวเลขราคา */
*{scrollbar-width:thin;scrollbar-color:var(--sb) transparent}
::-webkit-scrollbar{width:11px;height:11px}
::-webkit-scrollbar-track{background:transparent}
/* ขอบใสรอบ thumb ทำให้แท่งดูบางลอย ๆ ไม่ชนขอบกล่อง */
::-webkit-scrollbar-thumb{background-color:var(--sb);border-radius:999px;border:3px solid transparent;background-clip:content-box}
::-webkit-scrollbar-thumb:hover{background-color:var(--sb-on)}
::-webkit-scrollbar-corner{background:transparent}
/* พื้นผิวสีเข้มต้องใช้แท่งสีอ่อนแทน */
.seltool,.topbar{scrollbar-color:rgba(255,255,255,.38) transparent}
.seltool::-webkit-scrollbar-thumb,.topbar::-webkit-scrollbar-thumb{background-color:rgba(255,255,255,.38)}
.seltool::-webkit-scrollbar-thumb:hover,.topbar::-webkit-scrollbar-thumb:hover{background-color:rgba(255,255,255,.6)}
/* ผู้ใช้ที่ตั้งเครื่องว่า "ลดการเคลื่อนไหว" ต้องการเลิกเห็นของ "ขยับ"
   ไม่ได้แปลว่าอยากได้ UI ที่ตอบสนองแบบกระตุก — การไล่สี/ไล่ความจางไม่ทำให้เวียนหัว
   จึงตัดเฉพาะการเคลื่อนที่ (transform + animation) แล้วคงการไล่สีไว้ */
@media (prefers-reduced-motion:reduce){
  *{animation-duration:.01ms!important;animation-iteration-count:1!important;
    transition-property:background-color,border-color,color,fill,stroke,opacity,box-shadow,outline-color!important;
    transition-duration:var(--t-fast)!important;
    scroll-behavior:auto!important}
  /* ยกเลิกการยก/ยุบตัวทุกกรณี เหลือแค่สีกับเงาเป็นตัวบอกสถานะ */
  .hubcard:hover,.hdcard:hover,.libitem:hover,.pickrow:hover,
  .tbtn:active,.btn-primary:active,.wf-btn:active,.dbtn:active,
  .iconbtn:active,.hubcard:active,.pickrow:active{transform:none!important}
  .modal .sheet,.modal .lbsheet{transform:none!important}
}

/* ==========================================================================
   จุดตัดจอมาตรฐานของทั้งระบบ (ต้องตรงกับ UI_BREAK ใน ui.js)
     1080px = แถบข้างกลายเป็นลิ้นชัก · 640px = โหมดมือถือ
   เดิมแต่ละหน้าใช้คนละค่า (1180/980/900/820) ทำให้พฤติกรรมไม่เหมือนกันทั้งที่เป็นรูปแบบเดียวกัน
   ========================================================================== */

/* ---------- chrome ---------- */
.topbar{background:linear-gradient(120deg,var(--chrome-a),var(--chrome-b));color:var(--on-navy);display:flex;align-items:center;gap:20px;padding:9px 18px;border-bottom:1px solid var(--accent-line);box-shadow:0 2px 10px var(--sh-lg);position:relative;z-index:10}
.logo{width:34px;height:34px;border:2px solid var(--accent-on-navy);border-radius:var(--r-sm);display:flex;align-items:center;justify-content:center;font-weight:700;color:var(--accent-on-navy);font-size:14px;flex:none;letter-spacing:.5px}
.brand{flex:none;min-width:0}
.brand b{letter-spacing:2px;font-size:14px;display:block;white-space:nowrap}
.brand span{display:block;font-size:12px;color:var(--on-navy-3);letter-spacing:.5px}

/* ---------- ปุ่มสลับธีม ----------
   สองสถานะ: สว่าง ⇄ มืด — ไอคอนบอกโหมดที่ใช้อยู่ (ดวงอาทิตย์ = ตอนนี้สว่าง)
   ไอคอนและข้อความมาจาก CSS ทั้งหมด เลือกตาม data-theme ที่สคริปต์ใน <head>
   ตั้งไว้ก่อนวาดหน้าแรก — สองเหตุผล:
   1) ถ้าให้ JS มาสลับไอคอนทีหลัง จะเห็นไอคอนผิดวาบหนึ่งทุกครั้งที่โหลดหน้า
   2) ปุ่มในไฟล์ HTML เหลือบรรทัดเดียว ทั้งสี่หน้าจึงไม่มีทางหลุดเป็นคนละแบบ
   ตั้งค่าสว่างเป็นค่าตั้งต้นของกฎ (ไม่ผูกกับ attribute) ปุ่มจึงไม่ว่างเปล่าถ้า JS ไม่ทำงาน
   คำอธิบายสำหรับ screen reader ตั้งเป็น aria-label จาก Theme.syncButtons() */
.themebtn,.themefloat{display:inline-flex;align-items:center;gap:8px;white-space:nowrap}
.themebtn::before,.themefloat::before{content:"";flex:none;width:16px;height:16px;background-color:currentColor;
  -webkit-mask:no-repeat center/contain;mask:no-repeat center/contain;
  -webkit-mask-image:var(--ic-light);mask-image:var(--ic-light)}
:root[data-theme="dark"] .themebtn::before,:root[data-theme="dark"] .themefloat::before{
  -webkit-mask-image:var(--ic-dark);mask-image:var(--ic-dark)}
/* .lbl = ปุ่มที่มีที่ว่างพอจะใส่ข้อความกำกับ (แถบบนของหน้ารายการ/ตั้งค่า และหน้าเข้าสู่ระบบ) */
.lbl::after{content:"สว่าง"}
:root[data-theme="dark"] .lbl::after{content:"มืด"}
/* ปุ่มลอยมุมขวาบนสำหรับหน้าที่ไม่มีแถบบน (หน้าเข้าสู่ระบบ) — พื้นหลังกรมท่าเสมอ จึงใช้สีอ่อนตายตัว */
.themefloat{position:fixed;top:16px;right:16px;z-index:20;
  background:rgba(255,255,255,.10);border:1px solid rgba(255,255,255,.22);color:#E6EDF7;
  border-radius:999px;padding:8px 15px;font-size:13px;font-weight:700}
.themefloat:hover{background:rgba(255,255,255,.18)}

/* ---------- โซน 1 · งานที่เปิดอยู่ ---------- */
.tb-id{display:flex;align-items:center;gap:12px;flex:none;min-width:0}
.idtext{min-width:0}
.idline{display:flex;align-items:center;gap:8px}
.idline b{font-size:15px;font-weight:700;letter-spacing:.8px;white-space:nowrap}
.idcust{display:block;font-size:12px;color:var(--on-navy-3);max-width:210px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;margin-top:1px}
.topbar .statuschip{padding:2px 9px;font-size:10px;letter-spacing:.3px}
.topbar .statuschip.draft{background:rgba(143,190,239,.18);color:#BBD8F5}
.topbar .statuschip.confirmed{background:rgba(21,128,61,.2);color:#7FD8A4}

/* ---------- โซน 2 · ตัวเลข — ใช้เส้นคั่นบาง ๆ แทนกล่อง ให้อ่านเป็นแถวเดียวต่อเนื่อง ---------- */
.tb-metrics{display:flex;align-items:center;margin:0 auto;min-width:0;overflow-x:auto;scrollbar-width:none}
.tb-metrics::-webkit-scrollbar{display:none}
.metric{flex:none;position:relative;display:flex;flex-direction:column;gap:2px;text-align:left;padding:4px 16px}
.metric + .metric::before{content:'';position:absolute;left:0;top:50%;transform:translateY(-50%);width:1px;height:28px;background:var(--hair)}
.mlabel{display:flex;align-items:center;gap:4px;font-size:10px;font-weight:700;color:var(--on-navy-3);letter-spacing:1.1px;white-space:nowrap;text-transform:uppercase}
.mrow{display:flex;align-items:center;gap:8px}
.mvalue{font-size:17px;font-weight:700;font-variant-numeric:tabular-nums;white-space:nowrap;line-height:1.2}
.mvalue small{font-size:11px;font-weight:400;color:var(--on-navy-2);margin-left:1px}

/* ราคาเสนอคือตัวเลขที่ลูกค้าจ้องอยู่ และเป็นตัวเดียวที่กดเข้าไปแก้ได้ — ให้เด่นและดูกดได้ */
.metric.price{cursor:pointer;border:1px solid var(--accent-line);background:linear-gradient(180deg,rgba(46,127,204,.14),rgba(46,127,204,.06));border-radius:var(--r-sm);padding:4px 16px;margin:0 8px;transition:background var(--t-fast),border-color var(--t-fast)}
.metric.price:hover{background:linear-gradient(180deg,rgba(46,127,204,.24),rgba(46,127,204,.12));border-color:rgba(46,127,204,.6)}
.metric.price::before{display:none}
.metric.price .mlabel{color:#A9CBEC}
.metric.price .mvalue{font-size:20px;color:var(--on-navy);letter-spacing:.2px}
.editicon{font-size:10px;opacity:.85}
.mbadge{font-size:11px;font-weight:700;border-radius:999px;padding:2px 8px;white-space:nowrap;font-variant-numeric:tabular-nums}
.mbadge:empty{display:none}
.mbadge.neg{background:rgba(21,128,61,.28);color:#8FE0B0}
.mbadge.pos{background:rgba(180,83,9,.32);color:#F5CE94}

/* เกรดวัสดุเป็นตัวเลือก ไม่ใช่ตัวเลข — ทำให้เห็นชัดว่ากดเปลี่ยนได้ แต่ไม่แย่งสายตาราคา */
.metric.grade select{appearance:none;-webkit-appearance:none;border:1px solid var(--hair-2);background:rgba(255,255,255,.07);color:var(--on-navy);font-size:13px;font-weight:700;border-radius:var(--r-xs);padding:4px 26px 4px 10px;max-width:150px;
  background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238FBEEF' stroke-width='2.5' stroke-linecap='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 7px center;background-size:12px}
.metric.grade select:hover{border-color:var(--accent-line);background-color:rgba(46,127,204,.12)}
.metric.grade select option{color:var(--ink);background:var(--card)}
.mcaption{font-size:11px;color:var(--on-navy-3);white-space:nowrap;font-variant-numeric:tabular-nums}
.mcaption:empty{display:none}

/* ---------- โซน 3 · ผู้ใช้และทางออก ---------- */
.tb-user{display:flex;align-items:center;gap:8px;flex:none;padding-left:16px;margin-left:4px;border-left:1px solid var(--hair)}
.avatar{width:31px;height:31px;border-radius:50%;flex:none;display:flex;align-items:center;justify-content:center;background:rgba(143,190,239,.16);border:1px solid rgba(143,190,239,.45);color:var(--accent-on-navy);font-weight:700;font-size:13px}
.uinfo{line-height:1.3;min-width:0}
.uinfo b{display:block;font-size:13px;font-weight:700;white-space:nowrap;max-width:130px;overflow:hidden;text-overflow:ellipsis}
.uinfo span{display:block;font-size:10px;color:var(--on-navy-3);letter-spacing:.8px;text-transform:uppercase}
.iconbtn{width:34px;height:34px;flex:none;display:flex;align-items:center;justify-content:center;border:1px solid var(--hair-2);border-radius:var(--r-sm);color:var(--on-navy-2);background:rgba(255,255,255,.04);transition:background var(--t-fast),color var(--t-fast),border-color var(--t-fast)}
.iconbtn:hover{background:rgba(255,255,255,.12);color:var(--on-navy);border-color:rgba(255,255,255,.3)}
.iconbtn svg{width:17px;height:17px;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.jobchip{margin-left:auto;display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.chip{background:rgba(255,255,255,.08);border:1px solid var(--hair-2);border-radius:999px;padding:5px 14px;font-size:13px}
.chip b{color:var(--accent-on-navy)}
.chip button{color:var(--on-navy-2);font-size:12px;font-weight:700}
.chip button:hover{color:var(--on-navy)}

main{padding:16px 20px 28px}

/* ---------- app shell: หน้าสตูดิโอสูงเต็มจอ ผ้าใบยืดกินพื้นที่ที่เหลือ
     ราคาเสนอกับแถบเครื่องมือจึงอยู่ในสายตาเสมอ ไม่ต้องเลื่อนหน้า ---------- */
body.studio{height:100dvh;overflow:hidden}
body.studio #wrap{height:100%;display:flex;flex-direction:column;min-height:0}
body.studio .topbar{flex:none}
body.studio main{flex:1;min-height:0;display:flex;padding:12px 16px}
body.studio .cols{flex:1;min-height:0}
body.studio .side{overflow-y:auto;overscroll-behavior:contain}
body.studio .stage{min-height:0}
body.studio .deck{flex:none}
body.studio .canvas-shell{flex:1;min-height:0}
body.studio #plansvg{height:100%}

/* ---------- cards & layout ---------- */
/* min-width:0 จำเป็น — ไม่ใส่แล้วขนาดตามเนื้อหาของ svg ผืนแบบ (กว้างตามขอบเขตแปลน)
   จะดันคอลัมน์ให้กว้างเกินจอ ทำให้ทั้งหน้าเลื่อนซ้ายขวาบนมือถือ/แท็บเล็ต */
.cols{display:flex;gap:16px;align-items:stretch;min-width:0}
.side{width:250px;flex:none;display:flex;flex-direction:column;gap:12px}
.card{background:var(--card);border:1px solid var(--line);border-radius:var(--r-md);padding:12px 14px}
.card h3{font-size:12px;letter-spacing:1.5px;color:var(--muted);text-transform:uppercase;margin-bottom:10px}
.card h3 b{color:var(--ink)}

/* ---------- แถบเครื่องมือซ้ายแบบพับเก็บได้ ----------
   ใช้ grid-template-rows 0fr→1fr เพื่อให้ยืด/หุบลื่นโดยไม่ต้องรู้ความสูงเนื้อหาล่วงหน้า
   (เบราว์เซอร์เก่าที่ไม่ทำ transition ให้ ก็ยังหุบสนิทเพราะแถวสูง 0) */
/* การ์ดต้องไม่ถูกบีบให้เตี้ยลง ไม่งั้น overflow:hidden จะตัดรายการท้าย ๆ ทิ้งโดยไม่มีแถบเลื่อนให้เลื่อนไปดู
   (ให้แถบข้างเป็นตัวเลื่อนแทน) */
.side > .card{flex:none}
.card.acc{padding:0;overflow:hidden}
.acchead{display:flex;align-items:center;gap:8px;width:100%;min-height:42px;padding:9px 13px;text-align:left;cursor:pointer;transition:background var(--t-fast)}
.acchead:hover{background:var(--surf2)}
.acchead:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}
/* หัวข้อต้องอยู่บรรทัดเดียวคู่กับป้ายและลูกศร — ไทยกับ letter-spacing กว้าง ๆ จะตกบรรทัดจนหัวข้อสูงไม่เท่ากัน */
.acctitle{flex:1;min-width:0;font-size:13px;font-weight:700;letter-spacing:.5px;color:var(--muted);text-transform:uppercase;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.acctitle b{color:var(--ink)}
.accbadge{flex:none;font-size:11px;font-weight:700;color:var(--accent-ink);background:var(--tintbg);border:1px solid var(--line);border-radius:999px;padding:1px 8px;white-space:nowrap;font-variant-numeric:tabular-nums}
.accbadge:empty{display:none}
.accchev{flex:none;width:15px;height:15px;fill:none;stroke:var(--muted);stroke-width:2.4;stroke-linecap:round;stroke-linejoin:round;transition:transform var(--t-slow) var(--ease)}
.acc.open .acchead{background:var(--surf2);box-shadow:inset 0 -1px 0 var(--line)}
.acc.open .acchead .accchev{transform:rotate(180deg);stroke:var(--accent)}
.accbody{display:grid;grid-template-rows:0fr;transition:grid-template-rows var(--t-slow) var(--ease)}
.acc.open .accbody{grid-template-rows:1fr}
/* visibility กันไม่ให้ปุ่มที่หุบอยู่ถูก Tab ไปโดน — หน่วงจนแอนิเมชันจบก่อนค่อยซ่อน */
.accinner{overflow:hidden;min-height:0;visibility:hidden;transition:visibility 0s var(--t-slow)}
.acc.open .accinner{visibility:visible;transition:visibility 0s}
.accpad{padding:11px 13px 13px}

/* ---------- palette ---------- */
.blocklist{display:flex;flex-direction:column;gap:6px}
.pal{display:flex;align-items:center;gap:10px;border:1px solid var(--line);border-radius:var(--r-sm);padding:7px 9px;background:var(--surf);text-align:left;width:100%}
.pal:hover{border-color:var(--accent);background:var(--tint)}
.pal:disabled{opacity:.45;cursor:default}
.pal .sw{flex:none;border:1.5px solid var(--navy2);background:var(--surf3);border-radius:3px}
.pal .nm{font-size:13px;font-weight:700;color:var(--ink)}
.pal .dim{font-size:12px;color:var(--muted)}
.pal.door .sw{background:var(--door);border-color:var(--door-deep)}
.pal.win .sw{background:var(--win);border-color:var(--win-deep)}
/* คลังประตู/หน้าต่าง — ภาพตัวอย่างวาดจากรูปทรงจริงที่จะไปอยู่บนแปลน */
.palgroup{font-size:11px;font-weight:800;color:var(--muted);letter-spacing:.04em;margin:9px 0 1px}
.palgroup:first-child{margin-top:0}
.pal.opening{padding:5px 8px}
.pal.opening .opsw{flex:none;display:flex;align-items:center;justify-content:center;width:56px;height:32px;border:1px solid var(--line);border-radius:var(--r-xs)}
.pal.opening.door .opsw{background:var(--cv-doorsw-bg);border-color:var(--cv-doorsw-line)}
.pal.opening.win .opsw{background:var(--cv-winsw-bg);border-color:var(--cv-winsw-line)}
.pal.stair .sw{background:repeating-linear-gradient(90deg,var(--surf3) 0 4px,var(--cv-stair) 4px 5px)}
.ftag{display:inline-block;font-size:10px;font-weight:700;color:var(--warn);background:var(--warn-bg);border-radius:999px;padding:1px 7px;margin-left:5px;vertical-align:middle}
.hint{font-size:12px;color:var(--muted);line-height:1.6;margin-top:8px}
.subnote{font-size:11px;color:var(--muted);margin-top:2px;line-height:1.5}

/* ---------- versions panel ---------- */
.verlist{display:flex;flex-direction:column;gap:4px;max-height:220px;overflow-y:auto}
.ver{display:flex;justify-content:space-between;align-items:center;border:1px solid var(--line);border-radius:var(--r-xs);padding:6px 9px;font-size:12px;background:var(--surf);width:100%;text-align:left}
.ver:hover{border-color:var(--accent)}
.ver b{color:var(--ink)}
.ver .vmeta{color:var(--muted);font-size:11px}

/* ---------- canvas area ---------- */
.stage{flex:1;display:flex;flex-direction:column;gap:10px;min-width:0}
.tbtn{background:var(--card);border:1px solid var(--line);border-radius:var(--r-sm);padding:7px 13px;font-size:13px;font-weight:700;color:var(--ink)}
.tbtn:hover{border-color:var(--accent);background:var(--tint)}
.tbtn:disabled{opacity:.4;cursor:default}
.tbtn.primary{background:var(--navy2);border-color:var(--navy2);color:#fff}
.tbtn.primary:hover{background:var(--navy-hov);border-color:var(--navy-hov)}
.tbtn.primary:disabled{background:var(--navy2)}

/* ==========================================================================
   แถบเครื่องมือเหนือผ้าใบ
   ปัญหาเดิม: ปุ่ม 8 ปุ่มน้ำหนักเท่ากันหมดเรียงกันสองแถว — "ย้อนกลับ" ที่กดวันละร้อยครั้ง
   หน้าตาเท่ากับ "Confirm จบบรีฟ" ที่กดครั้งเดียวแล้วล็อกถาวร · ใช้ emoji เป็นไอคอน ·
   คำแนะนำการใช้เมาส์เป็นข้อความเทายาวคาอยู่กลางแถบตลอดเวลา · กินความสูงผ้าใบไปสองแถว
   แนวทางใหม่: แผงเดียวแบ่งโซนด้วยเส้นคั่นบาง ๆ · ไอคอนเส้นชุดเดียว ·
   ความเด่นของปุ่มแปรตามความถี่และความสำคัญ · สิ่งที่อ่านครั้งเดียวพอย้ายเข้าเมนู
   ========================================================================== */
/* flex-wrap:wrap ไม่ใช่ overflow-x:auto — เมนูดรอปดาวน์เป็น absolute อยู่ในแถบนี้
   ถ้าตั้ง overflow บนตัวแถบ เมนูจะถูกตัดหายทันทีที่จอแคบพอจะเกิดแถบเลื่อน
   จอแคบจึงให้ตกบรรทัดแทน ทุกคำสั่งยังเห็นครบและกดได้ */
.deck{display:flex;align-items:center;gap:4px;flex-wrap:wrap;min-width:0;
  background:var(--card);border:1px solid var(--line);border-radius:var(--r-md);
  padding:6px 8px;box-shadow:var(--e1)}
.dbtn{display:inline-flex;align-items:center;gap:8px;flex:none;height:34px;padding:0 12px;border-radius:var(--r-sm);
  font-size:13px;font-weight:700;color:var(--ink);background:transparent;border:1px solid transparent;
  white-space:nowrap;transition:background .13s,border-color .13s,color .13s}
.dbtn:hover:not(:disabled){background:var(--surf2)}
.dbtn:disabled{opacity:.35;cursor:default}
.dbtn.ico{width:34px;padding:0;justify-content:center}
.i{width:17px;height:17px;flex:none;fill:none;stroke:currentColor;stroke-width:1.9;stroke-linecap:round;stroke-linejoin:round}
.dgrp{display:inline-flex;gap:2px;flex:none}
.dsep{flex:none;width:1px;height:20px;background:var(--line);margin:0 4px}
.dspace{flex:1 1 auto;min-width:6px}
.dwrap{position:relative;display:inline-flex;flex:none}

/* ปุ่มแบบแบ่งช่อง = "สถานะของมุมมอง" (ชั้นไหน · ซูมเท่าไร) ต่างจากปุ่มกดสั่งงานชัดเจน */
.dseg{display:inline-flex;align-items:center;gap:2px;flex:none;background:var(--surf3);border-radius:var(--r-sm);padding:2px}
.dseg button{display:inline-flex;align-items:center;justify-content:center;height:30px;padding:0 12px;border-radius:var(--r-xs);
  font-size:13px;font-weight:700;color:var(--muted);transition:background .13s,color .13s}
.dseg button:hover{color:var(--ink)}
.dseg button.son{background:var(--card);color:var(--ink);box-shadow:var(--e1)}
.dseg.zoom button{padding:0 7px;color:var(--ink)}
.dseg.zoom .zval{min-width:54px;font-variant-numeric:tabular-nums;letter-spacing:.2px}
.dseg.zoom button:hover{background:var(--card)}

/* ปุ่มบันทึกบอกสถานะในตัว: มีของค้าง = ทึบและเด่น · บันทึกแล้ว = จางลงจนไม่แย่งสายตา */
.dbtn.save{border-color:var(--line)}
.dbtn.save .ic-dirty{display:none}
.dbtn.save.dirty .ic-dirty{display:block}
.dbtn.save.dirty .ic-clean{display:none}
.dbtn.save.dirty{background:var(--navy2);border-color:var(--navy2);color:#fff;box-shadow:0 2px 9px rgba(30,58,95,.3)}
.dbtn.save.dirty:hover:not(:disabled){background:var(--navy-hov);border-color:var(--navy-hov)}
.dbtn.save:not(.dirty) .i{color:var(--ok)}
.dbtn.save:not(.dirty){color:var(--muted);font-weight:400}
.dbtn.present{border-color:var(--accent-line);color:var(--accent-ink)}
.dbtn.present:hover:not(:disabled){background:var(--tint);border-color:var(--accent)}
.dbtn .chev{width:13px;height:13px;opacity:.55;margin-left:-2px}
.dbtn[aria-expanded="true"]{background:var(--surf2)}
.dbtn[aria-expanded="true"] .chev{transform:rotate(180deg)}
/* ระหว่างสร้างไฟล์ ปุ่มยังต้องอ่านออกว่ากำลังทำอะไรอยู่ — เมนูปิดไปแล้วจึงโชว์ที่ปุ่มแม่ */
.dbtn.busy{opacity:1;color:var(--accent-ink)}
.dbtn.busy .i{animation:dspin 1s linear infinite;transform-origin:center}
@keyframes dspin{to{transform:rotate(360deg)}}

/* ---------- เมนูในแถบเครื่องมือ ---------- */
.dmenu{position:absolute;top:calc(100% + 8px);right:0;z-index:22;display:none;
  min-width:270px;max-width:min(360px,92vw);background:var(--card);border:1px solid var(--line);
  border-radius:var(--r-md);padding:6px;box-shadow:0 20px 48px var(--sh-lg)}
.dmenu.on{display:block}
.dmenu > button{display:flex;align-items:flex-start;gap:10px;width:100%;text-align:left;
  padding:9px 10px;border-radius:var(--r-sm);font-size:13px;font-weight:700;color:var(--ink)}
.dmenu > button:hover:not(:disabled){background:var(--surf2)}
.dmenu > button:disabled{opacity:.4;cursor:default}
.dmenu > button .i{margin-top:1px;color:var(--muted)}
.dmenu small{display:block;font-weight:400;font-size:11px;color:var(--muted);margin-top:4px;line-height:1.55;white-space:normal}
/* Confirm เป็นหมุดหมายที่ย้อนกลับไม่ได้ ให้หน้าตาต่างจากคำสั่งทั่วไปในเมนูเดียวกัน */
.dmenu > button.milestone{border:1px solid var(--warn-line);background:var(--warn-bg)}
.dmenu > button.milestone,.dmenu > button.milestone .i{color:var(--warn)}
.dmenu > button.milestone:hover:not(:disabled){background:var(--warn-bg);border-color:var(--warn)}
.dmenu > button.milestone .dlab{color:var(--ink)}

/* แผงวิธีใช้ — เปิดจากปุ่ม ? แทนที่จะคาข้อความไว้กลางแถบ */
.dmenu.help{left:0;right:auto;min-width:340px;padding:13px 15px}
.dmenu.help h5{font-size:11px;letter-spacing:1.3px;text-transform:uppercase;color:var(--muted);margin:0 0 9px}
.dmenu.help h5 + .klist{margin-bottom:12px}
.dmenu.help .klist:last-child{margin-bottom:0}
.klist{display:grid;grid-template-columns:auto 1fr;gap:8px 12px;align-items:baseline;font-size:12px;margin:0}
.klist dt{display:flex;gap:4px;justify-content:flex-end;flex-wrap:wrap}
.klist dd{margin:0;color:var(--muted);line-height:1.5}
kbd{font-family:inherit;font-size:11px;font-weight:700;color:var(--ink);background:var(--surf3);
  border:1px solid var(--line);border-bottom-width:2px;border-radius:5px;padding:2px 6px;white-space:nowrap}
@media (prefers-reduced-motion:no-preference){
  .dmenu.on{animation:dpop .14s ease-out}
  @keyframes dpop{from{opacity:0;transform:translateY(-5px)}to{opacity:1;transform:none}}
}

.canvas-shell{position:relative;background:var(--cv-bg);border:1px solid var(--line);border-radius:var(--r-md);overflow:hidden}
#plansvg{display:block;width:100%;height:auto;touch-action:none;user-select:none}
.seltool{position:absolute;display:none;gap:4px;background:var(--float);border-radius:var(--r-sm);padding:5px;box-shadow:0 6px 18px var(--sh-lg);align-items:center;flex-wrap:nowrap;z-index:5}
.seltool button{color:var(--on-navy);font-size:12px;font-weight:700;padding:4px 9px;border-radius:var(--r-xs)}
.seltool button:hover{background:rgba(255,255,255,.15)}
/* ปุ่มลบย้อนกลับไม่ได้ทันที — กันชนไม่ให้ชนกับปุ่มคัดลอกที่หน้าตาใกล้กัน */
.seltool .sep{flex:none;width:1px;align-self:stretch;background:rgba(255,255,255,.22);margin:2px 5px}
.seltool button.del{color:#FCA5A5}
.seltool button.del:hover{background:rgba(248,113,113,.25)}
.seltool select{border:none;border-radius:var(--r-xs);font-size:12px;padding:4px 6px;background:var(--card);color:var(--ink);max-width:130px}
.seltool .selcount{color:var(--accent-on-navy);font-size:12px;font-weight:700;padding:0 4px;white-space:nowrap}
.seltool .selcount:empty{display:none}
.sizebox{display:flex;align-items:center;gap:4px;color:var(--on-navy-2);font-size:12px}
.sizebox input{width:56px;border:none;border-radius:var(--r-xs);font-size:12px;padding:4px 5px;background:var(--card);color:var(--ink);font-variant-numeric:tabular-nums}
.sizebox small{font-size:11px;color:var(--on-navy-2)}
.overlapwarn{display:none;background:var(--bad-bg);color:var(--bad);border:1px solid var(--bad-line);border-radius:var(--r-sm);padding:9px 14px;font-size:13px;font-weight:700;flex:none}
.overlapwarn.on{display:block}
/* แถบแจ้งเตือนใต้ผ้าใบ — ใช้กับเรื่องที่ต้องคาไว้จนกว่าจะแก้ ไม่ใช่ toast ที่หายเอง */
.notice{display:none;border-radius:var(--r-sm);padding:9px 14px;font-size:13px;line-height:1.6;flex:none}
.notice.on{display:block}
.notice.warn{background:var(--warn-bg);color:var(--warn);border:1px solid var(--warn-line)}
.notice.warn b{color:var(--ink)}
.lockbadge{position:absolute;right:10px;top:10px;background:var(--float);color:var(--on-navy);font-size:11px;border-radius:999px;padding:4px 12px;display:flex;gap:6px;align-items:center;box-shadow:0 2px 8px var(--sh)}
.lockbadge b{color:var(--accent-on-navy)}
.modebanner{position:absolute;left:50%;transform:translateX(-50%);top:10px;background:var(--navy2);color:#fff;font-size:13px;font-weight:700;border-radius:999px;padding:6px 18px;display:none;box-shadow:var(--e2)}
.modebanner.on{display:block}

/* ---------- CAD underlay card ---------- */
.uploadbtn{display:block;width:100%;text-align:center;background:var(--card);border:1px dashed var(--line);border-radius:var(--r-sm);padding:9px;font-size:13px;font-weight:700;color:var(--ink);cursor:pointer}
.uploadbtn:hover{border-color:var(--accent);background:var(--tint)}
.uploadbtn.busy{opacity:.5;cursor:default}
.cadrow{border:1px solid var(--line);border-radius:var(--r-sm);padding:8px 10px;background:var(--surf);margin-bottom:8px}
.cadrow .fn{font-size:13px;font-weight:700;color:var(--ink);word-break:break-all;display:flex;justify-content:space-between;gap:6px;align-items:flex-start}
.cadrow .meta{font-size:11px;color:var(--muted);line-height:1.5;margin-top:4px}
.cadrow .fail{font-size:11px;color:var(--bad);background:var(--bad-bg);border-radius:var(--r-xs);padding:5px 7px;margin-top:4px;line-height:1.5}
.cadacts{display:flex;flex-wrap:wrap;gap:4px;margin-top:8px}
.cadacts button{font-size:11px;font-weight:700;color:var(--ink);border:1px solid var(--line);border-radius:var(--r-xs);padding:4px 9px;background:var(--card)}
.cadacts button:hover{border-color:var(--accent);background:var(--tint)}
.cadacts button.on{background:var(--navy);border-color:var(--navy);color:var(--accent-on-navy)}
.cadacts button.danger{color:var(--bad)}
.statuschip{font-size:11px;font-weight:700;border-radius:999px;padding:3px 12px}
.statuschip.tpl{background:var(--info-bg);color:var(--info)}
.statuschip.ready{background:var(--ok-bg);color:var(--ok)}
.statuschip.run{background:var(--warn-bg);color:var(--warn)}
.statuschip.fail{background:var(--bad-bg);color:var(--bad)}
.statuschip.draft{background:var(--warn-bg);color:var(--warn)}
.statuschip.confirmed{background:var(--ok-bg);color:var(--ok)}

/* ==========================================================================
   ที่มาราคา — หน้านี้เปิดให้ลูกค้าดูตรง ๆ จึงออกแบบเป็น "ใบเสนอราคา" ไม่ใช่ฟอร์ม
   ลำดับสายตา: ราคาเสนอ → เส้นทางที่มาของราคา → รายละเอียดห้อง → เทียบเกรด → เครื่องมือฝ่ายขาย
   ========================================================================== */
/* overflow:auto ไม่ใช่ hidden — เนื้อหายาวกว่าจอต้องเลื่อนดูได้ (มุมมนยังตัดให้อยู่) */
.sheet.quote{max-width:780px;padding:0;overflow:auto;border-radius:var(--r-xl);box-shadow:0 34px 90px var(--sh-xl)}
/* หน้านี้เป็นหน้าที่ยื่นให้ลูกค้าดู ใช้แถบเลื่อนสีแบรนด์ไปเลย
   (มาตรฐาน scrollbar-color ไม่มี state ตอนชี้ที่แท่ง จึงเลือกสีที่อ่านออกทั้งบนพื้นขาวและพื้นกรมท่า) */
.sheet.quote{scrollbar-color:var(--sb-on) transparent}
.sheet.quote::-webkit-scrollbar-thumb{background-color:var(--sb-on)}
.sheet.quote::-webkit-scrollbar-thumb:hover{background-color:var(--accent)}

/* --- แถบหัว --- */
/* ติดหัวไว้บนสุดตอนเลื่อน — ปุ่มปิดกับสวิตช์โหมดลูกค้าต้องกดได้ตลอดเวลาที่กำลังนำเสนอ */
.q-top{position:sticky;top:0;z-index:3;display:flex;align-items:center;gap:12px;padding:13px 20px;border-bottom:1px solid var(--line);background:var(--card)}
/* ต้องเจาะจงกว่ากฎ ".sheet img" ที่ตั้ง width:100% ไว้สำหรับภาพแปลน ไม่งั้นตราบริษัทจะยืดเต็มความกว้าง */
.sheet .q-logo{width:34px;height:34px;flex:none;object-fit:contain;border:none;border-radius:0}
.q-topid{flex:1;min-width:0;line-height:1.35}
.q-topid b{display:block;font-size:14px;color:var(--ink);letter-spacing:.2px}
.q-topid span{display:block;font-size:12px;color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.q-close{flex:none;width:32px;height:32px;border-radius:var(--r-sm);border:1px solid var(--line);color:var(--muted);font-size:13px;font-weight:700;background:var(--card)}
.q-close:hover{background:var(--surf2);color:var(--ink)}

/* สวิตช์โหมดลูกค้า — กดครั้งเดียวหน้าจอกลายเป็นใบเสนอราคาสะอาด ๆ ให้ลูกค้าดู */
.q-toggle{flex:none;display:flex;align-items:center;gap:8px;cursor:pointer;user-select:none}
.q-toggle input{position:absolute;opacity:0;width:0;height:0}
.q-track{width:36px;height:20px;border-radius:999px;background:var(--surf3);position:relative;transition:background var(--t-base)}
.q-dot{position:absolute;top:2px;left:2px;width:16px;height:16px;border-radius:50%;background:#fff;box-shadow:0 1px 3px var(--sh-lg);transition:transform var(--t-base)}
.q-toggle input:checked + .q-track{background:var(--accent)}
.q-toggle input:checked + .q-track .q-dot{transform:translateX(16px)}
.q-toggle input:focus-visible + .q-track{outline:2px solid var(--accent);outline-offset:2px}
.q-tlabel{font-size:12px;font-weight:700;color:var(--muted);white-space:nowrap}
.q-toggle input:checked ~ .q-tlabel{color:var(--accent-ink)}

/* --- ราคาเสนอ (hero) --- */
.q-hero{position:relative;display:flex;align-items:center;gap:24px;flex-wrap:wrap;
  padding:22px 24px;color:#fff;background:linear-gradient(135deg,#0F2138 0%,#1E3A5F 55%,#2A5488 100%);overflow:hidden}
/* แสงจาง ๆ มุมขวา — ให้ดูมีมิติโดยไม่ต้องใส่ลวดลาย */
.q-hero::after{content:"";position:absolute;right:-70px;top:-90px;width:280px;height:280px;border-radius:50%;
  background:radial-gradient(circle,rgba(143,190,239,.26),rgba(143,190,239,0) 68%);pointer-events:none}
.q-hero-main{flex:1;min-width:230px;position:relative;z-index:1}
.q-kicker{font-size:11px;letter-spacing:2.2px;text-transform:uppercase;color:#9DB2D4;font-weight:700}
.q-price{font-size:40px;font-weight:700;color:#fff;letter-spacing:-.5px;line-height:1.1;margin-top:4px;font-variant-numeric:tabular-nums}
.q-chips{display:flex;gap:6px;flex-wrap:wrap;margin-top:8px}
.q-chip{font-size:11px;font-weight:700;border-radius:999px;padding:3px 10px;background:rgba(255,255,255,.10);border:1px solid rgba(255,255,255,.18);color:#D9E3F5}
.q-chip.brand{background:rgba(143,190,239,.18);border-color:rgba(143,190,239,.5);color:#CFE3F8}
.q-chip.cut{background:rgba(21,128,61,.22);border-color:rgba(74,222,128,.45);color:#A7E8C0}
.q-hero-stats{position:relative;z-index:1;display:grid;grid-template-columns:repeat(3,auto);gap:0 22px;
  border-left:1px solid rgba(255,255,255,.14);padding-left:22px}
.q-stat{line-height:1.35}
.q-stat i{display:block;font-style:normal;font-size:10px;letter-spacing:.6px;color:#8FA5C9;white-space:nowrap}
.q-stat b{display:block;font-size:15px;font-weight:700;color:#fff;font-variant-numeric:tabular-nums;white-space:nowrap}
.q-stat b small{font-size:11px;font-weight:400;color:#B9C8E2;margin-left:2px}

/* --- เส้นทางของราคา --- */
.q-flow{display:flex;align-items:stretch;gap:0;flex-wrap:wrap;padding:11px 24px;background:var(--surf);border-bottom:1px solid var(--line)}
.q-step{display:flex;align-items:center;gap:8px}
.q-step + .q-step::before{content:"";width:16px;height:16px;flex:none;margin:0 7px;opacity:.45;
  background:no-repeat center/contain url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%235E6C86' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9 6l6 6-6 6'/%3E%3C/svg%3E")}
:root[data-theme="dark"] .q-step + .q-step::before{opacity:.6;
  background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%239AABC4' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9 6l6 6-6 6'/%3E%3C/svg%3E")}
.q-step i{display:block;font-style:normal;font-size:10px;letter-spacing:.5px;color:var(--muted);white-space:nowrap}
.q-step b{display:block;font-size:13px;font-weight:700;color:var(--ink);font-variant-numeric:tabular-nums;white-space:nowrap}
.q-step.cut b{color:var(--ok)}
.q-step.add b{color:var(--warn)}
.q-step.final b{color:var(--accent-ink)}

/* --- บล็อกเนื้อหา --- */
.q-block{padding:15px 24px;border-top:1px solid var(--line);background:var(--card)}
.q-block:first-of-type{border-top:none}
.q-h{display:flex;align-items:baseline;gap:10px;margin-bottom:10px}
.q-h > span{font-size:12px;letter-spacing:1.2px;text-transform:uppercase;font-weight:700;color:var(--ink);display:flex;align-items:center;gap:6px}
.q-hnote{font-style:normal;font-size:11px;color:var(--muted);margin-left:auto;text-align:right}
.q-lock{width:13px;height:13px;fill:none;stroke:var(--muted);stroke-width:2;stroke-linecap:round}

.pm-breakdown{overflow-x:auto}
.pm-breakdown table{width:100%;border-collapse:collapse;font-size:13px;min-width:420px}
.pm-breakdown th{text-align:left;color:var(--muted);font-weight:700;padding:4px 8px;border-bottom:1px solid var(--line);font-size:11px;white-space:nowrap}
/* หน่วยอยู่ใต้ชื่อคอลัมน์ — กันอ่านผิดว่าช่อง "เป็นเงิน" เป็นตารางเมตร */
.pm-breakdown th small{display:block;font-weight:400;font-size:10px;letter-spacing:.3px;opacity:.85}
.pm-breakdown td{padding:4px 8px;border-bottom:1px solid var(--line-soft)}
.pm-breakdown td.num,.pm-breakdown th.num{text-align:right;font-variant-numeric:tabular-nums}
.pm-breakdown td.money{font-weight:700;color:var(--ink)}
.pm-breakdown tr.total td{font-weight:700;color:var(--ink);border-top:2px solid var(--accent-ink);border-bottom:none}
.pm-breakdown tr.rate td{color:var(--muted);font-size:12px;padding-top:6px;border-bottom:none}
.pm-breakdown tr.rate.adj td{color:var(--warn)}
.pm-breakdown tr.rate.adj b{color:var(--ink)}
/* --- เทียบเกรด: การ์ดเลือกได้ ไม่ใช่แค่ป้ายราคา --- */
.q-grades{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:10px}
.q-grade{position:relative;text-align:left;border:1px solid var(--line);border-radius:var(--r-md);padding:12px 14px;background:var(--card);
  transition:border-color var(--t-fast),box-shadow var(--t-fast),transform var(--t-fast)}
.q-grade:hover{border-color:var(--accent);box-shadow:0 6px 18px var(--sh);transform:translateY(-1px)}
.q-grade .gn{font-size:12px;font-weight:700;color:var(--muted);letter-spacing:.4px}
.q-grade .gp{font-size:20px;font-weight:700;color:var(--ink);font-variant-numeric:tabular-nums;line-height:1.25;margin-top:4px;letter-spacing:-.2px}
.q-grade .gr{font-size:11px;color:var(--muted);margin-top:2px;font-variant-numeric:tabular-nums}
.q-grade .gd{margin-top:8px;font-size:11px;font-weight:700;border-radius:999px;padding:2px 9px;display:inline-block;background:var(--surf3);color:var(--muted)}
.q-grade .gd.up{background:var(--warn-bg);color:var(--warn)}
.q-grade .gd.down{background:var(--ok-bg);color:var(--ok)}
.q-grade.cur{border-color:var(--accent);background:var(--tint);box-shadow:0 0 0 1px var(--accent) inset}
.q-grade.cur .gp{color:var(--accent-ink)}
.q-grade.cur .gd{background:var(--accent-fade);color:var(--accent-ink)}
.q-grades.locked .q-grade{pointer-events:none}
/* แปลนที่ Confirm แล้วเปลี่ยนเกรดไม่ได้ — การ์ดยังอ่านเทียบราคาได้แต่ต้องไม่ทำท่าว่ากดได้ */
.q-grade:disabled{cursor:default}
.q-grade:disabled:hover{border-color:var(--line);box-shadow:none;transform:none}
.q-grade.cur:disabled:hover{border-color:var(--accent)}

/* --- โซนฝ่ายขาย: พื้นหลังคนละสีให้เห็นชัดว่าไม่ใช่ส่วนของลูกค้า --- */
.q-internal{background:var(--surf2)}
.q-internal .q-h > span{color:var(--muted)}
.q-seg{display:flex;gap:4px;background:var(--surf3);border-radius:var(--r-sm);padding:3px;margin-bottom:10px;flex-wrap:wrap}
.q-seg button{flex:1;min-width:88px;border-radius:var(--r-xs);padding:7px 10px;font-size:13px;font-weight:700;color:var(--muted);background:transparent;transition:background var(--t-fast),color var(--t-fast),box-shadow var(--t-fast)}
.q-seg button:hover{color:var(--ink)}
.q-seg button.on{background:var(--card);color:var(--ink);box-shadow:var(--e1)}
.q-inputs{display:flex;flex-wrap:wrap;gap:8px;align-items:center;margin-bottom:10px}
.q-field{display:flex;align-items:center;background:var(--card);border:1px solid var(--line);border-radius:var(--r-sm);padding:0 12px;height:40px;min-width:170px}
.q-field.wide{flex:1 1 100%}
.q-field:focus-within{border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-fade)}
.q-field input{flex:1;min-width:0;border:none;outline:none;font-size:14px;color:var(--ink);background:transparent;font-variant-numeric:tabular-nums}
.q-unit{font-size:12px;color:var(--muted);font-weight:700;white-space:nowrap;margin-left:8px}
.q-reasons{display:flex;gap:6px;flex-wrap:wrap;flex:1 1 100%}
.q-reasons button{border:1px solid var(--line);background:var(--card);border-radius:999px;padding:5px 12px;font-size:12px;font-weight:700;color:var(--muted)}
.q-reasons button:hover{border-color:var(--accent);color:var(--ink);background:var(--tint)}
.q-reasons button.on{border-color:var(--accent);background:var(--accent);color:#fff}
.pm-quick{font-size:12px;color:var(--muted);display:flex;gap:4px;align-items:center}
.pm-quick button{border:1px solid var(--line);border-radius:var(--r-xs);padding:6px 11px;font-size:12px;font-weight:700;color:var(--ink);background:var(--card)}
.pm-quick button:hover{border-color:var(--accent);background:var(--tint)}
.pm-result{font-size:14px;color:var(--ink);background:var(--card);border:1px solid var(--line);border-radius:var(--r-sm);padding:11px 14px;margin-bottom:10px;line-height:1.65}
.pm-result b{font-variant-numeric:tabular-nums}
.pm-result .neg{color:var(--ok);font-weight:700}
.pm-result .pos{color:var(--warn);font-weight:700}
.pm-result .err{color:var(--bad);font-weight:700}
.pm-actions{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin-bottom:8px}
.q-btn{border:1px solid var(--line);background:var(--card);border-radius:var(--r-sm);padding:9px 16px;font-size:13px;font-weight:700;color:var(--ink)}
.q-btn:hover{border-color:var(--accent)}
.q-btn.primary{background:linear-gradient(180deg,#2E7FCC,#1E3A5F);border-color:#17304F;color:#fff;box-shadow:0 3px 10px rgba(30,58,95,.32)}
.q-btn.primary:hover{background:linear-gradient(180deg,#3B8CD8,var(--navy-hov))}
.q-hint{font-size:11px;color:var(--muted)}

.q-foot{display:flex;flex-wrap:wrap;gap:4px 18px;justify-content:space-between;
  padding:11px 24px;border-top:1px solid var(--line);background:var(--surf);font-size:11px;color:var(--muted);line-height:1.6}
.q-foot b{color:var(--accent-ink);font-weight:700}

/* โหมดลูกค้า: ซ่อนทุกอย่างที่ไม่ใช่เรื่องของลูกค้า */
.sheet.quote.cust .q-internal{display:none}
.sheet.quote.cust #qGradeHint{visibility:hidden}

@media (max-width:640px){
  .q-hero{padding:18px}
  .q-price{font-size:32px}
  .q-hero-stats{border-left:none;padding-left:0;border-top:1px solid rgba(255,255,255,.14);padding-top:12px;width:100%}
  .q-block,.q-flow,.q-top{padding-left:16px;padding-right:16px}
}

/* ---------- toast & modal ---------- */
#toasts{position:fixed;right:18px;bottom:18px;display:flex;flex-direction:column;gap:8px;z-index:60}
.toast{background:var(--float);color:var(--on-navy);font-size:13px;border-left:4px solid var(--accent-on-navy);border-radius:var(--r-sm);padding:10px 16px;box-shadow:0 8px 24px var(--sh-lg);max-width:340px;line-height:1.5;display:flex;align-items:center;gap:12px}
.toast.err{border-left-color:#F87171}
.toast-act{flex:none;color:var(--accent-on-navy);font-size:13px;font-weight:700;border:1px solid rgba(143,190,239,.5);border-radius:var(--r-xs);padding:5px 11px}
.toast-act:hover{background:rgba(143,190,239,.16)}
.modal{position:fixed;inset:0;background:var(--scrim);display:none;align-items:center;justify-content:center;z-index:50;padding:30px}
.modal.on{display:flex}
.sheet{background:var(--card);border-radius:var(--r-lg);max-width:860px;width:100%;padding:18px 20px;position:relative;max-height:92vh;overflow:auto;box-shadow:0 24px 70px var(--sh-xl)}
.sheet h4{color:var(--ink);font-size:15px;margin-bottom:10px}
.sheet .close{position:absolute;right:14px;top:12px;font-size:13px;font-weight:700;color:var(--muted);padding:4px 10px;border-radius:var(--r-xs);border:1px solid var(--line);background:var(--card)}
.sheet img{display:block;width:100%;border:1px solid var(--line);border-radius:var(--r-sm)}
.imgacts{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-top:12px}
.present-exit{position:fixed;top:14px;right:14px;z-index:40;display:none;background:var(--float);color:var(--on-navy);font-size:13px;font-weight:700;border-radius:999px;padding:8px 18px;box-shadow:0 6px 18px var(--sh-lg)}
/* โหมดนำเสนอ: เหลือผ้าใบกับตัวเลขที่ลูกค้าต้องเห็น ซ่อนเครื่องมือกับตัวเลือกเกรดที่ยังแก้ได้ */
#wrap.present .side,#wrap.present .deck,#wrap.present .dock,
#wrap.present .tb-user,#wrap.present .metric.grade{display:none}
#wrap.present .present-exit{display:block}
#wrap.present .tb-metrics{margin-right:170px}

/* ---------- admin ---------- */
.admtabs{display:flex;gap:6px;margin-bottom:16px}
.admtab{font-size:14px;font-weight:700;color:var(--muted);background:var(--card);border:1px solid var(--line);border-radius:var(--r-sm);padding:8px 20px}
.admtab.on{background:var(--navy);border-color:var(--navy);color:var(--accent-on-navy)}
/* กล่องอธิบายวิธีใช้ — เป็นข้อมูล ไม่ใช่คำเตือน จึงใช้โทนสีเน้นของแบรนด์ทั้งกล่อง
   (เดิมเป็นพื้นฟ้า+ขอบทอง+ตัวหนังสือทอง ตกค้างจากธีมเก่า อ่านแล้วเหมือนมีอะไรผิด) */
.admnote{background:var(--tint);border:1px solid var(--accent-line);border-radius:var(--r-sm);padding:11px 15px;font-size:13px;color:var(--ink);line-height:1.7;margin-bottom:16px}
.admnote b{color:var(--accent-ink)}
.ratecard{background:var(--card);border:1px solid var(--line);border-radius:var(--r-md);padding:14px 16px;margin-bottom:16px}
.rc-head{display:flex;justify-content:space-between;align-items:flex-start;gap:16px;flex-wrap:wrap;margin-bottom:10px}
.rc-code{font-size:15px;font-weight:700;color:var(--ink);margin-right:8px}
.rc-note{font-size:12px;color:var(--muted);margin-top:4px}
.rc-meta{font-size:12px;color:var(--muted);text-align:right;line-height:1.6}
.rc-acts{display:flex;gap:6px;flex-wrap:wrap;margin-top:10px;align-items:center}
.rc-save{font-size:12px;color:var(--muted);margin-left:auto}
.rc-save.dirty{color:var(--warn);font-weight:700}
.rc-save.ok{color:var(--ok);font-weight:700}
.rc-save.err{color:var(--bad);font-weight:700}
.ratetable{width:100%;border-collapse:collapse}
.ratetable th{background:var(--surf2);color:var(--muted);font-size:12px;letter-spacing:1px;text-transform:uppercase;text-align:left;padding:7px 10px;border:1px solid var(--line)}
.ratetable th.num,.ratetable td.num{text-align:right}
.ratetable td{padding:4px 6px;border:1px solid var(--line)}
.ratetable td.muted{color:var(--muted);font-size:13px;text-align:center;padding:12px}
.ratetable input{width:100%;border:1px solid transparent;border-radius:var(--r-xs);padding:6px 8px;font-size:13px;color:var(--ink);background:transparent}
.ratetable input:hover:not(:disabled){border-color:var(--line)}
.ratetable input:focus{border-color:var(--accent);background:var(--card);outline:none}
.ratetable input:disabled{color:var(--muted)}
.ratetable td.num input{text-align:right;font-variant-numeric:tabular-nums}
.linkbtn{font-size:12px;font-weight:700;color:var(--ink);padding:3px 7px;border-radius:var(--r-xs)}
.linkbtn:hover{background:var(--surf2)}
.linkbtn.danger{color:var(--bad)}
.plantable tr.off td{opacity:.5}
.grid2{display:grid;grid-template-columns:1fr 1fr;gap:10px}

/* ---------- print / PDF ---------- */
#printView{display:none}
@media print{
  /* กระดาษเป็นสีขาวเสมอ ไม่ว่าหน้าจอจะตั้งเป็นโหมดมืดอยู่หรือไม่ — บังคับ token กลับเป็นชุดสว่าง
     กันไม่ให้สีที่สืบทอดมาจากโหมดมืดหลุดลงไปในไฟล์ PDF */
  :root{color-scheme:light;--ink:#132B46;--muted:#5E6C86;--line:#D8DFEB;--paper:#FFFFFF;--card:#FFFFFF}
  /* A4 แนวตั้ง: พื้นที่พิมพ์ 190 × 277 มม. — หัวกระดาษ ~18 + ภาพไม่เกิน 200 + ตาราง ~34 + หมายเหตุ ~6 */
  /* A4 แนวตั้ง: พื้นที่พิมพ์ 190 × 277 มม. — หัวกระดาษ ~18 + ภาพไม่เกิน 200 + ตาราง ~34 + หมายเหตุ ~6 */
  @page{size:A4 portrait;margin:10mm}
  body{background:#fff;color:#132B46}
  body.studio{height:auto;overflow:visible}
  #wrap,#toasts,.modal,.scrim,.themefloat{display:none!important}
  #printView{display:block}
  .pr-head{display:flex;justify-content:space-between;align-items:flex-start;border-bottom:2px solid #132B46;padding-bottom:8px;margin-bottom:10px}
  /* หัวกระดาษเป็นเหมือนหัวจดหมายของบริษัท — ตราสัญลักษณ์อยู่คู่กับชื่อสตูดิโอ */
  .pr-id{display:flex;align-items:center;gap:4mm}
  .pr-logo{flex:none;width:14mm;height:14mm;object-fit:contain;print-color-adjust:exact;-webkit-print-color-adjust:exact}
  .pr-brand{font-size:16pt;font-weight:700;color:#132B46;letter-spacing:1px}
  .pr-sub{font-size:8.5pt;color:#5E6C86;margin-top:2px}
  .pr-job{text-align:right;font-size:12pt;font-weight:700;color:#132B46}
  .pr-job div:last-child{font-size:9pt;font-weight:400;color:#5E6C86;margin-top:2px}
  /* กรอบต้องรัดรูปภาพจริง ไม่ใช่กล่องเต็มความกว้างแล้วเหลือขอบขาว — ผังทรงลึกจะได้ไม่มีแถบว่างสองข้าง */
  #printImg{display:block;max-width:100%;max-height:200mm;margin:0 auto;border:1px solid #D8DFEB}
  .pr-table{width:100%;border-collapse:collapse;margin-top:8px;font-size:9.5pt;page-break-inside:avoid}
  .pr-table th{background:#EFF2F7;color:#5E6C86;text-align:left;padding:5px 9px;border:1px solid #D8DFEB;width:16%;font-weight:700}
  .pr-table td{padding:5px 9px;border:1px solid #D8DFEB;font-weight:700;color:#132B46}
  .pr-note{font-size:8pt;color:#5E6C86;margin-top:6px}
}

/* ---------- dock: แถบวางห้องด่วน (แท็บเล็ต/มือถือ) ---------- */
.dock{display:none}
.dockstrip{display:flex;gap:8px;overflow-x:auto;padding:2px 0 4px;-webkit-overflow-scrolling:touch;scrollbar-width:thin}
.dockchip{flex:none;display:flex;flex-direction:column;justify-content:center;gap:2px;background:var(--card);border:1px solid var(--line);border-left:4px solid var(--navy2);border-radius:var(--r-sm);padding:7px 12px;min-height:50px;text-align:left}
.dockchip:hover{border-color:var(--accent);border-left-color:var(--accent);background:var(--tint)}
.dockchip:disabled{opacity:.45}
.dockchip .dn{font-size:13px;font-weight:700;color:var(--ink);white-space:nowrap}
.dockchip .dd{font-size:12px;color:var(--muted);white-space:nowrap}
.dockchip.door{border-left-color:var(--cv-door)}
.dockchip.win{border-left-color:var(--cv-win)}
.dockchip.stair{border-left-color:var(--cv-stair)}

/* ---------- drawer + scrim ---------- */
.paneltoggle{display:none}
.scrim{position:fixed;inset:0;background:var(--scrim);z-index:44;opacity:0;pointer-events:none;transition:opacity var(--t-base)}
.scrim.on{opacity:1;pointer-events:auto}

/* ---------- tablet: palette ลงมาเป็น dock ล่างผ้าใบ · การ์ดที่เหลือเข้า drawer
     เพื่อไม่ให้ขั้นตอน "เลือกห้อง → วาง" ต้องเลื่อนหน้าไปมา ---------- */
@media (max-width:1080px){
  #wrap{min-width:0}
  body.studio main{padding:10px 12px}
  .side{
    position:fixed;top:0;bottom:0;left:0;z-index:45;width:310px;max-width:88vw;
    background:var(--paper);border-right:1px solid var(--line);padding:12px;
    transform:translateX(-102%);transition:transform var(--t-slow) var(--ease);
    box-shadow:0 0 40px var(--sh-lg)
  }
  .side.open{transform:none}
  .side .palette-card{display:none}
  .stage{min-width:0}
  .paneltoggle{display:block}
  .dock{display:block;flex:none}
  /* จอแคบลง: ปุ่มที่ไอคอนสื่อความหมายชัดอยู่แล้วเหลือแต่ไอคอน จะได้ไม่ตกบรรทัด
     แต่ปุ่มบันทึกเก็บข้อความไว้ เพราะมันบอก "สถานะ" (บันทึกแล้ว rev เท่าไร) ไม่ใช่แค่ชื่อคำสั่ง
     ส่วนข้อความในเมนูต้องอยู่ครบเสมอ ไม่งั้นเมนูจะกลายเป็นไอคอนเปล่า */
  #tplbtn .dlab,#exportmenubtn .dlab,.dbtn.present .dlab{display:none}
  #tplbtn,#exportmenubtn,.dbtn.present{padding:0 10px}
  .dmenu .dlab{display:inline!important}
}

/* จอแคบลง: ตัวเลขสรุปลงมาอยู่แถวของตัวเอง จะได้ไม่เบียดกับชื่องานและปุ่ม */
@media (max-width:1080px){
  .topbar{gap:12px;padding:8px 14px;flex-wrap:wrap}
  .topbar .logo{display:none}
  .brand b{font-size:13px;letter-spacing:1px}
  .idcust{max-width:150px}
  .tb-metrics{order:3;width:100%;margin:0;border-top:1px solid rgba(255,255,255,.08);padding-top:8px}
  .metric:first-child{padding-left:0}
  .tb-user{margin-left:auto}
  .uinfo{display:none}
}

/* ---------- ปุ่มขนาดนิ้วเมื่อใช้จอสัมผัส ---------- */
@media (pointer:coarse){
  .tbtn{min-height:42px;padding:9px 14px}
  .dseg button{min-height:40px}
  .dbtn{min-height:40px}
  .dbtn.ico{width:40px}
  .pal{min-height:56px}
  .dockchip{min-height:56px}
  .acchead{min-height:48px}
  .chip button{min-height:40px;padding:0 12px}
  .chip{padding:0 2px}
  .seltool{padding:6px}
  .seltool button{min-width:42px;min-height:38px}
  .seltool select,.sizebox input{min-height:38px}
  .linkbtn,.cadacts button{min-height:40px}
  /* หน้ามุมมอง 3D — แผงควบคุมลอยบนผืนภาพ ปุ่มต้องกดด้วยนิ้วได้ */
  .v3panel button,.v3panel .seg button{min-height:40px;padding-left:12px;padding-right:12px}
  .seg{min-height:40px}
  .themebtn,.themefloat{min-height:38px}
}

/* ---------- มือถือ ---------- */
@media (max-width:640px){
  .topbar{padding:8px 10px;gap:8px;flex-wrap:wrap}
  .brand span{display:none}
  .idcust{display:none}
  .jobchip{gap:6px}
  .chip{padding:4px 10px;font-size:12px}
  /* จอแคบ: ปุ่มธีมเหลือไอคอน ไม่ต้องมีข้อความ */
  .chip .themebtn .tlabel{display:none!important}
  .themefloat{top:10px;right:10px;padding:8px 12px}
  body.studio main{padding:8px}
  .deck{border-radius:var(--r-sm);padding:5px 6px}
  .dspace{display:none}
  /* จอแคบ: เหลือเฉพาะราคาเสนอกับเกรด — พื้นที่ดูได้ในหน้าต่างที่มาราคา */
  .tb-metrics .metric:not(.price):not(.grade){display:none}
  .metric{padding:2px 12px}
  .metric.price{margin-left:0}
  .metric.price .mvalue{font-size:20px}
  .metric.grade select{max-width:118px}
  #rateHist,.mcaption{display:none}
  .seltool{max-width:calc(100vw - 24px);overflow-x:auto}
  main{padding:12px}
  .listhead{flex-wrap:wrap}
  .sheet{padding:14px 14px 18px}
  .modal{padding:12px}
}

/* ---------- login ---------- */
.field{margin-bottom:12px}
.field label{display:block;font-size:12px;font-weight:700;color:var(--ink);margin-bottom:4px}
.field input{width:100%;border:1px solid var(--line);border-radius:var(--r-sm);padding:9px 12px;font-size:14px;background:var(--card);color:var(--ink)}
.btn-primary{width:100%;background:var(--navy2);color:#fff;font-size:14px;font-weight:700;border-radius:var(--r-sm);padding:11px;margin-top:6px}
.btn-primary:hover{background:var(--navy-hov)}
.btn-primary:disabled{opacity:.6}
.form-err{font-size:13px;color:var(--bad);background:var(--bad-bg);border-radius:var(--r-xs);padding:8px 12px;margin-bottom:10px;display:none}

/* ---------- plans list ---------- */
.listhead{display:flex;align-items:center;gap:12px;margin-bottom:16px}
.listhead h2{font-size:17px;color:var(--ink)}
.plantable{width:100%;border-collapse:collapse;background:var(--card);border:1px solid var(--line);border-radius:var(--r-md);overflow:hidden}
.plantable th{background:var(--surf2);color:var(--muted);font-size:12px;letter-spacing:1px;text-transform:uppercase;text-align:left;padding:10px 14px;border-bottom:1px solid var(--line)}
.plantable td{padding:11px 14px;font-size:14px;border-bottom:1px solid var(--line-soft)}
.plantable tr:last-child td{border-bottom:none}
.plantable tbody tr{cursor:pointer}
.plantable tbody tr:hover{background:var(--tint)}
.plantable .job{font-weight:700;color:var(--ink)}
.plantable .num{font-variant-numeric:tabular-nums;text-align:right}
.empty{padding:40px;text-align:center;color:var(--muted);font-size:14px;background:var(--card);border:1px dashed var(--line);border-radius:var(--r-md)}

/* ---------- ระบบสร้างภาพบ้าน 3D ---------- */
/* หน้าเดียวสองสถานะ: รายการงาน (ไม่มี ?id) กับพื้นที่ทำงาน (มี ?id)
   ภาษาเดียวกับหน้าอื่น: การ์ดขาว เส้นบาง โทนเนวี่ — ตัวเลือกบรีฟใช้ select ธรรมดา
   เพราะฝ่ายขายกรอกต่อหน้าลูกค้า ต้องเดาได้ว่ากดตรงไหนโดยไม่ต้องเรียนรู้ใหม่ */
.d3head{display:flex;align-items:center;gap:10px;margin-bottom:16px;flex-wrap:wrap}
.d3head h2{font-size:17px;color:var(--ink);letter-spacing:.2px}
.d3head h2 .dash{color:var(--line);margin:0 2px}
.d3head h2 .cust{font-weight:400;color:var(--muted)}
.d3head .sub{font-size:13px;color:var(--muted)}
.d3head .back{width:34px;padding:7px 0;text-align:center}
.d3wrap{display:grid;grid-template-columns:344px minmax(0,1fr);gap:16px;align-items:start}

/* ---- รายการงาน: การ์ดที่เห็นภาพจริง + ค้นหา/กรอง ---- */
.d3tools{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-bottom:16px}
.d3search{flex:1;min-width:220px;max-width:380px;display:flex;align-items:center;gap:8px;background:var(--card);border:1px solid var(--line);border-radius:var(--r-sm);padding:0 12px}
.d3search svg{width:16px;height:16px;flex:none;fill:none;stroke:var(--muted);stroke-width:2;stroke-linecap:round}
.d3search input{flex:1;min-width:0;border:0;background:none;padding:9px 0;font-size:14px;color:var(--ink);outline:none}
.d3search:focus-within{border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-fade)}
.segs{display:flex;gap:4px;background:var(--surf3);border-radius:var(--r-sm);padding:3px;flex-wrap:wrap}
.seg{border-radius:var(--r-xs);padding:6px 12px;font-size:13px;font-weight:700;color:var(--muted);display:flex;align-items:center;gap:6px}
.seg .n{font-size:11px;font-weight:700;color:var(--muted);background:var(--card);border-radius:999px;padding:0 6px;min-width:20px;text-align:center}
.seg:hover{color:var(--ink)}
.seg.on{background:var(--card);color:var(--ink);box-shadow:var(--e1)}
.seg.on .n{background:var(--tintbg);color:var(--accent-ink)}
.seg.empty{opacity:.45}

.hdgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(268px,1fr));gap:16px}
.hdcard{display:block;background:var(--card);border:1px solid var(--line);border-radius:var(--r-lg);overflow:hidden;text-decoration:none;color:inherit;transition:border-color var(--t-fast),box-shadow var(--t-fast),transform var(--t-fast)}
.hdcard:hover{border-color:var(--accent);box-shadow:var(--e2);transform:translateY(-2px)}
.hdcard .thumb{position:relative;display:block;aspect-ratio:16/10;background:var(--surf2);border-bottom:1px solid var(--line-soft)}
.hdcard .thumb img{width:100%;height:100%;object-fit:cover;display:block}
.hdcard .thumb .ph{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;color:var(--muted);font-size:12px}
.hdcard .thumb .statuschip{position:absolute;left:10px;top:10px;backdrop-filter:blur(6px)}
.hdcard .meta{display:block;padding:11px 13px 13px}
.hdcard .code{display:block;font-size:13px;font-weight:700;color:var(--accent-ink);letter-spacing:.4px}
.hdcard .cust{display:block;font-size:15px;font-weight:700;color:var(--ink);margin-top:1px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.hdcard .sub{display:block;font-size:12px;color:var(--muted);margin-top:4px}
.hdcard .foot{display:flex;justify-content:space-between;gap:8px;font-size:11px;color:var(--muted);margin-top:8px;padding-top:9px;border-top:1px solid var(--line-soft)}
.d3acts{display:flex;gap:8px;margin-top:12px;flex-wrap:wrap}
.d3acts .tbtn{flex:1;text-align:center}
.d3assets{display:flex;flex-wrap:wrap;gap:8px;margin-top:8px}
.d3asset{position:relative;width:76px;height:76px;border:1px solid var(--line);border-radius:var(--r-sm);overflow:hidden;background:var(--surf2)}
.d3asset img{width:100%;height:100%;object-fit:cover;display:block}
.d3asset .rm{position:absolute;top:2px;right:2px;width:20px;height:20px;border-radius:var(--r-xs);background:rgba(19,43,70,.72);color:#fff;font-size:11px;line-height:20px;text-align:center}
.d3asset .rm:hover{background:var(--bad)}
.d3asset .k{position:absolute;left:0;right:0;bottom:0;background:rgba(19,43,70,.72);color:#fff;font-size:9px;text-align:center;padding:1.5px 2px}
/* ป้ายสถานะถอดแบบบนรูปตัวอย่าง — ✓ ถอดแล้ว (กดดูรายละเอียด) · กำลังถอด · ถอดไม่ได้ */
.d3asset .ana{position:absolute;top:2px;left:2px;font-size:9px;font-weight:700;border-radius:var(--r-xs);padding:2px 5px;pointer-events:none;line-height:1.3}
.d3asset .ana.ok{background:var(--ok);color:#fff}
.d3asset .ana.run{background:rgba(19,43,70,.72);color:#fff}
.d3asset .ana.bad{background:var(--bad);color:#fff}
/* หน้าต่างผลถอดแบบรายใบ */
.refimg{border:1px solid var(--line);border-radius:var(--r-md);overflow:hidden;background:var(--surf2);min-height:120px;max-height:240px;display:flex;align-items:center;justify-content:center;margin-bottom:8px}
.refimg img{width:100%;height:100%;max-height:240px;object-fit:contain;display:block}
.refname{font-size:12px;color:var(--muted);margin-bottom:10px;word-break:break-all}
.refrow{display:flex;gap:10px;font-size:13px;padding:7px 0;border-bottom:1px solid var(--line-soft);line-height:1.6}
.refrow b{flex:none;width:104px;color:var(--muted);font-size:12px;font-weight:700}
.refrow span{min-width:0;color:var(--ink)}
.refrow.hi span{color:var(--accent-ink);font-weight:600}
/* บรรทัด "จุดเด่นที่จะเก็บ" ในกล่องตรวจแบบ */
.pf-item.refhi{background:var(--tint);color:var(--accent-ink)}
.d3banner{border-radius:var(--r-sm);padding:10px 14px;font-size:13px;margin-bottom:12px;border:1px solid}
.d3banner.warn{background:var(--warn-bg);color:var(--warn);border-color:transparent}
.d3banner.ok{background:var(--ok-bg);color:var(--ok);border-color:transparent}
/* ---- การ์ดรอบภาพ ----
   ตัวสินค้าของหน้านี้คือ "ภาพบ้าน" — เลย์เอาต์จึงยกภาพพระเอกให้ใหญ่ที่สุดในการ์ด
   (ของเดิมทุกภาพกว้าง 201px เท่ากันหมดในการ์ดกว้าง 870px เหลือที่ว่างครึ่งแถว) */
.d3round{background:var(--card);border:1px solid var(--line);border-radius:var(--r-lg);padding:14px 16px 16px;margin-bottom:16px;box-shadow:var(--e1)}
.d3round.latest{border-color:var(--accent-line);box-shadow:0 6px 22px -14px var(--sh-lg),0 0 0 1px var(--accent-fade)}
.d3round.picked{border-color:var(--ok);box-shadow:0 0 0 1px var(--ok)}
.d3rhead{display:flex;align-items:center;gap:8px;flex-wrap:wrap;padding-bottom:11px;margin-bottom:12px;border-bottom:1px solid var(--line-soft)}
.d3rhead b{font-size:15px;color:var(--ink);letter-spacing:.2px}
.d3rhead .when{font-size:12px;color:var(--muted);margin-left:auto;text-align:right}
.d3elapsed{font-size:12px;font-weight:700;color:var(--accent-ink);background:var(--tint);border:1px solid var(--accent-line);border-radius:999px;padding:2px 10px;font-variant-numeric:tabular-nums}
.d3redo{font-size:12px;color:var(--ink);background:var(--surf2);border-left:3px solid var(--accent-line);border-radius:var(--r-xs);padding:7px 11px;margin-bottom:12px;line-height:1.6}
.d3redo b{color:var(--muted);font-weight:700;margin-right:4px}
.d3fail{font-size:13px;color:var(--bad);background:var(--bad-bg);border-radius:var(--r-xs);padding:7px 10px;margin-bottom:12px}

/* ---- แกลเลอรี: ภาพพระเอก + แปลนอ้างอิง แล้วแถวภาพด้าน ---- */
.d3gal{display:grid;grid-template-columns:minmax(0,1.85fr) minmax(0,1fr);gap:12px;align-items:start}
.d3gal.solo{grid-template-columns:minmax(0,1fr)}
.d3elev{grid-column:1/-1;display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:12px}
.d3shot{display:flex;flex-direction:column;min-width:0}
.d3shot .shotbtn{position:relative;display:block;width:100%;padding:0;border-radius:var(--r-md);overflow:hidden;background:var(--surf2);border:1px solid var(--line);cursor:zoom-in;transition:border-color var(--t-fast),box-shadow var(--t-fast),transform var(--t-fast)}
.d3shot .shotbtn:hover{border-color:var(--accent);box-shadow:var(--e2)}
.d3shot .shotbtn:disabled{cursor:default}
.d3shot .media{display:block;aspect-ratio:3/2}
.d3shot img{display:block;width:100%;height:100%;object-fit:cover}
.d3shot.hero .media{aspect-ratio:3/2}
/* แปลนเป็นภาพจัตุรัส/แนวตั้ง — ถ้าครอบเป็น 3:2 เหมือนภาพอื่นจะโดนตัดหัวท้ายทิ้ง */
.d3shot.plan .media{aspect-ratio:1/1}
.d3shot.plan img{object-fit:contain;background:var(--cv-bg)}
.d3shot .ph{width:100%;height:100%;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px;color:var(--muted);font-size:12px;padding:10px;text-align:center;line-height:1.5}
.d3shot .ph.fail{color:var(--bad)}
.d3shot .ph small{color:var(--muted);font-size:11px}
.d3shot .zoomhint{position:absolute;right:9px;bottom:9px;background:rgba(19,43,70,.82);color:#fff;font-size:11px;font-weight:700;border-radius:999px;padding:4px 11px;opacity:0;transform:translateY(4px);transition:opacity var(--t-fast),transform var(--t-fast);pointer-events:none}
.d3shot .shotbtn:hover .zoomhint,.d3shot .shotbtn:focus-visible .zoomhint{opacity:1;transform:none}
.d3shot figcaption{display:flex;align-items:center;justify-content:space-between;gap:6px;padding:7px 2px 0;font-size:13px;font-weight:700;color:var(--ink)}
.d3shot.hero figcaption{font-size:14px}
/* กล่องเลือกมุมที่จะสร้าง — checkbox รายมุมพร้อมป้ายราคา */
.pickbox{display:flex;flex-direction:column;gap:8px;margin-bottom:16px}
.pickview{display:flex;align-items:center;gap:10px;border:1px solid var(--line);border-radius:var(--r-sm);padding:10px 12px;cursor:pointer;transition:border-color var(--t-fast),background var(--t-fast)}
.pickview:hover{border-color:var(--accent);background:var(--tint)}
.pickview input{width:16px;height:16px;accent-color:var(--accent)}
.pickview span{font-size:14px;font-weight:700;color:var(--ink);flex:1}
.pickview small{font-size:12px;color:var(--muted)}

/* ชิปผลด่านตรวจภาพเทียบแปลน — ⚠ hover เห็นรายการจุดต่างใน title */
.d3shot .gchk{flex:none;font-size:11px;font-weight:700;border-radius:999px;padding:2.5px 8px;line-height:1.3;cursor:help}
.d3shot .gchk.ok{background:var(--ok-bg);color:var(--ok)}
.d3shot .gchk.warn{background:var(--warn-bg);color:var(--warn)}
.d3shot .rbtn{flex:none;width:26px;height:26px;border-radius:var(--r-xs);border:1px solid var(--line);color:var(--muted);font-size:13px;line-height:1;background:var(--card)}
.d3shot .rbtn:hover{border-color:var(--accent);color:var(--accent-ink);background:var(--tint)}
.d3spin{width:18px;height:18px;border:2px solid var(--line);border-top-color:var(--accent);border-radius:50%;animation:d3spin .9s linear infinite}
.d3queue{width:18px;height:18px;border:2px dashed var(--line);border-radius:50%}
@keyframes d3spin{to{transform:rotate(360deg)}}

.d3rfoot{display:flex;gap:12px;margin-top:16px;flex-wrap:wrap;align-items:center;padding-top:13px;border-top:1px solid var(--line-soft)}
.d3rfoot .note{font-size:12px;color:var(--muted);line-height:1.6;flex:1;min-width:200px}
.tbtn.big{padding:11px 20px;font-size:14px;border-radius:var(--r-sm)}

@media (max-width:1080px){
  .d3gal{grid-template-columns:minmax(0,1fr)}
  .d3elev{grid-template-columns:repeat(2,minmax(0,1fr))}
}
.d3srcpick{display:grid;gap:8px;margin-bottom:12px}
.d3srcpick label{display:flex;gap:10px;align-items:flex-start;border:1px solid var(--line);border-radius:var(--r-sm);padding:10px 12px;cursor:pointer;font-size:13px;color:var(--ink)}
.d3srcpick label:has(input:checked){border-color:var(--accent);background:var(--tint)}
.d3srcpick input{margin-top:4px}
.d3srcpick small{display:block;color:var(--muted);font-size:12px;margin-top:2px}
.d3json{background:var(--surf2);border:1px solid var(--line);border-radius:var(--r-sm);padding:12px;font-size:12px;max-height:50vh;overflow:auto;white-space:pre-wrap;word-break:break-all;color:var(--ink)}
/* ---- หน้าต่างดูภาพเต็ม ----
   ท่าที่ฝ่ายขายใช้จริงคือไล่ให้ลูกค้าดูทีละมุม — จึงต้องเลื่อนดูทั้งรอบได้ในหน้าต่างเดียว
   และภาพต้องพอดีจอเสมอ (ของเดิมสูง 1011px ในจอสูง 720px ต้องเลื่อนดูในกล่อง) */
.modal.lightbox{background:rgba(6,14,30,.86);padding:0;align-items:stretch;justify-content:stretch}
.lbsheet{display:flex;flex-direction:column;width:100%;height:100%;min-height:0}
.lbhead{display:flex;align-items:center;gap:12px;padding:12px 16px;color:var(--on-navy);flex:none}
.lbtitle{min-width:0}
.lbtitle b{display:block;font-size:15px;font-weight:700;line-height:1.3}
.lbtitle span{display:block;font-size:12px;color:var(--on-navy-3);letter-spacing:.4px}
.lbcount{margin-left:auto;font-size:12px;font-weight:700;color:var(--on-navy-2);background:rgba(255,255,255,.1);border-radius:999px;padding:4px 12px;font-variant-numeric:tabular-nums}
.lbhead .tbtn{background:rgba(255,255,255,.08);border-color:var(--hair-2);color:var(--on-navy)}
.lbhead .tbtn:hover{background:rgba(255,255,255,.16);border-color:rgba(255,255,255,.34)}
.lbstage{flex:1;min-height:0;display:flex;align-items:center;justify-content:center;gap:16px;padding:0 16px}
.lbstage img{max-width:100%;max-height:100%;object-fit:contain;border-radius:var(--r-md);background:var(--cv-bg);box-shadow:0 24px 60px rgba(0,0,0,.5)}
.lbnav{flex:none;width:46px;height:46px;border-radius:50%;display:flex;align-items:center;justify-content:center;background:rgba(255,255,255,.1);border:1px solid var(--hair-2);color:#fff;transition:background var(--t-fast)}
.lbnav:hover{background:rgba(255,255,255,.22)}
.lbnav:disabled{opacity:.25;cursor:default}
.lbnav svg{width:22px;height:22px;fill:none;stroke:currentColor;stroke-width:2.2;stroke-linecap:round;stroke-linejoin:round}
.lbthumbs{flex:none;display:flex;gap:8px;justify-content:center;flex-wrap:wrap;padding:14px 16px 18px}
.lbthumb{width:84px;height:56px;border-radius:var(--r-sm);overflow:hidden;border:2px solid transparent;background:rgba(255,255,255,.09);padding:0;opacity:.6;transition:opacity var(--t-fast),border-color var(--t-fast)}
.lbthumb img{width:100%;height:100%;object-fit:cover;display:block}
.lbthumb .ph{display:block;width:100%;height:100%}
.lbthumb:hover{opacity:1}
.lbthumb.on{opacity:1;border-color:var(--accent-on-navy)}
@media (max-width:640px){
  .lbthumbs{flex-wrap:nowrap;overflow-x:auto;justify-content:flex-start}
  .lbnav{width:38px;height:38px}
  .lbhead .tbtn .lbl{display:none}   /* เหลือไอคอนดาวน์โหลด ยังกดได้เหมือนเดิม */
  .lbhead{gap:8px;padding:10px 12px}
  .lbtitle b{font-size:14px}
}

/* ---- 3D: แถบเครื่องมือบรีฟ (รีดีไซน์ 2026-08-17) ----
   ปัญหาของแบบเดิม: ตัวเลือก 12 อย่างน้ำหนักเท่ากันหมดเรียงเป็นฟอร์มยาว ชิปตกบรรทัดกลุ่มละ 3 แถว
   จนแยกไม่ออกว่ากลุ่มไหนจบตรงไหน และปุ่มสร้างภาพจมอยู่ก้นฟอร์มต้องเลื่อนหา
   แบบใหม่ใช้หัวข้อพับได้ตัวเดียวกับสตูดิโอ 2D (.card.acc) — หัวข้อที่หุบยังโชว์ค่าที่เลือกไว้ที่ป้าย
   จึงเห็นบรีฟทั้งชุดโดยไม่ต้องกางอะไรเลย · การ์ดสรุปกับปุ่มหลักปักบนสุดตลอด */
.d3side{display:flex;flex-direction:column;gap:10px;min-width:0}
@media (min-width:1081px){
  .d3side{position:sticky;top:12px;max-height:calc(100vh - 24px);overflow-y:auto;overscroll-behavior:contain}
}

/* ---- พับแถบบรีฟบนจอกว้าง ----
   บรีฟกรอกครั้งเดียวแล้วดูภาพยาว ๆ — พับแล้วภาพได้ความกว้างคืนมาเกือบ 300px
   เหลือรางบางที่ยังกางกลับและกดสร้างภาพได้ ไม่ใช่ซ่อนหายไปทั้งแถบ */
.d3rail{display:none;flex-direction:column;align-items:center;gap:8px;background:var(--card);border:1px solid var(--line);border-radius:var(--r-lg);padding:10px 6px 14px;box-shadow:var(--e1)}
.railbtn{position:relative;width:36px;height:36px;flex:none;display:flex;align-items:center;justify-content:center;border:1px solid var(--line);border-radius:var(--r-sm);color:var(--muted);background:var(--card);transition:border-color var(--t-fast),background var(--t-fast),color var(--t-fast)}
.railbtn:hover{border-color:var(--accent);background:var(--tint);color:var(--accent-ink)}
.railbtn svg{width:18px;height:18px;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.railbtn.gen{background:var(--navy2);border-color:var(--navy2);color:#fff;font-size:15px}
.railbtn.gen:hover{background:var(--navy-hov);border-color:var(--navy-hov);color:#fff}
.d3rail.dirty .expand::after{content:'';position:absolute;top:-3px;right:-3px;width:9px;height:9px;border-radius:50%;background:var(--warn);border:2px solid var(--card)}
.rlabel{writing-mode:vertical-rl;font-size:12px;font-weight:700;letter-spacing:1.2px;color:var(--muted);margin-top:2px}
.d3collapse{width:26px;height:26px;flex:none;display:flex;align-items:center;justify-content:center;border:1px solid transparent;border-radius:var(--r-xs);color:var(--muted)}
.d3collapse:hover{border-color:var(--line);background:var(--surf2);color:var(--ink)}
.d3collapse svg{width:16px;height:16px;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}

@media (min-width:1081px){
  .d3wrap{transition:grid-template-columns .24s var(--ease)}
  .d3wrap.slim{grid-template-columns:56px minmax(0,1fr)}
  .d3wrap.slim .d3side{overflow:visible}
  .d3wrap.slim .d3side > .card,.d3wrap.slim .d3cpick,
  .d3wrap.slim .d3panelhead,.d3wrap.slim .d3panelfoot{display:none}
  .d3wrap.slim .d3rail{display:flex}
}

/* ---- จอแคบ: ภาพมาก่อน บรีฟเป็นลิ้นชัก ----
   ของเดิมแถบบรีฟสูง 1,500px กองอยู่เหนือแกลเลอรี ภาพแรกเริ่มที่ y≈1,750
   ซึ่งเป็นจอที่เอาไปเปิดให้ลูกค้าดูหน้างานพอดี */
.brieftoggle{display:none}
@media (max-width:1080px){
  .d3wrap{grid-template-columns:minmax(0,1fr)}
  .brieftoggle{display:block;margin-left:auto}
  .d3side{
    position:fixed;top:0;bottom:0;left:0;z-index:45;width:360px;max-width:90vw;
    background:var(--paper);border-right:1px solid var(--line);padding:12px;
    overflow-y:auto;overscroll-behavior:contain;transform:translateX(-102%);
    transition:transform var(--t-slow) var(--ease);box-shadow:0 0 44px var(--sh-lg)
  }
  .d3side.open{transform:none}
  body.drawer-open{overflow:hidden}
}
.d3side > .card{flex:none}
.d3side select,.d3side textarea{width:100%;border:1px solid var(--line);border-radius:var(--r-sm);padding:8px 10px;font-size:14px;background:var(--card);color:var(--ink)}
.d3side textarea{resize:vertical;min-height:70px}
.d3side .field{margin-bottom:12px}
.d3side .hint{margin-top:8px}
.d3side .lock{opacity:.5;pointer-events:none}
/* ป้ายค่าที่เลือกของหัวข้อที่หุบอยู่ — วางเป็นบรรทัดที่สองเต็มความกว้าง ไม่ใช่ป้ายเล็กข้างชื่อหัวข้อ
   เพราะค่าภาษาไทยยาวจริง ("ระแนงไม้ / ตกแต่งไม้ · กรอบดำ (อลูมิเนียม)") ถ้าบีบไว้ข้างชื่อจะโดนตัดด้วย …
   ซึ่งทำลายเหตุผลทั้งหมดของการโชว์ค่าไว้บนหัวข้อ · หัวข้อที่กางอยู่ซ่อนบรรทัดนี้ เพราะเห็นค่าจากตัวเลือกอยู่แล้ว */
.d3side .acchead{display:grid;grid-template-columns:1fr auto;column-gap:8px;row-gap:1px;align-items:center;padding:8px 13px}
.d3side .acctitle{grid-column:1;grid-row:1}
.d3side .accchev{grid-column:2;grid-row:1/-1;align-self:center}
.d3side .accbadge{grid-column:1;grid-row:2;justify-self:start;max-width:100%;background:none;border:0;padding:0;
  font-size:11px;font-weight:400;color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.d3side .accbadge b{font-weight:700;color:var(--accent-ink)}
.d3side .accbadge i{display:inline-block;width:9px;height:9px;border-radius:50%;border:1px solid rgba(0,0,0,.22);vertical-align:-1px;margin-right:3px}
.d3side .acc.open .accbadge{display:none}

/* ---- หัวแถบ (บนสุด) กับแถบสั่งงาน (ล่างสุด) ----
   ปักหัวไว้บนเพื่อให้ปุ่มพับอยู่ที่เดิมเสมอ และปักปุ่มไว้ล่างเพราะบรีฟกรอกจากบนลงล่าง
   ปุ่มควรรออยู่ปลายทาง ไม่ใช่มาขวางก่อนเนื้อหา */
.d3panelhead{position:sticky;top:0;z-index:4;display:flex;align-items:center;gap:8px;padding:2px 4px 9px;background:var(--paper);border-bottom:1px solid var(--line)}
.d3panelhead h3{margin:0;flex:1;min-width:0;font-size:12px;letter-spacing:1.5px;color:var(--muted);text-transform:uppercase}
.d3panelhead h3 b{color:var(--ink)}
.d3collapse,.d3drawerclose{width:30px;height:30px;flex:none;display:flex;align-items:center;justify-content:center;border:1px solid var(--line);border-radius:var(--r-sm);color:var(--muted);background:var(--card)}
.d3collapse:hover,.d3drawerclose:hover{border-color:var(--accent);background:var(--tint);color:var(--accent-ink)}
.d3collapse svg,.d3drawerclose svg{width:17px;height:17px;fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}
.d3panelhead .d3drawerclose{display:none}
@media (max-width:1080px){
  .d3panelhead .d3collapse{display:none}
  .d3panelhead .d3drawerclose{display:flex}
}

.d3panelfoot{position:sticky;bottom:0;z-index:4;margin-top:2px;padding:11px 12px;background:var(--card);border:1px solid var(--line);border-radius:var(--r-lg);box-shadow:0 -8px 20px -14px var(--sh-lg)}
.d3panelfoot .d3state{display:none}
.d3panelfoot.dirty .d3state,.d3panelfoot.locked .d3state{display:block;margin-bottom:8px}
.d3dirty{display:none;align-items:center;gap:6px;font-size:11px;font-weight:700;color:var(--warn);background:var(--warn-bg);border-radius:999px;padding:3px 10px 3px 8px}
.d3dirty::before{content:'';width:6px;height:6px;border-radius:50%;background:var(--warn)}
.d3panelfoot.dirty .d3dirty{display:inline-flex}
.d3lockchip{display:none;font-size:11px;font-weight:700;color:var(--ok);background:var(--ok-bg);border-radius:999px;padding:3px 10px;line-height:1.5}
.d3panelfoot.locked .d3lockchip{display:inline-block}
.d3panelfoot.locked .d3dirty{display:none}
.d3panelfoot .d3acts{margin-top:0}

/* หัวกลุ่มย่อยในการ์ดรวม รูปทรง/สี/วัสดุ — สามการ์ดเดิมถูกรวมเป็น dropdown เดียว (เจ้าของสั่ง 2026-08-21)
   เส้นประคั่นบอกว่าเปลี่ยนกลุ่มแล้ว แต่เบากว่าเส้นขอบการ์ด จะได้ไม่อ่านเป็นการ์ดซ้อนการ์ด */
.d3grouplabel{font-size:11px;font-weight:700;letter-spacing:.8px;color:var(--muted);margin:14px 0 9px;padding-top:12px;border-top:1px dashed var(--line)}
.d3grouplabel:first-child{margin-top:0;padding-top:0;border-top:0}
/* ป้ายสรุปของการ์ดรวมยาวกว่าการ์ดเดี่ยว — ยอมตกบรรทัดแทนตัดด้วย … (เหตุผลเดียวกับที่ย้ายป้ายลงบรรทัดสอง) */
.d3side .accbadge.wrap{white-space:normal;overflow:visible;text-overflow:clip;line-height:1.6}

/* ป้ายคั่นกลุ่ม — หน้า 3D เลิกใช้แล้ว (การ์ดชุดสไตล์ถูกตัด 2026-08-21) แต่หน้าคอนเท้นยังใช้อยู่ ห้ามลบ */
.d3seclabel{display:flex;align-items:center;gap:8px;margin:6px 2px -2px;font-size:11px;font-weight:700;letter-spacing:1.1px;text-transform:uppercase;color:var(--muted)}
.d3seclabel small{font-size:11px;font-weight:400;letter-spacing:0;text-transform:none;color:var(--muted);opacity:.8}
.d3seclabel::after{content:'';flex:1;height:1px;background:var(--line)}

/* (การ์ดชุดสไตล์ถูกตัดออกตามคำเจ้าของ 2026-08-21 — สไตล์ .d3presets/.d3preset ลบไปด้วย) */

/* ตัวเลือกข้อความแบบตาราง 2 ช่อง — ชื่อไทยยาวไม่เท่ากัน ถ้าปล่อยเป็น pill ตกบรรทัดเองจะอ่านเป็นก้อนเดียว */
.d3opts{display:grid;grid-template-columns:1fr 1fr;gap:6px}
.d3opt{border:1px solid var(--line);border-radius:var(--r-sm);padding:7px 9px;min-height:34px;font-size:12px;line-height:1.35;text-align:left;color:var(--ink);background:var(--card)}
.d3opt:hover{border-color:var(--accent);background:var(--tint)}
.d3opt.on{border-color:var(--accent);background:var(--tint);color:var(--accent-ink);font-weight:700;box-shadow:inset 0 0 0 1px var(--accent)}

/* จานสี — แผ่นสีใหญ่อ่านเร็วกว่าจุดเล็ก 13px ในชิป และ 9 สีลงได้ 2 แถวแทนที่จะตก 3 แถว */
.d3sw{display:grid;grid-template-columns:repeat(5,1fr);gap:8px}
.d3swb{padding:0;background:none;text-align:center}
.d3swb i{display:block;height:30px;border-radius:var(--r-xs);border:1px solid rgba(0,0,0,.2);box-shadow:inset 0 -7px 12px rgba(0,0,0,.08)}
.d3swb span{display:block;font-size:10px;line-height:1.25;color:var(--muted);margin-top:4px}
.d3swb:hover i{border-color:var(--accent)}
.d3swb.on i{box-shadow:inset 0 -7px 12px rgba(0,0,0,.08),0 0 0 2px var(--card),0 0 0 4px var(--accent)}
.d3swb.on span{color:var(--accent-ink);font-weight:700}

/* ช่อง "สีอื่น…" — ไอคอนวงล้อสีตอนยังไม่ได้เลือก · กลายเป็นสีจริง+ชื่อไทยเมื่อเลือกแล้ว */
.d3swb.cust i.rainbow{background:conic-gradient(#E5484D,#F5A524,#EFE156,#46A758,#29A7C3,#3E63DD,#B658C4,#E5484D)}
/* ⚠ ตัวเลือกต้องเจาะจงกว่า `.field input{width:100%}` ของฟอร์มกลาง (แผงนี้อยู่ใน .field)
   ไม่งั้นช่องสีจะถูกยืดเต็มแถวจนดันปุ่ม "ใช้สีนี้" หลุดออกนอกการ์ด แล้วโดน overflow:hidden
   ของหัวข้อพับตัดหายไปเลย — บั๊กจริงที่เจ้าของเจอ 2026-08-17 */
.d3cpick{display:flex;flex-wrap:wrap;gap:8px;align-items:center;margin-top:8px;padding:9px;border:1px solid var(--line);border-radius:var(--r-sm);background:var(--surf2)}
.d3cpick[hidden]{display:none}
/* input type=color คือปุ่มเปิดหน้าต่างเลือกสีของเบราว์เซอร์ (ไล่เฉด + hue + hex + หลอดดูดสี) — ขยายให้กดง่าย */
.d3cpick .d3cpick-native{flex:none;width:48px;height:48px;padding:2px;border:1px solid var(--line);border-radius:var(--r-sm);background:var(--card);cursor:pointer}
.d3cpick-mid{flex:1 1 120px;min-width:0;display:flex;flex-direction:column;gap:4px;justify-content:center}
.d3cpick .d3cpick-hex{width:100%;border:1px solid var(--line);border-radius:var(--r-xs);padding:6px 9px;font-size:13px;font-family:ui-monospace,Consolas,monospace;letter-spacing:.5px;background:var(--card);color:var(--ink);text-transform:uppercase}
.d3cpick .d3cpick-hex.bad{border-color:var(--bad);color:var(--bad)}
.d3cpick-nm{font-size:11px;color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* ปุ่มยืนยันลงบรรทัดใหม่เต็มความกว้าง — แถบข้างกว้างแค่ ~300 px และฝ่ายขายกดบนแท็บเล็ตด้วย */
.d3cpick .d3cpick-ok{flex:1 0 100%;text-align:center}

/* แถวข้อเท็จจริงที่แก้ไม่ได้ (เช่น จำนวนชั้นที่ยึดตามแปลน) — ต้องดูต่างจากช่องกรอกชัด ๆ
   ไม่งั้นฝ่ายขายจะพยายามกดแก้แล้วงงว่าทำไมกดไม่ได้ */
.d3fixed{display:flex;align-items:center;gap:6px;font-size:12px;color:var(--muted);background:var(--surf2);border:1px solid var(--line-soft);border-radius:var(--r-sm);padding:8px 10px}
.d3fixed b{color:var(--ink)}
.d3tile .cap .capr{display:inline-flex;align-items:center;gap:6px}
.d3tile .rbtn{border:1px solid var(--line);border-radius:var(--r-xs);width:24px;height:22px;font-size:13px;color:var(--muted);background:var(--card);line-height:1}
.d3tile .rbtn:hover{border-color:var(--accent);color:var(--accent);background:var(--tint)}

/* ---- 3D: ด่านตรวจแบบก่อนสร้าง (2026-08-17) ---- */
.pf-item{border-radius:var(--r-sm);padding:8px 12px;font-size:13px;margin-bottom:6px}
.pf-item.bad{background:var(--bad-bg);color:var(--bad)}
.pf-item.warn{background:var(--warn-bg);color:var(--warn)}
.pf-item.ok{background:var(--ok-bg);color:var(--ok)}
.pf-item.info{background:var(--surf2);color:var(--muted)}
.pf-sec{margin-top:12px}
.pf-h{font-size:12px;font-weight:700;letter-spacing:.6px;color:var(--muted);margin-bottom:8px;text-transform:uppercase}
.pf-guides{display:flex;gap:8px;flex-wrap:wrap}
.pf-guide{width:104px;margin:0}
.pf-guide .ph,.pf-guide img{width:104px;height:78px;object-fit:contain;background:#fff;border:1px solid var(--line);border-radius:var(--r-xs);display:flex;align-items:center;justify-content:center;cursor:zoom-in}
.pf-guide figcaption{font-size:11px;color:var(--muted);text-align:center;margin-top:4px}
.pf-sides{display:flex;flex-wrap:wrap;gap:6px;margin-top:6px}
.pf-side{font-size:12px;color:var(--ink);background:var(--surf2);border:1px solid var(--line-soft);border-radius:999px;padding:3px 10px}
.pf-sides{display:block;margin-top:6px}
.pf-side-row{display:flex;gap:10px;align-items:baseline;font-size:12px;padding:4px 0;border-top:1px solid var(--line-soft)}
.pf-side-row b{flex:0 0 62px;color:var(--ink)}
.pf-side-row span{color:var(--muted)}

/* ---------- ลายน้ำ: สวิตช์ในหน้าตั้งค่า + แถบเตือนเมื่อปิดอยู่ ----------
   ปิดลายน้ำคือการปลดการป้องกันงาน สถานะจึงต้องอ่านออกตั้งแต่แวบแรกและเตือนทุกหน้าที่ส่งไฟล์ออก */
.wmcard{background:var(--card);border:1px solid var(--line);border-radius:var(--r-lg);padding:16px 18px}
.wmcard.off{border-color:var(--warn-line);background:var(--warn-bg)}
.wmmain{display:flex;align-items:center;gap:16px}
.wmicon{font-size:26px;line-height:1;flex:none}
.wmtext{flex:1;min-width:0}
.wmtext b{display:block;font-size:15px;color:var(--ink)}
.wmtext span{display:block;font-size:13px;color:var(--muted);line-height:1.6;margin-top:2px}
.wmcard.off .wmtext b{color:var(--warn)}
.wmswitch{flex:none;width:56px;height:31px;border-radius:999px;background:var(--surf3);border:1px solid var(--line);padding:2px;display:flex;align-items:center;transition:background var(--t-base),border-color var(--t-base)}
.wmswitch .knob{width:25px;height:25px;border-radius:50%;background:var(--card);box-shadow:var(--e1);transition:transform var(--t-base)}
.wmswitch.on{background:var(--ok);border-color:var(--ok)}
.wmswitch.on .knob{transform:translateX(25px)}
.wmmeta{font-size:12px;color:var(--muted);margin-top:12px;padding-top:11px;border-top:1px solid var(--line-soft)}
.wmmeta b{color:var(--ink)}

.wmbanner{display:none;align-items:center;gap:10px;background:var(--warn-bg);border:1px solid var(--warn-line);border-radius:var(--r-sm);padding:9px 14px;font-size:13px;color:var(--warn);line-height:1.6;margin-bottom:12px}
.wmbanner.on{display:flex}
.wmbanner b{font-weight:700}

/* ---------- ศูนย์รวมระบบ (hub) ----------
   การ์ดหนึ่งใบ = โมดูลหนึ่งระบบ สร้างจาก registry ใน hub.js ล้วน ๆ
   เพิ่มระบบใหม่แล้วการ์ดต้องดูดีเองโดยไม่ต้องแตะไฟล์นี้ */
/* แถบต้อนรับ — พื้นกรมท่าไล่เฉด ให้หน้าแรกมีจุดยึดสายตาก่อนลงไปที่การ์ด */
.hub-hero{display:flex;align-items:center;gap:24px;flex-wrap:wrap;
  background:linear-gradient(125deg,#0F2138 0%,#1E3A5F 58%,#2A5488 100%);
  border-radius:var(--r-xl);padding:22px 26px;margin:6px 0 26px;color:var(--on-navy);
  box-shadow:var(--e3)}
.hero-main{flex:1;min-width:230px}
.hub-hero h1{font-size:22px;letter-spacing:.2px;color:var(--on-navy);font-weight:700}
.hub-hero h1 b{color:var(--accent-on-navy)}
.hub-hero p{font-size:13px;color:var(--on-navy-3);margin-top:4px;letter-spacing:.2px}
.hero-pulse{display:flex;gap:10px;flex-wrap:wrap}
.pulse{display:flex;flex-direction:column;gap:1px;min-width:96px;padding:10px 14px;border-radius:var(--r-md);
  background:rgba(255,255,255,.08);border:1px solid var(--hair-2);text-decoration:none;
  transition:background var(--t-fast),border-color var(--t-fast),transform var(--t-fast)}
.pulse:hover{background:rgba(255,255,255,.16);border-color:rgba(255,255,255,.34);transform:translateY(-1px)}
.pulse b{font-size:20px;font-weight:700;color:var(--on-navy);font-variant-numeric:tabular-nums;line-height:1.15}
.pulse span{font-size:11px;color:var(--on-navy-3);letter-spacing:.3px}
.pulse.live b{color:var(--accent-on-navy)}
.pulse.live::after{content:'';position:absolute}
@media (max-width:640px){
  .hub-hero{padding:18px;gap:16px}
  .hub-hero h1{font-size:20px}
  .hero-pulse{width:100%}
  .pulse{flex:1;min-width:0}
}
.hub-group{margin-bottom:24px}
.hub-glabel{display:flex;align-items:center;gap:10px;font-size:11px;font-weight:700;letter-spacing:1.2px;text-transform:uppercase;color:var(--muted);margin:0 2px 10px}
.hub-glabel::after{content:'';flex:1;height:1px;background:var(--line)}
.hub-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(305px,1fr));gap:16px}
.hubcard{position:relative;display:flex;flex-direction:column;gap:12px;background:var(--card);
  border:1px solid var(--line);border-radius:var(--r-xl);padding:18px;cursor:pointer;overflow:hidden;
  transition:border-color var(--t-base),box-shadow var(--t-base),transform var(--t-base)}
/* เส้นเน้นบางบนขอบบน โผล่ตอนชี้ — ให้การ์ดรู้สึก "มีชีวิต" โดยไม่ต้องใช้สีจัด */
.hubcard::before{content:'';position:absolute;inset:0 0 auto;height:3px;
  background:linear-gradient(90deg,var(--accent),var(--accent-on-navy));
  opacity:0;transition:opacity var(--t-base)}
.hubcard:hover::before{opacity:1}
.hubcard:hover{border-color:var(--accent);box-shadow:var(--e3);transform:translateY(-3px)}
.hubcard:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.hubcard.soon{cursor:default;border-style:dashed;background:transparent;opacity:.75}
.hubcard.soon:hover{border-color:var(--line);box-shadow:none;transform:none}
.hub-top{display:flex;gap:12px;align-items:flex-start}
.hubicon{width:44px;height:44px;border-radius:var(--r-md);background:var(--tint);color:var(--accent-ink);display:flex;align-items:center;justify-content:center;flex:none}
.hubicon svg{width:24px;height:24px;fill:none;stroke:currentColor;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}
.hubcard h3{font-size:15px;color:var(--ink);display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.hubcard .hdesc{font-size:13px;color:var(--muted);line-height:1.65;margin-top:4px}
.hubstats{font-size:12px;color:var(--muted);font-variant-numeric:tabular-nums;line-height:1.6;min-height:19px}
.hubstats b{color:var(--ink)}
.hubacts{display:flex;gap:8px;margin-top:auto}
.hubacts .tbtn{flex:1;display:flex;align-items:center;justify-content:center;text-decoration:none}
.soonchip{font-size:10px;font-weight:700;color:var(--warn);background:var(--warn-bg);border-radius:999px;padding:2px 9px}

/* ---------- ระบบสร้างภาพคอนเท้น ----------
   ซ้าย = บรีฟ + คลังรูปอ้างอิง · ขวา = ผลงานแต่ละครั้ง (ผ่าน/ไม่ผ่าน)
   ภาษาเดียวกับหน้า 3D — ผู้ใช้กลุ่มเดียวกัน ไม่ควรต้องเรียนรู้ใหม่ */
.cwrap{display:grid;grid-template-columns:360px minmax(0,1fr);gap:16px;align-items:start}
.cside{display:flex;flex-direction:column;gap:10px;min-width:0}
@media (min-width:1081px){
  .cside{position:sticky;top:12px;max-height:calc(100vh - 24px);overflow-y:auto;overscroll-behavior:contain}
}
.cside > .card{flex:none}
.cside input[type=text],.cside input:not([type]),.cside textarea,.cside select{
  width:100%;border:1px solid var(--line);border-radius:var(--r-sm);padding:8px 10px;font-size:14px;background:var(--card);color:var(--ink)}
.cside textarea{resize:vertical;min-height:52px}
.cside .field{margin-bottom:12px}
.cside .hint{margin-top:8px}
.cside .acchead{display:grid;grid-template-columns:1fr auto;column-gap:8px;row-gap:1px;align-items:center;padding:8px 13px}
.cside .acctitle{grid-column:1;grid-row:1}
.cside .accchev{grid-column:2;grid-row:1/-1;align-self:center}
.cside .accbadge{grid-column:1;grid-row:2;justify-self:start;max-width:100%;background:none;border:0;padding:0;
  font-size:11px;font-weight:400;color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.cside .accbadge b{font-weight:700;color:var(--accent-ink)}
.cside .accbadge i{display:inline-block;width:9px;height:9px;border-radius:50%;border:1px solid rgba(0,0,0,.22);vertical-align:-1px}
.cside .acc.open .accbadge{display:none}
.cpicked{font-weight:400;color:var(--accent-ink);font-size:11px;margin-left:6px}

/* ---- ตัวอย่างข้อความสด — เห็นของจริงก่อนจ่ายเครดิต ---- */
.tprev-head{display:flex;align-items:center;gap:6px;font-size:11px;font-weight:700;letter-spacing:.8px;text-transform:uppercase;color:var(--muted);margin-bottom:6px}
.tprev-head span{font-weight:400;letter-spacing:0;text-transform:none;color:var(--muted)}
.tprev{position:relative;width:100%;aspect-ratio:1/1;border-radius:var(--r-sm);overflow:hidden;background:var(--surf2);border:1px solid var(--line)}
.tprev-bg{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.tprev-text{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:4px;text-align:center;padding:10% 8%;
  text-shadow:0 1px 6px rgba(0,0,0,.45),0 0 2px rgba(0,0,0,.35)}
.tp-h{font-size:clamp(15px,7cqw,30px);font-weight:700;line-height:1.25}
.tp-d{font-size:clamp(11px,4.2cqw,17px);font-weight:700;opacity:.95}
.tp-b{font-size:clamp(10px,3.4cqw,14px);line-height:1.5;opacity:.92}
.tprev{container-type:inline-size}
.tprev-empty{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;text-align:center;padding:14px;font-size:12px;color:var(--muted)}
.tprev-empty.on-img{position:static;color:rgba(255,255,255,.85);text-shadow:0 1px 4px rgba(0,0,0,.6)}

/* คลังรูปอ้างอิง — แตะเลือก ติ๊กถูกมุมขวา */
.refgrid{display:grid;grid-template-columns:repeat(3,1fr);gap:8px}
.refgrid.lock{opacity:.55;pointer-events:none}
.refitem{position:relative;display:block;aspect-ratio:1/1;padding:0;border:2px solid var(--line);border-radius:var(--r-sm);overflow:hidden;background:var(--surf2);cursor:pointer}
.refitem img{width:100%;height:100%;object-fit:cover;display:block}
.refitem .tick{position:absolute;top:5px;right:5px;width:20px;height:20px;border-radius:50%;background:var(--accent);color:#fff;font-size:11px;font-weight:700;line-height:20px;text-align:center;opacity:0;transform:scale(.6);transition:opacity var(--t-fast),transform var(--t-fast)}
.refitem:hover{border-color:var(--accent)}
.refitem.on{border-color:var(--accent);box-shadow:0 0 0 2px var(--accent-fade)}
.refitem.on .tick{opacity:1;transform:none}
.refitem.nostate{cursor:default;width:64px;height:64px;aspect-ratio:auto;flex:none}
.pf-refs{display:flex;flex-wrap:wrap;gap:8px}

/* ผลงานแต่ละครั้ง */
.cattempt{background:var(--card);border:1px solid var(--line);border-radius:var(--r-lg);padding:14px 16px;margin-bottom:16px;box-shadow:var(--e1)}
.cattempt.picked{border-color:var(--ok);box-shadow:0 0 0 1px var(--ok)}
.cmedia{border:1px solid var(--line);border-radius:var(--r-md);overflow:hidden;background:var(--surf2)}
.cmedia img{display:block;width:100%;max-height:560px;object-fit:contain;background:var(--cv-bg);cursor:zoom-in}
.cmedia .ph{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px;min-height:220px;color:var(--muted);font-size:13px}
.cmedia .ph.fail{color:var(--bad)}

/* คลังรูปแบรนด์ (ADMIN) */
.brandchips{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:4px}
.brandchip{display:flex;align-items:center;gap:8px;border:1px solid var(--line);border-radius:999px;padding:7px 14px;font-size:13px;background:var(--card);color:var(--ink)}
.brandchip b{color:var(--accent-ink)}
.brandchip span{font-size:11px;color:var(--muted)}
.brandchip:hover{border-color:var(--accent)}
.brandchip.on{border-color:var(--accent);background:var(--tint);box-shadow:inset 0 0 0 1px var(--accent)}
.brandchip.off{opacity:.5}
.libgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(190px,1fr));gap:12px}
.libitem{background:var(--card);border:1px solid var(--line);border-radius:var(--r-md);overflow:hidden}
.libitem.off{opacity:.55}
.libitem img{width:100%;aspect-ratio:4/3;object-fit:cover;display:block;background:var(--surf2)}
.libtags{width:100%;border:none;border-top:1px solid var(--line-soft);padding:7px 10px;font-size:12px;background:var(--card);color:var(--ink)}
.libtags:focus{outline:none;background:var(--tint)}
.libfoot{display:flex;justify-content:space-between;align-items:center;gap:6px;padding:5px 10px 7px;border-top:1px solid var(--line-soft)}
.libfoot small{font-size:11px;color:var(--muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}

/* ---- ระบบคอนเท้น: รูปต้นแบบ (เพิ่มเติม — ห้ามแตะกฎของโมดูลเดิมด้านบน) ---- */
.refitem.tpl{border-color:var(--warn);box-shadow:0 0 0 2px rgba(201,162,39,.35)}
.refitem.tpl::after{content:'★ ต้นแบบ';position:absolute;left:0;right:0;bottom:0;background:rgba(138,110,20,.92);color:#fff;font-size:11px;font-weight:700;text-align:center;padding:2px 0}
.refitem.tpl .tick{opacity:0}
.cmode{display:flex;flex-direction:column;gap:6px}
.cmode button{display:block;width:100%;text-align:left;border:2px solid var(--line);border-radius:var(--r-sm);padding:8px 11px;background:var(--surf);cursor:pointer;transition:border-color var(--t-fast),background var(--t-fast)}
.cmode button b{display:block;font-size:13px;color:var(--ink)}
.cmode button small{display:block;font-size:11px;color:var(--muted);line-height:1.5;margin-top:2px}
.cmode button.on{border-color:var(--accent);background:var(--card);box-shadow:0 0 0 2px var(--accent-fade)}
.cmode button:disabled{opacity:.55;cursor:default}
.clogo{display:grid;grid-template-columns:repeat(3,1fr);gap:4px}
.clogo button{border:1.5px solid var(--line);border-radius:var(--r-xs);padding:6px 4px;font-size:12px;font-weight:700;color:var(--muted);background:var(--surf);cursor:pointer;transition:border-color .13s,color .13s,background .13s}
.clogo button.on{border-color:var(--accent);background:var(--card);color:var(--ink);box-shadow:0 0 0 1.5px var(--accent-fade)}
.clogo button:disabled{opacity:.5;cursor:default}
.libfilter{display:flex;gap:4px;flex-wrap:wrap;margin-bottom:8px}
.libfilter button{border:1px solid var(--line);border-radius:999px;padding:3px 11px;font-size:12px;font-weight:700;color:var(--muted);background:var(--surf)}
.libfilter button.on{border-color:var(--accent);color:var(--accent-ink);background:var(--accent-fade)}
.refitem .zoombtn{position:absolute;left:5px;bottom:5px;width:22px;height:22px;border-radius:var(--r-xs);background:rgba(10,22,40,.62);color:#fff;font-size:12px;line-height:22px;text-align:center;opacity:0;transition:opacity var(--t-fast)}
.refitem:hover .zoombtn{opacity:1}
.refitem.tpl .zoombtn{bottom:24px}
.attrchips{display:flex;gap:4px;flex-wrap:wrap;margin:0 0 8px}
.attrchip{display:inline-flex;align-items:center;gap:4px;border:1px solid var(--line);border-radius:999px;padding:2px 10px;font-size:11px;font-weight:700;color:var(--muted);background:var(--surf)}
.attrchip.good{border-color:var(--ok);color:var(--ok)}
.attrchip.warn{border-color:var(--warn);color:var(--warn)}
.bprofile{border:1px solid var(--line);border-radius:var(--r-md);background:var(--card);padding:12px 14px;margin:12px 0}
.bprofile .brow{display:flex;gap:10px;align-items:center;flex-wrap:wrap;margin-bottom:8px}
.bprofile img.blogo{height:44px;max-width:150px;object-fit:contain;background:var(--surf2);border:1px solid var(--line);border-radius:var(--r-xs);padding:4px}
.bprofile input[type=text]{border:1px solid var(--line);border-radius:var(--r-xs);padding:6px 9px;font-size:13px;min-width:200px;flex:1}
.libitem .librow{display:flex;gap:4px;margin-top:4px}
.libitem .librow select{border:1px solid var(--line);border-radius:var(--r-xs);font-size:12px;padding:3px 4px;background:var(--surf)}
.libitem .librow input{flex:1;min-width:0;border:1px solid var(--line);border-radius:var(--r-xs);font-size:12px;padding:3px 7px}
.usageline{font-size:12px;color:var(--muted);margin-left:auto}
.usageline b{color:var(--ink)}
.logopick{display:flex;gap:6px;flex-wrap:wrap;margin-top:8px}
.logopick .logoitem{display:flex;flex-direction:column;align-items:center;gap:4px;border:2px solid var(--line);border-radius:var(--r-sm);padding:6px 8px;background:var(--surf);cursor:pointer;max-width:110px}
.logopick .logoitem img{height:30px;max-width:90px;object-fit:contain}
.logopick .logoitem small{font-size:11px;color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:92px}
.logopick .logoitem.on{border-color:var(--accent);box-shadow:0 0 0 1.5px var(--accent-fade)}
.logopick .logoitem.on small{color:var(--accent-ink);font-weight:700}
.logoadmin{display:flex;gap:8px;flex-wrap:wrap}
.logoadm{border:1px solid var(--line);border-radius:var(--r-sm);padding:7px;background:var(--surf);width:150px;display:flex;flex-direction:column;gap:4px}
.logoadm.off{opacity:.55}
.logoadm img.blogo{height:38px;width:100%;object-fit:contain}
.logoadm input{border:1px solid var(--line);border-radius:var(--r-xs);font-size:12px;padding:3px 7px;width:100%}
/* ---- โหมดตกแต่ง + แก้เฉพาะจุด (ระบบคอนเท้น) ---- */
.lyr-sheet{max-width:980px;width:96vw}
.lyr-wrap{display:flex;gap:16px;align-items:stretch}
.lyr-stagebox{flex:1;min-width:0;display:flex;align-items:center;justify-content:center;background:var(--surf2);border:1px solid var(--line);border-radius:var(--r-md);padding:8px;max-height:70vh;overflow:auto;position:relative}
.lyr-stage{position:relative;line-height:0}
.lyr-stage img.base{max-width:100%;max-height:64vh;display:block;user-select:none;-webkit-user-drag:none}
.lyr-node{position:absolute;transform:translate(-50%,-50%);cursor:grab;user-select:none;touch-action:none}
.lyr-node img{width:100%;display:block;pointer-events:none}
.lyr-node.sel{outline:2px dashed var(--accent);outline-offset:3px}
.lyr-node .txt{white-space:nowrap;font-weight:400;line-height:1.2;pointer-events:none}
.lyr-node .txt.pill{padding:.32em .7em;border-radius:999px}
.lyr-side{width:250px;flex:none;display:flex;flex-direction:column;gap:8px}
.lyr-add{display:flex;gap:4px;flex-wrap:wrap}
.lyr-pick{display:grid;grid-template-columns:repeat(3,1fr);gap:6px;max-height:180px;overflow:auto;border:1px solid var(--line);border-radius:var(--r-sm);padding:6px;background:var(--surf)}
.lyr-pick button{border:1.5px solid var(--line);border-radius:var(--r-xs);background:var(--card);padding:5px;cursor:pointer}
.lyr-pick button img{width:100%;height:38px;object-fit:contain;display:block}
.lyr-pick button small{display:block;font-size:10px;color:var(--muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.lyr-props{border:1px solid var(--line);border-radius:var(--r-sm);padding:9px;background:var(--surf);display:flex;flex-direction:column;gap:8px;font-size:12px}
.lyr-props label{font-size:11px;font-weight:700;color:var(--muted)}
.lyr-props input[type=text],.lyr-props select{width:100%;border:1px solid var(--line);border-radius:var(--r-xs);padding:5px 8px;font-size:13px}
.lyr-props input[type=range]{width:100%}
.lyr-colors{display:flex;gap:4px;flex-wrap:wrap}
.lyr-colors button{width:22px;height:22px;border-radius:var(--r-xs);border:1.5px solid var(--line);cursor:pointer}
.lyr-colors button.on{outline:2px solid var(--accent);outline-offset:1px}
.lyr-foot{margin-top:auto}
.rp-stagebox{cursor:crosshair}
#rpImage,#rpPaint{max-width:100%;max-height:64vh;display:block}
#rpPaint{position:absolute;inset:8px auto auto 8px}
.rptools{display:flex;gap:4px}
.rptools .tbtn.on{border-color:var(--accent);color:var(--accent-ink);background:var(--accent-fade)}
.lyr-guide{position:absolute;background:rgba(214,69,69,.75);pointer-events:none;z-index:5}
.lyr-guide.v{width:1px;top:0;bottom:0}
.lyr-guide.hz{height:1px;left:0;right:0}
.cmpbox{position:relative}
.cmpbox #imgPrev{position:absolute;inset:0;width:100%;border-radius:var(--r-sm);border:1px solid var(--line);clip-path:inset(0 100% 0 0)}
.cmpbar{display:flex;align-items:center;gap:10px;margin-top:8px}
.cmpbar input{flex:1}
.sk-area{border:2px dashed #1F7A3D;background:rgba(31,122,61,.12);color:#1F7A3D;font-size:12px;font-weight:700;display:flex;align-items:center;justify-content:center;text-align:center;border-radius:var(--r-xs);padding:4px}

/* ---------- ระบบคอนเท้น: การ์ดผลงาน (รีดีไซน์) ----------
   เดิมทุกการ์ดมี 6 ปุ่มน้ำหนักเท่ากัน จังหวะตัดสินใจ "ผ่าน/ไม่ผ่าน" เลยจมไปกับเครื่องมือช่าง
   ตอนนี้เหลือ 2 ปุ่มหลัก + เมนู ⋯ และการ์ดเก่าหุบเหลือแถบเดียว */
.cattempt.folded .cbody{display:none}
.cattempt.folded{padding-bottom:10px;opacity:.92}
.cattempt.folded .d3rhead{margin-bottom:0;padding-bottom:0;border-bottom:0;cursor:pointer;border-radius:var(--r-sm);padding:4px 6px;margin:-4px -6px}
.cattempt.folded .d3rhead:hover{background:var(--surf2)}
.cattempt .unfold{font-size:12px;font-weight:700;color:var(--accent-ink);white-space:nowrap}
.cattempt.picked .d3rhead b{color:var(--ok)}

.cmenu{position:relative}
.cmenu-pop{position:absolute;right:0;bottom:calc(100% + 6px);z-index:20;min-width:262px;display:none;flex-direction:column;gap:2px;
  background:var(--card);border:1px solid var(--line);border-radius:var(--r-md);padding:6px;box-shadow:var(--e3)}
.cmenu.on .cmenu-pop{display:flex}
.cmenu-pop button{display:block;width:100%;text-align:left;border-radius:var(--r-xs);padding:8px 10px;font-size:13px;font-weight:700;color:var(--ink)}
.cmenu-pop button:hover{background:var(--tint);color:var(--accent-ink)}
.cmenu-pop small{display:block;font-size:11px;font-weight:400;color:var(--muted);margin-top:1px;line-height:1.45}

/* ภาพจัตุรัสไม่ต้องกินกล่องกว้างเต็มการ์ด — บีบกล่องตามสัดส่วนภาพจริง */
.cmedia img{margin:0 auto}

/* ---------- จอแคบ: ภาพมาก่อน บรีฟเป็นลิ้นชัก (ท่าเดียวกับหน้า 3D) ---------- */
@media (max-width:1080px){
  .cwrap{grid-template-columns:minmax(0,1fr)}
  .cside{
    position:fixed;top:0;bottom:0;left:0;z-index:45;width:370px;max-width:92vw;
    background:var(--paper);border-right:1px solid var(--line);padding:12px;
    overflow-y:auto;overscroll-behavior:contain;transform:translateX(-102%);
    transition:transform var(--t-slow) var(--ease);box-shadow:var(--e4);order:0;max-height:none
  }
  .cside.open{transform:none}
  #attemptsBox{order:1}
}
@media (min-width:1081px){ .cwrap .brieftoggle{display:none} }

/* พับแถบบรีฟของหน้าคอนเท้นเหลือรางบาง — กติกาเดียวกับหน้า 3D */
@media (min-width:1081px){
  .cwrap.slim{grid-template-columns:56px minmax(0,1fr)}
  .cwrap.slim .cside{overflow:visible}
  .cwrap.slim .cside > .card,.cwrap.slim .cside > .d3seclabel,
  .cwrap.slim .d3panelhead,.cwrap.slim .d3panelfoot{display:none}
  .cwrap.slim .d3rail{display:flex}
}

/* คลังรูปในแถบบรีฟมีได้หลายสิบใบ — จำกัดความสูงแล้วเลื่อนในตัวเอง
   ไม่งั้นหัวข้ออื่นถูกดันลงไปไกลจนต้องเลื่อนทั้งแถบเหมือนเดิม */
.cside .refgrid{max-height:270px;overflow-y:auto;overscroll-behavior:contain;padding-right:3px}
.cside .libfilter{margin-bottom:8px}

/* ---------- ตารางที่พลิกเป็นการ์ดบนมือถือ ----------
   เดิมตารางแปลน 9 คอลัมน์กว้าง 802px ดันทั้งหน้าให้เลื่อนไปทางข้างบนจอ 375px
   แก้ด้วยการพลิกเป็นการ์ดต่อแถว โดยดึงชื่อช่องจาก data-label — DOM ชุดเดียว ไม่มีทางเพี้ยนกัน */
@media (max-width:640px){
  .plantable{border:0;background:none;display:block}
  .plantable thead{display:none}
  .plantable tbody{display:block}
  .plantable tr{display:block;background:var(--card);border:1px solid var(--line);border-radius:var(--r-lg);
    padding:12px 14px;margin-bottom:10px;box-shadow:var(--e1)}
  .plantable tr:hover{border-color:var(--accent)}
  .plantable td{display:flex;align-items:center;justify-content:space-between;gap:12px;
    border:0;padding:5px 0;font-size:13px;text-align:right}
  .plantable td::before{content:attr(data-label);flex:none;color:var(--muted);font-size:12px;
    font-weight:700;letter-spacing:.3px;text-align:left}
  .plantable td:empty,.plantable td[data-label=""]::before{display:none}
  .plantable td.job{font-size:15px;font-weight:700;color:var(--accent-ink);
    padding-bottom:9px;margin-bottom:4px;border-bottom:1px solid var(--line-soft)}
  .plantable td.num{font-variant-numeric:tabular-nums}
  .plantable td.rowacts{display:flex;gap:8px;justify-content:stretch;padding-top:11px;margin-top:4px;
    border-top:1px solid var(--line-soft)}
  .plantable td.rowacts .tbtn{flex:1;min-height:40px}
}

/* ---------- ตัวเลือกแปลนบนหน้าหลัก ---------- */
.picklist{max-height:52vh;overflow-y:auto;overscroll-behavior:contain;display:flex;flex-direction:column;gap:6px}
.pickrow{display:grid;grid-template-columns:auto 1fr auto auto;align-items:center;gap:10px;
  padding:10px 12px;border:1px solid var(--line);border-radius:var(--r-sm);background:var(--card);
  text-decoration:none;color:inherit;transition:border-color var(--t-fast),background var(--t-fast)}
.pickrow:hover{border-color:var(--accent);background:var(--tint)}
.pk-code{font-size:13px;font-weight:700;color:var(--accent-ink);letter-spacing:.3px;white-space:nowrap}
.pk-name{font-size:14px;color:var(--ink);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pk-area{font-size:12px;color:var(--muted);font-variant-numeric:tabular-nums;white-space:nowrap}
@media (max-width:640px){
  .pickrow{grid-template-columns:1fr auto;row-gap:4px}
  .pk-name{grid-column:1/-1}
  .picklist{max-height:60vh}
}

/* ==========================================================================
   ชั้นรายละเอียด — สิ่งที่ทำให้ระบบ "รู้สึกมีชีวิต" ไม่ใช่แค่ทำงานได้
   ทุกอย่างในบล็อกนี้ปิดตัวเองอัตโนมัติเมื่อผู้ใช้ตั้งเครื่องว่าไม่ชอบภาพเคลื่อนไหว
   (กฎ prefers-reduced-motion อยู่บนสุดของไฟล์)
   ========================================================================== */

/* ---- ปุ่ม: กดแล้วต้องรู้สึกว่ากดติด ---- */
.tbtn,.btn-primary,.wf-btn,.dbtn,.seg,.iconbtn,.hubcard,.pickrow,.pulse{
  transition:background var(--t-fast) var(--ease),border-color var(--t-fast) var(--ease),
             color var(--t-fast) var(--ease),box-shadow var(--t-base) var(--ease),
             transform var(--t-fast) var(--ease)}
.tbtn:active:not(:disabled),.btn-primary:active:not(:disabled),
.wf-btn:active:not(:disabled),.dbtn:active:not(:disabled),.iconbtn:active{transform:translateY(1px) scale(.985)}
.hubcard:active{transform:translateY(-1px) scale(.995)}
.pickrow:active{transform:scale(.995)}

/* ---- โฟกัสที่ออกแบบมา ไม่ใช่กรอบเริ่มต้นของเบราว์เซอร์ ----
   วงแหวนนุ่ม 3px + เว้นระยะ อ่านออกทั้งสองธีมและไม่บังเนื้อหา */
:where(button,a,input,select,textarea,[tabindex]):focus-visible{
  outline:2px solid var(--accent);outline-offset:2px;
  box-shadow:0 0 0 5px var(--accent-fade);border-radius:var(--r-xs)}
.hubcard:focus-visible,.pickrow:focus-visible{outline-offset:3px}

/* ---- โครงร่างระหว่างโหลด (skeleton) — บอกรูปร่างของสิ่งที่กำลังมา
   ดีกว่าวงหมุนเปล่า ๆ เพราะสายตาเตรียมที่ไว้รอได้ ---- */
.sk{position:relative;overflow:hidden;background:var(--surf2);border-radius:var(--r-sm)}
.sk::after{content:'';position:absolute;inset:0;transform:translateX(-100%);
  background:linear-gradient(90deg,transparent,rgba(255,255,255,.42),transparent);
  animation:sk-slide 1.35s infinite}
:root[data-theme="dark"] .sk::after{background:linear-gradient(90deg,transparent,rgba(255,255,255,.07),transparent)}
@keyframes sk-slide{100%{transform:translateX(100%)}}
.sk-line{height:11px;margin-bottom:8px}
.sk-line.w60{width:60%}.sk-line.w40{width:40%}.sk-line.w80{width:80%}
.sk-card{height:150px;border-radius:var(--r-lg)}

/* ---- หน้าต่าง: เข้าอย่างมีทิศทาง ไม่ใช่กระพริบโผล่ ---- */
.modal{opacity:0;transition:opacity var(--t-base) var(--ease)}
.modal.on{opacity:1}
.modal .sheet,.modal .lbsheet{transform:translateY(10px) scale(.985);opacity:0;
  transition:transform var(--t-slow) var(--ease-out),opacity var(--t-base) var(--ease)}
.modal.on .sheet,.modal.on .lbsheet{transform:none;opacity:1}
.modal .sheet{box-shadow:var(--e4)}

/* ---- การ์ดในรายการ: ไล่โผล่ทีละใบเล็กน้อย ให้สายตาไล่ตามได้ ---- */
@keyframes rise{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}
.hdgrid > *,.hub-grid > *{animation:rise var(--t-slow) var(--ease-out) both}
.hub-grid > *:nth-child(2){animation-delay:40ms}
.hub-grid > *:nth-child(3){animation-delay:80ms}
.hub-grid > *:nth-child(4){animation-delay:120ms}
.hdgrid > *:nth-child(2){animation-delay:30ms}
.hdgrid > *:nth-child(3){animation-delay:60ms}
.hdgrid > *:nth-child(4){animation-delay:90ms}
.hdgrid > *:nth-child(n+5){animation-delay:120ms}

/* ---- ตัวเลขที่เปลี่ยนค่า: ต้องไม่ขยับตำแหน่งหลัก ---- */
.mvalue,.pulse b,.hubstats,.pk-area,.wfp-text b,.tmv{font-variant-numeric:tabular-nums}

/* ---- แถบเลื่อนในแผงข้าง: บางลง ไม่แย่งสายตาจากเนื้อหา ---- */
.cside,.d3side,.side,.picklist,.refgrid{scrollbar-width:thin;scrollbar-color:var(--sb) transparent}
.cside::-webkit-scrollbar,.d3side::-webkit-scrollbar,.side::-webkit-scrollbar,
.picklist::-webkit-scrollbar,.refgrid::-webkit-scrollbar{width:9px}
.cside::-webkit-scrollbar-thumb,.d3side::-webkit-scrollbar-thumb,.side::-webkit-scrollbar-thumb,
.picklist::-webkit-scrollbar-thumb,.refgrid::-webkit-scrollbar-thumb{
  background:var(--sb);border-radius:var(--r-pill);border:2px solid transparent;background-clip:content-box}

/* ==========================================================================
   ธีมมืด — ปรับรายองค์ประกอบ
   token สีครอบได้เกือบทั้งหมดแล้ว เหลือกรณีที่ "สลับค่าสีเฉย ๆ ไม่พอ"
   เพราะตัวองค์ประกอบเองตั้งสมมติฐานว่าพื้นหลังเป็นสีขาว
   ========================================================================== */

/* จุดสีในหัวข้อที่พับอยู่ ใช้ขอบสีดำจาง — บนพื้นมืดขอบหายสนิท จุดเลยลอยไม่มีรูปทรง */
:root[data-theme="dark"] .d3side .accbadge i,
:root[data-theme="dark"] .cside .accbadge i{border-color:rgba(255,255,255,.28)}

/* ภาพลายเส้น (แบบ guide) ต้องคงพื้นขาวไว้ถึงจะอ่านเส้นออก
   แต่แผ่นขาวล้วนบนหน้าจอมืดจะแยงตา — หรี่ลงนิดแล้วคืนความสว่างเต็มตอนชี้ */
:root[data-theme="dark"] .pf-guide img{filter:brightness(.9);transition:filter var(--t-base) var(--ease)}
:root[data-theme="dark"] .pf-guide img:hover{filter:none}

/* โลโก้แบรนด์เป็นไฟล์หมึกเข้มพื้นใส — วางบนการ์ดมืดแล้วมองไม่เห็น
   จึงรองแผ่นสว่างไว้ใต้โลโก้เฉพาะธีมมืด */
:root[data-theme="dark"] .logopick .logoitem img{
  background:rgba(255,255,255,.9);border-radius:4px;padding:2px 4px}

/* ภาพในไลบรารีมักถ่ายมาสว่างจัด — หรี่ลงเล็กน้อยให้เข้ากับหน้า แล้วคืนเต็มตอนชี้ */
:root[data-theme="dark"] .libitem img,
:root[data-theme="dark"] .refitem img,
:root[data-theme="dark"] .hdcard .thumb img{
  filter:brightness(.93);transition:filter var(--t-base) var(--ease)}
:root[data-theme="dark"] .libitem:hover img,
:root[data-theme="dark"] .refitem:hover img,
:root[data-theme="dark"] .hdcard:hover .thumb img{filter:none}

/* พื้นหลังหน้า: ธีมมืดล้วนแบนราบ เติมไล่สีจาง ๆ ให้มีความลึก */
:root[data-theme="dark"] body{
  background-image:radial-gradient(1200px 600px at 50% -10%,rgba(74,147,220,.07),transparent 70%);
  background-attachment:fixed}

/* การ์ดตอนพักต้องมีน้ำหนักอยู่แล้ว ไม่ใช่แบนสนิทแล้วกระโดดขึ้นตอนชี้
   ลำดับชั้น: พัก e1 → ชี้ e3 (ยกตัวจริง) → กด e2 (ยุบกลับ) */
.hubcard,.hdcard,.libitem,.dockchip{box-shadow:var(--e1)}
.hubcard.soon{box-shadow:none}
.hdcard:hover,.libitem:hover{box-shadow:var(--e3);border-color:var(--accent-line)}
.hubcard:active,.hdcard:active{box-shadow:var(--e2)}

/* ==========================================================================
   ชั้น "มีชีวิต" — จังหวะที่ทำให้ระบบรู้สึกตอบสนอง ไม่ใช่แค่เปลี่ยนภาพทันที
   ทุกกฎในบล็อกนี้ถูกกฎลดการเคลื่อนไหวปิดทับได้เสมอ
   ========================================================================== */

/* ---- ข้อความแจ้งเตือน: เลื่อนเข้ามาจากขวาแบบมีแรงหน่วง แล้วค่อยจางออก ---- */
@keyframes toast-in{
  from{opacity:0;transform:translateX(28px) scale(.96)}
  to{opacity:1;transform:none}}
.toast{animation:toast-in var(--t-slow) var(--ease-out) both;box-shadow:var(--e3)}
.toast.leaving{opacity:0;transform:translateX(28px) scale(.96);
  transition:opacity var(--t-base) var(--ease),transform var(--t-base) var(--ease)}

/* ---- เนื้อในหัวข้อที่กางออก: ไม่โผล่พรึบพร้อมกรอบ แต่จางเข้าตามหลังนิดหนึ่ง ---- */
.accbody > *{opacity:0;transition:opacity var(--t-base) var(--ease) 60ms}
.acc.open .accbody > *{opacity:1}

/* ---- ปุ่มบันทึกตอนสำเร็จ: ยืนยันด้วยสีเขียวสั้น ๆ แล้วคืนสภาพเดิม
        ผู้ใช้ต้องเห็นว่า "ติดแล้ว" โดยไม่ต้องอ่านข้อความ ---- */
@keyframes ok-flash{
  0%{transform:scale(1)}
  35%{transform:scale(1.04)}
  100%{transform:scale(1)}}
.dbtn.saved,.tbtn.saved{background:var(--ok-bg)!important;border-color:var(--ok-line-strong)!important;
  color:var(--ok)!important;animation:ok-flash var(--t-slow) var(--ease-out)}

/* ---- ตัวเลขในแถบสรุปที่เพิ่งเปลี่ยนค่า: กะพริบเน้นหนึ่งครั้ง
        ไม่งั้นราคาขยับแล้วผู้ใช้ไม่ทันเห็นว่าอะไรเปลี่ยน ---- */
@keyframes val-bump{
  0%{transform:translateY(0);color:var(--ink)}
  30%{transform:translateY(-2px);color:var(--accent)}
  100%{transform:translateY(0)}}
.mvalue.changed,.q-price.changed{animation:val-bump 520ms var(--ease-out)}

/* ---- หน้าเปิด: เนื้อหาหลักไล่เข้าเบา ๆ กันความรู้สึก "กระตุกเข้ามาทั้งหน้า" ---- */
@keyframes page-in{from{opacity:0;transform:translateY(4px)}to{opacity:1;transform:none}}
main{animation:page-in var(--t-slow) var(--ease-out) both}

/* ---- แถบข้างตอนกาง/พับ: ให้เนื้อหาข้างในตามมาทีหลังโครง ---- */
.side,.cside,.d3side{transition:width var(--t-slow) var(--ease),transform var(--t-slow) var(--ease)}

/* ---- ปุ่มที่กำลังทำงานอยู่: แถบวิ่งบาง ๆ ใต้ปุ่ม บอกว่ายังไม่ค้าง ---- */
@keyframes busy-sweep{from{transform:translateX(-100%)}to{transform:translateX(300%)}}
.tbtn[aria-busy="true"],.dbtn[aria-busy="true"],.btn-primary[aria-busy="true"]{position:relative;overflow:hidden}
.tbtn[aria-busy="true"]::after,.dbtn[aria-busy="true"]::after,.btn-primary[aria-busy="true"]::after{
  content:'';position:absolute;left:0;bottom:0;height:2px;width:33%;
  background:currentColor;opacity:.7;animation:busy-sweep 1.1s infinite var(--ease)}

/* ==========================================================================
   หน้าเข้าสู่ระบบ — ภาพผลงานเต็มจอ + การ์ดกระจกลอยอยู่กลาง
   หน้านี้ตรึงเป็นโทนมืดเสมอ ไม่ตามปุ่มสลับธีม เพราะการ์ดวางบนภาพถ่าย
   ถ้าปล่อยให้สลับเป็นพื้นสว่างจะอ่านตัวหนังสือบนภาพไม่ออก
   ========================================================================== */
.lg-body{margin:0;background:#0A1626;color:#fff;overflow:hidden}
.lg{position:relative;min-height:100dvh;display:grid;place-items:center;
  padding:24px max(24px,env(safe-area-inset-right)) 24px max(24px,env(safe-area-inset-left))}

/* ---- ชั้นภาพพื้นหลัง ----
   ฉากไล่สีข้างล่างคือภาพสำรอง วาดด้วย CSS ล้วน ใช้โทนแสงเย็นเดียวกับภาพจริง
   ถ้าไฟล์ภาพยังไม่มีหรือโหลดไม่ทัน หน้ายังดูสมบูรณ์และอ่านออกทันที */
.lg-bg{position:fixed;inset:0;z-index:0;overflow:hidden;
  background:
    radial-gradient(120% 90% at 88% 78%,rgba(255,190,110,.85),transparent 55%),
    radial-gradient(90% 70% at 70% 88%,rgba(255,148,74,.45),transparent 60%),
    linear-gradient(190deg,#0E4C8A 0%,#1E6FB0 32%,#63A6CE 58%,#D9A45E 82%,#8A5A2B 100%)}
.lg-photo{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  object-position:62% 60%;            /* ตัวบ้านอยู่ค่อนขวา-ล่าง — จอแนวตั้งให้ครอบฟ้าทิ้งก่อน ไม่ครอบบ้าน */
  animation:lg-settle 1.5s var(--ease-out) both}
@keyframes lg-settle{from{opacity:0;transform:scale(1.05)}to{opacity:1;transform:none}}

/* ผ้าคลุมไล่สี — รับประกันว่าตัวหนังสือบนการ์ดอ่านออกเสมอ
   ไม่ว่าภาพตรงนั้นจะเป็นท้องฟ้าสว่างหรือแสงอาทิตย์จ้า */
.lg-scrim{position:absolute;inset:0;
  background:linear-gradient(180deg,rgba(4,12,26,.16),transparent 40%,rgba(4,12,26,.22))}

/* ---- การ์ดกระจก ----
   มุมคมตามภาษาแบบของงานสถาปัตย์ ไม่ใช้มุมมนใหญ่เหมือนการ์ดในระบบหลัก */
.lg-card{position:relative;z-index:1;width:100%;max-width:460px;
  padding:38px 36px 40px;border-radius:3px;
  background:linear-gradient(165deg,rgba(255,255,255,.10),rgba(255,255,255,.03));
  border:1px solid rgba(255,255,255,.55);overflow:hidden;
  box-shadow:0 44px 100px -34px rgba(0,0,0,.6),inset 0 1px 0 rgba(255,255,255,.22);
  backdrop-filter:blur(26px) saturate(1.2);-webkit-backdrop-filter:blur(26px) saturate(1.2);
  animation:lg-in 700ms var(--ease-out) both 120ms}
@keyframes lg-in{from{opacity:0;transform:translateY(16px)}to{opacity:1;transform:none}}
/* เบราว์เซอร์ที่เบลอพื้นหลังไม่ได้ ต้องทึบขึ้นแทน ไม่งั้นภาพทะลุขึ้นมาจนอ่านไม่ออก */
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  .lg-card{background:rgba(9,22,40,.82)}
}

/* แสงสะท้อนบนผิวกระจก — แถบสว่างเฉียงมุมบนซ้าย ค่อย ๆ จางหายราวหนึ่งในสามของการ์ด
   ตามภาพบรีฟ ให้ความรู้สึกว่าเป็นแผ่นกระจกจริง ไม่ใช่สี่เหลี่ยมโปร่งแสงเฉย ๆ */
.lg-card::before{content:'';position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(118deg,rgba(255,255,255,.30),rgba(255,255,255,.10) 18%,transparent 38%)}

.lg-mark{display:block;height:154px;width:auto;max-width:100%;margin:0 auto 16px;object-fit:contain;
  filter:drop-shadow(0 2px 10px rgba(0,0,0,.45))}
/* DB Adman X ตัว Latin แคบมาก — ต้องใช้ขนาดใหญ่กว่าฟอนต์ทั่วไปถึงจะกินความกว้าง
   การ์ดราว 85% แบบบรีฟ (วัดจากตัวอักษรจริงด้วย Range ไม่ใช่กล่อง h1) */
.lg-name{margin:0;text-align:center;color:#fff;font-size:45px;font-weight:400;
  letter-spacing:2.4px;line-height:1.15;white-space:nowrap}
.lg-tag{margin:12px 0 52px;text-align:center;color:rgba(255,255,255,.88);
  font-size:13px;line-height:1.7;letter-spacing:.2px}

/* ---- ช่องกรอกแบบป้ายลอย ----
   ตอนว่าง ป้ายนั่งกลางช่องดูเหมือนข้อความตัวอย่าง พอเริ่มพิมพ์ป้ายลอยขึ้นไปด้านบน
   ได้หน้าตาสะอาดเท่าการใช้ placeholder แต่ป้ายไม่หายไปตอนมีข้อความแล้ว */
.lg-field{position:relative;margin-bottom:15px;padding-top:22px}
.lg-field input{width:100%;height:52px;padding:0 22px;border-radius:999px;
  background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.55);
  color:#fff;font-size:15px;line-height:52px;
  transition:border-color var(--t-base) var(--ease),background var(--t-base) var(--ease),
             box-shadow var(--t-base) var(--ease)}
#password{padding-right:52px}
.lg-field input:hover{border-color:rgba(255,255,255,.58)}
.lg-field input:focus{outline:none;background:rgba(255,255,255,.16);
  border-color:#fff;box-shadow:0 0 0 4px rgba(255,255,255,.16)}
.lg-field label{position:absolute;left:22px;top:calc(50% + 11px);transform:translateY(-50%);
  color:rgba(255,255,255,.72);font-size:15px;pointer-events:none;
  transition:transform var(--t-base) var(--ease-out),font-size var(--t-base) var(--ease-out),
             color var(--t-base) var(--ease),letter-spacing var(--t-base) var(--ease)}
.lg-field input:focus + label,
.lg-field input:not(:placeholder-shown) + label{
  transform:translateY(calc(-50% - 38px));font-size:12px;font-weight:700;
  letter-spacing:.8px;color:rgba(255,255,255,.95)}

/* ช่องที่โปรแกรมจำรหัสผ่านเติมให้ — Chrome ยัดพื้นฟ้าอ่อนกับตัวหนังสือสีเข้มมาเอง
   บนการ์ดมืดจะอ่านไม่ออกเลย ต้องบังคับกลับด้วยเงาด้านในและสีตัวอักษรที่เติมทับได้ */
/* ตอน Chrome เติมรหัสให้เอง มันทาพื้นสว่างทับช่อง ทำให้ตัวหนังสือขาวจมหาย
   ลูกเล่นหน่วง transition เอาไม่อยู่กับบางเวอร์ชัน — ใช้วิธีเด็ดขาดกว่า:
   background-clip:text จำกัดพื้นของ Chrome ให้เหลือแค่ในเนื้อตัวอักษร (มองไม่เห็น)
   แล้วคืนสีจาง ๆ ของช่องด้วยเงาด้านในแทน เพราะเงาไม่ใช่ background จึงไม่ถูกตัดไปด้วย
   ผลคือช่องที่ถูกเติมให้กับช่องที่พิมพ์เอง หน้าตาเหมือนกันทุกประการ */
.lg-field input:-webkit-autofill,
.lg-field input:-webkit-autofill:hover,
.lg-field input:-webkit-autofill:focus,
.lg-field input:-webkit-autofill:active{
  -webkit-text-fill-color:#fff;caret-color:#fff;
  -webkit-background-clip:text;background-clip:text;
  box-shadow:inset 0 0 0 999px rgba(255,255,255,.06);
  transition:background-color 9999s ease-out}
.lg-field input:-webkit-autofill:focus{
  box-shadow:inset 0 0 0 999px rgba(255,255,255,.16),0 0 0 4px rgba(255,255,255,.16)}

/* ---- ปุ่มดูรหัสผ่าน ---- */
.lg-eye{position:absolute;right:9px;top:calc(50% + 11px);transform:translateY(-50%);
  width:38px;height:38px;display:flex;align-items:center;justify-content:center;
  border-radius:50%;color:rgba(255,255,255,.78);
  transition:background var(--t-fast) var(--ease),color var(--t-fast) var(--ease)}
.lg-eye:hover{background:rgba(255,255,255,.14);color:#fff}
.lg-eye svg{width:20px;height:20px;fill:none;stroke:currentColor;stroke-width:1.7;
  stroke-linecap:round;stroke-linejoin:round}
.lg-eye .eye-off{opacity:0;transition:opacity var(--t-fast) var(--ease)}
.lg-eye.on .eye-off{opacity:1}

/* ---- Caps Lock ---- */
.lg-caps{margin:-12px 0 10px;padding-left:22px;font-size:11.5px;
  color:#FFD79A;letter-spacing:.3px}
.lg-caps[hidden]{display:none}

/* ---- แถวจดจำฉันไว้ / ลืมรหัสผ่าน (ตาม mockup) ---- */
.lg-row{display:flex;align-items:center;justify-content:space-between;
  margin:30px 4px 0;font-size:13px;color:rgba(255,255,255,.92)}
.lg-remember{display:flex;align-items:center;gap:10px;cursor:pointer;user-select:none}
.lg-remember input{position:absolute;opacity:0;width:0;height:0}
.lg-check{width:17px;height:17px;flex:none;border-radius:3px;
  border:1.5px solid rgba(255,255,255,.85);background:transparent;position:relative;
  transition:background var(--t-fast) var(--ease),border-color var(--t-fast) var(--ease)}
.lg-remember input:checked + .lg-check{background:#fff;border-color:#fff}
.lg-check::after{content:'';position:absolute;left:4.5px;top:1.5px;width:5px;height:9px;
  border:solid #12263E;border-width:0 2px 2px 0;transform:rotate(42deg) scale(0);
  transition:transform var(--t-fast) var(--ease-out)}
.lg-remember input:checked + .lg-check::after{transform:rotate(42deg) scale(1)}
.lg-remember input:focus-visible + .lg-check{outline:2px solid #fff;outline-offset:2px}
.lg-forgot{color:rgba(255,255,255,.92);font-size:13px;padding:4px 2px;
  border-radius:4px;transition:color var(--t-fast) var(--ease)}
.lg-forgot:hover{color:#fff;text-decoration:underline;text-underline-offset:3px}

/* ---- ปุ่มเข้าสู่ระบบ ---- */
.lg-go{width:100%;height:52px;border-radius:999px;background:#fff;color:#12263E;
  font-size:15px;font-weight:700;letter-spacing:.4px;margin-top:20px;
  box-shadow:0 10px 26px -12px rgba(0,0,0,.7);
  transition:background var(--t-fast) var(--ease),transform var(--t-fast) var(--ease),
             box-shadow var(--t-base) var(--ease)}
.lg-go:hover:not(:disabled){background:#EAF2FB;box-shadow:0 14px 32px -12px rgba(0,0,0,.8)}
.lg-go:active:not(:disabled){transform:translateY(1px) scale(.99)}
.lg-go:disabled{opacity:.72;cursor:progress}

/* ---- แถบแจ้งข้อผิดพลาด ---- */
.lg-err{display:none;margin-bottom:16px;padding:10px 16px;border-radius:12px;
  background:rgba(190,50,50,.30);border:1px solid rgba(255,150,150,.55);
  color:#FFE0E0;font-size:12.5px;line-height:1.6}
.lg-err.on{display:block;animation:lg-shake 380ms var(--ease)}
@keyframes lg-shake{
  0%,100%{transform:translateX(0)} 22%{transform:translateX(-5px)}
  46%{transform:translateX(4px)} 70%{transform:translateX(-2px)}}

/* ---- โฟกัสบนพื้นภาพ: วงแหวนสีเน้นของระบบจมไปกับภาพ ใช้ขาวแทนเพื่อให้เห็นชัดทุกฉาก ---- */
.lg :where(button,input):focus-visible{outline:2px solid #fff;outline-offset:2px;
  box-shadow:0 0 0 5px rgba(255,255,255,.28)}

/* ---- จอเตี้ย (โน้ตบุ๊ก 768px หรือมือถือแนวนอน): บีบระยะแนวตั้งไม่ให้การ์ดล้นจอ ---- */
@media (max-height:700px){
  .lg{align-items:start;padding-top:20px;padding-bottom:20px}
  .lg-body{overflow:auto}
  .lg-card{padding:26px 30px 30px}
  .lg-mark{height:104px;margin-bottom:8px}
  .lg-name{font-size:34px}
  .lg-tag{margin-bottom:28px}
}
@media (max-width:420px){
  .lg{padding-left:16px;padding-right:16px}
  .lg-card{padding:30px 22px 34px}
  .lg-mark{height:118px}
  .lg-name{font-size:30px;letter-spacing:1.6px}
  .lg-tag{margin-bottom:34px}
}

/* ================= ระบบสมาชิก & สิทธิ์ (หน้า admin) =================
   ช่องติ๊กสิทธิ์จัดกลุ่มตามโมดูล — ใช้ token กลางทั้งหมด รองรับสองธีมอัตโนมัติ */
.permgroup{border:1px solid var(--line);border-radius:11px;padding:10px 14px 12px;margin:0 0 10px}
.permgroup legend{font-size:13px;font-weight:700;color:var(--accent-ink);padding:0 6px}
.permitem{display:inline-flex;align-items:center;gap:7px;margin:4px 16px 4px 0;font-size:13.5px;cursor:pointer;user-select:none}
.permitem input{accent-color:var(--accent);width:15px;height:15px;cursor:pointer}
.permitem.diff span{font-weight:600}
.permdiff{color:var(--accent);font-style:normal;font-size:10px;vertical-align:2px}
.deptrow{display:flex;align-items:center;gap:12px;padding:8px 2px;border-top:1px dashed var(--line)}
.deptrow .deptlevel{min-width:120px;font-weight:600;font-size:13.5px}
