/* =====================================================================
   ⚡ ไฟล์: css/base/perf.css
   หน้าที่: ลดการใช้ CPU/GPU บนมือถือ + เคารพ user motion preference
   มาตรฐาน: ดู [[feedback_no_background_polling]]

   ลำดับการ load: ต้องอยู่ "หลัง" component CSS ทั้งหมด (เป็น override layer)
   ===================================================================== */

/* ─── 1. User explicitly wants reduced motion ─────────────────────────
   iOS Settings → Accessibility → Motion → Reduce Motion
   Android Settings → Accessibility → Remove animations
   เคารพการตั้งค่าผู้ใช้ — kill infinite animation ทุกที่
*/
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        animation-delay: 0ms !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
}

/* ─── 2. Auto-pause animations บน element ที่ซ่อนอยู่ ────────────────
   CSS spec บอกว่า display:none ควร pause animation อยู่แล้ว แต่ Safari
   เก่าและ Chrome Android บางเวอร์ชันยัง run อยู่ — กฎนี้บังคับให้หยุด
*/
[hidden],
.is-hidden,
.login-overlay[style*="display: none"],
.login-overlay[style*="display:none"] {
    animation-play-state: paused !important;
}
[hidden] *,
.is-hidden * {
    animation-play-state: paused !important;
}

/* ─── 3. Mobile/Tablet: ลบ backdrop-filter ทุกที่ ────────────────────
   blur() บังคับ GPU composite ทุก paint frame = ร้อนสุด ๆ บนมือถือ
   (เปลี่ยนเป็น solid background opacity แทน — มอบ visual แต่ไม่เปลือง)

   ⚠️ breakpoint จับ "อุปกรณ์สัมผัส" ไม่ใช่แค่ความกว้าง:
   iPad ทุกรุ่นกว้าง 768-1024px (เกิน 720px) → เคยหลุดทุกกฎประหยัดแบต
   ทำให้ backdrop-filter + animation infinite วิ่งเต็มสูบ (กินแบต ~50%/ชม.).
   `(hover: none) and (pointer: coarse)` = จอสัมผัสไม่มีเมาส์ = มือถือ+แท็บเล็ต
   ทุกขนาด ขณะที่ desktop (มีเมาส์) ยังได้ effect ครบเหมือนเดิม.
*/
@media (max-width: 720px), (hover: none) and (pointer: coarse) {
    .login-overlay,
    #main-action-bar,
    .action-bar,
    .chapter-dashboard-card,
    .chapter-dashboard-tile,
    .chapter-dashboard-section,
    .chapter-progress-tile,
    .dq-toast,
    .dq-modal,
    .dq-modal-overlay,
    .character-overlay-shell,
    .mobile-menu-overlay,
    .student-editor-modal,
    .footer-print,
    .achievement-detail-card {
        backdrop-filter: none !important;
        -webkit-backdrop-filter: none !important;
    }

    /* catch-all: กัน backdrop-filter ที่ลิสต์ทีละ class ตกหล่น
       (scope อยู่ใน touch-device เท่านั้น — ไม่กระทบ desktop)
       blur ทั้งจอคือตัวกินแบต/ทำเครื่องร้อนหนักสุดบน iOS Safari */
    *, *::before, *::after {
        backdrop-filter: none !important;
        -webkit-backdrop-filter: none !important;
    }

    /* ─── 4. Mobile: หยุด decorative infinite animation ─────────────
       Animation ที่เป็น "feedback / pulse / shimmer" ที่รันตลอด
       — ผู้ใช้ไม่ได้สังเกตหลัง 2-3 วินาทีแรก แต่ chip CPU/GPU ไม่หยุด
       Functional animation (toast appear, modal popGlow one-shot) ไม่กระทบ
    */
    .login-brand-mark,
    .action-button-rebirth,
    .achievement-badge.unlocked,
    .dq-tier-card,
    .dq-tier-vip,
    .dq-tier-chosen,
    .dq-pulse-ring,
    .vip-badge,
    .chosen-chip,
    .chosen-ribbon,
    .achievement-banner,
    .action-bar,           /* persistent barPulse — เคยเขียน .barPulse ผิด (เป็น keyframe ไม่ใช่ class) */
    #main-action-bar,
    .cd-float-anim,
    /* ── ชื่อ class จริงที่ render บนหน้า quest/home (verified 2026-06-06) ──
       list เดิมใช้ชื่อ .chosen-chip/.vip-badge ที่ไม่ตรง DOM จริง → หลุดรอด
       วิ่ง infinite ตลอดบนหน้าหลัก. ทั้งหมดเป็น decorative (shine/glow/
       shimmer/pulse/flowing-gradient). ⚠️ ห้ามใส่ .boot-spinner — มันคือ
       สปินเนอร์ตอนโหลดจริง (functional) ปิดแล้วจะดูเหมือนค้าง. */
    .chip-vip-tag,                 /* vip-badge-shine + vip-chip-tag-glow */
    .chip-chosen-tag,              /* chosen-shimmer + chosen-chip-pulse */
    .chosen-screen-ribbon-band,    /* chosen-shimmer + chosen-glow */
    .quest-start-button,           /* questStartPulse */
    .fancy-footer {                /* flowBG gradient */
        animation: none !important;
    }

    /* ลด box-shadow blur radius บนมือถือ (ลด GPU rasterize cost)
       ใช้เฉพาะตัวที่มี shadow ใหญ่ (>10px blur)
    */
    .login-box,
    .chapter-dashboard-card,
    .dq-modal,
    .student-editor-modal {
        box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15) !important;
    }
}

/* ─── 5. Defensive: ป้องกัน animation ที่ลืม pause ตอนเปลี่ยนหน้า ──
   ถ้า element มี class .perf-paused (set โดย JS ตอน navigate away)
*/
.perf-paused,
.perf-paused * {
    animation-play-state: paused !important;
}

/* ─── 6. Bucket-scope: หยุด animation ของ bucket อื่นเมื่อ user เปลี่ยน bucket ─
   launcher set body[data-active-bucket="<id>"] ตอนเปิด bucket
   ถ้า user อยู่ bucket A แต่ DOM ของ bucket B ยังอยู่ → animation B ต้องหยุด

   - Daily Quest pulses/shimmers รันก็ต่อเมื่อ user อยู่หน้า DQ จริงๆ
   - Chosen ribbon shimmers รันก็ต่อเมื่อ user อยู่หน้า main-quest หรือหน้าหลัก
   - Achievement banner/badge animations รันก็ต่อเมื่อ user อยู่หน้า achievements

   Selector trick: `body[data-active-bucket]:not([data-active-bucket="X"])`
   = "body มี attribute แต่ค่าไม่ใช่ X" = อยู่ bucket อื่น (ไม่ใช่หน้า launcher home)
*/

/* Daily Quest animations — kill เมื่ออยู่ bucket อื่น */
body[data-active-bucket]:not([data-active-bucket="daily-quest"]) .dq-tier-card,
body[data-active-bucket]:not([data-active-bucket="daily-quest"]) .dq-tier-vip,
body[data-active-bucket]:not([data-active-bucket="daily-quest"]) .dq-tier-chosen,
body[data-active-bucket]:not([data-active-bucket="daily-quest"]) .dq-pulse-ring,
body[data-active-bucket]:not([data-active-bucket="daily-quest"]) .dq-pulse-normal,
body[data-active-bucket]:not([data-active-bucket="daily-quest"]) .dq-pulse-vip,
body[data-active-bucket]:not([data-active-bucket="daily-quest"]) .dq-pulse-chosen,
body[data-active-bucket]:not([data-active-bucket="daily-quest"]) [class*="dq-pulse"],
body[data-active-bucket]:not([data-active-bucket="daily-quest"]) [class*="dq-ring"] {
    animation: none !important;
}

/* Chosen ribbon — kill เมื่ออยู่ bucket ที่ไม่เกี่ยวข้องกับ quest */
body[data-active-bucket]:not([data-active-bucket="main-quest"]):not([data-active-bucket="daily-quest"]):not([data-active-bucket="character"]) .chosen-ribbon,
body[data-active-bucket]:not([data-active-bucket="main-quest"]):not([data-active-bucket="daily-quest"]):not([data-active-bucket="character"]) .chosen-chip,
body[data-active-bucket]:not([data-active-bucket="main-quest"]):not([data-active-bucket="daily-quest"]):not([data-active-bucket="character"]) .vip-badge,
body[data-active-bucket]:not([data-active-bucket="main-quest"]):not([data-active-bucket="daily-quest"]):not([data-active-bucket="character"]) [class*="chosen-shimmer"],
body[data-active-bucket]:not([data-active-bucket="main-quest"]):not([data-active-bucket="daily-quest"]):not([data-active-bucket="character"]) [class*="vip-rainbow"] {
    animation: none !important;
}

/* Achievement animations — kill เมื่ออยู่ bucket อื่น */
body[data-active-bucket]:not([data-active-bucket="achievements"]):not([data-active-bucket="character"]) .achievement-badge.unlocked,
body[data-active-bucket]:not([data-active-bucket="achievements"]):not([data-active-bucket="character"]) .achievement-banner {
    animation: none !important;
}

/* Chapter dashboard cdFloat — kill เมื่ออยู่ bucket ที่ไม่ใช่ main-quest/overview */
body[data-active-bucket]:not([data-active-bucket="main-quest"]):not([data-active-bucket="overview"]) [class*="cdFloat"],
body[data-active-bucket]:not([data-active-bucket="main-quest"]):not([data-active-bucket="overview"]) .cd-float-anim {
    animation: none !important;
}

/* ─── 7. Defensive: SVG SMIL pause-on-hidden ─────────────────────────
   Chrome Android บางเวอร์ชันไม่ pause SMIL auto บน display:none
   CSS ทำได้แค่นี้: stop CSS animation. ส่วน SVG <animate> ต้อง JS pauseAnimations()
   ดู js/core/section-lifecycle.js (Phase 5)
*/
[hidden] svg,
.is-hidden svg,
[style*="display: none"] svg,
[style*="display:none"] svg {
    /* CSS ไม่สามารถ pause SMIL ได้โดยตรง — ใช้ visibility:hidden เป็น fallback
       เพื่อให้ browser ไม่ paint แม้ animation ยังคำนวณ */
    visibility: hidden;
}

/* ─── 8. Responsive SVG — mobile overflow fix ────────────────────────
   SVG ที่มี fixed width จะเกินกรอบบน mobile Chrome/Safari

   ⚠️ KaTeX วาด surd (√ ∛), เส้นเศษส่วน, brace ด้วย inline SVG width:400em
   ที่ถูก parent .hide-tail (overflow:hidden) clip + สืบทอดความสูงจาก em.
   ถ้ากฎ svg กวาดรวมไปโดน → max-width บีบ surd หาย, height:auto/revert ยุบ
   ความสูงเหลือ ~0px → เครื่องหมายหายทั้งเล่ม (เนื้อหา+ข้อสอบ).

   กันถาวร: กฎ svg กว้างใช้ selector ธรรมดา (รองรับทุกเบราว์เซอร์)
   แล้วใช้ override ตอกย้ำด้วย !important ให้ KaTeX ชนะเสมอ — ต่อให้มี
   กฎ svg ใหม่ (ที่ไม่ใช่ !important) มาทับ KaTeX ในอนาคตก็ยังรอด.
   ⚠️ ห้ามใช้ svg:not(.katex svg) — :not() ที่มี descendant combinator
   เป็น Selectors L4 ถ้าเบราว์เซอร์เก่าไม่รองรับจะทิ้งทั้งกฎ → SVG
   เนื้อหาทุกตัวล้นจอ หน้าพัง (เกิดจริง 2026-05-31).
   ดู memory: feedback-katex-svg-max-width-bug (เคยพังซ้ำหลายรอบ)
*/
svg {
    max-width: 100%;
    height: auto;
}
.katex svg,
.katex-display svg {
    max-width: none !important;
    height: inherit !important;
}

/* ───────────────────────────────────────────────────────────────────
   KaTeX font reset — กัน ≠ ≤ ≥ ฯลฯ เป็นกล่อง □ (เกิดจริง 2026-06-01)

   ปัญหา: foundation.css มี `* { font-family: 'Segoe UI','Sarabun' }`
   (universal selector) → apply กับ "ทุก" element รวม descendant ของ
   .katex ด้วย. ตัว \neq ที่ KaTeX วาดใช้ขีดทับ glyph U+E020 ซึ่งมี
   *เฉพาะ* ในฟอนต์ KaTeX_Main — พอโดน * บังคับเป็น Segoe UI/Sarabun
   ที่ไม่มี glyph นี้ → เหลือกล่อง □ (= แสดงได้เพราะทุกฟอนต์มี แต่ขีดทับหาย).
   ไม่เกี่ยวกับ CDN/self-host — เป็น CSS specificity ล้วนๆ.

   แก้: บังคับเฉพาะ "สัญลักษณ์ที่ตั้งตรงเสมอ" (relation/binary/delimiter/
   punct) กลับไปใช้ KaTeX_Main — กลุ่มนี้ KaTeX วาดด้วย KaTeX_Main อยู่แล้ว
   จึงปลอดภัย. **ห้ามใส่ .mord/.mathnormal** เพราะตัวแปรเอียง (a,b,c) ใช้
   KaTeX_Math เอียง — ถ้า force KaTeX_Main จะกลายเป็นตั้งตรง = ผิดคณิต.
   .katex root ก็ reset กัน fallback ของ * ที่ชั้นนอก.
*/
.katex,
.katex .mrel,
.katex .mbin,
.katex .mopen,
.katex .mclose,
.katex .mpunct {
    font-family: KaTeX_Main, 'Times New Roman', serif;
}
