/* ==========================================================================
   UNIDEA — style.css
   ทิศทางงานออกแบบ: โปสเตอร์ริโซกราฟติดบอร์ดมหาลัย — ยกพาเลตต์มาจากโลโก้ทั้งชุด
   พื้นครีม (หน้าแรกเป็นภาพลายที่เจ้าของวาด) + การ์ดกระดาษลอยอยู่บนนั้น
   + หมึกดำอมม่วง + สีเน้นอำพัน/แดงส้ม/ม่วงแดงจากโลโก้ + ลายจุดฮาล์ฟโทน
   ========================================================================== */

/* ---------- โทเคนสี: ใช้ oklch เพื่อให้ความสว่างสม่ำเสมอทั้งพาเลตต์ ---------- */
:root {
  /* ---------- พาเลตต์จากโลโก้ public/logo.jpg (เปลี่ยนโลโก้ 13 ก.ย. 2569) ----------
     ดูดจากไฟล์ตรง ๆ ไม่ได้เดา:
       ครีมพื้น #F3DCBC · อำพัน #EB9F25 (ช่องบนของจอ) · แดงส้ม #DB3623 (ช่องล่าง)
       ม่วงแดง #A01C58 (เงาชั้นในของตัวอักษร) · ดำอมม่วง #251E25 (คนในจอ/เส้นขอบ)

     ⚠️ ชื่อโทเคนยังเป็นชื่อจากพาเลตต์เก่า (ชมพู/ม่วง/ส้ม/เหลือง)
     คงชื่อไว้เพราะถูกอ้างร้อยกว่าที่ ทั้ง style.css, landing.css, legal.css,
     index.html และ frontend/ — ให้ยึด "หน้าที่" ของโทเคน ไม่ใช่ชื่อสี:
       --grape     ปุ่มลงมือทำ/ไปต่อ   → ม่วงแดง
       --vermilion เตือน/รายงาน       → แดงส้ม
       --sun       เน้น/เทปกาว/OTP    → อำพัน
       --magenta   วงโฟกัส/ป้ายเล็ก    → ชมพูหม่นจากภาพพื้นหลัง
       --leaf      ✓ ชื่อมหาลัย        → เขียว (ตัวเดียวที่ไม่มาจากโลโก้ เจ้าของขอเอง)

     พื้นที่กว้างใช้ครีมความอิ่มต่ำ (0.042) โดยตั้งใจ — พาเลตต์ก่อนหน้า
     เจ้าของบอกสองรอบว่าพื้นสีอิ่มจัดเต็มจอ "แสบตา" ทั้งที่คอนทราสต์ผ่านหมด
     ถ้าจะให้พื้นสดขึ้น ขยับ chroma ตัวเดียว อย่าเกิน ~0.08 */
  /* ครีมจากภาพพื้นหลังที่เจ้าของวาด (#EEDDC1) — ตัวเดียวกับสีสำรองระหว่างรอโหลดภาพ */
  --ground:       oklch(90.4% 0.042 80);
  /* ครีมพื้นของไฟล์โลโก้ — ใช้กับป้าย .wordmark เท่านั้น
     jpeg ไม่มีพื้นใส ป้ายต้องเป็นสีเดียวกับพื้นในไฟล์ ไม่งั้นเห็นกรอบรอบรูปที่ครอป */
  --logo-ground:  #F3DCBC;

  /* กระดาษ — ครีมอุ่น ไม่ใช่ขาวจ้า
     ขาว 99% เป็นพื้นการ์ดใหญ่ ๆ สะท้อนแสงจอเกือบเต็มที่ ซึ่งแสบตาพอกับชมพูสด
     กระดาษริโซจริงก็ไม่ใช่ขาววอก ลดลงมาที่ 97.5% แล้วเติมความอุ่นนิดหน่อย
     ยังทำหน้าที่เป็นสีตัวหนังสือบนพื้นมืดได้เหมือนเดิม (สว่างพอ) */
  --paper:        oklch(97.5% 0.012 85);
  --paper-2:      oklch(94.5% 0.018 85);
  --paper-3:      oklch(90% 0.03 86);

  /* หมึก — ดำอมม่วงของคนในจอกับเส้นขอบในโลโก้ ความอิ่มต่ำจนเกือบเป็นดำ
     บนกระดาษ 15.1:1 · บนพื้นครีม 12.2:1 */
  --ink:          oklch(24.6% 0.017 326);
  /* ตัวหนังสือรอง — วางบนพื้นครีมได้ 7.9:1 ไม่ใช่แค่บนการ์ด */
  --ink-2:        oklch(37% 0.02 330);
  /* ตัวหนังสือจาง — ใช้บนการ์ดกระดาษเท่านั้น (5.4:1 · บนการ์ดฟอร์มอำพันนวล 4.86:1)
     บนพื้นครีมได้ 4.36:1 ไม่ผ่าน · ถ้าจะหรี่กระดาษลงอีก ต้องขยับตัวนี้ตามทุกครั้ง */
  --ink-3:        oklch(51% 0.02 330);

  /* หมึกของงานริโซ — ดูดจากไฟล์โลโก้ตรง ๆ ใช้เป็นพื้น/ลายเส้น/ไอคอนได้ตามใจ
     แต่ตัวสดเป็นตัวหนังสือบนกระดาษได้ไม่ครบเกณฑ์ทุกตัว (แดงส้ม 4.25 · อำพัน ~2.2)
     เลยมีคู่สีเข้มต่อท้ายไว้ให้ใช้ตอนต้องการตัวหนังสือหรือเงาแข็ง */
  /* แดงส้ม — ช่องล่างของจอในโลโก้ (#DB3623) */
  --vermilion:     oklch(58.7% 0.204 31);
  /* แดงไส้ตัวอักษร UNIDEA (#C32D2F) — รองตัวหนังสือครีมได้ 5.2:1 ใช้เป็นพื้นชิป/ปุ่มเล็ก */
  --vermilion-lo:  oklch(53.8% 0.186 27);
  /* แดงระดับหมึก — เป็นตัวหนังสือบนพื้นแดงจางได้ 5.4:1 + ใช้เป็นเงาแข็ง */
  --vermilion-ink: oklch(46% 0.17 29);

  /* ม่วงแดง — เงาชั้นในของตัวอักษรในโลโก้ (#A01C58) รับหน้าที่ "ไปต่อ" = ปุ่มลงมือทำทุกตัว
     เป็นตัวหนังสือได้ทั้งบนกระดาษ (6.95:1) และพื้นครีม (5.6:1)
     เป็นพื้นปุ่มที่มีตัวหนังสือขาวทับได้ 7.5:1 */
  --grape:         oklch(47.1% 0.172 359);
  --grape-lo:      oklch(38% 0.15 359);

  /* ชมพูหม่น — แถบสีในภาพพื้นหลังที่เจ้าของวาด (#BE808B)
     เป็นสีเดียวที่ไม่ได้รับหน้าที่อื่นในเว็บ เลยเหมาะกับวงโฟกัสที่สุด */
  --magenta:       oklch(66.6% 0.078 8);
  /* ตัวสดบนกระดาษได้แค่ ~2.9:1 ต่ำกว่าเกณฑ์ 3:1 ของ non-text — ตัวเข้มได้ 5.95:1 */
  --magenta-lo:    oklch(50% 0.12 6);

  /* อำพัน — ช่องบนของจอในโลโก้ (#EB9F25) ตัวหนังสือหมึกทับได้ 7.4:1 */
  --sun:           oklch(75.9% 0.153 73);
  /* อำพันเข้ม — ใช้เป็นเงาแข็งกับเส้นขอบเท่านั้น ไม่เคยเป็นตัวหนังสือ */
  --sun-lo:        oklch(64% 0.14 68);

  /* เขียว — ไม่ได้มาจากโลโก้ เจ้าของขอเอง (14 ก.ย. 2569) ใช้กับป้าย "✓ ชื่อมหาลัย" ตอนพิมพ์อีเมลเท่านั้น
     เขียว = ตรวจเจอแล้ว ใช้ได้ อ่านออกทันทีโดยไม่ต้องอ่านคำ อย่าเอาไปใช้กับปุ่มหรือพื้นที่อื่น
     เป็นตัวหนังสือบนการ์ดครีมหน้าแรกได้ 4.71:1 (วัดจากจอจริง) — ห้ามสว่างกว่านี้ จะตกเกณฑ์ 4.5 */
  --leaf:          oklch(50% 0.13 150);

  /* เวทีวิดีโอ — ดำอมม่วงเข้มกว่าหมึก ให้เป็นญาติกัน ไม่ใช่ดำสนิท
     ตัวหนังสือกระดาษบนนี้ได้ 16.9:1 · อำพัน 8.2:1 */
  --stage:        oklch(20% 0.02 326);
  --stage-2:      oklch(26% 0.022 326);

  --line:         color-mix(in srgb, var(--ink) 16%, var(--paper));
  --line-strong:  color-mix(in srgb, var(--ink) 30%, var(--paper));

  /* "หมึก" ของงานพิมพ์ — เส้นขอบคมกับเงาแข็งเยื้อง
     หน้าแรกใช้ภาษานี้อยู่แล้ว (โปสเตอร์ริโซติดบอร์ด) แต่ห้องคุยยังเป็นการ์ดเว็บ
     เรียบ ๆ ขอบ 1px เงาฟุ้ง เลยดูเหมือนคนละเว็บ ยกมาเป็นโทเคนกลางให้พูดภาษาเดียวกัน */
  /* เส้นขอบหมึก — ต้องเข้มกว่าธีมครีมเดิมมาก
     หมึกโปร่ง 34% ซ้อนบนพื้นชมพูได้คอนทราสต์แค่ 1.85:1 ขอบการ์ดหายไปกับพื้น
     ต้องขึ้นถึง ~65% ถึงจะผ่านเกณฑ์ 3:1 ของขอบเขตพื้นผิว — ตั้ง 72% ได้ 4.2:1
     ซึ่งตรงกับภาษาโปสเตอร์ริโซอยู่แล้ว (ขอบหมึกหนา) และตรงกับกรอบม่วงรอบจอในโลโก้ */
  --ink-line:  color-mix(in oklch, var(--ink) 88%, transparent);
  --ink-drop:  color-mix(in oklch, var(--ink) 45%, transparent);

  /* ความหนาเส้นหมึกมาตรฐาน — ทั้งเว็บใช้ค่าเดียว ก่อนหน้านี้มี 1px/1.5px/2px
     ปนกันจนขอบแต่ละชิ้นหนาไม่เท่ากัน ซึ่งเป็นสิ่งแรกที่ทำให้งานดู "ไม่ได้ตั้งใจ" */
  --ink-w: 2px;

  /* เงาแข็งสามระดับ — ทึบ ไม่ใช่โปร่ง
     ของเดิมเป็นหมึกโปร่ง 26% ซ้อนบนพื้นชมพู ได้เงาสีชมพูอมม่วงจาง ๆ
     ซึ่งอ่านว่า "เงาฟุ้งที่เบลอไม่ขึ้น" มากกว่าจะเป็นเพลทหมึกอีกชั้น
     งานริโซจริงเงาคือหมึกอีกสีที่พิมพ์เหลื่อมลงไป ต้องทึบถึงจะอ่านออกแบบนั้น */
  --drop-1: 3px 3px 0 var(--ink);
  --drop-2: 5px 5px 0 var(--ink);
  --drop-3: 8px 8px 0 var(--ink);
  --paper-lift: var(--drop-2);

  /* ⚠️ เฉดจาง (สีแบรนด์ผสมกับ --paper) ต้องใช้ color-mix(in srgb) เท่านั้น
     oklch ไล่สีตามมุม hue พอ --paper เป็นขาวอมชมพู (hue 320) เฉดจางของส้ม/เหลือง
     จะถูกลากผ่านโซนชมพู — ทดสอบกับ Chrome จริงแล้ว ปุ่ม "หยุด" ที่ควรเป็นพีช
     ได้ #FCDCF3 (ชมพู) ใน oklch แต่ได้ #FDDACB (พีช) ใน srgb
     ส่วนการผสมกับ transparent และ white ให้ผลเท่ากันทั้งสอง space ใช้ oklch ต่อได้ */

  /* รัศมีมีแค่สามค่า: ปุ่ม/ช่องกรอก · แผ่นกระดาษ · แคปซูล
     เดิมมี 8/11/12/13/14/15/16/18/20/22/24px ปนกัน สายตาจับจังหวะไม่ได้
     โลโก้เองใช้แค่สองทรง — จอสี่เหลี่ยมมุมมนนิดเดียว กับตัวอักษรกลมสุด */
  --radius:   13px;
  --radius-lg: 20px;
  /* ระยะขอบ/ช่องไฟระหว่างบาน — ใช้ตัวเดียวกันทุกบาน ขอบถึงจะตรงกัน */
  --pane-gap: clamp(0.5rem, 1.2vw, 0.85rem);

  /* เงากระดาษมาตรฐาน — ชี้ไปที่เงาแข็งชุดเดียวกับทุกอย่าง
     ห้ามใส่เงาฟุ้งกลับมาเป็นเงาหลัก มันคือสิ่งที่ทำให้การ์ดดูเป็นเว็บแอปทั่วไป */
  --lift: var(--drop-2);

  --ease: cubic-bezier(0.16, 1, 0.3, 1);   /* ease-out-expo — ชะลอตัวแบบธรรมชาติ */

  color-scheme: light;
}

*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; padding: 0; }

html { -webkit-text-size-adjust: 100%; }

body {
  font-family: 'Anuphan', 'Segoe UI', system-ui, sans-serif;
  font-size: clamp(0.95rem, 0.9rem + 0.2vw, 1.05rem);
  line-height: 1.65;
  color: var(--ink);
  background: var(--ground);
  min-height: 100svh;
  overflow: hidden;
  -webkit-font-smoothing: antialiased;
}

h1, h2, .wordmark__text, .btn__label, .waiting__title {
  font-family: 'Mali', 'Anuphan', sans-serif;
  font-weight: 500;
  line-height: 1.25;
  letter-spacing: -0.01em;
}

/* ---------- ระบบสลับหน้าจอ ---------- */
.screen { display: none; }
.screen.active { display: flex; }

/* โฟกัสต้องเห็นชัดเสมอ */
/* ใส่ attribute hidden แล้วต้องหายไปจริง ทุกที่ ไม่มีข้อยกเว้น
   [hidden] มี specificity เท่ากับ class เดียว (0,1,0) — กฎที่มี class และอยู่
   ทีหลังในไฟล์จึงชนะมันได้ เช่น .toggle { display: inline-flex }
   ผลคือปุ่มพลิกกล้องที่ตั้ง hidden ไว้ โผล่บนเครื่องกล้องตัวเดียวมาตลอด
   ทั้งที่กดแล้วไม่มีอะไรเกิดขึ้น */
[hidden] { display: none !important; }

/* ชมพูหม่น (--magenta) ไม่ได้ทำหน้าที่อื่นในเว็บเลย วงโฟกัสเลยเด้งออกจากของรอบตัวได้ชัดสุด
   ใช้ตัวเข้ม เพราะตัวสดบนกระดาษได้แค่ ~2.9:1 ต่ำกว่าเกณฑ์ 3:1 (ตัวเข้มได้ 5.95:1) */
:focus-visible {
  outline: 3px solid var(--magenta-lo);
  outline-offset: 3px;
  border-radius: 4px;
}

/* ==========================================================================
   หน้าเข้าใช้งาน
   ========================================================================== */
#login-screen {
  flex-direction: column;
  height: 100svh;
  overflow-y: auto;
  position: relative;
  isolation: isolate;
}

/* ---------- พื้นกระดาษ ----------
   พื้นเป็นครีมเรียบ ไม่ไล่สี (หน้าแรกจริงทับด้วยภาพลายที่เจ้าของวาด ดู landing.css)

   ของเดิมกองคราบสีสามชั้น (เหลือง/ส้ม/ม่วง) ไล่เบลอทับพื้นชมพู ผลคือพื้นวิ่ง
   จากชมพูไปส้มแบบ mesh gradient ซึ่งเป็นลายเซ็นของเทมเพลตเว็บสำเร็จรูป
   ไม่ใช่ของงานพิมพ์ — โลโก้ไม่มีการไล่สีอยู่สักจุดเดียว มีแต่สีแบน ๆ ชนกันตรง ๆ
   ความน่าสนใจย้ายไปอยู่ที่ลายเส้นทแยงกับจุดฮาล์ฟโทนแทน ซึ่งเป็นพื้นผิวของหมึกจริง */
#login-screen::before {
  content: '';
  position: fixed;
  inset: 0;
  z-index: -2;
  background:
    repeating-linear-gradient(
      -22deg,
      color-mix(in oklch, var(--grape) 7%, transparent) 0 3px,
      transparent 3px 22px),
    var(--ground);
}
#login-screen::after {
  content: '';
  position: fixed;
  inset: 0;
  z-index: -1;
  background-image: radial-gradient(color-mix(in oklch, var(--ink) 38%, transparent) 1px, transparent 1.1px);
  background-size: 7px 7px;
  opacity: 0.09;
  pointer-events: none;
}

/* ---------- กริดหลัก: ไม่สมมาตร ฝั่งซ้ายหนักกว่า ---------- */
.login-grid {
  flex: 1;
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(2.5rem, 5vw, 4.5rem);
  width: min(1180px, 100%);
  margin-inline: auto;
  padding: clamp(2rem, 5vw, 4.5rem) clamp(1.25rem, 5vw, 3rem);
}

/* จัดกลางแนวตั้งเฉพาะจอกว้าง จอแคบให้ไหลลงแล้วเลื่อนดูได้ตามปกติ */
@media (min-width: 940px) {
  .login-grid {
    grid-template-columns: 1.08fr 0.92fr;
    align-items: center;
  }
}

/* ---------- ฝั่งซ้าย: คำโปรย ---------- */
/* โลโก้ทั้งอันเป็นสติกเกอร์ครีมใบเดียว ไม่ใช่ป้ายสองใบวางข้างกัน

   ตอนแยกเป็นสองใบ (ป้ายจอมีขอบ+เงาของตัวเอง ตัวอักษรก็เป็นบล็อกสีอีกก้อน)
   สายตาอ่านเป็นของสองชิ้นที่บังเอิญอยู่ใกล้กัน ไม่ได้อ่านเป็นโลโก้อันเดียว
   ย้ายขอบหมึกกับเงาแข็งมาไว้ที่กล่องนอก แล้วให้ทั้งสองก้อนใช้พื้นครีมผืนเดียวกัน
   — ครีมในไฟล์โลโก้กับ --logo-ground เป็นสีเดียวกัน รอยต่อจึงมองไม่เห็น */
.wordmark {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.32rem 0.6rem 0.32rem 0.4rem;
  background: var(--logo-ground);
  border: var(--ink-w) solid var(--ink);
  border-radius: 14px;
  box-shadow: var(--drop-1);
  transform: rotate(-2deg);
  text-decoration: none;
  color: inherit;
  margin-bottom: clamp(1.5rem, 3vw, 2.25rem);
  transition: transform 0.3s var(--ease), box-shadow 0.3s var(--ease);
}
.wordmark:hover {
  transform: rotate(1deg) translateY(-2px);
  box-shadow: var(--drop-2);
}
/* ---------- โลโก้จริง ----------
   ทั้งป้ายและตัวอักษรครอปมาจาก public/logo.jpg ตรง ๆ ไม่ได้วาดเลียนแบบอีกแล้ว

   ไฟล์โลโก้ 1280x1280 มีงานสองก้อนวางซ้อนกันตามแนวตั้ง
   (วัดจากไฟล์จริงด้วยการไล่พิกเซลที่ "ไม่ใช่ครีมพื้น" ไม่ได้กะเอา)
     จอมือถือ    x 465-865  y 134-877   (รวมสันข้างแบบสามมิติ)
     ตัว UNIDEA  x 153-1125 y 896-1147  (รวมเงาซ้อนสามชั้นใต้ตัวอักษร)
   เว็บวางโลโก้เป็นแนวนอน (ป้ายซ้าย ตัวอักษรขวา) แต่ไฟล์วางแนวตั้ง
   เลยครอปทีละก้อนด้วย background-size + background-position แทนการตัดไฟล์ใหม่
   ใช้ไฟล์เดียวได้ทั้งสองที่ ไม่ต้องเพิ่มไฟล์รูปและไม่ต้องยิงรีเควสต์เพิ่ม

   สูตรครอป: background-size     = ขนาดภาพ / ขนาดกรอบที่ต้องการ
             background-position = ระยะจากขอบ / (ขนาดภาพ - ขนาดกรอบ)
   สองค่านี้ผูกกัน ถ้าจะขยับกรอบต้องคำนวณใหม่ทั้งคู่ แก้ค่าเดียวภาพจะเลื่อน

   พื้นครีมติดมากับไฟล์ (jpeg ไม่มีพื้นใส) ป้าย .wordmark เลยต้องเป็นครีม
   ตัวเดียวกับในไฟล์ (#F3DCBC = --logo-ground) ขอบรอบรูปที่ครอปจึงเนียนสนิท */
.wordmark__mark {
  width: 1.4rem;
  aspect-ratio: 401 / 744;              /* สัดส่วนจอมือถือในโลโก้ */
  height: auto;
  background-image: url('logo.jpg');
  background-size: 319.20% 172.04%;     /* 1280/401 · 1280/744 */
  background-position: 52.90% 25%;      /* 465/879 · 134/536 */
  background-repeat: no-repeat;
  flex: none;
}
/* SVG ที่เคยวาดเลียนแบบไว้ยังอยู่ใน HTML เผื่ออยากสลับกลับ
   (เวกเตอร์คมกว่าและเปลี่ยนสีตามโทเคนได้ ต่างจาก jpeg ที่สีตายตัว) */
.wordmark__mark svg { display: none; }
/* ตัวอักษรก็ครอปมาจากไฟล์โลโก้เหมือนกัน

   ทรงตัวอักษรในโลโก้เป็นแบบบวมกลมเส้นหนา ซึ่งไม่มีฟอนต์เว็บตัวไหนทำได้
   ก่อนหน้านี้เลียนด้วย Mali 700 + -webkit-text-stroke ซึ่งได้แค่ "หนาใกล้เคียง"
   แต่ทรงตัวอักษรคนละเรื่องกันเลย — ใช้ของจริงจบกว่า

   ข้อความ UNIDEA ยังอยู่ใน DOM ครบ แค่ดันออกนอกกรอบด้วย text-indent
   สกรีนรีดเดอร์กับ SEO ยังอ่านชื่อแบรนด์ได้เหมือนเดิม ไม่ได้หายไปเป็นรูปเปล่า ๆ
   (นี่คือเหตุผลที่ไม่ใช้ <img> แทน — จะต้องไปแก้ HTML ทุกที่ที่วางโลโก้)

   หมายเหตุคอนทราสต์: ตัวอักษรขาวบนชมพูได้ 2.29:1 ซึ่งต่ำกว่าเกณฑ์ปกติ
   แต่ WCAG 1.4.3 ยกเว้น "logotype" ไว้ — ชื่อแบรนด์ในรูปแบบโลโก้ไม่ต้องผ่านเกณฑ์
   และข้อความจริงยังอยู่ใน DOM ให้เครื่องช่วยอ่านอยู่แล้ว */
.wordmark__text {
  /* ในไฟล์โลโก้ ตัวอักษรกว้างกว่าจอมือถือ 2.4 เท่า ชื่อแบรนด์คือพระเอก
     ถ้าปล่อยให้ตัวอักษรเตี้ยกว่านี้ จอมือถือจะกลายเป็นตัวเด่นแทน ซึ่งกลับด้าน */
  height: 1.55rem;
  aspect-ratio: 973 / 252;              /* สัดส่วนตัวอักษรในโลโก้ */
  background-image: url('logo.jpg');
  background-size: 131.55% 507.94%;     /* 1280/973 · 1280/252 */
  background-position: 49.84% 87.16%;   /* 153/307 · 896/1028 */
  background-repeat: no-repeat;
  /* ดันตัวอักษรจริงออกนอกกรอบ แต่ไม่ได้ลบทิ้ง */
  text-indent: -100em;
  overflow: hidden;
  white-space: nowrap;
  flex: none;
}

.pitch__headline {
  font-size: clamp(2.35rem, 1.1rem + 5.4vw, 4.1rem);
  /* Mali เบากว่า Mitr ที่น้ำหนักเท่ากัน หัวข้อเลยต้องขึ้นเป็น 700
     และคลาย letter-spacing เพราะทรงตัวอักษรมนอยู่แล้ว บีบอีกจะอ่านยาก */
  font-weight: 700;
  letter-spacing: -0.015em;
  margin-bottom: 1.25rem;
}
/* ขีดเน้นแบบปากกาเมจิก วาดด้วย gradient ให้ดูเหมือนหมึกทับ */
.pitch__accent {
  position: relative;
  /* เดิมเป็นตัวหนังสือส้มบนแถบเหลืองโปร่ง ซึ่งใช้กับพื้นครีมได้
     พอพื้นเป็นชมพู แถบเหลืองโปร่งจะกลายเป็นส้ม (#FF9F32) ตัวหนังสือส้มเหลือ 1.57:1
     เลยเปลี่ยนเป็นแถบเหลืองทึบ + ตัวหนังสือหมึกม่วง ได้ 8.23:1 */
  color: var(--ink);
  background-image: linear-gradient(var(--sun) 0 100%);
  background-size: 100% 0.42em;
  background-position: 0 78%;
  background-repeat: no-repeat;
  padding-inline: 0.12em;
}

.pitch__lede {
  font-size: clamp(1rem, 0.95rem + 0.35vw, 1.18rem);
  color: var(--ink-2);
  max-width: 34ch;
  margin-bottom: 2rem;
}

.pitch__points { list-style: none; display: grid; gap: 0.85rem; }
.pitch__points li {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.7rem;
  align-items: baseline;
  font-size: 0.95rem;
  color: var(--ink-2);
  max-width: 42ch;
}
.dot {
  width: 0.7rem; height: 0.7rem;
  border-radius: 50%;
  translate: 0 0.15rem;
}
.dot--sun { background: var(--sun); }
.dot--grape { background: var(--grape); }
.dot--vermilion { background: var(--vermilion); }

/* ---------- ฝั่งขวา: แผงฟอร์ม ---------- */
.panel {
  position: relative;
  background: color-mix(in oklch, var(--paper) 82%, white);
  border: 1.5px solid var(--ink-line);
  border-radius: var(--radius-lg);
  padding: clamp(1.75rem, 3.5vw, 2.5rem);
  box-shadow: var(--lift);
}
/* เทปกาวติดมุมแผง */
.panel__tape {
  position: absolute;
  top: -0.85rem; right: 1.75rem;
  background: var(--sun);
  color: var(--ink);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  padding: 0.3rem 0.9rem;
  border-radius: 999px;
  transform: rotate(3deg);
  box-shadow: 0 3px 0 color-mix(in oklch, var(--sun) 60%, var(--ink));
}

.panel__title { font-size: 1.6rem; font-weight: 600; letter-spacing: -0.025em; }
.panel__sub {
  color: var(--ink-2);
  font-size: 0.92rem;
  margin: 0.35rem 0 1.75rem;
}
.panel__sub strong { color: var(--ink); font-weight: 600; word-break: break-all; }

.step { display: grid; gap: 1.1rem; }
.step[hidden] { display: none; }

.field { display: grid; gap: 0.45rem; }
.field label {
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.03em;
  color: var(--ink-2);
  text-transform: uppercase;
}

/* ช่องกรอกเป็น "ช่องที่ถูกเจาะลงไปในกระดาษ" ไม่ใช่การ์ดที่ลอยขึ้นมา
   ขอบหมึกเต็มเส้นเหมือนทุกอย่าง + เงาแข็งกลับด้าน (inset) ตอนยังไม่โฟกัส */
input {
  font: inherit;
  width: 100%;
  padding: 0.85rem 1rem;
  border-radius: var(--radius);
  border: var(--ink-w) solid var(--ink);
  background: white;
  color: var(--ink);
  box-shadow: inset 3px 3px 0 color-mix(in oklch, var(--ink) 9%, transparent);
  transition: border-color 0.18s var(--ease), box-shadow 0.18s var(--ease);
}
input::placeholder { color: var(--ink-3); }
input:focus {
  outline: none;
  border-color: var(--ink);
  /* โฟกัสแล้วช่องยกขึ้นมาเป็นเหลือง = จุดที่กำลังพิมพ์อยู่ เห็นจากหางตาได้ */
  box-shadow: 0 0 0 4px var(--sun), 0 0 0 calc(4px + var(--ink-w)) var(--ink);
}

/* ป้ายบอกมหาลัยที่ตรวจเจอจากอีเมล */
.uni-detect {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--leaf);
  animation: rise 0.4s var(--ease) both;
}
.uni-detect[hidden] { display: none; }
.uni-detect--miss { color: var(--vermilion-lo); font-weight: 500; }

/* ---------- ช่องรหัส 6 หลัก ---------- */
.otp {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  justify-content: space-between;
}
.otp__box {
  flex: 1 1 0;
  min-width: 0;
  aspect-ratio: 3 / 3.6;
  padding: 0;
  text-align: center;
  font-family: 'Mali', sans-serif;
  font-size: clamp(1.25rem, 4vw, 1.6rem);
  font-weight: 500;
  background: var(--paper);
  caret-color: var(--vermilion);
}
.otp__box--filled {
  border-color: var(--ink);
  background: color-mix(in srgb, var(--sun) 22%, var(--paper));
}
.otp__sep {
  width: 0.75rem; height: 2px;
  background: var(--line-strong);
  border-radius: 2px;
  flex-shrink: 0;
}

.panel__foot {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
}

.fineprint { font-size: 0.8rem; color: var(--ink-3); }

/* ---------- ยินยอมก่อนเริ่ม (อายุ 18+ / เงื่อนไข) ---------- */
.consent {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.6rem;
  align-items: start;
  margin: 0.2rem 0 1rem;
  font-size: 0.84rem;
  line-height: 1.55;
  color: var(--ink-2);
  cursor: pointer;
}
.consent input {
  width: 1.15rem;
  height: 1.15rem;
  margin: 0.1rem 0 0;
  accent-color: var(--vermilion);
  cursor: pointer;
  flex: none;
}
/* ส้มสด (--vermilion) เป็นตัวหนังสือไม่ได้ — บนกระดาษขาวได้ 2.97:1
   และพอการ์ดฟอร์มเปลี่ยนเป็นพื้นเหลืองจาง เหลือ 2.90:1 ยิ่งแย่ลง
   --vermilion-ink คือเฉดเดียวกันที่เข้มพอเป็นตัวหนังสือ (4.65:1)
   ตามองแทบไม่เห็นต่าง แต่ผ่านเกณฑ์ — ใช้ตัวนี้กับลิงก์ทุกที่ที่อยู่บนกระดาษ */
.consent a {
  color: var(--vermilion-ink);
  text-underline-offset: 2px;
}
.consent a:hover { text-decoration-thickness: 2px; }

/* ปุ่มที่ยังกดไม่ได้ ต้องดูออกว่ากดไม่ได้ ไม่ใช่แค่จางลงเฉยๆ

   เดิมใช้ opacity + grayscale ซึ่งอ่านว่า "ปุ่มนี้เสีย" ปุ่มยังมีเงาแข็งอยู่
   เลยดูเหมือนปุ่มปกติที่จอเพี้ยน — ถอดเงาออกแล้วแทนด้วยขอบเส้นประ
   ปุ่มจึงแบนราบไปกับกระดาษ = ยังไม่ถูกยกขึ้นมาให้กด ซึ่งตรงกับความจริง
   และสื่อได้โดยไม่ต้องพึ่งสี ตรงกับหลักที่ตั้งไว้ใน .impeccable.md */
.btn:disabled {
  cursor: not-allowed;
  background: transparent;
  color: var(--ink-3);
  border: var(--ink-w) dashed color-mix(in oklch, var(--ink) 38%, transparent);
  box-shadow: none;
  transform: none;
}
/* ปุ่มที่ปิดอยู่บนเวทีมืดต้องกลับขั้วสี
   หมึกจาง --ink-3 เป็นสีเข้ม พอไปวางบนพื้นเวทีที่เข้มกว่าเหลือ 3.71:1
   บนพื้นมืดต้องใช้สีกระดาษ ไม่ใช่สีหมึก */
.stage .btn:disabled {
  color: color-mix(in oklch, var(--paper) 70%, transparent);
  border-color: color-mix(in oklch, var(--paper) 45%, transparent);
}

/* ---------- แผ่นข้อมูล PDPA ---------- */
.foot__link {
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
}
.foot__link:hover { color: var(--vermilion); }

/* เส้นขอบเป็นหมึกเข้ม ไม่ใช่เส้นจาง — ขาวบนชมพูได้แค่ 2.29:1
   ถ้าใช้เส้นจางแบบเดิม ขอบการ์ดจะหายไปกับพื้น */
.sheet {
  border: var(--ink-w) solid var(--ink);
  border-radius: var(--radius-lg);
  background: var(--paper);
  color: var(--ink);
  padding: 1.5rem;
  max-width: min(30rem, 92vw);
  box-shadow: var(--lift);
  /* `* { margin: 0 }` ด้านบนลบ margin:auto ที่เบราว์เซอร์ใช้วาง dialog กลางจอ หน้าต่างเลยไปติดมุมซ้ายบน */
  margin: auto;
}
.sheet::backdrop { background: color-mix(in oklch, var(--ink) 55%, transparent); }
.sheet__title { margin: 0 0 0.75rem; font-size: 1.1rem; }
.sheet__body { font-size: 0.88rem; line-height: 1.7; color: var(--ink-2); }
.sheet__body dl { display: grid; grid-template-columns: auto 1fr; gap: 0.35rem 0.9rem; margin: 0.5rem 0; }
.sheet__body dt { color: var(--ink-3); }
.sheet__body dd { margin: 0; word-break: break-all; }
.sheet__body code { font-size: 0.82rem; background: var(--paper-3); padding: 0.1rem 0.35rem; border-radius: 5px; }
.sheet__actions {
  display: flex;
  justify-content: space-between;
  gap: 0.75rem;
  margin-top: 1.25rem;
}

/* ---------- หน้ากั้น "ต้องเปิดกล้อง" (#cam-gate) ---------- */
/* จำกัดไว้ที่หน้านี้ ไม่แตะ .sheet__body ตัวอื่น (#mydata-dialog ใช้คลาสเดียวกัน) */
#cam-gate .sheet__body p { margin: 0 0 0.6rem; }
#cam-gate .sheet__body p:last-child { margin-bottom: 0; }

/* บรรทัดบอกสาเหตุ — ขึ้นก่อนคำอธิบายทั่วไป เพราะคนเปิดหน้านี้มาเพื่อรู้ว่า "ติดตรงไหน"
   ใช้ --vermilion-ink ตามกฎที่เขียนไว้ข้างบน (ส้มสดเป็นตัวหนังสือบนกระดาษไม่ผ่าน)
   ไม่ได้สื่อด้วยสีอย่างเดียว ตัวหนังสือบอกสาเหตุอยู่แล้ว */
.cam-gate__why {
  font-weight: 600;
  color: var(--vermilion-ink);
}

/* หัวข้อของรายการวิธีแก้ — ข้อความเปลี่ยนตามเคส (app.js เขียน) เช่น "ปลดแบบนี้:"
   ต้องเข้มกว่าตัวเนื้อ เพราะมันคือจุดที่สายตาต้องกระโดดลงไปอ่านขั้นตอน */
.cam-gate__steps-title {
  margin: 0.9rem 0 0;
  font-weight: 600;
  color: var(--ink);
}

.cam-gate__steps {
  margin: 0.4rem 0 0;
  padding-left: 1.15rem;
  display: grid;
  gap: 0.35rem;
}
.cam-gate__steps:empty { display: none; }

/* ---------- โดนแบน ---------- */
.banned {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: grid;
  place-items: center;
  padding: 1.5rem;
  background: var(--stage);
  color: var(--paper);
  text-align: center;
}
.banned[hidden] { display: none; }
.banned__inner { max-width: 26rem; display: grid; gap: 0.9rem; justify-items: center; }
.banned__icon { font-size: 2.5rem; }
.banned__title { margin: 0; font-size: 1.3rem; }
.banned__text { margin: 0; color: color-mix(in oklch, var(--paper) 72%, transparent); line-height: 1.7; }
.banned__hint { font-size: 0.85rem; color: color-mix(in oklch, var(--paper) 55%, transparent); }
.banned a { color: var(--sun); }

/* ---------- ข้อความแจ้งผล ---------- */
.notice {
  font-size: 0.88rem;
  padding: 0.75rem 0.95rem;
  border-radius: var(--radius);
  border: var(--ink-w) solid var(--ink);
  border-left-width: 6px;
  border-left-color: var(--vermilion);
  background: color-mix(in srgb, var(--vermilion) 14%, white);
  color: var(--vermilion-ink);
  animation: rise 0.35s var(--ease) both;
}
.notice[hidden] { display: none; }
.notice--info {
  border-left-color: var(--grape);
  background: color-mix(in srgb, var(--grape) 12%, white);
  color: color-mix(in oklch, var(--grape) 80%, var(--ink));
}

.foot {
  display: flex;
  justify-content: center;
  gap: 0.5rem;
  padding: 1.5rem;
  font-size: 0.78rem;
  color: var(--ink-3);
  flex-shrink: 0;
}
.foot__sep { opacity: 0.5; }

/* ==========================================================================
   ปุ่ม — ทรงคีย์แคป กดแล้วยุบลง
   ========================================================================== */
.btn {
  font: inherit;
  font-family: 'Mali', 'Anuphan', sans-serif;
  border: none;
  cursor: pointer;
  border-radius: var(--radius);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  transition: transform 0.14s var(--ease), box-shadow 0.14s var(--ease),
              background-color 0.18s var(--ease), color 0.18s var(--ease);
}

/* ม่วงคือสีของ "ลงมือทำ" ทั้งเว็บ — ปุ่มเริ่ม/คนถัดไปในห้องคุยเป็นม่วงอยู่แล้ว
   ปุ่มหลักหน้าแรกเคยเป็นเหลือง ซึ่งแปลว่าผู้ใช้ต้องเรียนรู้สีปุ่มหลักใหม่รอบหนึ่ง
   ตอนข้ามจากหน้าแรกเข้าห้องคุย ย้ายมาเป็นม่วงเหมือนกันหมด แล้วปล่อยให้เหลือง
   ทำหน้าที่เดียวคือ "เน้น" (เทป ขีดเส้นใต้หัวเรื่อง ป้าย) ไม่ใช่ทั้งเน้นทั้งสั่งงาน */
.btn--primary {
  background: var(--grape);
  color: white;
  padding: 0.9rem 1.5rem;
  font-size: 1.02rem;
  font-weight: 600;
  border: var(--ink-w) solid var(--ink);
  box-shadow: 0 5px 0 var(--ink);
}
.btn--primary:hover:not(:disabled) {
  background: color-mix(in oklch, var(--grape) 88%, white);
  transform: translateY(-1px);
  box-shadow: 0 6px 0 var(--ink);
}
.btn--primary:active:not(:disabled) {
  transform: translateY(5px);
  box-shadow: 0 0 0 var(--ink);
}

.btn--text {
  background: none;
  color: var(--ink-2);
  padding: 0.5rem 0.25rem;
  font-size: 0.88rem;
  font-family: 'Anuphan', sans-serif;
  font-weight: 500;
  text-decoration: underline;
  text-decoration-color: var(--line-strong);
  text-underline-offset: 4px;
}
.btn--text:hover { color: var(--vermilion); text-decoration-color: currentColor; }
.btn--text:disabled { opacity: 0.45; cursor: default; text-decoration: none; }

/* ปุ่มหลักเด้งหนึ่งครั้งตอนเพิ่งกดได้ — ผู้ใช้ติ๊กช่องยินยอมแล้วสายตายังอยู่ที่ช่องติ๊ก
   ปุ่มอยู่คนละที่กัน ถ้าไม่มีอะไรขยับเลยจะไม่รู้ว่าเพิ่งปลดล็อกอะไรให้
   (app.js ถอด disabled ออกเมื่อติ๊กครบ กฎนี้จึงยิงเองโดยไม่ต้องแตะ JS) */
.btn--primary:not(:disabled) { animation: unlock-pop 0.42s var(--ease); }
@keyframes unlock-pop {
  0%   { transform: scale(1); }
  38%  { transform: scale(1.035) translateY(-2px); }
  100% { transform: scale(1); }
}
@media (prefers-reduced-motion: reduce) {
  .btn--primary:not(:disabled) { animation: none; }
}

/* ---------- แอนิเมชันตอนกำลังโหลด ---------- */
.btn.is-busy .btn__label { opacity: 0.55; }
.btn.is-busy::after {
  content: '';
  width: 0.9rem; height: 0.9rem;
  border: 2px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  animation: spin 0.65s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* ==========================================================================
   ห้องคุย
   ========================================================================== */
/* พื้นห้องคุย = ครีมเรียบ ตัวเดียวกับพื้นในภาพลายที่เจ้าของวาด (หน้าแรก)
   ไม่ใช้ภาพลายนั้นซ้ำที่นี่ เพราะช่องไฟระหว่างการ์ดกว้างแค่ ~14px จะเห็นลาย
   เป็นเศษแถบสีตามขอบการ์ด ดูเหมือนจอเพี้ยนมากกว่าเป็นลาย
   ลายเส้นทแยง + จุดฮาล์ฟโทนเดิมถอดออกแล้ว (เป็นลายของธีมชมพูเก่า) — สีเรียบเข้ากับ
   ภาพวาดที่เป็นสีแบนมากกว่า และไม่แย่งสายตาจากวิดีโอ */
#chat-screen {
  display: none;
  height: 100svh;
  background: var(--ground);
  grid-template-columns: 1fr;
  grid-template-rows: 1fr auto;
}
#chat-screen.active { display: grid; }

/* ---------- เวทีวิดีโอ ---------- */
.stage {
  /* ต้องระบุช่องให้ชัด: เบราว์เซอร์วางของที่ล็อก grid-row ไว้ (คือ .chat) ก่อนของที่ไม่ล็อก
     ถ้าไม่ระบุ .chat จะไปกินคอลัมน์ 1fr แล้วดันวิดีโอไปอยู่คอลัมน์แคบแทน */
  grid-area: 1 / 1;
  /* ปัดแนวนอนเป็นของเรา (ข้ามไปคนถัดไป) เลื่อนแนวตั้งยังเป็นของเบราว์เซอร์
     ถ้าไม่จองไว้ Chrome บน Android จะกินท่าปัดข้างไปทำ "ย้อนกลับ" แทน */
  touch-action: pan-y;
  position: relative;
  overflow: hidden;
  background: var(--stage);
  margin: var(--pane-gap);
  margin-bottom: 0;
  border-radius: var(--radius-lg);
  /* ขอบหมึกคม + เงาแข็งเยื้อง = รูปที่ถูกแปะลงบนกระดาษ ไม่ใช่ div ที่มีเงาฟุ้ง */
  border: var(--ink-w) solid var(--ink);
  box-shadow: var(--drop-2);
}

/* กรอบอ้างอิงของทุกอย่างที่ลอยทับวิดีโออีกฝ่าย (ป้าย/หน้ารอ/หน้าเตรียมตัว)
   จอแคบ = เต็มเวที · จอกว้าง = บานซ้ายอย่างเดียว ไม่ล้ำไปทับวิดีโอตัวเอง */
.stage__remote {
  position: relative;
  width: 100%;
  height: 100%;
  overflow: hidden;
  background: var(--stage);
  /* ขนาดกระเบื้องภาพลายหน้าแรก — หน้าพัก (.empty-pane) กับหน้ารอ (.waiting) อ่านค่าเดียวกัน
     ประกาศที่บานนี้ ไม่ใช่ที่ลูกแต่ละตัว: ถ้าสองหน้าใช้ขนาดต่างกัน ตอนกดเริ่มลายจะกระตุกเปลี่ยนขนาด
     กว้างเท่าหน้าแรก (landing.css 604px) สูงตามสัดส่วนไฟล์กระเบื้อง 1208x1212 */
  --tile-w: 604px;
  --tile-h: calc(var(--tile-w) * 1212 / 1208);
  /* ระยะมุมของป้ายแชมป์บนบานนี้ (ความหมายเดียวกับที่ .selfie) */
  --tag-x: 0.75rem;
  --tag-y: 0.6rem;
  --frame-w: 0px;
}

#remote-video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* ---------- ช่องคู่สนทนาตอนยังไม่มีใคร ---------- */
/* โผล่เฉพาะตอนอยู่ห้องเตรียมตัว พอกดเริ่มแล้ว overlay "กำลังหาคนคุย" จะมาทับ */
.empty-pane { display: none; }
/* พื้นลายหน้าแรกแบบ "นิ่ง" + การ์ดกระดาษ — ชุดเดียวกับหน้า "กำลังหาคนคุย" ซึ่งลายเลื่อน
   (เจ้าของเลือก 14 ก.ย. 2569) กดเริ่มแล้วสิ่งที่เปลี่ยนคือลายเริ่มขยับกับข้อความในการ์ด
   = คนรู้สึกว่าหน้าเดิมเริ่มทำงาน ไม่ใช่กระโดดไปอีกหน้า
   เดิมเป็นพื้นมืดกับกรอบเส้นประ พอหน้ารอเปลี่ยนเป็นลายครีม กดเริ่มทีจอเปลี่ยนจากมืดเป็นสว่างทันที
   ไม่เลื่อนลายตรงนี้ เพราะคนกำลังเช็คหน้าตัวเองในบานข้าง ๆ และการขยับต้องเก็บไว้บอกว่า "กำลังหา"
   ไม่มีกรอบเส้นประแล้ว — เส้นประในเว็บนี้แปลว่า "ยังกดไม่ได้" (ปุ่มหยุดตอนยังไม่เริ่ม)
   ลายเริ่มที่มุมซ้ายบนเหมือน .waiting::before ตอนสลับหน้าลายเลยอยู่ตำแหน่งเดิมพอดี */
#chat-screen.is-lobby .empty-pane {
  display: grid;
  position: absolute;
  inset: 0;
  z-index: 1;
  place-items: center;
  padding: 2rem;
  text-align: center;
  background: var(--ground) url('login-bg.jpg') repeat left top / var(--tile-w) var(--tile-h);
}
/* หน้าตาการ์ดใช้กฎร่วมกับ .waiting__inner (อยู่ส่วน "สถานะระหว่างรอ") ตรงนี้แค่เป็นจุดเกาะของดาว */
.empty-pane__card { position: relative; }
/* บานนี้คือพื้นที่ใหญ่ที่สุดที่เห็นตอนเข้าห้อง และเป็นอย่างแรกที่ผู้ใช้ใหม่เจอ
   ของเดิมเป็นกล่องมืดโล่ง ๆ ที่มีตัวหนังสือจาง 72%/45% ลอยอยู่กลาง
   ซึ่งอ่านว่า "ยังไม่มีอะไร" มากกว่า "กำลังจะสนุกแล้ว" — ดันน้ำหนักขึ้นให้เป็น
   หัวเรื่องจริง แล้วทำบรรทัดบอกวิธีเริ่มเป็นป้ายเหลืองที่มองไม่พลาด */
.empty-pane__text {
  margin: 0.35rem 0 0;
  font-family: 'Mali', 'Anuphan', sans-serif;
  font-size: clamp(1.3rem, 1.05rem + 1vw, 1.85rem);
  font-weight: 700;
  letter-spacing: -0.015em;
  color: var(--ink);
}
/* บอกขั้นตอนถัดไปตรงนี้เลย ผู้ใช้ครั้งแรกจะได้ไม่ต้องกวาดตาหาปุ่ม
   ป้ายเหลืองขอบหมึก = ภาษาเดียวกับเทป/ป้ายทั้งเว็บ แค่กลับมาอยู่บนพื้นมืด */
/* ป้ายบอกวิธีเริ่มมีสองคำ สลับตาม "อุปกรณ์ชี้หลัก" ไม่ใช่ความกว้างจอ:
     จอสัมผัส (โทรศัพท์ + iPad ทั้งแนวตั้งและแนวนอน) = "ปัดซ้ายบนวิดีโอ"
     เมาส์/ทัชแพด (รวมหน้าต่างคอมที่ย่อแคบ — ใช้เมาส์ปัดไม่ได้) = "กดปุ่ม เริ่ม"
   เดิมสลับที่ 859px iPad แนวนอนกว้างกว่านั้น เลยได้คำว่ากดปุ่มทั้งที่ถือเครื่องปัดอยู่ (เจ้าของทัก 14 ก.ย. 2569)
   ต้องตรงกับ startHow() ใน app.js ซึ่งถาม (pointer: coarse) แบบเดียวกัน */
.empty-pane__how--swipe { display: none; }
@media (pointer: coarse) {
  .empty-pane__how--button { display: none; }
  .empty-pane__how--swipe { display: inline; }
}
/* โชว์ทีละใบ: ปกติใบชวนเริ่ม · กล้องไม่ติดสลับเป็นใบบอกให้เปิดกล้อง (app.js ใส่ .cam-blocked) */
.empty-pane__hint--cam { display: none; }
#chat-screen.cam-blocked .empty-pane__hint:not(.empty-pane__hint--cam) { display: none; }
#chat-screen.cam-blocked .empty-pane__hint--cam { display: block; }

.empty-pane__hint {
  margin: 0.55rem 0 0;
  padding: 0.4rem 1rem;
  border-radius: 999px;
  background: var(--sun);
  border: var(--ink-w) solid var(--ink);
  box-shadow: 0 3px 0 var(--ink);
  color: var(--ink);
  font-size: 0.92rem;
  font-weight: 600;
  transform: rotate(-1.2deg);
}

/* ดาวกระจายสองดวงแปะมุมการ์ด — ตัวเดียวกับที่แปะมุมฟอร์มหน้าแรก
   ทำให้ห้องคุยตอนว่างยังรู้สึกเป็นเว็บเดียวกับหน้าแรก ไม่ใช่จอดำของแอปอื่น */
.empty-pane__card::before,
.empty-pane__card::after {
  content: '';
  position: absolute;
  z-index: 1;
  background-repeat: no-repeat;
  background-size: contain;
  pointer-events: none;
  opacity: 0.85;
}
.empty-pane__card::before {
  width: 46px; height: 46px;
  top: -24px; left: -22px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 48 48'%3E%3Cpath d='M24 1.5 29.4 16l14.6-5-5 14.6 14.4 5.4-14.4 5.4 5 14.6-14.6-5L24 60l-5.4-14.4-14.6 5 5-14.6L-5.4 30.6 9 25.2l-5-14.6 14.6 5Z' transform='scale(0.78) translate(6.5 6.5)' fill='%23EB9F25' stroke='%23251E25' stroke-width='2.4' stroke-linejoin='round'/%3E%3C/svg%3E");
  animation: sticker-drift 9s var(--ease) infinite;
}
.empty-pane__card::after {
  width: 34px; height: 34px;
  right: -16px; bottom: -16px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 48 48'%3E%3Cpath d='M24 1.5 29.4 16l14.6-5-5 14.6 14.4 5.4-14.4 5.4 5 14.6-14.6-5L24 60l-5.4-14.4-14.6 5 5-14.6L-5.4 30.6 9 25.2l-5-14.6 14.6 5Z' transform='scale(0.78) translate(6.5 6.5)' fill='%23BE808B' stroke='%23251E25' stroke-width='2.4' stroke-linejoin='round'/%3E%3C/svg%3E");
  animation: sticker-drift 11s var(--ease) infinite reverse;
}
/* ลอยขึ้นลงเบา ๆ พร้อมหมุนนิดหน่อย — ไม่ใช่หมุนรอบตัวเองแบบหน้าแรก
   เพราะบานนี้มีตัวหนังสือให้อ่านอยู่ตรงกลาง การหมุนต่อเนื่องจะดึงสายตาเกินไป */
@keyframes sticker-drift {
  0%, 100% { transform: translateY(0) rotate(-8deg); }
  50%      { transform: translateY(-12px) rotate(8deg); }
}

/* โลโก้ขึ้นทุกขนาดจอ — เดิมจอกว้างใช้อีโมจิ 👋 แทน ด้วยเหตุผลว่าโลโก้ซ้ำกับ
   หัวหน้าแรกที่เพิ่งผ่านมา แต่ 👋 เป็นอีโมจิของระบบปฏิบัติการ หน้าตาเปลี่ยนไป
   ตามเครื่อง (Apple/Google/Windows คนละแบบ) และไม่ได้เป็นของแบรนด์นี้เลย
   บานนี้เป็นพื้นที่ใหญ่ที่สุดที่คนเปิดค้างไว้จ้อง — ให้เป็นโลโก้จริงคุ้มกว่า */
.empty-pane__logo {
  display: inline-flex;
  margin: 0 0 0.55rem;
}
.empty-pane__logo .wordmark__mark { width: 1.85rem; }
.empty-pane__logo .wordmark__text { height: 2.05rem; }

/* ---------- จอแคบ: หน้าพักตัวเล็กลงหนึ่งขั้น ----------
   เดิมตรงนี้คือชุดกฎของปุ่มที่ลอยทับบานคู่สนทนา (.stage-actions / .stage-gender)
   ตอนที่จอแคบไม่มีแถบปุ่มแล้วใช้ปัดแทน — ถอดออกทั้งชุดเมื่อโทรศัพท์กลับมาใช้
   แถบปุ่มแบบ iPad (เจ้าของเลือก 14 ก.ย. 2569) ท่าปัดยังใช้ได้เป็นทางลัด
   ป้ายเหลือง "กดปุ่ม เริ่ม" ห้ามตั้งสีตัวหนังสือทับในจอแคบ — กฎเก่าเคยสั่งขาว 62%
   ทับพื้นเหลืองจนเหลือคอนทราสต์ 1.29:1 ปล่อยให้ใช้สีหมึกจากกฎรวมข้างบน */
@media (max-width: 859px) {
  #chat-screen.is-lobby .empty-pane { padding: 1.2rem; }
  /* ขอบบานเหลือแค่ ~19px รอบการ์ด ดาวที่ยื่นออกมุมละ 22px ของจอกว้างโดนขอบบานตัดหาย
     ย่อดาวลงแล้วดึงเข้ามาให้ยื่นพ้นมุมการ์ดไม่เกินระยะนั้น (วัดแล้วที่จอ 320–390) */
  .empty-pane__card::before { width: 36px; height: 36px; top: -16px; left: -12px; }
  .empty-pane__card::after  { width: 28px; height: 28px; right: -10px; bottom: -12px; }
  .empty-pane__logo { margin-bottom: 0.35rem; }
  /* ภาพครอปจากไฟล์โลโก้มีพื้นติดมาเอง ยืนบนพื้นมืดของเวทีได้โดยไม่ต้องสลับสี */
  .empty-pane__logo .wordmark__mark { width: 1.25rem; }
  .empty-pane__logo .wordmark__text { height: 1.4rem; }
}

/* ---------- ป้ายสติกเกอร์บนเวที ---------- */
.sticker {
  position: absolute;
  z-index: 4;
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.45rem 0.9rem;
  border-radius: 999px;
  font-size: 0.82rem;
  font-weight: 600;
  animation: rise 0.5s var(--ease) both;
}
.sticker[hidden] { display: none; }

/* มีแต่สัญลักษณ์ ไม่มีคำ — ขยายตัวอักษรให้ 🎓 ไม่จิ๋ว และลดขอบข้างให้ป้ายไม่โหวง */
.sticker--peer {
  top: 1rem; left: 1rem;
  padding: 0.35rem 0.65rem;
  font-size: 1.05rem;
  line-height: 1;
  background: var(--sun);
  color: var(--ink);
  transform: rotate(-1.5deg);
  border: var(--ink-w) solid var(--ink);
  box-shadow: var(--drop-1);
}
/* ต้องอยู่เหนือ overlay ระหว่างรอ เพราะเป็นข้อมูลที่ต้องเห็นตลอด
   อยู่ในบานของเรา (.selfie) ไม่ใช่บานอีกฝ่าย เพราะพูดถึงกล้องของเรา */
.sticker--demo {
  border: var(--ink-w) solid var(--ink);
  box-shadow: var(--drop-1);
  top: 1rem; left: 50%;
  translate: -50% 0;
  z-index: 6;
  /* ส้มสดรองตัวหนังสือครีมได้แค่ 2.97:1 ไม่ผ่าน — ส้มเข้มได้ 4.53:1 ตาแทบไม่เห็นต่าง */
  background: var(--vermilion-lo);
  color: var(--paper);
  font-weight: 500;
  max-width: calc(100% - 1.5rem);
  text-align: center;
  /* เป็น <button> แล้ว — ล้างฟอนต์ระบบกับพื้นหลังเริ่มต้นของปุ่มทิ้ง ให้เหมือนป้ายอื่นๆ */
  font-family: inherit;
  cursor: pointer;
}
.sticker--demo:hover { background: var(--vermilion-ink); }
.sticker--demo:focus-visible { outline: 3px solid var(--sun); outline-offset: 2px; }

/* ตัวจับเวลาการคุย (#session-timer) เอาออกแล้ว — เจ้าของไม่อยากให้มี (15 ก.ย. 2569) */

/* ---------- สถานะระหว่างรอ ---------- */
.waiting {
  position: absolute;
  inset: 0;
  z-index: 5;
  display: grid;
  place-items: center;
  padding: 2rem;
  text-align: center;
  /* พื้นเป็นภาพลายที่เจ้าของวาด ตัวเดียวกับหน้าแรก (เจ้าของขอ 14 ก.ย. 2569) แล้วเลื่อนขึ้นช้า ๆ
     บานนี้เป็นบานเดียวที่ผู้ใช้จ้องนาน ๆ ระหว่างรอ ถ้านิ่งสนิทจะอ่านว่า "จอค้าง"
     มากกว่า "กำลังหาให้อยู่" — เดิมเป็นเส้นทแยงบนพื้นไล่สีมืด ซึ่งผิดกฎ "สีแบน ห้ามไล่สี"
     ลายอยู่บนชั้น ::before แยก เพื่อเลื่อนด้วย transform (การ์ดจอทำให้ ไม่ต้องวาดใหม่ทุกเฟรม)
     ถ้าเลื่อน background-position ตรง ๆ โทรศัพท์ต้องวาดพื้นทั้งบานใหม่ 60 ครั้งต่อวินาที
     ขนาดกระเบื้องเท่าหน้าแรก (landing.css): กว้าง 604px สูงตามสัดส่วนไฟล์ 1208x1212
     เลื่อนครบหนึ่งกระเบื้องแนวตั้งแล้ววนใหม่ = ไม่เห็นรอยต่อ (แนวตั้งซ้ำทุก 1212px ของไฟล์เป๊ะ
     ส่วนแนวนอนวาดมือ ซ้ำไม่เป๊ะ จึงเลื่อนแนวตั้งอย่างเดียว) */
  background: var(--ground);
  overflow: hidden;
  isolation: isolate;          /* ให้ชั้นลาย z-index: -1 อยู่ใต้การ์ด แต่ยังอยู่ในบานนี้ */
}
.waiting::before {
  content: '';
  position: absolute;
  inset: 0 0 calc(-1 * var(--tile-h)) 0;   /* ยาวเกินล่างหนึ่งกระเบื้อง ไว้ให้เลื่อนขึ้นได้ไม่เห็นขอบ */
  z-index: -1;
  background: url('login-bg.jpg') repeat left top / var(--tile-w) var(--tile-h);
  animation: waiting-drift 32s linear infinite;
  will-change: transform;
  pointer-events: none;
}
/* ~19px ต่อวินาทีบนจอกว้าง — เร็วกว่านี้กวนสายตาเวลาอ่านทิป ช้ากว่านี้ดูไม่ออกว่าขยับ */
@keyframes waiting-drift {
  to { transform: translateY(calc(-1 * var(--tile-h))); }
}
@media (prefers-reduced-motion: reduce) {
  .waiting::before { animation: none; }
}
.waiting[hidden] { display: none; }
/* ตัวหนังสือวางบนการ์ดกระดาษ ไม่ใช่ลอยบนลายตรง ๆ — ลายเป็นครีมสลับแถบสี ตัวหนังสือสีไหนก็อ่านไม่ออกทั้งแผ่น
   ภาษาเดียวกับหน้าแรก: ภาพลายเป็นพื้น แผ่นกระดาษขอบหมึกเงาแข็งวางทับ */
/* .empty-pane__card ของหน้าพักใช้กฎเดียวกัน กว้างเท่ากัน — กดเริ่มแล้วการ์ดไม่เปลี่ยนขนาด
   ดูเป็นการ์ดใบเดิมเปลี่ยนข้อความ (ความสูงยังตามเนื้อหา หน้ารอมีทิปจึงสูงกว่านิดหน่อย) */
.waiting__inner,
.empty-pane__card {
  width: min(24rem, 100%);
  display: grid;
  gap: 0.6rem;
  justify-items: center;
  padding: 1.5rem 1.75rem;
  background: var(--paper);
  border: var(--ink-w) solid var(--ink);
  border-radius: var(--radius-lg);
  box-shadow: var(--drop-2);
}

/* นักศึกษาโบกมือ — สติกเกอร์ที่เจ้าของส่งมาแทนอีโมจิ 🎓👋😄 (14 ก.ย. 2569)
   อีโมจิหน้าตาเปลี่ยนตามเครื่อง (Apple/Google/Windows คนละแบบ) และไม่ใช่ของแบรนด์
   เหตุผลเดียวกับที่ถอด 👋 ออกจากหน้าพัก (ดู .empty-pane__logo)
   ภาพเป็นชิ้นเดียว แยกขยับเฉพาะมือไม่ได้ เลยโยกทั้งตัวจากฐาน (transform-origin ใกล้เท้า)
   โยกไปมาสามจังหวะแบบคนโบกทักทาย แล้วพักพร้อมเด้งเบา ๆ — โยกตลอดเวลาจะกวนตาคนที่รออยู่นาน */
.waiting__faces { display: flex; justify-content: center; margin-bottom: 0.5rem; }
.waiting__mascot {
  display: block;
  height: var(--mascot-h, 5.5rem);
  width: auto;
  transform-origin: 50% 94%;
  animation: wave-hello 2.6s ease-in-out infinite;
}
@keyframes wave-hello {
  0%   { transform: rotate(0deg); }
  10%  { transform: rotate(9deg); }
  22%  { transform: rotate(-6deg); }
  34%  { transform: rotate(8deg); }
  46%  { transform: rotate(0deg) translateY(0); }
  70%  { transform: rotate(0deg) translateY(var(--mascot-lift, -6px)); }
  90%, 100% { transform: rotate(0deg) translateY(0); }
}
@media (prefers-reduced-motion: reduce) {
  .waiting__mascot { animation: none; }
}

/* หัวเรื่องตอนรอเคยเป็นตัวหนังสือขนาดปกติกลางจอมืด ๆ ดูเหมือนหน้าโหลดค้าง
   ขยายให้เป็น "หัวเรื่อง" จริง ๆ จะได้รู้สึกว่าระบบกำลังทำงานให้อยู่ */
.waiting__title {
  color: var(--ink);
  font-family: 'Mali', 'Anuphan', sans-serif;
  font-size: clamp(1.45rem, 1.15rem + 1.3vw, 2.1rem);
  font-weight: 500;
  letter-spacing: -0.02em;
  line-height: 1.35;
}
.waiting__elapsed {
  color: var(--ink-3);
  font-size: 0.85rem;
  font-variant-numeric: tabular-nums;
}
/* ทิปเป็นเทปอำพันอ่อนแปะเอียงนิดหน่อยบนการ์ด (ภาษา "ป้าย = เทปกาวเอียง")
   อำพันผสมกระดาษ 22% เท่านั้น — พื้นที่ขนาดนี้ใช้อำพันเต็มสูบจะแย่งสายตาจากหัวเรื่อง */
.waiting__tip {
  margin-top: 0.9rem;
  padding: 0.6rem 1rem;
  border-radius: var(--radius);
  transform: rotate(-0.6deg);
  border: var(--ink-w) solid var(--ink);
  background: color-mix(in oklch, var(--sun) 22%, var(--paper));
  box-shadow: var(--drop-1);
  color: var(--ink);
  font-size: 0.87rem;
  transition: opacity 0.4s var(--ease);
}
.waiting__tip.is-fading { opacity: 0; }

/* ---------- วิดีโอตัวเอง ---------- */
.selfie {
  position: absolute;
  right: 1rem; bottom: 1rem;
  z-index: 4;
  /* ระยะจากมุมล่างซ้ายของบาน — ป้าย "คุณ" กับป้ายแชมป์ใช้ค่าเดียวกัน
     บานใหญ่ขึ้นค่านี้ก็ขึ้นตาม (ตั้งใหม่ในมีเดียควีรีข้างล่าง) จะได้ไม่ต้องแก้สองที่ */
  --tag-x: 0.4rem;
  --tag-y: 0.35rem;
  /* ความหนากรอบแชมป์ (frontend/quiz.css) — ป้ายมุมล่างขยับเข้ามาเท่านี้ จะได้ไม่ทับเส้นกรอบ
     มหาลัย = แถบสามสี 5+5+5 · ประเทศ = วงแหวนทอง ทั้งคู่ 15px (เจ้าของขอ 16 ก.ย. 2569 "ไม่อยากให้โดนกรอบ") */
  --frame-w: 0px;
  width: clamp(108px, 15vw, 186px);
  aspect-ratio: 4 / 3;
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--stage-2);
  /* ขอบกระดาษขาวรอบภาพ + เส้นหมึก + เงาแข็ง = รูปโพลารอยด์ที่วางทับโปสเตอร์ */
  box-shadow:
    0 0 0 4px var(--paper),
    0 0 0 calc(4px + var(--ink-w)) var(--ink),
    7px 8px 0 -1px var(--ink);
  transition: transform 0.35s var(--ease);
}
.selfie:hover { transform: scale(1.04) rotate(-1deg); }
#local-video {
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
  transform: scaleX(-1);   /* กลับด้านเหมือนกระจก จะได้ไม่งง */
}
/* ภาพจำลองมีตัวหนังสือ ถ้ากลับด้านจะอ่านไม่ออก */
#local-video.no-mirror { transform: none; }
.selfie__tag {
  position: absolute;
  left: calc(var(--tag-x) + var(--frame-w)); bottom: calc(var(--tag-y) + var(--frame-w));
  font-size: 0.68rem;
  font-weight: 600;
  color: var(--ink);
  background: var(--sun);
  padding: 0.12rem 0.5rem;
  border-radius: 999px;
  border: 1.5px solid var(--ink);
}

/* ป้าย "CHAMPION NO.1 ของมหาวิทยาลัย" จากแบบวาดของเจ้าของ — มุมล่างขวาของบานเรา
   (เจ้าของขอ 16 ก.ย. 2569 · เดิมอยู่ซ้ายล่าง 320px → 210px → ย้ายขวาล่าง 150px) โชว์เมื่อ app.js ใส่ .quiz-champion ให้บาน ไม่มีสวิตช์ใน JS แยก
   ตัดจาก Downloads/S__14008343.jpg แล้วทำพื้นครีมโปร่งใส → 552x106 (เจ้าของขอ "ไม่มีพื้นหลัง" + เล็กลง)
   ลบครีมเฉพาะก้อนที่ต่อกับขอบภาพ + รูในตัวอังกฤษ (O, 0) — ไม่ได้ลบทุกจุดที่สีครีม
   เพราะไส้ตัวอักษร (ห่างครีม ~14) กับกำปั้น ✊ (ห่าง ~44) สีใกล้พื้นมาก ถ้าลบตามสีอย่างเดียวจะเป็นรู
   รูในอักษรไทยคงครีมไว้ เส้นไทยบาง ถ้าเจาะทะลุเป็นวิดีโอจะอ่านไม่ออกตอนย่อเล็ก
   z-index 9 = เหนือกรอบแชมป์ (::after ใช้ 8) ไม่งั้นเส้นกรอบพาดทับป้าย */
.champion-tag {
  position: absolute;
  right: calc(var(--tag-x) + var(--frame-w)); bottom: calc(var(--tag-y) + var(--frame-w));
  z-index: 9;
  display: none;
  width: min(45%, 150px);
  aspect-ratio: 552 / 106;
  background: url('champion-no1.png') center / contain no-repeat;
  pointer-events: none;
}
/* กรอบแชมป์ทั้งสองระดับหนา 15px (มหาลัย = แถบสามสี 5+5+5 · ประเทศ = วงแหวนทอง) */
.selfie.quiz-champion, .stage__remote.quiz-champion { --frame-w: 15px; }
/* แชมป์ประเทศใช้ป้าย "CHAMPION NO.1 ของประเทศ" (แบบวาดของเจ้าของ Downloads/S__14008344.jpg 16 ก.ย. 2569)
   ทำพื้นโปร่งใสวิธีเดียวกับป้ายมหาลัย (รูในอักษรไทยคงครีม) ย่อเหลือ 560 กว้าง · สัดส่วนต่างจากป้ายมหาลัย ต้องตั้ง aspect-ratio ใหม่ */
.quiz-champion--national > .champion-tag {
  aspect-ratio: 560 / 120;
  background-image: url('champion-no1-national.png');
}
/* โชว์ทั้งบานเราและบานคู่สนทนา (เจ้าของขอให้คนอื่นเห็นด้วย 16 ก.ย. 2569) */
.selfie.quiz-champion > .champion-tag, .stage__remote.quiz-champion > .champion-tag { display: block; }
/* จอกว้างที่มีกล้องหลายตัว ปุ่มพลิกกล้องอยู่มุมขวาล่างเดียวกัน → ยกป้ายขึ้นไปเหนือปุ่ม
   ป้าย "คุณ" อยู่ซ้ายล่างตามเดิม ไม่ต้องย้ายแล้ว */
.selfie.quiz-champion:has(> #flip-btn:not([hidden])) .champion-tag { bottom: calc(var(--tag-y) + var(--frame-w) + 2.4rem); }

/* ---------- แชท ---------- */
.chat {
  grid-area: 1 / 2;          /* คอลัมน์ขวาเสมอ (จอเล็กจะถูก override เป็น absolute ด้านล่าง) */
  display: grid;
  /* minmax(0, 1fr) ไม่ใช่ 1fr เฉยๆ — ต้องยอมให้ช่องข้อความหดได้
     ไม่งั้นมันดันช่องพิมพ์ทะลุการ์ดแล้วโดน overflow:hidden ตัดหายไปทั้งแถว */
  grid-template-rows: auto minmax(0, 1fr) auto auto;
  background: var(--paper);
  border-radius: var(--radius-lg);
  border: var(--ink-w) solid var(--ink);
  margin: clamp(0.5rem, 1.2vw, 0.85rem);
  margin-bottom: 0;
  overflow: hidden;
  box-shadow: var(--paper-lift);
  animation: slide-in 0.4s var(--ease) both;
}
.chat[hidden] { display: none; }

.chat__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.85rem 1.1rem;
  border-bottom: 1px solid var(--line);
}
.chat__head h2 {
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.07em;
  padding: 0.3rem 0.8rem;
  border-radius: 999px;
  background: var(--sun);
  color: var(--ink);
  border: var(--ink-w) solid var(--ink);
  box-shadow: 0 2px 0 var(--ink);
  transform: rotate(-1.2deg);
}
.chat__close { padding: 0.2rem 0.4rem; font-size: 0.82rem; }

.chat__log {
  overflow-y: auto;
  min-height: 0;
  padding: 1rem;
  display: flex;
  flex-direction: column;
  gap: 0.45rem;
  scrollbar-width: thin;
}
.chat__empty {
  margin: auto;
  text-align: center;
  color: var(--ink-3);
  font-size: 0.87rem;
  max-width: 22ch;
}

.msg {
  padding: 0.5rem 0.85rem;
  border-radius: 16px;
  font-size: 0.92rem;
  max-width: 88%;
  word-break: break-word;
  animation: pop 0.32s var(--ease) both;
}
.msg.me {
  background: var(--ink);
  color: var(--paper);
  align-self: flex-end;
  border-bottom-right-radius: 5px;
}
.msg.them {
  background: var(--sun);
  color: var(--ink);
  align-self: flex-start;
  border-bottom-left-radius: 5px;
  border: 1.5px solid var(--ink);
}
.msg.me { border: 1.5px solid var(--ink); }

/* ---------- ปุ่มทักลัด ---------- */
.chat__quick {
  display: flex;
  gap: 0.4rem;
  padding: 0 1rem 0.6rem;
  flex-wrap: wrap;
}
.chat__quick[hidden] { display: none; }
.chat__quick button {
  font: inherit;
  font-size: 0.8rem;
  padding: 0.3rem 0.75rem;
  border-radius: 999px;
  border: 1.5px solid var(--line-strong);
  background: none;
  color: var(--ink-2);
  cursor: pointer;
  transition: all 0.18s var(--ease);
}
.chat__quick button {
  background: var(--paper);
  border: var(--ink-w) solid var(--ink);
  color: var(--ink);
  box-shadow: 0 2px 0 var(--ink);
}
.chat__quick button:hover {
  background: var(--sun);
  transform: translateY(-1px);
  box-shadow: 0 3px 0 var(--ink);
}
.chat__quick button:active { transform: translateY(2px); box-shadow: 0 0 0 var(--ink); }

.chat__form {
  display: flex;
  gap: 0.5rem;
  padding: 0.85rem 1rem 1rem;
  border-top: 1px solid var(--line);
}
.chat__form input { padding: 0.65rem 0.9rem; }
.btn--send {
  background: var(--vermilion-lo);
  color: var(--paper);
  width: 2.75rem;
  flex-shrink: 0;
  font-size: 1.15rem;
  border: var(--ink-w) solid var(--ink);
  box-shadow: 0 3px 0 var(--ink);
}
.btn--send:hover:not(:disabled) { transform: translateY(-1px); box-shadow: 0 4px 0 var(--ink); }
.btn--send:active:not(:disabled) { transform: translateY(3px); box-shadow: 0 0 0 var(--ink); }

/* ---------- แถบควบคุม ---------- */
/* container query: กฎที่ตามมาข้างล่างถามจาก "ความกว้างของแถบ" ไม่ใช่ความกว้างจอ
   เพราะแถบนี้กว้างไม่เท่ากันในแต่ละสถานการณ์ (เปิด/ปิดบานแชท) ทั้งที่จอเท่ากัน
   ปลอดภัยเพราะความกว้างแถบมาจาก grid ข้างนอก ไม่ได้มาจากเนื้อหาข้างใน */
.controls { container-type: inline-size; container-name: bar; }
.controls {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: clamp(0.6rem, 2vw, 1.5rem);
  padding: clamp(0.7rem, 1.6vw, 1rem) clamp(0.85rem, 2vw, 1.5rem);
  padding-bottom: max(clamp(0.7rem, 1.6vw, 1rem), env(safe-area-inset-bottom));
}
.controls__left, .controls__right {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex: none;
}

/* ปุ่มรองทุกตัวในแถบนี้สูงเท่ากันหมด แถวถึงจะดูเป็นเส้นเดียว
   (ก่อนหน้านี้ toggle 36px, รายงาน 37px, ออก เป็นตัวหนังสือขีดเส้นใต้) */
.controls .toggle,
.controls .btn--report,
.controls .picker__btn,
.controls .btn--text {
  min-height: 42px;
}

/* "ออก" เคยเป็นลิงก์ขีดเส้นใต้ อยู่ปนกับปุ่มแคปซูลแล้วดูหลุดกลุ่ม
   ทำให้เป็นแคปซูลเหมือนกัน แต่จางกว่า เพราะไม่ใช่ปุ่มที่อยากให้กดบ่อย */
.controls .btn--text {
  padding: 0.5rem 1rem;
  border: 1.5px solid var(--line-strong);
  border-radius: 999px;
  text-decoration: none;
  color: var(--ink-3);
}
.controls .btn--text:hover {
  border-color: var(--ink-2);
  color: var(--ink);
}

/* ปุ่มรองเคยเป็นแคปซูลขอบบางพื้นเดียวกับการ์ด = อ่านว่า "กล่องเปล่า" มากกว่าปุ่ม
   ให้ขอบหมึกกับเงาแข็งชุดเดียวกับปุ่มหลัก ต่างกันแค่ไม่มีสี — ลำดับความสำคัญยังชัด
   แต่ทุกอันดูกดได้เท่ากัน */
.toggle {
  font: inherit;
  font-size: 0.82rem;
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.55rem 0.9rem;
  border-radius: 999px;
  border: var(--ink-w) solid var(--ink);
  background: var(--paper);
  color: var(--ink);
  cursor: pointer;
  box-shadow: 0 3px 0 var(--ink);
  transition: background-color 0.18s var(--ease), color 0.18s var(--ease),
              border-color 0.18s var(--ease), transform 0.14s var(--ease),
              box-shadow 0.14s var(--ease);
}
.toggle:hover {
  background: var(--sun);
  transform: translateY(-1px);
  box-shadow: 0 4px 0 var(--ink);
}
.toggle:active { transform: translateY(3px); box-shadow: 0 0 0 var(--ink); }
.toggle__icon { font-size: 1rem; line-height: 1; }

/* ---------- ปุ่มหลักในแถบควบคุม ----------
   หน้าตาตามแบบที่เจ้าของวาดเอง (13 ก.ย. 2569): พื้นครีมตัวเดียวกับพื้นโลโก้
   ขอบหมึก เงาแข็งใต้ปุ่ม และตัวอักษรซ้อนชั้น (ครีม → อำพัน → แดงส้ม → ม่วงแดง)
   ทรงเดียวกับตัวอักษร UNIDEA ในโลโก้

   "เริ่ม" "หยุด" และ "คนถัดไป" ใช้ตัวอักษรที่ตัดมาจากไฟล์วาดจริง (public/btn/*.png พื้นใส)
   เพราะฟอนต์เว็บทำทรงนี้ไม่ได้ — ข้อความจริงยังอยู่ใน DOM ดันออกนอกกรอบด้วย
   text-indent เหมือน .wordmark__text สกรีนรีดเดอร์และตัวตรวจคอนทราสต์ยังอ่านได้
   "คนถัดไป" ได้แบบวาดพร้อมลูกศรมา 15 ก.ย. 2569 — ก่อนหน้านั้นเลียนทรงด้วย .btn-letter

   ไป/หยุด ไม่ได้แยกด้วยสีพื้นแล้ว (ทั้งคู่ครีมตามแบบ) แยกด้วยคำบนปุ่มกับตำแหน่ง
   ซึ่งตรงกับหลัก "ไม่สื่อด้วยสีอย่างเดียว" อยู่แล้ว

   ทุกปุ่มในเว็บใช้กลไกเดียวกัน = ขอบหมึก + เงาแข็งใต้ปุ่ม + กดแล้วยุบลงไปชนเงา */
.controls__main { display: contents; }

.btn--go,
.btn--stop {
  background: var(--logo-ground);
  color: var(--ink);
  font-weight: 500;
  padding: 0.85rem 1.9rem;
  font-size: 1.05rem;
  white-space: nowrap;
  border: var(--ink-w) solid var(--ink);
  /* แบบวาด: ขอบหนา ~2% และเงาหนา ~4% ของความสูงปุ่ม = 2px กับ 4px ที่ปุ่มสูง 80-100px */
  box-shadow: 0 4px 0 var(--ink);
}
/* hover ยกปุ่มขึ้นอย่างเดียว ไม่เปลี่ยนสีพื้น — เนื้อครีมในตัวอักษร png ใกล้กับพื้นในไฟล์วาด
   จนถูกตัดเป็นพื้นใสไปบางส่วน พื้นปุ่มต้องเป็นครีมตัวเดียวกับไฟล์ ไม่งั้นเห็นเป็นจุด ๆ ในตัวอักษร */
.btn--go:hover,
.btn--stop:hover:not(:disabled) {
  transform: translateY(-1px);
  box-shadow: 0 5px 0 var(--ink);
}
.btn--go:active,
.btn--stop:active:not(:disabled) { transform: translateY(4px); box-shadow: 0 0 0 var(--ink); }

/* ตัวอักษรจากไฟล์วาด — ความสูงเป็น em จึงโตตามขนาดตัวหนังสือของปุ่ม
   ที่ถูกย่อ/ขยายตามจอไว้แล้ว · aspect-ratio = ขนาดไฟล์ png */
/* ขนาดเทียบจากแบบวาด: "เริ่ม" สูง 47% ของปุ่ม · "หยุด" 40% (ไม่มีวรรณยุกต์ข้างบน)
   ปุ่มแถวบนสูง ~100px ที่จอ 1440 → ตัวอักษร ~47px กับ ~40px */
.btn--start .btn__label,
.btn--stop .btn__label,
.btn--next .btn__label {
  display: block;
  height: 2.2em;
  background: center / contain no-repeat;
  text-indent: -100em;
  overflow: hidden;
  white-space: nowrap;
}
.btn--start .btn__label { aspect-ratio: 275 / 217; background-image: url('btn/start.png'); }
/* จัดกลางที่ "ตัวอักษร" ไม่ใช่ที่กรอบภาพ — start.png มีสระ/วรรณยุกต์ ิ่ อยู่บน ตัวอักษรเลยกินแค่
   แถว 30–126 จาก 130 (กลางตัวอยู่ 60% ของภาพ) ส่วน stop.png ตัวอักษรเต็มภาพ (กลางอยู่ 50%)
   กรอบภาพสองอันจัดกลางปุ่มเท่ากันเป๊ะ แต่ "เริ่ม" เลยห้อยต่ำกว่า "หยุด" ~6px ที่จอ 1440
   (เจ้าของทัก 14 ก.ย. 2569) ยกขึ้น 10% ของความสูงตัวเอง = กลางตัวอักษรตรงกลางปุ่มพอดีทุกขนาดจอ
   ถ้าเปลี่ยนไฟล์ภาพ ต้องวัดแถวหมึกใหม่แล้วปรับตัวเลขนี้ */
.btn--start .btn__label { translate: 0 -10%; }
.btn--stop .btn__label { aspect-ratio: 347 / 188; height: 2em; background-image: url('btn/stop.png'); }
/* "คนถัดไป" + ลูกศร จากแบบวาดของเจ้าของ (15 ก.ย. 2569) — ภาพกว้างราว 3.4 เท่าของความสูง
   ตัดจาก Downloads/S__14000137.jpg เอาเฉพาะของข้างในกรอบที่วาดมา (กรอบ/เงาปุ่มมาจาก CSS เหมือนปุ่มอื่น)
   ลบพื้นครีม สี่เหลี่ยมสีอ่อนที่ติดมาหลังตัวอักษร และเงาฟุ้งใต้ลูกศรออกหมด ขอบขาวของลูกศรเก็บไว้
   ปุ่มแคบ ความกว้างถูกบีบด้วย max-width แล้ว contain ย่อภาพลงตามเอง ไม่ล้นปุ่ม */
.btn--next .btn__label { aspect-ratio: 404 / 120; background-image: url('btn/next.png'); }
/* ยังกดหยุดไม่ได้ (ห้องเตรียมตัว) — ขอบเส้นประจาก .btn:disabled บอกสถานะอยู่แล้ว
   ตัวอักษรหรี่ลงให้เข้ากับปุ่มที่แบนราบไปกับกระดาษ */
.btn--stop:disabled .btn__label { opacity: 0.4; }

/* ปุ่มเกม (React, frontend/quiz.tsx) สถานะปกติ = ภาพ "ท้าดวล!" กับคนสองคนจากไฟล์วาด
   แทนทั้งไอคอน ⚡ และข้อความ — กรอบ/เงาแดงส้มอยู่ใน frontend/quiz.css
   กฎนี้อยู่ที่นี่ไม่ใช่ใน quiz.css เพราะ esbuild พยายามรวม url() ของรูปเข้า bundle แล้วพัง
   ความสูง 1.65em ของตัวปุ่ม ไม่ใช่มากกว่านี้ — measure.mjs บังคับว่าปุ่มแถวล่าง
   ต้องไม่กว้างกว่าแป้นแถวบน ซึ่งจอ 900px แป้นกว้างแค่ ~129px (1.75em × 1.1em เคยได้ 136.6 ตก)

   สีหมึกและถอดขอบ/เงาของ .btn-letter ออก: ข้อความถูกดันออกนอกกรอบก็จริง
   แต่ตัวตรวจคอนทราสต์ยังวัดสีมันอยู่ (ครีมบนครีมได้ 1.24:1) — ทำแบบเดียวกับ .wordmark__text */
/* ถูกท้า (data-state="challenged") = **ป้ายทั้งใบ** จากแบบวาดของเจ้าของ รวมกรอบแดงมนด้วย
   (เจ้าของเลือกเอง 16 ก.ย. 2569 — เดิมตัดเฉพาะของข้างในกรอบแล้วใช้กรอบ/เงาของปุ่มแทน
   คนสองคนที่ยืนคร่อมเส้นกรอบล่างในแบบวาดจึงหายไป ซึ่งทำด้วย CSS ไม่ได้)
   ตัดจาก Downloads/S__14008345.jpg กล่อง (46, 449)–(1232, 894) → public/btn/challenged-sign.png 426x160
   กรอบแดงด้านนอกอยู่ที่ (50, 453)–(1227, 889) มุมมนรัศมี 45 เส้นล่างหนา 25px (ด้านอื่น 8px)
   ครีมข้างในกรอบเก็บไว้ทึบ (ไม่ทำโปร่งใสแบบ duel.png) เพราะแถบปุ่มเป็น --paper ขาวกว่าครีมในแบบวาด
   โปร่งใสเฉพาะนอกกรอบ — หน้ากากสี่เหลี่ยมมุมมนวาดใหญ่ 4 เท่าแล้วย่อ ขอบมนจึงเนียน
   ไฟล์เดิม challenged.png (ไม่มีกรอบ) ยังใช้อยู่ในแผงเกม (.quiz-challenged__art) ซึ่งมีกรอบแดงของตัวเอง
   ปุ่มยังเต้นวงแดงส้ม (.quiz-launch--alert) และ aria-label "มีคนท้าคุณ!" เหมือนเดิม */
.quiz-launch:is([data-state="idle"], [data-state="challenged"]) .quiz-launch__icon { display: none; }
.quiz-launch:is([data-state="idle"], [data-state="challenged"]) .quiz-launch__text {
  display: block;
  font-size: 1em;
  height: 1.65em;
  aspect-ratio: 874 / 246;
  background: url('btn/duel.png') center / contain no-repeat;
  color: var(--ink);
  -webkit-text-stroke: 0;
  text-shadow: none;
  text-indent: -100em;
  overflow: hidden;
}

/* ตัวอักษรซ้อนชั้นด้วย CSS — ใช้กับป้ายที่ยังไม่มีแบบวาด (ถูกท้า! · กลับเกม)
   ขอบหมึกด้วย text-stroke + paint-order ให้เส้นอยู่ใต้เนื้อตัวอักษร (ตัวไม่ผอมลง)
   ตัวตัวอักษรยื่นลงขวาเป็นแท่งทึบเหมือนแบบวาด "เริ่ม": อำพัน → แดงส้ม → ม่วงแดง
   แต่ละแถบคั่นด้วยเส้นหมึกบาง ๆ (เงาหมึกชั้นเดียวแทรกระหว่างสี) แล้วปิดท้ายด้วยหมึก
   เงาต้องห่างกันไม่เกิน ~0.02em ไม่งั้นแท่งขาดเป็นชั้น ๆ (แบบเดิมห่าง 0.03em ดูเป็นเส้นซ้อน ไม่ใช่แท่ง)
   ขอบหมึกบางไว้ (0.06em) — หนากว่านี้เส้นรอบตัวกลืนแถบสีจนดูดำทั้งก้อน
   ตัวอักษรครีมบนพื้นครีมอ่านออกเพราะขอบหมึกรอบตัว ไม่ใช่เพราะสีเนื้อ
   ได้แบบวาดของป้ายไหนมาเมื่อไหร่ ให้เปลี่ยนไปใช้ภาพแบบ .btn--start */
/* ฟอนต์: Noto Sans Thai แบบบีบ (wdth 80) — ตัวผอมสูงไม่มีหัวแบบตัวอักษรในแบบวาด
   Kanit ที่เคยใช้กว้างและหนาเกิน วางข้าง "หยุด" แล้วดูคนละชุด (เจ้าของทัก 14 ก.ย. 2569)
   เงาเอียงลงมากกว่าไปขวา (y ≈ 1.7 เท่าของ x) ตามทิศเงาในไฟล์วาด */
/* สีให้เหมือนปุ่ม "หยุด" (เจ้าของขอ 14 ก.ย. 2569) — วัดจากภาพที่แสดงบนจอจริง ไม่ใช่พิกเซลทึบในไฟล์
   stop.png มีขอบโปร่งแสงเยอะ ย่อลงวางบนพื้นครีมแล้วสีที่ตาเห็นหม่นกว่าค่าในไฟล์มาก
   (เคยดูดจากพิกเซลทึบได้เส้นน้ำตาลเข้ม #543C30 กับอำพันสด — วางคู่กันแล้วยังคนละสี)
   และสีที่เห็นเปลี่ยนตามความละเอียดจอ: จอ 1x เส้น #908070 อำพัน #D09030 · จอ 2x เส้น #706050 อำพัน #E0A030
   ค่าข้างล่างเป็นค่ากลางสำหรับจอ 1x · จอความละเอียดสูง (มือถือ/Retina) มีชุดของตัวเองต่อท้าย
   ไม่ใช้โทเคนธีม — หมึกธีมเกือบดำ แต่เส้นในแบบวาดที่ขนาดปุ่มเป็นน้ำตาลอมเทา
   เนื้อตัวอักษรเป็นครีมอมเทาเข้มกว่าพื้นปุ่มนิดหน่อย (#E0D0B0 ทั้งสองจอ) ไม่ใช่ขาว */
.btn-letter {
  --letter-fill:  #E0D0B0;
  --letter-line:  #806C5E;
  --letter-amber: #D8982E;
  --letter-red:   #AA3232;
  --letter-plum:  #86284C;
  --letter-edge:  #6E5A4E;
  font-family: 'Noto Sans Thai', 'Kanit', 'Mali', sans-serif;
  font-weight: 750;
  font-stretch: 80%;
  color: var(--letter-fill);
  letter-spacing: 0.02em;
  -webkit-text-stroke: 0.07em var(--letter-line);
  paint-order: stroke fill;
  text-shadow:
    0.02em 0.035em 0 var(--letter-amber),
    0.035em 0.06em 0 var(--letter-amber),
    0.05em 0.085em 0 var(--letter-amber),
    0.06em 0.105em 0 var(--letter-line),
    0.07em 0.12em 0 var(--letter-red),
    0.085em 0.145em 0 var(--letter-red),
    0.095em 0.16em 0 var(--letter-line),
    0.105em 0.175em 0 var(--letter-plum),
    0.115em 0.195em 0 var(--letter-plum),
    0.125em 0.21em 0 var(--letter-edge),
    0.13em 0.22em 0 var(--letter-edge);
}
/* จอความละเอียดสูง (มือถือ แท็บเล็ต Mac) — stop.png ย่อน้อยลง ขอบโปร่งแสงน้อยลง
   สีที่เห็นเข้มและสดกว่าจอ 1x ชัดเจน วัดจากจอ 2x: เส้น #706050 อำพัน #E0A030 แดง #B03030 ม่วง #902050 */
@media (min-resolution: 2dppx) {
  .btn-letter {
    --letter-line:  #706050;
    --letter-amber: #E0A030;
    --letter-red:   #B03030;
    --letter-plum:  #902050;
    --letter-edge:  #5C4838;
  }
}

/* ---------- ตัวเลือกเพศ (บอกเอง ไม่ใช่ตัวกรอง) ----------
   หน้าตาตามแบบที่เจ้าของวาด: ปุ่มครีม ขอบหมึก เงาแข็ง ชุดเดียวกับ .btn--go
   คำว่า "ฉันคือ" กับสัญลักษณ์เพศ (♂ ♀ ?) ตัดมาจากไฟล์วาด (public/btn/*.png)
   กฎหน้าตาขึ้นต้นด้วย .picker (สองคลาส) เพื่อให้ชนะกฎพื้นฐานของ .picker__btn ที่อยู่ติดกัน */
.picker { position: relative; display: inline-flex; }
.picker__btn {
  font: inherit;
  font-family: 'Mali', 'Anuphan', sans-serif;
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.1rem;
  width: 100%;
  padding: 0.5rem 1.1rem;
  border: 1.5px solid var(--line-strong);
  border-radius: var(--radius);
  background: var(--paper-2);
  color: var(--ink);
  cursor: pointer;
  transition: background-color 0.18s var(--ease), border-color 0.18s var(--ease);
}
.picker .picker__btn {
  border: var(--ink-w) solid var(--ink);
  background: var(--logo-ground);
  box-shadow: 0 4px 0 var(--ink);
}
.picker__btn:hover {
  transform: translateY(-1px);
  box-shadow: 0 5px 0 var(--ink);
}
/* hover กับตอนเปิดเมนูไม่เปลี่ยนสีพื้น — ภาพจากไฟล์วาดต้องวางบนครีมตัวเดียวกับในไฟล์ (ดู .btn--go) */
.picker .picker__btn:hover { background: var(--logo-ground); }
.picker__btn:active { transform: translateY(4px); box-shadow: 0 0 0 var(--ink); }
/* เมนูเปิดอยู่ = ปุ่มค้างอยู่ในท่ากด บอกว่าเมนูงอกออกมาจากปุ่มตัวนี้ */
.picker[data-open] .picker__btn {
  transform: translateY(4px);
  box-shadow: 0 0 0 var(--ink);
}
.picker__label {
  font-size: 0.68rem;
  line-height: 1.2;
}
/* "ฉันคือ" จากไฟล์วาด — ข้อความจริงยังอยู่ ดันออกนอกกรอบด้วย text-indent
   สีหมึก ไม่ใช่ --ink-3: ข้อความถูกดันออกไปแล้วแต่ตัวตรวจคอนทราสต์ยังวัดสีมันอยู่
   (ink-3 บนครีมโลโก้ได้ ~4.3:1 ตก) · ความสูงเป็น em ของขนาดป้ายที่แต่ละจอตั้งไว้ */
.picker .picker__label {
  display: block;
  height: 2.6em;
  aspect-ratio: 450 / 185;
  background: url('btn/iam.png') center / contain no-repeat;
  color: var(--ink);
  text-indent: -100em;
  overflow: hidden;
  white-space: nowrap;
}

/* สัญลักษณ์เพศจากไฟล์วาด (♂ ชาย · ♀ หญิง · ? ไม่ระบุ) ผูกด้วย data-gender
   เนื้อในสัญลักษณ์เป็นครีมเกือบเท่าพื้นในไฟล์ (ต่างกันไม่ถึง 15 หน่วย) ตอนตัดพื้นทิ้งเลยใสไปด้วย
   จึงรองพื้นครีมตัวเดียวกับไฟล์ไว้ในตัวไอคอนเอง — วางบนเมนูกระดาษหรือป้ายอำพันก็ไม่เป็นรู
   บนปุ่มครีมพื้นกลืนหายไป ส่วนบนพื้นอื่นจะเห็นเป็นสติกเกอร์สี่เหลี่ยมมนเล็ก ๆ */
.gender-icon {
  display: inline-block;
  flex: none;
  width: 1.4em;
  height: 1.4em;
  padding: 0.1em;
  border-radius: 0.3em;
  background: var(--logo-ground) center / contain no-repeat;
  background-origin: content-box;
  vertical-align: -0.4em;
}
.gender-icon[data-gender="male"]   { background-image: url('btn/gender-male.png'); }
.gender-icon[data-gender="female"] { background-image: url('btn/gender-female.png'); }
.gender-icon[data-gender="other"]  { background-image: url('btn/gender-other.png'); }
.picker__value {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  font-size: 0.95rem;
  line-height: 1.2;
  white-space: nowrap;
}
.picker__emoji { font-size: 1.05rem; }
.picker__caret { display: none; }

.picker__menu {
  position: absolute;
  bottom: calc(100% + 0.6rem);
  left: 50%;
  translate: -50% 0;
  z-index: 20;
  width: max-content;
  min-width: 11rem;
  display: grid;
  gap: 0.15rem;
  padding: 0.6rem;
  background: var(--paper);
  border: var(--ink-w) solid var(--ink);
  border-radius: var(--radius);
  box-shadow: var(--drop-2);
  animation: rise 0.24s var(--ease) both;
}
.picker__menu[hidden] { display: none; }
.picker__title {
  font-size: 0.72rem;
  color: var(--ink-3);
  padding: 0.2rem 0.5rem 0.4rem;
  line-height: 1.4;
}
.picker__menu button {
  font: inherit;
  font-size: 0.92rem;
  text-align: left;
  padding: 0.5rem 0.6rem;
  border: none;
  border-radius: 8px;
  background: none;
  color: var(--ink);
  cursor: pointer;
}
/* ตัวเลือกเหลือแต่รูป (ไม่มีคำ) — เรียงเป็นแถวเดียวสามช่อง หัวข้อกินเต็มแถวบน */
.picker__menu:has(button[data-gender]) { grid-template-columns: repeat(3, 1fr); min-width: 0; }
.picker__menu .picker__title { grid-column: 1 / -1; }
.picker__menu button[data-gender] {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0.45rem;
  border: var(--ink-w) solid transparent;
}
.picker__menu button[data-gender] .gender-icon { width: 2.2em; height: 2.2em; }
.picker__menu button:hover { background: var(--paper-2); }
/* ตัวที่เลือกอยู่ต้องดูออกโดยไม่ต้องอาศัยสีอย่างเดียว — มีกรอบหมึกด้วย
   (เดิมใช้ ✓ ต่อท้ายคำ แต่ไม่มีคำแล้ว ✓ ข้างรูปทำให้ช่องกว้างไม่เท่ากัน) */
.picker__menu button[aria-checked="true"] {
  background: color-mix(in srgb, var(--sun) 30%, var(--paper));
  border-color: var(--ink);
}

/* ปกติซ่อน โชว์เฉพาะตอนอยู่ห้องเตรียมตัว (กฎอยู่ท้ายไฟล์) */
.btn--start { display: none; }
.btn__kbd {
  font-family: 'Anuphan', sans-serif;
  font-size: 0.68rem;
  font-weight: 700;
  padding: 0.05rem 0.4rem;
  border-radius: 5px;
  background: color-mix(in oklch, var(--ink) 14%, transparent);
  color: color-mix(in oklch, var(--ink) 75%, transparent);
}

.btn--report {
  background: var(--paper);
  border: var(--ink-w) solid var(--ink);
  color: var(--vermilion-ink);
  padding: 0.5rem 1rem;
  font-size: 0.85rem;
  font-family: 'Anuphan', sans-serif;
  font-weight: 600;
  box-shadow: 0 3px 0 var(--ink);
}
.btn--report:hover {
  background: color-mix(in srgb, var(--vermilion) 22%, white);
  transform: translateY(-1px);
  box-shadow: 0 4px 0 var(--ink);
}
.btn--report:active {
  transform: translateY(3px);
  box-shadow: 0 0 0 var(--ink);
}
.btn--report__icon { display: none; line-height: 1; }
.btn--report__icon svg { display: block; width: 1.1em; height: 1.1em; }

/* ---------- เมนูรายงาน (popover ไม่ใช่ modal) ---------- */
.report { position: relative; }
.report__menu {
  position: absolute;
  bottom: calc(100% + 0.6rem);
  right: 0;
  z-index: 20;
  width: max-content;
  min-width: 13rem;
  display: grid;
  gap: 0.15rem;
  padding: 0.6rem;
  background: var(--paper);
  border: var(--ink-w) solid var(--ink);
  border-radius: var(--radius);
  box-shadow: var(--drop-2);
  animation: rise 0.24s var(--ease) both;
}
.report__menu[hidden] { display: none; }
.report__title {
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--ink-3);
  padding: 0.2rem 0.5rem 0.5rem;
  margin-bottom: 0.2rem;
  border-bottom: 1.5px dashed var(--line-strong);
}
/* จุดแดงส้มหน้าแต่ละข้อ ชี้แล้วจุดยืดเป็นขีด — เห็นชัดว่ากำลังจะเลือกข้อไหน */
.report__menu button {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  font: inherit;
  font-size: 0.88rem;
  text-align: left;
  padding: 0.5rem 0.6rem;
  border: none;
  border-radius: 8px;
  background: none;
  color: var(--ink);
  cursor: pointer;
}
.report__menu button::before {
  content: "";
  flex: none;
  width: 0.4rem;
  height: 0.4rem;
  border-radius: 999px;
  background: var(--vermilion);
  transition: width 0.15s var(--ease);
}
.report__menu button:hover,
.report__menu button:focus-visible { background: color-mix(in oklch, var(--vermilion) 12%, transparent); color: var(--vermilion-lo); }
.report__menu button:hover::before,
.report__menu button:focus-visible::before { width: 0.9rem; }

/* ---------- แจ้งเตือนลอย ---------- */
/* ต้องลอยอยู่ "เหนือ" แถบปุ่ม ไม่ใช่ทับ — บนมือถือแถบปุ่มอยู่ขอบล่างพอดี
   ข้อความสอนท่าปัด (ซึ่งเด้งทุกครั้งที่เข้าห้อง) เลยไปบังปุ่มท้าดวลกับปุ่มแชท
   ใช้ตัวแปรที่ app.js วัดความสูงแถบจริงส่งมาให้ ตัวเดียวกับที่แผงเกมใช้
   ค่าสำรอง 1.25rem ไว้กันจังหวะแรกที่ยังวัดไม่เสร็จ และตอนอยู่หน้าแรก
   (หน้าแรกไม่มีแถบปุ่ม ค่าจึงไม่เคยถูกเขียน) */
.toasts {
  position: fixed;
  /* เปิดแผงเกมอยู่ = ยกขึ้นไปเหนือแผงอีกชั้น (quiz.tsx ส่ง --quiz-panel-lift = ความสูงแผง + ระยะลอย 12px)
     เดิมป้ายท่าปัดกับแชทเข้าบังปุ่ม "เล่นเลย!" ตอนถูกท้าบนมือถือ (เจ้าของสั่งแก้ 15 ก.ย. 2569)
     ปิดแผง = ไม่มีค่านี้ ป้ายกลับที่เดิมพอดี */
  bottom: calc(var(--controls-gap, 0px) + 1.25rem + var(--quiz-panel-lift, 0px));
  /* กว้างเต็มจอลบขอบ แล้วจัดป้ายไว้กลางด้วย justify-items ข้างล่าง
     เดิมใช้ left: 50% + translate — กล่อง fixed ที่เริ่มกลางจอได้ความกว้างสูงสุดแค่ครึ่งจอ
     ป้ายยาวบนโทรศัพท์เลยถูกบีบจนตัดกลางคำ ("คนถัด / ไป") ทั้งที่มี nbsp กันไว้แล้ว */
  left: 1rem;
  right: 1rem;
  z-index: 100;
  display: grid;
  gap: 0.5rem;
  justify-items: center;
  pointer-events: none;
}
.toast {
  background: var(--ink);
  color: var(--paper);
  font-size: 0.88rem;
  padding: 0.65rem 1.15rem;
  border-radius: 999px;
  border: var(--ink-w) solid var(--ink);
  box-shadow: var(--drop-1);
  animation: rise 0.3s var(--ease) both;
  /* ข้อความยาวบนจอแคบต้องตัดเป็นสองบรรทัดยาวพอ ๆ กัน ไม่ใช่บรรทัดแรกเต็ม บรรทัดสองเหลือคำเดียว */
  max-width: min(24rem, calc(100vw - 2rem));
  text-align: center;
  text-wrap: balance;
}
.toast.is-leaving { animation: rise 0.3s var(--ease) reverse both; }

/* ==========================================================================
   แอนิเมชันร่วม
   ========================================================================== */
@keyframes rise {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: translateY(0); }
}
@keyframes pop {
  from { opacity: 0; transform: scale(0.94) translateY(6px); }
  to   { opacity: 1; transform: scale(1) translateY(0); }
}
@keyframes slide-in {
  from { opacity: 0; transform: translateX(24px); }
  to   { opacity: 1; transform: translateX(0); }
}

/* เปิดหน้าแรก: ทยอยโผล่ทีละชิ้น */
.pitch > *, .panel { animation: rise 0.7s var(--ease) both; }
.wordmark        { animation-delay: 0.05s; }
.pitch__headline { animation-delay: 0.12s; }
.pitch__lede     { animation-delay: 0.19s; }
.pitch__points   { animation-delay: 0.26s; }
.panel           { animation-delay: 0.33s; }

/* ==========================================================================
   จอเล็ก
   ========================================================================== */
@media (min-width: 860px) {
  /* วางเป็นสี่ช่องแบบ OmeTV
       บนซ้าย = หน้าคู่สนทนา    บนขวา = หน้าเรา (ใหญ่เท่ากัน)
       ล่างซ้าย = ปุ่ม           ล่างขวา = แชท
     ของเดิมหน้าเราเป็นกล่องจิ๋วมุมล่างขวาทับวิดีโออีกฝ่าย มองแทบไม่เห็น
     เลยไม่รู้ว่าอีกฝ่ายกำลังเห็นเราเป็นยังไง */
  #chat-screen {
    grid-template-columns: 1fr 1fr;
    /* ล็อกความสูงแถวล่างไว้ ไม่ปล่อยให้แชทดันจนล้นจอ (เดิมปุ่มส่งโดนตัดหาย)
       minmax(0,1fr) = ยอมให้แถววิดีโอหดได้ ถ้าไม่ใส่ 0 มันจะยืนกรานตามเนื้อหา */
    grid-template-rows: minmax(0, 1fr) clamp(9.5rem, 24vh, 14rem);
  }

  .stage {
    display: grid;
    grid-template-columns: 1fr 1fr;
    grid-column: 1 / -1;
    gap: var(--pane-gap);
    background: none;
    overflow: visible;
    box-shadow: none;
    /* ต้องล้างขอบด้วย ไม่ใช่แค่พื้นกับเงา — จอกว้างแต่ละบานมีขอบหมึกของตัวเองแล้ว
       ขอบของ .stage ที่ค้างอยู่ไม่ได้โผล่ให้เห็น (พื้นใส) แต่มันดันบานข้างในเข้ามา
       เท่ากับความหนาขอบ ทำให้ขอบซ้ายบานวิดีโอไม่ตรงกับขอบซ้ายการ์ดปุ่มข้างล่าง
       ตอนขอบหนา 1.5px ยังพอดีเกณฑ์ 2px ของ measure.mjs เลยไม่มีใครเห็น
       พอขึ้นเป็น 2px ตามโทเคน --ink-w มันเลยโผล่ออกมา */
    border: none;
  }
  .stage > * {
    border-radius: var(--radius-lg);
    border: var(--ink-w) solid var(--ink);
    box-shadow: var(--drop-2);
  }
  .stage__remote { border-radius: var(--radius-lg); }

  /* หน้าเราเลิกเป็นกล่องลอย กลายเป็นบานเต็มช่องขวา
     relative ไม่ใช่ static — ป้าย "คุณ" ข้างในเป็น absolute ถ้าไม่มีจุดเกาะ
     มันจะไปเกาะ .stage แล้วโผล่ใต้วิดีโออีกฝ่ายแทน */
  .selfie {
    position: relative;
    inset: auto;          /* ล้าง right/bottom ของตอนเป็นกล่องลอยทิ้ง */
    width: auto;
    height: 100%;
    aspect-ratio: auto;
  }
  .selfie:hover { transform: none; }   /* บานใหญ่ขนาดนี้ไม่ต้องขยับตอนเอาเมาส์ชี้ */
  .selfie { --tag-x: 0.75rem; --tag-y: 0.6rem; }
  .selfie__tag { font-size: 0.78rem; }

  /* ---- แถวล่าง: การ์ดปุ่ม (ซ้าย) คู่กับการ์ดแชท (ขวา) ----
     ขอบนอกตรงกับบานวิดีโอข้างบน ขอบในเว้นครึ่งหนึ่งของช่องไฟคนละฝั่ง
     รวมกันแล้วช่องไฟตรงกลางเท่ากับช่องไฟระหว่างวิดีโอสองบานพอดี */
  .controls {
    grid-row: 2;
    margin: var(--pane-gap) calc(var(--pane-gap) / 2) var(--pane-gap) var(--pane-gap);
    padding: clamp(0.7rem, 1.5vh, 1.1rem);
    background: var(--paper);
    border: var(--ink-w) solid var(--ink);
    border-radius: var(--radius-lg);
    box-shadow: var(--paper-lift);
    align-items: stretch;      /* ปุ่มสูงเต็มการ์ด ไม่ใช่ลอยอยู่กลาง */
    gap: 0.55rem;
  }
  #chat-screen.has-chat .controls { grid-column: 1 / 2; }
  #chat-screen:not(.has-chat) .controls {
    grid-column: 1 / -1;
    margin-right: var(--pane-gap);
  }
  #chat-screen.has-chat .chat {
    grid-area: 2 / 2;
    min-height: 0;
    margin: var(--pane-gap) var(--pane-gap) var(--pane-gap) calc(var(--pane-gap) / 2);
  }

  /* แชทเป็นบานถาวรอยู่ขวาตลอด ปุ่มเปิด/ปิดจึงไม่มีอะไรให้ทำ เอาออกทั้งคู่
     ต้องเอาออก "ทั้งคู่" จริง ๆ — ถ้าเหลือปุ่มซ่อนไว้แต่ไม่มีปุ่มเปิดกลับ
     กดซ่อนทีเดียวแล้วตัน เปิดแชทคืนไม่ได้จนกว่าจะรีเฟรช */
  #chat-toggle, .chat__close { display: none; }

  /* การ์ดแชทในเลย์เอาต์สี่บานเตี้ยกว่าตอนเป็นแถบสูงเต็มจอมาก
     ส่วนที่สูงคงที่ต้องบางลง ไม่งั้นไม่เหลือที่ให้ข้อความเลย */
  .chat__head { padding: 0.55rem 1rem; }
  .chat__form { padding: 0.55rem 0.8rem 0.7rem; }
  .chat__quick { padding: 0 0.8rem 0.45rem; }

}

/* ==========================================================================
   ปุ่มควบคุม — ทุกขนาดจอใช้ชุดเดียวกัน: การ์ดกระดาษ + ปุ่มสี่เหลี่ยม 4 ช่องเท่ากัน
   เดิมกฎชุดนี้อยู่ใน @media (min-width: 860px) โทรศัพท์เลยได้ปุ่มแคปซูลอีโมจิอีกหน้าตาหนึ่ง
   เจ้าของส่งรูปโทรศัพท์เทียบกับ iPad แล้วเลือกให้โทรศัพท์ใช้ชุดเดียวกับ iPad ทั้งหมด (14 ก.ย. 2569)
   ปุ่มข้างในเป็น size container — จอกว้างได้ความสูงจากแถวล่างของ #chat-screen
   จอแคบต้องล็อกความสูงแถวเอง (ดูบล็อก max-width: 859px ข้างล่าง) ไม่งั้นป้ายภาพยุบหาย
   ========================================================================== */
/* ---- ปุ่มควบคุม ----
   รอบก่อนลองยืดปุ่มเต็มความสูงการ์ด ผลคือได้กล่องสูงผอมสองใบลอยอยู่กลาง
   การ์ดกว้าง 900px แล้วเหลือที่ว่างซ้ายขวาเป็นบริเวณกว้าง — ผิดทาง
   ที่ว่างมันอยู่แนวนอน ปุ่มก็ต้องกว้างเต็มการ์ด ส่วนความสูงเอาแค่พอดีปุ่ม

   display:contents ยุบกล่องครอบ (.controls__left/__right) ทิ้งไป
   ปุ่มทุกตัวเลยเป็นลูกโดยตรงของแถบ แล้วแบ่งความกว้างเฉลี่ยกันได้จริง
   ถ้าไม่ทำ กล่องครอบจะกินพื้นที่แทน ปุ่มข้างในไม่ยืดตาม */
/* ---- แถบควบคุม: แถวเดียว 4 ปุ่มขนาดเท่ากัน แบบ OmeTV ----
   เจ้าของเลือกจัดวางตาม OmeTV (13 ก.ย. 2569): เริ่ม/คนถัดไป · หยุด · ฉันคือ · ท้าดวล
   ปุ่มรายงานกับปุ่มพลิกกล้องไม่อยู่ในแถบนี้บนจอกว้าง — app.js (placeMainControls) ย้ายไปวางบนวิดีโอ
     รายงาน = มุมขวาบนของบานคู่สนทนา (ใกล้คนที่จะรายงาน ไกลปุ่มคนถัดไป กดพลาดยาก)
     พลิกกล้อง = มุมขวาล่างของบานเรา (จอแคบไปอยู่มุมขวาบนคู่กับปุ่มแชท ดู .selfie__tools)

   เคยเป็นแถวเดียวที่ปุ่มสูงเต็มการ์ดมาแล้วรอบหนึ่ง ได้ "กล่องโล่งที่มีคำเล็ก ๆ ลอยกลาง"
   ตอนนี้ตัวอักษรเป็นภาพที่ย่อ/ขยายตามขนาดปุ่มจริง (container query ข้างล่าง) ปัญหานั้นเลยไม่กลับมา

   กล่องครอบทั้งสาม (.controls__main/__left/__right) ยุบทิ้งด้วย display: contents
   ปุ่มทุกตัวเลยเป็นลูกโดยตรงของตารางเดียวกัน กว้างและสูงเท่ากันจริง
   ⚠️ ห้ามใส่ min-height ให้ปุ่ม — ความสูงการ์ดถูกล็อกไว้ที่แถวล่างของ #chat-screen
   ถ้าปุ่มดันจนเกิน การ์ดปุ่มจะสูงไม่เท่าการ์ดแชท (measure.mjs จับอยู่) */
.controls {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  grid-template-rows: minmax(0, 1fr);
  align-items: stretch;
  gap: 0.6rem;
}
.controls__main,
.controls__left,
.controls__right { display: contents; }
/* ปุ่มเกมล็อกไว้ช่องขวาสุด ที่เหลือไหลซ้ายไปขวาตามลำดับใน DOM (เริ่มกับคนถัดไปโชว์ทีละตัว) */
.controls .quiz-slot { grid-column: 4; }

/* ทุกช่องยืดเต็มช่องตาราง มุมมนเท่ากันหมด */
.controls .picker,
.controls .btn--stop,
.controls .btn--next,
.controls .btn--start,
.controls .quiz-slot {
  min-width: 0;
  min-height: 0;
  border-radius: var(--radius);
}

/* แป้นใหญ่ต้องมีตัวหนังสือใหญ่ตาม ไม่งั้นได้กล่องโล่ง ๆ ที่มีคำเล็ก ๆ ลอยกลาง
   ซึ่งอ่านว่าเลย์เอาต์พัง มากกว่าจะอ่านว่าปุ่มใหญ่ */
.controls .btn--next,
.controls .btn--start {
  font-size: clamp(1.15rem, 1.5vw, 1.4rem);
  padding: 0.5rem 1rem;
}
.controls .btn--stop {
  font-size: clamp(1.05rem, 1.35vw, 1.25rem);
  padding: 0.5rem 1rem;
}
.controls .quiz-launch { font-size: clamp(1.05rem, 1.35vw, 1.25rem); }

/* .picker เป็นกล่องครอบปุ่มกับเมนู (เหมือน .report) ปุ่มข้างในต้องเต็มกล่อง
   ห้ามใส่ height:100% — พอ cross size ไม่ใช่ auto จะไม่ stretch แล้ว
   ตัว % ก็อ้างอิงความสูงที่ยังไม่นิ่ง เลยยุบเหลือเท่าตัวหนังสือ (เคยพลาดมาแล้ว) */
.controls .picker__btn {
  min-height: 0;
  padding: 0.5rem 1rem;
  gap: 0.28rem;
}
/* แป้นแถวบนสูงเท่ากันทั้งสามตัว ตัวหนังสือก็ต้องหนักใกล้เคียงกัน
   ของเดิมตั้งไว้ตอนปุ่มยังเตี้ย พอปุ่มโตขึ้น "ฉันคือ / ไม่ระบุ" เลยดูจิ๋ว
   อยู่กลางกล่องใหญ่ ทั้งที่ปุ่มข้าง ๆ ตัวหนังสือ 1.25–1.4rem */
.controls .picker__label { font-size: 0.78rem; }
.controls .picker__value { font-size: clamp(1rem, 1.25vw, 1.15rem); font-weight: 600; }
/* ปุ่มมีแต่รูปเพศ ไม่มีคำคู่แล้ว — รูปต้องใหญ่พอให้ดูออกจากระยะ โตตามความสูงปุ่ม (container picker)
   เจ้าของขอให้ใหญ่ขึ้น 2 ต.ค. 2569 (เดิม min(2rem, 18cqh) · มือถือเดิม min(1.5rem, 26cqh))
   และใหญ่ขึ้นอีกนิด 3 ต.ค. 2569 (min(3rem, 26cqh) · มือถือ min(2.2rem, 32cqh)) */
.controls .picker__emoji { font-size: min(3.6rem, 31cqh); }

/* ปุ่มสูงเกือบเต็มการ์ด (24vh) แต่กว้างแค่ 1/4 ของการ์ด — จอ 1440 ได้ปุ่ม ~160 x 160
   จอ 900 เหลือ ~95 x 160 ภาพตัวอักษรเลยต้องถูกจำกัดทั้งสองแกน:
     สูงไม่เกิน % ของความสูงปุ่ม (cqh) · กว้างไม่เกินปุ่ม (max-width: 100% + contain ย่อภาพเอง)
   min-width: 0 เพราะ flex item ที่มี aspect-ratio ไม่ยอมหดต่ำกว่าขนาดตัวเอง
   ปุ่มเป็น size container ได้เพราะขนาดมาจากช่องตาราง ไม่ได้มาจากเนื้อหาข้างใน */
.controls .btn--go,
.controls .btn--stop { container-type: size; }
.controls .btn--start .btn__label,
.controls .btn--stop .btn__label,
.controls .btn--next .btn__label { min-width: 0; max-width: 100%; }
/* แบบวาด: "เริ่ม" สูง 47% ของปุ่ม · "หยุด" 40% (ไม่มีวรรณยุกต์ข้างบน) */
.controls .btn--start .btn__label { height: min(3em, 48cqh); }
.controls .btn--stop .btn__label { height: min(2.7em, 40cqh); }
/* "คนถัดไป" ภาพยาวแนวนอน (ตัวอักษร + ลูกศร) — สูงได้ไม่เกิน 40% ของปุ่มเหมือน "หยุด"
   ปุ่มแคบกว่าภาพ ความกว้างโดน max-width บีบ ภาพจะเตี้ยลงเองตามสัดส่วน */
.controls .btn--next .btn__label { height: min(2.6em, 40cqh); }
/* ป้ายคีย์ลัด N เป็นของแถม ปุ่มแคบตัดทิ้งก่อน (container ที่ใกล้สุดคือตัวปุ่มเอง) */
@container (max-width: 150px) {
  .controls .btn__kbd { display: none; }
}

.controls .picker { container: picker / size; }
.controls .picker .picker__label { flex: none; min-width: 0; max-width: 100%; height: min(3.2em, 30cqh); }

/* ปุ่มเกมอยู่ในกล่องซ้อนสองชั้น (slot > launchers > button) ต้องยืดให้สุดทุกชั้น
   ถึงจะเต็มช่องตารางเท่าปุ่มอื่น */
.controls .quiz-slot { display: flex; }
.controls .quiz-launchers { display: flex; flex: 1 1 auto; min-width: 0; }
.controls .quiz-launch {
  flex: 1 1 auto;
  min-width: 0;
  min-height: 0;
  padding: 0.5rem 0.8rem;
  container-type: size;
}
/* ภาพของสถานะถูกท้า — ต้องอยู่หลังกฎรวมข้างบน (ความเจาะจงเท่ากัน ตัวหลังชนะ) */
.quiz-launch[data-state="challenged"] .quiz-launch__text {
  aspect-ratio: 426 / 160;
  background-image: url('btn/challenged-sign.png');
}
/* ป้ายมีกรอบของตัวเองมาในภาพแล้ว ปุ่มจึงต้องไม่มีกรอบ/พื้น/เงา/ขอบในซ้อนอีกชั้น
   :hover กับ :active ต้องเขียนด้วย ไม่งั้นแพ้ .quiz-launch--primary:hover ใน quiz.css */
.quiz-launch[data-state="challenged"],
.quiz-launch[data-state="challenged"]:hover,
.quiz-launch[data-state="challenged"]:active {
  background: transparent;
  border-color: transparent;
  box-shadow: none;
  padding: 0;
  transform: none;
}
/* วงแดงส้มที่เต้น: ย้ายจากตัวปุ่ม (กล่องเต็มช่องตาราง วงจะลอยห่างป้าย) มาไว้ที่ตัวภาพ
   กล่องของภาพพอดีกับป้ายเป๊ะ เพราะ aspect-ratio ตรงกับไฟล์และ background-size: contain
   คีย์เฟรมของเดิม (quiz-knock) ใส่เงาแข็ง 0 4px 0 มาด้วย เลยต้องมีชุดของตัวเอง */
.quiz-launch[data-state="challenged"] { animation: none; }
.quiz-launch[data-state="challenged"] .quiz-launch__text { border-radius: 8px; }
@media (prefers-reduced-motion: no-preference) {
  .quiz-launch--alert[data-state="challenged"] .quiz-launch__text { animation: quiz-knock-sign 1.6s var(--ease) infinite; }
}
@keyframes quiz-knock-sign {
  0%, 62%, 100% { box-shadow: 0 0 0 0 color-mix(in oklch, var(--vermilion) 60%, transparent); }
  30%           { box-shadow: 0 0 0 10px color-mix(in oklch, var(--vermilion) 0%, transparent); }
}
/* ภาพ "ท้าดวล!" กว้างราว 3.5 เท่าของความสูง ปุ่มแคบให้หดตามความกว้าง (contain) */
.controls .quiz-launch[data-state="idle"] .quiz-launch__text {
  min-width: 0;
  max-width: 100%;
  height: min(2.6em, 40cqh);
}
/* ป้ายถูกท้าเป็นตัวปุ่มเอง ไม่ใช่ตัวอักษรในปุ่ม — กว้างเต็มช่องแล้วสูงตามสัดส่วนไฟล์
   ช่องเตี้ยกว่านั้น (จอแนวนอน) ให้ max-height บีบ แล้ว contain ย่อภาพลงเอง */
.controls .quiz-launch[data-state="challenged"] .quiz-launch__text {
  min-width: 0;
  width: 100%;
  height: auto;
  max-height: 100%;
}

/* เดิมตรงนี้ชดเชยด้วย flex-grow: 1.25 เพราะ .picker ไม่มี padding ติดกล่อง
   เลยแคบกว่าเพื่อนราว 30px — grid แบ่งช่องเท่ากันอยู่แล้ว ไม่ต้องชดเชยอีก */

/* ปุ่มรองเคยใช้พื้นสีเดียวกับการ์ด (--paper ทั้งคู่) เหลือแค่เส้นขอบบางๆ
   เลยดูเป็นกล่องเปล่ามากกว่าปุ่ม — เข้มขึ้นหนึ่งขั้นให้แยกออกจากพื้นการ์ด */
.controls .toggle {
  background: var(--paper-2);
  padding: 0.5rem 1rem;
  font-size: 0.98rem;
}
.controls .toggle:hover { background: var(--paper-3); }

/* ปุ่มกว้างแล้ว วางไอคอนข้างตัวหนังสือดีกว่าซ้อนบน
   ต้องสั่ง justify-content เองด้วย — .toggle ไม่เคยตั้งไว้ ค่าเริ่มต้นคือ
   flex-start ตอนปุ่มแคบมองไม่ออก แต่พอกว้าง 250px ของไปกองซ้ายทันที */
.controls .toggle {
  flex-direction: row;
  justify-content: center;
  gap: 0.5rem;
}
.controls .toggle .toggle__icon { font-size: 1.3rem; }

/* ---- ปุ่มบนวิดีโอ (app.js ย้ายมาจากแถบล่าง) ----
   รายงาน = มุมขวาบนของบานคู่สนทนา แบบ OmeTV · โชว์เฉพาะตอนคุยอยู่ (กฎ is-lobby ซ่อนไว้แล้ว)
   คงโทนแดงส้มไว้ เพราะเป็นปุ่มที่ต้องดูต่างจากปุ่มทั่วไป */
.stage__remote > .report {
  position: absolute;
  top: 1rem;
  right: 1rem;
  z-index: 7;              /* เหนือป้าย (4) และหน้ารอ (5) */
}
/* ธงอยู่ในวงกลมแดงส้ม ตัวหนังสือสีหมึก — ดูเป็นปุ่มเตือนแต่ไม่ตะโกน
   ชี้/เปิดเมนูอยู่ = ทั้งปุ่มกลายเป็นแดงส้ม วงกลมกลับเป็นสีกระดาษ */
.stage__remote > .report .btn--report {
  gap: 0.45rem;
  padding: 0.3rem 0.95rem 0.3rem 0.3rem;
  border-radius: 999px;
  background: var(--paper);
  color: var(--ink);
  box-shadow: var(--drop-1);
  transition: background 0.15s var(--ease), color 0.15s var(--ease), transform 0.15s var(--ease), box-shadow 0.15s var(--ease);
}
.stage__remote > .report .btn--report__icon {
  display: inline-grid;
  place-items: center;
  width: 1.9rem;
  height: 1.9rem;
  border-radius: 50%;
  background: var(--vermilion);
  color: var(--paper);
  transition: inherit;
}
.stage__remote > .report .btn--report__icon svg { width: 1rem; height: 1rem; }
.stage__remote > .report .btn--report:hover,
.stage__remote > .report .btn--report[aria-expanded="true"] {
  background: var(--vermilion);
  color: var(--paper);
  transform: translate(-1px, -1px);
  box-shadow: 4px 4px 0 var(--ink);
}
.stage__remote > .report .btn--report:hover .btn--report__icon,
.stage__remote > .report .btn--report[aria-expanded="true"] .btn--report__icon {
  background: var(--paper);
  color: var(--vermilion-ink);
}
.stage__remote > .report .btn--report:active {
  transform: translate(3px, 3px);
  box-shadow: 0 0 0 var(--ink);
}
/* อยู่ขอบบนของบานแล้ว เมนูต้องเปิดลงข้างล่าง ไม่ใช่ขึ้นข้างบนแบบตอนอยู่แถบล่าง */
.stage__remote > .report .report__menu { top: calc(100% + 0.6rem); bottom: auto; }

/* พลิกกล้อง = มุมขวาล่างของบานเรา (ป้าย "คุณ" อยู่มุมซ้ายล่าง) */
.selfie > #flip-btn {
  position: absolute;
  right: 0.75rem;
  bottom: 0.6rem;
  z-index: 6;
  min-height: 0;
  padding: 0.35rem 0.8rem;
  font-size: 0.85rem;
}

@media (max-width: 859px) {
  /* แชทลอยทับเวทีแทนการแบ่งคอลัมน์
     ⚠️ ต้อง override grid-area ด้วย! ของเดิมล็อกไว้ที่คอลัมน์ 2 (สำหรับจอกว้าง)
     แต่กล่อง position:absolute ที่มีตำแหน่ง grid ชัดเจน จะใช้ "ช่อง grid นั้น"
     เป็นกรอบอ้างอิง ไม่ใช่ทั้งหน้าจอ — พอจอเล็กมีคอลัมน์เดียว คอลัมน์ 2 กว้าง 0px
     แชทเลยถูกบีบจนมองไม่เห็น
     ตั้งเป็น 1/1 = อ้างอิงช่องของวิดีโอ ทำให้ลอยอยู่เหนือแถบปุ่มพอดี */
  .chat {
    grid-area: 1 / 1;
    position: absolute;
    z-index: 15;
    left: 0.5rem; right: 0.5rem;
    bottom: 0.5rem;
    max-height: min(62svh, 26rem);
    margin: 0;
    box-shadow: 0 24px 50px -24px oklch(20% 0.03 50 / 0.6);
  }
  /* แถววิดีโอต้องหดได้ (minmax 0) — 1fr เฉย ๆ คือ minmax(auto, 1fr) ซึ่งยืนกรานตามขนาดภาพกล้อง
     แถบปุ่มแถวล่างเลยโดนดันออกนอกจอ (กันซ้อนกับ min-height: 0 ของ .stage อีกชั้น) */
  #chat-screen { position: relative; grid-template-rows: minmax(0, 1fr) auto; }
  .btn__kbd { display: none; }

  /* ---- เวทีแบ่งสองบานเท่ากันเหมือนจอกว้าง (เดิมหน้าเราเป็นกล่องจิ๋วลอยทับ) ----
     กล่องจิ๋วมุมล่างขวาเล็กเกินกว่าจะรู้ว่าอีกฝ่ายเห็นเราเป็นยังไง และมันทับ
     หน้าคู่สนทนาอยู่ตลอด แบ่งครึ่งแล้วทั้งสองฝั่งได้พื้นที่เท่ากัน
     แนวตั้งแบ่งบน/ล่าง แนวนอนแบ่งซ้าย/ขวา — ตัดตามด้านที่ยาวกว่าเสมอ */
  /* สองบานแยกเป็นการ์ดของตัวเองแบบ iPad (เจ้าของเลือก 14 ก.ย. 2569)
     เดิมเป็นกล่องมืดกล่องเดียวมีเส้นบางคั่นกลาง อ่านเป็นคนละภาษากับการ์ดปุ่มข้างล่าง
     overflow: visible เพราะตอนปัด บานคู่สนทนาเลื่อนตามนิ้ว ต้องไม่ถูกตัดขอบกลางทาง
     (แต่ละบานมี overflow: hidden ของตัวเองอยู่แล้ว ภาพวิดีโอไม่ล้นมุมโค้ง)
     ⚠️ min-height: 0 ห้ามหาย — ลูก grid ที่ overflow: visible จะไม่ยอมเตี้ยกว่าเนื้อหาตัวเอง
     กล้องโทรศัพท์ถือตั้งให้ภาพแนวตั้ง 720x1280 เวทีเลยยืดสูงตามภาพจนแถบปุ่มหลุดใต้จอ
     (เจ้าของส่งรูปมา 14 ก.ย. 2569 · กล้องปลอมของ Playwright เป็นแนวนอน 640x480 เลยไม่เคยเจอ) */
  .stage {
    display: grid;
    min-height: 0;
    gap: var(--pane-gap);
    background: none;
    overflow: visible;
    border: none;
    border-radius: 0;
    box-shadow: none;
  }
  .selfie {
    position: relative;
    inset: auto;
    width: auto;
    height: auto;
    min-height: 0;      /* ไม่ใส่ = grid ยืนกรานตามขนาดวิดีโอ แล้วบานล่างจะล้น */
    aspect-ratio: auto;
    z-index: 2;
  }
  .stage > .stage__remote,
  .stage > .selfie {
    border: var(--ink-w) solid var(--ink);
    border-radius: var(--radius-lg);
    box-shadow: var(--drop-2);
  }
  .selfie:hover { transform: none; }   /* มือถือไม่มีเมาส์ชี้ และบานนี้ไม่ควรขยับ */
  .selfie { --tag-x: 0.6rem; --tag-y: 0.5rem; }
  .selfie__tag { font-size: 0.72rem; }
  #local-video { min-height: 0; }
}

@media (max-width: 859px) and (orientation: portrait) {
  .stage { grid-template-columns: 1fr; grid-template-rows: 1fr 1fr; }
}

@media (max-width: 859px) and (orientation: landscape) {
  .stage { grid-template-columns: 1fr 1fr; grid-template-rows: 1fr; }
}

@media (max-width: 520px) {
  .btn--report span, .controls__right .btn--text { font-size: 0.8rem; }
  .otp { gap: 0.3rem; }
  .otp__sep { width: 0.4rem; }
  .panel__tape { right: 1rem; }
}

/* ---------- ชวนเพื่อน (โผล่เมื่อรอนาน) ---------- */
.waiting__invite {
  margin-top: 1.1rem;
  padding-top: 1.1rem;
  border-top: 1.5px dashed var(--line-strong);
  display: grid;
  gap: 0.7rem;
  justify-items: center;
  animation: rise 0.5s var(--ease) both;
}
.waiting__invite[hidden] { display: none; }

.waiting__invite-text {
  margin: 0;
  font-size: 0.85rem;
  line-height: 1.6;
  color: var(--ink-2);
}
/* อยู่บนการ์ดกระดาษแล้ว (เดิมเป็นเส้นอำพันบนพื้นมืด ซึ่งบนครีมอ่านไม่ออก)
   "ชวนเพื่อน" คือการลงมือทำ = ม่วงแดงแบบปุ่มหลักทั้งเว็บ + ขอบหมึก + เงาแข็ง */
.waiting__invite-btn {
  padding: 0.6rem 1.5rem;
  font-size: 0.9rem;
  min-height: 44px;
  border: var(--ink-w) solid var(--ink);
  background: var(--grape);
  color: var(--paper);
  box-shadow: 0 3px 0 var(--ink);
}
.waiting__invite-btn:hover {
  transform: translateY(-1px);
  box-shadow: 0 4px 0 var(--ink);
}
.waiting__invite-btn:active { transform: translateY(3px); box-shadow: 0 0 0 var(--ink); }

/* ==========================================================================
   แถบเตือนเมื่อเปิดจากเบราว์เซอร์ในแอป
   ========================================================================== */
.inapp {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.7rem clamp(0.85rem, 3vw, 1.25rem);
  padding-top: max(0.7rem, env(safe-area-inset-top));
  background: var(--sun);
  color: var(--ink);
  border-bottom: 1.5px solid var(--sun-lo);
}
.inapp[hidden] { display: none; }

.inapp__body { flex: 1; min-width: 0; }
.inapp__title {
  margin: 0;
  font-size: 0.86rem;
  font-weight: 600;
  line-height: 1.4;
}
.inapp__how {
  margin: 0.15rem 0 0;
  font-size: 0.78rem;
  line-height: 1.45;
  color: color-mix(in oklch, var(--ink) 75%, transparent);
}

.inapp__actions {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  flex: none;
}
.inapp__copy {
  padding: 0.45rem 0.7rem;
  font-size: 0.78rem;
  border: 1.5px solid var(--ink);
  border-radius: 999px;
  background: transparent;
  color: var(--ink);
  white-space: nowrap;
  min-height: 36px;
}
.inapp__close {
  border: none;
  background: transparent;
  color: var(--ink);
  font-size: 1rem;
  line-height: 1;
  padding: 0.5rem;
  cursor: pointer;
  opacity: 0.6;
  min-width: 36px;
  min-height: 36px;
}
.inapp__close:hover { opacity: 1; }

@media (max-width: 520px) {
  .inapp { flex-wrap: wrap; gap: 0.5rem; }
  .inapp__body { flex: 1 1 100%; }
  .inapp__actions { flex: 1 1 100%; justify-content: space-between; }
}

/* ==========================================================================
   หน้าเตรียมตัวก่อนเริ่ม (lobby)
   ผู้ใช้เห็นภาพตัวเองเต็มจอ ปรับกล้อง/ไมค์ได้ แล้วค่อยกดเริ่มเอง
   ========================================================================== */

/* ห้องเตรียมตัวไม่ต้องมีกฎขนาดของตัวเอง — ทุกขนาดจอมีบานของเราถาวรอยู่แล้ว
   บานคู่สนทนาที่ยังว่างจะโชว์ .empty-pane แทน (เดิมจอแคบเอาหน้าเราขยายทับทิ้ง) */

/* ปุ่มที่ยังไม่มีความหมายตอนยังไม่ได้คุยกับใคร
   "หยุด" ไม่ได้ซ่อนด้วย — แค่กดไม่ได้ (ดู app.js) เพราะถ้าหายไปทั้งปุ่ม
   ปุ่มที่เหลือจะเลื่อนตำแหน่งทุกครั้งที่เริ่ม/ออก */
#chat-screen.is-lobby .btn--next,
#chat-screen.is-lobby .report { display: none; }

/* ระหว่างหาคน (หน้า "กำลังหาคนคุย" โชว์อยู่และยังไม่มีคู่) ก็ไม่มีใครให้รายงาน
   เซิร์ฟเวอร์รับรายงานเฉพาะคู่ปัจจุบัน (ws.partner) ถ้าไม่มีคู่ก็แค่พากลับเข้าคิว ไม่บันทึกอะไร
   แต่ปุ่มยังขึ้น "ส่งรายงานแล้ว ขอบคุณ" ให้ — คนกดจะเข้าใจผิดว่ารายงานคนที่เพิ่งข้ามไปแล้ว
   และบนโทรศัพท์ปุ่มนี้ไปทับมุมการ์ดหน้ารอพอดี (เจ้าของขอพื้นลายหน้าแรก 14 ก.ย. 2569)
   ป้ายคู่สนทนา (#peer-badge) = ตัวบอกว่ามีคู่: โชว์ตอน matched ซ่อนใน cleanupPeer ทุกทางที่คู่หาย
   ช่วง "เจอแล้ว! กำลังเชื่อมต่อ" หน้ารอยังโชว์แต่มีคู่แล้ว ปุ่มจึงยังอยู่ รายงานได้จริง
   เบราว์เซอร์เก่าที่ไม่รู้จัก :has() จะเห็นปุ่มเหมือนเดิม ไม่เสียอะไร */
.stage__remote:has(> #status-overlay:not([hidden])):has(> #peer-badge[hidden]) > .report { display: none; }

/* ...แล้วเอาปุ่มเริ่มมาอยู่ช่องนั้นแทน */
#chat-screen.is-lobby .btn--start { display: inline-flex; }

/* เดิมจอแคบซ่อนปุ่มแชทตอนอยู่ห้องเตรียมตัว (เหตุผล: ยังไม่มีคู่คุยให้พิมพ์)
   แต่ผลคือแถวปุ่มล่างเปลี่ยนจำนวนปุ่มตอนกดเริ่ม ปุ่มที่เหลือเลยขยับตำแหน่ง
   และแถวดูโหวงตอนอยู่ห้องเตรียมตัว ให้ปุ่มอยู่ครบทุกสถานะแทน
   กดตอนยังไม่มีคู่ก็ไม่เสียหาย แผงแชทบอกอยู่แล้วว่า "แชทจะเปิดเมื่อเจอคู่สนทนา" */

/* แสดงช่องพิมพ์ที่ยังปิดอยู่พร้อมเหตุผล แทนการซ่อนจนดูเหมือนแชทเสีย */
#chat-screen.is-lobby .chat__quick { display: none; }
.chat__form input:disabled { color: var(--ink-2); cursor: not-allowed; }
.chat__form button:disabled { opacity: .45; cursor: not-allowed; }

/* กล่องเตรียมตัวต้อง "เตี้ย" ที่สุดเท่าที่จะทำได้ และเกาะขอบล่าง
   เพราะจุดประสงค์คือให้ดูหน้าตัวเอง — ถ้าการ์ดบังหน้าก็เสียความหมายทั้งหมด
   เดิมมี 4 บรรทัด (หัวเรื่องเล็ก + หัวเรื่องใหญ่ + คำอธิบาย 2 บรรทัด + หมายเหตุ)
   กินสูงเกือบ 1 ใน 3 ของจอ ตัดเหลือคำอธิบายบรรทัดเดียว + ปุ่ม */
/* เหลือแค่คำอธิบายบรรทัดเดียวเกาะขอบล่างของบานเรา — ปุ่มเริ่มย้ายไปแถบปุ่มแล้ว
   ไม่มีอะไรให้กดในนี้ เลยปล่อยให้คลิกทะลุไปโดนวิดีโอได้ทั้งชั้น */
.lobby {
  position: absolute;
  inset: 0;
  z-index: 8;
  display: grid;
  align-items: end;
  justify-items: center;
  padding: 0.9rem;
  pointer-events: none;
  /* มืดเฉพาะแถบล่างพอให้อ่านออก ส่วนที่เป็นหน้าคนปล่อยใสไว้ */
  background: linear-gradient(
    to top,
    color-mix(in oklch, var(--stage) 72%, transparent) 0%,
    transparent 30%
  );
}
.lobby[hidden] { display: none; }
/* มีป้ายคนออนไลน์ซ้อนอยู่บนคำอธิบาย — ชิดล่างทั้งคู่ เว้นห่างนิดเดียว */
.lobby { align-content: end; gap: 0.45rem; }

/* ---------- ป้ายคนออนไลน์ ---------- */
/* จุดเขียวกะพริบเบาๆ = "สด ตอนนี้" แบบที่คนคุ้นจากแอปแชท */
.online-pill {
  justify-self: start;
  display: flex;             /* บรรทัดของตัวเอง ไม่ไปเบียดข้างโลโก้ */
  width: fit-content;
  align-items: center;
  gap: 0.5rem;
  margin: 0 0 1.1rem;
  padding: 0.3rem 0.85rem 0.3rem 0.7rem;
  border: var(--ink-w) solid var(--ink);
  border-radius: 999px;
  background: var(--paper);
  box-shadow: var(--drop-1);
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--ink);
  animation: rise 0.45s var(--ease) both;
}
.online-pill[hidden] { display: none; }
.online-pill__dot {
  position: relative;
  width: 0.6rem;
  height: 0.6rem;
  border-radius: 50%;
  background: oklch(68% 0.19 145);
  box-shadow: 0 0 0 1.5px var(--ink);
}
.online-pill__dot::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: oklch(68% 0.19 145);
  animation: online-ping 1.8s var(--ease) infinite;
}
@keyframes online-ping {
  from { transform: scale(1); opacity: 0.7; }
  to   { transform: scale(2.6); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .online-pill__dot::after { animation: none; }
}
/* บนการ์ดรอคู่: อยู่กลางการ์ด ใต้ "รอมา … วินาที" · ไม่ใส่เงา การ์ดมีเงาอยู่แล้ว */
.online-pill--card {
  margin: 0.7rem auto 0;
  box-shadow: none;
  font-size: 0.8rem;
}
/* บนวิดีโอ: ใช้แบบกระจกมืดเหมือนคำอธิบายข้างล่าง ไม่ใช่การ์ดกระดาษ */
.online-pill--dark {
  justify-self: center;
  margin: 0;
  border: none;
  box-shadow: none;
  font-size: 0.8rem;
  color: var(--paper);
  background: color-mix(in oklch, var(--stage) 60%, transparent);
  backdrop-filter: blur(6px);
}

.lobby__sub {
  margin: 0;
  padding: 0.4rem 0.9rem;
  border-radius: 999px;
  font-size: 0.82rem;
  line-height: 1.5;
  text-align: center;
  color: color-mix(in oklch, var(--paper) 88%, transparent);
  background: color-mix(in oklch, var(--stage) 60%, transparent);
  backdrop-filter: blur(6px);
  animation: rise 0.45s var(--ease) both;
}

@media (max-width: 600px) {
  .lobby { padding: 0.6rem; }
  .lobby__sub { font-size: 0.78rem; }
}

/* ==========================================================================
   มือถือ: notch, จอแนวนอน, การแตะ
   ========================================================================== */

/* เว้นที่ให้ notch / มุมโค้ง ทุกด้าน (คู่กับ viewport-fit=cover ใน index.html)
   ถ้าไม่เว้น ป้ายมหาลัยกับปุ่มออกจะโดนรอยบากทับบน iPhone */
@media (max-width: 859px) {
  .stage {
    margin-left:  max(clamp(0.5rem, 1.2vw, 0.85rem), env(safe-area-inset-left));
    margin-right: max(clamp(0.5rem, 1.2vw, 0.85rem), env(safe-area-inset-right));
    margin-top:   max(clamp(0.5rem, 1.2vw, 0.85rem), env(safe-area-inset-top));
  }
  /* ---- การ์ดปุ่มแบบ iPad (เจ้าของเลือก 14 ก.ย. 2569) ----
     ขอบนอกตรงกับบานวิดีโอข้างบน: ระยะเว้นขอบชุดเดียวกับ .stage
     ความสูงแถวต้องล็อกเอง — ปุ่มเป็น size container ถ้าปล่อยเป็น auto ป้ายภาพข้างในยุบเหลือ 0
     10svh = ปุ่มโตตามความสูงจอ แต่ไม่เตี้ยกว่านิ้วโป้งกดสบาย (4.25rem ≈ 68px) และไม่สูงจนกินวิดีโอ */
  .controls {
    grid-row: 2;
    grid-template-rows: clamp(4.25rem, 10svh, 6rem);
    gap: 0.45rem;
    margin: clamp(0.5rem, 1.2vw, 0.85rem);
    margin-left:   max(clamp(0.5rem, 1.2vw, 0.85rem), env(safe-area-inset-left));
    margin-right:  max(clamp(0.5rem, 1.2vw, 0.85rem), env(safe-area-inset-right));
    margin-bottom: max(clamp(0.5rem, 1.2vw, 0.85rem), env(safe-area-inset-bottom));
    padding: 0.5rem;
    background: var(--paper);
    border: var(--ink-w) solid var(--ink);
    border-radius: var(--radius-lg);
    box-shadow: var(--paper-lift);
  }
  /* ปุ่มกว้างแค่ ~80px บนจอ 390 — ขอบในแบบจอกว้าง (1rem) กินที่ป้ายภาพไปเกือบครึ่ง */
  .controls .btn--next,
  .controls .btn--start,
  .controls .btn--stop,
  .controls .picker__btn,
  .controls .quiz-launch { padding: 0.3rem 0.35rem; }
  /* รูปเพศตามสัดส่วนจอกว้าง (18cqh) เหลือ ~12px บนปุ่มสูง 68px เล็กจนดูไม่ออก */
  .controls .picker__emoji { font-size: min(2.6rem, 36cqh); }
  /* กลับเกม ห้ามตัดคำ ช่องแคบใส่ทั้ง ⚡ และคำไม่พอ — เหลือแต่คำ (ถูกท้าเป็นภาพวาดแล้ว ไม่เข้ากฎนี้) */
  .controls .quiz-launch[data-state="playing"] .quiz-launch__icon { display: none; }
  .controls .quiz-launch[data-state="playing"] .quiz-launch__text { font-size: 0.9rem; }

  /* ปุ่มแชทกับพลิกกล้อง: มุมขวาบนของบานเรา (app.js ย้ายมา)
     z-index เหนือคำอธิบายห้องเตรียมตัว (8) ไม่งั้นกดไม่โดนตอนยังไม่เริ่ม */
  .selfie__tools {
    position: absolute;
    top: 0.6rem;
    right: 0.6rem;
    z-index: 9;
    display: flex;
    gap: 0.4rem;
  }
  .selfie__tools .toggle {
    padding: 0.3rem 0.8rem;
    font-size: 0.85rem;
    box-shadow: var(--drop-1);
  }

  /* นิ้วต้องแตะโดนง่าย — ปุ่มเล็กกว่า 44px คนกดพลาดบ่อย */
  .toggle, .btn--report, .btn--text { min-height: 44px; }

  /* ครึ่งบนของจอโทรศัพท์ไม่ได้สูงขนาดนั้น ของในหน้ารอย่อลงหนึ่งขั้น
     และเรียงเป็นลำดับเดียว: หัวเรื่อง → เวลารอ (เกาะหัวเรื่อง) → ทิปบรรทัดเล็ก
     (เจ้าของส่งรูปจากโทรศัพท์มาบอกว่ามั่ว 14 ก.ย. 2569) */
  /* กระเบื้องลายเล็กลงเท่าหน้าแรกจอแคบ (420px) ให้ยังเห็นลายครบชุดในบานที่เตี้ยครึ่งจอ
     ประกาศที่บาน หน้าพักกับหน้ารอจะได้ใช้ขนาดเดียวกัน (ดู .stage__remote) */
  .stage__remote { --tile-w: 420px; }
  .waiting { padding: 1.2rem; }
  .waiting__inner,
  .empty-pane__card { gap: 0.4rem; padding: 0.9rem 1.1rem; }
  /* บานครึ่งจอเตี้ย — สติกเกอร์ย่อลงและเด้งน้อยลง ไม่งั้นการ์ดล้นบาน */
  .waiting__faces { --mascot-h: 3rem; --mascot-lift: -3px; margin-bottom: 0.1rem; }
  /* จองความสูงไว้ — สามวินาทีแรกบรรทัดนี้ว่าง พอข้อความโผล่ของข้างล่างจะกระตุกลง */
  .waiting__elapsed { margin-top: -0.3rem; min-height: 1.3em; }
  /* ทิปถอดเทปออก เหลือตัวหนังสือเล็กบนการ์ด — บานครึ่งจอเตี้ย กล่องซ้อนกล่องจะล้นบาน */
  .waiting__tip {
    margin-top: 0.3rem;
    padding: 0;
    border: 0;
    background: none;
    box-shadow: none;
    transform: none;
    font-size: 0.8rem;
    line-height: 1.5;
    text-wrap: balance;
    color: var(--ink-2);
  }
  /* ป้ายคนออนไลน์ (30 ก.ย. 2569) ทำให้การ์ดสูงขึ้น พอรอนานจนกล่องชวนเพื่อนโผล่
     ปุ่ม "ชวนเพื่อน" ล้นบานครึ่งจอจนมองไม่เห็น (เจ้าของส่งรูปจาก iPhone มา 30 ก.ย. 2569)
     ตอนชวนเพื่อนโผล่ ถอดทิปกับสติกเกอร์ออก (ชวนเพื่อนสำคัญกว่า) แล้วบีบระยะห่างลง
     ถอดแค่ทิปยังไม่พอ ปุ่มยังโดนตัดครึ่งบนจอ iPhone */
  .online-pill--card { margin-top: 0.3rem; }
  .waiting__inner:has(.waiting__invite:not([hidden])) :is(.waiting__tip, .waiting__faces) { display: none; }
  .waiting__invite { margin-top: 0.3rem; padding-top: 0.6rem; gap: 0.5rem; }
  /* กันเหนียว: จอเตี้ยกว่าที่คิด การ์ดเลื่อนดูได้ในตัว ไม่โดนตัดทิ้ง */
  .waiting { grid-template-rows: minmax(0, 1fr); }
  .waiting__inner { max-height: 100%; overflow-y: auto; }

  /* กันเบราว์เซอร์ซูมเองตอนแตะช่องพิมพ์ (เกิดเมื่อ font เล็กกว่า 16px บน iOS) */
  .chat__form input, #email-input { font-size: 16px; }
}

/* ==========================================================================
   โทรศัพท์ (≤600px)
   แถบปุ่มใช้การ์ดชุดเดียวกับ iPad แล้ว (ดูบล็อก max-width: 859px ข้างบน)
   เดิมตรงนี้จัดแถบปุ่มแคปซูลอีโมจิของโทรศัพท์ทั้งชุด ถอดออกเมื่อเจ้าของเลือกแบบ iPad (14 ก.ย. 2569)
   เหลือแค่ของที่ต้องหลบรอยบากกับขอบจอแคบจริง ๆ
   ========================================================================== */
@media (max-width: 600px) {
  /* ป้ายต่างๆ ต้องหลบรอยบาก ไม่งั้นโดนบังบน iPhone */
  .sticker--peer  { top: max(1rem, calc(env(safe-area-inset-top) + 0.5rem)); left: 0.75rem; }
  .sticker--demo  { top: max(1rem, calc(env(safe-area-inset-top) + 0.5rem)); }
  /* ปุ่มรายงานมุมขวาบน ต้องอยู่ระดับเดียวกับป้ายมหาลัยที่มุมซ้าย ไม่งั้นแถวบนดูเบี้ยว */
  .stage__remote > .report { top: max(1rem, calc(env(safe-area-inset-top) + 0.5rem)); right: 0.75rem; }

  .chat { left: 0.5rem; right: 0.5rem; bottom: 0.5rem; }
}

/* โทรศัพท์แนวนอน — จอเตี้ยมาก ปุ่มสูง 68px จะเหลือที่ให้วิดีโอไม่ถึงครึ่งจอ */
@media (max-width: 859px) and (max-height: 480px) {
  .controls { grid-template-rows: 3.25rem; padding: 0.35rem; }
}

/* แถบแคบลงเมื่อเปิดบานแชท: ยุบป้ายทีละขั้นตามลำดับความสำคัญ
   ปุ่มที่ใช้น้อยกว่ายอมเหลือแต่ไอคอนก่อน ทุกตัวที่ยุบมี title + aria-label
   กำกับไว้แล้ว ไม่ได้หายไปเฉยๆ

   ⚠️ ตัวเลขชุดนี้ผูกกับจำนวนปุ่มต่อแถว ไม่ใช่ความกว้างจอ
   ตอนแถบเป็นแถวเดียวมีปุ่ม 6 ตัวแบ่งความกว้างกัน แต่ละช่องจึงแคบมาก
   เกณฑ์เดิมเลยต้องสูงถึง 700/680px พอแยกเป็นสองแถว (บน 3 ตัว · ล่างกว้างตามเนื้อหา)
   ช่องกว้างขึ้นเกือบเท่าตัว เกณฑ์เดิมกลายเป็นการซ่อนป้ายทั้งที่ยังมีที่เหลือเฟือ
   — ป้าย "ไม่ระบุ" กับ "รายงาน" หายตั้งแต่จอ 1440px ซึ่งไม่มีเหตุผลเลย
   ถ้าจะเพิ่ม/ลดปุ่มต่อแถวอีก ต้องมาปรับตัวเลขชุดนี้ด้วยเสมอ */
@media (min-width: 860px) {
  /* ขั้นแรก: ปุ่มแชทกับปุ่มรายงานเหลือแต่ไอคอน (สองตัวนี้กดน้อยที่สุดในแถบ) */
  @container bar (max-width: 420px) {
    .controls .toggle__text { display: none; }
    .controls .toggle { padding-inline: 0.7rem; }
    .controls .btn--report .btn__label { display: none; }
    .controls .btn--report__icon { display: inline; font-size: 1.25rem; }
  }
  /* ขั้นสอง: ปุ่มเพศกับปุ่มเกมลดขอบข้าง */
  @container bar (max-width: 400px) {
    .controls .picker__btn { padding-inline: 0.7rem; }
    .controls .quiz-launch { padding-inline: 0.7rem; }
  }
  /* ขั้นสาม: ปุ่มเกม — ภาพวาด ("ท้าดวล!" / "คุณถูกท้าดวล!") ย่อภาพลง
     ส่วนป้ายตัวหนังสือ (กลับเกม) ห้ามตัดคำ พอช่องแคบกว่านี้มันจะล้นไปทับ
     ปุ่มข้าง ๆ แทนที่จะหด เลยเหลือแต่ ⚡ (ปุ่มยังมี aria-label เต็มอยู่) */
  @container bar (max-width: 340px) {
    .controls .quiz-launch[data-state="playing"] .quiz-launch__text { display: none; }
    .controls .quiz-launch[data-state="idle"] .quiz-launch__text { height: 1.4em; }
    .controls .quiz-launch__icon { font-size: 1.25rem; }
  }
  /* ขั้นสี่: ตัดป้ายคีย์ลัด N ทิ้ง — เป็นของแถม ไม่ใช่ข้อมูลที่ต้องมี */
  @container bar (max-width: 300px) {
    .controls .btn__kbd { display: none; }
  }
}

/* จอกว้างแต่เตี้ย (โน้ตบุ๊ก 768px) — การ์ดแชทเหลือที่ให้ข้อความไม่ถึง 30px
   ตัดปุ่มทักทายออกก่อน เพราะพิมพ์เองได้ แต่ถ้าอ่านข้อความไม่เห็นคือใช้ไม่ได้เลย */
@media (min-width: 860px) and (max-height: 820px) {
  .chat__quick { display: none; }
}

/* จอแนวนอนบนมือถือ — เตี้ยมาก ต้องบีบทุกอย่างให้พอดี
   ไม่งั้นปุ่มควบคุมจะหลุดออกนอกจอ กด "คนถัดไป" ไม่ได้ */
@media (max-height: 480px) and (orientation: landscape) {
  .controls { padding-top: 0.35rem; padding-bottom: 0.35rem; }
  .toggle { padding: 0.4rem 0.6rem; }
  .btn--next, .btn--start { padding: 0.5rem 0.9rem; font-size: 0.88rem; }
  .btn--stop { padding: 0.5rem 0.8rem; font-size: 0.85rem; }
  .picker__btn { padding: 0.3rem 0.7rem; }
  .waiting__faces { --mascot-h: 2.4rem; }
  .waiting__tip { display: none; }
  .chat { max-height: 78svh; }
}

/* ==========================================================================
   จอสัมผัส (โทรศัพท์ + iPad): แชท · พลิกกล้อง · ฉันคือ · ท้าดวล
   เจ้าของขอ 16 ก.ย. 2569: ปุ่มแชทแทนช่อง "เริ่ม/คนถัดไป" ปุ่มพลิกกล้องแทนช่อง "หยุด"
   คนถือเครื่องใช้ท่าปัดอยู่แล้ว: ปัดซ้าย = เริ่ม/คนถัดไป · ปัดขวา = หยุด (bindSwipeToNext ใน app.js)
   ถาม "อุปกรณ์ชี้หลัก" ไม่ใช่ความกว้างจอ แบบเดียวกับป้าย .empty-pane__how — iPad แนวนอนกว้างเท่าจอคอมแต่ก็ปัด
   app.js (placeMainControls) ย้ายสองปุ่มนี้เข้าแถบ กฎชุดนี้เลยจับเฉพาะตอนอยู่ใน .controls

   ปุ่มเริ่ม/คนถัดไป/หยุด ไม่ได้ลบ แค่ซ่อนจากตา — VoiceOver/TalkBack ปัดบนวิดีโอไม่ได้ ต้องยังกดปุ่มได้
   เครื่องกล้องตัวเดียวไม่มีปุ่มพลิกกล้อง (hidden ดู setupCameraFlip) ปุ่มหยุดจึงกลับมาอยู่ช่องสองเหมือนเดิม
   ภาพตัวอักษรตัดจาก Downloads/chat.jpg กับ camera.jpg (ข้างในกรอบที่วาด (65, 468)–(1213, 858))
   ลบพื้นครีมด้วยการเติมสีจากขอบภาพ ครีมในตัวอักษรที่มีเส้นหมึกล้อมไว้จึงยังอยู่ แล้วย่อให้สูง 160px
   ========================================================================== */
@media (pointer: coarse) {
  .controls .btn--start,
  .controls .btn--next,
  .controls:has(#flip-btn:not([hidden])) .btn--stop {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    border: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
  /* ต้องล็อกแถว 1 ให้ทุกช่องด้วย ไม่ใช่แค่คอลัมน์ — ใน DOM "ฉันคือ" มาก่อนแชท
     พอ "ฉันคือ" จองคอลัมน์ 3 ไปแล้ว ตัวจัดวางของ grid เดินหน้าต่อเท่านั้น
     แชทที่ขอคอลัมน์ 1 เลยถูกดันไปแถวสอง (แถวที่ไม่มีความสูง ปุ่มเหลือ 14px — เทสจับได้) */
  .controls #chat-toggle,
  .controls #flip-btn,
  .controls .btn--stop,
  .controls .picker,
  .controls .quiz-slot { grid-row: 1; }
  .controls #chat-toggle { grid-column: 1; }
  .controls #flip-btn,
  .controls .btn--stop { grid-column: 2; }
  .controls .picker { grid-column: 3; }

  /* หน้าตาเดียวกับ .btn--go: พื้นครีมโลโก้ ขอบหมึก เงาแข็ง
     display ต้องสั่งเอง — จอกว้างซ่อน #chat-toggle ไว้ (แชทเป็นบานถาวร) แต่ iPad แนวนอนต้องมีปุ่มนี้
     ปุ่มพลิกกล้องที่ hidden ยังหายได้ เพราะ [hidden] เป็น !important */
  .controls #chat-toggle,
  .controls #flip-btn {
    display: inline-flex;
    min-width: 0;
    min-height: 0;
    padding: 0.3rem 0.35rem;
    border-radius: var(--radius);
    background: var(--logo-ground);
    box-shadow: 0 4px 0 var(--ink);
    container-type: size;
  }
  /* พื้นต้องเป็นครีมตัวเดียวกับไฟล์ภาพ (เหตุผลเดียวกับ .btn--go:hover) */
  .controls #chat-toggle:hover,
  .controls #flip-btn:hover {
    background: var(--logo-ground);
    transform: translateY(-1px);
    box-shadow: 0 5px 0 var(--ink);
  }
  .controls #chat-toggle:active,
  .controls #flip-btn:active { transform: translateY(4px); box-shadow: 0 0 0 var(--ink); }

  .controls #chat-toggle .toggle__icon,
  .controls #flip-btn .toggle__icon { display: none; }
  /* คำจริงยังอยู่ใน DOM ดันออกนอกกรอบแบบ .btn--next .btn__label
     display: block ชนะกฎยุบป้ายของแถบแคบ (.controls .toggle__text ใน @container bar) */
  .controls #chat-toggle .toggle__text,
  .controls #flip-btn .toggle__text {
    display: block;
    min-width: 0;
    max-width: 100%;
    height: min(2.6em, 40cqh);
    background: center / contain no-repeat;
    text-indent: -100em;
    overflow: hidden;
    white-space: nowrap;
  }
  .controls #chat-toggle .toggle__text { aspect-ratio: 522 / 160; background-image: url('btn/chat.png'); }
  .controls #flip-btn .toggle__text { aspect-ratio: 744 / 160; background-image: url('btn/flip.png'); }
}

/* วิดีโอไม่ควรถูกลากหรือกดค้างแล้วเด้งเมนูบันทึกภาพบนมือถือ */
#remote-video, #local-video {
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
}

/* ==========================================================================
   เคารพการตั้งค่าลดการเคลื่อนไหว
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

/* ==========================================================================
   ภาษาอังกฤษ (html[lang="en"] — i18n.js ตั้งให้ตอนเลือก EN) 27 ก.ย. 2569
   ได้แบบวาดภาษาอังกฤษของเจ้าของมา 2 ต.ค. 2569 → public/btn/en/*.png
   ตัดแบบเดียวกับภาพไทย: เอาเฉพาะของข้างในกรอบ ลบครีมที่ต่อกับขอบภาพ เนื้อตัวอักษรครีมคงไว้ทึบ
   ขอบตัวอักษรทำโปร่งแสงด้วย color-to-alpha เทียบครีม #F3DCBC (สคริปต์ตัดอยู่นอก repo)
   ป้ายแชมป์ลอยบนวิดีโอ จึงเจาะรูเล็ก ๆ ที่ครีมติดอยู่ในช่องตัวอักษรด้วย (O A P R, ช่องหูถ้วยรางวัล)
   แต่ไม่แตะกำปั้น ✊ เพราะสีผิวใกล้ครีม · กฎข้างล่างเปลี่ยนแค่ภาพกับ aspect-ratio (= ขนาดไฟล์)
   ปุ่ม "เริ่ม" ได้แบบวาด START มา 3 ต.ค. 2569 (ก่อนหน้านั้นใช้ตัวอักษรซ้อนชั้น .btn-letter)
   ========================================================================== */
/* START ไม่มีสระ/วรรณยุกต์ข้างบนแบบ "เริ่ม" ตัวอักษรเต็มภาพ — ไม่ต้องยกขึ้น 10%
   ภาพกว้าง 3.5 เท่าของความสูง ให้สูงเท่า STOP ปุ่มสองตัวจะดูเป็นชุดเดียวกัน */
html[lang="en"] .btn--start .btn__label { aspect-ratio: 417 / 120; height: 2em; max-width: 100%; translate: none; background-image: url('btn/en/start.png'); }
html[lang="en"] .controls .btn--start .btn__label { height: min(2.7em, 40cqh); }
/* ภาพ EN กว้างกว่าภาพไทย (STOP 2.9 เท่าของความสูง · ไทย 1.85) — max-width ให้ contain ย่อลงเองถ้าปุ่มแคบ */
html[lang="en"] .btn--stop .btn__label { aspect-ratio: 328 / 112; max-width: 100%; background-image: url('btn/en/stop.png'); }
html[lang="en"] .btn--next .btn__label { aspect-ratio: 399 / 120; background-image: url('btn/en/next.png'); }
html[lang="en"] .picker .picker__label { aspect-ratio: 179 / 100; background-image: url('btn/en/iam.png'); }
/* "I'M" — 2 ต.ค. 2569 เจ้าของขอให้เล็กลง (min(3.2em, 30cqh) → min(2.6em, 24cqh))
   3 ต.ค. 2569 ขอให้ใหญ่ขึ้น: เพดาน em ผูกกับตัวหนังสือ 0.78rem ของป้าย ภาพเลยค้างที่ ~32px ในปุ่มสูง ~160px
   ตัดเพดาน em ทิ้ง ให้โตตามความสูงปุ่มอย่างเดียว · ปุ่มแคบ max-width บีบแล้ว contain ย่อภาพเอง
   ลองแล้วเจ้าของขอเล็กลงนิดนึง (34cqh → 30cqh) */
html[lang="en"] .controls .picker .picker__label { height: 30cqh; }
html[lang="en"] .quiz-launch:is([data-state="idle"], [data-state="challenged"]) .quiz-launch__text {
  /* เจ้าของขอให้คนสองคนอยู่ใต้คำ (2 ต.ค. 2569) — ภาพเป็น 2 บรรทัด จึงสูงได้กว่าภาพไทยแถวเดียว
     ปุ่มแคบ max-width บีบความกว้างแล้ว contain ย่อภาพตาม · cqh = ความสูงปุ่ม (.controls .quiz-launch) */
  aspect-ratio: 458 / 200;
  height: min(4.6em, 72cqh);
  max-width: 100%;
  background-image: url('btn/en/duel.png');
}
/* เจ้าของขอตัวอักษรใหญ่ขึ้นอีก — ความกว้างปุ่มคือตัวจำกัด เลยลดขอบในซ้ายขวาของปุ่มเหลือน้อยสุด */
html[lang="en"] .controls .quiz-launch[data-state="idle"] { padding-inline: 0.2rem; }
html[lang="en"] .quiz-launch[data-state="challenged"] .quiz-launch__text { aspect-ratio: 426 / 160; background-image: url('btn/en/challenged-sign.png'); }
@media (pointer: coarse) {
  html[lang="en"] .controls #chat-toggle .toggle__text { aspect-ratio: 404 / 110; background-image: url('btn/en/chat.png'); }
  html[lang="en"] .controls #flip-btn .toggle__text { aspect-ratio: 599 / 100; background-image: url('btn/en/flip.png'); }
}
/* แผงเกมตอนถูกท้า — src ของ <img> สลับเป็น btn/en/challenged.png ใน frontend/quiz.tsx */
html[lang="en"] .quiz-challenged__art { aspect-ratio: 344 / 160; }
/* ป้ายแชมป์มุมกล้อง */
html[lang="en"] .champion-tag { aspect-ratio: 560 / 110; background-image: url('btn/en/champion-no1.png'); }
html[lang="en"] .quiz-champion--national > .champion-tag { aspect-ratio: 560 / 110; background-image: url('btn/en/champion-no1-national.png'); }
