/* ═══════════════════════════════════════════════════════════
 *  Anvár UI — main layout & components
 * ═══════════════════════════════════════════════════════════
 *
 * The bulk of the UI's style: the .app grid, sidebar, server
 * row, status bar, tab strip, tab panels, search controls,
 * results table, reader pane, full-book side panel, modals
 * (folder picker, manage collections, invite user), upload box,
 * collections tree, books tab, compilations, config tab, and
 * the bookmarks/passage-pin UI.
 *
 * Reads color and length variables from base.css (loaded
 * first). Anything that styles the login overlay or embedded
 * Clerk auth panels is in auth.css instead — those are
 * conceptually one feature and v20.0 keeps them grouped.
 *
 * Extracted in v20.0 from the inline <style> block at lines
 * 56-1077 of the monolithic persian_search_ui.html. No rules
 * were modified during the move; this file should be a verbatim
 * copy of that range, prefixed with this header.
 */


/* v2.29 — Top header height. Used by .app's height calc and the
   header's own sizing. Keeping it as a variable lets the rest of
   the layout (which is height:100vh-based) adjust automatically
   if the header ever needs to grow taller. */
:root { --top-h: 62px; }

/* v2.29 — Top header bar, mirrors the mockup's .top:
     - sticky/fixed at viewport top so it stays visible
     - translucent paper bg with backdrop blur (saturate amplifies
       the warm tones of any content showing through)
     - thin --warm bottom rule to separate from the app shell
   The header sits BEFORE .app in the DOM and its height is
   reserved out of .app via height:calc(100vh - var(--top-h)). */
.top {
  position: sticky;
  top: 0;
  z-index: 50;
  height: var(--top-h);
  background: rgba(246, 241, 232, 0.92);
  backdrop-filter: saturate(140%) blur(8px);
  -webkit-backdrop-filter: saturate(140%) blur(8px);
  border-bottom: 1px solid var(--warm);
  flex-shrink: 0;
}
.top-inner {
  /* v1.6.1 — Lock the header chrome to LTR regardless of the
     document's RTL/LTR mode. When the user flips the UI to
     Persian, the body content flips RTL but the chrome —
     brand on the left, nav items on the right with their
     original order (User badge → Language toggle → Version →
     Settings → Help) — stays put. Persian translations of nav
     labels still display correctly inside their own boxes
     (the browser bidi algorithm renders Persian characters RTL
     within a button even when the button itself flows LTR).
     Without this rule, the whole header mirrored on language
     flip — Anvár brand jumped to the right, nav items to the
     left — which made the chrome harder to find muscle-memory.
     direction:ltr is inherited by all descendants, so a single
     rule on .top-inner covers brand, top-nav, every button. */
  direction: ltr;
  max-width: 1280px;
  height: 100%;
  margin: 0 auto;
  padding: 0 28px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
}
.brand {
  /* v1.9 — Now a flex ROW: a 9-pointed star icon (.brand-icon)
     followed by the existing two-line text block (.brand-text).
     Pre-v1.9 .brand was the column; it now becomes the outer
     row with the column moved to .brand-text. min-width:0 stays
     on .brand so the subtitle truncation still works at narrow
     viewports. */
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 12px;
  min-width: 0;
}
.brand-icon {
  flex-shrink: 0;
  width: 38px;
  height: 38px;
  /* No animation — the entrance flourish + pulse on the login
     card belong to that one moment of arrival; the chrome should
     sit still so the eye doesn't keep getting drawn back to it.
     The geometry/colors are identical to .login-star-icon — only
     the size and the lack of motion differ. */
}
.brand-text {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.brand-title {
  /* v1.6.3 — Brand "انوار" / "Anvár" reads in Scheherazade New,
     the same typeface used for Persian/Arabic book bodies in the
     reader, so the chrome and the content read in one voice.
     Set as the primary font in both UI modes (FA and EN), not
     just FA: Scheherazade has solid Latin glyphs, so the EN
     "Anvár" rendering matches the FA "انوار" in one consistent
     brand-identity look. The Latin display fallbacks (Fraunces,
     EB Garamond, Garamond, Times) cover the case of a missing/
     failed Scheherazade .ttf load — Fraunces and EB Garamond are
     self-hosted via /fonts-english/ since v2.31 (see base.css). */
  font-family: 'Scheherazade New', 'Fraunces', 'EB Garamond', 'Garamond', 'Times New Roman', serif;
  font-weight: 700;
  font-size: 24px;
  letter-spacing: 0.01em;
  color: var(--ink);
  line-height: 1.1;
}
.brand-subtitle {
  font-family: 'EB Garamond', 'Garamond', 'Times New Roman', serif;
  font-style: italic;
  font-size: 13px;
  color: var(--ink-2);
  letter-spacing: 0.02em;
  /* truncate if the subtitle ever runs long on narrow viewports */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
html[lang="fa"] .brand-subtitle {
  font-family: 'Scheherazade New', Arial, Helvetica, sans-serif;
  font-style: normal;
  font-size: 14px;
}
.top-nav {
  display: flex;
  gap: 22px;
  font-size: 12.5px;
  color: var(--ink-2);
  text-transform: uppercase;
  letter-spacing: 0.12em;
  flex-shrink: 0;
  /* Reserve space on the right edge for the absolute-positioned
     #top-version-wrap (Version + 💡 bulb pinned at right:28px). Without
     this, the rightmost flex item (Language toggle) collides with the
     version cluster. ~120px clears "v4.3.0" + gap + bulb + breathing
     room across both EN and FA labels. */
  margin-right: 120px;
  /* v2.94 — Center-align flex items vertically. Without this,
     items default to align-items:stretch and each child sits at
     its own intrinsic top/bottom — the version label looked
     "low" relative to Help, Sign Out, Name (which are buttons /
     spans with different default baselines). align-items:center
     pins all children to the same vertical midline. */
  align-items: center;
}
html[lang="fa"] .top-nav {
  text-transform: none;
  letter-spacing: 0.04em;
  font-size: 13px;
}
.top-nav a {
  padding: 4px 0;
  border-bottom: 1px solid transparent;
  transition: border-color 160ms;
  text-decoration: none;
  color: inherit;
}
.top-nav a:hover { border-bottom-color: var(--rust); }

/* v2.30 — User badge + lang toggle inside the top header.
   The original sidebar-header versions had a dark background
   (against the rust gradient header bar). Up here in the top
   header we're on warm parchment, so the controls take a much
   lighter treatment: thin border, ink text, hover-driven accent.
   The IDs are unchanged from the sidebar-header markup so all
   existing JS continues to work. */
.top-user-badge {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 12px;
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink-2);
}

/* ── v2.87 / v2.88 — Top-nav item order ─────────────────────
   v2.87 requested order: Language, Account, Version, Name, Help, Sign Out
   v2.88: Account moved into a dropdown under the Name, so the
   top-nav surface no longer carries an Account button. New order:
     Language, Version, Name (▾ Account), Help, Sign Out
   Source order in HTML is fixed (badge wrapper first, then lang
   toggle, version, help). To get the requested visual order:
     1. set #user-badge to display:contents (auth.js) so its
        children become direct flex items of .top-nav
     2. .badge-name-dropdown stays as a normal positioned flex
        item (NOT display:contents) because it has to be the
        positioning anchor for the absolute .badge-menu inside it
     3. each top-nav item gets an `order` value matching the new
        sequence */
/* ── v2.87 / v2.88 / v2.95 — Top-nav item order ─────────────
   Final order (English UI, left → right):
     Language, Help, Version, Username (▾ Account / Sign Out)
   v2.95 — Sign Out moved into the badge-menu dropdown alongside
   Account; help moved before version; version sits before username.
   Source order in HTML is: badge-name-dropdown, ui-lang-toggle,
   top-version, help-dropdown — fixed for now. To reorder we use
   CSS `order` on each top-nav flex item. The #user-badge wrapper
   is set display:contents in auth.js so its child .badge-name-dropdown
   becomes a direct flex item of .top-nav and its `order` applies. */
/* v4.2.1 — Reordered. Visual (left → right): Help, Settings,
   Recommendations, Name, Lang, Version. .top-inner is forced
   direction:ltr above, so flex flows LTR in BOTH UI languages —
   a single set of order values produces the same screen layout
   in EN and FA. */
/* v4.5.x — Language and Name swapped vs. v4.2.1 (lang now sits
   before the username in the visual flow). */
#help-dropdown                { order: 1; }
#settings-top-nav             { order: 2; }
/* v4.7.0 — Language picker is now a wrapper span around the
   trigger button; keep #ui-lang-toggle in the rule for older
   layouts/specs that still match it, but #lang-dropdown is the
   actual flex child now. */
#lang-dropdown                { order: 3; }
#ui-lang-toggle               { order: 3; }
.badge-name-dropdown          { order: 4; }
/* v4.2.2 — Version pinned to the FULL viewport right, outside
   .top-inner's 1280px max-width. Absolute positioning takes it
   out of the flex flow; .top is position:sticky which provides
   the containing block.
   v4.2.3 — The 💡 Recommendations shortcut rides along with
   Version in #top-version-wrap, so the positioning moved onto
   the wrapper. #top-version + #top-recommend-btn flow inline
   inside it. */
#top-version-wrap {
  order: 5;
  position: absolute;
  right: 28px;
  top: 50%;
  transform: translateY(-50%);
  display: inline-flex;
  align-items: center;
  gap: 10px;
}
#top-recommend-btn {
  position: relative;              /* anchor for the ::after tooltip */
  background: transparent;
  border: 0;
  padding: 2px 4px;
  cursor: pointer;
  line-height: 0;                  /* tight SVG box, no descender slack */
  color: var(--gold);              /* matches the Anvár brand star */
  border-radius: 4px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: background-color 140ms, color 140ms;
}
#top-recommend-btn:hover {
  background-color: rgba(163, 123, 43, 0.12);  /* var(--gold) at 12% */
  color: var(--rust);              /* matches the inner star detail */
}
/* Immediate CSS tooltip — reads attr(title), which is i18n-aware via
   data-i18n-title="topnav.recommend" (EN: "Recommendations" / FA:
   "پیشنهادها"). Sits below the button, right-aligned so it never
   overflows the viewport since the button is at the screen's right
   edge. The native title still shows on the OS delay; this one fires
   on first hover. */
#top-recommend-btn::after {
  content: attr(title);
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  background: var(--gold);          /* same gold as the bulb icon */
  color: #f6f1e8;                   /* parchment, for legibility on gold */
  padding: 7px 12px;                /* taller pill so descenders breathe */
  border-radius: 5px;
  font-size: 12px;
  line-height: 1.3;
  letter-spacing: 0.04em;
  text-transform: none;
  white-space: nowrap;
  pointer-events: none;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.18);
  opacity: 0;
  transform: translateY(-2px);
  transition: opacity 160ms, transform 160ms;
  z-index: 60;
}
#top-recommend-btn:hover::after {
  opacity: 1;
  transform: translateY(0);
}

/* The badge-name no longer inherits letter-spacing/text-transform
   reset from the (now contents-only) #user-badge wrapper — it has
   to take those over directly so the user's name doesn't get
   uppercased + letter-spaced like the rest of the top-nav text. */
.top-user-badge .badge-name {
  text-transform: none;
  letter-spacing: 0;
}

/* ── v2.88 — Badge-name as a clickable dropdown trigger ────
   The username is now a button that opens a small dropdown
   containing "Account" (and could host more profile actions
   later). Visual styling mirrors .help-trigger: plain text with
   a subtle hover underline + a small caret. The .badge-name-dropdown
   wrapper is the positioning anchor for the absolute .badge-menu
   inside it, so it stays as inline-flex (not display:contents). */
.badge-name-dropdown {
  position: relative;
  display: inline-flex;
  align-items: center;
}
.badge-name-dropdown .badge-name {
  cursor: pointer;
  background: transparent;
  border: none;
  padding: 4px 0;
  border-bottom: 1px solid transparent;
  transition: border-bottom-color 140ms;
}
.badge-name-dropdown .badge-name:hover,
.badge-name-dropdown.open .badge-name {
  border-bottom-color: var(--rust);
}
.badge-name-dropdown .badge-name::after {
  content: " ▾";
  font-size: .7em;
  color: var(--gold);
  margin-inline-start: 2px;
  vertical-align: middle;
}
.badge-menu {
  display: none;
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  background: var(--cream);
  border: 1.5px solid var(--gold);
  border-radius: var(--r);
  box-shadow: 0 8px 24px var(--shadow);
  min-width: 160px;
  z-index: 1000;
  padding: 4px;
}
html[lang="en"] .badge-menu {
  right: auto;
  left: 0;
}
.badge-name-dropdown.open .badge-menu {
  display: block;
}
.badge-menu button {
  display: block;
  width: 100%;
  text-align: start;
  background: transparent;
  border: none;
  color: var(--ink);
  font-family: inherit;
  font-size: .85rem;
  padding: 8px 12px;
  border-radius: var(--r);
  cursor: pointer;
  transition: background .14s;
}
.badge-menu button:hover {
  background: rgba(163,123,43,.18);
  color: var(--rust);
}
/* v4.7.0 — Thin gold separator between Account and Sign Out so
   the two items don't visually merge into one hover band. Matches
   the .lang-menu separator. */
.badge-menu button + button {
  border-top: 1px solid rgba(163,123,43,.28);
}
.top-user-badge .badge-name {
  font-family: 'EB Garamond', 'Garamond', 'Times New Roman', serif;
  font-style: italic;
  /* v2.82 — Same gold hue (matches the dropdown carets) but
     font-weight + size bumped so the name reads CLEARLY against
     the cream top-header background. v2.81's combination of
     italic 13px @ weight-500 in --gold (#a37b2b) on parchment
     was technically correct but visually faint because the gold
     and the parchment are in the same hue family. Going to
     weight-700 at 14px gives the type enough mass to assert
     without changing the color the user asked for.
     v2.83 — Color shifted from --gold (#a37b2b) to --rust
     (#7a3b2e). Same warm-brown family, but darker — improves
     contrast on the cream header so the name reads strongly
     without needing extra weight tricks. */
  font-size: 14px;
  font-weight: 700;
  /* v2.93 — Color stepped up to --ink (#1f1a14, near-black). The
     previous --rust (#7a3b2e) and --gold (#a37b2b) tones were
     correct in CSS but rendered as faint brown on the cream
     header — Safari/Mac in particular tends to mute button text
     colors via UA stylesheets. Using --ink with !important gives
     the username strong, unambiguous contrast against the
     parchment background. */
  color: var(--ink) !important;
  max-width: 200px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* v1.6.10 — Removed the html[lang="fa"] override on the badge
   name. Previously FA mode swapped the username face to
   Scheherazade New and dropped the italic. Usernames are
   account handles (Latin/ASCII in practice — Clerk usernames),
   so giving them a Persian-script face when the UI flipped
   was decorative-only and made the badge look inconsistent
   between modes. EN's EB Garamond italic now applies in both. */
.top-user-badge .manage-btn,
.top-user-badge .logout-btn {
  /* v2.80 — Boxless. Was a thin-bordered pill; now matches the
     Help trigger style — plain text with a subtle hover underline.
     Keeps the uppercase + letter-spacing in English mode for
     visual rhythm with the other top-nav items. */
  font-family: inherit;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--ink-2);
  background: transparent;
  border: none;
  padding: 4px 0;
  border-bottom: 1px solid transparent;
  cursor: pointer;
  transition: border-bottom-color 140ms, color 140ms;
}
html[lang="fa"] .top-user-badge .manage-btn,
html[lang="fa"] .top-user-badge .logout-btn {
  text-transform: none;
  letter-spacing: 0.02em;
  font-size: 12px;
  font-family: 'Scheherazade New', Arial, Helvetica, sans-serif;
}
.top-user-badge .manage-btn:hover,
.top-user-badge .logout-btn:hover {
  border-bottom-color: var(--rust);
  color: var(--rust);
}

.top-lang-toggle {
  /* v2.80 — Boxless to match the rest of the top nav. Now just a
     text button with hover underline — same look as Help. The
     label switched from "EN" / "فا" to the full word ("English"
     / "فارسی") via the i18n key (see i18n.js).  */
  font-family: inherit;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-2);
  background: transparent;
  border: none;
  padding: 4px 0;
  border-bottom: 1px solid transparent;
  cursor: pointer;
  transition: border-bottom-color 140ms, color 140ms;
}
html[lang="fa"] .top-lang-toggle {
  text-transform: none;
  letter-spacing: 0.02em;
  font-size: 13px;
  font-family: 'Scheherazade New', Arial, Helvetica, sans-serif;
}
.top-lang-toggle:hover {
  border-bottom-color: var(--rust);
  color: var(--rust);
}

/* v2.54 — Top-nav version label. Sits between the lang toggle
   and Help. Italic Garamond, muted ink, monospace digits — same
   typographic family as the rt-meta counts elsewhere so it reads
   as quiet metadata rather than a clickable element. Hidden when
   empty (pre-fetch from /status).
   v2.58 — Font now MATCHES the "Help" link next to it: same
   sans-serif chain, same uppercase + letter-spacing, same size.
   Color stays muted (--ink-3) so it's clearly non-clickable
   metadata, not a third nav link. */
.top-version {
  /* v1.6.11 — Pin the font-family explicitly to the EN body
     stack instead of `inherit`. Inheriting bubbled up to body
     and picked up Scheherazade New in FA mode (where body's
     font is Persian-script), so the version label "v1.6.11"
     read in Scheherazade in FA but Albert Sans in EN. The
     version string is always Latin/ASCII, so anchoring it to
     a sans stack here makes both modes render identically. */
  font-family: 'Albert Sans', -apple-system, BlinkMacSystemFont,
               "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  font-style: normal;
  font-size: 12.5px;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
  direction: ltr;
  white-space: nowrap;
}
.top-version:empty {
  display: none;
}
/* v1.6.9 — Removed the html[lang="fa"] .top-version override.
   Previously FA mode swapped the version label to Scheherazade
   New, dropped the uppercase + letter-spacing, and bumped the
   size to 13px. The version string is always Latin/ASCII
   (e.g. "v.1.6.9"), so giving it a Persian-script face was
   purely decorative; matching the EN rules makes the label
   consistent across UI languages — the version reads the same
   way regardless of which mode the user is in. */

/* v2.29 — .app height now accounts for the top header. Without
   this, the app shell would extend to 100vh and the bottom of
   the sidebar / cards / reader would be cut off behind the
   page-bottom edge. */
.app{display:flex;height:calc(100vh - var(--top-h));overflow:hidden;position:relative;z-index:1}

/* Sidebar */
/* Sidebar fills whatever space the full-book panel doesn't take.
   flex:1 1 0 lets it grow/shrink freely as the book splitter moves.
   min-width:250px keeps it readable at minimum. */
.sidebar{
  min-width:250px;
  flex:1 1 0;
  box-sizing:border-box;
  display:flex;flex-direction:column;
  border-left:2px solid var(--warm);background:var(--cream);overflow:hidden}
.sidebar-header{background:linear-gradient(135deg,var(--rust),#a0440f);color:#fdf6e3;padding:10px 18px;flex-shrink:0;height:52px;display:flex;align-items:center;gap:10px;box-sizing:border-box}
.sidebar-header h1{font-family:'Scheherazade New',Arial,Helvetica,sans-serif;font-size:1.2rem;font-weight:700;display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;min-width:0;overflow:hidden}
.sidebar-header .sub{font-size:.72rem;opacity:.75;font-family:'Scheherazade New',Arial,Helvetica,sans-serif;font-weight:400}
.sidebar-header #stxt{line-height:1.3}
.sidebar-header input:focus{outline:none;border-color:var(--gold)}

.server-row{display:flex;gap:8px;align-items:center;padding:8px 12px;background:rgba(163,123,43,.08);border-bottom:1px solid var(--warm);flex-shrink:0}
.server-row input{flex:1;font-size:.78rem;padding:5px 8px;border:1.5px solid var(--warm);border-radius:var(--r);background:var(--parchment);color:var(--ink);font-family:'Scheherazade New',Arial,Helvetica,sans-serif;direction:ltr}
.server-row input:focus{outline:none;border-color:var(--gold)}

#status-bar{display:flex;align-items:center;gap:8px;padding:7px 12px;font-size:.76rem;background:var(--parchment);border-bottom:1px solid var(--warm);flex-shrink:0}
.dot{width:8px;height:8px;border-radius:50%;background:#ccc;flex-shrink:0;transition:background .3s}
.dot.ok{background:var(--sage);box-shadow:0 0 0 3px rgba(74,103,65,.2)}
.dot.err{background:var(--rust)}
.dot.pulse{background:var(--gold);animation:pulse 1s infinite}
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.4}}

/* v2.41 — Tab strip background pinned to --parchment so it
   matches the search tab's content area (set in v2.19). The
   sidebar's --cream default was bleeding through and giving the
   tab strip a slightly darker box than its surroundings. */
/* v2.77 — Top-level tab strip is hidden. The Search panel becomes
   the always-on default; Collections, Books, and Settings (config)
   are reached via Help → Settings instead. The .tabs element is
   kept in the DOM so the existing switchTab() handler still works
   (the panels themselves are toggled by it), but it's invisible. */
.tabs{display:none}
.tab{flex:1;padding:9px 4px;text-align:center;font-family:'Scheherazade New',Arial,Helvetica,sans-serif;font-size:.85rem;font-weight:700;cursor:pointer;color:#888;border-bottom:3px solid transparent;transition:color .2s,border-color .2s;margin-bottom:-2px}
.tab.active{color:var(--rust);border-color:var(--rust)}

.tab-body{flex:1;overflow-y:auto;min-height:0}
.tab-panel{display:none;padding:14px}
.tab-panel.active{display:block}

/* Search tab: pin the search box and meta row at the top so they
   stay visible while results scroll. When #tab-search is active we
   make it a flex column that fills .tab-body, then #search-split
   (the 3-pane grid) is the single flex child that grows to fill
   remaining vertical space. Each pane inside #search-split scrolls
   internally — see #results-body, #filter-tree-pane (which uses
   .rt-tree as its inner scroller), and the reader pane.

   v2.22 — Updated the selector to target #search-split instead of
   the legacy #results-body. Pre-v2.0 layout had #results-body as a
   direct child of #tab-search; with the 2/3-column grid wrapper
   added in v2.0+, it's now nested inside #search-split. The old
   rule was misfiring (looking for a child that didn't exist), so
   nothing was grabbing the flex-grow slot — the grid wrapper had
   to use explicit `height: calc(100vh - 220px)` math which broke
   on every viewport change. */
#tab-search.active{display:flex;flex-direction:column;height:100%;padding:10px 14px 14px;box-sizing:border-box;overflow:hidden;
  background:var(--parchment)}
#tab-search.active > :not(#search-split){flex-shrink:0}
#tab-search.active > #search-split{flex:1 1 auto;min-height:0;margin-top:0}
/* When the search tab is the active view, suppress the outer scroller so
   only the results section scrolls — avoids a visible double-scrollbar.
   The :has() rule handles modern browsers; the .tab-body.search-active
   class is a JS-set fallback for older ones (toggled in switchTab). */
.tab-body:has(> #tab-search.active){overflow:hidden}
.tab-body.search-active{overflow:hidden}

/* Form */
.field-label{font-size:.76rem;font-weight:700;color:var(--rust);margin-bottom:4px;letter-spacing:.04em}
input[type=text],input[type=number]{font-family:'Scheherazade New',Arial,Helvetica,sans-serif;color:var(--ink);background:var(--parchment);border:1.5px solid var(--warm);border-radius:var(--r)}
input:focus{outline:none;border-color:var(--gold);box-shadow:0 0 0 3px rgba(163,123,43,.12)}

/* Buttons */
.btn{display:inline-flex;align-items:center;gap:5px;padding:8px 16px;border:none;border-radius:var(--r);font-family:'Scheherazade New',Arial,Helvetica,sans-serif;font-size:.9rem;font-weight:700;cursor:pointer;transition:filter .15s,transform .1s;white-space:nowrap}
.btn:active{transform:scale(.97)}
.btn:disabled{opacity:.5;cursor:not-allowed}
.btn-primary{background:linear-gradient(135deg,var(--rust),#a0440f);color:#fdf6e3;box-shadow:0 2px 6px rgba(139,58,15,.3)}
.btn-primary:hover{filter:brightness(1.1)}
.btn-gold{background:linear-gradient(135deg,var(--gold),#a07800);color:#fdf6e3}
.btn-gold:hover{filter:brightness(1.1)}
.btn-teal{background:linear-gradient(135deg,var(--teal),#145a73);color:#fdf6e3;box-shadow:0 2px 6px rgba(31,111,139,.3)}
.btn-teal:hover{filter:brightness(1.1)}
.btn-danger{background:#c0392b;color:#fff}
.btn-danger:hover{filter:brightness(1.1)}
.btn-sm{padding:4px 10px;font-size:.76rem}

/* Destructive buttons (collection delete, clear-DB) get this
   class when destructive_ops_allowed is false on the server.
   Grey them out, drop pointer events, but keep them in the DOM
   so the layout doesn't shift between locked/unlocked states.
   The disabled HTML attribute also blocks the onclick — this CSS
   is the visual cue. */
.is-locked{opacity:.4;cursor:not-allowed;filter:grayscale(.7)}
.is-locked:hover{filter:grayscale(.7)}  /* override .btn-danger:hover brightness */
.btn-full{width:100%;justify-content:center;margin-bottom:8px}

/* Search */
.search-wrap{position:relative;margin-bottom:10px}
/* v2.12 — search input direction follows the UI language.
   Persian (default RTL): user types right-to-left.
   English (LTR): user types left-to-right.
   Achieved by removing the hardcoded `direction:rtl` and letting
   the input inherit from <html dir>, which applyUILang flips. */
.search-wrap input{width:100%;padding:11px 14px 11px 42px;font-size:1.05rem;border-width:2px;background:#fffdf7}
html[lang="fa"] .search-wrap input{direction:rtl}
html[lang="en"] .search-wrap input{direction:ltr;text-align:left}

/* Search history dropdown */
.history-menu{position:absolute;top:calc(100% + 2px);right:0;left:0;z-index:60;background:var(--cream);border:1.5px solid var(--warm);border-radius:var(--r);box-shadow:0 6px 20px var(--shadow);max-height:320px;overflow-y:auto;display:none}
.history-menu.open{display:block}
.history-header{display:flex;justify-content:space-between;align-items:center;padding:6px 12px;font-size:.7rem;color:#888;background:rgba(163,123,43,.06);border-bottom:1px solid var(--warm);font-weight:700}
.history-clear{background:none;border:none;color:var(--rust);font-size:.7rem;font-family:'Scheherazade New',Arial,Helvetica,sans-serif;cursor:pointer;padding:2px 6px;border-radius:3px}
.history-clear:hover{background:rgba(192,57,43,.1)}
.history-item{display:flex;align-items:center;gap:8px;padding:7px 12px;cursor:pointer;font-size:.88rem;color:var(--ink);border-bottom:1px solid rgba(163,123,43,.08);transition:background .1s}
.history-item:hover{background:rgba(163,123,43,.09)}
.history-item:last-child{border-bottom:none}
.history-item .h-text{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;direction:rtl;text-align:right}
/* v4.2.3+ — English UI: history rows read left-to-right. The FA rule
   above defaults to RTL for Persian/Arabic queries; override here so
   English entries don't appear right-aligned with RTL bidi. */
html[lang="en"] .history-item .h-text{direction:ltr;text-align:left}
.history-item .h-del{background:none;border:none;color:#aaa;font-size:.9rem;cursor:pointer;padding:2px 6px;border-radius:3px;line-height:1}
.history-item .h-del:hover{color:var(--rust);background:rgba(192,57,43,.1)}
/* v4.0.20 — Switched from physical `left` to logical
   `inset-inline-start` so the magnifier sits at the input's leading
   edge in BOTH UIs. In LTR English that's still the visual left;
   in RTL Persian it flips to the visual right. Pairs with the
   .col-dropdown-inset rule below, which now anchors to inline-end. */
.search-icon{position:absolute;inset-inline-start:32px;top:50%;transform:translateY(-50%);color:var(--gold);font-size:1rem;pointer-events:none}
/* v4.6.5 — Inline search-status indicator, sits on the leading-most
   edge of .search-wrap, just before .search-icon. Always visible.
   Two states: default = green ✓ (no active search), .has-results =
   red × (clicking clears the search). Same logical-property anchoring
   as .search-icon so it lands on the right in RTL Persian and the
   left in LTR English. */
.search-clear-x{
  position:absolute;inset-inline-start:8px;top:50%;
  transform:translateY(-50%);
  width:18px;height:18px;line-height:1;
  border:none;background:transparent;
  color:var(--sage);
  font-size:.95rem;font-weight:700;
  padding:0;cursor:default;
  display:flex;align-items:center;justify-content:center;
  border-radius:50%;
  transition:background .12s,color .12s;
}
.search-clear-x.has-results{
  color:var(--rust);
  font-size:1.05rem;
  cursor:pointer;
}
.search-clear-x.has-results:hover{
  background:rgba(192,57,43,.12);
  color:#a0440f;
}
/* Mirror the → arrow in RTL so it still points "into" the field (the
   input's text-start side). The × glyph is direction-agnostic, so only
   the idle (no .has-results) state needs flipping. */
html[dir="rtl"] .search-clear-x:not(.has-results){
  transform:translateY(-50%) scaleX(-1);
}

/* Collection filter dropdown */
.col-filter-label{font-size:.76rem;font-weight:700;color:var(--rust);margin-bottom:6px}
.col-dropdown{position:relative;user-select:none}

/* v2.66 — When the col-dropdown is anchored INSIDE the search
   input (.col-dropdown-inset, used by the new full-width search
   row), it floats absolutely against the trailing edge of the
   input. This mirrors how .search-icon sits on the leading edge.
   The trigger button is sized smaller and uses a transparent
   border so the input's own border carries the visual frame. */
.col-dropdown-inset {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  /* v4.0.20 — Logical anchor (was right:6px). Pairs with .search-icon
     using inset-inline-start: in LTR the dropdown stays on the visual
     right; in RTL Persian it flips to the visual left so the magnifier
     leads and the dropdown trails in both UIs. */
  inset-inline-end: 6px;
  z-index: 5;
}
.col-dropdown-inset .col-dropdown-trigger {
  padding: 3px 8px;
  font-size: .78rem;
  border: 1px solid transparent;
  background: rgba(163,123,43,.08);
  border-radius: var(--r);
  cursor: pointer;
  min-width: 0;
}
.col-dropdown-inset .col-dropdown-trigger:hover {
  background: rgba(163,123,43,.16);
  border-color: rgba(163,123,43,.3);
}
.col-dropdown-inset .col-dropdown-trigger.open {
  background: rgba(163,123,43,.18);
  border-color: var(--gold);
  box-shadow: 0 0 0 2px rgba(163,123,43,.10);
}
.col-dropdown-inset .label {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  /* v2.67 — Tightened from 90px to 50px now that the label is
     just the icon (with an optional small count like "🌐 3"). */
  max-width: 50px;
}

/* v2.68 — Search row spans BOTH columns of #search-split via
   grid-area:search. It is now a sibling of the filter tree pane
   and the cards body (was a child of #results-body in v2.32 →
   v2.66; moved out in v2.68 because #results-body's overflow:auto
   was clipping the negative-margin extension on its X-axis).
   Layout-wise, this row is a flex container holding the search
   wrap and the font stepper. */
.search-row-wide {
  position: relative;
  z-index: 6;
}
.search-row-wide .search-wrap-wide {
  /* The input is the only flex-grower in the row; explicitly
     tell it min-width:0 so it can shrink past its content's
     intrinsic minimum if the cards column gets very narrow. */
  min-width: 0;
}
.col-dropdown-trigger{
  display:flex;align-items:center;justify-content:space-between;gap:8px;
  padding:8px 12px;background:var(--parchment);border:1.5px solid var(--warm);
  border-radius:var(--r);cursor:pointer;font-family:'Scheherazade New',Arial,Helvetica,sans-serif;font-size:.85rem;
  color:var(--ink);transition:border-color .15s}
.col-dropdown-trigger:hover{border-color:var(--gold)}
.col-dropdown-trigger.open{border-color:var(--gold);box-shadow:0 0 0 3px rgba(163,123,43,.12)}
.col-dropdown-trigger .label{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.col-dropdown-trigger .caret{color:var(--gold);font-size:.7rem;transition:transform .2s}
.col-dropdown-trigger.open .caret{transform:rotate(180deg)}
.col-dropdown-menu{
  /* v1.7.6 — Was position:absolute anchored inside .col-dropdown.
     Two ancestors made that arrangement clip the panel:
       (a) .col-dropdown-inset uses transform:translateY(-50%), which
           per CSS spec creates a containing block for fixed-positioned
           descendants — so even position:fixed wouldn't escape it.
       (b) #tab-search.active and .tab-body both set overflow:hidden,
           which clipped the panel at the column-gap line in the
           middle of the page.
     Fix: open-time the JS reparents the menu to <body> and sets
     viewport-relative top/left|right inline. Reparented to <body>,
     position:fixed escapes both (a) and (b) cleanly. The static
     top/right/left declarations are gone — JS sets them per-open. */
  position:fixed;z-index:50;
  /* v2.53 — Wider and more prominent. The dropdown reads as a
     real "panel that emerged from the trigger" rather than a
     small attached menu:
       - min-width 480px / max-width 640px (was 320/480)
       - thicker, more saturated rust border
       - stronger drop shadow + slight glow underlay so it lifts
         visibly off the page
       - a touch more border-radius to match the elevated card feel
       - max-height bumped to 60vh so users can see more options
         without scrolling
     v1.7.7 — Width trimmed by roughly a third (480/640 → 320/430)
     because the v2.53 size felt oversized once the trigger was
     moved inside the search input. The other v2.53 lifts (border,
     shadow, radius, max-height) are kept. */
  min-width:320px;
  max-width:430px;
  background:var(--cream);
  border:2px solid var(--rust);
  border-radius:6px;
  box-shadow:
    0 12px 32px rgba(31,26,20,.22),
    0 4px 8px rgba(31,26,20,.10),
    0 0 0 1px rgba(163,123,43,.18);
  max-height:60vh;
  overflow-y:auto;
  display:none}
/* v1.7.6 — LTR anchor override removed; JS picks the side dynamically
   from document.documentElement.dir at open time. */
.col-dropdown-menu.open{display:block}
.col-opt{
  display:flex;align-items:center;gap:8px;padding:8px 12px;cursor:pointer;
  font-size:.85rem;transition:background .1s;border-bottom:1px solid rgba(163,123,43,.1)}
.col-opt:last-child{border-bottom:none}
.col-opt:hover{background:rgba(163,123,43,.08)}
.col-opt input[type=checkbox]{width:15px;height:15px;cursor:pointer;accent-color:var(--rust);flex-shrink:0}
.col-opt .opt-name{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.col-opt .opt-count{font-size:.7rem;color:#888;flex-shrink:0}
.col-opt.all-opt{background:rgba(163,123,43,.06);font-weight:700;color:var(--rust);border-bottom:2px solid var(--warm)}
.col-opt.all-opt:hover{background:rgba(163,123,43,.14)}
.col-opt-tools{
  display:flex;align-items:center;gap:8px;
  padding:6px 12px;background:rgba(163,123,43,.04);
  border-bottom:1px solid rgba(163,123,43,.18)}
.col-opt-tools .col-tool-btn{
  flex:0 0 auto;padding:3px 10px;font-size:.75rem;font-weight:600;
  background:transparent;border:1px solid rgba(163,123,43,.32);
  border-radius:4px;color:var(--rust);cursor:pointer;
  transition:background .12s,border-color .12s,color .12s}
.col-opt-tools .col-tool-btn:hover:not(:disabled){
  background:rgba(163,123,43,.18);border-color:var(--rust)}
.col-opt-tools .col-tool-btn:disabled{
  opacity:.45;cursor:default;color:#999;border-color:rgba(163,123,43,.18)}
/* Tree extensions: caret, indented book rows, tri-state visual for ◐ */
.col-opt .col-caret{flex-shrink:0;width:14px;text-align:center;color:var(--gold);
  font-size:.7rem;cursor:pointer;padding:2px 0;line-height:1;user-select:none;
  transition:color .1s}
.col-opt .col-caret:hover{color:var(--rust)}
.col-opt.book-opt{padding-right:36px;background:rgba(163,123,43,.02);font-size:.8rem}
.col-opt.book-opt:hover{background:rgba(163,123,43,.1)}
.col-opt.book-opt .opt-name{color:#555;font-weight:400}

/* v1.2 — Private-collection lock indicator. The 🔒 emoji sits
   inline next to the name in dropdowns and to the right of the
   collection cell in the search results table. The tinted
   background on private rows / cards uses a soft amber wash
   (same hue family as the brand chrome) so it reads as
   "yours" without screaming for attention. */
.col-opt[data-private="1"]{background:rgba(207,159,77,.08)}
.col-opt[data-private="1"]:hover{background:rgba(207,159,77,.16)}
.col-opt[data-private="1"] .opt-name{color:var(--rust);font-weight:600}
.col-lock{margin-right:6px;font-size:.85em;opacity:.85;vertical-align:baseline}
.result-lock{margin-left:4px;font-size:.85em;opacity:.85;vertical-align:baseline}
.td-collection-private{background:rgba(207,159,77,.10)!important}
.result-card-private{background:linear-gradient(0deg,rgba(207,159,77,.06),rgba(207,159,77,.06)),var(--parchment)}
.result-card-private .rc-collection{color:var(--rust);font-weight:600}
/* Partial-state collection: render a square inside the (otherwise empty)
   checkbox so users can see the ◐ meaning at a glance. We use ::after on
   a wrapper span-like pseudo because we can't style the checkbox itself
   directly. The trick: draw a small filled rectangle overlapping the
   checkbox when data-col-state="partial". */
.col-opt[data-col-state="partial"]{position:relative}
.col-opt[data-col-state="partial"] input[type=checkbox]{position:relative}
.col-opt[data-col-state="partial"] input[type=checkbox]::after{
  content:"";position:absolute;top:3px;left:3px;right:3px;bottom:3px;
  background:var(--rust);border-radius:1px;pointer-events:none}

/* Results */
.results-meta{font-size:.76rem;color:var(--gold);font-style:italic;margin-bottom:10px}
/* v2.0 — when used above the snippet card list (no table header to
   share visual weight with), bump the meta line up a notch and give
   it a faint bottom rule so it reads as a section header rather
   than a footnote. Scoped via :has() so the legacy table render is
   left untouched. */
#results-body:has(> .results-cards) ~ #results-meta,
.tab-panel#tab-search > div:has(#results-meta) #results-meta {
  font-size: .82rem;
  color: var(--ink);
  font-style: normal;
  font-weight: 700;
  letter-spacing: .01em;
}
/* "Show all results" button shown next to the truncated-result tally
   when the server cap kicked in. Inline with the meta text rather
   than its own row so it sits where the user is already looking. */
.btn-show-all-results{
  display:inline-block;margin-right:8px;padding:2px 9px;
  font-family:'Scheherazade New',Arial,Helvetica,sans-serif;font-size:.78rem;font-style:normal;
  font-weight:700;color:#fdf6e3;
  background:linear-gradient(135deg,var(--rust),#a0440f);
  border:none;border-radius:3px;cursor:pointer;
  transition:filter .15s,transform .1s;
  vertical-align:baseline}
.btn-show-all-results:hover{filter:brightness(1.1)}
.btn-show-all-results:active{transform:scale(.97)}
/* v2.56 — Right-edge rust stripe removed from EVERY card. The
   stripe was a holdover from the legacy table-style card and
   gave every card a permanent brown bar. The active-card stripe
   is handled separately by .result-card.row-selected (inset
   box-shadow on the trailing edge), so visually the stripe now
   appears ONLY on the clicked card and disappears when another
   card is clicked. */
.result-card{background:var(--parchment);border:1px solid var(--warm);border-radius:var(--r);margin-bottom:12px;overflow:hidden;transition:box-shadow .2s}
.result-card:hover{box-shadow:0 3px 12px var(--shadow)}
.result-card-hdr{display:flex;justify-content:space-between;align-items:center;padding:8px 12px;background:rgba(163,123,43,.07);border-bottom:1px solid var(--warm);gap:6px;flex-wrap:wrap}
.result-fname{font-family:'Scheherazade New',Arial,Helvetica,sans-serif;font-size:.95rem;font-weight:700;color:var(--rust);cursor:pointer}
.result-fname:hover{text-decoration:underline}
.result-col-badge{background:var(--gold);color:#fff;font-size:.65rem;padding:2px 8px;border-radius:20px;font-weight:700}
.result-occ-badge{background:var(--rust);color:#fff;font-size:.65rem;padding:2px 8px;border-radius:20px;font-weight:700}
.result-path{font-size:.68rem;color:#999;padding:2px 12px;direction:ltr;text-align:right;font-family:monospace;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* Config tab — two-column settings table (Description / Value) */
.config-table{width:100%;border-collapse:collapse;margin-bottom:14px;table-layout:fixed}
.config-table thead th{
  padding:8px 10px;
  font-family:'Scheherazade New',Arial,Helvetica,sans-serif;
  font-size:.8rem;font-weight:700;color:var(--rust);
  background:rgba(163,123,43,.12);
  border-bottom:2px solid var(--warm);
  text-align:right;
}
.config-table thead th.ct-value-col{text-align:center;width:150px}
.config-table tbody tr{border-bottom:1px solid rgba(163,123,43,.15)}
.config-table tbody tr:last-child{border-bottom:none}
.config-table tbody tr:hover{background:rgba(163,123,43,.05)}
/* Section dividers inside the config table — used to group related
   settings (e.g. Persian vs English font sizes). The row itself
   suppresses its hover + bottom-border so it reads as a label,
   not an interactive row. */
.config-table tbody tr.ct-section-head{background:rgba(163,123,43,.08);border-bottom:none}
.config-table tbody tr.ct-section-head:hover{background:rgba(163,123,43,.08)}
.config-table tbody tr.ct-section-head td{padding:7px 10px}
.ct-section-label{font-family:'Scheherazade New',Arial,Helvetica,sans-serif;font-size:.82rem;font-weight:700;
  color:var(--rust);letter-spacing:.03em;text-align:right}
.config-table td{padding:10px;vertical-align:top}
.config-table td.ct-value-cell{vertical-align:middle;text-align:center}
.ct-name{font-size:.88rem;font-weight:700;color:var(--ink);margin-bottom:3px;font-family:'Scheherazade New',Arial,Helvetica,sans-serif}
.ct-desc{font-size:.72rem;color:#777;line-height:1.65}
.ct-range{font-size:.68rem;color:#888;margin-top:5px;white-space:nowrap}
.ct-input{width:120px;padding:6px 8px;font-size:.92rem;text-align:center;
  border:1.5px solid var(--warm);border-radius:var(--r);
  background:var(--parchment);color:var(--ink);
  font-family:'Scheherazade New',Arial,Helvetica,sans-serif}
.ct-input:focus{outline:none;border-color:var(--gold)}
.ct-input-text{width:120px;padding:6px 8px;font-size:.8rem;
  direction:ltr;font-family:monospace;text-align:left;
  border:1.5px solid var(--warm);border-radius:var(--r);
  background:var(--parchment);color:var(--ink);
  box-sizing:border-box}
.ct-input-text:focus{outline:none;border-color:var(--gold)}
.ct-hint{font-size:.66rem;color:#888;font-family:monospace;direction:ltr;
  margin-top:5px;word-break:break-all;white-space:normal;line-height:1.4;text-align:left}

/* ═══════════════════════════════════════════════════════════
 *  v2.0 — Search results: snippet cards
 * ═══════════════════════════════════════════════════════════
 *
 * Replaces the prior tabular layout with a stack of cards, one
 * per (doc, snippet) pair. The data attributes (data-doc, data-chunk,
 * data-bm-doc-id) match the contract used by reader.js's
 * openReaderFromEl and search.js's refreshBookmarkIcons, so the
 * existing reader and bookmark plumbing keeps working without
 * any change to those modules.
 *
 * Visual pattern:
 *   - parchment card on cream paper
 *   - matched terms get an amber wash (gradient rising from below
 *     the baseline) — matches the .full-book-body match style for
 *     consistency between the snippet view and the reader view
 *   - on hover, the card lifts slightly via background tint and the
 *     action buttons (copy w/ ref, copy link) fade in to full opacity
 *   - clicking anywhere on the card fires openReaderFromEl
 *     (the action buttons stopPropagation so they don't double-fire)
 *
 * Layout coexists with the existing .results-table styles below;
 * they're never both rendered into #results-body at the same time
 * (renderSearchRows in v2.0 emits one or the other, never both).
 */

.results-cards {
  list-style: none;
  margin: 0;
  padding: 0 4px 32px;
  /* No max-width: the container (#results-body) already constrains
     us. Bottom padding keeps the last card's hover ring from
     clipping against the scroll container's edge. */
}

.result-card {
  position: relative;
  padding: 18px 16px 16px 18px;
  border-bottom: 1px solid rgba(163,123,43,.18);
  cursor: pointer;
  transition: background .16s ease;
  /* Pull the right edge of the active state into the gutter so the
     gold rule sits flush. RTL: "right" is the visual leading edge. */
  margin-right: 0;
}
.result-card:last-child { border-bottom: none; }
.result-card:hover {
  background: rgba(163,123,43,.05);
}
.result-card.row-selected,
.result-card.row-selected:hover {
  /* Match name kept compatible with reader.js's openReaderFromEl,
     which adds the .row-selected class to the clicked element.

     v2.57 — Stripe direction follows reading direction:
       Persian RTL: stripe on the right (inset -3px 0 0)
       English LTR: stripe on the left  (inset  3px 0 0)
     The gradient direction also flips so the warm tint fades
     toward the trailing edge in both languages. */
  background: linear-gradient(270deg, rgba(232,213,176,.45), transparent 65%);
  box-shadow: inset -3px 0 0 var(--rust);
}
html[lang="en"] .result-card.row-selected,
html[lang="en"] .result-card.row-selected:hover {
  background: linear-gradient(90deg, rgba(232,213,176,.45), transparent 65%);
  box-shadow: inset 3px 0 0 var(--rust);
}

.rc-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 6px;
  /* The cite line wraps if a collection name is long; the numeral
     stays anchored to the visual top-right (= top-end in RTL) of
     the card so it never gets pushed below. */
}
.rc-cite {
  flex: 1;
  min-width: 0;
  font-size: .88rem;
  color: #6b5a44;
  line-height: 1.45;
  /* word-break:break-word lets long Persian collection names wrap
     on word boundaries rather than overflowing horizontally. */
  word-break: break-word;
}
.rc-cite .rc-collection { color: var(--ink); font-weight: 700; }
.rc-cite .rc-book       { color: #4a3a28; font-style: italic; }
.rc-cite .rc-page       { color: #7a6a55; direction: ltr; display: inline-block; font-size: .78em; }
.rc-cite .rc-sep {
  color: var(--gold);
  margin: 0 4px;
  opacity: .55;
  user-select: none;
}
/* Tiny info / bookmark icons on the cite line. Both are inline-flex
   so they baseline-align with the surrounding text rather than
   floating to the line top. */
.rc-info-icon, .rc-bm-icon {
  display: inline-flex;
  align-items: center;
  margin-right: 4px; /* RTL: visual gap on the trailing side */
  opacity: .55;
  cursor: pointer;
  transition: opacity .15s;
  vertical-align: -1px;
}
.rc-info-icon:hover, .rc-bm-icon:hover { opacity: 1; }
.rc-info-icon.has-info { opacity: .85; color: var(--gold); }
.rc-bm-icon { color: var(--rust); }
.rc-bm-icon svg { display: block; }

.rc-num {
  flex-shrink: 0;
  font-family: 'Scheherazade New', Georgia, serif;
  font-size: 1.6rem;
  font-weight: 400;
  color: rgba(163,123,43,.32);
  line-height: 1;
  direction: ltr;
  font-variant-numeric: tabular-nums;
  user-select: none;
  /* Slight upward nudge so the numeral baseline matches the cite line
     visually rather than mathematically. */
  margin-top: -2px;
}

.rc-text {
  /* Live font control (v2.1.3): reads the same CSS variable that the
     legacy results table used (--results-font-size, set by
     applyResultsFontSize in config.js). Default 16px so the cards
     stay readable when no preference is saved yet. The per-language
     English variant below switches to --results-font-size-en. */
  font-size: var(--results-font-size, 16px);
  line-height: 1.7;
  color: var(--ink);
  margin: 4px 0 0;
  /* Clamp to four lines in the snippet view. The full passage is
     visible in the reader (right column / full-book panel) when the
     user clicks the card. The clamp prevents one verbose match from
     visually drowning the rest of the result list. */
  display: -webkit-box;
  -webkit-line-clamp: 4;
  -webkit-box-orient: vertical;
  overflow: hidden;
  /* word-wrap:break-word handles long unbreakable URLs / English
     fragments inside Persian content without horizontal overflow. */
  word-wrap: break-word;
}
.result-card.rc-lang-en .rc-text {
  /* English snippets render LTR and use the per-language variable so
     a user can dial Persian and English to different reading sizes
     independently — same separation the full-book reader uses
     (--reader-font-size vs --reader-font-size-en). */
  font-size: var(--results-font-size-en, 14px);
  text-align: left;
  direction: ltr;
  /* v2.14 — English cards show 3 paragraphs (before/match/after).
     The line-clamp from the parent rule (4 lines) doesn't fit the
     ~9 lines of text the 3-paragraph mode produces; remove it for
     English. Persian cards keep the 4-line clamp because they're
     still single-paragraph snippets. */
  -webkit-line-clamp: unset;
  display: block;
  overflow: visible;
}
/* v2.14 — paragraph separation inside the 3-paragraph English snippet.
   .rc-ctx-side = the before/after context paragraphs (lighter, italic).
   .rc-ctx-match = the matched paragraph (full ink, normal weight). */
/* v2.44 — English context spans now render INLINE so the
   before/match/after chunks read as one continuous paragraph
   instead of three stacked lines. The previous `display: block`
   gave each chunk its own line, which suited the original
   "before \n match \n after" framing but read awkwardly when
   the three chunks together are short enough to fit one wrapped
   paragraph. The match span keeps its higher-contrast ink and
   inherits the <mark> highlight, so it still stands out
   visually within the run of text. Whitespace between chunks
   comes from a literal " " character inserted by the renderer
   (search.js:fetchCardContext). */
.result-card.rc-lang-en .rc-ctx-side,
.result-card.rc-lang-en .rc-ctx-match {
  display: inline;
  margin: 0;
}
.result-card.rc-lang-en .rc-ctx-side {
  /* Subdued — lighter color, italicised. The intent is "this is
     context, the run with the highlight is the actual match". */
  color: rgba(31,26,20,.55);
  font-style: italic;
  font-size: .94em;
}
.result-card.rc-lang-en .rc-ctx-match {
  /* Normal ink — the <mark> highlight draws the eye. */
  color: var(--ink);
}
.rc-text mark {
  /* Marker-style highlight: gradient rising halfway up the line so
     the match reads as "underlined in amber" rather than a flat box.
     Matches the redesign mockup and (visually) the existing reader's
     in-book search highlight. */
  background: linear-gradient(180deg, transparent 55%, #f3d8a8 55%);
  color: inherit;
  padding: 0 2px;
  font-weight: 700;
  border-radius: 1px;
}

/* ── End v2.0 card section ─────────────────────────────────── */


/* compact 4-column results table */
.results-table{width:100%;border-collapse:collapse;font-size:var(--results-font-size,.85rem);direction:rtl;table-layout:fixed}
.results-table thead tr{background:rgba(163,123,43,.12);border-bottom:2px solid var(--warm)}
/* Sticky header: the th itself sticks (tr can't reliably sticky-position).
   Solid background on the th covers any row bleeding through as the body
   scrolls; box-shadow supplies the bottom border because a thead border
   drawn on tr disappears when the table scrolls under border-collapse. */
.results-table thead th{position:sticky;top:0;z-index:2;background:#f5e9c9;box-shadow:inset 0 -2px 0 var(--warm);cursor:grab}
.results-table thead th.dragging-col{opacity:.4;cursor:grabbing}
.results-table thead th.drop-target{background:#e6d0a0;box-shadow:inset 0 -2px 0 var(--gold),inset 0 2px 0 var(--gold)}
/* Child font-sizes below are `em` so they scale with .results-table's base.
   Ratios preserved from original rem values (base was 0.85rem). */
.results-table th{padding:6px 10px;font-family:'Scheherazade New',Arial,Helvetica,sans-serif;font-size:.88em;font-weight:700;color:var(--rust);text-align:right;white-space:nowrap;position:relative;overflow:hidden;text-overflow:ellipsis}
.results-table th.col-page{text-align:center}
.col-resizer{
  position:absolute; top:0; bottom:0; left:0;  /* in RTL this is the visual "start" edge */
  width:8px; cursor:col-resize; user-select:none;
  background:transparent; transition:background .15s;
}
/* thin always-visible line in the centre of the hit area — shows where to grab */
.col-resizer::before{
  content:""; position:absolute;
  top:15%; bottom:15%; left:50%; width:1px;
  background:var(--gold); opacity:.45;
  transform:translateX(-50%);
  transition:opacity .15s;
}
.col-resizer:hover::before,.col-resizer.dragging::before{opacity:1}
.col-resizer:hover,.col-resizer.dragging{background:rgba(163,123,43,.25)}
.results-table tbody tr{border-bottom:1px solid rgba(163,123,43,.1);cursor:pointer;transition:background .15s}
.results-table tbody tr:hover{background:rgba(163,123,43,.1)}
/* Row stays highlighted after click until another row is clicked. Stronger
   than hover so the last-clicked row is visually distinct even when the
   user's pointer is elsewhere. Ordered AFTER :hover so this wins on the
   clicked row when the cursor drifts back over it. */
.results-table tbody tr.row-selected,
.results-table tbody tr.row-selected:hover{
  background:rgba(139,58,15,.14);
  box-shadow:inset 3px 0 0 var(--rust)}
.results-table tbody tr:last-child{border-bottom:none}
.results-table td{padding:5px 10px;vertical-align:middle;line-height:1.65;overflow:hidden;text-overflow:ellipsis}
.td-text{font-size:1.04em;white-space:normal;word-wrap:break-word}
/* English snippets in results table use their own absolute size (px),
   not the em-scaled Persian size. Higher specificity wins over .td-text. */
.results-table .td-text.lang-en{font-size:var(--results-font-size-en,13px)}
.results-table thead tr.filter-row th{padding:3px 6px;background:#f5e9c9}
.results-table thead tr.filter-row{display:none}
.results-table thead tr.filter-row.visible{display:table-row}
.filter-toggle{background:none;border:none;cursor:pointer;font-size:.72rem;
  padding:0 2px;vertical-align:middle;line-height:1;color:#c0392b;opacity:1}
.filter-toggle:hover{filter:brightness(.8)}
.col-filter{width:100%;font-family:'Scheherazade New',Arial,Helvetica,sans-serif;font-size:.72rem;padding:3px 6px;
  border:1px solid var(--warm);border-radius:3px;background:var(--parchment);
  color:var(--ink);direction:rtl;box-sizing:border-box;cursor:pointer}
.col-filter:focus{outline:none;border-color:var(--gold)}
.td-info{text-align:center;width:32px;padding:0!important}
.info-icon{cursor:pointer;font-size:.95rem;opacity:.35;transition:opacity .15s,filter .15s;user-select:none}
.info-icon.has-info{opacity:1;filter:sepia(1) saturate(8) brightness(1.4) hue-rotate(5deg)}
.info-icon:hover{opacity:1}
/* BRL provenance dot — set on books whose source is "Bahá'í Reference
   Library" via the move-book modal. Rendered next to the book name
   wherever a book name appears (cards, search rows, reader title,
   filter-tree leaves, audit). See bookSourceDot() in dom.js.
   The dot's tooltip is a body-mounted .brl-tooltip element shown by
   a delegated mouseover handler in dom.js. We use body-mount rather
   than ::after because some render sites (.book-name) have
   overflow:hidden for ellipsis, which clips a child pseudo-tooltip
   in half. Body-mounting escapes every ancestor's clip. */
.brl-dot{display:inline-block;width:8px;height:8px;border-radius:50%;background:#1976d2;vertical-align:middle;margin-inline-start:6px;flex-shrink:0;cursor:help}
.brl-tooltip{position:fixed;transform:translate(-50%,-100%);background:#d4edda;color:#155724;border:1px solid #a3d4ae;font-size:.74rem;font-weight:500;padding:5px 10px;border-radius:4px;white-space:nowrap;pointer-events:none;opacity:0;transition:opacity .12s ease-out;z-index:10000;box-shadow:0 2px 6px rgba(0,0,0,.18);font-family:Arial,Helvetica,sans-serif;direction:ltr;line-height:1.4;left:0;top:0}
.brl-tooltip.brl-tooltip-visible{opacity:1}
/* v4.0.4 — Body-mounted tooltip showing a tree leaf's full book
   name when the row's text-overflow:ellipsis is in effect.
   Position is set inline (left/top/transform via JS) so the
   tooltip anchors at the leaf's start edge and pops above the
   row. Escapes the sidebar's overflow:hidden because it's
   mounted on <body>. */
.leaf-tooltip{
  position:fixed;left:0;top:0;
  /* v4.0.10 — Background matches the Anvár icon's outer star
     (muted gold #a37b2b == --gold) rather than the deeper rust
     of the inner star. Cream text for contrast. */
  background:var(--gold);color:#fdf6e3;
  border:1px solid #7a5d1f;
  font-family:'Scheherazade New','EB Garamond',Georgia,serif;
  font-size:.85rem;font-weight:500;
  padding:6px 12px;border-radius:6px;
  max-width:560px;white-space:normal;line-height:1.4;
  /* v4.0.11 — Centre the text and let direction follow the content
     (mostly Persian book names — `auto` keeps Persian right-aligned
     internally while the box itself is centred above the leaf, so
     the experience matches LTR exactly). */
  text-align:center;direction:auto;unicode-bidi:plaintext;
  pointer-events:none;opacity:0;
  transition:opacity .12s ease-out;
  z-index:10000;
  box-shadow:0 4px 12px rgba(0,0,0,.25);
}
.leaf-tooltip.leaf-tooltip-visible{opacity:1}
/* Tiny bookmark ribbon shown in the results table when a doc has bookmarks */
.result-bm-icon{display:inline-block;vertical-align:middle;margin-right:3px;cursor:default;opacity:.85;position:relative;top:3px}
.result-bm-icon svg path{fill:#C0392B;stroke:#C0392B;stroke-width:1;stroke-linejoin:round}
.td-page{font-size:.88em;font-weight:700;color:var(--gold);text-align:center;white-space:nowrap}
.td-collection{font-size:.85em;color:var(--gold);font-weight:700;white-space:nowrap}
.td-book{font-size:.85em;color:var(--rust);font-weight:700;white-space:nowrap}
mark{background:rgba(184,146,75,.85);color:var(--ink);font-weight:700;border-radius:3px;padding:1px 3px;box-shadow:0 0 0 1px rgba(139,58,15,.5);text-shadow:none}

/* Collections manager */
.col-card{background:var(--parchment);border:1px solid var(--warm);border-radius:var(--r);margin-bottom:10px;overflow:hidden}
.col-card-hdr{display:flex;align-items:center;gap:8px;padding:8px 12px;background:rgba(163,123,43,.07);border-bottom:1px solid var(--warm)}
.col-card-name{font-family:'Scheherazade New',Arial,Helvetica,sans-serif;font-size:.95rem;font-weight:700;color:var(--rust);flex:1;cursor:pointer}
.col-card-name:hover{text-decoration:underline}
.col-card-body{padding:8px 12px;font-size:.8rem;color:#666}
.col-dir{font-family:monospace;font-size:.72rem;color:#999;direction:ltr;display:block;margin-top:2px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.col-actions{display:flex;gap:6px;margin-top:8px;flex-wrap:wrap}

/* Book cards inside Books tab */
.book-card{display:flex;align-items:center;gap:10px;padding:8px 12px;background:var(--parchment);border:1px solid var(--warm);border-right:4px solid var(--gold);border-radius:var(--r);margin-bottom:6px;cursor:pointer;transition:box-shadow .15s,background .15s}
.book-card:hover{background:rgba(163,123,43,.08);box-shadow:0 2px 8px var(--shadow)}
.book-card .book-name{flex:1;min-width:0;font-family:'Scheherazade New',Arial,Helvetica,sans-serif;font-size:.92rem;font-weight:700;color:var(--rust);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.book-card .book-meta{font-size:.7rem;color:#888;white-space:nowrap}
.book-card .book-del{flex-shrink:0;background:transparent;border:1px solid transparent;color:#bbb;font-size:.85rem;padding:2px 6px;border-radius:3px;cursor:pointer;line-height:1;transition:color .15s,background .15s,border-color .15s}
.book-card .book-del:hover{color:#fff;background:#c0392b;border-color:#c0392b}
/* Collection name pill on cross-collection book search results.
   Shown in the gap between title and meta so the user can tell at
   a glance which collection a match belongs to. Limited to 140px
   wide with ellipsis so a long collection name doesn't squeeze the
   title. Only present in the search-results render path; the
   single-collection legacy view doesn't include it (the user
   already picked the collection from the dropdown). */
.book-card .book-col-tag{
  flex-shrink:0;max-width:140px;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap;font-size:.7rem;color:var(--teal);
  background:rgba(31,111,139,.12);border:1px solid rgba(31,111,139,.3);
  border-radius:10px;padding:2px 9px;font-family:'Scheherazade New',Arial,Helvetica,sans-serif}
/* v1.7.3 — Group header used by renderAllMarkedBooks() to label
   each collection's batch of marked books. Matches the visual
   weight of .field-label so it reads as a section divider, with
   a thin warm under-rule and a small italic count on the trailing
   side. .first-group trims the top margin so the list doesn't
   open with awkward leading whitespace before the very first
   header. The flex layout keeps the count on the opposite side of
   the collection name in both LTR and RTL contexts. */
.books-group-header{
  display:flex;align-items:baseline;gap:8px;
  margin:14px 0 6px 0;padding:0 0 4px 0;
  border-bottom:1px solid var(--warm);
  font-size:.92rem;font-weight:700;color:var(--rust);
  letter-spacing:.02em;
  font-family:'Scheherazade New',Arial,Helvetica,sans-serif}
.books-group-header.first-group{margin-top:2px}
.books-group-header .books-group-name{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* v1.7.5 — Small pill that labels each collection group with its
   declared language (Persian/Arabic or English). Reuses the teal
   accent the per-card .book-col-tag used pre-v1.7.3, keeping the
   visual cue for "scope/origin" consistent. Sits between the
   collection name and the trailing count. */
.books-group-header .books-group-lang{
  flex-shrink:0;font-size:.7rem;font-weight:400;
  color:var(--teal);background:rgba(31,111,139,.12);
  border:1px solid rgba(31,111,139,.3);border-radius:10px;
  padding:1px 9px;font-family:'Scheherazade New',Arial,Helvetica,sans-serif;
  font-style:normal;letter-spacing:0}
.books-group-header .books-group-count{
  flex-shrink:0;font-size:.78rem;font-weight:400;color:var(--gold);font-style:italic}
/* Match highlight inside book titles — same gold-on-parchment look
   as the search-results highlight, rendered via <mark>. Reset some
   of the browser's default <mark> styling. */
.book-card mark.anvar-match{
  background:rgba(184,146,75,.4);color:inherit;
  border-radius:2px;padding:0 1px}
/* ── Reading marks (whole-book bookmarks, added v14.2) ────────
   Star button on each book card lets the user set a reading status:
   to-read / reading / finished. Click cycles through states; long
   press / context menu to clear. The button is on the LEFT of the
   row in RTL flow because we want it to be the leading affordance
   the user reaches for, like a checkbox. */
.book-card .book-mark-btn{
  flex-shrink:0;background:transparent;border:none;cursor:pointer;
  font-size:1.1rem;padding:2px 4px;line-height:1;
  filter:grayscale(.7);opacity:.5;
  transition:filter .15s,opacity .15s,transform .1s}
.book-card:hover .book-mark-btn{opacity:.85}
.book-card .book-mark-btn:hover{filter:grayscale(0);opacity:1;transform:scale(1.15)}
.book-card .book-mark-btn.is-marked{filter:grayscale(0);opacity:1}
/* Toolbar star in the Full Book header. Same behaviour as the
   Books-tab star (toggles STATE.bookMarks via toggleBookStar) but
   styled to read against the cream-colored toolbar background:
   muted brown when unmarked, full gold when marked. (Earlier
   versions assumed a dark toolbar and used cream-tinted strokes
   that were invisible against the actual cream toolbar — fixed
   in v15.27.) */
.fb-mark-btn{
  flex-shrink:0;background:transparent;border:none;cursor:pointer;
  padding:2px 4px;line-height:0;
  display:inline-flex;align-items:center;justify-content:center;
  color:rgba(139,58,15,.55);   /* muted rust — visible on cream */
  transition:color .15s,transform .1s}
.fb-mark-btn svg{width:18px;height:18px;display:block}
.fb-mark-btn:hover{color:rgba(139,58,15,.95);transform:scale(1.15)}
.fb-mark-btn.is-marked{color:var(--gold)}
.fb-mark-btn.is-marked:hover{color:var(--gold);filter:brightness(1.15)}
/* Status dropdown that appears next to the title when a book is
   starred. Compact, color-coded by current status so the user can
   scan the list at a glance. The native <select> is styled to look
   like a pill, with a small caret hint that it's interactive. */
.book-card .book-status-select{
  flex-shrink:0;font-size:.7rem;padding:2px 22px 2px 9px;
  border-radius:10px;font-family:'Scheherazade New',Arial,Helvetica,sans-serif;font-weight:700;
  cursor:pointer;
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 5'><path d='M0 0l4 5 4-5z' fill='%23888'/></svg>");
  background-repeat:no-repeat;background-position:left 6px center;background-size:8px 5px;
  -webkit-appearance:none;-moz-appearance:none;appearance:none;
  outline:none;transition:filter .15s}
.book-card .book-status-select:hover{filter:brightness(1.05)}
.book-card .book-status-select.status-to-read{
  color:#7a3b2e;background-color:rgba(192,57,43,.12);
  border:1px solid rgba(192,57,43,.3)}
.book-card .book-status-select.status-reading{
  color:#1f6f8b;background-color:rgba(31,111,139,.12);
  border:1px solid rgba(31,111,139,.3)}
.book-card .book-status-select.status-finished{
  color:#5a6e3a;background-color:rgba(106,143,72,.15);
  border:1px solid rgba(106,143,72,.4)}
/* Active state for the "only bookmarked" filter button. Stays in
   the tabs row so the user can toggle it any time. */
#books-filter-marked-btn.active{
  background:linear-gradient(135deg,var(--gold),var(--rust)) !important;
  color:#fdf6e3 !important;border-color:var(--gold) !important}

/* Compilations */
.comp-card{display:flex;align-items:center;gap:10px;padding:8px 12px;background:var(--parchment);border:1px solid var(--warm);border-right:4px solid var(--sage);border-radius:var(--r);margin-bottom:6px;transition:box-shadow .15s,background .15s}
.comp-card:hover{background:rgba(163,123,43,.06);box-shadow:0 2px 8px var(--shadow)}
.comp-card .comp-name{flex:1;min-width:0;font-family:'Scheherazade New',Arial,Helvetica,sans-serif;font-size:.92rem;font-weight:700;color:var(--rust);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.comp-card .comp-path{font-size:.68rem;color:#888;font-family:monospace;direction:ltr;text-align:left;max-width:60%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;unicode-bidi:embed}
.comp-card .comp-del{flex-shrink:0;background:transparent;border:1px solid transparent;color:#bbb;font-size:.85rem;padding:2px 6px;border-radius:3px;cursor:pointer;line-height:1;transition:color .15s,background .15s,border-color .15s}
.comp-card .comp-del:hover{color:#fff;background:#c0392b;border-color:#c0392b}
/* The ctx-menu "back" item in the compilation picker */
.ctx-item.ctx-back{color:#888;font-size:.78rem;border-bottom:1px solid var(--warm);font-weight:700}
.ctx-item.ctx-back:hover{background:rgba(163,123,43,.1);color:var(--rust)}
.ctx-item.ctx-empty{color:#aaa;font-style:italic;cursor:default}
.ctx-item.ctx-empty:hover{background:transparent;color:#aaa}

/* Add collection form */
.add-col-form{background:rgba(163,123,43,.06);border:1px dashed var(--gold);border-radius:var(--r);padding:12px;margin-bottom:14px}
.add-col-form input{width:100%;padding:7px 10px;font-size:.88rem;margin-bottom:8px;display:block}

/* Index log */
#index-log{display:none;background:#1f1a14;color:#b8924b;font-family:monospace;font-size:.76rem;padding:10px;border-radius:var(--r);max-height:200px;overflow-y:auto;margin-top:10px;line-height:1.8}
.log-ok{color:#7ec87e} .log-skip{color:#888} .log-head{color:var(--gold-lt);font-weight:bold} .log-nc{color:#aaa}

/* Danger zone */
.danger-zone{background:rgba(192,57,43,.06);border:1px solid rgba(192,57,43,.3);border-radius:var(--r);padding:12px;margin-top:14px}
.danger-title{font-size:.8rem;font-weight:700;color:#c0392b;margin-bottom:8px}

/* Empty / spinner */
.empty{text-align:center;padding:32px 16px;color:#aaa}
.empty .ico{font-size:2.2rem;margin-bottom:8px;opacity:.4}
/* When the .ico slot holds the spinning Anvár SVG (search loading,
   etc.) override the emoji-tuned size/opacity so the star renders
   at a readable size with its own baked-in opacities. */
.empty .ico .ipm-anvar-spin{width:54px;height:54px;display:inline-block}
.empty .ico:has(.ipm-anvar-spin){opacity:1;font-size:0;line-height:0}
.spinner{display:inline-block;width:13px;height:13px;border:2px solid rgba(253,246,227,.3);border-top-color:#fdf6e3;border-radius:50%;animation:spin .7s linear infinite;vertical-align:middle}
@keyframes spin{to{transform:rotate(360deg)}}

/* v2.23 — Resize handles disabled to match the mockup's fixed
   panel widths. The drag-to-resize was a holdover from the
   original 2-pane layout where users wanted to dial sidebar/reader
   ratios on demand. The mockup uses fixed proportions
   (220px sidebar, 1fr cards, 1.25fr reader) so resizing isn't
   needed; collapsing the gripper to 0 width also recovers screen
   real-estate for actual content. The drag listeners stay wired
   up — they just have no element to listen on, so they're inert.
   The width:0 + display:none make sure even keyboard focus or
   accidental clicks can't trigger a resize. */
.resize-handle{
  width:0;background:transparent;cursor:default;flex-shrink:0;
  display:none;pointer-events:none;
  user-select:none}
.resize-handle:hover,
.resize-handle.dragging{background:transparent}
.resize-handle::before{content:none}
.collapse-btn{
  position:absolute;top:50%;transform:translateY(-50%);
  width:20px;height:44px;border-radius:0 8px 8px 0;
  background:var(--rust);color:#fdf6e3;border:none;cursor:pointer;
  font-size:.7rem;display:flex;align-items:center;justify-content:center;
  right:-20px;box-shadow:2px 0 6px var(--shadow);z-index:10;
  transition:background .2s;line-height:1}
.collapse-btn:hover{background:var(--gold)}
/* When the sidebar is collapsed to width:0, the resize handle slides to
   the right edge of the viewport. The button's default `right:-20px`
   would then push it 20px PAST the viewport edge — completely off-screen
   and unclickable. Flip it to the left side of the handle so it stays
   visible in the full-book area. Mirror the rounded corners and shadow
   so the visual reads correctly. */
.collapse-btn.collapsed{
  right:auto;left:-20px;
  border-radius:8px 0 0 8px;
  box-shadow:-2px 0 6px var(--shadow)}

/* Reader panel was retired in v3.4; dead CSS removed in v4.3.
   .reader-chunk / .reader-paragraph / .page-divider / .page-block are still
   used by the full-book renderer below — don't rename them casually. */

/* v2.21 — Hide all scrollbars globally to match the mockup's
   minimalist aesthetic. The mockup uses thin auto-hide scrollbars
   on macOS and effectively-invisible bars on other platforms. We
   go further and hide the bars entirely; scrolling still works
   via wheel, trackpad, keyboard, and pointer-drag. Individual
   panels can opt back in by setting scrollbar-width: thin and
   ::-webkit-scrollbar { width: 6px } if needed.
   The previous gold-tinted thumb everywhere felt heavy against
   the new lighter palette. */
*{scrollbar-width:none;scrollbar-color:transparent transparent}
::-webkit-scrollbar{width:0;height:0;background:transparent}
::-webkit-scrollbar-track{background:transparent}
::-webkit-scrollbar-thumb{background:transparent}
::-webkit-scrollbar-thumb:hover{background:transparent}
::-webkit-scrollbar-corner{background:transparent}
/* Chunk/paragraph classes are shared between the (now-removed) reader and
   the full-book panel below. Kept with original names for consistency. */
.reader-paragraph{margin:0 0 .9em 0}
.reader-paragraph:last-child{margin-bottom:0}
.reader-chunk{border-radius:3px}
.reader-chunk:hover{background:rgba(163,123,43,.07);cursor:default}
.reader-chunk.highlight-target{background:rgba(184,146,75,.45);padding:1px 2px;animation:flashIn 2s ease}
/* v3.6.x — Centered gold separator chunk inserted between merged
   xhtml fragments. Without display:block the short "✺ ✺ ✺ ✺ ✺"
   line in an RTL Persian book hugs the right edge (text-align:start
   is right in RTL); display:block + text-align:center centers it
   regardless of direction. Color matches var(--gold) #a37b2b — same
   value as the SVG anvár icon's polygon fill. .reader-chunk:hover
   above adds a faint background on hover; we suppress that on the
   separator since it's decorative, not selectable content. */
.reader-chunk--anvar-sep{
  display:block;text-align:center;
  color:var(--gold);
  letter-spacing:.5em;font-size:1.05rem;
  margin:1em 0;padding:0;cursor:default}
.reader-chunk--anvar-sep:hover{background:transparent}
/* Legacy: the .para-end class is no longer needed for spacing (paragraph
   boundaries come from the <p> wrapper). Kept as a no-op for any callers. */
.reader-chunk.para-end{}
@keyframes flashIn{0%{background:rgba(184,146,75,.8)}100%{background:rgba(184,146,75,.45)}}
/* min-width:0 on inner block containers ensures none of them reintroduce
   a content-based min-content size up the layout chain — which would
   defeat the .full-book-body min-width:0 / overflow-wrap:anywhere fix
   above. Cheap insurance. */
.page-block{margin-bottom:8px;min-width:0}
.page-divider{display:flex;align-items:center;gap:10px;margin:0 0 14px;color:var(--gold);font-size:.76rem;font-weight:700;letter-spacing:.08em;position:sticky;top:0;background:var(--parchment);padding:4px 0;z-index:2;min-width:0}
.page-divider::before,.page-divider::after{content:"";flex:1;border-top:1px solid var(--warm)}
/* Right-click context menu for reader text selection */
.ctx-menu{position:fixed;z-index:1000;background:var(--cream);border:1.5px solid var(--gold);border-radius:var(--r);box-shadow:0 6px 20px var(--shadow);padding:4px 0;min-width:200px;display:none;font-family:'Scheherazade New',Arial,Helvetica,sans-serif}
.ctx-menu.open{display:block}
.ctx-item{padding:8px 14px;cursor:pointer;font-size:.88rem;color:var(--ink);white-space:nowrap;transition:background .1s}
.ctx-item:hover{background:rgba(163,123,43,.14);color:var(--rust)}
.ctx-item .ctx-sub{display:block;font-size:.7rem;color:#888;margin-top:2px;max-width:280px;overflow:hidden;text-overflow:ellipsis}
/* Per-UI context-menu pruning. Riyad-ul-Lughat + Almaany + DeepL
   are Persian-side tools; Oxford + DeepL are English-side tools.
   Each side hides what doesn't apply. */
html[lang="en"] #ctx-translate-item,
html[lang="en"] #ctx-almaany-item,
html[lang="en"] #ctx-dehkhoda-item,
html[lang="en"] #ctx-vajehyab-item,
html[lang="en"] #ctx-deepl-item{display:none}
html[lang="fa"] #ctx-oed-item,
html[lang="fa"] #ctx-deepl-item{display:none}
/* In-book search boundary banner — sits at the top of the reading
   pane (above .full-book-body) when next/prev navigation hits the
   first or last match. Persists until the user clicks outside it. */
.fb-banner{
  background:var(--gold);
  color:#f6f1e8;
  text-align:center;
  font-weight:600;
  font-size:.82rem;
  padding:8px 14px;
  border-bottom:1px solid var(--warm);
  box-shadow:0 2px 6px rgba(0,0,0,.10);
  user-select:none;
  cursor:default}

/* Full-book side panel — leftmost in RTL flex order. Shows the entire
   document for free-scrolling alongside the search-result reader.
   Hidden by default; toggled via the 📖 button in the reader toolbar.
   When open, takes a configurable width and the reader (flex:1) shrinks
   to share space. */
.full-book{
  /* v2.40 — Width is FIXED. The panel always opens at 60% of the
     viewport (with .fullscreen class added below) and never shifts
     based on content, sibling, or window resize beyond proportional
     width. All width-related properties are locked together to
     prevent any cascade or content-based recalculation:

       width:        60%       — the explicit width
       max-width:    60%       — even oversized content can't expand
       min-width:    0         — but content also can't keep us BIG
       flex:         0 0 60%   — no grow, no shrink, basis 60%
       box-sizing:   border-box — border + radius don't add to width

     Earlier versions had `width:38%;min-width:260px;max-width:60%`
     which interacted poorly with .fullscreen's overrides. Now the
     base rule sets the final state directly; .fullscreen is now
     a no-op kept for backward compat with any code that adds the
     class. */
  width:60%;
  max-width:60%;
  min-width:0;
  flex:0 0 60%;
  box-sizing:border-box;
  display:none;flex-direction:column;
  background:#fffdf7;
  border:1px solid var(--warm);
  border-radius:var(--r);
  box-shadow:var(--shadow);
  /* Give the shadow room to render — without margin, the box-shadow
     would be clipped by adjacent panes. Top/bottom margins also
     let the panel look "lifted" rather than glued to the chrome. */
  margin:14px 14px 14px 0;
  overflow:hidden}
.full-book.open{display:flex}
/* v2.40 — .fullscreen is kept as a backward-compat no-op. All of
   its formerly distinguishing properties are now baked into the
   base rule above so the panel has the same width whether or not
   the class is present. */
.full-book.fullscreen{
  /* intentionally empty — see .full-book base rule */
}

/* v2.43 — English mode shifts the panel proportions:
     Persian: sidebar 40% / full-book 60% (default)
     English: sidebar 45% / full-book 55%
   English text wraps at narrower line-lengths (no joined-script
   advantage) and benefits from more horizontal room for snippet
   cards. The full-book panel still has plenty of room — 55% of a
   typical 1440px viewport is ~790px of book content area, which
   keeps Garamond reading at a comfortable measure. */
html[lang="en"] .full-book{
  width:55%;
  max-width:55%;
  flex:0 0 55%;
}
.full-book-toolbar{position:relative;
  display:flex;align-items:center;gap:10px;padding:9px 16px;
  /* v2.25 — Lighter bottom rule (1px var(--rule-soft)) and a soft
     gradient backdrop, matching the mockup's reader-head. The
     previous 2px solid --warm divider felt heavy against the
     elevated card.
     v1.5.3 — Height switched from a hard 52px to var(--header-rule-y)
     so the bottom rule aligns with the cards-meta and rt-head
     rules across the page. */
  background:var(--parchment);
  border-bottom:1px solid var(--rule-soft);
  flex-shrink:0;height:var(--header-rule-y);box-sizing:border-box}
.full-book-title{
  flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap;font-family:'Scheherazade New',Arial,Helvetica,sans-serif;
  font-size:.95rem;font-weight:700;color:var(--rust)}
.full-book-close{
  flex-shrink:0;background:transparent;border:1.5px solid var(--warm);
  color:#888;width:28px;height:28px;border-radius:var(--r);
  font-size:.95rem;line-height:1;cursor:pointer;display:flex;
  align-items:center;justify-content:center;padding:0;
  transition:background .15s,color .15s,border-color .15s}
.full-book-close:hover{background:rgba(192,57,43,.1);color:#c0392b;border-color:#c0392b}

/* Bookmark icons in the full-book toolbar — same shape as the close
   button but with their own hover colours. The list button is hidden
   by JS until a book is loaded. */
.fb-icon-btn{
  flex-shrink:0;background:transparent;border:1.5px solid var(--warm);
  color:var(--rust);width:30px;height:30px;border-radius:var(--r);
  font-size:.95rem;line-height:1;cursor:pointer;display:flex;
  align-items:center;justify-content:center;padding:0;
  transition:background .15s,border-color .15s,color .15s}
.fb-icon-btn:hover{background:rgba(163,123,43,.12);border-color:var(--gold)}
.fb-icon-btn.active{background:var(--gold);border-color:var(--gold);color:#fdf6e3}

/* Bookmark ribbon icon — inline SVG inside #fb-bookmark-btn. Default
   (no .has-bookmarks) is outline-only (empty book). With .has-bookmarks,
   becomes a solid red ribbon (at least one bookmark saved). The SVG's
   path carries no intrinsic fill/stroke; these rules drive the look so
   a single DOM mutation (classList.toggle) flips the state. */
#fb-bookmark-btn .fb-bookmark-svg{display:block}
#fb-bookmark-btn .fb-bookmark-svg path{
  fill:none;stroke:#C0392B;stroke-width:1.5;
  stroke-linejoin:round;transition:fill .15s}
#fb-bookmark-btn.has-bookmarks .fb-bookmark-svg path{
  fill:#C0392B;stroke:#C0392B;stroke-width:1}

/* Bookmark dropdown — anchored absolutely under the 🔖 button. JS sets
   left/top in pixels on open. Capped at ~360px wide and ~50vh tall, with
   internal scrolling if the user has many bookmarks. */
.bookmark-dropdown{
  position:absolute;z-index:1001;background:var(--cream);
  border:1.5px solid var(--gold);border-radius:var(--r);
  box-shadow:0 6px 20px var(--shadow);
  min-width:240px;max-width:360px;max-height:50vh;
  display:flex;flex-direction:column;overflow:hidden}
.bookmark-dropdown-header{
  padding:8px 12px;font-family:'Scheherazade New',Arial,Helvetica,sans-serif;font-size:.85rem;
  font-weight:700;color:var(--rust);background:rgba(163,123,43,.12);
  border-bottom:1px solid var(--warm);flex-shrink:0;text-align:right}
.bookmark-dropdown-body{
  flex:1;overflow-y:auto;direction:ltr  /* scrollbar on right inside the popover too */}
.bookmark-dropdown-body > *{direction:rtl}
.bookmark-row{
  display:flex;align-items:flex-start;gap:8px;padding:8px 12px;
  cursor:pointer;border-bottom:1px solid rgba(163,123,43,.15);
  transition:background .15s}
.bookmark-row:last-child{border-bottom:none}
.bookmark-row:hover{background:rgba(163,123,43,.08)}
.bookmark-row .bm-text{
  flex:1;min-width:0;font-family:'Scheherazade New',Arial,Helvetica,sans-serif;
  font-size:.88rem;color:var(--ink);line-height:1.5}
.bookmark-row .bm-page{font-weight:700;color:var(--rust);margin-left:6px}
.bookmark-row .bm-desc{color:#555}
.bookmark-row .bm-no-desc{color:#aaa;font-style:italic}
.bookmark-row .bm-delete{
  flex-shrink:0;background:transparent;border:none;color:#aaa;
  cursor:pointer;font-size:.95rem;line-height:1;padding:2px 6px;
  border-radius:var(--r);transition:background .15s,color .15s}
.bookmark-row .bm-delete:hover{background:rgba(192,57,43,.1);color:#c0392b}
/* Add-bookmark row — always first in the list, visually distinct so users
   can tell it's an action row, not a saved bookmark. Warm gold accent +
   accent left border to mark it as a CTA within the dropdown. */
.bookmark-row.bm-add{
  background:rgba(163,123,43,.06);
  border-bottom:1px solid rgba(163,123,43,.25);
  box-shadow:inset 3px 0 0 var(--gold);
  color:var(--rust);font-weight:700}
.bookmark-row.bm-add:hover{background:rgba(163,123,43,.14)}
.bookmark-row.bm-add{justify-content:center;text-align:center}
.bookmark-row.bm-add .bm-text{display:inline-flex;align-items:center;justify-content:center}
.bookmark-row.bm-add .bm-add-icon{
  font-size:1.4rem;line-height:1;color:var(--gold);font-weight:700;margin:0}
.full-book-body{
  flex:1;min-height:0;
  /* v2.28 — Inner border on the body removed. The toolbar, the
     in-book search row, and the body now ALL sit inside the
     SINGLE outer panel border (.full-book), forming one unified
     card. Previous versions framed the body separately, which
     pushed the toolbar visually outside the frame; user wanted
     them all in one bordered area. */
  /* min-width:0 — the body is itself a flex item (in .full-book's
     column flex layout) and a flex container with overflow:hidden
     ancestor. Without explicit min-width:0 a long unbreakable token
     can still report a non-zero min-content size up the flex chain,
     blocking the resize handle from being dragged past that point. */
  min-width:0;
  overflow-y:scroll;padding:6px 36px 28px;
  font-family:'Scheherazade New',Arial,Helvetica,sans-serif;
  font-size:var(--reader-font-size,1.15rem);line-height:2.1;
  color:var(--ink);text-align:justify;
  /* `overflow-wrap: anywhere` is critical (NOT break-word). Both
     visually break long unbreakable tokens at the container edge —
     same wrapping result on screen — but they differ in INTRINSIC
     MIN-CONTENT SIZE, which is what the flex algorithm sees:
       break-word: min-content = width of longest single word/token
       anywhere:   min-content = width of one character
     With break-word, dragging the resize handle past the longest
     token's width would be silently blocked by flexbox refusing to
     shrink the panel below its content's min-content size, even
     though the panel has min-width:0 set — because the constraint
     was reapplied at every layer of the flex chain. `anywhere`
     makes the panel genuinely shrinkable to any width the user
     drags it to. overflow-x:hidden keeps any residual horizontal
     scrollbar from appearing. word-wrap is the legacy alias. */
  overflow-x:hidden;
  overflow-wrap:anywhere;
  word-wrap:break-word;
  /* No scroll-behavior:smooth here on purpose. CSS scroll-behavior:smooth
     forces EVERY scroll into the element to animate, including
     scrollIntoView() calls that explicitly request behavior:'auto'.
     Bookmark jumps need to be instantaneous (a "snap to passage"
     experience, not a multi-second animated scroll through the whole
     book). Per-call animation is still possible — the in-book search
     nav passes behavior:'smooth' to scrollIntoView() when stepping
     between nearby matches. */
  /* Scrollbar placement follows the container's writing direction:
     direction:rtl puts it on the LEFT, direction:ltr puts it on the
     RIGHT. We want it on the right, so the SCROLL container is ltr
     and we restore rtl on the immediate children so the actual text
     content renders right-to-left. */
  direction:ltr;
  /* overflow-y:scroll (not auto) forces the scrollbar gutter to ALWAYS
     be reserved and the thumb to ALWAYS render — even when content
     fits — so the user has a draggable bar regardless of book size or
     OS-level overlay-scrollbar behaviour (macOS hides auto bars while
     idle). min-height:0 defeats the default flex min-height:auto, which
     would otherwise let the body grow to fit its content instead of
     internally scrolling. The global scrollbar theme (--warm thumb on
     --parchment track) has almost no contrast against this body's
     parchment background, so we override locally with a high-contrast
     gold thumb. */
  scrollbar-width:auto;
  scrollbar-color:var(--gold) rgba(163,123,43,.1)}
/* Restore RTL text flow for the actual content sitting inside the
   ltr scroll container above. */
.full-book-body > *{direction:rtl}
/* Language-specific overrides. When the indexer classifies a doc as
   English ('en'), flip content direction to LTR and left-align — so
   English paragraphs read naturally instead of being jammed into a
   Persian right-to-left frame. 'fa' and 'mixed' stay in the RTL
   default; 'mixed' is conservative since Bahá'í texts routinely
   intersperse English transliteration with Arabic/Persian.
   hyphens:auto activates the browser's hyphenation engine for English
   bodies, which gives nicer line breaks at the cost of an occasional
   "-" at the line end. The body needs lang="en" attribute (set by JS
   in loadFullBook) for hyphens:auto to actually engage. */
.full-book-body.lang-en{
  text-align:left;
  font-size:var(--reader-font-size-en,1rem);
  hyphens:auto;
  -webkit-hyphens:auto}
.full-book-body.lang-en > *{direction:ltr}
/* For English docs, force every chunk onto its own line. The book is
   rendered as a stream of inline <span class="reader-chunk"> elements
   joined with spaces — fine for Persian RTL (which has natural line-
   end wrapping behavior visible to users) but for English LTR it
   produced one continuous run that visually didn't wrap at the panel
   width on some browsers/setups. Setting display:block on each chunk
   guarantees a hard line break between chunks, regardless of what
   white-space/overflow-wrap negotiates. Since chunks are 15 words
   max from the indexer, this gives lines of up to 15 words. Persian
   docs are unaffected — this rule is gated by .lang-en. */
.full-book-body.lang-en .reader-chunk{
  display:block;
  margin:0 0 .15em 0}
/* The page-block wraps a run of chunks for one source page. For
   English we don't need the chunks to flow inline within it — they
   each take their own line via the rule above. Keep block-level
   default so nothing else changes. */
.full-book-body::-webkit-scrollbar{width:14px;background:transparent}
.full-book-body::-webkit-scrollbar-track{background:rgba(163,123,43,.1)}
.full-book-body::-webkit-scrollbar-thumb{
  background:var(--gold);border:3px solid var(--parchment);border-radius:7px}
.full-book-body::-webkit-scrollbar-thumb:hover{background:var(--rust)}
.full-book-empty{
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  height:100%;color:#bbb;text-align:center;gap:10px;padding:20px}
.full-book-empty .ico{font-size:3rem;opacity:.3}
/* v3.6.16 — Loading state for /document/<id>/full. Spinning anvár
   star + caption, replacing the legacy ⏳ glyph. Inherits the
   .ipm-anvar-spin rotation keyframes from the indexing modal. */
.full-book-loading{
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:14px;padding:60px 20px;color:#888;text-align:center}
.full-book-loading .ipm-anvar-spin{width:54px;height:54px}
.full-book-loading-text{
  font-family:'Scheherazade New',Arial,Helvetica,sans-serif;
  font-size:.95rem;color:var(--ink);opacity:.75}
/* Splash-style empty state: same Islamic geometric frame + 9-pointed
   Bahá'í star + title used on the boot splash, but reframed to fit
   inside the full-book panel. The frame SVG is responsive (preserves
   aspect ratio); the star sits centered with the title above and a
   small subtitle below — same composition as the splash, smaller
   scale. Direction stays RTL so the Persian text reads naturally. */
.fb-empty-splash{
  position:relative;width:100%;height:100%;
  display:flex;align-items:center;justify-content:center;
  direction:rtl}
.fb-empty-splash .splash-frame{
  position:absolute;inset:0;width:100%;height:100%;
  pointer-events:none;opacity:.65}
.fb-empty-splash .splash-inner{
  position:relative;display:flex;flex-direction:column;
  align-items:center;justify-content:center;gap:14px;
  padding:32px;text-align:center}
.fb-empty-splash .splash-title{
  font-family:'Scheherazade New',Arial,Helvetica,sans-serif;font-weight:700;
  font-size:3.2rem;line-height:1;color:#7a3b2e;
  text-shadow:0 2px 12px rgba(139,58,15,.18),0 1px 0 rgba(255,255,255,.5);
  letter-spacing:.02em;margin:0}
.fb-empty-splash .splash-subtitle{
  font-family:'Scheherazade New',Arial,Helvetica,sans-serif;font-size:.84rem;color:#5a3010;
  opacity:.7;letter-spacing:.03em;line-height:1.7;
  max-width:260px;margin:0}
.fb-empty-splash .splash-star{
  width:96px;height:96px;margin-top:6px;
  /* v4.2.3+ — One-shot spin when the splash renders (on page load,
     after closeFullBook, or any re-inject of fullBookEmptyHTML).
     2s, ease-out, ends at the rest position (0deg = 360deg). */
  transform-origin:50% 50%;
  animation:anvar-splash-spin 0.7s ease-in-out 1 both}
@keyframes anvar-splash-spin{
  0%  {transform:rotate(0deg)}
  50% {transform:rotate(40deg)}
  100%{transform:rotate(0deg)}
}
.fb-empty-splash .splash-hint{
  margin-top:10px;font-size:.78rem;color:#888;font-style:italic}
.fb-title-btn{cursor:pointer;border-bottom:1px dashed rgba(253,246,227,.4);transition:border-color .15s}
.fb-title-btn:hover{border-color:rgba(253,246,227,.9)}
.fb-meta-popup{position:absolute;top:100%;right:8px;z-index:200;background:var(--cream);
  border:1.5px solid var(--warm);border-radius:var(--r);box-shadow:0 6px 20px var(--shadow);
  padding:12px 16px;font-size:.78rem;line-height:1.8;
  min-width:min(440px,calc(100vw - 32px));max-width:min(90vw,580px);
  max-height:calc(100vh - 24px);
  overflow:auto;resize:both;display:none;direction:rtl}
/* EN UI: flip the meta popup to LTR so labels read left-to-right
   and the layout (label colon + value, two-column source row,
   save button alignment) mirrors naturally. The inner inputs that
   carry an explicit dir= attribute (author/toc with their RTL/LTR
   toggle, source-url with hard dir="ltr") keep their own direction. */
html[lang="en"] .fb-meta-popup{direction:ltr}
html[lang="en"] .fb-meta-input{direction:ltr}
/* Two-column row inside the meta popup — used for the Source +
   Source-URL pair so they sit side-by-side. Grid (rather than
   flex+wrap) so both columns always sit on the same row regardless
   of any language-conditional width math elsewhere — earlier the
   flex variant collapsed to a single column in the EN UI because
   the layout's html[lang="en"] .full-book width:55% rule narrowed
   the parent's effective box just enough to trip the wrap. min-
   width:0 on the cells so the inputs (which are width:100%) don't
   force the columns wider than 1fr each. */
.fb-meta-2col{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:6px}
.fb-meta-2col > .fb-meta-col{min-width:0}
.fb-meta-popup.open{display:block}
.fb-meta-popup .fm-row{display:flex;gap:8px;align-items:baseline}
.fb-meta-popup .fm-label{color:var(--rust);font-weight:700;white-space:nowrap}
.fb-meta-popup .fm-val{color:var(--ink)}
.fb-meta-input{width:100%;font-family:'Scheherazade New',Arial,Helvetica,sans-serif;font-size:.78rem;color:var(--ink);
  background:var(--parchment);border:1.5px solid var(--warm);border-radius:var(--r);
  padding:4px 7px;margin-top:2px;resize:vertical;direction:rtl}
.fb-meta-input:focus{outline:none;border-color:var(--gold)}
/* Honour the dir="ltr" attribute on .fb-meta-input — needed for the
   Source-URL field. Without this, the class rule's default
   direction:rtl wins over the HTML dir attribute (author CSS beats
   the UA stylesheet's [dir] rule), and URLs render mirrored. */
.fb-meta-input[dir="ltr"]{direction:ltr;text-align:left}
.fb-meta-save{margin-top:8px;font-size:.72rem;color:var(--sage);min-height:1em}
/* Source-URL row inside the meta popup — input + 🔗 link sit on
   one line. The link's `visibility:hidden` (set inline when the
   URL field is empty) leaves the layout space reserved so the
   input's width doesn't jiggle as the operator types. */
.fb-meta-url-row{display:flex;align-items:center;gap:6px;margin-top:2px}
.fb-meta-url-input{flex:1;margin-top:0}
.fb-meta-url-link{font-size:.95rem;text-decoration:none;color:var(--gold);flex-shrink:0;line-height:1;padding:2px 4px;border-radius:3px;transition:background .12s}
.fb-meta-url-link:hover{background:rgba(163,123,43,.15)}
.fm-dir-btn{background:none;border:1px solid var(--warm);border-radius:3px;font-size:.65rem;
  padding:1px 5px;cursor:pointer;color:#888;font-family:monospace;line-height:1.4;transition:background .1s}
.fm-dir-btn.active{background:var(--rust);color:#fff;border-color:var(--rust)}
.fm-dir-btn:hover:not(.active){background:rgba(163,123,43,.1)}

/* In-book search row — sits between the title toolbar and the scrollable
   body. Searches use the same /search endpoint as the main search but
   scoped to the currently displayed doc via ?docs=<id>, so all the same
   syntax (proximity, *…*, "…", «…», parens) works identically. */
.full-book-search{
  display:flex;align-items:center;gap:6px;padding:6px 12px;
  background:var(--parchment);border-bottom:1px solid var(--warm);
  flex-shrink:0;flex-wrap:nowrap}
.full-book-search input[type=text]{
  flex:1;min-width:0;padding:5px 10px;font-size:.85rem;
  font-family:'Scheherazade New',Arial,Helvetica,sans-serif;direction:rtl;
  border:1.5px solid var(--warm);border-radius:var(--r);
  background:#fffdf7;color:var(--ink)}
/* English UI: LTR + left-aligned text and placeholder. */
html[lang="en"] .full-book-search input[type=text]{direction:ltr;text-align:left}
.full-book-search input[type=text]:focus{outline:none;border-color:var(--gold)}
/* Disabled state — when no book is open, the in-book search is
   inactive (parallels the toolbar title/info-icon that hide while
   the panel shows its splash). Placeholder is hidden too so the
   field reads as truly inert until a book activates it. */
.full-book-search input[type=text]:disabled{
  background:transparent;color:#aaa;cursor:not-allowed}
.full-book-search input[type=text]:disabled::placeholder{color:transparent}
.full-book-search .fb-btn{
  flex-shrink:0;background:transparent;border:1.5px solid var(--warm);
  color:var(--rust);min-width:30px;height:30px;border-radius:var(--r);
  font-size:.85rem;line-height:1;cursor:pointer;display:flex;
  align-items:center;justify-content:center;padding:0 6px;
  transition:background .15s,border-color .15s,color .15s}
.full-book-search .fb-btn:hover:not(:disabled){background:rgba(163,123,43,.12);border-color:var(--gold)}
.full-book-search .fb-btn:disabled{opacity:.3;cursor:not-allowed}
.full-book-search .fb-match-count{
  flex-shrink:0;min-width:46px;text-align:center;font-size:.78rem;
  color:#888;font-family:'Scheherazade New',Arial,Helvetica,sans-serif;direction:ltr}
.full-book-search .fb-match-count.has-matches{color:var(--rust);font-weight:700}
.full-book-search .fb-match-count.no-matches{color:#c0392b}

/* Current-match highlight — a stronger version of the chunk hover so the
   user can see which match is currently focused while stepping through
   with ↑/↓. The <mark> tags inside still keep their per-word highlight. */
.reader-chunk.fb-current-match{background:rgba(184,146,75,.45);outline:2px solid var(--gold);outline-offset:1px;border-radius:3px}

/* The flash a chunk gets after a bookmark jump — gold pulse so the user
   sees where they landed when clicking a bookmark in the dropdown. */
.reader-chunk.fb-bookmark-flash{
  background:rgba(184,146,75,.55);outline:2px solid var(--gold);
  outline-offset:1px;border-radius:3px;
  animation:fbBookmarkFlash 1.6s ease-out}
@keyframes fbBookmarkFlash{
  0%   {background:rgba(184,146,75,.85)}
  100% {background:rgba(184,146,75,.55)}
}

/* Resize handle between the reader and the full-book panel. Same look
   as the sidebar resize handle but only present when full-book is open.
   We toggle visibility from JS by adding/removing the .open class on
   .full-book and reading it via :has() from the handle. Falls back to a
   JS-set inline style on browsers without :has(). */
/* Book splitter — draggable handle between the full-book panel
   and the sidebar. Hidden until the full-book opens (.visible
   class toggled by openFullBook / closeFullBook in reader.js).
   Dragging changes only the full-book width; sidebar is unaffected. */
.book-resize-handle{
  width:0;flex-shrink:0;display:none;
  cursor:col-resize;background:transparent;
  user-select:none;position:relative}
.book-resize-handle.visible{display:block;width:8px}
.book-resize-handle::before{
  content:'';position:absolute;
  top:8px;bottom:8px;
  left:50%;transform:translateX(-50%);
  width:1px;
  background:rgba(163,123,43,.28);
  transition:background 140ms,width 140ms}
.book-resize-handle:hover::before,
.book-resize-handle.dragging::before{
  background:var(--gold);width:2px}

/* ── Folder picker modal (root-folder index) ──────────────────────
   Shown after the user clicks "شروع" on the root-folder index. Lets
   them choose which immediate subfolders should become collections.
   Backdrop catches clicks outside the card to dismiss. */
.modal-overlay{
  position:fixed;inset:0;background:rgba(31,26,20,.5);z-index:1000;
  display:flex;align-items:center;justify-content:center;padding:20px}
.modal-card{
  background:var(--cream);border:2px solid var(--warm);
  border-radius:8px;box-shadow:0 12px 40px rgba(0,0,0,.35);
  width:100%;max-width:560px;max-height:80vh;
  display:flex;flex-direction:column;overflow:hidden;
  font-family:'Scheherazade New',Arial,Helvetica,sans-serif}
/* v1.5.14 — Folder picker modal (root-folder indexer) is wider
   than the default modal-card width, because each row carries
   more controls than the manage-cols modal does (checkbox +
   folder name + → + collection-name input + language select +
   file count). At the original 560px, the language picker added
   in v1.5.13 makes the row feel cramped on shorter folder names
   and forces awkward wrapping on longer ones. The other modals
   stay at their tighter default width. */
#folder-picker-modal .modal-card{max-width:780px}
/* v3.6.x — When the folder picker is opened from the Manage Collections
   modal toolbar's "Bulk-index folder" button, both modals are visible
   at once. .modal-overlay sets z-index:1000 on both, and #manage-cols-modal
   sits later in source order, so default stacking hides the picker
   behind it. Bump folder-picker above the 1000 baseline (#ipm-modal at
   1500 stays above us, so the upload-progress modal still wins on top
   later). */
#folder-picker-modal{z-index:1200}
/* v3.6.x — Widen Manage Collections to fit the per-row controls
   (rename pencil + name + path button + path + lang select + 🔄 ⚡
   ➕ 🗑 actions). At 560px the actions wrapped and the path
   ellipsis kicked in early; 820px feels comfortable without
   sprawling on big screens. */
/* v3.6.15 — widened so the collection-name column has more room
   before truncating; the per-row buttons (➕ refresh ⚡ delete +
   rename) take a fixed amount of width on the right, and at 820px
   the name column ran out of space on longer Persian names. */
#manage-cols-modal .modal-card{max-width:1040px}

/* ─── Help docs modal (v4.6.5) — Major Features overview ─── */
#help-docs-modal .modal-card.help-docs-card{
  max-width:1100px;width:92vw;
}
#help-docs-modal .help-docs-body{
  padding:18px 22px;
  background:var(--parchment);
  max-height:calc(85vh - 120px);
  overflow:auto;
}
#help-docs-modal .help-docs-grid{
  display:grid;
  grid-template-columns:240px 1fr;
  gap:22px;
  align-items:stretch;
}
#help-docs-modal .help-docs-rail{
  background:linear-gradient(155deg,#7a3b2e 0%,#5a2a20 100%);
  color:var(--parchment);
  border-radius:var(--r);
  padding:22px 18px;
  display:flex;flex-direction:column;
  position:relative;
  min-height:100%;
}
#help-docs-modal .help-docs-badge{
  width:42px;height:42px;border-radius:50%;
  background:var(--gold);color:var(--parchment);
  display:flex;align-items:center;justify-content:center;
  font-family:'Georgia',serif;font-weight:700;font-size:1.4rem;
  margin-bottom:18px;
  box-shadow:0 2px 4px rgba(0,0,0,.2);
}
#help-docs-modal .help-docs-title{
  font-family:'Georgia',serif;font-weight:700;
  font-size:2.4rem;line-height:1;
  color:#fff;
  margin-bottom:6px;
}
#help-docs-modal .help-docs-subtitle{
  font-size:.95rem;letter-spacing:.05em;
  color:var(--cream);
  text-transform:uppercase;
  margin-bottom:12px;
}
#help-docs-modal .help-docs-rule{
  width:42px;height:3px;background:var(--gold);
  margin-bottom:14px;border-radius:2px;
}
#help-docs-modal .help-docs-intro{
  font-size:.92rem;line-height:1.55;
  color:var(--cream);
  flex:1;
}
#help-docs-modal .help-docs-version{
  margin-top:14px;
  font-size:.75rem;color:rgba(246,241,232,.6);
  font-family:monospace;letter-spacing:.04em;
}
#help-docs-modal .help-docs-cards{
  display:grid;
  grid-template-columns:1fr 1fr;
  gap:14px;
}
#help-docs-modal .help-docs-card{
  background:var(--cream);
  border-radius:var(--r);
  padding:14px 16px 14px 22px;
  position:relative;
  border-left:4px solid var(--gold);
  display:flex;flex-direction:column;
  min-height:130px;
}
html[dir="rtl"] #help-docs-modal .help-docs-card{
  padding:14px 22px 14px 16px;
  border-left:none;border-right:4px solid var(--gold);
}
#help-docs-modal .help-docs-num{
  font-family:'Georgia',serif;font-weight:700;
  font-size:1.1rem;color:var(--rust);
  margin-bottom:2px;display:inline-block;
}
#help-docs-modal .help-docs-card-title{
  font-weight:700;font-size:1rem;color:var(--ink);
  margin-bottom:6px;line-height:1.2;
}
#help-docs-modal .help-docs-card-body{
  font-size:.85rem;line-height:1.5;
  color:#4a3f33;
}
/* Stack to single column on narrow viewports. */
@media (max-width: 820px){
  #help-docs-modal .help-docs-grid{grid-template-columns:1fr}
  #help-docs-modal .help-docs-cards{grid-template-columns:1fr}
  #help-docs-modal .help-docs-rail{min-height:auto}
}
/* ─── /Help docs modal ─── */

.modal-header{
  background:linear-gradient(135deg,var(--rust),#a0440f);
  color:#fdf6e3;padding:12px 18px;display:flex;align-items:center;
  justify-content:space-between;gap:10px;flex-shrink:0}
.modal-header h2{
  font-family:'Scheherazade New',Arial,Helvetica,sans-serif;font-size:1.05rem;font-weight:700;
  flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.modal-close{
  background:transparent;border:none;color:#fdf6e3;font-size:1.4rem;
  cursor:pointer;padding:0 6px;line-height:1;flex-shrink:0;border-radius:3px;
  transition:background .15s}
.modal-close:hover{background:rgba(253,246,227,.2)}
.modal-toolbar{
  display:flex;align-items:center;gap:8px;padding:9px 14px;
  background:rgba(163,123,43,.08);border-bottom:1px solid var(--warm);
  flex-shrink:0;flex-wrap:wrap;font-size:.78rem}
.modal-toolbar .fp-count{margin-right:auto;color:#666;font-weight:700}
/* Bulk-language tabs at the top of the folder-picker modal. The
   active button (matching the unanimous row language) is filled
   gold so the operator sees at a glance which language is in
   effect. Mixed rows → neither highlighted. Refresh fires from
   openFolderPicker, folderPickerSetLang, folderPickerSetAllLang. */
.fp-lang-bulk button{transition:background .12s,color .12s,border-color .12s}
.fp-lang-bulk button.fp-lang-active{
  background:linear-gradient(135deg,var(--gold),#a37b2b);
  color:#fff;border-color:var(--gold);font-weight:700}
.fp-lang-bulk button.fp-lang-active:hover{filter:brightness(1.05)}
.modal-body{
  flex:1;min-height:0;overflow-y:auto;padding:6px 8px}
.fp-row{
  display:flex;flex-direction:row;align-items:center;gap:10px;
  padding:8px 10px;border-bottom:1px solid rgba(163,123,43,.1);
  font-size:.92rem;border-radius:3px;transition:background .12s}
.fp-row:last-child{border-bottom:none}
.fp-row:hover{background:rgba(163,123,43,.08)}
.fp-row input[type=checkbox]{
  width:16px;height:16px;cursor:pointer;accent-color:var(--rust);flex-shrink:0}
/* Folder name: fixed width so every row aligns into a clean column.
   Long names truncate with ellipsis; the full path is in the row's
   title attribute so hovering reveals it. Click toggles selection. */
.fp-row .fp-name{
  flex:0 0 200px;width:200px;
  font-weight:700;color:var(--ink);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  cursor:pointer;user-select:none}
/* Subtle arrow between the folder name (source) and the collection
   name (output) so the user reads the row left-to-right as
   "folder → collection name". */
.fp-row .fp-arrow{
  color:var(--gold);font-size:.85rem;flex-shrink:0;
  pointer-events:none}
.fp-row .fp-fcount{font-size:.76rem;color:#888;flex-shrink:0;font-family:monospace}
/* Editable collection name. Fixed width so the inputs form a clean
   column down the modal — much easier to scan than the variable-
   width flex layout. The input itself still scrolls horizontally
   when text exceeds the visible width (default <input> behavior). */
.fp-row .fp-colname{
  flex:0 0 240px;width:240px;
  padding:4px 8px;font-size:.86rem;
  font-family:'Scheherazade New',Arial,Helvetica,sans-serif;direction:rtl;text-align:right;
  background:var(--cream);color:var(--ink);
  border:1px solid var(--warm);border-radius:3px;
  transition:border-color .15s,box-shadow .15s}
.fp-row .fp-colname:focus{
  outline:none;border-color:var(--rust);
  box-shadow:0 0 0 2px rgba(192,57,43,.15)}

/* ── Manage Collections modal rows ──────────────────────────
   Each row shows one collection: name on the right (RTL flow puts
   it visually first), folder path in monospace LTR (paths are
   inherently LTR), document/word counts, and a refresh button.
   Layout intentionally mirrors fp-row so the two modals feel like
   the same family of UI. */
.mc-row{
  display:flex;flex-direction:row;align-items:center;gap:10px;
  padding:8px 10px;border-bottom:1px solid rgba(163,123,43,.1);
  font-size:.92rem;border-radius:3px;transition:background .12s}
.mc-row:last-child{border-bottom:none}
.mc-row:hover{background:rgba(163,123,43,.08)}
/* Visually distinguish the rows that belong to the caller — every
   private collection in the list is one of theirs (the server's
   /collections endpoint filters out other users' privates before
   we ever see them). Soft sage tint, plus a left accent border
   so the row reads as "yours" at a glance even without color. */
.mc-row.mc-row--mine{background:rgba(106,153,78,.07);border-inline-start:3px solid var(--sage,#6a994e)}
.mc-row.mc-row--mine:hover{background:rgba(106,153,78,.13)}
.mc-row.busy{opacity:.6;pointer-events:none}
.mc-row .mc-info{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
/* Name row: holds the name span (or its in-place edit input) and a
   subtle pencil button that appears on hover. The pencil duplicates
   the click-to-edit affordance — click anywhere on the name OR the
   pencil to enter edit mode. */
.mc-row .mc-name-row{
  display:flex;align-items:center;gap:6px;min-width:0}
.mc-row .mc-name{
  font-weight:700;color:var(--ink);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  cursor:pointer;border-bottom:1px dashed transparent;
  transition:border-color .15s,color .15s;flex:1;min-width:0}
.mc-row .mc-name:hover{
  color:var(--rust);border-bottom-color:rgba(192,57,43,.4)}
.mc-row .mc-rename-btn{
  background:none;border:none;cursor:pointer;
  font-size:.8rem;padding:2px 4px;flex-shrink:0;
  opacity:0;transition:opacity .15s;line-height:1}
.mc-row:hover .mc-rename-btn{opacity:.7}
.mc-row .mc-rename-btn:hover{opacity:1}
/* In-place rename input — replaces .mc-name during edit. Sized and
   styled to match the surrounding row so the swap doesn't reflow. */
.mc-row .mc-name-input{
  flex:1;min-width:0;font-weight:700;color:var(--ink);
  font-family:'Scheherazade New',Arial,Helvetica,sans-serif;font-size:.92rem;
  padding:2px 6px;background:var(--cream);
  border:1px solid var(--rust);border-radius:3px;
  direction:rtl;text-align:right;
  box-shadow:0 0 0 2px rgba(192,57,43,.15)}
.mc-row .mc-name-input:disabled{opacity:.6}
/* Path row: same shape as name row but for the source folder. The
   📁 button sits on the visual right of the path (first flex child
   in RTL flex flow) and toggles between "open path edit" and
   "open OS picker" depending on whether the row is in edit mode. */
.mc-row .mc-path-row{
  display:flex;align-items:center;gap:6px;min-width:0}
.mc-row .mc-path{
  flex:1;min-width:0;
  font-family:monospace;font-size:.74rem;color:#888;
  direction:ltr;text-align:left;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  cursor:pointer;border-bottom:1px dashed transparent;
  transition:border-color .15s,color .15s}
.mc-row .mc-path:hover{
  color:var(--teal);border-bottom-color:rgba(31,111,139,.4)}
.mc-row .mc-path-btn{
  background:none;border:none;cursor:pointer;
  font-size:.78rem;padding:2px 4px;flex-shrink:0;
  opacity:0;transition:opacity .15s;line-height:1}
.mc-row:hover .mc-path-btn{opacity:.7}
.mc-row .mc-path-btn:hover{opacity:1}
.mc-row .mc-path-input{
  flex:1;min-width:0;font-family:monospace;font-size:.78rem;
  padding:2px 6px;background:var(--cream);color:var(--ink);
  border:1px solid var(--teal);border-radius:3px;
  direction:ltr;text-align:left;
  box-shadow:0 0 0 2px rgba(31,111,139,.15)}
.mc-row .mc-path-input:disabled{opacity:.6}
.mc-row .mc-path{
  font-family:monospace;font-size:.74rem;color:#888;
  direction:ltr;text-align:left;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.mc-row .mc-stats{font-size:.74rem;color:var(--gold);font-style:italic;flex-shrink:0;font-family:monospace}

/* v2.3 — Per-collection language picker. Sits between the book-count
   stat and the action buttons. Compact native <select> styled to the
   modal's parchment palette. Width is intentionally narrow — the two
   options ("فارسی/عربی" and "English") are short. */
.mc-row .mc-lang-select{
  flex-shrink:0;
  font-family:'Scheherazade New',Arial,Helvetica,sans-serif;
  font-size:.78rem;
  padding:3px 6px;
  border:1px solid var(--warm);
  border-radius:var(--r);
  background:var(--cream);
  color:var(--ink);
  cursor:pointer;
  margin:0 4px;
}
.mc-row .mc-lang-select:hover{border-color:var(--gold)}
.mc-row .mc-lang-select:focus{outline:none;border-color:var(--rust);box-shadow:0 0 0 2px rgba(139,58,15,.15)}
/* v1.5.13 — Same look for the per-row language picker in the
   folder picker modal (.fp-row > .fp-lang). The .mc-lang-select
   class is reused on the element for shape, but its rule above
   is parent-scoped to .mc-row, so we duplicate the styling here
   under .fp-row instead of broadening the original selector
   (broadening risks affecting other surfaces unintentionally). */
.fp-row .fp-lang{
  flex-shrink:0;
  font-family:'Scheherazade New',Arial,Helvetica,sans-serif;
  font-size:.78rem;
  padding:3px 6px;
  border:1px solid var(--warm);
  border-radius:var(--r);
  background:var(--cream);
  color:var(--ink);
  cursor:pointer;
  margin:0 4px;
}
.fp-row .fp-lang:hover{border-color:var(--gold)}
.fp-row .fp-lang:focus{outline:none;border-color:var(--rust);box-shadow:0 0 0 2px rgba(139,58,15,.15)}
/* v4.0.2 — Per-row Source dropdown (categorical None/BRL). Same
   visual shape as .fp-lang above so the picker row stays
   visually balanced. */
.fp-row .fp-source{
  flex-shrink:0;
  font-family:'Scheherazade New',Arial,Helvetica,sans-serif;
  font-size:.78rem;
  padding:3px 6px;
  border:1px solid var(--warm);
  border-radius:var(--r);
  background:var(--cream);
  color:var(--ink);
  cursor:pointer;
  margin:0 4px;
  max-width:160px;
}
.fp-row .fp-source:hover{border-color:var(--gold)}
.fp-row .fp-source:focus{outline:none;border-color:var(--rust);box-shadow:0 0 0 2px rgba(139,58,15,.15)}
/* v4.0.2 — Sub-row beneath each fp-row: source name + URL inputs.
   Indented to align with the colName column above so the
   visual association between the row and its provenance is
   obvious. */
.fp-source-row{
  display:flex;flex-wrap:wrap;gap:8px;align-items:center;
  padding:4px 14px 8px 38px;
  border-bottom:1px solid rgba(212,160,23,.18);
  background:rgba(212,160,23,.03);
  font-size:.78rem;
}
.fp-source-row .fp-source-label{
  color:#888;flex-shrink:0;font-size:.78rem;
}
.fp-source-row .fp-source-name,
.fp-source-row .fp-source-url{
  flex:1;min-width:120px;padding:3px 6px;height:24px;
  border:1px solid var(--warm);border-radius:var(--r);
  background:var(--parchment);
  font-family:'Scheherazade New',Arial,Helvetica,sans-serif;
  font-size:.78rem;
}
.fp-source-row .fp-source-url{font-family:monospace;font-size:.72rem}
.fp-source-row .fp-source-name:focus,
.fp-source-row .fp-source-url:focus{outline:none;border-color:var(--rust)}
/* v4.8.9 — Per-row categories strip beneath each fp-row. Same
   indent as .fp-source-row so the row's three sub-bars (source-
   row, cats-row) sit in a single visual column under the
   collection-name input. Chips reuse the .mc-cat-chip styling
   from the Manage Collections row chip column. */
.fp-cats-row{
  display:flex;align-items:center;gap:8px;
  padding:4px 14px 8px 38px;
  border-bottom:1px solid rgba(212,160,23,.18);
  background:rgba(212,160,23,.03);
  font-size:.78rem;
}
.fp-cats-row .fp-source-label{color:#888;flex-shrink:0}
.fp-cats-strip{
  display:flex;flex-wrap:wrap;gap:4px;align-items:center;flex:1;
}
/* Bulk-source toolbar — same active-state pattern as .fp-lang-bulk
   so unanimous rows highlight the matching button. */
.fp-source-bulk button.fp-lang-active{
  background:linear-gradient(135deg,var(--rust),#742d12);
  color:#fdf6e3;border-color:var(--rust);
}
.fp-source-bulk button.fp-lang-active:hover{filter:brightness(1.05)}
.mc-row .mc-actions{display:flex;gap:4px;flex-shrink:0}
.mc-row .mc-action-btn{
  background:linear-gradient(135deg,var(--teal),#176775);
  color:#fdf6e3;border:none;border-radius:3px;
  padding:4px 8px;font-size:.78rem;cursor:pointer;
  transition:filter .15s,transform .1s}
.mc-row .mc-action-btn:hover{filter:brightness(1.1)}
.mc-row .mc-action-btn:active{transform:scale(.95)}
.mc-row .mc-action-btn:disabled{
  background:#bbb;cursor:not-allowed;filter:none;transform:none}
/* Danger variant for the Delete button — same shape, red gradient.
   Kept visually distinct from the teal refresh button so the user
   can't fat-finger a delete in place of a refresh. */
.mc-row .mc-action-btn.mc-danger-btn{
  background:linear-gradient(135deg,#c0392b,#922b21)}
/* v3.x — Warning variant for the Force-Reindex button. Amber gradient
   sits visually between teal (safe refresh) and red (delete). The op
   wipes every row in the collection before re-indexing, so it warrants
   a visible "are you sure" cue without being marked as full-on dangerous
   the way delete is. Same .js-destructive class as the delete button so
   applyDestructiveOpsState() greys both out together when the server's
   destructive_ops_allowed flag is off. */
.mc-row .mc-action-btn.mc-warn-btn{
  background:linear-gradient(135deg,#d4882a,#a86419)}
/* v3.6.x — "Add books" variant. Sage gradient distinguishes it
   from the teal refresh / amber force-reindex / red delete trio
   so the operator reads "add" before "do something to this". */
.mc-row .mc-action-btn.mc-add-btn{
  background:linear-gradient(135deg,#6a994e,#4f7a3a)}
.modal-footer{
  display:flex;align-items:center;gap:8px;padding:11px 14px;
  background:rgba(163,123,43,.06);border-top:1px solid var(--warm);
  flex-shrink:0;justify-content:flex-start}
.modal-msg{
  padding:24px 16px;text-align:center;color:#888;font-size:.9rem}
.modal-msg.error{color:#c0392b}

/* ── Users panel + invite modal (v15.12) ── */
.users-list{
  display:flex;flex-direction:column;gap:6px;
  background:rgba(31,111,139,.04);border-radius:6px;padding:6px}
.user-row{
  display:flex;align-items:center;gap:8px;padding:8px 10px;
  background:#fff;border:1px solid rgba(163,123,43,.18);
  border-radius:5px;font-size:.78rem;line-height:1.3}
.user-row .user-info{flex:1;min-width:0;overflow:hidden}
.user-row .user-name{
  font-weight:600;color:var(--coffee);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.user-row .user-email{
  font-size:.72rem;color:#888;direction:ltr;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.user-row .user-meta{
  font-size:.7rem;color:#aaa;margin-top:2px;direction:ltr}
.user-row .role-pill{
  display:inline-block;padding:2px 8px;border-radius:10px;
  font-size:.68rem;font-weight:600;letter-spacing:.02em}
.user-row .role-pill.manager{
  background:rgba(163,123,43,.18);color:#8b6914;border:1px solid rgba(163,123,43,.4)}
.user-row .role-pill.user{
  background:rgba(31,111,139,.12);color:var(--teal);border:1px solid rgba(31,111,139,.3)}
.user-row .role-pill.pending{
  background:rgba(184,146,75,.18);color:#7a3b2e;border:1px solid rgba(184,146,75,.45);
  font-style:italic}
.user-row .user-actions{display:flex;gap:4px;flex-shrink:0}
.user-row .user-actions button{
  padding:4px 9px;font-size:.7rem;border-radius:3px;
  border:1px solid;background:transparent;cursor:pointer;
  transition:background .15s}
.user-row .user-actions .btn-revoke,
.user-row .user-actions .btn-remove{
  border-color:#c0392b;color:#c0392b}
.user-row .user-actions .btn-revoke:hover,
.user-row .user-actions .btn-remove:hover{
  background:rgba(192,57,43,.1)}
.user-row .user-actions .btn-promote,
.user-row .user-actions .btn-demote{
  border-color:var(--teal);color:var(--teal)}
.user-row .user-actions .btn-promote:hover,
.user-row .user-actions .btn-demote:hover{
  background:rgba(31,111,139,.1)}

.ce-modal-label{
  display:block;font-size:.75rem;color:#5a3010;
  margin:8px 0 3px;font-weight:600}
.ce-modal-input{
  width:100%;padding:7px 10px;font-size:.85rem;
  border:1px solid var(--warm);border-radius:4px;
  background:#fff;font-family:'Scheherazade New',Arial,Helvetica,sans-serif;
  box-sizing:border-box}
.ce-modal-input:focus{
  outline:none;border-color:var(--gold);
  box-shadow:0 0 0 3px rgba(163,123,43,.15)}

.modal-btn-primary{
  padding:8px 18px;font-size:.85rem;
  background:var(--gold);color:#fdf6e3;border:none;
  border-radius:4px;cursor:pointer;font-family:'Scheherazade New',Arial,Helvetica,sans-serif;
  transition:background .15s}
.modal-btn-primary:hover{background:#a87f0a}
.modal-btn-primary:disabled{opacity:.5;cursor:not-allowed}
.modal-btn-secondary{
  padding:8px 18px;font-size:.85rem;
  background:transparent;color:#5a3010;
  border:1px solid var(--warm);border-radius:4px;
  cursor:pointer;font-family:'Scheherazade New',Arial,Helvetica,sans-serif;
  transition:background .15s}
.modal-btn-secondary:hover{background:rgba(163,123,43,.1)}

/* ═══════════════════════════════════════════════════════════
 *  v2.0 — Search redesign (two-pane: results cards + reader)
 * ═══════════════════════════════════════════════════════════
 *
 * New layout for the Search tab introduced in v2.0:
 *   - The old <table class="results-table"> renderer is replaced
 *     by snippet cards (<li class="result-card">). Cards live
 *     inside #results-body so all existing $('results-body')
 *     consumers keep working.
 *   - A sibling reader pane (#reader-pane) shows the surrounding
 *     paragraphs of the clicked result, with the matched chunk
 *     highlighted and auto-scrolled into view.
 *   - The two panes are wrapped in #search-split, a CSS grid
 *     that collapses to a single column on narrow viewports.
 *
 * Scope: rules in this section ONLY apply inside #tab-search,
 * keyed off the .search-active class added to .tab-body when
 * the search tab is the active panel (existing pattern from
 * pre-v2.0 code). Other tabs are visually unaffected.
 *
 * The old results-table CSS upstream of this block is left in
 * place — the renderer no longer emits <table> markup, but the
 * rules cost nothing while they sit unused, and keeping them
 * makes a future "compact table view" toggle trivial.
 */

/* ── Two-pane split inside the search tab ────────────────── */
/* ── Two-pane split inside the search tab (v2.1.2) ─────────
   Order in DOM: filter-tree-pane → results-body. In RTL, DOM
   order flows right-to-left, so the tree appears on the visual
   RIGHT and the cards on the visual LEFT. The legacy full-book
   panel (#full-book) slides in over the cards when the user
   clicks one, restoring the v1.2 reading flow. */
/* v2.15 — Three-column search-tab layout, restored to match the
   uploaded mockup (search-mockup_3.html): filter tree + cards +
   persistent reader. Proportions follow the mockup:
     220px  | 1fr   | 1.25fr     ← desktop
   The reader is intentionally a bit wider than the cards because
   cards show a 3-line snippet while the reader shows a passage of
   2-5 paragraphs; giving the reader the larger column reduces the
   need to scroll inside it.

   In RTL: DOM order tree → cards → reader lays out right-to-left
   (tree on visual right, reader on visual left).
   In LTR: same DOM order lays out left-to-right (tree on visual
   left, reader on visual right) — matches the mockup. */
#search-split {
  display: grid;
  /* v2.68 — Two rows now:
       row 1 = the search input bar, spanning BOTH columns
       row 2 = filter tree + cards
     v2.17 kept this as a 2-column layout (third column for the
     in-tab reader was removed); v2.68 added the search row as a
     full-width row 1 so the input visually extends across both
     columns. */
  /* v4.2.3+ — Tree column is now a CSS variable so the resize
     handle can mutate it without touching anything else. Default
     220px matches the prior fixed value. The handle's own track
     sits between the tree and cards. */
  --tree-col: 220px;
  grid-template-columns: var(--tree-col) 24px minmax(0, 1fr);
  grid-template-rows: auto 1fr;
  grid-template-areas:
    "search search search"
    "filter handle cards";
  gap: 24px;
  /* Zero column-gap so the handle track itself supplies the
     24px visual spacing between tree and cards (otherwise the
     gap stacks on both sides of the handle and ends up at 56px). */
  column-gap: 0;
  /* Smaller row gap so the search bar visually hugs the columns
     beneath it; column gap unchanged (24px). */
  row-gap: 10px;
  column-gap: 24px;
  margin-top: 8px;
  /* v2.22 — Height comes from the flex parent (#tab-search.active).
     The parent's flex chain (.tab-body → #tab-search.active →
     #search-split) sizes us to fill remaining vertical space below
     the pinned search box and meta row. min-height:0 is critical:
     without it, the grid track would expand to fit content and the
     children's overflow:auto would never kick in. */
  height: 100%;
  min-height: 0;
}
#search-split > .search-row-wide { grid-area: search; }
#search-split > #filter-tree-pane { grid-area: filter; }
#search-split > #tree-resize-handle { grid-area: handle; }
#search-split > #results-body     { grid-area: cards;  }
/* v4.2.3+ — Tree/cards resize handle. 8px clickable track with a
   thin centerline that brightens on hover/drag. The grid gap (24px)
   already gives breathing room on each side, so the handle reads
   as a discrete bar without crowding the panes. */
#tree-resize-handle{
  cursor:col-resize;
  background:transparent;
  position:relative;
  user-select:none;
  align-self:stretch;
}
#tree-resize-handle::before{
  content:'';
  position:absolute;
  top:8px;bottom:8px;
  left:50%;transform:translateX(-50%);
  width:1px;
  background:rgba(163,123,43,0.28);
  transition:background 140ms,width 140ms;
}
#tree-resize-handle:hover::before,
#tree-resize-handle.dragging::before{
  background:var(--gold);
  width:2px;
}
.tab-body.search-active { overflow: hidden; }

#results-body {
  /* v2.22 — min-height:0 is critical for grid items: without it,
     the cell expands to fit all the cards and overflow:auto never
     fires (the column grows instead of scrolling). With it, the
     cell respects the grid track height (set by the parent's
     height:100%), and overflow-y:auto handles the spillover. */
  min-height: 0;
  /* v2.20 — Mockup look: hide the scrollbar visually but keep
     scrolling functional. The mockup achieves the "no scrollbar in
     the middle" feel by using thin auto-hide scrollbars; we go a
     little further and hide it entirely (the cards column has
     plenty of cite/page references to anchor the eye, so a missing
     scrollbar isn't disorienting). Wheel/trackpad scroll still
     works fine on every modern browser when the bar is hidden. */
  overflow-y: auto;
  padding-left: 8px; /* room for the right-edge active accent */
  scrollbar-width: none;        /* Firefox: hide */
  -ms-overflow-style: none;     /* old IE/Edge: hide */
}
#results-body::-webkit-scrollbar { width: 0; height: 0; }
#results-body::-webkit-scrollbar-thumb { background: transparent; }

/* v2.32 — Search input row + hint/meta row are now the first two
   children of #results-body. Pin them to the top as a "sticky"
   header so the search bar stays in view while cards scroll
   underneath. The two rows are direct children — we target the
   first two by relying on their unique inline display:flex
   styles. The sticky band gets a parchment background so card
   text doesn't show through as it scrolls underneath, and a thin
   bottom rule to mark the pinned/scrollable boundary. */
/* v2.68 — The previous sticky rule on #results-body's first two
   children is gone: the search row moved out of #results-body
   into its own grid-area:search (sibling of filter tree and
   cards), so it doesn't need sticky positioning anymore. The
   first child of #results-body is now #results-meta (hidden);
   the second is #results-cards-wrap, which scrolls along with
   the cards naturally. */

/* Empty state (the existing .empty div) — keep it centered
   in the new pane height. */
#results-body > .empty {
  height: 100%;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  text-align: center;
  color: var(--ink); opacity: .55;
}
#results-body > .empty .ico { font-size: 3rem; margin-bottom: 10px; }

/* ── Reader pane ─────────────────────────────────────────── */
#reader-pane {
  background: var(--cream);
  border: 1px solid rgba(163,123,43,.22);
  border-radius: var(--r);
  box-shadow: 0 1px 0 rgba(31,26,20,.04), 0 8px 24px -12px rgba(31,26,20,.18);
  display: flex; flex-direction: column;
  overflow: hidden;
  min-height: 0; /* let inner body claim flex space */
}
.reader-head {
  padding: 14px 22px 12px;
  border-bottom: 1px solid rgba(163,123,43,.12);
  background: linear-gradient(180deg, var(--cream), rgba(253,246,227,.92));
  display: flex; align-items: flex-start;
  justify-content: space-between;
  gap: 14px; flex-shrink: 0;
}
.reader-titles { min-width: 0; flex: 1; }
.reader-author {
  font-size: .72rem;
  color: var(--rust);
  font-weight: 700;
  letter-spacing: .04em;
  margin-bottom: 4px;
}
.reader-work {
  font-size: 1.18rem;
  font-weight: 700;
  color: var(--ink);
  line-height: 1.25;
  /* Truncate long book titles */
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.reader-section {
  font-size: .82rem;
  color: rgba(31,26,20,.55);
  margin-top: 4px;
}
.reader-tools { display: flex; gap: 3px; flex-shrink: 0; }
.reader-tool {
  width: 28px; height: 28px;
  display: inline-flex; align-items: center; justify-content: center;
  color: rgba(31,26,20,.55);
  background: transparent;
  border: none;
  border-radius: var(--r);
  cursor: pointer;
  transition: all 140ms;
}
.reader-tool:hover { background: var(--warm); color: var(--ink); }
.reader-tool svg { width: 14px; height: 14px; }

.reader-body {
  flex: 1;
  overflow-y: auto;
  padding: 22px 28px 50px;
  scrollbar-width: thin;
  scrollbar-color: rgba(163,123,43,.22) transparent;
}
.reader-body::-webkit-scrollbar { width: 7px; }
.reader-body::-webkit-scrollbar-thumb {
  background: rgba(163,123,43,.22); border-radius: 4px;
}

/* English documents: render the body LTR. The data-lang attr
   is set on the reader-body when openInReader populates it. */
.reader-body[data-lang="en"] {
  direction: ltr; text-align: left;
}

.passage {
  font-size: 1.05rem;
  line-height: 1.85;
  color: var(--ink);
  margin-bottom: 18px;
  padding: 5px 14px 5px 10px;
  margin-right: -14px;
  border-right: 2px solid transparent;
  transition: background 240ms, border-color 240ms;
}
.reader-body[data-lang="en"] .passage {
  padding: 5px 10px 5px 14px;
  margin-right: 0;
  margin-left: -14px;
  border-right: none;
  border-left: 2px solid transparent;
}
.passage .pnum {
  font-size: .68rem;
  color: rgba(31,26,20,.4);
  margin-left: 8px;
  user-select: none;
  display: inline-block;
  min-width: 30px;
  direction: ltr;
}
.reader-body[data-lang="en"] .passage .pnum {
  margin-left: 0;
  margin-right: 8px;
}
.passage.match {
  background: linear-gradient(270deg, rgba(243,216,168,.42), transparent);
  border-right-color: var(--gold);
}
.reader-body[data-lang="en"] .passage.match {
  background: linear-gradient(90deg, rgba(243,216,168,.42), transparent);
  border-right-color: transparent;
  border-left-color: var(--gold);
}
.passage.match .pnum { color: var(--rust); }

/* Reader empty state — shown before the user clicks any card */
.reader-empty {
  flex: 1;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  text-align: center; padding: 30px 24px;
  color: rgba(31,26,20,.55);
}
.reader-empty svg {
  width: 48px; height: 48px;
  color: rgba(163,123,43,.3); margin-bottom: 14px;
}
.reader-empty h3 {
  font-size: 1.05rem;
  color: rgba(31,26,20,.7);
  margin-bottom: 4px;
  font-weight: 700;
}
.reader-empty p { font-size: .9rem; max-width: 28ch; }

/* Loading state for chunk fetch */
.reader-loading {
  flex: 1;
  display: flex; align-items: center; justify-content: center;
  color: rgba(31,26,20,.5);
  font-size: .9rem;
}
.reader-loading::before {
  content: ""; width: 14px; height: 14px;
  border: 2px solid rgba(163,123,43,.3);
  border-top-color: var(--rust);
  border-radius: 50%;
  margin-left: 8px;
  animation: reader-spin .9s linear infinite;
}
@keyframes reader-spin { to { transform: rotate(360deg); } }

/* "Open full book" button at the foot of the reader head */
.reader-openfull {
  display: inline-flex; align-items: center; gap: 6px;
  margin-top: 8px;
  padding: 4px 10px;
  font-size: .78rem;
  color: var(--teal);
  background: transparent;
  border: 1px solid rgba(31,111,139,.3);
  border-radius: var(--r);
  font-family: inherit;
  cursor: pointer;
  transition: all 140ms;
}
.reader-openfull:hover {
  background: rgba(31,111,139,.08);
  border-color: var(--teal);
}

/* ── Toast (clipboard confirmation) ──────────────────────── */
.anvar-toast {
  position: fixed;
  bottom: 28px; left: 50%;
  transform: translateX(-50%) translateY(20px);
  background: var(--ink);
  color: var(--cream);
  padding: 9px 18px;
  font-size: .9rem;
  border-radius: var(--r);
  box-shadow: 0 8px 24px rgba(0,0,0,.25);
  opacity: 0; pointer-events: none;
  transition: all 240ms cubic-bezier(.2,.7,.3,1);
  z-index: 100;
}
.anvar-toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }
.anvar-toast .ico { color: var(--gold-lt); margin-left: 6px; }

/* ── Responsive ──────────────────────────────────────────── */
/* Medium viewport — drop the reader pane (tree + cards still side
   by side). The legacy full-book panel is still reachable from a
   "View full book" affordance on each card if needed. */
@media (max-width: 1180px) {
  #search-split {
    grid-template-columns: 220px minmax(0, 1fr);
  }
  #reader-pane { display: none; }
}
/* Narrow viewports — stack tree above cards. */
@media (max-width: 720px) {
  #search-split {
    grid-template-columns: 1fr;
    height: auto;
  }
  #filter-tree-pane { max-height: 220px; }
  .tab-body.search-active { overflow: auto; }
}

/* ═══════════════════════════════════════════════════════════
 *  v2.1 — Filter tree pane (right side in RTL)
 * ═══════════════════════════════════════════════════════════
 *
 * Hierarchical filter built from the current search results.
 * Each top-level branch is a collection (with total match count
 * across all books in that collection); each leaf is a book
 * within that collection (with its own match count). Click a
 * leaf to filter cards to that book; click a branch to filter
 * to that collection. The "پاک کردن" link in the head clears
 * the active filter.
 *
 * Built from STATE.lastResults inside renderSearchRows() in
 * search.js, so the tree always reflects the current result
 * set. STATE.treeFilter ({collection, book}) holds the active
 * selection, applied to cards by applyTreeFilterToCards().
 */
/* v2.13 — Filter tree restyled to match the search-mockup_3
   aesthetic: no background card, parchment-on-parchment, small
   uppercase tracked-out section label with a thin underline ruler,
   italic-serif counts, terracotta-italic "clear" link, slim guide
   line on the leaf indent. The previous boxed look (cream
   background + amber border + gradient header) was visually
   competing with the cards; this version recedes and lets the
   results breathe. */
#filter-tree-pane {
  /* No background, no border. Just text floating on the parchment
     with the rest of the page. */
  background: transparent;
  border: none;
  border-radius: 0;
  display: flex; flex-direction: column;
  overflow: hidden;
  min-height: 0;
  /* Slight right padding so the scrollbar (when active) doesn't
     hug the column edge. RTL flips this naturally via padding-inline. */
  padding-inline-end: 4px;
}
.rt-head {
  /* Replaces the old gradient header bar with a small uppercase
     section label plus a thin underline. The label is similar to
     a "FILTER BY" or "تنقیح" eyebrow above the tree.

     v2.49 — justify-content changed from space-between to flex-start
     so the auto-margins on .rt-meta (added in v2.48) actually
     control where the meta sits. With space-between + 3 children,
     the meta got pinned in the center regardless of margin. With
     flex-start, the meta's margin-inline-start:auto pushes it to
     the trailing edge in English mode while staying next to the
     title in Persian mode.

     v2.71 — Padding + margin + border copied from .cards-meta so
     that the two horizontal rules at the top of the filter pane
     and the top of the cards column land at exactly the same
     y-coordinate. Both use the same line color (--rule-soft) so
     they read as ONE continuous rule across the page.

     v1.5.3 — Min-height switched from a content-derived value to
     the shared --header-rule-y variable so the rule also aligns
     with the bottom of .full-book-toolbar (which is 52px tall).
     Earlier versions only aligned the two left-side panes; the
     full-book toolbar sat lower. Now all three bottom borders
     land on the same y. */
  display: flex; align-items: center; justify-content: flex-end;
  padding: 4px 8px 8px;
  margin-bottom: 8px;
  /* v1.5.5 — Pulled up 10px to lift the bottom rule above the
     filter pane closer to the bottom rule of the full-book
     toolbar on the right side of the screen.
     v1.5.6 — Reduced to 8px (came down 2px) per visual tuning.
     v1.5.7 — Down 1px more (now -7px).
     v1.5.8 — Down another half-pixel (-6.5px). */
  margin-top: -6.5px;
  border-bottom: 1px solid var(--rule-soft);
  /* Shared header height — see :root --header-rule-y. */
  min-height: var(--header-rule-y);
  flex-shrink: 0;
  background: none;
}
.rt-title {
  font-size: .66rem;
  text-transform: uppercase;
  letter-spacing: .18em;
  color: rgba(31,26,20,.55);
  font-weight: 600;
}
/* RTL — Persian/Arabic doesn't render uppercase, so undo it and
   keep the tracking restrained. */
html[lang="fa"] .rt-title {
  text-transform: none;
  letter-spacing: .02em;
  font-size: .78rem;
}
.rt-clear {
  /* Italic terracotta link, not a button. Hidden by default;
     visible only when a filter is active. */
  font-size: .78rem;
  color: var(--rust);
  background: transparent;
  border: none;
  cursor: pointer;
  padding: 0;
  font-style: italic;
  font-family: 'EB Garamond', Georgia, 'Times New Roman', serif;
  visibility: hidden;
}
html[lang="fa"] .rt-clear {
  /* Persian doesn't have italics; use the body font, normal style. */
  font-style: normal;
  font-family: 'Scheherazade New', Arial, Helvetica, sans-serif;
  font-size: .76rem;
}
.rt-clear:hover { text-decoration: underline; }
.rt-clear.visible { visibility: visible; }

/* v4.6.3 — Expand/collapse-all toggle + counts pill in the
   filter-tree header (siblings of .rt-clear). Sit at the leading
   edge; .rt-clear (margin-inline-start:auto) stays on the trailing
   edge as before. */
.rt-tool {
  font-size: .7rem;
  font-weight: 600;
  padding: 0;
  width: 22px;
  height: 22px;
  margin-inline-end: 8px;
  background: transparent;
  border: 1px solid rgba(163,123,43,.32);
  border-radius: 4px;
  color: var(--rust);
  cursor: pointer;
  font-family: inherit;
  line-height: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: background .12s, border-color .12s;
}
.rt-tool:hover {
  background: rgba(163,123,43,.14);
  border-color: var(--rust);
}
.rt-toggle-all {
  font-size: 1.05rem;
  font-weight: 700;
  /* +/− glyphs sit slightly low without a tiny nudge in some fonts. */
  padding-bottom: 2px;
}
.rt-counts {
  font-size: .7rem;
  color: rgba(31,26,20,.55);
  font-variant-numeric: tabular-nums;
  letter-spacing: .02em;
  white-space: nowrap;
}
html[lang="fa"] .rt-counts {
  font-family: 'Scheherazade New', Arial, Helvetica, sans-serif;
  font-size: .76rem;
}
/* v4.7.0 Phase 4 — .rt-mode-label now carries margin-inline-start:auto
   (see below) and absorbs the gap that pushes the trailing group to
   the row's inline-end. Clear sits naturally right after the mode
   label. (Was: .rt-clear had the auto-margin; that's now moved.) */
.rt-head .rt-clear { margin-inline-start: 6px; }

.rt-tree {
  flex: 1;
  overflow-y: auto;
  list-style: none;
  margin: 0;
  padding: 0;
  scrollbar-width: thin;
  scrollbar-color: rgba(163,123,43,.22) transparent;
}
.rt-tree::-webkit-scrollbar { width: 6px; }
.rt-tree::-webkit-scrollbar-thumb {
  background: rgba(163,123,43,.22); border-radius: 3px;
}

.rt-empty {
  padding: 14px 0;
  font-size: .8rem;
  color: rgba(31,26,20,.4);
  text-align: center;
  font-style: italic;
}
html[lang="fa"] .rt-empty { font-style: normal; }

/* A "branch" = one collection node with its books beneath. */
.rt-branch {
  display: flex; align-items: center; gap: 6px;
  padding: 5px 0;
  font-size: .88rem;
  color: rgba(31,26,20,.7);
  cursor: pointer;
  transition: color 120ms;
  user-select: none;
}
.rt-branch:hover { color: var(--ink); }
.rt-branch.active { color: var(--rust); font-weight: 600; }

.rt-chev {
  display: inline-block;
  width: 10px; height: 10px;
  flex: 0 0 10px;
  color: rgba(31,26,20,.4);
  /* Closed: chevron points right (LTR) or left (RTL) — matches
     the visual "click to expand" affordance. */
  transform: rotate(0deg);
  transition: transform 180ms ease;
}
html[lang="fa"] .rt-chev { transform: rotate(180deg); }
.rt-chev svg { width: 100%; height: 100%; display: block; }
/* Open state: rotate so chevron points down (both languages). */
.rt-tree li.rt-open > .rt-branch .rt-chev { transform: rotate(90deg); }
html[lang="fa"] .rt-tree li.rt-open > .rt-branch .rt-chev { transform: rotate(-90deg); }

.rt-count {
  /* Italic serif numerals in muted gray. margin-inline-start:auto
     pushes the count to the trailing edge in either RTL or LTR. */
  margin-inline-start: auto;
  font-family: 'EB Garamond', Georgia, 'Times New Roman', serif;
  font-style: italic;
  font-size: .78rem;
  color: rgba(31,26,20,.4);
  font-variant-numeric: tabular-nums;
  direction: ltr;
}
html[lang="fa"] .rt-count {
  /* Persian numerals + body font, no italic */
  font-family: 'Scheherazade New', Arial, Helvetica, sans-serif;
  font-style: normal;
  direction: rtl;
}
.rt-branch.active .rt-count,
.rt-leaf.active   .rt-count { color: var(--rust); opacity: .7; }

/* v2.46 — Result-set counts shown after the "Filter results" title.
   Same italic-serif numeric treatment as .rt-count so the header's
   typographic rhythm matches the per-collection counts below. The
   margin-inline-start: 8px nudges it away from the title text;
   margin-inline-end: auto pushes the "Clear" link to the trailing
   edge of the header (the row is flex-justify-content:space-between
   originally, but with three children we need explicit margins). */
/* v2.46 — Result-set counts shown after the "Filter results" title.
   Same italic-serif numeric treatment as .rt-count so the header's
   typographic rhythm matches the per-collection counts below. The
   margin-inline-start: 8px nudges it away from the title text;
   margin-inline-end: auto pushes the "Clear" link to the trailing
   edge of the header (the row is flex-justify-content:space-between
   originally, but with three children we need explicit margins).

   v2.70 — Element moved out of .rt-head into the top of the cards
   column (#results-body); selector now matches both legacy uses
   (.rt-meta) and the new home (.cards-meta). Layout simplified to
   match the cards header position rather than the tree header. */
.cards-meta,
.rt-meta {
  font-family: 'EB Garamond', Georgia, 'Times New Roman', serif;
  font-style: italic;
  font-size: .82rem;
  color: rgba(31,26,20,.45);
  font-variant-numeric: tabular-nums;
  direction: ltr;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}
.cards-meta {
  /* v2.70 — Counts at the top of the cards column. Padding gives
     a little breathing room above the first card; border-bottom
     marks where the cards list begins.
     v2.71 — Same min-height as .rt-head so the rules at the top
     of the filter pane and the top of the cards column align
     horizontally as one continuous line across the page.
     v2.72 — Sticky-pinned to the top of #results-body's scroll
     viewport so the counts + bottom border stay visible while
     the user scrolls through cards. Background covers the cards
     scrolling beneath; z-index sits above the cards but below
     dropdowns / history menus that anchor in the search row.
     v1.5.3 — min-height switched to the shared --header-rule-y
     so this rule also aligns with .full-book-toolbar's bottom
     border on the right side of the screen. */
  padding: 4px 8px 8px;
  margin-bottom: 8px;
  /* v1.5.5 — Pulled up 10px to lift the bottom rule above the
     cards column closer to the bottom rule of the full-book
     toolbar on the right side of the screen. Sticky `top` is
     also offset by the same amount so the bar still snaps to
     the visual top of #results-body's scroll viewport.
     v1.5.6 — Reduced to 8px (came down 2px) per visual tuning.
     v1.5.7 — Down 1px more (now -7px).
     v1.5.8 — Down another half-pixel (-6.5px). */
  margin-top: -6.5px;
  border-bottom: 1px solid var(--rule-soft);
  min-height: var(--header-rule-y);
  display: flex;
  align-items: center;
  position: sticky;
  top: -6.5px;
  z-index: 4;
  background: var(--parchment);
}
.cards-meta:empty,
.rt-meta:empty {
  /* v2.71 — Pre-search the meta has no text but we KEEP the row
     visible (with its border) so the horizontal rule across the
     top of the cards column aligns with the rule across the top
     of the filter pane. Both rules always show as one continuous
     line; the row just stays empty until a search runs. */
}
html[lang="fa"] .cards-meta,
html[lang="fa"] .rt-meta {
  font-family: 'Scheherazade New', Arial, Helvetica, sans-serif;
  font-style: normal;
  direction: rtl;
}
html[lang="en"] .cards-meta {
  /* Right-justify in English (LTR) so digits align with the
     trailing edge of the cards column. Mirrors the v2.48 rule
     that did this when the meta lived in the filter header. */
  text-align: right;
}

/* Leaves (books). Indented + connected with a thin guide line.
   Uses logical properties so RTL and LTR both render with the
   guide on the "leading" side. */
.rt-leaves {
  list-style: none;
  margin: 2px 0 6px;
  /* v4.0.6 — Pulled the leaf list closer to its branch by ~14px.
     margin-inline-start (was 22) flips automatically in RTL, so
     the shift is "leftward" in English and "rightward" in Persian
     — both moving the leaf toward the tree's start edge. */
  margin-inline-start: 8px;
  padding-inline-start: 8px;
  border-inline-start: 1px solid rgba(163,123,43,.18);
  display: none;
}
.rt-tree li.rt-open > .rt-leaves { display: block; }
.rt-leaf {
  display: flex; align-items: baseline; gap: 6px;
  padding: 4px 0;
  font-family: 'EB Garamond', Georgia, 'Times New Roman', serif;
  font-size: .9rem;
  color: rgba(31,26,20,.7);
  cursor: pointer;
  line-height: 1.4;
  user-select: none;
  overflow: hidden;
}
html[lang="fa"] .rt-leaf {
  font-family: 'Scheherazade New', Arial, Helvetica, sans-serif;
}
/* v4.0.7 — Hover color matches the book emoji's brownish tone
   (muted gold) instead of plain ink, so the row and the 📖 icon
   read as one visual unit on hover. The icon also pops to full
   opacity to reinforce the highlight. Active state still uses
   the stronger rust accent so selection stays distinguishable. */
.rt-leaf:hover { color: var(--gold); }
.rt-leaf:hover .rt-leaf-icon { opacity: 1; }
.rt-leaf.active { color: var(--rust); font-weight: 600; }
.rt-leaf > .rt-leaf-name {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  flex: 1; min-width: 0;
}
/* v4.0.5 — Small book icon sitting just before the leaf's name.
   Fixed-width so star + icon + name stay vertically aligned
   across leaves regardless of which optional elements are
   present. opacity slightly muted so it doesn't compete with
   the name text. */
.rt-leaf > .rt-leaf-icon {
  flex: 0 0 auto;
  font-size: .82rem;
  line-height: 1;
  opacity: .75;
  margin-inline-end: 4px;
  cursor: pointer;
  transition: opacity .12s, transform .1s;
}
.rt-leaf > .rt-leaf-icon:hover {
  opacity: 1;
  transform: scale(1.15);
}
/* v4.0.16 — Removed the BRL-yellow special case; all book icons
   now use the same muted-gold colour regardless of source. */
.rt-leaf > .rt-leaf-icon { color: var(--gold); }
.info-icon { color: #888; }
.info-icon.has-info { color: var(--rust); }

/* v2.65 — Star marker on filter-tree leaves for bookmarked books.
   Empty when the book has no mark; shows ★ in the rust accent
   when starred. The fixed width keeps name alignment consistent
   whether or not the star is present, so leaves don't visually
   shift as users mark / unmark books. */
.rt-leaf-star {
  flex: 0 0 14px;
  width: 14px;
  text-align: center;
  font-size: .82rem;
  color: var(--rust);
  margin-inline-end: 4px;
  user-select: none;
}
.rt-leaf-star.starred {
  color: var(--rust);
}

/* v2.61 — "Overflow" branches/leaves: hits exist server-side but
   weren't included in the current 500-cap, so clicking will
   trigger a new fetch narrowed to that collection / book. The
   visual cue is a subtle color shift in the count number plus a
   tiny "↻" glyph after it — enough to signal "this needs a
   fetch" without making the user pause to read. */
.rt-branch.rt-overflow .rt-count,
.rt-leaf.rt-overflow .rt-count {
  color: rgba(163,123,43,.55);
}
.rt-branch.rt-overflow .rt-count::after,
.rt-leaf.rt-overflow .rt-count::after {
  content: " ↻";
  opacity: .55;
}

/* ── v2.1.3 — Card font stepper (A−/A+) ─────────────────────
   Sits next to the results meta line. Visually styled to match
   the .fb-icon-btn buttons in the full-book toolbar, but smaller
   to fit the tighter meta-row context. */
.rc-font-stepper {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  padding: 2px;
  border: 1px solid rgba(163,123,43,.22);
  border-radius: var(--r);
  background: var(--cream);
}
.rc-font-btn {
  background: transparent;
  border: none;
  color: var(--ink);
  font-family: 'Scheherazade New', Arial, Helvetica, sans-serif;
  font-weight: 700;
  font-size: .82rem;
  padding: 2px 8px;
  cursor: pointer;
  border-radius: 2px;
  transition: background 140ms;
  /* Direction-locked LTR so "A−" / "A+" render naturally even
     in the RTL layout. */
  direction: ltr;
}
.rc-font-btn:hover {
  background: rgba(163,123,43,.14);
}
.rc-font-btn:active {
  background: rgba(163,123,43,.22);
}

/* v2.60 — Compact variant for the cards font stepper when it
   sits inside the filter tree header (.rt-head). The header is
   a tight row (title + counts + clear link) at small sizes, so
   the stepper buttons here use smaller padding + a smaller font
   size to fit without dominating. The rt-font-stepper class is
   added alongside .rc-font-stepper, so all the base styling
   (border, background, hover) is inherited. */
.rt-font-stepper {
  margin-inline-start: 6px;
  margin-inline-end: 6px;
}
.rt-font-stepper .rc-font-btn {
  font-size: .72rem;
  padding: 1px 6px;
}

/* ── v2.62 — Library audit panel ─────────────────────────── */
.library-audit-panel { padding: 0; }
.audit-summary {
  font-family: 'EB Garamond', Georgia, 'Times New Roman', serif;
  font-style: italic;
  font-size: .85rem;
  color: var(--ink-2);
  margin-bottom: 12px;
  padding: 8px 10px;
  background: rgba(163,123,43,.06);
  border-inline-start: 3px solid var(--rust);
  border-radius: var(--r);
}
html[lang="fa"] .audit-summary {
  font-family: 'Scheherazade New', Arial, Helvetica, sans-serif;
  font-style: normal;
}
.audit-col {
  margin-bottom: 8px;
  border: 1px solid var(--warm);
  border-radius: var(--r);
  background: var(--parchment);
  overflow: hidden;
}
.audit-col-summary {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 8px 12px;
  cursor: pointer;
  background: rgba(163,123,43,.04);
  list-style: none;
  user-select: none;
}
.audit-col-summary::-webkit-details-marker { display: none; }
.audit-col-summary::before {
  content: "▶";
  font-size: .7em;
  color: var(--rust);
  transition: transform .15s;
}
.audit-col[open] .audit-col-summary::before {
  transform: rotate(90deg);
}
.audit-col-name {
  flex: 1;
  font-weight: 700;
  font-size: .92rem;
  color: var(--ink);
}
.audit-col-count {
  font-family: 'EB Garamond', Georgia, 'Times New Roman', serif;
  font-style: italic;
  font-size: .82rem;
  color: var(--ink-3);
}
html[lang="fa"] .audit-col-count {
  font-family: 'Scheherazade New', Arial, Helvetica, sans-serif;
  font-style: normal;
}
.audit-col-warn {
  font-size: .78rem;
  color: var(--rust);
  font-weight: 600;
}
.audit-empty {
  padding: 12px;
  color: var(--ink-3);
  font-style: italic;
  font-size: .82rem;
}
.audit-table {
  width: 100%;
  border-collapse: collapse;
  font-size: .82rem;
}
.audit-table th {
  text-align: start;
  padding: 6px 10px;
  background: rgba(163,123,43,.05);
  font-weight: 600;
  font-size: .75rem;
  color: var(--ink-2);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  border-bottom: 1px solid var(--warm);
}
.audit-table td {
  padding: 6px 10px;
  border-bottom: 1px solid rgba(163,123,43,.1);
  vertical-align: top;
}
.audit-table .audit-id {
  font-family: 'EB Garamond', Georgia, 'Times New Roman', serif;
  font-variant-numeric: tabular-nums;
  color: var(--ink-3);
  width: 70px;
  white-space: nowrap;
}
html[lang="fa"] .audit-table .audit-id {
  font-family: 'Scheherazade New', Arial, Helvetica, sans-serif;
}
.audit-table .audit-name { color: var(--ink); }
.audit-table .audit-path {
  color: var(--ink-3);
  font-size: .72rem;
  font-family: 'SF Mono', Monaco, Consolas, monospace;
  word-break: break-all;
  direction: ltr;
}
.audit-row.audit-dup {
  background: rgba(192,57,43,.05);
}
.audit-row.audit-dup .audit-name {
  color: var(--rust);
  font-weight: 600;
}
.audit-dup-flag {
  display: inline-block;
  margin-inline-end: 6px;
  color: var(--rust);
}
/* v2.63 — Delete-book button in the audit table. Quiet trash
   icon by default, redder on hover. The actions column is sized
   to just the icon so name/path columns get the available width. */
.audit-table .audit-col-actions { width: 36px; }
.audit-table .audit-actions {
  width: 36px;
  text-align: center;
  vertical-align: middle;
}
.audit-del-btn {
  background: transparent;
  border: 1px solid transparent;
  color: var(--ink-3);
  font-size: 1rem;
  cursor: pointer;
  padding: 2px 6px;
  border-radius: var(--r);
  transition: color .14s, border-color .14s, background .14s;
}
.audit-del-btn:hover {
  color: var(--rust);
  border-color: rgba(192,57,43,.3);
  background: rgba(192,57,43,.08);
}

/* ── v2.77 — Settings overlay ────────────────────────────────
   Full-page view that replaces the search content when the user
   clicks Help → Settings. Hidden by default; openSettings adds
   the .visible class. Overlays the .app shell with a parchment
   background so search content is not visible underneath, and
   sits above .tab-body's normal scroll context.

   v2.79 — Positioned FIXED to the viewport (offset by --top-h
   so the top header stays visible — Help dropdown is still
   reachable, and the user remains visually anchored in Anvár).
   This makes the overlay cover the ENTIRE app area: the sidebar
   AND the full-book reader, not just the .tab-body. z-index sits
   above .app content but below modals (z-index 1000) so e.g.
   "Manage collection" modal can still appear over the overlay
   when the user opens it from inside Settings. */
.settings-overlay {
  display: none;
  position: fixed;
  top: var(--top-h, 62px);
  left: 0;
  right: 0;
  bottom: 0;
  background: var(--parchment);
  z-index: 200;
  overflow-y: auto;
  flex-direction: column;
}
.settings-overlay.visible {
  display: flex;
}
.tab-body {
  position: relative;  /* anchor for any other absolute children, harmless */
}

.settings-toolbar {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 16px;
  background: var(--cream);
  border-bottom: 1px solid var(--rule-soft);
  position: sticky;
  top: 0;
  z-index: 2;
}
.settings-back {
  background: transparent;
  border: 1px solid var(--rust);
  color: var(--rust);
  font-family: 'EB Garamond', 'Garamond', 'Times New Roman', serif;
  font-style: italic;
  font-size: .85rem;
  padding: 4px 12px;
  border-radius: var(--r);
  cursor: pointer;
  transition: background .14s, color .14s;
  flex-shrink: 0;
}
html[lang="fa"] .settings-back {
  font-family: 'Scheherazade New', Arial, Helvetica, sans-serif;
  font-style: normal;
}
.settings-back:hover {
  background: var(--rust);
  color: var(--cream);
}

.settings-subtabs {
  display: flex;
  gap: 4px;
  flex-wrap: wrap;
}
.settings-subtab {
  background: transparent;
  border: 1px solid transparent;
  color: var(--ink-2);
  font-size: .85rem;
  padding: 5px 12px;
  border-radius: var(--r);
  cursor: pointer;
  font-family: inherit;
  transition: background .14s, color .14s, border-color .14s;
}
.settings-subtab:hover {
  background: rgba(163,123,43,.08);
  color: var(--ink);
}
.settings-subtab.active {
  background: rgba(163,123,43,.16);
  color: var(--rust);
  border-color: rgba(163,123,43,.35);
  font-weight: 600;
}

.settings-body {
  padding: 16px;
  flex: 1;
  min-height: 0;
}
/* Inside the overlay, the panel that's marked .active is shown
   via the existing .tab-panel.active rule. Other panels stay
   display:none. */

/* ═══════════════════════════════════════════════════════════
 *  v1.6.7 — Custom <select> replacement (.cs-*)
 * ═══════════════════════════════════════════════════════════
 *
 * Drop-in visual replacement for a native <select> that renders
 * the popup with HTML+CSS instead of relying on the browser's
 * native (= OS-level) popup widget. This was forced by a
 * Chrome-on-macOS limitation: the native popup ignores
 * color-scheme:light when the OS is in dark mode, so a
 * dark-mode user saw a gray rectangle with invisible options
 * (clickable but unreadable). The HTML popup below is under
 * page CSS authority so it always renders parchment + ink, no
 * matter the OS theme.
 *
 * The original <select> stays in the DOM (display:none) so all
 * existing JS — sel.value reads, sel.options iteration,
 * sel.onchange handlers, sel.dispatchEvent('change') — keeps
 * working unchanged. The closed-state button mirrors the
 * select's currently-selected option text via csSyncLabel().
 *
 * Currently used by books-col-select only. Other native
 * selects in the app (index-col-select, rename-col-select,
 * upload-col-select) have the same Chrome/macOS limitation
 * and can be migrated to .cs-* by repeating the same wrap
 * pattern in the markup. */
.cs-wrap {
  position: relative;
  width: 100%;
  margin-bottom: 10px;
}
.cs-button {
  width: 100%;
  padding: 7px 10px;
  font-family: 'Scheherazade New', Arial, Helvetica, sans-serif;
  font-size: .88rem;
  border: 1.5px solid var(--warm);
  border-radius: var(--r);
  background: var(--parchment);
  color: var(--ink);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  cursor: pointer;
  text-align: right;
  direction: rtl;
  height: auto;
  line-height: 1.5;
}
.cs-button:hover { border-color: var(--gold); }
.cs-button:focus { outline: none; border-color: var(--rust); box-shadow: 0 0 0 2px rgba(122,59,46,.15); }
.cs-label {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.cs-arrow {
  color: var(--ink-3);
  font-size: .78rem;
  flex-shrink: 0;
  transition: transform .15s;
}
.cs-wrap.cs-open .cs-arrow { transform: rotate(180deg); }
.cs-popup {
  position: absolute;
  top: calc(100% + 2px);
  left: 0;
  right: 0;
  background: var(--parchment);
  border: 1.5px solid var(--warm);
  border-radius: var(--r);
  box-shadow: 0 6px 20px var(--shadow);
  z-index: 100;
  max-height: 340px;
  overflow-y: auto;
  padding: 4px 0;
}
.cs-option {
  padding: 7px 12px;
  font-family: 'Scheherazade New', Arial, Helvetica, sans-serif;
  font-size: .88rem;
  color: var(--ink);
  background: var(--parchment);
  cursor: pointer;
  direction: rtl;
  text-align: right;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.cs-option:hover { background: rgba(163,123,43,.10); }
.cs-option.cs-active {
  background: rgba(163,123,43,.16);
  color: var(--rust);
  font-weight: 700;
}
html[lang="en"] .cs-button,
html[lang="en"] .cs-option {
  font-family: 'Albert Sans', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  direction: ltr;
  text-align: left;
}

/* ── v2.77 — Help dropdown ────────────────────────────────── */
.help-dropdown {
  position: relative;
  display: inline-flex;
  align-items: center;
}
.help-trigger {
  background: transparent;
  border: none;
  color: inherit;
  font: inherit;
  font-size: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  cursor: pointer;
  padding: 4px 0;
  border-bottom: 1px solid transparent;
  transition: border-color 160ms;
}
.help-trigger:hover {
  border-bottom-color: var(--rust);
}
.help-menu {
  display: none;
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  background: var(--cream);
  border: 1.5px solid var(--gold);
  border-radius: var(--r);
  box-shadow: 0 8px 24px var(--shadow);
  min-width: 180px;
  z-index: 1000;
  padding: 4px;
}
html[lang="en"] .help-menu {
  right: auto;
  left: 0;
}
.help-dropdown.open .help-menu {
  display: block;
}
.help-menu a,
.help-menu button {
  display: block;
  width: 100%;
  text-align: start;
  background: transparent;
  border: none;
  color: var(--ink);
  font-family: inherit;
  font-size: .85rem;
  padding: 8px 12px;
  border-radius: var(--r);
  cursor: pointer;
  text-decoration: none;
  transition: background .14s;
}
.help-menu a:hover,
.help-menu button:hover {
  background: rgba(163,123,43,.12);
  color: var(--rust);
}

/* v4.7.0 — Language picker dropdown. Reuses .help-menu structure
   so most of the look is inherited above. Adds:
     • A thin gold separator between the two language options.
     • An explicit hover color (the help-menu hover already paints
       a tinted background + rust text, but the separator means we
       want the hover to read as a clearly highlighted band — so
       we ride on top of the base rule with a slightly deeper
       background and matching rust text). */
.lang-menu button + button {
  border-top: 1px solid rgba(163,123,43,.28);
}
.lang-menu button {
  font-weight: 600;
}
.lang-menu button:hover {
  background: rgba(163,123,43,.18);
  color: var(--rust);
}
/* v4.7.0 — Hide the currently-active language from the picker so
   only the OTHER option is offered. Driven off the <html lang="…">
   attribute that applyUILang sets, so it stays in sync without any
   JS plumbing on this menu. With one entry hidden, the separator
   on the remaining `button + button` no longer matches (only one
   sibling), which is exactly what we want. */
html[lang="en"] .lang-menu button[lang="en"],
html[lang="fa"] .lang-menu button[lang="fa"] {
  display: none;
}

/* ═══════════════════════════════════════════════════════════
 *  v2.8 — Indexing-progress modal (#ipm-modal)
 * ═══════════════════════════════════════════════════════════
 *
 * Single popup that drives every long-running indexing-shaped
 * operation: file upload, single-collection re/index, root
 * bulk index, and refresh-all. Lives inside .modal-overlay /
 * .modal-card so the existing modal infrastructure (z-index,
 * scrim, header gradient, footer band) carries over without
 * change. The bits below are just the body styling: the
 * "currently indexing" line, the progress bar, the live
 * counters, and the swap-in summary block.
 *
 * Note: no .modal-close in the header markup — this modal is
 * dismissable ONLY via the OK button in the footer once the run
 * has completed. A long indexing run shouldn't be interrupted
 * by a stray click on a close × in the header.
 */

/* "Currently indexing" — collection label on top (smaller, muted)
   and book/file name below (larger, ink colour). Both lines clip
   with ellipsis so a pathologically long filename can't expand
   the modal. */
.ipm-current-wrap{
  margin-bottom:12px;
  text-align:center;
  min-height:44px;     /* reserves space so the bar doesn't jump
                          when the collection line first arrives */
}
.ipm-current-col{
  font-size:.78rem;color:#888;font-weight:600;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  margin-bottom:2px;min-height:1em}
.ipm-current-file{
  font-size:.95rem;color:var(--ink);font-weight:600;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  direction:ltr;unicode-bidi:plaintext}
/* v4.8.9 — Live word counter for the current book. Sits directly
   under the file name, smaller + muted so it reads as a sub-line.
   Empty by default (no padding when blank). */
.ipm-current-words{
  font-size:.78rem;color:var(--teal);font-weight:500;
  margin-top:2px;min-height:1em;letter-spacing:.02em}

/* Progress bar — same gradient / radius as the inline strips
   so the eye recognises it as the same indicator. */
.ipm-bar-wrap{
  height:10px;background:rgba(163,123,43,.18);
  border-radius:5px;overflow:hidden;margin-bottom:10px}
.ipm-bar{
  height:100%;width:0%;
  background:linear-gradient(90deg,var(--teal),var(--gold));
  transition:width .25s ease}

/* Live counters strip below the bar. Centered, monospace-ish
   colour so the running numbers don't fight the heading. */
.ipm-counts{
  text-align:center;font-size:.8rem;color:#666;line-height:1.4}

/* Summary block — replaces the running widgets on completion.
   Headline takes the top, secondary line below, then a stat
   grid: two columns, label on the left, big number on the right. */
.ipm-summary-headline{
  font-size:1.05rem;font-weight:700;text-align:center;
  margin-bottom:4px;line-height:1.3}
.ipm-summary-headline.ipm-ok{color:var(--sage)}
.ipm-summary-headline.ipm-err{color:#c0392b}
.ipm-summary-secondary{
  font-size:.82rem;color:#666;text-align:center;
  margin-bottom:14px;line-height:1.4}
.ipm-summary-secondary.ipm-err-msg{
  color:#c0392b;font-weight:600;
  background:rgba(192,57,43,.06);
  border:1px solid rgba(192,57,43,.25);
  border-radius:4px;padding:6px 10px;
  margin-bottom:12px}
.ipm-summary-stats{
  display:flex;flex-direction:column;gap:6px;
  background:rgba(31,111,139,.05);
  border:1px solid rgba(31,111,139,.2);
  border-radius:6px;padding:10px 14px}
.ipm-stat{
  display:flex;align-items:baseline;justify-content:space-between;
  gap:12px;font-size:.85rem;line-height:1.5}
.ipm-stat-label{color:#666}
.ipm-stat-value{
  font-weight:700;color:var(--ink);
  font-variant-numeric:tabular-nums}
.ipm-stat-value.ipm-stat-ok{color:var(--sage)}
.ipm-stat-value.ipm-stat-skip{color:#c0392b}

/* v3.6.x — Upload-phase panel. Sits below the bar; replaces the
   stats grid while phase==='upload'. The 9-pointed anvár star
   (same SVG geometry as the login card) rotates continuously to
   signal "work in flight"; the status line below it reads
   "Uploading <file> (i / N)". On phase transition the panel hides
   and the stats grid takes its place at the same vertical slot. */
.ipm-phase--upload{
  display:flex;flex-direction:column;align-items:center;gap:10px;
  padding:12px 0 4px}
.ipm-anvar-spin{
  width:54px;height:54px;
  animation:anvar-spin 2.6s linear infinite;
  transform-origin:50% 50%}
@keyframes anvar-spin{
  from{transform:rotate(0deg)}
  to  {transform:rotate(360deg)}}
.ipm-upload-status{
  font-size:.85rem;color:var(--ink);text-align:center;
  font-family:'Scheherazade New',Arial,Helvetica,sans-serif;
  line-height:1.4;max-width:100%;overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap;padding:0 6px}

/* ─ v3.6.11 — security-check phase ─────────────────────────────
   Shares the same spinning anvár star as the upload phase.
   Adds a headline ("Security Check in Progress") + status line
   ("Scanning X of N…") and a slot for the red rejection list
   when validation fails. Layout mirrors .ipm-phase--upload so
   the modal height doesn't jump on the security→upload handoff. */
.ipm-phase--security{
  display:flex;flex-direction:column;align-items:center;gap:10px;
  padding:12px 0 4px}
.ipm-security-headline{
  font-size:1.05rem;font-weight:600;color:var(--rust);
  text-align:center;
  font-family:'Scheherazade New',Arial,Helvetica,sans-serif}
.ipm-security-headline--err{
  color:#c0392b}
.ipm-security-status{
  font-size:.85rem;color:var(--ink);text-align:center;
  font-family:'Scheherazade New',Arial,Helvetica,sans-serif;
  line-height:1.4;max-width:100%;overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap;padding:0 6px}
.ipm-security-rejected{
  margin-top:8px;width:100%;max-height:240px;overflow-y:auto;
  border:1px solid #e2c9a2;border-radius:6px;
  background:#fff7ec;padding:8px 10px}
/* v3.6.11 — header above the skipped-files list rendered at end-of-run */
.ipm-skipped-header{
  font-weight:600;color:#7a3b2e;
  font-family:'Scheherazade New',Arial,Helvetica,sans-serif;
  font-size:.95rem;margin-bottom:6px}

/* ─ v3.6.11 — end-of-run "processed files" scrolling list ─────────
   One row per file with an icon, name, and detail (word count for
   newly-added, reason for skipped/rejected). Sorted so rejections
   and skips bubble to the top — user sees problems first without
   needing to scroll past hundreds of OK rows. The list itself
   scrolls inside its own scrollbox so the modal stays bounded. */
.ipm-processed{
  margin-top:14px;padding-top:10px;
  border-top:1px solid rgba(163,123,43,.25);width:100%}
.ipm-pf-header{
  font-weight:600;color:#7a3b2e;text-align:center;margin-bottom:8px;
  font-family:'Scheherazade New',Arial,Helvetica,sans-serif;
  font-size:.95rem}
.ipm-pf-list{
  list-style:none;margin:0;padding:0;
  max-height:280px;overflow-y:auto;
  border:1px solid #e2c9a2;border-radius:6px;background:#fff7ec}
.ipm-pf{
  display:flex;align-items:flex-start;gap:8px;
  padding:6px 10px;border-bottom:1px dotted #e2c9a2;
  font-size:.85rem;line-height:1.45}
.ipm-pf:last-child{border-bottom:none}
.ipm-pf-icon{
  flex-shrink:0;font-size:1rem;width:1.4em;text-align:center;
  line-height:1.4}
.ipm-pf-body{
  display:flex;flex-direction:column;flex:1;min-width:0}
.ipm-pf-name{
  font-weight:600;color:#3a2f24;word-break:break-all}
.ipm-pf-detail{
  margin-top:2px;font-size:.78rem;color:#7a6855;word-break:break-word}
.ipm-pf--ok        .ipm-pf-name{color:#1e6f3a}
.ipm-pf--unchanged .ipm-pf-name{color:#6e5a3f}
.ipm-pf--unchanged .ipm-pf-icon{color:#a37b2b}
.ipm-pf--skipped   .ipm-pf-name{color:#c0392b}
.ipm-pf--skipped   .ipm-pf-detail{color:#c0392b}
.ipm-pf--rejected  .ipm-pf-name{color:#c0392b}
.ipm-pf--rejected  .ipm-pf-detail{color:#c0392b}
.ipm-rj-list{
  list-style:none;margin:0;padding:0;
  font-size:.85rem;line-height:1.5}
.ipm-rj-list li{
  display:flex;flex-direction:column;
  padding:4px 0;border-bottom:1px dotted #e2c9a2}
.ipm-rj-list li:last-child{border-bottom:none}
.ipm-rj-name{
  color:#7a3b2e;font-weight:600;
  word-break:break-all}
.ipm-rj-reason{
  color:#c0392b;font-size:.8rem;
  margin-top:2px;word-break:break-word}

/* ═══════════════════════════════════════════════════════════
 *  v2.10 — Collections-tab sub-tabs
 * ═══════════════════════════════════════════════════════════
 *
 * Three sub-panels under #tab-collections: Manage / Full Indexing
 * / Upload. The strip below the main tab row paints which one is
 * active. Visual language matches the main tabs (rust underline
 * on active) but smaller — these are nested navigation, not the
 * primary surface.
 *
 * Manager-only sub-tabs (Full Indexing today) hide via the
 * existing body.role-user .manager-only{display:none} cascade,
 * same mechanism used for the manager-only main tabs. The
 * matching sub-PANEL also carries .manager-only so a console
 * call to switchColSubtab('full-index') can't reveal the panel
 * for a non-manager.
 */

.col-subtabs{
  display:flex;
  gap:2px;
  border-bottom:1.5px solid rgba(163,123,43,.25);
  margin-bottom:14px;
}

.col-subtab{
  flex:0 1 auto;
  padding:8px 16px;
  background:transparent;
  border:none;
  border-bottom:2px solid transparent;
  margin-bottom:-1.5px;       /* overlap the strip's bottom border */
  font-family:'Scheherazade New',Arial,Helvetica,sans-serif;
  font-size:.85rem;
  font-weight:700;
  color:#888;
  cursor:pointer;
  transition:color .18s, border-color .18s;
  white-space:nowrap;
}

.col-subtab:hover{ color:var(--ink); }

.col-subtab.active{
  color:var(--rust);
  border-bottom-color:var(--rust);
}

/* Sub-panels behave like .tab-panel — display:none by default,
   only the .active one is shown. switchColSubtab toggles the
   .active class on both the buttons and the panels in lockstep. */
.col-subtab-panel{ display:none; }
.col-subtab-panel.active{ display:block; }

/* English direction — LTR layout for the sub-tab row. The
   default .col-subtabs flex flow already does the right thing
   in both directions because flex respects writing direction;
   no en-specific override needed. */

/* v4.1.2 — Red-dot indicator next to the Recommendations sub-tab
   label inside Settings → Users. Shows the count of recommendations
   whose status is 'New'; hidden when there are none. Polled on boot
   (refreshRecommendationsUnreadDot) and recomputed after every
   loadRecommendationsAdmin() so it can't drift. */
.users-recommend-dot{
  display:inline-block;
  margin-inline-start:6px;
  min-width:18px;
  height:18px;
  padding:0 5px;
  background:var(--rust, #c0392b);
  color:#fff;
  font-size:.66rem;
  font-weight:700;
  line-height:18px;
  text-align:center;
  border-radius:9px;
  vertical-align:middle;
}

/* v4.1.4 — Recommendation modal body uses a 2-col grid (form +
   scrollable history). On narrow viewports stack to a single
   column so neither pane gets squeezed below readability. */
@media (max-width:720px){
  .modal-body.recommend-body{
    grid-template-columns:1fr !important;
    max-height:none !important;
    overflow:auto !important;
  }
  .recommend-col-mine{
    max-height:50vh !important;
  }
}

/* ═══════════════════════════════════════════════════════════
 *  v2.11 — Inline full-rename panel (Manage Collections modal)
 * ═══════════════════════════════════════════════════════════
 *
 * Click a row's name (or pencil) in the Manage Collections modal
 * and an inline panel expands beneath the row with two fields
 * (new display name + new subfolder), a locked books_root prefix,
 * a live target-path preview, and Save/Cancel buttons. Submits
 * to /collections/<id>/full-rename as one atomic op (display
 * name + on-disk folder + every document.path), replacing the
 * old separate "Maintenance" form that used to live on the
 * Collections tab. See manageColsBeginRename for the JS side.
 */

/* The row that's currently being edited gets a subtle highlight
   so the user can see at a glance which collection the panel
   below is acting on. */
.mc-row.mc-row--editing{
  background:rgba(212,160,23,.08);
}

.mc-rename-panel{
  background:rgba(212,160,23,.06);
  border:1px solid var(--gold);
  border-top:none;
  padding:12px 14px;
  margin-bottom:6px;        /* same gap that mc-row uses below itself */
  border-radius:0 0 var(--r) var(--r);
}

.mc-rename-grid{
  display:flex;
  flex-direction:column;
  gap:10px;
}

.mc-rename-field label{
  display:block;
  font-size:.74rem;
  color:#666;
  margin-bottom:3px;
}

.mc-rename-field input[type="text"]{
  width:100%;
  padding:6px 10px;
  font-size:.85rem;
  height:34px;
  box-sizing:border-box;
  border:1.5px solid var(--warm);
  border-radius:var(--r);
  background:var(--parchment);
  color:var(--ink);
  font-family:'Scheherazade New',Arial,Helvetica,sans-serif;
}

/* Subfolder field gets a different font (mono) and direction (LTR)
   because it's a path component, not free text. The locked
   books_root prefix to its left also reads LTR. */
.mc-rename-field input.mc-rename-subfolder{
  font-family:monospace;
  font-size:.82rem;
}

.mc-rename-prefix-wrap{
  display:flex;
  align-items:stretch;
  gap:0;
  margin-bottom:4px;
}

.mc-rename-prefix{
  flex-shrink:0;
  display:flex;
  align-items:center;
  height:34px;
  padding:0 8px;
  background:var(--parchment);
  border:1.5px solid var(--warm);
  border-right:none;
  border-radius:var(--r) 0 0 var(--r);
  font-family:monospace;
  font-size:.78rem;
  color:#888;
  white-space:nowrap;
  max-width:60%;
  overflow:hidden;
  text-overflow:ellipsis;
}

.mc-rename-prefix-wrap input.mc-rename-subfolder{
  border-radius:0 var(--r) var(--r) 0;
  border-left:none;
}

.mc-rename-target{
  font-size:.72rem;
  color:#666;
  text-align:left;
  word-break:break-all;
}

.mc-rename-target-label{
  color:var(--gold);
  font-weight:700;
}

.mc-rename-target code{
  font-family:monospace;
  font-size:.72rem;
}

.mc-rename-actions{
  display:flex;
  gap:6px;
  justify-content:flex-end;
}

.mc-rename-status{
  font-size:.78rem;
  text-align:center;
  min-height:1em;
  margin-top:2px;
}

.mc-rename-loading{
  font-style:italic;
  color:#aaa;
}

/* ═══════════════════════════════════════════════════════════
 *  v2.13 — Manage sub-panel small-button row
 * ═══════════════════════════════════════════════════════════
 *
 * Two small buttons side by side at the top of the Manage sub-
 * panel: "Collections" (opens the management modal) and
 * "Delete All Collections" (manager-only). Replaces the
 * pre-v2.13 layout of a full-width primary button + a bordered
 * Danger-zone block with a title and warning. The buttons keep
 * their visual weight (primary teal vs btn-danger red) so the
 * destructive one is still easy to spot, but the surrounding
 * ceremony is gone.
 *
 * On narrow viewports the buttons wrap to two rows naturally
 * via flex-wrap; at typical sub-panel widths (~400-700px) they
 * sit on one line.
 */
.col-manage-actions{
  display:flex;
  flex-wrap:wrap;
  gap:8px;
  align-items:center;
  margin-bottom:8px;
}

/* ═══════════════════════════════════════════════════════════
 *  v2.14 — Manage Collections two-column layout (by language)
 * ═══════════════════════════════════════════════════════════
 *
 * The pre-v2.14 modal rendered every collection in a single
 * vertical stack. v2.14 splits that stack into two side-by-side
 * columns — Persian/Arabic on one side, English on the other —
 * driven by the row's `language` value. Changing the language
 * dropdown on a row now physically moves it to the other column
 * (manageColsSetLang), so the visual placement is the immediate
 * confirmation that the save took.
 *
 * Layout:
 *   .mc-cols-grid    flex container holding the two columns
 *   .mc-col          one column; flex:1 so they share width evenly
 *   .mc-col-header   sticky title + count badge at top of column
 *   .mc-col-body     vertical stack of .mc-row + any open rename
 *                    panel (.mc-rename-panel) — same flow as the
 *                    pre-v2.14 single-column body
 *
 * Responsive: at narrow widths the columns stack vertically so
 * each row keeps usable horizontal space. The breakpoint is
 * set above the size where rows would start truncating awkwardly.
 */

.mc-cols-grid{
  display:flex;
  flex-wrap:wrap;
  gap:14px;
  padding:0 4px;
}

.mc-col{
  flex:1 1 360px;
  min-width:0;     /* lets ellipsis on long paths work inside flex */
  display:flex;
  flex-direction:column;
}

.mc-col-header{
  display:flex;
  align-items:baseline;
  justify-content:space-between;
  gap:8px;
  padding:8px 4px 6px;
  margin-bottom:6px;
  border-bottom:1.5px solid rgba(163,123,43,.25);
  font-size:.86rem;
  font-weight:700;
  color:var(--teal);
}

.mc-col-title{ flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; }

.mc-col-count{
  flex-shrink:0;
  font-family:monospace;
  font-size:.78rem;
  color:#888;
  background:rgba(31,111,139,.08);
  border:1px solid rgba(31,111,139,.18);
  border-radius:10px;
  padding:1px 8px;
  font-variant-numeric:tabular-nums;
}

.mc-col-body{
  display:flex;
  flex-direction:column;
  gap:6px;
  flex:1;
}

.mc-col-empty{
  padding:14px 8px;
  font-size:.78rem;
  color:#aaa;
  font-style:italic;
  text-align:center;
}

/* ═══════════════════════════════════════════════════════════
 *  v2.15 — Indexing-progress modal stacking
 * ═══════════════════════════════════════════════════════════
 *
 * The indexing-progress modal (#ipm-modal) is a secondary popup
 * that fires from INSIDE other modals — the most common case is
 * a per-row 🔄 refresh from inside the Manage Collections modal.
 * Both #manage-cols-modal and #ipm-modal use .modal-overlay,
 * which sets z-index:1000, so source order decides the painting
 * order. #manage-cols-modal sits later in persian_search_ui.html
 * (around line 1660) than #ipm-modal (around line 1543), so the
 * default stacking puts manage-cols on top — and the progress
 * modal disappears behind it.
 *
 * Fix: bump #ipm-modal's z-index well above any other modal so
 * it always paints in front, regardless of source order or what
 * triggered it. 1500 is high enough that no other element on the
 * page touches it (next-highest is 1001 on the folder-picker
 * inline filter; everything else is at-or-below 1000).
 *
 * v2.16 — Backdrop lightened so a parent modal underneath
 * (e.g. Manage Collections) stays clearly visible while the
 * progress modal is up. The default .modal-overlay backdrop is
 * rgba(31,26,20,.5) — fine for a top-level modal, but when
 * stacked over another modal the parent already provides 50%
 * darkening on the page; piling another 50% on top dimmed the
 * parent modal to near-invisibility. We use a near-transparent
 * tint (.05) so the only "focus" comes from the progress card
 * itself; the parent modal's backdrop continues to handle the
 * page-level dimming. Pointer events still fall through the
 * backdrop element, so the parent modal's controls are inert
 * while the progress modal is up — exactly what we want, since
 * a refresh in flight shouldn't be interrupted by another
 * click on the row that started it.
 *
 * The same rule applies in reverse if we ever stack a tertiary
 * modal on top of #ipm-modal — that future modal would need
 * z-index >= 1600 to win.
 */
#ipm-modal{
  z-index:1500;
  background:rgba(31,26,20,.05);
}

/* v2.18 — The pre-v2.18 finishIndexProgressOK appended a separate
   .ipm-summary-block containing its own stats grid; v2.17 added a
   dashed divider above that block. v2.18 collapsed both views into
   one always-on layout, so .ipm-summary-block is no longer
   rendered. The rule below is kept (rather than deleted) so any
   in-flight sessions or cached older artifacts that DO emit it
   still render passably — but new builds won't reach it. */
.ipm-summary-block{ margin-top:14px; padding-top:12px; border-top:1px dashed rgba(163,123,43,.3); }

/* v2.18 — Completion / error colour states for the
   .ipm-current-file line. Pre-v2.18 the line only carried
   "the file currently being processed" text (or "Starting…");
   on completion the body was rebuilt entirely with a separate
   summary headline. v2.18 reuses the SAME element for both
   running and completed states, so we need explicit done /
   error colour classes that finishIndexProgressOK and
   finishIndexProgressError toggle on. */
.ipm-current-file--done{
  color:var(--sage);
  font-weight:700;
}
.ipm-current-file--err{
  color:#c0392b;
  font-weight:700;
  white-space:normal;       /* allow long error messages to wrap */
}

/* ═══════════════════════════════════════════════════════════
 *  v2.19 — Books tab split-pane (list + mini reader)
 * ═══════════════════════════════════════════════════════════
 *
 * The Books tab now has two columns: a list of books on one
 * side and a mini reader pane on the other. The direction
 * is set on .books-split[data-language] by openBookInBooksTab
 * BEFORE adding .books-split--reader-open, so the panes land
 * on the correct sides immediately:
 *
 *   data-language="fa" (or "ar") → list on right, reader on left
 *   data-language="en"           → list on left,  reader on right
 *
 * When no book is open, the reader has flex:0 and is invisible,
 * so the list takes the full row — pre-v2.19 behaviour preserved.
 * The .--reader-open modifier flips the reader to flex:1 with a
 * smooth transition.
 *
 * Mobile / narrow viewports: at <720px the columns stack
 * vertically (list on top, reader below) so each pane keeps
 * usable horizontal space. Up to designers if you'd rather have
 * the reader take over the screen at that width — for now it
 * stacks because clicking another book in the list while the
 * reader is open is a common flow.
 */

.books-split{
  /* v4.1.1 — Grid (was flex). Two 1fr columns with 14px gap so the
     list and reader columns match the picker / search-input row above
     (also a grid). Grid columns are computed identically regardless of
     each child's border / box-sizing; flex would let .books-split-reader's
     1px border push its outer width 1-2px past the toolbar's input. */
  display:grid;
  grid-template-columns:1fr 1fr;
  column-gap:14px;
  align-items:stretch;
  /* v2.20 — Fixed height so the inner reader pane has something
     concrete to scroll inside of. Without a bounded height, flex
     children can't decide where to put the scrollbar — the page
     itself ends up being the scroller, which defeats the point of
     having a list + reader side by side.
     calc(100vh - 230px) leaves room for the page's chrome (header,
     tab strip, books-tab toolbar above this wrapper); tweak if you
     adjust those. The 400px minimum prevents the pane from
     collapsing on very short windows. */
  height:calc(100vh - 230px);
  min-height:400px;
}

/* v2.20 — Direction is now driven by the GLOBAL UI language
   (the html[lang=...] attribute set by setUiLang), not by the
   per-collection language as in v2.19. Persian/Arabic UI: reader
   on the LEFT, list on the right (RTL-natural). English UI:
   reader on the RIGHT, list on the left.

   The pre-v2.20 .books-split[data-language=...] hook is no longer
   set by the JS, but the rules are kept in case an operator (or a
   future feature) wants to override per-collection. They take
   precedence over the html[lang] rules below by sitting later in
   the file. */
/* v4.1.1 — In FA/AR the visual layout is list-on-LEFT, reader-on-RIGHT
   (same as EN). With grid+RTL inheritance, col 1 is visually RIGHT and
   col 2 is visually LEFT, so to put list on the LEFT we place it in col 2
   and reader in col 1. Was achieved pre-v4.1.1 via flex-direction:row-reverse
   on flex; preserving the same visual layout with explicit grid-column.
   The .books-split[data-language=...] override is kept for any future
   per-collection override. */
html[lang="fa"] .books-split-list,
html[lang="ar"] .books-split-list,
.books-split[data-language="fa"] .books-split-list,
.books-split[data-language="ar"] .books-split-list{
  /* grid-row:1 forces same-row placement; without it, the default
     auto-flow:row cursor advances past col 2 after placing this
     (first) child, then can't backtrack when the reader asks for
     col 1, so reader wraps to row 2 — the bug that put the mini-
     reader way down the page in Persian UI. */
  grid-column:2;
  grid-row:1;
}
html[lang="fa"] .books-split-reader,
html[lang="ar"] .books-split-reader,
.books-split[data-language="fa"] .books-split-reader,
.books-split[data-language="ar"] .books-split-reader{
  grid-column:1;
  grid-row:1;
}

.books-split-list{
  min-width:0;          /* enables ellipsis on long book names */
  overflow-y:auto;      /* v2.20 — list also scrolls inside its own */
                        /* pane so long collections don't push the */
                        /* whole page. */
  /* v4.1.1 — Hide the vertical scrollbar visually so cards extend
     to the full column width, matching the picker above. The list
     still scrolls (mouse wheel, trackpad, keyboard) — only the
     visible bar is suppressed. Same approach macOS Safari uses by
     default (overlay scrollbars), applied here for Chromium/Firefox.
     Without this, the bar reserves ~15px inside the column → cards
     end 15px before the column boundary, creating a visible kink
     against the picker row above which has no scrollbar. */
  scrollbar-width:none;            /* Firefox */
  min-height:0;
}
.books-split-list::-webkit-scrollbar{ display:none; }  /* Chromium / Safari */

.books-split-reader{
  /* v2.20 — Always visible, half-width by default. The pre-v2.20
     "closed → flex:0" / "open → flex:1 50%" toggle (driven by the
     .books-split--reader-open class) is gone; the pane now sits
     persistently next to the list and shows a placeholder when no
     book is loaded. The .--reader-open class is still added by JS
     for backward-compat with anything that might key off it, but
     the CSS no longer cares.
     overflow:hidden on the WRAPPER bounds the children; the body
     inside (.bsr-body) carries the actual scrollbar.
     v4.1.1 — flex:1 1 50% removed; the parent is now a 1fr-1fr grid
     so this column's outer width is governed by the grid track. The
     1px border now sits inside the grid cell rather than pushing the
     outer width past the toolbar input above. */
  min-width:0;
  background:var(--parchment);
  border:1px solid var(--warm);
  border-radius:var(--r);
  display:flex;
  flex-direction:column;
  min-height:0;
  overflow:hidden;
}

/* Header — one row with title, pencil, close X. The pencil
   sits next to the title (clickable as well as the standalone
   button below it inside the body); close is on the far end. */
.bsr-header{
  display:flex;
  align-items:center;
  gap:6px;
  padding:8px 12px;
  border-bottom:1px solid var(--warm);
  background:linear-gradient(180deg, rgba(212,160,23,.08), transparent);
  flex-shrink:0;
}

.bsr-title{
  flex:1;
  min-width:0;
  font-weight:700;
  color:var(--ink);
  font-size:.95rem;
  white-space:nowrap;
  overflow:hidden;
  text-overflow:ellipsis;
}

.bsr-action{
  flex-shrink:0;
  border:none;
  background:transparent;
  padding:2px 6px;
  cursor:pointer;
  font-size:.95rem;
  color:#888;
  border-radius:3px;
  transition:background .15s, color .15s;
}
.bsr-action:hover{
  background:rgba(163,123,43,.12);
  color:var(--rust);
}
.bsr-action.bsr-close{
  font-size:1.1rem;
  color:#aaa;
}
.bsr-action.bsr-close:hover{ color:#c0392b; }

/* Inline rename panel inside the reader header area. Same
   visual language as the collection-rename inline panel in
   the Manage modal, just simpler (only one field). */
.bsr-rename-panel{
  background:rgba(212,160,23,.08);
  border-bottom:1px solid var(--gold);
  padding:10px 12px;
  flex-shrink:0;
}
.bsr-rename-label{
  display:block;
  font-size:.74rem;
  color:#666;
  margin-bottom:3px;
}
.bsr-rename-input{
  width:100%;
  padding:6px 10px;
  font-size:.85rem;
  height:34px;
  box-sizing:border-box;
  border:1.5px solid var(--warm);
  border-radius:var(--r);
  background:var(--parchment);
  color:var(--ink);
  font-family:'Scheherazade New',Arial,Helvetica,sans-serif;
  margin-bottom:8px;
}
.bsr-rename-actions{
  display:flex;
  gap:6px;
  justify-content:flex-end;
}
.bsr-rename-status{
  font-size:.78rem;
  text-align:center;
  min-height:1em;
  margin-top:4px;
  color:#666;
}

/* Body — scrollable book content, paragraph styling matches
   the existing reader. Uses tabular Garamond for English and
   Scheherazade for Persian/Arabic; direction is set via
   dir="auto" on the element so each chunk's natural direction
   wins, which works for mixed-script books. */
.bsr-body{
  /* v2.20 — flex:1 alone doesn't guarantee a scrollable child in
     a flex column; without min-height:0 the child grows to fit
     its content and the scrollbar appears on the page instead.
     The :1 1 0% form (flex-grow 1, flex-shrink 1, basis 0) plus
     min-height:0 lets overflow-y:auto take effect inside the
     bounded .books-split-reader column. */
  flex:1 1 0%;
  min-height:0;
  overflow-y:auto;
  padding:16px 20px;
  font-family:'Scheherazade New',Arial,Helvetica,sans-serif;
  font-size:1rem;
  line-height:2;
  color:var(--ink);
}
.bsr-body p{
  margin:0 0 1em 0;
}
.bsr-body .bsr-loading,
.bsr-body .bsr-error{
  text-align:center;
  padding:24px 12px;
  color:#888;
  font-style:italic;
}
.bsr-body .bsr-error{ color:#c0392b; font-style:normal; }

/* Pencil button on book-card rows. Matches the collection
   modal's .mc-rename-btn visually. Hidden until row hover so
   it doesn't compete with the book name when the user is
   just scanning the list. */
.book-card .book-rename-btn{
  flex-shrink:0;
  background:transparent;
  border:none;
  padding:2px 6px;
  cursor:pointer;
  font-size:.85rem;
  color:#aaa;
  opacity:0;
  transition:opacity .15s, color .15s;
  border-radius:3px;
}
.book-card:hover .book-rename-btn{ opacity:1; }
.book-card .book-rename-btn:hover{ color:var(--gold); background:rgba(163,123,43,.12); }

/* Inline-rename UI inside .book-name when the pencil is clicked.
   Swaps the book title for an editable input + Save/Cancel + an
   inline status line. The .book-card.br-renaming class lets us
   override the .book-name ellipsis clipping so the input can
   actually be edited at full width. */
.book-card.br-renaming{ cursor:default; }
.book-card.br-renaming .book-name{
  display:flex; align-items:center; gap:6px;
  overflow:visible; white-space:nowrap;
}
.book-card .br-rename-input{
  flex:1; min-width:0;
  font-family:'Scheherazade New',Arial,Helvetica,sans-serif;
  font-size:.92rem; font-weight:700; color:var(--rust);
  padding:3px 6px;
  border:1px solid var(--gold); border-radius:4px;
  background:#fff;
}
.book-card .br-rename-input:focus{
  outline:none; box-shadow:0 0 0 2px rgba(163,123,43,.25);
}
.book-card .br-rename-save,
.book-card .br-rename-cancel{
  flex-shrink:0;
  background:transparent; border:1px solid transparent;
  font-size:.95rem; line-height:1;
  padding:3px 7px; border-radius:3px; cursor:pointer;
  transition:color .15s, background .15s, border-color .15s;
}
.book-card .br-rename-save{ color:#1e7a3a; }
.book-card .br-rename-save:hover{ color:#fff; background:#1e7a3a; border-color:#1e7a3a; }
.book-card .br-rename-cancel{ color:#888; }
.book-card .br-rename-cancel:hover{ color:#fff; background:#888; border-color:#888; }
.book-card .br-rename-save:disabled,
.book-card .br-rename-cancel:disabled{ opacity:.45; cursor:not-allowed; }
.book-card .br-rename-status{
  flex-shrink:0; font-size:.72rem; color:#666; font-weight:400;
}

/* Active row state — when a book is open in the mini reader,
   highlight its row in the list so the user can see which
   one they're viewing. */
.book-card.book-card--open{
  background:rgba(31,111,139,.08);
  border-color:var(--teal);
  box-shadow:inset 0 0 0 1px rgba(31,111,139,.3);
}

/* Narrow-viewport: stack vertically. v4.1.1 — grid single-column. */
@media (max-width:720px){
  .books-split,
  .books-split[data-language="fa"],
  .books-split[data-language="ar"]{
    grid-template-columns:1fr;
  }
  html[lang="fa"] .books-split-list,
  html[lang="ar"] .books-split-list,
  html[lang="fa"] .books-split-reader,
  html[lang="ar"] .books-split-reader{
    grid-column:1;
  }
  .books-split--reader-open .books-split-reader{
    min-height:300px;
  }
}

/* v2.20 — Placeholder shown in the mini reader before any book
   has been clicked. Same muted-italic look as .bsr-loading; the
   text is set in i18n.js under books.reader.placeholder. */
.bsr-body .bsr-placeholder{
  display:flex;
  align-items:center;
  justify-content:center;
  height:100%;
  text-align:center;
  padding:24px 12px;
  color:#aaa;
  font-style:italic;
}

/* v2.23 — Move-book button on each book row. Same hover-reveal
   behaviour as the v2.19 .book-rename-btn so it doesn't compete
   with the book name during scanning. Sits between the pencil
   (rename) and the trash (delete) in source order, which puts
   it visually between them in both LTR and RTL. */
.book-card .book-move-btn{
  flex-shrink:0;
  background:transparent;
  border:none;
  padding:2px 6px;
  cursor:pointer;
  font-size:.85rem;
  color:#aaa;
  opacity:0;
  transition:opacity .15s, color .15s;
  border-radius:3px;
}
.book-card:hover .book-move-btn{ opacity:1; }
.book-card .book-move-btn:hover{
  color:var(--teal);
  background:rgba(31,111,139,.12);
}

/* ═══════════════════════════════════════════════════════════
 *  v2.24 — Move-book modal label + select clipping fix
 * ═══════════════════════════════════════════════════════════
 *
 * Pre-v2.24 the move modal used a single inline-styled <div> for
 * the "Book: <name>" line and reused .bsr-rename-input on the
 * <select> — which sets height:34px. That fixed height clipped
 * Persian/Arabic option text in the dropdown because Scheherazade's
 * descenders extend below the baseline and the option-rendering
 * line-box couldn't grow. The label row also forced direction:ltr
 * which made a Persian "کتاب:" label sit oddly next to a Persian
 * book name.
 *
 * Fixes:
 *   1. .bmm-book-line wraps name + label on a single row with
 *      enough line-height for descenders, no forced direction.
 *   2. .bsr-rename-input--select swaps the fixed height for a
 *      min-height + line-height so the rendered option grows to
 *      fit. Padding is roomier than the text-input flavor too,
 *      since <select>s look more cramped at the same numbers.
 */
.bmm-book-line{
  display:flex;
  flex-wrap:wrap;
  align-items:baseline;
  gap:6px;
  font-size:.85rem;
  line-height:1.8;
  margin-bottom:10px;
}
.bmm-book-label{ color:#666; flex-shrink:0; }
#bmm-book-name{
  color:var(--ink);
  font-weight:700;
  word-break:break-word;     /* long names wrap rather than push */
  min-width:0;
}

/* The .bsr-rename-input--select modifier overrides the height
   and tightens up padding so <select> renders its option text
   without bottom-clipping. min-height (not height) lets the
   browser grow the control if its own font metric is taller. */
.bsr-rename-input--select{
  height:auto;
  min-height:36px;
  padding:7px 10px;
  line-height:1.6;
}

/* ═══════════════════════════════════════════════════════════
 *  v2.28 — Inline rename panel under book-card rows
 * ═══════════════════════════════════════════════════════════
 *
 * Matches the look and feel of the .mc-rename-panel from the
 * Manage Collections modal (v2.11) and the .bsr-rename-panel
 * inside the mini reader (v2.19/v2.24). Pre-v2.28 the row
 * pencil opened a window.prompt(); v2.28 makes it a proper
 * inline editor that expands beneath the row.
 *
 * The book-card whose panel is open gets a subtle gold tint
 * via .book-card--editing so the operator can see at a glance
 * which book the panel below is acting on. Same affordance
 * the .mc-row--editing rule provides in the manage-cols modal.
 */

.book-card.book-card--editing{
  background:rgba(212,160,23,.08);
}

.book-rename-panel{
  background:rgba(212,160,23,.06);
  border:1px solid var(--gold);
  border-top:none;
  padding:12px 14px;
  margin-bottom:6px;        /* same gap book-cards have between them */
  border-radius:0 0 var(--r) var(--r);
}
.book-rename-panel .bsr-rename-label{
  display:block;
  font-size:.74rem;
  color:#666;
  margin-bottom:3px;
}
.book-rename-panel .bsr-rename-input{
  margin-bottom:8px;
}
.book-rename-panel .bsr-rename-actions{
  display:flex;
  gap:6px;
  justify-content:flex-end;
}
.book-rename-panel .bsr-rename-status{
  font-size:.78rem;
  text-align:center;
  min-height:1em;
  margin-top:4px;
}


/* ═══════════════════════════════════════════════════════════
   v4.7.0 Phase 2b — categories UI
   ═══════════════════════════════════════════════════════════
   Three chunks: (1) per-row chip strip on Manage Collections,
   (2) the floating picker dropdown, (3) the Manage Categories
   modal. Rust/sage palette matches the rest of the surface;
   private chips get the lock glyph + a muted background tint
   so "personal" reads at a glance even without color. */

/* ── Per-row chip strip ─────────────────────────────────── */
.mc-cats{
  display:flex;flex-wrap:wrap;align-items:center;gap:6px;
  margin-top:2px;
}
.mc-cat-chip{
  display:inline-flex;align-items:center;gap:4px;
  font-size:.74rem;line-height:1.2;
  padding:2px 6px 2px 8px;
  border-radius:11px;
  background:rgba(163,123,43,.12);
  color:var(--ink);
  border:1px solid rgba(163,123,43,.22);
  white-space:nowrap;
}
.mc-cat-chip--private{
  background:rgba(106,153,78,.13);
  border-color:rgba(106,153,78,.32);
}
.mc-cat-chip-name{font-weight:600}
.mc-cat-chip-x{
  background:none;border:none;cursor:pointer;
  color:var(--rust,#c0392b);
  font-size:.95rem;line-height:1;padding:0 2px 0 4px;
  opacity:.55;transition:opacity .12s;
}
.mc-cat-chip-x:hover{opacity:1}
.mc-cat-add{
  background:none;border:1px dashed rgba(163,123,43,.4);
  color:var(--ink);cursor:pointer;
  font-size:.72rem;padding:2px 8px;border-radius:11px;
  transition:background .12s,border-color .12s;
}
.mc-cat-add:hover{
  background:rgba(163,123,43,.14);
  border-color:rgba(163,123,43,.7);
}

/* ── Floating picker dropdown ───────────────────────────── */
.cat-picker{
  position:fixed;z-index:10000;
  background:#fff;color:var(--ink);
  border:1px solid rgba(163,123,43,.4);
  border-radius:8px;
  box-shadow:0 8px 24px rgba(0,0,0,.18);
  width:300px;max-width:90vw;
  display:flex;flex-direction:column;
  font-size:.86rem;
}
.cat-picker-hd{padding:8px;border-bottom:1px solid rgba(163,123,43,.18)}
.cat-picker-input{
  width:100%;box-sizing:border-box;
  padding:6px 8px;font-size:.86rem;
  border:1px solid rgba(163,123,43,.4);border-radius:4px;
}
.cat-picker-list{
  max-height:260px;overflow:auto;
}
.cat-picker-opt{
  padding:7px 10px;cursor:pointer;
  display:flex;align-items:center;gap:8px;
  border-bottom:1px solid rgba(163,123,43,.07);
}
.cat-picker-opt:hover{background:rgba(163,123,43,.1)}
.cat-picker-opt:last-child{border-bottom:none}
.cat-picker-opt-vis{
  margin-inline-start:auto;font-size:.72rem;opacity:.65;
}
.cat-picker-opt--create{
  background:rgba(106,153,78,.08);
  font-style:italic;
}
.cat-picker-opt--create:hover{background:rgba(106,153,78,.16)}
.cat-picker-empty{
  padding:14px 10px;color:#888;font-style:italic;font-size:.82rem;
  text-align:center;
}

/* ── Manage Categories modal ─────────────────────────────── */
.mcat-overlay{
  position:fixed;inset:0;
  background:rgba(0,0,0,.45);
  z-index:9500;
  display:flex;align-items:center;justify-content:center;
}
.mcat-modal{
  background:#fdfaf3;color:var(--ink);
  border-radius:10px;
  box-shadow:0 12px 40px rgba(0,0,0,.35);
  width:min(720px,92vw);
  max-height:80vh;
  display:flex;flex-direction:column;
  border:1px solid rgba(163,123,43,.3);
}
.mcat-hd{
  display:flex;align-items:center;
  padding:10px 14px;border-bottom:1px solid rgba(163,123,43,.2);
}
.mcat-title{flex:1;font-weight:700;font-size:1rem}
.mcat-close{
  background:none;border:none;cursor:pointer;
  font-size:1rem;color:var(--rust);
}
.mcat-toolbar{
  display:flex;gap:6px;flex-wrap:wrap;
  padding:8px 12px;border-bottom:1px solid rgba(163,123,43,.15);
}
.mcat-btn{
  background:#fff;border:1px solid rgba(163,123,43,.4);
  border-radius:5px;cursor:pointer;
  padding:4px 10px;font-size:.78rem;
}
.mcat-btn:hover{background:rgba(163,123,43,.1)}
.mcat-btn--primary{background:var(--gold,#d4a017);color:#fff;border-color:var(--gold,#d4a017)}
.mcat-btn--primary:hover{background:#b58a14}
.mcat-btn--danger{color:var(--rust);border-color:rgba(192,57,43,.4)}
.mcat-btn--danger:hover{background:rgba(192,57,43,.1)}
.mcat-list{
  flex:1;overflow:auto;padding:0 14px 14px 14px;
}
.mcat-loading,.mcat-empty{
  padding:24px 14px;color:#888;text-align:center;font-style:italic;
}
.mcat-row{
  display:grid;
  grid-template-columns:1fr auto 220px 100px auto;
  gap:8px;align-items:center;
  padding:8px 6px;border-bottom:1px solid rgba(163,123,43,.1);
  font-size:.86rem;
}
.mcat-row:last-child{border-bottom:none}
/* v4.7.0 Phase 6 — Column header row. Same grid as .mcat-row so
   the parent column label sits directly above the dropdown,
   making the affordance obvious. */
.mcat-header{
  font-size:.74rem;
  text-transform:uppercase;
  letter-spacing:.04em;
  color:#888;
  border-bottom:1px solid rgba(163,123,43,.25);
  padding-bottom:6px;
  padding-top:4px;
  position:sticky;top:0;background:var(--parchment,#f6f1e6);z-index:2;
}
.mcat-header .mcat-hd-parent{
  color:var(--rust,#8a3b1f);
  font-weight:700;
}
.mcat-header .mcat-hd-count{text-align:end}
.mcat-name{font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.mcat-vis{
  font-size:.7rem;padding:2px 6px;border-radius:9px;white-space:nowrap;
}
.mcat-vis--public{background:rgba(163,123,43,.13);color:var(--ink)}
.mcat-vis--private{background:rgba(106,153,78,.13);color:var(--ink)}
.mcat-parent,.mcat-parent-static{
  font-size:.78rem;width:100%;
  padding:3px 6px;border-radius:4px;
  border:1px solid rgba(163,123,43,.25);background:#fff;
}
.mcat-parent-static{border:none;background:transparent;color:#666;font-style:italic}
.mcat-count{font-size:.74rem;color:#777;text-align:end}
.mcat-actions{display:flex;gap:4px;justify-content:flex-end}


/* ── v4.7.0 Phase 3 — Sidebar Categories tab + tree ─────── */
.col-dropdown-tabs{
  display:flex;gap:0;
  border-bottom:1px solid rgba(163,123,43,.2);
  background:rgba(253,250,243,.7);
}
.col-dropdown-tab{
  flex:1;background:none;border:none;cursor:pointer;
  padding:6px 8px;font-size:.78rem;
  color:var(--ink);
  border-bottom:2px solid transparent;
  transition:background .12s,border-color .12s;
}
.col-dropdown-tab:hover{background:rgba(163,123,43,.08)}
.col-dropdown-tab.active{
  border-bottom-color:var(--gold,#d4a017);
  font-weight:700;
}
.cat-tree-loading,.cat-tree-empty{
  padding:14px 12px;color:#888;font-style:italic;font-size:.82rem;
  text-align:center;
}
/* Reuse .col-opt for the category rows — same checkbox / caret /
   count layout. Private-cat rows pick up a soft sage tint to mirror
   the "personal" theme used elsewhere in the categories UI. */
.col-opt.cat-opt--private{
  background:rgba(106,153,78,.06);
}
.col-opt.cat-opt--private:hover{
  background:rgba(106,153,78,.14);
}

/* v4.7.0 Phase 6 — Sub-category rows in the category picker get a
   faint tint + ↳ indent so the user can tell them apart from
   roots. The indent itself is set inline via padding-inline-start
   so depth scales smoothly. */
.cat-picker-opt--sub{
  background:rgba(163,123,43,.05);
  font-size:.85em;
}


/* ── v4.7.0 Phase 4 — view flip switch (Collections / Categories) ──
   Plain iOS-style toggle: a rounded track with no icons and a
   sliding thumb. OFF = Collections (thumb at inline-start),
   ON  = Categories (thumb at inline-end + gold track). Logical
   inline-* properties keep the slide direction correct under RTL. */
.view-flip-switch{
  position:relative;
  display:inline-flex;
  align-items:center;
  margin-inline-end:6px;
  cursor:pointer;
  user-select:none;
  flex-shrink:0;
}
.view-flip-switch input{
  position:absolute;opacity:0;width:0;height:0;
  pointer-events:none;
}
.view-flip-track{
  position:relative;
  display:inline-block;
  width:40px;height:22px;
  border:1px solid rgba(163,123,43,.34);
  border-radius:12px;
  background:#ece4d2;
  transition:background .18s,border-color .18s;
}
.view-flip-switch:hover .view-flip-track{
  border-color:rgba(163,123,43,.6);
}
.view-flip-switch input:checked ~ .view-flip-track{
  background:var(--gold,#d4a017);
  border-color:var(--gold,#d4a017);
}
.view-flip-thumb{
  position:absolute;top:50%;
  inset-inline-start:2px;
  width:16px;height:16px;
  background:#fff;
  border-radius:50%;
  box-shadow:0 1px 3px rgba(31,26,20,.25);
  transform:translateY(-50%);
  transition:inset-inline-start .2s ease;
}
.view-flip-switch input:checked ~ .view-flip-track .view-flip-thumb{
  inset-inline-start:20px;
}
.view-flip-switch input:focus-visible ~ .view-flip-track{
  outline:2px solid var(--gold,#d4a017);
  outline-offset:2px;
}

/* Active-view label in the filter-tree header, pushed to the
   trailing edge of .rt-head — opposite the [-] / c.N/b.X group.
   Reads "Collections" or "Category" depending on the view-flip
   switch. Inherits font + size from .rt-counts so the items in
   .rt-head render at the same visual scale in both languages.
   margin-inline-start:auto pushes the label all the way to the
   row's inline-end — physical RIGHT in LTR English, physical
   LEFT in RTL Persian. */
.rt-mode-label{
  font-size:.7rem;
  color:rgba(31,26,20,.55);
  letter-spacing:.02em;
  margin-inline-start:auto;
  /* Negative inline-end margin pulls the label past .rt-head's
     8px inline-end padding so it sits flush with the modal edge. */
  margin-inline-end:-8px;
  user-select:none;
  white-space:nowrap;
}
.rt-mode-label:empty{display:none}
html[lang="fa"] .rt-mode-label{
  font-family:'Scheherazade New', Arial, Helvetica, sans-serif;
  font-size:.76rem;
}


/* ── Filter-tree Categories-view headers (right pane) ───── */
.rt-cat-branch > .rt-cat-header{
  background:rgba(163,123,43,.08);
  font-weight:700;
}
.rt-cat-branch > .rt-cat-header .rt-name{
  letter-spacing:.02em;
}
.rt-cat-uncat > .rt-cat-header{
  background:rgba(0,0,0,.04);
  font-style:italic;
}
