/* --q-ui-scale - multiplies every UI text font-size across every
   .q-popover/menu in the app (button labels, dialog titles, status
   line, sliders...), never the actual Quran text itself (its own
   separate --q-arabic-scale/--q-mushaf-fit-scale). Used to be
   redeclared at 1.15 separately in .q-mushaf-frame (mushaf.css) and
   .q-surah-reading-frame (surah-player.css) only - own report: "renomme
   le en quelque chose pourque ca marche pour tout... a utiliser dans
   popover.css par exemple en commun" (also explains the name drop of
   its old "mushaf" prefix: nothing mushaf-specific about it, every page
   loading this file - home included - benefits the same way those 2
   already did). One :root default here instead, so base.html's own
   #q-panel-plus/.q-plus-menu (previously stuck at the un-scaled
   fallback, own report: "la font size... n'est pas comme /ar/s/X")
   gets it for free too, no frame class of its own needed. */
:root {
    --q-ui-scale: 1.15;
    /* Shared "..." menu shell width - /ar/s/X's own .q-surah-popover
       (surah-player.css) and home's own desktop html.q-open-plus
       .q-plus-menu (input.css) both reference this instead of each
       hardcoding the same 15rem literal (own report: "pourquoi c'est pas
       commun" - same reasoning as --q-ui-scale just above). */
    --q-menu-shell-width: 15rem;
    /* Own report: "l'espace entre les submenu et leur bouton declencheur
       n'est pas parfaitement egale a l'espace entre #q-panel-plus et son
       propre bouton, de meme pour le popover Durée" - 3 popovers, 3
       valeurs différentes (-1px, 2.5rem, 0.5rem) posées séparément au fil
       des sessions. Un seul chiffre ici, référencé par les 3 (own
       comment sur chacun) plutôt que 3 littéraux à garder synchronisés
       à la main. */
    --q-popover-trigger-gap: 0.5rem;
}

/* Generic popover chrome shared across pages (mushaf.css/surah-player.css
   both load this) - title + "✕" close button sharing one row. Not scoped
   to any one popover on purpose: every popover across the app that
   follows this same title+close pattern reuses these classes as-is
   rather than each page redeclaring its own near-identical copy (own
   report: surah-player.css used to duplicate this under a q-surah-
   prefix, same values by hand instead of guaranteed identical by
   definition - moved here, both pages load this file now). */
/* Own report: "il faut definir les variables comme --app-popover-border
   pour la home page ... ces themes ne sont applicables que dans leur
   pages ... la front page doit avoir des valeurs constantes" -
   surah-player.css/mushaf.css only ever set --app-popover-* under their
   own reading-frame theme attributes ([data-q-mushaf-theme][data-q-
   mushaf-mode], scoped to /ar/s/X/ and /ar/c/ only), so any OTHER page
   loading this file (home, search, downloads...) had these custom
   properties fully undefined - invalid at computed-value time, so every
   rule below using them silently dropped that one declaration instead
   of erroring. Real light/dark constants here, same "original" theme
   preset's own measured values as the reading pages' own default -
   this is the fallback every non-reading page actually uses; a reading
   page's own attribute selector still wins on its own page (higher
   specificity than this plain :root), so nothing here ever fights that
   theme system, it only fills the gap outside it. Same :root/prefers-
   color-scheme/[data-theme] structure as --app-bg & co (input.css). */
:root {
    --app-popover-bg: #eaeaea;
    --app-popover-text: #696969;
    --app-popover-divider: #d0d0d1;
    --app-popover-border: #d5d5d5;
    --app-popover-btn-text: #010102;
    --app-popover-btn-bg: #d9d9da;
}
@media (prefers-color-scheme: dark) {
    :root {
        --app-popover-bg: #202020;
        --app-popover-text: #9a9a9a;
        --app-popover-divider: #2f2f30;
        --app-popover-border: #4c4c4c;
        --app-popover-btn-text: #ffffff;
        --app-popover-btn-bg: #3c3c3f;
    }
}
:root[data-theme="light"] {
    --app-popover-bg: #eaeaea;
    --app-popover-text: #696969;
    --app-popover-divider: #d0d0d1;
    --app-popover-border: #d5d5d5;
    --app-popover-btn-text: #010102;
    --app-popover-btn-bg: #d9d9da;
}
:root[data-theme="dark"] {
    --app-popover-bg: #202020;
    --app-popover-text: #9a9a9a;
    --app-popover-divider: #2f2f30;
    --app-popover-border: #4c4c4c;
    --app-popover-btn-text: #ffffff;
    --app-popover-btn-bg: #3c3c3f;
}

/* --app-link reset for every popover/menu box - .q-mushaf-frame/.q-
   surah-reading-frame's own rule further below re-derives --app-link
   from --app-text (content links follow the reading palette, own
   comment there), but every .q-popover on /ar/s/X and /ar/c is nested
   *inside* that same scope in the DOM, so it inherited that content
   value too instead of the plain accent every popover elsewhere uses
   (own report: "le checkmark n'a pas la meme couleur que la home
   page"). .q-popover resets it back here, same literal values/4-tier
   structure as --app-link itself (input.css) - can't reference that
   token's own "outer" value once shadowed, so this duplicates the 2
   constants rather than being a genuine bug on non-reading pages too
   (a no-op override there, already the same value). */
.q-popover {
    --app-link: #1a0dab;
}
@media (prefers-color-scheme: dark) {
    .q-popover {
        --app-link: #99c3ff;
    }
}
:root[data-theme="light"] .q-popover {
    --app-link: #1a0dab;
}
:root[data-theme="dark"] .q-popover {
    --app-link: #99c3ff;
}
/* Même reset, mais seulement pour le thème de lecture "Neutre"
   (data-q-mushaf-theme="neutral") - own report: le bleu générique jure
   avec la palette des autres thèmes (Calme/warm notamment), "on fait
   pas un [bleu] pour chaque theme et on laisse ce bleu que pour le
   neutre" - chaque autre thème garde son --app-link recyclé depuis
   --app-text (déjà assorti à sa propre palette). Couvre .q-popover ET
   .q-surah-menu-submenu (pas de classe .q-popover commune aux deux
   pages - /ar/c scope sur .q-mushaf-frame, /ar/s/X sur
   html.q-surah-reading-frame, mêmes 4 valeurs littérales que le reset
   générique ci-dessus). */
.q-mushaf-frame[data-q-mushaf-theme="neutral"] .q-popover,
html.q-surah-reading-frame[data-q-mushaf-theme="neutral"] .q-popover,
html.q-surah-reading-frame[data-q-mushaf-theme="neutral"] .q-surah-menu-submenu {
    --app-link: #1a0dab;
}
@media (prefers-color-scheme: dark) {
    .q-mushaf-frame[data-q-mushaf-theme="neutral"] .q-popover,
    html.q-surah-reading-frame[data-q-mushaf-theme="neutral"] .q-popover,
    html.q-surah-reading-frame[data-q-mushaf-theme="neutral"] .q-surah-menu-submenu {
        --app-link: #99c3ff;
    }
}
:root[data-theme="light"] .q-mushaf-frame[data-q-mushaf-theme="neutral"] .q-popover,
html:root[data-theme="light"].q-surah-reading-frame[data-q-mushaf-theme="neutral"] .q-popover,
html:root[data-theme="light"].q-surah-reading-frame[data-q-mushaf-theme="neutral"] .q-surah-menu-submenu {
    --app-link: #1a0dab;
}
:root[data-theme="dark"] .q-mushaf-frame[data-q-mushaf-theme="neutral"] .q-popover,
html:root[data-theme="dark"].q-surah-reading-frame[data-q-mushaf-theme="neutral"] .q-popover,
html:root[data-theme="dark"].q-surah-reading-frame[data-q-mushaf-theme="neutral"] .q-surah-menu-submenu {
    --app-link: #99c3ff;
}
/* Même exception Neutre, mais sur <html> lui-même cette fois - own
   report ("l'icone ne devient pas active/pas la meme couleur que
   data-q-toggle=plus, au moins pour le theme neutre"): le reset
   générique plus bas (html:root.q-surah-reading-frame, own comment
   là-bas) retombe --app-link sur --app-text pour TOUT thème de lecture
   y compris Neutre - l'exception ci-dessus ne le corrige que dans un
   .q-popover déjà ouvert, jamais pour les boutons du <header> partagé
   eux-mêmes (sibling de .q-mushaf-frame, jamais un de ses descendants,
   depuis que ces boutons en sont sortis cette session) - donc leur état
   actif tombait sur un gris/--app-text au lieu du bleu attendu même en
   Neutre. Spécificité (html+:root+classe+attribut) bat déjà le reset
   générique (html+:root+classe seule) peu importe l'ordre des règles,
   pas besoin de :not() ici. */
html:root.q-surah-reading-frame[data-q-mushaf-theme="neutral"] {
    --app-link: #1a0dab;
}
@media (prefers-color-scheme: dark) {
    html:root.q-surah-reading-frame[data-q-mushaf-theme="neutral"] {
        --app-link: #99c3ff;
    }
}
html:root[data-theme="light"].q-surah-reading-frame[data-q-mushaf-theme="neutral"] {
    --app-link: #1a0dab;
}
html:root[data-theme="dark"].q-surah-reading-frame[data-q-mushaf-theme="neutral"] {
    --app-link: #99c3ff;
}
/* Inverse - tout thème de lecture *autre* que Neutre doit suivre sa
   propre palette (own report: "il faut que ca suit le theme"), pas le
   bleu générique ci-dessus. .q-popover a plus de poids que le reset
   générique (.q-popover seul, en haut) grâce à :not() ajoutant une
   classe d'ancêtre réelle à la spécificité - sans ça le reset générique
   gagnerait toujours (déjà posé sur .q-popover lui-même). */
.q-mushaf-frame:not([data-q-mushaf-theme="neutral"]) .q-popover,
html.q-surah-reading-frame:not([data-q-mushaf-theme="neutral"]) .q-popover,
html.q-surah-reading-frame:not([data-q-mushaf-theme="neutral"]) .q-surah-menu-submenu {
    --app-link: var(--app-text);
}
/* Exception - "Tranquille" (data-q-mushaf-theme="dark") en mode clair :
   son --app-text clair (#ebebf5, quasi blanc) est pensé pour SON propre
   fond sombre (#4a4a4d), pas pour le fond fixe du popover (#eaeaea) -
   quasi invisible une fois recyclé là (own report: "presque du blanc
   donc on le voit pas", contraste ~1:1, viole la règle AA de
   CLAUDE.md). --app-bg de ce même thème/mode (#4a4a4d, déjà posé par la
   règle plus haut) sert de repli foncé à la place - "le check ... doit
   etre un peu foncé" (own report), et déjà mesuré à bon contraste
   contre #eaeaea. Plus spécifique que la règle générale ci-dessus
   (attribut de mode en plus), donc gagne pour ce cas précis. */
.q-mushaf-frame[data-q-mushaf-theme="dark"][data-q-mushaf-mode="light"] .q-popover,
html.q-surah-reading-frame[data-q-mushaf-theme="dark"][data-q-mushaf-mode="light"] .q-popover,
html.q-surah-reading-frame[data-q-mushaf-theme="dark"][data-q-mushaf-mode="light"] .q-surah-menu-submenu {
    --app-link: #4a4a4d;
}
/* "Contraste élevé" (input.css's own :root[data-contrast="high"], same
   --app-border escalation) never reached this token - own report: menu/
   submenu borders (Réglages/#q-panel-plus and its Langue/Affichage
   flyouts on every page, own report: "meme dans front page") stayed
   flat regardless of the toggle, since .q-popover's own border (below)
   reads --app-popover-border, a fully separate token from --app-border,
   untouched by input.css's own rule. Same escalated grays input.css
   already picked for --app-border (#5c5c5c/#9a9a9a) - one consistent
   "this is what high contrast looks like" colour across every border
   token in the app instead of a 2nd pair invented here. Same 4-tier
   structure as every other contrast/theme rule in this file. */
:root[data-contrast="high"] {
    --app-popover-border: #5c5c5c;
    --app-popover-divider: #5c5c5c;
}
@media (prefers-color-scheme: dark) {
    :root[data-contrast="high"] {
        --app-popover-border: #9a9a9a;
        --app-popover-divider: #9a9a9a;
    }
}
:root[data-contrast="high"][data-theme="light"] {
    --app-popover-border: #5c5c5c;
    --app-popover-divider: #5c5c5c;
}
:root[data-contrast="high"][data-theme="dark"] {
    --app-popover-border: #9a9a9a;
    --app-popover-divider: #9a9a9a;
}

/* Rounded-card look (reference screenshot - iOS-style context menu).
   --app-popover-bg/-text (own real measured sRGB values per theme) - a
   separate palette from the reading page's own --app-bg/-text, not
   color-mix'd off --app-surface/--app-sub. Shared chrome for every
   popover/menu across the app - one consistent padding/radius/border/
   background/shadow, moved here (own report: "un composant popup...
   utilisé là où des popup vont être utilisé") instead of mushaf.css
   defining it for itself with surah_detail.html just along for the
   ride via its own <link>. */
.q-popover {
    padding: 0.375rem;
    border-radius: 16px;
    border: 1px solid var(--app-popover-border);
    background: var(--app-popover-bg);
    box-shadow: 0 8px 28px rgb(0 0 0 / 20%);
    font-size: calc(0.8125rem * var(--q-ui-scale, 1));
    color: var(--app-popover-text);
}
.q-popover-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    margin: 0 0 0.5rem;
    /* Same horizontal inset as .q-popover-item's own 0.5rem padding
       (mushaf.css) on the title's side only - the close button's own
       circular hit target stays flush against the popover's own base
       0.375rem padding instead (asked for explicitly), rather than
       pushed in by an extra 0.5rem it doesn't need. */
    padding-inline-start: 0.5rem;
}
.q-popover-title {
    margin: 0;
    font-size: calc(0.75rem * var(--q-ui-scale, 1));
    font-weight: 600;
    color: var(--app-popover-text);
}
/* Explicit close button next to every popover's own title - not just
   relying on Escape/outside-click. Small enough it doesn't compete with
   the title, but still a real >=24px hit target via padding, not just
   the visible icon's own size. One of the "Bouton" chip-chrome elements
   (--app-popover-btn-bg/-text). Also reused, unstyled, as the small
   round icon-button look for other per-row delete buttons (bookmarks/
   notes/recent searches, mushaf.js) elsewhere in the app. */
.q-popover-close {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    padding: 0.25rem;
    border-radius: 999px;
    background: var(--app-popover-btn-bg);
    color: var(--app-popover-btn-text);
}
.q-popover-close:hover:not(:disabled),
.q-popover-close:focus-visible {
    background: color-mix(in srgb, var(--app-popover-btn-text) 12%, var(--app-popover-btn-bg));
}
.q-popover-close:focus-visible {
    outline: 2px solid var(--app-link);
    outline-offset: 1px;
}
/* Own report: hx-disabled-elt joins a close button on some pages (e.g.
   surah_detail.html's #surah-reading-script) - same opacity/pointer-
   events convention as every other disabled control in the app. */
/* Shared scrolling-body piece of the same header/body pattern as
   .q-popover-head above (own report: "il y a un style en commun pour
   les popup avec header, body et footer, comme q-mushaf-surah-popover" -
   that popover's own mobile layout already splits its title from its
   scrolling list this way, own comment in surah-player.css; this is
   that same split promoted to a real shared class instead of a 2nd,
   id-scoped copy of the same flex-child rules per popover). Marks
   whichever element is the actual scrolling region of a popover (a
   list, a tile grid...) so its own head/search stay outside the scroll
   and only this part moves - parent needs display:flex;flex-direction:
   column;overflow:hidden for this flex-sizing to take effect, inert
   otherwise (e.g. a popover whose outer box scrolls as a whole, no
   flex column split). */
.q-popover-body {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
}
.q-popover-close:disabled {
    opacity: 0.5;
    pointer-events: none;
}
/* Moved here from mushaf.css (own report: "meme structure et meme
   class css" - #q-mushaf-surah-popover's own mobile bottom-sheet reuses
   this exact class now too, not a 2nd copy under a q-surah- prefix).
   Dims the page behind whichever mobile sheet is open - :not([hidden])
   rather than a plain unconditional rule, same reasoning as mushaf.css's
   own comment on its sibling .q-mushaf-mobile-menu-logo/-menu rules
   (this file loads after tailwind.css's own preflight [hidden] reset,
   an unconditional display could otherwise win the cascade on source
   order alone and never actually hide). */
.q-mushaf-mobile-menu-backdrop:not([hidden]) {
    position: fixed;
    inset: 0;
    background: rgb(0 0 0 / 45%);
    z-index: 40;
}
@media (min-width: 1024px) {
    .q-mushaf-mobile-menu-backdrop {
        display: none !important;
    }
}
/* Moved here from mushaf.css too, same report - the mobile bottom-sheet
   shell itself. mushaf.html's own trigger only ever shows this below
   1024px (desktop keeps the separate hover-corner icons instead), so
   the original rule never needed its own max-width gate, just the
   :not([hidden]) attribute selector for specificity (0,2,0) plus a
   min-width:1024px !important backstop against a resize-while-open
   edge case. surah_detail.html's own shell (data-q-mushaf-surah-shell)
   reuses this exact class too, same reasoning: its own trigger stays
   visible at every width (unlike mushaf.html's, hidden outright at
   desktop), so this box needs a real max-width gate of its own rather
   than relying on the trigger already being gone above 1024px. */
@media (max-width: 1023px) {
    .q-mushaf-mobile-menu:focus {
        outline: none;
    }
    /* Own report ("des elements ne s'affichent que si il y a des
       données, le menu doit grandir, pas scroller") - Notes/Signets
       pills (updateMobileListVisibility, mushaf.js) apparaissent/
       disparaissent selon le contenu réel, donc ce menu est plus court
       la plupart du temps que son ancien max-height:70vh fixe -
       [data-q-mushaf-mobile-list]'s own overflow-y:auto (plus bas)
       créait un scroll interne dès que le contenu dépassait cette
       hauteur fixe au lieu de simplement grandir avec lui. max-height
       remonté à une limite haute (garde-fou réel seulement, jamais
       atteint par les ~9 pills possibles) - overflow:hidden -> auto ici
       à la place, un seul scroll de secours sur la boîte entière plutôt
       qu'un 2e cadre interne. */
    .q-mushaf-mobile-menu:not([hidden]) {
        position: fixed;
        left: 0.75rem;
        right: 0.75rem;
        bottom: calc(env(safe-area-inset-bottom, 0px) + 0.75rem);
        z-index: 41;
        display: flex;
        flex-direction: column;
        gap: 0.5rem;
        max-height: calc(100dvh - 1.5rem);
        overflow-y: auto;
        padding: 0.75rem;
        border-radius: 20px;
        border: 1px solid var(--app-popover-border);
        background: var(--app-popover-bg);
        box-shadow: 0 8px 28px rgb(0 0 0 / 20%);
    }
}
@media (min-width: 1024px) {
    .q-mushaf-mobile-menu {
        display: none !important;
    }
}
/* Own report: "il reste un léger delta" - .q-mushaf-mobile-menu's own
   gap:0.5rem above already spaces every direct child; its own head
   (_popover_head.html, shared with surah_detail.html's own shell too)
   also carries its own margin-bottom:0.5rem (used elsewhere without a
   flex gap to double up against) - zeroed here so the flex gap stays
   the single source of that spacing, not stacked on top of it. */
.q-mushaf-mobile-menu > .q-popover-head {
    margin-bottom: 0;
}

/* ===== Moved from mushaf.css (own report: "on créer un fichier popup qui va avoir les trucs en commun") - every popup/panel row, list, and Thèmes-panel control shared between mushaf.html and surah_detail.html now lives here, not duplicated or borrowed cross-file. ===== */


/* "Intensité" dimming scrim (mushaf.html/mushaf.js applyMushafBrightness) -
   plain opacity, not filter:brightness() on .q-mushaf-frame (see
   mushaf.html's own comment on why - clipped popover colours to white at
   low Intensité). Opacity set inline per value by JS, 0 by default (no-op
   before that first call). -1px inset (not 0) so it also dims the frame's
   own 1px --app-border, not just its padding-box content. Border-radius
   matches .q-mushaf-frame's own 12px (below) - this box isn't clipped by
   the frame (no overflow:hidden there), so it needs its own rounded
   corners to not paint square over the frame's rounded ones. */
.q-mushaf-dim-scrim {
    position: absolute;
    inset: -1px;
    border-radius: 12px;
    background: #000;
    opacity: 0;
    pointer-events: none;
}
/* surah_detail.html's own copy of this scrim (own comment there) has no
   positioned ancestor to size against (neither <main> nor <body> set
   `position` here) - it falls back to the initial containing block (the
   viewport itself), so the -1px inset above (meant to bleed over
   .q-mushaf-frame's 1px border on /ar/c) instead made it 2px wider/
   taller than the viewport there, a static overflow real enough to
   survive `overflow-x:hidden` on html/body (iOS Safari still lets the
   rubber-band gesture reveal it) - own bug found live on an iPhone 13
   Pro (Safari Web Inspector, scrollWidth 391-392 vs clientWidth 390).
   No frame border to bleed over in this context, inset:0 is exactly
   right here. */
body:has(#q-karaoke-root) .q-mushaf-dim-scrim {
    inset: 0;
}

/* opacity:0 (own comment, mushaf.html) - forces a real layout+paint pass
   (unlike display:none/[hidden], which skips font shaping/rendering
   entirely) so each font's bold file (input.css @font-face) gets
   requested/cached once at page load, not the first time a reader
   actually toggles "Gras". */
.q-mushaf-bold-preload {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    opacity: 0;
    font-weight: 900;
    pointer-events: none;
}

/* Small corner menu (page-jump + Affichage shortcut) instead of a
   centered toolbar - same muted-icon/hover-fill treatment
   .q-header-menu-btn already uses elsewhere on the site, so it reads as
   "app chrome" rather than book content. Lives inside .q-mushaf-frame
   now, same top row as .q-mushaf-title, always on the frame's physical
   right - direction:ltr (not relying on inset-inline-end) so it never
   flips to the left for Arabic (dir=rtl) visitors, the site's own
   default language. Hidden until the frame is hovered, or one of these
   buttons themselves gets keyboard focus (:focus-within - so it's still
   reachable via Tab without a mouse, not hover-only chrome). */
/* Cancels frameEl's own filter:brightness() ("Intensité", mushaf.js) on
   every toolbar control - same brightness(100/pct) trick as
   .q-mushaf-jump-popover's own comment explains (nested filters
   multiply, so this exactly undoes the parent's dimming). Only actually
   live above 100% now (mushaf.js only sets frameEl's own filter for the
   single brighten step past default, --q-mushaf-brightness-pct pinned to
   100/no-op below that) - dimming below 100% is .q-mushaf-dim-scrim
   above instead (own comment on why), which never touches these controls
   in the first place, so there's nothing here left to cancel for that
   direction. Kept for the brighten side: these icon buttons (currentColor
   stroke, no filled background of their own) lost contrast fast without
   it - WCAG contrast ratio isn't linear in a uniform brightness scale, it
   collapses toward 1 as both foreground and background luminance shrink
   toward 0 together. Only the actual reading surface (frameEl's own
   --app-surface paper fill + slotEl's text) is meant to change with this
   setting - every *control* stays at full contrast, same reasoning as
   the popovers below. */
/* Scoped to .q-mushaf-brightened (mushaf.js applyMushafBrightness toggles
   it, only above 100%) rather than always-on - an unconditional `filter`
   here forced these 3 elements onto their own compositing layer on every
   visit regardless of the Intensité setting (even at the default 100%,
   where the computed value is a no-op brightness(1)), which is
   WebKit/Safari's own trigger for noticeably delayed :hover repaints on
   filtered elements - reported as the page-turn buttons' hover state
   lagging on Safari specifically. Below/at 100% now carries no filter at
   all, matching frameEl's own filter (mushaf.js) which was already gated
   the same way. */
.q-mushaf-frame.q-mushaf-brightened .q-mushaf-topleft,
.q-mushaf-frame.q-mushaf-brightened .q-mushaf-topright,
.q-mushaf-frame.q-mushaf-brightened .q-mushaf-edge-btn {
    filter: brightness(calc(100 / var(--q-mushaf-brightness-pct, 100)));
}

.q-mushaf-jump-popover {
    position: absolute;
    top: 3rem;
    /* Physical right (not inset-inline-end, which flips with dir) - its
       own trigger button (.q-mushaf-topright) is forced to the physical
       right the same way, for Arabic visitors. No direction:ltr here
       unlike that button row - `right` isn't direction-dependent to
       begin with, and this popover holds real text content (the search
       input, its placeholder) that needs to follow the page's actual
       direction, not be forced ltr like a row of icon buttons. */
    right: 3.5rem;
    z-index: 10;
    display: flex;
    flex-direction: column;
    width: 20rem;
    max-width: calc(100vw - 2rem);
}

/* Cancels frameEl's own filter:brightness() (mushaf.js
   applyMushafBrightness, "Intensité") - nested CSS filters multiply, so
   brightness(pct/100) on frameEl * brightness(100/pct) here == 1. Only
   actually live above 100% now: mushaf.js only ever sets frameEl's own
   filter for the single brighten step past default, pinning
   --q-mushaf-brightness-pct back to 100/no-op below that instead. Used
   to also run below 100% (dimming) - removed, because the compensating
   >1 factor that direction needs (100/70 = 1.43 at minimum) clips any
   popover colour already close to white *before* frameEl's own filter
   scales it back down, so near-white --app-popover-bg and
   --app-popover-btn-bg both clipped to the same pure white then dimmed
   identically - the popover's own "chip" buttons lost their background/
   border against it ("les boutons des popup ne sont plus clairs... leur
   bordure et background prennent la même couleur que le background du
   popup"). .q-mushaf-dim-scrim (top of this file) now handles dimming
   instead, structurally outside any filter these popovers sit under, so
   there's nothing left to compensate for that direction.
   Scoped to *direct* children of frameEl specifically, not just
   .q-mushaf-jump-popover alone - .q-mushaf-transition-popover/
   .q-mushaf-theme-mode-popover both carry that same class too but are
   nested *inside* the theme popover, not frameEl directly; that
   popover's own filter above already un-dims everything painted through
   it, nested popovers included, so giving them this same filter a
   second time would compound into a real over-brightening. */
.q-mushaf-frame.q-mushaf-brightened > .q-mushaf-jump-popover {
    filter: brightness(calc(100 / var(--q-mushaf-brightness-pct, 100)));
}

/* Same shared-border wrapper pattern as the header's own .q-header-search
   (base.html/tailwind.css) - input and submit button both borderless
   inside one rounded/bordered row, not each styled separately, so the
   focus ring reads as "this whole field", not just the text part. */
/* #q-mushaf-jump-popover specifically (own report) - not the shared
   .q-mushaf-jump-popover class (also carried by #q-mushaf-surah-popover
   for its own positioning/sizing), that one's own search field now
   reuses .q-surah-popover-search instead (canonical block further
   above) so it's styled 100% identically to surah_detail.html's own
   #q-mushaf-surah-popover, not a 2nd near-duplicate of this rule. */
#q-mushaf-jump-popover form {
    display: flex;
    align-items: center;
    border: 1px solid var(--app-border);
    border-radius: 6px;
    background: var(--app-bg);
}

#q-mushaf-jump-popover form:focus-within {
    border-color: var(--app-link);
}

#q-mushaf-jump-popover input {
    flex: 1;
    min-width: 0;
    border: 0;
    background: transparent;
    padding: 0.5rem 0.625rem;
    color: var(--app-text);
    font-size: calc(0.875rem * var(--q-ui-scale, 1));

}

#q-mushaf-jump-popover input:focus-visible {
    outline: none;
}

/* type="search" draws its own native "x" clear button in WebKit/Blink
   once there's text - redundant next to this popover's own search
   icon and not present at all on the plain type="text" jump-input this
   same rule already styles, so it read as an inconsistent extra
   control rather than a deliberate one. */
#q-mushaf-jump-popover input::-webkit-search-cancel-button {
    display: none;
}

/* Mirror of the jump popover above, physical left (its own trigger,
   .q-mushaf-topleft, is on that side) - same base look
   (.q-mushaf-jump-popover), just the opposite corner. */
.q-mushaf-surah-popover {
    left: 3.5rem;
    right: auto;
    width: 15rem;
}

/* Right-anchored, same default as .q-mushaf-jump-popover (its own
   trigger lives in .q-mushaf-topright, not topleft) - just narrower,
   2 short rows is all it ever holds. */
.q-mushaf-share-popover {
    width: 13rem;
}

/* Canonical popover list-row/menu-item look - a real class, meant to be
   added directly to markup anywhere a popover/menu needs a row (this
   page or elsewhere in the app), not just aliased in a growing list of
   selectors alongside whatever page-specific class happened to exist
   already. Every row on this page (Sourates, Signets, Notes,
   recherches récentes, résultats de recherche, Partager, Police,
   Animation, Apparence, the selection menu) uses this one class now -
   own comment in mushaf.html/.js on each. Base is block/full-width/
   start-aligned (a plain text row); .q-popover-item-icon (below) is
   the flex/gap modifier for icon+label rows or a 2-part row (content +
   its own delete button) - added alongside, not a different class
   family. */
.q-popover-item {
    display: block;
    width: 100%;
    text-align: start;
    padding: 0.5rem;
    border-radius: 0;
    color: var(--app-popover-text);
    font-size: calc(0.875rem * var(--q-ui-scale, 1));

    line-height: 1.5;
}
/* Own report: "redrend les elements apres le separateur desactivé jusqu'a
   ce que je choisi trier par quoi" (#q-plus-surah-sortby-submenu, own
   report) - même valeur que le groupe [disabled] de surah_list.html
   (pointer-events:none, opacity:0.5), scopé ici (popover.css, global) car
   ce menu vit dans base.html. */
.q-popover-item[disabled] {
    pointer-events: none;
    opacity: 0.5;
}

.q-popover-item:hover {
    /* color-mix against --app-popover-text, not the reading page's own
       --app-text - this is the popover chrome's own separate palette
       (mushaf.css [data-q-mushaf-theme][data-q-mushaf-mode] blocks). */
    background: color-mix(in srgb, var(--app-popover-text) 12%, transparent);
}

/* Own report: "on dirait un hover" - sleep-timer.js's own open() (and
   every other roving-tabindex radiogroup here) calls .focus() on the
   already-checked item as soon as the popover opens, no mouse involved -
   sharing :hover's own background wash made that look like a stuck
   hover state instead of "here's your keyboard focus". Outline alone
   still satisfies the a11y need (focus must stay visible), just doesn't
   read as a hover the user never triggered. */
.q-popover-item:focus-visible {
    outline: 2px solid var(--app-link);
    outline-offset: -2px;
}

.q-popover-item-icon {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.q-popover-item-icon svg {
    flex-shrink: 0;
    color: var(--app-popover-text);
}

/* Moved here from surah-player.css (own report: "meme structure, meme
   code html et class, meme css et meme js" - every "row with its own
   flyout submenu" widget uses these same classes now, not just
   surah_detail.html's own Récitant/Thèmes/Lecture/Partager rows -
   base.html's own Langue-inside-Réglages row too). */
.q-surah-menu-item {
    display: flex;
    align-items: center;
    justify-content: flex-start;
    gap: 0.5rem;
    width: 100%;
    padding: 0.5rem;
    border: none;
    background: transparent;
    color: var(--app-popover-text);
    font-size: calc(0.875rem * var(--q-ui-scale, 1));
    line-height: 1.5;
    text-align: start;
}
/* Own report: trigger row should stay in its own "hovered" look while
   its flyout is open, not just for the literal duration the pointer
   sits over it - aria-expanded (kept in sync by open()/close()) is the
   real "this row's submenu is showing" signal. */
.q-surah-menu-item:hover,
.q-surah-menu-item[aria-expanded="true"] {
    background: color-mix(in srgb, var(--app-popover-text) 12%, transparent);
    border-radius: 8px;
}
/* Own report: "en mobile les popover sont trop étroit... en desktop il y
   a un peu d'espace après le wording" - .q-surah-popover a une largeur
   shrink-to-fit sur ce type de menu (data-q-card-menu-wrap/initRowMenu,
   popover.js - JS pose left/right:auto en inline, jamais de width, donc
   la boîte prend juste la largeur de son contenu). Un min-width et un
   peu plus de padding sur mobile seulement donnent la même respiration
   qu'en desktop, sans toucher au desktop (déjà correct là). */
@media (max-width: 1023px) {
    .q-surah-popover {
        min-width: 13rem;
    }
    .q-surah-menu-item {
        padding: 0.625rem 0.875rem;
    }
}
/* Header disclosure button (Langue/Affichage/Récitant/Lecture,
   base.html) for whichever panel is currently open - aria-expanded is
   already kept in sync by __qSetPanelOpen (base.html JS) for every
   toggle, purely CSS from there. Same background/border/color/bold combo
   as the selected-choice states above (input.css), for one consistent
   "this is the active one" language across the whole app instead of a
   one-off style just for this. Lives here rather than input.css/
   tailwind.css - own report: "il ne faut pas que le style hover
   l'emporte" - .q-icon-btn:hover (tailwind.css) needs to lose that
   tie, and this file already loads after tailwind.css on every page
   (base.html's own <link> order), so being here is enough on its own,
   no specificity trick or !important needed. */
[data-q-toggle][aria-expanded="true"] {
    background: var(--app-link-soft);
    border-color: var(--app-link);
    color: var(--app-link);
    font-weight: 600;
}
/* Même "état actif" - own report ("les boutons doivent devenir actifs
   comme data-q-toggle=plus"): data-q-surah-menu-toggle (/ar/s/1, "...")
   et data-q-mushaf-surah-toggle (/ar/c, Sourates) mettent déjà à jour
   aria-expanded eux-mêmes (bindPopover, surah-player.js/mushaf.js) mais
   n'avaient encore aucune règle CSS dessus - juste deux attributs de
   plus sur le même sélecteur plutôt qu'une règle dupliquée.
   own report ("le hover l'emporte, et les couleurs sont differentes"):
   2 bugs, pas 1.
   1) Couleurs: --app-link/--app-link-soft ne sont en fait JAMAIS
      redéfinis par thème de lecture à ce niveau - les resets par thème
      (plus haut dans ce fichier) ne portent que sur .q-popover/
      .q-surah-menu-submenu (contenu d'un panneau déjà ouvert), pas sur
      le <header> partagé, qui est un sibling de .q-mushaf-frame depuis
      que ces boutons en sont sortis cette session (own report "ils
      doivent vivre dans le header partagé") - jamais un descendant. Même
      valeurs globales que /ar/s dans tous les thèmes de lecture ici,
      color-mix (essayé un instant) aurait justement introduit un écart
      qui n'existait pas (16% fixe vs le 10%/16% réel de
      --app-link-soft selon clair/sombre, input.css).
   2) Hover: .q-icon-btn:hover/.q-mushaf-icon-btn:hover (surah-
      player.css/mushaf.css) chargent APRES ce fichier (extra_head) et
      ont la même spécificité (0,2,0) qu'un simple [attr][attr] (0,2,0) -
      égalité tranchée par l'ordre de chargement, donc le hover gagnait
      toujours. Combiné avec la classe .q-icon-btn/.q-mushaf-icon-btn
      ici (0,3,0) pour battre le hover peu importe l'ordre des fichiers.
   Own report ("chaque bouton dont le popover s'ouvre doit devenir
   actif, pas juste Sourates") - générique sur [aria-expanded="true"]
   plutôt que listé par data-attribut : couvre Notes/Sourates/Aller à la
   page/Signets/Partager/Thèmes/Langue/Lecture (data-q-mushaf-*-toggle)
   et "..." (data-q-surah-menu-toggle) d'un coup, tous de vrais boutons
   disclosure aria-expanded (bindPopover). Le bookmark-btn (aria-pressed,
   pas aria-expanded, icône on/off séparée) n'est pas concerné, aucun
   [aria-expanded] dessus. */
.q-icon-btn[aria-expanded="true"]:not(:disabled):not([hidden]),
.q-mushaf-icon-btn[aria-expanded="true"]:not(:disabled):not([hidden]) {
    background: var(--app-link-soft);
    border-color: var(--app-link);
    color: var(--app-link);
    font-weight: 600;
}
/* Same "this is the active one" look as [data-q-toggle] above, reused as
   plain CSS rather than the data-q-toggle attribute itself - these two
   don't go through base.html's own generic panel-open delegation
   (data-q-panel counterpart, __qSetPanelOpen), own click handlers in
   _surah_list_section.html instead - own report: "le bouton doit avoir
   l'etat active quand son popover est ouvert ... comme data-q-toggle=
   plus". Was [data-q-sleep-timer-toggle] (ex-minuterie de veille,
   retirée) - même règle reprise ici plutôt que dupliquée. Shared here
   (not surah-player.css) since surah_list.html only loads this sheet. */
#q-surah-duration-toggle[aria-expanded="true"] {
    background: var(--app-link-soft);
    border-color: var(--app-link);
    color: var(--app-link);
    font-weight: 600;
}
/* Own report: "le premier reste comme hover meme si je survole un
   autre élément" - open()'s own firstItem.focus() keeps the outline's
   own row focus-visible for as long as it holds keyboard focus, real
   and correct for a keyboard user tabbing through, but that used to
   *also* paint the same background fill as :hover above - with the
   pointer now hovering a *different* row, 2 rows read as "active" at
   once. Outline alone still marks focus (never just colour, CLAUDE.md),
   without also claiming the same fill hovering itself uses. */
.q-surah-menu-item:focus-visible {
    outline: 2px solid var(--app-link);
    outline-offset: -2px;
}
.q-surah-menu-item:disabled {
    opacity: 0.5;
    pointer-events: none;
}
/* Partager's own row (q-surah-menu-item-sub) - icon+label cluster on one
   side (q-surah-menu-item-content, same gap/order as every other menu
   item), chevron pinned to the far edge as the submenu affordance - this
   one button needs space-between (unlike the plain flex-start items
   above) precisely so the chevron reaches that far edge. */
.q-surah-menu-item-sub {
    justify-content: space-between;
}
.q-surah-menu-item-content {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    min-width: 0;
}
.q-surah-menu-item-chevron {
    flex-shrink: 0;
    color: var(--app-sub);
}
/* Points toward inline-end at rest (icon itself drawn LTR/pointing
   right) - mirrored under RTL, same scaleX(-1) convention as every
   other directional glyph in this codebase. Static either way, not a
   live open/close indicator - aria-expanded/aria-haspopup already carry
   the live state for screen readers. */
[dir="rtl"] .q-surah-menu-item-chevron {
    transform: scaleX(-1);
}
/* Flyout shell - position context for it is each caller's own
   [data-q-*-wrap] { position: relative } rule (base.html/surah-player.css
   respectively) - own report: "il faut faire pareil que Thèmes",
   nothing lives here for that half, it's per-widget. Copies .q-popover's
   own base chrome exactly - fully opaque, no blur, same as every other
   top-level popover. */
/* Moved from surah-player.css (own report: "ne duplique pas le code") -
   base.html's own #q-panel-plus carries this same class too now, needed
   loaded site-wide, not just on /ar/s/X. */
.q-surah-popover {
    position: absolute;
    /* 2.25rem = hauteur de .q-icon-btn (le bouton déclencheur,
       même classe ici et sur data-q-toggle="plus") + --q-popover-trigger-
       gap - own report sur l'égalité des 3 espaces, voir sa définition. */
    top: calc(2.25rem + var(--q-popover-trigger-gap));
    /* inset-inline-start (pas right) - own report ("en LTR mal
       positionné, mobile ET desktop") : #q-panel-plus/data-q-toggle=
       "plus" vit dans #q-header-col-start (justify-self:start,
       base.html), qui suit dir - bascule au bord physique gauche en
       LTR. right:0 (physique, jamais réévalué) restait collé à droite
       dans les deux langues, décollé du bouton en LTR. inset-inline-
       start:0 vaut right:0 en RTL (identique à avant, rien ne change
       côté arabe) et left:0 en LTR - suit le bouton dans les deux cas. */
    inset-inline-start: 0;
    /* z-index:60 (own report: "une partie en bas est cachée par
       #q-mini-player-mobile-bar" sur /ar/s mobile) - au-dessus de
       .q-bottombar (z-index:55, input.css) et #q-mini-player-mobile-bar
       (z-index:30, surah_list.html), pas seulement du backdrop
       (.q-mushaf-mobile-menu-backdrop, z-index:40) : ce panneau est une
       vraie superposition modale quand ouvert, rien d'autre du chrome
       fixe ne doit rester au-dessus. */
    z-index: 60;
    width: var(--q-menu-shell-width);
    max-height: calc(100dvh - 1rem);
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: 0.375rem;
    border-radius: 16px;
    border: 1px solid var(--app-popover-border);
    background: var(--app-popover-bg);
    box-shadow: 0 8px 28px rgb(0 0 0 / 20%);
    font-size: calc(0.8125rem * var(--q-ui-scale, 1));
    color: var(--app-popover-text);
}
/* Own report: right:0 above assumes a trigger at the far edge of its own
   row (#q-panel-plus, .q-surah-menu-toggle - nothing past them, endless
   room to open toward) - surah_list.html's sleep-timer trigger sits
   mid-row instead, packed into a 16rem-wide column alongside shuffle/
   prev/play/next, narrower than this popover's own 15rem width, so
   anchoring to either edge risks spilling out one side depending on
   viewport width. Centered under the button instead - splits any
   overflow evenly on both sides rather than gambling on one. Sibling
   selector (not a class on #q-sleep-timer-popover itself) - the
   attribute lives on the trigger, not the popover, same split as
   data-q-sleep-timer-anchor-default itself (sleep-timer.js). Scoped to
   min-height:551px - a plain ID selector's own #q-sleep-timer-popover
   bottom-sheet rule just below (max-height:550px) would otherwise lose
   the specificity fight against this one (attribute + id beats id
   alone) and get its own left/transform silently overridden on a short
   viewport, breaking the full-width sheet instead of centering anything
   meaningful. */
@media (min-height: 551px) {
    [data-q-sleep-timer-anchor-default] ~ #q-sleep-timer-popover {
        left: 50%;
        right: auto;
        transform: translateX(-50%);
    }
}
/* Moved from surah-player.css (own report: "meme chose pour /ar/s/ ...
   sans dupliquer le code") - #q-sleep-timer-popover is now shared between
   surah_detail.html and surah_list.html (staticfiles/js/sleep-timer.js),
   and only surah_list.html loads popover.css, not surah-player.css.
   #q-mushaf-surah-popover kept alongside it, same reasoning as its own
   earlier migration just above (own report: "ne duplique pas le code").
   The row-anchored clamp (sleep-timer.js's own open()) keeps these
   popovers inside a *short* browser window, but "clamped to a 550px-tall
   sliver with its own internal scrollbar" still reads as broken, not
   fixed - a real bottom-sheet reads as intentional instead. Height-
   based, not a width-based mobile breakpoint (own report: a wide desktop
   window dragged short hits this exact same problem, nothing to do with
   narrow/mobile). JS skips its own top/left/right inline positioning
   under this same threshold so these rules aren't fought by leftover
   inline styles from a previous open() at a taller size.
   #q-mushaf-surah-popover removed from this list (own report) - it's a
   real .q-surah-menu-submenu row-item now (surah_detail.html, moved out
   of #q-surah-menu-popover), not the old standalone top-level popover
   this rule was written for. A short-viewport fixed-bottom-sheet here
   fought that family's own shared width-based mobile handling instead
   of matching it (own report: "je n'arrive jamais a aller avec la
   souris [vers] popover, il se cache" - rendered far from its own
   trigger row on a short window, nothing continuous for the pointer to
   follow between them). */
@media (max-height: 550px) {
    #q-sleep-timer-popover {
        position: fixed;
        inset-inline: 0;
        top: auto;
        bottom: 0;
        margin-inline: auto;
        width: 100%;
        max-width: 22rem;
        max-height: min(80vh, calc(100dvh - 1rem));
        border-radius: 16px 16px 0 0;
        padding-bottom: calc(0.375rem + env(safe-area-inset-bottom, 0px));
    }
}
.q-surah-menu-submenu {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    inset-inline-end: 100%;
    width: 12rem;
    max-height: none;
    padding: 0.25rem;
    border-radius: 16px;
    border: 1px solid var(--app-popover-border);
    background: var(--app-popover-bg);
    box-shadow: 0 8px 28px rgb(0 0 0 / 20%);
    z-index: 42;
    font-size: calc(0.8125rem * var(--q-ui-scale, 1));
    color: var(--app-popover-text);
    text-align: start;
}
/* Mobile bottom-sheet for the whole .q-surah-menu-submenu family - was
   surah-player.css-only (/ar/s/X), moved here (loaded site-wide,
   base.html) so #q-panel-plus's own Langue/Traduction/Lecture/Récitant
   flyouts get the exact same treatment instead of a 2nd copy (own
   report: "meme chose... ne duplique pas le code"). The row-anchored
   flyout (base rule above, width:12rem/20rem, inset-inline-end:100% off
   the trigger row) has nowhere to grow on a narrow viewport - a fixed,
   edge-margined, fully-rounded card instead, same shape as mushaf's own
   .q-mushaf-mobile-menu. */
.q-surah-submenu-mobile-head {
    display: none;
}
@media (max-width: 1023px) {
    .q-surah-menu-submenu {
        position: fixed;
        inset-inline-end: auto;
        margin-inline-end: 0;
        left: 0.75rem;
        right: 0.75rem;
        top: auto;
        bottom: calc(env(safe-area-inset-bottom, 0px) + 0.75rem);
        width: auto;
        max-height: 70vh;
        overflow-y: auto;
        border-radius: 20px;
        padding: 0.375rem;
        display: flex;
        flex-direction: column;
        gap: 0.5rem;
        /* Cancels the desktop base rule's own translateY(-50%) vertical
           centering above - without it a leftover -50% shift still
           applies on top of position:fixed;bottom, pushing the sheet up
           by half its own height. */
        transform: none;
    }
    .q-surah-submenu-mobile-head {
        display: flex;
    }
    /* #q-mushaf-surah-popover only - own report: "l'input change de
       position a chaque fois qu'on filtre" (fewer visible rows shrank
       the *whole sheet*, floating the search row up/down with it) then
       "collé au bord bas comme les autres" (reverting the sheet itself
       to the shared bottom-anchored rule above brings that back). Fixed
       height on the *list* alone instead of the whole sheet - own
       reserved viewport that never shrinks with the filtered count, so
       the search row above it never moves, while the sheet itself still
       hugs the bottom edge exactly like every other submenu. */
    #q-mushaf-surah-popover .q-popover-list {
        height: 50vh;
        overflow-y: auto;
    }
}

/* Shared 20rem submenu width + 0.5rem padding - own report: "pourquoi
   c'est pas le meme code d'ailleurs" (home's own #q-plus-display-submenu/
   #q-plus-accessibility-submenu/#q-plus-reading-submenu vs /ar/s/X's own
   .q-surah-reading-submenu/-theme-submenu/-reciter-submenu/
   -accessibility-submenu) - used to be a literal width:20rem duplicated in
   each of those own id/class rules (input.css/surah-player.css), padding
   drifted apart the same way (0.5rem in some, 0.375rem in others - own
   report: "le padding n'est pas pareil", no real reason for the
   difference). One shared class for both now, each submenu's own
   remaining overrides (height/max-height/overflow-y/flex layout) stay
   separate on purpose - those still genuinely differ. Placed *after* the
   base .q-surah-menu-submenu rule above on purpose - own report: "t'as
   cassé le width" - equal specificity (single class each), so source
   order alone decides which value wins; before this move the base rule's
   own width:12rem/padding:0.25rem (later in the file back then) silently
   beat this one regardless of which elements carried it. */
.q-menu-submenu-lg {
    width: 20rem;
    padding: 0.5rem;
}
/* Own report ("un peu large") - Accessibilité (/ar/s/1 et /ar/s) n'a
   qu'une liste de switches empilés (_accessibility_switches.html), pas
   besoin des 20rem pensés pour la grille 2 colonnes du Récitant
   (.q-menu-submenu-lg, own comment ci-dessus, toujours utile ailleurs)
   - override scopé aux 2 ids seulement, id+class même spécificité que
   .q-menu-submenu-lg, l'id gagne peu importe l'ordre. Desktop only
   (>=1024px, own report "meme largeur que les autres popover sur
   mobile") - sans ça cet id (plus spécifique) battait aussi la règle
   mobile juste en dessous (width:auto, le même sheet edge-margined que
   tous les autres q-menu-submenu-lg), gardant ce seul submenu étroit à
   16rem au lieu du plein sheet mobile partagé. */
@media (min-width: 1024px) {
    #q-surah-accessibility-submenu,
    #q-plus-accessibility-submenu {
        width: 16rem;
    }
}
/* Own report: "la largeur n'est pas bonne" - this rule's own unconditional
   width:20rem otherwise beats the mobile bottom-sheet's width:auto above
   (equal specificity, source order - this rule comes later in the file),
   pinning Lecture/Récitant/Thèmes/Accessibilité (all q-menu-submenu-lg)
   to a narrow floating box instead of the shared edge-margined sheet
   every other submenu already gets on mobile. */
@media (max-width: 1023px) {
    .q-menu-submenu-lg {
        width: auto;
        padding: 0.375rem;
    }
}
/* .q-reciter-list's own base grid-template-columns:repeat(3,1fr)
   (input.css) was sized for the old, wider index-page reciter panel -
   too cramped at this 20rem family's own width. Scoped to the shared
   class both /ar/s/X's own #q-surah-reciter-submenu and home's own
   #q-plus-reciter-submenu carry (own report: "2 colonnes comme /ar/s/X")
   instead of one id-scoped copy per page. */
.q-menu-submenu-lg .q-reciter-list {
    grid-template-columns: repeat(2, 1fr);
}
/* No fixed/max height (own report: remove it) - now that the search
   box (former own report: it moved down as filtered results shrank
   the grid) is gone, the submenu just sizes to however many reciter
   tiles there actually are, however many that grows to. Flex column +
   overflow:hidden - .q-reciter-list carries the shared .q-popover-body
   class, kept in case a future taller list needs its own scroll
   again. Shared by /ar/s/X's own #q-surah-reciter-submenu and home's
   own #q-plus-reciter-submenu (own report: "la hauteur n'est pas comme
   /ar/s/X") instead of one id-scoped copy per page. */
.q-reciter-submenu {
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

/* Explicit divider between menu rows (own report: "après Récitant,
   avant Partager" on /ar/s/X, generic name now - moved here from
   surah-player.css since base.html/home page needs it too and only
   loads this file, not that one) - the rows around it don't have their
   own border-top, so this is its own dedicated element rather than
   reusing that hidden li+li border. */
.q-menu-divider {
    height: 1px;
    margin: 0.25rem 0.625rem;
    background: var(--app-popover-divider);
}
/* Bigger gap before "Signaler un problème" (own report, IMG_7589.jpg) -
   a full section break, not the plain hairline the divider above draws
   between 2 related rows - same background colour as that one (own
   report), just thicker/full-width instead of the 1px inset line. */
.q-menu-divider-lg {
    height: 4px;
    margin: 0.375rem 0;
}

/* "Langue de traduction" (base.html, home page only) - translation
   names vary too much in length (own report: some wrapped to 2 lines
   at a fixed rem width) for one guessed width to fit every one on a
   single line - size to content instead, clamped so it never overflows
   the viewport on a narrow desktop window. */
@media (min-width: 1024px) {
    #q-plus-translation-submenu {
        width: max-content;
        max-width: min(90vw, 26rem);
    }
}
#q-plus-translation-submenu .q-popover-item {
    white-space: nowrap;
}

/* "Lecture" (base.html, home page only) - same #mark-toggles/.q-mark-desc
   negative-margin compensation as surah_detail.html's own
   #q-surah-reading-submenu copy (surah-player.css), needed here too since
   this submenu isn't loaded on the same page (that CSS file is
   surah_detail.html-only, own <link> there) and popover.css is the file
   actually shared with base.html. */
#q-plus-reading-submenu #mark-toggles {
    margin-bottom: 0.75rem;
}
#q-plus-reading-submenu #mark-toggles-label {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border-width: 0;
}

/* Divider/inset/rounding between rows aren't here - a row is a <li>
   wrapping a .q-popover-item button in most lists but a flat
   .q-popover-item with no <li> at all in the selection menu, so those
   rules need 2 different selectors per concern rather than one; kept
   together further down this file instead of splitting that logic
   across 2 places. */
.q-mushaf-theme-popover {
    /* 19->20rem (back to the shared .q-mushaf-jump-popover default just
       above, no longer a slimmer override) - this popover now also
       carries the Texte/Accessibilité controls folded in from the old
       "Personnaliser le thème" dialog (own comment further below), which
       need a bit more breathing room than the swatch grid/quickrow alone
       ever did. */
    width: 20rem;
    /* Can grow past the viewport now on a short screen once
       "Personnaliser" reveals its own extra sliders - same max-height +
       overflow-y treatment as .q-mushaf-selection-popover elsewhere in
       this file (own comment there), simpler than trying to keep
       .q-popover-head's own close button pinned above a separate
       scrolling zone the way the old dialog's fixed header/footer did
       (own comment further below on why that dialog is gone) - Escape/
       outside-click/scrolling back up all still reach it fine. */
    max-height: calc(100vh - 2rem);
    overflow-y: auto;
}

/* 4 columns - size-toggle spans 2, the transition-picker and quick
   theme buttons each take 1, matching the reference screenshot's own
   proportions (stepper roughly the width of the 2 icon buttons
   combined). Was 3 columns/no transition button before that moved out
   of this popover's own inline flow into its own quick popover
   (mushaf.html) - .q-mushaf-arabic-size-dots below still only spans
   the first 2 (under the size-toggle specifically), unaffected by the
   extra column. */
.q-mushaf-theme-quickrow {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 0.5rem;
    margin-bottom: 0.75rem;
}

/* Taille du texte arabe + Intensité, own row above the quickrow
   (mushaf.html, own comment there) - both use the same .q-mushaf-theme-
   size-toggle chip, own 2-column grid so they always pair together
   regardless of what the quickrow below still has free. Each column is
   a plain flex column (stepper on top, its own dots row under it) -
   .q-mushaf-theme-arabic-size and .q-mushaf-theme-brightness both rely
   on this same child rule instead of repeating it twice. */
.q-mushaf-theme-quickrow-row {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 0.5rem;
    margin-bottom: 0.75rem;
}

/* Reported: tapping these controls in quick succession (bumping the
   Arabic size stepper or brightness slider dots repeatedly) triggered
   the mobile browser's own double-tap-to-zoom instead of registering as
   2 separate taps - no CSS here was telling it these are discrete
   controls, not page content to zoom into. manipulation keeps pinch-
   zoom/pan working everywhere else on the page, just drops the
   double-tap-zoom gesture specifically over these 4. */
.q-mushaf-theme-brightness,
.q-mushaf-theme-arabic-size,
.q-mushaf-theme-size-toggle,
.q-mushaf-arabic-size-dots {
    touch-action: manipulation;
}

.q-mushaf-theme-quickrow-row > div {
    display: flex;
    flex-direction: column;
}

/* Own report: each column's own .q-mushaf-arabic-size-dots stretches
   edge-to-edge (space-between, own rule further below) - flush against
   both columns' shared inner edge, the 2 dot rows read as one
   continuous strip instead of 2 separate ones. Insets both sides so
   neither row reaches that shared boundary, same gap on the outer
   edges too rather than a direction-specific one-sided fix. */
.q-mushaf-theme-quickrow-row .q-mushaf-arabic-size-dots {
    padding-inline: 0.5rem;
}

/* Segmented "A A" pair (small/large) - .q-mushaf-arabic-size-step (1/-1)
   steps the *same* petit/normal/grand/tres-grand radios the site-wide
   panel already has (mushaf.js), not a separate scale. Same border/
   radius/padding/height as .q-mushaf-personalize-reset further below -
   one consistent "control" look across this popover, not a pill here
   and a rectangle there. */
/* "Bouton" chrome (--app-popover-btn-bg/-text) - the popover's own
   real measured "chip control" palette, a filled background distinct
   from the popover's own body (--app-popover-bg) rather than a plain
   bordered/transparent control - same elements throughout this
   popover use it: this stepper, .q-mushaf-theme-quick-btn,
   .q-mushaf-personalize-reset, .q-popover-close. */
.q-mushaf-theme-size-toggle {
    grid-column: span 2;
    display: flex;
    border-radius: 8px;
    background: var(--app-popover-btn-bg);
    overflow: hidden;
}

.q-mushaf-theme-size-toggle button {
    flex: 1;
    /* display:flex + centering, not text-align/line-height alone - those
       2 centered the "A"/"A" text fine (own report: no complaint there)
       but left the newer svg icon buttons (espacement lignes/mots, own
       comment further below) visibly off-center - vertical-align:middle
       on a lone inline svg with no sibling text to align against isn't
       reliable the way it is for a text baseline. Flex centers either
       kind of content the same way. */
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0.5rem 0;
    color: var(--app-popover-btn-text);
    font-weight: 600;
    line-height: 1;
    /* Own report: same size on both buttons here - matches
       .q-mushaf-personalize-reset's own font-size, same as every icon-
       only stepper in this family (espacement lignes/mots, Intensité).
       Only .q-mushaf-arabic-size-toggle's own "A"/"A" pair overrides
       this asymmetrically further below - a real small/big size
       *difference* is the whole point there, not something every other
       stepper reusing this same class should inherit too. */
    font-size: calc(0.8125rem * var(--q-ui-scale, 1));

}

.q-mushaf-theme-size-toggle button:first-child {
    border-inline-end: 1px solid var(--app-popover-divider);
}

.q-mushaf-arabic-size-toggle button:first-child {
    /* Smaller than the "big A" (below) - was 0.6875rem (matching
       .q-mushaf-personalize-reset's own text), nudged down further so
       the size gap between the two reads clearer at a glance. */
    font-size: calc(0.625rem * var(--q-ui-scale, 1));

}

.q-mushaf-theme-size-toggle button:hover,
.q-mushaf-theme-size-toggle button:focus-visible {
    /* color-mix against --app-popover-btn-text, layered on top of this
       control's own --app-popover-btn-bg (a hover mixed against
       --app-popover-text/-bg instead, like the plain list rows just
       below, would barely show up against this already-different
       "chip" background). */
    background: color-mix(in srgb, var(--app-popover-btn-text) 12%, var(--app-popover-btn-bg));
}

.q-mushaf-theme-quick-btn {
    grid-column: span 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    padding: 0.5rem;
    border-radius: 8px;
    background: var(--app-popover-btn-bg);
    color: var(--app-popover-btn-text);
}

.q-mushaf-theme-quick-btn:hover,
.q-mushaf-theme-quick-btn:focus-visible,
/* Own report: stays in its own hovered look while its own popover is
   open (data-q-mushaf-theme-mode-toggle, the only user of this class
   with aria-expanded at all - harmless no-op selector for every other
   plain .q-mushaf-theme-quick-btn, own comment above on who else uses
   this class). */
.q-mushaf-theme-quick-btn[aria-expanded="true"] {
    background: color-mix(in srgb, var(--app-popover-btn-text) 12%, var(--app-popover-btn-bg));
}

/* Widget rapide Apparence (#q-panel-plus, juste avant "Thèmes et
   réglages", base.html data-q-quick-theme-pill) - même famille visuelle
   que .q-mushaf-theme-size-toggle (steppers "Thèmes et réglages") au
   lieu d'une pilule flottante à hauteur fixe: 3 boutons flex:1 pleine
   largeur, même hauteur de ligne que les autres items du menu. Le <li>
   n'a pas la classe .q-popover-item-row (pas de bouton unique à
   surligner sur toute la ligne ici, own report: "hover d'un element du
   menu qui se declenche... c'est moche" - ce groupe gère son propre
   état visuel par bouton). */
.q-quick-theme-pill-row {
    padding: 0.25rem;
}

.q-quick-theme-pill {
    display: flex;
    border-radius: 8px;
    background: var(--app-popover-btn-bg);
    overflow: hidden;
}

.q-quick-theme-pill-btn {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0.3125rem 0;
    color: var(--app-popover-btn-text);
    background: none;
}

.q-quick-theme-pill-btn:not(:last-child) {
    border-inline-end: 1px solid var(--app-popover-divider);
}

.q-quick-theme-pill-btn:hover,
.q-quick-theme-pill-btn:focus-visible {
    background: color-mix(in srgb, var(--app-popover-btn-text) 12%, var(--app-popover-btn-bg));
}

.q-quick-theme-pill-btn[aria-checked="true"] {
    background: color-mix(in srgb, var(--app-popover-btn-text) 18%, var(--app-popover-btn-bg));
}

.q-quick-theme-pill-btn:focus-visible {
    outline: 2px solid var(--app-link);
    outline-offset: -2px;
}

/* Sits under .q-mushaf-theme-size-toggle only, not the sun button next
   to it - starts a new row in the quickrow's own 3-column grid but
   explicitly spans just the first 2 columns (grid-column), same box
   width as the stepper above it. space-between (no fixed gap) spreads
   the 15 dots edge-to-edge across that full width, matching the
   toggle's own two flex:1 buttons visually filling their box - a
   fixed gap left them bunched on one side instead. No horizontal
   padding either, so the first/last dot land flush with the toggle's
   border, same as its buttons. */
.q-mushaf-arabic-size-dots {
    grid-column: 1 / span 2;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0.375rem 0 0;
}
/* Own report: missed by the earlier mushaf.css->popover.css move (name
   didn't match that pass's own prefix list) - the actual dot itself,
   .q-mushaf-arabic-size-dots above is just the row container. */
.q-mushaf-arabic-dot {
    width: 0.375rem;
    height: 0.375rem;
    border-radius: 999px;
    /* --app-border (own report: "pas bien visible") is too low-contrast
       for a state indicator this small (CLAUDE.md ≥3:1 non-text). Neither
       that nor --app-sub/--app-text is actually a page-independent value
       though (own report: "une couleur pour les dots sur la home, une
       autre sur /ar/s/X") - html:root.q-surah-reading-frame
       (surah-player.css) and [data-q-mushaf-theme] (mushaf.css) both
       re-derive --app-text/-sub/-border per active Mushaf reading theme
       (Original/Tranquille/Papier/...), an axis this popover's other
       pages (Affichage, here) don't have at all. --app-popover-divider/
       -text instead - this dot lives inside a popover
       (.q-surah-menu-submenu), so it uses that same self-contained
       palette every other divider/text in this exact popover system
       already does (own comment further up: "the popover chrome's own
       separate palette... not the reading page's --app-bg/--app-text
       above") - same code, not a hardcoded guess, correctly following
       whichever Mushaf theme is active exactly like its neighbours
       instead of drifting from it. */
    background: var(--app-popover-divider);
    flex-shrink: 0;
}
.q-mushaf-arabic-dot-filled {
    background: var(--app-popover-text);
}

/* "Intensité" (reference screenshot) - same stepper+dots chip as the
   Arabic size control above (.q-mushaf-theme-size-toggle/
   .q-mushaf-arabic-size-dots, own comment on the markup) rather than the
   native <input type="range"> this replaces, so it reads like every
   other control on this page instead of being the one native slider
   among them. mushaf.js applies filter:brightness() on .q-mushaf-frame
   itself, Mushaf-scoped same as the 6 theme presets. Paired with the
   Arabic size stepper on their own .q-mushaf-theme-quickrow-row (own
   comment there) - flex-column layout comes from that row's own
   ">div" rule, nothing needed on this class itself. */
.q-mushaf-theme-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 0.5rem;
    margin-bottom: 0.75rem;
}

/* Bigger card, closer to the reference screenshot's own tiles - was a
   thin 0.75rem/0.25rem pad with a 1.25rem "Aa", read cramped/plain next
   to it. */
/* Own report: "tout ce qui est bouton ne marche pas" (Thèmes et
   réglages panel, surah_detail.html) - every real control in here is a
   plain <button> needing a JS click listener to do anything (unlike
   the native radio/label controls elsewhere on this same page, which
   never stopped working) - forcing position/z-index/pointer-events
   explicitly here rules out any ancestor/overlay stacking accident
   swallowing clicks before they reach the button. */
[data-q-surah-theme-view-main] button,
[data-q-surah-theme-view-personalize] button {
    position: relative;
    z-index: 1;
    pointer-events: auto;
}

.q-mushaf-theme-swatch {
    position: relative;
    z-index: 1;
    pointer-events: auto;
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 0 0.5rem 0.75rem;
    border: 1px solid var(--app-border);
    border-radius: 12px;
    /* Grid items default to an automatic min-width equal to their own
       unbreakable content width - a long font label (font grid below,
       "KFGQPC Naskh"/"PDMS Saleem") pushed its own 1fr column wider than
       its 5 siblings instead of the 3 columns splitting evenly. Forces
       the column back to sharing the grid's own 1fr math; the label text
       still wraps at its own space rather than overflowing. */
    min-width: 0;
}

/* Own report: a fixed-height "header" (the glyph) and a fixed-height
   "footer" (the label) below, not one shared height budget on the
   button itself (own report: that still needed constant min-height:0/
   overflow:hidden fighting to stay pinned whenever the 2 grids' own
   content didn't land on the exact same total by coincidence). Each
   zone owns its own fixed height instead, so both grids match by
   construction regardless of glyph/label content differences - no
   overall .q-mushaf-theme-swatch height needed anymore, it's just the
   sum of these 2 fixed zones plus padding either way. */
.q-mushaf-theme-swatch-aa {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 3.5rem;
    /* Own report: measured a few px taller on the font grid's own tiles
       even with this height fixed - custom Arabic web fonts (Scheherazade,
       KFGQPC...) render "الله" with a taller real ascent/descent than the
       generic "serif" "Aa" glyph the main theme grid uses at the same
       line-height:1, so the glyph's own *painted* pixels bled past this
       box's edge without actually growing its layout size. Clips that
       paint overflow at the box edge instead, so a screen ruler measures
       the same height on both grids. */
    overflow: hidden;
    font-size: calc(0.75rem * var(--q-ui-scale, 1));

    font-weight: 700;
    font-family: serif;
    line-height: 1;
}

.q-mushaf-theme-swatch-label {
    display: flex;
    align-items: center;
    justify-content: center;
    height: calc(0.6875rem * 1.2 * 2 * var(--q-ui-scale, 1));
    /* Same paint-overflow clip as .q-mushaf-theme-swatch-aa above, own
       comment there. */
    overflow: hidden;
    font-size: calc(0.6875rem * var(--q-ui-scale, 1));
    line-height: 1.2;
    text-align: center;
    /* "Scheherazade" (font grid) has no space to wrap at like
       "KFGQPC Naskh"/"PDMS Saleem" do - without this, that one word
       alone overflows its own column instead of wrapping, undoing the
       min-width:0 equal-column fix above. */
    overflow-wrap: break-word;
    min-width: 0;
    /* The swatch button is align-items:center (own comment on the
       markup - centers the "Aa"/glyph + label pair as a block, not
       stretched to the button's own width), so on the cross axis this
       label's box defaults to its own natural content width instead of
       the button's real available width - overflow-wrap then has
       nothing to actually wrap against, "Scheherazade" (no space to
       break at) just sat 10px into the button's own 8px padding on
       both sides instead of breaking there (confirmed live). Forces the
       real available width back so overflow-wrap has something to work
       with. */
    width: 100%;

    /* Inherits the swatch button's own inline color (mushaf.html
       style="background:…;color:…" per tile) - same as
       .q-mushaf-theme-swatch-aa right above already does. That color
       is chosen as a *pair* with the same inline background, both set
       together on the button itself, so it's exactly as readable here
       as it already is for the "Aa" sample sitting on that same
       background - not the popover's own ambient var(--app-sub)
       (tried first, read as visually disconnected from that tile's
       own colour). */
}

.q-mushaf-theme-swatch:hover,
.q-mushaf-theme-swatch:focus-visible {
    border-color: var(--app-link);
}

.q-mushaf-theme-swatch:focus-visible {
    outline: 2px solid var(--app-link);
    outline-offset: 2px;
}

/* Current selection - a ring plus a checkmark badge, not just a border
   color change (CLAUDE.md: not color alone). aria-pressed carries the
   same fact non-visually. */
.q-mushaf-theme-swatch[aria-pressed="true"] {
    /* --app-text, pas --app-link - ce swatch affiche déjà le fond/texte
       propres du thème en aperçu direct (style inline posé par
       surah-player.js/mushaf.js depuis ses data-bg-*/data-text-*), pas
       le chrome ambiant du popover. --app-link (bleu Neutre ou recyclé/
       exempté ailleurs pour matcher le fond FIXE du popover) peut au
       contraire matcher pile le fond propre de CE swatch (own report:
       "Tranquille" en clair, fond #4a4a4d = exception --app-link ->
       check invisible dessus). --app-text est le seul des deux garanti
       contrasté contre le fond de ce swatch précis, quel que soit le
       thème/mode - "theme claire doit etre quelque chose de claire". */
    border-color: var(--app-text);
    /* Own report: "il fait un décalage" - border-width 1px->2px on
       select shrank the border-box content area by those extra pixels,
       shifting the "Aa"/label inside instead of just thickening the
       ring. inset box-shadow layers the same visual weight without
       touching the box model/layout at all. */
    box-shadow: inset 0 0 0 1px var(--app-text);
}

.q-mushaf-theme-swatch[aria-pressed="true"]::after {
    content: "✓";
    position: absolute;
    top: 0.25rem;
    right: 0.25rem;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 1rem;
    height: 1rem;
    border-radius: 999px;
    background: var(--app-text);
    color: var(--app-surface);
    font-size: calc(0.625rem * var(--q-ui-scale, 1));

    line-height: 1;
}

/* Same bg/fg as "Original" (both data-q-mushaf-theme="original") - the
   real difference is this heavier weight, not colour. */
.q-mushaf-theme-swatch-intense .q-mushaf-theme-swatch-aa {
    font-weight: 900;
}

/* Style d'écriture arabe grid (mushaf.html) - same .q-mushaf-theme-grid/
   -swatch tiles as the theme/font pickers (own report: wanted this to
   read exactly the same, "الله" preview like the font grid's own), but a
   real <label><input type="radio" class="sr-only"></label> pair
   underneath instead of a plain aria-pressed button (own report: native
   "change" is what this radiogroup's own hx-trigger="change" fires on,
   same reasoning as .q-popover-item-choice above) - :has() reads the
   sr-only input's own state instead of an aria-pressed attribute,
   otherwise the exact same border/checkmark treatment as
   .q-mushaf-theme-swatch[aria-pressed="true"] above. */
.q-mushaf-theme-swatch-choice {
    cursor: pointer;
    /* Own report: wanted this preview to actually show the reader's own
       currently-picked theme/font, not the popover's own ambient chrome
       colour (--app-popover-btn-bg/-text, base .q-mushaf-theme-swatch's
       own background elsewhere) every other control in this popover
       deliberately uses instead of the live reading page's colours (own
       comment further up on why). --app-bg/--app-text are that live
       pair, set on .q-mushaf-frame itself per selected theme/mode - this
       popover is a real descendant of that frame, so they're already in
       scope here without any extra wiring. */
    background: var(--app-bg);
    color: var(--app-text);
}

/* Own report: any glyph carrying both .q-mushaf-theme-swatch-aa and
   .font-quran (theme grid + script picker, mushaf.html) still rendered
   in the generic "serif" font regardless - base .q-mushaf-theme-swatch-aa
   own font-family:serif (below) and .font-quran's own font-family:
   var(--font-quran) (tailwind.css) are equal specificity (1 class
   each), and mushaf.css loads *after* tailwind.css, so the plain serif
   here always won. 2-class selector wins outright instead of depending
   on load order - the font grid's own per-font-family rules further
   below (3 selectors: .q-mushaf-font-grid [data-q-mushaf-font=...]
   .q-mushaf-theme-swatch-aa) still beat this regardless, unaffected
   (those tiles never carry .font-quran to begin with, each already
   picks its own specific font instead of the reader's live one). */
.q-mushaf-theme-swatch-aa.font-quran {
    font-family: var(--app-font-arabic);
}

/* Own report: back to #mark-toggles' own original chip layout (site-wide
   .q-choice-item, input.css - flex-wrap pills, own report: the stacked
   full-width list this used to override to didn't read right) - only
   the *colours* recoloured to this popover's own chip button palette
   (--app-popover-btn-bg/-text) instead of the site-wide --app-surface/
   -border/-text pair, scoped to this popover only (not touching the
   shared partial, .q-choice-item still wanted as-is on every other page
   that includes it). */
/* Same convention as this popover's other own buttons
   (.q-mushaf-theme-quick-btn above) - always-visible background from
   the popover's own --app-popover-btn-bg/-text pair, hover/checked
   mixed against --app-popover-btn-text, not .q-mushaf-icon-btn's
   transparent-until-hover header-button look (wrong surface: that
   one's meant for buttons sitting directly on the page background, not
   inside a popover sheet). No border - matches the quick-btn pair too,
   this popover doesn't outline its own chips. */
#q-mushaf-reading-popover .q-choice-item {
    /* Own report: "rub-el-hizb" (#mark-toggles' own longest chip label)
       wrapped to 2 lines at .q-choice-item's site-wide 0.8125rem
       (tailwind.css) - smaller size scoped to this popover only, other
       pages keep the original size on their own chip groups. */
    font-size: 0.72rem;
    padding: 0.5rem;
    border-radius: 8px;
    border-color: transparent;
    background: var(--app-popover-btn-bg);
    color: var(--app-popover-btn-text);
}

.q-mushaf-theme-swatch-choice:has(:focus-visible) {
    /* --app-text, pas --app-link - même raison que
       .q-mushaf-theme-swatch[aria-pressed="true"] plus haut : ce swatch
       affiche background: var(--app-bg)/color: var(--app-text) (le
       thème de lecture courant, own comment plus haut), pas le chrome
       fixe du popover. */
    border-color: var(--app-text);
    outline: 2px solid var(--app-text);
    outline-offset: 2px;
}

.q-mushaf-theme-swatch-choice:hover {
    border-color: var(--app-text);
}

/* Own report: "il faut disable les éléments de surah-reading-script
   pendant l'appel ajax aussi" - #surah-reading-script's own hx-
   disabled-elt (surah_detail.html) already disables the real radio
   <input> during that request, but this label is what's actually
   painted/hovered - same opacity/pointer-events convention as every
   other disabled control here (own report elsewhere), applied via
   :has(:disabled) since the disabled state lives on the input, not the
   label itself. */
.q-mushaf-theme-swatch-choice:has(:disabled) {
    opacity: 0.5;
    pointer-events: none;
}

.q-mushaf-theme-swatch-choice:has(:checked) {
    /* --app-text, pas --app-link - même raison que
       .q-mushaf-theme-swatch[aria-pressed="true"] plus haut. */
    border-color: var(--app-text);
    /* Same reasoning as .q-mushaf-theme-swatch[aria-pressed="true"]
       above (own report: "il fait un décalage") - box-shadow instead of
       a 2nd border-width, no box-model shift on select. */
    box-shadow: inset 0 0 0 1px var(--app-text);
}

.q-mushaf-theme-swatch-choice:has(:checked)::after {
    content: "✓";
    position: absolute;
    top: 0.25rem;
    right: 0.25rem;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 1rem;
    height: 1rem;
    border-radius: 999px;
    background: var(--app-text);
    color: var(--app-surface);
    font-size: calc(0.625rem * var(--q-ui-scale, 1));

    line-height: 1;
}

/* "Police" grid in the "Personnaliser" view (mushaf.html) - same 3-column
   .q-mushaf-theme-grid/.q-mushaf-theme-swatch tiles as the main view's
   theme grid above (own report: wanted it to read exactly the same),
   just no per-tile background/text color override (these swatches never
   set data-bg-*/data-text-* inline like the theme ones do, so they fall
   back to this popover's own ambient --app-popover-text/plain background
   - a font choice has no colour of its own to preview). Current
   script_variant's own real preview word (views.py's
   current_script_preview) instead of a plain "Aa" - each tile still
   needs to show ITS OWN font rendering the same real word, same base
   .q-mushaf-theme-swatch-aa font-size (0.75rem) as the theme/script
   grids now, no override needed here anymore. */
/* Own report: full font names ("Scheherazade New", "KFGQPC Naskh"...)
   read inconsistently against the theme grid's own short single-word
   labels - some wrapped to 2 lines, "Scheherazade" alone (no space to
   break at) hit the column edge/broke mid-word. Smaller caption + less
   side padding than the theme tiles (same macOS Books "Aa" panel this
   whole popover is modeled after, own comment above - captions there
   run smaller too, under a much bigger preview glyph) - every name
   still wraps on its own real word boundary now instead of mid-word. */
.q-mushaf-font-grid .q-mushaf-theme-swatch-label {
    /* Own report: 1-word names ("Scheherazade", "Me Quran") read fine at
       1 line while 2-word ones ("Scheherazade New", "KFGQPC Naskh") wrap
       to 2 - the base label's own fixed height (2-line reserve, shared
       by both grids now, own comment there) already gives every tile
       identical glyph placement regardless, own display:flex centering
       there too, nothing left to override here but the font-size. */
    font-size: calc(0.6875rem * var(--q-ui-scale, 1));
}

.q-mushaf-font-grid .q-mushaf-theme-swatch {
    padding-left: 0.25rem;
    padding-right: 0.25rem;
}

.q-mushaf-font-grid [data-q-mushaf-font="scheherazade"] .q-mushaf-theme-swatch-aa {
    font-family: "Scheherazade New", serif;
}

.q-mushaf-font-grid [data-q-mushaf-font="scheherazade-classic"] .q-mushaf-theme-swatch-aa {
    font-family: "Scheherazade Classic", serif;
}

.q-mushaf-font-grid [data-q-mushaf-font="kfgqpc-hafs"] .q-mushaf-theme-swatch-aa {
    font-family: "KFGQPC Hafs", serif;
}

.q-mushaf-font-grid [data-q-mushaf-font="kfgqpc-naskh"] .q-mushaf-theme-swatch-aa {
    font-family: "KFGQPC Naskh", serif;
}

.q-mushaf-font-grid [data-q-mushaf-font="me-quran"] .q-mushaf-theme-swatch-aa {
    font-family: "Me Quran", serif;
}

.q-mushaf-font-grid [data-q-mushaf-font="pdms-saleem"] .q-mushaf-theme-swatch-aa {
    font-family: "PDMS Saleem", serif;
}

/* Nested quick popover (mushaf.html/.js) - a real descendant of
   #q-mushaf-theme-popover now (see mushaf.html's own comment on why),
   so position:absolute here resolves against *that* popover's own box
   (its nearest positioned ancestor), not the frame. top/left are set
   inline in JS instead (mushaf.js positionTransitionPopover), not
   fixed here - a fixed `right` offset (tried first) only ever lined
   up under the trigger button in one text direction; the button's own
   *physical* position genuinely differs between rtl/ltr (grid
   auto-placement flows opposite ways), a single hardcoded value can't
   track both. Narrower than the shared 20rem/calc(100vw - 2rem)
   default - just a short list, no need for the full width. z-index
   above the theme popover it's nested in (both inherit 10 from
   .q-mushaf-jump-popover) so it's never hidden behind it while both
   are open. */
.q-mushaf-transition-popover {
    z-index: 11;
    width: 11rem;
    /* Très léger flou/transparence, ces 2 sous-popovers seulement (pas
       le popover "Thèmes et réglages" parent, resté opaque - voir
       commentaire plus haut sur --app-popover-*). ~97% opaque + flou
       minime: assez pour lire "en profondeur" sans repasser sous le
       contraste AA du texte/fond. */
    background: color-mix(in srgb, var(--app-popover-bg) 97%, transparent);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
}

/* Page-change animation picker (mushaf.html) - real radiogroup, list
   rows like .q-popover-item-icon above rather than the swatch tiles'
   own grid (4 short labels read better as a list than as squares). */
/* Current pick - bold label plus a checkmark, not colour alone
   (CLAUDE.md). aria-checked carries the same fact non-visually.
   ::after lands as the flex item; margin-inline-start:auto pushes it
   to the row's own end regardless of .q-popover-item-icon's own
   display:flex. Generic on the shared class (not "transition" in the
   name) - any radiogroup built from .q-popover-item rows gets this
   same treatment, .q-mushaf-theme-mode-list included. */
.q-popover-item[aria-checked="true"] {
    font-weight: 600;
}

.q-popover-item[aria-checked="true"]::after {
    content: "✓";
    margin-inline-start: auto;
    color: var(--app-link);
    font-size: calc(0.8125rem * var(--q-ui-scale, 1));

    flex-shrink: 0;
}

/* Style d'écriture arabe (mushaf.html) - same q-popover-list/-item rows
   as every plain radiogroup here, but real <label><input type="radio"
   class="sr-only"></label> pairs underneath (own report: native "change"
   event is what this radiogroup's own hx-trigger="change" fires on),
   not role="radio" buttons - :has() reads the sr-only input's own state
   instead of an aria-checked attribute, same checkmark convention as
   .q-popover-item[aria-checked="true"] above otherwise. */
.q-popover-item-choice {
    display: flex;
    align-items: center;
    cursor: pointer;
}

.q-popover-item-choice:has(:focus-visible) {
    outline: 2px solid var(--app-link);
    outline-offset: -2px;
}

.q-popover-item-choice:has(:checked) {
    font-weight: 600;
}

.q-popover-item-choice:has(:checked)::after {
    content: "✓";
    margin-inline-start: auto;
    color: var(--app-link);
    font-size: calc(0.8125rem * var(--q-ui-scale, 1));

    flex-shrink: 0;
}

/* Entry point into the "Personnaliser" 2nd view (mushaf.html/.js
   data-q-mushaf-theme-view-*, own comment there on why a drill-down and
   not tabs) - same full-width chip-row look .q-mushaf-personalize-reset
   further below already uses for a lone button sitting on this
   popover's own plain background. */
.q-mushaf-personalize-entry {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    width: 100%;
    padding: 0.5rem;
    border-radius: 8px;
    background: var(--app-popover-btn-bg);
    color: var(--app-popover-btn-text);
    font-size: calc(0.8125rem * var(--q-ui-scale, 1));

    font-weight: 600;
}

.q-mushaf-personalize-entry:hover,
.q-mushaf-personalize-entry:focus-visible {
    background: color-mix(in srgb, var(--app-popover-btn-text) 12%, var(--app-popover-btn-bg));
}

.q-mushaf-personalize-entry:focus-visible {
    outline: 2px solid var(--app-link);
    outline-offset: -2px;
}

/* Gras + Justifier, one segmented pill (same "chip" look/grid span as
   .q-mushaf-theme-size-toggle in the main view) - 2 real, independently-
   toggled buttons (aria-pressed), not mutually exclusive like axis/font
   further below, own comment on the markup for why role="group" still
   applies here regardless. Icon-only (own aria-label carries the text) -
   same convention as .q-mushaf-theme-quick-btn, this pair is too narrow
   for readable inline text at 2 buttons sharing 2 grid columns. */
.q-mushaf-personalize-toggle-pair {
    grid-column: span 2;
    display: flex;
    border-radius: 8px;
    background: var(--app-popover-btn-bg);
    overflow: hidden;
}

.q-mushaf-personalize-toggle-pair button {
    flex: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0.5rem 0;
    color: var(--app-popover-btn-text);
    /* Own report: same weight/line-height/font-size as .q-mushaf-theme-
       size-toggle button - this had none of the 3, defaulting to
       normal weight/inherited line-height/inherited ~1rem size instead
       of matching that sibling "chip" control family. #mark-toggles
       used to override this smaller (own history, own report reversed
       it) for "rub-el-hizb" - the only visible text in that group is
       "Pause" though (own comment, _mark_toggles.html - sajdah/rub/
       tatweel are icon-only), nothing here to actually wrap at this
       size. */
    font-weight: 600;
    line-height: 1;
    font-size: calc(0.8125rem * var(--q-ui-scale, 1));
}

/* :not(:last-child), not :first-child - equivalent for the original
   2-button Gras/Justifier pair, but #mark-toggles reuses this same
   class with 4 buttons (_mark_toggles.html's own as_buttons branch,
   Pause/Sajdah/Rub/Tatweel) - :first-child only ever drew 1 divider
   (between button 1 and 2), leaving 2↔3 and 3↔4 with none. */
.q-mushaf-personalize-toggle-pair button:not(:last-child) {
    border-inline-end: 1px solid var(--app-popover-divider);
}

.q-mushaf-personalize-toggle-pair button:hover:not(:disabled),
.q-mushaf-personalize-toggle-pair button:focus-visible {
    background: color-mix(in srgb, var(--app-popover-btn-text) 12%, var(--app-popover-btn-bg));
}

.q-mushaf-personalize-toggle-pair button[aria-pressed="true"] {
    background: color-mix(in srgb, var(--app-popover-btn-text) 18%, var(--app-popover-btn-bg));
}

/* iOS-style switch row (own report: image reference, "Accessibilité"
   settings screen - a visible label on one side, a real switch on the
   other, one option per line) - own new component, nothing existing to
   reuse (every other on/off control in the app so far is an icon-only
   aria-pressed button, own comment above on why that shape doesn't fit
   here: these 2 options - Contraste/Animations - need a readable label,
   not an icon guess). Real WAI-ARIA switch pattern (CLAUDE.md: custom
   widgets need the actual pattern, not a div pretending) - the whole
   row is one <button role="switch" aria-checked="...">, both the label
   and the visual track/thumb inside it, so the entire row is the hit
   target, not just the small track. inset-inline-start on the thumb
   (not left + a transform), so the slide direction flips for free under
   RTL instead of needing a 2nd, mirrored rule. Transition respects
   :root[data-motion="reduit"] * (input.css's own site-wide kill-switch)
   automatically, nothing extra needed here. */
.q-switch-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    width: 100%;
    padding: 0.625rem 0.5rem;
    border: none;
    border-radius: 8px;
    background: none;
    color: var(--app-popover-text);
    font: inherit;
    font-size: calc(0.8125rem * var(--q-ui-scale, 1));
    text-align: start;
    cursor: pointer;
}

.q-switch-row:hover:not(:disabled) {
    background: color-mix(in srgb, var(--app-popover-text) 8%, transparent);
}

.q-switch-row:focus-visible {
    outline: 2px solid var(--app-link);
    outline-offset: -2px;
}

.q-switch-row-label {
    min-width: 0;
}

.q-switch {
    flex-shrink: 0;
    position: relative;
    width: 2.5rem;
    height: 1.5rem;
    border-radius: 999px;
    background: var(--app-popover-btn-bg);
    transition: background-color 0.2s ease;
}

.q-switch-thumb {
    position: absolute;
    top: 2px;
    inset-inline-start: 2px;
    width: calc(1.5rem - 4px);
    height: calc(1.5rem - 4px);
    border-radius: 50%;
    background: #ffffff;
    box-shadow: 0 1px 2px rgb(0 0 0 / 25%);
    transition: inset-inline-start 0.2s ease;
}

.q-switch-row[aria-checked="true"] .q-switch {
    background: var(--app-link);
}

.q-switch-row[aria-checked="true"] .q-switch-thumb {
    inset-inline-start: calc(2.5rem - 1.5rem + 2px);
}

/* Own report: "l'effet disable comme pour les autres" - same opacity/
   pointer-events treatment as .q-surah-menu-item:disabled (surah-
   player.css) and every other disabled control here, covers both the
   permanent server-rendered disabled (marks_reliable false) and the
   temporary one hx-disabled-elt sets during the script-variant ajax
   call (surah_detail.html's own #surah-reading-script). */
.q-mushaf-personalize-toggle-pair button:disabled {
    opacity: 0.5;
    pointer-events: none;
}

/* Même traitement pour les steppers (taille/luminosité) et les 6
   palettes de "Thèmes et réglages" (base.html) - desactivés hors
   /ar/s/<n>/ et /ar/c (base.html's own DOMContentLoaded block juste
   après l'init "Apparence"), pas de règle :disabled pour ces deux-là
   avant ce cas d'usage. */
.q-mushaf-theme-size-toggle button:disabled,
.q-mushaf-theme-swatch:disabled {
    opacity: 0.5;
    pointer-events: none;
}

/* Colonnes multiples - moved into the quickrow (mushaf.html, own
   comment there), same radiogroup chip pattern as
   .q-mushaf-theme-axis-toggle further below rather than the iOS-style
   switch it replaces, so it follows whichever theme/light-dark the
   popover itself is in instead of a fixed --app-link blue. 2 explicit
   on/off choices (own report), aria-checked not aria-pressed. */
.q-mushaf-personalize-multicolumn-toggle {
    grid-column: span 2;
    display: flex;
    border-radius: 8px;
    background: var(--app-popover-btn-bg);
    overflow: hidden;
}

.q-mushaf-personalize-multicolumn-toggle button {
    flex: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0.5rem 0;
    color: var(--app-popover-btn-text);
}

.q-mushaf-personalize-multicolumn-toggle button:first-child {
    border-inline-end: 1px solid var(--app-popover-divider);
}

.q-mushaf-personalize-multicolumn-toggle button:hover,
.q-mushaf-personalize-multicolumn-toggle button:focus-visible {
    background: color-mix(in srgb, var(--app-popover-btn-text) 12%, var(--app-popover-btn-bg));
}

.q-mushaf-personalize-multicolumn-toggle button[aria-checked="true"] {
    background: color-mix(in srgb, var(--app-popover-btn-text) 18%, var(--app-popover-btn-bg));
}

/* Sleep timer toggle (surah_detail.html/surah_list.html, sleep-timer.js's
   own syncRadios) - own report: "quand le timer est off... icon timer
   off, et quand il est on... icone du timer en etat actif". Shared here
   (not surah-player.css) - surah_list.html doesn't load that sheet, same
   reasoning as this popover's own short-viewport rule further up. Icon
   shape itself changes, not just a color (CLAUDE.md: jamais la couleur
   comme seul signal). */
[data-q-sleep-timer-toggle] .q-icon-timer-on {
    display: none;
}
[data-q-sleep-timer-toggle][data-q-sleep-timer-on] .q-icon-timer-off {
    display: none;
}
[data-q-sleep-timer-toggle][data-q-sleep-timer-on] .q-icon-timer-on {
    display: block;
}
[data-q-sleep-timer-toggle][data-q-sleep-timer-on] {
    color: var(--app-link);
}

/* Police - opens the nested font popover (own comment on the markup),
   now a wide "chip" button (same look as .q-mushaf-theme-quick-btn)
   taking the other 2 grid columns instead of its own full-width list
   row. Just the current font name as visible content - no icon, same
   as this row's own aria-label-free previous version did. */
.q-mushaf-personalize-font-btn {
    grid-column: span 2;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.375rem;
    width: 100%;
    padding: 0.5rem;
    border-radius: 8px;
    background: var(--app-popover-btn-bg);
    color: var(--app-popover-btn-text);
    font-size: calc(0.8125rem * var(--q-ui-scale, 1));

}

.q-mushaf-personalize-font-btn:hover,
.q-mushaf-personalize-font-btn:focus-visible {
    background: color-mix(in srgb, var(--app-popover-btn-text) 12%, var(--app-popover-btn-bg));
}

.q-mushaf-personalize-font-btn:focus-visible {
    outline: 2px solid var(--app-link);
    outline-offset: -2px;
}

/* "Texte"/"Accessibilité et options de présentation" controls (reference
   screenshots, mushaf.html/.js) - the "Personnaliser" 2nd view's own
   content (own comment above), not a separate stage-and-commit <dialog>
   (own report: that dialog was copied from macOS Livres/Books' own "Aa"
   panel, but every control in Books' real panel applies instantly - no
   OK/Annuler, no separate preview text, the real page behind the
   popover already *is* the preview). --app-popover-* below, same as
   every other control on this page - reads whichever of the 6 theme
   tiles + light/dark mode is currently selected, not the *reading*
   page's own --app-surface/-text, which stays whatever the reader
   picked regardless of this chrome. */
.q-mushaf-personalize-group {
    /* Chip colour (--app-popover-btn-bg/-text), same as every other
       grouped control already sitting directly on this popover's own
       plain background (.q-mushaf-theme-size-toggle/-axis-toggle,
       .q-mushaf-theme-quick-btn) - this used to sit on top of the old
       "Personnaliser le thème" dialog's own tinted body zone instead
       (own comment further up on why that dialog is gone), which needed
       the *opposite* plain colour here to read as a distinct layer; now
       there's no tinted zone left to contrast against, only the
       popover's own plain background, so this needs the chip colour
       like everything else here instead. */
    border-radius: 10px;
    background: var(--app-popover-btn-bg);
    color: var(--app-popover-btn-text);
    overflow: hidden;
}

.q-mushaf-personalize-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    padding: 0.625rem 0.75rem;
    font-size: calc(0.875rem * var(--q-ui-scale, 1));

    /* --app-popover-btn-text, not the muted --app-popover-text every
       plain popover row elsewhere uses - this row sits on the chip-
       coloured .q-mushaf-personalize-group background now (own comment
       there), and --app-popover-text was only ever measured/tuned
       against the popover's own *plain* background, not this one. */
    color: var(--app-popover-btn-text);
}

.q-mushaf-personalize-row + .q-mushaf-personalize-row {
    border-top: 1px solid var(--app-popover-divider);
}

/* Espacement des lignes/mots, own line right under the Gras/Justifier
   quickrow (own report: moved out of #q-mushaf-customize-options, no
   visible text label above either now - aria-label moved onto each
   .q-mushaf-theme-size-toggle group itself, mushaf.html). Same stepper+
   dots pattern as the main view's own Arabic size (q-mushaf-theme-size-
   toggle/q-mushaf-arabic-size-dots, own comment on the markup), not the
   old native <input type="range"> pair this replaces - own
   .q-mushaf-theme-quickrow-row now too (own report), no more
   near-duplicate .q-mushaf-personalize-spacing-row/-col pair. */
/* Icon buttons reuse this same "A A" stepper chip (own report: wanted
   these 2 to look exactly like the font-size one) - svg sized off the
   button's own font-size instead of a fixed px, so the same first-child/
   last-child small/large rule above (own comment there) applies to
   these icons too without a 2nd copy of that rule. */
.q-mushaf-theme-size-toggle button svg {
    width: 1em;
    height: 1em;
    vertical-align: middle;
}

/* Same "chip button" colours as the swatch grid's own --app-popover-btn-*
   chrome every other control in this popover already uses. */
.q-mushaf-personalize-reset {
    width: 100%;
    text-align: center;
    padding: 0.5rem 1rem;
    border-radius: 8px;
    background: var(--app-popover-btn-bg);
    color: var(--app-popover-btn-text);
    font-size: calc(0.8125rem * var(--q-ui-scale, 1));
    font-weight: 600;
}

/* "Retour" (data-q-mushaf-personalize-back, moved down from the head
   above, own comment on the markup) + "Réinitialiser", own row - both
   share the same .q-mushaf-personalize-reset chip look now, this grid
   just splits the line in half between them instead of either one
   sitting full-width alone. */
.q-mushaf-personalize-footer-row {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 0.5rem;
}

/* Own report: same rounder radius as the mobile tap menu's own bottom-
   row icons (.q-mushaf-mobile-icon, further below) for these 3 full-
   width chip buttons, desktop and mobile alike - own report wanted
   them visually consistent with that menu's own look rather than the
   8px chip radius every other control in this popover still uses. */
.q-mushaf-personalize-entry,
.q-mushaf-personalize-reset {
    border-radius: 14px;
}

.q-mushaf-personalize-reset:hover,
.q-mushaf-personalize-reset:focus-visible {
    background: color-mix(in srgb, var(--app-popover-btn-text) 12%, var(--app-popover-btn-bg));
}

/* disabled (mushaf.js updateResetBtnState, whenever every field already
   matches PERSONALIZE_DEFAULTS) - the disabled attribute itself already
   carries the real (non-visual) signal, screen readers announce it
   regardless of styling here; opacity/cursor below are just the
   sighted/mouse-user cue. Hover/focus-visible above never match a
   disabled button (browsers don't dispatch those pseudo-classes for
   disabled form controls), so no extra override needed to silence them. */
.q-mushaf-personalize-reset:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

/* .q-popover-head/-title/-close (title+"✕" row) moved to popover.css
   (own report: "même structure et css comme /ar/c" - surah-player.css
   used to duplicate these under its own q-surah- prefix) - mushaf.html's
   own extra_head loads that file now, ahead of this one. */
/* Notes feature: the "Ajouter une note" bubble and the note-editing form
   that replaces it (mushaf.html/mushaf.js) - positioned via JS top/left
   (like .q-mushaf-jump-popover) but anchored to the current text
   selection's own rect instead of a fixed trigger corner, so no fixed
   top/right/left here. */
.q-mushaf-selection-popover {
    position: absolute;
    z-index: 20;
    display: flex;
    flex-direction: column;
    /* stretch, not center - every row shares the widest row's own
       width (reference screenshot: a clean rectangular menu), rather
       than each button hugging its own text and leaving a jagged edge. */
    align-items: stretch;
    min-width: 11rem;
    max-width: calc(100vw - 2rem);
    max-height: calc(100vh - 2rem);
    overflow-y: auto;
    /* No gap - same reasoning as .q-popover-list above (own comment
       there): a flex gap here only widened the space to the divider
       below a hovered row, never above it (that row's own border-top),
       so a hovered row's own distance to each neighbouring divider was
       unequal. */
}

/* Same brightness-filter cancellation as .q-mushaf-frame > .q-mushaf-jump-popover above. */
.q-mushaf-frame.q-mushaf-brightened > .q-mushaf-selection-popover {
    filter: brightness(calc(100 / var(--q-mushaf-brightness-pct, 100)));
}

/* Hover/focus fill as its own inset layer instead of this button's
   plain border-box background - a plain fill touched the divider below
   (own rule further down, .q-popover-item + .q-popover-item) flush on
   both sides, no breathing room. inset-block 0.25rem (shared row-
   spacing constant elsewhere in this file), inset-inline 0 so the fill
   stays as wide as the divider. Same technique .q-popover-item-row
   reuses further down. */
.q-mushaf-selection-popover > .q-popover-item {
    position: relative;
}

.q-mushaf-selection-popover > .q-popover-item:hover,
.q-mushaf-selection-popover > .q-popover-item:focus-visible {
    background: none;
}

.q-mushaf-selection-popover > .q-popover-item:hover::before,
.q-mushaf-selection-popover > .q-popover-item:focus-visible::before {
    content: "";
    position: absolute;
    inset-block: 0.25rem;
    inset-inline: 0;
    background: color-mix(in srgb, var(--app-popover-text) 12%, transparent);
    border-radius: inherit;
    z-index: -1;
}

/* "Ajouter une note" dialog - native <dialog>/showModal(), same
   fixed/inset:0/margin:auto centering trick every <dialog> on this page
   needs (Tailwind's preflight zeroes the UA stylesheet's own
   margin:auto dialog:modal otherwise relies on), display:none by
   default with a real [open] override further below (an unconditional
   flex-column here alone would render it - full box, fixed/centered -
   even closed, own past incident on the exact same trio elsewhere in
   this file). ::backdrop, not a filter-cancelling trick, handles
   dimming here - a showModal()'d <dialog> renders in the browser's own
   top layer, already outside frameEl's brightness filter, unlike the
   floating popovers further up this file. Height is natural/content-sized
   (own max-height + overflow-y below as a safety net only) rather than
   that dialog's fixed-height/3-scrolling-zones setup - this one's
   content (title/subtitle/textarea/colors/actions) is short and fixed,
   never needs its own internal scroll in practice. */
.q-mushaf-note-dialog {
    position: fixed;
    inset: 0;
    margin: auto;
    display: none;
    flex-direction: column;
    width: 26rem;
    max-width: calc(100vw - 2rem);
    max-height: calc(100vh - 4rem);
    overflow-y: auto;
    padding: 1.25rem;
    border-radius: 16px;
    border: 1px solid var(--app-popover-border);
    background: var(--app-popover-bg);
    color: var(--app-popover-text);
    box-shadow: 0 8px 28px rgb(0 0 0 / 20%);
}

.q-mushaf-note-dialog[open] {
    display: flex;
}

.q-mushaf-note-dialog::backdrop {
    background: rgb(0 0 0 / 45%);
}

.q-mushaf-note-dialog-title {
    text-align: center;
    margin-bottom: 0.25rem;
}

.q-mushaf-note-dialog-subtitle {
    margin: 0 0 1rem;
    text-align: center;
    font-size: calc(0.8125rem * var(--q-ui-scale, 1));

    color: var(--app-popover-text);
    opacity: 0.75;
    line-height: 1.6;
}

/* Flat/underline field (reference screenshot) instead of the all-round
   bordered box every other input on this page uses - rounded top
   corners only, no side/top border, a plain 1px bottom rule that
   thickens and switches to --app-link on focus (the field's only focus
   indicator, in place of an outline - still clearly visible, same
   reasoning input.css's own underline-style fields elsewhere use). */
.q-mushaf-note-dialog-textarea {
    display: block;
    width: 100%;
    resize: vertical;
    min-height: 7rem;
    border: 0;
    border-bottom: 1px solid var(--app-popover-border);
    border-radius: 8px 8px 0 0;
    background: var(--app-popover-btn-bg);
    color: var(--app-popover-btn-text);
    padding: 0.75rem 0.625rem;
    font-size: calc(0.875rem * var(--q-ui-scale, 1));

    font-family: inherit;
}

/* #q-plus-report-dialog (base.html) own report: fieldset "Type de
   problème" retiré (own report précédent) - le textarea suit
   directement le <h2> maintenant, sans l'air que ce fieldset donnait
   entre les deux. Scopé à ce seul dialog (pas la classe partagée
   .q-mushaf-note-dialog-textarea) - #q-surah-report-dialog
   (surah_detail.html) garde son fieldset, pas concerné. */
#q-plus-report-dialog .q-mushaf-note-dialog-textarea {
    margin-top: 0.75rem;
}

.q-mushaf-note-dialog-textarea:focus-visible {
    outline: none;
    border-bottom: 2px solid var(--app-link);
    padding-bottom: calc(0.75rem - 1px);
}

/* Own report: "je recois un email" - feedback d'envoi (sending/sent/
   error, popover.js:initReportDialog) sur les 2 dialogues "Signaler un
   problème". Couleur --app-link (déjà la couleur "info" utilisée
   ailleurs sur ce site, pas de --app-error dédié) - le texte lui-même
   ("Échec de l'envoi...") porte déjà le sens, la couleur n'est jamais le
   seul signal (CLAUDE.md). */
.q-mushaf-note-dialog-status {
    font-size: calc(0.8125rem * var(--q-ui-scale, 1));
    color: var(--app-link);
    margin: 0;
}

.q-mushaf-note-dialog-colors {
    display: flex;
    justify-content: center;
    gap: 0.5rem;
    margin-top: 0.875rem;
}

/* Toggle state (aria-pressed, mushaf.js) - a ring around the chosen
   color, same visual language as the swatch hover/focus ring further
   below, but persistent instead of only while hovered/focused. */
.q-mushaf-note-dialog-colors .q-mushaf-highlight-swatch[aria-pressed="true"] {
    box-shadow: 0 0 0 2px var(--app-popover-bg), 0 0 0 4px var(--app-popover-text);
}

.q-mushaf-note-form-actions {
    display: flex;
    justify-content: flex-end;
    gap: 0.5rem;
    margin-top: 1rem;
}

.q-mushaf-note-form-actions button {
    padding: 0.375rem 0.75rem;
    border-radius: 6px;
    border: 0;
    background: var(--app-popover-btn-bg);
    color: var(--app-popover-btn-text);
    font-size: calc(0.8125rem * var(--q-ui-scale, 1));

}

.q-mushaf-note-form-actions button:hover,
.q-mushaf-note-form-actions button:focus-visible {
    background: color-mix(in srgb, var(--app-popover-btn-text) 12%, var(--app-popover-btn-bg));
}

.q-mushaf-note-form-actions button:focus-visible {
    outline: 2px solid var(--app-link);
    outline-offset: 1px;
}

/* Note dialog's own compact color-toggle row (mushaf.html) - a plain
   round swatch, no visible text (own comment on .q-mushaf-color-dot
   below explains where the *named* version lives instead). Own "menu"
   sRGB values (user-supplied), a shade lighter/more pastel than the
   "applied" text-highlight colors above - reads better as a small UI
   chip than the deeper applied shade would. */
.q-mushaf-highlight-swatch {
    width: 1.5rem;
    height: 1.5rem;
    flex-shrink: 0;
    border-radius: 999px;
    border: 1px solid rgb(0 0 0 / 15%);
    padding: 0;
}

/* Selection popover's own color rows (mushaf.html) - reference
   screenshot (macOS-style text-selection menu): a plain menu-item row,
   .q-mushaf-selection-popover button's own generic style already gives
   the icon+label layout/hover/focus every other row here uses, this
   swatch button just adds a small leading color dot instead of an SVG
   icon. Same 5 "menu" sRGB values as the note dialog's own swatches
   above - a distinct class family (not .q-word-highlight-*, which is
   the "applied" text-highlight color and belongs on Quran text, not a
   menu chrome element) so there's no specificity fight to win against
   .q-mushaf-selection-popover button's own background. */
.q-mushaf-color-dot {
    display: inline-block;
    width: 0.85rem;
    height: 0.85rem;
    border-radius: 999px;
    flex-shrink: 0;
    border: 1px solid rgb(0 0 0 / 15%);
}

.q-mushaf-color-dot-yellow { background: #fcdc3f; }

.q-mushaf-color-dot-green { background: #99dc82; }

.q-mushaf-color-dot-blue { background: #95b9ff; }

.q-mushaf-color-dot-pink { background: #fc9bb4; }

.q-mushaf-color-dot-purple { background: #c5affb; }

/* Row + its own delete button as 2 real siblings, not a button nested
   inside a button (the delete action needs its own hit target distinct
   from "jump to this one") - shared by recherches récentes
   (mushaf.js renderRecent), Signets (renderBookmarks) and Notes
   (renderNotes), same row shape everywhere a row carries its own
   delete button. The hover/focus tint lives on this wrapper, not on
   the inner .q-popover-item alone (own rule further below cancels
   that one out) - .q-popover-item's own box only spans its own flex:1
   share, stopping short of the delete button's own space and leaving a
   gap in the middle of the hover rectangle; putting it here instead
   makes it span the *whole* row, delete button included, so it paints
   one continuous background underneath it rather than stopping short. */
.q-popover-item-row {
    display: flex;
    align-items: center;
    gap: 0.25rem;
    /* Square, not rounded - this row sits inside a divided list
       (.q-popover-list > li + li's own straight border-top), same as
       .q-popover-item's own canonical square rows (top of this file)
       - a rounded hover box clashed visibly against that straight
       divider line. */
    border-radius: 0;
    /* Anchors the hover/focus fill pseudo-element below. */
    position: relative;
}

/* Same pseudo-element technique as .q-mushaf-selection-popover's own
   items above - background-clip: content-box would've inset this fill
   by the <li>'s own padding-inline too (for the delete button, above),
   leaving it narrower than the divider it sits under. */
/* :has(:focus-visible), not :focus-within - own report on the sleep-
   timer popover: "on dirait un hover" - sleep-timer.js's open() (and
   every other roving-tabindex radiogroup here) calls .focus() on the
   already-checked item as soon as the popover opens, no pointer
   involved. :focus-within doesn't care how an element got focused, so
   that programmatic call alone kept this fill lit the entire time,
   reading as a stuck/phantom hover. :focus-visible's own browser
   heuristic only matches when focus should actually be shown (real
   keyboard nav), fixing every popover built on this row at once instead
   of one at a time.
   #q-surah-menu-popover's own rows stay excluded below regardless (own
   earlier report: "le premier élément reste comme hover") - a plain
   button each, no 2nd control to give this rule a reason to exist there
   (unlike bookmarks/notes rows, own comment above - a delete button
   living *next to* the main item, where focusing either one should
   still fill the whole row), and an earlier content:none override for
   that one popover suppressed the box outright, silencing :hover on it
   too the instant it also held focus (own report: "meme quand je hover
   il ne prend pas le style"). .q-surah-menu-item's own :focus-visible
   outline (surah-player.css) still marks focus correctly without this. */
.q-popover-item-row:hover::before,
.q-popover-item-row:not(#q-surah-menu-popover *):has(:focus-visible)::before {
    content: "";
    position: absolute;
    inset-block: 0.25rem;
    inset-inline: 0;
    background: color-mix(in srgb, var(--app-popover-text) 12%, transparent);
    border-radius: inherit;
    z-index: -1;
}

.q-popover-item-row > .q-popover-item,
/* .q-surah-menu-item(-sub) - the home page's own flyout trigger rows
   (Langue/Traduction/Affichage/Lecture/Accessibilité, base.html), now
   carrying this class too (own report: "meme style partout") - without
   this, the row's own display:flex (above) left the button sized to its
   own content instead of the full row width (no flex:1 of its own),
   the real root cause of the old "hitbox/hover misbehave" regression
   (own report there) - not the ::before fill itself, which was already
   a non-issue (own [data-q-*-wrap] rule further below wins that fight
   by source order regardless). */
.q-popover-item-row > .q-surah-menu-item {
    flex: 1;
    min-width: 0;
}

.q-popover-item-row > .q-popover-item:hover,
.q-popover-item-row > .q-popover-item:focus-visible,
.q-popover-item-row > .q-surah-menu-item:hover,
.q-popover-item-row > .q-surah-menu-item:focus-visible {
    background: none;
}

/* Flyout trigger rows (Récitant/Thèmes/Lecture/Partager/Accessibilité/
   Langue, surah-player.css; Langue/Affichage/Accessibilité/Lecture,
   base.html) - own report: "le hover se fait sur le li" pour les
   rows normales "et sur le bouton" pour celles-ci: .q-surah-menu-item's
   own :hover fill (top of this file) is inset to the BUTTON's own box
   (padding:0.5rem, no li-level padding to match) while every other row's
   fill is the row-wide ::before above, a visibly different size. Same
   ::before technique here, keyed off the existing [data-q-*-wrap]
   attribute selectors (already position:relative, surah-player.css/
   input.css) rather than adding .q-popover-item-row to these <li>s - that
   class already broke this exact row's hitbox/hover once before (own
   report, base.html/surah_detail.html comments on these same rows), not
   worth risking again just to reuse a name. */
[data-q-surah-share-wrap]:hover::before,
[data-q-surah-share-wrap]:focus-within::before,
[data-q-surah-reciter-wrap]:hover::before,
[data-q-surah-reciter-wrap]:focus-within::before,
[data-q-surah-reading-wrap]:hover::before,
[data-q-surah-reading-wrap]:focus-within::before,
[data-q-surah-theme-wrap]:hover::before,
[data-q-surah-theme-wrap]:focus-within::before,
[data-q-surah-accessibility-wrap]:hover::before,
[data-q-surah-accessibility-wrap]:focus-within::before,
[data-q-surah-langue-wrap]:hover::before,
[data-q-surah-langue-wrap]:focus-within::before,
[data-q-surah-sourates-wrap]:hover::before,
[data-q-surah-sourates-wrap]:focus-within::before,
[data-q-flyout-wrap]:hover::before,
[data-q-flyout-wrap]:focus-within::before {
    content: "";
    position: absolute;
    inset-block: 0.25rem;
    inset-inline: 0;
    background: color-mix(in srgb, var(--app-popover-text) 12%, transparent);
    border-radius: 8px;
    z-index: -1;
}

[data-q-surah-share-wrap] > .q-surah-menu-item:hover,
[data-q-surah-reciter-wrap] > .q-surah-menu-item:hover,
[data-q-surah-reading-wrap] > .q-surah-menu-item:hover,
[data-q-surah-theme-wrap] > .q-surah-menu-item:hover,
[data-q-surah-accessibility-wrap] > .q-surah-menu-item:hover,
[data-q-surah-langue-wrap] > .q-surah-menu-item:hover,
[data-q-surah-sourates-wrap] > .q-surah-menu-item:hover,
[data-q-flyout-wrap] > .q-surah-menu-item:hover,
[data-q-surah-share-wrap] > .q-surah-menu-item[aria-expanded="true"],
[data-q-surah-reciter-wrap] > .q-surah-menu-item[aria-expanded="true"],
[data-q-surah-reading-wrap] > .q-surah-menu-item[aria-expanded="true"],
[data-q-surah-theme-wrap] > .q-surah-menu-item[aria-expanded="true"],
[data-q-surah-accessibility-wrap] > .q-surah-menu-item[aria-expanded="true"],
[data-q-surah-langue-wrap] > .q-surah-menu-item[aria-expanded="true"],
[data-q-surah-sourates-wrap] > .q-surah-menu-item[aria-expanded="true"],
[data-q-flyout-wrap] > .q-surah-menu-item[aria-expanded="true"] {
    background: none;
}

/* Note row's own color dot (mushaf.js renderNotes) - leading dot in
   .q-popover-item-meta itself now, same .q-mushaf-color-dot the
   selection popover's own color rows use (own comment there), not a
   whole extra line-height tag (asked for explicitly - a note row
   already has up to 3 lines, a 4th just for the color name read as
   wasted space). .sr-only text right next to it (mushaf.js) keeps the
   color's name in the accessible name either way - still never colour
   alone as the only signal (CLAUDE.md), just off-screen instead of
   off the page. */
.q-popover-item-meta .q-mushaf-color-dot {
    margin-inline-end: 0.25rem;
    vertical-align: -1px;
}

/* Canonical Sourates-list row chrome - own report: "il doivent utiliser
   le même code css, même structure" - shared verbatim between this
   page's own #q-mushaf-surah-popover and surah_detail.html's own
   #q-mushaf-surah-popover (mushaf.css already loaded there, own comment
   further below on .q-popover-item-row) instead of 2 near-identical
   copies drifting apart (own report, caught live: different hover
   color/opacity, different number/translit color token, checkmark on
   the wrong side, different search-field margin). surah-player.css
   keeps only what's genuinely specific to that page - the favoris star
   (.q-surah-popover-fav*) and its own filter toggle, real DOM
   differences (that page's own <a href>/aria-current="page" navigation
   vs this page's own <button>/page-jump - own comment there on why
   neither becomes the other). */
/* Own report: "des petits messages brefs... un minuteur en live" - shared
   by both reciter fieldsets (base.html/surah_detail.html), revealed only
   for the duration of the request (player.js, qReciterStatusStart/-Stop).
   Same muted small-text look as .q-surah-popover-search's own color right
   below - both sit in the exact same spot above the reciter grid. */
.q-reciter-status {
    margin: 0 0 0.5rem;
    font-size: 0.8rem;
    color: var(--app-sub);
}

.q-surah-popover-search {
    display: flex;
    align-items: center;
    margin: 0 0 0.5rem;
    border: 1px solid var(--app-border);
    border-radius: 6px;
    background: var(--app-bg);
    color: var(--app-sub);
}

.q-surah-popover-search:focus-within {
    border-color: var(--app-link);
}

.q-surah-popover-search input {
    flex: 1;
    min-width: 0;
    border: 0;
    background: transparent;
    padding: 0.5rem 0.625rem;
    color: var(--app-text);
    font-size: calc(0.875rem * var(--q-ui-scale, 1));
}

.q-surah-popover-search input:focus-visible {
    outline: none;
}

.q-surah-popover-search input::-webkit-search-cancel-button {
    display: none;
}

.q-surah-popover-search svg {
    flex-shrink: 0;
    margin-inline-end: 0.625rem;
}

.q-popover-list {
    display: flex;
    flex-direction: column;
    max-height: 18rem;
    overflow-y: auto;
    margin: 0;
}

/* #q-surah-menu-popover (/ar/s/X, surah_detail.html) / #q-panel-plus
   (every page's own "Réglages", base.html) - a short menu of a handful
   of rows, never the long/scrollable kind .q-popover-list's own base
   max-height:18rem/overflow-y:auto above is really for (114-row
   Sourates, notes, bookmarks...). That overflow-y:auto implicitly forces
   overflow-x to clip too, per spec (setting only one axis to auto/scroll
   computes the other to auto as well, even left at its default
   "visible") - silently clipping any flyout submenu that pokes out
   sideways on purpose (inset-inline-end:100%, .q-surah-menu-submenu
   above). Same trap one level up too (own report, regression: a short-
   viewport fallback elsewhere gave the popover *itself* overflow-y:auto,
   re-clipping the exact same flyouts at the popover's own box instead of
   the list's) - both overridden here, in the one file both pages already
   share, instead of 2 near-identical ID-scoped copies living in
   surah-player.css and input.css (own report: "ca doit marcher
   automatiquement avec le code en commun"). */
#q-surah-menu-popover,
#q-surah-menu-popover > .q-popover-list,
#q-panel-plus,
#q-panel-plus > .q-popover-list {
    overflow: visible;
    max-height: none;
}
/* No divider, every row rounded - the real default now (own report:
   "on ne peut pas la mettre par défaut ?"): every popup on the site
   except #q-mushaf-jump-popover's own recent/search-results lists
   (own override further below, the one genuinely long/scrollable case
   a divider actually helps read) already wanted this exact look -
   Options/Sourates/Signets/Notes/Partager/Police/Animation/Apparence/
   sleep-timer/q-panel-langue/q-panel-plus were each opting into it one
   ID selector at a time before. Change this once, it changes
   everywhere that doesn't explicitly opt back out. */
.q-popover-list > li.q-popover-item-row,
.q-popover-list > li > .q-popover-item {
    border-radius: 8px;
}

.q-surah-popover-item {
    display: block;
    flex: 1;
    min-width: 0;
    width: 100%;
    text-align: start;
    padding: 0.5rem;
    border-radius: 0;
    font-size: calc(0.875rem * var(--q-ui-scale, 1));
    line-height: 1.5;
    color: var(--app-popover-text);
    text-decoration: none;
}

.q-surah-popover-item[aria-current="page"] {
    font-weight: 600;
}

/* No href/click at all on the current row (surah_detail.html's own
   aria-disabled="true", this page's own updateSurahHighlight never
   wires a click for it either since it's already the open surah). */
.q-surah-popover-item[aria-disabled="true"] {
    pointer-events: none;
    cursor: default;
}

.q-surah-popover-item:focus-visible {
    outline: 2px solid var(--app-link);
    outline-offset: -2px;
}

/* padding-inline-end (own report: "très collé au bord", /ar/c et
   /ar/s/X/v/X - visible surtout au survol) - .q-surah-popover-item juste
   avant porte son propre padding:0.5rem (popover.css) mais cette marque
   est un <span> frère dans le même li.q-popover-item-row (flex, gap
   0.25rem seulement), sans aucun padding à elle : rien ne la séparait du
   bord de la ligne/popover côté fin, contrairement au texte du bouton
   qui, lui, respire côté début. Même 0.5rem que ce padding de bouton,
   pour une marge symétrique des deux côtés de la ligne. */
.q-surah-popover-current-mark {
    flex-shrink: 0;
    padding-inline-end: 0.5rem;
    color: var(--app-link);
    font-size: calc(0.8125rem * var(--q-ui-scale, 1));
    position: relative;
}

/* Concordance's own surah-filter popover (_concordance.html, own report:
   "le loader ne doit pas être comme ça, au moins il doit être à la place
   du check") - htmx puts .htmx-request straight on the clicked
   .q-surah-popover-item (fetchConcordance's own source, ayah_detail.html),
   the ✓ mark is a later SIBLING in the same li (button then span, no
   :has() needed) - the ~ combinator alone reaches it. Same q-spin
   keyframe as .q-btn-loadable/.q-choice-loadable (top of this file),
   just anchored to this smaller span instead of the whole row/button so
   the number/name text stays fully readable while it spins. */
.q-surah-popover-item.htmx-request ~ .q-surah-popover-current-mark {
    visibility: hidden;
}
.q-surah-popover-item.htmx-request ~ .q-surah-popover-current-mark::after {
    content: "";
    visibility: visible;
    position: absolute;
    inset: 0;
    margin: auto;
    width: 0.75rem;
    height: 0.75rem;
    border: 2px solid color-mix(in srgb, var(--app-text) 30%, transparent);
    border-top-color: var(--app-text);
    border-radius: 50%;
    animation: q-spin 0.7s linear infinite;
}

.q-surah-popover-number {
    display: inline-block;
    min-width: 1.5rem;
    color: var(--app-popover-text);
    font-variant-numeric: tabular-nums;
}

.q-surah-popover-translit {
    display: block;
    margin-inline-start: 1.5rem;
    font-size: calc(0.75rem * var(--q-ui-scale, 1));
    color: var(--app-popover-text);
}

/* Signets groups by day (own heading rows above) - a divider between
   every single bookmark inside the same day read as too many lines,
   kept only right before each new day's own heading instead (never
   between 2 plain items, never between a heading and its own first
   item). No general divider to cancel out here anymore (.q-popover-list
   itself defaults to none, canonical block above) - this only ever
   *adds* one, scoped to the group boundary specifically. */
#q-mushaf-bookmarks-popover .q-popover-list > li + .q-mushaf-bookmarks-group {
    border-top: 1px solid var(--app-popover-divider);
}

/* .q-popover-list itself is defined at the top of this file (canonical
   block) - .q-mushaf-transition-list (Animation/Apparence's own real
   WAI-ARIA radiogroup) reuses that exact same class now instead of
   carrying a 2nd, parallel copy of this layout. */
/* Divider/inset/rounding below - a flat list of .q-popover-item buttons
   with no <li> at all (the selection menu, its own comment on
   mushaf.html explains why it isn't a <ul>). `.q-popover-item +
   .q-popover-item` (border on whichever item *has* a preceding
   sibling), not `:not(:last-child)` (border on every item *except*
   whichever is last). The <ul class="q-popover-list"><li> DOM shape
   every OTHER popover list uses gets this same divider/rounding
   treatment from its own rule further below instead (own class, own
   selector, not folded into this one - own report: "dans la langue on
   trouve une classe surah" was the old q-surah- prefixed name for
   that shared class, since renamed here to q-popover-list). */
.q-mushaf-selection-popover > .q-popover-item + .q-popover-item {
    border-top: 1px solid var(--app-popover-divider);
}


/* First/last row's own hover/focus/"current" background follows the
   popover's own curve (16px, .q-mushaf-jump-popover/.q-mushaf-
   selection-popover) instead of staying square at that one edge -
   these popovers don't clip their own content to that curve (no
   overflow:hidden), so a square corner right at the top/bottom
   otherwise pokes past it. Middle rows stay square (own comment above
   on why - the divider clash). */

.q-mushaf-selection-popover > .q-popover-item:first-child {
    border-top-left-radius: 8px;
    border-top-right-radius: 8px;
}

.q-mushaf-selection-popover > .q-popover-item:last-child {
    border-bottom-left-radius: 8px;
    border-bottom-right-radius: 8px;
}

/* The one real exception to .q-popover-list's own default (canonical
   block, top of this file, own report: "on ne peut pas la mettre par
   défaut ?") - #q-mushaf-jump-popover's own recent-searches/search-
   results lists (data-q-mushaf-recent-list/-search-results, mushaf.html)
   are the one genuinely open-ended, potentially-long list left (unlike
   every fixed-length short list elsewhere, own report), so a divider
   between rows and square middle rows still earns its keep here. Only
   the last row rounds (no search field sits visually above it the way
   the trigger/head do, own original reasoning). */
#q-mushaf-jump-popover .q-popover-list > li.q-popover-item-row,
#q-mushaf-jump-popover .q-popover-list > li > .q-popover-item {
    border-radius: 0;
}
#q-mushaf-jump-popover .q-popover-list > li + li {
    border-top: 1px solid var(--app-popover-divider);
}
#q-mushaf-jump-popover .q-popover-list > .q-popover-item-row:last-child,
#q-mushaf-jump-popover .q-popover-list > li:last-child > .q-popover-item {
    border-bottom-left-radius: 8px;
    border-bottom-right-radius: 8px;
}

/* Same block/full-width/start-aligned layout as the canonical
   .q-popover-item default (top of this file) - nothing left to add
   here. */
.q-popover-item mark {
    background: none;
    color: inherit;
    font-weight: 700;
}

/* Surah name / verset / page - own line above the snippet, small and
   muted like a byline (font-size below .q-popover-item-text's own,
   unset/inherited). Direction stays whatever the surrounding page is -
   only the surah-name span inside it (mushaf.js, its own lang="ar"
   dir="rtl") is forced Arabic. */
.q-popover-item-meta {
    display: block;
    font-size: calc(0.75rem * var(--q-ui-scale, 1));

    color: var(--app-sub);
    margin-bottom: 0.125rem;
}

.q-popover-item-text {
    display: block;
    font-size: calc(0.9375rem * var(--q-ui-scale, 1));

}

/* Notes/bookmarks rows only (.q-popover-item-row - search results/
   recent searches use plain <li>, unaffected) - a note's own quote/
   text line clamped to a single line with an ellipsis instead of
   wrapping the full thing (asked for explicitly, "un petit extrait"),
   these rows are a preview meant to open the real note, not show it
   whole inline. Surah name reuses this same class in the bookmarks
   list (renderBookmarks) - always short, this never visibly clips it. */
.q-popover-item-row .q-popover-item-text {
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

/* Mobile only (own report) - desktop's floating popover (own base rule
   further above, position:absolute/top set once at open) never moved
   from a growing results list to begin with, only the mobile drilldown
   sheet did (bottom-anchored, own comment further below) - min-height
   here on top of that would just force the popover open onto an
   otherwise-empty 18rem box on desktop it never needed. The popover box
   itself, not its inner .q-mushaf-search-results list (own report:
   first attempt, wrong element - the input sitting above that list kept
   sliding as the list itself grew/shrank with each keystroke, min-height
   on the list alone never reserved space for anything above it).
   #q-mushaf-jump-popover specifically, not the bare .q-mushaf-jump-popover
   class every other dropdown here also carries (Sourates/Signets/Notes/
   Partager, own comment on that shared class further above). */
@media (max-width: 1023px) {
    #q-mushaf-jump-popover {
        min-height: 18rem;
    }
}

/* "Thèmes et réglages" quick-picker (mushaf.html/mushaf.js, surah_
   detail.html/surah-player.js's own copy, AND now every _ayah_card.html
   instance site-wide - index/ayah_detail/root_detail/lemma_detail/
   word_detail/search) - each preset overrides the *same* --app-*
   custom properties input.css's own :root[data-theme] rules define,
   scoped to whichever of these 3 contexts carries the attributes rather
   than :root, so it only ever repaints that one frame/card, never the
   rest of the page/site the way actually flipping the site-wide
   data-theme/quran.theme would - not the site's existing Clair/Sombre/
   Sépia/Gris doux/Crème/Auto set (see mushaf.html's own comment on why
   "Intense" is the one exception, same bg/fg as "Original" - real
   distinction there is font-weight, .q-mushaf-theme-swatch-intense
   below).

   Single source for all 3 contexts now (own report: "au lieu de
   dupliquer les theme pour chaque page mets les dans un fichier
   unique... meme si il sont deja dupliquer dans l'existant, factorise
   les") - mushaf.css's own .q-mushaf-frame[...] and surah-player.css's
   own .q-surah-reading-frame[...]/html:root.q-surah-reading-frame[...]
   used to each carry a byte-for-byte identical copy of everything
   below, only the selector prefix differed (own comment there on why
   html:root is needed specifically for the surah page - frameEl IS
   :root there, not a descendant div, real specificity collision with
   input.css's own :root[data-theme] otherwise). [data-q-ayah-card] is
   the 3rd branch - already on every _ayah_card.html root div
   (popover.js's own __qSyncAyahCardFrames sets/updates these same
   attributes on every one it finds, gated behind quran.mushafTheme/
   quran.theme/quran.mushafBold/quran.mushafJustify, the exact same
   localStorage keys mushaf.js/surah-player.js's own "Personnaliser"
   panels already read/write - one shared preference, not a 3rd
   independent toggle).

   Each of the 6 themes now has its own light/dark pair (12 blocks
   below) - data-q-mushaf-mode ("Apparence" quick popover) toggles
   whichever theme is *currently selected* between its own 2 variants,
   not a single global light/dark swap. Every pair only sets --app-bg/
   --app-text as real literals (real sRGB values, measured on an actual
   display, not eyeballed hex) - --app-surface/--app-link/--app-sub/
   --app-border are all *derived* from those 2 right here in this one
   shared rule, not hand-picked per theme: --app-link mirrors text
   (matches 5 of the previous 6 hand-tuned themes' own values already;
   the one exception, "Papier"'s old distinct brown accent, is gone
   along with the rest of its old hand-tuned palette), --app-border an
   18% text-into-bg mix (subtle, decorative only, no contrast floor to
   hit).

   --app-sub is real *readable secondary text* though (surah-remaining
   counter, search result meta lines, etc.) - CLAUDE.md's "check any
   new colour" rule means an actual computed check here, not a guess:
   a single 58% mix (originally chosen to match "Original"'s own old
   hand-tuned ratio) came out under 4.5:1 for 6 of these 12 pairs once
   actually measured - "Tranquille" especially, its own already-muted
   135ish-on-black text (deliberately low headroom, own design intent)
   leaves a 58% *further* mute of that well below AA. --app-sub-mix
   splits it in two instead of forcing one number to fit both: 70%
   clears every other theme with room to spare (worst case 4.79:1),
   84% is what "Tranquille" itself actually needs (worst case 4.65:1) -
   both confirmed by computing real WCAG contrast ratios for all 12
   pairs, not eyeballed. */
.q-mushaf-frame,
html:root.q-surah-reading-frame,
/* Scoped to inside a reading-page frame only (own report: "les themes
   s'applique que sur /ar/s et /ar/s/1", not every [data-q-ayah-card]
   site-wide) - __qSyncAyahCardFrames (popover.js, comment above) still
   sets these data attributes on every ayah card it finds regardless of
   page, but without a .q-mushaf-frame/.q-surah-reading-frame/
   html.q-reading-page ancestor here to match against, that's inert
   everywhere else. html.q-reading-page (own report: "active les
   options... sur ces pages aussi" - search/ayah_detail/word_detail/
   lemma_detail/root_detail) added here to match the per-palette
   overrides a few rules below (html.q-reading-page [data-q-ayah-card]
   [data-q-mushaf-theme="..."][data-q-mushaf-mode="..."]), which already
   expected this base rule to also fire alongside them - card-scoped
   only (the [data-q-ayah-card] descendant selector), never the page
   background itself. */
.q-mushaf-frame [data-q-ayah-card][data-q-mushaf-theme][data-q-mushaf-mode],
html:root.q-surah-reading-frame [data-q-ayah-card][data-q-mushaf-theme][data-q-mushaf-mode],
html.q-reading-page [data-q-ayah-card][data-q-mushaf-theme][data-q-mushaf-mode] {
    /* Real `color`, not just the --app-text/--color-app-text custom
       properties below - .q-arabic-text/.ayah-block never set their own
       color (input.css, font-size only), they just inherit the plain
       `color` property. That property is a normal (non-custom)
       inherited property: its computed value is resolved *once*,
       wherever it's actually declared (<body class="text-app-text">,
       base.html - color: var(--color-app-text) there), then that
       already-resolved value cascades down unchanged - a card-level
       --app-text/--color-app-text override never reaches it unless
       `color` itself is re-declared this low too. Same reasoning as
       .q-mushaf-frame's own `color: var(--app-text)` a few lines below
       in mushaf.css (own comment there), just needed explicitly here
       too since this selector didn't have its own copy of that rule. */
    color: var(--app-text);
    --app-surface: var(--app-bg);
    --app-sub-mix: 70%;
    --app-sub: color-mix(in srgb, var(--app-text) var(--app-sub-mix), var(--app-bg));
    --app-border: color-mix(in srgb, var(--app-text) 18%, var(--app-bg));
    /* Own report: "le theme selectionne n'est pas applique au bloque de
       l'ayah... la font aussi" - _ayah_card.html (unlike mushaf.html/
       surah_detail.html's own hand-authored CSS, which reads --app-*
       directly) uses Tailwind utility classes (bg-app-surface/text-
       app-text/border-app-border/font-quran) that compile to var(--
       color-app-surface) etc (tailwind.css) - a *second* indirection
       layer, declared exactly once at :root's own @theme block
       (input.css). Custom-property inheritance passes each element's
       own *computed* value down, not a live pointer that keeps re-
       resolving per descendant - :root's own --color-app-surface
       computed once there (using :root's own --app-surface) is what
       every descendant inherits unless something re-declares --color-
       app-surface itself closer to that descendant. Exact same "re-
       resolve-here" trick mushaf.css's own .q-mushaf-frame already
       needed for color/--font-quran (own comment there: "redefining a
       custom property deeper in the tree doesn't retroactively change
       an ancestor's already-inherited computed value on its own") -
       just the fuller set here since a card can be styled by Tailwind
       utilities this shared rule's own --app-*/--font-quran overrides
       alone never reach. */
    --color-app-bg: var(--app-bg);
    --color-app-surface: var(--app-surface);
    --color-app-text: var(--app-text);
    --color-app-sub: var(--app-sub);
    --color-app-border: var(--app-border);
    --font-quran: var(--app-font-arabic);
}
/* --app-link/--color-app-link collapse (link color -> plain text color)
   kept separate from the shared block above, and only for the 2 real
   full-immersion reading frames (/ar/s/X, /ar/c - no _ayah_card.html
   there, own report: ".ayah-block n'existe pas dans surah_detail.html/
   mushaf.html", so this never reaches a real link on those pages) - own
   report: "le theme neutral a perdu la couleur des lien qui est celle de
   toute l'app" after html.q-reading-page got added to the shared block
   above (search/ayah_detail/etc): unlike those 2 pages, _ayah_card.html's
   [data-q-ayah-card] wrapper also contains real site-navigation links as
   siblings of .ayah-block (the title/reference <a data-slot="href">,
   shared_roots' own <a> list) that must always keep the app's real
   --app-link blue, verse-reading theme or not - collapsing it at the
   whole-card level like here would silently mute those too. */
.q-mushaf-frame [data-q-ayah-card][data-q-mushaf-theme][data-q-mushaf-mode],
html:root.q-surah-reading-frame [data-q-ayah-card][data-q-mushaf-theme][data-q-mushaf-mode] {
    --app-link: var(--app-text);
    --color-app-link: var(--app-link);
}
.q-mushaf-frame[data-q-mushaf-theme="dark"],
.q-surah-reading-frame[data-q-mushaf-theme="dark"],
html.q-reading-page [data-q-ayah-card][data-q-mushaf-theme="dark"] {
    --app-sub-mix: 84%;
}
/* Own report: "chaque theme n'a pas sa propre couleur de lien" - the
   collapse rule above (--app-link: var(--app-text)) is right for the 2
   full reading frames (verse text only, no real nav link inside) but
   wrong for these cards, whose title/reference link must stay a real
   distinguishable link, themed rather than either neutral-blue-always or
   muted-to-text. Same code-name/label trap as the text-colour block
   above: data-q-mushaf-theme="neutral" (labelled "Neutre") needs NO
   entry here - own report "la couleur du lien du theme neutral [est]
   celui de l'app" - it never matches this selector, so it keeps
   inheriting the site's own plain --app-link (input.css :root)
   untouched. "original" (labelled "Original") DOES get its own entry
   below instead, alongside the other 4 - own report "5 autres
   différents", all 5 mutually distinct hues, not just distinct from
   neutral. Same selector/value order as the bg/text rules below (source
   order after the collapse rule above - equal selector specificity, last
   declaration wins) so these rules only ever affect this card selector,
   never .q-mushaf-frame/.q-surah-reading-frame themselves. Every pair
   re-verified for real WCAG contrast (≥4.5:1) against the site's own
   plain --app-bg, not eyeballed. */
html.q-reading-page [data-q-ayah-card][data-q-mushaf-theme="original"][data-q-mushaf-mode="light"] {
    --app-link: #6a1bb8;
    --color-app-link: var(--app-link);
}
html.q-reading-page [data-q-ayah-card][data-q-mushaf-theme="original"][data-q-mushaf-mode="dark"] {
    --app-link: #d0a9ff;
    --color-app-link: var(--app-link);
}
html.q-reading-page [data-q-ayah-card][data-q-mushaf-theme="dark"][data-q-mushaf-mode="light"] {
    /* Own report: "les liens de ce theme en mode claire ne sont pas
       claire" - #c9dcff (own earlier design pass) was contrast-checked
       against this theme's own historical bg (#4a4a4d, its full-page
       reading frame background) instead of the real card background
       (site's plain --app-bg, #ffffff here) once cards stopped painting
       their own bg - 1.38:1 against real white, nearly invisible.
       #2851b8 re-verified against the real #ffffff (7.1:1). */
    --app-link: #2851b8;
    --color-app-link: var(--app-link);
}
html.q-reading-page [data-q-ayah-card][data-q-mushaf-theme="dark"][data-q-mushaf-mode="dark"] {
    --app-link: #8fb8ff;
    --color-app-link: var(--app-link);
}
html.q-reading-page [data-q-ayah-card][data-q-mushaf-theme="paper"][data-q-mushaf-mode="light"] {
    --app-link: #1a4fb8;
    --color-app-link: var(--app-link);
}
html.q-reading-page [data-q-ayah-card][data-q-mushaf-theme="paper"][data-q-mushaf-mode="dark"] {
    --app-link: #9dc4ff;
    --color-app-link: var(--app-link);
}
html.q-reading-page [data-q-ayah-card][data-q-mushaf-theme="warm"][data-q-mushaf-mode="light"] {
    --app-link: #8a4b12;
    --color-app-link: var(--app-link);
}
html.q-reading-page [data-q-ayah-card][data-q-mushaf-theme="warm"][data-q-mushaf-mode="dark"] {
    --app-link: #ffcf8a;
    --color-app-link: var(--app-link);
}
html.q-reading-page [data-q-ayah-card][data-q-mushaf-theme="cream"][data-q-mushaf-mode="light"] {
    --app-link: #1f6f4a;
    --color-app-link: var(--app-link);
}
html.q-reading-page [data-q-ayah-card][data-q-mushaf-theme="cream"][data-q-mushaf-mode="dark"] {
    --app-link: #8fe0bd;
    --color-app-link: var(--app-link);
}
/* --app-popover-* (bg/text/divider/btn-text/btn-bg) - the popover
   chrome's own separate palette (mushaf.js/surah-player.js-driven
   popovers: jump/surah/bookmarks/share/theme/transition/theme-mode),
   not the reading page's --app-bg/--app-text above. Real measured sRGB
   values per theme, same "check any new colour" rule as --app-sub's
   own comment above. */
.q-mushaf-frame[data-q-mushaf-theme="original"][data-q-mushaf-mode="light"],
.q-surah-reading-frame[data-q-mushaf-theme="original"][data-q-mushaf-mode="light"] {
    --app-bg: #ffffff;
    --app-text: #000000;
}
.q-mushaf-frame[data-q-mushaf-theme="original"][data-q-mushaf-mode="dark"],
.q-surah-reading-frame[data-q-mushaf-theme="original"][data-q-mushaf-mode="dark"] {
    --app-bg: #000000;
    --app-text: #ffffff;
}
.q-mushaf-frame[data-q-mushaf-theme="dark"][data-q-mushaf-mode="light"],
.q-surah-reading-frame[data-q-mushaf-theme="dark"][data-q-mushaf-mode="light"] {
    --app-bg: #4a4a4d;
    --app-text: #ebebf5;
}
.q-mushaf-frame[data-q-mushaf-theme="dark"][data-q-mushaf-mode="dark"],
.q-surah-reading-frame[data-q-mushaf-theme="dark"][data-q-mushaf-mode="dark"] {
    --app-bg: #000000;
    --app-text: #8d8d93;
}
.q-mushaf-frame[data-q-mushaf-theme="paper"][data-q-mushaf-mode="light"],
.q-surah-reading-frame[data-q-mushaf-theme="paper"][data-q-mushaf-mode="light"] {
    --app-bg: #eeeded;
    --app-text: #1e1a1a;
}
.q-mushaf-frame[data-q-mushaf-theme="paper"][data-q-mushaf-mode="dark"],
.q-surah-reading-frame[data-q-mushaf-theme="paper"][data-q-mushaf-mode="dark"] {
    --app-bg: #1c1c1e;
    --app-text: #f2f2f0;
}
.q-mushaf-frame[data-q-mushaf-theme="neutral"][data-q-mushaf-mode="light"],
.q-surah-reading-frame[data-q-mushaf-theme="neutral"][data-q-mushaf-mode="light"] {
    --app-bg: #ffffff;
    --app-text: #1f1f1f;
}
.q-mushaf-frame[data-q-mushaf-theme="neutral"][data-q-mushaf-mode="dark"],
.q-surah-reading-frame[data-q-mushaf-theme="neutral"][data-q-mushaf-mode="dark"] {
    --app-bg: #22242a;
    --app-text: #e8e8e8;
}
.q-mushaf-frame[data-q-mushaf-theme="warm"][data-q-mushaf-mode="light"],
.q-surah-reading-frame[data-q-mushaf-theme="warm"][data-q-mushaf-mode="light"] {
    --app-bg: #f1e2c9;
    --app-text: #34281b;
}
.q-mushaf-frame[data-q-mushaf-theme="warm"][data-q-mushaf-mode="dark"],
.q-surah-reading-frame[data-q-mushaf-theme="warm"][data-q-mushaf-mode="dark"] {
    --app-bg: #423b30;
    --app-text: #f9ecdb;
}
.q-mushaf-frame[data-q-mushaf-theme="cream"][data-q-mushaf-mode="light"],
.q-surah-reading-frame[data-q-mushaf-theme="cream"][data-q-mushaf-mode="light"] {
    --app-bg: #fffcf4;
    --app-text: #141200;
}
.q-mushaf-frame[data-q-mushaf-theme="cream"][data-q-mushaf-mode="dark"],
.q-surah-reading-frame[data-q-mushaf-theme="cream"][data-q-mushaf-mode="dark"] {
    --app-bg: #18160b;
    --app-text: #fcf6e7;
}
/* Own report: "au lieu d'avoir ces couleurs de texte, on peut créer des
   couleurs qui matchent avec notre thème neutral" - the pairs above were
   designed for the 2 full immersive reading frames, each with their OWN
   matching --app-bg (paper/dark/warm/cream all repaint the whole page).
   Cards never repaint their background anymore (own report: "le
   background... je n'ai pas aimé" - removed), so those same raw --app-
   text values (often near-pure white/black, tuned for a bespoke bg) sit
   on the SITE's own plain --app-bg here instead (input.css :root -
   #ffffff light/#22242a dark) - re-tinted per theme, verified for real
   contrast (≥4.5:1, mostly well past 10:1) against that real card
   background, not the theme's own bespoke one. Code name vs display
   label trap (own report, caught live): data-q-mushaf-theme="neutral" is
   the swatch LABELLED "Neutre" (base.html) - own report: "neutral c'est
   la couleur de l'app" - needs NO entry here, stays unset so the card
   just inherits the site's own plain --app-text (#1f1f1f light/#e8e8e8
   dark). data-q-mushaf-theme="original" is the one LABELLED "Original"
   instead, and DOES get its own entry below - own report: "5 autres
   différents" - reuses its own official pair's text values as-is
   (#000000/#ffffff), already real high-contrast (>15:1) against the
   site's own plain bg, unlike dark/paper/warm/cream's own official
   values above (tuned for THEIR bespoke bg, not this one). */
html.q-reading-page [data-q-ayah-card][data-q-mushaf-theme="original"][data-q-mushaf-mode="light"] {
    --app-text: #000000;
}
html.q-reading-page [data-q-ayah-card][data-q-mushaf-theme="original"][data-q-mushaf-mode="dark"] {
    --app-text: #ffffff;
}
html.q-reading-page [data-q-ayah-card][data-q-mushaf-theme="dark"][data-q-mushaf-mode="light"] {
    --app-text: #3a3d46;
}
html.q-reading-page [data-q-ayah-card][data-q-mushaf-theme="dark"][data-q-mushaf-mode="dark"] {
    --app-text: #c7cbd6;
}
html.q-reading-page [data-q-ayah-card][data-q-mushaf-theme="paper"][data-q-mushaf-mode="light"] {
    --app-text: #33302c;
}
html.q-reading-page [data-q-ayah-card][data-q-mushaf-theme="paper"][data-q-mushaf-mode="dark"] {
    --app-text: #ded8cf;
}
html.q-reading-page [data-q-ayah-card][data-q-mushaf-theme="warm"][data-q-mushaf-mode="light"] {
    --app-text: #4a3319;
}
html.q-reading-page [data-q-ayah-card][data-q-mushaf-theme="warm"][data-q-mushaf-mode="dark"] {
    --app-text: #f0dcc0;
}
html.q-reading-page [data-q-ayah-card][data-q-mushaf-theme="cream"][data-q-mushaf-mode="light"] {
    --app-text: #3b2e12;
}
html.q-reading-page [data-q-ayah-card][data-q-mushaf-theme="cream"][data-q-mushaf-mode="dark"] {
    --app-text: #f5ecd6;
}
/* "Contraste élevé" (input.css's own :root[data-contrast="high"]) never
   reached these on their own - own report: "je ne vois rien de
   special" on /ar/c/, "meme dans les menu et sous menu des autres
   pages". --app-border: a descendant's own declaration for a custom
   property always wins over whatever it would've inherited from :root
   regardless of specificity (.q-mushaf-frame/[data-q-ayah-card] branch,
   real descendants of <html>) - html:root.q-surah-reading-frame needs
   [data-contrast="high"] directly on its own selector instead (same
   element as :root there, a real specificity fight input.css's own
   :root[data-contrast="high"][data-theme] pair would otherwise win,
   own comment further up this file). --app-popover-border: one of the
   12 hardcoded per-theme/mode literals above, re-derived via color-mix
   from THIS context's own --app-popover-text/-bg instead of a 13th
   hardcoded pair per theme - already correct for whichever of the 6
   themes/light/dark is active. Every .q-popover/menu nested inside a
   .q-mushaf-frame/.q-surah-reading-frame inherits --app-border from
   here too, so these 2 rules also cover "Thèmes et réglages" and every
   other submenu on /ar/c/ and /ar/s/X, not just the reading frame's
   own outlines. */
:root[data-contrast="high"] .q-mushaf-frame,
html:root.q-surah-reading-frame[data-contrast="high"],
:root[data-contrast="high"] [data-q-ayah-card][data-q-mushaf-theme][data-q-mushaf-mode] {
    --app-border: color-mix(in srgb, var(--app-text) 50%, var(--app-bg));
}
/* html:root[data-q-mushaf-theme][data-q-mushaf-mode] added below (own
   report: dots/menu chrome colour on the home page didn't match
   /ar/s/X) - --app-popover-border/-divider are pure chrome (see the
   same bare html:root split further up this file), so this escalation
   needs that pairing too, not just the 3 content-scoped selectors
   above (--app-border stays as-is there, a content property). */
:root[data-contrast="high"] .q-mushaf-frame[data-q-mushaf-theme][data-q-mushaf-mode],
html:root.q-surah-reading-frame[data-contrast="high"][data-q-mushaf-theme][data-q-mushaf-mode],
:root[data-contrast="high"] [data-q-ayah-card][data-q-mushaf-theme][data-q-mushaf-mode],
html:root[data-contrast="high"][data-q-mushaf-theme][data-q-mushaf-mode] {
    --app-popover-border: color-mix(in srgb, var(--app-popover-text) 60%, var(--app-popover-bg));
    /* Own report: "Augmenter le contraste" never touched the divider
       between menu rows, only the border above - same color-mix escape
       hatch as --app-popover-border right above, one consistent "this
       is what high contrast looks like" line everywhere in the app now
       (own comment further up this file on --app-popover-border). */
    --app-popover-divider: color-mix(in srgb, var(--app-popover-text) 60%, var(--app-popover-bg));
}
/* "Gras"/"Justifier le texte" (mushaf.js/surah-player.js's own
   "Personnaliser" panels, now also every _ayah_card.html instance site-
   wide) - .ayah-block is this card's own arabic <p> (_ayah_card.html),
   #q-karaoke-track > p is /ar/s/X's own multi-line flow, own comment
   there on why justify's default polarity differs from mushaf.css's
   own .q-mushaf-no-justify (that page's flow is justified by default,
   this one and every card default to plain text-align:start/RTL). */
/* Own report: "l'option gras est flashé au chargement" - même piège que
   --q-mushaf-line-height/-word-spacing plus haut : .q-mushaf-bold-text
   n'était ajoutée que tard en JS (applyMushafBoldToFrames/mushaf.js/
   surah-player.js, tous différés) sur le frame réel, donc le poids par
   défaut (400) s'affichait un instant avant le vrai 900 sauvegardé. Var
   avec repli au lieu d'exiger la classe - base.html's own early prefill
   inscrit --q-mushaf-bold-weight sur <html> avant tout rendu, hérité par
   les 3 contextes (carte, /ar/s/X où le frame EST <html>, /ar/c dont le
   propre frame descend quand même de <html>) sans avoir à dupliquer ce
   prefill dans le script séparé de mushaf.html. .q-mushaf-bold-text
   reste ajoutée en JS (classList.toggle inchangé) mais n'est plus lue
   ici - gardée pour ne pas casser un futur sélecteur qui s'y fierait. */
.q-mushaf-frame .q-arabic-text,
.q-surah-reading-frame .q-arabic-text,
[data-q-ayah-card] .q-arabic-text {
    font-weight: var(--q-mushaf-bold-weight, 400);
}
.q-surah-reading-frame.q-mushaf-justify-text #q-karaoke-track > p,
[data-q-ayah-card].q-mushaf-justify-text .ayah-block {
    text-align: justify;
}

/* "Police" (own report: "utilise la meme structure... c'est la seule
   difference" - own copy of mushaf.css/surah-player.css's own
   [data-q-mushaf-font=...] rules, card-scoped instead of page-frame-
   scoped, same 6 fonts/values. */
[data-q-ayah-card][data-q-mushaf-font="scheherazade"] { --app-font-arabic: "Scheherazade New", serif; }
[data-q-ayah-card][data-q-mushaf-font="scheherazade-classic"] { --app-font-arabic: "Scheherazade Classic", serif; }
[data-q-ayah-card][data-q-mushaf-font="kfgqpc-hafs"] { --app-font-arabic: "KFGQPC Hafs", serif; }
[data-q-ayah-card][data-q-mushaf-font="kfgqpc-naskh"] { --app-font-arabic: "KFGQPC Naskh", serif; }
[data-q-ayah-card][data-q-mushaf-font="me-quran"] { --app-font-arabic: "Me Quran", serif; }
[data-q-ayah-card][data-q-mushaf-font="pdms-saleem"] { --app-font-arabic: "PDMS Saleem", serif; }
/* "Interligne"/"Espacement des mots" - surah-player.css's own
   equivalent targets #q-karaoke-track > p/.q-arabic-text (that page's
   own multi-line flow); this card's own single-paragraph equivalent is
   .ayah-block/.q-arabic-text (_ayah_card.html). Own report: "le text
   est petit puis grandit" - like --q-arabic-scale/--app-font-arabic
   before it, .q-mushaf-custom-spacing (popover.js's own
   applyLineHeightToFrames/applyWordSpacingToFrames) only ever got added
   per-element, late (deferred/DOMContentLoaded) - first paint used
   .ayah-block's plain leading-loose (line-height:2) and .q-arabic-text's
   browser-default word-spacing until that class landed a moment later.
   No class gate here anymore - --q-mushaf-line-height/-word-spacing
   inherit from <html> (base.html's own early anti-flash prefill, same
   spot as --q-arabic-scale/--app-font-arabic) from the very first paint,
   with the exact same CSS fallback (1.85/normal) as popover.js's own
   LINE_HEIGHT_DEFAULT(185)/WORD_SPACING_DEFAULT(0) for a reader who's
   never touched either slider. */
[data-q-ayah-card] .ayah-block {
    line-height: var(--q-mushaf-line-height, 1.85);
}
[data-q-ayah-card] .q-arabic-text {
    word-spacing: var(--q-mushaf-word-spacing, normal);
}

/* Shared "Menu de lecture"/drilled-in title (mushaf.html - the one
   .q-popover-head that's a *direct* child of the sheet, not a drilled-
   in popover's own hidden one) - a plain, non-growing flex item now
   (.q-mushaf-mobile-menu's own comment above on why), never part of
   the scrolling box below it to begin with, nothing more needed here
   for the list to read as scrolling "under" it. */
.q-mushaf-mobile-menu > .q-popover-head {
    flex: 0 0 auto;
}

/* Jump's own search field specifically (own report: "et le input" -
   the reader still needs it reachable while the results list below
   scrolls, same as it stays put above that list on desktop). Sticky
   *within* the drilldown view's own 70vh scroll box (further below),
   not the outer sheet's - a 2nd, independent stick point right under
   the shared title's own, not competing with it for the same slot. */
[data-q-mushaf-mobile-drilldown] #q-mushaf-jump-popover form {
    position: sticky;
    top: 0;
    z-index: 1;
    background: var(--app-popover-bg);
}

/* The real #q-mushaf-*-popover node itself lands here on drill-in
   (mushaf.js mobileDrillInto - moved, not copied), still carrying its
   own .q-popover/.q-mushaf-jump-popover/etc base rules (padding/
   border/background/shadow/width, own rules further below) meant for
   floating over the frame at a JS-computed position. Flattened back
   into a plain block that reads as part of *this* sheet instead of a
   card floating inside another card - position/inset reset in mushaf.js
   itself (inline styles beat any external rule here regardless of
   specificity, own comment there), everything else (border/shadow/
   fixed width) overridden here with the extra
   [data-q-mushaf-mobile-drilldown-slot] ancestor giving this enough
   specificity to beat the base rules regardless of source order. */
[data-q-mushaf-mobile-drilldown-slot] > .q-popover {
    position: static;
    width: 100%;
    max-width: none;
    border: 0;
    background: transparent;
    box-shadow: none;
    padding: 0;
    /* q-mushaf-theme-popover carries its own max-height/overflow-y
       (own comment there - room for "Personnaliser" on a short desktop
       screen) - redundant once drilled in here,
       [data-q-mushaf-mobile-drilldown]'s own flex:1/overflow-y:auto
       (mushaf.css) already scrolls the whole panel on its own. Own
       report/screenshot: left as-is, this nested scroll box was the
       actual trigger for the chip buttons inside
       (Intensité/Taille du texte arabe/Gras-Justifier/Colonnes
       multiples) rounding their top corners but not their bottom ones
       - #mark-toggles' own identical chip markup/CSS never had the
       bug, the one real difference being q-mushaf-reading-popover
       never sets its own overflow-y, so it never nests a 2nd scroll
       box inside the mobile menu's own the way this one did. */
    max-height: none;
    overflow-y: visible;
}

/* The popover's own title+"✕" head (own comment above - moved in as
   part of the same node, not stripped out) would otherwise duplicate
   the mobile menu's own shared header right above it (mushaf.html) -
   own report: 1 header, not 2 stacked "✕" close buttons. mushaf.js
   copies this head's own title text onto the shared header instead
   (mobileDrillInto/restoreMobileDrilldown) so the reader still sees
   "السور"/etc, not the menu's own generic "Menu de lecture" while
   drilled in. Scoped to the drilled-in popover's own *direct* head
   only (`>` twice, not a bare descendant selector) - themePopover
   nests further quick popovers of its own (Animation de page/
   Apparence/Sens de défilement), each a real descendant here too once
   themePopover itself lands in the slot; a plain descendant selector
   matched their heads as well, silently hiding their own title/"✕"
   the instant one of those got opened on mobile (own report: "on ne
   voit pas q-popover-head"). */
[data-q-mushaf-mobile-drilldown-slot] > .q-popover > .q-popover-head {
    display: none;
}
/* Same 2 rules, single-item version for surah_detail.html's own
   #q-mushaf-surah-popover (own report: "100% identique", drillIntoSurah/
   restoreSurahShell in surah-player.js mirroring mushaf.js's own
   mobileDrillInto/restoreMobileDrilldown - no pill list to go back to
   here, just this one popover moved in/out of its own dedicated
   shell). */
[data-q-mushaf-surah-shell-slot] > .q-popover {
    position: static;
    width: 100%;
    max-width: none;
    border: 0;
    background: transparent;
    box-shadow: none;
    padding: 0;
    max-height: none;
    overflow-y: visible;
}
[data-q-mushaf-surah-shell-slot] > .q-popover > .q-popover-head {
    display: none;
}

/* Own report: continuous flowing text under the 4 mark buttons
   (_mark_toggles.html's own as_buttons branch, shared by both pages'
   Lecture panel) - every glyph's own short description, wraps
   normally. Missed by the earlier mushaf.css->popover.css move (no ID
   scope like its neighbours there, own report: "ajoute un petit margin
   bas" - was rendering with none at all on surah_detail.html, this
   rule's own margin-bottom simply wasn't loading there). */
.q-mark-desc {
    margin: -0.5rem 0 0.75rem;
    font-size: 0.72rem;
    line-height: 1.6;
    color: var(--app-popover-btn-text);
    opacity: 0.85;
}
.q-mark-desc span {
    font-weight: 600;
}
/* Own report: the middle-dot separator (·) read as barely-there at
   this font-size/opacity - bigger bullet (•), own weight/opacity so it
   doesn't inherit the glyph spans' own bold (rule above) or the
   paragraph's own dimmed 0.85 opacity. */
.q-mark-desc span.q-mark-desc-sep {
    font-weight: 400;
    opacity: 1;
    margin: 0 0.1em;
}

/* #surah-list-viewport busy state (_surah_list_section.html, surah_list.
   html only page loading this sheet with the id) - own report: "pendant
   l'attente fait un blur de surah-list et ajoute un loader ... il y a ce
   principe dans le site, essaye de ne pas dupliquer le code". Same
   sibling-spinner-over-dimmed-content shape as .q-surah-spinner/
   .q-mushaf-spinner (surah_detail.html/mushaf.html, karaoke.css/
   mushaf.css - not loaded on /ar/s/, own class name reused here instead
   of a new one) - [aria-busy] toggled by showListBusy/hideListBusy
   (_surah_list_section.html's own script) around any async wait: tri
   par durée, génération de combinaison, recherche/filtre. */
#surah-list-viewport[aria-busy="true"] #surah-list {
    opacity: 0.4;
    filter: blur(3px);
}
@media (prefers-reduced-motion: no-preference) {
    #surah-list {
        transition: opacity 0.15s ease, filter 0.15s ease;
    }
}
/* CLAUDE.md: prefers-reduced-motion - le flou reste un effet de
   mouvement/profondeur, own report ailleurs sur ce même principe
   (karaoke.css) - juste la dimming, pas le blur, sous ce media query. */
@media (prefers-reduced-motion: reduce) {
    #surah-list-viewport[aria-busy="true"] #surah-list {
        filter: none;
    }
}
/* #q-surah-duration-total (_surah_list_section.html) - own report:
   "le blur pendant le calcul pas sur la liste mais plutôt ici" - même
   recette que le blur de #surah-list ci-dessus (opacity + blur +
   transition + reduced-motion), juste reciblée sur ce seul span au
   lieu de toute la liste. */
#q-surah-duration-total[aria-busy="true"] {
    opacity: 0.7;
    filter: blur(1px);
}
@media (prefers-reduced-motion: no-preference) {
    #q-surah-duration-total {
        transition: opacity 0.15s ease, filter 0.15s ease;
    }
}
@media (prefers-reduced-motion: reduce) {
    #q-surah-duration-total[aria-busy="true"] {
        filter: none;
    }
}
#surah-list-viewport > .q-surah-spinner {
    display: none;
}
#surah-list-viewport[aria-busy="true"] > .q-surah-spinner {
    display: flex;
}
