/* Printpao — product.css
 * หน้าสินค้า:
 *   ครึ่งบน  = รูปซ้าย + แผงเลือกตัวเลือก/ราคาขวา (จบในตัว)
 *   ครึ่งล่าง = รายละเอียดเต็มความกว้างจอ ไม่แบ่งซ้ายขวา
 */

.crumb { margin-bottom: 12px; font-size: 14px; color: var(--ink-mute); padding-block: 18px 0; }
.crumb a { color: var(--ink-soft); text-decoration: none; }
.crumb a:hover { color: var(--purple); }

/* ═══════════ แบนเนอร์เต็มจอ (hero) ═══════════
   ★ อัตราส่วน 3:1 ตรงกับไฟล์จริง (เช่น plastic-fan-hero.jpg 1600×533)
     ถ้าใช้ background-size:cover กับกรอบคนละสัดส่วนจากไฟล์ จะโดนตัดขอบบน-ล่าง/ซ้าย-ขวา
     ผิดจากที่ตากล้องตั้งใจจัดองค์ประกอบไว้ — ให้ทีมกราฟิกถ่าย/crop มาที่ 3:1 เป๊ะ
     (ดูตาราง "สเปกรูป" ที่คุยกันไว้ก่อนหน้า) */
.pdp-hero {
  width: 100%;
  aspect-ratio: 3 / 1;
  background-size: cover;
  background-position: center;
  background-color: var(--surface-2);   /* กันจอวาบขาวระหว่างรอรูปโหลด */
  position: relative;
}
/* วิดีโอแทนรูป (TASK-203) — เต็มกรอบ 3:1 ทับรูปพื้นหลัง */
.pdp-hero video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
@media (max-width: 880px) {
  .pdp-hero { aspect-ratio: 16 / 9; }   /* จอแคบ 3:1 จะแบนเกินไป อ่านรายละเอียดในรูปไม่ออก */
}

/* ═══════════ ครึ่งบน ═══════════ */

/* ★ ข้อความไทยไม่มีช่องว่างระหว่างคำเสมอไป (เช่น "แนวตั้ง", "ประชาสัมพันธ์บนโต๊ะและเคาน์เตอร์")
   ถ้าเบราว์เซอร์หาจุดตัดคำไม่ได้ ข้อความจะไหลยาวเป็นบรรทัดเดียวจนดันทั้งหน้าล้นขวา (เกิดจริงบนจอมือถือแคบ)
   บังคับตัดคำได้ทุกตัวอักษรถ้าจำเป็น กันไว้ทั้งหน้าสินค้า — ไม่กระทบ .buybar-name ฯลฯ ที่ตั้ง white-space:nowrap ไว้เฉพาะจุด */
.pdp, .pdp-section, .pdp-cta { overflow-wrap: anywhere; }
/* ★ .config-body/#opts/.chips เป็น grid ซ้อนหลายชั้น — grid ลูกแต่ละชั้นมี min-width:auto เป็นค่าเริ่มต้น
   (ไม่ใช่ 0) ถ้าเนื้อหาข้างในกว้างกว่าที่ตั้งใจ มันแอบดันกล่องแม่ให้กว้างตามได้ทุกชั้นที่ไม่ได้ตั้ง min-width:0 ไว้
   กันทุกชั้นในคราวเดียวกันไปเลย กว่าจะไล่ตั้งทีละ class */
.config *, .pdp-section * { min-width: 0; }

.pdp {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 440px;
  gap: 40px;
  align-items: start;
  padding-block: 20px 56px;
}
.pdp > * { min-width: 0; }

/* ── แกลเลอรี ── */
.gallery { position: sticky; top: 80px; }   /* 2026-10-03 — เว้นให้แถบขั้นตอนติดจอ (64px) แทน header */

.gal-main {
  aspect-ratio: 1 / 1;
  max-width: 500px; /* 👈 เพิ่มบรรทัดนี้ (ปรับตัวเลขลด-เพิ่มได้ตามต้องการ) */
  margin: 0 auto;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: #fff;      /* พื้นขาว ไม่แย่งสายตากับตัวรูป */
  padding: 8px;
  display: grid; place-items: center;
  color: var(--ink-mute); font-size: 14px;
  overflow: hidden;
}
.gal-main { position: relative; cursor: zoom-in; }
/* ★ 2026-09-24 — ทำไม position:absolute แทน width/height:100% ธรรมดา:
   .gal-main เป็น display:grid ที่ไม่มี grid-template-rows ชัดเจน (สูงมาจาก aspect-ratio เฉยๆ)
   Chrome ไม่ถือว่าความสูงที่มาจาก aspect-ratio เป็นค่า "แน่นอน (definite)" พอให้ลูก resolve
   height:100% ได้ตรงๆ เลย fallback ไปคำนวณความสูงจาก "ความกว้าง ÷ อัตราส่วนจริงของรูป" แทน
   ★ บั๊กที่เจอจริง (2026-09-24): กรอบ 3:1 (.prep-guide-wrap .gal-main) ที่ padding 8px ทำให้ content-box
   มีอัตราส่วนเพี้ยนจาก 3:1 เล็กน้อย (ไม่ตรงกับรูปเป๊ะ) รูปเลยถูกคำนวณสูงเกิน padding ไปกิน
   ขอบมุมโค้งของกรอบ — เจอง่ายกับรูปทดสอบ (บั๊กจริงมีทุกที่ที่ใช้ .gal-main แต่รูปจริงมีขอบขาวใน
   ตัวไฟล์อยู่แล้วเลยไม่ทันสังเกต) แก้ด้วย position:absolute+inset ตัด percentage-height ของ grid
   ออกไปเลย ให้คำนวณจากกรอบ (top/left/right/bottom) ตรงๆ แทน ไม่ง้อ aspect-ratio ของพ่อ */
.gal-main img { position: absolute; top: 8px; left: 8px; right: 8px; bottom: 8px; width: calc(100% - 16px); height: calc(100% - 16px); object-fit: contain; }

/* ป้ายบอกว่ากดดูรูปเต็มได้ — โผล่ตอนเอาเมาส์ชี้ */
.gal-zoom {
  position: absolute; right: 14px; bottom: 14px;
  background: rgba(20,16,31,.78); color: #fff;
  font-size: 12.5px; padding: 6px 12px; border-radius: 999px;
  opacity: 0; transition: .15s; pointer-events: none;
}
.gal-main:hover .gal-zoom { opacity: 1; }

/* thumbnail ที่กำลังถูกเลือก */
.gal-thumbs div.on { border-color: var(--purple); box-shadow: inset 0 0 0 1px var(--purple); }

/* ★ เดิมเป็น grid 5 คอลัมน์ตายตัว — รูปเยอะตกไปแถว 2 ดูไม่เรียบร้อย รูปน้อยก็ดูโหว่ (2026-09-19)
   เปลี่ยนเป็นแถวเดียวเลื่อนซ้าย-ขวา รูปเล็กขนาดคงที่เสมอ ไม่ว่าจะมีกี่รูปก็ไม่ล้นแถว/ไม่ดูโหว่ */
.gal-thumbs {
  display: flex;
  justify-content: center;           /* รูปน้อยไม่ล้นแถว → อยู่กึ่งกลางแทนที่จะชิดซ้ายโดดๆ */
  gap: 10px;
  margin-top: 10px;
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x proximity;
  padding-bottom: 4px;               /* กันเงา/scrollbar ชนขอบล่างพอดี */
  scrollbar-width: thin;
}
.gal-thumbs div {
  flex: 0 0 72px;                    /* ขนาดคงที่เสมอ ไม่ยืด/หดตามจำนวนรูป */
  aspect-ratio: 1;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--surface-2);
  overflow: hidden;
  cursor: pointer;
  scroll-snap-align: start;
  transition: .15s;
}
.gal-thumbs div:hover { border-color: var(--purple); }
.gal-thumbs img { width: 100%; height: 100%; object-fit: cover; }

/* ── ลิงก์ Template เล็กๆ ใต้รูป ──
   ของเดิมเป็น section ใหญ่ด้านล่างหน้า ย้ายมาตรงนี้เพราะเป็นข้อมูลประกอบ ไม่ใช่พระเอก
   ตัวเต็มจะไปโผล่อีกทีในขั้นตอน "เตรียมไฟล์งาน" ซึ่งเป็นจังหวะที่ลูกค้าต้องใช้จริง */
.tpl-mini {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px 14px;
  margin-top: 14px; padding-top: 14px;
  border-top: 1px dashed var(--line);
  font-size: 13.5px;
}
.tpl-mini-label { color: var(--ink-mute); font-weight: 600; }
.tpl-mini a {
  color: var(--purple); text-decoration: none;
  border-bottom: 1px dotted var(--purple-br);
  padding-bottom: 1px;
}
.tpl-mini a:hover { border-bottom-style: solid; }


/* ── แผงเลือกตัวเลือก ── */
.pdp-title { margin: 0 0 6px; font-size: 32px; line-height: 1.2; }
.pdp-sub { color: var(--ink-soft); margin: 0; font-size: 15px; }

.config {
  position: sticky; top: 80px;   /* เว้นให้แถบขั้นตอนติดจอ (.osteps 64px) */
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: #fff;
  box-shadow: var(--shadow);
  overflow: hidden;
}
.config-body { padding: 22px; display: grid; gap: 20px; }

#opts { display: grid; gap: 20px; }

/* ★ 2026-10-05 (มติเจ้าของ) — ป้าย "เริ่มต้น ฿ต่อชิ้น" ใต้ชื่อสินค้า ดึงดูดก่อนเลือกตัวเลือก (product-configurator.blade.php) */
.price-teaser { display: flex; align-items: baseline; flex-wrap: wrap; gap: 6px 10px; margin: 2px 0 18px; }
/* ป้ายราคาใต้ชื่อสินค้า (components/sf-card-price full) — เด่นรอง ไม่แย่งกล่องยอดรวมด้านล่าง */
.price-teaser { flex-direction: column; align-items: flex-start; gap: 6px; }
.pt-main { font-size: 16px; font-weight: 600; color: var(--ink-soft); }
.pt-main b { font-size: 24px; font-weight: 800; color: var(--sf-pink-dk, var(--purple)); }
.pt-main em { font-style: normal; font-size: 14px; font-weight: 500; color: var(--ink-mute); }
.pt-sub { font-size: 14px; color: var(--purple); background: var(--purple-lt); border: 1px solid var(--purple-br); border-radius: 999px; padding: 3px 12px; }
.pt-sub b { font-weight: 700; }
.price-teaser-label { font-size: 14px; color: var(--ink-mute); }
.price-teaser-amount { font-size: clamp(28px, 4vw, 34px); font-weight: 900; color: var(--sf-pink-dk, var(--purple)); line-height: 1; }
.price-teaser-unit { font-size: 13.5px; color: var(--ink-mute); }
.price-teaser-was { font-size: 13.5px; color: var(--ink-mute); text-decoration: line-through; }
.price-teaser-off {
  font-size: 12.5px; font-weight: 800; color: #fff; background: #e11d48;
  padding: 2px 8px; border-radius: 999px; line-height: 1.6;
}

.optgroup > .lbl { display: flex; align-items: baseline; gap: 8px; margin-bottom: 10px; }
.optgroup .lbl b { font-size: 15.5px; flex: none; }   /* 2026-10-31 — คำอธิบายขวายาว (ขั้นต่ำ · สั่งออนไลน์ได้ถึง) ห้ามบีบหัวข้อจนตัดคำ */
.optgroup .lbl span { font-size: 13px; color: var(--ink-mute); margin-left: auto; text-align: right; }

.chips { display: grid; gap: 8px; grid-template-columns: repeat(2, 1fr); }
.chip { position: relative; }
.chip input { position: absolute; opacity: 0; inset: 0; cursor: pointer; }
.chip span {
  display: block;
  border: 1.5px solid var(--line);
  border-radius: var(--r-sm);
  padding: 11px 13px;
  font-size: 14.5px; line-height: 1.35;
  cursor: pointer; transition: .12s; background: #fff;
}
.chip span small { display: block; color: var(--ink-mute); font-size: 12.5px; }
.chip input:checked + span { border-color: var(--purple); background: var(--purple-lt); box-shadow: inset 0 0 0 1px var(--purple); }
.chip input:focus-visible + span { outline: 2px solid var(--yellow); outline-offset: 2px; }
.chip span:hover { border-color: var(--purple-br); }

.qty-row { display: flex; align-items: center; gap: 10px; }
.qty-row input[type=number] {
  font: inherit; width: 130px; padding: 11px 12px;
  border: 1.5px solid var(--line); border-radius: var(--r-sm); text-align: center;
}
.qty-row input:focus { border-color: var(--purple); outline: none; }

/* ปุ่ม − [จำนวน] + (2026-09-25) — กล่องเดียวกัน ขอบร่วมกัน · ตัดลูกศรขึ้นลงของเบราว์เซอร์ออก (มีปุ่มแล้ว) */
/* ★ 2026-09-28 (เจ้าของขอ) — ยืดเต็มความกว้างกล่องตัวเลือก ปุ่ม −/+ คงขนาด ช่องตัวเลขตรงกลางยืดแทน
   อยากเปลี่ยนความกว้าง: แก้ width ตรงนี้ (เช่น 260px หรือ 60%) · ความกว้างปุ่ม: .qty-stepper button · ความสูง: padding ของ input */
.qty-stepper {
  display: flex; align-items: stretch; width: 100%;
  border: 1.5px solid var(--line); border-radius: var(--r-sm); overflow: hidden; background: #fff;
}
.qty-row .qty-stepper input[type=number] { flex: 1; min-width: 0; }
.qty-stepper:focus-within { border-color: var(--purple); }
.qty-stepper button {
  width: 46px; border: 0; background: var(--surface-2); color: var(--ink);
  font: inherit; font-size: 20px; line-height: 1; cursor: pointer;
}
.qty-stepper button:hover { background: var(--purple-lt); color: var(--purple); }
.qty-stepper button:active { background: var(--purple-br); }
.qty-row .qty-stepper input[type=number] {
  width: 84px; border: 0; border-inline: 1.5px solid var(--line); border-radius: 0;
  font-size: 18px; -moz-appearance: textfield; appearance: textfield;
}
.qty-stepper input::-webkit-outer-spin-button,
.qty-stepper input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }

.qty-presets { display: flex; gap: 6px; flex-wrap: wrap; }
.qty-presets button {
  font: inherit; font-size: 13.5px; padding: 7px 12px; border-radius: 999px;
  border: 1px solid var(--line); background: #fff; cursor: pointer; transition: .12s;
}
.qty-presets button:hover { border-color: var(--purple-br); background: var(--purple-lt); }
.qty-presets button.on { border-color: var(--purple); background: var(--purple-lt); color: var(--purple); font-weight: 700; }

/* ── กล่องราคา ── */
.pricebox { background: var(--purple-lt); border-top: 1px solid var(--purple-br); padding: 20px 22px 22px; }
.price-line { display: flex; justify-content: space-between; align-items: baseline; font-size: 14.5px; color: var(--ink-soft); }
.price-line + .price-line { margin-top: 6px; }
.price-total { display: flex; justify-content: space-between; align-items: baseline; margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--purple-br); }
.price-total span { font-size: 15px; font-weight: 700; }
.price-total b { font-size: 30px; color: var(--purple); line-height: 1; }
.price-total b small { font-size: 15px; font-weight: 600; }
.eta { font-size: 13.5px; color: var(--ink-soft); margin-top: 10px; }
.eta b { color: var(--ink); }
.pricebox .btn { margin-top: 16px; }

/* ★ 2026-10-03 (มติเจ้าของ) — ปุ่มไปขั้นถัดไปอยู่ใต้ยอดรวม กลางกล่อง + เด้งเบาๆ เป็นจังหวะให้สะดุดตา
   transform อย่างเดียว (ไม่ดันเนื้อหารอบข้าง = CLS ไม่เสีย) · ชี้/โฟกัสแล้วหยุด · เครื่องตั้งลดการเคลื่อนไหว = ไม่เด้ง */
.pv-cta { display: flex; justify-content: center; flex-wrap: wrap; gap: 10px; }   /* flex-wrap + gap: เมื่อมีลิงก์/ข้อความใต้ปุ่มออกแบบ (EPIC-011) */
.pv-cta .btn { width: 100%; max-width: 320px; }
.cta-bounce { animation: cta-bounce 2.6s ease-in-out infinite; }
.cta-bounce:hover, .cta-bounce:focus-visible, .cta-bounce:disabled { animation-play-state: paused; }
@keyframes cta-bounce {
  0%, 62%, 100% { transform: translateY(0); }
  70% { transform: translateY(-6px); }
  78% { transform: translateY(0); }
  85% { transform: translateY(-3px); }
  92% { transform: translateY(0); }
}
@media (prefers-reduced-motion: reduce) { .cta-bounce { animation: none; } }

#pv-end { display: block; height: 1px; }   /* จุดอ้างอิงท้ายกล่องราคา — JS ซ่อน/โชว์แถบล่างตามจุดนี้ */
.server-note { font-size: 12px; color: var(--ink-mute); margin-top: 10px; text-align: center; }

/* ═══════════ ครึ่งล่าง — เต็มความกว้างจอ ═══════════ */

.pdp-section { padding-block: 64px; border-top: 1px solid var(--line); }
.pdp-section.alt { background: var(--surface-2); }

/* คุมความกว้างข้อความให้อ่านสบาย แต่พื้นหลังยังเต็มจอ */
.wrap-narrow { max-width: 860px; }

.pdp-section-title {
  font-size: 30px;
  margin: 0 0 14px;
  letter-spacing: -.01em;
}
.pdp-section-title::after {
  content: "";
  display: block;
  width: 56px; height: 4px;
  background: var(--yellow);
  border-radius: 2px;
  margin-top: 12px;
}

.pdp-lead {
  color: var(--ink-soft);
  font-size: 16.5px;
  line-height: 1.8;
  margin: 0 0 24px;
  white-space: pre-line;
}

.pdp-section-img {
  width: 100%;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: #fff;
}

/* ตารางสเปค */
.spec-table { width: 100%; table-layout: fixed; border-collapse: collapse; font-size: 15.5px; }
.spec-table th, .spec-table td {
  text-align: left; padding: 14px 16px;
  border-bottom: 1px solid var(--line); vertical-align: top;
  overflow-wrap: anywhere;
}
.spec-table th { width: 32%; color: var(--ink-soft); font-weight: 600; background: #fff; }
.pdp-section.alt .spec-table th { background: var(--surface-2); }

/* ── แถบปิดท้าย ── */
.pdp-cta {
  background: var(--purple);
  color: #fff;
  text-align: center;
  padding-block: 56px;
  border-top: 4px solid var(--yellow);
}
.pdp-cta h2 { font-size: 28px; margin: 0 0 8px; }
.pdp-cta p { color: rgba(255,255,255,.85); margin: 0 0 24px; }
.pdp-cta-actions { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; }
.pdp-cta .btn-ghost { background: transparent; color: #fff; border-color: rgba(255,255,255,.5); }
.pdp-cta .btn-ghost:hover { background: rgba(255,255,255,.12); }

/* ═══════════ จอแคบ ═══════════ */
@media (max-width: 980px) {
  .pdp { grid-template-columns: 1fr; gap: 28px; }
  .gallery, .config { position: static; }
  .pdp-title { font-size: 26px; }
  .pdp-section { padding-block: 44px; }
  .pdp-section-title { font-size: 24px; }
}
@media (max-width: 560px) {
  .gal-thumbs div { flex-basis: 60px; }   /* จอแคบลดขนาด thumbnail ลงหน่อย ยังเลื่อนแถวเดียวเหมือนเดิม */
  .spec-table th { width: 42%; }
  .spec-table th, .spec-table td { padding: 11px 12px; font-size: 14px; }
  .qty-row input[type=number] { width: 100%; }
  .qty-stepper { width: 100%; }
  .qty-stepper button { width: 56px; }
  .qty-row .qty-stepper input[type=number] { flex: 1; width: auto; }
  .pdp-lead { font-size: 15.5px; }
}
/* ═══════════ แถบสรุปยอดลอยด้านล่าง (buybar) — เอาออกแล้ว 2026-10-03 (มติเจ้าของ) ═══════════
   ปุ่มไปต่ออยู่ใต้ราคาในกล่องราคาอย่างเดียว (.pv-cta) */


/* ═══════════ ดูรูปเต็มจอ (lightbox) ═══════════
   สร้างโดย public/js/gallery.js แล้วแปะไว้ท้าย <body> */

.lightbox {
  /* ★ 2026-10-06 (มติเจ้าของ: "กดดูรูป header กับปุ่ม LINE ยังโชว์อยู่ ต้องปิดทุกอย่าง") — z-index เดิม (100)
     ต่ำกว่า header (800) ปุ่ม LINE (900) แผ่นกรอง (950) ตามสเกลที่ตั้งไว้ใน storefront.css เลยโผล่ทับ
     lightbox ได้ทั้งที่ควรจะอยู่บนสุดตอนดูรูปเต็มจอ — ยกให้สูงกว่าทุกชั้นที่มีในเว็บตอนนี้ */
  position: fixed; inset: 0; z-index: 1200;
  background: rgba(20,14,24,.92);
  display: flex; align-items: center; justify-content: center;
  padding: 40px;
}
.lightbox img {
  max-width: 100%; max-height: 100%;
  object-fit: contain;
  border-radius: var(--r-sm);
  background: #fff;
}
.lightbox.flat img { border-radius: 0; }   /* รูปงานออกแบบของลูกค้า — เห็นขอบจริงของงาน ไม่มีมุมมน */
.lightbox-close {
  position: absolute; top: 18px; right: 22px;
  width: 44px; height: 44px;
  font-size: 30px; line-height: 1;
  background: rgba(255,255,255,.14); color: #fff;
  border: 0; border-radius: 999px; cursor: pointer;
}
.lightbox-close:hover { background: rgba(255,255,255,.28); }

.lightbox-nav {
  position: absolute; top: 50%; transform: translateY(-50%);
  width: 52px; height: 52px;
  font-size: 34px; line-height: 1;
  background: rgba(255,255,255,.14); color: #fff;
  border: 0; border-radius: 999px; cursor: pointer;
}
.lightbox-nav:hover { background: rgba(255,255,255,.28); }
.lightbox-nav.prev { left: 20px; }
.lightbox-nav.next { right: 20px; }
/* ★ 2026-09-28 — เปิดรูปเดี่ยวจากปุ่มแว่นขยาย (printpaoOpenLightbox) ไม่มีชุดรูปให้เลื่อน → ซ่อนลูกศร */
.lightbox.single .lightbox-nav { display: none; }

@media (max-width: 560px) {
  .lightbox { padding: 16px; }
  .lightbox-nav { width: 42px; height: 42px; font-size: 26px; }
  .lightbox-nav.prev { left: 8px; }
  .lightbox-nav.next { right: 8px; }
}

/* ═══════════ จุดขายสั้นๆ ═══════════ */
.selling-points {
  list-style: none; padding: 0; margin: 0 0 28px;
  display: grid; gap: 10px;
}
.selling-points li {
  position: relative; padding-left: 30px;
  font-size: 16px; color: var(--ink);
}
.selling-points li::before {
  content: "✓";
  position: absolute; left: 0; top: 1px;
  width: 20px; height: 20px;
  display: grid; place-items: center;
  background: var(--purple); color: #fff;
  border-radius: 999px; font-size: 12px; font-weight: 700;
}

/* ═══════════ มาตรฐานการผลิต — แถวสลับซ้าย-ขวา ═══════════
   ★ HTML เรียง "รูป → ข้อความ" เหมือนกันทุกแถวเสมอ
     การสลับข้างทำด้วย CSS ตรงนี้ที่เดียว (order: 2 ในแถวเลขคู่)
     เหตุผล: ลำดับ DOM คงที่ = โปรแกรมอ่านหน้าจอและปุ่ม Tab เดินถูกทุกแถว
     และถ้าวันหลังเพิ่มแถวที่ 4 มันจะสลับข้างเองโดยไม่ต้องแก้อะไร */

.pres .pres-head { max-width: 860px; margin-bottom: 40px; }

.pres-rows { display: grid; gap: 56px; }

.pres-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 40px;
  align-items: center;
}

.pres-fig { margin: 0; }
.pres-fig img {
  width: 100%; aspect-ratio: 4 / 3; object-fit: cover;
  border-radius: var(--r-md);
  border: 1px solid var(--line);
  background: #fff;
}

/* แถวเลขคู่ → ดันรูปไปอยู่ขวา ข้อความเลื่อนมาซ้ายเอง */
.pres-row:nth-child(even) .pres-fig { order: 2; }

.pres-eyebrow {
  display: inline-block;
  background: var(--purple-lt); color: var(--purple);
  border: 1px solid var(--purple-br);
  font-size: 12.5px; font-weight: 700;
  padding: 4px 12px; border-radius: 999px;
  margin-bottom: 12px;
}
.pres-text h3 { font-size: 23px; margin: 0 0 12px; line-height: 1.3; }
.pres-text p  { color: var(--ink-soft); font-size: 16px; line-height: 1.8; margin: 0; }

@media (max-width: 880px) {
  .pres-row { grid-template-columns: 1fr; gap: 20px; }
  .pres-row:nth-child(even) .pres-fig { order: 0; }   /* จอแคบ เรียงบน-ล่างเหมือนกันหมด */
  .pres-rows { gap: 44px; }
  .pres-text h3 { font-size: 20px; }
  .selling-points li { font-size: 15px; }
}


/* ═══════════════════════════════════════════════════════════
 * ขั้น ② หน้าเตรียมไฟล์งาน (.wrap-prep)
 *
 * layout: คอลัมน์เดียว กว้าง 880px สรุปราคาอยู่ล่างสุด
 *   มติเจ้าของ 2026-09-16 — ให้ลูกค้าอ่านวิธีทำไฟล์จนจบก่อนเห็นยอดเงิน
 *
 * ★ หน้านี้มีคลาสของตัวเอง (.sum-* .px-* .check-* .need-* .flow-*)
 *   ไม่ยืม .chips/.chip ของหน้าสินค้ามาใช้ เพราะที่นั่นเป็น grid ปุ่มเลือก
 *   ยืมมาแล้วป้ายอ่านอย่างเดียวจะกลายเป็นตาราง 2 คอลัมน์หน้าตาประหลาด
 * ═══════════════════════════════════════════════════════════ */

/* ───────── แถบบอกขั้นตอน (progress bar) ─────────
   ol เพราะลำดับมีความหมายจริง (โปรแกรมอ่านหน้าจอจะอ่านว่า "ข้อ 2 จาก 4")

   ★ 2026-09-23 — เปลี่ยนจากเม็ดยาเรียงกันเป็น progress bar วงกลม+เส้นเชื่อม
   ★ 2026-10-03 (มติเจ้าของ) — แนวนอน "ติดขอบบนจอ" แทน header (header ใน 4 หน้านี้เลื่อนหายไปตามหน้า)
     · ขั้นที่อยู่ = วงม่วงทึบ + ชื่อ + คำอธิบายสั้น (settings: order_steps) · ขั้นอื่นหดเหลือเลข+ชื่อ
     · ขั้นที่เคยไปถึงแล้ว (reached) ม่วงค้างไว้ ไม่ถอยตามขั้นที่อยู่ · มือถือ: ขั้นอื่นเหลือแค่วงเลข
     · animation: เส้นเติมสีวิ่งทีละช่วง + คำอธิบายเลื่อนเข้า + วงขั้นปัจจุบันมีคลื่นแสง
       ใช้แค่ transform/opacity — ไม่ดันเนื้อหาอื่นขยับ (คะแนน CLS ไม่เสีย) · ปิดให้ถ้าเครื่องตั้งลดการเคลื่อนไหว */
body:has(.osteps) .sf-head { position: relative; }   /* header ไม่ติดจอในหน้าที่มีแถบขั้นตอน */

.osteps {
  --osteps-h: 64px;
  position: sticky; top: 0; z-index: 700;
  background: rgba(255,255,255,.96);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--line);
  box-shadow: 0 6px 18px -14px rgba(20,16,31,.35);
}
.osteps-list {
  display: flex; align-items: center;
  min-height: var(--osteps-h);
  list-style: none; margin: 0; padding: 8px 0;
}
.osteps-step {
  display: flex; align-items: center;
  flex: 1 1 0; min-width: 0;
}
.osteps-step:last-child { flex: 0 0 auto; }
.osteps-step.is-on { flex-grow: 2.2; }   /* ขั้นที่อยู่กว้างกว่า — มีที่ให้คำอธิบาย */
.osteps-step.is-on:last-child { flex: 0 0 auto; }   /* ขั้น 4 (ขวาสุด) เมื่ออยู่ที่ขั้นนี้ ห้ามขยาย — ไม่งั้นเนื้อหาค้างซ้ายของกล่อง ไม่ชิดมุมขวา (มติเจ้าของ 2026-10-09) */

.osteps-item {
  display: flex; align-items: center; gap: 10px;
  min-width: 0; flex: 0 1 auto;
  color: inherit; text-decoration: none;
}
.osteps-dot {
  width: 30px; height: 30px; flex: none; position: relative;
  display: grid; place-items: center;
  border-radius: 50%; border: 2px solid var(--line);
  background: #fff; color: var(--ink-mute);
  font-size: 13px; font-weight: 800;
  transition: transform .15s, border-color .15s, color .15s;
}
.osteps-text { display: flex; flex-direction: column; min-width: 0; }
.osteps-label { font-size: 13px; font-weight: 700; color: var(--ink-mute); line-height: 1.3; white-space: nowrap; }
.osteps-note {
  font-size: 12px; color: var(--ink-soft); line-height: 1.35;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  animation: osteps-note-in .45s .35s ease-out both;
}

/* เส้นเชื่อม — พื้นเทา + ชั้นสีม่วงที่วิ่งเติมจากซ้าย (scaleX) ทีละช่วงตามลำดับขั้น */
.osteps-line {
  flex: 1 1 auto; min-width: 16px; height: 3px; margin-inline: 12px;
  border-radius: 3px; background: var(--line); position: relative; overflow: hidden;
}
.osteps-line.is-filled::after {
  content: ""; position: absolute; inset: 0; background: var(--purple);
  transform-origin: left;
  animation: osteps-fill .5s calc(var(--i) * .12s) ease-out both;
}

/* สถานะ */
.osteps-step.is-done .osteps-dot { background: var(--purple); border-color: var(--purple); color: #fff; }
.osteps-step.is-done .osteps-label { color: var(--ink); }
.osteps-step.is-on .osteps-dot {
  width: 34px; height: 34px; font-size: 14px;
  background: var(--purple); border-color: var(--purple); color: #fff;
}
.osteps-step.is-on .osteps-dot::after {   /* คลื่นแสงรอบวง — บอกว่า "อยู่ตรงนี้" */
  content: ""; position: absolute; inset: -3px; border-radius: 50%;
  border: 2px solid var(--purple);
  animation: osteps-pulse 2s ease-out infinite;
}
.osteps-step.is-on .osteps-label { color: var(--purple); font-weight: 800; font-size: 14px; }
.osteps-step.is-todo .osteps-dot,
.osteps-step.is-todo .osteps-label { opacity: .6; }

/* ขั้นที่กดสลับไปได้ — ต้องรู้สึกกดได้จริง ไม่ใช่แค่ป้ายบอกสถานะ */
.osteps-step.is-clickable .osteps-item { cursor: pointer; }
.osteps-item[aria-disabled] { cursor: not-allowed; }   /* 2026-10-03 — ขั้นที่ยังทำขั้นก่อนหน้าไม่ครบ (เช่น ยังไม่มีไฟล์งาน) กดไม่ได้ */
.osteps-step.is-clickable .osteps-dot,
.osteps-step.is-clickable .osteps-label { opacity: 1; }
.osteps-step.is-clickable:hover .osteps-dot { transform: scale(1.08); border-color: var(--purple); }
.osteps-step.is-clickable:hover .osteps-label { color: var(--purple); text-decoration: underline; }

@keyframes osteps-fill { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@keyframes osteps-note-in { from { opacity: 0; transform: translateX(-8px); } to { opacity: 1; transform: none; } }
@keyframes osteps-pulse { 0% { transform: scale(1); opacity: .7; } 100% { transform: scale(1.55); opacity: 0; } }

/* มือถือ — ขั้นอื่นเหลือแค่วงเลข · ขั้นที่อยู่ยังมีชื่อ+คำอธิบาย */
@media (max-width: 720px) {
  .osteps { --osteps-h: 56px; }
  .osteps-step:not(.is-on) .osteps-text { display: none; }
  .osteps-step:not(.is-on) { flex: 0 1 auto; }
  .osteps-step.is-on { flex: 1 1 auto; }
  .osteps-step:not(:last-child) .osteps-line { flex-basis: 14px; }
  .osteps-line { margin-inline: 6px; min-width: 10px; }
  .osteps-item { gap: 8px; }
  .osteps-dot { width: 26px; height: 26px; font-size: 12px; }
  .osteps-step.is-on .osteps-dot { width: 30px; height: 30px; }
  .osteps-step.is-on .osteps-label { font-size: 13px; }
  .osteps-note { font-size: 11.5px; }
}

@media (prefers-reduced-motion: reduce) {
  .osteps-line.is-filled::after, .osteps-note, .osteps-step.is-on .osteps-dot::after { animation: none; }
}

/* คำอธิบาย render ไว้ทุกขั้น (โหมด editor สลับขั้นได้) — โชว์เฉพาะขั้นที่อยู่ */
.osteps-step:not(.is-on) .osteps-note { display: none; }

/* ── โลโก้ + ตะกร้าในแถบขั้นตอน (2026-10-10 มติเจ้าของ) ──
   ซ่อน (จาง) ตอน header ยังอยู่ในจอ · โผล่เมื่อ header พ้นจอ (body.is-head-gone) หรือเปิด editor (body.is-pp-editing)
   ★ ช่องจองที่ไว้ตลอด แค่ opacity/transform — แถบขั้นตอนไม่ขยับตอนเลื่อน (ไม่เสียคะแนน CLS) */
/* ★ 2026-10-10 (มติเจ้าของ) — 3 คอลัมน์: โลโก้ชิดขอบจอซ้าย · ขั้นตอนตรงกลาง (กว้างเท่าเนื้อหา .wrap เดิม) · ตะกร้าชิดขอบจอขวา
   คอลัมน์ข้างกว้างอย่างน้อยเท่าโลโก้/ตะกร้า (max-content) — จอแคบช่องกลางหดแทน ไม่ทับกัน */
.osteps-bar {
  display: grid; align-items: center; gap: 16px;
  grid-template-columns: minmax(max-content, 1fr) minmax(0, calc(var(--wrap) - 48px)) minmax(max-content, 1fr);
  max-width: none;
}
.osteps-bar .osteps-list { min-width: 0; }
.osteps-bar .osteps-logo { justify-self: start; }   /* ไม่ยืดเต็มคอลัมน์ — พื้นที่กดเท่าตัวโลโก้ */
.osteps-bar .osteps-cart { justify-self: end; }
.osteps-logo, .osteps-cart {
  flex: none; opacity: 0; pointer-events: none;
  transition: opacity .25s ease-out, transform .3s ease-out;
}
.osteps-logo { display: inline-flex; line-height: 0; transform: translateX(-10px); }
.osteps-logo img { height: 48px; width: auto; }   /* แถบสูง 64 → เว้นบนล่าง 8px (หัวเว็บ PC ใช้ 56 ในหัวเว็บสูง 72 · storefront.css .sf-logo) */
.osteps-cart { transform: translateX(10px); }
body.is-head-gone .osteps-logo, body.is-head-gone .osteps-cart,
body.is-pp-editing .osteps-logo, body.is-pp-editing .osteps-cart {
  opacity: 1; transform: none; pointer-events: auto;
}

/* ── โหมด editor ออกแบบ (PitchPrint · printpaoSteps.editing) ──
   PitchPrint เปิด editor เป็น <iframe> เต็มจอ (fixed · top 0 · z-index 999999999 · ใส่ style inline เอง) ทับทั้งหน้า
   → แถบนี้ติดบนสุด แล้วดัน iframe ลงมาใต้แถบ (!important ชนะ style inline ของ PitchPrint) · ไม่ต้องแก้ไฟล์ของเขา */
/* z-index สูงกว่า header — PitchPrint ล็อก scroll แล้ว header โผล่กลับมาทับครึ่งล่างของแถบ (เจอตอนลองจริง) */
body.is-pp-editing .osteps { position: fixed; top: 0; left: 0; right: 0; z-index: 999999998; }
body.is-pp-editing > iframe[src*="pitchprint.io"] {
  top: var(--osteps-bar-h, 65px) !important;
  height: calc(100dvh - var(--osteps-bar-h, 65px)) !important;
}
body.is-pp-editing .osteps-list { pointer-events: none; }   /* วงขั้นเป็นตัวบอกสถานะ — ปิด editor ใช้ปุ่ม X ของ PitchPrint */
body.is-pp-editing .pv-switch,
body.is-pp-editing .au-overlay,
body.is-pp-editing .pp-loading { z-index: 1000000000; }   /* modal ถามก่อนออก / popup login ตอนกด Submit (2026-10-19) / ตัวโหลดตอนบันทึก ต้องอยู่เหนือ iframe */

@media (max-width: 720px) {
  .osteps-bar { gap: 10px; }
  .osteps-logo img { height: 40px; }
  .osteps-cart { width: 36px; height: 36px; }
}

/* ───────── โครงหน้า ───────── */
.wrap-prep {
  max-width: 1400px;          /* 2026-09-28 (เจ้าของขอ) — ขยายให้เท่ากับ --wrap ทั้งเว็บ (เดิม 1200px)
                                 2026-09-24: ขยายจาก 880 → 960 เพราะรูปสอนเตรียมไฟล์ (.prep-guide-wrap)
                                 บีบแคบจนอ่านรายละเอียดในรูปไม่ออก */
  /* ★ 2026-09-25 — ระยะห่างบนต้องเป็นของ .wrap-prep เอง ห้ามพึ่ง .crumb (padding-block: 18px 0)
     เป็นตัวเว้นระยะแทน เพราะหน้า orders/show.blade.php ไม่มี .crumb (จ่ายเงินแล้ว ไม่มี "ย้อนกลับไปแก้"
     ให้กด) พอไม่มี .crumb เนื้อหาก็ไปติด header ทันที (บั๊กที่เจอจริง) — ใส่ระยะบนตรงนี้แทนให้ทุกหน้า
     ที่ใช้ .wrap-prep มีระยะเท่ากันเสมอ ไม่ว่าจะมี .crumb นำหน้าหรือไม่ */
  padding-block: 20px 64px;
}

/* หัวหน้า */
.prep-hero { margin-bottom: 22px; }
.prep-eyebrow {
  display: inline-block; margin: 0 0 8px;
  background: var(--purple-lt); color: var(--purple);
  border: 1px solid var(--purple-br);
  font-size: 12.5px; font-weight: 700;
  padding: 4px 12px; border-radius: 999px;
}
.prep-hero h1 { margin: 0; font-size: 30px; line-height: 1.25; letter-spacing: -.01em; }
.prep-hero-sub { margin: 8px 0 0; color: var(--ink-soft); font-size: 16px; }

/* ───────── การ์ดเนื้อหา ─────────
   แต่ละบล็อกเป็นการ์ดแยกกัน อ่านทีละเรื่อง */
.prep-block {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  padding: 24px 26px;
  margin-bottom: 18px;
}
.prep-block:last-child { margin-bottom: 0; }

/* หัวการ์ด — ขีดเหลืองสั้นๆ นำหน้า ให้กวาดตาเจอง่ายตอนเลื่อนยาวๆ */
.prep-block > h2 {
  display: flex; align-items: center; gap: 10px;
  margin: 0 0 16px; font-size: 19px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--line);
}
.prep-block > h2::before {
  content: ""; flex: none;
  width: 4px; height: 18px;
  background: var(--yellow); border-radius: 2px;
}

.prep-note { color: var(--ink-soft); font-size: 15.5px; line-height: 1.8; margin: 12px 0 0; }
.prep-note:first-of-type { margin-top: 0; }

/* รูปคู่มือ (เผื่อขอบ ฯลฯ) — ใช้ .gal-main/.gal-zoom ตัวเดียวกับหน้าสินค้า
   เพื่อให้กดดูเต็มจอได้ (data-gallery ใน blade) หน้าตาเลยเหมือนกันทั้งเว็บ
   ไม่ต้องคิดสไตล์ซูมใหม่ ต่างแค่ margin-top ห่างจากข้อความด้านบน */
.prep-guide-wrap { margin-top: 14px; }
.prep-guide-wrap .gal-main { aspect-ratio: 3/1;  max-width: none;}
/* 2026-09-24 — จอแคบ 3:1 จะเตี้ยเกินไป รายละเอียดในรูป (เผื่อขอบ ฯลฯ) อ่านไม่ออก
   ใช้อัตราส่วนเดียวกับ .pdp-hero (สูงขึ้นตอนจอแคบ) */
@media (max-width: 880px) {
  .prep-guide-wrap .gal-main { aspect-ratio: 16/9; }
}

/* ───────── การ์ดสรุปรายการที่สั่ง ─────────
   รูปทรงซ้าย + สเปคเป็นคู่ label/value ขวา
   อ่านง่ายกว่าป้ายลอยๆ ที่ไม่บอกว่าค่าไหนคืออะไร
   ★ คอลัมน์รูปกว้าง 460px — ให้เห็นรูปตัวอย่างสินค้าชัดๆ ใหญ่ๆ ไม่ย่อจนดูไม่ออก
   ★ รูปทรง/ขนาดสินค้าทุกไฟล์ (shape-*.jpg, size-*.jpg) เป็นสี่เหลี่ยมจัตุรัส 1:1
     จึงบังคับ aspect-ratio 1/1 ตรงนี้ ไม่ใช้ 3:2 ของ .gal-main เดิม (จะเกิดขอบขาวข้างรูป) */
.sum-grid { display: grid; grid-template-columns: 460px minmax(0, 1fr); gap: 28px; align-items: start; }
.sum-grid:has(> .sum-specs:only-child) { grid-template-columns: minmax(0, 1fr); }

.sum-fig { margin: 0; }
.sum-fig .gal-main { aspect-ratio: 1 / 1; }
.sum-fig figcaption {
  margin-top: 8px; text-align: center;
  font-size: 13.5px; color: var(--ink-mute);
}

.sum-specs { margin: 0; display: grid; gap: 0; }
.sum-specs > div {
  display: grid; grid-template-columns: 34% minmax(0, 1fr);
  gap: 12px; padding: 10px 0;
  border-bottom: 1px dashed var(--line);
}
.sum-specs > div:first-child { padding-top: 0; }
.sum-specs > div:last-child { border-bottom: 0; padding-bottom: 0; }
.sum-specs dt { color: var(--ink-mute); font-size: 14.5px; }
.sum-specs dd { margin: 0; font-size: 15.5px; font-weight: 600; overflow-wrap: anywhere; }

.sum-foot {
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px 16px;
  margin-top: 18px; padding-top: 14px;
  border-top: 1px solid var(--line);
}
.sum-eta { font-size: 14.5px; color: var(--ink-soft); }
.sum-eta b { color: var(--ink); }
.sum-edit {
  margin-left: auto; font-size: 14px; font-weight: 600;
  color: var(--purple); text-decoration: none;
  border-bottom: 1px dotted var(--purple-br); padding-bottom: 1px;
}
.sum-edit:hover { border-bottom-style: solid; }

/* ───────── ความละเอียดไฟล์ ─────────
   รายการบรรทัดเดียวต่อแถว label ซ้าย ตัวเลขขวา — ไม่ต้องทำเป็นการ์ดใหญ่
   เน้นให้กวาดตาแล้วรู้เลยว่า "พอ / ไม่พอ" จากสี ไม่ใช่จากขนาดตัวอักษร */
.px-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.px-list li {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 12px;
  border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--surface-2); padding: 10px 14px;
  font-size: 14.5px;
}
.px-label { color: var(--ink-soft); }
.px-val { margin-left: auto; font-weight: 700; }
.px-sub { font-weight: 500; color: var(--ink-mute); font-size: 13px; }
.px-list li.ok { border-color: #BFE3CE; background: #F3FAF5; }
.px-list li.ok .px-label { color: var(--ok); font-weight: 600; }
.px-list li.warn { border-color: #F0DBA8; background: var(--warn-bg); }
.px-list li.warn .px-label { color: var(--warn); font-weight: 600; }

/* ───────── รายการ Template ─────────
   ป้ายนามสกุลไฟล์อยู่หน้าสุด รู้ตั้งแต่ยังไม่โหลดว่าเปิดด้วยโปรแกรมอะไร */
.tpl-list { display: grid; gap: 8px; margin-top: 14px; }
.tpl-item {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 16px; border-radius: var(--r-sm);
  border: 1px solid var(--purple-br); background: var(--purple-lt);
  color: var(--purple); font-weight: 600; font-size: 15px;
  text-decoration: none; transition: .15s;
}
.tpl-item:hover { background: #fff; border-color: var(--purple); box-shadow: var(--shadow); }
.tpl-ext {
  flex: none; min-width: 46px; text-align: center;
  padding: 4px 8px; border-radius: 6px;
  background: var(--purple); color: #fff;
  font-size: 11.5px; font-weight: 700; letter-spacing: .04em;
}
.tpl-name { min-width: 0; overflow-wrap: anywhere; }
.tpl-ico {
  margin-left: auto; flex: none;
  width: 26px; height: 26px;
  display: grid; place-items: center; border-radius: 50%;
  background: #fff; border: 1px solid var(--purple-br);
  font-size: 14px;
}
.tpl-item:hover .tpl-ico { background: var(--purple); color: #fff; border-color: var(--purple); }

/* ───────── รายการ "เตรียมอะไรมาบ้าง" (เคสจ้างออกแบบ) ───────── */
.need-list { list-style: none; margin: 16px 0 0; padding: 0; display: grid; gap: 10px; }
.need-list li {
  position: relative; padding-left: 30px;
  font-size: 15.5px; line-height: 1.7; color: var(--ink-soft);
}
.need-list li b { color: var(--ink); }
.need-list li::before {
  content: "✓"; position: absolute; left: 0; top: 3px;
  width: 20px; height: 20px;
  display: grid; place-items: center;
  background: var(--purple); color: #fff;
  border-radius: 999px; font-size: 12px; font-weight: 700;
}

/* ───────── ลำดับขั้นหลังจากนี้ (เคสจ้างออกแบบ) ───────── */
.flow-list { list-style: none; margin: 0; padding: 0; counter-reset: flow; display: grid; gap: 14px; }
.flow-list li {
  counter-increment: flow;
  position: relative; padding-left: 40px;
  font-size: 15.5px; line-height: 1.7; color: var(--ink-soft);
}
.flow-list li b { color: var(--ink); }
.flow-list li::before {
  content: counter(flow);
  position: absolute; left: 0; top: 0;
  width: 26px; height: 26px;
  display: grid; place-items: center;
  border-radius: 50%;
  background: var(--purple-lt); border: 1px solid var(--purple-br);
  color: var(--purple); font-size: 13px; font-weight: 700;
}

/* ───────── บล็อกสรุปราคา (ล่างสุด) ─────────
   ทำให้ต่างจากการ์ดอื่นชัดๆ เพราะเป็นปลายทางของหน้า */
.prep-summary { border-color: var(--purple-br); background: var(--purple-lt); }
.prep-summary > h2 { border-bottom-color: var(--purple-br); }
.prep-summary .pricebox {
  background: #fff; border: 0; border-radius: var(--r-sm);
  padding: 18px 20px;
}
.prep-summary .price-total { border-top-color: var(--line); }
.prep-summary .server-note { text-align: left; margin-top: 12px; }

/* ปุ่มท้ายหน้า — ปุ่มหลักอยู่ซ้าย */
.prep-actions { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 18px; }
.prep-actions .btn:disabled { opacity: .45; cursor: not-allowed; }

/* ── EPIC-026 F2 — รายชื่อไฟล์งานที่แนบไว้ในร่าง (ขั้น 2) ── */
.prep-upload { border-color: var(--purple-br); }
.draft-files { list-style: none; margin: 0 0 16px; padding: 0; display: grid; gap: 8px; }
.draft-files li {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 14px; border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--surface-2);
}
.draft-files li svg { width: 20px; height: 20px; flex: none; color: var(--purple); }
.draft-files-name { flex: 1; min-width: 0; font-weight: 600; overflow-wrap: anywhere; }
.draft-files li small { color: var(--ink-mute); white-space: nowrap; }
.draft-files li form { margin: 0; }
.draft-files-del {
  border: 0; background: none; padding: 4px 8px; border-radius: 6px;
  color: var(--sf-pink-dk, var(--danger)); font: inherit; font-size: 13.5px; font-weight: 700; cursor: pointer;
}
.draft-files-del:hover { background: var(--purple-lt); }
.prep-actions-note { margin: 12px 0 0; font-size: 13.5px; color: var(--ink-mute); }

/* ───────── จอแคบ ─────────
   (แถบขั้นตอนบนจอแคบ ย้ายไปอยู่กับบล็อก .osteps แล้ว — 2026-10-03) */
@media (max-width: 880px) {
  .prep-hero h1 { font-size: 25px; }
  .prep-block { padding: 18px 16px; }
  /* จอแคบเรียงบน-ล่าง — รูปเต็มความกว้างการ์ดเลย ไม่ย่อเล็ก */
  .sum-grid { grid-template-columns: 1fr; gap: 16px; }
  .prep-actions .btn { width: 100%; text-align: center; }
}
@media (max-width: 560px) {
  .sum-specs > div { grid-template-columns: 1fr; gap: 2px; padding: 9px 0; }
  .sum-specs dd { font-size: 15px; }
  .sum-edit { margin-left: 0; }
  .px-val { margin-left: 0; }
}


/* ══════════════════════════════════════════════════════════
   ขั้น ③ หน้ากรอกข้อมูลผู้สั่ง (.co-*) + หน้าออเดอร์
   ใช้ตัวแปรสี/รัศมีชุดเดียวกับทั้งเว็บ ไม่ตั้งค่าสีดิบใหม่
   ══════════════════════════════════════════════════════════ */

/* กล่องแจ้งเตือน — ใช้ทั้ง error จาก validate และ session('error') */
.alert {
  border-radius: var(--r-sm);
  padding: 14px 16px;
  margin-bottom: 18px;
  font-size: 15px;
  line-height: 1.7;
}
.alert ul { margin: 6px 0 0; padding-left: 20px; }
.alert-error {
  background: var(--warn-bg);
  border: 1px solid var(--warn);
  color: var(--ink);
}
/* ★ 2026-09-23 — "โอนเงินมาแล้ว ไม่ต้องโอนซ้ำ" เขียวไม่ใช่เหลือง เพราะเป็นข่าวดี ไม่ใช่คำเตือน
   ถ้าใช้สีเดียวกับ error ลูกค้าจะตกใจคิดว่ามีอะไรผิดพลาดทั้งที่ทุกอย่างเรียบร้อย */
.alert-paid,
.alert-success {
  background: #EAF7F0;
  border: 1px solid var(--ok);
  color: var(--ink);
}

/* TASK-012 — error ใต้ช่องที่กรอกผิด (<x-field>) ลูกค้าเห็นตรงจุด ไม่ต้องไล่อ่านจากกล่องบนสุด */
.co-field.has-error input,
.co-field.has-error select,
.co-field.has-error textarea { border-color: var(--danger); }
.co-field-error { margin: 6px 0 0; font-size: 13.5px; color: var(--danger); }

/* ดอกจันช่องบังคับ */
.req { color: var(--sf-pink-dk, var(--warn)); font-weight: 700; }   /* 2026-10-03 — ชมพูธีมใหม่ (เดิม --warn น้ำตาลทองคู่เหลืองธีมเก่า) */

/* ── ฟอร์ม ── */
.co-form > h2 { margin-top: 28px; }
.co-form > h2:first-of-type { margin-top: 0; }

.co-field { margin-top: 16px; }
.co-field > label {
  display: block;
  margin-bottom: 6px;
  font-size: 14.5px;
  font-weight: 600;
  color: var(--ink-soft);
}
.co-field input[type="text"],
.co-field input[type="tel"],
.co-field input[type="email"],
.co-field input[type="date"],
.co-field input[type="time"],
.co-field input[type="number"],
.co-field input[type="url"],
.co-field select,
.co-field textarea {
  width: 100%;
  padding: 11px 13px;
  font: inherit;
  font-size: 15.5px;
  color: var(--ink);
  background: var(--bg);
  border: 1.5px solid var(--line);
  border-radius: var(--r-sm);
  transition: border-color .15s, opacity .15s;
  cursor: pointer;
}

/* ── select ── เอาลูกศร/กรอบเดิมของ OS ออก แล้ววาดลูกศรเองด้วย SVG
   เพื่อให้หน้าตาเหมือนกันทุกเบราว์เซอร์ เข้าธีมเดียวกับช่องอื่น */
.co-field select {
  appearance: none;
  -webkit-appearance: none;
  padding-right: 36px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='9' viewBox='0 0 14 9'%3E%3Cpath d='M1 1l6 6 6-6' fill='none' stroke='%236b5b95' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 13px center;
}

/* select ที่ยังกดไม่ได้ (รอเลือกช่องก่อนหน้า) — จางลงให้รู้สึกว่า "ยังไม่พร้อม" */
.co-field select:disabled {
  opacity: .5;
  cursor: not-allowed;
  background-color: var(--surface);
}

/* ช่องรหัสไปรษณีย์ — readonly เพราะมาจากตำบลที่เลือกเท่านั้น ไม่ใช่ให้พิมพ์เอง
   ทำให้ดู "ปิด" ชัดเจน ต่างจากช่องที่พิมพ์ได้ปกติ */
.co-field input[readonly] {
  background: var(--surface);
  color: var(--ink-soft);
  cursor: default;
}

/* ไอคอนปฏิทิน/นาฬิกาฝั่งขวา — ของเบราว์เซอร์ (webkit) เท่านั้นที่แต่งได้
   Firefox ไม่มี pseudo-element นี้ ปล่อยเป็นค่าเริ่มต้นไป */
.co-field input[type="date"]::-webkit-calendar-picker-indicator,
.co-field input[type="time"]::-webkit-calendar-picker-indicator {
  cursor: pointer;
  padding: 4px;
  border-radius: var(--r-sm);
  transition: background .15s;
}
.co-field input[type="date"]::-webkit-calendar-picker-indicator:hover,
.co-field input[type="time"]::-webkit-calendar-picker-indicator:hover {
  background: var(--purple-lt);
}

.co-field input:focus,
.co-field select:focus,
.co-field textarea:focus {
  outline: none;
  border-color: var(--purple);
}
.co-field textarea { resize: vertical; line-height: 1.6; }

/* 2 ช่องเรียงข้างกันบนจอกว้าง */
.co-row { display: grid; grid-template-columns: 1fr 1fr; gap: 0 16px; }

/* ★ 2026-10-03 (EPIC-026) — กลุ่มช่องที่เปิด/ปิดตามตัวเลือก (ใบกำกับภาษี)
   <fieldset disabled> = ช่องข้างในไม่ถูกบังคับกรอกและไม่ถูกส่ง · ล้างกรอบ/ระยะของ fieldset เบราว์เซอร์ทิ้ง */
.co-fieldset { border: 0; margin: 0; padding: 0; min-width: 0; }
.co-fieldset[hidden] { display: none; }
#tax-fields { margin-top: 14px; }

/* 3 ช่อง (จังหวัด/อำเภอ/ตำบล) เรียงแถวเดียวกันบนจอกว้าง */
.co-row-3 { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 0 16px; }
@media (max-width: 720px) {
  .co-row-3 { grid-template-columns: 1fr; }
}

/* ── เวลาที่โอน (ชั่วโมง : นาที) ──
   บังคับ 24 ชม. เอง ไม่พึ่ง <input type="time"> ของเบราว์เซอร์
   select 2 ตัวสั้นๆ พอสำหรับตัวเลข 2 หลัก ไม่ต้องเต็มความกว้างเหมือนช่องอื่น */
.co-time { display: flex; align-items: center; gap: 6px; }
.co-time select {
  width: 72px;
  flex: none;
  text-align: center;
  padding-right: 30px; /* เผื่อลูกศร SVG ที่ยังใช้ร่วมกับ select ทั่วไป */
}
.co-time-sep { font-size: 18px; font-weight: 700; color: var(--ink-mute); }
.co-time-hint { font-size: 13.5px; color: var(--ink-mute); margin-left: 4px; }

/* ── PDPA — ติ๊กยอมรับเงื่อนไข ──
   วางไว้ล่างสุดของฟอร์ม (ใต้ปุ่มยืนยันสั่งซื้อ) ให้ลูกค้าเห็นทุกอย่างครบก่อนติ๊ก
   ★ ซ่อน <input type="checkbox"> จริงไว้ (แต่ยัง focus/tab ได้ตามปกติ ไม่ใช้ display:none)
     แล้ววาดกล่องเช็คเองด้วย .co-consent-box เพื่อคุมหน้าตาให้เหมือนกันทุกเบราว์เซอร์ */
/* โค้ดส่วนลดในการ์ด "สรุปราคา" หน้าข้อมูลผู้สั่ง (2026-11-03) — ช่องพิมพ์ + ปุ่มอยู่แถวเดียวกัน ข้อความผลลัพธ์ใต้ช่อง */
.co-coupon { margin-top: 16px; }
.co-coupon-label { display: block; margin-bottom: 6px; font-size: .9rem; font-weight: 600; color: var(--sf-ink, #14101F); }
.co-coupon-row { display: flex; gap: 8px; }
.co-coupon-row input { flex: 1; min-width: 0; padding: 10px 12px; border: 1px solid var(--line, #E4E2EB); border-radius: 10px; font: inherit; background: #fff; }
.co-coupon-row input:not(:placeholder-shown) { text-transform: uppercase; letter-spacing: .06em; }
.co-coupon-row input:read-only { background: #f7f7f9; }
.co-coupon-msg { margin: 8px 0 0; font-size: .88rem; }
.co-coupon-msg.is-ok { color: #1A7F37; }
.co-coupon-msg.is-error { color: #C62828; }

.co-consent-wrap{
  margin-top: 5px;
  padding: 16px 18px;
     }
.co-consent {
  display: flex; align-items: flex-start; gap: 12px;
  margin-top: 10px;
  /* padding: 16px 18px; */
  /* background: var(--surface);
  border: 1.5px solid var(--line);
  border-radius: var(--r-md); */
  font-size: 15px;
  /* line-height: 1.65; */
  color: var(--ink-soft);
  cursor: pointer;
  transition: border-color .15s, background .15s;
}
/* .co-consent:hover { border-color: var(--purple-br); } */

.co-consent input {
  position: absolute;
  width: 1px; height: 1px;
  opacity: 0;
  pointer-events: none;
}

.co-consent-box {
  flex: none;
  width: 22px; height: 22px;
  margin-top: 1px;
  border: 2px solid var(--line);
  border-radius: 6px;
  background: var(--bg);
  transition: border-color .15s, background .15s;
  position: relative;
}
/* เครื่องหมายถูก — วาดด้วย border เป็นตัว "L" หมุน 45 องศา ไม่ต้องพึ่งไอคอน/รูปภาพ */
.co-consent-box::after {
  content: "";
  position: absolute;
  left: 6px; top: 2px;
  width: 6px; height: 11px;
  border: solid #fff;
  border-width: 0 2.5px 2.5px 0;
  transform: rotate(45deg);
  opacity: 0;
  transition: opacity .1s;
}
.co-consent input:checked + .co-consent-box {
  background: var(--purple);
  border-color: var(--purple);
}
.co-consent input:checked + .co-consent-box::after { opacity: 1; }
.co-consent input:focus-visible + .co-consent-box { outline: 2px solid var(--yellow); outline-offset: 2px; }

/* ── ปุ่มเลือกแบบกลมเล็ก (radio) — ใช้กับ "LINE ID / เบอร์โทรที่ผูก LINE" (2026-09-24)
   ★ หลักเดียวกับ .co-consent: ซ่อน input จริง (ยัง focus/tab ได้) แล้ววาดวงกลมเอง
     เลือกแล้ว = วงนอกสีม่วง + จุดม่วงตรงกลาง */
.co-pick-row { display: flex; flex-wrap: wrap; gap: 8px 22px; margin-bottom: 10px; }
.co-pick {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: 15px; color: var(--ink-soft);
  cursor: pointer; position: relative;
}
.co-pick input { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
.co-pick-dot {
  flex: none;
  width: 18px; height: 18px;
  border: 2px solid var(--line);
  border-radius: 50%;
  background: var(--bg);
  position: relative;
  transition: border-color .15s;
}
.co-pick-dot::after {
  content: "";
  position: absolute; inset: 3px;
  border-radius: 50%;
  background: var(--purple);
  transform: scale(0);
  transition: transform .12s;
}
.co-pick:hover .co-pick-dot { border-color: var(--purple-br); }
.co-pick input:checked + .co-pick-dot { border-color: var(--purple); }
.co-pick input:checked + .co-pick-dot::after { transform: scale(1); }
.co-pick input:checked ~ span:last-child { color: var(--ink); font-weight: 600; }
.co-pick input:focus-visible + .co-pick-dot { outline: 2px solid var(--yellow); outline-offset: 2px; }

/* ยังไม่ติ๊กแล้วพยายามกดสั่งซื้อ — เบราว์เซอร์ยิง 'invalid' มา (ดู script ท้ายหน้า) */
.co-consent.is-invalid {
  border-color: var(--danger);
  background: var(--danger-bg);
}
.co-consent.is-invalid .co-consent-box { border-color: var(--danger); }
.co-consent.is-invalid span:last-child { color: var(--danger); font-weight: 600; }

/* ── สรุปยอด ── */
.co-total {
  margin-top: 24px;
  padding: 18px 20px;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
}
.co-total dl { margin: 0; display: grid; gap: 0; }
.co-total dl > div {
  display: flex; justify-content: space-between; align-items: baseline; gap: 16px;
  padding: 9px 0;
  border-bottom: 1px dashed var(--line);
}
.co-total dl > div:last-child { border-bottom: 0; padding-bottom: 0; }
.co-total dt { color: var(--ink-mute); font-size: 15px; }
.co-total dd { margin: 0; font-size: 15.5px; font-weight: 600; }

.co-grand { margin-top: 4px; padding-top: 14px !important; border-top: 2px solid var(--line); }
.co-grand dt { color: var(--ink) !important; font-size: 16.5px !important; font-weight: 700; }
.co-grand dd { font-size: 22px !important; font-weight: 800; color: var(--purple); }

/* ── กล่องบัญชีธนาคาร ──
   โลโก้วางบนสุด แล้วไล่ ธนาคาร / ชื่อบัญชี / เลขบัญชี ลงมา
   แถวเลขบัญชีเป็นพระเอก: ตัวใหญ่ สีม่วง ปุ่มคัดลอกชิดขวาสุด */
.co-bank {
  padding: 20px 22px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
}
.co-bank-logo {
  display: block;
  width: 108px; height: auto;
  margin-bottom: 16px;
}
.co-bank .sum-specs > div { padding: 12px 0; }
.co-bank .sum-specs dd { font-size: 16px; }

/* ★ dd เป็น flex — span อยู่ซ้าย ปุ่มถูกดันไปขวาสุดด้วย space-between */
.co-bank-no dd {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  font-size: 19px; font-weight: 800;
  color: var(--purple);
  letter-spacing: .04em;
}
/* flex: none กันปุ่มถูกบีบจนตัวหนังสือตกบรรทัดตอนจอแคบ */
.co-copy { flex: none; padding: 8px 18px; font-size: 14px; font-weight: 700; }

@media (max-width: 560px) {
  .co-bank-no dd { font-size: 17px; }
  .co-copy { padding: 7px 14px; font-size: 13px; }
}


@media (max-width: 640px) {
  .co-row { grid-template-columns: 1fr; }
  .co-grand dd { font-size: 20px !important; }
}


/* ══════ กล่องแนบไฟล์ <x-file-drop> (2026-09-24) — ใช้ทั้งสลิปและไฟล์งาน ══════
   เส้นประ = สัญญะสากลว่า "วางของตรงนี้ได้" · <input type=file> โปร่งใสวางทับทั้งกล่อง
   (ลากมาวาง/กดตรงไหนก็เลือกไฟล์ได้ เบราว์เซอร์ทำให้เอง) · JS อยู่ใน public/js/file-drop.js */
.file-drop {
  position: relative;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 6px; text-align: center;
  padding: 32px 20px;
  background: var(--bg);
  border: 2px dashed var(--purple-br);
  border-radius: var(--r-md);
  transition: border-color .15s, background .15s;
}
.file-drop-input {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  opacity: 0; cursor: pointer;
}
.file-drop:hover,
.file-drop.is-dragover { border-color: var(--purple); background: var(--purple-lt); }
.file-drop.is-dragover { border-style: solid; }

.file-drop-icon { width: 36px; height: 36px; color: var(--purple); }
.file-drop-title { font-size: 16px; color: var(--purple); overflow-wrap: anywhere; }
.file-drop-hint { font-size: 14px; color: var(--ink-mute); }

/* เลือกไฟล์แล้ว — เส้นทึบสีเขียว + รายชื่อไฟล์ ให้เห็นชัดว่าแนบติดแล้ว */
.file-drop.is-filled { border-style: solid; border-color: var(--ok); background: var(--surface); }
.file-drop.is-filled .file-drop-title,
.file-drop.is-filled .file-drop-icon { color: var(--ok); }
.file-drop-list {
  list-style: none; margin: 6px 0 0; padding: 0;
  width: 100%; max-width: 460px;
  display: grid; gap: 4px; font-size: 13.5px;
}
.file-drop-list li {
  display: flex; align-items: center; gap: 12px;
  padding: 6px 6px 6px 10px; border-radius: var(--r-sm); background: var(--bg);
}
.file-drop-name { flex: 1; min-width: 0; overflow-wrap: anywhere; text-align: left; }
.file-drop-size { flex: none; color: var(--ink-mute); }
/* ปุ่มถังขยะท้ายแถว (file-drop.js · 2026-10-28) — ยกเหนือ input ใส ไม่งั้นกดแล้วเปิดหน้าต่างเลือกไฟล์แทน */
.file-drop-remove {
  position: relative; z-index: 2; flex: none;
  display: grid; place-items: center; width: 32px; height: 32px; padding: 0;
  border: 0; border-radius: 8px; background: transparent; color: var(--ink-mute); cursor: pointer;
  transition: background .15s, color .15s;
}
.file-drop-remove svg { width: 18px; height: 18px; }
.file-drop-remove:hover, .file-drop-remove:focus-visible { background: var(--danger-bg); color: var(--danger); outline: none; }
.is-uploading .file-drop-remove { visibility: hidden; }   /* ระหว่างอัปห้ามลบ */

/* ไฟล์ใหญ่เกิน / อัปไม่สำเร็จ */
.file-drop.is-error { border-style: solid; border-color: var(--danger); background: var(--danger-bg); }
.file-drop-error { margin: 4px 0 0; font-size: 13.5px; font-weight: 700; color: var(--danger); }

/* แถบ % ตอนอัปโหลด — ระหว่างอัปห้ามกดเปลี่ยนไฟล์ (input ถูกปิดด้วย pointer-events) */
.file-drop-progress { width: 100%; max-width: 460px; display: grid; gap: 6px; margin-top: 8px; }
.file-drop-bar { height: 10px; border-radius: 999px; background: var(--line); overflow: hidden; }
.file-drop-bar span { display: block; height: 100%; width: 0; background: var(--purple); transition: width .2s; }
.file-drop-percent { font-size: 13.5px; font-weight: 700; color: var(--purple); }
.is-uploading .file-drop-input { pointer-events: none; }

/* แถวทางเลือกในกรอบ (:pickers · 2026-10-28) — เฉพาะจอที่มีเมาส์ · มือถือ = กรอบแบบเดิม
   ★ pointer-events: none — คลิก/วางไฟล์ทะลุถึง input ใสด้านล่าง (ปุ่มที่กดได้จริงในอนาคตต้องยกเหนือ input + กันไฟล์ที่วางบนปุ่ม) */
.file-drop-picks { display: none; width: 100%; max-width: 420px; margin-top: 10px; pointer-events: none; }
.file-drop-pick {
  display: flex; align-items: center; gap: 12px; padding: 12px 14px; text-align: left;
  border: 1px solid var(--purple-br); border-radius: 12px; background: #fff;
  transition: border-color .15s, box-shadow .15s;
}
.file-drop-pick-icon { flex: none; width: 24px; height: 24px; color: var(--purple); }
.file-drop-pick > span { flex: 1; min-width: 0; display: grid; gap: 1px; }
.file-drop-pick b { font-size: 14.5px; color: var(--ink); }
.file-drop-pick small { font-size: 12.5px; color: var(--ink-soft); }
.file-drop-pick-go { flex: none; width: 18px; height: 18px; color: var(--ink-soft); }
.file-drop:hover .file-drop-pick { border-color: var(--purple); box-shadow: 0 2px 10px rgba(91, 24, 242, .10); }
.file-drop.is-filled .file-drop-picks { display: none; }   /* แนบแล้ว = โชว์ชื่อไฟล์แทน (selector หนักกว่ากฎใน @media ด้านล่าง) */
@media (hover: hover) and (pointer: fine) and (min-width: 641px) {   /* จอขนาดมือถือไม่โชว์ แม้เปิดในเครื่องมือจำลองที่มีเมาส์ */
  .file-drop-picks { display: grid; gap: 8px; }
}
/* ปุ่ม "นำเข้ารูปจากโทรศัพท์" (phone="..." · 2026-10-28) — กดได้จริง: ยกเหนือ input ใส · JS เปิดเมื่อเบราว์เซอร์รองรับ (phone-upload.js) */
.file-drop-pick-phone {
  position: relative; z-index: 2; width: 100%;
  font: inherit; color: inherit; cursor: pointer; pointer-events: auto;
}
.file-drop-pick-phone:hover, .file-drop-pick-phone:focus-visible {
  border-color: var(--sf-pink-dk, #E0127A); box-shadow: 0 4px 14px rgba(224, 18, 122, .16); outline: none;
}
.file-drop-pick[hidden] { display: none; }

/* หน้าตากรอบที่มีแถวทางเลือก (:pickers → คลาส has-picks จาก component) — ไอคอนในกล่องขาว · ปุ่มเป็นแคปซูลกลางกรอบ
   ★ 2026-10-29 (เจ้าของ) — ย้ายมาจาก order.css (.pay-col-slip) ให้ทุกที่ที่ใช้ component นี้หน้าตาเดียวกัน: แนบสลิป · อัปรูปก่อนเปิด editor */
.file-drop.has-picks {
  min-height: 220px; gap: 8px; border-radius: 16px;
  background: radial-gradient(circle at 50% 55%, #F1ECFF 0%, #FAF8FF 55%, #fff 100%);
}
.has-picks .file-drop-icon { width: 60px; height: 60px; padding: 16px; border-radius: 16px; background: #fff; box-shadow: var(--shadow); }
.has-picks .file-drop-title { color: var(--sf-ink, #14101F); font-size: 1.05rem; }
.has-picks .file-drop-picks { width: auto; max-width: none; }
@media (hover: hover) and (pointer: fine) and (min-width: 641px) {   /* แคปซูลเรียงข้างกัน (ขึ้นบรรทัดใหม่เองถ้ากรอบแคบ) */
  .has-picks .file-drop-picks { display: flex; flex-wrap: wrap; justify-content: center; }
}
.has-picks .file-drop-pick { width: auto; padding: 8px 16px; border-radius: 12px; box-shadow: var(--shadow); }
.has-picks .file-drop-pick small, .has-picks .file-drop-pick-go { display: none; }
.has-picks .file-drop-pick b { color: var(--sf-violet, #5B18F2); font-size: .85rem; }
.has-picks .file-drop-pick-icon { width: 18px; height: 18px; color: var(--sf-pink-dk, #E0127A); }

@media (max-width: 560px) {
  .file-drop { padding: 24px 16px; }
  .file-drop-title { font-size: 15px; }
  .file-drop-hint { font-size: 13px; }
}

/* ══════ EPIC-013 — กล่องบอกผลตรวจสลิป (checkout) ══════
   ใช้สีเดียวกับระบบ: เขียว = ผ่าน · เหลือง = ต้องกรอกเอง · แดง = สลิปใช้ไม่ได้ */
.slip-check {
  display: flex; align-items: center; gap: 8px;
  margin: 12px 0 4px;
  padding: 12px 16px;
  border: 1px solid var(--purple-br);
  border-radius: var(--r-md);
  font-size: 14.5px;
  line-height: 1.6;
}
.slip-check-text { font-weight: 600; overflow-wrap: anywhere; }

.slip-check.is-checking { background: var(--purple-lt); border-color: var(--purple-br); color: var(--purple); }
.slip-check.is-ok       { background: #E8F6EE; border-color: #A8DCBE; color: var(--ok); }
.slip-check.is-warn     { background: var(--warn-bg); border-color: #F0DBA8; color: var(--warn); }
.slip-check.is-error    { background: #FDECEC; border-color: #F3C2C2; color: #B42318; }

/* ★ ตัวหมุนบอกว่า "กำลังตรวจสอบอยู่" — ของเดิมมีแค่ข้อความนิ่งๆ ดูเหมือนค้าง (2026-09-22)
   โผล่เฉพาะตอน .is-checking เท่านั้น ตัวอื่นไม่ต้องมี (ตรวจเสร็จแล้วไม่ต้องหมุนต่อ) */
.slip-spinner {
  flex: none;
  width: 16px; height: 16px;
  border: 2px solid rgba(101, 47, 128, .25);
  border-top-color: var(--purple);
  border-radius: 50%;
  animation: slip-spin .7s linear infinite;
}
@keyframes slip-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .slip-spinner { animation: none; }
}

/* ★ ปุ่มยืนยันสั่งซื้อเด้งเรียกความสนใจตอนสลิปตรวจผ่านแล้ว (2026-09-22)
   เด้ง 3 รอบแล้วหยุดเอง (animation-iteration-count) ไม่รบกวนตลอดไป — แค่ชี้ว่า "ขั้นต่อไปคือปุ่มนี้" */
#co-submit.is-pulse { animation: co-submit-pulse .6s ease-in-out 3; }
@keyframes co-submit-pulse {
  0%, 100% { transform: scale(1); box-shadow: 0 0 0 0 rgba(253, 202, 0, .55); }
  50%      { transform: scale(1.045); box-shadow: 0 0 0 10px rgba(253, 202, 0, 0); }
}
@media (prefers-reduced-motion: reduce) {
  #co-submit.is-pulse { animation: none; }
}

/* ช่องที่ระบบกรอกให้จากสลิป — กันแก้ แต่ยังส่งค่าไปกับฟอร์ม
   (ไม่ใช้ disabled เพราะ input/select ที่ disabled จะไม่ถูกส่งไปกับฟอร์มเลย) */
.co-form .is-locked {
  background: var(--bg);
  color: var(--ink-mute);
  border-color: var(--purple-br);
  pointer-events: none;
}

/* ── ป็อปอัพชำระเงิน — ยังเป็น <form> เดียวกับข้อมูลผู้สั่งทั้งหมด (2026-09-22)
   แค่ซ่อน/โชว์ด้วย CSS+JS ให้ดูเหมือนคนละขั้นตอน ไม่ใช่แยกหน้าจริง
   ★ ตั้งใจไม่ให้กดพื้นหลังเพื่อปิด (backdrop ไม่มี click listener) — มีแค่ปุ่ม "◀ ย้อนกลับ"
   ในป็อปอัพเท่านั้นที่ปิดได้ กันลูกค้ากดพลาดแล้วข้อมูลที่กรอกในป็อปอัพหาย */
.pay-modal-backdrop {
  position: fixed; inset: 0;
  background: rgba(36, 27, 43, .6);
  z-index: 1000;
}
.pay-modal {
  position: fixed;
  top: 4%; bottom: 4%; left: 3%; right: 3%;
  z-index: 1001;
  background: var(--surface);
  border-radius: 20px;
  box-shadow: 0 24px 64px rgba(36, 27, 43, .4);
  display: flex;
  flex-direction: column;
  /* ★ overflow:hidden ตรงนี้ (ไม่ใช่ overflow-y:auto) — ตัวที่เลื่อนได้จริงคือ .pay-modal-scroll
  ข้างใน ไม่งั้น scrollbar ของเบราว์เซอร์ (แท่งเหลี่ยมตรงๆ) จะไปทับมุมโค้งขวาบน/ขวาล่างของกล่องนี้
  ทำให้ขอบดูไม่สมดุล (2026-09-22) */
  overflow: hidden;
}
.pay-modal-head {
  flex: none;
  display: flex; align-items: center; gap: 14px;
  padding: 16px 24px 12px;
  border-bottom: 1px solid var(--line);
}
.pay-modal-head h2 { margin: 0; font-size: 18px; }
.pay-modal-scroll {
  flex: 1;
  overflow-y: auto;
  padding: 18px 24px 24px;
}
/* ★ ล็อกไม่ให้พื้นหลังเลื่อนตามตอนป็อปอัพเปิดอยู่ (ผูก class นี้ที่ <html> และ <body> ด้วย JS)
   ต้องใส่ทั้งคู่ — ตัวที่เบราว์เซอร์ใช้เลื่อนจริง (scrolling element) คือ <html> ไม่ใช่ <body>
   ถ้าใส่แค่ body พอเบราว์เซอร์เจอฟิลด์ required ที่ยังไม่กรอก (เช่น checkbox ยอมรับเงื่อนไข)
   แล้วพยายาม scrollIntoView ให้เห็น มันจะเลื่อน <html> แทน ทะลุ overflow:hidden ของ body ไปได้
   หน้าเว็บที่ซ่อนอยู่หลังป็อปอัพ (position:fixed) เลยเลื่อนเห็นพื้นที่ว่างขาวโล่งด้านล่าง */
html.pay-modal-open,
body.pay-modal-open { overflow: hidden; }

@media (max-width: 640px) {
  .pay-modal { top: 2%; bottom: 2%; left: 2%; right: 2%; }
  .pay-modal-head { padding: 14px 16px 10px; }
  .pay-modal-scroll { padding: 14px 16px 16px; }
}

/* ─────────────────────────────────────────────
   2026-10-10 — แถบสถานะใหญ่บนสุดหน้าออเดอร์ลูกค้า (กำลังจัดส่ง / สำเร็จ / ยกเลิก)
   หน้ารีเฟรชเองเมื่อสถานะเปลี่ยน (ดู orders/show.blade.php) แถบนี้เลยเป็นสิ่งแรกที่ลูกค้าเห็น
   ───────────────────────────────────────────── */
.status-hero {
  display: flex; align-items: center; gap: 16px;
  margin-bottom: 18px; padding: 20px 22px;
  border: 2px solid var(--purple-br); border-radius: var(--r-md); background: var(--purple-lt);
}
.status-hero > svg { width: 44px; height: 44px; flex: none; }
.status-hero-title { margin: 0; font-size: 22px; font-weight: 800; line-height: 1.3; }
.status-hero-sub { margin: 4px 0 0; font-size: 14px; }
.status-hero-production { color: var(--purple); }
.status-hero-production .status-hero-sub { color: var(--ink-soft); }
/* เครื่องพิมพ์ขยับ — SVG อยู่ที่ components/printing-animation.blade.php */
.status-hero > svg.pp-print { width: 120px; height: 100px; }
.pp-print-head { animation: pp-print-sweep 2.4s ease-in-out infinite alternate; }
.pp-print-led { animation: pp-print-blink 1s steps(2, jump-none) infinite; }
.pp-print-part { transform-box: fill-box; transform-origin: bottom; animation: pp-print-grow 4.8s ease-in-out infinite; }
@keyframes pp-print-sweep { from { transform: translateX(-28px); } to { transform: translateX(52px); } }
@keyframes pp-print-blink { 50% { opacity: .2; } }
@keyframes pp-print-grow { 0% { transform: scaleY(.5); } 50% { transform: scaleY(1); } 100% { transform: scaleY(.5); } }
/* ภาพขยับของสถานะอื่น: ตรวจไฟล์ (checking-animation) + รถส่งของ (delivery-animation) */
.status-hero > svg.pp-anim { width: 120px; height: 100px; flex: none; }
.pp-check-lens { animation: pp-check-scan 2.2s ease-in-out infinite alternate; }
.pp-check-tick { transform-box: fill-box; transform-origin: center; animation: pp-check-pop 2.2s ease-in-out infinite; }
.pp-ship-truck { animation: pp-ship-bump .5s ease-in-out infinite alternate; }
.pp-ship-road { animation: pp-ship-road .6s linear infinite; }
@keyframes pp-check-scan { from { transform: translate(0, 0); } to { transform: translate(34px, 64px); } }
@keyframes pp-check-pop { 0%, 60% { transform: scale(1); } 80% { transform: scale(1.25); } 100% { transform: scale(1); } }
@keyframes pp-ship-bump { from { transform: translateY(0); } to { transform: translateY(-2px); } }
@keyframes pp-ship-road { to { stroke-dashoffset: 28; } }
/* ติ๊กถูกสำเร็จ (success-animation) — เล่นรอบเดียวแล้วค้างภาพสุดท้าย */
.status-hero > svg.pp-ok { width: 110px; height: 110px; flex: none; overflow: visible; }
.pp-ok-disc { transform-box: fill-box; transform-origin: center; animation: pp-ok-pop .7s cubic-bezier(.34, 1.56, .64, 1) both; }
.pp-ok-tick { stroke-dasharray: 100; animation: pp-ok-draw .5s ease-out .45s both; }
.pp-ok-c { transform-box: fill-box; transform-origin: center; animation: pp-ok-burst 1.1s ease-out .5s both; }
@keyframes pp-ok-pop { from { transform: scale(.2); } to { transform: scale(1); } }
@keyframes pp-ok-draw { from { stroke-dashoffset: 100; } to { stroke-dashoffset: 0; } }
@keyframes pp-ok-burst {
  from { transform: translate(0, 0) scale(.4); opacity: 1; }
  to { transform: translate(var(--dx), var(--dy)) scale(1); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .pp-ok-disc, .pp-ok-tick { animation: none; }
  .pp-ok-c { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .pp-print-head, .pp-print-led, .pp-print-part,
  .pp-check-lens, .pp-check-tick, .pp-ship-truck, .pp-ship-road { animation: none; }
}
.status-hero-shipping { color: var(--purple); }
.status-hero-shipping .status-hero-sub { color: var(--ink-soft); }
.status-hero-done { background: #E6F4EA; border-color: var(--ok); color: var(--ok); }
.status-hero-done .status-hero-sub { color: var(--ink-soft); }
.status-hero-cancelled { background: var(--danger-bg); border-color: var(--danger); color: var(--danger); }
@media (max-width: 600px) {
  .status-hero { padding: 16px; gap: 12px; }
  .status-hero > svg { width: 36px; height: 36px; }
  .status-hero-title { font-size: 18px; }
}

/* ─────────────────────────────────────────────
   2026-09-28 — วิธีเลือกจำนวนแบบ "ทั้งสองแบบ" (ปุ่มขั้น + กรอกเอง)
   ───────────────────────────────────────────── */
.qty-row-both { margin-top: 10px; flex-wrap: wrap; }
.qty-tier-note { font-size: 13px; color: var(--ink-soft); }
.qty-next-tier {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin-top: 10px; padding: 10px 14px;
  background: var(--warn-bg); border: 1px solid #F0DFAF; border-radius: var(--r-sm);
  font-size: 14px; color: var(--warn);
}
.qty-next-tier .btn { padding: 7px 14px; font-size: 13.5px; margin-left: auto; }

/* ─────────────────────────────────────────────
   2026-09-28 — ช่องโค้ดส่วนลด (หน้าตาอย่างเดียว ยังไม่มีระบบหลังบ้าน)
   ───────────────────────────────────────────── */
.promo-row { display: flex; gap: 8px; }
.promo-row input {
  flex: 1; min-width: 0; font: inherit; padding: 11px 14px;
  border: 1.5px solid var(--line); border-radius: var(--r-sm); background: #fff;
}
.promo-row input:focus { border-color: var(--purple); outline: none; }
.promo-row .btn { padding: 11px 18px; border-radius: var(--r-sm); flex: none; }
.promo-msg { margin: 8px 0 0; font-size: 13px; color: var(--warn); }

/* ─────────────────────────────────────────────
   2026-09-28 — รูปตัวอย่างของตัวเลือกที่เลือก (1:1 เต็มความกว้างกลุ่ม · เหนือปุ่มตัวเลือก)
   พื้นเทาอ่อน + ขอบมน · รูปวางกลางแบบ contain (รูปไม่โดนตัด ถ้าแอดมินอัปมาไม่ใช่ 1:1)
   ───────────────────────────────────────────── */
.opt-preview {
  aspect-ratio: 1 / 1; width: 50%; margin-bottom: 10px;
  align-self: center; justify-self: center;
  background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--r-md);
  overflow: hidden; display: grid; place-items: center;
  animation: opt-preview-in .2s ease;
}
.opt-preview[hidden] { display: none; }
.opt-preview img { width: 100%; height: 100%; object-fit: contain; }
@keyframes opt-preview-in {
  from { opacity: 0; transform: scale(.98); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) { .opt-preview { animation: none; } }

/* ─────────────────────────────────────────────
   2026-09-28 — การ์ดตัวเลือกมีรูป เลื่อนแนวนอนได้ (display_style = cards)
   ใช้กับกลุ่มที่มีรูปให้เทียบและอาจมีตัวเลือกเยอะในอนาคต (แอดมินสลับได้ต่อกลุ่ม ไม่ผูกกับชื่อกลุ่ม)
   ───────────────────────────────────────────── */
/* ★ 2026-09-28 (มติเจ้าของ รอบ 2) — ปิดไว้ก่อนเป็นกล่องสรุป กดแล้วค่อยขยายเป็นตาราง (ไม่ใช่โชว์ตลอด) */
.opt-picker-summary {
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 10px 12px; border: 1.5px solid var(--line); border-radius: var(--r-sm);
  background: #fff; font: inherit; font-size: 14.5px; font-weight: 600; color: var(--ink);
  cursor: pointer; text-align: left;
}
.opt-picker-summary:hover { border-color: var(--purple-br); }
.opt-picker-summary[aria-expanded="true"] { border-color: var(--purple); }
.opt-picker-thumb {
  width: 36px; height: 36px; flex: none; border-radius: var(--r-sm); overflow: hidden;
  background: var(--surface-2);
}
.opt-picker-thumb img { width: 100%; height: 100%; object-fit: cover; }
.opt-picker-label { flex: 1; }
.opt-picker-chevron {
  width: 18px; height: 18px; flex: none; fill: none; stroke: currentColor; stroke-width: 2;
  stroke-linecap: round; stroke-linejoin: round; color: var(--ink-mute); transition: transform .15s;
}
.opt-picker-summary[aria-expanded="true"] .opt-picker-chevron { transform: rotate(180deg); }

/* ★ 2026-10-05 (มติเจ้าของ) — เลือกแล้ว: ขอบ/พื้นม่วงจาง + ติ๊กถูก เห็นได้โดยไม่ต้องกดกางดูข้างใน
   สีชุดเดียวกับ .opt-card ตอนเลือก (input:checked) กันสีเพี้ยนคนละจุด */
.opt-picker-summary.is-picked { border-color: var(--purple); background: var(--purple-lt); }
.opt-picker-check {
  display: none; width: 16px; height: 16px; flex: none;
  fill: none; stroke: var(--purple); stroke-width: 2.6; stroke-linecap: round; stroke-linejoin: round;
}
.opt-picker-summary.is-picked .opt-picker-check { display: block; }

/* ตารางการ์ด — ขยายลงมาใต้กล่องสรุปตอนกด (grid ไม่ใช่เลื่อนแนวนอน) */
.opt-cards {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); gap: 10px;
  margin-top: 10px;
}
.opt-cards[hidden] { display: none; }
.opt-card { position: relative; }
.opt-card input { position: absolute; opacity: 0; inset: 0; cursor: pointer; margin: 0; }
.opt-card-body {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  height: 100%; padding: 8px; text-align: center;
  border: 1.5px solid var(--line); border-radius: var(--r-md); background: #fff;
}
/* ★ 2026-09-28 — ตัวเลือกไม่มีรูป: ไม่มี .opt-card-thumb ให้ยึดความสูง → จัดกลางแนวตั้งแทน
   กันการ์ดในแถวเดียวกันสูงไม่เท่ากันเวลาผสมกับใบที่มีรูป (grid แถวเดียวกันสูงเท่ากันอยู่แล้ว แค่เนื้อในไม่ล้นบน) */
.opt-card-body.no-thumb { justify-content: center; min-height: 72px; }
.opt-card-thumb-wrap { position: relative; width: 100%; aspect-ratio: 1 / 1; }
.opt-card-thumb {
  /* ★ 2026-10-06 (มติเจ้าของ: "รูปขอให้มี radius สักนิดๆ") — var(--r-sm) 8px บนรูปเล็กแทบไม่เห็นมุมโค้ง */
  width: 100%; height: 100%; border-radius: 10px; overflow: hidden;
  background: var(--surface-2);
}
.opt-card-thumb img { width: 100%; height: 100%; object-fit: cover; }
.opt-card-label { font-size: 13px; font-weight: 700; line-height: 1.3; }
.opt-card-note { display: block; color: var(--ink-mute); font-size: 11px; }
.opt-card-check {
  position: absolute; top: 6px; right: 6px; width: 20px; height: 20px; border-radius: 999px;
  background: var(--purple); color: #fff; font-size: 12px; line-height: 1;
  display: none; align-items: center; justify-content: center;
}
.opt-card input:checked + .opt-card-body {
  border-color: var(--purple); background: var(--purple-lt); box-shadow: inset 0 0 0 1px var(--purple);
}
.opt-card input:checked + .opt-card-body .opt-card-check { display: flex; }
.opt-card input:focus-visible + .opt-card-body { outline: 2px solid var(--yellow); outline-offset: 2px; }
.opt-card-body:hover { border-color: var(--purple-br); }

@media (max-width: 640px) {
  .opt-card { flex-basis: 92px; }
}

/* ─────────────────────────────────────────────
   2026-09-28 — ปุ่มแว่นขยายมุมขวาล่างบนรูปตัวเลือก (การ์ด + กล่องรูปใหญ่) → ดูรูปเต็มจอ
   พื้นมืดโปร่งแสง ให้เห็นชัดทั้งบนรูปสว่างและรูปมืด · อยู่เหนือรูปแต่ไม่บังรูปเยอะ
   ───────────────────────────────────────────── */
.opt-preview { position: relative; }
.opt-zoom-btn {
  position: absolute; right: 6px; bottom: 6px; z-index: 2;
  width: 28px; height: 28px; padding: 0; border: 0; border-radius: 999px;
  background: rgba(36, 27, 43, 0.067); color: #fff; cursor: zoom-in;
  display: grid; place-items: center;
  transition: background .15s, transform .15s;
}
.opt-zoom-btn:hover { background: var(--purple); transform: scale(1.08); }
.opt-zoom-btn:focus-visible { outline: 2px solid var(--yellow); outline-offset: 2px; }
.opt-zoom-btn svg {
  width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 2.2;
  stroke-linecap: round; stroke-linejoin: round;
}
/* กล่องรูปใหญ่ — ปุ่มใหญ่ขึ้นนิดตามขนาดกล่อง */
.opt-preview .opt-zoom-btn { width: 34px; height: 34px; right: 10px; bottom: 10px; }
.opt-preview .opt-zoom-btn svg { width: 18px; height: 18px; }

/* ★ 2026-10-06 (มติเจ้าของ) — ชี้เมาส์ค้างบนรูปตัวเลือก (ทุกกลุ่ม/ทุกรูปแบบแสดงผล) = โชว์รูปขยายลอยตาม
   เมาส์ทันที ไม่ต้องกดแว่นขยาย (อันนั้นเปิดเต็มจอ ไว้ดูละเอียดจริงๆ) อันนี้แค่ดูไวๆ ไม่บังทั้งจอ
   ★ position: fixed — หนีการโดนตัดของกล่อง .opt-cards.is-list ที่มี overflow:auto (ดู JS ใน
   product-configurator.blade.php ที่ย้ายตำแหน่งตามเมาส์ + เช็ค hover:hover กันค้างบนจอสัมผัส) */
.opt-hover-preview {
  position: fixed; top: 0; left: 0; z-index: 60; width: 220px; height: 220px;
  border-radius: var(--r-md); overflow: hidden; background: var(--surface-2);
  border: 3px solid #fff; box-shadow: 0 10px 30px rgba(20, 16, 31, .3);
  opacity: 0; transform: scale(.96); pointer-events: none;
  transition: opacity .1s, transform .1s;
}
.opt-hover-preview.is-on { opacity: 1; transform: scale(1); }
.opt-hover-preview img { width: 100%; height: 100%; object-fit: cover; }

/* ═══════════════════════════════════════════════════════════════════════
   EPIC-025 — หน้าสินค้าแบบใหม่ (มติเจ้าของ 2026-10-02 · ตามแบบที่ส่งมา)
   ทับของเดิมด้านบนเฉพาะหน้าตา — โครง HTML/JS คิดราคาเดิมทุกอย่าง
   ═══════════════════════════════════════════════════════════════════════ */

/* แกลเลอรี: กรอบขาวมุมมน + เส้นขอบบาง · รูปเต็มกรอบ
   ★ มุมรูป = มุมกรอบ − ระยะขอบ → เส้นโค้งขนานกัน (เจ้าของ: "ขอบรูปมนเท่ากับขอบข้างนอก") */
.gallery { --card-bg: #fff; --frame-r: 24px; --frame-pad: 10px; }   /* พื้นขาวเสมอ (เจ้าของ: หน้าสินค้าไม่ต้องดูดสี) */
.gal-main {
  max-width: none; padding: var(--frame-pad); border: 0; border-radius: var(--frame-r);
  background: var(--card-bg); box-shadow: 0 0 0 1px rgba(20,16,31,.06);
}
.gal-main img,
.gal-main video {   /* วิดีโอแทนรูป (TASK-203) — กรอบเดียวกับรูป */
  position: absolute;
  top: var(--frame-pad); left: var(--frame-pad); right: var(--frame-pad); bottom: var(--frame-pad);
  width: calc(100% - var(--frame-pad) * 2); height: calc(100% - var(--frame-pad) * 2);
  object-fit: cover; border-radius: calc(var(--frame-r) - var(--frame-pad));
}
.gal-main video[hidden], .gal-main img[hidden] { display: none; }
/* รูปงานที่ลูกค้าออกแบบ (หน้าสินค้า): สัดส่วนตามขนาดงานจริง ไม่ตรงกับกรอบ — ต้องเห็นทั้งใบ ห้ามตัดขอบ (cover ใช้กับรูปสินค้าเท่านั้น) */
.gal-main img[data-design-preview-img],
.gal-main img[data-design-preview-fallback],
.gal-thumbs .gal-thumb-design img { object-fit: contain; }
/* ★ 2026-10-06 (มติเจ้าของ: "กดดูรูปมันเป็นวีดีโอ ซ้อนกันแบบนี้") — เบราว์เซอร์มือถือ (โดยเฉพาะ Safari/iOS)
   โชว์แถบควบคุมวิดีโอของตัวเองทันทีที่แตะ <video> แม้เราไม่ได้ใส่ attribute controls เลย กลายเป็นซ้อนทับ
   ป้าย/ปุ่ม "ดูรูปเต็ม" ของเรา ดูเหมือนบั๊ก — ปิดแถบควบคุมเบราว์เซอร์ + ให้แตะทะลุวิดีโอไปที่ container แทน
   (ดู pointer-events ด้านล่าง คู่กับ gallery.js ที่ย้าย tap handler ไปอยู่ที่ [data-gallery-main] อยู่แล้ว) */
.gal-main video { pointer-events: none; }
.gal-main video::-webkit-media-controls,
.gal-main video::-webkit-media-controls-enclosure,
.gal-main video::-webkit-media-controls-start-playback-button {
  display: none !important;
}
/* กำลังเล่นวิดีโออยู่ — ซ่อนป้าย "ดูรูปเต็ม" (กดแล้วไม่มีอะไรเกิดขึ้นอยู่แล้ว ดู openLightbox guard ใน gallery.js) */
.gal-main.is-playing-video .gal-zoom { display: none; }

/* ★ 2026-10-06 (มติเจ้าของ: "กดรูปย่อที่เป็นวิดีโอ ทำไมเล่นให้เองเลย ต้องกดเล่นเอง") — เลือกรายการที่มี
   วิดีโอแล้ว ระบบแค่โชว์รูปปกค้างไว้ก่อน (ไม่เล่นอัตโนมัติ) ปุ่มเล่นวงกลมกลางจอ กดถึงเล่นจริง
   ★ has-video (มีวิดีโอ แต่ยังไม่ได้กดเล่น) โชว์ปุ่ม · is-playing-video (กำลังเล่นอยู่) ซ่อนปุ่ม */
.gal-play-btn {
  display: none; position: absolute; inset: 0; margin: auto; width: 64px; height: 64px;
  border: 0; border-radius: 999px; background: rgba(20, 16, 31, .6); color: #fff;
  align-items: center; justify-content: center; cursor: pointer; z-index: 2;
  transition: background .15s, transform .15s;
}
.gal-play-btn svg { width: 28px; height: 28px; fill: currentColor; margin-left: 3px; }
.gal-play-btn:hover { background: var(--sf-violet); transform: scale(1.06); }
.gal-main.has-video:not(.is-playing-video) .gal-play-btn { display: flex; }
/* มีวิดีโอแต่ยังไม่เล่น — ซ่อนป้าย "ดูรูปเต็ม" ไปก่อนด้วย (ให้เห็นแต่ปุ่มเล่น ไม่รกสองปุ่มซ้อนกัน) */
.gal-main.has-video:not(.is-playing-video) .gal-zoom { display: none; }
/* รูปย่อที่เป็นวิดีโอ — ป้าย ▶ มุมล่างซ้าย */
.gal-thumbs div.is-video { position: relative; }
.gal-thumbs div.is-video::after {
  content: '▶'; position: absolute; left: 6px; bottom: 6px; display: grid; place-items: center;
  width: 22px; height: 22px; border-radius: 50%; background: rgba(20,16,31,.7); color: #fff; font-size: 10px;
}

/* แถบรูปย่อ + ลูกศร (JS ใน products/show) */
.gal-thumbs-wrap { display: flex; align-items: center; gap: 8px; margin-top: 12px; }
.gal-thumbs-wrap .gal-thumbs { flex: 1; margin-top: 0; justify-content: flex-start; scrollbar-width: none; scroll-behavior: smooth; }
.gal-thumbs-wrap .gal-thumbs::-webkit-scrollbar { display: none; }
.gal-thumbs div { flex-basis: calc((100% - 30px) / 4); border-radius: 14px; border-width: 2px; background: var(--card-bg); }
.gal-thumbs div.on { border-color: var(--sf-pink); box-shadow: none; }
.gal-thumbs-btn {
  flex: none; display: grid; place-items: center; width: 34px; height: 34px; border-radius: 50%;
  border: 1px solid var(--line); background: #fff; color: var(--sf-ink); cursor: pointer;
}
.gal-thumbs-btn:hover { background: var(--sf-lime); border-color: var(--sf-lime); }
.gal-thumbs-btn[disabled] { opacity: .3; pointer-events: none; }
.gal-thumbs-btn svg { width: 18px; height: 18px; }

/* รายละเอียดสินค้าใต้รูป (ย้ายมาจากครึ่งล่าง) */
.pdp-spec { margin-top: 28px; }
.pdp-spec-title { margin: 0 0 12px; font-size: 20px; }
.pdp-spec .selling-points { margin: 0 0 14px; }
.pdp-spec .spec-table { font-size: 14.5px; }
.pdp-spec .spec-table th, .pdp-spec .spec-table td { padding: 7px 0; border: 0; background: transparent; vertical-align: top; }
.pdp-spec .spec-table th { width: 38%; padding-right: 14px; }
.pdp-spec .spec-table tr + tr th, .pdp-spec .spec-table tr + tr td { border-top: 1px dashed var(--line); }

/* แผงขวา: กรอบม่วง มุมมน */
.config { border: 2px solid var(--sf-violet); border-radius: 24px; box-shadow: none; }
.pdp-title { font-size: clamp(24px, 2vw, 28px); }

/* ★ 2026-10-02 (เจ้าของ: "เลื่อนลงก็เลื่อนไปเลย ไม่ต้องมีลูกเล่น") — ไม่ sticky ทั้งรูปและแผงขวา หน้าเลื่อนตามปกติ
   ความกว้างครึ่งบน → ดู .pdp ท้ายไฟล์ */
.gallery, .config { position: static; }

/* ตัวเลือกทุกกลุ่ม = กล่อง dropdown (ปุ่มเดิมเลิกใช้ — ดู product-configurator) */
.opt-picker-summary { padding: 11px 14px; border: 1.5px solid #CFC8DA; border-radius: 12px; }
.opt-picker-summary[aria-expanded="true"] { border-color: var(--sf-violet); box-shadow: 0 0 0 3px var(--purple-lt); }
.opt-picker-thumb { width: 30px; height: 30px; border-radius: 8px; }

/* ★ 2026-10-06 (มติเจ้าของ) — "แนวนอน" (inline_list) ต้องเป็นกริดการ์ดแบบเดียวกับ "แนวตั้ง" ทุกอย่าง
   (กรอบ/ขนาด/จำนวนคอลัมน์เท่ากัน) ต่างแค่ในการ์ดเดียวย้ายรูปไปซ้ายข้อความ (row) แทนอยู่บน (column)
   ★ ห้ามใช้ .is-list ตัวเดียวกับที่กางเป็น "รายการ" ใต้ dropdown chips (บรรทัด ~134) — คนละความต้องการ
   อันนั้นตั้งใจรวมเป็นลิสต์เดียวสกอลล์ได้ อันนี้ต้องแยกเป็นการ์ดเหมือนเดิม */
.opt-cards.is-horizontal {
  /* 120px (ขนาดปกติของการ์ดแนวตั้ง) แคบไปสำหรับ รูป+ข้อความเรียงแถว — ข้อความเลยเบียดชนไอคอนติ๊กถูก */
  grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
}
.opt-cards.is-horizontal .opt-card-body,
.opt-cards.is-horizontal .opt-card-body.no-thumb {
  /* ★ 2026-10-07 (เจ้าของ: "text เละ ตัวอักษรลอย") — เดิมเป็น flex-wrap แล้วดันคำอธิบายด้วย margin-left:66px
     (เดาว่ามีรูปเสมอ) → ใบที่ไม่มีรูปคำอธิบายลอยไม่ตรงชื่อ · ใบที่มีรูปคำอธิบายหล่นไปแถวล่างใต้รูป
     เปลี่ยนเป็น grid: [รูป] [ชื่อ ↓ คำอธิบาย ซ้อนกันในคอลัมน์เดียว] [ติ๊กถูก] — ไม่ต้องเดาความกว้างรูป */
  display: grid; grid-template-columns: 56px minmax(0, 1fr) auto; align-items: center;
  column-gap: 12px; row-gap: 2px; text-align: left;
}
/* ไม่มีรูป: ชื่อ(+คำอธิบาย) กองรวมกันแล้วอยู่กึ่งกลางความสูงการ์ด (การ์ดข้างเคียงสูงกว่าก็ไม่ตกลงล่าง) */
.opt-cards.is-horizontal .opt-card-body.no-thumb { grid-template-columns: minmax(0, 1fr) auto; align-content: center; }
.opt-cards.is-horizontal .no-thumb .opt-card-label,
.opt-cards.is-horizontal .no-thumb .opt-card-note { align-self: auto; }
.opt-cards.is-horizontal .no-thumb .opt-card-check { align-self: center; }
.opt-cards.is-horizontal .opt-card-thumb-wrap { grid-column: 1; grid-row: 1 / span 2; width: 56px; }
.opt-cards.is-horizontal .opt-card-label { grid-column: 2; grid-row: 1; align-self: end; min-width: 0; }
.opt-cards.is-horizontal .opt-card-note { grid-column: 2; grid-row: 2; align-self: start; margin: 0; }
.opt-cards.is-horizontal .no-thumb .opt-card-label,
.opt-cards.is-horizontal .no-thumb .opt-card-note { grid-column: 1; }
/* ติ๊กถูกเดิมลอยทับมุมขวาบน (ใช้ได้กับการ์ดแนวตั้งที่ไม่มีข้อความยาวบังอยู่) — แถวนี้ข้อความยาวอาจชนไอคอน
   เปลี่ยนเป็นช่องคงที่ชิดขวา ไม่ซ้อนทับตัวหนังสือ */
.opt-cards.is-horizontal .opt-card-check { position: static; grid-column: 3; grid-row: 1 / span 2; }
.opt-cards.is-horizontal .no-thumb .opt-card-check { grid-column: 2; }
/* ★ 2026-10-06 (มติเจ้าของ: "แว่นขยายบังรูปหมดแล้ว") — รูป 56px เล็กไป ปุ่มแว่นขยาย 28px ปิดเกือบมิด
   ย่อปุ่มลง + ดันออกไปครึ่งหนึ่งนอกขอบรูป (wrap ไม่มี overflow:hidden แล้ว ไม่โดนตัด) */
.opt-cards.is-horizontal .opt-zoom-btn {
  width: 18px; height: 18px; right: -5px; bottom: -5px;
  background: rgba(36, 27, 43, .55); box-shadow: 0 0 0 2px #fff;
}
.opt-cards.is-horizontal .opt-zoom-btn svg { width: 11px; height: 11px; }

/* กางออกแบบ "รายการ" (กลุ่มที่ไม่ใช่การ์ดมีรูป) — แถวเดียว ชิดซ้าย มีเครื่องหมายถูกตอนเลือก */
.opt-cards.is-list {
  grid-template-columns: 1fr; gap: 0; margin-top: 6px; padding: 4px; max-height: 300px; overflow: auto;
  border: 1.5px solid var(--purple-br); border-radius: 12px; background: #fff;
}
.opt-cards.is-list .opt-card-body,
.opt-cards.is-list .opt-card-body.no-thumb {
  flex-direction: row; align-items: center; justify-content: flex-start; gap: 10px; min-height: 0;
  padding: 10px 12px; text-align: left; border: 0; border-radius: 9px;
}
.opt-cards.is-list .opt-card-thumb-wrap { width: 36px; flex: none; }
.opt-cards.is-list .opt-card-label { font-size: 14.5px; font-weight: 600; }
.opt-cards.is-list .opt-card-note { margin-left: auto; font-size: 12.5px; }
.opt-cards.is-list .opt-card-check { position: static; margin-left: 6px; flex: none; }
.opt-cards.is-list .opt-card-note + .opt-card-check { margin-left: 8px; }
.opt-cards.is-list .opt-card:not(:has(.opt-card-note)) .opt-card-check { margin-left: auto; }
.opt-cards.is-list .opt-card-body:hover { background: var(--purple-lt); }
/* ★ 2026-10-06 — รูป 36px เล็กกว่า is-horizontal อีก ย่อ+ดันปุ่มแว่นขยายออกนอกรูปเหมือนกัน */
.opt-cards.is-list .opt-zoom-btn {
  width: 16px; height: 16px; right: -4px; bottom: -4px;
  background: rgba(36, 27, 43, .55); box-shadow: 0 0 0 2px #fff;
}
.opt-cards.is-list .opt-zoom-btn svg { width: 10px; height: 10px; }
.opt-cards.is-list .opt-card input:checked + .opt-card-body { background: var(--purple-lt); box-shadow: none; color: var(--sf-violet); }

/* กล่องราคา: พื้นเขียวมะนาวอ่อน · ยอดรวมตัวใหญ่สีชมพู */
.pricebox { background: color-mix(in oklab, var(--sf-lime) 45%, #fff); border-top: 2px solid var(--sf-violet); }
.price-line { color: var(--sf-ink); }
.price-total { border-top-color: rgba(20,16,31,.15); }
.price-total b { color: var(--sf-pink-dk); font-size: 34px; }
.price-total span { color: var(--sf-pink-dk); }   /* 2026-10-02 (เจ้าของ) — คำว่า "ยอดรวม" ชมพูเดียวกับตัวเลข */

/* แถบปิดท้าย "พร้อมสั่งแล้วใช่ไหม?" — 2026-10-02 (เจ้าของ) พื้นชมพูตามธีม (เดิมม่วง) · ชมพูเข้มให้ตัวขาวอ่านชัด */
.pdp-cta { background: var(--sf-pink-dk); border-top-color: var(--sf-lime); }
.server-note { color: var(--ink-soft); }

/* ═══ รีวิวสินค้า (ท้ายหน้าสินค้า) ═══ */
.pdp-reviews { position: relative; padding-block: 56px 64px; margin-top: 30px; background: var(--sf-mist); }
.pdp-reviews h2 { margin: 0 0 22px; font-size: clamp(26px, 3vw, 34px); display: inline-block; }
.pdp-reviews h2 span { color: var(--sf-pink); }
.pdp-reviews h2::after { content: ""; display: block; height: 8px; margin-top: 4px; background: radial-gradient(circle at 4px 0, transparent 4px, var(--sf-violet) 4.5px, var(--sf-violet) 6px, transparent 6.5px) 0 0 / 12px 8px repeat-x; }

@media (max-width: 900px) {
  .gal-thumbs div { flex-basis: 64px; }
  .config { border-radius: 20px; }
}

/* ★ 2026-10-06 (มติเจ้าของ) — กลับไปที่มติ 2026-10-02 เดิม: จำกัดฝั่งละ 460px + จัดกลางจอ
   (ลอง 1fr แล้วรูปใหญ่เกินไป — เจ้าของขอกลับเป็นแบบนี้) */
.pdp { grid-template-columns: repeat(2, minmax(0, 460px)); justify-content: center; gap: 44px; }
@media (max-width: 980px) { .pdp { grid-template-columns: 1fr; } }

/* ★ 2026-10-08 (EPIC-011 · มติเจ้าของ) — หน้าตรวจงานออกแบบออนไลน์: พรีวิวใหญ่ตรงกลาง (ภายหลังเพิ่มปุ่มสลับดู 3D ที่กล่องนี้) */
.design-view { text-align: center; }
.design-preview { margin: 0 auto 18px; max-width: 620px; padding: 16px; background: #f4f4f6; border-radius: 14px; }
.design-preview img { display: block; width: 100%; height: auto; border-radius: 0; box-shadow: 0 2px 12px rgba(0, 0, 0, .15); }
.design-actions { display: flex; flex-wrap: wrap; gap: 10px; justify-content: center; }
@media (max-width: 720px) { .design-preview { padding: 10px; } }

/* ★ 2026-10-08 (EPIC-011 · มติเจ้าของ) — หน้าสินค้าที่ออกแบบออนไลน์ได้: ลิงก์ "เตรียมไฟล์เลย" (ปุ่ม Livewire หน้าตาเป็นลิงก์) + ลิงก์บริการออกแบบใต้ปุ่มออกแบบ */
.pv-cta .eta { flex-basis: 100%; text-align: center; }

/* 2026-10-10 (มติเจ้าของ) — การ์ดเลือกทางส่งไฟล์ แทนปุ่ม/ลิงก์เดิม: ไอคอนซ้าย · หัวข้อ + คำอธิบาย · ลูกศรขวา */
.pv-path {
  display: flex; align-items: center; gap: 14px; width: 100%; padding: 16px 18px;
  border: 1.5px solid transparent; border-radius: 14px; font: inherit; text-align: left; cursor: pointer;
  transition: transform .15s ease, box-shadow .15s ease;
}
.pv-path[hidden] { display: none; }   /* display:flex ด้านบนทับ hidden ของเบราว์เซอร์ — ต้องบอกซ้ำ */
.pv-path:hover { transform: translateY(-2px); box-shadow: 0 8px 20px rgba(20, 16, 31, .12); }
.pv-path:disabled { opacity: .6; cursor: wait; transform: none; }
.pv-path-design { background: var(--sf-pink-dk, #E0127A); color: #fff; }
.pv-path-variant { display: contents; }   /* ปุ่มออกแบบมี 2 หน้าตา (แก้ไขดีไซน์ / ออกแบบออนไลน์) สลับด้วย hidden — ห่อด้วย contents ให้ลูกยังเรียงใน flex ของ .pv-path */
.pv-path-variant[hidden] { display: none; }
.pv-path-new { background: #fff; border-color: var(--sf-pink-dk, #E0127A); color: var(--sf-pink-dk, #E0127A); }   /* ออกแบบงานใหม่ — ขอบชมพู รองจากปุ่มทึบ */
.pv-path-new .pv-path-text small { color: var(--ink, #14101F); opacity: .75; }
/* 2026-10-19 — มีงานแล้ว (ปุ่มเป็น "แก้ไขดีไซน์") = ปุ่มรองขอบชมพู · ปุ่มหลักของจอคือ "เพิ่มลงตะกร้า" (.pv-cart) — 1 จอ 1 ปุ่มหลัก */
.pv-path-design:has([data-variant="edit"]:not([hidden])) { background: #fff; border-color: var(--sf-pink-dk, #E0127A); color: var(--sf-pink-dk, #E0127A); }
.pv-path-design:has([data-variant="edit"]:not([hidden])) .pv-path-text small { color: var(--ink, #14101F); opacity: .75; }
.pv-cart { display: flex; flex-direction: column; gap: 6px; width: 100%; }
.pv-cart[hidden] { display: none; }
.pv-cta .pv-cart .btn { display: flex; align-items: center; justify-content: center; gap: 8px; width: 100%; max-width: none; }
.pv-cart .btn .icon { width: 20px; height: 20px; }

/* ── ปุ่มเพิ่มลงตะกร้าแบบอนิเมชัน (components/cart-add-button · public/js/cart-add.js · 2026-10-20 · TASK-288) ──
   .ca-face = ข้อความ+ไอคอนปกติ · .ca-run = ตะกร้าที่วิ่งข้ามปุ่มตอนกด (ระยะวิ่ง --ca-dist กับเวลา --ca-ms JS ตั้งตามความกว้างปุ่มจริง)
   ใช้ transform/opacity ล้วน (วิ่งบน GPU ไม่กระตุกหน้า) · ลดการเคลื่อนไหวตามระบบผู้ใช้ท้ายบล็อก */
/* ปุ่มใหญ่ — เป็นปุ่มหลักของจอ (เจ้าของ 2026-10-20: "ทำปุ่มเพิ่มตะกร้าให้ใหญ่หน่อย") · มีเงาชมพูให้ลอยขึ้นจากพื้น กดแล้วยุบ */
.pv-cart .ca-btn {
  min-height: 68px; padding-inline: 28px; font-size: 1.22rem; font-weight: 800; letter-spacing: .01em;
  box-shadow: 0 8px 22px rgba(224, 18, 122, .32); transition: transform .15s, box-shadow .2s, background-color .2s;
}
.pv-cart .ca-btn:hover { box-shadow: 0 12px 30px rgba(224, 18, 122, .42); }
.pv-cart .ca-btn:active { transform: scale(.975); box-shadow: 0 4px 12px rgba(224, 18, 122, .3); }
.pv-cart .ca-btn .icon { width: 28px; height: 28px; }

.ca-btn { position: relative; overflow: hidden; isolation: isolate; }
.ca-face { display: inline-flex; align-items: center; justify-content: center; gap: 10px; transition: opacity .2s, transform .25s cubic-bezier(.5, 0, .75, 0); }
/* กดแล้ว: ข้อความลอยขึ้นหาย */
.ca-btn.is-adding { cursor: progress; }
.ca-btn.is-adding .ca-face { opacity: 0; transform: translateY(-12px) scale(.94); }
/* จบแล้ว: ข้อความเด้งกลับ (สปริง) */
.ca-btn.is-done .ca-face { animation: ca-face-in .5s cubic-bezier(.34, 1.56, .64, 1); }
@keyframes ca-face-in { from { opacity: 0; transform: translateY(14px) scale(.9); } to { opacity: 1; transform: none; } }
/* แสงไหลผ่านปุ่ม: ตอนตะกร้าวิ่ง (ช้า ไหลตามตะกร้า) และตอนจบ (วาบเร็ว) */
.ca-btn::before {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none; transform: translateX(-110%);
  background: linear-gradient(100deg, transparent 15%, rgba(255, 255, 255, .26) 50%, transparent 85%);
}
.ca-btn.is-adding::before { animation: ca-sheen var(--ca-ms, 1250ms) cubic-bezier(.5, .02, .35, 1) forwards; }
.ca-btn.is-done::before { animation: ca-sheen .75s ease-out forwards; }
@keyframes ca-sheen { to { transform: translateX(110%); } }

/* ตะกร้าที่วิ่งข้ามปุ่ม (.ca-cart) — ระยะวิ่ง --ca-dist กับเวลา --ca-ms JS ตั้งตามความกว้างปุ่มจริง · เอียงตามแรงเร่ง/แรงเบรกเล็กน้อย */
.ca-run { position: absolute; inset: 0; opacity: 0; pointer-events: none; }
.ca-btn.is-adding .ca-run { opacity: 1; }
.ca-cart { position: absolute; top: 50%; left: 0; width: 48px; height: 48px; color: #fff; transform: translate(-100px, -50%); will-change: transform; }
.ca-cart svg { display: block; width: 100%; height: 100%; overflow: visible; filter: drop-shadow(0 3px 5px rgba(90, 0, 45, .35)); animation: ca-bob .26s ease-in-out infinite alternate; }
.ca-btn.is-adding .ca-cart { animation: ca-drive var(--ca-ms, 1250ms) cubic-bezier(.5, .02, .35, 1) forwards; }
@keyframes ca-drive {
  0%   { transform: translate(-100px, -50%) rotate(-7deg); }
  22%  { transform: translate(calc(var(--ca-dist, 320px) * .18 - 60px), -50%) rotate(3deg); }
  70%  { transform: translate(calc(var(--ca-dist, 320px) * .72), -50%) rotate(-1deg); }
  100% { transform: translate(var(--ca-dist, 320px), -50%) rotate(2deg); }
}
@keyframes ca-bob { from { transform: translateY(1.5px); } to { transform: translateY(-2px); } }   /* ตะกร้าสะเทือนตามจังหวะวิ่ง */
/* เส้นความเร็วด้านหลัง: 3 เส้นยาวไม่เท่ากัน ยืดหดสลับกัน */
.ca-trail {
  position: absolute; right: 74%; height: 3px; border-radius: 3px; transform-origin: right center;
  background: linear-gradient(90deg, rgba(255, 255, 255, 0), rgba(255, 255, 255, .9));
  animation: ca-trail .3s ease-in-out infinite alternate;
}
.ca-trail:nth-of-type(1) { top: 36%; width: 46px; }
.ca-trail:nth-of-type(2) { top: 54%; width: 70px; animation-delay: .08s; }
.ca-trail:nth-of-type(3) { top: 72%; width: 34px; animation-delay: .16s; }
@keyframes ca-trail { from { transform: scaleX(.4); opacity: .4; } to { transform: scaleX(1); opacity: 1; } }
/* จุด 3 จุดเหนือตะกร้า (ของที่ตกลงตะกร้า) กระโดดตามกันทีละจุด */
.ca-dots circle { fill: currentColor; stroke: none; transform-box: fill-box; transform-origin: center; animation: ca-hop .56s ease-in-out infinite; }
.ca-dots circle:nth-child(2) { animation-delay: .12s; }
.ca-dots circle:nth-child(3) { animation-delay: .24s; }
@keyframes ca-hop {
  0%, 100% { transform: translateY(0) scale(1); opacity: .55; }
  35%      { transform: translateY(-2.4px) scale(1.3); opacity: 1; }
  65%      { transform: translateY(1.2px) scale(.8); opacity: .7; }
}

/* ไอคอนที่เด้งกลางจอ (สปริง) แล้วลอยเป็นเส้นโค้งเข้าตะกร้าขวาบน (JS สร้าง/ลบเอง · Web Animations API) — วงกลมไล่สีชมพู + ป้าย +N สีเขียวนีออนตามแบรนด์ */
.ca-fly {
  position: fixed; z-index: 1500; left: 50%; top: 50%; width: 104px; height: 104px; margin: -52px 0 0 -52px;
  display: grid; place-items: center; border-radius: 50%; pointer-events: none; color: #fff; will-change: transform;
  background: radial-gradient(circle at 30% 25%, #FF7DBB 0%, #FF2E93 40%, #E0127A 100%);
  box-shadow: 0 18px 44px rgba(224, 18, 122, .45), 0 0 0 6px rgba(255, 255, 255, .92), 0 0 0 7px rgba(224, 18, 122, .16);
}
.ca-fly svg { width: 52px; height: 52px; filter: drop-shadow(0 2px 3px rgba(90, 0, 45, .3)); }
.ca-fly b {
  position: absolute; top: -8px; right: -12px; min-width: 40px; height: 30px; padding: 0 10px; border-radius: 15px;
  display: grid; place-items: center; font-size: 16px; font-weight: 800; line-height: 1;
  background: var(--sf-lime, #D4FF1A); color: var(--sf-ink, #14101F); box-shadow: 0 5px 12px rgba(20, 16, 31, .28);
}
/* ประกายที่หลุดตามทางลอย + วงคลื่น/ประกายกระจายตอนถึงตะกร้า */
.ca-spark { position: fixed; z-index: 1499; margin: -5px 0 0 -5px; border-radius: 50%; pointer-events: none; animation: ca-spark .6s ease-out forwards; }
@keyframes ca-spark { from { transform: scale(1); opacity: .9; } to { transform: scale(0); opacity: 0; } }
.ca-ring { position: fixed; z-index: 1499; width: 46px; height: 46px; margin: -23px 0 0 -23px; border-radius: 50%; pointer-events: none; border: 3px solid var(--sf-pink-dk, #E0127A); animation: ca-ring .7s ease-out forwards; }
@keyframes ca-ring { from { transform: scale(.4); opacity: .9; } to { transform: scale(2.7); opacity: 0; } }
.ca-burst { position: fixed; z-index: 1499; margin: -4px 0 0 -4px; border-radius: 50%; pointer-events: none; animation: ca-burst .65s cubic-bezier(.2, .7, .3, 1) forwards; }
@keyframes ca-burst { from { transform: translate(0, 0) scale(1); opacity: 1; } to { transform: translate(var(--bx, 0), var(--by, 0)) scale(.2); opacity: 0; } }
/* ถึงแล้ว: ไอคอนตะกร้าเด้ง + เลขแดงเด้งแล้วค่อยนิ่ง */
.sf-cart.ca-bump { animation: ca-bump .6s cubic-bezier(.34, 1.56, .64, 1); }
@keyframes ca-bump { 0% { transform: scale(1); } 30% { transform: scale(1.34) rotate(-8deg); } 60% { transform: scale(.94) rotate(4deg); } 100% { transform: scale(1) rotate(0); } }
.sf-cart.ca-bump .sf-cart-badge { animation: ca-badge .6s cubic-bezier(.34, 1.56, .64, 1); }
@keyframes ca-badge { 0% { transform: scale(.3); } 55% { transform: scale(1.55); } 100% { transform: scale(1); } }
/* ข้อความสถานะสำหรับโปรแกรมอ่านจอเท่านั้น (ไม่โชว์บนจอ) */
.ca-sr { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
@media (prefers-reduced-motion: reduce) {
  .ca-btn.is-adding .ca-cart { animation: none; transform: translate(calc(var(--ca-dist, 320px) / 2), -50%); }
  .ca-cart svg, .ca-trail, .ca-dots circle { animation: none; }
  .ca-btn.is-adding::before, .ca-btn.is-done::before, .ca-btn.is-done .ca-face { animation: none; }
  .sf-cart.ca-bump, .sf-cart.ca-bump .sf-cart-badge { animation: none; }
}
.pv-path-upload, .pv-path-form { background: #fff; border-color: var(--sf-violet, #5B18F2); color: var(--sf-violet, #5B18F2); }
/* 2026-10-31 — "ส่งคำขอผ่านแบบฟอร์ม" (ขอใบเสนอราคา) เป็นลิงก์ หน้าตาเดียวกับการ์ดรองด้านบน */
.pv-path-form, .pv-path-form:hover { text-decoration: none; color: var(--sf-violet, #5B18F2); }
/* 2026-10-19 — "สั่งผ่าน LINE" (ทางสำรองอัปไฟล์ปิดอยู่ + ตัวเลือกไม่มีแม่แบบ) · เขียวเข้มกว่าสี LINE (#06C755) เพราะตัวขาวบนสีทางการได้ contrast แค่ 2.3:1
   #037A34 = 5.5:1 ผ่าน WCAG AA */
.pv-path-line { background: #037A34; color: #fff; text-decoration: none; }
.pv-path-line:hover { color: #fff; }
.pv-path-icon { flex: none; width: 24px; height: 24px; }
.pv-path-arrow { flex: none; width: 18px; height: 18px; margin-left: auto; }
.pv-path-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.pv-path-text b { font-size: 17px; font-weight: 800; }
.pv-path-text small { font-size: 14px; opacity: .9; }
.pv-path-upload .pv-path-text small, .pv-path-form .pv-path-text small { color: var(--ink, #14101F); opacity: .75; }

/* ── กล่องถามก่อนเปลี่ยนทางส่งงาน (ออกแบบออนไลน์ ⇄ อัปไฟล์เอง · EPIC-011 · ProductConfigurator::$pendingMode) ── */
.pv-switch {
  position: fixed; inset: 0; z-index: 1000;
  display: flex; align-items: center; justify-content: center; padding: 16px;
  background: rgba(20, 16, 31, .55);
  -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px);
  animation: pv-switch-fade .15s ease-out;
}
.pv-switch-box {
  width: min(440px, 100%); padding: 28px 28px 24px;
  background: #fff; border-radius: 20px; box-shadow: 0 24px 60px rgba(20, 16, 31, .35);
  animation: pv-switch-pop .2s cubic-bezier(.2, .9, .3, 1.2);
}
.pv-switch-box h3 { margin: 0 0 10px; font-size: 1.25rem; line-height: 1.3; color: var(--sf-ink, #14101F); }
.pv-switch-box p { margin: 0; line-height: 1.6; color: var(--ink-soft, #4A4658); }
.pv-switch-actions { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 10px; margin-top: 24px; }
@media (max-width: 480px) {
  .pv-switch-actions { flex-direction: column-reverse; }
  .pv-switch-actions .btn { width: 100%; }
}
@keyframes pv-switch-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes pv-switch-pop { from { opacity: 0; transform: translateY(12px) scale(.96); } to { opacity: 1; transform: none; } }

/* ── ขั้น 3 "ดูตัวอย่าง" (products/review · 2026-10-09) — พรีวิวซ้าย · รายละเอียด/ราคา/ปุ่มขวา ── */
.rv-grid { display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr); gap: 28px; align-items: start; margin-top: 8px; }
.rv-preview { display: flex; flex-direction: column; align-items: center; gap: 12px; }
.rv-preview > .design-preview, .rv-preview > .rv-files { width: 100%; }
.rv-preview .design-preview { margin: 0; }
.rv-files { padding: 16px; background: #f4f4f6; border-radius: 14px; }
.rv-edit {
  display: inline-flex; align-items: center; gap: 6px; padding: 8px 14px;
  border: 0; border-radius: 999px; background: #fff; color: var(--sf-ink, #14101F);
  font: inherit; font-size: .9rem; font-weight: 600; text-decoration: none; cursor: pointer;
  box-shadow: 0 4px 14px rgba(20, 16, 31, .18);
}
.rv-edit svg { width: 16px; height: 16px; }
.rv-edit:hover { background: var(--sf-lime, #D4FF1A); }
.rv-edit[disabled] { opacity: .55; cursor: wait; }
.rv-title { margin: 0 0 12px; font-size: 1.4rem; }
.rv-qty-block { margin: 18px 0; }
.rv-price { display: flex; justify-content: space-between; align-items: baseline; padding-top: 14px; border-top: 1px solid var(--line, #E4E2EB); }
.rv-price b { font-size: 1.6rem; color: var(--sf-pink-dk, #E0127A); }
.rv-price small { font-size: .9rem; color: var(--ink-mute, #7C7889); }
.rv-actions { display: flex; flex-wrap: wrap; gap: 10px; margin: 18px 0 10px; }
.rv-incart { margin: 0 0 8px; color: #1F8A4C; font-weight: 600; }
@media (max-width: 820px) {
  .rv-grid { grid-template-columns: 1fr; }
  .rv-actions .btn { flex: 1 1 100%; }
}

/* ตะกร้า (cart/show) — ย้ายไป css/cart.css ทั้งหมด (2026-10-24) */

/* ขั้นย่อยของ "สั่งซื้อ" ในแถบขั้นตอน (ตะกร้า › ข้อมูลจัดส่ง › ชำระเงิน) */
.osteps-sub b { color: var(--sf-violet, #5B18F2); }

/* หน้าดูตัวอย่าง รอบ 2 (2026-10-09 เจ้าของ: รูปพอดีจอ อย่าล้น · หัวข้ออยู่ขวา)
   ★ ความสูงรูป = จอ − แถบขั้นตอนติดจอ (~170px) — ไม่ต้องเลื่อนหาปุ่มแก้แบบ · คอลัมน์ซ้ายติดจอตอนเลื่อนฝั่งขวา */
.rv-grid { margin-top: 24px; }
.rv-preview { position: sticky; top: 110px; }
.rv-preview .design-preview { display: flex; justify-content: center; width: auto; max-width: 100%; }
.rv-preview .design-preview img { width: auto; max-width: 100%; max-height: calc(100vh - 230px); object-fit: contain; }
.rv-detail .crumb { margin-top: 0; }
.rv-heading { margin: 6px 0 4px; font-size: 1.6rem; }
.rv-detail .prep-hero-sub { margin: 0 0 16px; }
.rv-detail .rv-title { margin-top: 18px; padding-top: 16px; border-top: 1px solid var(--line, #E4E2EB); font-size: 1.15rem; }
.rv-price-error { color: #C0262D; }
@media (max-width: 820px) {
  .rv-preview { position: static; }
  .rv-preview .design-preview img { max-height: 60vh; }
}


/* ช่องจำนวนแบบเล็ก "− 1 +" ในหน้าดูตัวอย่าง (ตะกร้ามีชุดของตัวเองใน cart.css · 2026-10-24 แยกออก)
   ★ สไตล์ช่องตัวเลขของ .qty-stepper ผูกกับ .qty-row (หน้าเลือกสินค้า) — ที่อื่นต้องตั้งเอง */
.rv-qty-block .qty-stepper { display: inline-flex; width: auto; }
.rv-qty-block .qty-stepper button { width: 34px; font-size: 18px; }
.rv-qty-block .qty-row .qty-stepper input[type=number] {
  flex: none; width: 56px; padding: 7px 4px; border: 0; border-inline: 1.5px solid var(--line); border-radius: 0;
  font: inherit; font-size: 16px; text-align: center; -moz-appearance: textfield; appearance: textfield;
}

/* หน้าดูตัวอย่าง: หัวข้อถูกซ่อน (เจ้าของ 2026-10-09) → ชื่อสินค้าขึ้นบนสุดของฝั่งขวา ไม่ต้องมีเส้นคั่น/ระยะห่างเหนือชื่อ */
.rv-detail .rv-title { margin-top: 0; padding-top: 0; border-top: 0; }

/* ปุ่มตกลงสีแดงในกล่องถามยืนยันกลาง (ใช้กับการลบ — data-confirm-danger · public/js/confirm-modal.js) */



/* ── หน้าตา modal ยืนยันให้เหมือนหลังบ้าน (Filament · 2026-10-09 เจ้าของ: "คนละตัวกับ modal กลางหลังบ้าน")
   โครงเดียวกับ Filament: จัดกึ่งกลาง · ไอคอนในวงกลมสีอ่อน · หัวข้อ · คำอธิบาย · ปุ่ม 2 ปุ่มเท่ากันเรียงข้างกัน
   ★ ใช้ร่วมกัน 2 ที่: modal กลาง (#pp-confirm · confirm-modal.js) + กล่องเปลี่ยนทางส่งงานหน้าสินค้า (product-configurator) ── */
.pv-switch-box { width: min(420px, 100%); padding: 24px; border-radius: 12px; text-align: center; }
.pv-switch-icon {
  display: grid; place-items: center; width: 48px; height: 48px; margin: 0 auto 14px; border-radius: 50%;
  background: #FFE3F1; color: var(--sf-pink-dk, #E0127A);   /* ชมพูธีมหน้าร้าน (2026-10-12 เจ้าของ: ต้องสีเดียวกับธีม ไม่ใช่ม่วงหลังบ้าน) */
}
.pv-switch-icon svg { width: 24px; height: 24px; }
.pv-switch-icon.is-danger { background: #FEE2E2; color: #DC2626; }   /* แดง = ลบ (Filament danger) */
.pv-switch-box h3 { margin: 0 0 8px; font-size: 1rem; font-weight: 600; }
.pv-switch-box p { font-size: .875rem; color: #6B7280; }
.pv-switch-actions { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-top: 24px; }
.pv-switch-actions .btn {
  display: flex; justify-content: center; align-items: center; width: 100%; padding: 9px 12px;
  border-radius: 8px; font-size: .875rem; font-weight: 600; line-height: 1.4; animation: none;
}
.pv-switch-actions .btn-ghost { background: #fff; color: #111827; border: 1px solid #D1D5DB; }
.pv-switch-actions .btn-ghost:hover { background: #F9FAFB; }
.pv-switch-actions .btn-pink { background: var(--sf-pink-dk, #E0127A); border-color: var(--sf-pink-dk, #E0127A); color: #fff; }   /* ปุ่มชมพูธีมหน้าร้าน (เดิมเป็นม่วงหลังบ้าน) */
.pv-switch-actions .btn-pink:hover { background: #C20E69; border-color: #C20E69; }
.pv-switch-actions .btn.is-danger { background: #DC2626; border-color: #DC2626; }
/* กล่องแจ้งเตือนปุ่มเดียว (printpaoAlert ซ่อนปุ่มยกเลิก) — ปุ่มตกลงเต็มแถว ไม่ค้างครึ่งซ้าย */
.pv-switch-actions [hidden] + .btn { grid-column: 1 / -1; }
.pv-switch-actions .btn.is-danger:hover { background: #B91C1C; border-color: #B91C1C; }

/* ตัวเลขที่ JS อัปเดตอยู่ใน <span> ภายใน <b> ของ .price-total (ตะกร้า · หน้าดูตัวอย่าง) — ต้องสืบทอดขนาด/สีจาก <b>
   ไม่ใช่โดน `.price-total span` (15px · ใช้กับป้าย "รวม" ฝั่งซ้าย) ทับจนตัวเลขเล็กกว่าคำว่า "บาท" (บั๊กที่เจอ 2026-10-09) */
.price-total b span { font-size: inherit; font-weight: inherit; color: inherit; }

/* หน้าดูตัวอย่าง: กดรูปพรีวิวแล้วขยายเต็มจอ (gallery.js ตัวกลาง) — กรอบเดียวกับรูปเดิม แค่ให้กดได้ + มีป้าย "ดูรูปเต็ม" */
.rv-zoomable { position: relative; display: flex; justify-content: center; cursor: zoom-in; }
/* TASK-244 — ป้ายระหว่างสร้างรูปพรีวิวในคิว (components/design-preview) · กินที่พอๆ กับรูป ไม่ให้หน้ากระโดด */
.design-preview-wait { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px; min-height: 360px; flex: 0 1 auto; width: min(440px, calc(100vw - 64px)); padding: 16px; color: var(--ink-soft, #4A4658); font-size: .92rem; text-align: center; cursor: default; }
/* TASK-249 — ป้ายกำกับ + คำเตือนใต้รูปพรีวิว (components/design-preview-notes) */
.design-preview-notes { width: 100%; max-width: 620px; margin: 0 auto 10px; text-align: center; }
.design-preview-label { margin: 6px 0 0; font-size: .82rem; color: var(--ink-soft, #4A4658); }
.design-preview-warning { margin: 8px 0 0; padding: 8px 12px; border-radius: 10px; background: #FEF3C7; color: #92400E; font-size: .88rem; line-height: 1.45; text-align: left; }
/* TASK-246 — ปุ่มที่รอผลตรวจงานออกแบบ (design-preview.js) · ข้อความสถานะใต้ปุ่ม */
[data-needs-check].is-checking { opacity: .55; pointer-events: none; cursor: progress; }
.rv-check-msg { margin-top: 8px; }
.rv-check-msg.is-error { color: #b91c1c; font-weight: 600; }
/* TASK-245 — มีรูปเดิมโชว์อยู่ (บันทึกซ้ำ/สร้างไม่สำเร็จ) → ป้ายเล็กลอยมุมล่างของรูปแทนกล่องใหญ่ */
.design-preview-wait.is-badge { position: absolute; left: 50%; bottom: 12px; transform: translateX(-50%); width: auto; min-height: 0; padding: 6px 12px; border-radius: 999px; background: rgba(17, 24, 39, .78); color: #fff; font-size: .82rem; flex-direction: row; white-space: nowrap; }
.design-preview-wait.is-badge .btn { padding: 2px 10px; font-size: .8rem; }
.rv-zoomable:hover .gal-zoom, .rv-zoomable:focus-visible .gal-zoom { opacity: 1; }
@media (hover: none) { .rv-zoomable .gal-zoom { opacity: 1; } }   /* มือถือไม่มี hover — โชว์ป้ายไว้เลย */

/* รูปพรีวิวงานออกแบบ (review · ตะกร้า) — ห้ามมุมมน ห้ามตัดขอบ: เห็นทั้งใบตามที่จะพิมพ์ (มติเจ้าของ 2026-10-09) */
.design-preview, .design-preview img, .rv-zoomable { border-radius: 0; }


/* หน้าดูตัวอย่าง: ปุ่ม "ดูตะกร้า" มีไอคอนตะกร้านำหน้า (เหมือนหัวเว็บ) · <a> ที่ปิดชั่วคราวระหว่างซิงก์จำนวนเข้าตะกร้า */
.rv-actions .btn svg { width: 20px; height: 20px; flex: none; }
.rv-actions a.btn[aria-disabled] { opacity: .5; pointer-events: none; }

/* หน้าดูตัวอย่าง รอบ 3 (2026-10-15 เจ้าของส่งแบบมา) — พรีวิวซ้ายบนพื้นเทา · ขวาเป็นการ์ดขาว แถวสเปกมีไอคอน · กล่องเตือนตรวจสอบใต้ปุ่ม */
.rv-preview .design-preview { width: 100%; padding: 28px; background: #EEEDF2; border-radius: 16px; }
.rv-preview .rv-zoomable { border-radius: 0; }
.rv-detail { padding: 24px 22px; background: #fff; border: 1px solid var(--line, #E4E2EB); border-radius: 16px; box-shadow: 0 6px 24px rgba(20, 16, 31, .05); }
.rv-detail .rv-title { margin: 0 0 6px; font-size: 1.9rem; }
.rv-rows { margin: 0; }
.rv-row { display: grid; grid-template-columns: 26px minmax(90px, 140px) minmax(0, 1fr); gap: 14px; align-items: start; padding: 16px 0; border-bottom: 1px solid var(--line, #E4E2EB); }
.rv-row > .icon { width: 22px; height: 22px; margin-top: 1px; color: var(--ink-soft, #4A4658); }
.rv-row dt { color: var(--ink-mute, #7C7889); font-size: .95rem; }
.rv-row dt small { display: block; margin-top: 4px; font-size: .8rem; line-height: 1.5; }
.rv-row dd { margin: 0; font-weight: 600; overflow-wrap: anywhere; }
/* จำนวน/ราคา: ชิดขวา และให้ป้ายซ้ายกินที่ข้อความใต้หัวข้อได้ยาว */
.rv-row:has(.rv-row-end) { grid-template-columns: 26px minmax(0, 1fr) auto; }
.rv-row-end { text-align: right; white-space: nowrap; }
.rv-row-price { font-size: 1.6rem; line-height: 1.1; color: var(--sf-pink-dk, #E0127A); }
.rv-row-price small { font-size: .85rem; font-weight: 500; color: var(--ink-soft, #4A4658); }
.rv-detail .rv-actions { margin-top: 22px; }
.rv-notice { display: flex; align-items: center; gap: 10px; margin: 16px 0 0; padding: 14px 16px; border-radius: 12px; background: var(--purple-lt, #F1ECFF); color: var(--ink-soft, #4A4658); font-size: .92rem; }
.rv-notice .icon { width: 22px; height: 22px; flex: none; color: var(--sf-violet, #5B18F2); }
/* หน้าดูตัวอย่าง: รูปย่อทุกหน้าของงานออกแบบหลายหน้า (2026-10-15) — แถวเดียวเลื่อนซ้าย-ขวาได้ · ใบที่ดูอยู่ขอบม่วง (gallery.js ใส่ .on) */
.rv-preview .design-preview { flex-direction: column; align-items: center; }
.rv-pages { display: flex; gap: 10px; width: 100%; margin-top: 16px; padding: 2px 2px 6px; overflow-x: auto; scrollbar-width: thin; }
.rv-page {
  display: flex; flex-direction: column; align-items: center; gap: 4px; flex: none; width: 76px; padding: 6px;
  border: 2px solid transparent; border-radius: 10px; background: #fff; font: inherit; font-size: .75rem; color: var(--ink-soft, #4A4658); cursor: pointer;
}
/* ★ selector ยาวให้ชนะ .rv-preview .design-preview img (ความสูง/เงาของรูปหลัก) */
.rv-preview .design-preview .rv-page img { width: 100%; height: 72px; max-height: none; object-fit: contain; box-shadow: none; }
.rv-page:hover { border-color: var(--purple-br, #D9CCFF); }
.rv-page.on { border-color: var(--sf-violet, #5B18F2); color: var(--sf-violet, #5B18F2); font-weight: 600; }

/* popup ตรวจสอบคำสั่งซื้อ (orders/checkout #co-review · 2026-10-15) — อ่านทวนอย่างเดียว · พื้นหลัง/อนิเมชันจาก .pv-switch
   ★ ตัวกล่องเลื่อนในตัวเอง (หัว/ปุ่มอยู่กับที่) — เนื้อหายาวบนมือถือไม่ดันปุ่มยืนยันหลุดจอ */
.co-review { align-items: center; }
.co-review-box {
  display: flex; flex-direction: column; width: min(760px, 100%); max-height: calc(100dvh - 32px);
  background: #fff; border-radius: 20px; box-shadow: 0 24px 60px rgba(20, 16, 31, .35); overflow: hidden;
  animation: pv-switch-pop .2s cubic-bezier(.2, .9, .3, 1.2);
}
.co-review-head { display: flex; align-items: flex-start; gap: 12px; padding: 20px 22px 14px; border-bottom: 1px solid var(--line, #E4E2EB); }
.co-review-head > .icon { width: 30px; height: 30px; flex: none; color: var(--sf-violet, #5B18F2); }
.co-review-head h2 { margin: 0; font-size: 1.3rem; }
.co-review-head p { margin: 2px 0 0; font-size: .88rem; color: var(--ink-mute, #7C7889); }
.co-review-x { margin-left: auto; padding: 6px; border: 0; border-radius: 50%; background: none; color: var(--ink-mute, #7C7889); cursor: pointer; }
.co-review-x:hover { background: #F1F0F4; }
.co-review-x .icon { width: 20px; height: 20px; display: block; }
.co-review-body { flex: 1; overflow-y: auto; padding: 16px 22px; }
.co-review-item { display: grid; grid-template-columns: 120px minmax(0, 1fr) auto; gap: 16px; align-items: start; padding: 14px; border: 1px solid var(--line, #E4E2EB); border-radius: 14px; }
.co-review-thumb { display: grid; place-items: center; align-content: center; gap: 4px; aspect-ratio: 1; padding: 8px; background: #EEEDF2; border-radius: 10px; color: var(--ink-soft, #4A4658); }
.co-review-thumb img { max-width: 100%; max-height: 104px; object-fit: contain; }
.co-review-thumb .icon { width: 28px; height: 28px; }
.co-review-info h3 { margin: 0 0 2px; font-size: 1.1rem; }
.co-review-info .rv-row { padding: 7px 0; border-bottom: 0; font-size: .92rem; }
.co-review-info .rv-row > .icon { width: 18px; height: 18px; }
.co-review-price { font-size: 1.3rem; color: var(--sf-pink-dk, #E0127A); white-space: nowrap; }
.co-review-warn { align-items: flex-start; margin-top: 12px; }
.co-review-warn b { display: block; color: var(--sf-violet, #5B18F2); }
.co-review-warn small { display: block; margin-top: 2px; font-size: .82rem; }
.co-review-ship { margin-top: 14px; padding: 14px 16px; border: 1px solid var(--line, #E4E2EB); border-radius: 14px; }
.co-review-ship h3 { display: flex; align-items: center; gap: 8px; margin: 0 0 10px; font-size: 1.05rem; }
.co-review-ship h3 .icon { width: 22px; height: 22px; color: var(--sf-violet, #5B18F2); }
.co-review-cols { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.co-review-cols > div, .co-review-tax { display: flex; flex-direction: column; gap: 3px; font-size: .92rem; overflow-wrap: anywhere; }
.co-review-tax { margin-top: 12px; padding-top: 10px; border-top: 1px dashed var(--line, #E4E2EB); }
.co-review-label { font-size: .8rem; color: var(--ink-mute, #7C7889); }
.co-review-sum.pricebox { margin-top: 14px; padding: 14px 16px; background: #FAFAFC; border: 1px solid var(--line, #E4E2EB); border-radius: 14px; }
.co-review-sum .price-total b { font-size: 26px; }
.co-review-foot { display: flex; justify-content: flex-end; gap: 10px; padding: 14px 22px; border-top: 1px solid var(--line, #E4E2EB); background: #FAFAFC; }
.co-review-foot .btn { display: inline-flex; align-items: center; justify-content: center; gap: 8px; }
.co-review-foot .icon { width: 20px; height: 20px; }
@media (max-width: 600px) {
  .co-review { padding: 0; align-items: flex-end; }
  .co-review-box { max-height: 94dvh; border-radius: 20px 20px 0 0; }
  .co-review-item { grid-template-columns: 76px minmax(0, 1fr); }
  .co-review-price { grid-column: 2; }
  .co-review-cols { grid-template-columns: 1fr; }
  .co-review-foot { flex-direction: column-reverse; }
  .co-review-foot .btn { width: 100%; }
}

/* หน้าชำระเงิน/หน้าออเดอร์ (.pay-*) — ย้ายไป css/order.css ทั้งหมด (2026-10-24) · .oi* ด้านล่างยังเป็นของกลางหลายหน้า */
/* ── แถวสรุปสินค้า 1 รายการ (components/order-item) — ตัวกลางเดียวของหน้าสรุปทุกหน้า (2026-10-20) ──
   เดิม .pay-item* ใช้แค่การ์ด "สรุปรายการสั่งซื้อ" ในหน้าชำระเงิน · ตอนนี้เป็นของกลาง: เตรียมไฟล์ · กรอกข้อมูล · หน้าออเดอร์
   ต่อกันกี่รายการก็ได้ (เส้นคั่นบางๆ ระหว่างรายการ · ไม่มีเส้นล่างสุด — ตัวถัดไปในการ์ดเว้นระยะเอง) */
.oi { display: grid; grid-template-columns: 76px minmax(0, 1fr) auto; gap: 12px; align-items: center; }
.oi + .oi { margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--line, #E4E2EB); }
.oi:not(:has(.oi-price)) { grid-template-columns: 76px minmax(0, 1fr); }   /* ไม่มีราคา (หน้าเตรียมไฟล์) = ไม่กันคอลัมน์ขวาไว้เปล่า */
.oi-thumb { display: grid; place-items: center; aspect-ratio: 1; padding: 6px; border-radius: 10px; background: #EEEDF2; color: var(--ink-soft, #4A4658); }
.oi-thumb img { max-width: 100%; max-height: 64px; object-fit: contain; }
.oi-thumb .icon { width: 24px; height: 24px; }
.oi-info { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.oi-info > b { overflow-wrap: anywhere; }
.oi-info small { color: var(--ink-mute, #7C7889); font-size: .82rem; overflow-wrap: anywhere; }
.oi-info small b { color: var(--ink-soft, #4A4658); }
.oi-price { white-space: nowrap; }
.oi-info small.oi-eta { display: inline-flex; align-items: center; gap: 5px; margin-top: 2px; }
.oi-eta .icon { width: 14px; height: 14px; flex: none; }
/* บรรทัดเสริมใต้แถวสินค้า (การจัดส่ง · ไฟล์งาน · ระยะเวลาผลิต · แก้รายละเอียด) */
.oi-extra { margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--line, #E4E2EB); }
.oi-extra .sum-specs > div { padding: 6px 0; font-size: 14px; }
.oi-extra .sum-foot { margin-top: 10px; }
@media (max-width: 420px) {
  .oi { grid-template-columns: 64px minmax(0, 1fr) auto; gap: 10px; }
  .oi:not(:has(.oi-price)) { grid-template-columns: 64px minmax(0, 1fr); }
  .oi-thumb img { max-height: 52px; }
}

@media (max-width: 600px) {
  .rv-preview .design-preview { padding: 14px; }
  .rv-detail { padding: 18px 16px; }
  .rv-detail .rv-title { font-size: 1.5rem; }
  .rv-row { grid-template-columns: 22px minmax(0, 1fr) auto; gap: 10px; }
  .rv-row-price { font-size: 1.3rem; }
}

/* ───────── สมุดที่อยู่จัดส่ง (TASK-250) ─────────
   ★★ ห้ามตั้งชื่อคลาสขึ้นต้นด้วย "ad-" (ย่อจาก address) — ตัวบล็อกโฆษณา (AdBlock/uBlock ใช้ฟิลเตอร์ .ad-card · .ad-list · .ad-badge ฯลฯ)
      ซ่อนการ์ดที่อยู่ทั้งหมดในเบราว์เซอร์ของลูกค้า "โชว์แล้วหายไปเอง" (บั๊กจริง 2026-10-12) → ใช้ abook-* แทน ★★
   การ์ดที่อยู่ใช้ 2 ที่: หน้า /account/addresses (.abook-card + ปุ่ม) และตัวเลือกในหน้า checkout (.abook-card.abook-pick + วงกลมเลือก)
   เนื้อในการ์ด = component address-summary (.abook-body) ตัวเดียวกัน */
.abook-list { display: grid; gap: 12px; }
.abook-card {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 16px;
  padding: 16px 18px;
  background: var(--surface);
  border: 1.5px solid var(--line);
  border-radius: var(--r-md);
}
.abook-card.is-default { border-color: var(--purple-br); background: var(--purple-lt); }
.abook-body { min-width: 0; flex: 1; }
.abook-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.abook-label { font-size: 16px; color: var(--ink); }
.abook-badge {
  padding: 2px 10px; border-radius: 999px;
  font-size: 12.5px; font-weight: 600;
  color: var(--purple); background: var(--purple-lt); border: 1px solid var(--purple-br);
}
.abook-card.is-default .abook-badge { background: #fff; }
.abook-who { margin: 6px 0 0; font-size: 14.5px; color: var(--ink-soft); }
.abook-text { margin: 4px 0 0; font-size: 14.5px; line-height: 1.7; color: var(--ink-soft); overflow-wrap: anywhere; }

.abook-actions { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 8px; flex: none; }
.abook-actions .btn { padding: 7px 14px; font-size: 14px; }
.abook-actions form { margin: 0; }
.abook-del { color: var(--danger); }
.abook-add { margin-top: 14px; display: inline-flex; align-items: center; gap: 6px; }
.abook-add .icon { width: 18px; height: 18px; }
.abook-form-actions { display: flex; justify-content: flex-end; flex-wrap: wrap; gap: 10px; margin-top: 18px; }

.abook-empty { text-align: center; padding-block: 36px; }
.abook-empty-icon { width: 48px; height: 48px; color: var(--purple); }
/* หัวข้อ empty state เป็น <p> ไม่ใช่ <h2> — .prep-block > h2 จะใส่ขีดเหลือง+เส้นใต้ทับ (บั๊กที่เจอ 2026-10-12) */
.abook-empty .abook-empty-title { margin: 12px 0 4px; font-size: 19px; font-weight: 700; color: var(--ink); }
.abook-empty p { margin: 0 0 18px; color: var(--ink-soft); }

/* หน้า checkout — เลือกที่อยู่จากสมุด (วงกลมเลือก + การ์ด + ลิงก์แก้ไข) */
.abook-note {
  margin: 0 0 14px; padding: 12px 14px; border-radius: var(--r-sm);
  font-size: 14.5px; color: var(--ink-soft); background: var(--purple-lt); border: 1px solid var(--purple-br);
}
.abook-pick { cursor: pointer; align-items: center; transition: border-color .15s, background .15s; }
.abook-pick > input { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
.abook-pick > .co-pick-dot { flex: none; }
.abook-pick:has(> input:checked) { border-color: var(--purple); background: var(--purple-lt); }
.abook-pick:has(> input:checked) > .co-pick-dot { border-color: var(--purple); }
.abook-pick:has(> input:checked) > .co-pick-dot::after { transform: scale(1); }
.abook-pick > input:focus-visible + .co-pick-dot { outline: 2px solid var(--yellow); outline-offset: 2px; }
.abook-pick .abook-edit { flex: none; font-size: 14px; color: var(--purple); text-decoration: underline; }
.abook-other { align-items: center; font-weight: 600; color: var(--ink-soft); }

/* หน้า checkout — ช่องทางการชำระเงิน (2026-10-28) · การ์ด/วงกลมเลือกใช้ .abook-pick ข้างบน
   ★ ตัวเลือกที่ยังไม่เปิด (.is-disabled) = สีเทา กดไม่ได้ */
.pay-list { gap: 10px; }
.pay-opt { justify-content: flex-start; gap: 12px; padding: 14px 16px; }
.pay-icon { flex: none; width: 22px; height: 22px; color: var(--purple); }
.pay-logo { flex: none; display: block; }   /* โลโก้สีของแบรนด์ (Thai QR) — กว้างเท่า .pay-icon ให้ตัวหนังสือตรงแนวกัน */
.pay-text { flex: 1; min-width: 0; display: grid; gap: 2px; }
.pay-text b { font-size: 15px; color: var(--ink); }
.pay-text small { font-size: 13px; color: var(--ink-soft); }
.pay-brands { flex: none; display: flex; align-items: center; gap: 6px; }
.pay-brands img { display: block; }
.pay-opt.is-disabled { cursor: not-allowed; background: var(--bg); opacity: .55; filter: grayscale(1); }
.pay-list.is-invalid .pay-opt:not(.is-disabled) { border-color: var(--danger); }
.pay-error { margin: 8px 0 0; font-size: 14px; color: var(--danger); }
/* จอมือถือ — ย่อโลโก้บัตร ให้ชื่อ "บัตรเครดิต / เดบิต" อยู่บรรทัดเดียว */
@media (max-width: 480px) {
  .pay-opt { gap: 10px; padding: 14px; }
  .pay-text b { white-space: nowrap; }
  .pay-brands { gap: 4px; }
  .pay-visa { width: 30px; height: 10px; }
  .pay-mc { width: 24px; height: 15px; }
}
#addr-new { margin-top: 14px; }
.abook-save { margin-top: 14px; }
@media (max-width: 720px) {
  .abook-card { flex-direction: column; }
  .abook-actions { justify-content: flex-start; }
  .abook-pick { flex-direction: row; }
}

/* ───────── ที่อยู่จัดส่งหน้า checkout — รอบแก้ตามเจ้าของ (TASK-250) ───────── */
/* แขก: กล่อง "ยังไม่ได้เข้าสู่ระบบ" + ปุ่มเข้าสู่ระบบ/สมัครสมาชิก */
.abook-login {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  margin-bottom: 4px; padding: 14px 16px;
  background: var(--purple-lt); border: 1px solid var(--purple-br); border-radius: var(--r-md);
}
.abook-login-icon { flex: none; width: 26px; height: 26px; color: var(--purple); }
.abook-login-text { flex: 1 1 240px; min-width: 0; }
.abook-login-text b { font-size: 15.5px; color: var(--ink); }
.abook-login-text p { margin: 2px 0 0; font-size: 14px; color: var(--ink-soft); }
.abook-login-btn { flex: none; background: #fff; }

/* สมาชิกยังไม่มีที่อยู่: กล่องว่าง + ปุ่มเพิ่ม (กดก่อนถึงกรอกได้) */
.abook-gate {
  position: relative; display: flex; flex-direction: column; align-items: center; gap: 4px; text-align: center;
  padding: 28px 16px; background: var(--surface-2, #FAF8FB); border: 1.5px dashed var(--purple-br); border-radius: var(--r-md);
}
.abook-gate .abook-empty-icon { width: 40px; height: 40px; color: var(--purple); }
.abook-gate b { margin-top: 6px; font-size: 16.5px; color: var(--ink); }
.abook-gate p { margin: 0 0 12px; font-size: 14.5px; color: var(--ink-soft); }
.abook-gate.is-invalid { border-color: var(--danger); background: var(--danger-bg); }
.abook-gate .co-field-error { margin: 10px 0 0; font-weight: 600; }
/* ช่อง required ที่มองไม่เห็นแต่โฟกัสได้ (display:none จะทำให้เบราว์เซอร์ validate ไม่ได้) */
.abook-gate-input { position: absolute; left: 50%; bottom: 0; width: 1px; height: 1px; opacity: 0; pointer-events: none; border: 0; padding: 0; }
.abook-cancel { margin-top: 14px; }

/* การ์ดที่อยู่: ปุ่มแก้ไขเป็นปุ่มกรอบ (แนวภาพที่เจ้าของชอบ) · ปุ่ม "เพิ่มที่อยู่ใหม่" เป็นการ์ดเส้นประ */
.abook-pick .abook-edit { display: inline-flex; align-items: center; gap: 6px; padding: 6px 12px; font-size: 14px; text-decoration: none; }
.abook-pick .abook-edit .icon { width: 15px; height: 15px; }
.abook-other { justify-content: center; gap: 8px; border-style: dashed; color: var(--purple); }
.abook-other > .co-pick-dot { display: none; }
.abook-other .abook-other-icon { width: 18px; height: 18px; }
.abook-other:has(> input:checked) { border-style: solid; }

/* ───────── หน้า checkout แบ่งซ้าย-ขวา (2026-10-12 · เจ้าของขอ แนวภาพตัวอย่าง) ─────────
   ซ้าย .co-main = ฟอร์ม (ผู้สั่งซื้อ · ที่อยู่ · ใบกำกับภาษี · ข้อมูลเพิ่มเติม)
   ขวา .co-aside = สรุปรายการ + สรุปราคา/ปุ่มสั่งซื้อ · ★ การ์ด "สรุปราคา" ติดตามจอตอนเลื่อน (sticky) ไม่มีแถบเลื่อนในกล่อง
     (เจ้าของ: แถบเลื่อนในคอลัมน์ใช้ยาก) — การ์ดสรุปรายการเลื่อนผ่านไปตามปกติ ปุ่มสั่งซื้อจึงอยู่ในจอเสมอ ไม่ว่าจอสูงเท่าไร
   ★ ทั้งสองฝั่งอยู่ใน <form> เดียว — submit ได้ครบทุกช่อง · .co-aside ยืดเท่าความสูงฝั่งซ้าย ให้ sticky มีที่เลื่อน */
.co-layout { display: grid; grid-template-columns: minmax(0, 1fr) 400px; gap: 24px; align-items: stretch; }
.co-main > #customer-fields > .prep-block:last-child { margin-bottom: 0; }
.co-aside .prep-block { margin-bottom: 16px; padding: 18px 20px; }
.co-aside .prep-block:last-child { margin-bottom: 0; }
.co-aside .prep-block > h2 { margin-bottom: 10px; padding-bottom: 10px; font-size: 18px; }
.co-aside .prep-summary { position: sticky; top: 88px; }   /* ใต้แถบขั้นตอน (ที่ติดขอบบนตอนเลื่อน) */
.co-aside .sum-grid { grid-template-columns: 1fr; }
.co-aside .sum-specs > div { padding: 7px 0; margin-bottom: 0; font-size: 14px; line-height: 1.55; }
.co-aside .sum-specs dd { overflow-wrap: anywhere; }
.co-aside .sum-foot { margin-top: 10px; }
.co-aside .server-note { margin: 8px 0 0; font-size: 12.5px; line-height: 1.5; }
.co-aside .co-consent-wrap { padding: 8px 0 0; margin-top: 0; }
.co-aside .prep-actions { margin-top: 10px; }
.co-aside .prep-actions .btn { width: 100%; }
.abook-same { margin: 4px 0 6px; }

/* ── ข้อมูลของฉัน (2026-10-20 · TASK-285) — หน้ารวมข้อมูลส่วนตัว + ที่อยู่ + ใบกำกับภาษี · คลาส pf-* (ไม่ใช้คำนำหน้า ad- — ตัวบล็อกโฆษณาซ่อน) ── */
.pf-jump { display: flex; flex-wrap: wrap; gap: 8px; margin: -6px 0 22px; }
.pf-jump a {
  display: inline-flex; align-items: center; gap: 6px; padding: 7px 14px; border: 1px solid var(--line); border-radius: 999px;
  background: #fff; font-size: 14px; font-weight: 600; color: var(--ink-soft); text-decoration: none;
}
.pf-jump a:hover { border-color: var(--purple-br); background: var(--purple-lt); color: var(--purple); }
.pf-jump .icon { width: 16px; height: 16px; color: var(--purple); }
.pf-sec { margin-bottom: 34px; padding-block: 0; scroll-margin-top: 84px; }   /* padding-block: theme.css ใส่ section { 56px } ทั้งเว็บ · scroll-margin: กดลิงก์ข้ามแล้วหัวข้อไม่จมใต้แถบหัวเว็บ */
.pf-sec-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; margin-bottom: 4px; }
.pf-sec-head h2 { display: flex; align-items: center; gap: 10px; margin: 0; font-size: 22px; line-height: 1.3; }
.pf-sec-head h2 .icon { width: 24px; height: 24px; color: var(--purple); }
.pf-sec-sub { margin: 0 0 14px; font-size: 14.5px; color: var(--ink-soft); }
.pf-sec > .card, .pf-sec > .abook-list { margin-top: 12px; }
.pf-edit, .pf-add { display: inline-flex; align-items: center; gap: 6px; padding: 7px 14px; font-size: 14px; }
.pf-edit .icon, .pf-add .icon { width: 16px; height: 16px; }
.pf-me { display: flex; align-items: center; gap: 14px; padding-bottom: 16px; margin-bottom: 6px; border-bottom: 1px solid var(--line); }
.pf-avatar { flex: none; width: 52px; height: 52px; font-size: 22px; display: grid; place-items: center; cursor: default; }
.pf-me-main { min-width: 0; display: flex; flex-direction: column; }
.pf-me-name { font-size: 18px; color: var(--ink); overflow-wrap: anywhere; }
.pf-me-mail { font-size: 14.5px; color: var(--ink-mute); overflow-wrap: anywhere; }
.pf-list { margin: 0; }
.pf-row { display: grid; grid-template-columns: 160px minmax(0, 1fr); gap: 12px; padding: 12px 0; border-bottom: 1px dashed var(--line); }
.pf-row:last-child { border-bottom: 0; }
.pf-row dt { font-size: 14.5px; color: var(--ink-soft); }
.pf-row dd { margin: 0; font-size: 15.5px; color: var(--ink); overflow-wrap: anywhere; }
.pf-empty { color: var(--ink-mute); }
.pf-lock { display: inline-flex; align-items: center; gap: 4px; margin-left: 8px; padding: 2px 9px; border-radius: 999px; background: var(--purple-lt); font-size: 12.5px; color: var(--ink-soft); }
.pf-lock .icon { width: 13px; height: 13px; }
.pf-google { vertical-align: -4px; margin-right: 6px; }
/* ── หน้าเปลี่ยนรหัสผ่าน (account/profile-password) ── ฟอร์มซ้าย · ข้อมูลบัญชีขวา · มือถือเรียงลงมา */
.pw-hero h1 { display: flex; align-items: center; gap: 10px; }
.pw-hero h1 .icon { flex: none; width: 28px; height: 28px; color: var(--purple); }
.pw-layout { display: grid; grid-template-columns: minmax(0, 560px) minmax(260px, 320px); gap: 28px; align-items: start; }
.pw-form { padding: 24px; background: var(--bg, #fff); border: 1px solid var(--line); border-radius: var(--r-md, 18px); }
.pw-form .au-field { margin-bottom: 16px; }
.pw-sep { margin: 4px 0 20px; border: 0; border-top: 1px dashed var(--line); }
.pw-actions { display: flex; justify-content: flex-end; flex-wrap: wrap; gap: 10px; margin-top: 24px; padding-top: 18px; border-top: 1px solid var(--line); }
.pw-aside { padding: 20px; background: var(--surface-soft, #F7F6FA); border-radius: var(--r-md, 18px); }
.pw-who { display: flex; align-items: center; gap: 12px; padding-bottom: 16px; margin-bottom: 16px; border-bottom: 1px solid var(--line); }
.pw-who-main { min-width: 0; display: flex; flex-direction: column; }
.pw-who-main b { color: var(--ink); overflow-wrap: anywhere; }
.pw-who-main span { font-size: 14px; color: var(--ink-soft); overflow-wrap: anywhere; }
.pw-aside-title { margin: 0 0 8px; font-size: 14.5px; font-weight: 700; color: var(--ink); }
.pw-notes { margin: 0; padding-left: 18px; display: grid; gap: 6px; font-size: 14px; color: var(--ink-soft); }
.pw-aside-foot { margin: 16px 0 0; padding-top: 14px; border-top: 1px solid var(--line); font-size: 13.5px; color: var(--ink-mute); }
@media (max-width: 760px) {
  .pw-layout { grid-template-columns: minmax(0, 1fr); }
  .pw-form { padding: 18px; }
  .pw-actions .btn { flex: 1 1 auto; }
}
.pf-edit-link { margin-left: 8px; font-weight: 600; color: var(--violet, #5B18F2); text-decoration: underline; text-underline-offset: 3px; }
.pf-hint { margin: 10px 0 0; font-size: 13.5px; color: var(--ink-mute); }
.pf-field-note { display: flex; align-items: center; gap: 6px; margin: 6px 0 0; font-size: 13.5px; color: var(--ink-mute); }
.pf-field-note .icon { flex: none; width: 14px; height: 14px; }
.co-field input[readonly][disabled] { background: var(--surface-2, #FAF8FB); color: var(--ink-soft); cursor: not-allowed; }
@media (max-width: 560px) {
  .pf-row { grid-template-columns: 1fr; gap: 2px; }
}
#addr-recipient { margin-top: 2px; }
@media (max-width: 980px) {
  .co-layout { grid-template-columns: 1fr; }
  .co-aside .prep-summary { position: static; }
}

/* ───────── คำสั่งซื้อของฉัน (TASK-253) ───────── */
.oh-list { display: grid; gap: 12px; }
.oh-card {
  display: block; padding: 16px 18px; color: inherit; text-decoration: none;
  background: var(--surface); border: 1.5px solid var(--line); border-radius: var(--r-md);
  transition: border-color .15s, box-shadow .15s;
}
.oh-card:hover { border-color: var(--purple-br); box-shadow: 0 4px 16px rgba(91, 24, 242, .08); }
.oh-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.oh-no { font-size: 16px; color: var(--ink); }
.oh-date { margin-left: 10px; font-size: 13.5px; color: var(--ink-mute); }
.oh-status {
  display: inline-flex; align-items: center; gap: 6px; padding: 3px 12px; border-radius: 999px;
  font-size: 13.5px; font-weight: 600; color: var(--purple); background: var(--purple-lt); border: 1px solid var(--purple-br);
}
.oh-status .icon { width: 15px; height: 15px; }
.oh-status.is-awaiting_payment, .oh-status.is-partial { color: var(--warn); background: var(--warn-bg); border-color: #F1DDA0; }
.oh-status.is-completed { color: var(--ok); background: #EAF7F0; border-color: #BFE5CF; }
.oh-status.is-cancelled { color: var(--ink-mute); background: var(--surface-2, #FAF8FB); border-color: var(--line); }
.oh-items { list-style: none; margin: 12px 0 0; padding: 0; display: grid; gap: 4px; font-size: 14.5px; color: var(--ink-soft); }
.oh-items li { display: flex; justify-content: space-between; gap: 12px; }
.oh-items small { color: var(--ink-mute); }
.oh-qty { flex: none; }
.oh-foot { display: flex; align-items: center; flex-wrap: wrap; gap: 8px 18px; margin-top: 12px; padding-top: 12px; border-top: 1px dashed var(--line); }
.oh-total { font-size: 14.5px; color: var(--ink-soft); }
.oh-total b { font-size: 17px; color: var(--ink); }
.oh-track { display: inline-flex; align-items: center; gap: 6px; font-size: 14px; color: var(--ink-soft); }
.oh-track .icon { width: 16px; height: 16px; }
.oh-go { margin-left: auto; font-size: 14.5px; font-weight: 600; color: var(--purple); }
.oh-pager { display: flex; justify-content: center; gap: 10px; margin-top: 18px; }

/* ═══ แผงขวาหน้าสินค้า — จัดโครงใหม่ (2026-10-23 · มติเจ้าของ · product-configurator.blade.php) ═══
   ลำดับอ่าน: เลือกสเปก (1-3…) → จำนวน → ยอดรวม (พระเอก) → ปุ่มสั่ง · รายละเอียดราคาพับไว้ · มือถือมีแถบล่างติดจอ */
.price-teaser[hidden] { display: none; }   /* .price-teaser เป็น flex ทับ hidden — บอกซ้ำ (JS สลับตอนมีราคาจริง) */

/* เลขขั้นหน้าหัวข้อ — CSS counter (ตัวเลขธรรมดา ไม่ใช้อักขระพิเศษ) นับต่อเนื่องทั้งกลุ่มตัวเลือกและจำนวน */
.config-body { counter-reset: pv-step; }
.config-body .optgroup > .lbl b { display: inline-flex; align-items: center; gap: 8px; }
.config-body .optgroup > .lbl b::before {
  counter-increment: pv-step; content: counter(pv-step);
  display: inline-grid; place-items: center; flex: none; width: 24px; height: 24px; border-radius: 50%;
  background: var(--sf-violet); color: #fff; font-size: 13px; font-weight: 800; line-height: 1;
}

/* "เลือกแล้ว" หน้าตาเดียวกับการ์ดตัวเลือก: ขอบม่วง 1.5px + วงใน 1px + พื้นม่วงจาง · ปุ่มจำนวนกดง่ายบนมือถือ (≥44px) */
.qty-presets { gap: 8px; }
.qty-presets button { min-height: 44px; min-width: 64px; border-width: 1.5px; border-radius: var(--r-md); }
.qty-presets button.on { box-shadow: inset 0 0 0 1px var(--purple); }

/* กล่องราคา: ยอดรวมนำ · รายละเอียดพับใน <details> */
.pricebox .price-total { margin-top: 0; padding-top: 0; border-top: 0; }
.price-details { margin-top: 4px; }
.price-details summary {
  display: flex; align-items: center; gap: 8px; min-height: 44px; cursor: pointer; list-style: none;
  font-size: 14px; font-weight: 600; color: var(--sf-ink); border-radius: 8px;
}
.price-details summary::-webkit-details-marker { display: none; }
.price-details summary::after {
  content: ""; width: 8px; height: 8px; margin-left: 2px; border: solid currentColor; border-width: 0 2px 2px 0;
  transform: translateY(-2px) rotate(45deg); transition: transform .2s cubic-bezier(.16, 1, .3, 1);
}
.price-details[open] summary::after { transform: translateY(2px) rotate(-135deg); }
.price-details summary:focus-visible { outline: 2px solid var(--sf-violet); outline-offset: 2px; }
.price-details[open] { padding-bottom: 6px; }
.price-details .price-line + .price-line { margin-top: 8px; }

/* แถบล่างมือถือ: ยอดรวม + ปุ่มพากลับโซนปุ่มสั่ง · JS สลับ hidden (มีราคาและโซนปุ่มสั่งพ้นจอ) · จอกว้างไม่แสดง */
.pv-bar { display: none; }
@media (max-width: 980px) {
  .pv-bar:not([hidden]) {
    display: flex; align-items: center; justify-content: space-between; gap: 14px;
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 850;   /* ใต้ปุ่ม LINE (900) · เหนือ header (800) */
    padding: 10px 16px calc(10px + env(safe-area-inset-bottom));
    background: #fff; border-top: 2px solid var(--sf-violet); box-shadow: 0 -8px 24px rgba(20, 16, 31, .12);
    animation: pv-bar-in .28s cubic-bezier(.16, 1, .3, 1);
  }
  .pv-bar-sum { display: grid; line-height: 1.15; min-width: 0; }
  .pv-bar-sum > small { font-size: 12.5px; color: var(--ink-soft); }
  .pv-bar-sum b { font-size: 24px; font-weight: 800; color: var(--sf-pink-dk); }
  .pv-bar-sum b small { font-size: 13px; font-weight: 600; }
  .pv-bar-go { flex: none; min-height: 48px; padding-inline: 26px; font-weight: 800; }
  /* เว้นท้ายหน้าไม่ให้แถบบังฟุตเตอร์ · ยกปุ่ม LINE ลอยหนีแถบ */
  body:has(.pv-bar:not([hidden])) { padding-bottom: calc(76px + env(safe-area-inset-bottom)); }
  body:has(.pv-bar:not([hidden])) .sf-fab { bottom: calc(88px + env(safe-area-inset-bottom)); }
}
@keyframes pv-bar-in { from { transform: translateY(100%); } }
@media (prefers-reduced-motion: reduce) {
  .pv-bar:not([hidden]) { animation: none; }
  .price-details summary::after { transition: none; }
}

/* ── รอบ 2 (2026-10-23 · ผลรีวิวหน้า /p) ── */
/* การ์ดตัวเลือกแนวตั้งที่ไม่มีรูป: เว้น "ด้านบน" ให้จุดติ๊ก (มุมขวาบน 20px) — ข้อความยาวเคยชนจุดติ๊ก (แบคดรอปผ้า "ผ้าโพลีเอสเตอร์ยืด 260 แกรม")
   เว้นบนแทนเว้นซ้ายขวา: การ์ดแคบ (3 คอลัมน์บนมือถือ) ยังเหลือที่ให้ตัวหนังสือเต็มความกว้าง */
.opt-cards:not(.is-horizontal):not(.is-list) .opt-card-body.no-thumb { padding: 26px 10px 12px; }

/* รายละเอียดสินค้า (.pdp-spec) อยู่หลังแผงตัวเลือกใน DOM — มือถือเรียงตามนั้นเอง · จอกว้างวางกลับใต้รูปฝั่งซ้าย
   แผงขวากิน 2 แถว · แถวที่ 2 เป็น 1fr ให้ส่วนสูงที่เกินของแผงขวาไปลงแถวล่าง ไม่ดันช่องว่างใต้รูป */
.pdp > .pdp-spec { margin-top: 0; }
@media (min-width: 981px) {
  .pdp { grid-template-rows: auto 1fr; }
  .pdp > .gallery { grid-column: 1; grid-row: 1; }
  .pdp .config { grid-column: 2; grid-row: 1 / span 2; }
  .pdp > .pdp-spec { grid-column: 1; grid-row: 2; }
}

/* สถานะ "สอบถาม" มีทางออก (ปุ่ม LINE) */
#pv-unavailable .pv-cta { margin-top: 16px; }

/* ── รอบ 3 (2026-10-23 · ความสม่ำเสมอระหว่างสินค้า) ── */
/* กลุ่มที่มีตัวเลือกเดียว: บรรทัดเดียว "หัวข้อ ค่า" บนพื้นเทาอ่อน · ไม่ใช่ขั้นที่ต้องเลือก จึงไม่นับเลขขั้น */
.optgroup.is-fixed {
  /* ★ 2026-10-26 — ตาราง 2 คอลัมน์ (เดิม flex ตัดแถว: จอแคบค่าทั้งก้อนตกลงใต้หัวข้อ แม้ค่าสั้น "1 หน้า")
     หัวข้อแคบตามคำ ไม่ตัดบรรทัด · ค่ากินที่ที่เหลือ ยาวก็ตัดบรรทัดอยู่ในคอลัมน์ตัวเอง ชิดซ้ายตรงกัน */
  display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: baseline; column-gap: 14px;
  padding: 11px 14px; border-radius: var(--r-md); background: var(--surface-2);
}
.optgroup.is-fixed > .lbl { margin: 0; white-space: nowrap; }
.optgroup.is-fixed > .lbl b { font-size: 14px; font-weight: 600; color: var(--ink-soft); }   /* หัวข้อเป็นตัวรอง ค่าเป็นตัวหลัก */
.config-body .optgroup.is-fixed > .lbl b::before { content: none; counter-increment: none; }
.optgroup.is-fixed .lbl span { display: none; }
.optgroup.is-fixed .opt-cards, .optgroup.is-fixed .opt-picker { display: contents; }
.optgroup.is-fixed .opt-picker-summary { display: none; }
.optgroup.is-fixed .opt-cards[hidden] { display: contents; }
.optgroup.is-fixed .opt-card input { pointer-events: none; }
.optgroup.is-fixed .opt-card-body,
.optgroup.is-fixed .opt-card input:checked + .opt-card-body {
  display: inline; padding: 0; min-height: 0; border: 0; background: none; box-shadow: none; text-align: left; color: var(--sf-ink);
}
.optgroup.is-fixed .opt-card-thumb-wrap, .optgroup.is-fixed .opt-card-check { display: none !important; }
.optgroup.is-fixed .opt-card-label { font-size: 15px; font-weight: 600; }
.optgroup.is-fixed .opt-card-note { display: inline; margin-left: 6px; font-size: 13px; }

/* กลุ่ม 3 ตัวเลือกพอดี: 3 คอลัมน์แถวเดียว (เดิมตก 2+1 เหลือใบเดี่ยวค้างซ้าย) · การ์ดแนวนอนเปลี่ยนเป็นรูปบน-ข้อความล่าง เพราะแคบลง */
.opt-cards:not(.is-list):has(> .opt-card:nth-child(3):last-child) { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.opt-cards.is-horizontal:has(> .opt-card:nth-child(3):last-child) .opt-card-body,
.opt-cards.is-horizontal:has(> .opt-card:nth-child(3):last-child) .opt-card-body.no-thumb {
  grid-template-columns: minmax(0, 1fr); justify-items: center; align-content: center; text-align: center;
  row-gap: 4px; padding: 26px 8px 12px;
}
.opt-cards.is-horizontal:has(> .opt-card:nth-child(3):last-child) .opt-card-thumb-wrap { grid-column: 1; grid-row: auto; width: 48px; }
.opt-cards.is-horizontal:has(> .opt-card:nth-child(3):last-child) :is(.opt-card-label, .opt-card-note) { grid-column: 1; grid-row: auto; align-self: auto; }
.opt-cards.is-horizontal:has(> .opt-card:nth-child(3):last-child) .opt-card-check { position: absolute; top: 6px; right: 6px; grid-column: auto; grid-row: auto; }

/* จำนวน: ช่องพิมพ์ (stepper) หน้าตาชุดเดียวกับปุ่มขั้น — สูง 44px · มุม r-md · ขอบ 1.5px */
.qty-stepper { min-height: 44px; border-radius: var(--r-md); }
.qty-row .qty-stepper input[type=number] { padding-block: 8px; font-size: 17px; }

/* "ดูรายละเอียดราคา" ให้ดูกดได้: ทั้งแถวเป็นปุ่ม ลูกศรชิดขวา พื้นจางตอนชี้ กรอบโฟกัสมีระยะ */
.price-details summary { margin-inline: -10px; padding-inline: 10px; justify-content: space-between; transition: background-color .15s; }
.price-details summary::after { margin-left: auto; margin-right: 4px; }
.price-details summary:hover { background: rgba(20, 16, 31, .06); }
.price-details summary:focus-visible { outline-offset: 0; }

/* ── รอบ 4 (2026-10-24 · มือถือ: แถบขั้นตอน + การ์ดตัวเลือกไม่ตกคำ) ── */
/* แถบขั้นตอนจอแคบ: เดิมช่องกลางเหลือ ~170px ขั้นที่หดได้ถึง 0 (min-width:0) → วงเลขล้นทับกัน (วัดได้กว้าง 6px) + คำอธิบายโดนตัด "…"
   แก้ที่ต้นเหตุ: (1) ไม่มีโลโก้ในแถบนี้ (header ด้านบนมีอยู่แล้ว) (2) วงเลข/ขั้นไม่หด ให้เส้นเชื่อมหดแทน (3) ขั้นที่อยู่โชว์แค่ชื่อขั้น */
@media (max-width: 720px) {
  .osteps-bar { grid-template-columns: minmax(0, 1fr) auto; }
  .osteps-bar .osteps-logo { display: none; }
  .osteps-item { flex: none; }
  .osteps-step:not(.is-on) { flex: 0 0 auto; }
  .osteps-step.is-on { flex: 1 1 auto; min-width: max-content; }
  .osteps-step:not(:last-child) .osteps-line { flex: 1 1 14px; min-width: 8px; }
  .osteps-step.is-on .osteps-note { display: none; }
  .osteps-cart { width: 44px; height: 44px; }   /* พื้นที่กด ≥44px (ไอคอนขนาดเท่าเดิม) */
}

/* การ์ดตัวเลือก: ตัวหนังสือหลายบรรทัดตัดบรรทัดให้สมดุล (ไม่เหลือคำเดียวค้างบรรทัดล่าง) */
.opt-card-label, .opt-card-note { text-wrap: balance; }

/* กลุ่ม 3 ใบ: กล่องตัวเลือกแคบกว่า 335px (มือถือ) = 3 คอลัมน์ได้ใบละ ~85px คำยาวตกบรรทัด ("ไดคัทตามรูป / ทรง")
   → เรียงเป็นแถวเต็มกว้าง รูปซ้าย ข้อความขวา (ข้อความได้ ~200px) · จอกว้างยัง 3 คอลัมน์เหมือนเดิม
   ★ ใช้ media query ไม่ใช้ container query — container-type กักตัวนับ (CSS counter) ไว้ในแต่ละกลุ่ม เลขขั้นเลยเป็น 1 ทุกกลุ่ม (เจอ 2026-10-24)
     แผงตัวเลือกบนมือถือกว้างตามจอ: กล่อง < 335px ≈ จอ ≤ 430px · จอ 431-980 แผงกว้างพอ 3 คอลัมน์ · จอกว้างแผงคงที่ 460px */
@media (max-width: 430px) {
  .opt-cards:not(.is-list):has(> .opt-card:nth-child(3):last-child) { grid-template-columns: minmax(0, 1fr); }
  .opt-cards:not(.is-list):has(> .opt-card:nth-child(3):last-child) .opt-card-body,
  .opt-cards:not(.is-list):has(> .opt-card:nth-child(3):last-child) .opt-card-body.no-thumb {
    display: grid; grid-template-columns: 48px minmax(0, 1fr) auto; align-items: center; justify-items: start;
    column-gap: 12px; row-gap: 2px; min-height: 0; padding: 10px 12px; text-align: left;
  }
  .opt-cards:not(.is-list):has(> .opt-card:nth-child(3):last-child) .opt-card-body.no-thumb { grid-template-columns: minmax(0, 1fr) auto; }
  .opt-cards:not(.is-list):has(> .opt-card:nth-child(3):last-child) .opt-card-thumb-wrap { grid-column: 1; grid-row: 1 / span 2; width: 48px; }
  .opt-cards:not(.is-list):has(> .opt-card:nth-child(3):last-child) .opt-card-label { grid-column: 2; grid-row: 1; align-self: end; }
  .opt-cards:not(.is-list):has(> .opt-card:nth-child(3):last-child) .opt-card-note { grid-column: 2; grid-row: 2; align-self: start; margin: 0; }
  .opt-cards:not(.is-list):has(> .opt-card:nth-child(3):last-child) .no-thumb :is(.opt-card-label, .opt-card-note) { grid-column: 1; }
  .opt-cards:not(.is-list):has(> .opt-card:nth-child(3):last-child) .opt-card-check { position: static; grid-column: 3; grid-row: 1 / span 2; align-self: center; justify-self: end; }
  .opt-cards:not(.is-list):has(> .opt-card:nth-child(3):last-child) .no-thumb .opt-card-check { grid-column: 2; }
}
/* แถวตัวเลือกเดียว: ค่ายาวตัดบรรทัดให้สมดุล (เคยเหลือ "mm" คำเดียวบรรทัดล่าง) — balance ใช้ได้กับกล่อง block เท่านั้น */
.optgroup.is-fixed .opt-card-body, .optgroup.is-fixed .opt-card input:checked + .opt-card-body { display: block; text-wrap: balance; }
/* จุดตัดบรรทัดของค่า: ตัดเฉพาะตรงเว้นวรรค (แบ่งช่วงด้วย .nobr ใน livewire/partials/option-card) */

/* ── popup อัปโหลดไฟล์กลางจอ <x-upload-modal> (2026-10-29) — กรอบเดียวกับ .pv-switch · ข้างในเป็น <x-file-drop> ── */
.upload-modal[hidden] { display: none; }   /* .pv-switch ตั้ง display:flex ไว้ ทับ hidden ของเบราว์เซอร์ */
.upload-modal-box { position: relative; width: min(520px, 100%); }
.upload-modal-box form { margin-top: 16px; text-align: left; }
.upload-modal-close {
  position: absolute; top: 10px; right: 10px; display: grid; place-items: center;
  width: 36px; height: 36px; border: 0; border-radius: 50%; background: transparent; color: #6B7280; cursor: pointer;
}
.upload-modal-close:hover { background: #F3F4F6; color: #111827; }
.upload-modal-close svg { width: 20px; height: 20px; }

/* ═══ รอบ 5 (2026-10-31 · มติเจ้าของ) — หน้าสินค้าใช้พื้นที่คุ้มขึ้น ไม่ต้องเลื่อนหาปุ่มสั่ง ═══
   ต้นเหตุที่วัดได้: คอลัมน์ล็อกฝั่งละ 460px (จอ 1440 ใช้แค่ 964px) · การ์ดตัวเลือกไม่มีรูปสูง 72px ทั้งที่มีข้อความบรรทัดเดียว
   · กลุ่มค่าเดียวเป็นกล่องเทาคนละแถว · ราคาเริ่มต้น 2 แถว — ตัวอักษรไม่ได้ใหญ่กว่าแบบตัวอย่าง (วัดเทียบแล้ว) จึงไม่ย่อตัวอักษร
   แผงขวายังไม่ sticky (มติ 2026-10-02 เดิม) · ดูเหตุผลเต็มใน decisions.md */

/* จอกว้าง: แผงขวา 460 → 580 · รูปซ้าย 460 → 480 (รูปแทบเท่าเดิม ตามมติ 2026-10-06 "รูปใหญ่เกินไป") — แผงกว้าง = ตัวเลือกเรียงต่อแถวได้มากขึ้น แผงเตี้ยลง */
@media (min-width: 981px) {
  .pdp { grid-template-columns: minmax(0, 480px) minmax(0, 580px); gap: 48px; }
  .config-body { padding: 26px 28px; }
}

/* หัวแผง: ชื่อ · คำโปรย · ป้ายสเปกค่าเดียว ชิดกันเป็นก้อนเดียว */
.pdp-head { display: grid; gap: 6px; }
.pdp-head .pdp-title, .pdp-head .pdp-sub { margin: 0; }
/* ราคาเริ่มต้นอยู่ในหัวแผงต่อจากคำอธิบาย (2026-10-31) — ระยะของป้ายเองเดิม (ล่าง 18px) ทำให้ห่างแถบสรุปเกิน → ย้ายระยะไปท้ายหัวแผงแทน */
.pdp-head .price-teaser { margin: 4px 0 0; }
.pdp-head { margin-bottom: 18px; }

/* แถบสเปกแบบใบสรุป (มติเจ้าของ 2026-10-31 "เอาแบบนี้" · เดิมป้ายแคปซูล ดูเหมือนปุ่ม/ฟิลเตอร์)
   ช่องเท่ากันคั่นเส้นบาง · หัวข้อเล็กบน ค่าหนาล่าง · ใช้ทั้งกลุ่มค่าเดียว (.optgroup.is-fixed) และตัวเลือกที่พับหลังออกแบบ (.pv-spec-chip)
   เส้นคั่น = box-shadow -1px -1px ของแต่ละช่อง แล้วกล่องตัดขอบ (overflow) → แถวแรก/คอลัมน์แรกไม่มีเส้นซ้ำกับกรอบ ตัดแถวกี่แถวก็ได้ */
/* ★ ชื่อ .pdp-summary ไม่ใช่ .pdp-spec — .pdp-spec คือกล่อง "รายละเอียดสินค้า" ใต้รูป (products/show) เคยชนกันจนกล่องนั้นถูกซ่อน (2026-10-31) */
.pdp-summary { display: grid; gap: 6px; margin-top: 8px; }
.pdp-summary:not(:has(.pdp-specline > .optgroup, #pv-spec:not([hidden]))) { display: none; }   /* ก่อนออกแบบ + ไม่มีกลุ่มค่าเดียว = ไม่มีอะไรให้สรุป */
.pdp-summary-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.pdp-summary-head[hidden] { display: none; }
.pdp-summary-head > b { font-size: 14px; font-weight: 700; color: var(--sf-ink); }
/* flex ไม่ใช่ grid: ช่องที่ตกแถวล่างยืดเต็มแถว ไม่เหลือช่องว่างข้างๆ (grid 3 ช่องบนมือถือเคยเป็น 2+1 มีที่ว่างค้าง) */
.pdp-specline {
  display: flex; flex-wrap: wrap;
  overflow: hidden; border: 1px solid var(--line); border-radius: var(--r-md); background: var(--surface);
}
.pdp-specline .optgroup.is-fixed,
.pv-spec-chip {
  flex: 1 1 84px; min-width: 0;
  display: grid; grid-template-columns: minmax(0, 1fr); align-content: start; gap: 2px; margin: 0;
  padding: 9px 14px 10px; border-radius: 0; background: none; box-shadow: -1px -1px 0 var(--line);
}
.pdp-specline .optgroup.is-fixed > .lbl b,
.pv-spec-chip small { font-size: 12.5px; font-weight: 500; color: var(--ink-mute); line-height: 1.4; }
.pdp-specline .optgroup.is-fixed .opt-card-body,
.pdp-specline .optgroup.is-fixed .opt-card input:checked + .opt-card-body { display: block; }
.pdp-specline .optgroup.is-fixed .opt-card-label,
.pv-spec-chip b { font-size: 14.5px; font-weight: 700; color: var(--sf-ink); line-height: 1.35; }
.pdp-specline .optgroup.is-fixed .opt-card-note { display: block; margin: 0; font-size: 12.5px; color: var(--ink-soft); }


/* การ์ดตัวเลือกไม่มีรูป: เตี้ยลง 72 → 52px · เว้นซ้ายขวาเท่ากันให้ข้อความอยู่กลางและไม่ชนจุดติ๊กมุมขวาบน
   กลุ่มที่ไม่มีรูปเลย: ใบยืดเต็มแถว (auto-fit) ไม่เหลือช่องว่างท้ายแถว · กลุ่มที่มีรูปคง auto-fill (กันรูปจัตุรัสยืดใหญ่) */
.opt-cards:not(.is-horizontal):not(.is-list) .opt-card-body.no-thumb { min-height: 52px; padding: 10px 28px; }
.opt-cards:not(.is-list):not(:has(.opt-card-thumb-wrap)) { grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); }

/* ปุ่มจำนวนบนจอคอม (เมาส์) เตี้ยลง 44 → 36px · มือถือคง 44px (เป้ากดนิ้วขั้นต่ำ) */
@media (min-width: 981px) {
  .qty-presets button { min-height: 36px; }
}

/* โซนปุ่มสั่ง: ห่างราคาพอดี (เดิม inline 2rem) */
#pv-available > .pv-cta { margin-top: 16px; }

/* หลังออกแบบ (ตามแบบ step 3): "เพิ่มลงตะกร้า" ปุ่มหลักเต็มกว้างบนสุด · "แก้ไขดีไซน์" + "ออกแบบงานใหม่" ปุ่มรองคู่กันแถวเดียว ไม่มีคำอธิบาย/ลูกศร */
.pv-cta:has(#pv-cart:not([hidden])) > :is(#pv-path-design, #pv-path-new) {
  flex: 1 1 calc(50% - 5px); width: auto; justify-content: center; gap: 8px; padding: 10px 12px;
}
.pv-cta:has(#pv-cart:not([hidden])) > :is(#pv-path-design, #pv-path-new) :is(small, .pv-path-arrow) { display: none; }
.pv-cta:has(#pv-cart:not([hidden])) > :is(#pv-path-design, #pv-path-new) .pv-path-text b { font-size: 15px; font-weight: 700; }
.pv-cta:has(#pv-cart:not([hidden])) > :is(#pv-path-design, #pv-path-new) .pv-path-icon { width: 20px; height: 20px; }
/* ★ 2026-10-31 — ปุ่มรองเป็นปุ่มเรียบ ตัวหนังสือสีหมึก ไม่มีขอบชมพู (เดิมชมพู 3 ก้อนติดกัน แย่งความเด่นปุ่มตะกร้า · Baymard #791 ปุ่มเด่นปุ่มเดียว) */
.pv-cta:has(#pv-cart:not([hidden])) > :is(#pv-path-design, #pv-path-new) {
  min-height: 44px; background: transparent; border-color: transparent; color: var(--sf-ink); box-shadow: none;
}
.pv-cta:has(#pv-cart:not([hidden])) > :is(#pv-path-design, #pv-path-new) .pv-path-icon { color: var(--sf-violet); }
/* มือถือ: "ออกแบบงานใหม่" เคยตกเป็น 2 บรรทัด → กว้างตามคำ (ไม่บังคับครึ่งต่อครึ่ง) + ไม่ตัดคำ + ไอคอนเล็กลง · จอ 360 ยังพอ */
.pv-cta:has(#pv-cart:not([hidden])) > :is(#pv-path-design, #pv-path-new) { flex: 1 1 auto; gap: 6px; padding-inline: 8px; white-space: nowrap; }
.pv-cta:has(#pv-cart:not([hidden])) > :is(#pv-path-design, #pv-path-new) .pv-path-icon { width: 18px; height: 18px; }
.pv-cta:has(#pv-cart:not([hidden])) > :is(#pv-path-design, #pv-path-new):hover { transform: none; box-shadow: none; background: var(--purple-lt); }

/* ── รอบ 5b (2026-10-31 · มติเจ้าของ: ทำไอเดีย "แนะนำ + น่าลอง" ทั้งหมด) ── */

/* แถบล่าง: ใช้ทุกจอแล้ว (เดิมเฉพาะมือถือ) — แผงขวาไม่ sticky จึงให้แถบนี้ขึ้นเฉพาะตอนปุ่มหลักหลุดจอ (JS showBar)
   ปุ่มไม่เต็มความกว้าง มีที่ว่างรอบ (Baymard #791) · คอมมีชื่อสินค้า + สเปกที่เลือกด้านซ้าย ให้รู้ว่ากำลังสั่งอะไร */
.pv-bar:not([hidden]) {
  display: block; position: fixed; left: 0; right: 0; bottom: 0; z-index: 850;   /* ใต้ปุ่ม LINE (900) · เหนือ header (800) */
  padding: 10px 16px calc(10px + env(safe-area-inset-bottom));
  background: #fff; border-top: 2px solid var(--sf-violet); box-shadow: 0 -8px 24px rgba(20, 16, 31, .12);
  animation: pv-bar-in .28s cubic-bezier(.16, 1, .3, 1);
}
.pv-bar-inner { display: flex; align-items: center; gap: 14px; max-width: 1108px; margin-inline: auto; }
.pv-bar-name { display: none; }
.pv-bar-sum { display: grid; line-height: 1.15; min-width: 0; margin-right: auto; }
.pv-bar-sum > small { font-size: 12.5px; color: var(--ink-soft); }
.pv-bar-sum b { font-size: 24px; font-weight: 800; color: var(--sf-pink-dk); }
.pv-bar-sum b small { font-size: 13px; font-weight: 600; }
/* ชื่อปุ่มยาวตามปุ่มจริง ("ออกแบบออนไลน์ทันที" ฯลฯ) — มือถือหดตัดบรรทัดได้ ไม่ดันยอดรวมจนล้น */
/* แถบขึ้นเฉพาะหลังออกแบบ ปุ่มเป็น "เพิ่มลงตะกร้า" เสมอ (สั้น) → ไม่ตัดคำ (เดิมตกเป็น 2 บรรทัดบนจอ 390) */
.pv-bar-go { flex: 0 0 auto; min-height: 48px; padding-inline: 22px; font-weight: 800; line-height: 1.25; white-space: nowrap; }
body:has(.pv-bar:not([hidden])) { padding-bottom: calc(76px + env(safe-area-inset-bottom)); }
body:has(.pv-bar:not([hidden])) .sf-fab { bottom: calc(88px + env(safe-area-inset-bottom)); }
@media (min-width: 981px) {
  .pv-bar:not([hidden]) { padding: 12px 44px; }
  .pv-bar-name { display: grid; flex: 1 1 auto; min-width: 0; margin-right: auto; line-height: 1.35; }
  .pv-bar-name b { font-size: 16px; font-weight: 700; }
  .pv-bar-name small { font-size: 13.5px; color: var(--ink-soft); overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
  .pv-bar-sum { margin-right: 0; text-align: right; }
  .pv-bar-go { max-width: none; white-space: nowrap; }
}

/* หลังออกแบบ: ตัวเลือกพับเป็นช่องในแถบสเปก + หัว "รายละเอียด / แก้ไข" (JS syncSpecSummary) — #opts เป็น grid ทับ hidden ต้องบอกซ้ำ */
#opts[hidden], .pv-spec[hidden] { display: none; }
#opts { scroll-margin-top: 140px; }   /* เลื่อนมาที่ตัวเลือก (กล่อง "เลือกรายละเอียดใหม่") ไม่ให้แถบขั้นตอนที่ติดบนจอบัง */
.pv-spec { display: contents; }
.pv-spec-edit {
  display: inline-flex; align-items: center; gap: 6px; min-height: 32px; margin-right: -10px; padding: 0 10px;
  border: 0; border-radius: var(--r-sm, 8px); background: transparent;
  font: inherit; font-size: 13.5px; font-weight: 700; color: var(--sf-violet); cursor: pointer; transition: background-color .15s;
}
.pv-spec-edit svg { width: 16px; height: 16px; }
.pv-spec-edit:hover { background: var(--purple-lt); }
.pv-spec-edit:focus-visible { outline: 2px solid var(--sf-violet); outline-offset: 2px; }

/* การ์ดปุ่มบนจอแคบ: คำอธิบายเคยตก 2 บรรทัด ("...เริ่มพิมพ์ได้ / ทันที") → ขอบใน/ช่องไฟแคบลง ตัวรองเล็กลง ตัดบรรทัดแบบสมดุลถ้ายังยาว */
@media (max-width: 430px) {
  .pv-path { gap: 12px; padding: 14px 14px 14px 16px; }
  .pv-path-text small { font-size: 13px; }   /* ไม่ใช้ balance — ภาษาไทยไปตัดกลางวลี ("ของ / คุณ") */
}
/* จอ ≤ 380 (เช่น 360): ปุ่มรองคู่ "แก้ไขดีไซน์ / ออกแบบงานใหม่" ตัวเล็กลงนิด ให้ยังอยู่แถวเดียวกัน */
@media (max-width: 380px) {
  .pv-cta:has(#pv-cart:not([hidden])) > :is(#pv-path-design, #pv-path-new) { gap: 4px; padding-inline: 4px; }
  .pv-cta:has(#pv-cart:not([hidden])) > :is(#pv-path-design, #pv-path-new) .pv-path-text b { font-size: 14px; }
}
/* กล่อง "เก็บงานเดิมไว้ก่อนไหม?" 3 ปุ่ม: เรียงแนวตั้ง ปุ่มหลักบนสุด (ยาวเกินจะวางคู่กันในกล่อง 420px) */
.pv-switch-actions.is-stack { grid-template-columns: minmax(0, 1fr); gap: 8px; }

/* เลขขั้นหน้าหัวข้อ: เหลือขั้นเดียว (ตัวเลือกพับ / สินค้ามีแต่กลุ่มค่าเดียว) = เลข "1" หน้า "จำนวน" ไม่มีความหมาย → ซ่อน */
.config-body:not(:has(#opts:not([hidden]) .optgroup)) .optgroup > .lbl b::before { display: none; }

/* ปุ่มจำนวน: บรรทัดที่สองเป็นราคาต่อชิ้นของขั้นนั้น (JS renderQtyPresets · computeQuote ตัวเดียวกับยอดรวม) */
.qty-presets button { line-height: 1.2; }
/* ปุ่มจำนวนเป็นตารางช่องเท่ากันเต็มความกว้าง (เดิม flex ขนาดตามตัวหนังสือ ขอบขวาไม่ตรง เหลือที่ว่างท้ายแถว) · "กำหนดเอง" ได้ช่องเท่าปุ่มอื่น */
.qty-presets { display: grid; grid-template-columns: repeat(auto-fill, minmax(78px, 1fr)); }
.qty-presets button { min-width: 0; padding-inline: 6px; white-space: nowrap; }
.qty-presets button small { display: block; margin-top: 2px; font-size: 11.5px; font-weight: 500; color: var(--ink-mute); }
.qty-presets button.on small { color: var(--sf-violet); }

/* ── รอบ 5c (2026-10-31 · มติเจ้าของ: หลังออกแบบต้องจบใน 1 จอ) ── เอาบรรทัด "ขั้นต่อไป" ออก (แถบขั้นตอนด้านบนบอกอยู่แล้ว) */

/* หลังออกแบบ: ซ่อนการ์ด "มีไฟล์พร้อมแล้ว" — เหลือปุ่มหลัก 1 + ปุ่มรอง 2 ตามแบบ step 3 · ทางอัปไฟล์ = ทิ้งงานที่ออกแบบไว้ ไม่ควรแข่งกับปุ่มตะกร้า
   ยังเข้าได้ตอนยังไม่มีงาน หรือกด "แก้ไขรายละเอียด" เปลี่ยนตัวเลือก */
.pv-cta:has(#pv-cart:not([hidden])) > .pv-path-upload { display: none; }

/* กล่องราคาแถวเดียว: "ยอดรวม / ยังไม่รวมค่าจัดส่ง" ซ้าย · ตัวเลขขวา · ขอบในบางลง */
.pricebox { padding: 14px 22px 16px; }
.price-total { align-items: center; }
.price-total > span { display: grid; line-height: 1.25; }
.price-total > span small { font-size: 12.5px; font-weight: 500; color: var(--ink-soft); }
.price-total > span small[hidden] { display: none; }
.price-details summary { min-height: 36px; }
#pv-available > .pv-cta { margin-top: 10px; }
#pv-leadtime { margin-top: 8px; text-align: center; }

/* ── รอบ 5d (2026-10-31 · มติเจ้าของ) ── กล่องแนะนำทับ editor ออกแบบ: ขึ้นทุกครั้งที่ editor เปิด · กล่องข้อความแยกชี้แต่ละจุด · ปุ่ม "เข้าใจแล้ว" กลางจอ
   JS ตั้ง --lx/--ly (กล่องซ้าย) · --rx/--ry (กล่องขวา) จากมุมกรอบ iframe ของ PitchPrint */
.ppt-back { position: fixed; inset: 0; z-index: 2147483000; background: rgba(20, 16, 40, .55); }
.ppt-box { position: absolute; width: min(260px, calc(100vw - 32px)); padding: 14px 16px; border-radius: 12px; background: #fff; color: var(--sf-ink); box-shadow: 0 12px 40px rgba(0, 0, 0, .35); font-size: 15px; line-height: 1.55; }
.ppt-box::before { content: ""; position: absolute; width: 16px; height: 16px; background: #fff; transform: rotate(45deg); }
.ppt-left { left: var(--lx, 90px); top: var(--ly, 90px); }
.ppt-left::before { left: -8px; top: 20px; } /* ลูกศรชี้ซ้าย → แถบเครื่องมือ */
.ppt-right { right: var(--rx, 16px); top: var(--ry, 70px); }
.ppt-right::before { right: 48px; top: -8px; } /* ลูกศรชี้ขึ้น → ปุ่มมุมขวาบน */
/* ปุ่ม "เข้าใจแล้ว": ปุ่มชมพูแบรนด์ (ใช้ --sf-pink-dk ให้ตัวอักษรขาวอ่านชัด ≥ 4.5) กลางจอ · โฟกัสคีย์บอร์ด = วงขาว */
.ppt-ok { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); padding: 12px 34px; border: 0; border-radius: 999px; background: var(--sf-pink-dk); color: #fff; font: inherit; font-size: 17px; font-weight: 600; cursor: pointer; box-shadow: 0 8px 24px rgba(20, 16, 31, .4); }
.ppt-ok:hover { background: var(--sf-pink); }
.ppt-ok:focus-visible { outline: 3px solid #fff; outline-offset: 3px; }
@media (max-width: 700px) {
  /* มือถือ: เลย์เอาต์ editor ต่างจากจอคอม ไม่ชี้ตำแหน่ง · เรียงกล่องลงมาจากบน */
  .ppt-left, .ppt-right { left: 16px; right: 16px; width: auto; }
  .ppt-left { top: 70px; }
  .ppt-right { top: 160px; }
  .ppt-box::before { display: none; }
}
