/* ============================================================
   EduFlow — ธีมกลาง "Warm Lion" (ดึงสีจากโลโก้ KRT: สิงโตส้ม + เขียวสด)
   ------------------------------------------------------------
   ไฟล์นี้คือ "แหล่งสีเดียวของทั้งเว็บ" — โหลด *หลัง* <style> ของแต่ละหน้า
   จึง override token เดิมที่ทำซ้ำไว้ในทุกไฟล์ได้ทันที
   อยากเปลี่ยนสีทั้งเว็บ → แก้ที่นี่ที่เดียว
   ============================================================ */
:root{
  /* โครง/ตัวอักษร — Navy & Orange (กรมท่า + ส้มสิงโต) */
  --ink:#12233D;            /* แถบเมนูเข้ม (กรมท่า) */
  --ink-light:#1C3151;
  --bg:#F5F7FA;             /* พื้นหลังเทาเย็น (เดิมครีม) */
  --card:#FFFFFF;
  --border:#E4E9EF;
  --line:#E4E9EF;           /* alias ของ --border (เผื่อโค้ดเก่าเรียก) */
  --hover:#EDF1F6;          /* พื้นตอนเมาส์ชี้ (ปุ่ม/ปุ่มไอคอน/แถวตาราง/รายการกดได้) — เข้มกว่า --bg พอให้รู้สึกว่า "โดน" */
  --muted:#EDF1F6;          /* พื้นของสถานะเฉย/ไม่ใช้งานแล้ว (ป้ายจบคอร์ส/ยกเลิก · วงกลมชื่อ) — ค่าเท่า --hover แต่คนละหน้าที่ (ปรับ hover ป้ายไม่ขยับตาม) · ⚠️ อย่าตั้งชื่อ token นี้เป็น "surface" เพราะ schedule.html มี var(...,#fff) ที่จะพังถ้ามี token นั้น */
  --text:#131A24;
  --text-soft:#64748B;
  --text-faint:#8A97A6;     /* เข้มพอสำหรับ WCAG */
  --text-on-muted:#5A6875;  /* ตัวหนังสือบนพื้น --muted (ป้ายสถานะเทา) — 5.04:1 */
  --code-bg:#E4EAF3;        /* พื้นป้ายรหัส .code-pill — ฟ้าน้ำเงินอ่อนตระกูล --ink (เจ้าของเลือกแบบ A 2026-08-02) · ต่างจาก --hover/--muted สีเทา กันป้ายกลืนตอนชี้เมาส์ */
  --code-bg-hover:#D6DFEE;  /* พื้นป้ายรหัสตอน hover — เข้มขึ้นเล็กน้อย (ไม่ใส่กรอบ · เจ้าของว่ากรอบรอบ label ดึงสายตาเกิน) */
  --radius:14px;

  /* สีหลัก = ส้มสิงโต */
  --accent:#E8743B;
  --accent-strong:#CF5E27;  /* ส้มกด/hover */
  --accent-light:#FDEEE3;   /* พื้นอ่อน/แท็ก */
  --accent-tint:#FDF7F2;    /* ส้มจางมาก — ไฮไลต์คอลัมน์/แถว (อ่อนกว่า -light ไม่สู้เนื้อหา) · v624 schedule "วันนี้" */
  --accent-text:#A34D18;    /* ตัวหนังสือบนพื้นอ่อน — 5.1:1 (จูนขึ้นจาก #B4561F ที่ได้ 4.31 บนพื้นอ่อน ตกเกณฑ์ AA · เข้าชุดกับ semantic -strong) */
  --action-primary:#C4511C; /* ปุ่ม/เมนู active ที่มีตัวอักษรขาว — 4.62:1; แยกจากส้มแบรนด์ */
  --action-primary-hover:#A83D14; /* hover/pressed + white — 6.28:1 */

  /* ---------- สีบอกสถานะ (semantic) — "แหล่งเดียว" ของทั้งเว็บ ----------
     กติกา: จุด/แถบ/ไอคอน ใช้ตัวหลัก · ตัวหนังสือใช้ -strong (คอนทราสต์ผ่าน WCAG AA) · พื้นอ่อนใช้ -light
     ห้ามฮาร์ดโค้ดสีเขียว/เหลือง/แดงในหน้าใด ๆ อีก — ให้ดึง token พวกนี้ไปใช้ */

  /* สำเร็จ/ปกติ = เขียวมรกต (เจ้าของเลือกเป็นเขียวหลักของธีม 2026-07-24) */
  --success:#178A5E;
  --success-strong:#0F6B47;  /* ตัวหนังสือบนพื้นขาว/พื้นอ่อน — 6.5:1 */
  --success-light:#E2F2EB;

  /* เฝ้าระวัง/รอดำเนินการ = อำพัน */
  --warn:#C98A1E;
  --warn-strong:#8A5E12;     /* ตัวหนังสือ — 5.7:1 */
  --warn-light:#FAF0DC;
  --warn-bg:#FAF0DC;         /* alias (บางหน้าเรียกชื่อนี้) */

  /* แจ้งเตือน/อันตราย = แดงอิฐ */
  --danger:#C0492C;
  --danger-strong:#A5382B;   /* ตัวหนังสือ — 6.0:1 */
  --danger-bg:#FBEBE6;
  --danger-light:#FBEBE6;    /* alias ให้ชื่อชุดเดียวกับ -light ตัวอื่น */

  /* นำส่งแล้ว/เก็บเข้าคลัง = น้ำเงิน (สถานะที่ 5 · ยกจากค่าเดิม #2B5CC4/#E7EEFB ที่ผ่านมาตรฐานอยู่แล้ว ห้ามคิดใหม่)
     ⛔ คนละตัวกับสีน้ำเงินในตารางเรียน (นั่นเป็นสีชุดบทเรียนที่ไล่วน — บังเอิญเลขเหมือนกันเท่านั้น ห้ามยุบรวม) */
  --info-strong:#2B5CC4;     /* ตัวหนังสือบนพื้นอ่อน — 5.25:1 */
  --info-light:#E7EEFB;
}

/* ============================================================
   EduFlow Design System v1.2 — promoted presentation primitives
   Shared layer owns anatomy/optics only. Routes still own copy, values,
   severity, permissions and business commands. Legacy aliases stay for
   one runtime while Students is the first pilot (#440).
   ============================================================ */
/* #592: shared table/card sorting presentation, route-owned state. */
.sort-head{font:inherit;color:inherit;background:transparent;border:0;padding:0;min-height:44px;width:100%;text-align:left;cursor:pointer}
.sort-head:focus-visible,.sort-card-controls select:focus-visible,.sort-card-controls button:focus-visible{outline:3px solid var(--action-primary);outline-offset:2px}
.sort-card-controls{display:none;gap:8px;align-items:center;flex-wrap:wrap;margin:12px 0}
.sort-card-controls select,.sort-card-controls button{font:inherit;min-height:44px;border:1px solid var(--border);border-radius:10px;background:var(--card);color:var(--text);padding:8px 12px}
.sort-card-controls label{font-size:14px;color:var(--text-soft)}
@media(max-width:1023px){.sort-card-controls{display:flex}.sort-card-controls select{flex:1;min-width:0}}
.ef-section-head{
  display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:start;
  column-gap:12px;row-gap:5px;margin:0 0 14px;
}
.ef-section-head h2{margin:0;color:var(--text);font-size:18px;line-height:1.35;font-weight:650;letter-spacing:0}
.ef-section-copy{max-width:100%;margin:0;color:var(--text-soft);font-size:13px;line-height:1.55;overflow-wrap:break-word}
.ef-count-badge{align-self:start;justify-self:end;flex:0 0 auto;padding:5px 10px;border-radius:999px;background:var(--muted);color:var(--text-on-muted);font-size:12px;font-weight:700;white-space:nowrap}
.ef-semantic-warning,.semantic-warning{display:inline-flex;align-items:flex-start;gap:4px;color:var(--warn-strong);line-height:1.55}
.ef-semantic-warning svg,.semantic-warning svg{width:1em;height:1em;flex:0 0 auto;margin-top:calc((1.55em - 1em)/2 - .06em)}

/* Filter + progressive disclosure mechanics (#456).
   Routes still own labels/counts/query/rows/summaries and business semantics. */
.ef-filter-group{display:grid;grid-auto-flow:column;grid-auto-columns:minmax(0,1fr);gap:4px;padding:4px;border:1px solid var(--border);border-radius:14px;background:var(--muted)}
.ef-filter-option{display:inline-flex;align-items:center;justify-content:center;gap:6px;min-width:0;min-height:44px;padding:8px 12px;border:1px solid transparent;border-radius:10px;background:transparent;color:var(--text-soft);font:inherit;font-size:13px;white-space:nowrap;cursor:pointer}
.ef-filter-option[aria-pressed="true"]{border-color:var(--border);background:var(--accent-light);color:var(--accent-text);font-weight:600;box-shadow:inset 0 0 0 1px rgba(196,81,28,.06)}
.ef-filter-option:disabled{opacity:.62;cursor:not-allowed}
.ef-filter-option:focus-visible,.ef-history-disclosure:focus-visible{outline:3px solid rgba(196,81,28,.28);outline-offset:2px}
.ef-history-disclosure{display:inline-flex;align-items:center;justify-content:center;min-height:44px;padding:9px 16px;border:1px solid var(--border);border-radius:10px;background:var(--card);color:var(--text);font:inherit;font-size:13px;font-weight:650;cursor:pointer}
.ef-history-disclosure:disabled{opacity:.62;cursor:not-allowed}
@media(hover:hover) and (pointer:fine){
  .ef-filter-option:hover:not([aria-pressed="true"]):not(:disabled),.ef-history-disclosure:hover:not(:disabled){background:var(--card);color:var(--text)}
}

/* ============================================================
   ⭐ ฟอนต์ — "1 ธีม = 1 ฟอนต์" (เจ้าของกำหนด 2026-07-24)
   ทั้งเว็บใช้ Noto Sans Thai ตัวเดียว ทั้งไทย อังกฤษ และตัวเลข
   เดิมปนกัน 8 ชุด (Inter / Sarabun / Segoe UI / system-ui / monospace)
   → ในหน้าเดียวกัน "ตัวเลขกับตัวหนังสือ" เป็นคนละฟอนต์ ป้ายสถานะดูไม่เป็นชุดเดียวกัน
   ยกเว้นทางเดียว = --font-mono สำหรับ "ผลลัพธ์ของเครื่อง" (log ระบบ) ที่ต้องเรียงคอลัมน์ตรงกัน
   ============================================================ */
:root{
  --font:'Noto Sans Thai',sans-serif;
  --font-mono:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
}
body{ font-family:var(--font); }
/* ฟอร์ม/ปุ่ม: บางหน้าไม่ได้สั่ง inherit ไว้ → บังคับให้เป็นฟอนต์เดียวกันหมด */
input, select, textarea, button{ font-family:var(--font); }
/* จุดที่เคยตั้ง Inter ไว้เป็นฟอนต์ที่ 2 — ดึงกลับมาเป็นฟอนต์เดียวของธีม
   รหัส (KRT143 / LSN52 / INV381) ยังคงบุคลิก "รหัส" ด้วยเลขความกว้างเท่ากัน + ระยะตัวอักษรกว้างขึ้นนิด */
.code-pill, .doc-code, .course-code, .next-code-note b, .detail-sub, .cred-value,
.wm-slider-label span, .hc-val, .kpi-value, .chip-value{
  font-family:var(--font);
}
.code-pill, .course-code, .cred-value{ font-variant-numeric:tabular-nums; letter-spacing:.03em; }
/* หน้าตากลางของ "ป้ายรหัสนักเรียน" (.code-pill) — ฟ้าน้ำเงินอ่อน + ตัวอักษรกรมท่า (เจ้าของเลือกแบบ A 2026-08-02 แทนโทนเทาเดิมที่กลืน hover)
   ไม่ใส่ font-family/letter-spacing (กฎฟอนต์ด้านบนคุมอยู่แล้ว) · ขนาด/ระยะขอบ/รัศมี คงเดิม */
.code-pill{ font-size:12px; font-weight:600; background:var(--code-bg); color:var(--ink); padding:3px 9px; border-radius:6px; }
/* ⭐ ป้ายรหัสสีน้ำเงิน (--code-bg) + ตัวอักษรกรมท่า ต่างจากพื้น hover/muted สีเทา (#EDF1F6) ชัดในตัว → ไม่กลืนตอนชี้เมาส์ ทั้งตาราง(tr) และการ์ดมือถือ(div) โดยไม่ต้องสลับสีตอน hover
   ตอนชี้เมาส์แถวตาราง แค่ทำพื้นน้ำเงินเข้มขึ้น (--code-bg-hover) ไม่ใส่กรอบ (เจ้าของว่ากรอบรอบ label ดึงสายตาเกิน 2026-08-03) · ครอบ .code-pill ในชิปนักเรียนด้วย
   ⛔ ไม่แตะ --muted (ป้ายสถานะเทา/วงกลมชื่อยังใช้) · .doc-code (ป้ายเอกสารส้มคลังเอกสาร คนละคลาส) ไม่โดน */
tr:hover .code-pill{ background:var(--code-bg-hover); }
/* log ระบบ = ข้อความเครื่อง ต้อง monospace จริง (ฟอนต์ระบบ ไม่ต้องโหลดเพิ่ม) */
.log-body{ font-family:var(--font-mono); }

/* ============================================================
   ⭐ ป้ายสถานะแบบ "ชิปพื้นอ่อน" — ขนาดเดียวกันทั้งเว็บ
   เดิมแต่ละหน้าตั้งเอง (.pay-badge 11px/500 · .finished-badge 10px/700)
   → วางเรียงกันในแถวเดียวแล้วสูงไม่เท่า/หนาไม่เท่า ดูเหมือนคนละฟอนต์
   กติกา: ขนาด-ทรง-น้ำหนัก มาจากที่นี่ที่เดียว · สีดึงจาก semantic token เท่านั้น (ห้ามฮาร์ดโค้ด)
   ============================================================ */
.pay-badge, .finished-badge, .pending-badge{
  display:inline-flex; align-items:center; gap:4px;
  padding:2px 9px; border-radius:999px;
  font-size:11px; font-weight:600; line-height:1.6;
  white-space:nowrap; vertical-align:middle;
  /* ไม่มีเส้นขอบ — ป้าย/ชิปทุกหน้าในเว็บเป็น "พื้นอ่อน + ตัวหนังสือเข้ม + ไม่มีขอบ" (แยกด้วยสีอย่างเดียว)
     v608 เคยใส่ border:1px solid currentColor เพราะตอนนั้นแถวติดลบยังทาพื้น --danger-light (ป้ายพื้นอ่อนบนพื้นเดียวกัน = contrast 1.00 ป้ายหาย)
     แต่ v608 เปลี่ยนแถวเป็นพื้นขาว + แถบซ้ายแดง 4px ไปพร้อมกันแล้ว → ขอบเลยเกิน + เป็นของแปลกหน้าเดียวในเว็บ → ถอดออก v610
     (padding คงเดิม 2px 9px · ป้ายเตี้ยลง 2px = ตั้งใจ แถวหลายป้ายเตี้ยลงไม่ได้สูงขึ้น) */
}
.pay-paid       { background:var(--success-light); color:var(--success-strong); }
.pay-unpaid     { background:var(--danger-light);  color:var(--danger-strong); }
.pay-none       { background:var(--muted);         color:var(--text-on-muted); }   /* เดิม #EDF1F6 + --text-soft = 4.20 ตก AA · โทเคนคู่นี้ทำมาสำหรับพื้นเทาอยู่แล้ว = 5.04 */
.finished-badge { background:var(--success-light); color:var(--success-strong); }
.pending-badge  { background:var(--warn-light);    color:var(--warn-strong); }

/* ⭐ ลำดับชั้นป้าย 3 ระดับ (ใช้คู่กับ .pay-badge) — ทุกป้ายพื้นอ่อนไม่มีขอบเหมือนทั้งเว็บ ให้ "สี" เป็นสัญญาณ
   ระดับ 1 ต้องลงมือ (badge-urgent · แดง) = เรื่องเงิน (ติดลบ / ยังไม่ชำระ) · ระดับ 2 ต้องตรวจ (badge-attn · เหลือง มีไอคอนสามเหลี่ยมนำ) = ข้อมูลผิด (ชนเวลา / ชั้นไม่ตรง) · ระดับ 3 ข้อมูลเฉยๆ = คลาสพื้นอ่อนด้านบน
   ⭐ ตัวชี้ "แถวไหนต้องลงมือ" = แถบซ้ายแดง 4px ของ .row-alert (คนละช่องทางกับสีป้าย) → ป้ายไม่ต้องทำซ้ำด้วยพื้นทึบ+ขอบ
   หมายเหตุ: v608 เคยใช้พื้นทึบ+ขอบเพราะแถวยังทาพื้นแดง — เปลี่ยนแถวเป็นขาวแล้วจึงถอดทั้งคู่ (v610) · ⛔ ห้ามใช้ color-mix() (iPad iOS<15.4) */
.badge-urgent { background:var(--danger-light); color:var(--danger-strong); font-weight:700; }
.badge-attn   { background:var(--warn-light);   color:var(--warn-strong);   font-weight:600; }

/* ---------- ปุ่ม: ปุ่มหลักเป็นสีส้มแบรนด์ + เด้งนุ่มเวลากด ----------
   ⚠️ "สีส้ม" ของ .btn-primary ด้านล่างเป็นค่าปริยายที่ยกขึ้นกลางมานานแล้ว (ทับ .btn-primary{navy} ในหน้ามาตรฐานที่กลายเป็นโค้ดตาย)
   → ปุ่มหลักทุกหน้าเป็นส้มเหมือนกันหมด · ยังไม่ใช่การตัดสินแบรนด์ขั้นสุดท้าย
   เจ้าของจะตัดสินสีปุ่มหลัก (ส้ม↔กรมท่า) จาก mockup เต็มหน้าทีหลัง — แก้ที่บรรทัด .btn-primary จุดเดียวครอบทุกหน้า (อย่าใช้เสียงข้างมากรายหน้าตัดสิน) */
.btn{ border-radius:10px; transition:background .15s, box-shadow .15s, transform .05s, border-color .15s; }
.btn:active{ transform:translateY(1px); }
/* ---------- ⭐ ฐานปุ่ม (ขนาด/สี/เส้นขอบ) — ของกลาง (spec-shared-ui-central รอบ C · ปรับ compat 29/7) ----------
   เจ้าของตัดสิน: ยุบเฉพาะขนาดให้เท่ากัน เก็บสีเดิม
   ⚠️ ต้องอยู่ "ก่อน" .btn-primary ด้านล่าง — (0,1,0) เท่ากัน กฎหลังชนะ · ถ้าวางหลัง จะทับพื้นส้มของปุ่มหลักจนกลายเป็นขาว
   ⚠️ GLOBAL ไม่กั้น scope — ครอบทุกหน้าแอป "และปุ่มใน modal อัตโนมัติ" (modal อยู่นอก .shell/.main) · เลิกใช้ :has()/:where() เพราะ iPad เก่า (iOS<15.4) ไม่รองรับ → ทิ้งกฎทั้งบล็อก ปุ่มกลายเป็นข้อความเปล่า
   หน้าที่ต้อง "ต่าง" ดันน้ำหนักในหน้าตัวเองด้วย body/html นำหน้า (0,1,1 ชนะ global 0,1,0):
     · ฟอร์มเต็มกว้าง: reset/reset-password (body .btn / body .btn-danger / body .btn-ghost)
     · ปุ่มเครื่องมือ ออกใบงาน/ใบความรู้ §3: gensheet/worksheet (html .btn ...)
   กฎจอแคบ + สีรอบ C (.detail-actions .btn / .btn.btn-edit / .btn.btn-danger ฯลฯ = 0,2,0) ยังชนะ global (0,1,0) เหมือนเดิม ไม่ต้องแตะสักกฎ */
.btn{
  display:inline-flex; align-items:center; gap:7px;
  padding:10px 16px; font-size:13.5px; font-weight:500;
  border:1px solid var(--border); background:var(--card); color:var(--text);
  cursor:pointer; font-family:inherit;
}
.btn svg{ flex-shrink:0; }
@media(hover:hover) and (pointer:fine){
  .btn:hover:not(:disabled){ background:var(--hover); }
  .btn-primary:hover:not(:disabled){ background:var(--action-primary-hover); border-color:var(--action-primary-hover); }
}
/* ปุ่มถูกปิดใช้งาน (เช่น "อนุมัติที่เลือก" ตอนยังไม่เลือก) — จางลง + กดไม่ได้ ให้รู้ว่ากดไม่ได้ */
.btn:disabled, .btn[disabled]{ opacity:.5; box-shadow:none; cursor:not-allowed; }
.btn-primary{
  background:var(--action-primary); border-color:var(--action-primary); color:#fff;
  box-shadow:0 2px 10px rgba(196,81,28,.28);
}
.btn-primary:active{ box-shadow:0 1px 5px rgba(196,81,28,.28); }

/* ปุ่มเข้าสู่ระบบ (หน้า login) ใช้สีแบรนด์เดียวกัน */
.btn-login{ background:var(--action-primary); box-shadow:0 2px 10px rgba(196,81,28,.28); }
.btn-login:hover{ background:var(--action-primary-hover); }

/* ---------- โฟกัสอินพุต: วงแหวนส้มบางเบา minimal + ขอบส้มเข้ม (มาตรฐานกลาง — ทุกหน้าใช้อันนี้ · ⛔ ห้าม override เป็นสีอื่น/ค่าอื่นรายหน้า) ---------- */
input:focus, select:focus, textarea:focus,
.combobox input[type="text"]:focus{
  border-color:var(--accent-strong);
  box-shadow:0 0 0 3px rgba(207,94,39,.12);
}
/* ช่องที่กรอกผิด (error) ตอนโฟกัส → วงแหวนแดงชุดเดียว ไม่ปนส้ม */
.field.error input:focus, .field.error select:focus, .field.error textarea:focus{
  border-color:var(--danger);
  box-shadow:0 0 0 3px rgba(192,73,44,.15);
}
/* ⭐ ช่องค้นหา (.search = กล่องมีขอบ ครอบ input ที่ไม่มีขอบ) → วงแหวนต้องไปที่ "กล่อง" ด้วย :focus-within ไม่งั้นวงแหวนขึ้นรอบ input ด้านใน = กรอบซ้อนกรอบ (เจ้าของทัก v723) */
.search:focus-within{ border-color:var(--accent-strong); box-shadow:0 0 0 3px rgba(207,94,39,.12); }
.search input:focus{ box-shadow:none; }   /* input ด้านในไม่มีขอบอยู่แล้ว → ปิดวงแหวนซ้อน (วงแหวนอยู่ที่กล่อง) */

/* ---------- กันโลโก้ placeholder วับตอนเปลี่ยนหน้า ----------
   ซ่อน brand ไว้ก่อน (ยังกินพื้นที่เท่าเดิม ไม่ขยับ layout) แล้วเฟดเข้าเมื่อ renderBrand วาดโลโก้จริงเสร็จ */
.sidebar .brand{ opacity:0; transition:opacity .12s ease; }
.sidebar .brand.brand-ready{ opacity:1; }

/* ---------- ชื่อโรงเรียนภาษาไทย (brand-sub) → บรรทัดเดียวเสมอ ไม่ห่อ 2 บรรทัด (เจ้าของขอ) ----------
   แก้ส่วนกลางทีเดียว ครอบทุกหน้า · ยาวเกินแถบ = ตัดด้วย … (ยังอ่านชื่อหลัก KRT EDUCATION ด้านบนได้) */
.sidebar .brand > div:last-child{ min-width:0; }   /* ให้กล่องข้อความย่อตามแถบได้ (กัน flex ดันล้น) */
.sidebar .brand-sub{
  font-size:10.5px; line-height:1.35;
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}

/* ---------- ชื่อคนในตาราง/รายชื่อ (directory) — ทุกหน้าเป็นชุดเดียวกัน ----------
   มาตรฐาน people-directory: ชื่อจริง+นามสกุล อยู่บรรทัดเดียว (ห้ามตัดคำกลางชื่อ), ชื่อเล่นอยู่บรรทัดล่าง (.s-nick)
   ใส่ส่วนกลางทีเดียว → ครอบ teachers/students/finance/lessons/attendance/courses/rooms ฯลฯ */
.s-name{ white-space:nowrap; }
.s-nick{ white-space:nowrap; }

/* ---------- ⭐ หน่วยข้อความ "มือถืออ่านบรรทัดต่อบรรทัด" (mobile-line-by-line) — ของกลาง ----------
   ใช้ห่อ "หน่วยความหมาย" ตอนสร้าง HTML เพื่อไม่ปล่อยให้เบราว์เซอร์ตัดเอง (ไทยไม่มีเว้นวรรค ตัดมั่วได้)
   .u-nb  = หน่วยสั้นที่ห้ามขาดกลาง  → "จ, พ 17:00-18:30" · "ห้อง 2" · "ป.4-ป.6" · "22 ก.ค. 69"
   .u-blk = หน่วยกลาง-ยาว (ชื่อคน/ชื่อคอร์ส/ประโยคย่อย) → ย้ายทั้งก้อนเมื่อบรรทัดไม่พอ
            แต่ยัง "ห่อในตัวเอง" ได้ถ้ายาวเกิน 1 บรรทัดจริง ๆ → ไม่มีวันล้นขอบ
   กติกา: จุดคั่น "·" ต้องผูกท้ายหน่วยซ้ายเสมอ (ห้ามให้ไปขึ้นต้นบรรทัดใหม่)
   ⛔ ห้ามใช้ word-break:keep-all แทน — ชื่อโรงเรียน/สถานที่ไทยยาวจะไม่ยอมห่อเลย แล้วล้นขอบ */
.u-nb{ white-space:nowrap; }
.u-blk{ display:inline-block; }

/* ---------- ป้าย "รอบ N" ในการ์ด (ติดตามงาน + ใบประเมิน) — ของกลาง (spec-card-consistency ข้อ 2.3) ----------
   ยึดหน้าตาแบบหน้าติดตามงาน (มีเส้นขอบ 11px) · self-contained ครบทุก prop (ไม่พึ่ง .chip — เพราะ .chip ชนกับการ์ด KPI หน้า health)
   ใช้เป็น class="chip c-round" (followup) หรือ class="c-round" (evaluation) ก็ได้ ได้หน้าตาเดียวกัน */
.c-round{ display:inline-flex; align-items:center; gap:4px; font-size:11px; font-weight:600; border-radius:8px; padding:2px 8px; background:var(--bg); color:var(--text-soft); border:1px solid var(--border); white-space:nowrap; }

/* ---------- ⭐ ป้ายอ้างอิงนักเรียนมาตรฐาน (EduFlow.studentChipHTML) ----------
   "[รหัส] ชื่อจริง (ชื่อเล่น) ชั้น" — บรรทัดเดียวเสมอ ไม่ตกบรรทัดทุกขนาดจอ
   จอแคบมาก: ย่อ "ชื่อเล่น" ด้วย … (ส่วนที่เหลือยังระบุตัวได้ครบ) แทนที่จะดันตกบรรทัด
   ระดับชั้นตั้งใจให้ "ไม่เด่น" (เทากลาง) เพราะเป็นข้อมูลประกอบ ไม่ใช่ตัวระบุหลัก */
.stu-chip{ display:inline-flex; align-items:center; gap:6px; min-width:0; max-width:100%; vertical-align:middle; }
.stu-chip .code-pill{ flex-shrink:0; }
.stu-chip .stu-first{ white-space:nowrap; font-weight:500; flex-shrink:0; }
.stu-chip .stu-nick{ color:var(--text-soft); font-weight:400; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; min-width:0; }   /* เดิม --text-faint 2.98 ตก AA · ชื่อเล่นเป็นข้อมูลสำคัญ (โรงเรียนเรียกด้วยชื่อเล่น) → --text-soft 4.76 ผ่าน · ยังจางกว่าชื่อจริง ลำดับชั้นคงเดิม */
.stu-chip .stu-grade{ flex-shrink:0; font-size:11px; font-weight:500; color:var(--text-soft); background:#EDF1F6; border-radius:6px; padding:1px 7px; white-space:nowrap; }
/* โหมดกะทัดรัด (studentChipHTML(code,{compact:true})) — ที่แคบมากที่วางชิปหลายตัวเรียงกัน (ตารางสัปดาห์/ตารางเรียน)
   ข้อมูลที่ตาเห็นเท่าเดิม (รหัส·ชื่อเล่น·ชั้น) แค่ "ย่อขนาด" + ซ่อนชื่อจริงด้วย CSS · ไม่มีสีใหม่ ทุกอย่างจากธีม */
.stu-chip.compact{ gap:4px; font-size:11px; }
.stu-chip.compact .code-pill{ font-size:10px; padding:1px 5px; border-radius:5px; }
.stu-chip.compact .stu-first{ display:none; }
.stu-chip.compact .stu-nick{ color:var(--text-soft); }
.stu-chip.compact .stu-grade{ font-size:9.5px; padding:0 5px; border-radius:4px; }
/* จอแคบมาก: ซ่อนป้ายชั้น เหลือที่ให้ชื่อเล่น (วิธีเดียวกับ lessons.html ≤380px ที่ซ่อน .stu-grade) */
@media (max-width:380px){ .stu-chip.compact .stu-grade{ display:none; } }

/* ============================================================
   ⭐ ตัวแบ่งหน้า (pagination) — ของกลาง (spec-pagination-central เฟส 1)
   ยกจาก 9 หน้าที่ก๊อป .pagination-bar เหมือนกันเป๊ะ · รวมชุดกฎจอแคบของ 5 หน้า (students/teachers/courses/lessons/staff)
   ให้ทุกหน้าเท่ากัน (เดิม finance/rooms ไม่มี → มือถือดีขึ้น)
   ⚠️ theme.css โหลดท้ายสุด = ชนะกฎหน้า · หน้าที่ต้องต่าง (ledger ฝังในกล่องตาราง) ต้อง override ด้วย specificity สูงกว่า
   ────────────────────────────────────────────────────────────
   📐 กฎ "ตาราง=มีตัวเลือก · การ์ด=ไม่มี" (spec-followup-assessed-date ข้อ 3.1 · เจ้าของตัดสิน 2026-07-29)
      หน้าตาราง (นักเรียน/ครู/คอร์ส/บทเรียน/ห้อง/บุคลากร/การเงิน — 7 หน้า) → มี .per-page-control "รายการ/หน้า"
      หน้าการ์ด (ใบประเมิน/บัญชี — 2 หน้า) → ⛔ ไม่มี โดยตั้งใจ · แถวการ์ดสูงกว่าแถวตารางหลายเท่า เลือก 100/หน้าจะเลื่อนนานแย่กว่าเดิม
      → 2 หน้านั้นที่ไม่มี .per-page-control ไม่ใช่ของตกหล่น · ห้าม audit เติมตัวเลือกให้ (จัดวางด้วย .page-range-text:first-child ด้านล่าง)
   ============================================================ */
.pagination-bar{ display:flex; align-items:center; justify-content:space-between; gap:14px; margin-top:14px; flex-wrap:wrap; }
.per-page-control{ display:flex; align-items:center; gap:8px; font-size:13px; color:var(--text-soft); flex-shrink:0; }
.pp-trail-short{ display:none; }
.per-page-control select{ border:1px solid var(--border); border-radius:8px; padding:6px 10px; font-size:13px; font-family:inherit; color:var(--text); background:var(--card); outline:none; cursor:pointer; }
.page-range-text{ font-size:13px; color:var(--text-soft); flex:1; text-align:center; min-width:140px; }
/* หน้าการ์ด (ไม่มี .per-page-control) → .page-range-text เป็นลูกตัวแรก → ชิดซ้าย · เลขหน้าชิดขวา (space-between) เต็มแถวสมดุล
   หน้าตาราง = .per-page-control เป็นลูกตัวแรก → range ไม่ใช่ first-child → คงกลาง (อยู่ระหว่างตัวเลือกกับเลขหน้า ไม่เปลี่ยน)
   ยึด "ตามของที่มีจริง" ไม่ใส่ช่องว่างหลอก (spec-followup-assessed-date ข้อ 3.2) */
.page-range-text:first-child{ text-align:left; }
.page-nav{ display:flex; align-items:center; gap:4px; flex-shrink:0; }
.page-btn{ border:1px solid var(--border); background:var(--card); border-radius:8px; width:32px; height:32px; display:inline-flex; align-items:center; justify-content:center; font-size:13px; color:var(--text-soft); cursor:pointer; font-family:inherit; }
.page-btn:hover:not(:disabled){ background:var(--hover); color:var(--text); }
.page-btn:disabled{ opacity:0.4; cursor:not-allowed; }
.page-btn.active{ background:var(--ink); color:#fff; border-color:var(--ink); font-weight:500; }
.page-ellipsis{ padding:0 4px; color:var(--text-faint); font-size:13px; }
@media (max-width:700px){
  .pagination-bar{ justify-content:center; }
  /* flex:0 0 100% (ไม่ใช่แค่ width:100%) — ป้ายช่วงฐานเป็น flex:1 (flex-basis:0 ยืดกินที่ว่าง) ซึ่งชนะ width:100% → ไม่ยอม wrap
     ต้องล้ม flex-basis เป็น 100% ให้ลงบรรทัดล่างเต็มกว้างจริงตั้งแต่ ≤700 (เหมือน ledger .page-range-text2) → เลขหน้ากลับมากึ่งกลางเองด้วย justify-content:center (spec-pagination-561-700) */
  .page-range-text{ order:3; flex:0 0 100%; }
  .page-range-text:first-child{ text-align:center; }   /* จอแคบ: range ลงบรรทัดล่างเต็มกว้าง → กลับมากึ่งกลาง (ล้มกฎ first-child ชิดซ้ายด้านบน · ยึดมาตรฐานเดิม §3.2) */
}
/* ช่วง 561–700 เท่านั้น (ไม่แตะ ≤560 ที่เพิ่งเสร็จ v483 · ไม่แตะ >700): หน้าตารางมี .per-page-control อยู่แถวเดียวกับเลขหน้า
   → justify-content:center จัด "กลุ่ม per-page+nav" กลาง เลขหน้าเลยเยื้องขวา · ให้ per-page ลงเต็มบรรทัดของตัวเอง (บนสุด) เลขหน้าจะเหลือเดี่ยวกลางแถวจริง = กึ่งกลางเหมือนใบประเมิน/บัญชีครบทั้ง 9 หน้า */
@media (min-width:561px) and (max-width:700px){
  .per-page-control{ flex:0 0 100%; justify-content:center; }
}
/* จอแคบ: per-page(ซ้าย) + เลขหน้า(ขวา) บรรทัดเดียว · ช่วง "x–y จาก z" ลงบรรทัดล่างเต็มกว้าง กึ่งกลางจาง (มาตรฐาน 5 หน้า) */
@media (max-width:560px){
  .pagination-bar{ flex-direction:row; flex-wrap:wrap; align-items:center; justify-content:space-between; gap:10px 6px; margin-top:16px; }
  .per-page-control{ order:1; font-size:12.5px; color:var(--text-faint); gap:5px; }
  .page-nav{ order:2; gap:3px; }
  /* หน้าการ์ด (ไม่มี .per-page-control → ป้ายช่วงเป็น "ลูกตัวแรก") จอแคบ page-nav อยู่คนเดียวบรรทัดบน · space-between ดันชิดซ้าย
     → margin-left:auto ดัน "ชิดขวา" ให้ตรงกับหน้าตาราง (per-page ซ้าย + nav ขวา) — เจ้าของทัก 2026-08-08 ว่าใบประเมินอยู่กลาง หน้าอื่นชิดขวา (เดิม v483 กึ่งกลาง 2 margin auto)
     เผื่อ 2 คลาสป้ายช่วง: หน้าอื่น .page-range-text · บัญชี .page-range-text2 · ⛔ ไม่แตะ 7 หน้าตาราง (per-page เป็นลูกตัวแรก selector ไม่ match) · ไม่ใช้ :has() */
  .page-range-text:first-child + .page-nav,
  .page-range-text2:first-child + .page-nav{ margin-left:auto; }
  .page-nav .pg-around{ display:none; }   /* §4.4ข: จอแคบเหลือ หน้าแรก·ปัจจุบัน·สุดท้าย + ลูกศร (ซ่อนเลข "รอบตัว") กันแถวปุ่มล้นจอตอนอยู่หน้ากลาง · PC ยังโชว์ครบ · หมุนจอปรับตามเอง */
  .page-range-text{ order:3; flex:0 0 100%; width:100%; text-align:center; font-size:12px; color:var(--text-faint); margin-top:1px; }
  .per-page-control .pp-lead, .per-page-control .pp-trail{ display:none; }
  .per-page-control .pp-trail-short{ display:inline; }
}

/* ---------- ปุ่ม "โหลดเพิ่ม" — ของกลาง (spec-teaching-log-display ข้อ F · ยกจากคลังเอกสาร .gal-more-* เปลี่ยนชื่อเป็นกลาง ไม่ผูกแกลเลอรี)
   ใช้ทั้งคลังเอกสาร (แกลเลอรี + ลิสต์ไฟล์) และติดตามการสอน · ⛔ ค่าเดิมเป๊ะ ห้ามเปลี่ยนหน้าตา · theme.css โหลดท้ายสุด ต้องลบสำเนาในคลังเอกสารออกจริง */
.load-more-wrap{ display:flex; justify-content:center; padding:22px 0 6px; }
.load-more-btn{ display:inline-flex; align-items:center; gap:8px; border:1px solid var(--accent); background:var(--accent-light); color:var(--accent-text); border-radius:10px; padding:11px 24px; font-family:inherit; font-size:14px; font-weight:600; cursor:pointer; }
.load-more-btn:hover{ background:var(--accent); color:#fff; }

/* ---------- ช่องค้นหา (search box) — ของกลาง (spec-shared-ui-central รอบ A) ----------
   ทุกหน้าใช้ <svg> ไอคอนแว่นขยาย · เดิม 8 หน้ามี `.search i` (โค้ดตายยุค icon-font) → svg ไม่ได้สี ไอคอนเลยเข้มผิด
   เจ้าของตัดสิน: ยึดแบบที่ทำงานจริง (svg เทาจาง) · input ใช้ flex:1 (ผลเท่า width:100% แต่ตรงกับกล่อง flex) · ค้นทั้งโปรเจกต์แล้วไม่ชนชื่ออื่น */
.search{ flex:1; min-width:220px; display:flex; align-items:center; gap:8px; background:var(--card); border:1px solid var(--border); border-radius:10px; padding:9px 14px; }
.search input{ border:none; outline:none; font-size:13.5px; flex:1; font-family:inherit; background:none; color:var(--text); }
.search svg{ color:var(--text-faint); flex-shrink:0; }

/* ---------- แถบเมนูข้าง (sidebar) — ของกลาง (spec-shared-ui-central รอบ B · คลาส 1) ----------
   markup เขียนต่อหน้าทุกไฟล์ (renderSidebar เติมแค่ nav-item) แต่ค่าเหมือนกัน · ยึดแบบส่วนใหญ่ (มี letter-spacing + transition)
   · `.brand-mark i` เดิม 8 หน้า = โค้ดตาย (ยุค icon-font) ไม่ยก · ทำงานร่วมกับกฎ sidebar อื่นที่มีอยู่แล้วด้านบน (brand fade / brand-sub / nav-section / active shadow) */
.sidebar{ width:230px; background:var(--ink); color:#fff; display:flex; flex-direction:column; flex-shrink:0; padding:22px 14px; }
/* ⚠️ .brand* scope ใต้ .sidebar — ชื่อคลาสนี้ชนกับ "การ์ดโลโก้หน้าสาธารณะ" (login/register/reset · โลโก้ใหญ่กว่า 42px) ที่โหลด theme.css ด้วย · ห้ามยกแบบ unscoped (จะไปหดโลโก้หน้าสาธารณะ) */
.sidebar .brand{ display:flex; align-items:center; gap:10px; padding:0 10px 24px; margin-bottom:6px; border-bottom:1px solid rgba(255,255,255,0.08); }
.sidebar .brand-mark{ width:34px; height:34px; border-radius:10px; background:var(--accent); display:flex; align-items:center; justify-content:center; flex-shrink:0; }
.sidebar .brand-name{ font-size:15px; font-weight:600; letter-spacing:0.2px; }
.sidebar .brand-sub{ color:rgba(255,255,255,0.45); margin-top:1px; }   /* font-size 10.5px มาจาก .sidebar .brand-sub ที่มีอยู่ด้านบนแล้ว */
.nav{ display:flex; flex-direction:column; gap:2px; margin-top:18px; }
.nav-item{ display:flex; align-items:center; gap:11px; min-height:44px; padding:10px 12px; border-radius:10px; color:rgba(255,255,255,0.6); font-size:13.5px; cursor:pointer; border:none; background:none; width:100%; text-align:left; font-family:inherit; transition:background 0.15s, color 0.15s; }
.nav-item svg{ flex-shrink:0; }
.nav-item:hover{ background:rgba(255,255,255,0.06); color:rgba(255,255,255,0.9); }
.nav-item.active{ background:var(--action-primary); color:#fff; font-weight:500; }
.sidebar-footer{ margin-top:auto; padding:12px 10px 0; border-top:1px solid rgba(255,255,255,0.08); display:flex; align-items:center; gap:10px; }
.admin-avatar{ width:32px; height:32px; border-radius:50%; background:#3A4458; display:flex; align-items:center; justify-content:center; font-size:12px; font-weight:600; color:#fff; flex-shrink:0; }
.admin-name{ font-size:12.5px; font-weight:500; color:#fff; }
.admin-role{ font-size:11px; color:rgba(255,255,255,0.45); }

/* ---------- โครงหน้า: พื้นที่เนื้อหา · หัวข้อหน้า · ปุ่มไอคอน · ชั้นพื้นหลัง modal — ของกลาง (spec-shared-ui-central รอบ B) ----------
   ยึดแบบส่วนใหญ่ · ตรวจทั้งโปรเจกต์แล้วไม่ชนหน้าสาธารณะ/จอห้องเรียน (ต่างจาก .brand* ที่ชน)
   .icon-btn = แบบเนื้อหา (สว่าง) · ปุ่ม logout ในแถบเมนูถูกบังคับเข้มด้วย data.js .sidebar-footer .icon-btn (specificity สูงกว่า) ทุกหน้าอยู่แล้ว
   .page-sub ไม่ยก — มี 4 แบบจริง (home margin 8px · health line-height · school margin-bottom 20px) ยังไม่เหมือนกัน */
.main{ flex:1; min-width:0; padding:32px 40px; }
.page-title{ font-size:23px; font-weight:600; margin:0; }
.page-sub{ font-size:13.5px; color:var(--text-soft); margin:4px 0 0; }   /* home มี .page-sub b{} เพิ่มเอง (คำสรุปตัวเข้ม) เก็บที่ home · health line-height / school margin-bottom เก็บที่หน้านั้น */
.icon-btn{ border:1px solid var(--border); background:var(--card); cursor:pointer; color:var(--text-soft); width:30px; height:30px; border-radius:8px; display:inline-flex; align-items:center; justify-content:center; flex-shrink:0; }
.icon-btn:hover{ background:var(--hover); color:var(--text); }
/* ชั้นพื้นหลัง modal + confirm ใช้โครงร่วม (spec-shared-ui-central รอบ E) — ดูแลที่เดียว · ต่างแค่ z-index (confirm อยู่เหนือ modal)
   confirm z90 = เหนือ modal(50)/modal2(70)/view(80) · ใต้ toast(100)
   ⚠️ ledger ยกเว้น: หน้านั้นมีระบบชั้นซ้อน confirm 8 กล่อง (ฐาน 70 → inline 90/95/96/122/150/155) → คงฐาน z70 ไว้ (body .confirm-overlay ในหน้า) ห้ามดันเป็น 90 */
.modal-overlay, .confirm-overlay{ display:none; position:fixed; inset:0; background:rgba(27,34,48,0.5); align-items:center; justify-content:center; padding:20px; }
.modal-overlay.open, .confirm-overlay.open{ display:flex; }
.modal-overlay{ z-index:50; }
.confirm-overlay{ z-index:90; background:rgba(27,34,48,0.55); }
/* v979: opt-in native dialog hosts fill the browser top layer while the
   existing inner .confirm-box continues to own the visible card. */
dialog.confirm-overlay{
  width:100%;
  max-width:none;
  height:100%;
  max-height:none;
  margin:0;
  border:0;
  overflow:hidden;
  color:inherit;
}
dialog.confirm-overlay::backdrop{ background:transparent; }

/* ---------- แถบเครื่องมือ (toolbar) + สถานะว่าง (empty) — ของกลาง (spec-shared-ui-central รอบ D) ----------
   ยึดแบบส่วนใหญ่ (8 หน้ามาตรฐาน) · GLOBAL (0,1,0) ไม่กั้น scope เหมือนรอบ C · หน้าที่ต่างดัน body นำหน้า (0,1,1) ในหน้าตัวเอง
   ⚠️ กฎมือถือ .toolbar .search/.filter-select/.filter-chip/#export-btn (0,2,0) ยังชนะ global — ไม่ถูกแตะ (finance ปุ่มกรอง 2×2 · evaluation/followup แบ่งครึ่ง · ซ่อน tab-divider)
   ต่าง: toolbar → documents/evaluation(mb18) followup(align) health(การ์ด) · empty → my-income/documents(การ์ดประ) ledger/eval/followup/worksheet/teaching-log/retention (faint) */
.toolbar{ display:flex; gap:10px; margin-bottom:16px; flex-wrap:wrap; }
.empty{ padding:60px 20px; text-align:center; color:var(--text-soft); }
/* ไอคอนสถานะว่าง: ทุกหน้าใช้ <svg> (ไม่มี <i> เลย · .empty i เดิมเป็นซากยุค icon-font แบบ .search i รอบ A) → ยึด .empty svg
   จัดกึ่งกลางเหนือข้อความ (display:block + margin auto) · เดิม 8 หน้ามาตรฐานไม่มีกฎนี้ ไอคอนเลยอยู่ข้างข้อความ = แก้ให้ตรงกัน (เจ้าของยืนยัน 8 หน้าเปลี่ยน) · ยุบจาก evaluation/followup/documents/my-income */
.empty svg{ width:34px; height:34px; display:block; margin:0 auto 10px; color:var(--text-faint); }
/* ⛔ กัน .empty svg (สีเทา/ใหญ่/บล็อก) รั่วไปโดนไอคอนใน "ปุ่ม CTA" ที่อยู่ใน .empty → ไอคอนตามสีปุ่ม (ปุ่มส้ม=ไอคอนขาว) · เจ้าของทัก v729 ปุ่ม "เพิ่มบันทึกแรก" ไอคอนเทาบนพื้นส้ม */
.empty .btn svg{ width:auto; height:auto; display:inline-block; margin:0; color:inherit; opacity:1; }

/* ---------- กล่อง modal + กล่องยืนยัน + สปินเนอร์ — ของกลาง (spec-shared-ui-central รอบ E) ----------
   ยึดแบบส่วนใหญ่ (8-9 หน้า) · GLOBAL (0,1,0) เหมือน C/D · หน้าที่ต่างดัน body นำหน้า (0,1,1) ในหน้าตัวเอง (ต้องเซ็ตทุก property กัน leak)
   keyframes pop/spin ยกมาด้วย (central .modal/.spinner อ้างถึง) · .spin(เล็ก) + .modal-head/body/footer/title เป็นคนละคลาส ไม่ยกรอบนี้
   ต่าง: modal → documents(90vh)/ledger(420·ไม่จำกัดสูง)/teaching-log(440·ไม่มี anim)/school(480·92vh·ไม่มี anim) · confirm-box → documents/followup(380)/school(400·center·ไม่มี anim) · spinner → worksheet(34·ส้ม)/login(15·สาธารณะ) */
.modal{ background:var(--card); border-radius:18px; width:100%; max-width:480px; max-height:88vh; overflow-y:auto; animation:pop 0.18s ease-out; }
.confirm-box{ background:var(--card); border-radius:16px; width:100%; max-width:360px; padding:24px; animation:pop 0.18s ease-out; }
.spinner{ width:14px; height:14px; border-radius:50%; border:2px solid rgba(255,255,255,0.35); border-top-color:#fff; animation:spin 0.6s linear infinite; flex-shrink:0; }
@keyframes pop{ from{opacity:0;transform:translateY(8px) scale(0.98)} to{opacity:1;transform:translateY(0) scale(1)} }
@keyframes spin{ to{transform:rotate(360deg)} }

/* ---------- ลูกของ modal + กล่องยืนยัน — ของกลาง (spec-shared-ui-central รอบ E · ลูก) ----------
   ยึดแบบส่วนใหญ่ (9-11 หน้า) · GLOBAL (0,1,0) · ต่าง: ledger/school (modal เล็กกว่า) ดัน body ในหน้าตัวเอง · followup (confirm-text pre-line) ดัน body
   .modal-head/body/footer/title/close = โครง modal (followup ใช้ .modal2-* คนละชุด ไม่เกี่ยว) · confirm-overlay/confirm-icon ยังไม่ยก (รอเสนอ z-index) */
.modal-head{ padding:22px 26px 16px; display:flex; align-items:flex-start; justify-content:space-between; border-bottom:1px solid var(--border); }
.modal-title{ font-size:17px; font-weight:600; margin:0; }
.modal-title-sub{ font-size:12.5px; color:var(--text-soft); margin-top:3px; }
.modal-close{ border:none; background:none; cursor:pointer; color:var(--text-faint); padding:6px; border-radius:8px; }
.modal-close:hover{ background:var(--hover); color:var(--text); }
.modal-body{ padding:22px 26px; }
.modal-footer{ display:flex; justify-content:flex-end; gap:10px; padding:16px 26px 22px; border-top:1px solid var(--border); }
.confirm-title{ font-size:15.5px; font-weight:600; margin:0 0 6px; }
.confirm-text{ font-size:13px; color:var(--text-soft); line-height:1.6; margin:0 0 20px; }
.confirm-actions{ display:flex; gap:10px; justify-content:flex-end; }
.confirm-icon{ width:44px; height:44px; border-radius:50%; background:var(--danger-bg); color:#A32D2D; display:flex; align-items:center; justify-content:center; margin-bottom:14px; }

/* v978/v979: Archive-reason confirmation has two stable layout owners.
   Only the body may scroll; the action footer stays outside the rotating
   scroll layer. v979 places the exact host in the native dialog top layer. */
.archive-confirm-overlay .archive-confirm-sheet{
  text-align:left;
  display:grid;
  grid-template-rows:minmax(0,1fr) auto;
  padding:0;
  overflow:hidden;
}
.archive-confirm-overlay .archive-confirm-body{
  min-height:0;
  padding:24px 24px 0;
  overflow-y:auto;
  overscroll-behavior:contain;
  -webkit-overflow-scrolling:auto;
}
.archive-confirm-overlay .archive-confirm-icon{
  margin:0 auto 14px;
}
.archive-confirm-overlay .archive-confirm-route-close,
.archive-confirm-overlay .archive-confirm-safe-boundary{display:none}
.archive-confirm-overlay .archive-confirm-actions{
  display:grid;
  grid-template-columns:repeat(2,minmax(0,1fr));
  gap:10px;
  margin:0;
  padding:16px 24px 24px;
  background:var(--card);
}

/* v981: the owner-accepted Editor pattern is the touch control for Archive.
   A direct-touch open fixes one stable <dialog> host in normal document flow;
   rotation never swaps it into a top-layer/positioned sheet. The page owns the
   only scroll surface, while fine-pointer hosts retain the native dialog above. */
body.archive-confirm-document-active{
  overflow-x:hidden;
  overflow-y:auto!important;
  overscroll-behavior-y:auto;
  background:var(--card);
}
body.archive-confirm-document-active .shell,
body.archive-confirm-document-active .ef-mobtop,
body.archive-confirm-document-active .ef-backdrop{display:none!important}
body.archive-confirm-document-active dialog.archive-confirm-overlay[data-ef-dialog-document-flow]{
  position:static;
  inset:auto;
  z-index:auto;
  display:block!important;
  width:100%;
  min-height:100vh;
  min-height:100dvh;
  height:auto;
  max-height:none;
  margin:0;
  padding:0;
  overflow:visible;
  background:transparent;
  color:inherit;
}
body.archive-confirm-document-active dialog.archive-confirm-overlay[data-ef-dialog-document-flow] .archive-confirm-sheet{
  position:static;
  display:grid;
  grid-template-rows:auto minmax(0,1fr) auto;
  width:min(100%,860px);
  min-height:100vh;
  min-height:100dvh;
  height:auto;
  max-width:860px;
  max-height:none;
  margin:0 auto;
  padding:0;
  border:0;
  border-radius:0;
  box-shadow:none;
  overflow:visible;
  animation:none!important;
  transform:none!important;
  background:var(--card);
}
body.archive-confirm-document-active .archive-confirm-safe-boundary{
  position:sticky;
  top:0;
  z-index:6;
  display:block;
  width:100%;
  height:max(24px,env(safe-area-inset-top));
  background:var(--card);
  pointer-events:none;
  touch-action:none;
  user-select:none;
}
body.archive-confirm-document-active .archive-confirm-body{
  min-height:0;
  padding:0;
  overflow:visible;
  overscroll-behavior:auto;
  -webkit-overflow-scrolling:auto;
  touch-action:auto;
}
body.archive-confirm-document-active .archive-confirm-main{display:block;max-width:700px;margin:0 auto}
body.archive-confirm-document-active .archive-confirm-head{
  display:grid;
  grid-template-columns:minmax(0,1fr) 48px;
  grid-template-areas:"title close" "icon icon";
  align-items:center;
  gap:12px;
  padding:12px max(16px,env(safe-area-inset-right)) 0 max(16px,env(safe-area-inset-left));
  border-bottom:1px solid var(--border);
  background:var(--card);
}
body.archive-confirm-document-active .archive-confirm-head .confirm-title{
  grid-area:title;
  margin:0;
  text-align:left!important;
  font-size:18px;
}
body.archive-confirm-document-active .archive-confirm-route-close{
  grid-area:close;
  display:inline-flex;
  align-items:center;
  justify-content:center;
  width:48px;
  height:48px;
  min-width:48px;
  min-height:48px;
  padding:0;
  justify-self:end;
  border:1px solid var(--border);
  border-radius:10px;
  background:var(--card);
  color:var(--text);
  cursor:pointer;
  touch-action:manipulation;
}
body.archive-confirm-document-active .archive-confirm-icon{
  grid-area:icon;
  justify-self:start;
  margin:8px 0 0;
}
body.archive-confirm-document-active .archive-confirm-intro,
body.archive-confirm-document-active .archive-confirm-field{
  margin-left:max(20px,env(safe-area-inset-left));
  margin-right:max(20px,env(safe-area-inset-right));
}
body.archive-confirm-document-active .archive-confirm-intro{
  margin-top:14px;
  margin-bottom:18px;
  text-align:left!important;
  font-size:14px;
}
body.archive-confirm-document-active .archive-confirm-field textarea{
  min-height:96px;
  height:auto;
  font-size:16px!important;
  resize:vertical;
}
body.archive-confirm-document-active .archive-confirm-actions{
  position:static;
  display:grid;
  grid-template-columns:repeat(2,minmax(0,1fr));
  gap:10px;
  margin-top:24px;
  padding:12px max(16px,env(safe-area-inset-right)) max(18px,env(safe-area-inset-bottom)) max(16px,env(safe-area-inset-left));
  border-top:1px solid var(--border);
  background:var(--card);
}
body.archive-confirm-document-active .archive-confirm-actions > button{min-height:48px}
@media(max-width:560px){
  body.archive-confirm-document-active .archive-confirm-safe-boundary{height:max(47px,env(safe-area-inset-top))}
}
@media(hover:none) and (pointer:coarse) and (orientation:landscape) and (max-height:500px){
  body.archive-confirm-document-active .archive-confirm-safe-boundary{height:max(23px,env(safe-area-inset-top))}
  body.archive-confirm-document-active .archive-confirm-head{padding-top:6px}
  body.archive-confirm-document-active .archive-confirm-intro{margin-top:10px;margin-bottom:10px}
  body.archive-confirm-document-active .archive-confirm-field textarea{min-height:72px;height:72px}
  body.archive-confirm-document-active .archive-confirm-actions{margin-top:14px;padding-top:7px;padding-bottom:max(12px,env(safe-area-inset-bottom))}
}
.archive-confirm-overlay .archive-confirm-actions > button{
  width:100%;
  min-height:44px;
  justify-content:center;
  touch-action:manipulation;
}
@media (max-width:1024px), (hover:none) and (pointer:coarse){
  .archive-confirm-overlay{
    align-items:flex-end;
    justify-content:center;
    padding:max(12px,env(safe-area-inset-top)) max(12px,env(safe-area-inset-right)) max(12px,env(safe-area-inset-bottom)) max(12px,env(safe-area-inset-left));
  }
  .archive-confirm-overlay .archive-confirm-sheet{
    max-width:560px;
    max-height:calc(100dvh - 24px - env(safe-area-inset-top) - env(safe-area-inset-bottom));
    border-radius:20px 20px 12px 12px;
    animation:none;
    transform:none;
    will-change:auto;
  }
  .archive-confirm-overlay .archive-confirm-actions{
    padding:16px 24px max(12px,env(safe-area-inset-bottom));
  }
  .archive-confirm-overlay .archive-confirm-sheet .archive-confirm-actions > .btn,
  .archive-confirm-overlay .archive-confirm-sheet .archive-confirm-actions > .btn-delete{
    min-height:48px;
  }
}
@media (max-width:1024px) and (max-height:560px) and (orientation:landscape){
  .archive-confirm-overlay{
    padding:8px max(12px,env(safe-area-inset-right)) max(8px,env(safe-area-inset-bottom)) max(12px,env(safe-area-inset-left));
  }
  .archive-confirm-overlay .archive-confirm-sheet{
    width:min(100%,720px);
    max-width:720px;
    max-height:calc(100dvh - 8px - env(safe-area-inset-top) - env(safe-area-inset-bottom));
    border-radius:18px 18px 10px 10px;
  }
  .archive-confirm-overlay .archive-confirm-body{
    padding:14px 18px 8px;
  }
  .archive-confirm-overlay .archive-confirm-main{
    display:grid;
    grid-template-columns:210px minmax(0,1fr);
    grid-template-areas:"head field" "intro field";
    gap:7px 18px;
    align-items:start;
  }
  .archive-confirm-overlay .archive-confirm-head{ grid-area:head; }
  .archive-confirm-overlay .archive-confirm-intro{
    grid-area:intro;
    text-align:left !important;
    margin:0;
    font-size:12px;
  }
  .archive-confirm-overlay .archive-confirm-field{ grid-area:field; }
  .archive-confirm-overlay .archive-confirm-icon{
    width:40px;
    height:40px;
    margin-bottom:7px;
  }
  .archive-confirm-overlay .archive-confirm-head .confirm-title{
    text-align:left !important;
    font-size:17px;
  }
  .archive-confirm-overlay .archive-confirm-field textarea{
    min-height:62px;
    height:62px;
    resize:none;
  }
  .archive-confirm-overlay .archive-confirm-actions{
    padding:8px 18px max(10px,env(safe-area-inset-bottom));
  }
}

/* The older native-sheet media query above remains for non-document-flow
   dialogs. Once touch document flow is selected, it must never regain the
   landscape grid/sheet owner through a later cascade rule. */
body.archive-confirm-document-active dialog.archive-confirm-overlay[data-ef-dialog-document-flow] .archive-confirm-main{display:block}
body.archive-confirm-document-active dialog.archive-confirm-overlay[data-ef-dialog-document-flow] .archive-confirm-head{
  display:grid;
  grid-template-columns:minmax(0,1fr) 48px;
  grid-template-areas:"title close" "icon icon";
  align-items:center;
}
body.archive-confirm-document-active dialog.archive-confirm-overlay[data-ef-dialog-document-flow] .archive-confirm-intro{
  text-align:left!important;
  font-size:14px;
}
body.archive-confirm-document-active dialog.archive-confirm-overlay[data-ef-dialog-document-flow] .archive-confirm-icon{
  width:44px;
  height:44px;
  margin:8px 0 0;
}
body.archive-confirm-document-active dialog.archive-confirm-overlay[data-ef-dialog-document-flow] .archive-confirm-field textarea{
  min-height:96px;
  height:auto;
  resize:vertical;
}
body.archive-confirm-document-active dialog.archive-confirm-overlay[data-ef-dialog-document-flow] .archive-confirm-actions{
  margin-top:24px;
  padding:12px max(16px,env(safe-area-inset-right)) max(18px,env(safe-area-inset-bottom)) max(16px,env(safe-area-inset-left));
}
@media(hover:none) and (pointer:coarse) and (orientation:landscape) and (max-height:500px){
  body.archive-confirm-document-active dialog.archive-confirm-overlay[data-ef-dialog-document-flow] .archive-confirm-field textarea{min-height:72px;height:72px}
  body.archive-confirm-document-active dialog.archive-confirm-overlay[data-ef-dialog-document-flow] .archive-confirm-actions{margin-top:14px;padding-top:7px;padding-bottom:max(12px,env(safe-area-inset-bottom))}
}

/* v982: compact visual composition for the exact Students/Teachers Archive
   document-flow cohort. Keep the v981 page/DOM owner and first-close lifecycle,
   but group icon/title/X and keep consequence, reason and actions consecutive.
   The document remains the only scroll owner; no fixed/sticky action footer. */
body.archive-confirm-document-active dialog.archive-confirm-overlay[data-ef-dialog-document-flow]{
  box-sizing:border-box;
  padding:max(18px,env(safe-area-inset-top)) max(16px,env(safe-area-inset-right)) max(22px,env(safe-area-inset-bottom)) max(16px,env(safe-area-inset-left));
  background:var(--card);
}
body.archive-confirm-document-active dialog.archive-confirm-overlay[data-ef-dialog-document-flow] .archive-confirm-sheet{
  display:block;
  width:min(100%,680px);
  min-height:0;
  margin:18px auto 0;
  border:1px solid var(--border);
  border-radius:18px;
  box-shadow:0 8px 24px rgba(23,34,53,.09);
  overflow:hidden;
}
body.archive-confirm-document-active dialog.archive-confirm-overlay[data-ef-dialog-document-flow] .archive-confirm-safe-boundary{display:none}
body.archive-confirm-document-active dialog.archive-confirm-overlay[data-ef-dialog-document-flow] .archive-confirm-body{padding:0;overflow:visible}
body.archive-confirm-document-active dialog.archive-confirm-overlay[data-ef-dialog-document-flow] .archive-confirm-main{max-width:none;margin:0}
body.archive-confirm-document-active dialog.archive-confirm-overlay[data-ef-dialog-document-flow] .archive-confirm-head{
  grid-template-columns:44px minmax(0,1fr) 48px;
  grid-template-areas:"icon title close";
  gap:12px;
  padding:18px 18px 14px;
  border-bottom:0;
}
body.archive-confirm-document-active dialog.archive-confirm-overlay[data-ef-dialog-document-flow] .archive-confirm-head .confirm-title{
  font-size:18px;
  line-height:1.35;
}
body.archive-confirm-document-active dialog.archive-confirm-overlay[data-ef-dialog-document-flow] .archive-confirm-icon{
  justify-self:start;
  margin:0;
}
body.archive-confirm-document-active dialog.archive-confirm-overlay[data-ef-dialog-document-flow] .archive-confirm-intro,
body.archive-confirm-document-active dialog.archive-confirm-overlay[data-ef-dialog-document-flow] .archive-confirm-field{
  margin-left:18px;
  margin-right:18px;
}
body.archive-confirm-document-active dialog.archive-confirm-overlay[data-ef-dialog-document-flow] .archive-confirm-intro{
  margin-top:0;
  margin-bottom:16px;
  padding-top:14px;
  border-top:1px solid var(--border);
}
body.archive-confirm-document-active dialog.archive-confirm-overlay[data-ef-dialog-document-flow] .archive-confirm-actions{
  position:static;
  margin:14px 18px 18px;
  padding:0;
  border-top:0;
}
@media(hover:none) and (pointer:coarse) and (orientation:landscape) and (max-height:500px){
  body.archive-confirm-document-active dialog.archive-confirm-overlay[data-ef-dialog-document-flow]{
    padding:max(8px,env(safe-area-inset-top)) max(12px,env(safe-area-inset-right)) max(10px,env(safe-area-inset-bottom)) max(12px,env(safe-area-inset-left));
  }
  body.archive-confirm-document-active dialog.archive-confirm-overlay[data-ef-dialog-document-flow] .archive-confirm-sheet{
    width:min(100%,640px);
    max-width:640px;
    margin-top:4px;
  }
  body.archive-confirm-document-active dialog.archive-confirm-overlay[data-ef-dialog-document-flow] .archive-confirm-main{
    display:block;
  }
  body.archive-confirm-document-active dialog.archive-confirm-overlay[data-ef-dialog-document-flow] .archive-confirm-head{
    padding:10px 14px 8px;
  }
  body.archive-confirm-document-active dialog.archive-confirm-overlay[data-ef-dialog-document-flow] .archive-confirm-intro{
    margin:0 14px 10px;
    padding-top:10px;
  }
  body.archive-confirm-document-active dialog.archive-confirm-overlay[data-ef-dialog-document-flow] .archive-confirm-field{
    margin:0 14px;
  }
  body.archive-confirm-document-active dialog.archive-confirm-overlay[data-ef-dialog-document-flow] .archive-confirm-actions{
    margin:8px 14px 10px;
  }
}

/* ---------- ปุ่มลบ/ไอคอนอันตราย: ทันสมัย + hover แดงนุ่ม (ใช้ร่วมทุกหน้า) ---------- */
.icon-btn.danger{ transition:all .12s; }
.icon-btn.danger:hover{ background:#FCEBEB; color:#A32D2D; border-color:#F0997B; }
.btn-delete{ border-radius:10px; transition:background .15s, box-shadow .15s, transform .05s, border-color .15s; }
.btn-delete:active{ transform:translateY(1px); }
/* ฐานปุ่มลบ (เส้นขอบแดง พื้นการ์ด) ยกจากมาตรฐาน · GLOBAL (spec-shared-ui-central รอบ C · ปรับ compat 29/7)
   ครอบปุ่มลบในหน้า+modal อัตโนมัติ · หน้าที่เก็บ "พื้นแดงทึบ" (documents/ledger) override ด้วย html .btn-delete (0,1,1 > 0,1,0) · ปุ่มยืนยันลบใช้ inline style ทับเป็นสีทึบเหมือนเดิม */
.btn-delete{
  display:inline-flex; align-items:center; gap:6px;
  padding:8px 14px; font-size:13px; font-weight:500;
  border:1px solid #E24B4A; background:var(--card); color:#A32D2D;
  cursor:pointer; font-family:inherit;
}
.btn-delete:hover{ background:#FCEBEB; }
.btn-delete:disabled{ opacity:0.45; cursor:not-allowed; background:var(--card); }
.btn-delete:disabled:hover{ background:var(--card); }

/* ---------- หัวข้อกลุ่มในเมนู (จัดเมนูยาว ๆ ให้อ่านง่าย) ---------- */
.nav-section{
  font-size:10.5px; font-weight:600; letter-spacing:.06em; text-transform:uppercase;
  color:rgba(255,255,255,.32); padding:14px 12px 5px; user-select:none;
}
.nav-section:first-child{ padding-top:4px; }

/* ---------- โฟกัสคีย์บอร์ด (ปุ่ม/ลิงก์/เมนู/การ์ด) ใช้เส้นแบรนด์ ---------- */
/* ⛔ ห้ามใส่ input/select/textarea/combobox ที่นี่ — ช่องกรอกมีวงแหวน :focus ครอบทั้งเมาส์+คีย์บอร์ดแล้ว (ถ้าใส่ = เส้นแข็งซ้อนวงแหวน + มุมเด้ง 9→6px ตอนคลิก · verify documents 2026-08-11) */
a:focus-visible, button:focus-visible, [tabindex]:focus-visible, .nav-item:focus-visible,
.btn:focus-visible, .icon-btn:focus-visible, .home-card:focus-visible{
  outline:2px solid var(--accent); outline-offset:2px;
}
/* #594: preserve existing focus geometry outside the approved two-route pilot. */
:where(body:not(.students-v11):not(.teachers-v12):not([data-focus673])) a:focus-visible,
:where(body:not(.students-v11):not(.teachers-v12):not([data-focus673])) button:focus-visible,
:where(body:not(.students-v11):not(.teachers-v12):not([data-focus673])) [tabindex]:focus-visible,
:where(body:not(.students-v11):not(.teachers-v12):not([data-focus673])) .nav-item:focus-visible,
:where(body:not(.students-v11):not(.teachers-v12):not([data-focus673])) .btn:focus-visible,
:where(body:not(.students-v11):not(.teachers-v12):not([data-focus673])) .icon-btn:focus-visible,
:where(body:not(.students-v11):not(.teachers-v12):not([data-focus673])) .home-card:focus-visible{border-radius:6px}
.ef-skip-link{position:fixed;top:10px;left:10px;z-index:10050;transform:translateY(-160%);padding:10px 14px;border-radius:10px;background:var(--ink);color:#fff;font-size:14px;font-weight:600;text-decoration:none;box-shadow:var(--shadow-md)}
.ef-skip-link:focus{transform:translateY(0)}

/* ============================================================
   POLISH — ยกระดับให้ดูโปรขึ้น โดยไม่แตะ layout (โหลดหลังสุด → ครอบทุกหน้า)
   เงาอุ่นเข้าธีมส้ม (เดิมเงาน้ำเงิน-เทาเย็น) + hover การ์ดยกนุ่ม + stat-card มีขอบสี
   ============================================================ */
:root{
  --shadow-sm:0 1px 3px rgba(18,35,61,.06), 0 1px 2px rgba(18,35,61,.05);
  --shadow-md:0 6px 18px rgba(18,35,61,.09);
  --shadow-lg:0 16px 38px rgba(18,35,61,.14);
  --accent-grad:linear-gradient(135deg,#F0863F,#CF5E27);
}

/* การ์ดทั่วไป: เงาอุ่นนุ่ม (ลอยขึ้นเล็กน้อย ดูพรีเมียม) */
.stat-card, .detail-card, .home-card, .table-card, .doc-card, .eval-card,
.course-card, .lesson-card, .gal-sess, .room-hcard, .recurring-box{
  box-shadow:var(--shadow-sm);
}
/* การ์ดที่กดได้: ยกขึ้นนุ่ม ๆ ตอน hover + ขอบส้มจาง */
.home-card, .doc-card, .course-card, .lesson-card, .room-hcard, .eval-card{
  transition:box-shadow .18s ease, transform .12s ease, border-color .15s ease;
}
.home-card:hover, .doc-card:hover, .course-card:hover, .lesson-card:hover,
.room-hcard:hover, .eval-card:hover{
  box-shadow:var(--shadow-md); transform:translateY(-2px); border-color:var(--accent-light);
}
.home-card:active, .doc-card:active, .course-card:active, .lesson-card:active, .room-hcard:active{
  transform:translateY(0);
}

/* stat-card: แถบสีแบรนด์บางด้านซ้าย (ดูเป็นระบบ ทันสมัย) */
.stat-card, .detail-card{ position:relative; overflow:hidden; }
.stat-card::before, .detail-card::before{
  content:""; position:absolute; left:0; top:0; bottom:0; width:3px;
  background:var(--accent-grad); opacity:.9;
}
/* การ์ดสถิติพื้นเข้ม (lead) ใช้แถบขาวจางแทน เพื่อไม่จมพื้น */
.stat-card.lead::before{ background:rgba(255,255,255,.5); }

/* ตัวเลขสถิติ/เงิน: เรียงหลักสวย (tabular) ไม่ขยับตอนเปลี่ยนเลข */
.stat-value, .detail-stat-value, .stat-number, .stat-num, .amount{
  font-variant-numeric:tabular-nums; letter-spacing:-.01em;
}

/* ปุ่มหลัก + เมนูที่เลือก: เงาส้มอุ่นขึ้นนิด ให้เด่นแบบพรีเมียม */
.btn-primary{ box-shadow:0 4px 14px rgba(196,81,28,.26); }
@media(hover:hover) and (pointer:fine){.btn-primary:hover{ box-shadow:0 6px 18px rgba(168,61,20,.30); }}
.nav-item.active{ box-shadow:0 2px 10px rgba(196,81,28,.28); }

/* หัวข้อหน้า: คมขึ้นนิด */
.page-title{ letter-spacing:-.01em; }
/* empty state: นุ่มตา */
.empty svg{ opacity:.7; }

/* ============================================================
   RESPONSIVE กลาง — iPad/มือถือ (โหลดท้ายสุด → ครอบทุกหน้าที่มี .main/.shell)
   ปรับเฉพาะ display: ลด padding เนื้อหาบนแท็บเล็ต + ปุ่มแตะง่ายขึ้นบนจอสัมผัส
   ============================================================ */
/* iPad: เดิมหลายหน้า .main padding 32px 40px กว้างไป → เนื้อหาบีบ */
@media (max-width:1024px){
  .main{ padding:26px 24px; }
}
/* มือถือ: ให้เนื้อหาชิดขอบพอดี (เติมให้หน้าที่ยังไม่มีกฎนี้ เช่น retention/my-income/teaching-log) */
@media (max-width:560px){
  .main{ padding:22px 16px; }
}

/* ============================================================
   SKELETON กลาง (loading-until-synced) — ใช้ซ้ำทุกหน้าที่ดึงข้อมูลจากคลาวด์
   หลักการ: ยังไม่ firstSyncDone() → โชว์โครงจาง ห้ามโชว์แคชเก่า (หลอกผู้ใช้)
   namespace .ef-skel-* กันชนกับ .att-skel-* ของหน้าเช็คชื่อ
   ============================================================ */
@keyframes efSkel{ 0%{background-position:100% 50%} 100%{background-position:0 50%} }
.ef-skel-card{ background:var(--card); border:1px solid var(--border); border-radius:14px; padding:18px; margin-bottom:14px; box-shadow:var(--shadow-sm); }
.ef-skel-line{ height:13px; border-radius:7px; background:linear-gradient(90deg,#EEF1F5 25%,#E3E8EF 37%,#EEF1F5 63%); background-size:400% 100%; animation:efSkel 1.3s ease infinite; }
.ef-skel-row{ display:flex; align-items:center; gap:12px; margin-top:16px; }
.ef-skel-dot{ width:34px; height:34px; border-radius:50%; flex-shrink:0; background:linear-gradient(90deg,#EEF1F5 25%,#E3E8EF 37%,#EEF1F5 63%); background-size:400% 100%; animation:efSkel 1.3s ease infinite; }
.ef-loading-note{ text-align:center; color:var(--text-soft); font-size:13px; padding:10px 0 4px; }
@media (prefers-reduced-motion:reduce){ .ef-skel-line,.ef-skel-dot{ animation:none; } }

/* ============================================================
   LOCAL-FIRST — ป้าย "กำลังอัพเดต" (มาตรฐานเว็บ: โชว์แคชทันที + sync เบื้องหลัง)
   ป้ายเล็กมุมล่าง ไม่บล็อกจอ · หายเองเมื่อ sync รอบแรกเสร็จ
   ============================================================ */
.ef-sync-pill{position:fixed;bottom:16px;left:50%;transform:translateX(-50%);z-index:8000;
  display:flex;align-items:center;gap:8px;background:var(--ink,#1B2230);color:#fff;
  font-family:var(--font,sans-serif);font-size:12.5px;font-weight:500;padding:8px 15px;border-radius:999px;
  box-shadow:0 4px 16px rgba(0,0,0,.22);opacity:.96;transition:opacity .35s ease,transform .35s ease}
.ef-sync-pill.done{opacity:0;transform:translateX(-50%) translateY(10px);pointer-events:none}
.ef-sync-spin{width:13px;height:13px;border:2px solid rgba(255,255,255,.32);border-top-color:#fff;border-radius:50%;animation:efSyncSpin .7s linear infinite;flex-shrink:0}
@keyframes efSyncSpin{to{transform:rotate(360deg)}}
@media (prefers-reduced-motion:reduce){ .ef-sync-spin{animation:none} }
/* จอสัมผัส (iPad/มือถือ): ขยายพื้นที่แตะปุ่มไอคอน/เลขหน้า ให้ถึง ~40px (เดิม 30–32px กดยาก) */
html.ef-touch .icon-btn,
html.ef-touch .page-btn{ min-width:40px; min-height:40px; }

/* ============================================================
   ป้ายสถานะ (status badge) — แบบ "Minimal Dot" (เจ้าของเลือก 2026-07-24)
   ไม่มีพื้น/ขอบ มีแค่จุดสี + ตัวหนังสือ → ตารางโล่ง สบายตา ชื่อนักเรียนเด่น
   ใช้ "สีของธีม" ล้วน — จุด = สีสด, ตัวหนังสือ = เฉดเข้มขึ้น (คอนทราสต์ผ่าน WCAG AA):
     เขียวใบไม้ = กำลังเรียน/ชำระแล้ว · ส้มสิงโต = รอ/พักงาน · แดง = ค้างชำระ · สเลท = จำหน่าย/ยกเลิก
   โหลดท้ายสุด → ครอบทุกหน้าที่ใช้คลาสนี้ (students/finance/staff/rooms/lessons/courses/attendance)
   ============================================================ */
.status-badge{
  display:inline-flex; align-items:center;   /* ⭐ v613: เดิมไม่มี display → span เป็น inline · gap+จุดไม่ทำงาน = จุดสถานะ Minimal Dot หายทั้งหน้า students(ตั้งแต่ v567)+staff(v593) ~1 ปี · finance/attendance/rooms รอดเพราะประกาศ display เอง (ค่าเท่ากัน ไม่พัง) */
  gap:8px; padding:0; border:0; border-radius:0; background:none;
  font-weight:600; letter-spacing:.01em;
}
.status-badge::before{ content:""; width:8px; height:8px; border-radius:50%; flex:0 0 auto; }   /* ⭐ v613: เดิมไม่มี content → pseudo-element ไม่เกิด = ไม่มีจุด (finance/rooms/attendance ประกาศ content เองเลยมีจุด) */

.status-active, .status-badge.pay-paid            { background:none; color:var(--success-strong); }
.status-active::before, .status-badge.pay-paid::before   { background:var(--success); }

.status-paused                                    { background:none; color:var(--accent-text); }
.status-paused::before                            { background:var(--accent); }

.status-badge.pay-unpaid                          { background:none; color:var(--danger); }   /* ค้างชำระ = แดงธีม (เร่งด่วนกว่า "รอ") */
.status-badge.pay-unpaid::before                  { background:var(--danger); }

.status-archived, .status-cancelled,
.status-badge.pay-void                            { background:none; color:var(--text-soft); }
.status-archived::before, .status-cancelled::before,
.status-badge.pay-void::before                    { background:var(--text-faint); }

/* ============================================================
   v781 · explicit orphan-Auth reclaim (shared Super Admin modal)
   The flow is injected by data.js and shared by teachers/school pages.
   ============================================================ */
.ef-reclaim-overlay{z-index:120}
body .modal.ef-reclaim-modal{max-width:720px;border-radius:18px;overflow:hidden}
.ef-reclaim-head-main{display:flex;gap:13px;min-width:0}
.ef-reclaim-icon{width:42px;height:42px;flex:0 0 42px;border-radius:12px;background:var(--warn-light);color:var(--warn-strong);display:flex;align-items:center;justify-content:center;font-size:20px;font-weight:800}
.ef-reclaim-title{margin:0;font-size:18px;font-weight:700;color:var(--text)}
.ef-reclaim-sub{margin:4px 0 0;color:var(--text-soft);font-size:13px}
.ef-reclaim-summary{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-bottom:16px}
.ef-reclaim-summary-item{background:var(--bg);border:1px solid var(--border);border-radius:10px;padding:10px 12px;min-width:0}
.ef-reclaim-summary-item span{display:block;color:var(--text-soft);font-size:11px}
.ef-reclaim-summary-item strong{display:block;margin-top:3px;color:var(--text);font-size:13px;overflow-wrap:anywhere}
.ef-reclaim-notice{margin-bottom:15px;padding:10px 12px;border:1px solid var(--warn);border-radius:10px;background:var(--warn-light);color:var(--warn-strong);font-size:12px}
.ef-reclaim-grid{display:grid;grid-template-columns:1fr 1fr;gap:13px}
.ef-reclaim-field{min-width:0}
.ef-reclaim-field.full{grid-column:1/-1}
.ef-reclaim-field label{display:block;margin-bottom:6px;color:var(--text);font-size:12px;font-weight:700}
.ef-reclaim-field input,.ef-reclaim-field textarea{box-sizing:border-box;width:100%;min-height:44px;border:1px solid var(--border);border-radius:9px;background:var(--card);color:var(--text);font:inherit;padding:10px 12px;outline:none}
.ef-reclaim-field textarea{min-height:74px;resize:vertical}
.ef-reclaim-field input:focus,.ef-reclaim-field textarea:focus{border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-light)}
.ef-reclaim-check{display:flex;align-items:flex-start;gap:9px;padding:11px;border-radius:9px;background:var(--bg);color:var(--text);font-size:12px;cursor:pointer}
.ef-reclaim-check input{width:18px;height:18px;min-height:0;margin:0;accent-color:var(--accent);flex:0 0 18px}
.ef-reclaim-error{display:none;margin-top:12px;padding:9px 11px;border-radius:9px;background:var(--danger-light);color:var(--danger-strong);font-size:12px}
.ef-reclaim-error.show{display:block}
.ef-reclaim-audit-note{margin-right:auto;align-self:center;color:var(--text-soft);font-size:11px}
.ef-reclaim-modal .modal-footer{align-items:center}
.ef-reclaim-modal .modal-footer .btn{min-height:44px}
@media(max-width:900px){
  body .modal.ef-reclaim-modal{max-width:640px!important}
  .ef-reclaim-grid{grid-template-columns:1fr}
  .ef-reclaim-field.full{grid-column:auto}
  .ef-reclaim-modal .modal-footer{flex-wrap:wrap}
  .ef-reclaim-audit-note{width:100%;margin:0 0 3px}
}
@media(max-width:560px){
  .ef-reclaim-overlay{padding:0;align-items:flex-end}
  body .modal.ef-reclaim-modal{max-width:none!important;max-height:92vh;border-radius:18px 18px 0 0}
  .ef-reclaim-modal .modal-head{padding:16px}
  .ef-reclaim-modal .modal-body{padding:14px 16px}
  .ef-reclaim-summary{grid-template-columns:1fr}
  .ef-reclaim-summary-item:nth-child(n+3){display:none}
  .ef-reclaim-modal .modal-footer{padding:12px 16px 16px;display:flex;flex-direction:column-reverse;align-items:stretch}
  .ef-reclaim-modal .modal-footer .btn{width:100%;min-height:46px}
  .ef-reclaim-audit-note{text-align:center;order:3}
}
/* v783 — explicit device-trust logout boundary (shared by every protected page) */
.ef-logout-overlay{position:fixed;inset:0;z-index:100000;display:flex;align-items:center;justify-content:center;padding:24px;background:rgba(11,24,43,.58);backdrop-filter:blur(3px);-webkit-backdrop-filter:blur(3px);font-family:var(--font);box-sizing:border-box}
.ef-logout-modal{width:min(100%,520px);max-height:calc(100dvh - 48px);overflow:auto;background:#fff;border:1px solid var(--border);border-radius:18px;box-shadow:0 24px 64px rgba(15,31,54,.28);color:var(--text)}
.ef-logout-head{padding:22px 24px 17px;border-bottom:1px solid var(--border)}
.ef-logout-head h3{margin:0;font-size:20px;line-height:1.35;font-weight:800;color:var(--text)}
.ef-logout-head p{margin:5px 0 0;font-size:13px;line-height:1.55;color:var(--text-soft)}
.ef-logout-body{padding:18px 24px}
.ef-logout-notice,.ef-logout-warning{display:flex;flex-direction:column;gap:4px;padding:14px 16px;border-radius:12px;background:#f6f8fb;border:1px solid var(--border);font-size:13px;line-height:1.55}
.ef-logout-warning{background:#fff4dc;border-color:#f2d8a0;color:#80500b}
.ef-logout-notice b,.ef-logout-warning b{font-size:13.5px}.ef-logout-notice span,.ef-logout-warning span{color:var(--text-soft)}
.ef-logout-list{display:grid;gap:8px;margin:15px 0 0;padding:0;list-style:none;font-size:13px;color:var(--text-soft)}
.ef-logout-list li:before{content:"✓";display:inline-grid;place-items:center;width:19px;height:19px;margin-right:8px;border-radius:6px;background:#e7f5ee;color:#087a50;font-weight:800}
.ef-logout-foot{display:flex;justify-content:flex-end;gap:10px;padding:16px 24px 22px;border-top:1px solid var(--border)}
.ef-logout-foot button{min-height:44px;padding:0 17px;border-radius:11px;font:inherit;font-size:13.5px;font-weight:700;cursor:pointer}.ef-logout-foot button:disabled{cursor:wait;opacity:.65}
.ef-btn-secondary{background:#fff;border:1px solid var(--border);color:var(--text)}.ef-btn-primary{background:var(--action-primary);border:1px solid var(--action-primary);color:#fff}.ef-btn-danger{background:#c7472c;border:1px solid #c7472c;color:#fff}
.ef-logout-link{display:block;margin:14px auto 0;padding:3px 5px;border:0;background:none;color:#b63c25;text-decoration:underline;font:inherit;font-size:12.5px;cursor:pointer}
.ef-logout-status{min-height:20px;margin-top:10px;text-align:center;color:var(--text-soft);font-size:12px;line-height:1.5}
@media(max-width:600px){.ef-logout-overlay{padding:16px}.ef-logout-modal{width:100%;max-width:360px;max-height:calc(100dvh - 32px);border-radius:16px}.ef-logout-head{padding:19px 18px 15px}.ef-logout-head h3{font-size:18px}.ef-logout-body{padding:16px 18px}.ef-logout-foot{padding:14px 18px 18px;flex-direction:column-reverse}.ef-logout-foot button{width:100%}}

/* UX-02 v904 — shared page-local interaction-state primitive */
.ef-read-compact596{min-height:calc(100svh - 180px);display:flex;align-items:center;justify-content:center;gap:12px;padding:24px;color:var(--text-soft);font-size:14px;line-height:22px}
.ef-read-host[hidden]{display:none!important}
.ef-read-strip{display:flex;align-items:flex-start;justify-content:space-between;gap:14px;margin:0 0 14px;padding:12px 14px;border:1px solid var(--border);border-radius:13px;background:var(--card);font-size:13px;line-height:1.5}
.ef-read-strip strong,.ef-read-strip small{display:block}.ef-read-strip small{margin-top:2px;color:var(--text-soft)}
.ef-read-strip.refresh{border-color:#bcd5ec;background:#eef6fd;color:#144d7e}.ef-read-strip.offline{border-color:#e7c478;background:#fff7df;color:#6e4704}
.ef-read-panel{min-height:310px;display:grid;place-items:center;padding:28px;border:1px solid var(--border);border-radius:16px;background:var(--card);text-align:center}
.ef-read-panel.error{border-color:#efbeb4;background:#fffafa}.ef-read-panel.account{border-color:#12233d;background:#12233d;color:#fff}
.ef-read-inner{width:min(100%,450px)}.ef-read-icon{width:54px;height:54px;display:grid;place-items:center;margin:0 auto 14px;border-radius:16px;background:var(--muted);color:var(--text-soft);font-size:26px;font-weight:800}
.ef-read-panel.error .ef-read-icon{background:var(--danger-light);color:var(--danger-strong)}.ef-read-panel.account .ef-read-icon{background:rgba(255,255,255,.12);color:#fff}
.ef-read-panel h2{margin:0 0 7px;font-size:20px}.ef-read-panel p{margin:0 auto;color:var(--text-soft);line-height:1.65}.ef-read-panel.account p{color:#c5d2e1}
.ef-read-retry{min-height:44px;margin-top:16px;padding:0 15px;border:1px solid var(--border);border-radius:11px;background:var(--card);color:var(--text);font:inherit;font-weight:700;cursor:pointer}.ef-read-retry:disabled{cursor:wait;opacity:.6}.ef-read-retry:focus-visible{outline:3px solid #2f78b7;outline-offset:2px}
.ef-read-spinner{width:20px;height:20px;display:inline-block;flex:0 0 20px;border:3px solid #bdd6ea;border-top-color:#2f78b7;border-radius:50%;animation:ef-read-spin .8s linear infinite}
.ef-read-skeleton{width:min(100%,420px);display:grid;gap:11px;margin:22px auto 0}.ef-read-skeleton span{display:block;height:14px;border-radius:999px;background:#e5ebf1}.ef-read-skeleton span:nth-child(2){width:78%}.ef-read-skeleton span:nth-child(3){width:55%}
@keyframes ef-read-spin{to{transform:rotate(360deg)}}
@media(prefers-reduced-motion:reduce){.ef-read-spinner{animation:none}}
@media(max-width:560px){.ef-read-strip{display:block}.ef-read-strip .ef-read-retry{width:100%}.ef-read-panel{min-height:360px;padding:24px 16px}}

/* #594 owner-approved focus pilot: one visual owner, not a second halo.
   Keep pointer-return/heading exceptions in the route styles. */
:is(.students-v11,.teachers-v12):where(:not([data-focus673])){--ef-focus-color:var(--accent-strong);--ef-focus-ring:2px;--ef-focus-gap:2px;--ef-focus-soft:rgba(207,94,39,.12);--ef-focus-error-soft:rgba(192,73,44,.15)}
:is(.students-v11,.teachers-v12):where(:not([data-focus673])) :is(input,select,textarea):focus{outline:none;border-color:var(--ef-focus-color);box-shadow:0 0 0 2px var(--ef-focus-soft)}
:is(.students-v11,.teachers-v12):where(:not([data-focus673])) :is(input,select,textarea):focus-visible{outline:var(--ef-focus-ring) solid var(--ef-focus-color);outline-offset:var(--ef-focus-gap);box-shadow:none;border-color:var(--border)}
:is(.students-v11,.teachers-v12):where(:not([data-focus673])) :is(a,button,[tabindex],.btn,.icon-btn,.sort-head,.ef-filter-option,.ef-history-disclosure,.upload-circle,.result-comment-toggle,.parent-balance-retry,.ef-read-retry):focus-visible{outline:var(--ef-focus-ring) solid var(--ef-focus-color);outline-offset:var(--ef-focus-gap)}
:is(.students-v11,.teachers-v12):where(:not([data-focus673])) .search:focus-within{border-color:var(--ef-focus-color);box-shadow:0 0 0 2px var(--ef-focus-soft)}
:is(.students-v11,.teachers-v12):where(:not([data-focus673])) .search:has(input:focus-visible){outline:2px solid var(--ef-focus-color);outline-offset:2px;box-shadow:none;border-color:var(--border)}
:is(.students-v11,.teachers-v12):where(:not([data-focus673])) .search input:focus{outline:none;box-shadow:none}
:is(.students-v11,.teachers-v12):where(:not([data-focus673])) .field.error :is(input,select,textarea):focus{border-color:var(--danger);box-shadow:0 0 0 2px var(--ef-focus-error-soft)}
:is(.students-v11,.teachers-v12):where(:not([data-focus673])) .field.error :is(input,select,textarea):focus-visible{outline-color:var(--danger);box-shadow:none;border-color:var(--border)}
/* Existing inline outline:none on both archive textareas must not hide Tab focus. */
:is(.students-v11,.teachers-v12):where(:not([data-focus673])) #archive-reason:focus-visible{outline:2px solid var(--ef-focus-color)!important;outline-offset:2px;box-shadow:none}
@media(forced-colors:active){:is(.students-v11,.teachers-v12):where(:not([data-focus673])) :focus-visible{outline-color:Highlight!important}}
/* #593 scoped Save tracking; approved #568 states, existing theme controls. */
.save593-tracking{display:grid;gap:12px;min-width:0;margin-block:12px}
.save593-success{display:flex;align-items:center;gap:10px;padding:12px 16px;margin:12px 0;background:var(--success-light);color:var(--success-strong);border-left:3px solid var(--success);border-radius:8px;font-size:14px;line-height:1.5}
.save593-success p{margin:0;overflow-wrap:anywhere}.save593-success svg{flex:none;width:20px;height:20px}
.save593-status{display:flex;flex-wrap:wrap;gap:10px;padding:16px;border:1px solid var(--border);border-radius:var(--radius,16px);background:var(--card);min-width:0}
.save593-status p{flex-basis:100%;margin:0;overflow-wrap:anywhere;font-size:14px}
.save593-status .save593-reference{color:var(--text-soft);font-size:12px}
.save593-status .btn{min-height:48px;max-width:100%;white-space:normal}
.save593-status input{flex-basis:100%;width:100%;min-width:0;min-height:48px;font:inherit;font-size:16px}
.save593-status label{flex-basis:100%;min-width:0;font-size:14px}
@media(max-width:560px){.save593-status .btn{flex-basis:100%;width:100%}}

/* #638 approved quiet control feedback; exact proposal637 follows. */
/* Proposal only. No layout, focus, selection, field appearance or data rules. */
:is(.students-v11,.teachers-v12,.staff619) :is(.search input,.field input:not([type="checkbox"]):not([type="file"]),.field select,.field textarea,.combobox input,.pw-input-field input,#archive-reason){-webkit-tap-highlight-color:transparent}
:is(.students-v11,.teachers-v12,.staff619) :is(.page-header,.detail-actions,#modal-overlay) :is(.btn,.modal-close,.pw-eye-btn,.pw-gen-btn),
:is(.students-v11,.teachers-v12,.staff619) .confirm-actions .btn:not(.btn-delete):not(.btn-primary){-webkit-tap-highlight-color:transparent}
/* CSS hover leak on the two confirmed Teacher field actions, touch only.
   Fine mouse hover retains the native page rules. */
@media(hover:none),(pointer:coarse){
 .teachers-v12 .pw-eye-btn:hover{background:transparent;color:var(--text-faint)}
 .teachers-v12 .pw-gen-btn:hover{background:var(--card)}
 /* Soft press fill, not a second focus ring. Selected/danger actions excluded. */
 :is(.students-v11,.teachers-v12,.staff619) :is(.page-header,.detail-actions,#modal-overlay,.confirm-actions) .btn:not(.btn-primary):not(.btn-delete):not(:disabled):not([aria-pressed="true"]):active,
 .teachers-v12 .pw-eye-btn:not(:disabled):active,
 .teachers-v12 .pw-gen-btn:not(:disabled):active{background:var(--accent-light)}
 .students-v11 #modal-overlay #student-modal-close:not(:disabled):active,
 .teachers-v12 #modal-overlay #teacher-modal-close:not(:disabled):active,
 .staff619 #modal-overlay #editor-close619:not(:disabled):active{background:var(--accent-light)}
 :is(.students-v11,.teachers-v12,.staff619) .page-header .btn-primary:not(:disabled):active,
 :is(.students-v11,.teachers-v12,.staff619) #modal-overlay #save-btn:not(:disabled):active{background:var(--action-primary-hover);border-color:var(--action-primary-hover)}
 :is(.students-v11,.teachers-v12,.staff619) :is(.page-header,.detail-actions,#modal-overlay) .btn:not(.btn-delete):active,
 :is(.students-v11,.teachers-v12,.staff619) .confirm-actions .btn:not(.btn-delete):not(.btn-primary):active{transform:none}
}

/* #640 approved navigation feedback; exact proposal639 follows. */
/* Native proposal639 only. No global reset; keyboard focus stays with its owner. */
:is(.students-v11,.teachers-v12,.staff619,.courses627) .back-link{
 -webkit-tap-highlight-color:transparent;border-radius:10px;
}
.courses627 .course-heading639{display:flex;align-items:center;gap:12px;margin:0 0 8px;min-height:44px}
.courses627 .course-title639{flex:1;min-width:0;font-size:18px;font-weight:600;overflow-wrap:anywhere}
.courses627 .course-heading639 .course-open627{flex:0 0 44px;width:44px;height:44px;margin:0;justify-content:center;border-radius:10px;-webkit-tap-highlight-color:transparent}
@media(hover:hover) and (pointer:fine){.courses627 .course-heading639 .course-open627:hover{background:var(--hover)}}
@media(hover:none),(pointer:coarse){
 :is(.students-v11,.teachers-v12,.staff619,.courses627) .back-link:hover{color:var(--text-soft)}
 :is(.students-v11,.teachers-v12,.staff619,.courses627) .back-link:active,
 .courses627 .course-heading639 .course-open627:active{background:var(--accent-light)}
}
/* #678 Approved677 whole-footer presentation: one owner, five audited routes.
   Route renderers keep paging/data/commands; global legacy and touch semantics stay intact. */
:is(.students-v11,.teachers-v12,.staff619,.courses627,.lessons668,.rooms710) #pagination-bar{display:flex!important;flex-direction:row;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:14px;margin-top:14px;min-height:64px;padding:9px 12px;border:1px solid var(--border);border-radius:15px;background:var(--card)}
:is(.students-v11,.teachers-v12,.staff619,.courses627,.lessons668,.rooms710) #pagination-bar[style*="none"]{display:none!important}
:is(.students-v11,.teachers-v12,.staff619,.courses627,.lessons668,.rooms710) #pagination-bar :is(.student-pagination-support,.teacher-pagination-support,.pagination-support639){display:contents}
:is(.students-v11,.teachers-v12,.staff619,.courses627,.lessons668,.rooms710) #pagination-bar .per-page-control{display:flex;order:initial;flex:0 0 auto;gap:8px;font-size:13px}
:is(.students-v11,.teachers-v12,.staff619,.courses627,.lessons668,.rooms710) #pagination-bar #per-page-select{min-width:44px;min-height:44px!important;height:auto!important;font-size:13px}
:is(.students-v11,.teachers-v12,.staff619,.courses627,.lessons668,.rooms710) #pagination-bar .page-range-text{order:initial;flex:1 1 auto;width:auto;min-width:0;margin:0;text-align:center;font-size:13px;color:var(--text-soft)}
:is(.students-v11,.teachers-v12,.staff619,.courses627,.lessons668,.rooms710) #pagination-bar .page-nav{display:flex;align-items:center;gap:4px;order:initial;margin:0}
:is(.students-v11,.teachers-v12,.staff619,.courses627,.lessons668,.rooms710) #pagination-bar .page-btn{min-width:44px!important;width:auto!important;min-height:44px!important;height:auto!important;padding-inline:6px}
:is(.students-v11,.teachers-v12,.staff619,.courses627,.lessons668,.rooms710) #pagination-bar :is(.student-page-nav-mobile,.teacher-page-nav-mobile,.page-nav-mobile639,.student-range-compact,.teacher-range-compact,.range-compact639){display:none}
@media(min-width:561px) and (max-width:1023px){
 :is(.students-v11,.teachers-v12,.staff619,.courses627,.lessons668,.rooms710) #pagination-bar{display:grid!important;grid-template-columns:minmax(0,1fr) auto;gap:12px}
 :is(.students-v11,.teachers-v12,.staff619,.courses627,.lessons668,.rooms710) #pagination-bar .per-page-control{display:none}
 :is(.students-v11,.teachers-v12,.staff619,.courses627,.lessons668,.rooms710) #pagination-bar .page-range-text{text-align:left;flex:none}
 :is(.students-v11,.teachers-v12,.staff619,.courses627,.lessons668,.rooms710) #pagination-bar .page-nav{justify-self:end}
}
@media(max-width:560px){
 :is(.students-v11,.teachers-v12,.staff619,.courses627,.lessons668,.rooms710) #pagination-bar :is(.student-mobile-page-btn,.teacher-mobile-page-btn,.mobile-page-btn639,.student-page-position,.teacher-page-position,.page-position639){display:flex;align-items:center;justify-content:center;border-radius:10px}
 :is(.students-v11,.teachers-v12,.staff619,.courses627,.lessons668,.rooms710) #pagination-bar :is(.student-mobile-page-btn,.teacher-mobile-page-btn,.mobile-page-btn639){border:1px solid var(--border);background:var(--card);color:var(--text);cursor:pointer}
 :is(.students-v11,.teachers-v12,.staff619,.courses627,.lessons668,.rooms710) #pagination-bar :is(.student-mobile-page-btn,.teacher-mobile-page-btn,.mobile-page-btn639):disabled{background:var(--card);color:var(--text);cursor:not-allowed;opacity:1}
 :is(.students-v11,.teachers-v12,.staff619,.courses627,.lessons668,.rooms710) #pagination-bar :is(.student-mobile-page-btn,.teacher-mobile-page-btn,.mobile-page-btn639):disabled svg{opacity:.52}
 :is(.students-v11,.teachers-v12,.staff619,.courses627,.lessons668,.rooms710) #pagination-bar :is(.student-page-position,.teacher-page-position,.page-position639){padding:0 3px;border:0;background:transparent;color:var(--ink);font-size:12px;font-weight:600;pointer-events:none;box-shadow:none}
 :is(.students-v11,.teachers-v12,.staff619,.courses627,.lessons668,.rooms710) #pagination-bar{padding:9px;gap:8px;margin-top:10px}
 :is(.students-v11,.teachers-v12,.staff619,.courses627,.lessons668,.rooms710) #pagination-bar :is(.student-pagination-support,.teacher-pagination-support,.pagination-support639){display:flex;align-items:center;justify-content:space-between;gap:6px;flex:1 1 auto;min-width:min-content;flex-wrap:wrap}
 :is(.students-v11,.teachers-v12,.staff619,.courses627,.lessons668,.rooms710) #pagination-bar .per-page-control{order:2;font-size:12px;gap:0}
 :is(.students-v11,.teachers-v12,.staff619,.courses627,.lessons668,.rooms710) #pagination-bar :is(.pp-lead,.pp-trail,.pp-trail-short,.student-range-full,.teacher-range-full,.range-full639,.page-nav){display:none}
 :is(.students-v11,.teachers-v12,.staff619,.courses627,.lessons668,.rooms710) #pagination-bar #per-page-select{width:max(68px,4em)!important;min-width:68px;padding:0 22px 0 7px;font-size:12px;border-radius:10px}
 :is(.students-v11,.teachers-v12,.staff619,.courses627,.lessons668,.rooms710) #pagination-bar .page-range-text{order:1;flex:1 1 auto;min-width:max-content;text-align:left;font-size:12px;white-space:nowrap;overflow:visible;text-overflow:clip}
 :is(.students-v11,.teachers-v12,.staff619,.courses627,.lessons668,.rooms710) #pagination-bar :is(.student-range-compact,.teacher-range-compact,.range-compact639){display:inline}
 :is(.students-v11,.teachers-v12,.staff619,.courses627,.lessons668,.rooms710) #pagination-bar :is(.student-page-nav-mobile,.teacher-page-nav-mobile,.page-nav-mobile639){display:grid;grid-template-columns:44px minmax(64px,1fr) 44px;align-items:center;gap:5px;flex:0 1 auto;width:max-content;min-width:162px;max-width:100%;margin-left:auto}
 :is(.students-v11,.teachers-v12,.staff619,.courses627,.lessons668,.rooms710) #pagination-bar :is(.student-mobile-page-btn,.teacher-mobile-page-btn,.mobile-page-btn639){width:44px;min-height:46px;height:46px;border-radius:10px}
 :is(.students-v11,.teachers-v12,.staff619,.courses627,.lessons668,.rooms710) #pagination-bar :is(.student-page-position,.teacher-page-position,.page-position639){min-width:0;min-height:46px;height:auto;white-space:normal;text-align:center;overflow-wrap:normal}
 :is(.students-v11,.teachers-v12,.staff619,.courses627,.lessons668,.rooms710) #pagination-bar :is(.student-page-nav-mobile,.teacher-page-nav-mobile,.page-nav-mobile639):empty{display:none}
}
@media(max-width:360px){
 :is(.students-v11,.teachers-v12,.staff619,.courses627,.lessons668,.rooms710) #pagination-bar{display:grid!important;grid-template-columns:minmax(0,1fr);padding:8px}
 :is(.students-v11,.teachers-v12,.staff619,.courses627,.lessons668,.rooms710) #pagination-bar :is(.student-pagination-support,.teacher-pagination-support,.pagination-support639){min-width:0}
 :is(.students-v11,.teachers-v12,.staff619,.courses627,.lessons668,.rooms710) #pagination-bar :is(.student-page-nav-mobile,.teacher-page-nav-mobile,.page-nav-mobile639){width:100%;grid-template-columns:58px minmax(0,1fr) 58px}
 :is(.students-v11,.teachers-v12,.staff619,.courses627,.lessons668,.rooms710) #pagination-bar :is(.student-mobile-page-btn,.teacher-mobile-page-btn,.mobile-page-btn639){width:100%}
}

/* #642 approved641 design contract start. */
/* Proposal641 only; native geometry/selected/disabled/focus ownership retained. */
:is(.students-v11,.teachers-v12,.staff619) th.sortable .sort-arrow{display:inline-block;width:12px;margin-left:6px;font-size:10px;line-height:1;vertical-align:middle;opacity:1}
/* #642 approved641 design contract end. */

/* #675 Decorative button icons share the native button pointer target.
   Five audited routes only; no paint, geometry, focus or command changes. */
body[data-render675] button svg,body[data-render675] button svg *{pointer-events:none}

/* #673 approved672 shared focus owner. Explicit five-route opt-in only.
   Important field resets defeat legacy combobox specificity and inline outline:none;
   action priority defeats existing scoped controls. No geometry or autofocus rules. */
body[data-focus673]{--ef-focus-color:var(--accent-strong);--ef-focus-ring:2px;--ef-focus-gap:2px}
body[data-focus673] :is(input:where(:not([type=checkbox]):not([type=radio]):not([type=file])),select,textarea):focus{
 outline:2px solid var(--ef-focus-color)!important;outline-offset:2px;box-shadow:none!important;border-color:var(--border)!important;
}
body[data-focus673] :is(a,button,summary,[tabindex],.btn,.icon-btn,.sort-head,.ef-filter-option,.upload-circle):not([tabindex="-1"]):not(.student-pointer-focus-return):not(.teacher-pointer-focus-return):focus-visible{
 outline:2px solid var(--ef-focus-color)!important;outline-offset:2px!important;
}
body[data-focus673] .upload-circle:focus-visible{border-color:var(--border)}
body[data-focus673] :is(input[type=checkbox],input[type=radio]):focus-visible{outline:2px solid var(--ef-focus-color)!important;outline-offset:2px!important;box-shadow:none!important}
body[data-focus673] .error-summary654:focus-visible{outline-color:var(--danger)!important}
body[data-focus673] #f-subjects[aria-invalid=true]:focus-visible{outline:2px solid var(--danger)!important;outline-offset:2px!important}
body[data-focus673] .search:focus-within{outline:2px solid var(--ef-focus-color);outline-offset:2px;box-shadow:none!important;border-color:var(--border)!important}
body[data-focus673] .search input:focus{outline:none!important;box-shadow:none!important}
body[data-focus673] :is(.field.error,.field.has-error) :is(input,select,textarea):focus,
body[data-focus673] :is(input,select,textarea)[aria-invalid=true]:focus{outline-color:var(--danger)!important}
@media(forced-colors:active){
 body[data-focus673]{--ef-focus-color:Highlight}
 body[data-focus673] :is(.field.error,.field.has-error) :is(input,select,textarea):focus,
 body[data-focus673] :is(input,select,textarea)[aria-invalid=true]:focus,
 body[data-focus673] .error-summary654:focus-visible,
 body[data-focus673] #f-subjects[aria-invalid=true]:focus-visible{outline-color:Highlight!important}
}
/* #681 Approved680 dirty intent; explicit registrations only. */
html body .dirty-panel681[data-dirty681]{box-sizing:border-box;width:100%;max-width:360px;min-width:0;padding:24px;border:0;border-radius:16px;background:var(--card);color:var(--text);font:13px/1.6 var(--font);text-align:left;animation:pop .18s ease-out;overflow-wrap:anywhere}
html body dialog.dirty-panel681[data-dirty681]{width:calc(100% - 40px);margin:auto;max-height:calc(100dvh - 40px)}
html body .dirty-host681:not(.dirty-panel681){padding:20px;background:rgba(27,34,48,.55)}
html body dialog.dirty-panel681[data-dirty681]::backdrop{background:rgba(27,34,48,.55)}
html body .dirty-host681:focus{outline:none}
html body .dirty-panel681[data-dirty681] .dirty-icon681{display:flex;align-items:center;justify-content:center;width:44px;height:44px;margin:0 0 14px;border-radius:50%;background:var(--danger-bg);color:var(--danger-strong)}
html body .dirty-panel681[data-dirty681] .dirty-icon681 svg{width:22px;height:22px}
html body .dirty-panel681[data-dirty681] .dirty-title681{font:600 15.5px/1.5 var(--font);color:var(--text);padding:0;margin:0 0 6px}
html body .dirty-panel681[data-dirty681] .dirty-copy681{font:400 13px/1.6 var(--font);color:var(--text-soft);padding:0;margin:0 0 20px;white-space:normal}
html body .dirty-panel681[data-dirty681] .dirty-actions681{display:flex;justify-content:flex-end;align-items:stretch;flex-wrap:wrap;gap:10px;margin:0;padding:0;border:0}
html body .dirty-panel681[data-dirty681] .dirty-actions681>button{box-sizing:border-box;flex:0 1 auto;min-height:44px;min-width:44px;max-width:100%;margin:0;padding:10px 14px;border:1px solid var(--border);border-radius:10px;background:var(--card);color:var(--text);font:500 13.5px/1.5 var(--font);white-space:normal;overflow-wrap:anywhere;box-shadow:none;cursor:pointer}
html body .dirty-panel681[data-dirty681] .dirty-actions681>.dirty-discard681{color:var(--danger-strong);border-color:var(--danger)}
@media(hover:hover) and (pointer:fine){html body .dirty-panel681[data-dirty681] .dirty-actions681>button:hover{background:var(--hover)}html body .dirty-panel681[data-dirty681] .dirty-actions681>.dirty-discard681:hover{background:var(--danger-light)}}
@media(hover:none),(pointer:coarse){html body .dirty-panel681[data-dirty681] .dirty-actions681>button:active{background:var(--accent-light);transform:none}html body .dirty-panel681[data-dirty681] .dirty-actions681>.dirty-discard681:active{background:var(--danger-light)}}
@media(max-height:360px){html body .dirty-panel681[data-dirty681]{padding:16px}html body .dirty-panel681[data-dirty681] .dirty-icon681{margin-bottom:8px}html body .dirty-panel681[data-dirty681] .dirty-copy681{margin-bottom:12px}}
@media(prefers-reduced-motion:reduce){html body .dirty-panel681[data-dirty681]{animation:none}}

/* #698 Approved697 long-popup contract. Explicit opt-in only; no orientation rebuild. */
.ef-popup698 .ef-popup-head698{display:grid;grid-template-columns:minmax(0,1fr) 48px;gap:8px 12px;align-items:start;text-align:left}
.ef-popup698 .ef-popup-head698 :is(h2,h3){grid-column:1;grid-row:1;margin:0;min-width:0;overflow-wrap:anywhere}
.ef-popup698 .ef-popup-head698 :is(h2,h3):focus{outline:none}
.ef-popup698 .ef-popup-head698 p{grid-column:1;grid-row:2;margin:0;overflow-wrap:anywhere}
.ef-popup698 .ef-popup-x698{grid-column:2;grid-row:1/3;width:48px;height:48px;min-width:48px;min-height:48px;padding:0;font-size:24px;line-height:1;align-self:start;display:flex;align-items:center;justify-content:center}
.ef-popup698>.confirm-box>.confirm-icon{display:none}
.ef-popup698>.confirm-box>.ef-popup-head698{margin-bottom:20px}
.ef-popup698 :is(.history-text,.confirm-text,.modal2-sub,.cred-value){min-width:0;overflow-wrap:anywhere}
.ef-popup698 .history-amount{white-space:nowrap}
.ef-popup-master698 .ef-popup-head698{display:flex;justify-content:space-between;gap:16px;margin-bottom:16px}
.ef-popup-master698 .ef-popup-head698 :is(h2,h3){font-size:20px;line-height:1.5;font-weight:600}
.ef-popup-master698 .ef-popup-head698>:not(button){min-width:0;overflow-wrap:anywhere}
.ef-popup-master698 .ef-popup-x698{flex-shrink:0}
.ef-popup-master698 .confirm-actions{flex-wrap:wrap}
.ef-popup-master698 .confirm-actions button{min-height:48px;justify-content:center}
html:has(dialog.ef-popup698[data-ef-dialog-document-flow]){scroll-behavior:auto}
html body:has(dialog.ef-popup698[data-ef-dialog-document-flow]){background:var(--card)!important;height:auto!important;overflow:auto!important}
html body:has(dialog.ef-popup698[data-ef-dialog-document-flow])>:not(dialog[open]):not(script):not(style):not(link){display:none!important}
html body:has(dialog.ef-popup698[data-ef-dialog-document-flow]:not([inert]))>dialog[data-ef-dialog-document-flow][inert],html body:has(dialog.ef-popup698[data-ef-dialog-document-flow]:not([inert]))>#modal-overlay[inert]{display:none!important}
html body dialog.ef-popup698[data-ef-dialog-document-flow]{position:relative!important;inset:auto!important;display:block!important;width:100%!important;max-width:none!important;height:auto!important;max-height:none!important;min-height:100dvh;margin:0!important;padding:0!important;background:var(--card)!important;overflow:visible!important;border:0!important}
html body dialog.ef-popup698[data-ef-dialog-document-flow]>:is(.modal,.modal2,.confirm-box){box-sizing:border-box;width:100%!important;max-width:860px!important;min-height:100dvh;max-height:none!important;height:auto!important;margin:0 auto!important;border:0;border-radius:0;box-shadow:none;overflow:visible!important;transform:none!important;animation:none!important;text-align:left}
html body dialog.ef-popup698[data-ef-dialog-document-flow]>.confirm-box{padding:20px max(20px,env(safe-area-inset-right)) max(20px,env(safe-area-inset-bottom)) max(20px,env(safe-area-inset-left))}
html body dialog.ef-popup698[data-ef-dialog-document-flow] :is(.modal-head,.modal-body,.modal2-head,.modal2-body,.modal2-footer,.confirm-actions){position:static;max-height:none!important;overflow:visible!important}
dialog.ef-popup698[data-ef-dialog-document-flow] :is(.modal2-head,.modal2-body,.modal2-footer){padding-left:max(20px,env(safe-area-inset-left));padding-right:max(20px,env(safe-area-inset-right))}
dialog.ef-popup698[data-ef-dialog-document-flow] .ef-popup-head698{padding-top:max(12px,env(safe-area-inset-top))}
dialog.ef-popup698[data-ef-dialog-document-flow] :is(.modal2-footer,.confirm-actions){position:static;flex-wrap:wrap;padding-bottom:max(20px,env(safe-area-inset-bottom))}
dialog.ef-popup698[data-ef-dialog-document-flow] :is(.modal2-footer,.confirm-actions)>button{flex:1 1 140px;min-height:48px;justify-content:center}
.lessons668 dialog:is(#confirm-overlay,#discard-overlay,#withdraw-overlay)[open]{overflow:auto;align-items:safe center}
@media(orientation:landscape) and (max-height:500px){dialog.ef-popup698[data-ef-dialog-document-flow] .modal2-head{padding-block:8px}dialog.ef-popup698[data-ef-dialog-document-flow] .modal2-body{padding-block:12px}}

/* #758 owner-approved desktop overlay correction; preserve698 touch document-flow. */
html body dialog.ef-popup698:is(#requests-overlay,#attend-history-overlay,#dismissed-overlay,#stu-info-overlay):not([data-ef-dialog-document-flow]){
 width:100%;max-width:none;height:100%;max-height:none;margin:0;border:0;
 overflow:hidden;color:inherit;
}
html body dialog.ef-popup698:is(#requests-overlay,#attend-history-overlay,#dismissed-overlay,#stu-info-overlay):not([data-ef-dialog-document-flow])::backdrop{background:transparent}
.students-v11 #requests-overlay .req-card-top>:last-child{min-width:0;overflow-wrap:anywhere}
.students-v11 #requests-overlay .req-detail{grid-template-columns:repeat(2,minmax(0,1fr))}
.students-v11 #requests-overlay .req-detail>div{min-width:0;overflow-wrap:anywhere}
