/* ---- IndoPak Nastaleeq Quran font (official quran.com / Quran Foundation CDN,
   CORS-open, ~84 KB). Pairs with the text_indopak_nastaleeq field. Falls back to
   Scheherazade New while loading or offline so verses always render. ---- */
@font-face {
  font-family: 'IndoPak';
  src: url('https://verses.quran.foundation/fonts/quran/hafs/nastaleeq/indopak/indopak-nastaleeq-waqf-lazim-v4.2.1.woff2') format('woff2'),
       url('https://verses.quran.foundation/fonts/quran/hafs/nastaleeq/indopak/indopak-nastaleeq-waqf-lazim-v4.2.1.woff') format('woff');
  font-display: swap;
}

/* ---- Design tokens — the single source of truth for motion, spacing, radii and semantic colour.
   The whole app can lean on these so it feels cohesive (not hand-tuned per element), and the colour
   roles are what Phase 2 (dark mode) swaps in a single [data-theme="dark"] block. ---- */
:root {
  color-scheme: light;   /* browser-default surfaces (canvas during repaint, scrollbars, form controls) follow the theme → no white flash */
  /* Seerah fonts: a literary serif for the Roman-Urdu body; Amiri for ﷺ/Arabic/titles */
  --font-seerah: 'Spectral', 'Scheherazade New', Georgia, 'Times New Roman', serif;
  --font-arabic: 'Amiri', 'Scheherazade New', serif;
  /* Motion */
  --ease-emphasized: cubic-bezier(.22, .68, .16, 1);
  --ease-standard: cubic-bezier(.4, 0, .2, 1);
  --dur-fast: 120ms;
  --dur: 200ms;
  --dur-slow: 300ms;
  /* Spacing (4/8 grid) */
  --sp-1: 4px; --sp-2: 8px; --sp-3: 12px; --sp-4: 16px; --sp-5: 20px; --sp-6: 24px;
  /* Radii */
  --r-sm: 10px; --r: 14px; --r-lg: 18px; --r-xl: 22px;
  /* Semantic colours — LIGHT values are the app's exact existing hexes, so migrating an inline colour to
     its var() leaves light mode pixel-identical. Dark mode is then a single [data-theme="dark"] swap below. */
  --c-bg: #F3EEE1;          /* app background (warm paper) */
  --c-surface: #FFFDF8;     /* cards / sheets */
  --c-surface-2: #F0EEE4;   /* inset / elevated paper (inputs, skeletons, alt rows) */
  --c-text: #15211C;        /* primary text */
  --c-text-2: #2C3A34;      /* secondary strong text */
  --c-text-soft: #5A655F;   /* soft body text */
  --c-muted: #616B63;       /* muted labels — darkened to clear WCAG-AA 4.5:1 on the paper bg (outdoor/older users) */
  --c-faint: #5F6A62;       /* faint / placeholder — darkened to ~4.5:1 AA on paper/inputs (was #79837B, 3.4–3.9:1) */
  --c-border: #EDE8DD;      /* hairline borders */
  --c-border-2: #D9D4C8;    /* tracks / dividers */
  --c-accent: #0F6957;      /* brand green — FOREGROUND use (text/icons/borders). Green BACKGROUNDS stay hardcoded. */
  --c-accent-deep: #0A4636;
  --c-soft: #E7F0EC;        /* soft green tint background (chips, icon wells) */
  --c-danger: #C8593F;      /* favourite heart / destructive / warning */
  --c-danger-soft: #FBEAE4; /* soft red tint background */
  --c-gold: #B68A3E;        /* "popular" / authenticity gold */
  --c-gold-soft: #FAF1D9;   /* soft gold tint background */
  --c-glass: rgba(255,255,255,.95);   /* frosted/blurred surfaces: bottom nav, audio bars */
  --c-glass-bg: rgba(245,242,234,.94);/* frosted sticky headers/footers (page-background tint) */
  /* DEPTH & FINISH (mockup): two-layer shadows = a tight contact shadow + a soft ambient lift, so cards read as
     genuinely raised paper instead of one flat drop. --c-hairline is a translucent warm hairline (mockup --line)
     that sits over any surface without the hard edge an opaque #EDE8DD gives. Color/shadow tokens are perf-free. */
  --c-shadow-card: 0 1px 2px rgba(22,40,30,.05), 0 10px 28px -14px rgba(22,40,30,.16);
  --c-shadow-tile: 0 1px 2px rgba(22,40,30,.04), 0 7px 18px -10px rgba(22,40,30,.18);
  --c-hairline: rgba(26,38,32,.09);
  --c-brass-line: rgba(156,122,46,.55);
}

/* ---- Dark / night mode — a deep, warm green-charcoal (for Fajr/Isha in the dark). Reverent, not pure black.
   Brand-green BACKGROUNDS (hero, primary buttons) stay green with white text in both themes by design. ---- */
[data-theme="dark"] {
  color-scheme: dark;
  --c-bg: #0E1311;
  --c-surface: #181E1B;
  --c-surface-2: #1F2723;
  --c-text: #EAF0EC;
  --c-text-2: #C6D1CB;
  --c-text-soft: #9BA8A1;
  --c-muted: #8B968D;
  --c-faint: #8A938C;       /* brightened to clear AA on the dark surfaces (was #69726B, 3.4:1) */
  --c-border: #29302C;
  --c-border-2: #333B36;
  --c-accent: #33B98D;       /* brightened so green text/icons stay legible on dark surfaces */
  --c-accent-deep: #2A9D78;
  --c-soft: #15302A;
  --c-danger: #E8765C;
  --c-danger-soft: #36201B;
  --c-gold: #D2AC5A;
  --c-gold-soft: #312A18;
  --c-glass: rgba(20,26,23,.92);
  --c-glass-bg: rgba(14,19,17,.94);
  /* Dark counterparts: deeper, darker ambient layers (mockup dark --shadow-card/--shadow-hero) so cards still
     lift off the green-charcoal bg; hairline brightens to a faint warm white; brass line stays luminous. */
  --c-shadow-card: 0 1px 2px rgba(0,0,0,.32), 0 14px 32px -16px rgba(0,0,0,.62);
  --c-shadow-tile: 0 1px 2px rgba(0,0,0,.34), 0 9px 22px -12px rgba(0,0,0,.6);
  --c-hairline: rgba(255,255,255,.08);
  --c-brass-line: rgba(210,172,90,.5);
}
/* Smoothly cross-fade colours when the theme flips (not on every inline change — only the themed props). */
[data-theme] .screen, [data-theme] #app { transition: background-color var(--dur) ease; }

/* ---- Global resets ---- */
* {
  box-sizing: border-box;
  -webkit-tap-highlight-color: transparent;
}
html, body {
  margin: 0;
  padding: 0;
  /* Root surface matches the active theme so it can NEVER flash white through #app during a full
     re-render (e.g. tapping a bottom tab in dark mode). The dark .screen used to be the only dark
     layer; the browser-default white root showed for one frame on each innerHTML swap. */
  background-color: var(--c-bg);
}
body {
  font-family: Manrope, sans-serif;
}

/* Hide scrollbars on the scrolling regions (matches the design) */
.noor-scroll::-webkit-scrollbar { display: none; }
.noor-scroll {
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;   /* momentum scrolling on iOS */
  overscroll-behavior: contain;        /* don't bleed rubber-band to the page / pull-to-refresh */
}
/* Promote the single main vertical scroller to its own compositor layer so a fling is a cheap layer
   translate on low-end Android (don't lean on the browser's conservative low-end layer heuristics).
   translateZ(0) is preferred over a permanent will-change:transform (no standing memory cost). SAFE: the
   bottom nav + audio dock are SIBLINGS of #scroller, not descendants, so the new containing block can't
   shift them; sticky bars inside the scroller still anchor correctly. Scoped to #scroller alone (NOT every
   .noor-scroll) to avoid layer-proliferation on the short horizontal rails. */
#scroller { transform: translateZ(0); }
/* iOS auto-zooms when a focused input's font-size is < 16px. 16px floor prevents the
   jarring zoom-and-shift; larger inline sizes (OTP code field etc.) still win. */
input, textarea, select { font-size: 16px; }
/* Placeholders must read as faint HINTS, never like a real entry. Inputs can be bold/dark (e.g. the
   sign-up phone field is font-weight:700 / --c-text), and a placeholder otherwise INHERITS that weight —
   so "98765 43210" looked like a typed number. Force a light weight + faint colour (opacity:1 so Firefox's
   default placeholder fade doesn't double up). */
input::placeholder, textarea::placeholder { color: var(--c-faint); font-weight: 500; opacity: 1; }
/* Tafsir (verse commentary) panel — styles the HTML quran.com returns (headings, paragraphs). */
.noor-tafsir { font-size: 13.5px; line-height: 1.75; color: var(--c-text-soft); font-weight: 500; }
.noor-tafsir h1, .noor-tafsir h2, .noor-tafsir h3 { font-size: 14.5px; font-weight: 800; color: var(--c-text); margin: 15px 0 7px; line-height: 1.4; }
.noor-tafsir h1:first-child, .noor-tafsir h2:first-child, .noor-tafsir h3:first-child { margin-top: 0; }
.noor-tafsir p { margin: 0 0 10px; }
.noor-tafsir p:last-child { margin-bottom: 0; }
.noor-tafsir b, .noor-tafsir strong { color: var(--c-text); font-weight: 800; }
.noor-tafsir-ur { direction: rtl; text-align: right; font-family: 'Noto Nastaliq Urdu', serif; line-height: 2.45; font-size: 15px; }
/* Disabled controls (e.g. the Listen seek bar while a surah is buffering) read as inactive. */
input[disabled] { opacity: .5; cursor: not-allowed; }

/* ---- Animations ---- */
@keyframes noorAzSlide {
  from { opacity: 0; transform: translateY(18px); }
  to { opacity: 1; transform: translateY(0); }
}
@keyframes noorPulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50%      { opacity: .4; transform: scale(.8); }
}
@keyframes noorFade {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}
@keyframes noorSpin { to { transform: rotate(360deg); } }
/* Skeleton placeholders gently pulse while content loads (opacity-only = cheap on low-end). */
@keyframes noorSkel { 0%, 100% { opacity: 1; } 50% { opacity: .55; } }
/* Tasbih: a calm "set complete" swell on the count circle each time 33 is reached (reverent, not confetti). */
@keyframes noorTasbihDone {
  0%   { transform: scale(1);    box-shadow: 0 26px 54px -22px rgba(11,70,54,.75); }
  40%  { transform: scale(1.06); box-shadow: 0 26px 60px -18px rgba(17,121,106,.95), 0 0 0 10px rgba(17,121,106,.12); }
  100% { transform: scale(1);    box-shadow: 0 26px 54px -22px rgba(11,70,54,.75); }
}

/* Quran quick-action: a slow gold "light" travelling around the icon-box border — draws the eye to the word
   of Allah, intuitively, without shouting. Sweeps a conic gradient via @property (the element never rotates,
   so no corner poke-out), masked to just the ~1.6px ring. The static gold border underneath is always there,
   so unsupported browsers / reduce-motion / lite-mode just see a refined gold border (no animation). */
@property --noor-ring-angle { syntax: '<angle>'; initial-value: 0deg; inherits: false; }
/* The Quran tile's living border: a golden trail circling CLOCKWISE led by a bright point of white "noor".
   We rotate the conic-gradient's start ANGLE (not the element) so the rounded-square border shape stays put;
   @property registers the angle as an <angle> so it interpolates smoothly (without it the rotation jumps). */
@keyframes noorRingSweep { to { --noor-ring-angle: 360deg; } }
.noor-quran-ring { position: relative; --noor-ring-angle: 0deg; }
.noor-quran-ring::before {
  content: ''; position: absolute; inset: -0.5px; border-radius: inherit; padding: 2px; pointer-events: none;
  background: conic-gradient(from var(--noor-ring-angle),
    rgba(232,190,99,0) 0deg,
    rgba(232,190,99,.42) 72deg,
    #E2B65C 150deg,
    #F4DEA0 208deg,
    #FFFFFF 247deg,
    #FFFFFF 260deg,
    rgba(244,222,160,.55) 288deg,
    rgba(232,190,99,0) 322deg);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
  animation: noorRingSweep 7s linear infinite;
  /* The home re-renders every second (the countdown), which recreates this tile and would restart the spin.
     --ring-delay is set inline from the global clock (negative delay) so each new ring RESUMES its phase. */
  animation-delay: var(--ring-delay, 0s);
}
/* The white "noor" head glows: a co-rotating second ring carrying only the bright lead point, softly blurred.
   Capable devices when idle only — dropped during scroll / lite so it never costs a low-end scroll frame. */
.noor-quran-ring::after {
  content: ''; position: absolute; inset: -1.5px; border-radius: inherit; padding: 3px; pointer-events: none;
  background: conic-gradient(from var(--noor-ring-angle), transparent 240deg, rgba(255,255,255,.95) 253deg, transparent 267deg);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
  filter: blur(2.5px);
  animation: noorRingSweep 7s linear infinite;
  animation-delay: var(--ring-delay, 0s);
}
body.noor-lite .noor-quran-ring::after, body.noor-scrolling .noor-quran-ring::after { display: none; }
@media (prefers-reduced-motion: reduce) { .noor-quran-ring::before { display: none; } }

/* The prayer-ring centre flips like a watch face: front = "time left", back = a live analogue clock. A slow
   alternation (each face ~5.5s) makes the card feel alive without nagging. transform-only (compositor-cheap);
   --flip-delay (global-clock negative delay, 13s period) keeps it continuous across the 1s countdown
   re-renders, exactly like --ring-delay. Disabled under lite / reduced-motion (just shows the time-left face). */
.noor-flip { perspective: 340px; }
.noor-flip-inner { position: absolute; inset: 0; transform-style: preserve-3d; animation: noorFlip 16s ease-in-out infinite; animation-delay: var(--flip-delay, 0s); }
.noor-flip-face { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; -webkit-backface-visibility: hidden; backface-visibility: hidden; }
.noor-flip-back { transform: rotateY(180deg); }
@keyframes noorFlip { 0%, 42% { transform: rotateY(0deg); } 50%, 92% { transform: rotateY(180deg); } 100% { transform: rotateY(360deg); } }
body.noor-lite .noor-flip-inner { animation: none; }
@media (prefers-reduced-motion: reduce) { .noor-flip-inner { animation: none; } }
body.noor-lite .noor-quran-ring::before { display: none; }
/* Pause continuously-repainting animations while the user scrolls — eliminates scroll jank on slower
   devices (set/cleared by JS via body.noor-scrolling). They resume the moment scrolling stops. */
body.noor-scrolling .noor-quran-ring::before { animation-play-state: paused; }
body.noor-scrolling [style*="noorGlow"] { animation-play-state: paused; }
/* SCROLL/LOW-END GPU WIN (audit, v99): a backdrop-filter:blur must re-sample + Gaussian-blur the pixels
   behind it every frame its backdrop changes — and the backdrop IS the scrolling content, so the glass
   bottom nav's blur(20px) plus the audio docks / sticky bars all re-blur on EVERY scroll frame. That is
   the dominant scroll stutter on low-end GPUs. Drop the blur while actively scrolling AND permanently in
   lite-mode; every such surface is already ≥92% opaque (var(--c-glass)/--c-glass-bg), so it stays the same
   translucent fill — just flat — and the blur snaps back the instant scrolling settles (~180ms idle).
   !important is REQUIRED: the blurs are INLINE styles (app.js), and inline beats a plain stylesheet rule. */
body.noor-scrolling .noor-bottomnav,
body.noor-lite .noor-bottomnav {
  -webkit-backdrop-filter: none !important;
  backdrop-filter: none !important;
  background: var(--c-glass) !important;
}
body.noor-scrolling [style*="backdrop-filter"],
body.noor-lite [style*="backdrop-filter"] {
  -webkit-backdrop-filter: none !important;
  backdrop-filter: none !important;
}
@media (prefers-reduced-motion: no-preference) { .noor-skel { animation: noorSkel 1.4s ease-in-out infinite; } }
body.noor-lite .noor-skel { animation: none; }
/* Girih texture overlay on the dark-green hero / Majlis cards (references #noorGirih in index.html). Sits
   behind the card content (DOM order, no z-index needed — same as the existing decorative circles), one
   tiled paint. ADAPTIVE: dropped entirely on low-end (noor-lite) so cheap Androids pay nothing for it. */
.noor-girih { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; opacity: .5; }
body.noor-lite .noor-girih, body.noor-lite .noor-girih-c { display: none; }   /* .noor-girih-c = corner star watermark (verse card) */
/* Gentle glow pulse on the hero countdown in the last 10 min before adhan (opacity-only = cheap on low-end). */
@keyframes noorGlow { 0%, 100% { opacity: 1; } 50% { opacity: .8; } }

/* ---- World-class scroll: list items gently rise + fade as they scroll into view. Pure CSS scroll-driven
   animation (animation-timeline: view()) — NO JavaScript, GPU-only (transform/opacity), and crucially it's
   driven by SCROLL POSITION not a one-shot timer, so it survives the app's frequent innerHTML re-renders
   without flicker (a rebuilt item that's already in view snaps straight to its end state). Where the API
   isn't supported (older Safari/Firefox) the element is simply fully visible — never stuck hidden. ---- */
@keyframes noorReveal { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .noor-reveal {
      animation: noorReveal linear both;
      animation-timeline: view();
      animation-range: entry 1% entry 30%;   /* reveal across the first third of the item's entry */
    }
  }
}
/* Low-end / save-data devices and reduced-motion: no scroll animation, always fully visible. */
body.noor-lite .noor-reveal { animation: none !important; opacity: 1 !important; transform: none !important; }
/* During an active fling, also pause the per-item reveal on capable (non-lite) devices — it drives a
   transform/opacity timeline on every visible card; snapping each to its current progress (same pattern as
   the ring above) frees the compositor for the scroll itself. Resumes the instant scrolling stops. */
body.noor-scrolling .noor-reveal { animation-play-state: paused !important; }

/* ---- Smooth screen transitions (View Transitions API) + tap feedback ---- */
@media (prefers-reduced-motion: no-preference) {
  /* Navigations cross-fade with a gentle upward drift on the incoming view. */
  ::view-transition-old(root) { animation: noorVtOut var(--dur-fast) ease both; }
  ::view-transition-new(root) { animation: noorVtIn var(--dur-slow) var(--ease-emphasized) both; }

  /* Tactile press feedback on every tappable element — a subtle whole-element depress (cards included)
     plus a firmer squeeze on buttons. Uses the shared motion tokens so the whole app presses alike. */
  [data-act] { transition: opacity var(--dur-fast) ease, transform var(--dur-fast) var(--ease-emphasized); }
  [data-act]:active { opacity: .72; transform: scale(.99); }
  button[data-act]:active { transform: scale(.955); opacity: .92; }
}
@keyframes noorVtIn  { from { opacity: 0; transform: translateY(9px) scale(.995); } to { opacity: 1; transform: none; } }
@keyframes noorVtOut { from { opacity: 1; } to { opacity: 0; } }

/* Respect users who prefer reduced motion */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .001ms !important; animation-iteration-count: 1 !important; transition-duration: .001ms !important; }
  .noor-pulse-dots span { opacity: .7; }
  ::view-transition-group(*), ::view-transition-old(*), ::view-transition-new(*) { animation: none !important; }
}
/* "Lite mode" — applied by JS (body.noor-lite) on slow/offline networks (and save-data) so the
   app feels instant on weak links / low-end devices: no animations, no press transitions. */
body.noor-lite *, body.noor-lite *::before, body.noor-lite *::after { animation-duration: .001ms !important; animation-iteration-count: 1 !important; transition-duration: .001ms !important; }
body.noor-lite ::view-transition-group(*), body.noor-lite ::view-transition-old(*), body.noor-lite ::view-transition-new(*) { animation: none !important; }

/* ---- Stage: warm-paper backdrop ---- */
.stage {
  min-height: 100vh;
  min-height: 100dvh;   /* track iOS Safari's dynamic viewport */
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: radial-gradient(120% 120% at 50% 0%, #E4E1D8 0%, #D6D3CA 100%);
  padding: 32px 16px;
  font-family: Manrope, sans-serif;
}

/* ---- Phone frame ---- */
.phone {
  width: 412px;
  height: 892px;
  max-height: calc(100vh - 24px);
  max-height: calc(100dvh - 24px);   /* iOS dynamic viewport — keeps the bottom nav visible under Safari's toolbar */
  background: #111312;
  border-radius: 56px;
  padding: 13px;
  box-shadow: 0 50px 90px -30px rgba(20, 30, 26, .55), 0 0 0 1px rgba(0, 0, 0, .4);
  position: relative;
}
.notch {
  position: absolute;
  top: 13px;
  left: 50%;
  transform: translateX(-50%);
  width: 120px;
  height: 30px;
  background: #111312;
  border-radius: 0 0 18px 18px;
  z-index: 40;
}
.screen {
  width: 100%;
  height: 100%;
  background: var(--c-bg);
  border-radius: 44px;
  overflow: hidden;
  position: relative;
  display: flex;
  flex-direction: column;
}

/* ---- Status bar ---- */
.statusbar {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 52px;
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  padding: 0 30px 8px;
  z-index: 30;
  pointer-events: none;
}
.statusbar-time {
  font-size: 15px;
  font-weight: 700;
  color: var(--c-text);
  letter-spacing: -.2px;
}
.statusbar-icons {
  display: flex;
  align-items: center;
  gap: 7px;
  color: var(--c-text);
}

/* ---- App mount: fills the screen below the status bar ---- */
#app {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 0;
  position: relative;
}

/* Real devices (any TOUCH screen — phones, foldables, tablets) get a true full-screen, edge-to-edge
   app: no phone-frame mock, no notch. Detect by pointer/hover — this catches large phones and unfolded
   foldables whose logical width exceeds any breakpoint (the old `max-width: 480px`-only rule left them
   showing the desktop phone-frame "inside" the display). A width/landscape fallback covers narrow
   non-touch windows. Desktop (fine pointer, wide) keeps the centred phone-frame preview. dvh tracks the
   mobile browser's dynamic viewport so the bottom nav isn't hidden behind the address bar. */
@media (pointer: coarse), (hover: none), (max-width: 600px), (orientation: landscape) and (max-height: 600px) {
  .stage { padding: 0; align-items: stretch; background: var(--c-bg); }
  .phone {
    width: 100%;
    height: 100vh;        /* fallback */
    height: 100dvh;       /* tracks the visible viewport on mobile */
    /* Fill the ENTIRE screen on every touch device — phones, AND unfolded foldables / tablets. No cap,
       no left/right gutters (founder's call: use all the width rather than a centred column). */
    max-width: none;
    max-height: none;     /* fill the device fully — drop the desktop 24px gutter */
    margin: 0 auto;
    border-radius: 0;
    padding: 0;
  }
  .notch { display: none; }
  /* Inset content out of the notch / Dynamic Island / side-notch in a standalone PWA.
     In a Safari tab these insets are 0, so there's no change there. The bottom nav and
     full-screen players handle their own safe-area-inset-bottom, so .screen omits it. */
  .screen {
    border-radius: 0;
    padding-top: env(safe-area-inset-top);
    padding-left: env(safe-area-inset-left);
    padding-right: env(safe-area-inset-right);
  }
  /* Anchor the bottom nav to the VISIBLE viewport bottom (fixed), not the dvh/vh box. This
     prevents the nav "sinking" below the mobile address bar on first load / before the
     browser toolbar settles (absolute+bottom:0 was relative to a momentarily-too-tall #app).
     Scoped to mobile only — the desktop phone-mock keeps the inline position:absolute. */
  .noor-bottomnav {
    position: fixed !important;
    left: 0;
    right: 0;
    bottom: 0;
    max-width: none;
    margin-left: auto;
    margin-right: auto;
  }
  /* Same fix for the audio player (full + mini): anchor to the VISIBLE viewport so it can't sink
     below the bottom before the mobile address bar settles (the absolute+bottom box was momentarily
     measured against a too-tall #app). Desktop keeps the inline position:absolute (mock intact). */
  .noor-audio-full {
    position: fixed !important;
    left: 0;
    right: 0;
    max-width: none;
    margin-left: auto;
    margin-right: auto;
  }
  .noor-audio-mini {
    position: fixed !important;
    max-width: none;
    margin-left: auto;
    margin-right: auto;
  }
}

/* ============ Seerah reader (Ar-Raheequl Makhtoom — Roman Urdu) ============ */
.seerah-cover{ position:relative; overflow:hidden; padding:60px 30px 50px; text-align:center;
  background:radial-gradient(120% 90% at 50% -10%, #15806B 0%, #0F6957 38%, #0A4636 78%, #073227 100%); color:#fff; }
.seerah-cover::after{ content:''; position:absolute; left:0; right:0; bottom:0; height:120px;
  background:linear-gradient(to bottom, rgba(7,50,39,0) 0%, var(--c-bg) 100%); pointer-events:none; }
.seerah-foil{ background:linear-gradient(100deg,#9E7B2E,#C9A24B 22%,#F4E3A8 48%,#C9A24B 74%,#9E7B2E);
  -webkit-background-clip:text; background-clip:text; -webkit-text-fill-color:transparent; color:#C9A24B; text-shadow:0 1px 0 rgba(0,0,0,.18); }
.seerah-cta{ display:inline-flex; align-items:center; justify-content:center; gap:9px; padding:15px 30px;
  background:linear-gradient(135deg,#E7CB82,#C9A24B 55%,#A9842F); color:#0A4636; font:800 15px Manrope,sans-serif; letter-spacing:.2px;
  border:none; border-radius:999px; cursor:pointer; box-shadow:0 14px 30px -12px rgba(201,162,75,.7), inset 0 1px 0 rgba(255,255,255,.45); }
.seerah-read{ padding:6px 22px 56px; }
.seerah-p{ margin:0 0 19px; font-family:var(--font-seerah); font-size:17px; line-height:1.78; letter-spacing:.1px; color:var(--c-text); font-weight:400; text-wrap:pretty; }
.seerah-p--first::first-letter{ font-family:var(--font-arabic); float:left; font-size:3.05em; line-height:.82; padding:6px 10px 0 0; color:var(--part-accent,var(--c-accent)); font-weight:700; }
.seerah-pull{ position:relative; margin:30px -6px; padding:28px 18px 22px; text-align:center; border-top:1px solid var(--c-border-2); border-bottom:1px solid var(--c-border-2); }
.seerah-pull::before{ content:'\201C'; position:absolute; top:1px; left:50%; transform:translateX(-50%); font-family:var(--font-arabic); font-size:46px; line-height:1; color:var(--part-accent,var(--c-accent)); opacity:.42; }
.seerah-pull-text{ margin:14px 0 0; font-family:var(--font-seerah); font-style:italic; font-size:20px; line-height:1.55; color:var(--c-text); font-weight:500; }
.seerah-pull-by{ margin:13px 0 0; font:700 11.5px Manrope,sans-serif; letter-spacing:.3px; color:var(--c-muted); text-transform:uppercase; unicode-bidi:plaintext; }
.seerah-saw{ font-family:var(--font-arabic); color:var(--c-gold); font-size:1.05em; padding:0 .04em; font-weight:400; }

/* ---- a11y: visible keyboard-focus ring for native AND custom (role="button" / tabindex / data-act)
   interactive elements. Uses :focus-visible so it only shows for keyboard/switch users, never on touch. ---- */
[data-act]:focus-visible, button:focus-visible, a:focus-visible, [tabindex]:focus-visible {
  outline: 3px solid var(--c-accent);
  outline-offset: 2px;
  border-radius: 6px;
}

/* ===== Compact-width tiers — slim phones (≤355px) and fold cover screens (≤300px). =====
   The app's layouts are fluid (1fr grids, flex:1 rows), so nothing overflows even at 280px —
   these tiers only shrink the few FIXED-size ornaments (quick-row icon boxes, header buttons)
   that outgrow their grid columns on very narrow screens, keeping gaps and tap targets honest.
   Inline styles require !important here — same precedent as the backdrop-filter overrides. */
@media (max-width: 355px) {
  .qr-ico { width: 50px !important; height: 50px !important; border-radius: 17px !important; }
}
@media (max-width: 300px) {
  .qr-ico { width: 42px !important; height: 42px !important; border-radius: 14px !important; }
  .hdr-btn { width: 38px !important; height: 38px !important; border-radius: 12px !important; }
  /* Reclaim gutter: the standard 18px side padding → 12px on fold-cover widths */
  #app [style*="padding:8px 18px"], #app [style*="padding:4px 18px"] { padding-left: 12px !important; padding-right: 12px !important; }
}

/* Grid-blowout guard (all widths): items in 1fr grid tracks default to min-width:auto, so a
   tile's content (icon box + label) can force its column wider and push the last column out on
   narrow screens. Letting items shrink keeps every 4-col/5-col grid honest down to 280px. */
#app [style*="repeat(4,1fr)"] > *, #app [style*="repeat(5,1fr)"] > * { min-width: 0; }

/* Bottom-sheet slide-up (Majlis options, Share, Report, Delete — all use .noor-sheet). Guarded by
   reduced-motion so it only animates for users who haven't asked for less motion. */
@keyframes noorSheetUp { from { transform: translateY(12%); opacity: .4; } to { transform: translateY(0); opacity: 1; } }
@media (prefers-reduced-motion: no-preference) {
  .noor-sheet { animation: noorSheetUp .28s cubic-bezier(.2,.85,.25,1); }
}
