/* ══════════════════════════════════════════════════════════════
   AI คัดกรองฟันผุ — design system
   สีของกล่องตรวจจับ (--D / --d) ห้ามเปลี่ยน ต้องแยกออกจากกันชัดเจน
   ══════════════════════════════════════════════════════════════ */
:root{
  --navy-900:#062040; --navy-700:#12447f;
  --cyan:#22d3ee; --teal:#0ea5a4; --teal-deep:#0b7f7e;
  --ink:#08243f; --ink-soft:#42607d;
  /* --ink-faint เคยเป็น #7d95ab ซึ่งได้ contrast 3.11 บนพื้นขาวและ 2.81 บนพื้น
     ของหน้า -- ตกเกณฑ์ AA ทั้งคู่ และเป็นสีของ ``.hint`` ทุกบรรทัดในระบบ รวมถึง
     หมายเหตุบนหน้าครูที่ถูกอ่านกลางแดดที่โรงเรียน

     ค่าใหม่ผ่าน 5.03 บนขาว และ 4.55 บนพื้นหน้า โดยยังอ่อนกว่า --ink-soft
     ชัดเจน (ค่าความสว่าง 0.159 เทียบกับ 0.106) ลำดับสามชั้นจึงยังอยู่ครบ

     ข้อนี้ไม่ใช่เรื่องความสวย จึงแก้ทั้งระบบ ไม่ใช่แค่หน้าสาธารณะ */
  --ink-faint:#56728c;
  --D:#12b76a; --d:#f79009; --warn:#b45309;
  --glass:rgba(255,255,255,.66); --glass-line:rgba(255,255,255,.8);
  --s-s:0 2px 8px rgba(8,36,63,.06);
  --s-m:0 10px 30px -8px rgba(8,36,63,.15);
  --s-l:0 26px 60px -18px rgba(8,36,63,.28);
  --r-lg:26px; --r-md:18px; --r-sm:12px;
  /* สีกรอบ focus แยกสองค่า เพราะพื้นขาวกับพื้นน้ำเงินเข้มต้องใช้คนละสี
     ให้เห็นได้จริง -- teal เข้มตัดกับขาว ส่วน cyan อ่อนตัดกับ navy */
  --focus:#0b7f7e; --focus-dark:#67e8f9;

  /* ── สีประจำบทบาท ──
     ก่อนมีสามสีนี้ หน้าครูกับหน้าทันตแพทย์เหมือนกันทุกพิกเซลยกเว้นข้อความ
     หัวข้อ จับภาพหน้าจอสองใบมาวางเทียบกันแล้วแยกไม่ออกว่าอันไหนของใคร

     แยกเป็นสองค่าต่อบทบาทเพราะสีเดียวทำสองงานไม่ได้ -- เข้มพอจะอ่านออกบน
     พื้นขาว แปลว่าเข้มเกินกว่าจะเป็นพื้นของป้าย ค่า soft จึงมีไว้เป็นพื้นโดยเฉพาะ

     **เกณฑ์ที่ต้องผ่านคือคู่ เข้ม-บน-soft ไม่ใช่ เข้ม-บน-ขาว** เพราะป้ายบทบาท
     กับไอคอนวางบนพื้น soft ไม่ใช่บนขาว ตัวอักษรในป้ายเป็น 11 px หนา ซึ่งไม่
     นับเป็น large text จึงต้องผ่าน 4.5:1 เต็ม ๆ ค่าที่วัดได้คือ
     ครู 4.92 · ทันตแพทย์ 5.72 · ผู้ดูแลระบบ 6.02
     และตัวอักษรขาวบนพื้นสีเข้ม (ปุ่ม "อยู่ตรงนี้") ได้ 5.59 · 6.70 · 7.10

     สีครูเคยตั้งเป็น #0b7f7e (ค่าเดียวกับ --focus) ซึ่งบนขาวผ่านสบาย แต่บนพื้น
     soft ของตัวเองตกที่ 4.24 -- เข้มขึ้นอีกนิดเดียวแก้ได้และไม่มีใครดูออก

     สีทันตแพทย์ตรงกับสีที่ FLOW.md ใช้เน้นขั้น "ทันตแพทย์ทบทวน" อยู่ก่อนแล้ว */
  --role-teacher:#0a7472; --role-teacher-soft:#e2f4f3;
  --role-dentist:#1d4ed8; --role-dentist-soft:#e7edfc;
  --role-admin:#6d28d9;   --role-admin-soft:#f0e9fd;

  /* ── โทนพาสเทลของหน้าสาธารณะ ──
     เพิ่มเข้ามาไม่ทับของเดิม navy ยังอยู่ครบ แค่เปลี่ยนหน้าที่จาก "สีพื้น"
     เป็น "สีตัวอักษร" ซึ่งเป็นงานที่มันทำได้ดีกว่า

     ทั้งสี่ค่านี้อ่อนเกินกว่าจะเป็นสีตัวอักษรได้ ใช้เป็นพื้นเท่านั้น */
  --sky-50:#f7fbff; --sky-100:#eaf4fd;
  --lilac-100:#efeafd; --blush-100:#ffeef3;
}

/* บทบาทถูกอ้างถึงสามที่ในหน้าเดียวกันได้ -- แถบหัว ป้ายข้างชื่อ และการ์ด
   จึงประกาศคู่ตัวแปรไว้ครั้งเดียวต่อบทบาท แล้วให้แต่ละชิ้นหยิบ --rc ไปใช้เอง */
[data-role="teacher"]{--rc:var(--role-teacher);--rc-soft:var(--role-teacher-soft)}
[data-role="dentist"]{--rc:var(--role-dentist);--rc-soft:var(--role-dentist-soft)}
[data-role="admin"]{--rc:var(--role-admin);--rc-soft:var(--role-admin-soft)}

/* ── โซนของหน้า ──
   ``data-zone`` เขียนตายไว้ในไฟล์ HTML ไม่ได้มาจากบัญชีที่ล็อกอินอยู่
   สีของหน้าตอบว่า "ฉันอยู่หน้าของใคร" ส่วนป้าย ``.rolechip`` ข้างชื่อผู้ใช้ตอบว่า
   "ฉันเป็นใคร" -- ผู้ดูแลระบบที่เปิดหน้าครูจึงเห็นหน้าสีครูพร้อมป้ายสีผู้ดูแลระบบ
   ซึ่งอ่านออกทันทีว่ากำลังยืนอยู่ในบ้านคนอื่น ดูเหตุผลเต็มใน i18n.js */
body[data-zone="teacher"]{--zone:var(--role-teacher);--zone-soft:var(--role-teacher-soft)}
body[data-zone="dentist"]{--zone:var(--role-dentist);--zone-soft:var(--role-dentist-soft)}
body[data-zone="admin"]{--zone:var(--role-admin);--zone-soft:var(--role-admin-soft)}
*{box-sizing:border-box;-webkit-tap-highlight-color:transparent}
html{scroll-behavior:smooth}
body{
  margin:0;font-family:"IBM Plex Sans Thai",system-ui,-apple-system,sans-serif;
  color:var(--ink);background:#eef4fc;overflow-x:hidden;
}
img{max-width:100%;display:block}
button{font:inherit;cursor:pointer;border:0}

/* ── เห็นว่าตัวเองอยู่ตรงไหนตอนใช้คีย์บอร์ด ──
   ``.field input`` กับ ``.search`` สั่ง outline:0 ไว้เพื่อให้ช่องกรอกดูเป็น
   การ์ดใบเดียวไม่มีขอบซ้อน แต่นั่นลบสัญญาณเดียวที่คนใช้คีย์บอร์ดมีทิ้งไปด้วย
   คนที่ tab มาถึงช่องรหัสผ่านจะไม่เห็นเลยว่าเคอร์เซอร์อยู่ไหน

   ใช้ :focus-visible ไม่ใช่ :focus เพราะกรอบไม่ควรขึ้นตอนคลิกเมาส์
   ทั้งสองตัวข้างล่างต้องระบุชื่อคลาสซ้ำ เพราะ outline:0 เดิมชนะด้วย specificity */
:focus-visible{outline:3px solid var(--focus);outline-offset:2px}
.field input:focus-visible,.search:focus-visible{
  outline:3px solid var(--focus);outline-offset:-1px;border-radius:8px;
}
/* ``.classbar`` ยังเป็นพื้น navy อยู่ (แถบโหมดตรวจทั้งห้อง) จึงยังต้องใช้กรอบ
   สีอ่อน ส่วนปุ่มภาษาย้ายมาอยู่บนพื้นสว่างแล้วตั้งแต่ปรับหน้าสาธารณะ */
.classbar .chip:focus-visible{outline-color:var(--focus-dark)}
.wrap{max-width:1080px;margin:0 auto;padding:0 20px}
.hidden{display:none !important}

/* ── ส่วนที่พับเก็บได้ ──
   หน้าแรกยาว กว่าจะเลื่อนถึงการ์ดบทบาทบนมือถือต้องผ่านสุขศึกษาทั้งบล็อก
   ใช้ <details> เพราะคีย์บอร์ดและโปรแกรมอ่านหน้าจอรองรับมาให้เองอยู่แล้ว
   ไม่ต้องเขียน aria เพิ่มและไม่ต้องดักปุ่ม Enter เอง */
.fold>summary{list-style:none;cursor:pointer;display:flex;align-items:center;gap:12px}
.fold>summary::-webkit-details-marker{display:none}
.fold>summary::after{content:"⌄";margin-left:auto;font-size:26px;line-height:1;
  color:var(--ink-faint);transition:transform .18s;flex:none}
.fold[open]>summary::after{transform:rotate(180deg)}
.fold>summary>div{min-width:0}
.fold>summary:focus-visible{outline:3px solid var(--focus);outline-offset:6px;border-radius:10px}

/* ── สลับหน้าจอ ── */
.screen{display:none}
.screen.active{display:block;animation:fade .28s ease}
@keyframes fade{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}

/* ── ปุ่มเปลี่ยนภาษา ── */
/* เคยมีสองชุด -- ชุดสว่างสำหรับหน้าพื้นขาว และชุดจางสำหรับหน้าพื้น navy
   ตอนนี้ไม่มีหน้าไหนพื้น navy แล้ว จึงเหลือชุดเดียว ``body.light-chrome``
   ที่ app.js ยังสลับอยู่ไม่ได้ทำอะไรกับปุ่มนี้อีกต่อไป แต่คงคลาสไว้เพราะ
   มันบอกโหมดของหน้า ซึ่งอาจมีคนใช้ต่อ */
.lang{
  position:fixed;top:14px;right:14px;z-index:60;display:flex;gap:2px;padding:3px;border-radius:99px;
  background:rgba(255,255,255,.82);border:1px solid rgba(8,36,63,.08);
  backdrop-filter:blur(12px);box-shadow:var(--s-s);
}
.lang button{
  padding:6px 14px;border-radius:99px;background:none;color:var(--ink-soft);
  font-size:12.5px;font-weight:600;
}
/* ขาวบน --role-teacher ได้ 5.59 -- ของเดิมใช้ --teal ซึ่งได้ 3.0 และตกเกณฑ์ */
.lang button[aria-pressed="true"]{background:var(--role-teacher);color:#fff}

/* ══ HERO ══
   หน้าปกเคยเป็นพื้น navy ทึบพร้อมภาพถ่ายในช่องปากจริงสามใบ ซึ่งเป็นภาพเปิด
   ที่ผู้ปกครองและเด็กเห็นเป็นอย่างแรกตอนสแกน QR เข้ามา

   ตอนนี้เป็นพื้นอ่อน ขาว → ฟ้า → ม่วง และ navy ย้ายไปทำหน้าที่ที่มันทำได้ดีกว่า
   คือเป็นสีตัวอักษร ส่วนตัวเอกเป็นมาสคอตที่วาดด้วยโค้ด

   **โทนนี้ใช้เฉพาะหน้าสาธารณะ** (หน้าปก · หน้าเลือกบทบาท · หน้าผู้ปกครอง)
   หน้าทำงานของครู ทันตแพทย์ และผู้วิจัย คงโทนสุขุมไว้เหมือนเดิมโดยตั้งใจ —
   หน้าที่ทันตแพทย์ใช้บันทึกค่าอ้างอิงของงานวิจัยไม่ควรหน้าตาเหมือนของเล่น */
.hero{
  position:relative;overflow:hidden;color:var(--ink);padding:56px 0 66px;
  background:
    radial-gradient(760px 420px at 82% 4%, var(--lilac-100) 0%, transparent 62%),
    radial-gradient(680px 420px at 8% 0%, #ffffff 0%, transparent 58%),
    linear-gradient(166deg,#f8fcff 0%,#eaf4fd 48%,#ebe9fc 100%);
}
.orb{position:absolute;border-radius:50%;filter:blur(64px);opacity:.42;pointer-events:none}
.orb.a{width:320px;height:320px;background:#9fe3dc;top:-70px;left:-100px}
.orb.b{width:380px;height:380px;background:#c9b9f8;bottom:-170px;right:-130px}
.hero .in{position:relative;display:grid;grid-template-columns:1.08fr .92fr;gap:40px;align-items:center}

/* เวทีของมาสคอต -- วงแสงนุ่มหลังตัว ทำให้ตัวการ์ตูนไม่ลอยอยู่บนพื้นเปล่า ๆ */
.heroart{position:relative;display:grid;place-items:center;min-height:290px}
.heroart .stage{
  position:absolute;width:82%;aspect-ratio:1;border-radius:50%;
  background:radial-gradient(circle at 50% 45%,#ffffff 0%,rgba(255,255,255,.55) 46%,transparent 70%);
}
.heroart .mascot{position:relative;filter:drop-shadow(0 24px 34px rgba(70,105,150,.20))}

.hero h1{font-size:41px;line-height:1.26;margin:0 0 16px;font-weight:700;letter-spacing:-.03em}
.hero h1 em{font-style:normal;background:linear-gradient(96deg,#0a7472,#1d4ed8);
  -webkit-background-clip:text;background-clip:text;color:transparent}
.hero .lead{font-size:16px;line-height:1.85;color:var(--ink-soft);margin:0 0 30px;max-width:44ch}

/* ปุ่มหลักเป็นไล่สีของสองบทบาทที่ใช้ระบบทุกวัน -- ไม่ได้เลือกเพราะสวยอย่างเดียว
   แต่เพราะตัวอักษรขาวบนสองค่านี้ผ่าน AA ทั้งคู่ (5.59 และ 6.70) ต่างจากไล่สี
   cyan ของเดิมที่ต้องใช้ตัวอักษรสีเข้มเพราะขาวอ่านไม่ออก */
.cta{
  display:inline-flex;align-items:center;gap:11px;padding:17px 32px;border-radius:18px;
  font-size:17px;font-weight:600;color:#fff;text-decoration:none;
  background:linear-gradient(100deg,var(--role-teacher),var(--role-dentist));
  box-shadow:0 16px 34px -14px rgba(29,78,216,.75);
  transition:transform .16s,box-shadow .16s;
}
.cta:hover{transform:translateY(-2px);box-shadow:0 22px 42px -14px rgba(29,78,216,.85)}
.cta.ghosted{background:#fff;border:1px solid rgba(8,36,63,.09);
  color:var(--ink-soft);box-shadow:var(--s-s);font-size:15px;padding:16px 26px}
.cta.ghosted:hover{background:#fff;box-shadow:var(--s-m);color:var(--ink)}
.ctarow{display:flex;gap:12px;flex-wrap:wrap;align-items:center}
.ctahint{font-size:14px;line-height:1.8;color:var(--ink-soft);margin:16px 0 0;max-width:56ch}

/* ── แถบบนสุด ────────────────────────────────────────────
   ของเดิมเป็นปุ่มลอยมุมซ้ายบนขนาดเล็ก ซึ่งไม่มีใครมองหา -- เจ้าของระบบเอง
   ยังเปิดเว็บมาแล้วหาทางเข้าไม่เจอ แถบเต็มความกว้างคือที่ที่คนมองหาปุ่ม
   เข้าสู่ระบบจริง ๆ เพราะเว็บทุกเว็บวางไว้ตรงนี้

   sticky ไม่ใช่ fixed -- มันเป็นแถบจริงที่กินพื้นที่ เนื้อหาข้างล่างจึงไม่ถูกทับ
   ต่างจากปุ่มลอยเดิมที่ทับหัวข้อของทุกส่วนที่เลื่อนผ่าน */
.topbar{
  position:sticky;top:0;z-index:60;display:flex;align-items:center;gap:14px;
  padding:11px 20px;background:rgba(255,255,255,.8);backdrop-filter:blur(18px);
  border-bottom:1px solid rgba(8,36,63,.07);
}
.topbar .brand{display:flex;align-items:center;gap:11px;text-decoration:none;flex:1;min-width:0}
.topbar .logo{width:34px;height:34px;border-radius:11px;flex:none;display:grid;place-items:center;
  color:var(--role-teacher);background:var(--role-teacher-soft);
  border:1px solid rgba(10,116,114,.16)}
.topbar .names{min-width:0}
.topbar .names b{display:block;font-size:14.5px;font-weight:700;color:var(--ink);letter-spacing:-.01em;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.topbar .names em{display:block;font-style:normal;font-size:11px;color:var(--ink-faint);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.topnav{display:flex;gap:7px;align-items:center;flex:none}
.topnav a{font-size:13.5px;font-weight:600;padding:9px 16px;border-radius:99px;
  text-decoration:none;color:var(--ink-soft);background:rgba(255,255,255,.72);
  border:1px solid rgba(8,36,63,.09);white-space:nowrap}
.topnav a:hover{background:#fff;color:var(--ink)}
/* ปุ่มหลักของแถบ -- ตัวอักษรขาวบน role-dentist ได้ 6.70 ผ่าน AA */
.topnav a.solid{background:var(--role-dentist);color:#fff;border-color:var(--role-dentist)}
.topnav a.solid:hover{background:#1a45bd;color:#fff}

/* ปุ่มภาษาในแถบนี้เป็นสมาชิกของแถว ไม่ใช่ของลอย จึงต้องล้างตำแหน่ง fixed ทิ้ง */
.topbar .lang{position:static;flex:none}

@media (max-width:640px){
  /* เดิมแถบนี้ห่อลงบรรทัดที่สองบนมือถือ (topnav width:100%) รวมกับโลโก้แล้ว
     กินความสูงเกือบร้อยพิกเซลก่อนถึงเนื้อหาจริง ซึ่งเจ็บที่สุดบนหน้าถ่ายภาพ
     ที่ยังมีหัวข้อของตัวเองอีกชั้น จึงบีบให้อยู่บรรทัดเดียว

     และเหลือปุ่มหลักปุ่มเดียว -- "เปิดใช้งานบัญชี" ยังกดได้จากการ์ดบทบาทบน
     หน้าแรกและจากหน้าเข้าสู่ระบบ ไม่ได้หายไปไหน */
  .topbar{gap:8px;padding:8px 12px;flex-wrap:nowrap}
  .topbar .names em{display:none}
  .topbar .names b{font-size:13.5px}
  .topbar .logo{width:30px;height:30px;border-radius:9px}
  .topnav{order:0;width:auto}
  .topnav a{padding:8px 13px;font-size:13px}
  .topnav a:not(.solid){display:none}
  .lang button{padding:6px 11px}
}
.chips{display:flex;gap:10px;margin-top:26px;flex-wrap:wrap}
/* ``>`` สำคัญ -- ข้างในแต่ละชิปมี <span> ของ data-i18n อีกชั้น ถ้าเลือกแบบ
   ไม่เจาะจงลูกโดยตรง ข้อความข้างในจะกลายเป็นชิปซ้อนชิป */
.chips>span{display:inline-flex;align-items:center;gap:7px;font-size:12.5px;font-weight:500;
  color:var(--ink-soft);padding:9px 15px;border-radius:99px;background:rgba(255,255,255,.78);
  border:1px solid rgba(8,36,63,.07);box-shadow:var(--s-s)}
.chips i{display:inline-flex;flex:none;color:var(--role-teacher)}

/* ── ภาพจริงห้ามุม ──
   เคยเป็นตาราง 2 คอลัมน์ของภาพสามใบบนหน้าปก ตอนนี้เป็นแถบเรียงห้าใบใต้
   ขั้นตอนที่ 1 ซึ่งเป็นที่ที่ "ห้ามุมคือมุมไหนบ้าง" เป็นคำถามจริง */
.shots5{display:grid;grid-template-columns:repeat(5,1fr);gap:10px;margin-top:16px}
.shots5 figure{margin:0;border-radius:16px;overflow:hidden;box-shadow:var(--s-m);
  border:1px solid rgba(255,255,255,.7);position:relative;aspect-ratio:4/3}
.shots5 img{width:100%;height:100%;object-fit:cover}
.shots5 figcaption{position:absolute;inset:auto 0 0 0;font-size:10.5px;color:#fff;
  padding:16px 9px 7px;background:linear-gradient(transparent,rgba(4,24,44,.86))}
.shotsnote{font-size:13px;line-height:1.8;color:var(--ink-soft);margin:12px 2px 0}
@media (max-width:720px){
  .shots5{grid-template-columns:repeat(2,1fr)}
  .shots5 figure:first-child{grid-column:span 2;aspect-ratio:16/9}
}

/* ══ sections ══ */
section{padding:58px 0}
.eyebrow{font-size:12px;font-weight:600;letter-spacing:.09em;text-transform:uppercase;color:var(--role-teacher);margin:0 0 8px}
h2{font-size:27px;margin:0 0 10px;letter-spacing:-.02em}
.sub{color:var(--ink-soft);font-size:15px;line-height:1.8;margin:0 0 30px;max-width:60ch}

.steps{display:grid;grid-template-columns:repeat(3,1fr);gap:16px}
.step{background:var(--glass);border:1px solid var(--glass-line);border-radius:22px;padding:24px;backdrop-filter:blur(18px);box-shadow:var(--s-s)}
.step .n{width:38px;height:38px;border-radius:13px;display:grid;place-items:center;font-weight:700;font-size:16px;color:#fff;background:linear-gradient(140deg,var(--role-teacher),#086361);margin-bottom:15px;box-shadow:0 8px 18px -6px rgba(10,116,114,.55)}
.step h3{margin:0 0 6px;font-size:16.5px}
.step p{margin:0;font-size:13.5px;line-height:1.8;color:var(--ink-soft)}

.stat{border-radius:var(--r-lg);padding:32px 34px;color:#fff;display:grid;grid-template-columns:auto 1fr;gap:30px;align-items:center;background:linear-gradient(135deg,#0d7f7e,#0a5f66);box-shadow:0 24px 54px -20px rgba(11,127,126,.75);position:relative;overflow:hidden}
.stat .glow{position:absolute;width:280px;height:280px;border-radius:50%;background:rgba(255,255,255,.13);filter:blur(50px);top:-120px;right:-60px}
.stat .big{font-size:52px;font-weight:700;line-height:1;letter-spacing:-.03em;position:relative}
.stat .big small{font-size:17px;font-weight:500;opacity:.85;display:block}
.stat p{margin:0 0 8px;font-size:15px;line-height:1.8;position:relative}
.stat cite{font-style:normal;font-size:13px;opacity:.78;position:relative}
.statnote{font-size:13.5px;color:var(--ink-faint);margin:12px 2px 0;line-height:1.8}

.tips{display:grid;grid-template-columns:repeat(3,1fr);gap:16px;margin-top:18px}
.tip{background:#fff;border-radius:20px;padding:22px;box-shadow:var(--s-s)}
/* เคยเป็น emoji ที่ font-size:21px -- เปลี่ยนสีไม่ได้ และเรนเดอร์คนละแบบทุกเครื่อง
   สามใบใช้คนละสีในโทนพาสเทลเดียวกัน ให้แยกกันได้โดยไม่ต้องอ่านหัวข้อ */
.tip .ic{width:44px;height:44px;border-radius:14px;display:grid;place-items:center;
  margin-bottom:13px;color:var(--role-teacher);background:var(--role-teacher-soft)}
.tip:nth-child(2) .ic{color:#be185d;background:var(--blush-100)}
.tip:nth-child(3) .ic{color:var(--role-admin);background:var(--role-admin-soft)}
.tip h4{margin:0 0 6px;font-size:15.5px}
.tip p{margin:0 0 10px;font-size:13px;line-height:1.8;color:var(--ink-soft)}
.tip cite{font-style:normal;font-size:12.5px;color:var(--ink-faint)}

.can{display:grid;grid-template-columns:1fr 1fr;gap:16px}
.can>div{border-radius:22px;padding:24px}
.can .yes{background:#e9f9f1;border:1px solid #b7ebd0}
.can .no{background:#fff4ed;border:1px solid #fcd9c2}
/* ✅ กับ ⛔ เดิมเป็น emoji -- ไอคอนเส้นรับสีจากหัวข้อ จึงเข้ากับกล่องที่มันอยู่ */
.can h3{display:flex;align-items:center;gap:9px;margin:0 0 14px;font-size:16px}
.can h3 i{display:inline-flex;flex:none}
.can .yes h3{color:#0f6b45}
.can .no h3{color:#9a3412}
.can ul{margin:0;padding-left:20px;font-size:13.5px;line-height:2.05;color:var(--ink-soft)}

/* ── การ์ดสามบทบาท บนหน้าแรก ─────────────────────────────────────
   แต่ละใบต้องตอบสองคำถามในสายตาเดียว: ทำอะไรได้ (ย่อหน้า) และได้บัญชี
   มายังไง (แถบ .how) แถบนั้นจึงมีพื้นหลังแยก ไม่ใช่ย่อหน้าธรรมดา -- เพราะ
   คนที่งงว่าตัวเองควรกดอะไร กำลังหาคำตอบข้อหลัง ไม่ใช่ข้อแรก */
.roles{display:grid;grid-template-columns:repeat(3,1fr);gap:16px;align-items:stretch}
.rolecard{display:flex;flex-direction:column;gap:10px;padding:24px;border-radius:22px;
  background:var(--card,#fff);border:1px solid rgba(8,36,63,.09);box-shadow:var(--s-s)}
/* เคยเป็น emoji ตัวเดียว (font-size:26px) ซึ่งเปลี่ยนสีไม่ได้ จึงบอกสีประจำ
   บทบาทไม่ได้ และเรนเดอร์คนละแบบในแต่ละเครื่อง ตอนนี้เป็นไอคอนชุดเดียวกับ
   ที่หน้าเลือกบทบาทและแถบหัวทุกหน้าใช้ -- ดู renderRoleIcons ใน staff.js */
.rolecard .ic{width:44px;height:44px;border-radius:14px;display:grid;
  place-items:center;color:var(--rc,var(--role-teacher));background:var(--rc-soft,var(--role-teacher-soft))}
.rolecard h3{margin:0;font-size:16px}
.rolecard p{margin:0;font-size:13.5px;line-height:1.95;color:var(--ink-soft)}
.rolecard .how{margin-top:2px;padding:11px 13px;border-radius:12px;background:#f1f6fb;
  font-size:14px;line-height:1.85;color:var(--ink-soft)}
.rolecard .how b{color:var(--ink)}
/* ปุ่มไปชิดล่างเสมอ การ์ดสามใบข้อความยาวไม่เท่ากัน ปุ่มลอยคนละระดับจะอ่านยาก */
.rolecard .chip{margin-top:auto;align-self:flex-start;text-decoration:none}

@media (max-width:900px){
  .roles{grid-template-columns:1fr}
}

footer{background:#062040;color:#8fb4d1;font-size:12.5px;line-height:1.95;padding:36px 0 44px}
footer a{color:#a9dced}
footer .row{display:grid;grid-template-columns:1.4fr 1fr;gap:34px}
footer b{color:#dceefa;display:block;margin-bottom:7px;font-size:13px}
.warnbox{margin-top:22px;padding:14px 17px;border-radius:13px;background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.12);color:#cfe4f4}

/* ══ แถบหัวหน้าจอย่อย ══ */
.bar{position:sticky;top:0;z-index:40;background:rgba(255,255,255,.9);backdrop-filter:blur(16px);border-bottom:1px solid rgba(8,36,63,.07)}
/* แถบหัวเคยพยายามใส่ทุกอย่างในแถวเดียว -- หัวข้อ ชื่อผู้ใช้ ป้ายบทบาท เมนู
   ข้ามหน้า และตัวเลือกห้องเรียน ที่ 375 px มันสูง 139 px ทุกชิ้นตกบรรทัด และ
   ตัวเลือกห้องล้นออกนอกจอ ตอนนี้เหลือสามชิ้น: ตรา · ชื่อหน้า · ปุ่มเมนู
   ที่เหลือย้ายเข้าแผ่นเมนู ดู shell.js */
.bar .in{display:flex;align-items:center;gap:11px;padding:9px 0}
.back{width:44px;height:44px;border-radius:13px;background:#eef6fc;display:grid;place-items:center;color:var(--ink-soft);font-size:17px;flex:none}
.bar .ttl{flex:1;min-width:0}
.bar .t{font-weight:600;font-size:16.5px;line-height:1.3;letter-spacing:-.01em;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.bar .s{font-size:12px;color:var(--ink-faint)}

/* ตราที่กดกลับหน้าของบทบาทตัวเองได้ -- คำตอบของ "อยากมีทางกลับหน้าหลัก"
   โดยไม่ต้องเพิ่มแถบใหม่ทั้งแถบ และรับสีของโซนไปด้วยในตัว จึงบอกได้พร้อมกัน
   ว่า "นี่คือหน้าของใคร" โดยไม่ต้องมีไอคอนแยกอีกอัน */
.brandmark{width:44px;height:44px;border-radius:14px;flex:none;display:grid;
  place-items:center;text-decoration:none;
  color:var(--zone,var(--role-teacher));background:var(--zone-soft,var(--role-teacher-soft))}
.brandmark:hover{filter:brightness(.97)}

/* ตัวเลือกห้องเรียนอยู่บนแถบ เพราะครูสลับห้องบ่อยพอ -- แต่เป็นบรรทัดที่สอง
   ใต้ชื่อหน้า ไม่ใช่กล่องแยกที่เบียดจนล้นจอ ``select`` ตัวจริงยังอยู่ครบ
   มือถือจึงได้ตัวเลือกของระบบปฏิบัติการซึ่งใช้ง่ายกว่าอะไรที่เราวาดเอง */
.roompick{border:0;background:none;padding:0;font:inherit;font-size:12.5px;
  color:var(--ink-soft);max-width:100%;appearance:none;
  background-image:linear-gradient(45deg,transparent 50%,var(--ink-faint) 50%),
    linear-gradient(135deg,var(--ink-faint) 50%,transparent 50%);
  background-position:right 4px center,right 0 center;
  background-size:5px 5px,5px 5px;background-repeat:no-repeat;padding-right:15px}

.burger{width:44px;height:44px;border-radius:13px;flex:none;display:grid;
  place-items:center;background:rgba(8,36,63,.05);color:var(--ink-soft)}
.burger span[aria-hidden],.burger span[aria-hidden]::before,
.burger span[aria-hidden]::after{
  display:block;width:17px;height:2px;border-radius:2px;background:currentColor}
.burger span[aria-hidden]{position:relative}
.burger span[aria-hidden]::before,.burger span[aria-hidden]::after{
  content:"";position:absolute}
.burger span[aria-hidden]::before{top:-5.5px}
.burger span[aria-hidden]::after{top:5.5px}

/* ชื่อผู้ใช้ในปุ่ม -- ซ่อนบนมือถือ โผล่บนเดสก์ท็อป
   ขีดสามขีดบนจอกว้างสื่อว่า "มีเมนูซ่อนอยู่" ทั้งที่เมนูโผล่อยู่ข้าง ๆ แล้ว
   สิ่งที่อยู่ข้างในคือชื่อผู้ใช้ ป้ายบทบาท ภาษา และออกจากระบบ -- เรื่องของบัญชี */
.burger .bname,.burger .bav{display:none}

/* ── บนเดสก์ท็อปปุ่มนี้คือบัญชี ไม่ใช่ลิงก์อีกอัน ──
   ขีดสามขีดสื่อว่า "มีเมนูซ่อนอยู่" ทั้งที่เมนูโผล่อยู่ข้าง ๆ แล้ว
   พอเปลี่ยนเป็นชื่อเฉย ๆ มันก็กลายเป็นพี่น้องของลิงก์ "บันทึกผลตรวจ" ที่อยู่ติดกัน --
   หน้าตาเหมือนกันทั้งที่อันหนึ่งคือ *ที่ที่จะไป* อีกอันคือ *คุณเป็นใคร*

   ตัวแยกคือวงกลมไอคอนสีของบทบาท ซึ่งไม่มีลิงก์ไหนมี บวกเส้นคั่นข้างหน้า
   แบบเดียวกับที่ .navsep ใช้คั่นกลุ่ม "ข้ามบทบาท"

   สีของไอคอนมาจาก --rc คือสีของ *บทบาทที่ล็อกอิน* ไม่ใช่สีของหน้า
   ผู้ดูแลระบบที่เปิดหน้าครูจึงเห็นหน้าสีครูกับไอคอนสีผู้ดูแลระบบ -- เหตุผลเดียวกับ .rolechip */
@media (min-width:720px){
  /* flex ไม่ใช่ grid -- ``place-items:center`` ของกฎฐานบีบคอลัมน์ชื่อ
     จนเหลือ 17 px และชื่อกลายเป็นขีดเดียว */
  .burger{display:flex;width:auto;gap:8px;padding:0 13px 0 8px;
    align-items:center;justify-content:center;background:none;
    margin-left:6px;border-left:1px solid rgba(8,36,63,.14);border-radius:0}
  .burger:hover{background:none}
  .burger .bav{display:grid;place-items:center;flex:none;
    width:26px;height:26px;border-radius:50%;
    color:var(--rc,var(--ink-soft));background:var(--rc-soft,#eef6fc)}
  .burger span[aria-hidden]{display:none}
  /* ลูกศรลง วาดด้วย border ไม่ต้องโหลดไอคอนเพิ่ม */
  .burger::after{content:"";width:0;height:0;flex:none;
    border-left:4px solid transparent;border-right:4px solid transparent;
    border-top:5px solid var(--ink-faint)}
}

/* ชื่อขึ้นช้ากว่าไอคอน -- แถบหัวมีชื่อหน้า ตัวเลือกห้อง เมนูสองกลุ่ม
   อยู่แล้ว ที่ 720 px พื้นที่เหลือไม่พอให้ชื่อคนด้วย แล้วแถบจะดันเนื้อหาจนล้นจอ
   ไอคอนกับลูกศรลงเพียงสองอย่างก็อ่านออกแล้วว่าเป็นเมนูบัญชี ชื่อเป็นของแถม */
@media (min-width:1024px){
  .burger .bname{display:block;font-size:12.5px;font-weight:600;
    color:var(--ink-soft);white-space:nowrap;overflow:hidden;
    text-overflow:ellipsis;flex:none;max-width:150px}
}

/* เมนูข้ามหน้าโชว์บนแถบเฉพาะจอกว้าง มือถือไปอยู่ในแผ่นเมนูแทน
   วาดทั้งสองที่เสมอ แล้วให้ CSS เลือก ไม่แตกสาขาใน JS ตามความกว้างจอ
   ซึ่งจะพังตอนคนหมุนจอ

   **แต่ปุ่มเมนูต้องอยู่ทุกขนาดจอ** -- ชื่อผู้ใช้ ป้ายบทบาท ปุ่มเปลี่ยนภาษา
   และปุ่มออกจากระบบ อยู่ในแผ่นนั้นที่เดียว เคยซ่อนปุ่มนี้บนเดสก์ท็อป ผลคือ
   คนที่ใช้คอมออกจากระบบไม่ได้เลย และสลับภาษาก็ไม่ได้ */
@media (max-width:719px){ .bar .rolenav{display:none} }

/* แถบสีบนสุดของหน้า -- ใส่เฉพาะหน้าที่เป็นของบทบาทใดบทบาทหนึ่งจริง ๆ
   หน้าถ่ายภาพและหน้าผลใช้ ``.bar`` เหมือนกันแต่ไม่ได้เป็นของใคร จึงไม่มีแถบ */
body[data-zone] .bar{border-top:3px solid var(--zone)}

/* ป้ายบอกว่า "คนที่กำลังใช้อยู่คือใคร" -- สีมาจาก data-role ของตัวมันเอง
   ไม่ใช่จากโซนของหน้า ตรงนี้คือจุดที่การข้ามบทบาทมองเห็นได้ */
.rolechip{display:inline-flex;align-items:center;gap:4px;
  padding:3px 10px 3px 8px;border-radius:99px;font-size:11.5px;font-weight:600;
  color:var(--rc,var(--ink-soft));background:var(--rc-soft,#eef6fc);
  /* "ผู้ดูแลระบบ" ยาวพอจะขึ้นบรรทัดใหม่กลางป้ายบนจอแคบ ซึ่งอ่านเป็นของเสีย */
  white-space:nowrap}

/* ══ แผ่นเมนู ══
   เลื่อนขึ้นจากล่างเพราะนิ้วโป้งไปถึง ไม่ใช่จากมุมบนขวาซึ่งเป็นมุมที่ไกลที่สุด
   ของจอมือถือ ดูเหตุผลเต็มใน shell.js */
.sheetwrap{position:fixed;inset:0;z-index:70;display:flex;align-items:flex-end}
.sheetdim{position:absolute;inset:0;background:rgba(8,36,63,.42);
  backdrop-filter:blur(2px);animation:fadein .18s ease}
.sheetcard{position:relative;width:100%;max-height:86vh;overflow-y:auto;
  background:#fff;border-radius:24px 24px 0 0;padding:16px 16px calc(18px + env(safe-area-inset-bottom));
  box-shadow:0 -18px 50px -20px rgba(8,36,63,.5);animation:sheetup .22s cubic-bezier(.2,.8,.3,1)}
@media (min-width:720px){
  .sheetwrap{align-items:center;justify-content:center}
  .sheetcard{max-width:400px;border-radius:22px;animation:fadein .18s ease}
}
@keyframes sheetup{from{transform:translateY(14%)}to{transform:none}}
@keyframes fadein{from{opacity:0}to{opacity:1}}
@media (prefers-reduced-motion:reduce){
  .sheetcard,.sheetdim{animation:none}
}
.sheethd{display:flex;align-items:center;gap:9px;padding-bottom:13px;
  border-bottom:1px solid rgba(8,36,63,.08)}
.sheethd b{flex:1;min-width:0;font-size:15px;font-weight:600;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.sheetx{width:44px;height:44px;border-radius:13px;flex:none;
  background:rgba(8,36,63,.05);color:var(--ink-soft);font-size:15px}
.sheetnav{display:flex;flex-direction:column;gap:6px;padding:12px 0}
.migrp{margin:8px 0 2px;font-size:11px;font-weight:600;letter-spacing:.07em;
  text-transform:uppercase;color:var(--ink-faint)}
.mi{display:block;width:100%;text-align:left;padding:13px 14px;border-radius:13px;
  font-size:14.5px;text-decoration:none;background:rgba(8,36,63,.04);color:var(--ink-soft)}
.mi.here{background:var(--zone,var(--role-teacher));color:#fff;font-weight:600}
/* หน้าของบทบาทอื่นที่เข้าได้ -- เส้นประบอกว่ากำลังจะออกไปที่อื่น */
.mi.cross{background:none;border:1px dashed rgba(8,36,63,.22);color:var(--ink-faint)}
.sheetfoot{display:flex;align-items:center;gap:12px;padding-top:13px;
  border-top:1px solid rgba(8,36,63,.08)}
/* ปุ่มภาษาย้ายมาอยู่ในแผ่น จึงไม่ลอยอีกต่อไป */
.sheetfoot .lang{position:static;box-shadow:none;background:rgba(8,36,63,.05)}
.sheetout{margin-left:auto;padding:12px 16px;border-radius:13px;font-size:14px;
  font-weight:600;color:#a4231c;background:#fdeceb}

@media (min-width:720px){
  /* บนจอกว้าง เมนูตามบทบาทอยู่บนแถบหัวอยู่แล้ว การเอามาใส่ซ้ำในแผ่นนี้
     คือการเปิดเมนูมาเจอรายการที่มองเห็นอยู่แล้ว แล้วดันของที่เปิดมาหาจริง ๆ
     (ภาษา · ออกจากระบบ) ไปอยู่ล่างสุด

     กฎคือ แผ่นนี้มีเมนูเมื่อแถบหัวไม่มี -- ตรงข้ามกับ
     ``@media (max-width:719px){ .bar .rolenav{display:none} }`` พอดี
     ที่เหลือจึงเป็นเมนูบัญชีล้วน ๆ ชื่อ บทบาท ภาษา ออกจากระบบ */
  .sheetnav{display:none}
  /* เหลือเส้นคั่นเส้นเดียว ไม่ใช่สองเส้นชนกัน */
  .sheetfoot{border-top:0;padding-top:16px}
}

/* เขียนเป็น padding-top/bottom ไม่ใช่ ``padding`` ย่อ -- ``.wrap`` กับ ``.pagepad``
   อยู่บน element เดียวกันและ specificity เท่ากัน การเขียนย่อจึงลบ ``padding:0 20px``
   ของ ``.wrap`` ทิ้ง แล้วเนื้อหาทุกหน้าหลังล็อกอินไปชนขอบจอบนมือถือ */
.pagepad{padding-top:22px;padding-bottom:90px}

/* ══ ถ่ายภาพ ══ */
.prog{display:flex;align-items:center;gap:14px;background:var(--glass);border:1px solid var(--glass-line);border-radius:var(--r-md);padding:15px 17px;margin-bottom:14px;backdrop-filter:blur(18px);box-shadow:var(--s-s)}
.ring{width:50px;height:50px;flex:none}
.ring circle{transition:stroke-dasharray .4s ease}
.prog .n{font-size:21px;font-weight:700;line-height:1}
.prog .l{font-size:14px;color:var(--ink-faint);margin-top:2px}

.slots{display:grid;grid-template-columns:repeat(auto-fit,minmax(210px,1fr));gap:13px}
.slot{position:relative;border-radius:var(--r-md);overflow:hidden;aspect-ratio:4/3;background:#fff;border:1.5px dashed #a9cbe6;box-shadow:var(--s-s);cursor:pointer;transition:transform .16s,box-shadow .16s}
.slot:hover{transform:translateY(-2px);box-shadow:var(--s-m)}
/* ภาพตัวอย่างเคยจางที่ .32 ซึ่งกลางแจ้งหรือบนจอที่หรี่แสงแทบมองไม่ออกว่าเป็น
   มุมไหน จางพอให้รู้ว่ายังไม่ใช่ภาพจริงก็พอ ไม่ต้องจางจนดูไม่ออก */
.slot img{width:100%;height:100%;object-fit:cover;opacity:.5;filter:saturate(.75) contrast(1.08)}
/* ── หน้ารายละเอียดการตรวจ ──
   กรอบวางทับภาพเป็นเปอร์เซ็นต์ ไม่ใช่พิกเซล ภาพย่อขยายตามความกว้างจอ
   กรอบจึงขยับตามเอง โดยไม่ต้องวาดใหม่หรือใช้ canvas */
.detshot{position:relative;border-radius:var(--r-md);overflow:hidden;margin:10px 0}
.detshot img{width:100%;display:block}
.detshot.none{padding:34px 0;text-align:center;color:var(--ink-faint);
  background:#eef6fc;font-size:14px}
.detbox{position:absolute;border:2px solid var(--D);border-radius:3px;pointer-events:none}
.detbox.prim{border-color:var(--d)}
.detbox b{position:absolute;top:-19px;left:-2px;padding:1px 5px;border-radius:4px;
  background:var(--D);color:#fff;font-size:11px;font-weight:700;white-space:nowrap}
.detbox.prim b{background:var(--d)}
a.hrow{text-decoration:none;color:inherit;cursor:pointer}
a.hrow:hover{box-shadow:var(--s-m)}

.slot .tap{position:absolute;inset:0;display:grid;place-content:center;padding:0 12px;
  text-align:center;pointer-events:none}
.slot .tap span{background:rgba(255,255,255,.88);border-radius:99px;padding:8px 15px;
  font-size:14px;font-weight:600;color:var(--navy-900);box-shadow:var(--s-s)}
.slot.filled .tap{display:none}
/* ป้ายล่างซ้ำกับป้ายกลางตอนยังไม่มีภาพ เก็บไว้ให้ช่องที่ถ่ายแล้ว */
.slot:not(.filled) .lab{display:none}
.slot.filled{border-style:solid;border-color:transparent;box-shadow:var(--s-m)}
.slot.filled img{opacity:1;filter:none}
.slot.warned{border:2px solid var(--d)}
.slot .lab{position:absolute;inset:auto 0 0 0;padding:8px 11px;font-size:13.5px;font-weight:500;color:#fff;background:linear-gradient(transparent,rgba(6,32,64,.85))}
.slot .badge{position:absolute;top:9px;right:9px;min-width:24px;height:24px;padding:0 7px;border-radius:99px;display:grid;place-items:center;font-size:12px;font-weight:600;color:#fff;box-shadow:var(--s-s)}
.badge.ok{background:var(--D)} .badge.wait{background:#b8cfe3} .badge.busy{background:var(--role-teacher)}
.badge.warn{background:var(--d)}
.slot input[type=file]{display:none}

.hint{font-size:14px;line-height:1.8;color:var(--ink-soft);background:rgba(255,255,255,.62);border-radius:var(--r-sm);padding:12px 14px;margin-top:14px}

.dock{position:fixed;inset:auto 0 0 0;z-index:50;padding:14px 20px calc(14px + env(safe-area-inset-bottom));background:linear-gradient(transparent,rgba(231,243,252,.96) 32%)}
.dock .in{max-width:1080px;margin:0 auto}
.primary{
  width:100%;padding:16px;border-radius:16px;font-size:16px;font-weight:600;color:#fff;
  background:linear-gradient(96deg,var(--role-teacher),#086361);box-shadow:0 14px 32px -10px rgba(10,116,114,.6);
  transition:transform .16s,opacity .16s;
}
.primary:hover{transform:translateY(-2px)}
.primary:disabled{opacity:.45;transform:none;cursor:not-allowed}
.ghost{width:100%;padding:14px;border-radius:15px;font-size:14.5px;font-weight:600;color:var(--ink-soft);background:rgba(255,255,255,.75);box-shadow:var(--s-s);margin-top:9px}

/* ══ คำเตือนคุณภาพ ══ */
.qwarn{display:flex;gap:11px;background:#fffbeb;border:1px solid #fde68a;border-left:4px solid var(--d);border-radius:var(--r-sm);padding:12px 14px;margin:12px 0}
.qwarn .ic{font-size:18px;line-height:1.2}
.qwarn b{display:block;font-size:13.5px;color:var(--warn);margin-bottom:3px}
.qwarn p{margin:0;font-size:14px;line-height:1.7;color:#78350f}

/* ══ ผลตรวจ ══ */
.verdict{border-radius:var(--r-lg);padding:24px;color:#fff;margin-bottom:16px;position:relative;overflow:hidden}
.verdict.none{background:linear-gradient(140deg,#12b76a,#059862);box-shadow:0 20px 44px -16px rgba(5,152,98,.6)}
.verdict.few,.verdict.several{background:linear-gradient(140deg,#f79009,#e07000);box-shadow:0 20px 44px -16px rgba(224,112,0,.6)}
.verdict .glow{position:absolute;width:200px;height:200px;border-radius:50%;background:rgba(255,255,255,.2);filter:blur(34px);top:-80px;right:-40px}
.verdict .k{font-size:14px;opacity:.9;position:relative}
.verdict .v{font-size:28px;font-weight:700;margin:6px 0 8px;letter-spacing:-.02em;position:relative}
.verdict .v small{font-size:15px;font-weight:500;opacity:.92}
.verdict p{margin:0;font-size:13px;line-height:1.75;opacity:.95;position:relative}

.stats2{display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-bottom:16px}
.stats2 .box{background:#fff;border-radius:var(--r-md);padding:15px 17px;box-shadow:var(--s-s)}
.stats2 .n{font-size:25px;font-weight:700;line-height:1.1;display:flex;align-items:center;gap:8px}
.stats2 .l{font-size:13.5px;color:var(--ink-faint);margin-top:4px}
.dot{width:10px;height:10px;border-radius:3px;display:inline-block}

.shot{border-radius:var(--r-md);overflow:hidden;margin-bottom:12px;box-shadow:var(--s-s);background:#fff}
.shot .im{position:relative;line-height:0}
.shot canvas{width:100%;height:auto;display:block}
.shot .cap{display:flex;justify-content:space-between;align-items:center;padding:10px 14px;font-size:13.5px}
.shot .cap span{color:var(--ink-faint);font-size:11.5px}

/* ══ ฟอร์ม ══ */
.pill{display:inline-flex;align-items:center;gap:6px;font-size:13px;color:var(--role-teacher);background:#dff5f4;padding:6px 12px;border-radius:99px;font-weight:600;margin-bottom:14px}
.field{background:#fff;border-radius:var(--r-sm);padding:11px 14px;margin-bottom:10px;box-shadow:var(--s-s)}
.field label{display:block;font-size:14px;color:var(--ink-soft);margin-bottom:3px}
.field input{width:100%;border:0;outline:0;font:inherit;font-size:15px;font-weight:500;color:var(--ink);background:none}
.list{background:var(--glass);border:1px solid var(--glass-line);border-radius:var(--r-md);padding:16px 18px;font-size:13px;line-height:2.05;color:var(--ink-soft)}
.disclaim{margin-top:14px;font-size:14px;line-height:1.75;color:var(--ink-soft);text-align:center}

/* ══ หน้ากระดาษสำหรับ PDF (ซ่อนไว้) ══ */
#paper{position:fixed;left:-4000px;top:0;width:794px;background:#fff;padding:44px 48px;font-size:14px}
#paper h2{font-size:21px;margin:0 0 2px}
#paper .brandline{height:3px;background:var(--teal);width:52px;border-radius:2px;margin:10px 0 20px}
#paper .meta{display:grid;grid-template-columns:1fr 1fr;gap:10px 26px;font-size:13.5px;margin-bottom:20px}
#paper .meta div{display:flex;gap:8px;border-bottom:1px dotted #e2e8f0;padding-bottom:7px}
#paper .meta span{color:#64748b;min-width:110px}
#paper table{width:100%;border-collapse:collapse;font-size:13px;margin-bottom:18px}
#paper th,#paper td{text-align:left;padding:8px 10px;border-bottom:1px solid #e2e8f0}
#paper th{background:#f8fafc;color:#64748b;font-size:12px}
#paper td.n{text-align:center}
#paper .pshots{display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-bottom:18px}
#paper .pshot{border:1px solid #e2e8f0;border-radius:8px;overflow:hidden}
#paper .pshot .c{font-size:11.5px;padding:6px 9px;background:#f8fafc;color:#64748b}
#paper .sign{display:grid;grid-template-columns:1fr 1fr;gap:34px;margin:28px 0 16px}
#paper .sign div{border-top:1px solid #94a3b8;padding-top:7px;font-size:12px;color:#64748b}
#paper .limits{font-size:11px;line-height:1.85;color:#64748b;background:#f8fafc;border-radius:8px;padding:13px 15px}

@media (max-width:900px){
  /* บนจอแคบ ปุ่มเข้าสู่ระบบมุมซ้ายบนจะทับโลโก้ ถ้า padding เหลือ 44px */
  .hero{padding:68px 0 54px}
  .hero .in{grid-template-columns:1fr;gap:32px}
  .hero h1{font-size:29px}
  .steps,.tips,.can,footer .row{grid-template-columns:1fr}
  .stat{grid-template-columns:1fr;gap:16px;padding:26px}
  section{padding:42px 0}
  h2{font-size:23px}
}

/* ══ แถบสถานะการบันทึกเข้าระบบ ══
   ขึ้นเฉพาะเมื่อหน้านี้ผูกกับนักเรียน (?student= หรือ ?p=)
   สีแดงต้องอ่านว่า "ยังไม่เข้าระบบ" ไม่ใช่ "ตรวจไม่สำเร็จ" -- ผลตรวจบนจอ
   ยังถูกต้องเสมอไม่ว่าแถบนี้จะเป็นสีอะไร */
.save-bar{display:flex;align-items:flex-start;gap:11px;border-radius:var(--r-sm);
  padding:12px 14px;margin-bottom:16px;font-size:13.5px;line-height:1.6}
.save-bar b{font-weight:600}
.save-bar p{margin:3px 0 0;font-size:14px;line-height:1.7;opacity:.9}
.save-bar p.why{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:13px;opacity:.75}
.save-bar .dot{width:9px;height:9px;border-radius:50%;flex:0 0 auto;margin-top:6px}
.save-bar>div{flex:1}
.save-bar button{background:transparent;border:1px solid currentColor;color:inherit;
  border-radius:999px;padding:6px 14px;font-size:12.5px;font-weight:600;flex:0 0 auto}
.save-bar.busy{background:#eff6ff;border:1px solid #bfdbfe;color:#1e40af}
.save-bar.busy .dot{background:#3b82f6;animation:save-pulse 1.1s ease-in-out infinite}
.save-bar.ok{background:#ecfdf5;border:1px solid #a7f3d0;color:#065f46}
.save-bar.ok .dot{background:var(--D)}
.save-bar.bad{background:#fef2f2;border:1px solid #fecaca;color:#991b1b}
.save-bar.bad .dot{background:#ef4444}
@keyframes save-pulse{0%,100%{opacity:1}50%{opacity:.25}}

/* ══ หน้าครู ══ */
.pick{font:inherit;font-size:13.5px;font-weight:600;color:var(--ink);background:#fff;
  border:1px solid rgba(8,36,63,.12);border-radius:999px;padding:8px 12px;max-width:46vw}

.stats4{display:grid;grid-template-columns:repeat(4,1fr);gap:10px}
.stats4 .box{background:#fff;border-radius:var(--r-sm);padding:13px;box-shadow:var(--s-s)}
.stats4 .box.warn{background:#fffbeb;box-shadow:inset 0 0 0 1px #fde68a}
.stats4 .box .n{font-size:21px;font-weight:700;letter-spacing:-.02em}
.stats4 .box .l{font-size:11px;color:var(--ink-faint);margin-top:2px;line-height:1.4}
@media(max-width:640px){.stats4{grid-template-columns:1fr 1fr}}

.levels{display:flex;gap:9px;flex-wrap:wrap}
.lvl{display:flex;align-items:baseline;gap:7px;background:#fff;border-radius:999px;
  padding:8px 15px;box-shadow:var(--s-s);font-size:14px;color:var(--ink-soft)}
.lvl b{font-size:16px;color:var(--ink)}
.lvl.none{box-shadow:inset 0 0 0 1.5px rgba(18,183,106,.4)}
.lvl.few{box-shadow:inset 0 0 0 1.5px rgba(247,144,9,.4)}
.lvl.several{box-shadow:inset 0 0 0 1.5px rgba(224,112,0,.75)}

.refer{display:flex;align-items:center;gap:12px;background:#fff;border-radius:var(--r-sm);
  padding:11px 14px;margin-bottom:7px;box-shadow:var(--s-s);border-left:4px solid var(--d)}
.refer.several{border-left-color:#e07000}
.refer .who{flex:1;font-size:14px}
.refer .who span{display:block;font-size:13.5px;color:var(--ink-faint)}
.refer .cnt{font-size:13px;font-weight:600;color:var(--warn);white-space:nowrap}

.rosterhead{display:flex;align-items:center;gap:10px;margin:28px 0 10px;flex-wrap:wrap}
.rosteract{margin-left:auto;display:flex;gap:7px}
.chip{background:#fff;border-radius:999px;padding:7px 14px;font-size:12.5px;font-weight:600;
  color:var(--ink-soft);box-shadow:var(--s-s);text-decoration:none;display:inline-block}
.chip.solid{background:var(--role-teacher);color:#fff}
.chip.tiny{padding:5px 11px;font-size:11.5px}
.chip.yes{color:#065f46;background:#ecfdf5;box-shadow:inset 0 0 0 1px #a7f3d0}
.chip.no{color:#991b1b;background:#fef2f2;box-shadow:inset 0 0 0 1px #fecaca}
.chip:disabled{opacity:.5}

/* ใช้ทั้งฟอร์มเพิ่มนักเรียนและฟอร์มบันทึกผลของทันตแพทย์ -- กรอบเดียวกับกล่อง
   นำเข้ารายชื่อ เพื่อให้ทุกฟอร์มในระบบอ่านเป็นของชนิดเดียวกัน */
.addbox{background:#fff;border-radius:var(--r-lg);padding:22px 24px;margin:14px 0;
  border:1px solid rgba(8,36,63,.06);
  box-shadow:0 1px 2px rgba(8,36,63,.04), 0 18px 40px -26px rgba(8,36,63,.4)}
.addbox .field{box-shadow:none;background:#f6fafd;margin-bottom:8px}
.addact{display:flex;gap:9px;flex-wrap:wrap;margin-top:8px}
.addact .chip{min-height:44px;padding:0 20px;display:inline-flex;align-items:center}

.tablewrap{overflow-x:auto;-webkit-overflow-scrolling:touch}
table.roster{width:100%;border-collapse:collapse;background:#fff;border-radius:var(--r-md);
  overflow:hidden;box-shadow:var(--s-s);font-size:13.5px;min-width:560px}
table.roster th{text-align:left;font-size:11px;font-weight:600;letter-spacing:.05em;
  text-transform:uppercase;color:var(--ink-faint);padding:11px 13px;
  border-bottom:1px solid rgba(8,36,63,.07)}
table.roster td{padding:10px 13px;border-bottom:1px solid rgba(8,36,63,.05);vertical-align:middle}
table.roster tr:last-child td{border-bottom:0}
table.roster td.right{text-align:right;white-space:nowrap}
table.roster td.right .chip{margin-left:5px}
.mono{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12.5px}
.muted{color:var(--ink-faint)}
.linkish{background:none;padding:0;font:inherit;font-size:13.5px;color:var(--ink);
  text-align:left;border-bottom:1px dashed rgba(8,36,63,.25)}
/* จุดสีนี้ใช้ทั้งในตารางบนเดสก์ท็อปและในการ์ดบนมือถือ -- วาดจาก lastCell()
   ตัวเดียวกัน ขอบเขตจึงต้องครอบทั้งสองที่ ไม่ใช่แค่ ``.roster`` */
.roster .dot,.scard .dot{display:inline-block;width:9px;height:9px;border-radius:50%;
  margin-right:6px}
.roster .dot.none,.scard .dot.none{background:var(--D)}
.roster .dot.few,.scard .dot.few{background:var(--d)}
.roster .dot.several,.scard .dot.several{background:#e07000}
.tick{color:var(--role-teacher);font-weight:700}

/* ══ แผ่นพิมพ์ลิงก์ผู้ปกครอง ══
   ซ่อนบนจอทั้งหมด ปรากฏเฉพาะตอนสั่งพิมพ์ แปดใบต่อหน้า A4 */
.qrsheet{display:none}
@media print{
  body>*:not(.qrsheet){display:none !important}
  .qrsheet{display:grid;grid-template-columns:1fr 1fr;gap:0}
  .qrnote{grid-column:1/-1;font-size:10px;color:#666;margin:0 0 6px}
  .qrcard{display:flex;gap:10px;align-items:center;border:1px dashed #999;
    padding:8px;height:6.4cm;break-inside:avoid}
  .qrcard img{width:3.2cm;height:3.2cm}
  .qrmeta{font-size:10px;line-height:1.5}
  .qrmeta b{font-size:11px;display:block;margin-bottom:2px}
  .qrname{font-size:12px;font-weight:600}
  .qrmeta p{margin:4px 0 0;color:#555}
  @page{size:A4;margin:8mm}
}

/* ── หน้าทันตแพทย์ ─────────────────────────────────────── */
.casehead{display:flex;justify-content:space-between;align-items:baseline;gap:12px;margin-bottom:14px}
.casecode{font-size:19px;font-weight:700;letter-spacing:-.01em}
.shots{display:grid;grid-template-columns:1fr 1fr;gap:11px}
.shots .shot{margin:0}
.shots .shot:first-child{grid-column:span 2}
.shot img{width:100%;height:auto;display:block}
/* กรอบที่ระบบตรวจพบ -- วางทับภาพ เห็นได้เฉพาะหลังบันทึกผลแล้ว
   ไม่ใช้ชื่อ .box เพราะชนกับการ์ดตัวเลขใน .stats4 */
.det{position:absolute;border:2px solid var(--teal);border-radius:3px;pointer-events:none}
.det.d{border-color:var(--d)}
.choices{display:flex;gap:8px;flex-wrap:wrap;margin-top:6px}
.choices .chip.on{background:var(--role-teacher);color:#fff}
/* .caselist แปลว่า "รายการที่แต่ละแถวเป็นปุ่มกดได้ทั้งแถว" -- ใช้ในหน้าทันตแพทย์
   .rowlist คือกรอบหน้าตาเดียวกันแต่ไม่ผูกความหมายนั้น ใช้กับรายการที่มีปุ่มเล็ก
   อยู่ข้างใน อย่างรายการบัญชีผู้ใช้ ก่อนหน้านี้หน้า admin ยืม .caselist ไปใช้
   แล้วปุ่ม "ออก PIN ใหม่" ก็กว้างเต็มแถวตาม จนหนึ่งบัญชีกินพื้นที่สามบรรทัด */
.caselist,.rowlist{background:#fff;border-radius:var(--r-md);box-shadow:var(--s-s);overflow:hidden;margin-top:12px}
.caselist button{display:flex;justify-content:space-between;align-items:baseline;gap:10px;
  width:100%;padding:13px 15px;text-align:left;font:inherit;background:none;
  border-bottom:1px solid rgba(6,32,64,.07)}
.caselist button:last-child{border-bottom:0}
.caselist .code{font-size:15px;font-weight:700;letter-spacing:-.01em}
.caselist .nm{font-size:12.5px;color:var(--ink-faint);flex:1}
.caselist .dt{font-size:11.5px;color:var(--ink-faint);white-space:nowrap}
.search{width:100%;border:0;outline:0;font:inherit;font-size:15px;background:#fff;
  border-radius:var(--r-sm);padding:12px 15px;box-shadow:var(--s-s)}

/* ── หน้าผู้ปกครอง ─────────────────────────────────────── */
/* ── หน้าสาธารณะ ──
   หน้าแรกกับหน้าเลือกบทบาทมีพื้นหลังของตัวเอง ส่วนหน้าผู้ปกครองใช้คลาสนี้
   **ไม่ใส่ในหน้าทำงาน** — ครู ทันตแพทย์ และผู้วิจัยคงพื้นเรียบไว้เหมือนเดิม */
body.publicpage{
  background:
    radial-gradient(700px 380px at 86% 0%, var(--lilac-100) 0%, transparent 58%),
    linear-gradient(180deg,#f9fcff 0%,#eaf4fd 50%,#eeeafc 100%);
  background-attachment:fixed;
}

/* "ยังไม่เคยตรวจ" เคยเป็นกล่องเตือนสีเหลือง ทั้งที่เป็นสถานะปกติของทุกคน
   ก่อนตรวจครั้งแรก -- พ่อแม่ที่สแกน QR เข้ามาไม่ควรเจอคำเตือนเป็นสิ่งแรก */
.pnever{display:flex;align-items:center;gap:18px;padding:20px 24px;border-radius:24px;
  background:rgba(255,255,255,.82);border:1px solid rgba(8,36,63,.06);box-shadow:var(--s-s)}
.pnever .mascot{flex:none;filter:drop-shadow(0 12px 18px rgba(70,105,150,.18))}
.pnever b{display:block;font-size:17px;letter-spacing:-.01em}
.pnever p{margin:6px 0 0;font-size:13.5px;line-height:1.85;color:var(--ink-soft)}
@media (max-width:520px){.pnever{flex-direction:column;text-align:center;gap:6px}}

/* จุดสีสามระดับ -- ใช้ค่าสีเดียวกับกล่องตรวจจับ ห้ามเปลี่ยนตามข้อกำหนดบนหัวไฟล์ */
.pdot{display:inline-block;width:11px;height:11px;border-radius:50%;flex:none;
  background:var(--D);box-shadow:0 0 0 3px rgba(18,183,106,.16)}
.pdot.few{background:var(--warn);box-shadow:0 0 0 3px rgba(180,83,9,.15)}
.pdot.several{background:var(--d);box-shadow:0 0 0 3px rgba(247,144,9,.18)}
.caselist .code:has(.pdot){display:inline-flex;align-items:center}

.pcard{background:#fff;border-radius:var(--r-md);padding:16px 18px;box-shadow:var(--s-s);
  border-left:4px solid var(--D)}
.pcard.few{border-left-color:var(--warn)}
.pcard.several{border-left-color:var(--d)}
.pv{display:flex;align-items:center;gap:10px;font-size:18px;font-weight:700;
  letter-spacing:-.01em;line-height:1.5}
.pmeta{font-size:12.5px;color:var(--ink-faint);margin-top:4px}
.pnote{font-size:13.5px;line-height:1.85;color:var(--ink-soft);margin:12px 0 0}
.pdent{margin-top:12px;padding-top:12px;border-top:1px solid rgba(6,32,64,.08);font-size:13.5px}

/* ── แถบนำทางตามบทบาท ──────────────────────────────────── */
.rolenav{display:flex;gap:4px;flex-wrap:wrap;align-items:center}
.rolenav a,.rolenav .navhere{font-size:12.5px;font-weight:600;padding:6px 12px;
  border-radius:999px;text-decoration:none;white-space:nowrap}
.rolenav a{color:var(--ink-soft);background:rgba(255,255,255,.7)}
.rolenav a:hover{background:#fff}
/* ปุ่ม "อยู่ตรงนี้" ใช้สีของโซน ไม่ใช่สี teal ตายตัว -- เป็นสัญญาณเดียวกับ
   แถบบนสุดและไอคอน จึงต้องเป็นสีเดียวกัน */
.rolenav .navhere{color:#fff;background:var(--zone,var(--role-teacher))}

/* ── ลิงก์ข้ามบทบาท ──
   ครูเห็นหน้าทันตแพทย์ได้จริง เพราะครูคีย์ผลตามกระดาษของหมอเป็นงานที่มีอยู่
   (ดูช่อง #examiner-field ในหน้านั้น) ลิงก์นี้จึงไม่ควรถูกตัดทิ้ง แต่ของเดิม
   วางปนกับหน้าของตัวเองในแถวเดียว การข้ามบทบาทเลยหน้าตาเหมือนการอยู่บ้าน
   ตัวเอง เส้นคั่นกับเส้นประบอกว่ากำลังจะออกไปที่อื่น */
.rolenav .navsep{font-size:11px;color:var(--ink-faint);align-self:stretch;
  display:flex;align-items:center;padding-left:9px;margin-left:4px;
  white-space:nowrap;border-left:1px solid rgba(8,36,63,.14)}
.rolenav a.cross{padding:5px 11px;background:none;color:var(--ink-faint);
  border:1px dashed rgba(8,36,63,.22)}
.rolenav a.cross:hover{background:rgba(255,255,255,.7);color:var(--ink-soft)}

/* ── กล่อง PIN ที่แสดงครั้งเดียว ────────────────────────── */
.pinbox{background:#fff;border-radius:var(--r-md);padding:18px;box-shadow:var(--s-l);
  border:2px solid var(--role-teacher);margin:14px 0}
.pincode{font-family:ui-monospace,"Cascadia Mono",Consolas,monospace;
  font-size:34px;font-weight:700;letter-spacing:.22em;text-align:center;
  padding:14px 0;color:var(--role-teacher)}
.userrow{display:flex;align-items:center;gap:10px;flex-wrap:wrap;
  padding:12px 15px;border-bottom:1px solid rgba(6,32,64,.07)}
.userrow:last-child{border-bottom:0}
.userrow .un{font-weight:700;font-size:14.5px}
.userrow .rl{font-size:11.5px;color:var(--ink-faint);flex:1}
.userrow .chip{flex:0 0 auto;width:auto;padding:6px 12px;font-size:11.5px}
.tag{font-size:10.5px;font-weight:700;padding:3px 9px;border-radius:999px;
  background:#fffbeb;color:var(--warn);border:1px solid #fde68a}
.tag.off{background:#fef2f2;color:#b91c1c;border-color:#fecaca}

/* ── ทางเข้าสำหรับเจ้าหน้าที่ บนหน้าแรก ─────────────────── */
/* ทางเข้าเจ้าหน้าที่ ลอยอยู่กับที่เหมือนปุ่มเปลี่ยนภาษาอีกฝั่ง จึงต้องอ่านออก
   ทั้งบนฮีโร่สีเข้มและบนการ์ดสีขาวที่เลื่อนผ่านข้างล่าง -- พื้นหลังจึงทึบทั้งคู่
   ไม่ใช่กระจกใส แล้วแยกความสำคัญด้วยสีตัวอักษรแทน */
/* absolute ไม่ใช่ fixed -- ปุ่มคู่นี้อยู่มุมซ้ายบน ซึ่งเป็นที่ที่ข้อความทุกบรรทัด
   เริ่มต้น ถ้าลอยค้างไว้มันจะทับหัวข้อของทุกส่วนที่เลื่อนผ่าน ทางเข้าสำหรับ
   เจ้าหน้าที่เป็นเรื่องของตอนเปิดหน้าเข้ามา ไม่ใช่ตอนอ่านไปครึ่งหน้าแล้ว และ
   คนที่เลื่อนลงไปจะเจอส่วน "ใครใช้ส่วนไหน" ซึ่งมีลิงก์ครบกว่านี้อยู่แล้ว */
.staffbar{position:absolute;top:14px;left:14px;z-index:60;display:flex;gap:6px;flex-wrap:wrap}
.staffbar a{font-size:12.5px;font-weight:600;padding:8px 15px;border-radius:99px;
  text-decoration:none;color:var(--ink-soft);background:#fff;
  border:1px solid rgba(8,36,63,.10);box-shadow:var(--s-s)}
.staffbar a.solid{color:var(--navy-900);border-color:#fff}

/* ── หน้าเข้าสู่ระบบ ──────────────────────────────────────
   หน้านี้เคยเป็นฟอร์มสองช่องลอยอยู่บนพื้นขาว ไม่มีตรา ไม่มีอะไรบอกว่ากำลัง
   เข้าในฐานะอะไร ทั้งที่หน้าก่อนหน้าเพิ่งให้เลือกบทบาทไป */
.loginbrand{display:flex;align-items:center;gap:11px;margin-bottom:26px;
  text-decoration:none;color:inherit}
.loginbrand .logo{width:34px;height:34px;border-radius:11px;flex:none;
  display:grid;place-items:center;color:var(--role-teacher);
  background:var(--role-teacher-soft);border:1px solid rgba(10,116,114,.18)}
.loginbrand .names b{display:block;font-size:14.5px;font-weight:700;
  letter-spacing:-.01em;color:var(--ink)}
.loginbrand .names em{display:block;font-style:normal;font-size:11px;color:var(--ink-faint)}

/* ป้ายบทบาทที่หน้าเลือกบทบาทส่งมา -- สื่อสารล้วน ไม่ใช่สิทธิ์
   บทบาทจริงในบัญชียังเป็นตัวตัดสินปลายทาง ดู destination() ใน login.html */
.rolebadge{display:flex;align-items:center;gap:12px;padding:13px 15px;
  border-radius:16px;margin:0 0 10px;color:var(--rc);background:var(--rc-soft)}
.rolebadge .ic{width:38px;height:38px;border-radius:12px;flex:none;
  display:grid;place-items:center;background:rgba(255,255,255,.72)}
.rolebadge .tx{min-width:0}
/* ไม่ใช้ opacity ทำให้จาง -- 11.5 px ที่ opacity .82 บนพื้น soft เหลือ contrast
   3.56:1 ซึ่งตกเกณฑ์ ลำดับความสำคัญมาจากขนาดกับน้ำหนักตัวอักษรแทน */
.rolebadge em{display:block;font-style:normal;font-size:11.5px;font-weight:500}
.rolebadge b{display:block;font-size:16px;font-weight:700;line-height:1.35}
.rolechange{margin:0 0 22px;font-size:12.5px}
.rolechange a{color:var(--ink-faint)}

/* ทางสำรองท้ายหน้า -- "มี PIN แล้ว" หรือ "สมัครผู้ดูแลระบบ" ตามบทบาทที่เลือกมา
   แสดงทีละอัน ไม่เคยพร้อมกัน ดู showAltPath() ใน login.html */
.loginalt{display:block;text-align:center;margin:16px 0 0;font-size:12.5px;
  color:var(--ink-faint)}
.loginalt a{color:var(--role-admin);font-weight:600;margin-left:6px}

/* ── หน้าเลือกบทบาท ──────────────────────────────────────
   พื้นหลังตามฮีโร่ของหน้าแรกเสมอ เพราะเป็นหน้าที่เดินทางมาจากตรงนั้น
   ถ้าสองหน้าคนละโทนจะรู้สึกเหมือนหลุดไปคนละเว็บ -- ตอนที่ฮีโร่เป็นพื้น navy
   หน้านี้ก็เป็น navy ตอนนี้ฮีโร่เป็นพื้นอ่อน หน้านี้จึงย้ายตาม */
body.startpage{
  min-height:100vh;color:var(--ink);
  background:
    radial-gradient(700px 400px at 84% 2%, var(--lilac-100) 0%, transparent 60%),
    linear-gradient(168deg,#f8fcff 0%,#eaf4fd 46%,#ebe9fc 100%);
  background-attachment:fixed;
}
.startwrap{max-width:960px;margin:0 auto;padding:44px 20px 60px}
.startwrap h1{font-size:31px;line-height:1.3;margin:0 0 10px;font-weight:700;
  letter-spacing:-.03em;text-align:center}
.startwrap .sub{font-size:14.5px;line-height:1.85;color:var(--ink-soft);margin:0 auto 30px;
  text-align:center;max-width:52ch}

/* auto-fit ไม่ใช่ ``1fr 1fr 1fr`` -- สามใบต่อแถวบนจอกว้าง แล้วยุบเองเมื่อแคบ
   โดยไม่ต้องเขียน breakpoint เพิ่มอีกชั้น */
.pickgrid{display:grid;grid-template-columns:repeat(auto-fit,minmax(232px,1fr));
  gap:14px;margin-bottom:14px}

/* การ์ดใหญ่ = สามบทบาทที่มีบัญชี
   ตอนหน้านี้เป็นพื้น navy สีประจำบทบาทใช้ไม่ได้เพราะมันเลือกมาให้อ่านออกบน
   พื้นขาว พอย้ายมาพื้นอ่อนแล้วจึงใช้ได้ -- การ์ดสามใบตอนนี้เป็นสีเดียวกับ
   แถบหัวของหน้าที่มันพาไป ซึ่งเป็นสัญญาณต่อเนื่องตั้งแต่ก่อนล็อกอิน */
.pick2{display:flex;flex-direction:column;gap:11px;padding:26px;border-radius:24px;
  text-decoration:none;background:rgba(255,255,255,.82);
  border:1px solid rgba(8,36,63,.07);box-shadow:var(--s-s);
  transition:box-shadow .16s,transform .16s}
.pick2:hover{box-shadow:var(--s-m);transform:translateY(-3px)}
.pick2 b{font-size:19px;font-weight:700;color:var(--ink);letter-spacing:-.01em}
.pick2 p{margin:0;font-size:13.5px;line-height:1.9;color:var(--ink-soft)}
.pick2 .go{margin-top:auto;align-self:flex-start;display:inline-flex;align-items:center;
  gap:8px;font-size:13px;font-weight:700;color:#fff;background:var(--rc,var(--role-teacher));
  padding:11px 20px;border-radius:99px}

.pick2 .ic,.pickwide .ic,.pick1 .ic{width:48px;height:48px;border-radius:15px;flex:none;
  display:grid;place-items:center;color:var(--rc,var(--role-teacher));
  background:var(--rc-soft,var(--role-teacher-soft))}

/* แถบกว้าง = ผู้ปกครอง ซึ่งเป็นผู้ใช้หลักแต่ไม่ได้เข้าทางนี้ */
.pickwide{display:flex;align-items:center;gap:20px;padding:24px 26px;border-radius:24px;
  background:rgba(255,255,255,.6);border:1px solid rgba(8,36,63,.06);margin-bottom:14px}
.pickwide .ic{color:var(--role-dentist);background:var(--role-dentist-soft)}
.pickwide b{display:block;font-size:17px;font-weight:700;color:var(--ink);margin-bottom:4px}
.pickwide p{margin:0;font-size:13.5px;line-height:1.85;color:var(--ink-soft)}

/* margin-top ต้องมี เพราะของที่อยู่เหนือเส้นคั่นตอนนี้คือบรรทัด "ยังไม่มีบัญชี
   ผู้ดูแลระบบ" ซึ่งเป็นข้อความ ไม่ใช่การ์ดที่มีระยะของตัวเอง ถ้าไม่เว้น
   หัวข้อของสองกลุ่มจะอ่านติดกันเป็นย่อหน้าเดียว */
.picksep{display:flex;align-items:center;gap:14px;margin:30px 0 16px;
  font-size:12px;font-weight:600;letter-spacing:.04em;color:var(--ink-soft)}
.picksep::before,.picksep::after{content:"";flex:1;height:1px;background:rgba(8,36,63,.1)}

/* การ์ดเล็ก = ทางรอง เหลือใบเดียวคือ "ลองใช้เครื่องมือ" */
.pick1{display:flex;align-items:center;gap:13px;padding:18px 22px;border-radius:18px;
  text-decoration:none;background:rgba(255,255,255,.42);
  border:1px solid rgba(8,36,63,.08);transition:background .15s}
.pick1:hover{background:rgba(255,255,255,.72)}
.pick1.dashed{border-style:dashed;border-color:rgba(8,36,63,.16)}
/* จางกว่าการ์ดใหญ่ตั้งใจ -- ไม่ใช่บทบาท จึงไม่ใช้สีประจำบทบาท */
.pick1 .ic{width:42px;height:42px;border-radius:13px;background:rgba(8,36,63,.05);
  color:var(--ink-faint)}
.pick1 b{display:block;font-size:14px;font-weight:600;color:var(--ink-soft)}
.pick1 p{margin:2px 0 0;font-size:12px;line-height:1.7;color:var(--ink-soft)}

.pickfoot{text-align:center;margin-top:26px;font-size:12.5px;color:var(--ink-soft)}

@media (max-width:760px){
  .pickgrid{grid-template-columns:1fr}
  .pickwide{flex-direction:column;align-items:flex-start;gap:14px}
}

/* ป้ายบอกว่าชุดนั้นถ่ายไม่ครบห้ามุม -- ต้องเห็นได้จากรายชื่อโดยไม่ต้องกดเข้าไป */
.partial{font-size:13.5px;font-weight:700;padding:2px 8px;border-radius:99px;
  background:#fffbeb;color:#b45309;border:1px solid #fde68a;margin-left:6px;cursor:help}
.chip.warn{background:#fff4ed;color:#b45309;box-shadow:inset 0 0 0 1px #fcd9c2}

/* ── โหมดตรวจทั้งห้อง ────────────────────────────────────
   แถบนี้ต้องอยู่ในสายตาตลอดเวลาที่ถ่าย เพราะครูถือมือถืออยู่หน้าเด็กและต้อง
   รู้สองอย่างโดยไม่ต้องคิด: กำลังถ่ายให้ใคร และเหลืออีกกี่คน */
.classbar{display:flex;align-items:center;gap:14px;padding:12px 20px;
  background:#062040;color:#fff}
.classbar .cbwho{flex:1;min-width:0}
.classbar .cbwho b{display:block;font-size:15px;font-weight:600;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.classbar .cbwho span{font-size:11.5px;color:#8fb4d1}
.classbar .cbbar{width:120px;height:6px;border-radius:99px;
  background:rgba(255,255,255,.16);overflow:hidden;flex:none}
.classbar .cbbar i{display:block;height:100%;background:#22d3ee;transition:width .3s}
.classbar .chip{background:rgba(255,255,255,.14);color:#cfe6f7;box-shadow:none;
  text-decoration:none;flex:none}
/* ปุ่มข้ามเป็นการกระทำหลักของแถบนี้เมื่อเจอคนที่ตรวจแล้ว จึงต้องเด่นกว่า "ออก" */
.classbar .chip.solid{background:#fff;color:var(--navy-900)}
.cbdone-tag{font-size:10.5px;font-weight:700;padding:1px 8px;border-radius:999px;
  background:rgba(18,183,106,.24);color:#a7f3d0;white-space:nowrap}
.classbar .cbdone{display:flex;align-items:center;gap:14px;width:100%}
.classbar .cbdone b{flex:1;font-size:15px}
.classbar .cbdone .chip.solid{background:#fff;color:var(--navy-900)}

/* ปุ่มไปคนถัดไป -- ใหญ่ที่สุดบนหน้าผล เพราะเป็นสิ่งเดียวที่ครูจะกดต่อ */
.nextstudent{padding:14px 20px 0}
.nextstudent .primary{display:block;text-align:center;text-decoration:none}

@media (max-width:640px){
  .classbar{padding:11px 14px;gap:10px}
  .classbar .cbbar{width:64px}
}

/* ── แผงงานผู้วิจัย ──────────────────────────────────────
   เรียงตามคำถามที่ถามจริง: เก็บไปถึงไหน · AI ตรงกับหมอไหม · ข้อมูลใช้ได้ไหม
   ไม่ใช่เรียงตามโครงสร้างตาราง */
/* ── การ์ดบนแผงภาพรวม ──
   ปัญหาเดิม: การ์ดเป็นพื้นขาว และกล่องตัวเลขข้างในก็ขาว วางบนพื้นหน้าที่เกือบขาว
   ทั้งสามชั้นจึงกลืนกันหมด อ่านเป็นแผ่นเดียวติดกันโดยไม่มีความลึก

   แก้ด้วยการให้แต่ละชั้นต่างกันจริง: พื้นหน้าเป็นไล่สีอ่อน → การ์ดขาวมีเงาเป็นชั้น
   → กล่องข้างในเป็นพื้นจมสีฟ้าอ่อน ไม่ใช่ขาวบนขาว */
.dashcard{background:#fff;border-radius:var(--r-lg);padding:24px 26px;
  border:1px solid rgba(8,36,63,.05);
  box-shadow:0 1px 2px rgba(8,36,63,.04), 0 18px 40px -26px rgba(8,36,63,.45);
  margin-top:20px}
.dashcard h3{margin:0 0 3px;font-size:16.5px;font-weight:700;letter-spacing:-.01em;
  display:flex;align-items:center;gap:9px}
/* ขีดสีของโซนหน้าหัวข้อ -- บอกว่าการ์ดเริ่มตรงไหนโดยไม่ต้องใช้เส้นกรอบ */
.dashcard h3::before{content:"";width:4px;height:17px;border-radius:99px;flex:none;
  background:var(--zone,var(--role-admin))}
.dashcard h3 .tag{font-size:10.5px;font-weight:700;padding:3px 9px;border-radius:99px;
  background:#eef4fa;color:var(--ink-soft);border:0}
.dashgrid{display:grid;grid-template-columns:1fr 1fr;gap:20px;align-items:start}
.dashgrid .dashcard{margin-top:0}

/* กล่องตัวเลขที่อยู่ "ใน" การ์ด ต้องเป็นพื้นจม ไม่ใช่ขาวบนขาว */
.dashcard .stats4 .box{background:#f3f7fd;box-shadow:none;
  border:1px solid rgba(8,36,63,.06)}
.dashcard .stats4 .box.warn{background:#fffbeb;border-color:#fde68a}

/* ── การ์ดความคืบหน้า · แผงเข้ม ──
   เป็นคำตอบของคำถามเดียวที่ผู้วิจัยเปิดหน้านี้มาถาม จึงเป็นชิ้นเดียวในหน้าที่
   พื้นเข้ม ทุกอย่างที่เหลือเป็นพื้นสว่าง -- ความต่างนั้นคือลำดับความสำคัญ
   สีเดียวกับกล่องเกณฑ์ความมั่นใจ ซึ่งเป็นสีที่เข้ากับชุดนี้อยู่แล้ว */
.dashcard.lead{color:#fff;border-color:transparent;
  background:radial-gradient(700px 320px at 88% -20%, rgba(109,40,217,.5) 0%, transparent 62%),
    linear-gradient(150deg,#0d2b52 0%,#08203f 58%,#061a33 100%);
  box-shadow:0 22px 52px -26px rgba(6,26,51,.85)}
.dashcard.lead h3{color:#fff}
.dashcard.lead h3::before{background:#a78bfa}
.dashcard.lead .stats4 .box{background:rgba(255,255,255,.07);
  border-color:rgba(255,255,255,.12)}
.dashcard.lead .stats4 .box .n{color:#fff}
.dashcard.lead .stats4 .box .l{color:#9fb6d0}
.dashcard.lead .stats4 .box.warn{background:rgba(247,144,9,.16);
  border-color:rgba(247,144,9,.4)}
.dashcard.lead .stats4 .box.warn .n{color:#fcd9a0}
.dashcard.lead .stats4 .box.warn .l{color:#e8c08a}

.bigline{display:flex;align-items:baseline;gap:10px;margin:14px 0 10px}
.bigline b{font-size:40px;font-weight:700;letter-spacing:-.03em;
  font-variant-numeric:tabular-nums}
.bigline span{font-size:15px;color:var(--ink-soft);flex:1}
.dashcard.lead .bigline span{color:#bdd0e6}
.bigline em{font-style:normal;font-size:17px;font-weight:700;color:var(--teal-deep)}
.dashcard.lead .bigline em{color:#5eead4}
.bigbar{height:12px;border-radius:99px;background:#eef4fa;overflow:hidden}
.dashcard.lead .bigbar{background:rgba(255,255,255,.12)}
.bigbar i{display:block;height:100%;background:var(--D)}

.agrow{display:flex;align-items:center;gap:12px;padding:12px 0;
  border-bottom:1px solid rgba(6,32,64,.07)}
.agrow:last-child{border-bottom:0}
.agrow .lbl{flex:1;font-size:14px}
.agrow .num{font-size:18px;font-weight:700}
.agrow .pc{font-size:12.5px;color:var(--ink-faint);width:42px;text-align:right}
.agrow.over .num{color:var(--d)}
.agrow.under .num{color:#b91c1c}
.agrow.ok .num{color:var(--D)}

.qrow{display:flex;align-items:center;justify-content:space-between;
  padding:11px 0;border-bottom:1px solid rgba(6,32,64,.07);font-size:13.5px}
.qrow:last-child{border-bottom:0}
.qrow b{font-size:16px}

.roomrow{display:grid;grid-template-columns:1fr 1.1fr 100px 62px;gap:12px;
  align-items:center;padding:11px 0;border-bottom:1px solid rgba(6,32,64,.07)}
.roomrow:last-child{border-bottom:0}
.roomrow .rn{font-size:14px;font-weight:600}
.roomrow .rg{font-size:12px;color:var(--ink-faint)}
.roomrow .rbar{height:7px;border-radius:99px;background:#eef4fa;overflow:hidden}
.roomrow .rbar i{display:block;height:100%;background:var(--D)}
.roomrow .rc{font-size:12.5px;font-weight:600;text-align:right}

/* ── หัวข้อโรงเรียนในรายการห้องเรียน ────────────────────
   ชื่อโรงเรียนเป็นหัวข้อของกลุ่ม ไม่ใช่คอลัมน์ที่ต้องอ่านซ้ำทุกบรรทัด
   ขึ้นเฉพาะเมื่อมีมากกว่าหนึ่งโรงเรียน -- ดู renderRooms() */
.roomgroup + .roomgroup{margin-top:18px}
.roomhead{display:flex;align-items:baseline;gap:8px;padding-bottom:5px;
  border-bottom:1.5px solid rgba(6,32,64,.13)}
.roomhead .rh{font-size:13px;font-weight:700;color:var(--ink)}
.roomhead .rhc{font-size:11px;color:var(--ink-faint);letter-spacing:.03em}
.roomdone{margin:8px 0 0;font-size:12px;color:var(--ink-faint)}
.roomdrawer{margin-top:18px}

/* ── เปรียบเทียบระดับโรงเรียน ───────────────────────────
   แถวสูงกว่า .roomrow เพราะมีสามชั้น: ชื่อ+เปอร์เซ็นต์ · แถบสี · ตัวหาร
   ตัวหารอยู่ในแถวเดียวกันเสมอ ไม่ใช่ให้ไปเปิดดูที่อื่น -- 40% จาก 5 คน
   กับ 40% จาก 300 คน วาดแถบยาวเท่ากัน ถ้าไม่เขียนก็แยกไม่ออก

   สีเขียว/เหลือง/ส้ม เป็นชุดเดียวกับ .lvl บนหน้าครู ไม่ได้คิดใหม่ */
.scrow{padding:14px 0;border-bottom:1px solid rgba(6,32,64,.07)}
.scrow:last-of-type{border-bottom:0}
/* wrap -- ชื่อโรงเรียนไทยยาวได้มาก ถ้าไม่ให้ตกบรรทัด เปอร์เซ็นต์จะถูกดันตกขอบ */
.sctop{display:flex;align-items:baseline;gap:9px;flex-wrap:wrap}
.sctop .scname{font-size:14.5px;font-weight:700;color:var(--ink)}
.sctop .sccode{font-size:11.5px;color:var(--ink-faint);letter-spacing:.03em}
/* ดันตัวขวาสุดไปชิดขอบ ไม่ว่าจะเป็นเปอร์เซ็นต์หรือป้าย "ข้อมูลยังน้อย" */
.sctop .scpc,.sctop .scthin{margin-left:auto}
.sctop .scpc{font-size:19px;font-weight:800;color:var(--ink);
  font-variant-numeric:tabular-nums}
.sctop .scthin{font-size:11.5px;font-weight:600;color:#7a5c18;
  background:#fef6e3;border-radius:999px;padding:3px 10px}

.scbar{display:flex;height:9px;border-radius:99px;overflow:hidden;
  background:#eef4fa;margin:9px 0 7px}
.scbar i{display:block;height:100%}
.scbar i.several{background:#e07000}
.scbar i.few{background:#f79009}
.scbar i.none{background:#12b76a}
/* โรงเรียนที่ยังเทียบไม่ได้ แถบจางลง -- ยังอ่านสัดส่วนได้ แต่ไม่ชวนให้เอาไปเทียบ */
.scrow.thin .scbar i{opacity:.42}

.scfoot{display:flex;flex-wrap:wrap;gap:4px 14px;font-size:12.5px;
  color:var(--ink-soft)}
.scfoot .scdent{color:var(--ink-faint)}
.scnote{margin:0;font-size:12.5px;color:var(--ink-faint)}

.sclegend{margin:16px 0 0;font-size:12px;color:var(--ink-faint)}
.sccaveat{margin:7px 0 0;font-size:12px;line-height:1.75;color:var(--ink-faint)}

@media(min-width:720px){
  /* บนจอกว้าง ตัวหารกับตัวเลขของทันตแพทย์แยกไปคนละฝั่ง อ่านเป็นสองคอลัมน์ */
  .scfoot{justify-content:space-between;flex-wrap:nowrap}
}

/* ── ตัวเลื่อนเกณฑ์ ─────────────────────────────────────
   สีต่างจากการ์ดอื่นโดยตั้งใจ -- ตัวเลขในนี้เป็นการทดลอง ไม่ใช่ผลที่บันทึกไว้ */
.thbox{background:#062040;color:#fff;border-radius:var(--r-md);
  padding:24px 26px;margin-top:16px}
.thhead{display:flex;align-items:flex-start;justify-content:space-between;gap:16px}
.thbox h3{margin:2px 0 0;font-size:17px;font-weight:700}
.thbox .eyebrow{color:#a5f3fc}
.thbox .hint{background:rgba(255,255,255,.06);color:#bdd9ef;padding:12px 14px}
.thval b{font-size:30px;font-weight:700;letter-spacing:-.02em;
  font-variant-numeric:tabular-nums}
.thbox input[type=range]{width:100%;margin:16px 0 6px;accent-color:#22d3ee}
.thscale{display:flex;justify-content:space-between;font-size:11px;color:#8fb4d1}
.thout{display:grid;grid-template-columns:repeat(3,1fr);gap:12px;margin:18px 0 4px}
.thcell{background:rgba(255,255,255,.08);border:1px solid rgba(255,255,255,.14);
  border-radius:14px;padding:16px 18px}
.thcell .n{font-size:26px;font-weight:700;letter-spacing:-.02em}
.thcell .l{font-size:11.5px;color:#bdd9ef;margin-top:3px}
.thcell.warn{background:rgba(247,144,9,.16);border-color:rgba(247,144,9,.34)}

@media (max-width:760px){
  .dashgrid{grid-template-columns:1fr}
  /* แถบตกมาอยู่บรรทัดของตัวเอง ไม่ใช่หายไป
     เคยเขียนไว้ให้ตกบรรทัดตั้งแต่ต้น แต่เขียนด้วย flex-wrap สมัยที่แถวนี้ยังเป็น flex
     พอเปลี่ยนเป็น grid กฎนั้นก็เงียบไป และแถบก็โดนซ่อนทั้งที่มันคือ
     สิ่งที่อ่านได้เร็วที่สุดในการ์ดนี้ -- 14/37 กับ 31/35 ต้องอ่านทีละตัว */
  .roomrow{grid-template-columns:1fr 70px;gap:6px 8px}
  .roomrow .rg{display:none}
  .roomrow .rn{grid-column:1;grid-row:1}
  .roomrow .rc{grid-column:2;grid-row:1}
  .roomrow .rbar{grid-column:1/-1;grid-row:2}
  .thout{grid-template-columns:1fr}
}

/* ── ประวัติของนักเรียนหนึ่งคน ───────────────────────────
   กล่องบนสุดคือสิ่งที่ต้องทำต่อ ไม่ใช่ตัวเลขสรุป -- ครูเปิดหน้านี้เพราะอยาก
   รู้ว่าเด็กคนนี้ค้างอะไร ไม่ได้เปิดมาอ่านสถิติ */
.tdo{border-radius:var(--r-md);padding:18px 20px;box-shadow:var(--s-s);
  border-left:4px solid var(--ink-faint);background:#fff}
.tdo b{display:block;font-size:16px;font-weight:700;margin-bottom:4px}
.tdo p{margin:0;font-size:13px;line-height:1.85;color:var(--ink-soft)}
.tdo.bad{background:#fff4ed;border-color:#fcd9c2;border-left-color:var(--warn)}
.tdo.warn{background:#fffbeb;border-color:#fde68a;border-left-color:#fbbf24}
.tdo.ok{background:#ecfdf5;border-color:#a7f3d0;border-left-color:var(--D)}

.hrow{display:grid;grid-template-columns:1fr 64px 1.2fr;gap:12px;align-items:center;
  background:#fff;border-radius:var(--r-sm);padding:14px 16px;margin-bottom:8px;
  box-shadow:var(--s-s);border-left:4px solid transparent}
.hrow.none{border-left-color:var(--D)}
.hrow.few{border-left-color:#fbbf24}
.hrow.several{border-left-color:var(--d)}
.hrow .hd b{display:block;font-size:14.5px;font-weight:600}
.hrow .hd span{font-size:11.5px;color:var(--ink-faint)}
.hrow .hn{font-size:17px;font-weight:700;display:flex;align-items:center;gap:7px}
.hrow .ht{display:flex;gap:6px;flex-wrap:wrap;justify-content:flex-end}
.tag.ok{background:#ecfdf5;color:#065f46;border-color:#a7f3d0}

@media (max-width:640px){
  .hrow{grid-template-columns:1fr auto}
  .hrow .ht{grid-column:1 / -1;justify-content:flex-start}
}

/* แบบจำลองที่อยู่เบื้องหลังข้อมูล -- ปนกันได้ แต่ต้องเห็นว่าปน */
.mrow{display:grid;grid-template-columns:1fr 1.4fr 60px;gap:12px;align-items:center;
  padding:11px 0;border-bottom:1px solid rgba(6,32,64,.07)}
.mrow:last-child{border-bottom:0}
.mrow .mf{font-family:ui-monospace,monospace;font-size:13px;font-weight:600}
.mrow .mc{font-size:12px;color:var(--ink-faint)}
.mrow .mn{font-size:15px;font-weight:700;text-align:right}

/* ค่าที่ระบบใช้จริง -- ต้องอ่านได้ก่อนตัวเลื่อนเสมอ ไม่งั้นคนจะนึกว่าระบบ
   ยังไม่ได้ตั้งค่าและโยนให้ผู้ใช้เลือกเอง ซึ่งไม่ใช่สิ่งที่เกิดขึ้น */
.thlive{text-align:right;flex:none}
.thlive span{display:block;font-size:11px;color:#8fb4d1;margin-bottom:2px}
.thlive b{font-size:30px;font-weight:700;letter-spacing:-.02em;
  font-variant-numeric:tabular-nums}
.thsep{display:flex;align-items:center;gap:12px;margin:20px 0 4px;
  font-size:11.5px;color:#8fb4d1}
.thsep::before,.thsep::after{content:"";flex:1;height:1px;background:rgba(255,255,255,.14)}
.throw{display:flex;align-items:center;gap:14px;margin-top:10px}
.throw input[type=range]{flex:1;margin:0}
.throw .thval b{font-size:22px;font-variant-numeric:tabular-nums}
.throw .chip{background:rgba(255,255,255,.14);color:#cfe6f7;box-shadow:none;flex:none}
.thscale{margin-top:6px}

/* กำลังดูค่าสมมติ -- ขอบเปลี่ยนสีเพื่อไม่ให้อ่านผิดว่าเป็นผลจริงของระบบ */
.thbox.exploring{box-shadow:inset 0 0 0 2px rgba(247,144,9,.55)}
.thbox.exploring .thout{opacity:.94}

/* ทางสมัครผู้ดูแลระบบคนแรก บนหน้าเลือกบทบาท */
.picknew{text-align:center;margin:18px 0 0;font-size:13px;color:var(--ink-soft)}
.picknew a{color:var(--role-admin);font-weight:600;margin-left:6px;text-decoration:underline}
.picknew a:hover{color:#5b21b6}

/* ══ การ์ดพระเอกของหน้าทำงาน ══════════════════════════════
   เหตุผลทั้งหมดอยู่ใน teacher.js -- สรุปสั้น ๆ: หน้าจอต้องบอกว่าตอนนี้ควรทำ
   อะไรต่อ ก่อนจะบอกว่ามีตัวเลขอะไรบ้าง

   **ห้ามตั้งชื่อคลาสนี้ว่า .hero** -- ชื่อนั้นเป็นของฮีโร่หน้าแรกซึ่งเป็นแถบ
   เต็มความกว้างพร้อมไล่สีพาสเทล การใช้ชื่อซ้ำทำให้กฎของการ์ดใบนี้ไปทับพื้นหลัง
   ของหน้าแรกทั้งก้อน เหลือเป็นกล่องขาวมุมมนที่ดูเหมือนมีขอบ */
.nextup{background:#fff;border-radius:var(--r-lg);padding:20px;
  box-shadow:0 14px 34px -18px rgba(8,36,63,.4);border:1px solid rgba(8,36,63,.05)}
.nextup .k{font-size:12.5px;color:var(--ink-faint)}
.nextup .v{font-size:34px;font-weight:700;letter-spacing:-.03em;line-height:1.15;margin-top:2px}
.nextup .v em{font-style:normal;font-size:15px;font-weight:500;color:var(--ink-soft);margin-left:8px}
.nextup .who{margin-top:13px;padding:11px 13px;border-radius:13px;font-size:14px;
  font-weight:600;color:var(--zone,var(--role-teacher));
  background:var(--zone-soft,var(--role-teacher-soft))}
/* ปุ่มรับสีของโซน หน้าครูจึงเขียวน้ำเงิน หน้าหมอเป็นน้ำเงิน โดยไม่ต้องมีกฎซ้ำ */
.nextup .nextgo{display:block;width:100%;margin-top:12px;text-align:center;border-radius:16px;
  padding:15px 14px;font-size:15.5px;font-weight:700;color:#fff;text-decoration:none;
  background:var(--zone,var(--role-teacher));
  box-shadow:0 12px 28px -14px var(--zone,var(--role-teacher))}
.nextup .nextgo:hover{filter:brightness(1.06)}
/* ตรวจครบแล้วคือสถานะที่ครูทำอะไรต่อไม่ได้ -- ต้องไม่มีปุ่มและต้องไม่ดูเหมือนงานค้าง */
.nextup.done{background:var(--role-teacher-soft);box-shadow:none;
  border-color:rgba(10,116,114,.16)}
.nextup.done .k{font-size:17px;font-weight:700;color:var(--role-teacher);letter-spacing:-.01em}
/* ใช้ทั้งสถานะ "ตรวจครบแล้ว" และ "ยังไม่มีนักเรียน" -- ทั้งคู่คือ
   คำอธิบายหนึ่งบรรทัด ไม่ใช่ชื่อเด็กที่ต้องเน้นแบบ .who */
.nextup .sub{margin-top:5px;font-size:13.5px;line-height:1.8;color:var(--ink-soft)}

.sumline{margin:12px 0 0;padding:11px 14px;border-radius:14px;font-size:13px;
  line-height:1.7;color:var(--ink-soft);background:rgba(255,255,255,.66)}

/* ── การ์ดนักเรียน · เฉพาะมือถือ ── */
.rostercards{display:flex;flex-direction:column;gap:10px;margin-top:12px}
.scard{background:#fff;border-radius:var(--r-md);padding:14px;
  box-shadow:var(--s-s);border-left:4px solid rgba(8,36,63,.08)}
.scard .stop{display:flex;align-items:baseline;gap:9px}
.scard .mono{font-size:12.5px;color:var(--ink-faint)}
.scard .snm{flex:1;min-width:0;text-align:left;font-size:15px;font-weight:600;
  background:none;padding:0;color:var(--ink)}
.scard .sst{margin-top:6px;font-size:13px;color:var(--ink-soft)}
.scard .sact{display:flex;gap:8px;margin-top:12px}
.scard .sact a,.scard .sact .more{display:grid;place-items:center;min-height:44px;
  border-radius:13px;font-size:14px;font-weight:600;text-decoration:none;
  background:rgba(8,36,63,.05);color:var(--ink-soft)}
.scard .sact a{flex:1}
.scard .sact a.go{background:var(--role-teacher);color:#fff}
.scard .sact a.warn{background:#fff4ed;color:var(--warn);box-shadow:inset 0 0 0 1px #fcd9c2}
.scard .sact .more{flex:0 0 52px;font-size:18px}

/* ตารางกับการ์ดวาดพร้อมกันเสมอ แล้วให้ความกว้างจอเลือกว่าจะโชว์อันไหน */
@media (max-width:719px){ .tablewrap{display:none} }
@media (min-width:720px){ .rostercards{display:none} }

/* ปุ่มในตารางบนเดสก์ท็อปโตขึ้นจาก 29 px และเว้นห่างกันมากขึ้น */
table.roster td.right .chip{margin-left:7px;padding:8px 13px;font-size:12px}

/* ── กล่องโต้ตอบ ── */
.mi.danger{background:#fdeceb;color:#a4231c;font-weight:600}
.chip.danger{background:#a4231c;color:#fff;box-shadow:none}
.dlgbody{margin:16px 0 0;font-size:14px;line-height:1.85;color:var(--ink-soft)}
.dlgform{margin-top:14px}
.dlgact{display:flex;gap:9px;justify-content:flex-end;margin-top:18px}
.dlgact .chip{min-height:44px;padding:0 18px;display:inline-flex;align-items:center}

/* บนเดสก์ท็อปการ์ดพระเอกกางเป็นแถบกว้าง ไม่ใช่กล่องสูงที่กินครึ่งจอ
   ลำดับการอ่านยังเหมือนเดิม: ทำอะไรต่อ → ให้ใคร → ปุ่ม */
@media (min-width:720px){
  .nextup{display:flex;align-items:center;gap:22px;padding:20px 24px}
  .nextup .k{flex:none}
  .nextup .v{margin:0;flex:none;white-space:nowrap}
  .nextup .who,.nextup .sub{margin:0;flex:1;min-width:0}
  /* ``width:100%`` ของกฎฐานมีไว้สำหรับมือถือ บนแถบแนวนอนมันดันปุ่มล้นการ์ด */
  .nextup .nextgo{margin:0;flex:none;width:auto;padding:15px 30px;white-space:nowrap}
  .nextup.done{display:block}
}

/* ══ หน้าทันตแพทย์ · คิวเคส ══
   ของเดิมเป็นแถวเตี้ย ๆ ที่วันที่ถูกบีบเป็นตัวหนังสือเล็กชิดขวา -- หมอที่เคลียร์
   คิวย้อนหลังต้องรู้ว่าเคสไหนเก่า และต้องแตะได้ทั้งใบ */
.qcases{display:flex;flex-direction:column;gap:9px;margin-top:12px}
.qcases button{display:flex;align-items:center;gap:12px;width:100%;text-align:left;
  min-height:72px;padding:13px 15px;border-radius:var(--r-md);background:#fff;
  box-shadow:var(--s-s)}
.qcases button:hover{box-shadow:var(--s-m)}
.qcases .l{flex:1;min-width:0}
.qcases .code{display:block;font-size:15px;font-weight:700;letter-spacing:-.01em}
.qcases .nm{display:block;font-size:13.5px;font-weight:600;color:var(--ink-soft);margin-top:1px}
.qcases .dt{display:block;font-size:11.5px;color:var(--ink-faint);margin-top:3px}
.qcases .ar{flex:none;font-size:19px;color:var(--role-dentist)}

/* ภาพห้ามุมบนมือถือ -- เต็มความกว้าง ของเดิมเล็กเกินกว่าจะดูอะไรออก */
@media (max-width:719px){
  #shots{display:flex;flex-direction:column;gap:12px}
  #shots .shot{width:100%}
}

/* ปุ่มหลักในหน้าที่เป็นของบทบาทใดบทบาทหนึ่ง ใช้สีของโซนนั้น
   หน้าที่ไม่มีโซน (เข้าสู่ระบบ · เปิดใช้งานบัญชี · สมัคร) ยังใช้ไล่สีเดิม */
body[data-zone] .primary{background:var(--zone)}

/* ── หน้าผู้วิจัย · มือถือ ──
   ``.dashgrid`` เป็นสองคอลัมน์ตายตัว ที่ 375 px จึงบีบจนอ่านไม่ได้ */
@media (max-width:719px){
  .dashgrid{grid-template-columns:1fr}
}
/* ตัวเลข 71 / 24 / 8 อ่านยากกว่าแท่งที่ยาวไม่เท่ากัน -- แท่งบอกสัดส่วนได้ในสายตาเดียว */
.agrow .bar2{flex:1;min-width:60px;height:7px;border-radius:999px;
  background:#eef2f8;overflow:hidden}
.agrow .bar2 i{display:block;height:100%;border-radius:999px;background:#8fb4d1}
.agrow.ok .bar2 i{background:var(--D)}
.agrow.over .bar2 i{background:var(--d)}
.agrow.under .bar2 i{background:#b91c1c}
.agrow .lbl{flex:0 0 auto}
.agrow .num{min-width:34px;text-align:right;font-variant-numeric:tabular-nums}

/* ปุ่มในรายการบัญชีต้องแตะได้บนมือถือเหมือนที่อื่น */
@media (max-width:719px){
  .userrow .chip{min-height:44px;padding:0 14px;display:inline-flex;align-items:center}
  .userrow .rl{flex-basis:100%}
}

/* คำอธิบายใต้ชื่อระบบ -- เล็กกว่าหัวเรื่องแต่ใหญ่กว่าย่อหน้า
   เพราะมันคือสิ่งที่บอกว่าระบบนี้ทำอะไร ให้คนที่เพิ่งสแกน QR เข้ามาอ่าน */
.herotag{font-size:19px;line-height:1.5;font-weight:600;letter-spacing:-.01em;
  color:var(--ink-soft);margin:0 0 18px;max-width:34ch}
@media (max-width:640px){ .herotag{font-size:17px} }

/* ── พื้นหลังของหน้าหลังล็อกอิน ──
   ธีมเดียวกับหน้าแรก แต่จางกว่า -- หน้าทำงานยังต้องอ่านง่ายตลอดวัน
   ไล่สีทำให้การ์ดขาวมีอะไรให้ลอยอยู่เหนือ ต่างจากพื้นเรียบสีเดียวที่การ์ด
   กับพื้นแทบแยกกันไม่ออก */
body[data-zone]{
  background:
    radial-gradient(820px 420px at 88% -6%, var(--lilac-100) 0%, transparent 58%),
    radial-gradient(680px 380px at 4% 0%, #ffffff 0%, transparent 54%),
    linear-gradient(180deg,#f6fbff 0%,#eaf3fd 46%,#eef0fc 100%);
  background-attachment:fixed;
}

/* ── ลิ้นชักเครื่องมือขั้นสูง ──
   ของที่ระบบตั้งค่าให้แล้วและผู้ใช้ทั่วไปไม่ต้องแตะ ควรอยู่หลังการกดหนึ่งครั้ง
   ไม่ใช่กางอยู่กลางหน้าให้คนที่ไม่รู้ว่ามันคืออะไรเห็นแล้วกังวล */
.drawer{margin-top:20px;border-radius:var(--r-lg);background:rgba(255,255,255,.66);
  border:1px dashed rgba(8,36,63,.16)}
.drawer[open]{background:rgba(255,255,255,.86);border-style:solid}
.drawer > summary{list-style:none;cursor:pointer;display:flex;align-items:center;
  gap:12px;padding:18px 22px}
.drawer > summary::-webkit-details-marker{display:none}
.drawer > summary::after{content:"⌄";margin-left:auto;font-size:19px;
  color:var(--ink-faint);transition:transform .18s}
.drawer[open] > summary::after{transform:rotate(180deg)}
.drawer .dw b{display:block;font-size:15px;font-weight:600;letter-spacing:-.01em}
.drawer .dw span{display:block;font-size:12.5px;line-height:1.7;color:var(--ink-soft);
  margin-top:2px;max-width:64ch}
.drawer .thbox{margin:0 14px 14px}
@media (prefers-reduced-motion:reduce){ .drawer > summary::after{transition:none} }

/* ══ นำเข้ารายชื่อจากไฟล์ ══════════════════════════════════
   กล่องนี้ต้องอ่านเหมือน "แบบฟอร์มที่มีเงื่อนไข" ไม่ใช่ปุ่มอัปโหลดเปล่า ๆ
   เพราะกฎเรื่องคอลัมน์ชื่อคือสิ่งที่ทำให้ครูเสียเวลาถ้าไม่รู้ก่อนเลือกไฟล์ */
.importbox{background:#fff;border-radius:var(--r-lg);padding:22px 24px;margin-top:14px;
  border:1px solid rgba(8,36,63,.06);
  box-shadow:0 1px 2px rgba(8,36,63,.04), 0 18px 40px -26px rgba(8,36,63,.4)}
.importbox h3{margin:0 0 4px;font-size:16.5px;font-weight:700;letter-spacing:-.01em;
  display:flex;align-items:center;gap:9px}
.importbox h3::before{content:"";width:4px;height:17px;border-radius:99px;flex:none;
  background:var(--zone,var(--role-teacher))}
.ihint{margin:0;font-size:13px;line-height:1.8;color:var(--ink-soft)}

/* สองกล่องนี้ไม่ใช่คำเตือนว่าครูทำผิด เป็นเงื่อนไขที่ต้องอ่านก่อนเลือกไฟล์
   กล่องแรกใช้สีของโซน (สิ่งที่ระบบทำให้ และสิ่งที่ครูควรทำต่อ)
   กล่องที่สองใช้สีเตือน เพราะมันคือกรณีที่ไฟล์จะถูกปฏิเสธจริง */
.inote{display:flex;gap:11px;align-items:flex-start;margin:12px 0;
  padding:13px 15px;border-radius:14px;font-size:13px;line-height:1.85;
  color:var(--zone,var(--role-teacher));background:var(--zone-soft,var(--role-teacher-soft))}
.inote.warn{color:var(--warn);background:#fffbeb;box-shadow:inset 0 0 0 1px #fde68a}
.inote .ic{flex:none;display:inline-flex;margin-top:2px}
.iact{display:flex;gap:9px;flex-wrap:wrap;margin-bottom:12px}
.iact .chip{min-height:44px;padding:0 18px;display:inline-flex;align-items:center;
  cursor:pointer}

.iresult{margin-top:14px;padding:14px 16px;border-radius:14px;
  background:#e9f9f1;border:1px solid #b7ebd0;font-size:14px}
.iresult > b{color:#0f6b45}
.iskip{margin-top:10px;padding-top:10px;border-top:1px solid rgba(15,107,69,.18);
  font-size:12.5px;color:var(--ink-soft)}
.iskip ul{margin:6px 0 0;padding-left:18px;line-height:1.9}
