/* WOFF2 មុន TTF ជា Fallback — File TTF ដើមធំពេក (204KB/465KB) ធ្វើឲ្យ Download យឺត ហើយឃើញ Font Swap
   (Flash of Fallback Font) យូរជាង ១វិនាទីលើ Refresh — WOFF2 តូចជាង ~75-87% (កាត់ដោយ wawoff2, Glyph/
   Hinting ដើមទាំងអស់រក្សាទុក មិនកែប្រែឡើយ) ដោះស្រាយបញ្ហានេះដោយផ្ទាល់ (មិនមែនត្រឹមតែ Preload ដែលមិនគ្រប់គ្រាន់
   ព្រោះ File ខ្លួនឯងនៅតែធំ) */
@font-face {
  font-family: 'Khmer OS Battambang';
  src: url('/fonts/KhmerOSBattambang.woff2') format('woff2'),
       url('/fonts/KhmerOSBattambang.ttf') format('truetype');
  font-weight: normal;
  font-style: normal;
  font-display: swap;
}

/* Font នេះលែងត្រូវបានប្រើក្នុង Markup ណាមួយទៀតទេ (ទាំង .brand-name ខាងក្រោម និង .tutorials-title-text ខាងក្រោម
   ២ កន្លែងសុទ្ធតែជា SVG inline ទាំងអស់ឥឡូវ ដើម្បីកម្ចាត់ការលោត Font/Fallback ពេល Refresh ឬ iOS Safari)។ រក្សា
   @font-face ទុកសម្រាប់តែជាឯកសារយោង (Browser មិន Download Font ដែលគ្មាននរណាប្រើទេ) — ប្រសិនបើត្រូវប្រើវាម្តងទៀត
   សូមប្រើ font-display: block (មិនមែន swap) */
@font-face {
  font-family: 'Khmer Chhay Style 3';
  src: url('/fonts/Khmer-Chhay-Style-3.woff2') format('woff2'),
       url('/fonts/Khmer-Chhay-Style-3.ttf') format('truetype');
  font-weight: normal;
  font-style: normal;
  font-display: block;
}

:root {
  --bg: #0f0f0f;
  --bg-raised: #212121;
  --bg-card: #181818;
  --gold: #3ea6ff;
  --gold-soft: #7cc4ff;
  --red: #f28b82;
  --cream: #f1f1f1;
  --muted: #aaaaaa;
  --border: #303030;
  --gold-tint: rgba(62, 166, 255, 0.15);
  --radius: 14px;
  --shadow: 0 12px 32px rgba(0, 0, 0, 0.35);
}

:root[data-theme="light"] {
  --bg: #f4faf9;
  --bg-raised: #ffffff;
  --bg-card: #ffffff;
  --gold: #0d9488;
  --gold-soft: #0f766e;
  --red: #c0392b;
  --cream: #10302c;
  --muted: #5b7d79;
  --border: rgba(13, 148, 136, 0.22);
  --gold-tint: rgba(13, 148, 136, 0.15);
  --shadow: 0 12px 32px rgba(16, 48, 44, 0.1);
}

* { box-sizing: border-box; }

html { scroll-behavior: smooth; }

/* ទប់ស្កាត់ iOS/Android "Pull-to-Refresh" ដែល Browser ធ្វើ Reload ទំព័រពិតទាំងមូល (មិនមែន Browser Chrome
   ធម្មតា Refresh Icon ទេ — កើតឡើងស្វ័យប្រវត្តិពេល Drag ចុះក្រោមខណៈ Scroll នៅកំពូលទំព័រ) — User រាយការណ៍ថា
   ប្តូរ Tab ទំព័រដើម/ពេញនិយម/Premium "មិន Smooth" ដែលពិតជា Pull-to-Refresh កើតឡើងចៃដន្យខណៈកំពុងចុច/Scroll
   ជិតកំពូលទំព័រ (Wallet Balance ត្រឡប់ទៅ "0៛"/Grid បង្ហាញ Text "កំពុងផ្ទុក..." សុទ្ធសឹងជា Static HTML Shell
   Fallback — សញ្ញាសម្គាល់ច្បាស់ថាជា Page Reload ពិត មិនមែន JS Transition ធម្មតាឡើយ)។ overscroll-behavior-y:
   contain រារាំង Browser Gesture នេះទាំងស្រុង ខណៈនៅតែអនុញ្ញាតឲ្យ Scroll ធម្មតាដំណើរការដដែល — មិនប៉ះពាល់
   ABA PayWay Popup ឡើយ ព្រោះនោះជា Browsing Context ដាច់ដោយឡែក (Iframe/Popup Window) មិនចែក html/body
   ជាមួយទំព័រយើងទេ */
html, body { overscroll-behavior-y: contain; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--cream);
  font-family: 'Battambang', sans-serif;
  line-height: 1.7;
}

h1, h2, h3, .brand-name {
  font-family: 'Moul', 'Battambang', serif;
  font-weight: 400;
  letter-spacing: 0.01em;
}

.wrap {
  max-width: 1100px;
  margin: 0 auto;
  padding: 0 24px;
}

a { color: inherit; }

/* ---------- Header ---------- */
.site-header {
  position: sticky;
  top: 0;
  z-index: 40;
  background: rgba(18, 21, 42, 0.85);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--border);
}
/* backdrop-filter ធ្វើឲ្យ .site-header បង្កើត Compositing Layer ដាច់ដោយឡែក (Root Cause ដូចគ្នានឹង
   Comment ខាងក្រោម style.css អំពី Drawer z-index) — លើ iOS Safari Layer នេះ ជួនកាលមិន Alpha-Blend ជាមួយ
   Backdrop ខ្មៅ (0.72) របស់ .modal-overlay/.mobile-menu-backdrop ត្រឹមត្រូវទេ (z-index/hit-test ត្រឹមត្រូវ
   ស្រាប់ — User ចុចមិនកាត់ Modal ទេ — ប៉ុន្តែ Visual មិនស្រអាប់ត្រឹមត្រូវ) ធ្វើឲ្យ Search Bar/Category Pill
   បង្ហាញភ្លឺដដែលទាំង Modal/Drawer កំពុងបើក — User មានអារម្មណ៍ថា "នៅតែឃើញ/ជាប់ទំព័រពិត" ក្រោម Modal ("លោត
   ចេញទៅក្រៅ") — ដកចេញ backdrop-filter ពេល Modal ឬ Drawer ណាមួយកំពុងបើក លុប Compositing Layer ដែលបង្ក
   បញ្ហានេះចោល (Header នៅតែបាំងដោយ Backdrop ខ្មៅត្រឹមត្រូវតាម z-index ធម្មតា វិញ) */
body.modal-open .site-header,
body.mobile-menu-locked .site-header { backdrop-filter: none; }
.header-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  height: 68px;
  flex-wrap: wrap;
  /* ត្រូវតែស្មើ main.wrap ជានិច្ច ទើប Logo/Sidebar Align ស្មើគ្នានៅគ្រប់ទំហំអេក្រង់ */
  max-width: 1800px;
}
.brand { display: flex; align-items: center; gap: 4px; text-decoration: none; cursor: pointer; flex-shrink: 0; }

/* YouTube-style search bar in the header */
/* .header-search-wrap ជា Flex Item ពិត (ទំហំ/Order កំណត់ទីនេះ) — .header-search (Form) គ្រាន់តែបំពេញ 100% ខាងក្នុង
   ដើម្បីឲ្យ #search-suggestions (Dropdown ណែនាំ — មើល index.html/app.js) Position Absolute ដោយផ្អែកលើ Wrap នេះ */
.header-search-wrap {
  position: relative;
  flex: 1 1 auto;
  max-width: 560px;
  min-width: 160px;
}
.header-search {
  display: flex;
  align-items: center;
  width: 100%;
}
.header-search input {
  flex: 1;
  min-width: 0;
  height: 38px;
  box-sizing: border-box;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-right: none;
  border-radius: 999px 0 0 999px;
  padding: 0 18px;
  color: var(--cream);
  font-family: inherit;
  font-size: 0.92rem;
}
.header-search input::placeholder { color: var(--muted); }
.header-search input:focus { outline: none; border-color: var(--gold); }
.header-search button {
  height: 38px;
  width: 46px;
  box-sizing: border-box;
  display: flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
  background: var(--bg-raised);
  border: 1px solid var(--border);
  border-left: none;
  border-radius: 0 999px 999px 0;
  padding: 0;
  color: var(--cream);
  font-size: 0.95rem;
  cursor: pointer;
  transition: background 0.15s ease;
}
.header-search button:hover { background: var(--bg-card); border-color: var(--gold); }
/* ណែនាំចំណងជើងវីដេអូ (Suggestion) ខណៈវាយបញ្ចូល — Absolute ក្រោម .header-search-wrap (Position:relative) —
   ចុចធាតុមួយបើកវីដេអូនោះដោយផ្ទាល់ (មិនមែនគ្រាន់តែបំពេញអក្សរឡើងវិញទេ — មើលកំណត់ចំណាំក្នុង app.js) */
.search-suggestions {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  right: 0;
  background: var(--bg-raised);
  border: 1px solid var(--border);
  border-radius: 14px;
  box-shadow: var(--shadow);
  padding: 6px;
  max-height: 340px;
  overflow-y: auto;
  z-index: 60;
}
/* dropdownFadeIn ដូចគ្នានឹង .account-dropdown ខាងលើ (style.css:352) — មើលកំណត់ត្រានៅទីនោះ */
.search-suggestions:not(.hidden) { animation: dropdownFadeIn 0.18s cubic-bezier(0.16, 1, 0.3, 1); }
@media (prefers-reduced-motion: reduce) {
  .search-suggestions:not(.hidden) { animation: none; }
}
.search-suggestion-item {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  background: none;
  border: none;
  border-radius: 10px;
  padding: 7px 8px;
  text-align: left;
  color: var(--cream);
  font-family: inherit;
  font-size: 0.86rem;
  cursor: pointer;
}
.search-suggestion-item:hover,
.search-suggestion-item:focus-visible { background: var(--bg-card); outline: none; }
.search-suggestion-item img {
  width: 46px;
  height: 30px;
  border-radius: 6px;
  object-fit: cover;
  flex-shrink: 0;
  background: var(--bg-card);
}
.search-suggestion-title {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* ឈ្មោះ Brand ជា SVG inline (ខ្សែបន្ទាត់ vector ពី Font Khmer Chhay Style 3 — មិនប្រើ Font ពេល Render ទៀតទេ ដូច្នេះគ្មានការ
   លោត Font ពេល Refresh/បណ្តាញយឺត)។ ទំហំកំណត់តាម em ដូច្នេះ font-size (1.9rem Desktop / 1.4rem Mobile / -sm) នៅតែគ្រប់គ្រង
   ទំហំដដែល (viewBox 601×204 ⇒ កម្ពស់ ≈ 1.36em); ពណ៌ចេញពី color (currentColor) តាម Theme */
.brand-name { font-size: 1.9rem; color: var(--gold-soft); line-height: 0; }
.brand-name svg { display: block; height: 1.36em; width: auto; fill: currentColor; }
.brand-logo {
  display: block;
  width: 44px;
  height: 44px;
  background-image: url('/img/logo.png');
  background-size: contain;
  background-position: center;
  background-repeat: no-repeat;
}
.brand-logo-sm { width: 30px; height: 30px; }
.brand-name-sm { font-size: 1.4rem; }
.header-actions { display: flex; align-items: center; gap: 12px; }

/* ---------- Account menu (Avatar + Dropdown, ដូច YouTube) ---------- */
.account-menu { position: relative; }
.account-avatar-btn {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  border: none;
  background: var(--gold);
  color: #fff;
  font-weight: 700;
  font-size: 0.9rem;
  font-family: 'Battambang', sans-serif;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: box-shadow 0.15s ease;
}
.account-avatar-btn:hover { box-shadow: 0 0 0 3px var(--gold-tint); }
.account-avatar-btn .account-avatar-img { width: 100%; height: 100%; border-radius: 50%; object-fit: cover; display: block; }
/* សមាជិក Premium — រង្វង់មាស + ម្កុដតូច ជុំវិញ Avatar ក្នុង Header (Desktop) ដូចគ្នានឹង Avatar ក្នុង Mobile Drawer
   (.mobile-menu-user-crown) — ប្រើពណ៌មាសពិត Literal Hex (មិនមែន var(--gold) ដែលការពិតជាពណ៌ខៀវក្នុង Theme នេះ) ដូចគ្នា
   នឹង .header-membership-btn — .site-header ខ្លួនឯងស្ថិតជាបារងងឹតជានិច្ចទោះ Theme ណាក៏ដោយ (style.css:86) ដូច្នេះមិន
   ចាំបាច់មាន Override សម្រាប់ Light Theme ដូច .header-membership-btn ទេ (ជម្រុញ Contrast ដដែលគ្រប់ Theme) */
.account-menu:has(#member-badge:not(.hidden)) .account-avatar-btn {
  box-shadow: 0 0 0 1.5px #ffd479, 0 0 6px rgba(255, 212, 121, 0.55);
}
.account-avatar-crown {
  position: absolute;
  right: -2px;
  bottom: -2px;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: #1a1330;
  border: 1.5px solid #ffd479;
  color: #ffd479;
  display: none;
  align-items: center;
  justify-content: center;
}
.account-avatar-crown svg { width: 8px; height: 8px; }
.account-menu:has(#member-badge:not(.hidden)) .account-avatar-crown { display: flex; }

.account-avatar-section {
  display: flex;
  align-items: center;
  gap: 16px;
  margin-bottom: 20px;
  padding-bottom: 20px;
  border-bottom: 1px solid var(--border);
}
.account-avatar-preview {
  width: 64px;
  height: 64px;
  border-radius: 50%;
  flex-shrink: 0;
  background: var(--gold);
  color: #fff;
  font-weight: 700;
  font-size: 1.3rem;
  font-family: 'Battambang', sans-serif;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
.account-avatar-preview img { width: 100%; height: 100%; object-fit: cover; display: block; }
.account-avatar-upload-btn { display: inline-block; cursor: pointer; }
.account-settings-form { padding-top: 18px; margin-top: 4px; border-top: 1px solid var(--border); }
.account-settings-form:first-of-type { padding-top: 0; margin-top: 0; border-top: none; }

/* ---------- ផ្ទាំង "គណនីរបស់ខ្ញុំ" (modal-account-settings) — កាតប្រវត្តិរូប + ក្បាលផ្នែក + គម្លាតតូច (បង្រួមកម្ពស់ផ្ទាំង) ----------
   Selector ប្រើ .modal.modal-account-settings (Specificity ខ្ពស់ជាង .modal h3/.modal form ដែលនៅខាងក្រោមក្នុងឯកសារ) */
.modal.modal-account-settings { padding: 22px 20px 20px; }
.modal.modal-account-settings h3 {
  font-family: 'Battambang', sans-serif;
  font-weight: 700;
  font-size: 1.3rem;
  color: var(--cream);
  margin: 0 0 12px;
  padding-right: 36px;
}
.modal.modal-account-settings .account-avatar-section {
  gap: 12px;
  margin: 0 0 12px;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 14px;
  background: rgba(255, 255, 255, 0.04);
}
.account-avatar-wrap { position: relative; display: block; flex-shrink: 0; border-radius: 50%; cursor: pointer; }
.modal-account-settings .account-avatar-preview { width: 54px; height: 54px; font-size: 1.2rem; }
.account-avatar-badge {
  position: absolute;
  right: -3px;
  bottom: -3px;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--bg-raised);
  border: 1.5px solid var(--border);
  color: var(--cream);
  display: flex;
  align-items: center;
  justify-content: center;
}
.account-who { min-width: 0; display: flex; flex-direction: column; }
.account-who-name { font-size: 1.02rem; color: var(--cream); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; line-height: 1.4; }
.account-who-id { color: var(--muted); font-size: 0.8rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; line-height: 1.4; }
.account-avatar-link { width: fit-content; margin-top: 1px; color: var(--gold-soft); font-size: 0.8rem; text-decoration: underline; cursor: pointer; }
.modal.modal-account-settings .account-avatar-section .form-hint { margin: 0; min-height: 0; }
.modal.modal-account-settings .account-avatar-section .form-hint:empty { display: none; }
.modal.modal-account-settings form { gap: 8px; }
.modal.modal-account-settings .account-settings-form { padding-top: 12px; margin-top: 0; }
.modal.modal-account-settings .account-settings-form:first-of-type { padding-top: 0; }
.modal.modal-account-settings label { gap: 4px; }
.modal.modal-account-settings input { border-radius: 10px; }
.account-section-title { display: flex; align-items: center; gap: 6px; margin: 0; font-size: 0.75rem; font-weight: 700; letter-spacing: 0.04em; color: var(--muted); }
.account-name-row { display: flex; gap: 8px; }
.account-name-row input { flex: 1; min-width: 0; }
.account-name-row .btn { flex-shrink: 0; padding: 0 16px; }
.account-name-row .btn:disabled { opacity: 0.6; cursor: default; }
.modal.modal-account-settings .form-error:empty { display: none; }
.modal.modal-account-settings .form-hint { margin: 0; min-height: 0; }
.password-toggle-btn { color: var(--muted); }
.password-toggle-btn svg { display: block; width: 20px; height: 20px; }
.account-dropdown {
  position: absolute;
  top: calc(100% + 10px);
  right: 0;
  min-width: 240px;
  background: var(--bg-raised);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: var(--shadow);
  padding: 6px;
  z-index: 200;
}
/* Dropdown តូចៗ (Account Menu ខាងលើ + Search Suggestion ខាងក្រោម) ធ្លាប់លេចឡើងភ្លាមៗគ្មាន Animation
   ទាល់តែសោះ (ខុសពី Modal/Drawer ដែលមាន Fade/Slide រួចហើយ) — មិនស៊ីគ្នា។ Duration ខ្លីជាង Modal ដោយចេតនា
   (0.18s vs 0.28-0.32s) ព្រោះ Dropdown តូច/ជិត Element ដើមគួរមានអារម្មណ៍រហ័សជាង Modal ពេញអេក្រង់ — Browser
   Trigger Animation នេះស្វ័យប្រវត្តិរាល់ពេល display ប្តូរពី none ទៅ Value ធម្មតា (ដូចគ្នាបេះបិទនឹង
   .modal-overlay:not(.hidden) ខាងក្រោម) គ្មានចាំបាច់កែ JS ឡើយ — បិទវិញនៅតែភ្លាមៗ (Dropdown ខ្នាតតូច
   Snap ចេញភ្លាមៗជាទម្លាប់ធម្មតារបស់ Website ភាគច្រើន មិនចាំបាច់ Animation ចេញដូច Modal ធំៗទេ) */
@keyframes dropdownFadeIn { from { opacity: 0; transform: translateY(-6px); } to { opacity: 1; transform: translateY(0); } }
.account-dropdown:not(.hidden) { animation: dropdownFadeIn 0.18s cubic-bezier(0.16, 1, 0.3, 1); }
@media (prefers-reduced-motion: reduce) {
  .account-dropdown:not(.hidden) { animation: none; }
}
.account-dropdown-header {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 10px 12px 12px;
  margin-bottom: 4px;
  border-bottom: 1px solid var(--border);
}
#user-greeting { color: var(--cream); font-size: 0.92rem; font-weight: 700; }
.account-dropdown .member-badge { align-self: flex-start; }
/* display:flex (ពីមុន block) — ត្រូវការសម្រាប់តម្រឹម Icon SVG ខាងក្រោមឲ្យស្របជួរជាមួយអក្សរ (មិនប៉ះពាល់ .mobile-menu-account-items
   .account-dropdown-item ដែលកំណត់ display:flex ដដែលស្រាប់ ជា Selector ជាក់លាក់ជាង) */
.account-dropdown-item {
  display: flex;
  align-items: center;
  width: 100%;
  text-align: left;
  background: none;
  border: none;
  color: var(--cream);
  font-family: inherit;
  font-size: 0.88rem;
  padding: 10px 12px;
  border-radius: 8px;
  cursor: pointer;
}
.account-dropdown-item:hover { background: var(--bg-card); }
.account-dropdown-item-danger { margin-top: 4px; border-top: 1px solid var(--border); border-radius: 0 0 8px 8px; padding-top: 12px; color: var(--red); }
/* Icon SVG ស្តើង (currentColor) មុនអក្សរ — ដូចគ្នានឹង Icon ក្នុង Mobile Drawer (#btn-mobile-purchases/#btn-mobile-logout ខាងក្រោម)
   ::before (មិនមែន Real Text) កុំឲ្យ i18n.js (ដែលកំណត់ textContent) លុបវាចោលពេលប្តូរភាសា */
#btn-account-settings::before { content: ''; width: 16px; height: 16px; margin-right: 10px; flex-shrink: 0; background: currentColor; -webkit-mask: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%222%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cpath%20d%3D%22M19%2021v-2a4%204%200%200%200-4-4H9a4%204%200%200%200-4%204v2%22%2F%3E%3Ccircle%20cx%3D%2212%22%20cy%3D%227%22%20r%3D%224%22%2F%3E%3C%2Fsvg%3E") center / contain no-repeat; mask: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%222%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cpath%20d%3D%22M19%2021v-2a4%204%200%200%200-4-4H9a4%204%200%200%200-4%204v2%22%2F%3E%3Ccircle%20cx%3D%2212%22%20cy%3D%227%22%20r%3D%224%22%2F%3E%3C%2Fsvg%3E") center / contain no-repeat; }
#btn-my-purchases::before { content: ''; width: 16px; height: 16px; margin-right: 10px; flex-shrink: 0; background: currentColor; -webkit-mask: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%222%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cpath%20d%3D%22M4%202v20l2-1%202%201%202-1%202%201%202-1%202%201%202-1%202%201V2l-2%201-2-1-2%201-2-1-2%201-2-1-2%201Z%22%2F%3E%3Cpath%20d%3D%22M16%208h-6a2%202%200%201%200%200%204h4a2%202%200%201%201%200%204H8%22%2F%3E%3Cpath%20d%3D%22M12%2017.5v-11%22%2F%3E%3C%2Fsvg%3E") center / contain no-repeat; mask: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%222%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cpath%20d%3D%22M4%202v20l2-1%202%201%202-1%202%201%202-1%202%201%202-1%202%201V2l-2%201-2-1-2%201-2-1-2%201-2-1-2%201Z%22%2F%3E%3Cpath%20d%3D%22M16%208h-6a2%202%200%201%200%200%204h4a2%202%200%201%201%200%204H8%22%2F%3E%3Cpath%20d%3D%22M12%2017.5v-11%22%2F%3E%3C%2Fsvg%3E") center / contain no-repeat; }
#btn-logout::before { content: ''; width: 16px; height: 16px; margin-right: 10px; flex-shrink: 0; background: currentColor; -webkit-mask: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%222%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cpath%20d%3D%22M9%2021H5a2%202%200%200%201-2-2V5a2%202%200%200%201%202-2h4%22%2F%3E%3Cpolyline%20points%3D%2216%2017%2021%2012%2016%207%22%2F%3E%3Cline%20x1%3D%2221%22%20x2%3D%229%22%20y1%3D%2212%22%20y2%3D%2212%22%2F%3E%3C%2Fsvg%3E") center / contain no-repeat; mask: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%222%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cpath%20d%3D%22M9%2021H5a2%202%200%200%201-2-2V5a2%202%200%200%201%202-2h4%22%2F%3E%3Cpolyline%20points%3D%2216%2017%2021%2012%2016%207%22%2F%3E%3Cline%20x1%3D%2221%22%20x2%3D%229%22%20y1%3D%2212%22%20y2%3D%2212%22%2F%3E%3C%2Fsvg%3E") center / contain no-repeat; }

/* សមតុល្យ Wallet — ប៊ូតុងតូចក្នុង Header ខ្លួនឯង (រវាង Logo/Search និង Theme Toggle) ដាច់ដោយឡែកទាំងស្រុងពី
   សមាជិកភាព Premium (.member-badge) — ដូចគ្នាទាំង Desktop និង Mobile (មើល @media ≤720px ខាងក្រោម ដែល
   ទុកចន្លោះនេះនៅតែបង្ហាញនៅជួរទី ១ ខណៈពេលដែលធាតុ Header ផ្សេងទៀតទាំងអស់ផ្លាស់ទីទៅ Hamburger Drawer) */
.wallet-header-btn {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 5px 10px;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 999px;
  color: var(--cream);
  font-family: inherit;
  cursor: pointer;
  flex-shrink: 0;
}
.wallet-header-btn:hover { border-color: var(--gold); }
.wallet-header-icon {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--gold-tint);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.85rem;
  flex-shrink: 0;
}
.wallet-header-text { display: flex; flex-direction: column; align-items: flex-start; line-height: 1.15; }
#wallet-header-balance { font-weight: 700; font-size: 0.82rem; color: var(--cream); white-space: nowrap; }
.wallet-header-topup { font-size: 0.66rem; color: var(--gold-soft); font-weight: 600; white-space: nowrap; }

/* ---------- Mobile menu (Hamburger → Slide-in Drawer) — លាក់ដោយ Default, បង្ហាញតែក្នុង Mobile Media Query ខាងក្រោម ---------- */
/* ធាតុថ្មីទាំងអស់នេះ មិនប៉ះពាល់ Desktop ទេ ព្រោះ Class ថ្មីទាំងស្រុង + display:none លំនាំដើម —
   .mobile-menu-wrap ខ្លួនឯង display:none លើ Desktop ដូច្នេះកូនចៅខាងក្នុង (Position:fixed ក៏ដោយ) មិនដែលបង្ហាញទេ */
/* User រាយការណ៍ថា Hamburger Icon បាត់ពេល Modal ណាមួយបើក (Register/Login/Account/Payment History/
   Membership) — Root Cause៖ #mobile-menu-wrap ធ្លាប់ជា Descendant នៃ .site-header ដែលមាន
   position:sticky+z-index:40 ជានិច្ច (បង្កើត Stacking Context) ដូច្នេះ Descendant ណាមួយ (រួមទាំង Button
   នេះ ទោះមាន z-index ខ្ពស់ប៉ុន្មានក៏ដោយ) មិនអាចរួចផុតទៅលើ .modal-overlay (z-index:100) បានឡើយ ព្រោះជាប់
   កំណត់ត្រឹម Header ខ្លួនឯង (z:40) ជានិច្ច — ដូច្នេះ Move #mobile-menu-wrap ចេញទៅជា Sibling ក្រៅ <header>
   ទាំងស្រុង (មើល index.html) ដើម្បីរួចផុតពី Stacking Context នេះ ហើយ Position ត្រឹមតែផ្ទាល់ខ្លួន (Fixed)
   ដើម្បីមើលទៅដូចដើមទាំងស្រុង (Pixel-Measured៖ top:12px ស្មើ Header padding-top, left:5px ស្មើ Header
   padding-left 16px ដក Margin-Left -11px ចាស់) */
.mobile-menu-wrap { position: relative; display: none; }
@media (max-width: 720px) {
  .mobile-menu-wrap {
    position: fixed;
    top: 12px;
    left: 5px;
    z-index: 302;
    /* User រាយការណ៍ថា ☰ "រត់តាម Scroll" (ផ្លាស់ទីតាម Content ខណៈកំពុង Scroll ជំនួសនៅនឹងកន្លែងថេរ) — iOS
       Safari មាន Bug ស្គាល់ស្រាប់ដូចគ្នានឹង .mobile-bottom-nav ខាងក្រោម៖ position:fixed ខ្វះ Compositor
       Layer ផ្ទាល់ខ្លួន ជួនកាល "អូស"/យឺតតាម Content ខណៈ Momentum Scroll (កាន់តែងាយកើតលើ Body-Level Element
       ថ្មីៗដូចនេះ) — បង្ខំ Compositor Layer ដូចគ្នាដោះស្រាយ */
    transform: translateZ(0);
    -webkit-transform: translateZ(0);
    will-change: transform;
    /* User ស្នើដោយផ្ទាល់ជុំចុងក្រោយ៖ "ធ្វើអោយវាបង្ហាញបែប Smooth ទន់ៗ" ក្រោយពីព្យាយាម Instant (គ្មាន
       Animation ទាល់តែសោះ) មិនដោះស្រាយអារម្មណ៍ "លោត" បានពេញលេញ — ត្រឡប់មក Animate វិញ ប៉ុន្តែ Opacity
       ម្នាក់ឯង (មិនមាន Transform/Slide ដូចជុំមុនទៀតទេ ព្រោះ Slide ជាមូលហេតុគួរឲ្យសង្ស័យនៃ "លោត" ដើម) —
       Fade ស្រាលៗ 0.25s មិនមាន Motion ណាមួយឲ្យមើលទៅដូច "លោត" ថែមទៀត */
    transition: opacity 0.25s ease;
  }
  .mobile-menu-wrap.scroll-hidden {
    opacity: 0;
    pointer-events: none;
  }
}
@media (prefers-reduced-motion: reduce) {
  .mobile-menu-wrap { transition: none; }
}
.mobile-menu-btn {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  /* គ្មានរង្វង់/ផ្ទៃ — ☰ ជា icon ស្រាលតែម្នាក់ឯង (ងាយតម្រឹមគែមឆ្វេងជាមួយ Content)។ ពណ៌ថេរស (មិនប្រើ --cream ទេ) ព្រោះ
     .site-header នៅតែងងឹតក្នុង Light Theme ដែល --cream ក្លាយជាពណ៌ងងឹត (មើលមិនឃើញលើផ្ទៃងងឹត)។ User ស្នើដកចេញ
     Background/Blur ដែលធ្លាប់សាកល្បង (ត្រឡប់ទៅ Design ដើមវិញ) — ដោះស្រាយ "☰ រត់តាម Scroll" ដោយ Scroll-Hide
     ជំនួសវិញ (មើល .mobile-menu-wrap.scroll-hidden ខាងលើ + app.js) */
  border: none;
  background: none;
  color: #f1f1f1;
  cursor: pointer;
  align-items: center;
  justify-content: center;
  -webkit-tap-highlight-color: transparent;
}
/* Spacer ជំនួសកន្លែងទំនេរក្នុង Header (មើល index.html) — #mobile-menu-wrap ខ្លួនឯង Move ចេញទៅ Body-Level
   ហើយទៅជា position:fixed ដូច្នេះលែងកាន់កាប់ទំហំក្នុង Flex Row នេះទៀតទេ — Spacer នេះរក្សាទំហំដដែល (29px —
   Pixel-Measured ស្មើនឹង Flex-Item Width ចាស់របស់ .mobile-menu-wrap រួមទាំង Margin-Left -11px ចាស់) ដើម្បី
   កុំឲ្យ .brand ខាងស្តាំផ្លាស់ទី */
.mobile-menu-btn-spacer { display: none; }
@media (max-width: 720px) {
  .mobile-menu-btn-spacer { display: block; width: 29px; height: 40px; flex-shrink: 0; }
}
.mobile-menu-btn svg { width: 26px; height: 26px; }
.mobile-menu-btn:active { background: rgba(255, 255, 255, 0.1); }
.mobile-menu-backdrop {
  position: fixed;
  /* top/left:0 + vw/dvh (មិនមែន inset:0 ដែលប្រើ right/bottom ជា % ទេ) ព្រោះ .site-header មាន
     backdrop-filter ខ្លួនឯង (style.css:79) ដែលធ្វើឲ្យវាក្លាយជា Containing Block សម្រាប់ Descendant
     position:fixed ណាមួយ (Backdrop នេះជា Descendant របស់ .mobile-menu-wrap ដែលនៅក្នុង .site-header) —
     inset:0 (=right/bottom:0) នឹងគណនាទំហំតាម Containing Block នោះ (ខ្ពស់ត្រឹមតែ ~68px របស់ Header ខ្លួនឯង
     មិនមែនពេញអេក្រង់ទេ) ធ្វើឲ្យផ្ទាំងក្រោម Header លេចមិនត្រូវបានការពារ ចុចទម្លុះទៅដល់ Video Card ពិតបាន —
     width:100vw/height:100dvh ជា Viewport Unit ដូចគ្នានឹង .mobile-menu-dropdown ខាងក្រោម (មិនរងផលប៉ះពាល់ពី
     Containing Block ណាមួយឡើយ) ដោះស្រាយបញ្ហានេះទាំងស្រុង */
  top: 0;
  left: 0;
  width: 100vw;
  height: 100dvh;
  background: rgba(8, 6, 20, 0.65);
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease;
  z-index: 300;
}
/* Premium streaming-app style drawer — dark navy/charcoal "glass" panel intentionally NOT wired to
   the site's light/dark theme toggle (same technique as .modal-auth below) so it reads as one
   consistent premium surface no matter which site theme is active. The --drawer-* variables are
   scoped to this subtree only and never touch the global theme variables. User រាយការណ៍ថា Drawer
   ពណ៌ស្វាយ (Indigo/Purple) ខ្លាំងពេក ខុសពី Dashboard/Header ដែលប្រើ Dark Navy/Black — ជុំដំបូងប្តូរទៅ
   Charcoal-Navy ស្រទន់ជិត --bg/--bg-card សកល ប៉ុន្តែនោះនៅតែខុសពី .site-header ពិត (rgba(18,21,42,.85)
   ជា Navy-Blue ច្បាស់) ដូច្នេះជុំនេះប្តូរ --drawer-navy/-deep/-indigo ម្តងទៀតឲ្យផ្គូផ្គង Hue ជាមួយ Header
   ដដែលដោយផ្ទាល់ (មិនប្រើ var() ផ្ទាល់ ដើម្បីរក្សា Drawer ឲ្យតែងតែងងឹត ទោះ Site ប្តូរទៅ Light Theme ក៏ដោយ) —
   --drawer-purple ដកចេញទាំងស្រុង ជំនួសដោយ --drawer-blue-deep (ខៀវជ្រៅ) សម្រាប់ Gradient/Glow ដែលធ្លាប់ចាប់ជាមួយ Purple */
.mobile-menu-dropdown {
  --drawer-navy: #12152a;
  --drawer-navy-deep: #090b18;
  --drawer-indigo: #1a1e3d;
  --drawer-gold: #d8b06a;
  --drawer-gold-soft: #eccb8f;
  --drawer-text: #f2eee3;
  --drawer-muted: #9a9aa5;
  --drawer-border: rgba(255, 255, 255, 0.1);
  --drawer-blue: #4f8cff;
  --drawer-blue-deep: #2f5fc4;

  position: fixed;
  top: 0;
  left: 0;
  height: 100dvh;
  width: 84vw;
  max-width: 340px;
  background: linear-gradient(165deg, var(--drawer-indigo) 0%, var(--drawer-navy) 55%, var(--drawer-navy-deep) 100%);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  border: 1px solid var(--drawer-border);
  border-radius: 0 26px 26px 0;
  box-shadow: 10px 0 50px rgba(0, 0, 0, 0.55), 0 0 40px rgba(0, 0, 0, 0.3), inset 1px 0 0 rgba(255, 255, 255, 0.04);
  color: var(--drawer-text);
  padding: 14px 10px 16px;
  z-index: 301;
  overflow-y: auto;
  overflow-x: hidden;
  transform: translateX(-100%);
  transition: transform 0.35s cubic-bezier(0.22, 1, 0.36, 1);
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.mobile-menu-wrap.open .mobile-menu-backdrop { opacity: 1; pointer-events: auto; }
.mobile-menu-wrap.open .mobile-menu-dropdown { transform: translateX(0); }
.mobile-menu-close-btn {
  width: 34px;
  height: 34px;
  flex-shrink: 0;
  border-radius: 50%;
  border: 1px solid var(--drawer-border);
  background: rgba(255, 255, 255, 0.04);
  color: var(--drawer-text);
  font-size: 0.9rem;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: box-shadow 0.15s ease, border-color 0.15s ease, background 0.15s ease;
}
/* ប៊ូតុងបិទស្ថិតក្នុងជួរ Avatar (.mobile-menu-user) — តម្រឹមខាងលើស្តាំ ដើម្បីនៅតែនៅកន្លែងដដែលទោះភ្ញៀវ
   (មានប៊ូតុង ចូលគណនី/ចុះឈ្មោះ ខាងក្រោមឈ្មោះ) ធ្វើឲ្យជួរខ្ពស់ជាងមុនក៏ដោយ */
.mobile-menu-user .mobile-menu-close-btn { align-self: flex-start; margin-left: auto; }
.mobile-menu-close-btn:hover,
.mobile-menu-close-btn:active {
  border-color: var(--drawer-blue);
  background: rgba(79, 140, 255, 0.15);
  box-shadow: 0 0 12px rgba(79, 140, 255, 0.35);
}
.mobile-menu-categories {
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding-bottom: 8px;
}
.mobile-menu-categories .sidebar-item {
  width: 100%;
  gap: 12px;
  padding: 8px 12px;
  border-radius: 13px;
  color: var(--drawer-text);
  background: rgba(255, 255, 255, 0.03);
  transition: background 0.15s ease, box-shadow 0.15s ease;
}
.mobile-menu-categories .sidebar-item::after {
  content: '›';
  margin-left: auto;
  padding-left: 8px;
  color: var(--drawer-muted);
  font-size: 1.1rem;
  line-height: 1;
  opacity: 0.6;
}
.mobile-menu-categories .sidebar-item:hover { background: rgba(255, 255, 255, 0.07); }
/* ខណៈកំពុងរង់ចាំខ្លឹមសារថ្មី (មុននឹង Drawer បិទ) — មើលកំណត់ចំណាំក្នុង app.js ("is-pending" Handler) —
   ធ្វើឲ្យស្រអាប់ស្រាល + ទប់ស្កាត់ចុចទ្វេដង ដើម្បីប្រាប់ថាការចុចត្រូវបានទទួល ខណៈកំពុងផ្ទុក */
.mobile-menu-categories .sidebar-item.is-pending { opacity: 0.55; pointer-events: none; }
.mobile-menu-categories .sidebar-item.active {
  background: linear-gradient(135deg, var(--drawer-blue), var(--drawer-blue-deep));
  color: #fff;
  font-weight: 700;
  box-shadow: 0 4px 16px rgba(79, 140, 255, 0.35);
}
.mobile-menu-categories .sidebar-item.active::after { color: rgba(255, 255, 255, 0.85); opacity: 1; }
/* Premium category row keeps a gold accent (icon glow always-on, gold gradient when selected)
   distinct from the blue gradient every other item uses when active */
/* Icon ជា SVG ស្តើង (currentColor) ជំនួស Emoji — ស្របគ្នាគ្រប់ឧបករណ៍ (Emoji ខុសគ្នាតាម iOS/Android) */
.mobile-menu-categories .sidebar-icon { width: 22px; height: 22px; display: inline-flex; align-items: center; justify-content: center; color: var(--drawer-muted); }
.mobile-menu-categories .sidebar-icon svg { width: 19px; height: 19px; }
.mobile-menu-categories .sidebar-item.active .sidebar-icon { color: currentColor; }
.mobile-menu-categories #drawer-item-premium .sidebar-icon { color: var(--drawer-gold-soft); }
.mobile-menu-categories #drawer-item-premium.active {
  background: linear-gradient(135deg, var(--drawer-gold), #b5883f);
  color: #1a1330;
  box-shadow: 0 4px 16px rgba(216, 176, 106, 0.4);
}
.mobile-menu-categories #drawer-item-premium.active::after { color: rgba(26, 19, 48, 0.7); }
.mobile-menu-account-items {
  border-top: 1px solid var(--drawer-border);
  margin-top: 4px;
  padding-top: 6px;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.mobile-menu-account-items .account-dropdown-item {
  display: flex;
  align-items: center;
  width: 100%;
  color: var(--drawer-muted);
  border-radius: 14px;
  padding: 9px 14px;
  transition: background 0.15s ease;
}
.mobile-menu-account-items .account-dropdown-item:hover { background: rgba(255, 255, 255, 0.06); }
/* Icons via ::before mask SVG (not real text) — safe against i18n.js overwriting textContent on language switch;
   Mask ប្រើ currentColor ដូច្នេះ ចាកចេញ (ក្រហម) ឆ្លាស់ពណ៌តាមអក្សរ */
.mobile-menu-account-items #btn-mobile-purchases::before { content: ''; width: 18px; height: 18px; margin-right: 12px; flex-shrink: 0; background: currentColor; -webkit-mask: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%222%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cpath%20d%3D%22M4%202v20l2-1%202%201%202-1%202%201%202-1%202%201%202-1%202%201V2l-2%201-2-1-2%201-2-1-2%201-2-1-2%201Z%22%2F%3E%3Cpath%20d%3D%22M16%208h-6a2%202%200%201%200%200%204h4a2%202%200%201%201%200%204H8%22%2F%3E%3Cpath%20d%3D%22M12%2017.5v-11%22%2F%3E%3C%2Fsvg%3E") center / contain no-repeat; mask: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%222%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cpath%20d%3D%22M4%202v20l2-1%202%201%202-1%202%201%202-1%202%201%202-1%202%201V2l-2%201-2-1-2%201-2-1-2%201-2-1-2%201Z%22%2F%3E%3Cpath%20d%3D%22M16%208h-6a2%202%200%201%200%200%204h4a2%202%200%201%201%200%204H8%22%2F%3E%3Cpath%20d%3D%22M12%2017.5v-11%22%2F%3E%3C%2Fsvg%3E") center / contain no-repeat; }
.mobile-menu-account-items #btn-mobile-logout::before { content: ''; width: 18px; height: 18px; margin-right: 12px; flex-shrink: 0; background: currentColor; -webkit-mask: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%222%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cpath%20d%3D%22M9%2021H5a2%202%200%200%201-2-2V5a2%202%200%200%201%202-2h4%22%2F%3E%3Cpolyline%20points%3D%2216%2017%2021%2012%2016%207%22%2F%3E%3Cline%20x1%3D%2221%22%20x2%3D%229%22%20y1%3D%2212%22%20y2%3D%2212%22%2F%3E%3C%2Fsvg%3E") center / contain no-repeat; mask: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%222%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cpath%20d%3D%22M9%2021H5a2%202%200%200%201-2-2V5a2%202%200%200%201%202-2h4%22%2F%3E%3Cpolyline%20points%3D%2216%2017%2021%2012%2016%207%22%2F%3E%3Cline%20x1%3D%2221%22%20x2%3D%229%22%20y1%3D%2212%22%20y2%3D%2212%22%2F%3E%3C%2Fsvg%3E") center / contain no-repeat; }
.mobile-menu-account-items .account-dropdown-item-danger {
  margin-top: 2px;
  border-top: 1px solid var(--drawer-border);
  border-radius: 14px;
  padding-top: 10px;
  color: #ff8a8a;
}

/* ភ្ញៀវ (មិនចូលគណនី) — ប៊ូតុង 👤 លាក់លើ Desktop ដោយ Default ព្រោះជា Component សម្រាប់ Mobile ប៉ុណ្ណោះ */
#mobile-guest-avatar-wrap { display: none; }

/* ---------- Drawer User Block (Avatar + ឈ្មោះ) — Sync ដោយ renderAuthUI() ---------- */
.mobile-menu-user {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 0 4px 14px 6px;
  margin-bottom: 6px;
  border-bottom: 1px solid var(--drawer-border);
}
.mobile-menu-user-avatar {
  width: 54px;
  height: 54px;
  border-radius: 50%;
  background: linear-gradient(135deg, var(--drawer-blue), var(--drawer-blue-deep));
  color: #fff;
  font-weight: 700;
  font-size: 1.3rem;
  font-family: 'Battambang', sans-serif;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  overflow: hidden;
  box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.08), 0 0 16px rgba(79, 140, 255, 0.35);
}
.mobile-menu-user-avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Avatar + ឈ្មោះ ចុចបាន (ចូលគណនីរួច) — Badge ✎ ជាសញ្ញាកែបាន; ភ្ញៀវមិនបង្ហាញ Badge/Hint */
.mobile-menu-user-avatar-wrap { position: relative; flex-shrink: 0; border-radius: 50%; }
.mobile-menu-user-edit {
  position: absolute;
  right: -3px;
  bottom: -3px;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--drawer-navy);
  border: 1.5px solid rgba(255, 255, 255, 0.35);
  color: var(--drawer-text);
  display: flex;
  align-items: center;
  justify-content: center;
}
.mobile-menu-user-edit svg { width: 11px; height: 11px; }
.mobile-menu-user-hint { display: block; color: var(--drawer-muted); font-size: 0.78rem; line-height: 1.3; }
.mobile-menu-user-hint::after { content: ' ›'; }
.mobile-menu-user:not(.is-clickable) .mobile-menu-user-edit,
.mobile-menu-user:not(.is-clickable) .mobile-menu-user-hint,
/* ភ្ញៀវ — មិនបង្ហាញពាក្យ "ភ្ញៀវ" (Avatar + ប៊ូតុង ចូលគណនី/ចុះឈ្មោះ ប្រាប់ស្ថានភាពរួចហើយ) */
.mobile-menu-user:not(.is-clickable) .mobile-menu-user-name { display: none; }
.mobile-menu-user.is-clickable { cursor: pointer; -webkit-tap-highlight-color: transparent; }
.mobile-menu-user.is-clickable:active .mobile-menu-user-avatar { opacity: 0.85; }
.mobile-menu-user-avatar-wrap:focus-visible { outline: 2px solid var(--drawer-gold); outline-offset: 3px; }
.mobile-menu-user-meta { min-width: 0; flex: 1; }
.mobile-menu-user-name {
  display: block;
  color: var(--drawer-text);
  font-weight: 700;
  font-size: 1.02rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* សមាជិក Premium — រង្វង់មាសជុំវិញ Avatar + មកុដតូចនៅជ្រុងខាងលើស្តាំ (ជំនួស Badge អក្សរ "👑 Premium") — visibility driven
   purely by CSS :has(), reading the existing #mobile-membership-status.hidden toggle that renderMemberBadge() (app.js)
   already maintains. Zero new JS: this is the same state the existing membership card below already reacts to. */
.mobile-menu-user-crown {
  position: absolute;
  right: -4px;
  top: -4px;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: linear-gradient(135deg, var(--drawer-gold-soft), #b5883f);
  border: 1.5px solid var(--drawer-navy);
  color: #1a1330;
  display: none;
  align-items: center;
  justify-content: center;
}
.mobile-menu-user-crown svg { width: 12px; height: 12px; }
.mobile-menu-dropdown:has(#mobile-membership-status:not(.hidden)) .mobile-menu-user-crown { display: flex; }
.mobile-menu-dropdown:has(#mobile-membership-status:not(.hidden)) .mobile-menu-user-avatar {
  box-shadow: 0 0 0 2.5px var(--drawer-gold), 0 0 16px rgba(216, 176, 106, 0.5);
}
.mobile-menu-guest-actions { display: flex; gap: 8px; }
.mobile-menu-guest-actions .btn { flex: 1; text-align: center; min-height: 38px; padding: 8px 10px; font-size: 0.85rem; }
.mobile-menu-guest-actions .btn-primary { background: linear-gradient(135deg, var(--drawer-gold), #b5883f); color: #1a1330; }
.mobile-menu-guest-actions .btn-ghost { background: rgba(255, 255, 255, 0.04); border-color: var(--drawer-border); color: var(--drawer-text); }
.mobile-menu-guest-actions .btn-ghost:hover { border-color: var(--drawer-gold); }

/* ---------- Drawer Settings (ភាសា/Theme) — ហៅ Function ពិតដែលមានស្រាប់ (window.i18n / window.theme) ---------- */
.mobile-menu-settings {
  border-top: 1px solid var(--drawer-border);
  padding-top: 8px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.mobile-menu-setting-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 2px 12px;
}
.mobile-menu-setting-label { color: var(--drawer-text); font-size: 0.88rem; display: inline-flex; align-items: center; gap: 10px; }
.mobile-menu-setting-label svg { width: 19px; height: 19px; color: var(--drawer-muted); flex-shrink: 0; }
.mobile-menu-toggle-group {
  display: flex;
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid var(--drawer-border);
  border-radius: 999px;
  padding: 2px;
  gap: 2px;
}
.mobile-menu-toggle-btn {
  border: none;
  background: none;
  color: var(--drawer-muted);
  font-family: inherit;
  font-size: 0.8rem;
  font-weight: 700;
  padding: 5px 14px;
  border-radius: 999px;
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease;
}
.mobile-menu-toggle-btn.active {
  background: linear-gradient(135deg, var(--drawer-blue), var(--drawer-blue-deep));
  color: #fff;
}

/* ---------- Mobile Bottom Navigation — លាក់លើ Desktop ដោយ Default ---------- */
.mobile-bottom-nav { display: none; }

/* Row នៃ ចូលគណនី/ចុះឈ្មោះ — display:contents លើ Desktop មានន័យថាមិនបង្កើត Box អ្វីសោះ
   (btn-login/btn-register នៅតែជា Flex Item ផ្ទាល់របស់ .header-actions ដដែល Desktop មិនប៉ះពាល់ទាល់តែសោះ) */
.header-auth-actions { display: contents; }

.link-btn {
  background: none;
  border: none;
  color: var(--muted);
  cursor: pointer;
  font-family: inherit;
  font-size: 0.92rem;
}
.link-btn:hover { color: var(--gold-soft); }

/* ប៊ូតុង "សមាជិកភាព" ក្នុង Header (Desktop) — Pill ផ្ទៃមាសស្រាល + មកុដ (ជម្រើស C ដែលបានជ្រើសរើសពី Preview) —
   ជំនួស .link-btn អក្សរទទេ ដែលមើលទៅមិនទាក់ទាញ ខណៈ Pill ជិតខាង (កាបូប/Theme/EN) សុទ្ធតែមានផ្ទៃ+Border។ លាក់លើ
   Mobile ដោយ Rule "body:has(#mobile-menu-wrap) .header-actions #btn-open-pricing" ខាងក្រោមដដែល (ប្រើកាត Premium ក្នុង Drawer) */
.header-membership-btn {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 8px 16px;
  border-radius: 999px;
  border: 1px solid rgba(230, 184, 92, 0.5);
  background: rgba(230, 184, 92, 0.13);
  color: #f0c56e;
  font-family: inherit;
  font-size: 0.92rem;
  font-weight: 700;
  line-height: 1.2;
  white-space: nowrap;
  cursor: pointer;
  flex-shrink: 0;
  transition: background 0.15s ease, border-color 0.15s ease, transform 0.1s ease;
}
.header-membership-btn svg { width: 16px; height: 16px; flex-shrink: 0; }
.header-membership-btn:hover { background: rgba(230, 184, 92, 0.22); border-color: rgba(230, 184, 92, 0.75); }
.header-membership-btn:active { transform: scale(0.97); }
.header-membership-btn:focus-visible { outline: 2px solid #f0c56e; outline-offset: 2px; }
/* Light Theme — .site-header នៅតែជាបារងងឹត (rgba(18,21,42,.85) មិនប្តូរតាម Theme) ជាមួយ Pill ពណ៌សជិតខាង (កាបូប/
   Theme/EN) — ដូច្នេះប្រើ Pill ស/ក្រែម + អក្សរមាសចាស់ ស្របនឹង Pill ជិតខាង (មាសខ្មៅលើផ្ទៃងងឹតមើលស្ទើរមិនឃើញ) */
:root[data-theme="light"] .header-membership-btn { color: #7a4e00; background: #fff8e6; border-color: #e6b85c; }
:root[data-theme="light"] .header-membership-btn:hover { background: #ffefc2; border-color: #d9a13a; }

.member-badge {
  background: var(--gold-tint);
  border: 1px solid var(--border);
  color: var(--gold-soft);
  font-size: 0.8rem;
  font-weight: 700;
  padding: 6px 12px;
  border-radius: 999px;
  white-space: nowrap;
}

.theme-toggle-btn {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: var(--bg-card);
  color: var(--cream);
  font-size: 0.95rem;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: border-color 0.15s ease, transform 0.15s ease;
}
.theme-toggle-btn:hover { border-color: var(--gold); transform: rotate(15deg); }

.lang-toggle-btn {
  height: 34px;
  padding: 0 12px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--bg-card);
  color: var(--cream);
  font-family: inherit;
  font-size: 0.82rem;
  font-weight: 700;
  cursor: pointer;
  transition: border-color 0.15s ease;
}
.lang-toggle-btn:hover { border-color: var(--gold); }

.btn {
  border: 1px solid transparent;
  border-radius: 999px;
  padding: 9px 20px;
  font-family: 'Battambang', sans-serif;
  font-size: 0.92rem;
  cursor: pointer;
  transition: transform 0.15s ease, background 0.15s ease;
}
.btn:active { transform: scale(0.97); }
.btn-primary { background: var(--gold); color: #fff; font-weight: 700; }
.btn-primary:hover { background: var(--gold-soft); }
.btn-ghost { background: transparent; border-color: var(--border); color: var(--cream); }
.btn-ghost:hover { border-color: var(--gold); }
.btn-lg { padding: 13px 30px; font-size: 1.02rem; }
.btn-block { width: 100%; }
.hidden { display: none !important; }

/* ---------- Pagination (Video Grid) ---------- */
.pagination {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  margin: 32px 0 8px;
  flex-wrap: wrap;
}
.pagination-btn {
  border: 1px solid var(--border);
  background: var(--bg-card);
  color: var(--cream);
  border-radius: 999px;
  font-family: 'Battambang', sans-serif;
  font-size: 0.88rem;
  padding: 8px 16px;
  cursor: pointer;
  transition: border-color 0.15s ease, background 0.15s ease;
}
.pagination-btn:hover:not(:disabled) { border-color: var(--gold); }
.pagination-btn:disabled { opacity: 0.4; cursor: not-allowed; }
.pagination-numbers { display: flex; align-items: center; gap: 6px; }
.pagination-num {
  min-width: 38px;
  height: 38px;
  padding: 0 8px;
  border: 1px solid var(--border);
  background: var(--bg-card);
  color: var(--cream);
  border-radius: 999px;
  font-family: 'Battambang', sans-serif;
  font-size: 0.88rem;
  cursor: pointer;
}
.pagination-num:hover { border-color: var(--gold); }
.pagination-num.active { background: var(--gold); color: #fff; font-weight: 700; border-color: var(--gold); }
.pagination-ellipsis { color: var(--muted); padding: 0 4px; }
.pagination-compact-label { color: var(--cream); font-size: 0.9rem; padding: 0 6px; white-space: nowrap; }

/* Mobile — Prev/Page X/Next ប៉ុណ្ណោះ, លាក់ជួរលេខទំព័រធំ */
@media (max-width: 720px) {
  .pagination-numbers { display: none; }
}
/* Desktop — លាក់ Label បង្រួម, បង្ហាញជួរលេខទំព័រវិញ */
@media (min-width: 721px) {
  .pagination-compact-label { display: none; }
}

/* ---------- Video grid ---------- */
.section-title {
  font-size: 1.25rem;
  color: var(--gold-soft);
  margin: 0 0 8px;
  text-align: center;
}
main.wrap { padding-top: 48px; padding-bottom: 80px; max-width: 1800px; }

/* ---------- Home Sidebar (កំពុងមើលបន្ត/កំពុងពេញនិយម/ចំណូលចិត្ត) ---------- */
.home-layout { display: flex; gap: 24px; align-items: flex-start; }
.home-sidebar {
  flex: 0 0 200px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  position: sticky;
  /* .site-header ខ្លួនឯងជា sticky (top:0, កម្ពស់ ≈ 69px) — top:24px ចាស់ធ្វើឲ្យ Sidebar ជាប់ក្រោម Header
     (Item ខាងលើបាត់ពី View ពេល Scroll) — ត្រូវ Offset ឲ្យលើសកម្ពស់ Header ទើបជាប់នៅនឹងកន្លែងពិតប្រាកដ */
  top: 92px;
  /* បើអេក្រង់ទាបជាង Sidebar — ឲ្យ Scroll ក្នុង Sidebar ខ្លួនឯង ជំនួសឲ្យ Item ខាងក្រោម (Telegram Support)
     ហួសអេក្រង់ ដែលមិនអាចចូលដល់ */
  max-height: calc(100vh - 92px - 16px);
  overflow-y: auto;
  scrollbar-width: thin;
}
.sidebar-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 14px;
  border-radius: 8px;
  background: none;
  border: none;
  color: var(--cream);
  font-family: inherit;
  font-size: 0.9rem;
  cursor: pointer;
  text-align: left;
  transition: background 0.15s ease;
}
.sidebar-item:hover { background: var(--bg-card); }
.sidebar-item.active { background: var(--gold); color: #fff; font-weight: 700; }
.sidebar-icon { font-size: 1.1rem; flex-shrink: 0; line-height: 1; }
/* Sidebar Desktop — Icon ជា SVG ស្តើង (currentColor) ស្របនឹង Drawer Mobile (មើល .mobile-menu-categories .sidebar-icon) ជំនួស
   Emoji (Emoji ខុសគ្នាតាមប្រព័ន្ធប្រតិបត្តិការ) — Icon ពណ៌ស្រាល (--muted) ពេលធម្មតា, ស/ពណ៌អក្សរពេល Active, ហើយ Premium ជាមាស */
.home-sidebar .sidebar-icon { width: 22px; height: 22px; display: inline-flex; align-items: center; justify-content: center; color: var(--muted); }
.home-sidebar .sidebar-icon svg { width: 20px; height: 20px; }
.home-sidebar .sidebar-item:hover .sidebar-icon { color: var(--cream); }
.home-sidebar .sidebar-item.active .sidebar-icon { color: currentColor; }
.home-sidebar #sidebar-item-premium .sidebar-icon { color: #eccb8f; }
:root[data-theme="light"] .home-sidebar #sidebar-item-premium .sidebar-icon { color: #b5883f; }
.home-sidebar #sidebar-item-premium.active .sidebar-icon { color: currentColor; }
.sidebar-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ទាក់ទងជំនួយ Telegram — Item ចុងក្រោយក្នុង Sidebar ពិត (Desktop) និង Drawer Category List (Mobile) —
   Static Link ទាំងពីរ (reuse .sidebar-item សម្រាប់ Click Target/Layout មូលដ្ឋាន, មិនមែន View Filter
   ទេ) ប៉ុន្តែ Redesign ជា Premium Card ដាច់ដោយឡែក (Background/Border/Glow ផ្ទាល់ខ្លួន) ដូចគ្នានឹង
   .modal-auth/.mobile-menu-dropdown ធ្វើ — ប្រើ Color ថេរ (មិនមែន Theme Variable ទេ) ដេលចេតនាមិនប្តូរតាម
   Light/Dark Toggle ដើម្បីរក្សា Premium Look ស្ថិតស្ថេរជានិច្ច ដូចគ្នាទាំង Desktop/Mobile (មិនប៉ះពាល់
   Theme Variable សកលណាមួយឡើយ — Component នេះខ្លួនឯងគ្រាន់តែជ្រើសមិនប្រើ Variable ទាំងនោះ) */
.sidebar-item-telegram {
  text-decoration: none;
  align-items: center;
  gap: 12px;
  background: linear-gradient(135deg, rgba(62, 166, 255, 0.16), rgba(13, 20, 33, 0.6));
  border: 1px solid rgba(62, 166, 255, 0.35);
  border-radius: 12px;
  box-shadow: 0 0 14px rgba(62, 166, 255, 0.12);
  transition: background 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease, transform 0.1s ease;
}
.sidebar-item-telegram:hover {
  background: linear-gradient(135deg, rgba(62, 166, 255, 0.24), rgba(13, 20, 33, 0.66));
  border-color: rgba(62, 166, 255, 0.6);
  box-shadow: 0 0 20px rgba(62, 166, 255, 0.22);
}
.sidebar-item-telegram:active { transform: scale(0.98); }
.sidebar-icon-telegram {
  flex: 0 0 auto;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: linear-gradient(135deg, #4fb2ff, #1c6fb0);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 0 10px rgba(62, 166, 255, 0.45);
}
.sidebar-label-telegram { flex: 1; display: flex; flex-direction: column; gap: 2px; overflow: hidden; }
.sidebar-label-telegram-main {
  color: #fbfdff;
  font-size: 0.88rem;
  font-weight: 700;
  line-height: 1.2;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.sidebar-label-telegram-sub {
  color: rgba(255, 255, 255, 0.68);
  font-size: 0.7rem;
  line-height: 1.15;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.sidebar-label-telegram-user {
  color: #8fcbff;
  font-size: 0.68rem;
  line-height: 1.15;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.sidebar-telegram-arrow {
  flex: 0 0 auto;
  color: rgba(143, 203, 255, 0.85);
  font-size: 1rem;
  line-height: 1;
  transition: transform 0.15s ease, color 0.15s ease;
}
.sidebar-item-telegram:hover .sidebar-telegram-arrow { transform: translateX(2px); color: #8fcbff; }

/* Desktop Sidebar ពិត — Card ទំហំពេញលក្ខណៈ (~65-75px កម្ពស់) */
.home-sidebar .sidebar-item-telegram { margin-top: 8px; padding: 13px 14px; }

/* ក្នុង Row ផ្តេក (Tablet/ចង្អៀត — មើល @media max-width:860px ខាងក្រោម) — Card នៅតែរក្សាទំហំ Desktop
   ដដែល គ្រាន់តែកំណត់ Max-width កុំឲ្យវែងហួសហេតុក្នុងជួរផ្តេកដែលមាន Scroll ស្រាប់ (.home-sidebar
   overflow-x:auto) */
@media (max-width: 860px) {
  .home-sidebar .sidebar-item-telegram { margin-top: 0; max-width: 220px; }
}

/* Mobile Drawer — Category List ដដែល (មើល .mobile-menu-categories .sidebar-item ខាងលើ សម្រាប់ Rounded
   Row/Hover ដែលទទួលមកដោយស្វ័យប្រវត្តិរួចហើយ) — Card តូចជាង (~44-56px កម្ពស់): Padding/Icon/Font បន្ថយ
   បន្តិច ដូចគ្នានឹង Design Language ខាងលើដដែល គ្រាន់តែទំហំតូចជាង។ លាក់ Chevron "›" ដែលមានស្រាប់សម្រាប់
   Item ផ្សេងទៀត (.mobile-menu-categories .sidebar-item::after) ព្រោះ Item នេះប្រើ .sidebar-telegram-arrow
   ផ្ទាល់ខ្លួន (Arrow "→" ជាក់លាក់តាម Spec) ជំនួសវិញ */
/* Selector ចែករួមគ្នារវាង .mobile-menu-categories (Instance ភ្ញៀវ) និង .mobile-menu-account-items (Instance ចូលគណនីរួច
   ក្រោម "ប្រវត្តិទូទាត់") — Style ដូចគ្នាបេះបិទ ទោះស្ថិតក្នុង Container ណាមួយ */
.mobile-menu-categories .sidebar-item-telegram,
.mobile-menu-account-items .sidebar-item-telegram { margin: 8px 0; padding: 7px 12px; gap: 10px; }
.mobile-menu-categories .sidebar-item-telegram::after { content: none; }
.mobile-menu-categories .sidebar-icon-telegram,
.mobile-menu-account-items .sidebar-icon-telegram { width: 26px; height: 26px; }
.mobile-menu-categories .sidebar-icon-telegram svg,
.mobile-menu-account-items .sidebar-icon-telegram svg { width: 13px; height: 13px; }
.mobile-menu-categories .sidebar-label-telegram,
.mobile-menu-account-items .sidebar-label-telegram { gap: 1px; }
.mobile-menu-categories .sidebar-label-telegram-main,
.mobile-menu-account-items .sidebar-label-telegram-main { font-size: 0.74rem; line-height: 1.1; }
.mobile-menu-categories .sidebar-label-telegram-sub,
.mobile-menu-categories .sidebar-label-telegram-user,
.mobile-menu-account-items .sidebar-label-telegram-sub,
.mobile-menu-account-items .sidebar-label-telegram-user { font-size: 0.6rem; line-height: 1.05; }
.mobile-menu-categories .sidebar-telegram-arrow,
.mobile-menu-account-items .sidebar-telegram-arrow { font-size: 0.8rem; }

.home-content { flex: 1; min-width: 0; }

@media (max-width: 860px) {
  .home-layout { flex-direction: column; }
  .home-sidebar {
    /* flex: 0 0 200px ពី Desktop ជា "ទទឹង" (Row) — ត្រូវកំណត់ថ្មីទាំងស្រុងទីនេះ ព្រោះ
       .home-layout ប្តូរទៅ Column ធ្វើឲ្យ Flex-Basis ដដែលនោះក្លាយជា "កម្ពស់" 200px ជំនួសវិញ
       (បណ្តាលឲ្យ Sidebar Item ខ្ពស់ខុសប្រក្រតី) */
    flex: 0 0 auto;
    align-items: center; /* ការពារ Sidebar Item កុំឲ្យ Stretch ខ្ពស់ពេញ Container */
    position: static;
    max-height: none;
    flex-direction: row;
    overflow-x: auto;
    width: 100%;
    padding-bottom: 6px;
    scrollbar-width: thin;
  }
  .sidebar-item { flex: 0 0 auto; white-space: nowrap; }
}


/* User រាយការណ៍ថា Content ក្រោម Category Filter "លោត" ឡើង/ចុះ ពេលប្តូរ Tab (all↔trending/premium/...) —
   ដំបូង Fix ដោយ Animate Show/Hide (max-height Collapse) ប៉ុន្តែ User រាយការណ៍បន្តទៀតថា Content នៅតែ
   "លោត" មើលទៅ ព្រោះ Content ខាងក្រោមនៅតែផ្លាស់ទី Position រាល់ពេល Category Bar Collapse/Expand ទោះជា
   Animate រលូនក៏ដោយ — ដូច្នេះប្តូរ Architecture ទាំងស្រុង៖ Category Bar ក្លាយជា Persistent ជានិច្ច (មិន
   Hide/Collapse/Unmount ទៀតទេ — Height/Position ថេរជានិច្ច) លើគ្រប់ Tab ទាំងអស់ ដើម្បីកុំឲ្យ Content
   ខាងក្រោមមាន Layout Shift ណាមួយសោះ។ Tab ក្រៅពី "ទាំងអស់" មិន Support Filter តាម Category ទេ (Server
   Business Logic ដើម — មិនប៉ះពាល់) ដូច្នេះ Chip ត្រូវ Disable (មើលទៅស្រអាប់ + មិន Clickable) លើ Tab ទាំង
   នោះ ជំនួសការលាក់ទាំងមូល (User ជ្រើសរើសយក Option នេះផ្ទាល់ — មើលកំណត់ត្រា setHomeView()/
   syncCategoryFilterEnabled() ក្នុង app.js) */
.category-filter {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-start;
  gap: 8px;
  margin: 0 0 28px;
}
.chip {
  background: var(--bg-card);
  border: none;
  color: var(--cream);
  border-radius: 999px;
  padding: 6px 14px;
  font-family: inherit;
  font-size: 0.84rem;
  font-weight: 500;
  cursor: pointer;
  transition: background 0.15s ease, opacity 0.15s ease;
}
.chip:hover { background: var(--border); }
.chip.active { background: var(--gold); color: #fff; font-weight: 700; }
.chip:disabled { opacity: 0.4; cursor: not-allowed; pointer-events: none; }

/* រឿងភាគ (Series/Episode) — Badge "ភាគ N" លើ Video Card ណាមួយដែលមាន episodeNumber (Feature ថ្មី — មើល
   videoCardHtml() ក្នុង public/js/app.js) */
.video-episode-badge {
  align-self: flex-start;
  background: var(--gold-tint);
  color: var(--gold-soft);
  font-size: 0.72rem;
  font-weight: 700;
  padding: 3px 10px;
  border-radius: 999px;
}

.video-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(380px, 100%), 1fr));
  gap: 24px;
}
/* Fade-In ខ្លីៗរាល់ពេល Grid បាន Render ថ្មី (paintGrid() ក្នុង app.js) — ជំនួសការសាកល្បងមុន (Dim ខណៈកំពុងរង់ចាំ API)
   ដែលនៅលើ Theme ងងឹតស្រាប់ មើលទៅដូចជា Grid ខ្មៅ/បាត់ជាយូរលើបណ្តាញយឺត — ជំនួសវិញ Grid ចាស់ឃើញពេញលក្ខណៈជានិច្ចខណៈកំពុងរង់ចាំ
   ហើយ Fade-In តែម្តងគត់ (រយៈពេលថេរ 0.25s មិនអាស្រ័យលើល្បឿន Network) ពេលខ្លឹមសារថ្មីពិតជារួចរាល់ (Innerhtml បាន Replace)
   Scoped ត្រឹមតែ Empty/Error State (<p class="loading">) ប៉ុណ្ណោះ — Card ពិតប្រើ .video-card-reveal Cascade
   ខាងក្រោមវិញ (មើលកំណត់ត្រា paintGrid() ក្នុង app.js) ជំនួសការ Fade ជាដុំតែមួយ Block ដែល User រាយការណ៍ថា
   "ធ្ងន់"/មិន Smooth ខណៈប្តូរ Tab (ទាំង Grid លោតឡើងក្នុងពេលតែមួយ) — ចង់បាន "ស្រាល" ដូច Scroll Reveal វិញ */
@keyframes videoGridFadeIn {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: translateY(0); }
}
.video-grid.is-fresh > p.loading { animation: videoGridFadeIn 0.25s ease; }
@media (prefers-reduced-motion: reduce) {
  .video-grid.is-fresh > p.loading { animation: none; }
}
/* Grid Paint ក្រោយ First Load (Tab/Category/Search/Pagination — មើលកំណត់ត្រា paintGrid() ក្នុង app.js) —
   បន្ទាប់ពី Tuning ជាច្រើនជុំ (Crossfade/Slide-Down/Double-Buffer) ដែល User បន្តរាយការណ៍ថា "រឹង"/ឆ្ងាយពី
   Motion ចាស់ — Git History Archaeology រកឃើញថា Animation ដើមគឺ Commit 3465d95 ("Fix the grid 'goes
   black' moment") ចុះថ្ងៃ 2026-09-22 — ប្រើ videoGridFadeIn ដដែលនឹងខាងលើ (opacity ពិត 0→1, translateY
   6px→0, 0.25s ease សាមញ្ញ — មិនមែន Custom Cubic-Bezier ទេ) អនុវត្តលើ .video-grid ទាំងមូលដោយផ្ទាល់។
   ឥឡូវយក Parameter ដើមមកវិញបេះបិទ (មិនមែន Tune ថ្មី "ស្រដៀង" ទៀតទេ) — Class ឈ្មោះ grid-swap-fade នៅតែ
   ប្រើជា Trigger ដូចគ្នា (សម្គាល់ Non-First-Render) ប៉ុន្តែ Animation ខ្លួនឯង Reuse keyframe videoGridFadeIn
   ដើមឡើយ (មិនមែន Keyframe ផ្ទាល់ខ្លួនទៀតទេ) */
.video-grid.grid-swap-fade { animation: videoGridFadeIn 0.25s ease; }
@media (prefers-reduced-motion: reduce) {
  .video-grid.grid-swap-fade { animation: none; }
}
/* រក្សា ៣ Column ដដែល (ដូចមុន Sidebar) នៅទំហំ Desktop ដែល Sidebar បង្ហាញផងដែរ */
@media (min-width: 861px) {
  .video-grid { grid-template-columns: repeat(3, 1fr); }
}
.loading { text-align: center; color: var(--muted); grid-column: 1 / -1; }

.video-card {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
  box-shadow: var(--shadow);
  display: flex;
  flex-direction: column;
  transition: transform 0.2s ease, border-color 0.2s ease;
}
.video-card:hover { transform: translateY(-4px); border-color: var(--gold); }

/* Scroll-Reveal (Video Card + Tutorial Card ចែក Class តែមួយ — មើល observeCardReveals()/cardRevealClass()
   ក្នុង app.js) — កំណត់ opacity/transform តាម :not(.is-revealed) ប៉ុណ្ណោះ (មិនកំណត់ Base លើ .video-card-reveal
   ខ្លួនឯងទេ) ដើម្បីកុំបុក .video-card:hover{transform:translateY(-4px)} ខាងលើ — ពេល .is-revealed បន្ថែម Class
   នេះលែងកំណត់ transform/opacity អ្វីទៀត ដូច្នេះ Hover នៅតែដំណើរការធម្មតាទាំងស្រុងក្រោយ Reveal ចប់ */
/* 0.5s → 0.65s (User ស្នើឲ្យ "ស្រាល"/យឺតជាងមុន — មើលកំណត់ត្រា paintGrid() ក្នុង app.js សម្រាប់ Stagger
   Delay រវាង Card ដែលបានបង្កើនស្របគ្នាដែរ) — ប៉ះពាល់ទាំង Tab-Switch Cascade ខាងលើ និង Scroll-Reveal ធម្មតា
   (ដូចគ្នា Visual Language តែមួយ គួរជាប់លាប់គ្នា) */
.video-card-reveal {
  transition: opacity 0.65s cubic-bezier(0.22, 1, 0.36, 1), transform 0.65s cubic-bezier(0.22, 1, 0.36, 1);
}
.video-card-reveal:not(.is-revealed) {
  opacity: 0;
  transform: translateY(18px);
}
/* Mobile ធ្លាក់មក 1 Column ពេញ Width (មើល "@media (min-width: 861px)" លើ .video-grid ខាងលើ ដែលរក្សា ៣
   Column លើ Desktop) — Card នីមួយៗកាន់កាប់ពេញ Screen Width ធ្វើឲ្យ translateY 18px ដដែល មើលទៅ "ធ្ងន់"/លេចធ្លោ
   ជាង Desktop ដែល Card តូចជាង Distance ដូចគ្នាមិនសូវសម្គាល់ (User បញ្ជាក់ថា Desktop ល្អស្រាប់ កុំប៉ះ — មានតែ
   Mobile ដែលនៅតែធ្ងន់/លឿនពេក) ដូច្នេះបន្ថយ Distance សម្រាប់ Mobile ដំបូង (18px→10px) — ប៉ុន្តែ User រាយការណ៍
   បន្តទៀតថានៅតែធ្ងន់/លឿន ព្រោះ 10px ខ្លីពេក មើលទៅដូច "Fade/ភ្លឹប" មិនមែន "រអិល" ពិត (ចង់បាន "រអិលពីលើចុះក្រោម"
   ច្បាស់លាស់) ដូច្នេះប្តូរទិសដៅមក ចាប់ផ្តើមពី "លើ" (translateY អវិជ្ជមាន) ជំនួសពី "ក្រោម" ដើម្បីអោយមានទិសដៅ
   ចុះក្រោមច្បាស់ ព្រមទាំងបង្កើនចម្ងាយឲ្យមើលឃើញជា "ចលនា" ច្បាស់ជាង (មិនមែនត្រឹមតែ Opacity Fade) */
@media (max-width: 860px) {
  .video-card-reveal:not(.is-revealed) {
    transform: translateY(-20px);
  }
  /* Curve ដើម cubic-bezier(0.22,1,0.36,1) ខ្លាំងពេក Front-Load (67% ចប់តាំងពី 20% នៃ Duration) ធ្វើឲ្យ
     មើលទៅ "លោត"/Snap — ប្តូរទៅ cubic-bezier(0.4,0,0.2,1) (Material Standard) លើកមុន ប៉ុន្តែ Curve នេះយឺត
     ពេកត្រង់ដើម (2.6% at 10%, 6.6% at 15% នៃ Duration) ធ្វើឲ្យ Card ថ្មី (ដែលពិតជានៅក្នុង DOM រួច Opacity
     កំពុង Animate ស្រាប់ — បញ្ជាក់ដោយ getComputedStyle ផ្ទាល់ មិនមែន Data មិនទាន់ Ready ទេ) មើលទៅ "Blank" ~100ms
     មុននឹងចាប់ផ្តើមមើលឃើញ (User រាយការណ៍ "Content ចាស់ដក់ចេញ → ទទេ → ទើប Fade ចូល") ដូច្នេះប្តូរទៅ `ease`
     ស្តង់ដារ (ចាប់ផ្តើមមើលឃើញច្បាស់ភ្លាមៗ ~9.5% ត្រឹម 10%, ~18.5% ត្រឹម 15%) ជៀសវាងទាំង Blank-Looking-Start
     (Curve ចាស់) និង Snap-At-End (Curve ដើមដំបូង) — User ស្នើមិនចង់ឲ្យ Duration យឺតជាងនេះទៀត ដូច្នេះរក្សា 0.9s
     ដដែល ប្តូរតែ Curve (Mobile ប៉ុណ្ណោះ — Desktop រក្សា Curve/Duration ដើម) */
  .video-card-reveal {
    transition: opacity 0.9s ease, transform 0.9s ease;
  }
}
@media (prefers-reduced-motion: reduce) {
  .video-card-reveal,
  .video-card-reveal:not(.is-revealed) {
    opacity: 1;
    transform: none;
    transition: none;
  }
}

/* ផ្ទៃខាងក្រោយ var(--bg-card) (ពីមុន #000 ពិត) — ខណៈកំពុងរង់ចាំរូបភាព Download (ជាពិសេស Category ថ្មីមិនទាន់
   Cache) មើលទៅដូចកន្លែងកំពុង Load មួយផ្នែកនៃ Design (ស្របនឹង Theme ងងឹត) ជំនួសជាប្រហោង/ខូច។ រូបភាពខ្លួនឯង Fade
   ចូលដាច់ដោយឡែក (.is-loaded បន្ថែមដោយ revealThumbsWhenLoaded() ក្នុង app.js ពេល Load/Error ពិត) — មិនអាស្រ័យ
   លើ Animation Fade-In របស់ Grid ទាំងមូលទេ (ដែលចប់លឿនជាង Network មិនចាំបាច់រង់ចាំរូបភាព) */
.video-thumb {
  position: relative;
  aspect-ratio: 5 / 3;
  background: var(--bg-card);
}
.video-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  opacity: 0;
  transition: opacity 0.25s ease;
}
.video-thumb img.is-loaded { opacity: 1; }
@media (prefers-reduced-motion: reduce) {
  .video-thumb img { transition: none; }
}
.badge {
  position: absolute;
  top: 12px;
  right: 12px;
  padding: 4px 12px;
  border-radius: 999px;
  font-size: 0.78rem;
  font-weight: 700;
  backdrop-filter: blur(4px);
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
/* ពណ៌មាស (ដូច Premium Crown/Bottom-Nav — មើល #btn-bottomnav-premium ខាងក្រោម) ជំនួសពណ៌ក្រហម/ផ្កាឈូកចាស់
   ដែល User មតិថាមិនចូល Theme — Text ងងឹតលើផ្ទៃមាស ដើម្បី Contrast ច្បាស់លើ Thumbnail ណាមួយ */
/* Locked — Icon Lock តែម្នាក់ឯង គ្មាន Text (User ចង់បាន Badge តូច មិនបាំង Thumbnail) ដូច្នេះទម្រង់
   ជារង្វង់តូច (Width=Height) ជំនួសទម្រង់ Pill វែងសម្រាប់ Text — Gold Surface + Dark Icon ដដែល។ ប្តូរទៅ
   ពណ៌មាសភ្លឺ #ffd479 (ដូច Premium Glow Ring ជុំវិញ Avatar សមាជិក — មើល .account-menu:has(#member-badge)
   .account-avatar-btn ខាងក្រោម) + Glow ស្រាលៗជុំវិញ ព្រោះ User មតិថា Badge ចាស់ (Gradient ត្នោតស្រាល)
   មិនសូវលេចដាច់ពី Thumbnail ខ្លះដែលចម្រុះពណ៌/ភ្លឺរួចហើយ */
.badge.locked {
  background: linear-gradient(135deg, #ffd479, #d8a13f);
  color: #2a1f0a;
  width: 24px;
  height: 24px;
  padding: 0;
  justify-content: center;
  gap: 0;
  box-shadow: 0 0 0 1.5px rgba(255, 212, 121, 0.6), 0 0 6px rgba(255, 212, 121, 0.55);
}
.badge.unlocked { background: var(--gold); color: #fff; }
.badge-lock-icon { width: 0.85em; height: 0.85em; flex-shrink: 0; }
.badge.locked .badge-lock-icon { width: 13px; height: 13px; }

/* វីដេអូ "ពិសេស" (excludeFromSubscription — មិនរាប់បញ្ចូលក្នុង Premium Subscribe ទេ) — ធ្លាប់ដាក់ Overlay លើ
   Thumbnail ប៉ុន្តែ User មតិថាចង្អៀត ព្រោះត្រួតជាមួយ Badge ផ្សេងទៀត (New/Locked) — ផ្លាស់ទីមក Meta Row
   ក្រោម Title ជំនួសវិញ (កន្លែងទំនេរបន្ថែមក្រោយដក .video-category ចេញ) ជា Pill Tint ធម្មតាដូច
   .video-episode-badge (មិនមែន Overlay ទៀតទេ) */
.badge-exclude-subscription {
  align-self: flex-start;
  background: rgba(147, 51, 234, 0.15);
  color: #c084fc;
  font-size: 0.72rem;
  font-weight: 700;
  padding: 3px 10px;
  border-radius: 999px;
  white-space: nowrap;
}

/* "ថ្មី"/"New" (គ្មាន Emoji) — មើលមតិយោបល់ isNewContent() ក្នុង app.js — Style តាមគំរូ .badge ខាងលើ (Backdrop-Blur/
   Border-Radius/Font-Size ដូចគ្នា) ប៉ុន្តែពណ៌ផ្ទាល់ខ្លួន (បៃតង) ដើម្បីញែកពី Locked/Unlocked/Free ច្បាស់លាស់ —
   left: 12px ធម្មតា (មិនចាំបាច់ 52px ជៀសវាង .fav-btn ទៀតទេ ព្រោះប៊ូតុងបេះដូងត្រូវបានដកចេញ — មើលកំណត់ចំណាំ
   ជិត videoCardHtml() ក្នុង app.js) */
.new-badge {
  position: absolute;
  top: 12px;
  left: 12px;
  padding: 4px 10px;
  border-radius: 999px;
  font-size: 0.78rem;
  font-weight: 700;
  background: rgba(46, 160, 90, 0.9);
  color: #fff;
  backdrop-filter: blur(4px);
  white-space: nowrap;
  z-index: 2;
}

.video-body { padding: 18px 18px 20px; display: flex; flex-direction: column; gap: 8px; flex: 1; }
.video-title-row { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.video-meta-right { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
.video-title-row h3 {
  margin: 0; font-size: 1.15rem; color: var(--cream); font-family: 'Battambang', sans-serif; font-weight: 700;
  /* ចំណងជើងវែង → ១ ជួរ កាត់ដោយ Ellipsis (...) ដូច Mobile — មិន Wrap ធ្វើឲ្យ Card មិនស្មើកម្ពស់ */
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; flex: 1 1 auto;
}
.video-body p { margin: 0; color: var(--muted); font-size: 0.9rem; flex: 1; }
.video-duration { color: var(--muted); font-size: 0.82rem; flex-shrink: 0; }

/* User រាយការណ៍ថា Mobile ឃើញ Video ច្រើនតិចពេក (Card 1 Column ពេញ Width ឃើញត្រឹមតែ ~2 Card ក្នុង Screen
   មួយ) — ប្តូរទៅ 2 Column លើ Phone ពិត (ដូច YouTube/Netflix App) ដើម្បីឲ្យឃើញ Video ច្រើនជាង 3 ដងក្នុង
   កម្ពស់ Screen ដូចគ្នា។ 767px ជ្រើសរើសដោយចេតនា (មិនប៉ះពាល់ 768-860px Tablet ដែលនៅតែប្រើ Base Rule
   auto-fill ខាងលើ) — Card Body/Title/Meta ខាងក្រោមក៏បន្ថយទំហំតាមគ្នា ដើម្បីសមនឹង Card តូចជាង។ Block នេះ
   ដាក់នៅទីនេះ (ក្រោយ Base Rule ទាំងអស់ខាងលើ) ដោយចេតនា — បើដាក់មុន Base Rule ដែល Specificity ស្មើគ្នា
   នោះ Base Rule (មកក្រោយក្នុង Cascade) នឹងឈ្នះ ធ្វើឲ្យ Override មិនដំណើរការ (Bug រកឃើញពេល Verify) */
@media (max-width: 767px) {
  .video-grid { grid-template-columns: repeat(2, 1fr); gap: 10px; }
  .video-body { padding: 10px 10px 12px; gap: 4px; }
  /* flex-wrap: wrap ចាស់ ធ្វើឲ្យ Browser ជ្រើសរើស Wrap ចំណងជើង+Meta ទៅ ២ ជួរដាច់ដោយឡែក ជំនួសការបង្រួម h3
     (Shrink) នៅតែក្នុងជួរដដែល ព្រោះ Flexbox គិត Hypothetical Size មុន Shrink ពេល Wrap បើក — nowrap ទើប
     បង្ខំ Browser ត្រូវបង្រួម h3 (មាន min-width:0 ខាងក្រោម) ដើម្បីនៅតែ ១ ជួរជាមួយ Meta ជានិច្ច */
  .video-title-row { flex-wrap: nowrap; gap: 4px; }
  /* User ចង់បានចំណងជើងតែ ១ ជួរ (មិនមែន ២ ជួរ Clamp ដូចមុន) — វែងហួសកាត់ដោយ Ellipsis (...) ជំនួស */
  .video-title-row h3 {
    font-size: 0.82rem;
    line-height: 1.3;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    min-width: 0;
    flex: 1 1 auto;
  }
  /* នាទី/ពិសេស/ភាគ ក៏ត្រូវនៅ ១ ជួរដូចគ្នា — nowrap ជំនួស wrap ដើម្បីកុំឲ្យធាតុទាំងនេះលោតចុះជួរទី ២ */
  .video-meta-right { gap: 5px; flex-wrap: nowrap; }
  .video-episode-badge,
  .badge-exclude-subscription { font-size: 0.62rem; padding: 2px 7px; white-space: nowrap; }
  .video-duration { font-size: 0.68rem; }
  /* Badge លើ Thumbnail ខ្លួនឯង (Locked/Unlocked/New) — បន្ថយទំហំតាមគ្នា ព្រោះ Thumbnail តូចជាង
     ក្នុង 2-Column (~182px ធៀបនឹង ~350px ក្នុង 1-Column) កុំឲ្យ Badge ធំហួសសមាមាត្រ ឬហួសគែម */
  .badge,
  .new-badge { top: 6px; padding: 3px 8px; font-size: 0.62rem; }
  .badge { right: 6px; }
  .badge.locked { width: 20px; height: 20px; padding: 0; }
  .badge.locked .badge-lock-icon { width: 11px; height: 11px; }
  .new-badge { left: 6px; }
}

/* ---------- Pricing ---------- */
.section-sub {
  text-align: center;
  color: var(--muted);
  margin: -10px 0 18px;
  font-size: 0.85rem;
}
.pricing-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 14px;
  margin: 0 auto;
}

.plan-card {
  position: relative;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 20px 16px 18px;
  text-align: center;
  display: flex;
  flex-direction: column;
  gap: 4px;
  transition: transform 0.2s ease, border-color 0.2s ease;
}
.plan-card:hover { transform: translateY(-4px); border-color: var(--gold); }
.plan-card.popular { border-color: var(--gold); }
.plan-badge {
  position: absolute;
  top: -10px;
  left: 50%;
  transform: translateX(-50%);
  background: var(--gold);
  color: #fff;
  font-size: 0.65rem;
  font-weight: 700;
  padding: 3px 12px;
  border-radius: 999px;
  white-space: nowrap;
}
.plan-card h3 { margin: 4px 0 2px; color: var(--cream); font-size: 0.98rem; }
.plan-price { font-size: 1.35rem; font-weight: 700; color: var(--gold-soft); margin: 2px 0; }
.plan-price-old { font-size: 0.9rem; font-weight: 400; color: var(--muted); text-decoration: line-through; margin-right: 6px; }
.plan-tagline { color: var(--muted); font-size: 0.78rem; margin: 0 0 10px; }
.plan-card .btn { margin-top: auto; padding: 8px 16px; font-size: 0.85rem; }

/* ---------- Pricing modal polish (ក្បាល, CTA តែមួយសំខាន់, តម្លៃ/ខែ, Chip សន្សំ, កូដបញ្ចុះតម្លៃបត់) ----------
   ចំណងជើង/ឈ្មោះ Package ប្រើ Battambang ដិត (មិនមែន Moul — User មិនចូលចិត្តសម្រាប់ Modal ទូទាត់) ចំពោះតែ .modal-pricing
   ប៉ុណ្ណោះ — h2/h3 ផ្សេងក្នុង Site នៅតែ Moul ដដែល */
.modal-pricing .section-title { font-family: 'Battambang', sans-serif; font-weight: 700; font-size: 1.45rem; }
.modal-pricing .plan-card h3 { font-family: 'Battambang', sans-serif; font-weight: 700; font-size: 1.08rem; }
.coupon-toggle {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 0 auto 16px;
  padding: 4px 8px;
  background: none;
  border: none;
  color: var(--gold-soft);
  font-family: inherit;
  font-size: 0.85rem;
  text-decoration: underline;
  cursor: pointer;
}
.coupon-toggle:hover { color: var(--gold); }
.coupon-toggle:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; border-radius: 6px; }
.coupon-row { margin-bottom: 8px; }
.modal-pricing .coupon-msg:empty { display: none; }
.modal-pricing .coupon-msg { margin-bottom: 16px; }
.plan-permonth { margin: 0; color: var(--cream); opacity: 0.72; font-size: 0.8rem; }
.plan-save {
  display: inline-block;
  padding: 2px 11px;
  border-radius: 999px;
  background: rgba(34, 197, 94, 0.16);
  border: 1px solid rgba(34, 197, 94, 0.42);
  color: #4ade80;
  font-size: 0.76rem;
  font-weight: 700;
}
:root[data-theme="light"] .plan-save { background: rgba(22, 163, 74, 0.12); border-color: rgba(22, 163, 74, 0.45); color: #15803d; }
/* CTA ពេញ (Filled) មានតែ Package ពេញនិយមមួយ — ផ្សេងទៀតជា Outline (ប៊ូតុង disabled "កំពុងសកម្ម" មិនប៉ះ) */
.plan-card:not(.popular) .btn-subscribe:not(:disabled) {
  background: transparent;
  color: var(--gold-soft);
  border: 1.5px solid var(--gold-soft);
}
.plan-card:not(.popular) .btn-subscribe:not(:disabled):hover { background: var(--gold-tint); }
.plan-card.popular .btn-subscribe:not(:disabled) { box-shadow: 0 4px 16px rgba(62, 166, 255, 0.38); }
:root[data-theme="light"] .plan-card.popular .btn-subscribe:not(:disabled) { box-shadow: 0 4px 16px rgba(13, 148, 136, 0.35); }

.coupon-row {
  max-width: 420px;
  margin: 0 auto 8px;
  display: flex;
  gap: 10px;
}
.coupon-row input {
  flex: 1;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 10px 14px;
  color: var(--cream);
  font-family: inherit;
  font-size: 0.9rem;
}
.coupon-row input:focus { outline: 2px solid var(--gold); outline-offset: 1px; }
.coupon-msg {
  text-align: center;
  font-size: 0.85rem;
  color: var(--gold-soft);
  min-height: 1.2em;
  margin: 0 0 24px;
}
.coupon-msg.coupon-error { color: var(--red); }
.telegram-status { font-size: 0.85rem; color: var(--gold-soft); text-align: center; margin: 0; }
.register-guide-title { font-size: 0.82rem; font-weight: 700; color: var(--gold-soft); margin: -8px 0 4px; }
.register-guide {
  background: var(--gold-tint);
  border-radius: 8px;
  padding: 12px 16px 12px 32px;
  margin: 0 0 16px;
  color: var(--muted);
  font-size: 0.85rem;
  line-height: 1.6;
}
.register-guide li { margin-bottom: 2px; }
.register-guide li:last-child { margin-bottom: 0; }
.register-tutorial-link {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  width: 100%;
  margin: 0 0 16px;
  padding: 10px 12px;
  background: var(--gold-tint);
  border: 1px solid var(--gold-tint);
  border-radius: 10px;
  color: var(--gold-soft);
  font-family: inherit;
  font-size: 0.92rem;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease;
}
.register-tutorial-link:hover,
.register-tutorial-link:focus-visible {
  background: var(--gold);
  border-color: var(--gold);
  color: #fff;
  outline: none;
}
.register-tutorial-link-sub { font-size: 0.74rem; font-weight: 400; color: var(--muted); }
.register-tutorial-link:hover .register-tutorial-link-sub,
.register-tutorial-link:focus-visible .register-tutorial-link-sub { color: rgba(255, 255, 255, 0.85); }

/* Overlay ដាច់ដោយឡែកពី .modal-overlay ធម្មតា ចេតនា (មិនមែន Class ជ្រើសនាមខុសទេ) — សូមមើលមូលហេតុលម្អិត
   ក្នុង index.html ខាង #modal-register-tutorial-video — z-index ខ្ពស់ជាង .modal-overlay (100) ដើម្បីឲ្យ
   ចាក់ពីលើ Modal ចុះឈ្មោះបាន */
.register-tutorial-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.72);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 150;
  padding: 20px;
  touch-action: none;
}
.channel-toggle { display: flex; gap: 8px; }
.channel-btn {
  flex: 1;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 7px 10px;
  color: var(--muted);
  font-family: inherit;
  font-size: 0.85rem;
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}
.channel-btn.active { background: var(--gold); border-color: var(--gold); color: #fff; font-weight: 700; }

/* ---------- Footer ---------- */
.site-footer {
  border-top: 1px solid var(--border);
  padding: 26px 0;
  text-align: center;
  color: var(--muted);
  font-size: 0.85rem;
}
/* Desktop — Legal (Copyright + Nav) ខាងឆ្វេង, Payment Badge ខាងស្តាំ, កំពស់ Align ដូចគ្នា (align-items:
   center) — Mobile (មើល Media Query ក្រោម .legal-nav) នឹង Wrap ចុះក្រោមធម្មតា គ្មាន Horizontal Scroll ព្រោះ
   flex-wrap + max-width:100% លើ Logo */
.footer-inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 14px 24px;
}
.footer-legal { flex: 1 1 auto; min-width: 0; }
.footer-payments {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-shrink: 0;
}
.footer-payments-label { white-space: nowrap; }
.footer-payment-logo {
  height: 32px;
  width: auto;
  max-width: 100%;
  object-fit: contain;
  display: block;
}
@media (max-width: 600px) {
  .footer-payments { width: 100%; justify-content: center; }
}

/* ---------- Modal ---------- */
.modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.72);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 100;
  padding: 20px;
  touch-action: none;
}
/* Pop-in ស្រទន់ៗពេល Modal លេចឡើង (ជំនួស Snap ភ្លាមៗ ដែលធ្លាប់មានពីមុន — .hidden ប្រើ display:none
   ដែល Animate/Transition ដោយផ្ទាល់មិនកើតទេ ដូច្នេះប្រើ @keyframes ជំនួស Transition — Animation ចាប់ផ្តើម
   ដោយស្វ័យប្រវត្តិរាល់ពេល .hidden ត្រូវដកចេញ (display ប្តូរពី none ទៅ flex ជាមុនសិន រួច Animation ដំណើរការ)
   Backdrop Fade + Card លោតបន្តិចទាបស្រាលៗ (Scale/Translate) អោយមានអារម្មណ៍ Smooth មិនមែនលោតដាច់ៗ) —
   prefers-reduced-motion គោរព User ដែលបិទ Animation ក្នុង OS Setting ជានិច្ច */
@keyframes modalOverlayFadeIn { from { opacity: 0; } to { opacity: 1; } }
@keyframes modalCardPopIn {
  from { opacity: 0; transform: scale(0.96) translateY(8px); }
  to { opacity: 1; transform: scale(1) translateY(0); }
}
/* រយៈពេល Animation ចូល/ចេញ បង្កើនឡើងបន្តិច (0.18/0.24s → 0.28/0.32s ចូល, 0.16s → 0.24s ចេញ) — User រាយការណ៍ថា
   0.16-0.24s ដើម នៅតែលឿនពេក មានអារម្មណ៍ដូច "Snap" ជាង "Smooth" — 0.24-0.32s ជិតដល់ចំណុចដែល Motion Design
   ទូទៅចាត់ទុកជា "Perceptible/Smooth" សម្រាប់ Modal Presentation (ធម្មតា ~250-350ms)
   Timing Function Backdrop ដូចគ្នាទៅនឹង Card ខាងក្រោម (មិនមែន "ease" ដូចមុនទេ) — ផ្ទៀងផ្ទាត់ដោយគណនា Bezier
   ផ្ទាល់ (មិនមែនទាយ) ឃើញថា "ease" នៅត្រង់ 30%/50%/70% នៃរយៈពេល សម្រេចបានត្រឹមតែ 51%/80%/94% ខណៈ Card
   Curve ខាងក្រោម (cubic-bezier(0.16,1,0.3,1) ជា Ease-Out ខ្លាំង) សម្រេច 88%/97%/99.6% ទៅហើយ — Card បង្ហាញ
   ពេញលក្ខណៈស្ទើរតែភ្លាមៗ ខណៈ Backdrop នៅតែភ្លឺ (មិនទាន់ងងឹត) អស់រយៈពេលជិត 200ms ធ្វើឲ្យឃើញ Content
   "ភ្លឹប" លើ Background ភ្លឺមុននឹង Backdrop ដល់ទាន់ (Bug ពិតដែលរាយការណ៍ថា "ញាក់" លើទាំង iPhone/Desktop
   សូម្បីក្រោយកែ Drawer/Scrollbar រួច) — ប្រើ Curve ដូចគ្នា ធានាថា Backdrop ងងឹតស្របគ្នានឹង Card លេចឡើង */
.modal-overlay:not(.hidden), .register-tutorial-overlay:not(.hidden) { animation: modalOverlayFadeIn 0.28s cubic-bezier(0.16, 1, 0.3, 1); }
.modal-overlay:not(.hidden) > .modal, .register-tutorial-overlay:not(.hidden) > .modal { animation: modalCardPopIn 0.32s cubic-bezier(0.16, 1, 0.3, 1); }
/* ចេញ (Exit) — ស៊ីគ្នា (Symmetric) ជាមួយ Pop-in ខាងលើ (ពីមុនគ្មាន Animation ចេញទាល់តែសោះ — hideModalOverlay()
   ក្នុង app.js ដាក់ Class នេះ រង់ចាំ animationend (ឬ setTimeout Fallback) ទើប display:none ពិត) — លឿនជាង
   ការចូលបន្តិច (0.24s vs 0.32s) ព្រោះការចាកចេញគួរមានអារម្មណ៍រហ័សជាងការចូល។ ដាក់ក្រោម Rule ចូល ដើម្បីឈ្នះ Specificity
   ស្មើគ្នា (Rule ក្រោយឈ្នះពេល Specificity ស្មើ) — pointer-events:none ទប់ស្កាត់ចុចម៉ូឌាលកំពុងរលត់ */
@keyframes modalOverlayFadeOut { to { opacity: 0; } }
@keyframes modalCardPopOut { to { opacity: 0; transform: scale(0.96) translateY(8px); } }
.modal-overlay.is-closing, .register-tutorial-overlay.is-closing { animation: modalOverlayFadeOut 0.24s ease forwards; pointer-events: none; }
.modal-overlay.is-closing > .modal, .register-tutorial-overlay.is-closing > .modal { animation: modalCardPopOut 0.24s ease forwards; }
/* ប្តូរ Modal ភ្លាមៗ (មើល openModal() ក្នុង app.js) — Backdrop មិន Fade ចូល/ចេញ ដើម្បីកុំឲ្យទំព័រភ្លឺភ្លែត។
   ប្រើ animation-duration:0s (មិនមែន animation:none) — ដោយសារប្តូរ animation-name ពេលដក Class ចេញវិញ នឹងធ្វើឲ្យ
   Fade លេងម្តងទៀត (ឃើញ Backdrop ភ្លឺភ្លែតទី២) ខណៈប្តូរ Duration លើ Animation ដែលចប់ហើយ មិនលេងឡើងវិញទេ — គ្របដណ្តប់
   ទាំង Animation ចូល និងចេញ (Selector ខាងលើទាំងអស់) ដោយសារ Specificity ខ្ពស់ជាង (Class body.modal-switching បន្ថែម) */
body.modal-switching .modal-overlay:not(.hidden), body.modal-switching .register-tutorial-overlay:not(.hidden) { animation-duration: 0s; }
@media (prefers-reduced-motion: reduce) {
  .modal-overlay:not(.hidden),
  .modal-overlay:not(.hidden) > .modal,
  .modal-overlay.is-closing,
  .modal-overlay.is-closing > .modal,
  .register-tutorial-overlay:not(.hidden),
  .register-tutorial-overlay:not(.hidden) > .modal,
  .register-tutorial-overlay.is-closing,
  .register-tutorial-overlay.is-closing > .modal { animation: none; }
}
/* body.modal-open — ដាក់ដោយ lockBodyScroll()/unlockBodyScroll() ក្នុង app.js ពេល Modal ណាមួយបើក/បិទ —
   position:fixed លើ body ខ្លួនឯង (មិនមែន overflow:hidden ម្នាក់ឯងទេ) ត្រូវការសម្រាប់ការពារ iOS Safari
   មិនធ្វើឲ្យ Background (រួមទាំង Video Player កំពុងចាក់ + Bottom Nav) នៅតែ Scroll តាមក្រោយ ខណៈ User
   កំពុង Swipe ខាងក្នុង Modal ខ្លួនឯង — `top` កំណត់ដោយ JS ជា -scrollY ដើម្បីរក្សាទីតាំង Visual ដដែល */
body.modal-open {
  position: fixed;
  left: 0;
  right: 0;
  width: 100%;
  overflow: hidden;
}
.modal {
  position: relative;
  background: var(--bg-raised);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 32px 28px 28px;
  width: 100%;
  max-width: 420px;
  box-shadow: var(--shadow);
  /* Allows vertical swipe-to-scroll INSIDE the modal card itself (overridden from the overlay's
     touch-action:none above) and stops that scroll from chaining into the page behind it once the
     modal's own content hits its top/bottom edge — critical on iPhone Safari. */
  touch-action: pan-y;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  /* លាក់ Scrollbar ដោយចេតនា (ដូចគ្នានឹង .category-filter ខាងក្រោម) — Modal ខ្លះ (Pricing, Video-Purchase,
     Tutorials ។ល។) ប្រើ overflow-y:auto ដើម្បីទុកជា Safety Net ពេលអេក្រង់តូចខ្លាំង/មាតិកាវែងលើសធម្មតា
     (កុំឲ្យមាតិកាត្រូវកាត់ចោល Inaccessible) — ប៉ុន្តែ Scrollbar ដែលឃើញ (ជាពិសេស Windows Classic Style)
     មិនចង់បានលេចមកវិញ Popup ណាមួយក៏ដោយ — Scroll ដោយ Wheel/Swipe/Trackpad នៅតែដំណើរការធម្មតាទាំងស្រុង
     គ្រាន់តែមិនបង្ហាញ Bar ដែលមើលឃើញប៉ុណ្ណោះ */
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.modal::-webkit-scrollbar { display: none; }
.modal-account { max-width: 640px; }
.modal-pricing { max-width: 560px; max-height: 85vh; overflow-y: auto; padding: 22px 20px 20px; }
/* [ដកចេញ z-index:110 ថេរនៅទីនេះ] ធ្លាប់ប្រើដើម្បីអោយ Pricing ឈ្នះ Video (ទាំងពីរ z-index:100 ដូចគ្នា ក្នុង
   DOM Video នៅក្រោយ Pricing ដូច្នេះឈ្នះដោយចៃដន្យ) — ប៉ុន្តែ Value ថេរបែបនេះ បែរជាធ្វើឲ្យ Pricing (110) ឈ្នះ
   Login/Register (100) វិញ ពេល Login/Register ត្រូវបើកជា Popup ពីលើ Pricing ជាន់គ្នាថែមទៀត (ឧ. ចុច "ជាវ
   ឥឡូវនេះ" ខណៈមិនទាន់មានគណនី) ធ្វើឲ្យប៊ូតុង Login/Register (រួមទាំង ✕) មិនអាចចុចបានទាល់តែសោះ — សូមមើល
   pushModalOverVideo()/modalStackOverVideo ក្នុង app.js ដែលកំណត់ z-index ជា Inline Style ដោយស្វ័យប្រវត្តិ
   តាមជម្រៅ Stack ជំនួសវិញ (ធានាថា Modal ណាមួយ Push ចុងក្រោយបំផុត ឈ្នះជានិច្ច ទោះ DOM Order ជាយ៉ាងណាក៏ដោយ) */

/* Mobile-only compact layout for the pricing popup — ៤ Package ជង់ជាមួយគ្នាតាម Column តែមួយ (Layout
   Desktop ធម្មតា) ខ្ពស់ជាង Viewport លើ Mobile ភាគច្រើន ត្រូវ Scroll ក្នុង Modal ដែល User មិនចង់បាន — ប្តូរ
   ជា Grid ២ Column (២ជួរ x ២ជួរ) និងបង្រួម Padding/Font នៅគ្រប់ចំណុច ដើម្បីអោយមើលឃើញ Package ទាំង ៤
   ព្រមគ្នាដោយគ្មាន Scroll — Desktop (>600px) មិនប៉ះពាល់ទាល់តែសោះ */
@media (max-width: 600px) {
  #modal-pricing .modal-pricing {
    max-height: 94vh;
    max-height: 94dvh;
    padding: 16px 12px 12px;
  }
  #modal-pricing .section-title { font-size: 1.05rem; margin: 0 0 4px; }
  #modal-pricing .section-sub { font-size: 0.72rem; line-height: 1.3; margin: 0 0 12px; }
  #modal-pricing .coupon-toggle { margin-bottom: 10px; font-size: 0.78rem; }
  #modal-pricing .plan-permonth { font-size: 0.68rem; }
  #modal-pricing .plan-save { font-size: 0.62rem; padding: 1px 8px; }
  #modal-pricing .coupon-row { margin: 0 auto 6px; gap: 6px; }
  #modal-pricing .coupon-row input { padding: 8px 10px; font-size: 0.8rem; }
  #modal-pricing #btn-apply-coupon { padding: 8px 12px; font-size: 0.8rem; }
  #modal-pricing .coupon-msg { margin: 0 0 10px; font-size: 0.75rem; min-height: 1em; }
  #modal-pricing .pricing-grid { grid-template-columns: 1fr 1fr; gap: 8px; }
  #modal-pricing .plan-card { padding: 14px 8px 10px; gap: 2px; }
  #modal-pricing .plan-badge { font-size: 0.55rem; padding: 2px 8px; top: -8px; }
  #modal-pricing .plan-card h3 { font-size: 0.8rem; margin: 4px 0 0; }
  #modal-pricing .plan-price { font-size: 1rem; margin: 2px 0; }
  #modal-pricing .plan-price-old { font-size: 0.65rem; margin-right: 3px; }
  #modal-pricing .plan-tagline { font-size: 0.62rem; line-height: 1.2; margin: 0 0 6px; }
  #modal-pricing .plan-card .btn { padding: 7px 6px; font-size: 0.7rem; }
}

/* ម៉ូឌាល ជោគជ័យក្រោយទិញរឿង — Dark Theme ធម្មតា (មិនមែន Light Fix ដូច .payway-success-* ដែលរចនាឡើងសម្រាប់
   Modal ផ្ទាល់ខ្លួន .modal-video-payway/.modal-premium-payway ដែលមាន Background ភ្លឺថេរ) ដូច្នេះប្រើ
   var(--cream)/var(--muted) ធម្មតា មិនមែន Hex ថេរដូច Payway Success ទេ — ពណ៌បៃតង #16a34a ដដែលនឹង
   .payway-status-row.is-success ដើម្បីជាប់ជានិច្ចថា "បៃតង = ជោគជ័យ" ក្នុង Website ទាំងមូល */
.modal-purchase-success { max-width: 380px; text-align: center; }
.purchase-success-icon {
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: rgba(22, 163, 74, 0.15);
  color: #16a34a;
  font-size: 1.8rem;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 4px auto 14px;
}
.purchase-success-title { font-size: 1.15rem; font-weight: 700; color: var(--cream); margin: 0 0 8px; }
.purchase-success-sub { color: var(--muted); font-size: 0.9rem; margin: 0 0 20px; }

/* Modal Base ដែលចែករំលែក — Manual KHQR (Screenshot Upload) ត្រូវបានដកចេញទាំងស្រុង ដូច្នេះ .modal-manual-payment
   ឥឡូវសល់ត្រឹមតែ Base Sizing/Layout ដែល Modal Wallet Top-Up (ABA PayWay) ខាងក្រោមនៅតែប្រើប្រាស់ជា Base Class */
.modal-manual-payment { max-width: 420px; max-height: 90vh; overflow-y: auto; text-align: center; }
.modal-manual-payment h3 { margin: 0 0 4px; }

/* Modal បញ្ចូលទឹកប្រាក់ Wallet — ជំហានទី ១ (ជ្រើសរើសចំនួនទឹកប្រាក់) — មើល #modal-wallet-topup ក្នុង
   index.html — .modal-manual-payment កំណត់ text-align:center ជា Default (ចែករំលែកជាមួយ Modal ទូទាត់
   KHQR សមាជិកភាព) ដូច្នេះធាតុថ្មីៗខាងក្រោមកំណត់ text-align:left ដោយឡែកតាមតម្រូវការ */
.modal-wallet-topup .wallet-topup-header { display: flex; align-items: center; gap: 10px; text-align: left; margin: 0 0 4px; }
.modal-wallet-topup .wallet-topup-header h3 { margin: 0; }
.wallet-topup-header-icon {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--gold-tint);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.25rem;
  flex-shrink: 0;
  color: var(--gold-soft);
}
.wallet-topup-header-icon svg { width: 22px; height: 22px; display: block; }
/* Premium — មកុដពណ៌មាសពិត (ដូច 👑 ដើម) ខុសពីពណ៌ខៀវ Accent របស់ Wallet */
.wallet-topup-header-icon--premium { color: #e6b85c; }

/* Border ពណ៌ Gold Accent (មិនមែន --border ធម្មតាទេ) + Background Tint ស្រាល ដើម្បីឲ្យ Box នេះ (សមតុល្យ
   Wallet / គម្រោង Premium) លេចធ្លោជាងផ្ទៃខាងក្រោយ Modal ជុំវិញ */
.wallet-topup-balance-box {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  background: var(--gold-tint);
  border: 1.5px solid var(--gold);
  border-radius: 10px;
  padding: 12px 14px;
  margin: 14px 0 16px;
}
.wallet-topup-balance-label { font-size: 0.8rem; color: var(--muted); }
.wallet-topup-balance-value { display: inline-flex; align-items: center; gap: 6px; font-size: 1.05rem; font-weight: 700; color: var(--gold-soft); white-space: nowrap; }
.wt-balance-icon { flex-shrink: 0; }


.wallet-topup-note { font-size: 0.74rem; color: var(--muted); text-align: center; margin: 10px 0 0; }

.payway-section-label {
  display: block;
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--muted);
  text-align: left;
  margin: 0 0 8px;
}

/* Payment Method — Card "ជ្រើសរើសរួចស្រាប់" (Website មានវិធីទូទាត់ស្វ័យប្រវត្តិតែមួយគត់ ABA KHQR) — Spacing
   គោរពតាម ABA Bank Branding Guideline PDF ជាក់លាក់ (មិនមែនប៉ាន់ស្មានទេ)៖
   - Background ស (#ffffff) ជុំវិញ Logo — "Background Contrast: Completely White Background" តាម Guideline
   - Padding ជុំវិញ Logo យ៉ាងតិច 10px — "Clear Space: Protection space/padding or margin: 10px"
   - គម្លាត Logo→Label យ៉ាងតិច 10px — "Min. space between logo and label: 10px"
   - គម្លាត Title→Description យ៉ាងតិច 4px — "Min. space between label: 4px"
   - Description Text ពណ៌ប្រផេះ #697386 — "Description text should be in grey color (#697386)"
   Border ខៀវ (Selected State Indicator) ជា UI ផ្ទាល់របស់ Site នេះ មិនមែនផ្នែកនៃ Logo ខ្លួនឯងទេ */
.payway-method-section { margin: 0 0 18px; }
/* Card នេះឥឡូវជា <button> ដោយផ្ទាល់ (User ចុចលើ Card ភ្លាមៗ QR នឹងបង្កើត — មិនចាំបាច់មានប៊ូតុង "បង្កើត QR
   ទូទាត់" ដាច់ដោយឡែកទៀតទេ) — Reset Default Button Chrome (font/appearance/width) ឲ្យនៅតែមើលទៅដូច Card
   ធម្មតា, បន្ថែម Hover/Active/Focus/Disabled State សម្រាប់ Affordance/Loading Feedback */
.payway-method-card {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  background: #ffffff;
  border: 2px solid #0f5fbf;
  border-radius: 14px;
  padding: 10px;
  text-align: left;
  font-family: inherit;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
  transition: box-shadow 0.15s ease, transform 0.1s ease;
}
.payway-method-card:hover { box-shadow: 0 0 0 3px rgba(15, 95, 191, 0.15); }
.payway-method-card:active { transform: scale(0.99); }
.payway-method-card:focus-visible { outline: 2px solid #0f5fbf; outline-offset: 2px; }
.payway-method-card:disabled { opacity: 0.65; cursor: not-allowed; box-shadow: none; }
/* Logo ជា Official ABA KHQR Asset ពិតប្រាកដ (public/img/aba-khqr-logo.png, 100% Pixel ដើម មិនកែប្រែ/
   គូរឡើងវិញឡើយ) — Minimum Size តាម Guideline គឺ Height 20px/Width auto ប៉ុណ្ណោះ តែទុកឲ្យធំជាងនេះសម្រាប់
   ភាពច្បាស់ក្នុង Card — border-radius តូចមួយ (8px) ត្រឹមតែជា CSS Crop លើ Thumbnail ខាងក្រៅប៉ុណ្ណោះ (ដូច App
   ទូទាត់ស្តង់ដារទូទៅបង្ហាញ Logo ជា Rounded Icon) មិនប៉ះពាល់ Pixel ខាងក្នុង File PNG ដើមឡើយ (object-fit:
   contain រក្សា Aspect Ratio ដើមទាំងស្រុង) */
.payway-method-logo {
  flex-shrink: 0;
  display: block;
  height: 44px;
  width: auto;
  max-width: 100%;
  object-fit: contain;
  border-radius: 8px;
}
.payway-method-info { flex: 1 1 auto; min-width: 0; }
.payway-method-title-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
/* "ABA KHQR" ជា Brand Name ភាសាអង់គ្លេសសុទ្ធ (គ្មាន Khmer Script ទេ) — ABA Guideline មិនកំណត់ Font ណាមួយ
   ឡើយ (ឆែករួច — មើល Merchant Integration Guidelines.pdf) ដូច្នេះប្តូរទៅ System Font Stack ជំនួស Battambang
   (Khmer Font) ដើម្បីឲ្យ Text អង់គ្លេសនេះមើលទៅស្អាត/Professional ដូច App ទូទាត់ធំៗ (Stripe/PayPal) — Description
   ខាងក្រោម (.payway-method-desc) ជា Khmer ស្រាប់ (តាមសំណើ ABA Integration Team) ដូច្នេះប្រើ Font Stack
   ធម្មតារបស់ Site (Battambang) ជំនួសវិញ មិនប្រើ System Font Stack នេះទេ */
.payway-method-title {
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
  font-size: 0.95rem;
  font-weight: 700;
  color: #1a1f36;
}
/* Chevron "›" Indicator (មិនមែន Checkmark ឬ Radio Circle ទៀតទេ) — Card ខ្លួនឯងឥឡូវជា Button ដែលចុចដើម្បី
   បង្កើត QR ដោយផ្ទាល់ ដូច្នេះ Chevron សមស្របជាង Radio (ចង្អុលបង្ហាញ "ចុចដើម្បីបន្ត" មិនមែន "ជម្រើសក្នុងចំណោម
   ជម្រើសច្រើន" ព្រោះ ABA KHQR ជាវិធីទូទាត់តែមួយគត់ស្រាប់ គ្មានអ្វីត្រូវជ្រើសរើសរវាងគ្នាទេ) */
.payway-method-check {
  flex-shrink: 0;
  width: 20px;
  height: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #0f5fbf;
  font-size: 1.3rem;
  font-weight: 700;
  line-height: 1;
}
.payway-method-desc {
  font-size: 0.78rem;
  color: #697386;
  margin: 4px 0 0;
}

.payway-amount-section { margin: 0 0 6px; }

.wallet-topup-amount-input {
  width: 100%;
  box-sizing: border-box;
  padding: 14px 16px;
  border-radius: 12px;
  border: 1px solid var(--border);
  background: var(--bg-card);
  color: var(--cream);
  font-family: inherit;
  font-size: 1.3rem;
  font-weight: 700;
  text-align: center;
  margin: 0 0 8px;
}
.wallet-topup-amount-input:focus { outline: none; border-color: var(--gold); }

.payway-generate-btn { padding: 14px 18px; font-size: 1rem; border-radius: 12px; }

/* ABA KHQR ជំហាន QR — Modal ខ្លួនឯងក្លាយជា White/Light Card តែមួយ (មិនមែន Dark Outer Card + White Inner
   Card ដូចមុនទៀតទេ) ដោយប្រើ :has() ប្តូរ Background របស់ .modal.modal-wallet-topup ខណៈ Step បង្ហាញ QR កំពុង
   មើលឃើញ (មិនប៉ះពាល់ Step ជ្រើសរើសចំនួនទឹកប្រាក់ខាងលើទេ ដែលនៅតែប្រើ Dark Theme ធម្មតា) — :has()/:is() គាំទ្រពេញ
   លេញលើ Chrome 105+/Safari 15.4+/Firefox 121+ */
.modal.modal-wallet-topup:has(:is(#wallet-topup-payway-step, #premium-payway-step):not(.hidden)) {
  background: #ffffff;
  border-color: #e5e7eb;
  /* Padding តូចជាង 32px ដើមតែពេល Step QR/Success កំពុងបង្ហាញប៉ុណ្ណោះ (មិនប៉ះពាល់ Step បញ្ចូលចំនួនទឹកប្រាក់
     ទេ) — កាត់បន្ថយកម្ពស់ Modal សរុបជៀសវាង Scroll លើ Desktop សូម្បីតែ Browser Window ខ្លីៗ (~650px) */
  padding: 16px;
  /* Max-Width តូចជាង 560px ដើមដែរ — QR/Card/Transaction ID សុទ្ធតែតូចជាង 200px ចំកណ្តាល Modal ធំពេក
     បន្សល់ទុកទំហំទទេច្រើនសងខាង (Desktop) — 340px គ្រប់គ្រាន់ផ្តល់ Padding ស្រួល មិនតឹងពេក */
  max-width: 340px;
}
.modal.modal-wallet-topup:has(:is(#wallet-topup-payway-step, #premium-payway-step):not(.hidden)) .modal-close {
  color: #9199a8;
  /* ទាញ × ឡើងលើជិត Modal Edge ជាងលំនាំដើម (top:14px) ដើម្បីកាត់បន្ថយចន្លោះទទេនៅផ្នែកលើ Modal (Padding
     16px/20px + Margin-Top ចាស់ 26px/22px = ~42px សរុប មើលទៅច្រើនពេក) — .payway-topbar Margin-Top ខាងក្រោម
     បន្ថយតាមសមាមាត្រ ខណៈនៅតែរក្សាគម្លាតគ្រប់គ្រាន់មិនស្ទួន × ដដែល */
  top: 6px;
}
.modal.modal-wallet-topup:has(:is(#wallet-topup-payway-step, #premium-payway-step):not(.hidden)) .modal-close:hover {
  color: #1a1f36;
}

#wallet-topup-payway-step, #premium-payway-step { color: #1a1f36; text-align: center; }

/* ត្រឡប់ក្រោយ — Icon តូចមុំឆ្វេងលើ Position ដូចគ្នាបេះបិទនឹង × (.modal-close top:14/right:14 ដែល Position
   ដោយ .modal ខ្លួនឯង) ស្របគ្នាទាំងសងខាង ទំហំ/ទម្ងន់ស្រដៀងគ្នា មិនកាន់កាប់ Flow Space ទេ (Position Absolute) —
   មិនបន្ថែម "Header Block" ណាមួយឡើយ QR គឺ Hero តែមួយគត់ */
.payway-back-btn {
  position: absolute;
  top: 14px;
  left: 14px;
  background: none;
  border: none;
  color: #9199a8;
  font-size: 1.1rem;
  line-height: 1;
  padding: 6px;
  cursor: pointer;
}
.payway-back-btn:hover { color: #0f5fbf; }

/* Header Row — "ABA KHQR" ខាងឆ្វេង + Countdown ខាងស្តាំ (មិនមែន Logo/Text ក្លែងក្លាយពី ABA ទេ គ្រាន់តែជា
   Label Text ធម្មតា) — Countdown ជា Element/ID ដដែលដែល startPaywayCountdown() ក្នុង app.js សរសេរចូល
   ជានិច្ច (មិនប៉ះពាល់ Logic Countdown ណាមួយឡើយ ត្រឹមតែផ្លាស់ទីតាំង Visual) */
/* Margin-Top ត្រូវគ្រប់គ្រាន់ជៀសវាងស្ទួនជាមួយ × (.modal-close top:6px ក្នុង Step នេះ (មើលកំណត់ចំណាំខាងលើ) height:~23px
   → bottom≈29px ពី Modal Top ខណៈ Padding QR-Step ត្រឹមតែ 16px) — ដូចគ្នានឹង Fix ដែលធ្វើរួចលើ Mobile (មើល Media Query
   max-width:480px ខាងក្រោម) */
.payway-topbar { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin: 16px 0 10px; }
.payway-topbar-label { font-size: 0.85rem; font-weight: 700; color: #1a1f36; letter-spacing: 0.02em; }
.payway-countdown-chip { display: inline-flex; align-items: center; gap: 5px; }
.payway-countdown-ring { width: 9px; height: 9px; border-radius: 50%; border: 2px solid #c3c9d3; flex-shrink: 0; }
.payway-countdown { font-size: 0.82rem; font-weight: 700; color: #6b7280; font-variant-numeric: tabular-nums; }
.payway-countdown.payway-countdown-warning { color: #dc2626; }
.payway-countdown-chip:has(.payway-countdown-warning) .payway-countdown-ring { border-color: #dc2626; }

/* QR Integrity — Pixel ដែល ABA ត្រឡប់មកត្រូវបង្ហាញដូចដើមទាំងស្រុង។ ហាមប្រើ border-radius/filter/opacity/
   transform/rotate/scaleX/scaleY/clip-path/mask ឬ background-blend-mode លើ Element នេះជាដាច់ខាត — គ្មាន
   Container/Card ព័ទ្ធជុំវិញ QR ទៀតទេ ព្រោះ QR ខ្លួនឯង (មកពី ABA API ផ្ទាល់) មាន Card Design/Logo/ការណែនាំ
   ភ្ជាប់ស្រាប់រួច — UI របស់យើងមិនស្ទួន Content ណាមួយដែលមាននៅក្នុង QR រួចហើយទេ — object-fit:contain ត្រឹមតែ
   កំណត់ទំហំ Responsive ដោយរក្សា Aspect Ratio ដើម មិនប៉ះពាល់ Pixel ខាងក្នុងឡើយ */
.payway-qr-image {
  display: block;
  width: 100%;
  max-width: 175px;
  height: auto;
  object-fit: contain;
  margin: 0 auto 8px;
}

/* ស្ថានភាព Poll — Dot + Text មួយបន្ទាត់ Subtle តូច គ្មាន Background Box ដើម្បីកុំឲ្យប្រកួតជាមួយ QR */
.payway-status-row { display: flex; align-items: center; justify-content: center; gap: 7px; margin: 0 0 6px; }
.payway-status-dot { width: 7px; height: 7px; border-radius: 50%; background: #9ca3af; flex-shrink: 0; }
.payway-status-text { font-size: 0.8rem; font-weight: 600; color: #6b7280; }
.payway-status-row.is-pending .payway-status-dot { background: #f59e0b; animation: payway-pulse 1.4s ease-in-out infinite; }
.payway-status-row.is-success .payway-status-dot { background: #16a34a; }
.payway-status-row.is-success .payway-status-text { color: #16a34a; }
.payway-status-row.is-failed .payway-status-dot { background: #dc2626; }
.payway-status-row.is-failed .payway-status-text { color: #dc2626; }

@keyframes payway-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.35; }
}

/* លេខយោង Transaction ID — បន្ទាត់តូច Subtle តែមួយ (មិនមែន Card/Meta-Row Grid ទៀតទេ) Copy Button ដដែល */
.payway-tranid-btn {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  background: none;
  border: none;
  padding: 0;
  margin: 0 0 4px;
  font-family: inherit;
  font-size: 0.76rem;
  font-weight: 600;
  color: #9199a8;
  cursor: pointer;
  max-width: 100%;
}
.payway-tranid-label { color: #9199a8; font-weight: 500; }
.payway-tranid-btn span:not(.payway-tranid-label):first-of-type { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 160px; }
.payway-copy-icon { font-size: 0.76rem; color: #9199a8; flex-shrink: 0; }

/* Panel លេចឡើង Fade + Scale ស្រទន់ (មិនមែន Snap ភ្លាមៗឥតបញ្ចេញកន្លែងទេ) — ត្រឹមតែ Visual Entrance ប៉ុណ្ណោះ
   ពេលវេលា/លក្ខខណ្ឌ hidden→visible ដដែល មិនប៉ះពាល់ Logic ណាមួយឡើយ (Backend/Poll/Verify ដដែលទាំងស្រុង) —
   អនុវត្តទាំង QR Step (ពេលចុច "ABA KHQR" ពី Select Step) និង Success State (ពេល Backend បញ្ជាក់ paid) */
#wallet-topup-payway-step, #premium-payway-step,
#payway-success-state, #premium-payway-success-state {
  animation: payway-panel-in 0.32s ease-out forwards;
}
@keyframes payway-panel-in {
  from { opacity: 0; transform: translateY(6px) scale(0.98); }
  to { opacity: 1; transform: translateY(0) scale(1); }
}

/* Hero Zone — តំបន់ពណ៌ស្រទន់ខាងលើ Success State ត្រូវនឹង ABA Reference (#5.pdf) ដែលបង្ហាញ Checkmark
   ស្ថិតក្នុងតំបន់ពណ៌ខុសពី Background សំខាន់ — ប៉ុន្តែនេះ *មិនមែន* Card ដាច់ដោយឡែកទេ (គ្មាន Border/Shadow/
   Radius ផ្ទាល់ខ្លួន) គ្រាន់តែជា Background Wash នៅផ្នែកខាងលើផ្ទាំង Modal តែមួយ Bleed ដល់គែម Modal ដោយប្រើ
   Negative Margin ស្មើនឹង Padding របស់ .modal.modal-wallet-topup ខ្លួនឯង — តម្លៃ 16px នេះផ្គូផ្គងនឹង
   :has() Rule ខាងលើ (.modal.modal-wallet-topup:has(...) { padding: 16px }) ដែលកាត់បន្ថយ Padding ចេញពី
   32px ដើមតែពេល Step QR/Success/Verifying កំពុងបង្ហាញ — 32px ដើមធ្វើឲ្យ Hero Bleed លើសពី Modal ថែមទាំង២
   ខាង 16px (កំណត់ Scrollbar ផ្ដេកក្នុង Modal ខ្លួនឯង User រកឃើញ) — Border Top Radius ដូចគ្នានឹង Modal
   ខ្លួនឯង (20px) ដើម្បីមិនមាន "ជ្រុងលោត" (មើល Mobile Media Query ខាងក្រោម ដែលធ្លាប់ត្រឹមត្រូវរួចហើយ) */
.payway-success-hero {
  margin: -16px -16px 18px;
  padding: 26px 16px 18px;
  background: linear-gradient(180deg, #eefaf1 0%, #ffffff 100%);
  border-radius: 20px 20px 0 0;
}

/* Badge ជោគជ័យ — រង្វង់បៃតងតោនតែម្ខាង (មិនមែនតោនស + Icon ពណ៌តូចដូចមុនទៀតទេ) មាន Halo Ring ស្រទន់ជុំវិញ
   ត្រូវនឹង ABA Reference ដែលបង្ហាញ Badge មាន Glow ជុំវិញ — ពណ៌នៅតែបៃតង (មិនប្តូរទៅខៀវទេ) ដើម្បីស្របគ្នានឹង
   "បៃតង = ជោគជ័យ" ដែលប្រើជានិច្ចទូទាំង Site (.payway-status-row.is-success ។ល។) */
.payway-success-icon {
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: #16a34a;
  color: #fff;
  font-size: 1.5rem;
  font-weight: 800;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 4px auto 12px;
  box-shadow: 0 0 0 8px rgba(22, 163, 74, 0.12);
}
.payway-success-title { font-size: 1rem; font-weight: 700; color: #1a1f36; margin: 0; }

/* Spinner "កំពុងផ្ទៀងផ្ទាត់" — ទំហំ/margin ដូចគ្នាបេះបិទនឹង .payway-success-icon ខាងលើ (56px + margin 4px
   auto 12px) ដើម្បីកុំឲ្យកម្ពស់ .payway-success-hero លោត ពេលប្តូរពី Spinner នេះទៅ Checkmark — ពណ៌ខៀវដូចគ្នា
   នឹង #payway-success-state .btn-primary (#0f5fbf) ដើម្បីស្របគ្នាទាំង Card នេះ (មិនប្រើ --gold/--gold-soft
   ព្រោះតំបន់ hero នេះទាំងមូលប្រើពណ៌ Fixed មិនប្តូរតាម Theme ដដែលៗ ដូច .payway-success-icon/.payway-success-title) */
.payway-verifying-spinner {
  width: 56px;
  height: 56px;
  border-radius: 50%;
  margin: 4px auto 12px;
  border: 4px solid rgba(15, 95, 191, 0.15);
  border-top-color: #0f5fbf;
  animation: payway-verifying-spin 0.8s linear infinite;
}
@keyframes payway-verifying-spin {
  to { transform: rotate(360deg); }
}

/* ចំនួនទឹកប្រាក់ (Wallet) ឬ ឈ្មោះគម្រោង (Premium) — បន្ទាត់តែមួយ លេចធ្លោ គ្មាន Label ដដែល (លែងស្ទួន
   "ចំនួនទឹកប្រាក់"/"គម្រោង" ព្រោះ Title ខាងលើ + Amount ខ្លួនឯងគ្រប់គ្រាន់រួច) */
.payway-success-value { font-size: 1.5rem; font-weight: 800; color: #1a1f36; margin: 0 0 18px; }

/* Transaction ID — Block តូចផ្ដេក Label ស្រទាប់ (Muted) ពីលើ Value ខ្លាំងជាង គ្មាន Border/Card ព័ទ្ធជុំវិញ */
.payway-success-tranid-block { margin: 0 0 20px; }
.payway-success-tranid-label { display: block; font-size: 0.72rem; color: #6b7280; margin: 0 0 3px; }
.payway-success-tranid-value { display: block; font-size: 0.88rem; font-weight: 600; color: #4b5563; word-break: break-all; }

#payway-success-state .btn-primary,
#premium-payway-success-state .btn-primary {
  background: #0f5fbf;
  color: #fff;
  padding: 11px 20px;
}
#payway-success-state .btn-primary:hover,
#premium-payway-success-state .btn-primary:hover { background: #0d4f9e; }

/* ========================================================================
   Shared Payment Modal Design System — ប្រើដូចគ្នាទាំង #modal-wallet-topup
   (Wallet Top-Up) និង #modal-premium-payway (Premium Membership KHQR)
   ទាំងពីរ Modal មាន Class .modal-wallet-topup ដូចគ្នាលើ .modal Div ខ្លួនឯង (ឈ្មោះ Class មកពី Modal
   ដើមដែលបង្កើត Pattern នេះមុនគេ ប៉ុន្តែឥឡូវជា Shared Hook សម្រាប់ទាំងពីរ Modal ស្រាប់ — កុំច្រឡំថាមានតែ
   Wallet ប្រើ) ដូច្នេះការកែប្រែ Width/Padding/Typography/Spacing/Button/Card ខាងក្រោមអនុវត្តទៅទាំងពីរ
   Modal ស្វ័យប្រវត្តិ ពីកន្លែងតែមួយ — គ្មាន HTML ID/Event Handler ណាមួយត្រូវបានប្តូរឡើយ (មើល
   public/js/app.js openWalletTopupModal()/openPremiumPaywayModal() ។ល។) */
/* max-width 560 → 440px: លើ Desktop 560px ធំពេក (ចន្លោះទទេច្រើនសងខាង Balance Box/ប្រអប់វាយលុយ/កាត ABA) —
   440px ធ្វើឲ្យខ្លឹមសារជិតគ្នា ងាយមើលជាង។ លើ Mobile មិនមានផលប៉ះពាល់ (ទទឹងអេក្រង់តូចជាង 440px ស្រាប់) — CSS
   ប៉ុណ្ណោះ គ្មាន HTML/JS/Payment Flow ណាមួយត្រូវបានប្តូរ */
.modal.modal-wallet-topup { max-width: 440px; padding: 32px; border-radius: 20px; }
.modal-wallet-topup .modal-close { top: 16px; right: 16px; }
/* Overlay Padding មិនអាច Scope ដោយ .modal-wallet-topup Class បានទេ (Class នោះនៅលើ .modal Div ខាងក្នុង
   មិនមែននៅលើ .modal-overlay ខាងក្រៅទេ) ដូច្នេះនៅតែប្រើ ID រៀងៗខ្លួន (List តែមួយ ដើម្បីកុំឲ្យស្ទួន Declaration) */
#modal-wallet-topup.modal-overlay,
#modal-premium-payway.modal-overlay {
  padding: 10px;
}

.modal-wallet-topup .wallet-topup-header { align-items: center; gap: 10px; margin: 0 0 18px; }
.modal-wallet-topup .wallet-topup-header-text { flex: 1 1 auto; min-width: 0; }
/* Modal H3 ទាំងអស់ក្នុង Site ប្រើ Font "Moul" ជា Default (Decorative/Display Font — មើល h1,h2,h3 Rule
   ខាងលើក្នុងឯកសារនេះ) ដែល User មិនចូលចិត្តសម្រាប់ចំណងជើង Modal ទូទាត់ទាំងនេះ — Override ត្រឡប់ទៅ Battambang
   វិញ (ដូចគ្នានឹង Body Text ដទៃទៀតក្នុង Modal) Scope ដោយ .modal-wallet-topup ជានិច្ច ដូច្នេះមិនប៉ះពាល់ H3
   ដទៃទៀតក្នុង Site ឡើយ (ឧ. Modal ចូលគណនី/ចុះឈ្មោះ/វីដេអូបង្រៀន ដែលនៅតែប្រើ Moul ដដែល) */
/* Bold 700 + 1.35rem (ជម្រើស A ដែលបានជ្រើសរើសពី Preview) — ពីមុន font-weight 400 ស្តើង ធ្វើឲ្យចំណងជើង Modal ស្រាលជាង
   ចំណងជើងជំហាន (.wt-step-title Bold 700) ខាងក្រោម — Hierarchy ត្រឡប់ក្រោយ; Battambang មាន Weight 700 ស្រាប់ */
.modal-wallet-topup .wallet-topup-header-text h3 { font-size: 1.35rem; font-weight: 700; line-height: 1.3; font-family: 'Battambang', sans-serif; }
.modal-wallet-topup .wallet-topup-subtitle { margin: 3px 0 0; font-size: 0.82rem; font-weight: 400; color: var(--muted); line-height: 1.3; }

/* Font Khmer "Battambang" លំនាំដើម line-height:normal ~1.7x Font-Size (ខ្ពស់ជាង Latin ច្រើន) — កំណត់ 1.3
   ដោយផ្ទាល់លើ Text ខ្នាតតូចទាំងអស់ខាងក្រោមក្នុង Modal ទាំងពីរនេះ ដើម្បីកាត់បន្ថយកម្ពស់ដែលមិនចាំបាច់ (មិនប៉ះពាល់
   Text ណាមួយក្រៅពី Modal ទាំងពីរនេះទេ ព្រោះ Scope ដោយ .modal-wallet-topup ជានិច្ច) */
.modal-wallet-topup .wallet-topup-balance-box { padding: 12px 16px; margin: 0 0 16px; }
.modal-wallet-topup .wallet-topup-balance-label,
.modal-wallet-topup .wallet-topup-balance-value { line-height: 1.3; }

/* ជំហានលេខរៀង ១-៣ (Amount/Price → Payment Method [ចុចដើម្បីបង្កើត QR ដោយផ្ទាល់] → How-to-Pay) — Badge
   លេខរង្វង់តូច (22px) — Spacing រវាង Section/Heading បង្រួម ដើម្បីកុំឱ្យ Modal ខ្ពស់ពេក/Scroll នៅ Mobile */
.modal-wallet-topup .wt-step-block { margin: 0 0 20px; text-align: left; }
.modal-wallet-topup .wt-step-block:last-child { margin-bottom: 0; }
.modal-wallet-topup .wt-step-heading { display: flex; align-items: center; gap: 8px; margin: 0 0 10px; }
.modal-wallet-topup .wt-step-num {
  flex-shrink: 0;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--gold-tint);
  color: var(--gold-soft);
  font-size: 0.82rem;
  font-weight: 800;
  display: flex;
  align-items: center;
  justify-content: center;
}
.modal-wallet-topup .wt-step-title { font-size: 1.02rem; font-weight: 700; line-height: 1.3; color: var(--cream); }

.modal-wallet-topup .payway-amount-section { margin: 0; }
/* Amount Input (Wallet តែមួយគត់ — Premium មិនមាន Input ព្រោះតម្លៃមកពី Package ស្រេច) — កម្ពស់សរុបប្រហែល
   62-64px, មិនលើសពី 68px តាមសំណើ — កំណត់ line-height ដោយផ្ទាល់ (Browser លំនាំដើម "normal" លើ
   <input type=number> ធ្វើឲ្យខ្ពស់ជាងការគណនាធម្មតា) និងលាក់ Native Spin Button ដើម្បីកុំឱ្យបន្ថែមកម្ពស់
   ខាងក្រៅ Control (មិនប៉ះពាល់ Functionality — នៅតែជា <input type="number"> ធម្មតា វាយបញ្ចូល/Arrow Key
   នៅតែដំណើរការ) */
.modal-wallet-topup .wallet-topup-amount-input {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 1.7rem;
  line-height: 1.2;
  padding: 12px 16px;
  border-radius: 12px;
  margin: 0;
  -moz-appearance: textfield;
}
.modal-wallet-topup .wallet-topup-amount-input::-webkit-outer-spin-button,
.modal-wallet-topup .wallet-topup-amount-input::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}
/* Amount Input ក្នុងជួរដេកតែមួយ (Flex) — "អប្បបរមា" ជា Hint Text តូចខាងក្រោម (.wt-amount-hint) ជំនួស Pill Badge ចាស់
   ដែលមើលទៅដូចប៊ូតុងអាចចុចបាន — ខាងក្រោមនោះជាប៊ូតុងចំនួនលុយរហ័ស (.wt-quick-amounts) */
.modal-wallet-topup .wt-amount-row { display: flex; align-items: center; gap: 8px; }
.modal-wallet-topup .wt-amount-hint { margin: 8px 2px 0; font-size: 0.78rem; line-height: 1.3; color: var(--muted); text-align: left; }
.modal-wallet-topup .wt-quick-amounts { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 8px; margin-top: 12px; }
.modal-wallet-topup .wt-quick-amount {
  padding: 9px 4px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: transparent;
  color: var(--cream);
  font-family: inherit;
  font-size: 0.86rem;
  font-weight: 600;
  line-height: 1.2;
  cursor: pointer;
  white-space: nowrap;
  transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}
.modal-wallet-topup .wt-quick-amount:hover { border-color: var(--gold-soft); color: var(--gold-soft); }
.modal-wallet-topup .wt-quick-amount.is-active { background: var(--gold-tint); border-color: var(--gold-soft); color: var(--gold-soft); }

/* Price Display (Premium តែមួយគត់ — ជំហានទី ១ ស្មើនឹង Amount Input របស់ Wallet ប៉ុន្តែជា Text Static ព្រោះ
   តម្លៃមកពី Package ដែលបានជ្រើសរើសរួច Server គណនាស្រេច មិនមែន User វាយបញ្ចូលទេ) — ប្រើ Font-Size ដូចគ្នា
   បេះបិទនឹង Amount Input ដើម្បីឲ្យ "ជំហានទី ១" មើលទៅដូចគ្នារវាង Modal ទាំងពីរ */
/* Price Display ត្រូវមាន Border/Background ដូចគ្នាបេះបិទនឹង Amount Input របស់ Wallet (.wallet-topup-amount-input
   ខាងលើ) ដើម្បីកុំឲ្យមើលទៅដូច Text ទទេអណ្តែតនៅក្នុង Modal — User ស្នើសុំពិសេស */
.modal-wallet-topup .wt-price-display {
  display: block;
  box-sizing: border-box;
  border: 1px solid var(--border);
  background: var(--bg-card);
  border-radius: 12px;
  padding: 12px 16px;
  font-size: 1.7rem;
  font-weight: 800;
  color: var(--cream);
  text-align: center;
  margin: 0;
}

.modal-wallet-topup .payway-method-section { margin: 0; }
.modal-wallet-topup .payway-method-card { padding: 16px 16px; }
.modal-wallet-topup .payway-method-logo { height: 48px; }
.modal-wallet-topup .payway-method-title { font-size: 1.02rem; line-height: 1.3; }
.modal-wallet-topup .payway-method-desc { font-size: 0.84rem; line-height: 1.3; margin-top: 2px; }

.modal-wallet-topup .payway-generate-btn {
  min-height: 56px;
  padding: 16px 20px;
  font-size: 1.1rem;
  font-weight: 700;
  line-height: 1.3;
  border-radius: 12px;
}
.modal-wallet-topup .payway-generate-btn:disabled { opacity: 0.6; cursor: not-allowed; }

.modal-wallet-topup .wallet-topup-note { font-size: 0.82rem; line-height: 1.4; margin: 8px 0 0; text-align: center; }

/* Telegram Support (ទាំងពីរ Modal) — Icon រង្វង់ខៀវ + ក្ដារយន្តហោះស ជា Logo Telegram ស្តង់ដារដែលគេប្រើទូទៅ
   (គូរជា SVG ដោយផ្ទាល់ ព្រោះគ្មាន Official Asset File ក្នុង Project ទេ — រូបរាង/សមាមាត្រតាមទម្រង់ដែលទទួល
   ស្គាល់ជាសកល មិនមែនច្នៃប្រឌិតថ្មីទេ) — Icon ខ្លួនឯង Theme-Locked (រង្វង់ខៀវ #229ED9 ស្រាប់) ដូច ABA Logo,
   Text ពណ៌ខៀវ Telegram Brand ដូចគ្នា (#2AABEE Dark Theme / #0088CC Light Theme សម្រាប់ Contrast គ្រប់គ្រាន់
   លើ Background ស) — គ្មាន Background/Border/Card ដូច Button ទេ, Spacing ដាច់ដោយឡែកពី Generate QR Button
   ខាងលើ ដោយប្រើ margin-top ប៉ុណ្ណោះ */
.modal-wallet-topup .wt-support-link {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  margin: 18px 0 0;
  font-size: 0.92rem;
  line-height: 1.3;
  color: #2aabee;
  text-decoration: none;
}
.modal-wallet-topup .wt-support-link svg { flex-shrink: 0; width: 20px; height: 20px; }
:root[data-theme="light"] .modal-wallet-topup .wt-support-link { color: #0088cc; }
.modal-wallet-topup .wt-support-link:hover { text-decoration: underline; }

/* Mobile 375-430px — Spacing ទូលាយជាង Desktop (មិនមែនបង្រួមទៀតទេ) ដើម្បីមិនឲ្យរញ៉េរញ៉ៃ — ដកចេញ min-height
   ចាស់ (86vh) ដែលធ្វើឲ្យ Modal ខ្ពស់ជាង Content ជានិច្ច ទុកចន្លោះទទេនៅខាងក្រោម Telegram Support (User រាយការណ៍
   ថាមិនស្អាត) — ឥឡូវ Height កំណត់ដោយ Content ខ្លួនឯង (auto) ជានិច្ច — max-height:90vh/overflow-y:auto ពី
   .modal-manual-payment (Base Class) នៅតែរក្សាទុកជា Safety Net ចុងក្រោយ សម្រាប់ Content វែងជាង Viewport
   ណាមួយ */
@media (max-width: 480px) {
  #modal-wallet-topup.modal-overlay,
  #modal-premium-payway.modal-overlay {
    padding: 6px;
  }
  .modal.modal-wallet-topup { width: 96vw; max-width: 430px; padding: 24px 20px; border-radius: 20px; }
  /* ផ្ទាំង KHQR ខ្លួនឯង (មិនមែនជំហានបញ្ចូលចំនួនទឹកប្រាក់ទេ) — បង្រួម Modal ទាំងមូលឲ្យតូចជាង 96vw/430px ដដែល
     ខាងលើ (មិនត្រឹមតែ QR Image ខាងក្នុងទេ) ដោយប្រើ :has() កំណត់តែពេល Step QR/Success កំពុងបង្ហាញ */
  .modal.modal-wallet-topup:has(:is(#wallet-topup-payway-step, #premium-payway-step):not(.hidden)) {
    width: 78vw;
    max-width: 320px;
    padding: 20px 16px;
  }
  .payway-qr-image { max-width: 190px; }
  /* Hero Zone Bleed ត្រូវផ្គូផ្គងនឹង Padding ថ្មីខាងលើ (20px 16px មិនមែន 24px 20px ចាស់ទេ) ព័ន្ធ Hero Zone
     ក្នុង Success State ដដែល (មើលកន្លែងកំណត់ដើម .payway-success-hero ខាងលើ) */
  .payway-success-hero { margin: -20px -16px 16px; padding: 18px 16px 16px; }
  /* Topbar (ABA KHQR + Countdown) ស្ទួនគ្នាជាមួយ × (.modal-close top:6px ក្នុង Step នេះ height:~23px →
     bottom≈29px ពី Modal Top) ព្រោះ Padding-Top 20px ម្នាក់ឯងតូចជាង 29px — Margin-Top 12px ខាងក្រោមបំពេញ
     គម្លាតឲ្យគ្រប់គ្រាន់ (20+12=32px សរុប ស្របគ្នានឹង Desktop ខាងលើ) */
  .payway-topbar { margin-top: 12px; }
  .modal-wallet-topup .wallet-topup-header { margin: 0 0 20px; }
  .modal-wallet-topup .wallet-topup-header-text h3 { font-size: 1.12rem; }
  .modal-wallet-topup .wallet-topup-subtitle { margin: 2px 0 0; font-size: 0.74rem; }
  .modal-wallet-topup .wallet-topup-balance-box { padding: 12px 14px; margin: 0 0 22px; }
  .modal-wallet-topup .wt-step-block { margin: 0 0 24px; }
  .modal-wallet-topup .wt-step-heading { margin: 0 0 12px; }
  .modal-wallet-topup .wt-step-num { width: 22px; height: 22px; font-size: 0.74rem; }
  .modal-wallet-topup .wt-step-title { font-size: 0.92rem; }
  .modal-wallet-topup .payway-method-card { padding: 16px 14px; }
  .modal-wallet-topup .payway-method-logo { height: 40px; }
  .modal-wallet-topup .payway-method-title { font-size: 0.92rem; }
  .modal-wallet-topup .payway-method-desc { font-size: 0.76rem; }
  .modal-wallet-topup .payway-generate-btn { min-height: 56px; padding: 16px 18px; font-size: 1.02rem; }
  .modal-wallet-topup .wallet-topup-amount-input { font-size: 1.35rem; padding: 7px 12px; }
  .modal-wallet-topup .wt-amount-hint { margin-top: 6px; font-size: 0.72rem; }
  .modal-wallet-topup .wt-quick-amounts { gap: 6px; margin-top: 10px; }
  .modal-wallet-topup .wt-quick-amount { padding: 8px 2px; font-size: 0.78rem; }
  .modal-wallet-topup .wt-price-display { font-size: 1.35rem; padding: 7px 12px; }
  .modal-wallet-topup .wallet-topup-note { font-size: 0.76rem; margin: 6px 0 0; }
  .modal-wallet-topup .wt-support-link { font-size: 0.85rem; margin-top: 20px; }
  .modal-wallet-topup .wt-support-link svg { width: 18px; height: 18px; }
}

/* Modal បញ្ជាក់ការទិញរឿង Premium តែមួយ (កាត់ពី Wallet ដោយផ្ទាល់) — មើល #modal-video-purchase ក្នុង
   index.html — Card ផ្ទាល់ខ្លួនទាំងស្រុង (មិនប្រើ .modal-manual-payment ទៀតទេ ព្រោះ Text-Align/Layout
   ខុសគ្នា) — Background Navy ដាច់ដោយឡែក (មិនមែន --bg-raised ធម្មតាទេ) ដូចគ្នានឹង .modal-auth ដែលមាន
   Palette ផ្ទាល់ខ្លួនស្រាប់ (style.css ជិត .modal-auth) — ជា Pattern ដែលមានស្រាប់រួចហើយក្នុង Codebase នេះ */
.modal-video-purchase {
  max-width: 380px;
  max-height: 90vh;
  overflow-y: auto;
  padding: 20px 18px 18px;
  border-radius: 22px;
  background: linear-gradient(180deg, #141a30 0%, #10142780 100%), #12152a;
  border-color: rgba(255, 255, 255, 0.08);
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.55), 0 0 0 1px rgba(255, 255, 255, 0.02);
}

.vp-header { display: flex; align-items: center; justify-content: space-between; margin: 0 0 14px; }
.vp-premium-badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  background: linear-gradient(135deg, var(--gold), var(--gold-soft));
  color: #fff;
  font-size: 0.8rem;
  font-weight: 700;
  padding: 6px 14px;
  border-radius: 999px;
  white-space: nowrap;
  box-shadow: 0 2px 10px -2px var(--gold);
}
.vp-close-btn {
  position: static;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.06);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.9rem;
}
.vp-close-btn:hover { background: rgba(255, 255, 255, 0.12); }

.vp-thumb-wrap { margin: 0 0 16px; }
.vp-thumb {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  border-radius: 15px;
  background: var(--bg-card);
}

.vp-info { margin: 0 0 16px; text-align: left; }
.vp-info h3 { margin: 0 0 6px; color: var(--cream); font-size: 1.2rem; font-weight: 700; }
.vp-meta { color: var(--muted); font-size: 0.84rem; margin: 0; }

.vp-divider { height: 1px; background: rgba(255, 255, 255, 0.08); margin: 0 0 16px; }

/* Price + Wallet Balance ជា ២ ជួរជាប់គ្នាក្នុង Box តែមួយ (មាន Icon រង្វង់នាំមុខម្នាក់ៗ) — ជិតគ្នា ដូចគ្នា
   នឹង Reference Design (មិនមែន ២ Box ដាច់ដោយឡែកទៀតទេ ក៏មិនមែន ២ Column ប្រៀបធៀបទៀតទេ) */
.vp-summary-box {
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 14px;
  padding: 2px 14px;
  margin: 0 0 14px;
}
.vp-summary-row { display: flex; align-items: center; gap: 10px; padding: 12px 0; text-align: left; }
.vp-summary-row + .vp-summary-row { border-top: 1px solid rgba(255, 255, 255, 0.06); }
.vp-summary-icon {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--gold-tint);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.92rem;
  flex-shrink: 0;
}
.vp-summary-label { color: var(--muted); font-size: 0.88rem; flex: 1; min-width: 0; }
.vp-summary-value { color: var(--cream); font-weight: 700; font-size: 1.02rem; white-space: nowrap; }
.vp-summary-value.vp-price { color: var(--gold-soft); font-size: 1.15rem; }

/* Warning សមតុល្យមិនគ្រប់គ្រាន់ — Box តូចសុភាព (មិនមែនធំគួរឲ្យខ្លាចទេ) មាន Icon + អត្ថបទ ២ជួរ */
.vp-insufficient-note {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  background: rgba(226, 114, 91, 0.1);
  border: 1px solid rgba(226, 114, 91, 0.35);
  border-radius: 12px;
  padding: 12px 14px;
  margin: 0 0 14px;
  text-align: left;
}
.vp-insufficient-note .vp-note-icon { font-size: 1rem; line-height: 1.4; flex-shrink: 0; }
.vp-insufficient-note .vp-note-text { display: flex; flex-direction: column; gap: 2px; }
.vp-insufficient-note .vp-note-text strong { color: var(--red); font-size: 0.86rem; font-weight: 700; }
.vp-insufficient-note .vp-note-text span { color: var(--red); opacity: 0.85; font-size: 0.8rem; }

.vp-actions { display: flex; flex-direction: column; gap: 10px; margin-top: 4px; }
.vp-trust-note { color: var(--muted); font-size: 0.72rem; text-align: center; margin: 14px 0 0; }

/* វីដេអូណែនាំការប្រើប្រាស់ (Popup ពី Modal ចុះឈ្មោះ — មើល #modal-register-tutorial-video ក្នុង index.html
   និង openRegisterTutorialVideo() ក្នុង app.js) */
.modal-tutorial-player { max-width: 860px; max-height: 92vh; overflow-y: auto; padding: 24px; }
.modal-tutorial-player h3 { margin: 0 0 12px; color: var(--gold-soft); }
.tutorial-player-frame { width: 100%; aspect-ratio: 16 / 9; display: block; border: none; border-radius: 10px; background: #000; }
/* YouTube Shorts (វីដេអូបញ្ឈរ 9:16) — ប្រើប្រអប់ 16:9 ធម្មតាធ្វើឲ្យវីដេអូតូចនៅកណ្ដាលមានចន្លោះខ្មៅច្រើនសងខាង
   (មើល public/js/app.js isVerticalTutorialUrl()) ដូច្នេះកែជាប្រអប់បញ្ឈរតាមកម្ពស់ជំនួសវិញ ដើម្បីឲ្យវីដេអូ
   ខ្លួនឯងធំតាមដែលអាចធ្វើទៅបាន */
.tutorial-player-frame.is-vertical { width: auto; height: min(75vh, 700px); max-width: 100%; aspect-ratio: 9 / 16; margin: 0 auto; }

.account-status {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 12px 16px;
  color: var(--muted);
  font-size: 0.9rem;
  margin-bottom: 18px;
}
.account-status.active { color: var(--gold-soft); border-color: var(--gold); }

.account-table-wrap { overflow-x: auto; }
.account-table { width: 100%; border-collapse: collapse; font-size: 0.85rem; }
.account-table th {
  text-align: left;
  color: var(--muted);
  font-weight: 700;
  padding: 8px 10px;
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
}
.account-table td {
  padding: 10px;
  border-bottom: 1px solid var(--border);
  color: var(--cream);
  white-space: nowrap;
}
.row-coupon { color: var(--gold-soft); font-size: 0.78rem; }

.status-tag {
  padding: 3px 10px;
  border-radius: 999px;
  font-size: 0.76rem;
  font-weight: 700;
}
.status-tag.status-completed { background: var(--gold-tint); color: var(--gold-soft); }
.status-tag.status-pending { background: rgba(217, 164, 65, 0.2); color: #d9a441; }
.status-tag.status-failed { background: rgba(226, 114, 91, 0.18); color: var(--red); }
.status-tag.status-refunded { background: rgba(148, 148, 148, 0.2); color: var(--muted); }
.status-tag.status-approved { background: var(--gold-tint); color: var(--gold-soft); }
.status-tag.status-rejected { background: rgba(226, 114, 91, 0.18); color: var(--red); }
.status-tag.status-expired { background: rgba(148, 148, 148, 0.2); color: var(--muted); }
.modal-close {
  position: absolute;
  top: 14px;
  right: 14px;
  background: none;
  border: none;
  color: var(--muted);
  font-size: 1.1rem;
  cursor: pointer;
}
.modal h3 { margin: 0 0 20px; color: var(--gold-soft); }
.modal form { display: flex; flex-direction: column; gap: 14px; }
.modal label { display: flex; flex-direction: column; gap: 6px; font-size: 0.88rem; color: var(--muted); min-width: 0; }
.modal input, .modal select {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 10px 12px;
  color: var(--cream);
  font-family: inherit;
  font-size: 0.95rem;
  width: 100%;
  min-width: 0;
}
.modal input:focus { outline: 2px solid var(--gold); outline-offset: 1px; }
.password-field { position: relative; display: flex; }
.password-field input { flex: 1; padding-right: 40px; }
.password-toggle-btn {
  position: absolute;
  right: 4px;
  top: 50%;
  transform: translateY(-50%);
  background: none;
  border: none;
  cursor: pointer;
  font-size: 1rem;
  padding: 6px;
  line-height: 1;
  opacity: 0.7;
}
.password-toggle-btn:hover { opacity: 1; }
.form-error { color: var(--red); font-size: 0.85rem; min-height: 1em; margin: 0; }
.form-hint { color: var(--muted); font-size: 0.85rem; min-height: 1em; margin: -6px 0 0; }
.thumbnail-preview { width: 110px; flex: 0 0 auto; border-radius: 8px; border: 1px solid var(--border); object-fit: cover; aspect-ratio: 16/9; }
.modal-switch { margin: 16px 0 0; text-align: center; color: var(--muted); font-size: 0.88rem; }
.modal-switch button { background: none; border: none; color: var(--gold-soft); cursor: pointer; font-family: inherit; text-decoration: underline; }

/* ---------- Auth modal (Login/Register) — "Khmer Fairy-Tale" redesign ----------
   Scoped entirely to .modal-auth (only #modal-login/#modal-register use this class) — deliberately
   NOT wired to the site's light/dark theme toggle (--bg/--gold/etc.) so this stays a consistent,
   always-dark "storybook" auth surface regardless of which site theme the user has picked, the same
   way most apps keep a branded sign-in screen distinct from the rest of the UI. Nothing outside these
   two modals references .modal-auth or --auth-* variables, so no other page/section is affected. */
.modal-auth {
  --auth-gold: #d8b06a;
  --auth-gold-soft: #eccb8f;
  --auth-text: #f2eee3;
  --auth-muted: #9a9aa5;
  --auth-border: rgba(216, 176, 106, 0.28);

  position: relative;
  overflow: hidden;
  max-width: 460px;
  max-height: min(90vh, 760px);
  padding: 26px 26px 24px;
  border-radius: 22px;
  border: 1px solid var(--auth-border);
  color: var(--auth-text);
  /* User រាយការណ៍ថា Modal នេះមើលទៅ "ធ្ងន់ពេក" ធៀបនឹង Website — Shadow/Glow/Backdrop ខាងក្រោមខ្លាំងជាង
     Modal ដទៃទៀតរបស់ Site ច្រើន (Shadow 70px Blur/0.6 Opacity ធៀបនឹង --shadow សកល 32px/0.35) ដូច្នេះបន្ថយ
     ជុំទី១ រួច User ស្នើបន្ថយបន្ថែមទៀត — ជុំនេះខិតជិត --shadow សកលស្ទើរតែស្មើគ្នា (មិនដកចេញ 100% ដើម្បីនៅតែ
     មាន Mood បន្តិចបំផុត) ។ ក្រោយមក User ស្នើឲ្យផ្ទៃខាងក្រោយត្រូវផ្គូផ្គងជាមួយ .site-header (Dashboard
     Reference) ដែលប្រើ rgba(18,21,42,.85) ជា Navy-Blue ពិត មិនមែន Neutral Charcoal (#181818/--bg-card)
     ដូចធ្លាប់ប្រើនោះទេ — ដូច្នេះប្តូរមកជា #12152a ដើម្បីផ្គូផ្គង Hue ជាមួយ Header ដដែល */
  background: #12152a;
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.35), 0 0 14px rgba(0, 0, 0, 0.2), inset 0 1px 0 rgba(255, 255, 255, 0.04);
}
/* Descendant (Input/Select) ខ្លះអាចមាន Scrollbar ផ្ទាល់ខ្លួន (ឧ. <select> វែងៗ) — ទុក thin ដដែលសម្រាប់
   ពួកវា។ ចំណែក .modal-auth ខ្លួនឯង (ជា .modal ដែរ) ធ្លាប់មាន Rule scrollbar-width:thin ដាច់ដោយឡែកនៅទីនេះ
   ជាន់លើ .modal{scrollbar-width:none} សកលដែលបានផ្លាស់ទី Rule នេះទៅដកចេញ ដើម្បីអោយ Login/Register
   ស៊ីគ្នាជាមួយ Popup ដទៃទៀត (គ្មាន Scrollbar លេចមកវិញ Popup ណាមួយឡើយ) */
.modal-auth * { scrollbar-width: thin; }
/* Overflow only kicks in on very short viewports/long forms (register has more fields) — everything
   else stays a fixed, comfortably-sized card per the "no excessive modal height" requirement. */
.modal-auth { overflow-y: auto; }
/* ធ្លាប់ជា Starfield + Castle Silhouette — User ស្នើដកចេញ (ដំបូង Register ប៉ុណ្ណោះ ក្រោយមក Login ដែរ)
   ជំនួសដោយ Border Light Chase (ខាងក្រោម) លើ ::before — ::after លែងប្រើទៀត (Content ថ្មីមិនត្រូវការ Layer
   ទីពីរទៀត) */
.modal-auth::after { display: none; }
/* Border Light Chase (SVG stroke-dashoffset animated ring) ដកចេញទាំងស្រុងតាម User ស្នើ — ព្យាយាមកែច្រើន
   ជុំ (Conic-Gradient → SVG stroke-dasharray, rx/ry Responsive តាម Breakpoint) ប៉ុន្តែ User នៅតែឃើញថា
   ពន្លឺមិនតាមកែងផ្ទាំងត្រឹមត្រូវ ដូច្នេះសម្រេចដកចេញ (មិនដាក់វិញទេ) — Modal នៅសល់ត្រឹមតែ Border ធម្មតា
   (--auth-border) ដូច Popup ដទៃទៀតរបស់ Site */
.modal-auth > * { position: relative; z-index: 1; }

/* Deepen the backdrop specifically behind the auth modals for a moonlit-night feel — the generic
   .modal-overlay dimming (rgba(0,0,0,0.72)) is untouched for every other modal on the site. User
   រាយការណ៍ថា Modal នេះ "ធ្ងន់ពេក" — បន្ថយជុំទី១ (0.88→0.78) រួច User ស្នើបន្ថយបន្ថែមទៀត — ជុំនេះខិតជិត
   ស្មើ Site ទូទៅ (0.72) ស្ទើរតែទាំងស្រុង */
#modal-login.modal-overlay,
#modal-register.modal-overlay {
  background: radial-gradient(120% 100% at 50% 15%, rgba(36, 26, 77, 0.22), rgba(0, 0, 0, 0.72));
  /* iOS Safari/Chrome (both forced onto WebKit by Apple) have a long-documented flexbox bug: a flex
     item with non-"visible" overflow (our .modal-auth uses overflow-y:auto) and no explicit `height`
     can get its USED height computed from `max-height` instead of shrinking to its actual content —
     the card renders at the full max-height ceiling with empty space below the real content, exactly
     what was reported. Blink (Android Chrome, desktop Chromium, this sandbox) doesn't have this bug,
     which is why only iPhone was affected regardless of browser. Grid's sizing algorithm for a single
     auto-placed cell doesn't share this quirk, so we switch to grid here — every other modal keeps
     display:flex, untouched. grid-template-columns/rows are set explicitly to a definite 1fr (rather
     than relying on the default implicit "auto" track) — an auto-sized track's width is indefinite,
     which makes the card's own width:100% ambiguous, and several browsers resolve that by shrinking
     the whole track to the content's fit-content size instead of the full overlay width (confirmed:
     this exact regression appeared while testing with an implicit track — the desktop card narrowed
     from 460px down to ~330px). With an explicit 1fr track, width:100%/max-width:460px on .modal-auth
     resolve exactly as they did under flex, and justify-items:center then correctly centers the
     (already correctly max-width-capped) card within that full-size track. */
  display: grid;
  grid-template-columns: 1fr;
  grid-template-rows: 1fr;
  align-items: center;
  justify-items: center;
}

/* Font ធ្លាប់ជា 'Moul' (ជៀសវាង Bug Shaping "ឈ្ម" លើ iOS Safari សម្រាប់ register_title ចាស់ "ចុះឈ្មោះគណនី")
   ប៉ុន្តែ Text នោះលែងប្រើទៀតហើយ (ប្តូរទៅ "ចុះឈ្មោះឥតគិតថ្លៃ" ដែលធ្លាប់សាកល្បង Decorative Font ជា Image
   ក្រោយមក User រាយការណ៍ថា "សរសេរខុស"/មិនស្រួលអាន ដូច្នេះប្តូរមក Battambang ធម្មតាវិញ) — Login h3 ("ចូលគណនី")
   ក៏គ្មាន Coeng Subscript ដែរ ដូច្នេះ Battambang សុវត្ថិភាពសម្រាប់ទាំង ២ Modal — User ស្នើឲ្យ Glow Pulse/
   Sparkle Twinkle ដែលធ្លាប់សាកល្បងលើ Register ជាមុន អនុវត្តលើ Login ដូចគ្នាដែរ ដូច្នេះដាក់នៅ Base Rule
   នេះទាំងអស់ជំនួសកូពីស្ទួន */
@keyframes authTitleGlowPulse {
  0%, 100% { text-shadow: 0 0 20px rgba(216, 176, 106, 0.35); }
  50% { text-shadow: 0 0 30px rgba(216, 176, 106, 0.55); }
}
@keyframes authSparkleTwinkle {
  0%, 100% { opacity: 0.3; transform: scale(0.85); }
  50% { opacity: 1; transform: scale(1.15); }
}
.modal-auth h3 {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  margin: 0 0 4px;
  color: var(--auth-gold-soft);
  font-family: 'Battambang', sans-serif;
  font-size: 1.3rem;
  font-weight: 700;
  line-height: 1.3;
  letter-spacing: 0.01em;
  text-shadow: 0 0 20px rgba(216, 176, 106, 0.35);
  animation: authTitleGlowPulse 2.4s ease-in-out infinite;
}
.modal-auth h3::before,
.modal-auth h3::after {
  content: '✦';
  font-size: 0.55em;
  color: var(--auth-gold);
  animation: authSparkleTwinkle 2.4s ease-in-out infinite;
}
.modal-auth h3::after { animation-delay: 1.2s; }
@media (prefers-reduced-motion: reduce) {
  .modal-auth h3,
  .modal-auth h3::before,
  .modal-auth h3::after {
    animation: none;
  }
}
.auth-modal-subtitle {
  margin: 0 0 20px;
  text-align: center;
  color: var(--auth-muted);
  font-size: 0.85rem;
}
/* Circular glass close button — scoped to .modal-auth so it only affects the login/register modals'
   close button (the shared .modal-close class is used by many other modals across the site, all of
   which keep their current plain style). .modal-auth already has position:relative (see its own rule
   above), and .modal-close is already position:absolute — both requirements for this to anchor
   correctly to the modal itself rather than the viewport. */
.modal-auth .modal-close {
  /* .modal-auth > * (further down this file) sets position:relative for pseudo-element z-index
     layering, and at equal specificity to the base .modal-close{position:absolute} rule, source
     order made it win — the button was actually rendering top-left this whole time despite the base
     rule's top/right offsets implying top-right. This selector has higher specificity (two classes
     vs one), so re-asserting position:absolute here wins cleanly and genuinely anchors the button to
     the modal card via its own position:relative, restoring the intended top-right corner. */
  position: absolute;
  /* A later sibling (e.g. the h3 title, a full-width flex row) can have invisible box area that's
     visually narrower than its own box — that invisible box still covers the button's corner and, at
     the same z-index:1 from .modal-auth > *, wins paint/hit-test order simply by coming later in the
     DOM. Clicks landed on the sibling's empty area instead of the button underneath: visible, but
     unclickable. Raising this above every sibling fixes it. */
  z-index: 2;
  top: 16px;
  right: 16px;
  width: 40px;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
  font-size: 19px;
  font-weight: 500;
  color: var(--auth-text);
  background: rgba(36, 26, 77, 0.45);
  border: 1px solid var(--auth-border);
  border-radius: 50%;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.25);
  transition: background 0.15s ease, border-color 0.15s ease, transform 0.15s ease;
}
.modal-auth .modal-close:hover {
  background: rgba(36, 26, 77, 0.65);
  border-color: var(--auth-gold);
  transform: scale(1.05);
}
.modal-auth .modal-close:active { transform: scale(0.94); }
/* 44×44px minimum touch target on phones (both login and register share this compact-mode
   breakpoint — see their own @media blocks further below, both triggering at ≤600px). */
@media (max-width: 600px) {
  .modal-auth .modal-close {
    top: 16px;
    right: 16px;
    width: 44px;
    height: 44px;
    font-size: 21px;
  }
}
.modal-auth label { color: var(--auth-muted); }
.modal-auth input,
.modal-auth select {
  background: rgba(0, 0, 0, 0.25);
  border: 1px solid rgba(255, 255, 255, 0.1);
  color: var(--auth-text);
}
.modal-auth input:focus { outline: 2px solid var(--auth-gold); outline-offset: 1px; border-color: var(--auth-gold); }
.modal-auth .btn-primary {
  background: linear-gradient(135deg, var(--auth-gold), #b5883f);
  color: #1a1330;
}
.modal-auth .btn-primary:hover { filter: brightness(1.08); }
.modal-auth .btn-ghost { background: rgba(255, 255, 255, 0.03); border-color: rgba(255, 255, 255, 0.14); color: var(--auth-text); }
.modal-auth .btn-ghost:hover { border-color: var(--auth-gold); }
.modal-auth .channel-btn { background: rgba(255, 255, 255, 0.04); border-color: rgba(255, 255, 255, 0.12); color: var(--auth-muted); }
.modal-auth .channel-btn.active { background: var(--auth-gold); border-color: var(--auth-gold); color: #1a1330; }
.modal-auth .telegram-status { color: var(--auth-gold-soft); }
.modal-auth .register-guide-title { color: var(--auth-gold-soft); }
.modal-auth .register-guide { color: var(--auth-muted); }
.modal-auth .form-hint { color: var(--auth-muted); }
.modal-auth .modal-switch { color: var(--auth-muted); }
.modal-auth .modal-switch button { color: var(--auth-gold-soft); }

/* Compact floating card on mobile — login used to go full-screen (height:100dvh) here, which left a
   large empty gap below the last link on a short form like login's. Replaced with a centered card
   sized to its own content, height:auto capped by max-height, matching the treatment already used
   for the register popup (see the register-only mobile block further below). */
@media (max-width: 480px) {
  #modal-login.modal-overlay {
    padding: 16px;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
  }
  #modal-login .modal-auth {
    width: 90%;
    max-width: 380px;
    height: auto;
    min-height: 0;
    /* dvh (dynamic viewport height) tracks the ACTUAL visible viewport as Safari's address bar
       shows/hides — plain vh uses the "large" viewport (chrome collapsed) on iOS, which is taller
       than what's really visible and was a contributing factor to the oversized card. Declared after
       vh so unsupported browsers keep the vh value; dvh silently wins wherever it's supported. */
    max-height: 90vh;
    max-height: 90dvh;
    margin: auto;
    padding: 18px;
    border-radius: 18px;
    box-sizing: border-box;
    overflow-y: auto;
    overflow-x: hidden;
  }
  #modal-login .modal-auth h3 { font-size: 1.15rem; margin: 0 0 2px; }
  #modal-login .modal-auth .auth-modal-subtitle { font-size: 0.78rem; margin-bottom: 12px; }
  #modal-login .modal-auth form { gap: 10px; }
  #modal-login .modal-auth input,
  #modal-login .modal-auth select { padding: 9px 12px; min-height: 44px; box-sizing: border-box; }
  #modal-login .modal-auth .modal-switch { margin-top: 10px; }
}

/* ---------- Registration popup — refinement pass (register-only, scoped to #modal-register) ----------
   Everything below overrides/extends the shared .modal-auth theme above ONLY for #modal-register —
   #modal-login keeps its own form-specific layout (more fields — phone/password), but the visual
   theme itself (background, border glow, button sizing, heading treatment) is now shared via the
   base .modal-auth rules above, applying identically to both modals. */

/* [Google/Telegram-only Register] Form Phone+Password ចាស់ត្រូវបានដកចេញ — Content ខ្លីជាងច្រើនឥឡូវនេះ
   (Header + Subtitle + ២ ប៊ូតុង + Switch-Link ប៉ុណ្ណោះ) ដូច្នេះកាត់បន្ថយ CSS ដែលធ្លាប់សម្រាប់ Form/Field/
   Icon ដែលលែងមានទៀតហើយ (form gap, label gap, input padding, form-error, icon content ៣ដួង) — Subtitle
   ទទួល margin-bottom ជំនួស Divider ចាស់ ដើម្បីរក្សាគម្លាតរវាង Subtitle → ប៊ូតុងដដែល */
#modal-register .modal-auth { padding: 26px 24px 14px; max-height: min(97vh, 800px); }
/* [Wordmark ដកចេញ] ចំណងជើងក្លាយជា Element ដំបូងបំផុតឥឡូវនេះ (គ្មាន Logo/Wordmark Row ខាងលើទៀតទេ) —
   padding-top ខាងលើបានបន្ថែមផងដែរ ដើម្បីទុកគម្លាតជាមួយប៊ូតុងបិទ (Close) កំពូលស្តាំ ដែលពីមុនមាន Header Row
   ការពារជូនស្រាប់ (Login រក្សា Header Row ដដែល ដូច្នេះមិនត្រូវការ padding-top បន្ថែមនេះទេ) */
#modal-register .modal-auth .auth-modal-subtitle { margin-bottom: 16px; font-size: 0.82rem; }
#modal-register .modal-auth .modal-switch { margin-top: 10px; }
/* User រាយការណ៍ថា Google/Telegram Button "ក្រាស់ពេកវែងពេក" — 48px Height/24px Radius ខ្ពស់ជាង .btn សកល
   របស់ Site ច្រើន (padding 9px 20px ≈ 32-36px Height ធម្មតា) ដូច្នេះបន្ថយ Height/Radius ខ្លះ — ធ្លាប់ Scoped
   Register ជាមុន User ស្នើឲ្យ Login ដូចគ្នាដែរ ដូច្នេះផ្លាស់ទៅ Base Class ខាងក្រោមជំនួស (មើលកំណត់ត្រា
   .google-login-button/.telegram-login-button) */

/* Shared sizing for the primary auth-action buttons (Telegram verify and each modal's main submit
   button) — built from one class so they're pixel-identical by construction (46px height, 23px
   radius, full width). Applies at every size, not just mobile, since both modals want this parity
   on desktop too. */
.auth-action-button {
  width: 100%;
  height: 46px;
  min-height: 46px;
  max-height: 46px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  border-radius: 23px;
  box-sizing: border-box;
}

/* ---------- Google Sign-In — OAuth 2.0 Authorization Code Flow (Redirect ធម្មតា) ----------
   <a href> ធម្មតា Navigate ទៅ Server ខ្លួនឯង (/api/auth/google/start) — ជំនួស Implementation ចាស់
   (Google Identity Services Popup/renderButton() Iframe) ដែលមានបញ្ហាមិនអាចដោះស្រាយបានលើ Mobile
   (ចុចមិនចេញ, លេចរួចរលាយវិញ) — ទីនេះជា Element ដែល Site ខ្លួនឯង Style/Control ទាំងស្រុង (មិនមែន Iframe
   ក្រៅឡើយ) ដូច្នេះគ្មានហានិភ័យបញ្ហាបែបនោះទៀត — Touch Target 48px (Spec ស្នើ 48-52px) */
.auth-divider {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 14px 0 12px;
  color: var(--muted);
  font-size: 0.82rem;
}
.auth-divider::before,
.auth-divider::after { content: ''; flex: 1; height: 1px; background: rgba(255, 255, 255, 0.14); }

/* Height/Radius/Font-Size បន្ថយពី 48px/24px/0.94rem ដើម (User រាយការណ៍ "ក្រាស់ពេកវែងពេក" ធៀបនឹង .btn
   សកលរបស់ Site — ធ្លាប់ Scoped Register ជាមុន User ស្នើឲ្យ Login ដូចគ្នាដែរ ដូច្នេះកែត្រង់ Base នេះផ្ទាល់) */
.google-login-button {
  width: 100%;
  height: 42px;
  min-height: 42px;
  box-sizing: border-box;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  border-radius: 21px;
  border: 1px solid rgba(255, 255, 255, 0.85);
  background: #fff;
  color: #3c4043;
  font-family: inherit;
  font-size: 0.9rem;
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
  transition: background 0.15s ease, box-shadow 0.15s ease;
  /* touch-action:manipulation — កាត់បន្ថយ Delay 300ms លើ Mobile Browser មួយចំនួន, មិនប៉ះពាល់ Scroll ឡើយ */
  touch-action: manipulation;
}
.google-login-button:hover { background: #f8f8f8; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2); }
.google-login-button:active { background: #f1f1f1; }
/* Focus State ដែលមើលឃើញច្បាស់ — សម្រាប់ Keyboard Navigation (Tab + Enter) — មិនពឹងផ្អែកលើ Hover ឡើយ */
.google-login-button:focus-visible {
  outline: 2px solid #4285f4;
  outline-offset: 2px;
}
.google-login-icon { flex-shrink: 0; }

/* ដូចគ្នាបេះបិទនឹង .google-login-button ខាងលើ (ទំហំ/គម្លាត/Border-Radius ដូចគ្នា) គ្រាន់តែផ្លាស់ប្តូរពណ៌
   ជា Telegram Brand Blue (#229ED9 — ប្រើរួចហើយកន្លែងផ្សេងក្នុង File នេះ) ជំនួសពណ៌ស/Icon-Colored របស់ Google —
   margin-top ត្រូវការព្រោះ Button នេះតោងជាប់ក្រោម Google ដោយផ្ទាល់ គ្មាន .auth-divider ខាងលើដូច Google ទេ */
.telegram-login-button {
  width: 100%;
  height: 42px;
  min-height: 42px;
  box-sizing: border-box;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  border-radius: 21px;
  border: 1px solid transparent;
  background: #229ed9;
  color: #fff;
  font-family: inherit;
  font-size: 0.9rem;
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
  margin-top: 8px;
  transition: background 0.15s ease, box-shadow 0.15s ease;
  touch-action: manipulation;
}
.telegram-login-button:hover { background: #1e8bc3; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2); }
.telegram-login-button:active { background: #1a7aac; }
.telegram-login-button:disabled { opacity: 0.6; cursor: default; }
.telegram-login-button:focus-visible {
  outline: 2px solid #229ed9;
  outline-offset: 2px;
}
.telegram-login-icon { flex-shrink: 0; }

/* Compact, centered, non-full-screen popup on mobile (replaces a full-screen sheet approach for
   register specifically — login keeps its own separate full-screen behavior above, untouched). */
@media (max-width: 600px) {
  #modal-register.modal-overlay {
    padding: 16px;
    align-items: center;
    justify-content: center;
  }
  #modal-register .modal-auth {
    width: 92%;
    max-width: 420px;
    height: auto;
    min-height: 0;
    /* See the matching comment in the #modal-login mobile block above — same dvh/vh reasoning. */
    max-height: 90vh;
    max-height: 90dvh;
    overflow-y: auto;
    margin: auto;
    padding: 26px 16px 18px;
    border-radius: 16px;
  }
  #modal-register .modal-auth h3 { font-size: 1.25rem; margin: 0 0 2px; }
  #modal-register .modal-auth .auth-modal-subtitle { font-size: 0.78rem; margin-bottom: 12px; }
  #modal-register .modal-auth .modal-switch { margin-top: 8px; }
}

/* ---------- Video watch overlay (YouTube-like: full player on PC, stacked on mobile) ---------- */
#modal-video.modal-overlay {
  padding: 0;
  align-items: stretch;
  justify-content: stretch;
  background: var(--bg);
}
#modal-video .modal.modal-video {
  width: 100%;
  max-width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
  border: none;
  border-radius: 0;
  box-shadow: none;
  overflow-x: hidden;
  overflow-y: auto;
  background: var(--bg);
}
/* Top bar — persistent brand/logo + close, stays visible while watching (like YouTube's header)
   left/right:0 (មិនមែនគ្រាន់តែ width:100% ទេ) — iOS Safari ជួនកាលគណនាទទឹងខុសសម្រាប់ position:sticky
   ខាងក្នុង Container ដែលមាន overflow-y:auto ធ្វើឲ្យប៊ូតុងខាងស្តាំលិចលើសគែម */
.vm-topbar {
  position: sticky;
  top: 0;
  left: 0;
  right: 0;
  z-index: 105;
  height: 56px;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 16px;
  background: #161616;
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--border);
}
/* User រាយការណ៍ថា Header/Player/Content មាន Contrast ខ្លាំងពេក (var(--bg-raised) #212121 ភ្លឺជាង
   Player/Content #0f0f0f ខ្លាំង) — បន្ថយមកជា #161616 (ជិត Body ជាង) សម្រាប់ Dark Theme ដើម្បីអោយ
   មើលទៅ Premium/ស្រុះស្រួយជាង។ Light Theme រក្សា var(--bg-raised) ដដែល (កុំប៉ះ) */
:root[data-theme="light"] .vm-topbar { background: var(--bg-raised); }
.vm-brand { display: flex; align-items: center; gap: 8px; text-decoration: none; }
#modal-video .modal-close {
  position: static;
  width: 34px;
  height: 34px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--gold-tint);
  color: var(--cream);
  font-size: 0.95rem;
}

.vm-layout {
  display: flex;
  align-items: flex-start;
  gap: 24px;
  max-width: 1500px;
  margin: 0 auto;
  padding: 20px 20px 60px;
}
.vm-main { flex: 1 1 0; min-width: 0; }

/* ពណ៌ Fix ថេរ (មិនប្រើ var(--bg) ទេ — Light Theme --bg ជាពណ៌ភ្លឺ #f4faf9 ដែលនឹងធ្វើឲ្យ Playerភ្លឺខុសពី
   Video Player ធម្មតា) — ប្រើ Hex ដដែលនឹង Dark Theme --bg ខ្លួនឯង (#0f0f0f) ដោយផ្ទាល់ ជំនួស Pure #000
   ដើម្បីស្របតាម "Dark Theme ដដែលមានស្រាប់" ដូចសំណើ ខណៈនៅតែស្ថិតស្ថេរមិនប្តូរតាម Light/Dark Toggle (ដូច
   Video Player ធម្មតាទាំងអស់ជានិច្ច ដូចគ្នានឹង .modal-auth/.mobile-menu-dropdown ធ្វើដែរ) */
.vm-player-wrap { width: 100%; background: #0f0f0f; border-radius: 8px; overflow: hidden; }
.vm-player-inner { width: 100%; position: relative; }
.vm-info { padding-top: 16px; }

/* .vm-info កំណត់ Specificity (0,2,0) លើសពី .modal h3 ខាងលើ (Global Rule margin:0 0 20px សម្រាប់ h3
   ក្នុង Modal ណាមួយ) ដើម្បីឲ្យ Title→Author នៅតែ 8px ពិតប្រាកដ (មិនមែន 20px ដែល .modal h3 នឹង Win
   ដោយ Specificity ខ្ពស់ជាង បើប្រើ .vm-title ម្នាក់ឯង) — អនុវត្តដូចគ្នាទាំង ៣ Variant (Guest Gate/
   Normal Player/Premium Locked) ព្រោះទាំងអស់ស្ថិតក្នុង .vm-info ដូចគ្នា */
/* User រាយការណ៍ថាចំណងជើងមិនទាន់លេចគ្រប់គ្រាន់ (ធ្លាប់ Browser Default h3 ~18.7px) — ដំឡើងទៅ 1.35rem
   (~21.6px) + Glow ស្រាលៗពណ៌ដូច Text ខ្លួនឯង ឲ្យលេចជាងដោយមិនប្តូរ Color/Font */
.vm-info .vm-title { color: var(--gold-soft); margin: 0 0 10px; font-family: 'Battambang', sans-serif; font-weight: 700; font-size: 1.35rem; line-height: 1.3; text-shadow: 0 0 18px rgba(124, 196, 255, 0.28); }
:root[data-theme="light"] .vm-info .vm-title { text-shadow: none; }
.vm-uploader-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 12px;
  margin-bottom: 16px;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--border);
}
.vm-uploader { display: flex; align-items: center; gap: 7px; color: var(--muted); font-size: 0.88rem; margin: 0; }
.uploader-avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  flex-shrink: 0;
  border-radius: 50%;
  background: var(--gold);
  color: #fff;
  font-size: 0.72rem;
  font-weight: 700;
  font-family: 'Battambang', sans-serif;
}
.uploader-avatar-img {
  width: 22px;
  height: 22px;
  flex-shrink: 0;
  border-radius: 50%;
  object-fit: cover;
  background: var(--bg-card);
}
.uploader-name { color: var(--muted); }
.verified-badge { flex-shrink: 0; }
.vm-desc { color: var(--muted); margin: 0 0 18px; }
.vm-guest-cta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 10px;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 12px 16px;
  margin: 0 0 18px;
}
.vm-guest-cta p { margin: 0; color: var(--muted); font-size: 0.88rem; }
.vm-guest-cta .btn { white-space: nowrap; padding: 8px 16px; }
.vm-free-tag {
  display: flex;
  align-items: center;
  background: var(--gold-tint);
  color: var(--gold-soft);
  font-size: 0.76rem;
  font-weight: 700;
  padding: 6px 12px;
  border-radius: 999px;
}
/* Badge ក្នុង .vm-title ខ្លួនឯង (Inline ជាមួយអក្សរចំណងជើង) សម្រាប់ Video Premium/ពិសេស កំពុងចាក់ជា Preview
   មិនទាន់ Unlock ពិត — មើលកំណត់ត្រា setupLockedPreviewGate() ក្នុង app.js */
.vm-preview-badge {
  display: inline-flex;
  align-items: center;
  vertical-align: middle;
  margin-left: 8px;
  background: var(--gold-tint);
  color: var(--gold-soft);
  font-size: 0.7rem;
  font-weight: 700;
  padding: 4px 10px;
  border-radius: 999px;
  white-space: nowrap;
}
.vm-thumb { width: 100%; aspect-ratio: 16/9; object-fit: cover; display: block; }
.vm-thumb-blurred { filter: blur(12px) brightness(0.55); transform: scale(1.08); }

/* ប្រអប់ Locked ត្រូវអោយកម្ពស់ធំតាមមាតិកា (Icon + តម្លៃ + ប៊ូតុង ២) មិនមែនកាត់តាមសមាមាត្រវីដេអូ 16/9 ទេ
   បើមិនធ្វើដូច្នេះ លើ Mobile ប៊ូតុងលើសហួសប្រអប់ ហើយត្រូវផ្នែក "រឿងផ្សេងទៀត" លាក់ខាងក្រោមគ្របលើ — `aspect-ratio:
   16/9` ដើមក្លាយជា "កម្រិតអប្បបរមា" ខ្លួនឯង (មិនកាត់ Content ទេ តែក៏មិនអោយ Box ខ្លីជាង 16/9 បានដែរ) ដែល
   ធ្វើឲ្យ Hero ធំហួសទាំង Desktop (540px+ លើ Modal ធំៗ) និង Mobile — ប្តូរទៅ min-height ជាក់លាក់វិញ (Desktop
   380px / Mobile 195px ក្នុង Media Query ខាងក្រោម) ដើម្បីគ្រប់គ្រង Height ដោយផ្ទាល់ជំនួស Ratio
   [ករណីលើកលែង — --purchase ខាងក្រោម និង --gate ថ្មី] ទាំងពីរនេះ Override មកវិញជា True 16:9 (មិនប្រែប្រួល
   ពីទំហំវីដេអូធម្មតាទាល់តែសោះ ពេលកំពុងចាក់ ប្តូរទៅ Locked ភ្លាមៗ) ដោយបង្រួម Content ខាងក្នុងអោយសមតូច
   ជំនួសវិញ (មើល Rule របស់ពួកវានីមួយៗ) */
.vm-player-locked .vm-player-inner { aspect-ratio: auto; min-height: 380px; }
.vm-player-locked .vm-thumb-blurred {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  aspect-ratio: auto;
}
.vm-lock-overlay {
  position: relative;
  z-index: 1;
  min-height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 24px;
  text-align: center;
}
/* SVG ជំនួស Emoji 🔒 (ដូចគ្នាបេះបិទនឹង lockIconSvg()/.badge-lock-icon ក្នុង app.js/style.css ខាងលើ) —
   svg { width/height: 1em } ស្រូបទំហំតាម font-size របស់ Container ខាងក្រៅ ធានាថា Rule Responsive ចាស់
   ទាំងអស់ខាងក្រោម (font-size 1.5rem/1.15rem/1rem) នៅតែសម្រេចទំហំ Icon ដូចមុនដោយមិនចាំបាច់សរសេរឡើងវិញ */
.vm-lock-icon { font-size: 2.4rem; color: #eccb8f; }
.vm-lock-icon svg,
.vm-purchase-lock-icon svg { width: 1em; height: 1em; }
.vm-gate-title { font-size: 1.2rem; color: var(--cream); font-weight: 700; margin: 0; }
.vm-gate-sub { color: var(--muted); margin: 0 0 6px; max-width: 320px; }
.vm-lock-overlay .btn { width: 100%; max-width: 320px; }
.vm-lock-overlay .form-error { max-width: 320px; }

/* Guest Preview Gate (showPreviewGate() — "ចង់បន្តមើលទៀត?") — ដូចគ្នានឹង --purchase ខាងក្រោម រក្សា True
   16:9 ដើម្បីកុំឲ្យ Player ប្តូរទំហំភ្លាមៗពេល Guest មើលអស់ Preview Time ហើយ Gate នេះលេចជំនួសវីដេអូ (Bug
   ពិតដែលរាយការណ៍ — Player ខ្លីចុះភ្លាមៗ ខុសសមាមាត្រពីមុន) — បង្រួម Icon/Title/Subtitle/ប៊ូតុងអោយសមតូច
   ជំនួសវិញ ដូច --purchase បានធ្វើ (ជៀសវាង Bug ចាស់ខាងលើ ដែល --purchase ដោះស្រាយរួចហើយ) */
.vm-player-locked--gate .vm-player-inner { aspect-ratio: 16/9; min-height: 0; }
.vm-player-locked--gate .vm-lock-overlay { padding: 12px; gap: 4px; }
.vm-player-locked--gate .vm-lock-icon { font-size: 1.5rem; }
.vm-player-locked--gate .vm-gate-title { font-size: 0.92rem; }
.vm-player-locked--gate .vm-gate-sub { font-size: 0.72rem; margin: 0 0 2px; max-width: 280px; }
.vm-player-locked--gate .vm-lock-overlay .btn { height: 34px; padding: 0 12px; font-size: 0.82rem; max-width: 260px; }

/* ---------- Purchase Section (Premium-Locked Video, "ទិញរឿងនេះ" / "ចូលជាសមាជិក") ----------
   ដាក់ក្នុង .vm-lock-overlay ដដែល (ដូច Guest Preview Gate ខាងលើ — showPreviewGate() ដែលនៅតែប្រើ
   .vm-lock-overlay/.vm-lock-icon/.vm-player-locked ធម្មតាដដែលទាំងស្រុង មិនប៉ះពាល់ដោយ --purchase Modifier
   ខាងក្រោមឡើយ) — Content កណ្តាលទាំង Horizontal/Vertical (មិនមែនចុះក្រោមទៀតទេ) លើ True 16:9 Aspect-Ratio
   (មិនមែន Content-Driven Height ទៀតទេ) ដូចសំណើ "Maintain a clean 16:9 video-thumbnail proportion" —
   ប៊ូតុងតូចល្មម + Icon តូច ដើម្បីអោយសមនឹងកម្ពស់ 16:9 ពិត (~211px លើ 375px ទទឹង) ។ Base Class តែមួយ
   (.vm-purchase-btn) កំណត់ Width/Height/Padding/Border-Radius/Font-Size ដូចគ្នាបេះបិទរវាងប៊ូតុងទាំង ២ —
   មាន Modifier Class ២ (--buy/--member) ប្តូរតែ Background/Color ប៉ុណ្ណោះ ។ ប្រើ height ថេរ (មិនមែន
   min-height ទេ) ធានាកម្ពស់ដូចគ្នាបេះបិទ ទោះបីជាមាតិកា ១ ឬ ២ បន្ទាត់ក៏ដោយ */
.vm-lock-overlay--purchase {
  position: absolute;
  inset: 0;
  justify-content: center;
  gap: 8px;
  padding: 14px;
  background: rgba(12, 12, 12, 0.5);
}
/* aspect-ratio:16/9 (Override .vm-player-locked's Base aspect-ratio:auto;min-height:380px — Scoped ត្រឹម
   --purchase ប៉ុណ្ណោះ, Guest Gate មិនប៉ះពាល់ទេ) ត្រូវការនៅទីនេះទាំង Desktop និង Mobile — មើល Media Query
   ខាងក្រោមផងដែរ ព្រោះ Selector Specificity ស្មើគ្នា Source Order ក្រោយបំផុតឈ្នះ (Mobile Rule .vm-player-
   locked .vm-player-inner{...195px} នៅក្រោមទីនេះនឹងឈ្នះលើ Viewport តូច បើគ្មាន Override ជាក់លាក់ដដែល) */
.vm-player-locked--purchase .vm-player-inner { aspect-ratio: 16/9; min-height: 0; }
/* position:absolute;inset:0 លើ .vm-lock-overlay--purchase ខាងលើ ត្រូវការព្រោះ .vm-lock-overlay's Base
   min-height:100% មិនអាច Resolve បានត្រឹមត្រូវ ពេល Parent Height កំណត់ដោយ aspect-ratio ជំនួស height ពិត
   (Percentage Height តម្រូវ Parent មាន Definite Height) — inset:0 ធានាថា Overlay ពេញ Parent ជានិច្ច */
.vm-purchase-lock-icon { font-size: 1.15rem; line-height: 1; opacity: 0.9; color: #eccb8f; }
.vm-purchase-actions {
  display: flex;
  flex-direction: column;
  gap: 8px;
  width: 100%;
  max-width: 300px;
}
/* វីដេអូ "ពិសេស" (excludeFromSubscription) — btn-subscribe-cta មិន Render ទេ (មើល app.js) ដូច្នេះចន្លោះ
   នៅសល់គ្រប់គ្រាន់សម្រាប់ Note នេះ ដោយមិនហួស 16:9 ដែលបានកំណត់ (មើលកំណត់ចំណាំ .vm-player-locked--purchase
   ខាងក្រោម) — Font តូច Margin តូច ដើម្បីរក្សា Fit ដដែល */
.vm-exclude-subscription-note {
  margin: 6px 0 0;
  max-width: 300px;
  color: var(--gold-soft);
  font-size: 0.68rem;
  line-height: 1.3;
  text-align: center;
}
.vm-purchase-btn {
  all: unset;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1px;
  width: 100%;
  height: 40px;
  padding: 4px 14px;
  border-radius: var(--radius);
  text-align: center;
  cursor: pointer;
  font-family: 'Battambang', sans-serif;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.55);
  transition: transform 0.2s ease, filter 0.2s ease, background 0.2s ease;
}
.vm-purchase-btn:hover { transform: translateY(-1px); filter: brightness(1.1); }
.vm-purchase-btn:active { transform: scale(0.98) translateY(0); }
.vm-purchase-btn:focus-visible { outline: 2px solid var(--gold-soft); outline-offset: 2px; }
.vm-purchase-btn-title { font-size: 0.82rem; font-weight: 700; line-height: 1.2; }
.vm-purchase-btn-sub { font-size: 0.62rem; font-weight: 500; opacity: 0.9; line-height: 1.1; }
/* ពណ៌ Semi-Transparent ស្រាល (មិនមែន Solid/Gradient ដូចមុនទេ) តាមសំណើ "soft transparent colors... No
   strong solid blue/yellow... No gradient" — Thumbnail ព្រិលៗខាងក្រោមនៅតែឃើញបន្តិចតាមរយៈប៊ូតុង (rgba
   Alpha ០.៥៥) — ខៀវ (Buy) vs មាស (Member) ជាតម្លៃពណ៌ដាច់ដោយឡែក (មិនមែន var(--gold) ដែលជាខៀវឥឡូវនេះ ដើម្បី
   ឲ្យបានពណ៌ខៀវពិតប្រាកដតាមឧទាហរណ៍ rgba(50,160,255) ដែលស្នើ) */
.vm-purchase-btn--buy { background: rgba(50, 160, 255, 0.55); color: #fff; }
.vm-purchase-btn--member { background: rgba(230, 180, 70, 0.55); color: #fff; }
@media (prefers-reduced-motion: reduce) {
  .vm-purchase-btn { transition: none; }
  .vm-purchase-btn:hover { transform: none; }
}

video.vm-player, iframe.vm-player { width: 100%; aspect-ratio: 16/9; display: block; border: none; }

/* ---------- Custom Control Bar (MP4 ដោយផ្ទាល់ប៉ុណ្ណោះ — vm-local-player) ----------
   ជំនួស Native <video controls> ទាំងស្រុង ព្រោះ Browser ទំនើបៗលែងអនុញ្ញាតឲ្យ CSS ប្តូរពណ៌ Native Seek
   Bar (Played vs Remaining) ដោយទុកចិត្តបាន Cross-browser ទៀតទេ — មើល app.js videoPlayerHtml() +
   bindCustomProgressAndControls() សម្រាប់ Logic ពេញលេញ។ Overlay លើវីដេអូ (Position:absolute) ដូច
   .vm-settings ខាងក្រោម ដូច្នេះមិនកើនទំហំ/ប្តូរ Layout របស់ Player ទាល់តែសោះ (aspect-ratio 16/9 ដដែល) */
.vm-custom-controls {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 4;
  padding: 6px 12px 8px;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.75) 0%, rgba(0, 0, 0, 0.4) 65%, transparent 100%);
  color: #fff;
}
.vm-progress-row { display: flex; align-items: center; }
.vm-controls-row { display: flex; align-items: center; gap: 10px; margin-top: 2px; }
.vm-controls-spacer { flex: 1; }
.vm-volume-group { display: flex; align-items: center; gap: 6px; flex-shrink: 0; }
.vm-ctrl-btn {
  flex-shrink: 0;
  background: none;
  border: none;
  color: #fff;
  cursor: pointer;
  padding: 5px;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0.92;
  transition: opacity 0.15s ease, transform 0.1s ease;
}
.vm-ctrl-btn:hover { opacity: 1; }
.vm-ctrl-btn:active { transform: scale(0.9); }
.vm-icon-pause, .vm-icon-vol-muted, .vm-icon-fullscreen-exit { display: none; }
#vm-play-btn.is-playing .vm-icon-play { display: none; }
#vm-play-btn.is-playing .vm-icon-pause { display: inline-flex; }
#vm-mute-btn.is-muted .vm-icon-vol-high { display: none; }
#vm-mute-btn.is-muted .vm-icon-vol-muted { display: inline-flex; }
#vm-fullscreen-btn.is-fullscreen .vm-icon-fullscreen-enter { display: none; }
#vm-fullscreen-btn.is-fullscreen .vm-icon-fullscreen-exit { display: inline-flex; }
.vm-time-display {
  font-size: 0.78rem;
  color: rgba(255, 255, 255, 0.9);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

/* ---------- Progress/Seek Bar និង Volume Slider — សាងសង់ជា <div> ធម្មតា (មិនមែន <input type=range>) ----------
   មូលហេតុ៖ Browser ជាច្រើន (iOS Safari, Android WebView, Chrome ថ្មីៗតាម ::-webkit-slider-container)
   នៅតែបង្ខំបង្ហាញ Native Track/Focus Box លំនាំដើមផ្ទាល់ខ្លួន ទោះបីជា Reset CSS យ៉ាងម៉េចក៏ដោយ — នេះជា Root
   Cause ពិតនៃប្រអប់ប្រផេះ/ខ្មៅដែលរាយការណ៍ជាដដែលៗជុំវិញ Progress/Volume។ <div> ធម្មតាគ្មាន Native
   Appearance អ្វីទាំងអស់ ដូច្នេះលែងមានហានិភ័យនេះជារៀងរហូត — Drag/Click ដំណើរការតាម Pointer Events ក្នុង
   app.js (bindSlider) ជំនួស input/change Event ចាស់។ */
.vm-progress-bar, .vm-volume-bar {
  position: relative;
  height: 14px;
  display: flex;
  align-items: center;
  cursor: pointer;
  touch-action: none;
}
.vm-progress-bar { flex: 1; }
.vm-volume-bar { width: 100px; }
.vm-progress-bar::before, .vm-volume-bar::before {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  height: 2px;
  border-radius: 2px;
  background: rgba(255, 255, 255, 0.12);
}
.vm-progress-fill, .vm-volume-fill {
  position: absolute;
  left: 0;
  height: 2px;
  border-radius: 2px;
  background: var(--gold);
  width: 0%;
  pointer-events: none;
}
.vm-progress-thumb, .vm-volume-thumb {
  position: absolute;
  top: 50%;
  left: 0%;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--gold);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.5);
  transform: translate(-50%, -50%);
  transition: transform 0.12s ease;
  pointer-events: none;
}
.vm-progress-bar:hover .vm-progress-thumb, .vm-progress-bar:active .vm-progress-thumb,
.vm-volume-bar:hover .vm-volume-thumb, .vm-volume-bar:active .vm-volume-thumb {
  transform: translate(-50%, -50%) scale(1.25);
}
/* Div ទាំងនេះមាន tabindex=0 (ដើម្បី Keyboard Accessible) ដូច្នេះ Browser លំនាំដើមនឹងគូរ Outline ជុំវិញ
   ប្រអប់ទាំងមូលពេល Focus — បិទវា ហើយប្រើពន្លឺតូចនៅលើ Thumb ជំនួសវិញ (កុំឲ្យក្លាយជាប្រអប់ខៀវព័ទ្ធជុំវិញ Bar) */
.vm-progress-bar:focus, .vm-volume-bar:focus,
.vm-progress-bar:focus-visible, .vm-volume-bar:focus-visible {
  outline: none;
}
.vm-progress-bar:focus-visible .vm-progress-thumb, .vm-volume-bar:focus-visible .vm-volume-thumb {
  box-shadow: 0 0 0 3px rgba(62, 166, 255, 0.4);
}

/* ពេញអេក្រង់ — Center Video ក្នុង Letterbox ខ្មៅ (មិនទាញ Stretch ខូចសមាមាត្រ) */
.vm-player-inner:fullscreen {
  display: flex;
  align-items: center;
  justify-content: center;
  background: #000;
  height: 100%;
}
.vm-player-inner:fullscreen video.vm-player { width: auto; height: 100%; max-width: 100%; aspect-ratio: auto; }
.vm-player-inner:fullscreen .vm-custom-controls { position: fixed; }

@media (max-width: 767px) {
  .vm-time-display { font-size: 0.72rem; }
  .vm-controls-row { gap: 6px; }
  .vm-volume-bar { width: 56px; }
}

/* Gear settings menu — Trigger Button ឥឡូវនេះជាផ្នែកនៃ .vm-controls-row ធម្មតា (.vm-ctrl-btn) ដូច Button
   ដទៃទៀត, .vm-settings នៅសល់តែជា Wrapper positioned:relative សម្រាប់ Anchor ម៉ឺនុយ Dropdown ខាងក្រោម */
.vm-settings { position: relative; flex-shrink: 0; }

.vm-settings-menu {
  position: absolute;
  bottom: 42px;
  right: 0;
  min-width: 190px;
  background: var(--bg-raised);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: var(--shadow);
  padding: 6px 0;
  backdrop-filter: blur(6px);
}
.vm-settings-section + .vm-settings-section {
  border-top: 1px solid var(--border);
  margin-top: 4px;
  padding-top: 4px;
}
.vm-settings-label {
  color: var(--muted);
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding: 6px 14px 4px;
}
.vm-settings-option {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  background: none;
  border: none;
  color: var(--cream);
  font-family: inherit;
  font-size: 0.88rem;
  text-align: left;
  padding: 7px 14px;
  cursor: pointer;
}
.vm-settings-option:hover { background: var(--gold-tint); }
.vm-settings-option.active { color: var(--gold-soft); font-weight: 700; }
.vm-settings-check { width: 14px; color: var(--gold-soft); font-size: 0.8rem; }
.vm-settings-action {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  background: none;
  border: none;
  color: var(--cream);
  font-family: inherit;
  font-size: 0.88rem;
  text-align: left;
  padding: 7px 14px;
  cursor: pointer;
}
.vm-settings-action:hover { background: var(--gold-tint); }
.vm-settings-action .vm-settings-check { color: var(--muted); }

/* User រាយការណ៍ថា Channel/Like/Share Row មិនទាន់ស្មើគ្នា — បន្ថែម Border ស្រាលៗលើ Like/Share (មុន
   គ្មាន Border ទាល់តែសោះ ខណៈ Free-Tag មាន Background ខុសគ្នា) ឲ្យមើលទៅជាក្រុមតែមួយ + កំណត់ height
   ស្មើគ្នាបេះបិទ (34px) រវាង Like Button (Padding-Based) និង Share Button (Fixed Size ស្រាប់) */
.vm-engage-actions { display: flex; gap: 10px; align-items: center; flex-shrink: 0; }
.vm-action-btn {
  display: flex;
  align-items: center;
  gap: 8px;
  height: 34px;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 0 16px;
  color: var(--cream);
  font-family: inherit;
  font-weight: 700;
  font-size: 0.88rem;
  cursor: pointer;
  transition: background 0.15s ease;
  box-sizing: border-box;
}
.vm-action-btn svg { flex-shrink: 0; }
.vm-action-btn:hover { background: var(--border); }
.vm-action-btn[data-liked="true"] { background: rgba(242, 139, 130, 0.15); color: var(--red); }
.vm-share-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  flex-shrink: 0;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 50%;
  color: var(--cream);
  cursor: pointer;
  transition: background 0.15s ease;
  box-sizing: border-box;
}
.vm-share-btn:hover { background: var(--border); }

/* Comments */
/* User រាយការណ៍ថា Comment Box តំបន់ទាំងមូលមើលទៅទទេពេក — បន្ថយ margin/padding ជុំវិញ (h4→10px,
   Form→12px) ព្រម Empty/Loading State (.comment-list .loading ប៉ុណ្ណោះ — មិនប៉ះពាល់ .loading សកល
   ដែលប្រើកន្លែងផ្សេងទៀត) ដាក់ផ្ទៃស្រាលៗ + បង្រួម Padding ជំនួសទំហំទទេទទឹង */
.vm-comments { margin-top: 4px; }
.vm-comments h4 { color: var(--cream); font-size: 1rem; margin: 0 0 10px; }
#comment-form.comment-form { display: flex; flex-direction: row; align-items: center; gap: 8px; margin-bottom: 12px; }
.comment-form input {
  flex: 1;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 7px 14px;
  color: var(--cream);
  font-family: inherit;
  font-size: 0.88rem;
}
.comment-form input:focus { outline: 2px solid var(--gold); outline-offset: 1px; }
.comment-form .btn { border-radius: 999px; padding: 7px 18px; white-space: nowrap; }
.comment-login-note { color: var(--muted); font-size: 0.88rem; margin: 0 0 12px; }
.comment-list .loading { background: rgba(255, 255, 255, 0.02); border-radius: 10px; padding: 10px 12px; }
:root[data-theme="light"] .comment-list .loading { background: rgba(13, 148, 136, 0.05); }
.link-inline {
  background: none;
  border: none;
  color: var(--gold-soft);
  text-decoration: underline;
  cursor: pointer;
  font-family: inherit;
  padding: 0;
  font-size: inherit;
}

.comment-list { display: flex; flex-direction: column; gap: 18px; }
.comment-item { display: flex; gap: 12px; }
.comment-avatar {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  flex-shrink: 0;
  background: var(--gold);
  color: #fff;
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.9rem;
}
.comment-avatar-img { background: var(--bg-card); object-fit: cover; }
.comment-body { min-width: 0; }
.comment-meta { display: flex; align-items: baseline; gap: 8px; margin-bottom: 3px; flex-wrap: wrap; }
.comment-name { color: var(--cream); font-weight: 700; font-size: 0.86rem; }
.comment-date { color: var(--muted); font-size: 0.76rem; }
.comment-text { color: var(--cream); font-size: 0.9rem; margin: 0; word-break: break-word; }
.comment-reply-btn {
  background: none;
  border: none;
  color: var(--muted);
  font-size: 0.78rem;
  font-weight: 700;
  cursor: pointer;
  padding: 6px 0 0;
}
.comment-reply-btn:hover { color: var(--gold-soft); }
.comment-replies { display: flex; flex-direction: column; gap: 14px; margin: 12px 0 0 46px; }
.comment-reply-form { display: flex; gap: 8px; margin-top: 8px; }
.comment-reply-input {
  flex: 1;
  min-width: 0;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 8px 14px;
  color: var(--cream);
  font-family: inherit;
  font-size: 0.86rem;
}
.comment-reply-input:focus { outline: 2px solid var(--gold); outline-offset: 1px; }
.comment-reply-form .btn { border-radius: 999px; padding: 7px 16px; font-size: 0.84rem; white-space: nowrap; }

/* Toast */
.toast {
  position: fixed;
  bottom: 24px;
  left: 50%;
  transform: translateX(-50%) translateY(10px);
  background: var(--bg-raised);
  border: 1px solid var(--gold);
  color: var(--cream);
  padding: 10px 20px;
  border-radius: 999px;
  font-size: 0.88rem;
  z-index: 200;
  opacity: 0;
  transition: opacity 0.25s ease, transform 0.25s ease;
  pointer-events: none;
}
.toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }
/* .toast-nowrap — Option មិនកាតព្វកិច្ចទេ (Class .toast ធម្មតានៅតែ Wrap ធម្មតា មិនប៉ះពាល់ Toast ដទៃទៀត
   ក្នុង Site ទាំងមូលឡើយ) — ប្រើសម្រាប់សារខ្លីៗដូច Payway ដែលចង់ឲ្យនៅមួយបន្ទាត់ជានិច្ច (Shrink-To-Fit Auto-Width
   របស់ Position:Fixed ជួនកាលគណនាទទឹងតូចជាង Content ជាក់ស្តែងបន្តិច ធ្វើឲ្យ Wrap ដោយអចេតនា) */
.toast-nowrap { white-space: nowrap; font-size: 0.76rem; padding: 8px 16px; }

/* Sidebar — "up next" list, YouTube desktop-style: sticky + scrolls independently on hover */
.vm-sidebar { width: 360px; flex-shrink: 0; }
@media (min-width: 768px) {
  .vm-sidebar {
    position: sticky;
    top: 76px;
    max-height: calc(100vh - 96px);
    overflow-y: auto;
    scrollbar-width: thin;
    scrollbar-color: var(--border) transparent;
  }
  .vm-sidebar::-webkit-scrollbar { width: 8px; }
  .vm-sidebar::-webkit-scrollbar-track { background: transparent; }
  .vm-sidebar::-webkit-scrollbar-thumb { background: var(--border); border-radius: 8px; }
  .vm-sidebar::-webkit-scrollbar-thumb:hover { background: var(--gold); }
}
.vm-sidebar h4 {
  color: var(--muted);
  font-size: 0.8rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  margin: 0 0 12px;
}
/* User រាយការណ៍ថា Related Item Spacing ខ្លួនឯងល្អហើយ (កុំកែ Gap) ត្រូវការតែបន្ថែម Separation បន្តិចៗ
   ដើម្បីអានញែកគ្នាកាន់តែច្បាស់ — បន្ថែម Border-Bottom ស្តើងៗ (លើកលែង Item ចុងក្រោយ) ដោយមិនប៉ះ Gap ដើម */
.vm-sidebar-list { display: flex; flex-direction: column; gap: 8px; }
.vm-sidebar-item {
  display: flex;
  gap: 10px;
  cursor: pointer;
  border-radius: 8px;
  padding: 6px;
  padding-bottom: 12px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.06);
  transition: background 0.15s ease;
}
.vm-sidebar-item:last-child { border-bottom: none; padding-bottom: 6px; }
.vm-sidebar-item:hover { background: var(--bg-card); }
:root[data-theme="light"] .vm-sidebar-item { border-bottom-color: rgba(13, 148, 136, 0.12); }
.vm-sidebar-thumb {
  position: relative;
  width: 160px;
  flex-shrink: 0;
  aspect-ratio: 16/9;
  border-radius: 8px;
  overflow: hidden;
  background: #000;
}
.vm-sidebar-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.vm-sidebar-duration {
  position: absolute;
  bottom: 4px;
  right: 4px;
  background: rgba(0, 0, 0, 0.75);
  color: #fff;
  font-size: 0.68rem;
  padding: 1px 5px;
  border-radius: 4px;
}
.vm-sidebar-meta { min-width: 0; display: flex; flex-direction: column; gap: 3px; padding-top: 1px; }
.vm-sidebar-meta .t {
  color: var(--cream);
  font-size: 0.86rem;
  line-height: 1.35;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.vm-sidebar-meta .m { color: var(--muted); font-size: 0.76rem; }

/* Mobile — YouTube app-ish: player pinned to top edge-to-edge, info + up-next scroll beneath */
@media (max-width: 767px) {
  .vm-layout { flex-direction: column; gap: 0; padding: 0; }
  /* display:contents ដកយក .vm-main ចេញពី Box Model ដើម្បីឲ្យ .vm-player-wrap ជាប់ Sticky
     ធៀបនឹង .vm-layout (គ្របដណ្តប់ទាំង Info និង Sidebar) មិនមែនធៀបនឹង .vm-main ដែលចប់មុនគេទេ
     — បើមិនធ្វើដូច្នេះ Player នឹងរអិលបាត់ពេល Scroll ចូល "រឿងផ្សេងទៀត" */
  .vm-main { display: contents; }
  .vm-player-wrap { position: sticky; top: 56px; z-index: 5; border-radius: 0; width: 100%; }
  .vm-info { width: 100%; padding: 16px 16px 8px; }
  .vm-sidebar { width: 100%; padding: 12px 16px 50px; }

  /* Premium Lock Overlay — Compact Hero លើ Mobile ប៉ុណ្ណោះ (Desktop រក្សា Padding/Icon ដើមទាំងស្រុង ព្រោះ
     Layout ២ជួរឈរនៅតែមានកន្លែងគ្រប់គ្រាន់ស្រាប់ គ្មានបញ្ហា Scroll ដូច Mobile Sticky Player ទេ) — `aspect-ratio:
     16/9` ដើមលើ .vm-player-inner ក្លាយជា "កម្រិតអប្បបរមា" ដែលរារាំង Content-Driven Height ខាងក្រោមកុំឲ្យ
     ថយចុះក្រោម ~211px (375px width) ទោះបីជា Padding/Icon កាត់បន្ថយប៉ុន្មានក៏ដោយ — ត្រូវ Override ទៅជា
     min-height (195px ≈ 30% ថយចុះពី Baseline ~278px) វិញ ដើម្បីឲ្យ Padding/Icon ខាងក្រោមមានប្រសិទ្ធភាពពិត
     ប្រាកដ ខណៈនៅតែធានាថាមិនតូចជាង 195px ជានិច្ច (Error វែងៗនៅតែអាច Grow លើសបាន មិនកាត់ចោលទេ) */
  .vm-player-locked .vm-player-inner { aspect-ratio: auto; min-height: 195px; }
  .vm-lock-overlay { gap: 6px; padding: 14px 18px; }
  .vm-lock-icon { font-size: 1.5rem; }
  /* .form-error មាន min-height:1em ស្រាប់ (សម្រាប់ Form ទូទៅ) ដើម្បីទុកកន្លែងសារកំហុសទុកជាមុន — ប៉ុន្តែក្នុង
     Overlay នេះ Error ភាគច្រើនទទេ (មិនទាន់ព្យាយាមទិញ) ដូច្នេះលែងទុកកន្លែងទទេជាមុនទៀត (Error នៅតែបង្ហាញធម្មតា
     ពេលមាន គ្រាន់តែ Push មាតិកាខាងក្រោមបន្តិចវិញ ដែលធម្មតាទាំងស្រុងព្រោះកើតឡើងតាម User ចុចទិញខុសផ្ទាល់ខ្លួន) */
  .vm-lock-overlay .form-error { min-height: 0; }
  /* True 16:9 ដដែលលើ Mobile ដែរ — ត្រូវ Repeat Override នៅទីនេះព្រោះ Rule .vm-player-locked
     .vm-player-inner ខាងលើ (Specificity ស្មើគ្នា) ជា Source Order ក្រោយ នឹងឈ្នះបើគ្មាន Override ជាក់លាក់
     ទាំង Purchase ទាំង Guest Gate នេះទៀត (ដូចគ្នា — មើលកំណត់ចំណាំពេញលេញនៅ --gate ខាងលើ) */
  .vm-player-locked--purchase .vm-player-inner,
  .vm-player-locked--gate .vm-player-inner { aspect-ratio: 16/9; min-height: 0; }
  .vm-lock-overlay--purchase { padding: 10px; gap: 6px; }
  /* Box 16:9 ត្រូវតូចជាង Desktop ច្រើន (~211px កម្ពស់លើ 375px ទទឹង) — ប៊ូតុង 36px (ក្នុងចន្លោះ 34-40px
     ដែលស្នើ) នៅតែសមស្របណាស់ក្នុងកម្ពស់នេះ */
  .vm-purchase-lock-icon { font-size: 1rem; }
  .vm-purchase-actions { gap: 6px; }
  .vm-purchase-btn { height: 36px; padding: 3px 12px; }

  /* រឿងផ្សេងទៀត (Related Videos) — Gap/Border-Radius បន្តិចធំជាងមុនតាមសំណើ (14px Gap, 10px Radius) */
  .vm-sidebar-list { gap: 14px; }
  .vm-sidebar-thumb { border-radius: 10px; }
}

/* ---------- Legal / info pages ---------- */
.legal-content {
  max-width: 760px;
  margin: 0 auto;
  padding: 48px 24px 80px;
}
.legal-back {
  display: inline-block;
  color: var(--gold-soft);
  text-decoration: none;
  font-size: 0.9rem;
  margin-bottom: 20px;
}
.legal-back:hover { text-decoration: underline; }
.legal-content h1 { color: var(--gold-soft); font-size: 1.8rem; margin: 0 0 6px; }
.legal-updated { color: var(--muted); font-size: 0.85rem; margin: 0 0 32px; }
.legal-content h2 { color: var(--cream); font-size: 1.15rem; margin: 32px 0 10px; }
.legal-content p { color: var(--muted); margin: 0 0 14px; }
.legal-content ul { color: var(--muted); margin: 0 0 14px; padding-left: 22px; }
.legal-content li { margin-bottom: 6px; }
.legal-content a { color: var(--gold-soft); }
.legal-content strong { color: var(--cream); }
.contact-list { list-style: none; padding: 0; margin: 0 0 14px; }
.contact-list li {
  display: flex;
  gap: 10px;
  align-items: baseline;
  color: var(--cream);
  margin-bottom: 10px;
}
.contact-list .label { color: var(--muted); min-width: 130px; }

.legal-nav {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 16px;
  justify-content: center;
  padding: 18px 0;
  border-top: 1px solid var(--border);
  font-size: 0.82rem;
}
.legal-nav a { color: var(--muted); text-decoration: none; }
.legal-nav a:hover { color: var(--gold-soft); }

/* ---------- Status pages ---------- */
.status-page {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg);
  padding: 20px;
}
.status-card {
  background: var(--bg-raised);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 44px 36px;
  max-width: 440px;
  text-align: center;
  box-shadow: var(--shadow);
}
.status-icon {
  width: 56px; height: 56px;
  border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  margin: 0 auto 20px;
  font-size: 1.6rem;
}
.status-icon.success { background: rgba(94,234,212,0.2); color: var(--gold-soft); }
.status-icon.cancel { background: rgba(226,114,91,0.2); color: var(--red); }
.status-card h1 { font-size: 1.4rem; color: var(--cream); margin: 0 0 12px; }
.status-card p { color: var(--muted); }
.status-card .note { font-size: 0.8rem; margin-top: 18px; }
.status-card .btn { margin-top: 10px; display: inline-block; text-decoration: none; }

@media (max-width: 560px) {
  .header-actions { gap: 8px; }
  .header-actions .btn { padding: 7px 14px; font-size: 0.85rem; }
  .header-actions a.link-btn { display: none; }
  .account-dropdown { right: -8px; min-width: 220px; }
  .category-filter { gap: 4px; flex-wrap: nowrap; overflow-x: auto; -ms-overflow-style: none; scrollbar-width: none; }
  .category-filter::-webkit-scrollbar { display: none; }
  .chip { padding: 5px 8px; font-size: 0.7rem; flex-shrink: 0; }
}

@media (max-width: 720px) {
  /* position:relative (មិនមែន static) ដើម្បីឲ្យ z-index:40 (Base Rule) នៅតែមានប្រសិទ្ធភាព —
     .site-header មាន backdrop-filter ដែលបង្កើត Stacking Context ជានិច្ចទោះ Position អ្វីក៏ដោយ,
     ប៉ុន្តែបើ Position ជា static នោះ z-index មិនដំណើរការទេ ធ្វើឲ្យ Header ទាំងមូល (រួមទាំង Drawer/
     Profile Dropdown ខាងក្នុង) ជាប់ចាំក្នុង Stacking Context ទាបជាង <main> ដែលមកក្រោយក្នុង DOM —
     នេះជា Root Cause នៃបញ្ហា Video Card បង្ហាញលើ Drawer។ position:relative មិនប៉ះពាល់ Layout ទេ
     (មិន Sticky ដូចមុន — នៅតែរំកិលរួមជាមួយទំព័រ) គ្រាន់តែធ្វើឲ្យ z-index ដំណើរការឡើងវិញ */
  .site-header { position: relative; }

  /* ចាស់ធ្លាប់មាន .site-header:has(.mobile-menu-wrap.open){z-index:305} នៅទីនេះ ដើម្បី Elevate Header
     ពេល Drawer បើក (ព្រោះ Drawer ធ្លាប់ជា Descendant របស់ Header) — ដកចេញហើយ ព្រោះ #mobile-menu-wrap
     ត្រូវបាន Move ចេញទៅជា Sibling ក្រៅ <header> ទាំងស្រុង (មើលកំណត់ត្រា .mobile-menu-wrap ក្នុង index.html/
     style.css — ដោះស្រាយបញ្ហា Hamburger Icon បាត់ពេល Modal ណាមួយបើក) ដូច្នេះ :has() Selector នេះលែងផ្គូផ្គង
     អ្វីទៀតទេ (Dead Code) — Header ខ្លួនឯងក៏មិនចាំបាច់ Elevate ទៀតហើយដែរ ព្រោះ Drawer លែងជា Descendant
     របស់វា មិនរងផលប៉ះពាល់ពី Header ទាបជាង Modal ទៀតឡើយ */
  .header-inner { height: auto; padding: 12px 16px; gap: 12px; flex-wrap: wrap; justify-content: flex-start; }
  .header-search-wrap { order: 3; flex-basis: 100%; width: 100%; max-width: none; min-width: 0; }
  .brand-name { font-size: 1.4rem; }
  .brand-logo { width: 32px; height: 32px; }
  .brand { gap: 6px; }
  .lang-toggle-btn { padding: 0 8px; }

  /* ជួរទី ១ — ☰ + Logo ប៉ុណ្ណោះ (Theme/EN/Avatar/Login/Register ទាំងអស់ផ្លាស់ទីទៅ Hamburger Drawer វិញ) */
  .mobile-menu-wrap { display: flex; }
  /* User រាយការណ៍ថា Video Watch Page មាន "Menu" ចម្លែកនៅជ្រុងឆ្វេងលើ ត្រួតលើ Logo ខ្លួនរបស់ទំព័រនោះ —
     Root Cause៖ #mobile-menu-wrap ជា position:fixed;top:12px;left:5px ជានិច្ចគ្រប់ទំព័រ/Modal (ដោះស្រាយ
     Hamburger បាត់ក្រោយ Modal ពីមុន) ប៉ុន្តែ #modal-video មាន .vm-topbar ផ្ទាល់ខ្លួន (Logo→Home + ✕ Close)
     កាន់កាប់តំបន់ដូចគ្នាបេះបិទ ដូច្នេះ ☰ (Invisible Background ត្រឹមតែ SVG Line) ត្រួតលើ Logo នោះ ធ្វើឲ្យ
     ចុច Logo ក្លាយជាចុច ☰ ដោយចៃដន្យ — Video Page ខ្លួនឯងមាន Navigation គ្រប់គ្រាន់ស្រាប់ (Logo→Home/✕ Close)
     ដូច្នេះលាក់ ☰ សកលចោលពេល Video Modal បើក។ ជុំដំបូងប្រើ CSS `body:has(#modal-video:not(.hidden))` សុទ្ធ
     (Display:none) ក្រោយមកប្តូរទៅ Opacity ដើម្បីអោយ Fade Animate បាន ប៉ុន្តែ Verify ឃើញថា Browser នេះមិន
     Invalidate Style របស់ :has() ត្រឹមត្រូវ ពេល Condition ប្តូរពី True→False ទេ (Opacity ជាប់គាំង 0 សូម្បី
     Modal បិទរួច ទោះ document.body.matches() ខ្លួនឯង Confirm ថា Logic ត្រឹមត្រូវក៏ដោយ — ប្រហែល Browser Bug
     ជាក់លាក់ចំពោះ :has() Reactivity) ដូច្នេះលែងទុកចិត្ត :has() សម្រាប់ករណីនេះទៀតហើយ — ប្តូរទៅ JS គ្រប់គ្រង
     ដោយផ្ទាល់វិញ (Class .video-modal-open បន្ថែម/ដកចេញ ត្រង់ openModal()/hideModalOverlay() ក្នុង app.js
     ដោយឡែក ធានាភាព Reliable ជាង CSS Reactive Selector ណាមួយ) */
  .mobile-menu-wrap.video-modal-open { opacity: 0; pointer-events: none; }
  /* margin-left:-11px ចាស់ (ឲ្យបន្ទាត់ ☰ តម្រឹមគែម Content) លែងត្រូវការទៀតហើយ — #mobile-menu-wrap ខ្លួនឯង
     ឥឡូវ position:fixed;left:5px ដោយផ្ទាល់ (Pixel-Measured រួមបញ្ចូល Margin ចាស់នេះស្រេចហើយ — មើលកំណត់ត្រា
     .mobile-menu-wrap ខាងលើ) ដាក់ Margin ដដែលបន្ថែមទៀតនឹងរុញ Icon ខុសទីតាំង */
  .mobile-menu-btn { width: 40px; height: 40px; display: flex; }

  /* ប្រភេទរឿង (ទាំងអស់/ឥតគិតថ្លៃ/Premium/...) ផ្លាស់ទីទៅ Hamburger Drawer វិញ — លែងបង្ហាញជាជួរធំក្រៅ Header ទៀត */
  .home-sidebar { display: none; }

  /* Root Cause នៃ Bug "Card ទទឹងខុសគ្នារវាង Category" លើ Mobile៖ .home-layout ក្លាយជា flex-direction:
     column នៅ @media (max-width: 860px) ខាងក្រោម (ក្រៅពី Media Query នេះ) ហើយ .home-layout មាន
     align-items: flex-start (style.css:688) — ក្នុង Column Mode, align-items ដឹកនាំ Cross-Axis ដែលឥឡូវ
     ជា "ទទឹង" (មិនមែន "កម្ពស់" ទៀតទេ) ដូច្នេះ flex-start ធ្វើឲ្យ .home-content បង្រួញទៅតាមទំហំ Content
     ជាក់លាក់ (Shrink-To-Fit ដូច width:fit-content) ជំនួសការលាតសន្ធឹងពេញ .home-layout — ទំហំ Content
     ខុសគ្នាទៅតាមចំណងជើងវីដេអូ/ចំនួន Card ក្នុងប្រភេទនីមួយៗ ដូច្នេះ Category ខុសគ្នាបានទទឹង Card ខុសគ្នា
     ថ្វិត្បិត .video-grid ខ្លួនឯងកំណត់ 1fr/100% ត្រឹមត្រូវហើយក៏ដោយ។ ដោះស្រាយ៖ តម្រូវ Width ពេញច្បាស់លាស់
     ដោយផ្ទាល់ (មិនអាស្រ័យលើ align-items ទៀតទេ) — កំណត់វិសាលភាពត្រឹមតែ Mobile ពិត (≤720px) ប៉ុណ្ណោះ
     មិនប៉ះពាល់ Tablet (721-860px, Sidebar នៅតែបង្ហាញ) ឬ Desktop ទាល់តែសោះ */
  .home-content { width: 100%; }

  /* EN/សមាជិកភាព/Avatar/Login/Register លែងបង្ហាញក្នុង Header ទាំងស្រុង — ទាំងអស់នេះផ្លាស់ទីទៅ
     Hamburger Drawer វិញ (មើល .mobile-menu-user/.mobile-menu-settings)។ Theme Toggle (☀️/🌙) ប៉ុណ្ណោះ
     ត្រូវនៅតែបង្ហាញក្នុងជួរទី ១ — ប្រើ display:contents លើ .header-actions ខ្លួនឯង ដើម្បីអោយកូនចៅរបស់វា
     ក្លាយជា Flex Item ផ្ទាល់របស់ .header-inner (ដូចគ្នានឹង Technique ដែលធ្លាប់ប្រើពីមុន) រួចលាក់កូនចៅ
     នីមួយៗដាច់ដោយឡែក លើកលែងតែ #btn-theme-toggle។ Selector ធ្លាប់កំណត់ដោយ ".mobile-menu-wrap ~
     .header-actions" (Sibling Combinator) ព្រោះ contact/privacy/terms/refund/copyright/admin.html
     ក៏ប្រើ Class .header-actions/#btn-theme-toggle ដូចគ្នា ប៉ុន្តែគ្មាន .mobile-menu-wrap (Hamburger)
     ទេ — ក្រោយមក #mobile-menu-wrap ត្រូវ Move ចេញទៅ Body-Level (ដោះស្រាយ Hamburger បាត់ក្រោយ Modal)
     ធ្វើឲ្យលែងជា Sibling នៃ .header-actions ទៀតហើយ (ស្ថិតក្រៅ <header> ទាំងស្រុង) — Selector ចាស់
     ឈប់ផ្គូផ្គង Theme Toggle ក៏បាត់ជាប់ (Bug ពិតដែលរាយការណ៍)។ ប្តូរមកប្រើ "body:has(#mobile-menu-wrap)"
     ជំនួស (មិនអាស្រ័យលើទីតាំង DOM ទៀតទេ គ្រាន់តែពិនិត្យថាទំព័រនេះមាន Drawer ដែរឬទេ) រក្សា Behavior/
     វិសាលភាពដដែលបេះបិទ (index.html ប៉ុណ្ណោះ) ។ Rule ទូទៅ ".header-actions{display:none}" ខាងក្រោម
     រក្សា Behavior ដើមឡើយ (Theme Toggle លាក់លើ Mobile) សម្រាប់ទំព័រផ្សេងទៀត (contact/privacy/ល។)
     ចំណែក Selector ជាក់លាក់ខាងលើ Override វាតែលើ index.html ដោយសារ Specificity ខ្ពស់ជាង */
  .header-actions { display: none; }
  body:has(#mobile-menu-wrap) .header-actions { display: contents; }
  body:has(#mobile-menu-wrap) .header-actions .lang-toggle-btn { display: none; }
  body:has(#mobile-menu-wrap) .header-actions #btn-open-pricing { display: none !important; }
  body:has(#mobile-menu-wrap) .header-actions #mobile-guest-avatar-wrap { display: none !important; }
  body:has(#mobile-menu-wrap) .header-actions #account-menu { display: none !important; }
  body:has(#mobile-menu-wrap) .header-actions .header-auth-actions { display: none; }

  /* Theme Toggle — ខិតទៅជាប់ស្តាំជួរទី ១ ដោយ margin-left:auto (មិនប៉ះពាល់ទំហំ/ទីតាំងលើ Desktop ទេ
     ព្រោះជា Rule ថ្មីទាំងស្រុងក្នុង Media Query នេះ) — ប្រើ Function/Click Handler ពិតដដែលពី theme.js */
  body:has(#mobile-menu-wrap) .header-actions #btn-theme-toggle { display: flex; margin-left: auto; }

  /* ប៊ូតុងសមតុល្យ Wallet ត្រូវតូចជាង Desktop បន្តិច ដើម្បីទុកកន្លែងគ្រប់គ្រាន់សម្រាប់ ☰+Logo+Theme នៅ
     375px ដោយមិន Overflow ផ្តេក (Wallet Button ខ្លួនឯងមិនស្ថិតក្នុងបញ្ជី Selector ដែលលាក់ខាងលើទេ ដូច្នេះនៅ
     តែបង្ហាញធម្មតាតាម Flow លំដាប់ធម្មតា រវាង Logo និង margin-left:auto របស់ Theme Toggle) */
  .wallet-header-btn { padding: 4px 8px; gap: 5px; }
  .wallet-header-icon { width: 22px; height: 22px; font-size: 0.72rem; }
  #wallet-header-balance { font-size: 0.72rem; }
  .wallet-header-topup { font-size: 0.58rem; }

  /* ប៊ូតុង Search — ទទឹងថេរប្រហែល 52px មិនប្រែប្រួលតាមទំហំអេក្រង់ទេ, input យកកន្លែងទំនេរដែលនៅសល់ទាំងអស់ */
  /* ប្រអប់ស្វែងរក 44px (ស្តង់ដារ touch target — ពី 38px ដែលមើលទៅគៀន) + គម្លាត Header 12px */
  .header-search input { flex: 1; min-width: 0; height: 44px; }
  .header-search button { flex: 0 0 44px; width: 44px; height: 44px; }

  /* កន្លែងទំនេរខាងក្រោមទំព័រ សម្រាប់ Bottom Navigation (Fixed) កុំឲ្យបាំង Video Card ចុងក្រោយ +
     បន្ថយគម្លាតខាងលើ (48px→16px) ដើម្បីអោយជួរ Category Chip ខិតទៅជាប់ Search Bar បន្ថែមទៀត */
  /* គម្លាតគែមឆ្វេង/ស្តាំ Mobile = 16px ស្មើគ្នា (Header/Chips/កាត/Footer) — ពីមុន Header ជាប់គែម 0px ខណៈកាត 24px */
  .wrap { padding-left: 16px; padding-right: 16px; }
  .legal-content { padding-left: 16px; padding-right: 16px; }
  main.wrap { padding-top: 16px; padding-bottom: calc(84px + env(safe-area-inset-bottom)); }
  /* Footer (សម្រាប់តែ Legal Nav ដើមឡើយ) ស្ថិតនៅក្រៅ main.wrap ដូច្នេះមិនទទួល Padding ខាងលើទេ — ត្រូវការ
     Padding-Bottom ដូចគ្នាដែរ ដើម្បីកុំឲ្យ Fixed Bottom Nav បាំង Payment Badge/Link ចុងក្រោយពេល Scroll
     ដល់បាត Page ពិតប្រាកដ (Bug មានស្រាប់ ប៉ុន្តែឥឡូវឃើញច្បាស់ជាងមុនចាប់តាំងពី Footer មាន Content ច្រើនជាង) */
  .site-footer { padding-bottom: calc(26px + 84px + env(safe-area-inset-bottom)); }
  .category-filter { margin: 0 0 20px; }

  /* Bottom Navigation — z-index 50 (ក្រោម .modal-overlay ដែលមាន z-index:100) ដូច្នេះនៅពេល Modal
     ណាមួយបើក (រួមទាំង Video Player) វានឹងបាំង Bottom Nav ដោយស្វ័យប្រវត្តិ ដោយមិនចាំបាច់ JS បន្ថែម */
  /* គម្លាតគែម 16px ស្មើ Header/Chips/កាត (ពី 12px) — Bar ស្តើង (~៦០px) ផ្ទៃថ្លា ៨០% + blur ដើម្បីកុំឲ្យមើលទៅជាប្លុកធំបាំងមាតិកា;
     background ជួរទី ១ ជា Fallback សម្រាប់ Browser ដែលមិនគាំទ្រ color-mix() (ផ្ទៃទឹកស្រអាប់ដដែល) */
  .mobile-bottom-nav {
    display: flex;
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 50;
    background: var(--bg-raised);
    background: color-mix(in srgb, var(--bg-raised) 80%, transparent);
    -webkit-backdrop-filter: blur(16px);
    backdrop-filter: blur(16px);
    border: 1px solid var(--border);
    border-width: 1px 0 0;
    border-radius: 0;
    box-shadow: var(--shadow);
    padding: 4px 6px calc(4px + env(safe-area-inset-bottom));
    justify-content: space-around;
    align-items: center;
    /* iOS Safari មាន Bug ស្គាល់ស្រាប់៖ position:fixed + backdrop-filter ជួនកាល "បាត់"/ភ្លីបភ្លែត ខណៈ Momentum
       Scroll (កាន់តែងាយកើតលើទំព័រវែង/មាតិកាច្រើន ដូចជា User ដែល Log in រួចមាន Sidebar/Wallet បន្ថែម) — បង្ខំ
       ឲ្យ Element នេះមាន Compositor Layer ខ្លួនឯង (មិនរួមជាមួយ Layer ធម្មតារបស់ទំព័រ) ដោះស្រាយបញ្ហានេះ */
    transform: translateZ(0);
    -webkit-transform: translateZ(0);
    will-change: transform;
  }
  .mobile-bottom-nav-item {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1px;
    flex: 1;
    background: none;
    border: none;
    color: var(--muted);
    font-family: inherit;
    font-size: 0.72rem;
    line-height: 1.25;
    padding: 3px 4px;
    border-radius: 12px;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    transition: color 0.15s ease;
  }
  /* Icon SVG ស្តើង (currentColor) ក្នុង Pill — Pill ស្រាលពណ៌ប្រែពេល active (ស្ថានភាពច្បាស់ជាងអក្សរតែម្នាក់ឯង) */
  .mobile-bottom-nav-item .icon {
    width: 48px;
    height: 26px;
    border-radius: 999px;
    display: flex;
    align-items: center;
    justify-content: center;
    line-height: 1;
    transition: background 0.15s ease;
  }
  .mobile-bottom-nav-item .icon svg { width: 20px; height: 20px; }
  .mobile-bottom-nav-item.active { color: var(--gold-soft); font-weight: 700; }
  .mobile-bottom-nav-item.active .icon { background: var(--gold-tint); }
  /* Premium — មាសជានិច្ច (ទាំង active/មិន active) ជាធាតុពិសេស */
  #btn-bottomnav-premium .icon { color: #eccb8f; }
  #btn-bottomnav-premium.active { color: #eccb8f; }
  #btn-bottomnav-premium.active .icon { background: rgba(216, 176, 106, 0.2); }
  :root[data-theme="light"] #btn-bottomnav-premium .icon { color: #b5883f; }
  :root[data-theme="light"] #btn-bottomnav-premium.active { color: #8a6414; }
  :root[data-theme="light"] .mobile-bottom-nav { box-shadow: 0 8px 24px rgba(16, 48, 44, 0.14); }

  /* ---------- Card សមាជិកភាព Premium ក្នុង Hamburger Drawer (Mobile ប៉ុណ្ណោះ) — ជំនួស Text Link
     "សមាជិកភាព" ចាស់ ដោយ Card Glass ស្រដៀង Premium Streaming App (Netflix/Disney+ Style) ប្រើ --drawer-*
     Variables ពី .mobile-menu-dropdown (Card នេះតែងតែជា Descendant របស់វា) ---------- */
  /* ធ្លាប់ជា Gradient ស្វាយ/មាស (Purple/Gold) — User ស្នើដក Purple ចេញ ប៉ុន្តែរក្សា Gold Border ដើម្បីបំបែក
     ពី Menu ធម្មតា (User ស្នើផ្ទាល់) ដូច្នេះប្តូរ Gradient ទៅ Gold-Tint/Navy ជំនួស Purple/Navy ចាស់ */
  .mobile-membership-card { margin: 2px 0 4px; }
  .mobile-membership-upsell {
    background: linear-gradient(135deg, rgba(216, 176, 106, 0.14), rgba(10, 11, 16, 0.5));
    border: 1px solid rgba(216, 176, 106, 0.4);
    border-radius: 16px;
    padding: 12px 14px;
    box-shadow: 0 0 18px rgba(216, 176, 106, 0.12);
  }
  .mobile-membership-header {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 4px;
  }
  .mobile-membership-icon { display: inline-flex; color: var(--drawer-gold-soft); line-height: 1; }
  .mobile-membership-icon svg { width: 18px; height: 18px; }
  .mobile-membership-title { color: var(--drawer-gold-soft); font-weight: 700; font-size: 0.94rem; }
  /* ប្រយោជន៍ ៣ រួមជាបន្ទាត់តែមួយ (ជំនួសបញ្ជី ✓ ៣ បន្ទាត់) ដើម្បីសន្សំកម្ពស់ Drawer */
  .mobile-membership-desc { color: var(--drawer-muted); font-size: 0.76rem; line-height: 1.35; margin: 0 0 10px; }
  .mobile-membership-cta {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 7px;
    width: 100%;
    border: none;
    border-radius: 999px;
    background: linear-gradient(135deg, var(--drawer-gold), #b5883f);
    color: #1a1330;
    font-family: 'Battambang', sans-serif;
    font-weight: 700;
    font-size: 0.85rem;
    padding: 9px 10px;
    cursor: pointer;
    text-align: center;
    box-shadow: 0 4px 14px rgba(216, 176, 106, 0.3);
    transition: transform 0.15s ease;
  }
  .mobile-membership-cta svg { width: 16px; height: 16px; flex-shrink: 0; }
  .mobile-membership-cta:active { transform: scale(0.98); }
  .mobile-membership-status {
    background: linear-gradient(135deg, rgba(216, 176, 106, 0.16), rgba(11, 14, 46, 0.5));
    border: 1px solid rgba(216, 176, 106, 0.4);
    border-radius: 16px;
    padding: 12px 16px;
    display: flex;
    align-items: center;
    gap: 12px;
    box-shadow: 0 0 18px rgba(216, 176, 106, 0.12);
  }
  .mobile-membership-status-icon { display: inline-flex; color: var(--drawer-gold-soft); flex-shrink: 0; }
  .mobile-membership-status-icon svg { width: 24px; height: 24px; }
  .mobile-membership-status-text { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
  .mobile-membership-status-title { color: var(--drawer-gold-soft); font-weight: 700; font-size: 0.88rem; }
  .mobile-membership-status-sub { color: var(--drawer-muted); font-size: 0.76rem; }
}

/* អេក្រង់តូចខ្លាំង (≤350px ឧ. iPhone SE ជំនាន់ដំបូង) — គម្លាត Header ១៦px ធ្វើឲ្យជួរទី ១ (☰ Logo Wallet ☀️) មិនគ្រប់ទំហំ ហើយ ☀️
   ធ្លាក់ចុះជួរទី ២ — បង្រួម Gap/ទំហំ Logo/Padding Wallet បន្តិចដើម្បីនៅតែស្ថិតក្នុងជួរតែមួយ (វាស់ ៣២០ និង ៣៤០px) */
@media (max-width: 350px) {
  .header-inner { gap: 6px; }
  .brand-name { font-size: 1.2rem; }
  .wallet-header-btn { padding: 4px 6px; }
}

/* Body Scroll Lock ពេល Drawer បើក — ទប់ស្កាត់ការ Scroll ខាងក្រោយ Backdrop។ position:fixed លើ body ខ្លួនឯង
   (មិនមែន overflow:hidden ម្នាក់ឯងទេ) ត្រូវការសម្រាប់ការពារ iOS Safari/Browser ខ្លះនៅតែឲ្យ <html> Scroll
   ដដែល (Bug ពិតដែលរាយការណ៍ Background/Bottom Nav នៅតែ Scroll បានខណៈ Drawer បើក) — `top` កំណត់ដោយ JS
   ជា -scrollY ដើម្បីរក្សាទីតាំង Visual ដដែល (មើល openMobileMenu()/closeMobileMenu() ក្នុង app.js) */
body.mobile-menu-locked {
  position: fixed;
  left: 0;
  right: 0;
  width: 100%;
  overflow: hidden;
}

/* ABA PayWay Checkout Popup (checkout2-0.js — មើល AbaPayway.checkout() ក្នុង app.js) បង្កើត
   .aba-checkout-modal-container ដោយផ្ទាល់ជា Sibling នៃ <body> ដោយគ្មាន z-index កំណត់ (auto) — Modal
   របស់យើងផ្ទាល់ (#modal-wallet-topup) មាន z-index:100 ជានិច្ច ធ្វើឲ្យលាក់ Popup ABA នេះទាំងស្រុង (User
   មើលមិនឃើញ QR សោះ) ត្រូវបង្ខំ Popup នេះឲ្យនៅលើគេគ្រប់ពេល ទោះ Modal យើងបើកនៅពីក្រោយក៏ដោយ */
.aba-checkout-modal-container { position: fixed !important; inset: 0 !important; z-index: 999999 !important; }

/* Video Grid — Boot (First Load) កក់កន្លែងកម្ពស់ ដើម្បីកុំឲ្យ Footer លោតចុះក្រោមពេល Card ចូលមក (វីដេអូ IMG_6976:
   Static Shell "កំពុងផ្ទុក" ខ្លី → Grid ពេញ → Footer ត្រូវរុញទៅក្រោម) — ដោះចេញ (is-booting) ក្រោយ Paint ដំបូងរួច */
.video-grid.is-booting { min-height: 75vh; }

/* Template Animation Card Grid តែមួយ (CSS ទាំងស្រុង) — មើល paintGrid() ក្នុង app.js។ លំដាប់ ១→២→៣ ដោយ --i (Index)
   មិនមែន Timer/JS Class ទេ។ anim-in = First Load (ចាប់ពី opacity ០, ក្រោយ Thumbnail ដំបូងរួចរាល់);
   anim-in-soft = ចុច Logo/ប្តូរ Tab ដែលខ្លឹមសារប្តូរ (ចាប់ពី ០.៤ មិនដែលបាត់ ដូច្នេះគ្មាន "បាត់រួចលេច") */
.video-grid.anim-wait .video-card { opacity: 0; }
.video-grid.anim-in .video-card { animation: kgCardIn 0.8s cubic-bezier(0.25, 0.46, 0.45, 0.94) both; animation-delay: calc(var(--i, 0) * 70ms); }
.video-grid.anim-in-soft .video-card { animation: kgCardInSoft 0.7s cubic-bezier(0.25, 0.46, 0.45, 0.94) both; animation-delay: calc(var(--i, 0) * 50ms); }
@keyframes kgCardIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }
@keyframes kgCardInSoft { from { opacity: 0.5; transform: translateY(6px); } to { opacity: 1; transform: translateY(0); } }
@media (prefers-reduced-motion: reduce) {
  .video-grid.anim-in .video-card, .video-grid.anim-in-soft .video-card { animation: none; }
  .video-grid.anim-wait .video-card { opacity: 1; }
}

/* "មេរៀន & សេវាកម្ម" — Card សេវាកម្ម (ឧបករណ៍កាត់សំលេង) ក្នុង View video-lessons */
.services-panel { margin-bottom: 22px; }
.services-title { margin: 0 0 12px; font-size: 1.05rem; color: var(--cream); font-family: 'Battambang', sans-serif; letter-spacing: 0.01em; }
.service-card {
  position: relative; display: flex; align-items: center; gap: 16px; padding: 16px 18px; text-decoration: none;
  background: linear-gradient(135deg, var(--gold-tint), transparent 60%), var(--bg-card);
  border: 1px solid var(--border); border-radius: var(--radius); color: var(--cream);
  transition: border-color 0.2s ease, transform 0.2s ease, box-shadow 0.2s ease;
}
.service-card:hover { border-color: var(--gold); transform: translateY(-2px); box-shadow: var(--shadow); }
.service-card:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }
.service-card-icon {
  flex-shrink: 0; width: 52px; height: 52px; display: grid; place-items: center; border-radius: 14px;
  color: #fff; background: linear-gradient(135deg, var(--gold), #1f6fd1); box-shadow: 0 6px 16px rgba(62, 166, 255, 0.3);
}
.service-card-icon svg { width: 26px; height: 26px; }
.service-card-body { display: flex; flex-direction: column; gap: 5px; min-width: 0; flex: 1; align-items: flex-start; }
.service-card-body strong { font-size: 1.05rem; line-height: 1.4; }
.service-card-desc { color: var(--muted); font-size: 0.86rem; line-height: 1.55; }
.service-card-price {
  margin-top: 2px; padding: 2px 10px; border-radius: 999px; font-size: 0.78rem; font-weight: 700;
  color: var(--gold-soft); background: var(--gold-tint); border: 1px solid rgba(62, 166, 255, 0.35);
}
.service-card-go {
  flex-shrink: 0; width: 34px; height: 34px; display: grid; place-items: center; border-radius: 50%;
  color: var(--muted); background: var(--bg-raised); transition: background 0.2s ease, color 0.2s ease, transform 0.2s ease;
}
.service-card-go svg { width: 18px; height: 18px; }
.service-card:hover .service-card-go { background: var(--gold); color: #fff; transform: translateX(2px); }
@media (max-width: 767px) {
  .service-card { padding: 12px 14px; gap: 12px; }
  .service-card-icon { width: 44px; height: 44px; border-radius: 12px; }
  .service-card-icon svg { width: 22px; height: 22px; }
  .service-card-body strong { font-size: 0.95rem; }
  .service-card-desc { font-size: 0.8rem; }
}

/* ពេលមានតួ Login ក្នុង localStorage លាក់ប៊ូតុង "ចូលគណនី/ចុះឈ្មោះ" តាំងពី Frame ដំបូង (ជៀសវាងលេចមួយភ្លែតមុន JS ដឹងថា Login រួច) */
html.has-token #btn-login,
html.has-token #btn-register { display: none; }

