/**
 * assets/css/components.css
 * Song-row, chip, lyrics-card, playlist-dropdown, and restriction-modal
 * styles — split out of header.php's inline <style> block so the
 * browser can cache it across page loads instead of re-parsing an
 * identical block on every single request. Uses the same CSS custom
 * properties (--violet, --gold, --card-bg, --border, --radius, --font-ur
 * etc) already defined in assets/css/base.css / header.php's :root.
 */

/* ── List-hero (list.php / search.php / favorites.php / playlists.php) ──
   Previously duplicated with slightly different values in each page's
   own <style> block, which was ALSO positioned after the visible HTML
   — meaning the heading rendered unstyled until the browser parsed
   that far down, most visible on list.php's heaviest ("all songs")
   view. Moving it here (already <link>'d in <head>) fixes both the
   duplication and the flash-of-unstyled-content. */
.list-hero { padding: 1.5rem 0 .5rem; text-align: center; }
.list-hero h1 { font-family: var(--font-h); font-size: 1.7rem; color: var(--violet); }
.list-hero h1.ur { font-family: var(--font-ur); font-size: 2rem; }
.list-hero-count { color: var(--muted); font-size: .85rem; margin-top: .35rem; }
.no-results, .loading-state { text-align: center; padding: 2.5rem 1rem; color: var(--muted); }
.notice-warning {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: .6rem;
  text-align: center;
  background: var(--warn-bg);
  border: 1px solid var(--warn-border);
  border-radius: var(--radius);
  color: var(--warn-text);
  padding: 1.1rem 1.4rem;
}
.notice-warning i { color: var(--warn-text); flex-shrink: 0; }
.notice-warning p { margin: 0; }

/* ── list.php: full banner hero (song.php's .song-hero treatment,
   reused here so a category/poet/worshiper/"all songs" listing gets
   the same proper full-bleed welcome instead of plain text). Rendered
   OUTSIDE .boxed (see list.php) so it spans the full viewport width
   edge-to-edge exactly like .song-hero does — no border-radius/margin,
   both of which only made sense back when this sat inside .boxed as a
   rounded card. */
.list-hero-banner {
  width: 100%;
  background:
    linear-gradient(135deg, rgba(47,35,80,.86), rgba(110,63,163,.74)),
    url('https://fakhta.org/worship/images/bg12.jpg') center / cover no-repeat;
  text-align: center;
  padding: 2.75rem 1rem 2rem;
}
.list-hero-inner { max-width: 780px; margin: 0 auto; }
.list-hero-icon { font-size: 1.5rem; color: var(--gold-lt); margin-bottom: .6rem; display: inline-block; }
.list-hero-banner h1 { font-family: var(--font-h); font-size: 1.9rem; margin: 0 0 .4rem; color: #fff; }
.list-hero-banner h1.ur { font-family: var(--font-ur); font-size: 2.3rem; line-height: 1.7; }
.list-hero-tagline { color: rgba(255,255,255,.82); font-size: .92rem; margin: 0 0 .25rem; }
.list-hero-stats { display: flex; gap: 1rem; justify-content: center; margin-top: 1rem; font-size: .85rem; color: rgba(255,255,255,.9); }
.list-hero-stats i { color: var(--gold-lt); margin-inline-end: .3rem; }

/* ── list.php: A–Z strip + sort/per-page selects ── */
.alpha-strip { display: flex; flex-wrap: wrap; gap: 8px; margin: 1.1rem 0 0; }
.letter-pill {
  display: flex; align-items: center; gap: 6px; padding: .38rem .8rem;
  border-radius: 999px; background: var(--card-bg); border: 1px solid var(--border);
  font-size: .82rem; color: var(--text); transition: border-color .15s, background .15s, transform .1s, box-shadow .15s;
}
.letter-pill:hover { border-color: var(--violet-lt); box-shadow: var(--shadow); transform: translateY(-1px); }
.letter-pill.active { background: linear-gradient(135deg, var(--violet), var(--violet-lt)); color: #fff; border-color: var(--violet); box-shadow: 0 2px 8px rgba(110,63,163,.35); }
.letter-pill .alpha-count { font-size: .68rem; opacity: .85; background: rgba(0,0,0,.06); border-radius: 999px; padding: 1px 6px; }
.letter-pill.active .alpha-count { background: rgba(255,255,255,.22); }
[data-theme="dark"] .letter-pill .alpha-count { background: rgba(255,255,255,.08); }

/* ── list.php: Zaboor "browse by number" strip (independent of the
   letter strip — see includes/helpers.php buildSongBranches()'s
   $numberFilter) ── */
.number-strip { margin: 1rem 0 0; }
.number-strip-label { display: block; color: var(--muted); font-size: .8rem; margin-bottom: .5rem; }
.number-strip-row { display: flex; flex-wrap: wrap; gap: 5px; }
.number-pill {
  display: inline-flex; align-items: center; gap: 4px; min-width: 1.9rem; justify-content: center;
  padding: .2rem .45rem; border-radius: 6px; background: var(--card-bg); border: 1px solid var(--border);
  font-size: .7rem; font-weight: 600; color: var(--text); transition: border-color .15s, background .15s;
}
.number-pill:hover { border-color: var(--gold); }
.number-pill.active { background: linear-gradient(135deg, var(--gold), var(--gold-lt)); color: var(--ink2); border-color: var(--gold); }
.number-pill .number-count { font-size: .58rem; opacity: .75; }

/* ── list.php: sort + per-page selects, restyled to match index.php's
   .cat-sort-select pill look instead of a plain native <select> ── */
.list-controls { display: flex; gap: .5rem; flex-wrap: wrap; }
.sort-select {
  appearance: none; -webkit-appearance: none;
  background: var(--card-bg) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%239a8fae'/%3E%3C/svg%3E") no-repeat right .85rem center;
  border: 1px solid var(--border); border-radius: 999px; color: var(--text);
  font-size: .8rem; font-weight: 600; padding: .5rem 2.1rem .5rem .95rem; cursor: pointer;
}
html[dir="rtl"] .sort-select { background-position: left .85rem center; padding: .5rem .95rem .5rem 2.1rem; }
.sort-select:focus { outline: none; border-color: var(--violet); }
.sort-select.ur { font-family: var(--font-ur); font-size: .92rem; line-height: 1.6; }

/* ── list.php: live title-filter match count, next to the search box ── */
.live-filter-count { font-size: .75rem; color: var(--muted); white-space: nowrap; margin-inline-start: .5rem; }
.live-no-results { margin-top: .5rem; }

/* ── list.php: pagination "All/تمام" shortcut (jumps to per_page=all) ── */
.page-all { background: var(--bg2); font-weight: 700; }
.page-all:hover { background: var(--violet); color: #fff; }

/* ── search.php: scope pills + smart-match suggestions ── */
.search-scope-row { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; margin-top: .75rem; }
.scope-pill { padding: .3rem .7rem; border-radius: 999px; border: 1px solid var(--border); background: var(--card-bg); font-size: .78rem; color: var(--text); }
.scope-pill.active { background: var(--violet); color: #fff; border-color: var(--violet); }
.scope-sep { width: 1px; height: 18px; background: var(--border); margin: 0 .25rem; }
.smart-matches { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 1rem; }
.smart-match-pill { display: inline-flex; align-items: center; gap: .4rem; padding: .5rem .9rem; border-radius: var(--radius); background: var(--bg2); border: 1px solid var(--gold); color: #8A6D1F; font-size: .82rem; }

/* ── favorites.php ── */
.guest-note { text-align: center; margin-top: 1rem; font-size: .85rem; color: var(--muted); }
.guest-note a { color: var(--violet); font-weight: 600; }

/* ── playlists.php ── */
.report-submit-btn { background: var(--violet); color: #fff; border: none; padding: .6rem 1.2rem; border-radius: 6px; cursor: pointer; }

/* ── Song list container (list.php / search.php / favorites.php / playlists.php) ── */
.song-list { display: flex; flex-direction: column; gap: .6rem; margin-top: 1rem; }

/* ── Song row (list.php / search.php / favorites.php / playlists.php) ── */
.song-row {
  display: flex; flex-direction: column; gap: .5rem;
  padding: .85rem .9rem; background: var(--card-bg);
  border: 1px solid var(--border); border-radius: var(--radius);
  margin-bottom: .6rem; transition: box-shadow .15s, border-color .15s;
}
.song-row:hover { box-shadow: var(--shadow); border-color: var(--violet-lt); }
.song-row.is-hidden { display: none; } /* used by list.php's client-side title live-filter */

.song-row-top { display: flex; align-items: center; gap: .75rem; }
.song-num { flex-shrink: 0; width: 1.6rem; text-align: center; color: var(--muted); font-size: .8rem; }
.song-title { flex: 1; min-width: 0; display: block; font-weight: 600; color: var(--ink); font-size: 1rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.song-title:hover { color: var(--violet); }

/* invisible spacer between the title line and the meta chip row —
   not a visible rule, just breathing room; flip to a real border if
   a visible separator is ever wanted */
.song-row-divider { height: 1px; }

.song-meta { display: flex; flex-wrap: wrap; gap: .35rem; align-items: center; }
.chip {
  display: inline-flex; align-items: center; gap: .3rem;
  padding: .2rem .5rem; border-radius: 999px; font-size: .72rem;
  background: var(--bg2); color: var(--muted); border: 1px solid var(--border);
  white-space: nowrap;
  transition: background .15s, color .15s, border-color .15s;
}
.chip.cat { color: var(--violet); border-color: color-mix(in srgb, var(--violet) 30%, var(--border)); }
.chip.poet, .chip.worshiper, .chip.poet-worshiper { color: var(--sage); }
.chip.book { color: var(--gold); }
.chip.views-chip, .chip.icon-chip { background: transparent; border-color: transparent; padding-inline: .3rem; }

/* Solid-fill invert on hover — same treatment as song.php's .hero-chip
   (background flips to the chip's own color, text/icon flips to white)
   instead of just the previous faint background tint. Only the
   clickable <a> chips (cat/poet/worshiper/poet-worshiper/book) get
   this; the non-link views/icon chips are left alone. */
a.chip.cat:hover { background: var(--violet); border-color: var(--violet); color: #fff; }
a.chip.poet:hover, a.chip.worshiper:hover, a.chip.poet-worshiper:hover { background: var(--sage); border-color: var(--sage); color: #fff; }
a.chip.book:hover { background: var(--gold); border-color: var(--gold); color: #fff; }

.song-row-actions { flex-shrink: 0; display: flex; align-items: center; gap: .3rem; }
.fav-toggle, .playlist-add-btn, .playlist-remove-btn {
  width: 2rem; height: 2rem; border-radius: 50%; border: 1px solid var(--border);
  background: var(--card-bg); color: var(--muted); display: flex; align-items: center; justify-content: center;
  font-size: .85rem; transition: color .15s, border-color .15s, background .15s;
}
.fav-toggle:hover, .playlist-add-btn:hover { color: var(--violet); border-color: var(--violet-lt); }
.fav-toggle.is-favorited { color: #d9345c; border-color: #d9345c; }
.playlist-remove-btn:hover { color: #B23A48; border-color: #B23A48; }

/* ── Playlist (+) dropdown ── */
.playlist-add-wrap { position: relative; }
.playlist-dropdown {
  position: absolute; top: calc(100% + 6px); inset-inline-end: 0; z-index: 300;
  min-width: 220px; max-width: 280px; background: var(--card-bg);
  border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow);
  padding: .5rem;
}
.pd-loading, .pd-error { padding: .5rem; font-size: .8rem; color: var(--muted); text-align: center; }
.pd-list { display: flex; flex-direction: column; gap: .2rem; max-height: 220px; overflow-y: auto; }
.pd-item {
  display: flex; align-items: center; gap: .4rem; text-align: start;
  padding: .4rem .5rem; border-radius: 6px; font-size: .8rem; color: var(--text);
  background: transparent; border: none; width: 100%;
}
.pd-item:hover { background: var(--bg2); }
.pd-item.pd-item-added { color: #1a9e5c; }
.pd-item.pd-item-existing { color: var(--muted); text-decoration: none; cursor: pointer; }
.pd-item.pd-item-existing:hover { background: var(--bg2); color: var(--violet); }
.pd-item.pd-item-existing .pd-added-check { color: #1a9e5c; margin-inline-start: auto; font-size: .75rem; flex-shrink: 0; }
.pd-count { color: var(--muted); font-size: .72rem; }
.pd-new-form { display: flex; gap: .3rem; margin-top: .4rem; padding-top: .4rem; border-top: 1px solid var(--border); }
.pd-new-input { flex: 1; min-width: 0; padding: .35rem .5rem; border-radius: 6px; border: 1px solid var(--border); font-size: .78rem; background: var(--bg); color: var(--text); }
.pd-new-btn { width: 1.9rem; height: 1.9rem; border-radius: 6px; border: none; background: var(--violet); color: #fff; }
.pd-limit-note { font-size: .74rem; color: var(--muted); padding: .4rem .2rem 0; }

/* ── Real-time favorites/playlists count badges (nav, account
   dropdown, drawer) — hidden automatically when empty (count = 0),
   updated live by favorites.js/playlist-menu.js on add/remove. ── */
.nav-count-badge {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 1.15rem; height: 1.15rem; padding: 0 .32rem; margin-inline-start: .3rem;
  border-radius: 999px; background: var(--violet); color: #fff;
  font-size: .68rem; font-weight: 700; line-height: 1; vertical-align: middle;
}
.nav-count-badge:empty { display: none; }
.acct-dd-item .nav-count-badge, .drawer-nav-link .nav-count-badge { margin-inline-start: auto; }

/* ── Playlists page — tab bar (name + item-count badge) replacing
   the old click-through list of playlist rows ── */
.playlist-tabs {
  display: flex; flex-wrap: wrap; gap: .5rem;
  padding-bottom: 1rem; margin-bottom: 1.25rem; border-bottom: 1px solid var(--border);
}
.playlist-tab {
  display: inline-flex; align-items: center; gap: .5rem;
  padding: .5rem .9rem; border-radius: 999px; border: 1px solid var(--border);
  background: var(--card-bg); color: var(--text); text-decoration: none;
  font-size: .85rem; font-weight: 500; transition: background .15s, border-color .15s, color .15s;
}
.playlist-tab:hover { border-color: var(--violet-lt); color: var(--violet); }
.playlist-tab.active {
  background: var(--violet); border-color: var(--violet); color: #fff;
}
.playlist-tab.active .playlist-tab-badge { background: rgba(255,255,255,.25); color: #fff; }
.playlist-tab-badge {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 1.3rem; height: 1.3rem; padding: 0 .35rem; border-radius: 999px;
  background: color-mix(in srgb, var(--violet) 15%, transparent); color: var(--violet);
  font-size: .72rem; font-weight: 700; line-height: 1;
}

/* ── Lyrics card (song.php) ── */
.lyrics-card { background: var(--card-bg); border: 1px solid var(--border); border-radius: var(--radius); padding: 22px 24px; margin-bottom: 20px; }
.lyrics-toolbar { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 16px; padding-bottom: 14px; border-bottom: 1px solid var(--border); flex-wrap: wrap; }
.lyrics-toolbar-title { display: flex; align-items: center; gap: .4rem; font-size: 14px; font-weight: 700; color: var(--violet); }
.lyrics-toolbar-actions { display: flex; align-items: center; gap: .5rem; }
.font-stepper { display: flex; align-items: center; gap: .5rem; }
.font-step-btn { width: 1.8rem; height: 1.8rem; border-radius: 50%; border: 1px solid var(--border); background: var(--bg2); color: var(--text); font-size: 1rem; line-height: 1; }
.font-step-label { font-size: .78rem; color: var(--muted); min-width: 2.6rem; text-align: center; }
.lyrics-body { color: var(--ink); text-align: center; }
.lyrics-body.ur { font-family: var(--font-ur); font-size: calc(22px * var(--lyrics-scale, 1)); letter-spacing: 0;  line-height: 1.5; }
.lyrics-body:not(.ur) { font-size: calc(16px * var(--lyrics-scale, 1)); line-height: 1.6; }
.lyrics-body .lyrics-line-bold { font-weight: 700; color: #dc3545; }
.lyrics-empty { text-align: center; padding: 30px 10px; color: var(--muted); }

/* ── Restriction modal ── */
.restriction-modal-overlay {
  position: fixed; inset: 0; z-index: 1000; background: rgba(20, 14, 34, .55);
  display: flex; align-items: center; justify-content: center; padding: 1rem;
}
/* The [hidden] attribute is how restriction-modal.js's hide() closes this —
   but an author-stylesheet class rule (the display:flex above) beats the
   UA stylesheet's own `[hidden]{display:none}` at equal specificity, so
   without this override the overlay stayed visually open no matter what
   the JS did to the `hidden` property (clicking the × or the backdrop). */
.restriction-modal-overlay[hidden] { display: none; }
/* Used only by mobile_app_admin_only (see restriction-modal.js's
   showRestrictionModal()) — the page behind it is a blurred *preview*
   meant to be glimpsed (screenshots, feature list), not a blocked
   action like the default .55 overlay is for everywhere else, so this
   is deliberately lighter. Scoped to its own class specifically so
   tuning it never touches the shared default other modals use. */
.restriction-modal-overlay.rm-preview-overlay { background: rgba(20, 14, 34, .32); }
.restriction-modal {
  position: relative; width: 100%; max-width: 380px; background: var(--card-bg);
  border-radius: var(--radius); box-shadow: var(--shadow); padding: 1.75rem 1.5rem 1.5rem; text-align: center;
}
.restriction-modal-close { position: absolute; top: .6rem; inset-inline-end: .7rem; background: none; border: none; font-size: 1.3rem; color: var(--muted); line-height: 1; }
.rm-title { font-family: var(--font-h); color: var(--violet); font-size: 1.05rem; margin-bottom: .6rem; }
.rm-body { color: var(--muted); font-size: .88rem; line-height: 1.5; margin-bottom: 1.1rem; }
.rm-cta { display: inline-block; padding: .55rem 1.3rem; border-radius: 999px; background: var(--violet); color: #fff; font-weight: 600; font-size: .85rem; }
.rm-cta:hover { background: var(--violet-lt); }

/* ── Pagination (list.php) ── */
.pagination { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: .35rem; margin: 1.5rem 0; }
.page-link {
  display: inline-flex; align-items: center; gap: .3rem; min-width: 2.1rem; height: 2.1rem;
  padding: 0 .6rem; border-radius: 8px; border: 1px solid var(--border);
  background: var(--card-bg); color: var(--text); font-size: .82rem; font-weight: 600; justify-content: center;
}
.page-link:hover { border-color: var(--violet-lt); color: var(--violet); }
.page-link.active { background: var(--violet); border-color: var(--violet); color: #fff; }
.page-ellipsis { color: var(--muted); padding: 0 .2rem; }

/* ── AdSense slot wrapper — reserved space to avoid layout shift ── */
.ad-slot-wrap {
  margin: 1rem 0; padding: .5rem; text-align: center;
  background: var(--bg2); border: 1px dashed var(--border); border-radius: var(--radius);
  min-height: 100px; display: flex; align-items: center; justify-content: center; overflow: hidden;
}
/* The <ins class="adsbygoogle"> child must get a real, measurable width —
   inside a flex container with justify-content:center, an element with no
   explicit width shrinks to its (empty, pre-fill) content size, i.e. 0px.
   Google's script measures that 0px and silently aborts the ad request
   (no error, just a blank box) instead of filling it. Placeholders are
   unaffected since they're plain text/icon content, not a real ad request. */
.ad-slot-wrap > .adsbygoogle {
  width: 100%;
}
.ad-slot-placeholder-inner {
  display: flex; flex-direction: column; align-items: center; gap: .3rem;
  color: var(--muted); font-size: .78rem; font-weight: 600;
}
.ad-slot-placeholder-inner i { font-size: 1.1rem; opacity: .6; }
.ad-slot-placeholder-tier { font-size: .68rem; font-weight: 500; opacity: .75; text-transform: uppercase; letter-spacing: .03em; }

.playlist-remove-form { display: contents; } /* so the button lays out as a normal song-row-actions sibling, not a block */

/* ── AJAX row removal (playlist-remove.js) ── */
.song-row.is-removing { opacity: 0; transform: scale(.98); transition: opacity .2s, transform .2s; pointer-events: none; }

/* ── Shared confirm modal (assets/js/modules/alerts.js) — reuses
   .restriction-modal-overlay/.restriction-modal's card chrome, adds
   its own body/actions layout. ── */
.fc-body { margin-bottom: 1.1rem; }
.fc-actions { display: flex; gap: .6rem; justify-content: center; }
.fc-cancel { background: transparent; border: 1px solid var(--border); color: var(--text); box-shadow: none; }
.fc-cancel:hover { border-color: var(--violet-lt); color: var(--violet); }
.fc-confirm { background: var(--violet); }
.fc-confirm:hover { background: var(--violet-lt); }
.fc-confirm.fc-danger { background: #B23A48; box-shadow: 0 2px 8px color-mix(in srgb, #B23A48 35%, transparent); }
.fc-confirm.fc-danger:hover { background: #c94c5a; }

/* ── Toast notifications (assets/js/modules/alerts.js) ── */
.fakhta-toast-wrap {
  position: fixed; bottom: 1.25rem; inset-inline-end: 1.25rem; z-index: 1100;
  display: flex; flex-direction: column; gap: .5rem; max-width: min(320px, calc(100vw - 2rem));
}
.fakhta-toast {
  background: var(--ink); color: #fff; padding: .7rem 1rem; border-radius: 8px;
  box-shadow: var(--shadow); font-size: .85rem; line-height: 1.4;
  opacity: 0; transform: translateY(8px); transition: opacity .2s, transform .2s;
}
.fakhta-toast.ur { font-family: var(--font-ur); font-size: .95rem; }
.fakhta-toast.is-visible { opacity: 1; transform: translateY(0); }
.fakhta-toast-error { background: #B23A48; }

@media (max-width: 480px) {
  .lyrics-card { padding: 16px; }
}

/* ── Sidebar card + row system ──
   Moved here from sidebar.php's own inline <style> block so it's a
   cached, shared asset instead of something only pages that
   `require sidebar.php` happened to get — list.php's own
   sidebar-list.php needs the exact same card/row look and was
   rendering unstyled (plain text, no cards) before this moved out of
   sidebar.php and into the site-wide stylesheet every page already
   links. Ported from the old homepage's inc/sidebar-index.php, using
   worship's own theme variables (--violet/--gold/--bg2) instead of
   the old (--maroon/--cream). */
.sidebar-block {
    background: var(--card-bg);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 18px;
    margin-bottom: 20px;
}
.sidebar-block h3 {
    font-size: 14px;
    font-weight: 700;
    color: var(--violet);
    margin: 0 0 12px;
    text-transform: uppercase;
    letter-spacing: .04em;
    display: flex;
    align-items: center;
    gap: 8px;
}
.sidebar-block h3 i { color: var(--gold); font-size: 13px; }
.sidebar-block h3.ur { text-transform: none; font-family: var(--font-ur); }

.sidebar-list { list-style: none; margin: 0; padding: 0; }
.sidebar-list li {
    padding: 9px 0;
    border-bottom: 1px solid var(--border);
    font-size: 13.5px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 8px;
}
.sidebar-list li:last-child { border-bottom: none; }

.sidebar-item-left { display: flex; align-items: center; gap: 10px; min-width: 0; flex: 1; color: inherit; }

.sidebar-num {
    flex-shrink: 0;
    width: 22px;
    height: 22px;
    border-radius: 50%;
    background: var(--bg2);
    border: 1px solid var(--border);
    color: var(--violet);
    font-size: 11px;
    font-weight: 700;
    display: flex;
    align-items: center;
    justify-content: center;
}

.sidebar-item-title {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--text);
    font-weight: 600;
}
.sidebar-item-title.ur { font-family: var(--font-ur); line-height: 1.7; letter-spacing: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sidebar-list li a:hover .sidebar-item-title { color: var(--violet); }

/* Plain-text meta (date / views) — no pill/badge chrome, just a
   small muted label with an icon, matching the row's own type scale.
   Both badges get a fixed column width (not content-based auto-sizing)
   so the eye/clock icons line up in a straight vertical column row
   after row, regardless of how many digits the view count has or how
   long the date string is (this matters most in RTL/Urdu rows, where
   these badges sit flush against the sidebar's inner edge and any
   width change in one badge otherwise shoves its neighbour sideways).

   justify-content is flex-end (not flex-start): with a fixed-width
   box, flex-start packs the icon+text against the box's leading edge
   and leaves any leftover width dangling on the trailing edge — and
   the trailing edge is exactly the side that sits against the card's
   own edge (the right side in LTR, the left side in RTL, since these
   badges are always the last flex children in the row). That leftover
   space was rendering as a big, inconsistent gap between the date/view
   text and the sidebar border, most noticeable in Urdu/RTL rows where
   short relative dates ("3 دن") don't fill the reserved 92px column.
   flex-end anchors the icon+text group to that trailing/outer edge
   instead, so it sits flush against the border with any leftover
   space absorbed on the inner side, next to the title text. */
.date-badge, .views-badge {
    font-size: 11px;
    color: var(--muted);
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: flex-end;
    gap: 4px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    background: none;
    border: none;
    padding: 0;
}
/* .date-badge can't be excluded from the site-wide Mehr Nastaliq
   swap the way .views-badge is (base.css) — relativeDate()/formatDate()
   put real Urdu month names in it ("26 نومبر 2025"), so it has to stay
   on the Urdu font. Mehr Nastaliq's ascenders/descenders are taller
   than the plain body font's, so pinning line-height too tight (1, tried
   earlier) starves that ink of room and .date-badge's own overflow:hidden
   above then crops it — the clock icon's top and the month name's tail
   both got sliced. Giving the badge itself (and so its anonymous
   text-node flex item) a taller 1.5 line-height gives Nastaliq's ink
   the vertical room it actually needs, while re-pinning just the *icon*
   to line-height:1 keeps its own box tight — align-items:center then
   centers both boxes on the same row without clipping either one. */
.views-badge { width: 46px; }
.date-badge { width: 92px; line-height: 1.5; }
.date-badge i, .views-badge i { color: var(--gold); font-size: 11px; flex-shrink: 0; line-height: 1; }
.views-badge { cursor: pointer; user-select: none; transition: color .15s; }
.views-badge:hover, .views-badge:hover .views-num { color: var(--violet); }

.link-arrow { color: var(--gold); font-size: 12px; flex-shrink: 0; }
html[dir="rtl"] .link-arrow { transform: scaleX(-1); }

.social-list { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; }
.social-pill {
    background: var(--bg2);
    border: 1px solid var(--border);
    width: 38px;
    height: 38px;
    padding: 0;
    border-radius: 50%;
    font-size: 12.5px;
    color: var(--violet);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: background .15s, color .15s;
}
.social-pill:hover { background: var(--violet); color: #fff; }

/* ---------- Fakhta Exclusive (top dark block, sidebar.php only) ---------- */
.exclusive-block .sidebar-list li { border-bottom: 1px solid rgba(255,255,255,.14); }
.exclusive-block .sidebar-list li:last-child { border-bottom: none; }
.exclusive-block .sidebar-item-title { color: #fff; }
.exclusive-block .sidebar-item-left:hover .sidebar-item-title { color: var(--gold-lt); }
.exclusive-block .link-arrow { color: rgba(255,255,255,.5); }

.exclusive-icon {
    flex-shrink: 0;
    width: 26px;
    height: 26px;
    border-radius: 50%;
    background: rgba(255,255,255,.1);
    color: var(--gold-lt);
    font-size: 11px;
    display: flex;
    align-items: center;
    justify-content: center;
}

.exclusive-badge {
    flex-shrink: 0;
    font-size: 9.5px;
    font-weight: 700;
    letter-spacing: .02em;
    text-transform: uppercase;
    padding: 3px 7px;
    border-radius: 6px;
    color: #fff;
}
.exclusive-badge.new  { background: #0d6efd; }
.exclusive-badge.soon { background: #dc3545; }
.exclusive-badge.ur { font-family: var(--font-ur); text-transform: none; font-size: 11px; line-height: 1.4; }

/* Lock badges (restricted_link()) inside this card use the light/dark
   theme tokens by default, which don't have enough contrast against
   this block's own fixed dark gradient — override with fixed light
   colors instead, sized to match the block's .exclusive-badge. */
.exclusive-block .restricted-badge {
    font-size: 9.5px;
    padding: 3px 7px;
    border-radius: 6px;
    letter-spacing: .02em;
}
.exclusive-block .restricted-badge-premium {
    background: rgba(212,175,55,.18);
    border: 1px solid rgba(212,175,55,.55);
    color: var(--gold-lt);
}
.exclusive-block .restricted-badge-free {
    background: rgba(255,255,255,.08);
    border: 1px solid rgba(255,255,255,.35);
    color: #fff;
}

/* ---------- sidebar-list.php: scoped heading context + worshiper cloud ---------- */
.sidebar-heading-context { font-size: .78em; font-weight: 400; color: var(--muted); text-transform: none; }
.worshiper-cloud { display: flex; flex-wrap: wrap; gap: 8px; }
.worshiper-pill {
  display: inline-flex; align-items: center; gap: 6px;
  padding-block: .125rem; padding-inline: .125rem .75rem;
  border-radius: 999px; background: var(--bg2); border: 1px solid var(--border);
  font-size: .8rem; color: var(--text); transition: border-color .15s, background .15s;
}
.worshiper-pill-photo {
  width: 28px; height: 28px; border-radius: 50%; object-fit: cover;
  background: var(--card-bg); flex-shrink: 0;
}
.worshiper-pill:hover { border-color: var(--violet-lt); color: var(--violet); }
.worshiper-pill-count { color: var(--muted); font-size: .72em; }
.sidebar-empty { color: var(--muted); font-size: .85rem; }

/* ── Search bar (index.php / list.php / search.php) ──
   Moved here from index.php's own inline <style>. list.php and
   search.php both reuse the exact same .search-wrap/.search-icon/
   .search-input class names, but the actual pill/box look (background,
   border, radius, shadow, flex layout) was only ever defined on
   .search-bar — an inner element index.php nests inside .search-wrap.
   list.php and search.php never had that inner wrapper in their
   markup, so their search inputs rendered with zero box styling (bare
   input next to an icon). Fixed on the markup side (both now nest a
   .search-bar the same way index.php does); this move just makes sure
   all three pages can reach the same CSS instead of it being trapped
   in index.php's page-specific inline block. */
.search-wrap { position: relative; padding: 1.25rem 0 0; }
.search-bar {
  position: relative; display: flex; align-items: center; gap: .6rem;
  background: var(--card-bg); border: 1px solid var(--border); border-radius: 999px;
  padding: .7rem 1.1rem; box-shadow: var(--shadow);
}
.search-bar:focus-within { border-color: var(--violet); }
.search-icon { color: var(--muted); font-size: .95rem; flex-shrink: 0; }
.search-input {
  flex: 1; min-width: 0; border: none; outline: none; background: transparent;
  font-size: .95rem; color: var(--text); font-family: inherit;
}
.search-input.ur { font-family: var(--font-ur); font-size: 1.05rem; line-height: 1.9; }
.search-input::placeholder { color: var(--muted); }
.search-submit {
  flex-shrink: 0; width: 36px; height: 36px; border: none; border-radius: 50%;
  background: var(--violet); color: #fff; display: flex; align-items: center; justify-content: center;
  cursor: pointer; font-size: .85rem; transition: background .15s;
}
.search-submit:hover { background: var(--gold); color: #3a2b0c; }
html[dir="rtl"] .search-submit i { transform: scaleX(-1); }

/* ---------- Restricted-link badge (nav/drawer/carousels) ----------
   Shown next to any link that actually points at a gated page for a
   visitor who can't use it yet — see includes/helpers.php's
   restricted_link(). Two variants so the *reason* is legible at a
   glance instead of a bare lock icon: gold "Premium" for pages that
   need Premium (Worshipers/Poets/Composers/Song Books/Audio+Video
   Player); violet-outline "Free" for pages that only need an account,
   Premium or not (Sermons/Articles/eBooks) — signing in is free, so
   the badge shouldn't look like a paywall. */
.restricted-badge {
  display: inline-flex;
  align-items: center;
  gap: .3em;
  margin-inline-start: auto;
  padding: .12em .5em;
  border-radius: 999px;
  font-size: .68em;
  font-weight: 700;
  line-height: 1.6;
  letter-spacing: .02em;
  text-transform: uppercase;
  flex-shrink: 0;
  white-space: nowrap;
}
.restricted-badge i { font-size: .95em; }
.restricted-badge-premium {
  background: var(--warn-bg);
  border: 1px solid var(--warn-border);
  color: var(--warn-text);
}
.restricted-badge-free {
  background: transparent;
  color: var(--violet-lt);
  border: 1px solid var(--violet-lt);
}
.people-carousel-showall .restricted-badge,
.pc-showall-lock {
  margin-inline-start: .35rem;
}

/* ── Offline-download progress ring ──────────────────────────────
   Shared by song.php's .tb-offline (single song) and list.php's
   .list-offline-btn (whole category) — assets/js/modules/offline-
   lyrics.js injects this markup into the button on first use and
   toggles it via .is-busy. Replaces the old plain spinning-icon
   treatment with a real circular indicator: for a category batch,
   sw.js reports done/total as each song finishes so the ring fills
   in with a real percentage; for a single song (one request, no
   sub-progress to report) it spins indeterminately instead of
   showing a meaningless 0%->100% jump. */
.offline-progress { display: none; position: relative; width: 1.1em; height: 1.1em; flex-shrink: 0; }
.is-busy .offline-progress { display: inline-flex; align-items: center; justify-content: center; }
.tb-offline.is-busy i.fa-cloud-arrow-down,
.list-offline-btn.is-busy i.fa-cloud-arrow-down { display: none; }
.offline-progress-ring { width: 100%; height: 100%; transform: rotate(-90deg); }
.offline-progress-track { fill: none; stroke: currentColor; opacity: .25; stroke-width: 3.5; }
.offline-progress-bar {
  fill: none;
  stroke: currentColor;
  stroke-width: 3.5;
  stroke-linecap: round;
  transition: stroke-dasharray .25s ease;
}
.offline-progress-pct {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: .58em;
  font-weight: 600;
  line-height: 1;
}
/* Single-song downloads: no meaningful percentage, so spin the ring
   itself and hide the (empty) percent label rather than sit at 0%. */
.offline-progress.is-indeterminate .offline-progress-ring { animation: offlineProgressSpin 1s linear infinite; }
.offline-progress.is-indeterminate .offline-progress-bar { stroke-dasharray: 25, 100; }
.offline-progress.is-indeterminate .offline-progress-pct { display: none; }
@keyframes offlineProgressSpin { to { transform: rotate(270deg); } }

/* list.php's category button had no styling at all before — matching
   the teal "offline" pill language already used on song.php's toolbar. */
.list-offline-btn {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  padding: .5rem .9rem;
  border-radius: 999px;
  border: 1px solid color-mix(in srgb, #20c997 30%, var(--border));
  background: var(--bg2);
  color: #20c997;
  font-size: .82rem;
  cursor: pointer;
  transition: background .15s, color .15s, border-color .15s;
}
.list-offline-btn:not(:disabled):hover { background: #20c997; color: #fff; border-color: #20c997; }
.list-offline-btn:disabled { opacity: .6; cursor: wait; }
.list-offline-btn.is-downloaded { background: #20c997; color: #fff; border-color: #20c997; }
.list-offline-scope { opacity: .75; font-size: .9em; }

/* ── Downloads hub (downloads.php) ───────────────────────────────
   Tabs + "download all" bar + card grid. Cards reuse .list-offline-
   btn as their own dim overlay (see the ring/label rules further up
   this file) — .is-downloaded hides the overlay via display:none,
   which is what reveals the card body underneath fully instead of
   showing any separate "downloaded" variant markup. */
.downloads-offline-note {
  background: var(--warn-bg, #3a2f14);
  border: 1px solid var(--warn-border, #6b552a);
  color: var(--warn-text, #e8c976);
  padding: .7rem 1rem;
  border-radius: 10px;
  font-size: .85rem;
  margin-bottom: 1rem;
}
.downloads-empty { color: var(--muted); text-align: center; padding: 2rem 0; }

.dl-tabs { display: flex; gap: .5rem; flex-wrap: wrap; margin-bottom: 1.25rem; }
.dl-tab {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  padding: .5rem 1rem;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--bg2);
  color: var(--text);
  font-size: .85rem;
  text-decoration: none;
  transition: background .15s, color .15s, border-color .15s;
}
.dl-tab:hover { border-color: var(--violet-lt); }
.dl-tab.active { background: var(--violet); color: #fff; border-color: var(--violet); }

.dl-allbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  padding: 1rem 1.25rem;
  background: var(--bg2);
  border: 1px solid var(--border);
  border-radius: 14px;
  margin-bottom: 1.5rem;
}
.dl-allbar-info { display: flex; flex-direction: column; gap: .2rem; }
.dl-allbar-info strong { font-family: var(--font-h); color: var(--violet); font-size: 1rem; }
.dl-allbar-size { color: var(--muted); font-size: .82rem; }
.dl-allbar-btn {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  padding: .6rem 1.1rem;
  border-radius: 999px;
  border: 1px solid #20c997;
  background: transparent;
  color: #20c997;
  font-size: .85rem;
  cursor: pointer;
  flex-shrink: 0;
  transition: background .15s, color .15s;
}
.dl-allbar-btn:not(:disabled):hover { background: #20c997; color: #fff; }
.dl-allbar-btn.is-downloaded { background: #20c997; color: #fff; }
.dl-allbar-btn:disabled { opacity: .7; cursor: wait; }
.dl-allbar-btn .offline-progress { width: 1.2em; height: 1.2em; }

.dl-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(170px, 1fr));
  gap: 1rem;
}
.dl-card {
  position: relative;
  border: 1px solid var(--border);
  border-radius: 14px;
  background: var(--bg2);
  padding: 1.1rem 1rem 3.3rem;
  min-height: 108px;
  overflow: hidden;
}
/* Little checkmark corner once a card's overlay is hidden (fully
   downloaded) — :has() support is broad enough now (2023+ evergreen
   browsers) for this cosmetic touch; the overlay's own display:none
   already does the functional job with or without it. */
.dl-card:has(.dl-card-overlay.is-downloaded)::after {
  content: '\2713';
  position: absolute;
  top: .5rem;
  inset-inline-end: .6rem;
  width: 1.4rem;
  height: 1.4rem;
  border-radius: 50%;
  background: #20c997;
  color: #fff;
  font-size: .75rem;
  display: flex;
  align-items: center;
  justify-content: center;
}
.dl-card-title { font-family: var(--font-h); font-size: 1rem; color: var(--violet); margin: 0 0 .35rem; padding-inline-end: 1.6rem; }
.dl-card-meta { font-size: .78rem; color: var(--muted); }

/* Screen-reader-only text — visually hidden but still announced.
   Used by .dl-card-overlay's label below: the button only needs an
   icon now that it no longer covers the card's own title/meta, but
   "Download for Offline" should still be read out for anyone using a
   screen reader. */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* A compact round button in the card's bottom corner, NOT a full-card
   overlay — the card's own title/count/size (.dl-card-body, above)
   stay visible underneath at all times instead of being hidden behind
   a dim/blurred layer until download finishes. The checkmark badge
   once downloaded (.dl-card:has(...)::after, above) sits in the
   opposite top corner so the two never collide. */
.dl-card-overlay {
  position: absolute;
  bottom: .65rem;
  inset-inline-end: .65rem;
  inset-inline-start: auto;
  top: auto;
  width: 2.5rem;
  height: 2.5rem;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--violet);
  border: none;
  border-radius: 50%;
  cursor: pointer;
  color: #fff;
  padding: 0;
  box-shadow: 0 2px 8px rgba(0,0,0,.25);
  transition: background .15s, transform .15s;
}
.dl-card-overlay:not(:disabled):hover { background: #20c997; transform: scale(1.06); }
.dl-card-overlay:disabled { cursor: wait; }
.dl-card-overlay.is-downloaded { display: none; }
.dl-card-overlay-inner { display: flex; align-items: center; justify-content: center; }
.dl-card-overlay-inner i.fa-cloud-arrow-down { font-size: 1.05rem; }
.dl-card-overlay .offline-progress { width: 1.5em; height: 1.5em; }
.dl-card-overlay .offline-progress-pct { font-size: .58em; }
.dl-card-size { opacity: .85; }
