/* หน้าลูกค้า · แบบ E Minimal · v15
   หน้าเดียว: ทุกหน้าเป็น <section class="page"> สลับด้วย :target (ไม่มี JS · ปัดขอบจอย้อนกลับได้ · ข้อมูลที่กรอกอยู่ครบเพราะไม่โหลดใหม่)
   เลื่อนขึ้นลงเท่านั้น · เลื่อนซ้ายขวาได้แค่แถววัน (.days) กับราง การ์ด (.rail)
   แดง = R โลโก้ + สิ่งที่เลือก + ต้องทำ · เขียว = เสร็จ/ประหยัด · ไม่มีเบลอ (กระจกแดง/ดำ = สีโปร่งน้อย + ขอบสว่างบน + เงา) ยกเว้นชั้นเบลอหัวข้อ
   JS มีสองจุด: ปุ่ม −/+ เรียก stepUp/stepDown ของช่องตัวเลข · ปุ่ม Copy เรียก clipboard (ทั้งคู่ของ browser เอง) */
:root{
  /* ROOTS (OD-366) — ชั้นโทเคน: ระดับ/ขั้นของค่าหน้าตาที่ยังไม่มีราก · ค่าตรงกับของที่ใช้อยู่แล้วเป๊ะ (ไม่เปลี่ยนหน้าตา) · แก้ค่าที่นี่ที่เดียว = เปลี่ยนทั้งแอป
     ชื่อ: --<หมวด>-<ขั้น> · ขั้น = เลขเรียงจากน้อยไปมาก (fs lh ls t op ic) | เลขตามหน่วยฐาน (sp: ขั้น n = n×4px) | ไซส์เสื้อ xs…2xl (r) | ชื่อบทบาท (fw z · pill round dock toast…) · หมวด: r รัศมี · fs ขนาดตัวอักษร · fw น้ำหนัก · lh/ls ความสูงบรรทัด/ช่องไฟ · sp ระยะ · t ระยะเวลา · ease เส้นเวลา · z ชั้นซ้อน · op ความจาง · tap/ic ขนาดจิ้ม/ไอคอน
     ใช้: หยิบขั้นที่ใกล้สุด ห้ามเขียนตัวเลขตรงๆ · ต้องการขั้นใหม่ = ถามเจ้าของก่อน (Root Lab) แล้วเพิ่มที่นี่ที่เดียว · แผนที่ทั้งหมด: Bridge/design/ROOT-MAP.md · ratchet: wo376-roots-ratchet.test.ts */
  /* border-radius มุมโค้ง */
  --r-xs:10px;
  --r-sm:12px;
  --r-md:14px;
  --r-lg:18px;
  --r-xl:20px;
  --r-2xl:22px;
  --r-pill:999px;
  --r-round:50%;
  /* font-size ขนาดตัวอักษร */
  --fs-1:11px;
  --fs-2:11px;
  --fs-3:12px;
  --fs-4:12.5px;
  --fs-5:13px;
  --fs-6:14px;
  --fs-7:15px;
  --fs-8:16px;
  --fs-9:17px;
  --fs-10:18px;
  --fs-11:20px;
  --fs-12:22px;
  --fs-13:24px;
  --fs-14:26px;
  --fs-15:28px;
  --fs-16:30px;
  /* font-weight น้ำหนัก */
  --fw-regular:400;
  --fw-medium:500;
  --fw-semibold:600;
  --fw-bold:700;
  --fw-heavy:800;
  /* line-height ความสูงบรรทัด */
  --lh-1:1;
  --lh-2:1.1;
  --lh-3:1.2;
  --lh-4:1.25;
  --lh-5:1.3;
  --lh-6:1.35;
  --lh-7:1.4;
  --lh-8:1.45;
  /* letter-spacing ช่องไฟ */
  --ls-1:.02em;
  --ls-2:.04em;
  --ls-3:.08em;
  --ls-4:.1em;
  /* spacing ระยะ padding/margin/gap (ขั้น n = n×4px) */
  --sp-1:4px;
  --sp-2:8px;
  --sp-3:12px;
  --sp-4:16px;
  --sp-5:20px;
  --sp-6:24px;
  --sp-7:28px;
  --sp-9:36px;
  /* duration ระยะเวลา transition/animation */
  --t-1:.08s;
  --t-2:.1s;
  --t-3:.12s;
  --t-4:.2s;
  --t-5:.24s;
  --t-6:.25s;
  --t-7:.3s;
  --t-8:.35s;
  --t-9:.5s;
  /* easing เส้นเวลา (คีย์เวิร์ดมาตรฐาน · โค้งแอป: --ease --spring --dock-ease) */
  --ease-linear:linear;
  --ease-std:ease;
  --ease-inout:ease-in-out;
  --ease-out:ease-out;
  /* z-index ชั้นซ้อน */
  --z-1:1;
  --z-2:2;
  --z-3:3;
  --z-4:4;
  --z-5:5;
  --z-dock:6;
  --z-demo:7;
  --z-res:13;
  --z-sticky:14;
  --z-head:15;
  --z-sheet:20;
  --z-lang:21;
  --z-toast:30;
  --z-modal:40;
  --z-viewer:50;
  --z-viewer-ui:51;
  --z-viewer-hd:52;
  --z-zoom:53;
  --z-under:-1;
  /* opacity ความจางของสถานะ */
  --op-1:.3;
  --op-2:.35;
  --op-3:.4;
  --op-4:.45;
  --op-5:.5;
  --op-6:.6;
  /* tap ขนาดจิ้มขั้นต่ำ */
  --tap:44px;
  --mn-ph:72px;--mn-name-w:19ch;   /* OD-434: ความกว้างสูงสุดของชื่อเมนูในแถว — ชื่อยาวกว่านี้ตกเป็น 2 บรรทัดสมดุลเสมอ (Promotion / Mountain King Set) · สั้นกว่านี้บรรทัดเดียว */   /* OD-416b: รูปจตุรัสของแถวสินค้า (menu/Welcome Drinks) · แถว = รูป + 2×--sp-2 = 88 · ขยาย ×1.2 */
  --black:#000;   /* ดำสนิทของฉาก (เท่า html/body/ตัวดูรูป) — ชั้นฉากเต็มจอ (ซูมลอย) หยิบจากนี่ ไม่เขียน #000 ซ้ำ */
  /* icon ขนาดไอคอน (เฉพาะ rule ที่ลงท้าย .ic / svg) */
  --ic-1:14px;
  --ic-2:16px;
  --ic-3:18px;
  --ic-4:20px;
  --ic-5:22px;
  /* /ROOTS */
  --pcx-w:calc(3 * var(--tap) + 2 * var(--sp-1));   /* กล่อง − n + (OD-452): 3 วงกลม --tap + 2 ช่องไฟ — อยู่นอกบล็อก ROOTS เพราะประกอบจากโทเคนอื่น */
  --tile:#111214;--tile2:#1c1c1e;--line:#2a2a2e;--tx:#f5f5f7;--mu:#8e8e93;--dim:#5c5c61;--red:rgb(var(--accent-rgb));--red-cta:rgb(var(--red-cta-rgb) / var(--red-cta-a));--ok:rgb(var(--ok-rgb));
  --font:-apple-system,"SF Pro Display","SF Pro Text","Noto Sans Thai",system-ui,sans-serif;
  /* กระจกแดง dock + selector (OD-269): ทุกตัวเลขอยู่ตรงนี้ที่เดียว — สูตร POS (OD-333): พื้นแดง .92 + ขอบสว่างบน + เงา · ไม่มี backdrop-filter · alpha ตัวไหนตั้ง 0 = ตัดส่วนนั้นออกหมด (ขอบสว่าง/วงแหวน/เรืองใน/เงารอบ/พื้น) · เครื่องมือปรับ: Bridge/design/reserve-ideas/tune-glass.html */
  --glass-red-a:.73;   /* ฟิล์มแดง: ทึบ (OD-333: แบบ B ไม่เบลอ · OD-432: เจ้าของปรับจาก .92 เป็น .73 ผ่าน RM2 Lab — ใช้ร่วม dock กับตัวเลือกหน้าเนื้อหา · สี: dock = --accent-rgb · ตัวเลือก = --sel-red-rgb แยกโทเคน OD-452) */
  --glass-hi:.22;--glass-ring:.1;--glass-glow-a:.7;--glass-glow-r:35px;   /* ขอบสว่างบน · วงแหวน · เรืองใน (ทึบ/รัศมี) */
  --glass-drop-a:.75;--glass-drop-y:7px;--glass-drop-r:40px;   /* เงารอบ dock */
  --sel-drop-a:.15;--sel-drop-y:5px;--sel-drop-r:15px;   /* เงารอบ selector หน้าเนื้อหา */
  --dsel-bg-a:.3;--dsel-hi:.13;--dsel-ring:.06;   /* selector ใน dock: พื้นดำ · ขอบสว่างบน · วงแหวน */
  --dock-glass:rgb(var(--accent-rgb) / var(--glass-red-a));
  --dock-glass-rim:inset 0 1px 0 rgb(255 255 255 / var(--glass-hi)),inset 0 0 0 1px rgb(255 255 255 / var(--glass-ring)),inset 0 0 var(--glass-glow-r) rgb(var(--accent-rgb) / var(--glass-glow-a));
  --sel-glass:rgb(var(--sel-red-rgb) / var(--glass-red-a));   /* OD-452: แดง selector หน้าเนื้อหา (.cap .sel · วัน · ติ๊ก · ตัวนับ) แยกโทเคนจาก dock — ค่าเท่ากันวันนี้ ปรับแยกกันได้ที่ --sel-red-rgb */
  --sel-glass-rim:inset 0 1px 0 rgb(255 255 255 / var(--glass-hi)),inset 0 0 0 1px rgb(255 255 255 / var(--glass-ring)),inset 0 0 var(--glass-glow-r) rgb(var(--sel-red-rgb) / var(--glass-glow-a));
  --sel-press-scale:1.12;--sel-press-t:var(--sel-t);--sel-press-hi:calc(var(--glass-hi) * 1.6);   /* OD-452: กดค้าง = ตัวเลือกตัวเดียวโตขึ้น (ไม่มีชั้นผี) · ขอบสว่างบนขึ้น ×1.6 · เงาแรงขึ้นจาก --sel-drop ×1.6 · scale ใช้ property `scale` แยกจาก transform ที่เลื่อนตำแหน่ง */
  --sel-glass-rim-press:inset 0 1px 0 rgb(255 255 255 / var(--sel-press-hi)),inset 0 0 0 1px rgb(255 255 255 / var(--glass-ring)),inset 0 0 var(--glass-glow-r) rgb(var(--sel-red-rgb) / var(--glass-glow-a));
  --glass-drop:0 var(--glass-drop-y) var(--glass-drop-r) rgb(0 0 0 / var(--glass-drop-a));--sel-drop:0 var(--sel-drop-y) var(--sel-drop-r) rgb(0 0 0 / var(--sel-drop-a));--sel-drop-press:0 calc(var(--sel-drop-y) * 1.6) calc(var(--sel-drop-r) * 1.6) rgb(0 0 0 / calc(var(--sel-drop-a) * 2));
  --bell-cycle:2.2s;--bell-first:1.2s;--bell-n:1;--bell-deg:14deg;--bell-ping-t:1.3s;   /* OD-420/421: กระดิ่ง CTA สั่งครั้งแรกครั้งเดียวต่อการเข้าหน้าเมนู แบบจัดเต็มแต่เบา (transform+opacity ล้วน) — ระยะ 2.2 วิ · เริ่ม 1.2 วิหลังโผล่ · เอียงสูงสุด ±14° แล้วค่อยเบาลง · วงคลื่น 1.3 วิ (ปรับได้ที่นี่ที่เดียว) */
  --cta-w:180px;--cta-pad:9px;--cta-lab-w:110px;--cta-split-w:calc(3 * var(--tap) + 3 * 6px + var(--cta-lab-w));   /* CTA กว้างเดียวทุกหน้า/สถานะ (OD-393: 180 = ป้ายยาวสุด ~160 + ขอบข้างละ --cta-pad · ชิ้นในปุ่มส่ง [ตะกร้า] Send ฿9,999.99 = 156px วัดจริง) · แถวแตก [−][n][+][ป้าย] (menu.css) ต้องการ 3 ช่อง ≤44 + ช่องไฟ + ช่องป้าย --cta-lab-w จึงกว้างกว่าแคปซูล: วางล้นสองข้างเท่ากัน (ไม่ใช่ animate width) */
  --cta-h:52px;--dock-h:64px;--dock-pad:3px;--dock-edge:20px;--dock-icon:26px;--dock-sel-over:8px;--dsel-min:calc(var(--dock-h) - 2 * var(--dock-pad));   /* selector ของ dock กว้างกว่าช่องแท็บเท่านี้ (ข้างละครึ่ง · ตัวแปรเดียวปรับได้ · OD-260) · แถวไอคอนถูกเว้นเข้ามาข้างละครึ่งนี้ (padding ของ .dock) เพื่อให้ selector แท็บริมพอดีขอบใน dock และกึ่งกลางไอคอนทุกแท็บ */
  --dock-t:.65s;--dock-ease:cubic-bezier(.2,.9,.3,1);--dock-over:1;--dock-bounce:cubic-bezier(.4,0,.25,var(--dock-over));--sel-over:2;--sel-pop:var(--sel-anim,sel-pop) var(--sel-t) var(--spring);--spring:cubic-bezier(.3,0,.3,calc(1 + .25 * var(--sel-over)));--sel-t:.33s;   /* bounce = เลยเป้าตาม --dock-over (1 = ไม่เด้ง · 1.17 = เลย ~3–6px แล้วกลับ · OD-272) (วงกลม↔แคปซูล) · spring + --sel-t = แคปซูลเลือกเด้งไปแท็บ เร็วและติดนิ้ว (แยกจาก --dock-t ที่ใช้กับกาง/ยุบเท่านั้น) */   /* ความเร็ว dock ที่เดียว (.65s · OD-272: เจ้าของสั่ง 23 ต.ค. ให้ช้าลงจาก .45s · header ย่อ/กางใช้ตัวเดียวกันโดยตั้งใจ) — ทุก transition/stagger ของ dock คิดเป็นสัดส่วนของ --dock-t */   /* ขนาด dock ที่เดียว (เจ้าของ 22 ต.ค.: ผอมเกินไป · selector เกือบเต็มขอบ) — CTA · ปุ่ม Undo · ระยะท้ายหน้า คำนวณจากตัวแปรเหล่านี้ */
  /* สีสถานะ (แดง = ต้องทำ · เขียว = เสร็จ · เขียว LINE = ล็อกอิน) เป็น rgb ตัวเดียว → --red/--ok/--lineg และ glow ใช้ค่าเดียวกัน
     glow แบบ POS (OD-220 · ready/pos/ui/public/app.css): ปุ่ม/ชิป/วงกลมสถานะที่เป็นสีมี glow เสมอ · ตัวเด่น (CTA/แจ้งเตือน) = ring + glow ใหญ่ · ผูกด้วยบล็อกเดียวท้ายไฟล์ (app.css + staff.css) — ห้ามเขียน box-shadow สีแดง/เขียวแบบนอก inset ที่อื่น (css-glow.test.ts) */
  --accent-rgb:179 30 0;--red-cta-rgb:179 30 0;--red-cta-a:1;--ok-rgb:115 120 74;--sel-red-rgb:179 30 0;--line-rgb:6 199 85;   /* แดง dock/โลโก้/ที่เลือก = --accent-rgb (OD-277 · ที่อื่นห้ามมีเลขแดงของตัวเอง ใช้ rgb(var(--accent-rgb) / α)) · แดงปุ่ม CTA แยกโทเคน --red-cta-rgb (OD-385/WO-380: ค่าเท่ากันวันนี้เป๊ะ · ปรับแยกกันได้ในอนาคต · ล็อกทั้งสองใน locked-looks.json) */
  --red-text:rgb(213 131 115);   /* แดงสำหรับ "ตัวอักษร/ไอคอนเส้น" เท่านั้น: แดง dock บนพื้นดำอ่านยาก (~1.9:1) จึงใช้โทนเดียวกันที่สว่างขึ้น · พื้น/ขอบ/glow ใช้ --red */
  --glow-red:0 4px 16px rgb(var(--accent-rgb) / .35);--glow-ok:0 4px 16px rgb(var(--ok-rgb) / .35);
  --glow-red-strong:0 0 0 1px rgb(var(--accent-rgb) / .6),0 8px 32px rgb(var(--accent-rgb) / .35);--glow-ok-strong:0 0 0 1px rgb(var(--ok-rgb) / .6),0 8px 32px rgb(var(--ok-rgb) / .35);--glow-line-strong:0 0 0 1px rgb(var(--line-rgb) / .6),0 8px 32px rgb(var(--line-rgb) / .35);
  /* หายใจ (OD-222): สว่างขึ้นแล้วกลับมาเท่า glow ปัจจุบัน · geometry เท่าเดิม เปลี่ยนแค่ alpha · keyframe `breath` ตัวเดียว (ต่อยอด `glow` ของ CTA) · reduced-motion ตั้ง --breath:none = นิ่งที่ glow ปัจจุบัน */
  --glow-white:0 0 14px rgb(255 255 255 / .28);--glow-white-up:0 0 14px rgb(255 255 255 / .5);   /* ขั้นที่กำลังทำ = ขาวทึบ + แสงเล็กน้อย (OD-276 r2) */
  --glow-red-up:0 4px 16px rgb(var(--accent-rgb) / .7);--glow-ok-up:0 4px 16px rgb(var(--ok-rgb) / .7);
  --glow-red-strong-up:0 0 0 1px rgb(var(--accent-rgb) / .95),0 8px 32px rgb(var(--accent-rgb) / .7);--glow-ok-strong-up:0 0 0 1px rgb(var(--ok-rgb) / .95),0 8px 32px rgb(var(--ok-rgb) / .7);--glow-line-strong-up:0 0 0 1px rgb(var(--line-rgb) / .95),0 8px 32px rgb(var(--line-rgb) / .7);
  --glow-cta:0 0 0 1px rgb(var(--red-cta-rgb) / .65),0 8px 40px rgb(var(--red-cta-rgb) / .5),0 0 22px rgb(var(--red-cta-rgb) / .28);--glow-cta-up:0 0 0 1px rgb(var(--red-cta-rgb) / .95),0 8px 48px rgb(var(--red-cta-rgb) / .85),0 0 30px rgb(var(--red-cta-rgb) / .5);   /* OD-309+: แดงของปุ่มกลาง (CTA) แรงกว่าเดิมนิด — แยกจาก --glow-red-strong* (ตรงกับ POS · เทสต์ css-glow ล็อกไว้) */
  --focus-w:2px;--focus-off:2px;--focus-c:rgb(255 255 255 / .85);--focus-shadow:0 0 0 var(--focus-w) var(--focus-c);   /* กรอบโฟกัสคีย์บอร์ดชุดเดียว (WO-380 ข้อ 7): กฎกลาง :where(…):focus-visible ใช้ outline จากค่าเหล่านี้ · ปุ่มที่ input จริงซ่อนอยู่ (สวิตช์/ช่องติ๊ก/แท็บ) ใช้ --focus-shadow บนตัวพี่น้อง */
  --breath-t:2.6s;--breath:breath var(--breath-t) ease-in-out infinite;
  --pg-fade:pg-in var(--dock-t) var(--dock-ease) backwards;   /* จางเข้าหน้าของ .cta (opacity ล้วน ไม่เลื่อน) — ใส่ในรายการ animation ของทุกสถานะ .cta ให้ชื่อ pg-in อยู่ตำแหน่งแรกเสมอ: wait↔ready เปลี่ยนสถานะแล้วจางไม่เล่นซ้ำ · none ใน reduced-motion / html.lite / body.sw-still */
  /* กระจกดำ (เจ้าของสั่ง 2026-10-22): ทุกอย่างที่ไม่ใช่ปุ่มกลางกับ dock — toast · แถบเลือก · แผ่น · ป้าย · พื้นเกือบดำโปร่ง + ไฮไลต์ขอบบน + แสงจางด้านบน */
  --glass-dark:linear-gradient(180deg,rgb(255 255 255 / .10),rgb(255 255 255 / .02) 50%),rgb(10 10 12 / .86);
  --glass-dark-edge:inset 0 1px 0 rgb(255 255 255 / .32),inset 0 0 0 1px rgb(255 255 255 / .10);
  /* "โปร่งใสดำมืด" (dark glass · OD-352/355/363/436): สูตรเดียวของ "พื้นมืดลอยบนฉากมืด" — แยกชั้นรองตามบทบาท (Apple: เนื้อหามืดไม่ต้องหรี่ · เนื้อหาสว่าง/มีตัวหนังสือต้องมีชั้นหรี่ · Android: ป้องกันด้วยแผ่นไล่เฉดที่ขอบ ไม่ใช่ทึบทีละปุ่ม)
     ปุ่ม/ไอคอนล้วน (ควบคุม)  = `background:var(--dg-surface)` · พื้นรอง --dg-under = .79 (เจ้าของ OD-452 · เดิม OD-436 = 0) · ความอ่านออกมาจากแผ่นขอบ --edge-scrim (ล่าง) + เฟดหัว (บน) + ตัวดูรูป --vf-*
     การ์ด/แผ่น/ป้ายที่มีตัวหนังสืออ่าน = `background:var(--dg-surface-card)` · พื้นรอง --dg-under-card = .84 (OD-452 · ตัวหนังสือเมนูหลังการ์ดไม่โผล่ ghost ≤1.15 · ตัวหนังสือบนฉากขาว ≥.59 ผ่าน)
     ปุ่มที่ลอยทับเนื้อหาขาวได้ (#cta.again บนการ์ด QR) = ท้ายไฟล์ ใช้ --dg-under-light (≥.60 ตามค่าคำนวณ) · ตารางสังกัดทุก selector: Bridge/qa/wo398-roles.md
     --dg-line = กรอบบางชุดเดียว (inset box-shadow: ไม่กินพื้นที่ ไม่ขยับเลย์เอาต์) · ทุกชิ้นเขียน `background:var(--dg-surface…);box-shadow:var(--dg-line)` (ถ้าต้องมีเงาอื่น รวมเป็นประกาศเดียว) → ปรับตัวเลขตรงนี้ = เปลี่ยนทั้งแอป
     --dg-scrim = ม่านดำหลังการ์ด (ชั้นฉาก ไม่ใช่พื้นผิว) · ค่าที่ล็อกอยู่ใน Bridge/design/locked-looks.json (ราก 18) */
  --dg-scrim:rgb(0 0 0 / .77);--dg-under:rgb(4 4 5 / .79);--dg-under-card:rgb(4 4 5 / .84);--dg-under-light:rgb(4 4 5 / .62);--dg-fill:rgb(255 255 255 / .036);--dg-line-a:.09;   /* OD-452: เจ้าของ Copy จาก RM2 Lab (29 ต.ค. 2026) */
  --dg-surface-card:linear-gradient(var(--dg-fill),var(--dg-fill)),var(--dg-under-card);--dg-line:inset 0 0 0 1px rgb(255 255 255 / var(--dg-line-a));
  /* แผ่นป้องกันขอบล่าง (Android system-bars: gradient สีพื้น alpha 1 → .8 → 0 สูง 1.2× ของแถบ · OD-436): ความสูง = (dock + ช่องว่าง + CTA) × 1.2 · --edge-scrim-a = ตัวคูณความเข้มทั้งแผ่น · ใช้ที่ body.docscroll::after ที่เดียว */
  --svc-gap:max(var(--sp-1),min(var(--sp-2),calc((100% - 6 * var(--tap)) / 5)));--svc-d:clamp(var(--tap),calc((100% - 5 * var(--svc-gap)) / 6),var(--cta-h));   /* แถวปุ่มบริการ 6 วง (OD-436 · LAYOUT-SPACING D1): ช่องคงที่ --sp-2 (8) · วง = พื้นที่เหลือ÷6 ไม่เกิน --cta-h ไม่ต่ำกว่า --tap · % = ความกว้างแถว .mn-svc · ช่องหดเหลือ --sp-1 เฉพาะเมื่อ 6×44+5×8 ไม่พอ */
  --cta-b:calc(var(--dock-edge) + var(--dock-h) + 18px);--cta-top:calc(var(--cta-b) + var(--cta-h));--end-gap:var(--sp-6);--page-end:calc(var(--cta-top) + var(--end-gap));   /* ท้ายเนื้อหาทุกหน้า → ขอบบน CTA = --end-gap เดียว (เดิม 2 สูตร: .page เว้น 14 · เมนูเว้น 40) · .page padding-bottom + .sw-fill อ่าน --page-end */--edge-scrim-h:calc(var(--cta-top) * 1.2);--edge-scrim-a:1;
  --edge-scrim:linear-gradient(to top,rgb(0 0 0 / var(--edge-scrim-a)),rgb(0 0 0 / calc(var(--edge-scrim-a) * .8)) 50%,rgb(0 0 0 / 0));
  --ease:cubic-bezier(.32,.72,0,1);--side:max(24px,calc(50% - 215px));
  /* กล่องหัวข้อตรึง (OD-232): ปรับได้ที่เดียว — ช่วงจาง · ความเบลอ · ความทึบบน/ล่าง (เจ้าของปรับจากหน้าเครื่องมือ Bridge/design/reserve-ideas/tune.html แล้วส่งค่ามาใส่ตรงนี้) */
  --hd-fade:40px;--hd-blur:3px;--hd-top:1;--hd-bot:.7;   /* ค่าเจ้าของปรับเองจาก tune.html (2026-10-23) */
  /* หัวข้อย่อทันทีที่เลื่อน (OD-252): ตัวหนังสือ + ปุ่มภาษายกขึ้น --hd-up (กึ่งกลางบรรทัด 40 → 22 จากขอบบน) · พื้นหัวข้อสั้นลง --hd-cut (กล่อง 74 → 44) · --hd-over = พื้นยื่นเลยขอบบนเผื่อตอนย่อสเกล (ส่วนเกินถูกตัดทิ้งนอกจอ) */
  --hd-up:18px;--hd-cut:30px;--hd-over:60px;
  /* ตัวอักษร/โลโก้หัวข้อหน้า (WO-382 ข้อ g · OD-396): ค่าเริ่มต้น = ค่าเดิมของแอป (ไม่เปลี่ยนหน้าตา) · เจ้าของเลือกจาก Header Lab แล้วแก้บรรทัดนี้บรรทัดเดียว · min = ตอนหัวข้อย่อ */
  --hd-title-fs:var(--fs-16);--hd-title-fw:var(--fw-bold);--hd-title-ls:var(--ls-2);--hd-title-min-fs:var(--fs-9);--hd-title-min-fw:var(--fw-semibold);
  --hd-logo-w:.92em;--hd-logo-h:1.02em;--hd-logo-m:.06em;--hd-logo-c:var(--red);
  /* ชื่อหน้าขยับตอนเปลี่ยนหน้า dock (OD-415 · customer/title-motion.js อ่านด้วย getComputedStyle ครั้งเดียวต่อการเล่น) · ค่าเริ่มต้น = ค่าที่เจ้าของอนุมัติ (OD-335) · เจ้าของปรับจาก Header Lab (viewer-v3-a) แล้วแก้บรรทัดนี้บรรทัดเดียว · ช่วง/ขั้นต่ำอยู่ใน ROOT-MAP
     --hm-decode 1/0 = ตัวอักษรถอดรหัสหรือไม่ (0 = มีแต่ R เลื่อน) · --hm-frames จำนวนเฟรม (4–12) · --hm-step ms ต่อเฟรม (35–90) · --hm-order ltr = ซ้าย→ขวา · out = จาก R ออกไป · rand = สุ่ม · --hm-chars mix = A–Z0–9 ตัด I/M/W · letters = A–Z ตัด I/M/W · code = ตัวเลข+สัญลักษณ์ · --hm-stagger ms หน่วงเพิ่มต่อตัวตามอันดับ (0–30)
     R เลื่อน: --hm-glide-t (ล็อกไม่ต่ำกว่า --hm-glide-lo ไม่เกิน --hm-glide-hi) · --hm-over ตัวคูณส่วนที่เลยเป้า (0 = ไม่เด้ง · 2 = เหมือน selector ของ dock) · --hm-spring = เส้นโค้งอ่านค่านี้ */
  --hm-decode:1;--hm-frames:8;--hm-step:55ms;--hm-order:ltr;--hm-chars:mix;--hm-stagger:0ms;
  --hm-glide-t:var(--sel-t);--hm-glide-lo:300ms;--hm-glide-hi:700ms;--hm-over:var(--sel-over);--hm-spring:cubic-bezier(.3,0,.3,calc(1 + .25 * var(--hm-over)));
  /* ตัวดูรูป v3 (WO-382 · OD-394/396/397 · ค่าเริ่มต้นจากเดโม viewer-v3-a): เฟดดำบน/ล่าง = linear-gradient ล้วน เบลอ 0 (ไม่มีชั้นเบลอ) · a = ทึบต้นเฟด · am = ทึบที่ 72% · ae = ปลายเฟด */
  --vf-top-h:calc(190px + env(safe-area-inset-top));--vf-top-a:.94;--vf-top-am:.86;--vf-top-ae:0;
  --vf-bot-h:270px;--vf-bot-a:.95;--vf-bot-am:.85;--vf-bot-ae:0;--vf-imm-top:1.3;
  --vf-top:linear-gradient(to bottom,rgb(0 0 0 / var(--vf-top-a)) 0,rgb(0 0 0 / var(--vf-top-am)) 72%,rgb(0 0 0 / calc(var(--vf-top-ae) + (var(--vf-top-am) - var(--vf-top-ae)) * .4)) 86%,rgb(0 0 0 / var(--vf-top-ae)) 100%);   /* 4 จุด: ปลายโค้งนุ่ม ไม่เป็นเส้นแข็งบนรูปสว่าง */
  --vf-bot:linear-gradient(to top,rgb(0 0 0 / var(--vf-bot-a)) 0,rgb(0 0 0 / var(--vf-bot-am)) 72%,rgb(0 0 0 / calc(var(--vf-bot-ae) + (var(--vf-bot-am) - var(--vf-bot-ae)) * .4)) 86%,rgb(0 0 0 / var(--vf-bot-ae)) 100%);
  /* header ย่อ (ในตัวดูรูป): ชื่อเล็ก/จางกว่า R · to = ความทึบตัวหนังสือ · rs = ขนาดโลโก้ R · lo = ทึบโลโก้ · bo = ทึบปุ่มภาษา/ค้นหา */
  --vf-hd-fs:var(--fs-3);--vf-hd-fw:var(--fw-medium);--vf-hd-ls:var(--ls-3);--vf-hd-to:.62;--vf-hd-rs:18px;--vf-hd-lo:1;--vf-hd-bo:.72;--vf-hd-c:rgb(255 255 255 / var(--vf-hd-to));
  --vf-tx:rgb(255 255 255 / .92);--vf-tx-mu:rgb(255 255 255 / .75);--vf-shadow:0 1px 14px rgb(0 0 0 / .65);   /* ตัวหนังสือบนเฟด: คำบรรยาย · ป้ายหัวกลุ่ม · เงารองให้อ่านบนรูปสว่าง */
  --vf-drag-shrink:.35;--vf-drag-fade:1.4;--fly-t:calc(var(--sel-t) * 1.4);   /* ปัดลงปิด: หดสูงสุด 35% · ฉากจางหมดที่ ~71% ของความสูงจอ · บินเปิด/ปิด (OD-397) นานเท่า selector ×1.4 */
  /* dock ไวน้อยลง (OD-252 · OD-272): ต้องเลื่อนสะสมทิศเดียวถึงเท่านี้ dock ถึงยุบ/กาง · --dock-cooldown = หลังสลับแล้วห้ามสลับกลับจนครบเวลานี้ · ui.js initDock อ่านค่า (อ่านใหม่ทุกครั้งที่เปลี่ยนทิศเลื่อน) */
  --dock-collapse-travel:500px;--dock-expand-travel:400px;--dock-cooldown:500ms;   /* ค่าก่อนหน้า (OD-272 · เก็บไว้ย้อนกลับ): --dock-collapse-travel:240px;--dock-expand-travel:120px;--dock-t:.7s;--dock-over:1;--dock-cooldown:500ms · ค่าเก่ากว่า: 180/110/.6s/1.17 */}
@supports (color:color-mix(in srgb,red,white)){:root{--red-text:color-mix(in srgb,rgb(var(--accent-rgb)) 55%,white)}}   /* โทนเดียวกับแดง dock ผสมขาว 45% */
/* พื้นผิวปุ่ม/ไอคอนล้วน (สูตรเดียว): ประกาศรายการตัวเลือก = ที่ :root และทุก scope ที่เปลี่ยน --dg-under เฉพาะที่ (wo398-glass-roles ตรวจว่าครบ) · ต้องประกาศซ้ำในทุก scope เพราะ var() ในค่าโทเคนถูกแทนที่ที่ element ที่ประกาศ (ไม่ตามลงลูก) */
.mn-vpl,.mn-vpop,#cta.again,:root{--dg-surface:linear-gradient(var(--dg-fill),var(--dg-fill)),var(--dg-under)}
.mn-vpl,.mn-vpop{--dg-under:var(--dg-under-light)}   /* ปุ่ม/ไอคอนกลางรูปในตัวดูรูป: ไม่อยู่ใต้เฟดบน/ล่าง · ฉากหลังเป็นภาพ/วิดีโอสว่างได้ = บริบทสว่าง (พื้นรอง ≥.60) */
/* แผ่นป้องกันขอบล่าง (OD-436): ชั้นเดียวของทุกหน้าลูกค้าที่มี dock · เหนือเนื้อหา ใต้ dock/CTA/ตะกร้า/ตัวดูรูป (z-4 < z-dock) · ไม่รับทัช · แถบหัว = เฟด sticky เดิม (.tophd/h1) เป็นคู่บน ไม่ทำซ้ำ */
body.docscroll::after{content:"";position:fixed;left:0;right:0;bottom:0;height:var(--edge-scrim-h);background:var(--edge-scrim);pointer-events:none;z-index:var(--z-4);transition:opacity var(--t-7) var(--ease)}
body.docscroll.mn-open::after{opacity:0}   /* ตะกร้าเปิด: ม่านของแผ่น (--dg-scrim) ป้องกันอยู่แล้ว และแผ่น/ปุ่มบริการอยู่ใต้แผ่นนี้ในชั้นซ้อน #menuRoot → ไม่ให้มันหรี่การ์ดตะกร้า */
*{box-sizing:border-box;-webkit-tap-highlight-color:transparent}
html{background:#000;color-scheme:dark}
body{margin:0;font-family:var(--font);color:var(--tx);background:#000;-webkit-font-smoothing:antialiased;line-height:var(--lh-6);overflow:hidden;}
html,body{touch-action:pan-x pan-y}   /* ห้ามจีบนิ้วซูมทั้งแอป (OD-244) · Safari iOS ไม่ฟัง user-scalable ต้องใช้ touch-action · เลื่อนแนวตั้ง/ราง .days ยังได้ */
html:has(.qrbig) body.docscroll{overflow:hidden}   /* ตัวดูรูปเต็มจอเปิดอยู่ = ล็อกเอกสาร (เดิม body overflow:hidden ล็อกให้อยู่แล้ว) ไม่งั้นลากแล้วหน้าด้านหลัง/dock/แถบ URL ขยับ */
h1,h2,p,ol,ul{margin:0}
/* หัวข้อหน้า: ใหญ่ หนา ช่องไฟเยอะ (แบบ Airbnb/Apple large title) */
/* หัวข้อตรึง (OD-229/231/232): เต็มความกว้างจอ (ยื่นออกไปทับ padding ข้างของ .page) · พื้นดำทึบด้านบนไล่ลงมาโปร่งแสงนิดๆ + เบลอแบบ dock · เนื้อหาเลื่อนลอดใต้ไม่โผล่ข้างๆ
   ตัวหนังสือสูง 74 (padding ล่าง 16) + margin ล่าง 6 · ช่วงเฟดอยู่ในกล่องเอง (40px ล่างของกล่อง) เนื้อหาเริ่มที่ 80 · หน้าที่มี .steps (margin บน -6 ยุบกับ 6 นี้) แถบขั้นจึงเริ่มพอดีขอบล่างหัวข้อ ไม่โดนหัวข้อทับหัววงกลม */
h1{font-size:var(--hd-title-fs);font-weight:var(--hd-title-fw);letter-spacing:var(--hd-title-ls);line-height:36px;margin:0 calc(-1 * var(--side)) 6px;min-height:calc(74px + env(safe-area-inset-top));padding:calc(22px + env(safe-area-inset-top)) calc(76px + var(--side)) var(--sp-4) var(--side);text-transform:uppercase;white-space:nowrap;overflow:hidden}   /* C17: แถวบนสุดร่วมกับปุ่มภาษา (เว้นที่ขวาให้ปุ่มภาษาปุ่มเดียว: 14 ขอบ + ~50 ปุ่ม + 12 ช่องว่าง) · ฟอนต์ 30 ทุกหน้า ไม่ย่อ — ชื่อหน้าต้องสั้นพอ (≤ 13 ตัวอักษร ขวาสุดไม่เกิน 292 ที่จอ 390) · ไม่มีปุ่มย้อนกลับ หัวข้อชิดซ้าย var(--side) ทุกหน้า · การตรึง/พื้น/เบลอ ไม่อยู่ที่นี่ → ดูกฎกล่องหัวข้อตรึงด้านล่าง */
h1 .R{margin:0 var(--hd-logo-m);width:var(--hd-logo-w);height:var(--hd-logo-h);background:var(--hd-logo-c);animation:r-wiggle 7s var(--ease-inout) infinite}   /* OD-252: ทุก 7 วิ สั่นรอบมุมฐาน −9° ±4° ราว 1 วิแรก (14.3% ของ 7s) ที่เหลือนิ่ง · transform ตัวเดียว (compositor) · เฉพาะโลโก้ในหัวข้อ ไม่ใช่ .cl-root .R ในการ์ด */
@keyframes r-wiggle{0%,14.3%,100%{transform:rotate(-9deg)}3%{transform:rotate(-13deg)}6%{transform:rotate(-5deg)}9%{transform:rotate(-12deg)}12%{transform:rotate(-6deg)}}
.caps{font-weight:var(--fw-medium);letter-spacing:var(--ls-1);white-space:nowrap}
a{color:var(--tx);text-decoration:none}
button,input,textarea{font:inherit;color:inherit}
button{background:none;border:0;padding:0}
.ic{width:var(--ic-5);height:var(--ic-5);background:currentColor;-webkit-mask:var(--m) center/contain no-repeat;mask:var(--m) center/contain no-repeat;display:inline-block}
/* ตัว R โลโก้: ตัวอื่นปกติ · R แดง ใหญ่กว่านิด เอียง · หน้าละ 1 */
.R{display:inline-block;width:.92em;height:1.02em;margin:0 .02em;vertical-align:-.12em;background:var(--red);transform:rotate(-9deg);
  -webkit-mask:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='381 309 1347 1421'><path d='M381 309H1151A470 497 0 0 1 1363.7 1249.2L1727.8 1729.5H1370.3V1562.4H1194.1V1395.3H1018.1V1228.2H841.6V1061.1H659.5V1729.5H381Z'/></svg>") center/contain no-repeat;
  mask:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='381 309 1347 1421'><path d='M381 309H1151A470 497 0 0 1 1363.7 1249.2L1727.8 1729.5H1370.3V1562.4H1194.1V1395.3H1018.1V1228.2H841.6V1061.1H659.5V1729.5H381Z'/></svg>") center/contain no-repeat}
/* ===== หน้า ===== */
.page{display:none;position:fixed;inset:0;overflow:hidden auto;overscroll-behavior:contain;
  padding:0 var(--side) var(--page-end)}   /* C17: หัวข้ออยู่แถวเดียวกับปุ่มภาษา · ระยะ 22px จากขอบบนอยู่ใน padding ของ h1 เอง (ไม่ใช่ของ .page) — sticky ถึงจะพาดถึงขอบบนจอได้ ไม่โดนกล่องเนื้อหาบีบไว้ (OD-231) · .lang ขยับตาม (top = 22 − 4) */
.page.cur{display:block}   /* JS route(): หน้าที่เปิด = .cur (ไม่พึ่ง :has/:target) · ตัวหน้าไม่มีอนิเมชันเอง: เข้าจาง+เลื่อนทำที่ลูกทั้งหมด (ด้านล่าง) เพื่อยกเว้น .tophd ได้ — opacity บน .page จางหัวข้อไปด้วยเลี่ยงไม่ได้ (OD-291) */
@keyframes pg-in{from{opacity:0}}
/* ส่วนเลื่อนเข้าตามทิศ dock (--dir ตั้งใน initDock) อยู่ที่ลูกของหน้า ไม่ใช่ที่ .page — transform บน .page ทำให้ลูก position:fixed (.cta · .toast · .undo) ใช้ .page เป็นกรอบอ้างอิงตลอด 600ms: หน้าที่เลื่อนค้างไว้ ปุ่มจะลอยตามเนื้อหาแล้วกระโดดตอนจบ (WO-309 A2)
   ลูกที่ fixed ห้ามมี transform (และห้ามมีลูกหลาน fixed): .cta .toast #undo (แถบ Undo ของสตาฟ — ใช้ id เพราะชื่อคลาสของสตาฟห้ามอยู่ใน app.css · UI-KIT §5) + [data-mv] (กล่องในหน้า Membership ที่ห่อ .cta) → รายชื่อเดียวตรงนี้ · ใน [data-mv] เลื่อนที่ลูกแทน · sticky (h1 .tophd .stick) เลื่อนได้
   h1 ยกเว้นทั้งจางและเลื่อนด้วย (OD-312/335 · ชื่อหน้าไม่ตามหน้าเข้า: ตัว R เลื่อนเอง + ตัวอักษรอื่น decode — customer/title-motion.js)
   .tophd (หัวข้อ+แถบขั้น 1–4 ของ Reservation) ยกเว้นทั้งจางและเลื่อน (OD-290/291): เปลี่ยนขั้น = เปลี่ยนแค่เนื้อหา หัวข้ออยู่ที่เดิมขนาดเดิม · วงในแถบขั้นไม่มีอนิเมชันที่สถานะฐาน (เล่นเฉพาะ .wait/.pop ตอนสถานะเปลี่ยนจริง)
   :where() ทั้งหมด = ความจำเพาะ 0 → ลูกที่มี animation ของตัวเอง (.s-fresh ฯลฯ) ชนะเสมอ ไม่โดนทับ */
:where(.page.cur) > :where(:not(.cta,.toast,#undo,.tophd,h1,[data-mv])),:where(.page.cur) > :where([data-mv]) > :where(:not(.cta)){animation:pg-in var(--dock-t) var(--dock-ease) backwards,pg-slide var(--dock-t) var(--dock-ease) backwards}
:where(.page.cur) > :where(.cta),:where(.page.cur) > :where([data-mv]) > :where(.cta){animation:var(--pg-fade)}   /* .cta จางอย่างเดียว (fixed ห้าม translate) · ความจำเพาะ 0: .cta.ready/.wait/guest ประกาศรายการ animation ของตัวเองที่มี var(--pg-fade) นำหน้า */
@keyframes pg-slide{from{translate:calc(var(--dir,0) * 28px)}}   /* ใช้คุณสมบัติ translate ไม่ใช่ transform: ลูกตรงของ .page (รวม h1) มี transform ของ body.hd-min อยู่ — keyframes ที่ตั้ง transform จะทับแล้วหัวข้อกระโดดตอนจบ · translate แยกจาก transform (เบราว์เซอร์เก่าไม่รองรับ = ไม่สไลด์ แต่ไม่พัง) */
.hero{display:grid;place-items:center;text-align:center;font-size:var(--fs-16);line-height:var(--lh-5)}
/* ภาษา */
#th{display:none}
.lang{position:fixed;top:calc(18px + env(safe-area-inset-top));right:14px;z-index:var(--z-lang);height:var(--tap);display:flex;align-items:center;gap:2px;font-size:var(--fs-3);font-weight:var(--fw-semibold)}
.lang::before{content:"";position:absolute;inset:0 -3px}   /* ภาพกว้าง 39 กด 45 — ไม่ขยับรูป (OD-216 จุดแตะ ≥44) */
.lang span{height:var(--tap);padding:0 9px;border-radius:var(--r-pill);display:grid;place-items:center;color:#fff;transition:transform var(--dock-t) var(--dock-ease)}   /* OD-252: ตอนหัวข้อย่อ (body.hd-min) ปุ่มยกตามบรรทัดหัวข้อ · ใส่ที่ span ไม่ใช่ .lang เพราะ staff.css ตั้ง transition ของ .lang เอง (opacity) จะทับกัน */   /* ปุ่มเดียว: โชว์ภาษาเป้าหมาย (โหมด EN → "ไทย" · โหมด TH → "EN") */
/* ภาษา: ซ่อนด้วย !important เพื่อไม่ให้กฎ display ของ component (เช่น .x span{display:flex}) ทำให้สองภาษาโผล่พร้อมกัน — ซ่อนอย่างเดียว ไม่บังคับ display ตอนโชว์ (ข้อความไทยคง display เดิมของมัน)
   ขึ้นต้น `body:not(.th)` / `body.th` เสมอ: คลาสสถานะภาษาบน <body class="th"> ชื่อเดียวกับคลาสข้อความ .th — กฎ `.th{display:none}` เปล่าๆ จะซ่อนทั้งหน้าเมื่อสลับเป็นไทย (บั๊กตั้งแต่ WO-272) */
body:not(.th) .th{display:none!important}
body.th .en{display:none!important}
body:not(.th) .lang .go-en,body.th .lang .go-th{display:none}
@supports (transition-timing-function:linear(0,1)){:root{--dock-ease:linear(0, 0.069, 0.218, 0.388, 0.547, 0.681, 0.786, 0.864, 0.919, 0.956, 0.98, 0.994, 1.002, 1.005, 1.006, 1);--spring:linear(0, 0.05, 0.168, 0.318, 0.475, 0.621, 0.747, 0.849, 0.926, 0.982, calc(1 + var(--sel-over) * 0.018), calc(1 + var(--sel-over) * 0.039), calc(1 + var(--sel-over) * 0.048), calc(1 + var(--sel-over) * 0.05), calc(1 + var(--sel-over) * 0.046), calc(1 + var(--sel-over) * 0.04), calc(1 + var(--sel-over) * 0.032), calc(1 + var(--sel-over) * 0.024), calc(1 + var(--sel-over) * 0.017), calc(1 + var(--sel-over) * 0.011), 1)}}   /* --dock-ease = spring เทียบ SwiftUI .snappy (response .45s bounce .15): ζ=1-bounce=.85, ω0=2π/.45=13.96, ωd=ω0√(1-ζ²)=7.355 · x(t)=1-e^(-ζω0t)(cos ωd·t + ζω0/ωd·sin ωd·t) เก็บ 16 จุดที่ t=0….45s (=--dock-t) เลยเป้าสูงสุด ~0.6% แล้วนิ่ง · fallback cubic-bezier ออกตัวแรงจบนุ่ม · เด้งเลยขอบของแคปซูล (width) ยังเป็น --dock-bounce แยกคนละ property กับ scale ของไอคอนที่ใช้ --dock-ease จึงไม่เด้งซ้อน
   --spring: spring จริง (ζ≈.7) เมื่อเบราว์เซอร์รองรับ linear() (Safari 17.2+) · ไม่รองรับ = cubic-bezier ข้างบน · เด้ง selector ที่เดียว (OD-275) = --sel-over: ตัวคูณส่วนที่เลยเป้า (0 = ไม่เด้ง · 1 = เลย 5% · 2 = เลย ~10% เด้งแรงเท่า pop 1.06 ของ POS ตอนย้ายโต๊ะ) · ทั้งสองเส้นโค้งอ่านค่านี้ แก้ที่เดียว selector ทุกตัว (dock · .cap · ปุ่มวัน/ชิป/โต๊ะ/ปฏิทิน) เด้งตาม */
/* ===== dock แก้วแดง · ตัวเลือกชิ้นเดียวไหลตามหน้า · ย่อเมื่อเลื่อนลงจากบนสุด (scroll-driven · CSS ล้วน) · C16: แคปซูลลอยห่างขอบ 20px ทุกด้าน ไม่ผูก safe-area · ยุบ = วงกลม 56 มุมล่างขวา ===== */
@supports (transition-timing-function:linear(0,1)){:root{--hm-spring:linear(0, 0.05, 0.168, 0.318, 0.475, 0.621, 0.747, 0.849, 0.926, 0.982, calc(1 + var(--hm-over) * 0.018), calc(1 + var(--hm-over) * 0.039), calc(1 + var(--hm-over) * 0.048), calc(1 + var(--hm-over) * 0.05), calc(1 + var(--hm-over) * 0.046), calc(1 + var(--hm-over) * 0.04), calc(1 + var(--hm-over) * 0.032), calc(1 + var(--hm-over) * 0.024), calc(1 + var(--hm-over) * 0.017), calc(1 + var(--hm-over) * 0.011), 1)}}   /* เส้นโค้ง --spring ชุดเดียวกัน (เทสต์ wo387 เทียบตัวเลขให้เท่ากัน) แต่ความเด้งอ่าน --hm-over ของหัวข้อเอง */
.dock{position:fixed;left:auto;right:var(--dock-edge);bottom:var(--dock-edge);height:var(--dock-h);z-index:var(--z-dock);display:flex;padding:var(--dock-pad) calc(var(--dock-pad) + var(--dock-sel-over) / 2);border-radius:var(--r-pill);overflow:hidden;--p:0;width:calc((100% - 2 * var(--dock-edge)) - (100% - 2 * var(--dock-edge) - var(--dock-h)) * var(--p));min-width:calc(var(--dock-h) - 8px);
  /* กระจกแดง (เจ้าของเลือกค่านี้ 22 ต.ค. จบ): ฟิล์มแดงส้มทึบ .92 ไม่เบลอ (OD-333) · บนพื้นดำสีที่เห็นคือสีฟิล์มล้วนๆ จึงต้องเลือกสีฟิล์มให้เป็นสีที่อยากเห็น · GPU ล้วน ไม่มี JS */
  background:var(--dock-glass);
  box-shadow:var(--dock-glass-rim),var(--glass-drop);
  transition:width var(--dock-t) var(--dock-bounce);will-change:width;contain:layout style paint}   /* ยุบ/ขยายสมูธ ความเร็วตาม --dock-t · ของที่ขยับ = transform/opacity · contain กัน layout ลาม */
/* ย่อ (body.min): ไหลไปเป็นวงกลมมุมล่างขวา (ทุกอย่างเป็นค่าที่ interpolate ได้: left/width/opacity/scale · ไม่ใช้ display) */
.dock a{opacity:calc(1 - var(--p) * 1.6);transform:scale(calc(1 - var(--p) * .5));transition:opacity calc(var(--dock-t) * .5) var(--ease-std),transform var(--dock-t) var(--dock-ease)}   /* ไอคอนจางก่อนแถบหด */
body:not(.min) .dock a{transition:opacity calc(var(--dock-t) * .6) var(--ease-std),transform var(--dock-t) var(--dock-ease)}   /* ขยาย: ไอคอนโผล่พร้อมแคปซูลที่กาง — ตำแหน่งตามความกว้าง (flex) จึงกระจายออกจากจุดวงกลมเอง · transform/opacity เท่านั้น */
body.min .dock{--p:1}
/* ไอคอนแท็บที่เลือก (ui.js ใส่ class on) "ตรึง" (OD-274 r2): ไม่จาง ไม่ย่อ ไม่วาดใหม่ — เลื่อนอย่างเดียว ไปกึ่งกลางวงกลมมุมล่าง แล้วกลับช่องเดิมตอนกาง · ระยะปลายทาง --ix ui.js วัดจากเลย์เอาต์ยุบจริง · ตำแหน่งธรรมชาติเป็นเส้นตรงตามความกว้าง dock (ดู .dock a min-width:0) จึงคูณ --p ได้ตรงๆ และไปพร้อมกับ width (เวลา/เส้นโค้งเดียวกัน) · transform ล้วน */
.dock a.on{opacity:1;transform:none}
.dock a.on i{transform:translateX(calc(var(--ix,0px) * var(--p)));transition:transform var(--dock-t) var(--dock-bounce)}
body.measure .dock,body.measure .dock *,body.measure .dock *::before{transition:none!important}   /* ui.js วัด --ix: ใส่สถานะยุบชั่วคราว (FLIP) ต้องไม่มีอนิเมชันหลุด */
body.lft .dock{left:var(--dock-edge);right:auto}   /* ยึดขอบที่วงกลมไปอยู่ (ขวา = right · ซ้าย = left) แล้วเปลี่ยนแค่ width = ซ้าย/ขวาเด้งเท่ากัน ไม่ใช้ transform คู่กับ width (บนเครื่องจริงสองตัวเดินไม่พร้อมกัน → ฝั่งขวาเลยขอบไปไกล) */
body.drag .dock,body.drag .dock a,body.drag .dock a i,body.drag .dock .sel{transition:none}   /* ระหว่างลาก = ตามนิ้ว 1:1 ไม่มี transition */
.dock .sel{opacity:calc(1 - var(--p) * 2)}
body.min .dock a{pointer-events:none}
body.min .dock{cursor:pointer}
.dock,.cap{touch-action:pan-y;-webkit-user-select:none;user-select:none}
.dock,.dock a{-webkit-touch-callout:none}   /* กดแช่ลิงก์ใน dock ห้ามขึ้นเมนูของ iOS (OD-250) · ยังเป็น <a href="#…"> เพื่อให้ route ทำงาน */   /* ลากแนวนอนที่ selector = เลือกแท็บ (ui.js) · ลากแนวตั้ง = เลื่อนหน้าปกติ */
.dock a{flex:1;min-width:0;position:relative;display:grid;grid-template-columns:minmax(0,1fr);place-items:center;color:rgb(255 255 255 / .75)}
.dock a i{width:var(--dock-icon);height:var(--dock-icon);background:currentColor;-webkit-mask:var(--m) center/contain no-repeat;mask:var(--m) center/contain no-repeat}
.dock .sel{position:absolute;top:var(--dock-pad);bottom:var(--dock-pad);left:var(--dock-pad);width:max(var(--dsel-min),calc((100% - 2 * var(--dock-pad) - var(--dock-sel-over)) / var(--dock-n,5) + var(--dock-sel-over)));border-radius:var(--r-pill);background:rgb(0 0 0 / var(--dsel-bg-a));box-shadow:inset 0 1px 0 rgb(255 255 255 / var(--dsel-hi)),inset 0 0 0 1px rgb(255 255 255 / var(--dsel-ring));
  /* ตำแหน่ง selector (OD-260 · iOS 26): กึ่งกลาง selector = กึ่งกลางไอคอนทุกแท็บ (รวมริม) ด้วยสูตรเดียว ไม่มี clamp
     แถวไอคอนเว้นเข้ามาข้างละ over/2 (padding ของ .dock) → ช่อง s = (กว้างใน dock − over) ÷ --dock-n (ui.js fitDock · ไม่มี = 5) · selector กว้าง = s + over (= W ที่นี่ · 100% ใน translate = W) → ช่อง s = W − over
     ซ้ายสุดตั้งต้นที่ขอบใน dock (left:pad) แล้วเลื่อน i ช่อง: แท็บ 0 ขอบซ้าย = pad พอดี · แท็บ 4 ขอบขวา = ขอบใน dock พอดี · ลากเกินริมหยุดที่ ui.js (selFollow) */
  --sx:calc(var(--i,0) * (100% - var(--dock-sel-over)) + var(--selx,0px))}
body[data-dock="1"] .dock .sel{--i:1}
body[data-dock="2"] .dock .sel{--i:2}
body[data-dock="3"] .dock .sel{--i:3}
body[data-dock="4"] .dock .sel{--i:4}
/* selector ของแคปซูลทุกตัว (dock + .cap ทุกชนิด) ใช้กฎเดียวกันตรงนี้ = เคลื่อนไหวเหมือนกัน (OD-233) — --i = ตัวที่เลือก · --selx = ระยะที่นิ้วลากเพิ่ม · --sx = ตำแหน่งที่คำนวณเองของ dock (selector กว้างกว่าช่อง · ดูกฎ .dock .sel) ไม่มี = .cap ใช้ i × ความกว้างตัวเอง (ui.js ตั้งตอนลาก) · แตะ = --i เปลี่ยน spring เด้งเอง
   ลาก selector (iOS 26): ตามนิ้วทันที (ไม่มี transition) · ฟองแก้วนิดๆ = pseudo-element scale + ไฮไลต์ขอบ (หักเหจริงทำใน Safari ไม่ได้ · C16) · ปล่อย = เด้งไปแท็บใกล้สุด
   กดค้าง (OD-452): ตัวเลือกตัวเดียวโตขึ้นเอง (property `scale` · ไม่คูณกับ translate ของตำแหน่ง) + ขอบสว่างบน + เงาแรงขึ้น — ไม่มีชั้นที่สอง */
.dock .sel,.cap .sel{transform:translateX(var(--sx,calc(var(--i,0) * 100% + var(--selx,0px))));transition:transform var(--sel-t) var(--spring),opacity calc(var(--dock-t) * .4) var(--ease-std),scale var(--sel-press-t) var(--spring)}
/* OD-279: ตัวเลื่อนใน dock ไม่ผิดรูปตอนยุบ/กาง — กว้างไม่ต่ำกว่าวงกลม (--dsel-min) · ยุบ = จางเร็วก่อนแคปซูลหดจนบีบ · กาง = รอแคปซูลโตเกือบเต็มค่อยปรากฏ */
.dock .sel{transition:transform var(--sel-t) var(--spring),opacity calc(var(--dock-t) * .2) var(--ease-out),scale var(--sel-press-t) var(--spring)}
body:not(.min) .dock .sel{transition-delay:0s,calc(var(--dock-t) * .45),0s}
/* ตัวเลือกทุกอันในหน้าเนื้อหา (.cap .sel ทุกชนิด: โซน/แท็บ/search + ปุ่มวันที่ที่เลือก) = แก้วแดงสูตรเดียวกับ dock (OD-262 · คืนขอบสว่าง/วงแหวน/เรืองใน/เงา ตาม OD-269) · ตัวเลขทั้งหมดเป็นโทเคนใน :root แก้ที่เดียว ทั้ง dock และ selector ตามกัน */
.cap .sel,.days input:checked + label{background:var(--sel-glass);box-shadow:var(--sel-glass-rim),var(--sel-drop)}
/* ตัวเลือกแบบปุ่มเม็ดที่ไม่มีแผ่นเลื่อน (วัน · ชิป · โต๊ะ · ปฏิทิน · วันโปรฯ) = เด้งตอนผู้ใช้เลือก ด้วย keyframe + โทเคนชุดเดียวกับ selector ที่เลื่อน (OD-275 · --spring --sel-t --sel-over) · ขนาดเด้งคิดจาก --sel-over (2 → 0.92 → 1.06 → 1 เท่า pop ของ POS) · transform ล้วน ไม่ดันเลย์เอาต์ · --sel-pop = เล่นครั้งเดียวตอนผู้ใช้เลือกจริง: ui.js ใส่ class sel-hit ให้ label ของ input ที่ยิง change (ไม่เล่นตอนโหลดหน้า/ตอน JS render ใหม่) แล้วถอดตอน animationend · กฎเดียวใช้ทุกกลุ่มปุ่มเม็ด ไม่มีรายการกลุ่ม · --sel-anim:none = reduced-motion / html.lite */
@keyframes sel-pop{0%{transform:scale(calc(1 - .04 * var(--sel-over)))}55%{transform:scale(calc(1 + .03 * var(--sel-over)))}100%{transform:none}}
label.sel-hit{animation:var(--sel-pop)}
/* กดค้าง/ลาก = ตำแหน่งตามนิ้ว 1:1 (ไม่ transition transform) · มีแต่ scale ที่เด้งสปริง · dock = class อยู่ที่ body · .cap = อยู่ที่ตัวแคปซูลเอง */
body.seldrag .dock .sel,.cap.seldrag .sel{transition:scale var(--sel-press-t) var(--spring);scale:var(--sel-press-scale)}
body.seldrag .dock .sel{box-shadow:inset 0 1px 0 rgb(255 255 255 / var(--sel-press-hi)),inset 0 0 0 1px rgb(255 255 255 / var(--dsel-ring)),var(--sel-drop-press)}
.cap.seldrag .sel{box-shadow:var(--sel-glass-rim-press),var(--sel-drop-press)}
body.seldrag .dock{overflow:visible;contain:layout style}   /* กดค้าง: selector ที่โตเกินขอบ dock นิดหน่อยแบบ iOS 26 (ปกติ overflow/contain ตัดขอบไว้) */
.dock a.on{color:#fff}   /* แท็บปัจจุบันสว่าง: ui.js ใส่ .on ตามตำแหน่งจริงใน dock (เดิมผูก href ต่อ data-dock = พังเมื่อแท็บหาย) */
/* ===== ขั้นตอนจอง 1–4 (ใต้หัวข้อ) · ทำแล้ว = ขาว กดย้อนได้ · อยู่ตรงนี้ = แดง · ยังไม่ถึง = เทา ===== */
/* OD-231/232: หัวข้อตรึง = กล่องเฟดกลไกเดียวทุกหน้าทุกแอป · ใช้กับ h1 เดี่ยว (.page > h1 = หน้าที่ไม่มีแถบขั้น) และกล่อง .tophd (ครอบ h1 + .steps หน้า Reservation) · ภายใน .tophd ตัว h1 ไม่ตรึง ไม่มีพื้น ไม่มีเบลอเอง
   ไล่สีเดียวจากบนสุดลงมาจนจางหมด ไม่มีรอยต่อ */
.page > h1,.tophd{position:sticky;top:0;z-index:var(--z-head);isolation:isolate}   /* พื้นสีอยู่ที่ ::after (ดูล่าง) ไม่ใช่ที่กล่อง — กล่องต้องไม่มีอะไรที่ย่อตามต้องวาดใหม่ */
/* h1 เดี่ยว: ช่วงเฟดอยู่ในกล่องเอง ไม่ยื่นออกนอกกล่อง (OD-250 แก้ OD-249) · gradient/mask อ้าง calc(100% - --hd-fade) = 40px ล่างของกล่องเป็นช่วงเฟดอัตโนมัติ · เนื้อหาเริ่มที่ 80 (74 + margin 6) เหมือนก่อนมีช่วงเฟด */
.page.hd-flow > h1{position:relative;z-index:var(--z-1)}   /* หน้าที่มีแถบตรึงของตัวเอง (.stick ของ Service): หัวข้อเลื่อนพ้นตามเนื้อหา ไม่ตรึงที่ top:0 ซ้อนกับแถบ · relative เพราะ ::before/::after เป็น absolute ต้องมีกล่องของ h1 เป็นกรอบ · z ต่ำกว่า .stick */
.page > h1{min-height:var(--hd-box);padding-bottom:var(--sp-4);margin-bottom:6px}
.tophd{margin:0 calc(-1 * var(--side)) 18px;padding:0 var(--side) 10px}   /* ช่วงเฟดอยู่ในกล่อง (40px ล่าง) ไม่ยืดกล่องเพิ่ม · padding ล่าง 10 margin ล่าง 18 */
/* เบลอแบบค่อยๆ ลด (progressive blur แบบ iOS): 2 ชั้นซ้อน ชั้นเบลอแรงจบสูงกว่า ชั้นเบลอเบากว่าลงไปต่ำกว่า → ขอบเบลอไม่ตัด · mask ต่อชั้นเป็นเส้นโค้ง ไม่ใช่เส้นตรง */
.page > h1::before,.page > h1::after,.tophd::before,.tophd::after{content:"";position:absolute;inset:calc(var(--hd-over) * -1) 0 0;z-index:var(--z-under);pointer-events:none;transform-origin:bottom;transition:transform var(--dock-t) var(--dock-ease)}   /* พื้น/เบลอยื่นเลยขอบบน --hd-over (ส่วนเกินโดนตัดนอกจอ) เผื่อสเกลตอนย่อ · ต้นทางสเกล = ขอบล่าง → ขอบล่างไม่ขึ้นกับ safe-area */
.page > h1::before,.tophd::before{-webkit-backdrop-filter:blur(var(--hd-blur)) saturate(160%);backdrop-filter:blur(var(--hd-blur)) saturate(160%);
  -webkit-mask-image:linear-gradient(#000 calc(100% - var(--hd-fade)),rgb(0 0 0 / .5) calc(100% - var(--hd-fade) * .55),transparent calc(100% - var(--hd-fade) * .2));
  mask-image:linear-gradient(#000 calc(100% - var(--hd-fade)),rgb(0 0 0 / .5) calc(100% - var(--hd-fade) * .55),transparent calc(100% - var(--hd-fade) * .2))}
/* พื้นดำย้ายมาอยู่ ::after (ชั้นเดียวที่ย่อตามได้ด้วย transform) · ::after มี mask ของมันเอง (1 → .4 → 0 ที่ 0.7/0.3/0 ของช่วงเฟด) จึงใส่ไล่สี "เดิม ÷ mask" ให้ผลคูณตกที่ไล่สีเดิมพอดี: ที่ .7f ใช้ .7·bot · ที่ .3f ใช้ .3·bot ÷ .4 = .75·bot · ถึงขอบล่างคงที่ .75·bot (ปลายทางที่ mask = 0 พอดีจึงจางหายเอง) · จุดเริ่ม --hd-top อยู่ที่ --hd-over = ขอบบนเดิมของกล่อง */
.page > h1::after,.tophd::after{background:linear-gradient(rgb(0 0 0 / var(--hd-top)) var(--hd-over),rgb(0 0 0 / var(--hd-bot)) calc(100% - var(--hd-fade)),rgb(0 0 0 / calc(var(--hd-bot) * .7)) calc(100% - var(--hd-fade) * .7),rgb(0 0 0 / calc(var(--hd-bot) * .75)) calc(100% - var(--hd-fade) * .3),rgb(0 0 0 / calc(var(--hd-bot) * .75)));-webkit-backdrop-filter:blur(calc(var(--hd-blur) / 3));backdrop-filter:blur(calc(var(--hd-blur) / 3));
  -webkit-mask-image:linear-gradient(#000 calc(100% - var(--hd-fade) * .7),rgb(0 0 0 / .4) calc(100% - var(--hd-fade) * .3),transparent);
  mask-image:linear-gradient(#000 calc(100% - var(--hd-fade) * .7),rgb(0 0 0 / .4) calc(100% - var(--hd-fade) * .3),transparent)}
.tophd h1{margin:0 0 6px;padding-left:0;padding-right:76px}
/* OD-252: เลื่อนหน้าเกิน 2px (body.hd-min · ui.js initDock) → หัวข้อย่อเป็นแถบเล็ก (large title → inline title) · กฎรากเดียวทุกหน้าทั้ง 3 แอป ไม่มีกฎต่อหน้า
   ไม่เปลี่ยนขนาดเลย์เอาต์ของกล่องใดเลย (กล่อง 74 + safe, line-height 36, padding เท่าเดิมตลอด → พี่น้องไม่ reflow เนื้อหาไม่ขยับ) ขยับด้วย transform ล้วน:
   · กล่อง (.page > h1 / .tophd) translateY(−18) → กึ่งกลางบรรทัด 22+18=40 ขึ้นมาอยู่ 22 จากบน (= กึ่งกลางหัวข้อเล็ก 11+22/2 ของ OD-251) · ปุ่มภาษาเสมอบรรทัดเดียวกันด้วย −18 เท่ากัน
   · พื้น/เบลอ (::before ::after) ย่อขอบล่างขึ้นอีก (30−18)=12 → ขอบล่างรวมขึ้น 30 (74 → 44) · h1 เดี่ยวสเกลแนวตั้ง .55 รอบขอบล่าง ช่วงเฟด 40 → 22 (เท่า OD-251 เดิม ตัวหนังสือไม่ลอยบนพื้นจาง) · .tophd สูงพอ คงช่วงเฟด 40
   · .steps ใน .tophd ขึ้นรวม 30 ชิดหัวข้อเล็ก (กล่องพา −18 แล้ว เพิ่มอีก −12)
   ตัวหนังสือ: เหลือ font-size/weight เท่านั้นที่วาดใหม่ — h1 ความสูงตายตัว (line-height 36 คงที่) ขนาดตัวอักษรเปลี่ยนไม่ดันอะไร, ห่อ HTML เพิ่มให้ transform ไม่ได้โดยไม่แตะทุกหน้า */
.page > h1{--hd-k:.55;transition:transform var(--dock-t) var(--dock-ease),font-size var(--dock-t) var(--dock-ease),font-weight var(--dock-t) var(--dock-ease)}
.tophd{transition:transform var(--dock-t) var(--dock-ease)}
.tophd > h1{transition:font-size var(--dock-t) var(--dock-ease),font-weight var(--dock-t) var(--dock-ease)}
.tophd .steps{transition:transform var(--dock-t) var(--dock-ease)}
body.hd-min .page > h1,body.hd-min .tophd{transform:translateY(calc(var(--hd-up) * -1))}
body.hd-min .page > h1,body.hd-min .tophd > h1{font-size:var(--hd-title-min-fs);font-weight:var(--hd-title-min-fw)}
body.hd-min .page > h1::before,body.hd-min .page > h1::after,body.hd-min .tophd::before,body.hd-min .tophd::after{transform:translateY(calc(var(--hd-up) - var(--hd-cut))) scaleY(var(--hd-k,1))}
body.hd-min .tophd .steps{transform:translateY(calc(var(--hd-up) - var(--hd-cut)))}
body.hd-min .lang span{transform:translateY(calc(var(--hd-up) * -1))}
/* ข้อความย่อยข้างหัวข้อตอนย่อ (OD-290 f/g · เฉพาะหน้า Menu กับ Membership): h1.hd-row = แถว flex [ชื่อ .hd-t][.hd-sub] · ตอนกางจางหาย (opacity 0 · อยู่ในแถวแต่ไม่กินที่ของชื่อ ไม่ดันความสูง เพราะบรรทัดไม่ตัดคำ) · ย่อ (body.hd-min) แล้วจางเข้า+เลื่อนเข้าจากขวาเล็กน้อย (transform/opacity ล้วน)
   ขวาสุดเว้น 76px ให้ปุ่มภาษาด้วย padding ของ h1 เอง (กฎ h1 ฐาน) · ตัวเล็กกว่าหัวข้อย่อ (11.5px) สูงสุด 2 บรรทัด ล้นเกิน = ... */
h1.hd-row{display:flex;align-items:center;gap:var(--sp-3)}
.hd-t{flex:0 1 auto}
/* ชื่อหน้าขยับ (OD-312/335 · ชื่อคลาสมี hd- นำหน้า เพราะ .rw/.sr/.fl ชนกับของแอปสตาฟ · customer/title-motion.js ห่อ h1 ครั้งเดียวตอนเริ่ม): .hd-t = [.hd-sg ซ้าย][.hd-rw > .R][.hd-sg ขวา] · .hd-rw ห่อ .R เพื่อเลื่อนได้โดยไม่ทับ transform หมุน −9° + กระดิกของ .R · .hd-sg ล็อกความกว้างระหว่าง decode (JS) · .hd-sr = ข้อความจริงสำหรับตัวอ่านหน้าจอ (.hd-t เป็น aria-hidden) */
.hd-sg,.hd-rw{display:inline-block;white-space:nowrap}
.hd-rw.hd-fl{transition:transform clamp(var(--hm-glide-lo),var(--hm-glide-t),var(--hm-glide-hi)) var(--hm-spring)}   /* ค่าเริ่มต้น = สปริงเดียวกับ selector ของ dock (โทเคน --hm-*) · ใส่ .hd-fl ตอน R กำลังเลื่อนเท่านั้น (JS ถอดเมื่อจบ) · lite/ลดการเคลื่อนไหว = JS ไม่ใส่ .hd-fl เลย */
.hd-sr{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%)}
.hd-sub{flex:1 1 0;min-width:0;display:grid;font-size:11.5px;font-weight:var(--fw-medium);line-height:var(--lh-4);letter-spacing:0;text-transform:none;color:var(--mu);opacity:0;transform:translateX(8px);pointer-events:none;transition:opacity var(--dock-t) var(--dock-ease),transform var(--dock-t) var(--dock-ease)}
.hd-sub > *{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
body.hd-min .hd-sub{opacity:1;transform:none}
/* sw-still = มาถึงหน้าด้วยการปัดแล้ว: หน้าอยู่ที่ตำแหน่งแล้ว ไม่เล่นอนิเมชันเข้าซ้ำ (app.js onRoute ตั้ง) */
body.sw-still{--pg-fade:none}
body.sw-still :where(.page.cur) > :where(:not(.cta,.toast,#undo,.tophd,h1,[data-mv])),body.sw-still :where(.page.cur) > :where([data-mv]) > :where(:not(.cta)){animation:none}
@media (prefers-reduced-motion:reduce){.page > h1,.tophd,.tophd > h1,.tophd .steps,.page > h1::before,.page > h1::after,.tophd::before,.tophd::after,.lang span,.hd-sub{transition:none}h1 .R{animation:none}:where(.page.cur) > :where(:not(.cta,.toast,#undo,.tophd,h1,[data-mv])),:where(.page.cur) > :where([data-mv]) > :where(:not(.cta)){animation:none}}   /* OD-252: ลดการเคลื่อนไหว = สถานะเปลี่ยนทันที ไม่มีอนิเมชันที่เพิ่ม */
/* ===== docscroll (เฉพาะแอปลูกค้า · <body class="docscroll">): ให้ "เอกสาร" เป็นตัวเลื่อน ไม่ใช่ .page ที่ fixed ===== */
/* ต้นเหตุ: .page เป็น position:fixed + overflow ของตัวเอง และ body overflow:hidden → Safari ไม่เห็นการเลื่อนของเอกสารเลยจึงไม่พับแถบ URL · โหมดนี้หน้าไหลตามปกติ (หนึ่งหน้าที่ .cur = display:block ที่เหลือ none) แล้ว html/body เลื่อนเอง
   ไม่แตะ: h1/.tophd sticky (อ้างเอกสารแทน) · .dock .cta .toast fixed (อ้างจอ) · แอปสตาฟ/POS ไม่มี class นี้ = โครง fixed เดิมทุกอย่าง
   min-height 100dvh ให้หน้าสั้นยังเต็มจอ (ฟุตเตอร์ #home ดันลงล่างด้วย margin-top:auto) · 100vh บรรทัดแรกไว้ Safari ที่ยังไม่รู้จัก dvh
   */
body.docscroll{overflow-x:hidden;overflow-y:visible;overscroll-behavior-y:contain}   /* x ตัดเพราะลูกที่ translate (pg-slide/ปัด) ทำเอกสารกว้างเกินจอชั่วคราว · y contain = pull-to-refresh ของ Chrome/Android ไม่ล้างฟอร์ม (iOS Safari ไม่กระทบ แถบ URL ยังหด) */
.docscroll .page{position:static;overflow:visible;overscroll-behavior:auto;min-height:100vh;min-height:100dvh}
/* ===== ราง ปัดซ้าย-ขวา (OD-356 · ui.js swipeTrack): แทร็กแนวนอน scroll-snap ของเบราว์เซอร์ — เทคนิคเดียวกับ .mn-track ของหน้าเมนู (เบราว์เซอร์ไล่นิ้วเอง ไม่มี JS ไล่นิ้ว ไม่ animate เลย์เอาต์) =====
   ใช้กับ: ขั้นจอง 1–3 (#rsTrack · หน้า .page ทั้งสาม) · Reserved (#rvTrack) · Membership (#mbTrack) — เอกสารยังเป็นตัวเลื่อนแนวตั้งตัวเดียว (Safari พับแถบ URL ได้ · dock/หัวข้อย่ออ่านจากเอกสารเหมือนเดิม)
   .sw-cur = หน้าที่ดูอยู่ (JS) · หน้าข้างเคียงสูง 0 (เนื้อหายังล้นลงมาให้เห็นตอนปัด แต่ไม่ดันความสูงเอกสาร) และยกลงเท่า scrollY (--sy ตั้งตอนแตะ) ให้หัวหน้าข้างเคียงตรงขอบบนจอแทนที่จะเป็นส่วนล่างที่ว่าง
   data-fwd="no" = ด่านไปหน้าถัดไปไม่ผ่านตอนแตะ → ซ่อนหน้าถัดไป (ปัดแล้วเด้งกลับเฉยๆ ไม่โผล่เนื้อหาที่ยังเข้าไม่ได้) */
.sw-track{display:flex;align-items:flex-start;overflow-x:auto;overflow-y:hidden;scroll-snap-type:x mandatory;scrollbar-width:none;overscroll-behavior-x:contain;touch-action:pan-x pan-y;-webkit-overflow-scrolling:touch}
.sw-track::-webkit-scrollbar{display:none}
.sw-track > *{flex:0 0 100%;box-sizing:border-box;min-width:0;scroll-snap-align:start;scroll-snap-stop:always}   /* stop:always = สะบัดแรงก็ไม่ข้ามหน้า */
.sw-track > :not(.sw-cur){height:0;translate:var(--sy,none)}
.sw-track[data-fwd="no"] > .sw-cur ~ *{visibility:hidden}
.docscroll .sw-track > .page{display:block;min-height:0}   /* ขั้นจอง: ทั้งสามหน้าอยู่ในราง (หน้า .cur เดียวที่มีผลต่อ route/ปุ่มกลาง) */
.sw-track > [hidden],.docscroll .sw-track > .page[hidden]{display:none}   /* หน้าที่ข้ามไป (Modify ไม่ผ่านโปร = ไม่มีหน้า 2 · Membership นอกมุมมองสมุด) ไม่อยู่ในราง */
.sw-bleed{margin-inline:calc(-1 * var(--side))}   /* ราง เต็มความกว้างจอ (ยื่นทับ padding ข้างของ .page) → หน้าไหลออกขอบจอ ไม่ถูกตัดที่ขอบ padding */
.sw-pad > *{padding-inline:var(--side)}
.rs-flow > .sw-track{min-height:calc(100vh - var(--rs-hd));min-height:calc(100dvh - var(--rs-hd))}   /* รางสูงเท่าที่เหลือของจอ: หน้าสั้น (ขั้น 2) ก็ปัดได้ทั่วจอ + เอกสารสูงเท่าจอเหมือนเดิม (ไม่เลื่อนเกิน) */
.sw-fill{--sw-above:calc(var(--hd-box) + 76px + var(--page-end) + 100px);min-height:calc(100vh - var(--sw-above));min-height:calc(100dvh - var(--sw-above))}   /* Reserved/Membership: รางสูงเท่าที่เหลือหลังหัวข้อ+แท็บตรึง (76) และช่องใต้ราง (padding ล่างของ .page + 100 ให้แถวติดต่อ/แบนเนอร์) → รายการสั้นก็ปัดได้ทั่วหน้า โดยหน้าสั้นไม่เลื่อนเกิน */
/* ขั้นจอง 1–3: หัวข้อตรึง (.tophd) อยู่นอกราง — sticky อ้างตัวเลื่อนที่ใกล้สุด ถ้าอยู่ในราง (overflow-x) จะไม่ตรึง · เหลือหัวของขั้นปัจจุบันชุดเดียว (data-step ตั้งตาม route) */
.rs-flow{display:none;padding-inline:var(--side);--rs-hd:calc(var(--hd-box) + 83px)}   /* --rs-hd = หัวข้อ+แถบขั้น+ช่องไฟ ทั้งกล่อง (วัดจากจริง: 74 + 83 = 157 ที่ 390px · EN/TH เท่ากัน) */
.rs-flow.on{display:block}
.rs-flow > .tophd{display:none}
.rs-flow[data-step="1"] > .tophd[data-s="1"],.rs-flow[data-step="2"] > .tophd[data-s="2"],.rs-flow[data-step="3"] > .tophd[data-s="3"]{display:block}
.steps{list-style:none;padding:0;display:flex;margin:0}   /* หัวข้อ + แถบขั้น 1–4 ตรึงที่เดิมตอนเลื่อนลง (เจ้าของสั่ง) · ความสูงหัวข้อ = 22+36+22 → top ของแถบขั้น = 74 (ทับ padding ล่างของหัวข้อ 6px ตามระยะเดิม) */
.steps li{flex:1;position:relative;display:grid;justify-items:center;gap:6px;font-size:var(--fs-2);white-space:nowrap;color:var(--dim);text-align:center}
.steps li a{display:grid;justify-items:center;gap:6px;width:100%;min-height:var(--tap);color:var(--mu)}
.steps i{position:relative;width:28px;height:28px;border-radius:var(--r-round);background:var(--tile2);display:grid;place-items:center;font-style:normal;font-size:var(--fs-5);font-weight:var(--fw-semibold);color:var(--mu)}
.steps li:not(:last-child)::after{content:"";position:absolute;top:14px;left:calc(50% + 20px);right:calc(-50% + 20px);height:1px;background:var(--line)}
/* ทำแล้ว = แดง CTA + glow นิ่ง ตัวเลขขาว (ไม่เปลี่ยนเป็นติ๊ก · OD-284 ข้อยกเว้นของตาราง OD-276) · วง go ระหว่างรอจอง (.wait) สั่น/พองแต่คงสีเทาเดิม — แดงเมื่อจองสำเร็จเท่านั้น (ตอนนั้นหน้า 4 ทำแล้วทั้ง 4 วง · OD-298) */
.steps .done i,.steps.waiting .on i{background:var(--red);color:#fff;box-shadow:var(--glow-red)}
.steps i.go{font-size:var(--fs-3);font-weight:var(--fw-bold);letter-spacing:0;line-height:var(--lh-1);padding-bottom:1px}   /* "go" ตัวพิมพ์เล็กพอดีวง 28px เท่าวงอื่น (g มีหางลง จึงยกขึ้น 1px ให้ดูกลาง) */
.steps .done::after,.steps.waiting .on::after{background:rgb(var(--accent-rgb) / .6)}   /* เส้นเชื่อมของขั้นที่ทำแล้ว = แดงจาง */
/* หน้า 3 ระหว่างรอจอง (.waiting ตั้งโดย setCta3Busy · OD-290): วงของขั้นที่กำลังทำใช้กฎ "ทำแล้ว" ด้านบน (แดง + glow นิ่ง + เส้นเชื่อมแดงจาง) ส่วนวง go ด้านขวาสั่นต่อ · ความจำเพาะ (0,3,1) สูงกว่ากลุ่ม .on i ท้ายไฟล์ จึงชนะเอง */
.steps.waiting .on i{animation:none}   /* นิ่งเหมือนวง done (ไม่หายใจ) */
/* ค่าใช้จ่าย: วงเดียว 28px · transform/opacity ล้วน (compositor ไม่ re-layout/repaint) · เล่นเฉพาะตอนรอจอง (hold) หรือครั้งเดียวตอนจองสำเร็จ (pop + ring) · will-change เปิดเฉพาะตอนเล่น
   reduced-motion / html.lite ตั้ง --sel-anim:none (กลุ่มเดิม) → ไม่เล่นอะไร เหลือแต่สีสถานะ */
@keyframes go-hold{0%,100%{transform:scale(1) rotate(0)}10%{transform:scale(1.07) rotate(-8deg)}20%{transform:scale(1.14) rotate(8deg)}30%{transform:scale(1.22) rotate(-7deg)}40%{transform:scale(1.3) rotate(7deg)}50%{transform:scale(1.35) rotate(-8deg)}60%{transform:scale(1.3) rotate(8deg)}70%{transform:scale(1.22) rotate(-6deg)}80%{transform:scale(1.14) rotate(6deg)}90%{transform:scale(1.06) rotate(-4deg)}}
@keyframes go-pop{0%{transform:scale(1.45)}55%{transform:scale(.92)}100%{transform:scale(1)}}
@keyframes go-ring{from{transform:scale(1);opacity:.6}to{transform:scale(2.2);opacity:0}}
.steps i.wait{z-index:var(--z-1);transform-origin:center;will-change:transform;animation:var(--sel-anim,go-hold) .9s var(--ease-inout) infinite}   /* z-index: วงล้นช่องได้ ทับเพื่อนบ้านโดยไม่ดันเลย์เอาต์ */
.steps i.pop{z-index:var(--z-1);will-change:transform;animation:var(--sel-anim,go-pop) .55s var(--spring)}
.steps i.pop::after{content:"";position:absolute;inset:0;border-radius:var(--r-round);box-shadow:inset 0 0 0 2px rgb(var(--accent-rgb) / .8);opacity:0;pointer-events:none;will-change:transform,opacity;animation:var(--sel-anim,go-ring) .55s var(--ease-out)}   /* วงแหวนขยายจาง 1 ครั้ง */
.steps .on{color:#fff}.steps .on i{background:#fff;color:#000}   /* กำลังทำ = ขาวทึบ + แสงขาว (กลุ่ม glow ท้ายไฟล์) */
/* ===== ส่วนประกอบ ===== */
[hidden]{display:none!important}                                            /* hidden ต้องชนะ display ของ class ทุกตัว (UA stylesheet แพ้ .sec/.cap/.cta) */
.sec{display:grid;gap:14px;margin-bottom:var(--sp-9)}
.sec h2{display:flex;align-items:center;gap:10px;font-size:var(--fs-9);font-weight:var(--fw-semibold);letter-spacing:-.1px;position:relative}
.sec h2>.ic{width:20px;height:20px;color:var(--mu)}   /* แอปสตาฟยังใช้ <h2><i class="ic"> เปล่า (แอปลูกค้าใช้ .rs-n แล้ว) — อย่าลบ */
.cap .cn{font-variant-numeric:tabular-nums}   /* จำนวนในแคปซูล (Upcoming (2)) เปลี่ยนหลักแล้วความกว้างตัวเลขไม่ต่าง · ความกว้างแคปซูลล็อกโดยกริดอยู่แล้ว */
.sec h2 .due{margin-left:auto;font-size:var(--fs-11)}
.hint{font-size:var(--fs-5);color:var(--dim);line-height:var(--lh-8)}
.row{display:flex;gap:var(--sp-3);align-items:center}
.big{font-size:var(--fs-12);font-weight:var(--fw-semibold);line-height:var(--lh-5)}
.status{font-size:var(--fs-3);font-weight:var(--fw-semibold);display:inline-flex;align-items:center;gap:6px;white-space:nowrap}
.status::before{content:"";width:7px;height:7px;border-radius:var(--r-round);background:currentColor}
.status.red{color:var(--red-text)}.status.ok{color:var(--ok)}.status.ok::before{background:var(--ok)}.status.mu{color:var(--mu)}
.btn{height:54px;width:100%;border-radius:var(--r-pill);background:#fff;color:#000;font-size:var(--fs-9);font-weight:var(--fw-semibold);display:flex;align-items:center;justify-content:center;gap:6px}
.btn.line{background:none;color:#fff;box-shadow:inset 0 0 0 1px #3a3a3c}
.btn.off{background:var(--tile2);color:var(--dim)}
/* กรอบโฟกัสคีย์บอร์ด (WO-380 ข้อ 7): ทุกปุ่ม/ลิงก์/ช่อง/ปุ่ม role=button — :focus-visible = ขึ้นเมื่อใช้คีย์บอร์ดเท่านั้น (แตะบนมือถือไม่ขึ้น) · :where = ความจำเพาะ 0 ให้กฎเฉพาะ (outline-offset ติดขอบ · ช่องกรอกมีเส้น/วงของตัวเอง) ทับได้ · สี/ความหนา/ระยะ = --focus-* ชุดเดียว (ไม่เขียนตัวเลขกรอบที่อื่น) */
:where(a[href],button,input:not([type="hidden"]),select,textarea,summary,[role="button"],[tabindex]:not([tabindex="-1"])):focus-visible{outline:var(--focus-w) solid var(--focus-c);outline-offset:var(--focus-off)}
/* ไม่มี outline:none รายตัวบนปุ่ม/ลิงก์/ช่อง (ความจำเพาะสูงกว่ากฎกลางจึงกลบวงโฟกัสคีย์บอร์ด — Codex P2 WO-380): แตะ/คลิกเมาส์ที่ไม่ใช่ :focus-visible ซ่อนวงด้วยกฎนี้เดียว · ช่องกรอกมีสไตล์ :focus ของตัวเอง (เส้นล่าง/วงใน) อยู่แล้ว */
:where(a[href],button,input,select,textarea,summary,[role="button"]):focus:not(:focus-visible){outline:none}
.cta{position:fixed;left:0;right:0;margin:0 auto;width:min(var(--cta-w),calc(100% - 2*var(--side)));height:var(--cta-h);padding:0 var(--cta-pad);box-sizing:border-box;font-size:var(--fs-8);bottom:var(--cta-b);z-index:var(--z-5)}   /* C13: CTA ทุกหน้า/สถานะขนาดเดียว --cta-w × --cta-h กลางจอ สั้นกว่า dock · ป้ายทุกอัน (EN+ไทย) ต้องกว้างไม่เกิน --cta-w − 2×--cta-pad (เทสต์ wo380 วัดด้วยฟอนต์จริง) */
.cta .cta-t{white-space:nowrap}
input.f,textarea.f{width:100%;border:0;background:none;padding:14px 0;font-size:var(--fs-9);box-shadow:0 1px 0 var(--line);font-family:var(--font);color:var(--tx)}
input.f.auto{color:var(--mu)}            /* ค่าจาก LINE: เทา · แตะ = พิมพ์ใหม่ (ขาว) */
input.f.auto:focus{color:#fff}
textarea.f{min-height:72px;resize:none}
input.f:focus,textarea.f:focus{box-shadow:0 1px 0 var(--tx)}
input.f::placeholder,textarea.f::placeholder{color:var(--dim)}
.rules{padding-left:18px;display:grid;gap:var(--sp-2);font-size:var(--fs-6);color:var(--mu);line-height:var(--lh-7)}
.rules li::marker{color:var(--dim)}
.agree{display:flex;gap:var(--sp-3);align-items:center;font-size:var(--fs-7);color:var(--mu);min-height:var(--tap)}
.agree input{appearance:none;-webkit-appearance:none;width:26px;height:26px;margin:0;border-radius:var(--r-round);box-shadow:inset 0 0 0 1.5px #3a3a3c;display:grid;place-items:center;transition:background var(--t-6) var(--ease),box-shadow var(--t-6) var(--ease)}
.agree input::before{content:"";width:100%;height:100%;background:#fff;-webkit-mask:var(--tick-m) center/contain no-repeat;mask:var(--tick-m) center/contain no-repeat;opacity:0}   /* ติ๊กขาว = มาสก์ check ตัวเดียวกับ .tick (กึ่งกลางเป๊ะ) */
.agree input:checked{background:var(--sel-glass);box-shadow:var(--sel-glass-rim)}   /* ติ๊ก I Agree = selector แดง dock (OD-284): สูตรกระจกแดงเดียวกับ .cap .sel */
.agree input:checked::before{opacity:1}
.kv{display:grid;grid-template-columns:1fr auto;gap:var(--sp-3);font-size:var(--fs-7);margin:0}
.kv dt{color:var(--mu)}.kv dd{margin:0;text-align:right;color:#fff;font-weight:var(--fw-medium)}
.kv dd.mu{color:var(--mu);font-weight:var(--fw-regular)}
.tile{background:var(--tile);border-radius:var(--r-lg);padding:var(--sp-4);display:grid;gap:var(--sp-3)}
.total{display:flex;justify-content:space-between;align-items:baseline;padding-top:var(--sp-3);box-shadow:inset 0 1px 0 var(--tile2);font-size:var(--fs-9)}
.total b{font-size:var(--fs-14);font-weight:var(--fw-semibold)}
.acc{font-size:var(--fs-14);font-weight:var(--fw-semibold);letter-spacing:1px;font-variant-numeric:tabular-nums}
.cp{position:relative;width:32px;height:32px;border-radius:var(--r-round);display:inline-grid;place-items:center;color:#fff;box-shadow:inset 0 0 0 1px var(--line);vertical-align:middle}
.cp .ic{width:var(--ic-2);height:var(--ic-2)}
.tile .btn.line{margin-top:var(--sp-1)}
.tile.list{padding:0 var(--sp-4)}
.tile.list>a,.tile.list>span{display:flex;align-items:center;gap:var(--sp-3);min-height:54px;color:#fff;font-size:var(--fs-8);box-shadow:0 1px 0 var(--tile2)}
.tile.list>*>span{flex:1;white-space:nowrap}                               /* ป้ายแถวไม่พับ · คำอธิบาย (small) พับได้ (375px) */
.tile.list small{text-align:right}
.tile.list .ic{width:var(--ic-4);height:var(--ic-4);color:var(--mu);flex:none}
.tile.list>span.off,.tile.list>span.off .ic{color:var(--dim)}
.tile.list>*:last-child{box-shadow:none}
.tile.list small{color:var(--mu);font-size:var(--fs-6)}
.tile.list small::after{content:"›";margin-left:10px;color:var(--dim);font-size:var(--fs-10)}
/* แคปซูล + selector แก้วแดงเลื่อน */
.cap{--selx:0px;position:relative;display:grid;grid-template-columns:repeat(3,1fr);background:var(--dg-surface);box-shadow:var(--dg-line);border-radius:var(--r-pill);padding:var(--sp-1);isolation:isolate}
.cap.two{grid-template-columns:1fr 1fr}
.cap input{display:none}
.cap label{position:relative;z-index:var(--z-1);min-height:48px;display:grid;place-items:center;align-content:center;line-height:1.15;font-size:var(--fs-6);font-weight:var(--fw-medium);color:var(--mu);cursor:pointer}
.cap label small{font-size:var(--fs-2);color:var(--dim)}
.cap input:checked + label,.cap input:checked + label small{color:#fff}   /* ตัวเลือกที่เลือก = ตัวหนังสือขาวสว่างบน selector แดง (ทุก .cap) · เคยอยู่บนบรรทัดของ .vm แล้วหายตอนลบ .vm (WO-349) → ห้ามผูกกับกฎอื่น */
.cap .sel{position:absolute;top:4px;bottom:4px;left:4px;width:calc((100% - 8px) / 3);border-radius:var(--r-pill);
  }   /* OD-232/262: ตัวเลือกบนแคปซูล = แก้วแดงโปร่งแสง (กฎ .glass-red ข้างบนที่เดียว) + glow หายใจ (บล็อกท้ายไฟล์) */
.cap.two .sel{width:calc((100% - 8px) / 2)}
/* แคปซูลแท็บตรึงใต้หัวข้อ (OD-355): หน้าเมนู (.mn-head ของ menu.css) กับหน้า Reserved (.cap.tabs-pin) ใช้กฎเดียวกันตรงนี้ · ตำแหน่งตรึง = ใต้กล่องหัวข้อ (--hd-box) + 6 · หัวข้อย่อ (body.hd-min) แล้วตามขึ้นเท่ากัน (--hd-cut) */
:root{--hd-box:calc(74px + env(safe-area-inset-top))}
.cap.tabs-pin{position:sticky;top:calc(var(--hd-box) + 6px);z-index:var(--z-sticky)}
.mn-head,.cap.tabs-pin{transition:transform var(--dock-t) var(--dock-ease)}
body.hd-min .mn-head,body.hd-min .cap.tabs-pin{transform:translateY(calc(var(--hd-cut) * -1))}
@media (prefers-reduced-motion:reduce){.mn-head,.cap.tabs-pin{transition:none}}
#found{display:block}   /* sticky ใน grid ถูกจำกัดแค่แถวของตัวเอง → ใช้บล็อก + ระยะ 14 ใต้แท็บ (เท่า gap เดิม) */
#found>.cap.tabs-pin{margin-bottom:14px}
/* OD-309: ปุ่ม Demo ของสเตจจิ้ง — กลม 44px ทึบ ลอย "ขวา เหนือแถวปุ่มกลาง (.cta)" : ส่วนที่ติดจอทั้งหมด (หัวข้อ · ปุ่มภาษา · .cta · ดอค) อยู่คนละช่วงแนวตั้งกับปุ่มนี้ ทุกความกว้าง 320–768
   (CTA บนสุด = ขอบดอค + สูงดอค + 18 + 52 · ปุ่มนี้เริ่มสูงกว่านั้น 12px · ฝั่งขวา เพราะไอคอนการ์ด/วงกลมหัวข้ออยู่ซ้าย) · z-index เหนือเนื้อหา/CTA/ดอค ต่ำกว่าปุ่มภาษา/toast/overlay */
.demo{position:fixed;right:10px;bottom:calc(var(--cta-top) + 12px);z-index:var(--z-demo);width:var(--tap);height:var(--tap);padding:0;border-radius:var(--r-round);display:grid;place-items:center;font-size:var(--fs-3);font-weight:var(--fw-semibold);color:#fff;background:#26272b;box-shadow:inset 0 0 0 1px rgb(255 255 255 / .22),0 2px 8px rgb(0 0 0 / .5)}
/* แผ่น Demo: overlay ของ ui.js (.qrbig · แตะนอกการ์ด/✕/Esc/ปัดลง/Back ปิด) · แผ่นทึบสีการ์ด (--tile) ชิดล่างจอ ไม่ใช้กระจก · ฉากหลังเข้มพอไม่ให้หัวข้อทะลุ · สูงไม่เกิน 70vh เลื่อนในตัว · เคารพ safe-area ล่าง
   ชื่อคลาสของแผ่น = demosheet (ห้ามใช้ .demo ซ้ำกับปุ่ม: เคยทำให้ overlay หดเป็นกล่อง 44px มุมซ้ายบน) */
.qrbig.demosheet{place-items:end center;padding:0;background:rgb(0 0 0 / .6)}
.demo-card{width:min(100%,430px);max-height:70vh;max-height:70dvh;overflow:auto;overscroll-behavior:contain;display:grid;gap:var(--sp-2);padding:var(--sp-2) var(--sp-4) calc(16px + env(safe-area-inset-bottom));border-radius:24px 24px 0 0;background:var(--tile);box-shadow:0 -1px 0 var(--line);animation:demo-up var(--t-8) var(--ease)}
@keyframes demo-up{from{transform:translateY(100%)}}
@media (prefers-reduced-motion:reduce){.demo-card{animation:none}}
.demo-card header{position:sticky;top:0;z-index:var(--z-1);display:flex;align-items:center;justify-content:space-between;min-height:52px;margin:0 -16px;padding:0 var(--sp-2) 0 var(--sp-4);background:var(--tile);font-size:var(--fs-9);font-weight:var(--fw-semibold)}
.demo-x{width:var(--tap);height:var(--tap);display:grid;place-items:center;border-radius:var(--r-round);font-size:var(--fs-10);color:#fff;background:var(--dg-surface);box-shadow:var(--dg-line)}
.demo-list{display:grid;gap:var(--sp-2)}
.demo-list input{display:none}
.demo-list label{display:grid;align-content:center;gap:2px;min-height:56px;padding:10px var(--sp-4);border-radius:var(--r-lg);background:var(--dg-surface-card);box-shadow:var(--dg-line);color:var(--mu);font-size:var(--fs-5);line-height:var(--lh-5);cursor:pointer}
.demo-list label b{font-size:var(--fs-8);font-weight:var(--fw-semibold);color:var(--tx)}
.demo-list input:checked + label{color:#fff;background:var(--sel-glass);box-shadow:var(--sel-glass-rim),var(--sel-drop)}   /* แดงกระจกสูตรเดียวกับ .cap .sel (โทเคนชุดเดิม) */
.demo-list input:checked + label b{color:#fff}
/* toast กระจกดำ (เจ้าของสั่ง: ไม่ใช่แดง) */
.toast{display:none;position:fixed;top:calc(14px + env(safe-area-inset-top));left:24px;right:24px;z-index:var(--z-toast);padding:14px 18px;border-radius:var(--r-pill);color:#fff;font-size:var(--fs-7);font-weight:var(--fw-medium);text-align:center;
  background:var(--dg-surface-card);box-shadow:var(--dg-line),0 14px 36px rgb(0 0 0 / .5)}
.toast.on{display:block}   /* router (route.js) ใส่ .on ให้ toast ที่ตรงกับ path ปัจจุบัน (/closed · /open-in-line) แทน :target เดิม */
.toast .cn{display:block;margin-top:var(--sp-1);font-size:var(--fs-5);font-weight:var(--fw-regular);overflow-wrap:anywhere}.toast .cn:empty{display:none}   /* โน้ตวันปิด (ไม่บังคับ) */
/* ===== นอก LINE ยังไม่ล็อกอิน (OD-214): ดูได้ทุกหน้า ทำไม่ได้ — ช่องจางและกดไม่ได้ (เลย์เอาต์เดิม) · ของ guest-only โผล่ · CTA กลายเป็น Log In with LINE ===== */
body:not(.guest) .g-only{display:none}
body.guest .g-hide{display:none}
body.guest #reserve .rs-card{opacity:var(--op-4)}
body.guest #reserve .rs-card :is(input,textarea,button,label,a:not(.off)){pointer-events:none}   /* a.off = วันปิดจอง: แตะดูเหตุผล (toast) ได้แม้ยังไม่ล็อกอิน · อ่านอย่างเดียว ไม่เสี่ยง */
/* ยังไม่ล็อกอิน (เจ้าของสั่ง): ทุกปุ่มกลางเป็นปุ่ม Log In with LINE สีเขียวของ LINE · แตะช่องกรอกตอนยังไม่ล็อกอิน = เด้ง 1 ที (.nudge) · โฮสต์ไม่มี LIFF ก็โชว์ปุ่ม (กด = toast บอกว่ายังล็อกอินไม่ได้) */
:root{--lineg:rgb(var(--line-rgb))}
#cta.login{background:var(--lineg);color:#fff;--g:var(--glow-line-strong);--g-up:var(--glow-line-strong-up);box-shadow:var(--g)}
#cta.login:active{background:#05b34c}
.cta.nudge{animation:cta-nudge var(--t-9) var(--ease)!important}
@keyframes cta-nudge{0%{transform:scale(1)}35%{transform:scale(1.1)}65%{transform:scale(.97)}100%{transform:scale(1)}}
.btn.linelogin{background:var(--lineg);color:#fff}
@media (prefers-reduced-motion:reduce){.cta.nudge{animation:none!important}}
.sec h2 .via{margin-left:auto;font-size:var(--fs-3);font-weight:var(--fw-medium);color:var(--mu)}
.out .lnk{background:none;border:0;padding:0;min-height:var(--tap);margin:-10px 0;display:inline-flex;align-items:center;font:inherit;font-size:var(--fs-3);color:var(--mu);margin-left:var(--sp-3);text-decoration:underline}
/* ===== หน้า 1 จอง ===== */
/* การ์ดหน้าจอง (OD-230/234): ทุกหัวข้อเป็นการ์ดกางตลอด · วงกลมหน้าหัวข้อ = ไอคอนเดิมของหัวข้อ เปลี่ยนแค่สี: ว่าง = ขาวจาง · .done = เขียว · .miss = แดง (กด Next แล้วยังว่าง) · ค่าที่เลือกขึ้นมุมขวา
   prefix rs- เพราะ .card/.pill/.t/.v ชนชื่อใน staff.css (css-classes.test) · glow ของวงกลมผูกในบล็อกท้ายไฟล์ */
.rs-card{display:grid;gap:14px;margin-bottom:var(--sp-3);padding:14px var(--sp-4) var(--sp-4);border-radius:var(--r-xl);background:var(--tile)}
.rs-chd{display:flex;align-items:center;gap:var(--sp-3);min-height:34px}   /* สูงคงที่ 34 = ค่าว่าง/มีค่า/เม็ดวันที่ ไม่ดันเลย์เอาต์ */
.rs-n{flex:none;width:34px;height:34px;border-radius:var(--r-round);display:grid;place-items:center;background:var(--tile2);color:rgb(255 255 255 / .5);transition:color var(--t-8) var(--ease),background var(--t-8) var(--ease)}
.rs-n .ic{width:var(--ic-4);height:var(--ic-4)}
.mn-alg.done .rs-n,.rs-n.done,.rs-card.done .rs-n{color:#fff;background:var(--ok)}
.mn-alg.miss .rs-n,.rs-card.miss .rs-n{color:#fff;background:var(--red)}   /* ขาดข้อมูล = วงกลมแดง dock ทึบ ไอคอนขาว · ไม่มี glow (glow = CTA เท่านั้น) · OD-278 */
/* OD-286: Next ที่ยังไม่ครบ → วงกลมของการ์ดที่ขาดสั่นปฏิเสธ 1 ที (แบบ iOS) · ค่าใช้จ่าย: transform ล้วน (compositor) · วงกลมไม่กี่ตัว · เล่นครั้งเดียวต่อการกด (JS ใส่ class shake แล้วถอดตอนจบ) · --sel-anim:none (reduced-motion / html.lite) = ไม่เล่น กลุ่มเดียวกับ go-hold */
@keyframes rs-shake{0%,100%{transform:translateX(0)}17%{transform:translateX(-5px)}33%{transform:translateX(5px)}50%{transform:translateX(-4px)}67%{transform:translateX(4px)}83%{transform:translateX(-2px)}}
.mn-alg.miss .rs-n.shake,.rs-card.miss .rs-n.shake{animation:var(--sel-anim,rs-shake) .42s var(--ease-out)}
.rs-t{flex:1;font-size:var(--fs-9);font-weight:var(--fw-semibold);letter-spacing:-.1px}
.rs-v{font-size:var(--fs-6);color:var(--mu)}
.rs-card.done .rs-v{color:var(--tx)}
/* เม็ดวันที่แบบช่องวันที่ใน Settings ของ iPhone: input วันที่ของระบบซ้อนทับเต็มเม็ด แตะแล้วปฏิทินระบบขึ้น */
.rs-pill{position:relative;padding:var(--sp-2) var(--sp-3);border-radius:var(--r-pill);background:#2c2c2e;font-size:var(--fs-7);font-weight:var(--fw-medium);line-height:var(--lh-3);color:var(--tx);cursor:pointer}
.rs-pill::before{content:"";position:absolute;inset:-10px 0 0}   /* ภาพสูง 34 กด 44 · ขยายขึ้นด้านบนเท่านั้น (ด้านล่างติดแถวเลือกวัน = ต้องไม่ทับปุ่มวัน) */
.rs-pill input{position:absolute;inset:0;width:100%;height:100%;opacity:0;cursor:pointer;-webkit-appearance:none;appearance:none}
.rs-pill input:disabled{cursor:default}
.rs-pill input:disabled + span{opacity:var(--op-5)}   /* แก้ใบที่มีดริงก์ = ล็อกวัน (เหมือน .days.locked) */
.rs-card .days{margin:-12px -16px;padding:var(--sp-3) var(--sp-4);scroll-padding-inline:16px;   /* แถววันเต็มความกว้างการ์ด ปัดชนขอบการ์ด · scroll-padding = เม็ดแรก snap ที่ 16px ไม่ใช่ขอบที่จางอยู่ (OD-290 d) */
  -webkit-mask-image:linear-gradient(to right,transparent 0,#000 16px,#000 calc(100% - 16px),transparent 100%);mask-image:linear-gradient(to right,transparent 0,#000 16px,#000 calc(100% - 16px),transparent 100%)}   /* ขอบจาง 16px ตรงกับ padding: ตอนนิ่งเม็ดแรกอยู่หลังช่วงจางพอดี · เม็ดถัดไปโผล่ครึ่งเม็ดจางหาย = บอกว่าปัดได้ · mask ไม่เลื่อนตามเนื้อหา · ไม่ใช้ backdrop-filter/JS */
.days{display:flex;gap:var(--sp-2);overflow-x:auto;overscroll-behavior-x:contain;scrollbar-width:none;scroll-snap-type:x mandatory;margin:-12px calc(-1 * var(--side));padding:var(--sp-3) var(--side)}   /* ช่องว่าง 12px บน/ล่างให้ glow ของเม็ดที่เลือกไม่โดนตัด (margin ลบหักล้าง = เลย์เอาต์เท่าเดิม) */
.days::-webkit-scrollbar{display:none}
.days input{display:none}
.days a,.days label{flex:none;min-width:76px;height:66px;padding:0 var(--sp-3);border-radius:var(--r-2xl);background:var(--tile2);scroll-snap-align:start;display:grid;align-content:center;justify-items:center;gap:3px;color:var(--mu);cursor:pointer;transition:background var(--t-7) var(--ease)}
.days a small,.days label small{font-size:var(--fs-3)}
.days a b,.days label b{font-size:var(--fs-7);font-weight:var(--fw-semibold);color:#fff;white-space:nowrap}
.days input:checked + label{color:#fff}
.days a.off{opacity:var(--op-2)}
.days a.off b{text-decoration:line-through}
.step{display:flex;align-items:center;gap:var(--sp-3)}
.step button{width:54px;height:54px;border-radius:var(--r-round);background:var(--tile2);display:grid;place-items:center;font-size:var(--fs-14);color:#fff;flex:none}
.step input{flex:1;height:54px;border-radius:var(--r-pill);background:var(--sel-glass);box-shadow:var(--sel-glass-rim),var(--sel-drop);color:#fff;border:0;text-align:center;font-size:var(--fs-11);font-weight:var(--fw-semibold);-moz-appearance:textfield}   /* เลขจำนวนแขก = selector แดงกระจกสูตรเดียวกับแคปซูลวันที่ที่เลือก (OD-299) · − และ + ยังเป็นวงกลมเทา */
.step input{transition:background-color var(--t-7) var(--ease),box-shadow var(--t-7) var(--ease)}
.step input:focus,.step input:invalid{background:var(--tile2)}   /* OD-300: กำลังพิมพ์ / ค่าว่าง-นอกช่วงตอนออกจากช่อง = ช่องเทาเรียบ (เทาเดียวกับ input อื่น · ไม่มี glow) สลับสมูธ */
.step input:invalid{box-shadow:none}
.step input:focus{box-shadow:inset 0 0 0 1.5px var(--tx)}
.step input::-webkit-inner-spin-button,.step input::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}
.seats{display:none;grid-template-columns:repeat(4,1fr);gap:var(--sp-2)}
body:not([data-seatmap=off]) .seats{display:grid}
.seats span{aspect-ratio:1;border-radius:var(--r-sm);background:var(--tile2);display:grid;place-items:center;font-size:var(--fs-6);color:var(--mu)}
.seats span.x{opacity:var(--op-1)}
/* ===== หน้า 2 ดริงก์ ===== */
.promo{display:inline-flex;align-items:center;height:26px;padding:0 var(--sp-3);border-radius:var(--r-pill);margin:-14px 0 10px;font-size:var(--fs-2);font-weight:var(--fw-bold);letter-spacing:.12em;color:#fff;
  background:var(--dg-surface-card);box-shadow:var(--dg-line);position:relative;overflow:hidden}
.promo::after{content:"";position:absolute;inset:0;background:linear-gradient(100deg,transparent 30%,rgb(255 255 255 / .35) 50%,transparent 70%);transform:translateX(-100%);animation:sheen 3.2s var(--ease) infinite}
@media (prefers-reduced-motion:reduce){.promo::after{animation:none}}   /* แสงวิ่งวนไม่รู้จบ = ปิดเมื่อผู้ใช้ขอลดการเคลื่อนไหว */
@keyframes sheen{40%,100%{transform:translateX(100%)}}
.pitch{font-size:var(--fs-8);color:#c7c7cc;margin:0 0 var(--sp-6)}
.tabs{margin-bottom:var(--sp-2)}
.deals{gap:0}
/* หน้า 2 ของเสริม (OD-280 แบบ A · WO-330): หัวข้อ + แคปซูลลดสูงสุด + บรรทัดสิทธิ์เฉพาะจองล่วงหน้า · แถวสินค้า = ชิ้นกลาง product-row.js + สูตร CSS ใน customer/menu.css (OD-412) */
.ad-hd{display:flex;align-items:center;justify-content:space-between;gap:var(--sp-3);min-height:40px;margin:0 0 var(--sp-1)}
.ad-t{font-size:var(--fs-15);font-weight:var(--fw-bold);letter-spacing:-.4px;line-height:var(--lh-2)}
.ad-up{flex:none;font-size:var(--fs-3);font-weight:var(--fw-bold);color:#fff;background:var(--ok);padding:5px 11px;border-radius:var(--r-pill);white-space:nowrap}   /* แคปซูลใหญ่ชิ้นเดียวของหน้า: เขียว --ok ตัวขาว glow สีเดียวกับพื้น + หายใจ (บล็อก glow ท้ายไฟล์) */
.ad-up:empty{display:none}   /* ไม่มีราคาเทียบสักโปร = ไม่มีแคปซูล (ไม่เหลือจุดเรือง) */
.ad-note{margin:0 0 18px;font-size:var(--fs-6);color:var(--mu)}
.ad-chip{flex:none;margin-right:6px;padding:2px var(--sp-2);border-radius:var(--r-pill);background:var(--ok);color:#fff;font-size:var(--fs-2);font-weight:var(--fw-bold);white-space:nowrap}   /* ชิป −22%: พื้น --ok ตัวขาว glow + หายใจ */
.limit{font-size:var(--fs-5);color:var(--mu);margin-top:10px}
.edits{display:flex;gap:18px;margin:14px 0 var(--sp-9);font-size:var(--fs-6)}
.edits a{color:var(--mu)}
/* ยืนยันแล้ว: ติ๊กเขียว */
.okmsg{display:grid;justify-items:center;gap:14px;text-align:center;margin:-4px 0 var(--sp-7);color:#c7c7cc;font-size:var(--fs-7);line-height:var(--lh-8)}
.tick{width:72px;height:72px;border-radius:var(--r-round);background:var(--ok);position:relative}
/* ติ๊กในวงกลมเขียว (ทุกที่ที่ใช้ .tick: ลูกค้า + พนักงาน): กล่องมาสก์ = ทั้งวง (inset:0) และรูป --tick-m (ui.js · ICON.check) มี bbox กึ่งกลาง (12,12) ของ viewBox 24 → ติ๊กอยู่กลางวงเป๊ะ กว้าง ≈46% ของวง · ไม่ใช้ transform/ขอบหมุน */
.tick::after{content:"";position:absolute;inset:0;background:#fff;-webkit-mask:var(--tick-m) center/contain no-repeat;mask:var(--tick-m) center/contain no-repeat}
.soon{color:var(--mu);font-size:.85em;margin-left:.3em}   /* ป้าย "(soon)" เทา ใช้ทั้งลูกค้า+พนักงาน */
/* ===== ปุ่มหลัก 2 สถานะ: ยังไม่ครบ = เทา กดไม่ได้ · ครบ = เด้งเป็นขาว + แสงแดงหายใจ + ประกายวิ่งครั้งเดียว ===== */
.cta{transition:background var(--t-8) var(--ease),color var(--t-8) var(--ease)}
.cta.wait{background:var(--tile2);color:var(--dim);pointer-events:none;animation:var(--pg-fade);box-shadow:none}
.cta.ready{position:fixed;color:#fff;background:var(--red-cta);--g:var(--glow-cta);--g-up:var(--glow-cta-up);box-shadow:var(--g);animation:var(--pg-fade),cta-in var(--t-9) var(--ease),var(--breath)}   /* ปุ่มกลางแดงล้วนแบบปุ่มเขียว LINE: สีเรียบ + glow นุ่มหายใจ · ไม่มีขอบกระจก/ประกาย */
@keyframes cta-in{from{transform:scale(.94)}to{transform:scale(1)}}
/* ===== ปุ่มกลางตัวเดียวของแอปลูกค้า (#cta · OD-316) ===== อยู่นอกทุก .page (พี่น้องกับ dock) → เปลี่ยนหน้า = ไม่สร้าง/วาด/จางใหม่ · เปลี่ยนแค่ป้ายกับสี
   กฎ .cta.* ข้างบนยังเป็นของปุ่มรายหน้าในแอปพนักงาน (เข้าหน้าจาง pg-fade + cta-in) — #cta ตัดทิ้งทั้งคู่: ไม่มีอนิเมชันเข้า มีแต่ transition ของสี/เงา/ความทึบ และหายใจ (--breath) เฉพาะสถานะ ready · login (หน้าเปลี่ยน ค่า animation เท่าเดิม = เส้นเวลาไม่เริ่มใหม่)
   .gone = หน้าที่ไม่มีปุ่ม: จางหาย (opacity) + ซ่อนจากโฟกัส/ตัวอ่านจอหลังจางจบ (visibility) · wait ไม่หรี่ความทึบ (เทาด้วยสีล้วน) ไม่ให้ Next ที่รอโปรแวบเป็นสองจังหวะ */
#cta{transition:background-color var(--t-8) var(--ease),color var(--t-8) var(--ease),box-shadow var(--t-8) var(--ease),opacity var(--t-7) var(--ease),visibility 0s;cursor:pointer;-webkit-user-select:none;user-select:none}   /* div role=button ไม่มีสไตล์ปุ่มของเบราว์เซอร์ */
#cta.svc{transition:background-color 0s,color 0s,box-shadow 0s,opacity var(--t-7) var(--ease),visibility 0s}   /* หน้า Menu แตก 4 ส่วน (OD-331/351): สี/เงาของสถานะก่อนหน้าหายทันที ไม่ไล่ค้างใต้ชิ้นส่วน (ชั้นสีอยู่ใน #cta: menu.css .mn-cap/.mn-fill) · ลำดับ 5 ค่าเท่า #cta ให้ .gone (transition-delay ตามตำแหน่ง) ยังจางเข้า/ออกเหมือนเดิม */
#cta:focus-visible{outline-offset:3px}
#cta.wait{opacity:1;animation:none;pointer-events:auto}   /* wait แตะได้: Next ที่ยังไม่พร้อม → app.js ทำการ์ดที่ขาดเป็นแดง */
#cta.ready,#cta.login{animation:cta-glow var(--t-8) var(--ease),var(--breath);animation-delay:0s,var(--t-8)}   /* glow ค่อยเรืองขึ้นพร้อมสีพื้น (.35s) แล้วหายใจต่อ · เปลี่ยนหน้า/ready↔login ค่า animation เท่าเดิม = ไม่เริ่มใหม่ · lite/reduced-motion = ไม่มีอนิเมชันเลย เหลือ glow นิ่ง (กฎด้านล่าง ไม่พึ่ง --breath:none เพราะ cta-glow อยู่ในรายการเดียวกัน) */
@keyframes cta-glow{from{box-shadow:0 0 0 0 transparent}}
#cta.saved{animation:none}
#cta.again{background:var(--dg-surface);box-shadow:var(--dg-line);color:var(--tx);--dg-under:var(--dg-under-light)}   /* ปุ่มลอยทับการ์ด QR ขาว = บริบทสว่าง: พื้นรอง ≥.60 (OD-436) · state "again" ตั้งครั้งเดียวโดย CTA registry (app.js) ไม่ตั้งทีละชิ้น */   /* หน้า go (OD-405): ดำโปร่งสูตรเดียวกับทุกชิ้นลอยของหน้าเมนู (--dg-surface/--dg-line · ไม่มีสีใหม่) · กดได้ (ไม่ใช่ .wait) ไม่มี glow/หายใจ = สงบ ไม่แย่งจาก QR */
#cta.fade{opacity:.28}   /* OD-329 (เฉพาะเส้นทางที่ registry ตั้ง fadeOnScroll): เลื่อนลง = จางเฉพาะความทึบ · ขนาด/ตำแหน่ง/ตัวกด (pointer-events) ไม่เปลี่ยน · อยู่ก่อน .gone ให้ .gone ชนะ */
#cta.fade:is(:active,:focus-visible){opacity:1}   /* OD-418/418b: แตะ/โฟกัส = แดงค่อยๆ กลับ (ใช้ transition opacity ของ #cta เดิม) · แตะแรกแค่ปลุก ไม่ทำงาน (pressCta ใน app.js) · แตะสองทำงาน */
/* OD-420/421: กระดิ่ง (CTA เช็กอินแล้ว + ตะกร้าว่าง) สั่งครั้งแรกครั้งเดียว บอกว่ากดได้ · แกว่งหลายจังหวะเบาลงเหมือนกระดิ่งจริง + เด้งขยายนิด + วงคลื่นแผ่ออกหนึ่งวง · transform/opacity ล้วน (ไม่ขยับเลย์เอาต์ เบาบนเครื่องเก่า) · ตอนจางตามการเลื่อน/ลดการเคลื่อนไหว/lite = ไม่สั่น (--sel-anim:none กลุ่มเดิม) */
.mn-bell{position:relative}
.mn-bell .ic{transform-origin:50% 10%;animation:var(--sel-anim,bell-ring) var(--bell-cycle) var(--bell-first) var(--bell-n) var(--ease-inout) both}
.mn-bell::after{content:"";position:absolute;inset:0;margin:auto;width:var(--ic-5);height:var(--ic-5);border-radius:var(--r-round);box-shadow:inset 0 0 0 var(--sp-1) currentColor;opacity:0;pointer-events:none;animation:var(--sel-anim,bell-ping) var(--bell-ping-t) var(--bell-first) var(--bell-n) var(--ease-out) both}
.cta.fade .mn-bell .ic,.cta.fade .mn-bell::after{animation:none}
@keyframes bell-ring{0%{transform:rotate(0deg) scale(1)}6%{transform:rotate(var(--bell-deg)) scale(1.12)}14%{transform:rotate(calc(-1 * var(--bell-deg))) scale(1.12)}22%{transform:rotate(calc(.8 * var(--bell-deg))) scale(1.06)}30%{transform:rotate(calc(-.7 * var(--bell-deg))) scale(1)}38%{transform:rotate(calc(.55 * var(--bell-deg)))}46%{transform:rotate(calc(-.4 * var(--bell-deg)))}54%{transform:rotate(calc(.28 * var(--bell-deg)))}62%{transform:rotate(calc(-.18 * var(--bell-deg)))}72%{transform:rotate(calc(.08 * var(--bell-deg)))}82%,100%{transform:rotate(0deg) scale(1)}}
@keyframes bell-ping{0%{transform:scale(.7);opacity:var(--op-6)}100%{transform:scale(1.9);opacity:0}}
#cta.gone{opacity:0;visibility:hidden;pointer-events:none;transition-delay:0s,0s,0s,0s,var(--t-7)}   /* ท้ายกลุ่มสถานะ + ความจำเพาะเท่ากัน = .gone ชนะ .wait (opacity:1 · pointer-events:auto) ทุกสถานะ → จางเข้า/ออกสมมาตรทุกคู่ (ready·wait·login·saved × gone) */
#cta .cta-t.swap{animation:cta-t-in var(--t-3) var(--ease-linear)}   /* ป้ายเปลี่ยนตอนปุ่มโชว์อยู่ = จางเข้าสั้นๆ (ปุ่ม/ตำแหน่ง/ขนาดไม่ขยับ) */
@keyframes cta-t-in{from{opacity:0}}
@media (prefers-reduced-motion:reduce){#cta{transition:none}#cta .cta-t.swap,#cta.ready,#cta.login{animation:none}}
html.lite #cta .cta-t.swap,html.lite #cta.ready,html.lite #cta.login{animation:none}
/* หัวข้อย่อยของขั้น (ใต้แถบ 1234) · ปุ่มแก้ไขปุ่มเดียว · บล็อกชำระ */
.sub2{font-size:var(--fs-12);font-weight:var(--fw-bold);letter-spacing:.01em;margin-bottom:var(--sp-3)}
.edits{display:flex;justify-content:flex-end;margin:var(--sp-3) 0 var(--sp-7)}
.cp.big{width:40px;height:40px}
.cp.big .ic{width:var(--ic-3);height:var(--ic-3)}
/* ปุ่มไอคอนใต้ตั๋ว (หน้า booking · OD-232/239): .off = แก้ไม่ได้ จาง กดไม่ได้ · .gone = ซ่อนแต่ยังกินที่ (เลย์เอาต์ไม่ขยับ) · .linelogin = ต้องล็อกอิน LINE ก่อน */
.edits .off{opacity:var(--op-2);pointer-events:none}
.edits .gone{visibility:hidden}
.edits .danger{color:var(--red-text);box-shadow:inset 0 0 0 1px var(--red)}
.edits .linelogin{color:var(--lineg)}
.pay{gap:6px}
.pay small{font-size:var(--fs-2);font-weight:var(--fw-semibold);letter-spacing:var(--ls-4);color:var(--mu);margin-top:var(--sp-2)}
.pay small:first-child{margin-top:0}
.pay .r{display:flex;justify-content:space-between;align-items:center;gap:var(--sp-3);font-size:var(--fs-7)}
.pay .r b{font-weight:var(--fw-semibold);display:inline-flex;align-items:center;gap:var(--sp-2)}
.pay .r b.mu{color:var(--mu);font-weight:var(--fw-regular)}
.pay .tot{margin-top:var(--sp-3);padding-top:14px;box-shadow:inset 0 1px 0 var(--tile2);font-size:var(--fs-9)}
.pay .tot b{font-size:var(--fs-13)}
/* ===== แบบการ์ด (หน้า #cards) · ทุกแบบใช้โครงเดียว เปลี่ยนแค่พื้นผิว ===== */
 /* การ์ดชำระใบเดียว · QR PromptPay ระบุยอด (EMVCo · WO-265) ป้ายกลาง QR แทนโลโก้จริง (ของจริง = ไฟล์โลโก้ของร้าน) */
.bankcard{--pp-r:28px;gap:14px;border-radius:var(--pp-r)}   /* --pp-r = รัศมีบล็อกของการ์ดจ่ายเงินทั้งใบ (แคปซูล) · ปุ่ม/ชิป = 999px */
.bankcard .kv{background:var(--tile2);border-radius:var(--pp-r);padding:14px var(--sp-5)}
.bk-logo{width:18px;height:18px;flex:none;display:block}   /* โลโก้ธนาคารหลังชื่อ · เล็กพอมองเห็น */
.bankcard .kv dd{display:inline-flex;align-items:center;gap:var(--sp-2);justify-content:flex-end}
.bankcard .ppay{display:grid;justify-items:center;gap:10px;padding-top:14px;box-shadow:inset 0 1px 0 var(--tile2)}
.bankcard .ppay>small{font-size:var(--fs-3);color:var(--mu);background:var(--tile2);border-radius:var(--r-pill);padding:6px 14px}
.bankcard>.btn,.slip-box>.btn{height:var(--tap);width:auto;min-width:200px;justify-self:center;padding:0 var(--sp-7);font-size:var(--fs-7);margin-top:6px}   /* ปุ่มแนบสลิปอยู่ในการ์ดใต้ QR · 44pt ตัวเล็ก ไม่ล้น ไม่ชน QR */
/* กล่องแนบสลิป: สูงเท่ากันทั้งก่อน/หลังแนบ (รูป 64 + Replace 44) เพื่อไม่ให้เลย์เอาต์ขยับ · ก่อนแนบปุ่มอยู่กลางกล่อง */
.slip-box{display:grid;justify-items:center;align-content:center;height:108px}
.slip-box>.btn.line{margin:0}
.slip-thumb{position:relative;width:64px;height:64px;border-radius:var(--pp-r);background:var(--tile2);display:grid;place-items:center;color:var(--mu)}
.slip-thumb>img{width:100%;height:100%;object-fit:cover;border-radius:inherit}
.slip-thumb>.ic{width:28px;height:28px}
.slip-thumb>.rs-n{position:absolute;right:-6px;bottom:-6px;width:24px;height:24px}
.slip-thumb>.rs-n .ic{position:absolute;inset:0;width:auto;height:auto}   /* ติ๊กสลิป: รูป ICON.check เต็มวง → กว้าง ≈46% กึ่งกลางเป๊ะ (เหมือน .tick) */
.slip-re{display:flex;align-items:center;min-height:var(--tap);padding:0 var(--sp-4);font-size:var(--fs-5);color:var(--mu);cursor:pointer}
.bankcard>.hint{text-align:center}
/* ===== การ์ด (CSS ฐานจากดีไซเนอร์รอบ 3 · เฉพาะกฎที่ใช้) ===== */
.cl-root{margin:0;--red25:rgb(var(--accent-rgb) / .25);
  --hair:rgb(255 255 255 / var(--dg-line-a));--dim:rgba(255,255,255,.55);--mute:rgba(255,255,255,.4);
  font:14px/1.3 -apple-system,BlinkMacSystemFont,"SF Pro Text","Helvetica Neue",Arial,sans-serif;
  color:#fff;background:#000;padding:var(--sp-6);-webkit-font-smoothing:antialiased;
  font-variant-numeric:tabular-nums}
.cl-root .R{display:inline-block;width:.92em;height:1.02em;margin:0 .02em;vertical-align:-.12em;background:var(--red);transform:rotate(-9deg);
  -webkit-mask:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='381 309 1347 1421'><path d='M381 309H1151A470 497 0 0 1 1363.7 1249.2L1727.8 1729.5H1370.3V1562.4H1194.1V1395.3H1018.1V1228.2H841.6V1061.1H659.5V1729.5H381Z'/></svg>") center/contain no-repeat;
  mask:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='381 309 1347 1421'><path d='M381 309H1151A470 497 0 0 1 1363.7 1249.2L1727.8 1729.5H1370.3V1562.4H1194.1V1395.3H1018.1V1228.2H841.6V1061.1H659.5V1729.5H381Z'/></svg>") center/contain no-repeat}
.cl-card{position:relative;aspect-ratio:1.586;border-radius:var(--r-lg);overflow:hidden;isolation:isolate;
  background:#000;color:#fff;
  box-shadow:var(--dg-line),inset 0 1px 0 rgba(255,255,255,.2)}
.cl-card::after{content:"";position:absolute;inset:0;z-index:var(--z-5);pointer-events:none;border-radius:inherit;
  background:linear-gradient(118deg,rgba(255,255,255,.085) 0%,rgba(255,255,255,.025) 22%,transparent 46%)}
.cl-code{position:absolute;top:14px;left:16px;z-index:var(--z-3);font-weight:var(--fw-bold);font-size:var(--fs-7);letter-spacing:.05em;line-height:var(--lh-1);white-space:nowrap}
.cl-code.cl-fs{font-size:var(--fs-2);letter-spacing:.14em;top:16px}
.cl-chip{position:absolute;top:13px;right:16px;z-index:var(--z-3);font-size:var(--fs-1);font-weight:var(--fw-semibold);letter-spacing:var(--ls-3);text-transform:uppercase;
  line-height:var(--lh-3);padding:var(--sp-1) 9px;border-radius:var(--r-pill);border:1px solid rgba(255,255,255,.18);color:rgba(255,255,255,.85);white-space:nowrap}
.cl-chip.cl-act{background:none;border-color:var(--red);color:var(--red-text)}
.cl-chip.cl-ok{color:var(--ok);border-color:rgb(var(--ok-rgb) / .35)}
.cl-chip.cl-top{border-color:var(--red);color:#fff;box-shadow:inset 0 0 0 1px var(--red25),var(--glow-red)}
.cl-chip.cl-off{color:var(--mute);border-color:rgba(255,255,255,.1)}
.cl-done{color:rgba(255,255,255,.62);--glow-red:0 4px 16px rgb(var(--accent-rgb) / .22);--glow-red-up:0 4px 16px rgb(var(--accent-rgb) / .45);--red:rgb(var(--accent-rgb) / .64);--red25:rgb(var(--accent-rgb) / .2);--dim:rgba(255,255,255,.4)}
.cl-lab{display:block;font-size:var(--fs-1);letter-spacing:.12em;text-transform:uppercase;color:var(--dim);margin-bottom:2px}
.cl-qr{display:grid;justify-items:center;gap:6px;width:max-content}   /* C19: QR + ป้าย QR CHECK IN ล่าง stub (stub ทั้งคอลัมน์อยู่เหนือลิงก์เปิดใบ) · แตะ = ขยาย (ui.js) */
.cl-qr i{font-style:normal;font-size:var(--fs-1);letter-spacing:.18em;text-transform:uppercase;color:var(--dim)}
.cl-stub{display:grid;grid-template-columns:1fr 100px}
.cl-stub .cl-main{position:relative;padding:44px var(--sp-3) 14px var(--sp-4)}
/* stub ขวา (S1 boarding pass · เจ้าของยืนยัน 2026-10-22): เส้นปรุ + รูครึ่งวงกลม · บน = chip สถานะระดับเดียวกับรหัส (padding 20 = 16 + ครึ่งส่วนต่างปุ่มคัดลอก 30 กับ chip 22) · ล่าง = QR CHECK IN */
.cl-stub .cl-tear{position:relative;z-index:var(--z-3);border-left:1px dashed rgba(255,255,255,.28);display:flex;flex-direction:column;align-items:center;justify-content:space-between;padding:var(--sp-5) 0 var(--sp-3)}
.cl-stub .cl-tear::before,.cl-stub .cl-tear::after{content:"";position:absolute;left:-9px;width:16px;height:16px;border-radius:var(--r-round);background:#000;box-shadow:var(--dg-line)}
.cl-stub .cl-tear::before{top:-8px}
.cl-stub .cl-tear::after{bottom:-8px}
.cl-stub .cl-tear .cl-chip{position:static;padding:var(--sp-1) 7px;letter-spacing:.05em;white-space:normal;text-align:center;max-width:86px;font-size:var(--fs-1);line-height:var(--lh-4)}
.cl-stub .cl-row{display:flex;flex-wrap:wrap;gap:10px 18px;margin-top:var(--sp-3);font-size:var(--fs-3);font-weight:var(--fw-semibold);white-space:nowrap}
.cl-stub .cl-row .cl-lab{margin-bottom:1px}
.cl-stub .cl-who{position:absolute;left:16px;bottom:14px;font-size:var(--fs-2);color:var(--dim)}
.cl-stub .cl-main::before{content:"";position:absolute;left:0;top:0;bottom:0;width:120px;background:radial-gradient(70% 60% at 0% 100%,var(--red25),transparent 70%)}
/* ===== การ์ดจริง (เจ้าของเลือก 2026-10-22): บุ้คกิ้ง = S1 Stub (บอร์ดดิ้งพาส · แสงแดงเบลอใต้กระจก) · สมาชิก = M2 Hairline (ดำล้วน) ===== */
.cl-root{padding:0}
.cl-card .open{position:absolute;inset:0;z-index:var(--z-2)}
.cl-card .fn-cp{z-index:var(--z-3)}
.cl-card .cl-chip{z-index:var(--z-3)}
.fn-stub .cl-main{padding:var(--sp-4) var(--sp-3) 14px var(--sp-4)}
.fn-head{display:flex;align-items:center;gap:10px;margin-bottom:6px}
.fn-head .cl-code{position:static;font-size:var(--fs-15)}   /* เจ้าของเลือก E 28px (2026-10-22) */
.fn-cp{position:relative;flex:none;width:30px;height:30px;border-radius:var(--r-round);display:grid;place-items:center;color:rgba(255,255,255,.85);box-shadow:inset 0 0 0 1px rgba(255,255,255,.22);background:none;border:0;padding:0}
.fn-cp .ic{width:15px;height:15px}
.fn-date{display:grid;gap:2px}
.fn-date small{font-size:var(--fs-1);font-weight:var(--fw-bold);letter-spacing:.18em;text-transform:uppercase;color:var(--red-text)}
.fn-date b{font-size:36px;font-weight:var(--fw-heavy);letter-spacing:-.03em;line-height:.95}
.fn-date b span{font-size:var(--fs-11);font-weight:var(--fw-semibold);letter-spacing:0;color:rgba(255,255,255,.85)}
.cl-done .fn-date small{color:var(--dim)}
.fn-bloom{background:radial-gradient(75% 95% at 12% 105%,rgb(var(--accent-rgb) / .62),transparent 62%),radial-gradient(55% 70% at 100% -5%,rgb(var(--accent-rgb) / .32),transparent 60%),#000}
.fn-bloom .cl-main,.fn-bloom .cl-tear{background:rgba(255,255,255,.035)}
.fn-bloom .cl-main::before{display:none}
.cl-done.fn-bloom{background:radial-gradient(75% 95% at 12% 105%,rgba(120,120,120,.25),transparent 62%),#000}
.fn-m{background:#000;box-shadow:var(--dg-line),inset 0 1px 0 rgba(255,255,255,.18),0 20px 50px rgba(0,0,0,.6)}
.fn-m::before{content:"";position:absolute;inset:0;background:radial-gradient(90% 60% at 10% 0%,rgba(255,255,255,.07),transparent 60%)}
.fn-foot{position:absolute;left:16px;right:16px;bottom:16px;display:flex;justify-content:space-between;align-items:flex-end}
.fn-name{font-size:var(--fs-6);font-weight:var(--fw-semibold);display:grid;gap:3px}
.fn-name small{font-size:var(--fs-1);font-weight:var(--fw-medium);color:var(--dim);letter-spacing:var(--ls-2)}
.fn-pts{font-size:var(--fs-16);font-weight:var(--fw-semibold);letter-spacing:-.02em;line-height:var(--lh-1);display:inline-flex;align-items:baseline;gap:5px}
.fn-pts small{font-size:var(--fs-2);font-weight:var(--fw-medium);color:var(--dim)}
.fn-hair .fn-foot{padding-top:var(--sp-3);border-top:1px solid var(--hair)}
.soonword{font-size:var(--fs-5);font-weight:var(--fw-semibold);letter-spacing:.22em;color:var(--mu);text-align:center;margin:26px 0 34px}
.stack{display:grid;gap:14px}


/* บัตรสมาชิกดำหรู: ตัวหนังสือเงิน-แพลตินัม (ไล่เงาแบบโลหะ) ไม่ใช่ขาวล้วน · ป้ายเทาเงิน */
.fn-m{color:#d9d9de}
.fn-m .cl-code,.fn-m .fn-name,.fn-m .fn-pts{background:linear-gradient(180deg,#f4f4f6,#b9b9c0);-webkit-background-clip:text;background-clip:text;color:transparent}
.fn-m .cl-code .R{background:var(--red)}
.fn-m .fn-name small,.fn-m .fn-pts small{background:none;-webkit-text-fill-color:#8e8e93;color:#8e8e93}
.fn-m .cl-chip{color:#d9d9de;border-color:rgba(217,217,222,.28)}
.fn-m::before{background:radial-gradient(90% 60% at 10% 0%,rgba(255,255,255,.06),transparent 60%),linear-gradient(160deg,rgba(255,255,255,.04),transparent 40%)}
/* สมุดสมาชิก (#card · WO-301): หน้าบัตรเป็นรูปลูกค้าได้ · รหัสจับคู่ตัวใหญ่ · รูปการ์ดจริง · ข้อความสถานะอยู่ใต้การ์ดในที่ที่จองไว้ (layout ไม่ขยับ) */
.fn-m[data-face="photo"]{background:var(--face-photo) center/cover,#000}
.mpair{font-size:64px;font-weight:var(--fw-semibold);letter-spacing:.2em;text-align:center;font-variant-numeric:tabular-nums}
.mimg{width:100%;border-radius:16px}
#card .msg{margin-top:14px}
#mWallet{margin-bottom:var(--sp-7)}

/* ===== ของจริง (WO-266): ข้อความแจ้ง/ผิดพลาด จองพื้นที่ไว้ ไม่ขยับเลย์เอาต์ · แคปซูลโซน n คอลัมน์ · ปุ่มรอคำตอบ · โปรหมด · วันล็อกตอนแก้ ===== */
.msg{min-height:20px;font-size:var(--fs-5);color:var(--mu);margin:-10px 0 var(--sp-4);text-align:center}
.msg.bad{color:var(--red-text)}
.cap.zone{grid-template-columns:repeat(var(--n,3),1fr)}
.cap.zone .sel{width:calc((100% - 8px) / var(--n,3))}
.cap label.off{opacity:var(--op-3);cursor:default}
.cta.wait{opacity:var(--op-6);pointer-events:none}
.days.locked{pointer-events:none;opacity:var(--op-5)}
/* ใบรอเงิน (card() ใส่ cl-lock · OD-261): เบลอตัวหนังสือหลักเบาๆ (วันที่/ชื่อ/โซนพอเดาได้) กับลายหลอกแรงกว่า · ป้าย NP อยู่ใน .cl-tear นอก .cl-main/.cl-qr จึงคมชัด · เส้นปรุ/รูครึ่งวงกลม/กรอบอยู่ที่ .cl-tear/.cl-card ไม่ถูก filter
   filter เฉพาะตอน cl-lock (เบา iPad เก่า) · .cl-tear ปิด pointer-events ให้แตะตรงไหนของตั๋วก็ลงไปที่ลิงก์ .open (ไปจ่าย) ไม่ถูกคอลัมน์ stub บัง */
:root{--lock-blur:2.5px;--lock-blur-qr:6px}
.cl-lock .cl-main{filter:blur(var(--lock-blur))}
.cl-lock .cl-qr{filter:blur(var(--lock-blur-qr))}
.cl-lock .cl-tear{pointer-events:none}
.cl-fake{display:block;width:0;min-width:100%;aspect-ratio:1;border-radius:5px;background:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 33 33' shape-rendering='crispEdges'%3E%3Crect width='100%' height='100%' fill='%23fff'/%3E%3Cpath d='M2 2h7v1h-7zM12 2h2v1h-2zM15 2h3v1h-3zM20 2h1v1h-1zM24 2h7v1h-7zM2 3h1v1h-1zM8 3h1v1h-1zM10 3h1v1h-1zM12 3h3v1h-3zM17 3h1v1h-1zM19 3h2v1h-2zM22 3h1v1h-1zM24 3h1v1h-1zM30 3h1v1h-1zM2 4h1v1h-1zM4 4h3v1h-3zM8 4h1v1h-1zM10 4h4v1h-4zM16 4h1v1h-1zM18 4h1v1h-1zM21 4h1v1h-1zM24 4h1v1h-1zM26 4h3v1h-3zM30 4h1v1h-1zM2 5h1v1h-1zM4 5h3v1h-3zM8 5h1v1h-1zM10 5h1v1h-1zM12 5h1v1h-1zM16 5h2v1h-2zM19 5h4v1h-4zM24 5h1v1h-1zM26 5h3v1h-3zM30 5h1v1h-1zM2 6h1v1h-1zM4 6h3v1h-3zM8 6h1v1h-1zM11 6h1v1h-1zM13 6h1v1h-1zM15 6h3v1h-3zM19 6h4v1h-4zM24 6h1v1h-1zM26 6h3v1h-3zM30 6h1v1h-1zM2 7h1v1h-1zM8 7h1v1h-1zM12 7h2v1h-2zM15 7h2v1h-2zM18 7h2v1h-2zM24 7h1v1h-1zM30 7h1v1h-1zM2 8h7v1h-7zM10 8h1v1h-1zM12 8h1v1h-1zM14 8h1v1h-1zM16 8h1v1h-1zM18 8h1v1h-1zM20 8h1v1h-1zM22 8h1v1h-1zM24 8h7v1h-7zM10 9h1v1h-1zM12 9h4v1h-4zM20 9h2v1h-2zM2 10h1v1h-1zM8 10h1v1h-1zM10 10h1v1h-1zM14 10h1v1h-1zM16 10h2v1h-2zM19 10h1v1h-1zM27 10h3v1h-3zM2 11h1v1h-1zM4 11h2v1h-2zM9 11h1v1h-1zM11 11h1v1h-1zM13 11h2v1h-2zM16 11h1v1h-1zM20 11h2v1h-2zM23 11h1v1h-1zM25 11h2v1h-2zM28 11h2v1h-2zM6 12h1v1h-1zM8 12h1v1h-1zM10 12h3v1h-3zM19 12h2v1h-2zM22 12h2v1h-2zM2 13h2v1h-2zM5 13h1v1h-1zM9 13h1v1h-1zM12 13h2v1h-2zM16 13h3v1h-3zM22 13h1v1h-1zM24 13h2v1h-2zM27 13h1v1h-1zM3 14h9v1h-9zM13 14h4v1h-4zM21 14h2v1h-2zM24 14h2v1h-2zM30 14h1v1h-1zM2 15h2v1h-2zM5 15h1v1h-1zM13 15h1v1h-1zM15 15h2v1h-2zM19 15h4v1h-4zM24 15h1v1h-1zM26 15h1v1h-1zM29 15h2v1h-2zM2 16h1v1h-1zM4 16h1v1h-1zM7 16h3v1h-3zM11 16h2v1h-2zM15 16h5v1h-5zM24 16h2v1h-2zM27 16h2v1h-2zM3 17h4v1h-4zM9 17h1v1h-1zM15 17h2v1h-2zM18 17h1v1h-1zM23 17h1v1h-1zM25 17h2v1h-2zM28 17h1v1h-1zM30 17h1v1h-1zM2 18h5v1h-5zM8 18h1v1h-1zM16 18h2v1h-2zM19 18h1v1h-1zM22 18h1v1h-1zM25 18h1v1h-1zM27 18h2v1h-2zM2 19h1v1h-1zM7 19h1v1h-1zM10 19h2v1h-2zM13 19h2v1h-2zM18 19h5v1h-5zM24 19h3v1h-3zM28 19h3v1h-3zM2 20h4v1h-4zM8 20h1v1h-1zM11 20h2v1h-2zM15 20h2v1h-2zM18 20h2v1h-2zM21 20h1v1h-1zM27 20h1v1h-1zM30 20h1v1h-1zM2 21h1v1h-1zM4 21h1v1h-1zM10 21h2v1h-2zM13 21h2v1h-2zM16 21h3v1h-3zM23 21h4v1h-4zM2 22h1v1h-1zM4 22h6v1h-6zM12 22h3v1h-3zM18 22h1v1h-1zM20 22h1v1h-1zM22 22h5v1h-5zM28 22h3v1h-3zM10 23h1v1h-1zM12 23h4v1h-4zM18 23h3v1h-3zM22 23h1v1h-1zM26 23h2v1h-2zM2 24h7v1h-7zM10 24h10v1h-10zM21 24h2v1h-2zM24 24h1v1h-1zM26 24h3v1h-3zM2 25h1v1h-1zM8 25h1v1h-1zM12 25h4v1h-4zM19 25h4v1h-4zM26 25h1v1h-1zM29 25h2v1h-2zM2 26h1v1h-1zM4 26h3v1h-3zM8 26h1v1h-1zM12 26h1v1h-1zM15 26h1v1h-1zM17 26h3v1h-3zM21 26h7v1h-7zM29 26h1v1h-1zM2 27h1v1h-1zM4 27h3v1h-3zM8 27h1v1h-1zM10 27h2v1h-2zM13 27h2v1h-2zM18 27h1v1h-1zM20 27h2v1h-2zM23 27h1v1h-1zM25 27h1v1h-1zM27 27h3v1h-3zM2 28h1v1h-1zM4 28h3v1h-3zM8 28h1v1h-1zM10 28h1v1h-1zM15 28h2v1h-2zM20 28h10v1h-10zM2 29h1v1h-1zM8 29h1v1h-1zM10 29h1v1h-1zM12 29h1v1h-1zM15 29h3v1h-3zM23 29h3v1h-3zM27 29h2v1h-2zM30 29h1v1h-1zM2 30h7v1h-7zM11 30h2v1h-2zM14 30h2v1h-2zM18 30h1v1h-1zM20 30h2v1h-2zM23 30h6v1h-6z'/%3E%3C/svg%3E") center/100% 100%}   /* QR หลอกสมจริง = QR จริงที่สแกนแล้วได้ https://www.roofmatebkk.com (สร้างด้วย web/customer/qr.js · ใบรอเงินเบลออยู่ สแกนเช็กอินไม่ได้) ขนาดเท่า QR จริง (กว้างตามป้ายใต้มัน เหมือน .cl-qr svg) */
.cl-qr svg{display:block;width:0;min-width:100%;height:auto;aspect-ratio:1;border-radius:5px}   /* QR กว้างเท่าป้าย QR CHECK IN ใต้มัน (เจ้าของสั่ง) · width:0+min-width = ไม่ดันความกว้างของกล่อง ป้ายเป็นตัวกำหนด */      /* QR เช็กอิน (WO-269) ขนาดเดียวกับอีเมล */
/* กรอบ PromptPay (OD-227/230/237) ตามกฎ ธปท. (Thai QR Code): กรอบกรมนอก · แผ่นขาวเล็กกลางแถบบนใส่โลโก้ Thai QR Payment · แผ่นในขอบเขียวอมฟ้า: โลโก้ PromptPay → QR → แถวชื่อบัญชี+เลข
   สีกรอบ/ขอบเป็นสีทางการของแบรนด์ ไม่ผูกธีม · โลโก้ PromptPay ตั้งทับได้ที่ skin.promptpay_logo */
.pp-card{width:300px;max-width:100%;box-sizing:border-box;background:#0f3a6b;border-radius:var(--pp-r);padding:var(--sp-3);display:grid;gap:var(--sp-3)}
.pp-plate{justify-self:center;background:#fff;border-radius:var(--r-pill);padding:var(--sp-2) 22px;display:grid;place-items:center;min-height:50px}
.pp-plate img{height:34px;width:auto;display:block}
.pp-in{background:#fff;color:#111;border-radius:var(--pp-r);border:3px solid #1aa89a;padding:14px;display:grid;justify-items:center;gap:var(--sp-3);min-width:0}
.pp-brand{height:30px;width:auto;display:block}
.pp-qr{display:block;border:1.5px solid #e5e5ea;border-radius:var(--pp-r);overflow:hidden;line-height:0}   /* แผ่นรอง QR เป็นแคปซูลมีเส้นขอบบาง */
.pp-qr svg{display:block;width:200px;height:200px}
.pp-acc{display:flex;align-items:center;gap:var(--sp-3);width:100%;box-sizing:border-box;border:1.5px solid #e5e5ea;border-radius:var(--r-pill);padding:var(--sp-2) var(--sp-5) var(--sp-2) var(--sp-2)}   /* แถวชื่อบริษัท = แคปซูล */
.pp-co{width:48px;height:48px;flex:none;object-fit:contain}   /* โลโก้บริษัทสีดำเดิม ห้ามพื้นส้ม ห้ามเติมสี */
.pp-tx{flex:1;min-width:0;display:grid;gap:0;align-content:center}   /* 2 บรรทัดชิดกัน: ชื่อ EN (เล็ก เทา) + ชื่อไทย (เด่น) */
.pp-tx b{font-size:var(--fs-3);line-height:16px;font-weight:var(--fw-semibold);color:#6b6b70;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.pp-th{font-size:var(--fs-8);line-height:22px;font-weight:var(--fw-bold);color:#111;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.pp-row{display:flex;flex-wrap:wrap;gap:10px;justify-content:center;width:100%;min-width:0}   /* จอ 320 + ป้ายไทย: ปุ่มล้นแถว = ขึ้นบรรทัดใหม่ (ยังเป็นเม็ดเต็ม) ไม่ล้นการ์ด */
.pp-btn{position:relative;height:var(--tap);padding:0 18px;border:0;border-radius:var(--r-pill);background:var(--tile2);color:#fff;font-size:var(--fs-6);font-weight:var(--fw-semibold);display:inline-flex;align-items:center;gap:var(--sp-2);cursor:pointer;max-width:100%;min-width:0}
.pp-btn .ic{width:var(--ic-3);height:var(--ic-3);flex:none}
.pp-lab{display:inline-grid}   /* ป้ายปกติ + ป้ายยืนยัน ซ้อนช่องเดียวกัน = ปุ่มกว้างเท่ากับป้ายที่ยาวกว่าเสมอ สลับแล้วไม่ขยับ */
.pp-lab>*{grid-area:1/1;text-align:center;transition:opacity var(--t-6) var(--ease)}
.pp-ok{opacity:0}
.pp-btn.is-ok .pp-ok{opacity:1}
.pp-btn.is-ok .pp-l{opacity:0}
/* นับถอยหลังจ่าย (บนสุดของการ์ด · OD-278): ป้าย + ตัวเลขใหญ่ + แถบ scaleX · เหลือ <5 นาที = ตัวเลข --red-text + เส้นขอบบาง (ไม่มีพื้นแดง) */
.cd{height:116px;box-sizing:border-box;display:grid;align-content:center;justify-items:center;gap:var(--sp-1);padding:0 var(--sp-5);background:var(--tile2);border-radius:var(--pp-r);box-shadow:inset 0 0 0 1px transparent;transition:box-shadow var(--t-8) var(--ease)}
.cd-l{font-size:var(--fs-5);line-height:18px;color:var(--mu)}
.cd-t{font-size:38px;line-height:44px;font-weight:var(--fw-bold);font-variant-numeric:tabular-nums;letter-spacing:-.5px;color:#fff;transition:color var(--t-8) var(--ease)}
.cd-bar{display:block;width:100%;height:4px;border-radius:var(--r-pill);background:rgb(255 255 255 / .12);overflow:hidden;margin-top:6px}
.cd-bar u{display:block;height:100%;background:#fff;border-radius:inherit;transform-origin:left center;transform:scaleX(1);transition:transform 1s var(--ease-linear)}
.cd.low{box-shadow:inset 0 0 0 1px var(--red-text)}
.cd.low .cd-t{color:var(--red-text)}
.cd.slip .cd-t{font-size:var(--fs-7);line-height:20px;font-weight:var(--fw-medium);text-align:center;letter-spacing:0}   /* แนบสลิปแล้ว: ข้อความแทนตัวเลข · ความสูงกล่องเท่าเดิม */
.cd.slip .cd-bar{visibility:hidden}


/* จอแคบ 375px: ห้ามล้นขอบขวา — grid item ย่อได้ (min-width:0) · ของเสริมบนการ์ด/แถวโปรตัดคำได้ */
.cl-stub .cl-row{white-space:normal;gap:var(--sp-2) 14px}
.cl-stub .cl-row>div{min-width:0;max-width:100%;overflow-wrap:anywhere}
.cl-stub .cl-main{min-width:0}
.cl-who{max-width:calc(100% - 32px);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* แท็บ Upcoming/Past */


/* การ์ดใบที่จ่ายแล้ว · กล่อง "จ่ายแล้ว" · ปุ่มระหว่างรอ */
.paid{display:flex;justify-content:space-between;align-items:center}
.paid b{font-size:var(--fs-12);color:var(--ok)}
button.btn{border:0;font-family:var(--font)}
button.btn[disabled]{opacity:var(--op-6)}
.cap.tabs{grid-template-columns:repeat(var(--n,3),1fr)}
.cap.tabs .sel{width:calc((100% - 8px) / var(--n,3))}
#dateInput[disabled]{pointer-events:none}

/* แถวโปรบนจอแคบ: ปุ่มจำนวนเล็กลง ราคาเล็กลง ชื่อยังอ่านได้ */

/* C19: แตะ QR บนการ์ด = ขยายเต็มจอ (การ์ดไม่ขยาย) · แตะที่ไหนก็ได้ = ปิด */
.qrbig{position:fixed;inset:0;z-index:var(--z-viewer);touch-action:none;display:grid;place-items:center;background:rgb(0 0 0 / .92);animation:qr-in var(--t-8) var(--ease)}
.qrbig svg{width:min(72vw,300px);height:auto;border-radius:var(--r-md);background:#fff}
.qrbig>img{max-width:min(92vw,520px);max-height:84vh;object-fit:contain;border-radius:var(--r-md)}   /* ดูรูปโปรเต็มจอ (หน้า 2) ใช้ overlay เดียวกับ QR */
.qrbig.qrsave{align-content:center;justify-items:center;gap:14px;padding:var(--sp-6);text-align:center}   /* ตัวดูรูป PNG ของ Save QR (สำรองเมื่อเมนูแชร์ใช้ไม่ได้) */
.qrsave img{width:min(80vw,360px);height:auto;border-radius:var(--r-md);-webkit-touch-callout:default}
.qrsave p{margin:0;color:#fff;font-size:var(--fs-7)}
.qrsave a{color:var(--mu);font-size:var(--fs-6);text-decoration:underline}
@keyframes qr-in{from{opacity:0}}
/* ปัดลงปิด (ui.js data-dismiss · OD-295): ระหว่างลาก --dy ตั้งโดย JS (translate ล้วน ไม่แตะเลย์เอาต์) · dz-back = เด้งกลับ/ไหลออกด้วยโทเคนเดียวกับ selector · touch-action:none ที่ .qrbig (รูป/QR ไม่ซูมเอง ซูมหน้าถูกปิดทั้งแอป) */
.dz-on{translate:0 var(--dy,0px)}
.dz-back{transition:translate var(--sel-t) var(--spring)}
[data-hold]{-webkit-user-select:none;user-select:none;-webkit-touch-callout:none}   /* กดค้างปุ่ม −/+ : ไม่ให้ iOS เลือกข้อความ/ขึ้นแว่นขยาย */
@media (prefers-reduced-motion:reduce){.qrbig{animation:none}.dz-back{transition:none}}

/* OD-216: จุดแตะ ≥44pt ทุกตัว — วงกลมภาพเล็ก (คัดลอก 30–32px) ขยายพื้นที่กดด้วย ::before ไม่ขยับเลย์เอาต์ */
.cp::before,.fn-cp::before{content:"";position:absolute;inset:-7px}
.fn-cp::before{inset:-7px -3px -7px -11px}   /* ขวาถูก .cl-tear (z3 เหนือกว่า) ห่างแค่ 4px → ขยายซ้ายแทน (ทับตัวรหัสที่ไม่ใช่ปุ่ม) ให้กว้างรวม 44 */
.cap.mb-mini label::before{content:"";position:absolute;inset:-5px 0}   /* ภาษา EN/ไทย (ภาพสูง 34 · กด 44) · ขยายเฉพาะแนวตั้ง — สองป้ายชิดกันแนวนอน */
@media (prefers-reduced-motion:reduce){:root{--breath:none;--sel-anim:none;--dock-bounce:var(--dock-ease);--spring:var(--dock-ease)}.dock,.dock a,.dock a i,.dock .sel,.cap .sel,.dock a.on i,body:not(.min) .dock a,body:not(.min) .dock .sel{transition-duration:.01s;transition-delay:0s}}   /* 3 ตัวท้าย = ความจำเพาะเท่ากฎปกติของมัน (.dock a.on i · body:not(.min) …) และอยู่หลังกว่า จึงชนะ — ไม่งั้นไอคอนยังไหลช้า/selector ยังโผล่ช้า */

/* ===== หน้า Home (OD-322): ชื่อร้าน h1 + ข้อความรอเปิดกลางจอ + แถวไอคอนติดต่อ .mi-ct ล่างสุด (margin-top:auto ดันลง · พื้นที่เหนือ dock มาจาก padding ของ .page) ===== */
#home.cur{display:flex;flex-direction:column}
#home .hero{flex:1;min-height:34vh}
.hero-sub{margin-top:10px;font-size:var(--fs-8);color:var(--mu)}
#home .mi-ct{margin-top:auto;padding-top:var(--sp-6)}
.mi-ct{display:flex;justify-content:center;gap:var(--sp-5);margin-top:var(--sp-9)}   /* แถวติดต่อท้ายหน้า Membership (OD-299): วงกลมเทา .rs-n ไอคอนล้วน · แตะได้ 44px · เห็นทุกคน */
.mi-ct a{width:var(--tap);height:var(--tap);color:rgb(255 255 255 / .75)}
.mi-ct a:active{background:var(--line)}
.mi-ct a .ic{width:var(--ic-5);height:var(--ic-5)}
.mi-ct a[hidden],.mi-ct[hidden]{display:none}
[data-copy].copied{color:var(--ok)}   /* คัดลอกแล้ว = ไอคอนเป็นติ๊กเขียวสั้นๆ (ไม่ขยับเลย์เอาต์) */

/* ===== Membership (#card · WO-311 · OD-255/257): แท็บ Points · Bills · Profile — แท็บ/ปุ่ม/การ์ดใช้ของราก (.cap.tabs · .tile · .btn · .cl-card) ตรงนี้เฉพาะของที่ราก
   ยังไม่มี (prefix mb-) · ทุกแถวสูงคงที่ ปุ่มบันทึกจองพื้นที่ไว้ (visibility) = เลย์เอาต์ไม่ขยับ · ปุ่ม/เม็ดเป็นแคปซูลหรือวงกลมทั้งหมด ===== */
.mb-tabs{margin:0 0 22px}.mb-tabs.off{visibility:hidden}   /* ไม่ใช่มุมมองสมุด = ซ่อนแต่จองที่ไว้ (เลย์เอาต์ไม่ขยับ) */
.mb-lt{display:flex;align-items:center;gap:7px}.mb-lt .ic{width:var(--ic-3);height:var(--ic-3)}
.mb-big{display:flex;align-items:baseline;gap:var(--sp-2);margin-top:26px}
.mb-big b{font-size:64px;font-weight:var(--fw-bold);letter-spacing:-.03em;line-height:var(--lh-1);font-variant-numeric:tabular-nums}
.mb-big span{font-size:var(--fs-9);font-weight:var(--fw-medium);color:var(--mu)}
.mb-bar{height:10px;border-radius:var(--r-pill);background:var(--tile2);overflow:hidden;margin-top:var(--sp-4)}
.mb-bar i{display:block;height:100%;width:100%;transform:scaleX(var(--p,0));transform-origin:left;background:#fff;transition:transform .6s var(--ease)}   /* อนิเมต transform ไม่ใช่ width (ไม่ reflow บน iPad เก่า) */
@media (prefers-reduced-motion:reduce){.mb-bar i,.mb-pr,.mb-svb{transition:none}}
.mb-nxt{display:flex;justify-content:space-between;align-items:baseline;margin:var(--sp-3) 0 34px;font-size:var(--fs-7)}.mb-nxt small{font-size:var(--fs-5);color:var(--mu)}
.mb-flush{padding:0;gap:0;overflow:hidden}
.mb-row{display:flex;align-items:center;gap:var(--sp-3);min-height:62px;padding:var(--sp-3) var(--sp-4);box-shadow:0 1px 0 var(--tile2)}
.mb-row:last-child{box-shadow:none}
.mb-row .rs-n{width:36px;height:36px}
.mb-tx{flex:1;min-width:0;display:grid;gap:2px;font-size:var(--fs-8);font-weight:var(--fw-semibold)}.mb-tx small{font-size:var(--fs-5);font-weight:var(--fw-regular);color:var(--mu)}
.mb-am{font-size:var(--fs-9);font-weight:var(--fw-semibold);font-variant-numeric:tabular-nums}.mb-am.neg{color:var(--mu)}
.mb-soon{display:grid;justify-items:center;gap:var(--sp-3);padding:30px var(--sp-4);border-radius:var(--r-lg);box-shadow:inset 0 0 0 1px var(--line)}
.mb-soon .rs-n{width:48px;height:48px}.mb-soon .rs-n .ic{width:24px;height:24px}
.mb-soon .cl-chip{position:static;text-transform:none;font-size:var(--fs-5);letter-spacing:var(--ls-1);padding:7px 14px}
.mb-empty{display:grid;justify-items:center;gap:var(--sp-3);text-align:center;padding:8vh var(--sp-4) 0}
.mb-empty .rs-n{width:72px;height:72px}.mb-empty .rs-n .ic{width:34px;height:34px}
.mb-empty b{font-size:var(--fs-12);font-weight:var(--fw-semibold)}.mb-empty span{color:var(--mu);font-size:var(--fs-7)}
.mb-av{position:relative;width:96px;height:96px;margin:0 auto 22px;border-radius:var(--r-round);overflow:hidden;display:grid;place-items:center;background:var(--tile2);font-size:38px;font-weight:var(--fw-semibold);color:var(--mu)}
.mb-av img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.mb-gap{margin-bottom:18px}
.mb-pr{display:flex;align-items:center;gap:var(--sp-3);min-height:66px;padding:10px var(--sp-4);box-shadow:0 1px 0 var(--tile2);transition:background var(--t-6)}
.mb-pr:last-child{box-shadow:none}.mb-pr:focus-within{background:#17181a}
.mb-pr .rs-n{width:36px;height:36px}
.mb-pf{flex:1;min-width:0;display:grid;gap:1px}.mb-pf small{font-size:var(--fs-3);color:var(--mu)}
.mb-pf input{background:none;border:0;padding:0;color:#fff;font-size:var(--fs-9);width:100%;font-family:var(--font);min-height:24px}
.mb-pn{flex:1;font-size:var(--fs-9)}
.mb-svb{flex:none;width:36px;height:36px;border-radius:var(--r-round);display:grid;place-items:center;background:#fff;color:#000;visibility:hidden;transition:background var(--t-8) var(--ease)}
.mb-svb .ic{width:var(--ic-4);height:var(--ic-4)}
.mb-pr.dirty .mb-svb,.mb-pr.ok .mb-svb{visibility:visible}.mb-pr.ok .mb-svb{background:var(--ok);color:#fff}
.cap.mb-mini{width:136px;flex:none;padding:3px}.cap.mb-mini label{min-height:34px;font-size:var(--fs-5)}.cap.mb-mini .sel{top:3px;bottom:3px;left:3px;width:calc((100% - 6px) / 2)}
.mb-acct{display:grid;gap:14px;margin-top:6px}

/* ===== เชิญสมัครสมาชิก (OD-296 · #card มุมมอง intro) — บัตรเป็นพระเอก → คำชวน → บันไดขั้น 4 ขั้น → 3 ข้อเด่น → ปุ่มเดียว → ดูสิทธิ์ทั้งหมด · ทุกแถวสูงคงที่ ไม่ขยับตามภาษา ===== */
.mi{display:grid;gap:22px;margin-top:22px;margin-bottom:var(--sp-9)}
.mi-shine{display:none}   /* แสงวิ่งผ่านบัตรเฉพาะตอนเชิญสมัคร (#mCardWrap.mi-on · member.js) · transform ล้วน พักนานกว่าวิ่ง = นุ่ม ไม่ล่อตา */
.mi-on .mi-shine{display:block;position:absolute;inset:0;z-index:var(--z-4);pointer-events:none;width:46%;background:linear-gradient(105deg,transparent,rgb(255 255 255 / .09) 50%,transparent);transform:translateX(-120%) skewX(-14deg);animation:mi-shine 7s var(--ease) 1.2s infinite}
@keyframes mi-shine{0%,62%{transform:translateX(-120%) skewX(-14deg)}100%{transform:translateX(320%) skewX(-14deg)}}
@media (prefers-reduced-motion:reduce){.mi-on .mi-shine{display:none}}
html.lite .mi-on .mi-shine{display:none}
.mi-hd{display:grid;gap:var(--sp-2)}
.mi-hd b{font-size:var(--fs-14);line-height:var(--lh-3);font-weight:var(--fw-semibold);letter-spacing:-.4px;color:var(--tx)}
.mi-hd p{margin:0;font-size:var(--fs-7);line-height:1.55;color:var(--mu)}
/* บันไดขั้น: จุดกลมแบบ selector แดงของ dock (--sel-glass) = ขั้นที่ผู้ชมอยู่ · ขั้นอื่นเทาหม่น */
.mi-lad{display:grid;gap:10px}
.mi-lad ol{margin:0;padding:0;list-style:none;display:grid;grid-template-columns:repeat(4,1fr);position:relative}
.mi-lad ol::before{content:"";position:absolute;left:12.5%;right:12.5%;top:7px;height:2px;border-radius:2px;background:var(--tile2)}
.mi-lad li{position:relative;display:grid;align-content:start;justify-items:center;gap:2px;min-height:40px;text-align:center;font-size:var(--fs-5);font-weight:var(--fw-semibold);color:var(--mu)}
.mi-lad li::before{content:"";z-index:var(--z-1);width:16px;height:16px;border-radius:var(--r-round);background:var(--tile2);box-shadow:0 0 0 4px #000;margin-bottom:var(--sp-2)}
.mi-lad li.on{color:var(--tx)}
.mi-lad li.on::before{background:var(--sel-glass);box-shadow:var(--sel-glass-rim),0 0 0 4px #000}
.mi-lad p{margin:0;font-size:var(--fs-5);color:var(--dim)}
.mi-big{display:grid;gap:var(--sp-1)}
.mi-big > div{display:flex;gap:14px;align-items:center;min-height:76px}
.mi-big .rs-n{width:var(--tap);height:var(--tap)}.mi-big .rs-n .ic{width:var(--ic-5);height:var(--ic-5);color:#fff}
.mi-big span:last-child{display:grid;gap:2px;min-width:0}
.mi-big b{font-size:var(--fs-10);font-weight:var(--fw-semibold);color:var(--tx);line-height:var(--lh-4)}
.mi-big small{font-size:var(--fs-6);line-height:var(--lh-7);color:var(--mu)}
.mi-join{color:#fff;background:var(--sel-glass);box-shadow:var(--sel-glass-rim)}   /* ปิด (Coming Soon): แดงกระจกหรี่ ไม่มี glow ไม่หายใจ */
.mi-join:not(.mi-closed){background:var(--red-cta);--g:var(--glow-cta);--g-up:var(--glow-cta-up);box-shadow:var(--g);animation:var(--breath)}   /* เปิดรับสมัคร: สูตรเดียวกับ .cta.ready (แดงทึบ + glow + หายใจ · --breath:none ใน lite/reduced-motion) · แดง glow เดียวของหน้า */
.mi-join.mi-closed{opacity:var(--op-4);pointer-events:none;cursor:default}   /* ยังไม่เปิดรับสมัคร (signups_open=false): รูปทรงเดิมแต่หรี่ กดไม่ได้ ไม่มี error ไม่มี spinner */
.mi-join.mi-closed .mi-go,.mi-join:not(.mi-closed) .mi-wait{display:none}
/* OD-314: ปุ่มบันทึกการแก้ไข — สำเร็จ = เขียว --ok (ติ๊ก + Saved) ไม่หายใจ · ล้ม = สั่นปฏิเสธ (keyframe rs-shake เดียวกับวงกลมที่ขาดข้อมูล) */
.cta.saved{pointer-events:none;background:var(--ok);color:#fff;--g:var(--glow-ok-strong);box-shadow:var(--g)}
.cta.saved .ic{display:inline-block;width:var(--ic-4);height:var(--ic-4);margin-right:6px;vertical-align:-4px;background:currentColor}
.cta.shake,.cta.ready.shake,#cta.shake{animation:var(--sel-anim,rs-shake) .42s var(--ease-out)}
.mi-free{margin:-6px 0 0;display:grid;gap:2px;text-align:center;font-size:var(--fs-5);color:var(--dim)}
.mi-free b{font-size:var(--fs-7);font-weight:var(--fw-semibold);color:var(--tx)}
.mi-more summary{list-style:none;display:flex;align-items:center;justify-content:center;gap:6px;min-height:var(--tap);font-size:var(--fs-7);font-weight:var(--fw-medium);color:var(--mu);cursor:pointer}
.mi-more summary::-webkit-details-marker{display:none}
.mi-more summary::after{content:"";width:8px;height:8px;border:solid currentColor;border-width:0 2px 2px 0;transform:rotate(45deg) translateY(-2px);transition:transform var(--t-8) var(--ease)}
.mi-more[open] summary::after{transform:rotate(-135deg) translateY(-2px)}
.mi-more ul{margin:var(--sp-1) 0 0;padding:0;list-style:none;display:grid}
.mi-more li{display:flex;gap:var(--sp-3);align-items:center;height:52px;font-size:var(--fs-7);font-weight:var(--fw-medium);color:var(--tx)}
.mi-more li .rs-n{width:34px;height:34px}
.mi-soon{margin-left:auto;font-size:var(--fs-1);font-weight:var(--fw-semibold);letter-spacing:var(--ls-2);padding:1px var(--sp-2);border-radius:var(--r-pill);background:var(--tile2);color:var(--mu);white-space:nowrap}   /* เทา ไม่แดง/เขียว */
@media (prefers-reduced-motion:reduce){.mi-more summary::after{transition:none}}
/* โฆษณาสั้นในหน้า Search (ไม่ใช่สมาชิก): การ์ดสูงคงที่ วงกลม .rs-n + 2 บรรทัด + chevron · แตะ = กดไอคอน Membership บน dock */
.sr-ad{display:flex;align-items:center;gap:14px;width:100%;height:76px;padding:0 var(--sp-4);border-radius:var(--r-lg);background:var(--tile);box-shadow:inset 0 0 0 1px var(--line);text-align:left;color:var(--tx)}
.sr-ad .rs-n{width:var(--tap);height:var(--tap)}.sr-ad .rs-n .ic{width:var(--ic-5);height:var(--ic-5);color:#fff}
.sr-ad > span:nth-child(2){flex:1;min-width:0;display:grid;gap:2px}
.sr-ad b{font-size:var(--fs-9);font-weight:var(--fw-semibold);line-height:var(--lh-4)}
.sr-ad b,.sr-ad small{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}   /* หนึ่งบรรทัดต่อข้อความ แม้จอ 360 (ล้น = …) */
.sr-ad small{font-size:var(--fs-5);color:var(--mu);line-height:var(--lh-5)}
.sr-ad::after{content:"";flex:none;width:9px;height:9px;border:solid var(--mu);border-width:2px 2px 0 0;transform:rotate(45deg)}   /* chevron */
/* OD-307: แบนเนอร์ชวนสมัครอยู่ท้ายหน้า Reserved · ซ่อนไว้ก่อน (สมาชิกไม่แวบ) · โชว์เฉพาะแขก (body.guest) กับคนล็อกอินแล้ว /line-customer บอกว่ายังไม่เป็นสมาชิก (body.nonmem) */
.sr-ad{display:none}
body.guest .sr-ad,body.nonmem .sr-ad{display:flex}
.out{text-align:center;margin:var(--sp-2) 0 0}.out .lnk{margin:0}   /* Log Out เล็กๆ ท้ายหน้า Reserved (เดิมอยู่หัวข้อ Your Tickets) */

/* ===== glow หายใจ (OD-220 · OD-222 · OD-276 r2): เฉพาะ CTA แดง (บรรทัด .cta) · ขั้นที่กำลังทำ (ขาว) · เขียว = เสร็จ/LINE — แดงอื่นทุกตัวไม่มี glow — ที่เดียวของ app.css · ท้ายไฟล์เพื่อชนะกฎ box-shadow ก่อนหน้า =====
   แต่ละกลุ่มตั้ง --g (ระดับปัจจุบัน = ต่ำสุดของการหายใจ) กับ --g-up (สว่างสุด) · keyframe breath ตัวเดียว · --breath:none (reduced-motion) = นิ่งที่ --g */
@keyframes breath{0%,100%{box-shadow:var(--g)}50%{box-shadow:var(--g-up)}}
.steps .on i{--g:var(--glow-white);--g-up:var(--glow-white-up)}
.tick,.ad-chip,.ad-up,.status.ok::before{--g:var(--glow-ok);--g-up:var(--glow-ok-up)}
.rs-n.done,.rs-card.done .rs-n{--g:var(--glow-ok);--g-up:var(--glow-ok-up)}
.rs-card.rs-warn .rs-n{--g:var(--glow-red);--g-up:var(--glow-red-up)}   /* OD-300: จำนวนแขกว่าง/นอกช่วงตอนออกจากช่อง = วงกลม miss แดงเรืองหายใจ (คลาส rs-warn ใส่โดย app.js เฉพาะการ์ด guests · ไม่ใช่ miss ทั่วไป) */
.btn.linelogin{--g:var(--glow-line-strong);--g-up:var(--glow-line-strong-up)}
.mb-pr.ok .mb-svb{--g:var(--glow-ok);--g-up:var(--glow-ok-up)}   /* บันทึกชื่อสำเร็จ = เขียว */
.cl-chip.cl-act{--g:var(--glow-red);--g-up:var(--glow-red-up)}   /* ป้าย Need Payment = แดงเรืองหายใจช้า (OD-298): แดง = ต้องทำ · ข้อยกเว้นเดียวของชิปแดงที่มี glow นอกจาก cl-top */
.steps .on i,.tick,.ad-chip,.ad-up,.status.ok::before,.btn.linelogin,.rs-n.done,.rs-card.done .rs-n,.rs-card.rs-warn .rs-n,.mb-pr.ok .mb-svb,.cl-chip.cl-act{box-shadow:var(--g);animation:var(--breath)}

/* ===== Light Mode (html.lite · เครื่องเก่า/iPad รุ่นเก่า): ตัดของที่ GPU แพง เลย์เอาต์เหมือนเดิมทุกพิกเซล =====
   เปิดด้วย ?lite=1 หรือ localStorage rm.lite=1 (สคริปต์ใน <head> ของทั้งสองแอป) · สวิตช์ใน Settings ของสตาฟ
   เบลอ: ทั้งแอปไม่มี backdrop-filter เหลือ ยกเว้นชั้นเบลอหัวข้อ (::before) ที่ปิดด้านล่าง
   อนิเมชันตกแต่ง: R สั่น · หายใจ (โทเคน --breath เดียวกับ reduced-motion) · ประกาย · ดาวกะพริบ · หน้าเข้าจาง/ลูกสไลด์ · ที่เหลือ (ย่อ/กาง dock+หัวข้อ, selector) เป็น transform ของ compositor ถูกพอ คงไว้ */
html.lite{--breath:none;--sel-anim:none;--sel-over:0}
html.lite{--dg-under:rgb(8 8 10 / .98);--dg-under-card:var(--dg-under);--dg-under-light:var(--dg-under);--dg-scrim:rgb(0 0 0 / .90)}   /* lite: พื้นรอง/ม่านทึบขึ้นเล็กน้อยแทนเบลอ (OD-339) */
/* Increase Contrast ของระบบ (Safari/iOS 14.1+ · MDN prefers-contrast): พื้นรองทึบขึ้น ≥.85 · เส้นกรอบเข้ม .30 (Apple HIG Accessibility: ต้องมีชุดสีคอนทราสต์สูง) · lite ชนะด้วยความจำเพาะ (.98 ทึบกว่าอยู่แล้ว) · Reduce Transparency ไม่มี media query ใน Safari */
@media (prefers-contrast:more){:root{--dg-under:rgb(4 4 5 / .85);--dg-under-card:rgb(4 4 5 / .92);--dg-under-light:rgb(4 4 5 / .92);--dg-line-a:.30}}
html.lite{--pg-fade:none}   /* จาง .cta เข้าหน้า: ปิดในโหมดเบา และใน reduced-motion (ด้านล่าง) */
html.lite{--sel-press-scale:1}   /* OD-452: เครื่องเก่า/ลดการเคลื่อนไหว = กดค้างไม่ขยาย (ไม่มี scale · ไม่มีอนิเมชัน) */
@media (prefers-reduced-motion:reduce){:root{--sel-press-scale:1}}
@media (prefers-reduced-motion:reduce){:root{--pg-fade:none}}
html.lite .page > h1::before,html.lite .tophd::before{display:none}   /* ชั้นเบลอของกล่องหัวข้อไม่มีอะไรเหลือให้วาด (พื้นดำไล่สีอยู่ ::after ยังอยู่) */
html.lite .rs-card .days{-webkit-mask-image:none;mask-image:none}   /* เครื่องเก่า: ไม่ให้ตัวเลื่อนต้องวาดผ่านมาสก์ (ขอบตัดตรงๆ เหมือนเดิม) */
html.lite h1 .R,html.lite .promo::after{animation:none}
:where(html.lite) :where(.page.cur) > :where(:not(.cta,.toast,#undo,.tophd,h1,[data-mv])),:where(html.lite) :where(.page.cur) > :where([data-mv]) > :where(:not(.cta)){animation:none}   /* :where ทั้งหมด = ความจำเพาะ 0 เหมือนกฎ pg-slide: ลูกที่มีอนิเมชันของตัวเอง (.s-fresh) ชนะ ไม่โดนปิด */

/* OD-337/344 (WO-361): ของเสริมไม่คืนเงิน + VAT — บรรทัด "ราคายังไม่รวม VAT" ใต้หัวหน้า 2 (จองที่ 1 บรรทัดไว้ก่อนข้อมูลมา) · โน้ตเป็นการ์ดเล็ก ไม่ใช่ช่องติ๊ก (ข้อความเดียวทุกหน้า มาจาก app.js) */
.ad-vat{margin:-12px 0 18px;min-height:19px;font-size:var(--fs-5);color:var(--mu)}
.nc{margin:var(--sp-4) 0 0;padding:var(--sp-3) var(--sp-4);border-radius:var(--r-lg);background:var(--tile);color:var(--mu);font-size:var(--fs-5);line-height:var(--lh-8)}
#pay2{margin-top:var(--sp-4)}   /* หน้า 2: สรุปยอดอยู่ท้ายหน้า (โผล่เมื่อมีของเสริม · ไม่ดันอะไรที่อยู่ก่อนหน้า) */
.nc.off{visibility:hidden}   /* หน้า 2: ไม่มีของเสริม = จางหายแต่พื้นที่คงอยู่ (เลย์เอาต์ไม่ขยับตอนเพิ่ม/เอาออก) */
.pay .sn{margin:-2px 0 var(--sp-1);font-size:var(--fs-3);line-height:var(--lh-7);color:var(--mu)}
.pay .r.sub{font-size:var(--fs-5);color:var(--mu)}.pay .r.sub b{font-weight:var(--fw-regular)}
.sp .tot{margin-top:var(--sp-1);color:var(--tx);font-weight:var(--fw-semibold)}   /* บรรทัด "Total incl. VAT" ท้ายกล่องแยกยอดของกล่องจ่าย (OD-404) · ขาวตัวหนากว่าแถวบน · ใช้ dt/dd เดิม ไม่มีเส้น (เส้นใน grid จะขาดตรงช่องว่างคอลัมน์) */
.sp .sn{display:block;margin-top:2px;font-size:var(--fs-3);font-weight:var(--fw-regular);line-height:var(--lh-6);color:var(--mu)}
