/* ==========================================================
   Reusable Components — buttons, cards, tags, alerts, forms
   ========================================================== */

/* ----------------------------------------------------------
   Design Tokens — mirrors includes/tailwind_config.php so the
   plain-CSS rules below (which can't read Tailwind's config)
   stay in sync with the single source of truth.
   ---------------------------------------------------------- */
:root {
  /* قنوات RGB (تُستهلَك في tailwind_config.php بصيغة rgb(var(--x) / <alpha-value>)) */
  --background-rgb: 19 19 19;
  --surface-rgb: 21 21 21;
  --surface-container-lowest-rgb: 14 14 14;
  --surface-container-low-rgb: 28 27 27;
  --surface-container-rgb: 32 31 31;
  --surface-container-high-rgb: 42 42 42;
  --surface-container-highest-rgb: 53 53 52;
  --card-bg-rgb: 27 27 27;
  --text-primary-rgb: 255 255 255;
  --text-secondary-rgb: 179 179 179;
  --text-muted-rgb: 124 124 124;
  --primary-rgb: 255 180 170;
  --primary-container-rgb: 229 9 20;
  --on-primary-rgb: 105 0 3;
  --border-muted-rgb: 42 42 42;
  --success-rgb: 34 197 94;
  --warning-rgb: 245 158 11;
  --error-rgb: 239 68 68;

  /* نسخ hex مشتقّة (تُستهلَك في قواعد CSS العادية أدناه) */
  --background: rgb(var(--background-rgb));
  --surface: rgb(var(--surface-rgb));
  --surface-container-lowest: rgb(var(--surface-container-lowest-rgb));
  --surface-container-low: rgb(var(--surface-container-low-rgb));
  --surface-container: rgb(var(--surface-container-rgb));
  --surface-container-high: rgb(var(--surface-container-high-rgb));
  --surface-container-highest: rgb(var(--surface-container-highest-rgb));
  --card-bg: rgb(var(--card-bg-rgb));

  --text-primary: rgb(var(--text-primary-rgb));
  --text-secondary: rgb(var(--text-secondary-rgb));
  --text-muted: rgb(var(--text-muted-rgb));

  --primary: rgb(var(--primary-rgb));
  --primary-container: rgb(var(--primary-container-rgb));
  --on-primary: rgb(var(--on-primary-rgb));
  --tertiary: #A7C8FF;

  --border-muted: rgb(var(--border-muted-rgb));

  --success: rgb(var(--success-rgb));
  --warning: rgb(var(--warning-rgb));
  --error: rgb(var(--error-rgb));

  --radius: 4px;
  --radius-lg: 8px;
  --radius-xl: 12px;
  --radius-full: 9999px;

  --transition: 200ms cubic-bezier(.2, .8, .2, 1);
  --ease-standard: cubic-bezier(.2, .8, .2, 1);
  --ease-out-ios: cubic-bezier(.16, 1, .3, 1);
  --ease-in-ios: cubic-bezier(.4, 0, 1, 1);

  --shadow-elevation-1: 0 4px 12px rgba(0, 0, 0, .35);
  --shadow-lg: 0 12px 32px rgba(0, 0, 0, .5);
}

/* ----------------------------------------------------------
   Light mode palette (Part 6). Applied when <html> carries the
   `.light` class (toggled + persisted via assets/js/main.js).
   Only the color channels change; every component reads them via
   the CSS variables above, so nothing else needs to be rebuilt.
   Brand red + status colors stay identical for brand continuity.
   ---------------------------------------------------------- */
html.light {
  --background-rgb: 246 247 249;
  --surface-rgb: 255 255 255;
  --surface-container-lowest-rgb: 255 255 255;
  --surface-container-low-rgb: 241 242 244;
  --surface-container-rgb: 236 238 241;
  --surface-container-high-rgb: 226 229 233;
  --surface-container-highest-rgb: 215 219 224;
  --card-bg-rgb: 255 255 255;
  --text-primary-rgb: 22 24 29;
  --text-secondary-rgb: 74 80 89;
  --text-muted-rgb: 138 144 153;
  --primary-rgb: 192 0 12;
  --on-primary-rgb: 255 255 255;
  --border-muted-rgb: 226 229 233;

  --shadow-elevation-1: 0 4px 12px rgba(20, 22, 26, .08);
  --shadow-lg: 0 12px 32px rgba(20, 22, 26, .12);
}

/* Smooth, GPU-cheap cross-fade between themes (colors only). */
html.theme-ready body,
html.theme-ready body * {
  transition: background-color .35s var(--ease-standard),
    border-color .35s var(--ease-standard),
    color .35s var(--ease-standard);
}

@media (prefers-reduced-motion: reduce) {

  html.theme-ready body,
  html.theme-ready body * {
    transition: none !important;
  }
}

/* Smooth, GPU-cheap cross-fade between themes (colors only). */
html.theme-ready body,
html.theme-ready body * {
  transition: background-color .35s var(--ease-standard),
    border-color .35s var(--ease-standard),
    color .35s var(--ease-standard);
}

@media (prefers-reduced-motion: reduce) {

  html.theme-ready body,
  html.theme-ready body * {
    transition: none !important;
  }
}

/* Buttons */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 10px 18px;
  border-radius: var(--radius-lg);
  font-family: inherit;
  font-weight: 600;
  font-size: .9rem;
  border: 1px solid transparent;
  cursor: pointer;
  user-select: none;
  transition: all var(--transition);
  text-decoration: none;
}

.btn-primary {
  background: var(--primary-container);
  color: #fff;
}

.btn-primary:hover {
  background: #c0000c;
  color: #fff;
  transform: translateY(-1px);
}

.btn-ghost {
  background: transparent;
  color: var(--text-primary);
  border-color: var(--border-muted);
}

.btn-ghost:hover {
  background: var(--surface-container);
  color: var(--primary);
}

.btn-outline {
  background: transparent;
  color: var(--primary);
  border-color: var(--primary);
}

.btn-outline:hover {
  background: var(--primary);
  color: var(--on-primary);
}

.btn-sm {
  padding: 6px 12px;
  font-size: .8rem;
}

.btn-lg {
  padding: 14px 24px;
  font-size: 1rem;
}

.btn-block {
  display: flex;
  width: 100%;
}

/* ----------------------------------------------------------
   Register / primary auth submit button (register.php).
   Root cause of the old layout/spacing issues: the button was a
   raw utility stack (py-3 rounded-full font-bold) with no icon
   alignment, uneven optical padding and only an opacity hover —
   inconsistent with the design-system .btn family. This unifies
   it: proper flex alignment, balanced padding, clear typography,
   a lift + glow hover and an active press, fully responsive and
   RTL-safe (logical gap, no directional margins).
   ---------------------------------------------------------- */
.btn-register {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  padding: 13px 24px;
  border: 1px solid transparent;
  border-radius: var(--radius-full);
  background: var(--primary-container);
  color: #fff;
  font-family: inherit;
  font-weight: 700;
  font-size: 1rem;
  line-height: 1;
  letter-spacing: .2px;
  cursor: pointer;
  user-select: none;
  box-shadow: 0 4px 14px rgba(229, 9, 20, .22);
  transition: transform .25s var(--ease-out-ios), box-shadow .25s var(--ease-out-ios), background-color .2s ease;
}

.btn-register:hover {
  background: #c0000c;
  transform: translateY(-2px);
  box-shadow: 0 8px 22px rgba(229, 9, 20, .34);
}

.btn-register:active {
  transform: translateY(0) scale(.99);
  box-shadow: 0 3px 10px rgba(229, 9, 20, .24);
}

.btn-register:focus-visible {
  outline: 2px solid var(--primary-container);
  outline-offset: 3px;
}

.btn-register .material-symbols-outlined {
  font-size: 20px;
  line-height: 1;
}

@media (prefers-reduced-motion: reduce) {
  .btn-register {
    transition: background-color .2s ease;
  }

  .btn-register:hover,
  .btn-register:active {
    transform: none;
  }
}


/* ----------------------------------------------------------
   Nav auth buttons (login / register) — includes/site_nav.php.
   Root cause of the visual imbalance: the two pills used ad-hoc
   utility classes with different content widths, so "حساب جديد"
   wrapped to two lines while "دخول" stayed on one — mismatched
   heights. These share one base: identical height, padding, radius,
   single-line (no wrap), centered icon+label, with matching
   hover / active / focus states. RTL-safe (logical gap).
   ---------------------------------------------------------- */
.nav-auth-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  height: 40px;
  padding: 0 18px;
  border: 1px solid transparent;
  border-radius: var(--radius-full);
  font-family: inherit;
  font-weight: 700;
  font-size: .9rem;
  line-height: 1;
  white-space: nowrap;
  text-decoration: none;
  transition: transform .2s var(--ease-out-ios), background-color .2s ease,
    border-color .2s ease, color .2s ease, box-shadow .2s ease;
}

.nav-auth-btn .material-symbols-outlined {
  font-size: 18px;
  line-height: 1;
}

.nav-auth-btn--solid {
  background: var(--primary-container);
  color: #fff;
  box-shadow: 0 3px 10px rgba(229, 9, 20, .2);
}

.nav-auth-btn--solid:hover {
  background: #c0000c;
  color: #fff;
  transform: translateY(-1px);
  box-shadow: 0 6px 16px rgba(229, 9, 20, .3);
}

.nav-auth-btn--outline {
  background: transparent;
  color: var(--text-primary);
  border-color: var(--border-muted);
}

.nav-auth-btn--outline:hover {
  background: var(--surface-container-low);
  border-color: var(--primary-container);
  color: var(--text-primary);
  transform: translateY(-1px);
}

.nav-auth-btn:active {
  transform: translateY(0) scale(.97);
}

.nav-auth-btn:focus-visible {
  outline: 2px solid var(--primary-container);
  outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
  .nav-auth-btn {
    transition: background-color .2s ease, border-color .2s ease, color .2s ease;
  }

  .nav-auth-btn:hover,
  .nav-auth-btn:active {
    transform: none;
  }
}

/* Tag / Chip */
.tag {

  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 12px;
  border-radius: var(--radius-full);
  background: var(--surface-container);
  color: var(--text-secondary);
  font-size: .75rem;
  font-weight: 500;
}

.tag-primary {
  background: rgba(229, 9, 20, .12);
  color: var(--primary);
}

/* Article Card */
.article-card {
  background: var(--card-bg);
  border: 1px solid var(--border-muted);
  border-radius: var(--radius-xl);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  transition: transform var(--transition), border-color var(--transition);
}

.article-card:hover {
  transform: translateY(-4px);
  border-color: rgba(255, 180, 170, .25);
}

.article-card .thumb {
  position: relative;
  aspect-ratio: 16/10;
  overflow: hidden;
  background: var(--surface-container);
}

/* contain (لا cover): تُعرض الصورة كاملة دون قصّ أي جزء منها. */
.article-card .thumb img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  transition: transform .6s ease;
}

.article-card:hover .thumb img {
  transform: scale(1.05);
}

.article-card .thumb .tag {
  position: absolute;
  top: 12px;
  inset-inline-start: 12px;
  backdrop-filter: blur(8px);
  background: rgba(0, 0, 0, .55);
  color: #fff;
}

.article-card .body {
  padding: 18px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  flex: 1;
}

.article-card h3 {
  font-size: 1.1rem;
  line-height: 1.4;
  margin: 0;
}

.article-card h3 a {
  color: var(--text-primary);
}

.article-card h3 a:hover {
  color: var(--primary);
}

.article-card .excerpt {
  color: var(--text-secondary);
  font-size: .92rem;
  margin: 0;
  flex: 1;
}

.article-card .meta {
  display: flex;
  align-items: center;
  gap: 12px;
  color: var(--text-muted);
  font-size: .8rem;
  padding-top: 8px;
  border-top: 1px solid var(--border-muted);
}

.article-card .meta .material-symbols-outlined {
  font-size: 16px;
}

/* ----------------------------------------------------------
   Media Frame — الإطار الموحّد لعرض وسائط المقالات
   المصدر الوحيد لسلوك "اعرض الصورة كاملة" في كل الموقع.

   القاعدة: object-fit: contain — الصورة تُحتوى بالكامل داخل
   الإطار مع الحفاظ على نسبة أبعادها، فلا يُقتطع أي جزء منها
   ولا تتشوّه، أياً كانت نسبتها (أفقية/طولية/مربّعة).

   أي فراغ متبقٍّ داخل الإطار يُملأ بخلفية محيّدة من نفس نظام
   الألوان (متغيّر CSS) فتتبع الوضع الداكن والفاتح تلقائياً.
   الإطار متماثل الاتجاه فيعمل في RTL و LTR بلا أي تغيير.
   ---------------------------------------------------------- */
.media-frame {
  position: relative;
  display: block;
  width: 100%;
  overflow: hidden;
  background: var(--surface-container);
}

/* pictureTag() قد يلفّ <img> داخل <picture> لمصدر WebP — نضمن أن الغلاف يمتد بالكامل. */
.media-frame>picture {
  display: block;
  width: 100%;
  height: 100%;
}

.media-frame img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  /* الصورة كاملة دائماً — لا قصّ ولا تشويه */
  object-position: center;
}

/* النِسَب الجاهزة (لتوحيد ارتفاع البطاقات داخل الشبكات) */
.media-frame--video {
  aspect-ratio: 16 / 9;
}

.media-frame--card {
  aspect-ratio: 16 / 10;
}

.media-frame--square {
  aspect-ratio: 1 / 1;
}

/* إطار حرّ الارتفاع: يتبع نسبة الصورة نفسها فلا يظهر أي فراغ إطلاقاً.
   يُستخدم حيث لا حاجة لتوحيد الارتفاع (صورة المقال الرئيسية). */
.media-frame--natural {
  background: transparent;
}

.media-frame--natural img {
  height: auto;
}

/* تكبير لطيف عند المرور — يحفظ حِسّ الحركة الحالي في البطاقات.
   الحالة الأساسية تُظهر الصورة كاملة؛ التكبير تفاعل مؤقّت فقط. */
.media-frame--zoom img {
  transition: transform .6s var(--ease-standard);
}

.group:hover .media-frame--zoom img {
  transform: scale(1.05);
}

/* نسخة تُطبَّق مباشرةً على <img> حين لا يوجد عنصر إطار منفصل. */
.media-fit {
  object-fit: contain;
  object-position: center;
  background: var(--surface-container);
}

@media (prefers-reduced-motion: reduce) {

  .media-frame--zoom img,
  .group:hover .media-frame--zoom img {
    transition: none !important;
    transform: none !important;
  }
}

/* Hero Article */
.hero-article {
  position: relative;
  border-radius: var(--radius-xl);
  overflow: hidden;
  min-height: 460px;
  display: grid;
  align-items: end;
  background: var(--surface-container);
}

/* contain (لا cover): صورة المقال المميّز تُعرض كاملة دون قصّ أي جزء منها.
   الخلفية الداكنة تملأ أي فراغ فيبقى الشكل السينمائي متناسقاً مع الهوية. */
.hero-article img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  background: #0b0b0b;
  transition: transform .8s ease;
}

.hero-article:hover img {
  transform: scale(1.03);
}

.hero-article::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, transparent 30%, rgba(0, 0, 0, .85) 100%);
}

.hero-article .content {
  position: relative;
  padding: 40px;
  max-width: 900px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.hero-article h1 {
  font-size: clamp(1.6rem, 3.4vw, 2.8rem);
  color: #fff;
  margin: 0;
  line-height: 1.2;
}

.hero-article p {
  color: rgba(255, 255, 255, .85);
  margin: 0;
  font-size: 1.05rem;
}

.hero-article .meta {
  color: rgba(255, 255, 255, .75);
  font-size: .85rem;
  display: flex;
  gap: 14px;
}

/* Grid of cards */
.cards-grid {
  display: grid;
  gap: 24px;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
}

/* Sidebar widgets */
.widget {
  background: var(--card-bg);
  border: 1px solid var(--border-muted);
  border-radius: var(--radius-xl);
  padding: 20px;
  margin-bottom: 24px;
}

.widget h4 {
  font-size: 1rem;
  margin: 0 0 14px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--border-muted);
}

.widget ol {
  padding: 0;
  margin: 0;
  list-style: none;
  counter-reset: w;
}

.widget li {
  counter-increment: w;
  position: relative;
  padding: 10px 0 10px 0;
  padding-inline-start: 38px;
  border-bottom: 1px dashed var(--border-muted);
}

.widget li:last-child {
  border-bottom: 0;
}

.widget li::before {
  content: counter(w, decimal);
  position: absolute;
  inset-inline-start: 0;
  top: 10px;
  width: 28px;
  height: 28px;
  display: grid;
  place-items: center;
  background: var(--surface-container);
  color: var(--primary);
  border-radius: var(--radius-lg);
  font-weight: 700;
  font-size: .85rem;
}

.widget li a {
  color: var(--text-primary);
  font-size: .92rem;
  line-height: 1.5;
}

.widget li a:hover {
  color: var(--primary);
}

.widget li small {
  display: block;
  color: var(--text-muted);
  margin-top: 4px;
}

/* Forms */
.form-row {
  display: grid;
  gap: 6px;
  margin-bottom: 18px;
}

.form-row label {
  font-size: .9rem;
  color: var(--text-secondary);
  font-weight: 500;
}

.form-row input,
.form-row select,
.form-row textarea {
  width: 100%;
  padding: 12px 14px;
  border-radius: var(--radius-lg);
  background: var(--surface-container);
  border: 1px solid var(--border-muted);
  color: var(--text-primary);
  font-family: inherit;
  font-size: .95rem;
  outline: none;
  transition: border-color var(--transition);
}

.form-row textarea {
  min-height: 140px;
  resize: vertical;
  line-height: 1.7;
}

.form-row input:focus,
.form-row select:focus,
.form-row textarea:focus {
  border-color: var(--primary);
}

.form-row .hint {
  font-size: .8rem;
  color: var(--text-muted);
}

/* ==========================================================
   Toast Notifications — unified feedback system
   Renders as a floating banner at the top of the viewport,
   iOS-notification style. Server-rendered via ui_alert()/
   flash_render() (includes/ui_helpers.php) or created on the
   fly via window.AppToast.show() (assets/js/main.js).
   ========================================================== */
.app-toast-viewport {
  position: fixed;
  top: max(12px, env(safe-area-inset-top));
  inset-inline: 0;
  margin-inline: auto;
  z-index: 1100;
  display: flex;
  flex-direction: column;
  gap: 10px;
  width: min(92vw, 420px);
  padding: 0 4px;
  pointer-events: none;
}

.app-toast {
  pointer-events: auto;
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: 10px;
  background: rgba(24, 24, 24, .96);
  border: 1px solid var(--border-muted);
  border-radius: var(--radius-lg);
  padding: 14px;
  box-shadow: var(--shadow-lg);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  opacity: 0;
  transform: translateY(-16px) scale(.97);
  transition: transform .38s var(--ease-out-ios), opacity .38s var(--ease-out-ios);
  will-change: transform, opacity;
}

.app-toast.is-visible {
  opacity: 1;
  transform: translateY(0) scale(1);
}

.app-toast.is-leaving {
  opacity: 0;
  transform: translateY(-10px) scale(.98);
  transition-duration: .26s;
  transition-timing-function: var(--ease-in-ios);
}

.app-toast-success {
  border-color: rgba(34, 197, 94, .35);
}

.app-toast-error {
  border-color: rgba(239, 68, 68, .4);
}

.app-toast-warning {
  border-color: rgba(245, 158, 11, .35);
}

.app-toast-info {
  border-color: rgba(167, 200, 255, .3);
}

.app-toast-icon {
  font-size: 22px;
  line-height: 1;
  margin-top: 1px;
  flex-shrink: 0;
}

.app-toast-success .app-toast-icon {
  color: var(--success);
}

.app-toast-error .app-toast-icon {
  color: var(--error);
}

.app-toast-warning .app-toast-icon {
  color: var(--warning);
}

.app-toast-info .app-toast-icon {
  color: var(--tertiary);
}

.app-toast-msg {
  flex: 1;
  margin: 0;
  font-size: .92rem;
  line-height: 1.6;
  color: var(--text-primary);
}

.app-toast-close {
  flex-shrink: 0;
  background: transparent;
  border: 0;
  color: var(--text-muted);
  cursor: pointer;
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  border-radius: var(--radius-full);
  transition: background .15s ease, color .15s ease;
  margin: -4px;
}

.app-toast-close:hover,
.app-toast-close:focus-visible {
  background: var(--surface-container-high);
  color: var(--text-primary);
}

.app-toast-close .material-symbols-outlined {
  font-size: 16px;
}

/* ==========================================================
   Confirm Modal — replaces native confirm() for delete/leave-
   page style prompts. Triggered via data-confirm="..." on any
   <a>, submit <button>, or <form> (assets/js/main.js).
   ========================================================== */
.app-confirm-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, .6);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  z-index: 1000;
  opacity: 0;
  transition: opacity .2s var(--ease-standard);
}

.app-confirm-overlay.is-visible {
  opacity: 1;
}

.app-confirm-modal {
  width: 100%;
  max-width: 380px;
  background: var(--card-bg);
  border: 1px solid var(--border-muted);
  border-radius: var(--radius-xl);
  padding: 28px 24px;
  text-align: center;
  box-shadow: var(--shadow-lg);
  transform: translateY(12px) scale(.96);
  opacity: 0;
  transition: transform .26s var(--ease-out-ios), opacity .26s var(--ease-out-ios);
}

.app-confirm-overlay.is-visible .app-confirm-modal {
  transform: translateY(0) scale(1);
  opacity: 1;
}

.app-confirm-icon {
  font-size: 40px;
  color: var(--primary-container);
  margin-bottom: 10px;
  display: inline-block;
}

.app-confirm-msg {
  color: var(--text-primary);
  font-size: 1rem;
  line-height: 1.6;
  margin: 0 0 20px;
}

.app-confirm-actions {
  display: flex;
  gap: 10px;
  justify-content: center;
}

.app-confirm-actions .btn {
  flex: 1;
}

/* ==========================================================
   Global interactive polish — cursor, focus, hover motion
   (applies site-wide: public pages + admin, since this file
   is now linked from both includes/page_head.php and
   admin/_layout_top.php).
   ========================================================== */
a[href],
button:not(:disabled),
[role="button"],
select,
summary,
label[for] {
  cursor: pointer;
}

button:disabled,
[aria-disabled="true"],
input:disabled,
select:disabled {
  cursor: not-allowed;
}

:focus-visible {
  outline: 2px solid var(--primary-container);
  outline-offset: 2px;
  border-radius: var(--radius);
}

/* Baseline smooth hover for links/inputs that don't already carry a
   Tailwind `transition*` utility class or a dedicated component rule
   (.btn already defines its own transition, incl. transform, above).
   Transform is intentionally excluded here so it never fights
   component-specific hover animations (.article-card, .hero-article,
   category cards, .btn-primary's lift). */
a,
button,
select,
input,
textarea {
  transition: color .25s var(--ease-out-ios), background-color .25s var(--ease-out-ios), border-color .25s var(--ease-out-ios), opacity .25s var(--ease-out-ios), box-shadow .25s var(--ease-out-ios);
}

/* Tactile feedback for icon-only controls (nav bell, avatar, hamburger).
   Hover lifts subtly, press settles back — smooth spring easing throughout. */
.icon-btn,
#notifBtn,
#avatarBtn,
#mobileMenuBtn,
#adminMenuBtn {
  transition: background-color .25s var(--ease-out-ios), transform .2s var(--ease-out-ios);
}

.icon-btn:hover,
#notifBtn:hover,
#avatarBtn:hover,
#mobileMenuBtn:hover,
#adminMenuBtn:hover {
  transform: translateY(-1px);
}

.icon-btn:active,
#notifBtn:active,
#avatarBtn:active,
#mobileMenuBtn:active,
#adminMenuBtn:active {
  transform: scale(.92);
}


@media (prefers-reduced-motion: reduce) {

  .app-toast,
  .app-toast.is-visible,
  .app-toast.is-leaving,
  .app-confirm-modal,
  .app-confirm-overlay,
  .dropdown-panel,
  a,
  button,
  .btn,
  select,
  input,
  textarea,
  .icon-btn,
  #notifBtn,
  #avatarBtn,
  #mobileMenuBtn,
  #adminMenuBtn {
    transition-duration: .01ms !important;
    animation-duration: .01ms !important;
    transform: none !important;
  }
}

/* ==========================================================
   Smart site header — stays fixed at top, hides while the
   visitor scrolls down (more room to read), reveals instantly
   on any upward scroll. Toggled via #siteHeader in
   includes/site_nav.php + assets/js/main.js.
   ========================================================== */
.site-header {
  transition: transform .32s var(--ease-standard);
}

.site-header.nav-hidden {
  transform: translateY(-100%);
}

/* الحاوية العلوية الموحّدة (شريط "عاجل" + شريط التنقل) هي العنصر الثابت الذي
   يُخفى/يُظهر كوحدة واحدة.
   السبب الجذري لمشكلة "لا يظهر إلا عند بلوغ أعلى الصفحة": استخدام
   position: sticky مع transform يُعطِّل الالتصاق في عدة متصفحات جوال،
   فيمرّ الشريط مع المحتوى بدل أن يبقى مثبّتاً، ولا يعود إلا فعلياً عند
   موضعه أعلى الصفحة. الحل: position: fixed دائماً (كما طلب المستخدم)،
   مع عنصر فراغ (#siteTopbarSpacer) يحجز ارتفاع الشريط كي لا يختفي المحتوى
   خلفه. الإخفاء/الإظهار عبر translateY يعمل حينها بثبات في كل الأجهزة. */
.site-topbar {
  position: fixed;
  top: 0;
  inset-inline: 0;
  transition: transform .32s var(--ease-standard);
  will-change: transform;
}

.site-topbar.nav-hidden {
  transform: translateY(-100%);
}

@media (prefers-reduced-motion: reduce) {
  .site-topbar {
    transition-duration: .01ms !important;
  }
}



/* ==========================================================
   Back-to-top button — appears once the visitor has scrolled
   down past the top of the page, hides again on upward scroll
   (mirrors the header: when the header reveals, this hides).
   ========================================================== */
.back-to-top {
  position: fixed;
  bottom: 20px;
  inset-inline-end: 20px;
  width: 46px;
  height: 46px;
  display: grid;
  place-items: center;
  background: var(--primary-container);
  color: #fff;
  border: 0;
  border-radius: var(--radius-full);
  box-shadow: var(--shadow-lg);
  z-index: 400;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transform: translateY(14px) scale(.9);
  transition: opacity .28s var(--ease-out-ios), transform .28s var(--ease-out-ios), visibility 0s linear .28s, background-color .2s ease;
}

.back-to-top.is-visible {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transform: translateY(0) scale(1);
  transition: opacity .28s var(--ease-out-ios), transform .28s var(--ease-out-ios), visibility 0s linear 0s, background-color .2s ease;
}

.back-to-top:hover {
  background: #c0000c;
}

.back-to-top .material-symbols-outlined {
  font-size: 24px;
}

@media (prefers-reduced-motion: reduce) {

  .site-header,
  .back-to-top {
    transition-duration: .01ms !important;
  }
}

/* ==========================================================
   Password visibility toggle — injected by assets/js/main.js
   next to every input[type="password"]. Uses logical
   properties (inset-inline-end) so it sits correctly whether
   the page is RTL (this site) or LTR.
   ========================================================== */
.pw-field-wrap {
  position: relative;
}

.pw-field-wrap .pw-field-input {
  padding-inline-end: 44px;
}

.pw-field-wrap .pw-field-input::-ms-reveal,
.pw-field-wrap .pw-field-input::-ms-clear {
  display: none;
}

.pw-toggle-btn {
  position: absolute;
  inset-inline-end: 6px;
  top: 50%;
  transform: translateY(-50%);
  background: transparent;
  border: 0;
  color: var(--text-muted);
  cursor: pointer;
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  border-radius: var(--radius-full);
  transition: background-color .15s ease, color .15s ease;
}

.pw-toggle-btn:hover,
.pw-toggle-btn:focus-visible {
  color: var(--text-primary);
  background: var(--surface-container-high);
}

.pw-toggle-btn .material-symbols-outlined {
  font-size: 20px;
}

/* ==========================================================
   Category icon picker (admin/categories.php).
   Root causes fixed here:
   - Broken mobile layout: the old modal used a fixed 6/8-column
     grid + a rigid max-height, so on small screens icons were
     cramped and the panel overflowed. We use an auto-fill grid
     (cells size themselves) and a dvh-based height, and dock the
     sheet to the bottom on phones for a native feel.
   - Stray focus outline on the search box: the input sits inside a
     rounded pill that owns the focus affordance, so the input
     itself must not draw the global :focus-visible ring.
   ========================================================== */
.icon-picker__panel {
  max-height: 88vh;
}

@media (min-width: 640px) {
  .icon-picker__panel {
    max-height: 80vh;
  }
}

.icon-picker__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(44px, 1fr));
  gap: 6px;
  align-content: start;
}

.icon-picker__cell {
  min-width: 0;
}

.icon-picker__cell svg {
  width: 22px;
  height: 22px;
}

/* The search pill owns the focus highlight; the borderless input must not
   render its own outline/ring (matches the site-wide search treatment). */
.icon-picker__search:focus-within {
  border-color: var(--primary-container);
}

.icon-picker__search input:focus,
.icon-picker__search input:focus-visible {
  outline: none;
  box-shadow: none;
}

/* ==========================================================
   Breaking-news ticker bar (includes/site_nav.php).
   Root cause of the light-mode readability bug: the bar had a
   hardcoded dark background (bg-[#111111]) while its links used
   the theme token --text-primary, which becomes near-black in
   light mode → dark text on a dark bar. We give the bar its own
   dark surface in BOTH themes with explicitly light text, so
   contrast stays strong (AA+) regardless of the active theme,
   without touching the global Design System tokens.
   ========================================================== */
.breaking-bar {
  background: #111111;
}

html.light .breaking-bar {
  background: #1c1c1c;
}

/* يظل داكناً في الوضع الفاتح لتباين قوي */
.breaking-bar__link {
  color: #f5f5f5;
}

.breaking-bar__link:hover {
  color: var(--primary);
}

.breaking-bar__empty {
  color: #b3b3b3;
}

/* ==========================================================
   Hero slider (index.php) — shown automatically when 2+ articles
   are featured. Reuses the same is_featured data; single-featured
   pages keep the original hero untouched. Full-bleed premium
   slider: fade+slide track, arrows, dots, autoplay (JS), swipe,
   keyboard. RTL-aware (track flows right-to-left via JS transform).
   ========================================================== */
.hero-slider {
  position: relative;
  border-radius: var(--radius-xl);
  overflow: hidden;
}

.hero-slider__viewport {
  overflow: hidden;
  border-radius: var(--radius-xl);
}

.hero-slider__track {
  display: flex;
  /* transform is driven by JS; premium easing + longer duration keeps slide
     motion silky and cinematic (like top news sites). GPU-accelerated. */
  transition: transform .85s cubic-bezier(.22, .61, .36, 1);
  will-change: transform;
  backface-visibility: hidden;
  transform: translate3d(0, 0, 0);
}

.hero-slider__slide {
  position: relative;
  flex: 0 0 100%;
  min-width: 100%;
  height: 60vh;
  min-height: 400px;
}

/* Ken-Burns style slow zoom on the active slide's image — subtle, premium,
   hardware-accelerated. Non-active slides reset to neutral scale. */
.hero-slider__img {
  /* contain: الصورة كاملة دون قصّ. الخلفية الداكنة تملأ الفراغ بأناقة. */
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
  background: #0b0b0b;
  transform: scale(1.06);
  transform-origin: center;
  transition: transform 7s ease-out;
  will-change: transform;
  backface-visibility: hidden;
}

.hero-slider__slide.is-active .hero-slider__img {
  transform: scale(1);
}

/* pictureTag() wraps some images in <picture>; make its <img> fill too */
.hero-slider__slide picture {
  display: block;
  width: 100%;
  height: 100%;
}

.hero-slider__overlay {
  position: absolute;
  inset: 0;
  background: linear-gradient(0deg, rgba(11, 11, 11, .95) 0%, rgba(11, 11, 11, .55) 42%, rgba(11, 11, 11, 0) 100%);
}

.hero-slider__content {
  position: absolute;
  inset-inline: 0;
  bottom: 0;
  padding: 24px;
  opacity: 0;
  transform: translateY(16px);
  transition: opacity .6s var(--ease-out-ios) .15s, transform .6s var(--ease-out-ios) .15s;
}

@media (min-width: 768px) {
  .hero-slider__content {
    padding: 40px;
  }
}

.hero-slider__slide.is-active .hero-slider__content {
  opacity: 1;
  transform: translateY(0);
}

/* Arrows */
.hero-slider__arrow {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 3;
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: var(--radius-full);
  background: rgba(0, 0, 0, .45);
  color: #fff;
  cursor: pointer;
  backdrop-filter: blur(6px);
  transition: background-color .25s var(--ease-out-ios), transform .25s var(--ease-out-ios), opacity .25s ease;
  opacity: 0;
}

.hero-slider:hover .hero-slider__arrow,
.hero-slider:focus-within .hero-slider__arrow {
  opacity: 1;
}

.hero-slider__arrow:hover {
  background: var(--primary-container);
}

.hero-slider__arrow:active {
  transform: translateY(-50%) scale(.92);
}

.hero-slider__arrow--prev {
  inset-inline-end: 16px;
}

/* RTL: prev on the right */
.hero-slider__arrow--next {
  inset-inline-start: 16px;
}

@media (max-width: 640px) {
  .hero-slider__arrow {
    opacity: 1;
    width: 40px;
    height: 40px;
  }
}

/* Dots */
.hero-slider__dots {
  position: absolute;
  inset-inline: 0;
  bottom: 14px;
  z-index: 3;
  display: flex;
  justify-content: center;
  gap: 8px;
}

.hero-slider__dot {
  width: 9px;
  height: 9px;
  border-radius: var(--radius-full);
  border: 0;
  padding: 0;
  cursor: pointer;
  background: rgba(255, 255, 255, .5);
  transition: background-color .25s var(--ease-out-ios), transform .25s var(--ease-out-ios), width .3s var(--ease-out-ios);
}

.hero-slider__dot:hover {
  background: rgba(255, 255, 255, .8);
}

.hero-slider__dot.is-active {
  background: #fff;
  width: 24px;
}

@media (prefers-reduced-motion: reduce) {
  .hero-slider__track {
    transition: none !important;
  }

  .hero-slider__content {
    transition: none !important;
    opacity: 1;
    transform: none;
  }

  .hero-slider__arrow:active,
  .hero-slider__dot {
    transition: none !important;
  }
}

/* Auth Card */
.auth-wrapper {
  min-height: 70vh;
  display: grid;
  place-items: center;
  padding: 40px 0;
}


.auth-card {
  width: 100%;
  max-width: 420px;
  background: var(--card-bg);
  border: 1px solid var(--border-muted);
  border-radius: var(--radius-xl);
  padding: 32px;
  box-shadow: var(--shadow-lg);
}

.auth-card h1 {
  font-size: 1.5rem;
  margin-bottom: 8px;
}

.auth-card .muted {
  margin-bottom: 24px;
}

/* Empty state */
.empty {
  text-align: center;
  padding: 60px 20px;
  color: var(--text-secondary);
  border: 1px dashed var(--border-muted);
  border-radius: var(--radius-xl);
}

.empty .material-symbols-outlined {
  font-size: 48px;
  color: var(--text-muted);
  margin-bottom: 8px;
}

/* Pagination */
.pagination {
  display: flex;
  gap: 6px;
  justify-content: center;
  margin-top: 32px;
  flex-wrap: wrap;
}

.pagination a,
.pagination span {
  min-width: 38px;
  height: 38px;
  display: inline-grid;
  place-items: center;
  padding: 0 12px;
  border-radius: var(--radius-lg);
  background: var(--surface-container);
  color: var(--text-secondary);
  border: 1px solid var(--border-muted);
  font-size: .9rem;
}

.pagination a:hover {
  background: var(--surface-container-high);
  color: var(--text-primary);
}

.pagination .active {
  background: var(--primary-container);
  color: #fff;
  border-color: var(--primary-container);
}

/* ==========================================================
   UI Polish (Parts 5, 7, 8) — additive micro-interactions built
   entirely on the existing design tokens. No token overrides,
   no duplicated component rules; safe with the current markup.
   ========================================================== */

/* Forms — keep the design-system focus (border color change + the global
   :focus-visible keyboard ring). We intentionally do NOT add a colored
   box-shadow ring on every input, because it produced an unwanted red halo
   on borderless controls like the nav search box. */

/* Search inputs (nav + search page) — the search box sits on a rounded pill
   with its own border, and its <input> is intentionally borderless. Browsers
   apply an invalid/required validation style to type="search" that can render
   as a red outline once focused. We explicitly neutralise it here and let the
   pill container own the focus affordance (design-system red border), matching
   the rest of the UI. This is the root-cause fix for the unwanted red outline. */
input[type="search"] {
  outline: none;
  box-shadow: none;
}

input[type="search"]:focus,
input[type="search"]:focus-visible {
  outline: none;
  box-shadow: none;
}

input[type="search"]::-webkit-search-decoration,
input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-results-button,
input[type="search"]::-webkit-search-results-decoration {
  -webkit-appearance: none;
}

/* Focus affordance for search fields (requested): when the caret is inside a
   search input, the surrounding rounded pill lifts with a brand-tinted glow
   (colored shadow) + a red border, clearly marking the active field. The input
   itself stays borderless; the wrapping pill (the <form>) owns the highlight.
   Covers the nav desktop/mobile search and any rounded search form site-wide. */
form.rounded-full:focus-within,
.search-pill:focus-within {
  border-color: var(--primary-container) !important;
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary-container) 24%, transparent),
    0 6px 18px rgba(229, 9, 20, .20);
}

@media (prefers-reduced-motion: reduce) {

  form.rounded-full:focus-within,
  .search-pill:focus-within {
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary-container) 24%, transparent);
  }
}

/* ==========================================================
   Avatar lightbox (profile.php) — Instagram-style: tap the
   avatar to zoom it to the center of the screen over a blurred,
   dimmed backdrop. Built/controlled by assets/js/main.js.
   ========================================================== */
.avatar-zoomable {
  cursor: zoom-in;
}

.avatar-lightbox {
  position: fixed;
  inset: 0;
  z-index: 1200;
  display: grid;
  place-items: center;
  padding: 24px;
  background: rgba(0, 0, 0, .6);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity .3s var(--ease-out-ios), visibility 0s linear .3s;
}

.avatar-lightbox.is-visible {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transition: opacity .3s var(--ease-out-ios), visibility 0s linear 0s;
}

.avatar-lightbox__img {
  width: min(78vw, 78vh, 460px);
  height: min(78vw, 78vh, 460px);
  object-fit: cover;
  border-radius: var(--radius-full);
  border: 3px solid rgba(255, 255, 255, .85);
  box-shadow: 0 24px 70px rgba(0, 0, 0, .55);
  transform: scale(.7);
  opacity: 0;
  transition: transform .38s var(--ease-out-ios), opacity .38s var(--ease-out-ios);
}

.avatar-lightbox.is-visible .avatar-lightbox__img {
  transform: scale(1);
  opacity: 1;
}

.avatar-lightbox__close {
  position: absolute;
  top: max(16px, env(safe-area-inset-top));
  inset-inline-end: 16px;
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: var(--radius-full);
  cursor: pointer;
  background: rgba(255, 255, 255, .15);
  color: #fff;
  transition: background-color .2s ease, transform .2s var(--ease-out-ios);
}

.avatar-lightbox__close:hover {
  background: rgba(255, 255, 255, .28);
}

.avatar-lightbox__close:active {
  transform: scale(.92);
}

.avatar-lightbox__close .material-symbols-outlined {
  font-size: 26px;
}

@media (prefers-reduced-motion: reduce) {

  .avatar-lightbox,
  .avatar-lightbox__img {
    transition-duration: .01ms !important;
  }

  .avatar-lightbox__img {
    transform: none;
  }
}

/* Email-template color pickers (admin/settings.php) — keep the native swatch

   and the hex text tidy and fully contained on mobile (no overflow, no stray
   focus outline outside the rounded field).
   Root cause of the mobile glitch: the hex <input> had no width floor, so a
   long value pushed past the rounded field, and the global :focus-visible ring
   rendered *outside* the container. We contain both here without altering the
   design — the field itself carries the focus highlight instead of each child. */
.color-field {
  overflow: hidden;
  max-width: 100%;
}

.color-field:focus-within {
  border-color: var(--primary-container);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--primary-container) 22%, transparent);
}

.color-swatch {
  -webkit-appearance: none;
  appearance: none;
  padding: 0;
  border: 0;
  background: transparent;
  border-radius: 6px;
  overflow: hidden;
  flex: 0 0 auto;
}

.color-swatch::-webkit-color-swatch-wrapper {
  padding: 0;
}

.color-swatch::-webkit-color-swatch {
  border: 0;
  border-radius: 6px;
}

.color-swatch::-moz-color-swatch {
  border: 0;
  border-radius: 6px;
}

.color-hex {
  min-width: 0;
  width: 100%;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.color-field .color-hex:focus,
.color-field .color-hex:focus-visible,
.color-field .color-swatch:focus,
.color-field .color-swatch:focus-visible {
  outline: none;
  box-shadow: none;
}

/* Buttons — richer lift + glow on hover */
.btn-primary:hover {
  box-shadow: 0 6px 18px rgba(229, 9, 20, .28);
}

/* Tables — smooth row hover site-wide */
table tbody tr {
  transition: background-color .18s ease;
}

/* Article/generic cards — modern elevation that lifts on hover */
.article-card {
  box-shadow: 0 1px 2px rgba(0, 0, 0, .14);
}

.article-card:hover {
  box-shadow: var(--shadow-lg);
}

/* Dropdowns — refined origin + spring easing (panels defined in
   includes/page_head.php keep their base rules; this only tunes feel) */
.dropdown-panel {
  transform-origin: top center;
}

/* ---------- Scroll reveal (Part 5) ---------- */
[data-reveal] {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity .55s var(--ease-out-ios), transform .55s var(--ease-out-ios);
  will-change: opacity, transform;
}

[data-reveal].is-revealed {
  opacity: 1;
  transform: none;
}

[data-reveal][data-reveal-delay="1"] {
  transition-delay: .06s;
}

[data-reveal][data-reveal-delay="2"] {
  transition-delay: .12s;
}

[data-reveal][data-reveal-delay="3"] {
  transition-delay: .18s;
}

[data-reveal][data-reveal-delay="4"] {
  transition-delay: .24s;
}

[data-reveal][data-reveal-delay="5"] {
  transition-delay: .30s;
}

@media (prefers-reduced-motion: reduce) {
  [data-reveal] {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }
}

/* ---------- Category cards (Part 7) ---------- */
.cat-card {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 14px;
  padding: 26px 16px;
  background: var(--card-bg);
  border: 1px solid var(--border-muted);
  border-radius: var(--radius-xl);
  overflow: hidden;
  transition: transform .3s var(--ease-out-ios), border-color .3s ease,
    box-shadow .3s ease, background-color .3s ease;
}

.cat-card::before {
  content: "";
  position: absolute;
  inset-inline: 0;
  top: 0;
  height: 3px;
  background: var(--cat-color, var(--primary-container));
  transform: scaleX(0);
  transform-origin: center;
  transition: transform .35s var(--ease-out-ios);
}

.cat-card:hover {
  transform: translateY(-6px);
  border-color: color-mix(in srgb, var(--cat-color, var(--primary-container)) 55%, transparent);
  box-shadow: var(--shadow-lg);
}

.cat-card:hover::before {
  transform: scaleX(1);
}

.cat-card__icon {
  width: 60px;
  height: 60px;
  display: grid;
  place-items: center;
  border-radius: var(--radius-full);
  background: color-mix(in srgb, var(--cat-color, var(--primary-container)) 14%, transparent);
  color: var(--cat-color, var(--primary-container));
  transition: transform .4s var(--ease-out-ios), background-color .3s ease;
}

.cat-card:hover .cat-card__icon {
  transform: translateY(-2px) scale(1.09) rotate(-4deg);
  background: color-mix(in srgb, var(--cat-color, var(--primary-container)) 22%, transparent);
}

.cat-card__icon .material-symbols-outlined {
  font-size: 28px;
}

.cat-card__title {
  font-weight: 700;
  color: var(--text-primary);
  transition: color .25s ease;
  line-height: 1.4;
}

.cat-card:hover .cat-card__title {
  color: var(--cat-color, var(--primary-container));
}

.cat-card__count {
  font-size: .8rem;
  color: var(--text-secondary);
  margin-top: 2px;
}

@media (prefers-reduced-motion: reduce) {

  .cat-card,
  .cat-card::before,
  .cat-card__icon {
    transition: none !important;
  }

  .cat-card:hover {
    transform: none;
  }

  .cat-card:hover .cat-card__icon {
    transform: none;
  }
}

/* ---------- Navigation menu (Part 8) ---------- */
/* Mobile menu: animated slide/fade instead of an instant display
   toggle. The base display rule lives in page_head.php; here we add
   the motion + a soft themed backdrop for a premium feel. */
.mobile-menu {
  overflow: hidden;
  max-height: 0;
  opacity: 0;
  transform: translateY(-8px);
  transition: max-height .38s var(--ease-standard), opacity .28s ease, transform .38s var(--ease-standard);
  box-shadow: var(--shadow-lg);
}

.mobile-menu.open {
  max-height: min(80vh, 640px);
  opacity: 1;
  transform: translateY(0);
  overflow-y: auto;
}

.mobile-menu a {
  transition: background-color .18s ease, color .18s ease, transform .18s ease;
}

.mobile-menu a:hover {
  transform: translateX(-3px);
}

/* Mobile menu backdrop — soft dim + blur behind the open menu */
#navBackdrop {
  position: fixed;
  inset: 0;
  z-index: 40;
  background: rgba(0, 0, 0, .5);
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity .3s var(--ease-standard), visibility 0s linear .3s;
}

#navBackdrop.is-visible {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transition: opacity .3s var(--ease-standard), visibility 0s linear 0s;
}

@media (min-width: 1024px) {
  #navBackdrop {
    display: none;
  }
}

/* Desktop nav links — animated underline that grows from the center on hover.
   Skips the pill buttons (دخول / حساب جديد) and the logo. Uses logical
   left/right via a centered transform so it reads correctly in RTL. */
#siteHeader nav a[href]:not(.bg-primary-container):not(.rounded-full):not(.border) {
  position: relative;
}

#siteHeader nav a[href]:not(.bg-primary-container):not(.rounded-full):not(.border)::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  bottom: -4px;
  height: 2px;
  background: var(--primary-container);
  border-radius: 2px;
  transform: scaleX(0);
  transform-origin: center;
  transition: transform .28s var(--ease-out-ios);
}

#siteHeader nav a[href]:not(.bg-primary-container):not(.rounded-full):not(.border):hover::after {
  transform: scaleX(1);
}

/* Pill buttons in the nav (login / register) + hero CTA — subtle lift + press */
#siteHeader nav a.rounded-full {
  transition: transform .2s var(--ease-out-ios), background-color .2s ease, opacity .2s ease;
}

#siteHeader nav a.rounded-full:hover {
  transform: translateY(-1px);
}

#siteHeader nav a.rounded-full:active {
  transform: translateY(0) scale(.97);
}

.admin-menu {
  transition: opacity .25s ease;
}

@media (prefers-reduced-motion: reduce) {
  #siteHeader nav a[href]::after {
    transition: none !important;
  }

  #siteHeader nav a.rounded-full:hover,
  #siteHeader nav a.rounded-full:active {
    transform: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .mobile-menu {
    transition: none !important;
  }

  .mobile-menu a:hover {
    transform: none;
  }
}

/* ==========================================================
   Mobile menu & dropdown item hardening — root cause of the
   "text overlaps the icon" bug on phones: Material Symbols icons
   have no intrinsic flex-shrink guard, so when a label is long the
   icon and text collapse into each other inside flex rows. We make
   every icon inside a dropdown panel / mobile menu / admin menu
   non-shrinking, and let the neighbouring text truncate cleanly.
   CSS-only, no markup changes, RTL-safe (logical spacing).
   ========================================================== */
.dropdown-panel a,
.dropdown-panel button,
.mobile-menu a,
.admin-menu a {
  min-width: 0;
}

/* Every icon that sits inline with a text label in a menu / dropdown /
   nav toggle must never shrink into the text. This covers the "المزيد"
   button, notification/avatar toggles, admin menu, and auth pills. */
.dropdown-panel a .material-symbols-outlined,
.dropdown-panel button .material-symbols-outlined,
.mobile-menu a .material-symbols-outlined,
.admin-menu a .material-symbols-outlined,
.nav-auth-btn .material-symbols-outlined,
#moreCatsBtn .material-symbols-outlined,
#siteHeader nav button .material-symbols-outlined,
#adminMenuBtn .material-symbols-outlined {
  flex-shrink: 0;
}

/* Any flex button/link carrying an icon + label gets a guaranteed gap so
   the arrow/glyph can't visually collide with the text on tight widths. */
#moreCatsBtn,
#siteHeader nav button {
  gap: 6px;
}

/* Any label span sitting next to an icon in these menus truncates
   instead of pushing under/over the icon. */
.dropdown-panel a>span:not(.material-symbols-outlined),
.mobile-menu a>span:not(.material-symbols-outlined) {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Comfortable tap targets + no text/icon collision on small screens. */
@media (max-width: 640px) {

  .dropdown-panel a,
  .dropdown-panel button,
  .mobile-menu a {
    min-height: 44px;
    line-height: 1.35;
  }
}

/* ==========================================================
   Article meta row (article-details.php) — date • time-ago •
   read-time. On narrow screens these three items used to sit on
   a single nowrap line and overflow/overlap. Fix: flex-wrap so
   each item can drop to its own line, with a dot separator that
   only appears between items on the SAME line (CSS-only, no JS).
   ========================================================== */

/* ==========================================================
   Native <select> dropdowns — root cause of the "selected text
   overlaps the arrow" bug: browsers draw their own arrow glyph
   (on the LEFT in RTL) with no reserved padding, so a value like
   "الصين والعالم" runs underneath it. Fix: neutralise the native
   arrow (appearance:none), draw our own SVG chevron pinned to the
   inline-start edge (left in RTL, right in LTR), and reserve inline
   padding so the value text can never sit under the arrow. CSS-only,
   applied site-wide (public + admin), fully RTL-safe via logical
   properties + [dir] mirroring of the background position.
   ========================================================== */
select {
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%237c7c7c' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-size: 16px 16px;
  /* Arrow lives on the inline-END edge. In RTL that resolves to the LEFT
     (matching the browser's native RTL arrow position); in LTR to the right. */
  background-position: left .75rem center;
  /* Reserve room on the SAME (inline-end) side so the value text can never
     sit under the arrow. !important is required here to win over the
     Tailwind padding utilities (px-3 / p-2) some selects carry, which have
     higher specificity than this element selector. */
  padding-inline-end: 2.25rem !important;
}

/* LTR pages: mirror the arrow to the right edge (inline-end in LTR). */
[dir="ltr"] select,
html:not([dir="rtl"]) select {
  background-position: right .75rem center;
}

select::-ms-expand {
  display: none;
}

option {
  color: initial;
}


.article-meta {
  display: flex;
  flex-wrap: wrap;

  align-items: center;
  gap: 2px 0;
  row-gap: 2px;
}

.article-meta>span {
  white-space: nowrap;
}

/* Dot separator: appears before every span except the first */
.article-meta>span+span::before {
  content: " • ";
  white-space: pre;
  color: var(--text-muted);
}

@media (max-width: 480px) {
  .article-meta {
    gap: 1px 0;
  }

  .article-meta>span {
    font-size: .78rem;
  }
}


/* ==========================================================
   مشغّل الفيديو + شارة الوسائط (المرحلة 2B)
   يُبنى فوق .media-frame من المرحلة الأولى — لا نمط بصري جديد مستقل.
   كل الألوان من متغيّرات التصميم القائمة ⇒ يعمل في الوضعين الداكن والفاتح.
   ========================================================== */
.video-player {
  position: relative;
}

/* الإطار يورث نسبة 16:9 من .media-frame--video؛ الخلفية سوداء لأن الفيديو
   يُعرض بـ contain (بلا قصّ) فقد تظهر أشرطة جانبية للفيديو الطولي. */
.video-player__frame {
  background: #000;
  border-radius: .75rem;
  overflow: hidden;
}

/* contain لا cover: لا يُقتطع أي جزء من الفيديو مهما كانت نسبته —
   نفس فلسفة الصور في المرحلة الأولى. */
.video-player__el {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  background: #000;
}

/* زر الكتم: inset-inline-* منطقي الاتجاه ⇒ يستقر تلقائياً في الجهة الصحيحة
   في RTL وLTR بلا قواعد [dir] منفصلة. */
.video-player__mute {
  position: absolute;
  inset-block-start: .625rem;
  inset-inline-end: .625rem;
  z-index: 2;
  display: inline-grid;
  place-items: center;
  width: 2.25rem;
  height: 2.25rem;
  border: 1px solid rgba(255, 255, 255, .25);
  border-radius: 999px;
  background: rgba(0, 0, 0, .62);
  color: #fff;
  font-size: 15px;
  line-height: 1;
  cursor: pointer;
  transition: background-color .2s var(--ease-standard), transform .2s var(--ease-standard);
}

.video-player__mute:hover {
  background: rgba(0, 0, 0, .82);
}

.video-player__mute:active {
  transform: scale(.94);
}

.video-player__mute:focus-visible {
  outline: 2px solid var(--primary-container);
  outline-offset: 2px;
}

/* حالة الزر تُقرأ من aria-pressed نفسه ⇒ مصدر واحد للحقيقة يخدم
   قارئ الشاشة والعرض المرئي معاً (لا صنف حالة مكرّر). */
.video-player__mute[aria-pressed="true"] .video-player__mute-off {
  display: none;
}

.video-player__mute[aria-pressed="false"] .video-player__mute-on {
  display: none;
}

/* شارة «فيديو» على بطاقات القوائم — زخرفية ولا تحجب الرابط. */
.media-badge {
  position: absolute;
  inset-block-start: .5rem;
  inset-inline-start: .5rem;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 8px;
  border-radius: 999px;
  background: rgba(0, 0, 0, .68);
  color: #fff;
  font-size: .68rem;
  font-weight: 700;
  line-height: 1.4;
  pointer-events: none;
  backdrop-filter: blur(4px);
}

.media-badge svg {
  display: block;
}

.media-badge__txt {
  display: inline-block;
}

/* على الشاشات الصغيرة جداً نُبقي الأيقونة فقط (المساحة أضيق من النص). */
@media (max-width: 380px) {
  .media-badge__txt {
    display: none;
  }

  .media-badge {
    padding: 4px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .video-player__mute {
    transition: none !important;
  }

  .video-player__mute:active {
    transform: none !important;
  }
}


/* ==========================================================
   غلاف الفيديو في البطاقات والشرائح
   الفيديو هنا بديل مباشر لوسم <img> داخل نفس الإطار، فيأخذ نفس
   الأصناف تماماً (w-full h-full / hero-slider__img) ⇒ صفر إزاحة تخطيط
   وصفر فرق بصري عن غلاف الصورة.
   ========================================================== */
.video-cover__el {
  display: block;
  /* contain لا cover: لا يُقتطع أي جزء من الفيديو مهما كانت نسبته —
     نفس فلسفة الصور في .media-frame تماماً. */
  object-fit: contain;
  object-position: center;
  background: #0b0b0b;
  /* يملأ الأشرطة الجانبية للفيديو الطولي بأناقة في الوضعين */
}

/* داخل .media-frame (البطاقات): الإطار يفرض النسبة، والفيديو يملأه بالكامل. */
.media-frame .video-cover__el {
  width: 100%;
  height: 100%;
}

/* داخل الشريحة: يورث أبعاد .hero-slider__img نفسها، لكن نُلغي حركة Ken-Burns
   (تكبير/تصغير بطيء) لأن الفيديو يتحرّك أصلاً — الجمع بينهما يُشوّش المشهد. */
.hero-slider__slide video.hero-slider__img {
  transform: none !important;
  transition: none !important;
}

/* زر الكتم فوق الغلاف: يُرفَع قليلاً كي لا يتزاحم مع شارة «فيديو» في الجهة
   المقابلة. inset-inline-* منطقي الاتجاه ⇒ صحيح في RTL وLTR بلا قواعد منفصلة. */
.video-player__mute--cover {
  inset-block-start: .75rem;
  inset-inline-end: .75rem;
}

@media (max-width: 640px) {
  .video-player__mute--cover {
    width: 2rem;
    height: 2rem;
    font-size: 13px;
  }
}