/* ============================================================================
   دفترِ خواندن — Reading Desk
   Shangarf extension for long-form pages · Claude Design lane · 2026-07-19

   The brief: a collapsible side index so the text can be read full-width, plus a
   font-size control. The reference (shahname.web.app) keeps one long list open
   beside the text — good, but it is binary: the list is either there, eating a
   third of the screen, or you lose your place entirely.

   This does three things it doesn't:

   1. THREE RAIL STATES, not two.  باز (full TOC + apparatus) → تیغه (a slim
      numbered spine that still shows where you are, and expands on hover) →
      بسته (gone; the text takes the full measure). The middle state is the
      point: you can reclaim ~85% of the rail's width and still never lose your
      position in an 11,000-word transcript.

   2. THE INDEX KNOWS WHERE YOU ARE. An IntersectionObserver marks the section
      being read; the spine shows it as a filled pip, the open rail highlights
      the row, and a hairline progress bar under the header reports how far
      through the session you are. The reference list is inert by comparison.

   3. TEXT SIZE IS A READING SETTING, not a zoom.  Four steps scale the body,
      the ayah and the translation together on their own ratios — scripture
      keeps its dominance over prose at every step — while the chrome stays put.

   Every setting persists per-reader in localStorage.
   ========================================================================= */

/* ---------- reading settings: four text steps --------------------------- */
/* Prose only: 16→20.
   قلعهٔ آیه — the ayah block and its فولادوند translation are deliberately NOT on
   this ladder. They used to be (22→28 / 15→18), which meant the typography control
   resized scripture; the owner's ruling (2026-07-27) is that the reading controls
   must never touch the ayah. --fs-ayah / --lh-ayah / --fs-tr therefore keep the
   fixed values set in shangarf.css and are not restated here — restating them at
   this specificity is exactly how the ladder captured them the first time. */
:root[data-fs="1"]{--fs-body:16px}
:root[data-fs="2"]{--fs-body:17px}
:root[data-fs="3"]{--fs-body:18.5px}
:root[data-fs="4"]{--fs-body:20px}

/* ---------- reading settings: three leading steps ----------------------- */
/* Leading is its own axis, not a side effect of size. It used to ride along with
   the size ladder (1.9→2.05, a range too narrow to be worth having); a reader who
   wants air between the lines usually does not want larger glyphs as well.
   Step 2 is the previous default exactly, so an untouched reader sees no change.
   The ayah keeps --lh-ayah and is untouched here for the same reason as above. */
:root[data-lh="1"]{--lh-body:1.75}
:root[data-lh="2"]{--lh-body:1.95}
:root[data-lh="3"]{--lh-body:2.25}

/* ---------- قلعهٔ آیه, part two: the المیزان boxes ----------------------
   117 pages (almizan/*, nazm-fehrest) carry their own inline <style> sizing the
   ayah as `calc(1.15em * var(--dtfs,1))`. Retiring --dtfs makes that multiplier
   inert, but the `em` does not: it resolves against a body that the size ladder
   scales, so the ayah still travelled 18.4 → 23 px with a preference set on some
   other page — measured, 2026-07-27. These pages ship no reading control of their
   own, so nothing on the page revealed it.
   Pinned to what the default reader already sees (1.15 × 17px, .92 × 17px), so
   the freeze changes nothing for anyone at the default step. `:root` prefix only
   to outrank the page's inline rule, which is otherwise an exact specificity tie
   decided by document order. */
:root .ay-ar{font-size:calc(1.15 * 17px)}
:root .ay-fa{font-size:calc(.92 * 17px)}

/* ---------- al-Mizan touch targets (2026-07-29) ---------------------------
   Measured on /almizan/al-imran at 320/360/375: `.mz-toc a` hit boxes were
   20.0 px (single-line) and 38.8 px (two-line) — both under the 40 px floor that
   lecture text pages already meet. Chips and `.back` were already ≥40 px.
   Floor the TOC/nav links without changing page HTML. Padding moves onto the
   anchor so the whole row is the hit target; list-item padding is zeroed so the
   total does not double. */
.mz-toc a,
.mz-navlist a,
.mz-foot a{
  display:flex;align-items:center;min-height:44px;
  padding-block:10px;box-sizing:border-box
}
.mz-toc li{padding-block:0}
.mz-navlist li{padding-block:0}
/* Reading bar injected by reading-desk.js on al-Mizan text pages.
   Sits as first child of `main.mz-wrap` so mobile sees it above the rail. */
main.mz-wrap > .readbar2.mz-readbar,
.mz-main > .readbar2.mz-readbar{margin-top:0;margin-bottom:14px}

/* ---------- chrome offset tokens (BS 2026-07-30) --------------------------
   `#dtbar` is position:fixed; z-index 9000; ~39 px on desktop when `.show` is on
   (scrollY > 170). It is out of flow, so nothing used to clear it: the sticky
   reading bar at top:0 slid underneath (z-index 40 vs 9000) and h2 scroll-margin
   of 60 px undershot chrome+bar (~91 px). Heights are published at runtime by
   reading-desk.js — never hardcode 39; the bar is shorter on a phone. */
:root{
  --chrome-h:0px;
  --readbar-h:52px;
  --read-scroll-pad:calc(var(--chrome-h) + var(--readbar-h))
}
html{scroll-padding-top:var(--read-scroll-pad)}
/* Beat mvp2-compat's fixed 60 px so TOC jumps clear chrome + expanded bar.
   Targets include section.mz-passage[id] (al-Mizan rail links), not only h2. */
body.mvp2-live .matn-body h2,
.matn-body h2[id],
.prose h2[id],
.matn h2[id],
[data-reader-column] h2[id],
[data-reader-column] [id],
.mz-main h2[id],
.mz-body h2[id],
.mz-unit h2[id],
.mz-passage[id],
.mz-unit[id],
.g-year[id]{
  scroll-margin-top:var(--read-scroll-pad)
}

/* ---------- the reading bar (built by desk.js) --------------------------
   Moved here from surah/styles.css. It is not a تفسیر component: desk.js builds
   it on every transcript family, including روانکاوی, which never loads that file.
   Re-tokenised on the way — it was written against a hardcoded cream and a
   hardcoded brown, so it stayed light while the page went dark, and it now
   carries the theme control itself.

   BS 2026-07-30 — mechanism: sticky (not a free-floating fixed toolbar).
   Sticks BELOW the fixed chrome via top:var(--chrome-h). After the reader
   scrolls past, reading-desk.js collapses the bar and shows `.rb-peek` (a 44×44
   FAB in the thumb zone). Traded away: a permanently expanded sticky strip
   (would cost ~7 % of an 812 px phone screen for a control used once). */
.readbar2{position:sticky;top:var(--chrome-h,0px);z-index:50;display:flex;align-items:center;gap:5px;
  margin:0 0 16px;padding:7px 10px;background:var(--paper-mid);
  border:1px solid var(--line);border-radius:12px;
  transition:opacity .18s ease,box-shadow .18s ease}
.readbar2.stuck{box-shadow:var(--shadow)}
/* Collapsed: leave the in-flow slot (avoids layout shift of the text that was
   under the original bar position) but paint nothing — the peek FAB takes over. */
.readbar2.is-collapsed{
  opacity:0;pointer-events:none;box-shadow:none;
  /* Keep layout height so the document does not jump when the class toggles
     while the original box is still near the viewport. Visual hide only. */
  visibility:hidden
}
@media (prefers-reduced-motion:reduce){
  .readbar2{transition:none}
}
.readbar2 .rb-t{font-size:.78rem;font-weight:600;color:var(--ink-faint);
  margin-inline-end:auto;padding-inline-start:6px;overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap}
/* Base (mouse) target 36 px; phone media below raises to 44 px. Never leave
   the desktop size as the only size — 31 px was why four of seven controls
   measured under 40 px when the phone block did not apply or was not shipped. */
.rb2{width:36px;height:36px;flex:none;border:1px solid transparent;border-radius:8px;
  background:transparent;color:var(--ink-faint);display:grid;place-items:center;
  cursor:pointer;transition:background .14s,color .14s}
.rb2:hover{background:var(--paper-deep);color:var(--ink)}
.rb2.on{background:var(--paper-deep);color:var(--ink);border-color:var(--line-strong)}
.rb2:disabled{opacity:.35;cursor:default}
.rb2 svg{width:16px;height:16px;fill:none;stroke:currentColor;stroke-width:1.9;
  stroke-linecap:round;stroke-linejoin:round}
.readbar2 .sep2{width:1px;height:18px;background:var(--line);margin:0 3px}
.fsn2{font-size:.76rem;font-weight:700;color:var(--ink);min-width:1.1em;text-align:center}

/* ---------- the picker's faces, declared HERE on purpose ------------------
   `assets/fonts/fonts.css` is the site font manifest, but the TRANSCRIPT pages
   do not link it — measured: their <link> set is surah/styles.css, shangarf.css,
   reading-desk.css, mvp2-compat.css, final-light-center.css, sitewide-fixes.css,
   and their @font-face rules come from the first two. Declaring the picker's
   faces only in fonts.css left them undefined on every page that can pick them:
   they rendered correctly on this machine ONLY because Vazirmatn, Samim and
   Sahel happen to be installed as system fonts here, which a reader will not have.
   So they are declared in the file that owns the picker and is loaded wherever
   the bar appears. URLs are root-absolute: this file lives at /assets/, so a
   relative `fonts/…` would break on any page depth, and `cleanUrls:true` already
   makes relative urls resolve one level too high on index pages. */
@font-face{font-family:'Vazirmatn';font-style:normal;font-weight:400;font-display:swap;src:url('/assets/fonts/Vazirmatn-Regular.woff2') format('woff2')}
@font-face{font-family:'Vazirmatn';font-style:normal;font-weight:500;font-display:swap;src:url('/assets/fonts/Vazirmatn-Medium.woff2') format('woff2')}
@font-face{font-family:'Vazirmatn';font-style:normal;font-weight:700;font-display:swap;src:url('/assets/fonts/Vazirmatn-Bold.woff2') format('woff2')}
@font-face{font-family:'Samim';font-style:normal;font-weight:400;font-display:swap;src:url('/assets/fonts/Samim-Regular.woff2') format('woff2')}
@font-face{font-family:'Samim';font-style:normal;font-weight:500;font-display:swap;src:url('/assets/fonts/Samim-Medium.woff2') format('woff2')}
@font-face{font-family:'Samim';font-style:normal;font-weight:700;font-display:swap;src:url('/assets/fonts/Samim-Bold.woff2') format('woff2')}
@font-face{font-family:'Sahel';font-style:normal;font-weight:400;font-display:swap;src:url('/assets/fonts/Sahel-Regular.woff2') format('woff2')}
@font-face{font-family:'Sahel';font-style:normal;font-weight:700;font-display:swap;src:url('/assets/fonts/Sahel-Bold.woff2') format('woff2')}
/* the naskh option — one weight only; the face has no bold cut here, so headings
   inside a naskh reading column synthesise weight rather than swap family */
@font-face{font-family:'Noto Naskh Arabic';font-style:normal;font-weight:400;font-display:swap;src:url('/assets/fonts/NotoNaskhArabic-Regular.woff2') format('woff2')}

/* ---------- reader-selectable reading font (2026-07-27; BQ 2026-07-29) --
   Estedad remains the site face and the default; these are offered, never
   imposed. Latin stays Inter in every option so digits and Latin words do not
   jump between faces — only the Persian half of the stack changes.

   Binding is two-layer so a fifth family does not need another class listed:
   1. `[data-reader-column]` — stamped by desk.js / reading-desk.js after
      discovery (or authored in markup). Direct font-family for columns that
      inherit (transcripts).
   2. `--mz-ff` on `:root` — al-Mizan prose sets `font-family: var(--mz-ff)` on
      `.mz-body p` (measured), so inheritance from the stamped column never
      reaches the glyphs. Rebinding the variable is the one fix that lands.
   Historical class selectors stay as a no-stamp fallback. Never touch
   `--mz-ff-ayah`. */
:root[data-font="vazirmatn"]{
  --mz-ff:'Inter','Vazirmatn',system-ui,sans-serif}
:root[data-font="vazirmatn"] [data-reader-column],
:root[data-font="vazirmatn"] .matn-body,
:root[data-font="vazirmatn"] .prose,
:root[data-font="vazirmatn"] .matn{font-family:'Inter','Vazirmatn',system-ui,sans-serif}
:root[data-font="samim"]{
  --mz-ff:'Inter','Samim',system-ui,sans-serif}
:root[data-font="samim"] [data-reader-column],
:root[data-font="samim"] .matn-body,
:root[data-font="samim"] .prose,
:root[data-font="samim"] .matn{font-family:'Inter','Samim',system-ui,sans-serif}
:root[data-font="sahel"]{
  --mz-ff:'Inter','Sahel',system-ui,sans-serif}
:root[data-font="sahel"] [data-reader-column],
:root[data-font="sahel"] .matn-body,
:root[data-font="sahel"] .prose,
:root[data-font="sahel"] .matn{font-family:'Inter','Sahel',system-ui,sans-serif}
/* Naskh sets smaller than the sans faces at the same px: measured on a Persian
   sample, 304.3 px against Estedad's 343.6 px — 11.4 % narrower — so it carries
   a size compensation.
   The multiplier is 1.06, NOT the 1.129 the raw ratio suggests. `em` resolves
   against the PARENT, and `.matn-body` already sits below its parent, so a
   1.129em overshot to 19.04 px and made naskh 5.4 % WIDER than Estedad. 1.06
   lands on parity — verify by width, never by the nominal px.
   The reader's size steps survive this: they scale the parent, so the multiplier
   rides on top (measured 19.04 → 20.72 → 22.4 across the steps). The ayah pin
   below is unaffected — it re-declares family and never inherits this size. */
:root[data-font="naskh"]{
  --mz-ff:'Inter','Noto Naskh Arabic',serif}
:root[data-font="naskh"] [data-reader-column],
:root[data-font="naskh"] .matn-body,
:root[data-font="naskh"] .prose,
:root[data-font="naskh"] .matn{font-family:'Inter','Noto Naskh Arabic',serif;
  font-size:1.06em}
/* naskh size compensation on al-Mizan units that size from 1em */
:root[data-font="naskh"] .mz-body p{font-size:calc(1.06em * var(--dtfs,1))}

/* THE AYAH NEVER FOLLOWS THE PICKER — this pin is load-bearing, not defensive.
   `.quran-ar` does NOT in fact read `--ff-ayah` on these pages: measured, it
   computes to the body stack, so the Amiri variable is declared and unused.
   Without this rule a font change would re-set Quran text, which the project
   forbids outright. Specificity here (0,3,1) deliberately outranks the
   `:root[data-font=…] .matn-body` / `[data-reader-column]` rules above (0,2,1).
   al-Mizan ayah boxes use `.ay-ar` / `.ay-fa` — pin them too, or stamping
   `.mz-main` as the reader column would re-face scripture through inheritance. */
:root[data-font] .quran-ar,:root[data-font] .quran-fa,
:root[data-font] .ayah-ar,:root[data-font] .ayah-fa,
:root[data-font] .ay-ar,:root[data-font] .ay-fa,
:root[data-font] .matn-body .quran-ar,:root[data-font] .matn-body .quran-fa,
:root[data-font] .prose .quran-ar,:root[data-font] .prose .quran-fa,
:root[data-font] [data-reader-column] .quran-ar,:root[data-font] [data-reader-column] .quran-fa,
:root[data-font] [data-reader-column] .ay-ar,:root[data-font] [data-reader-column] .ay-fa{
  font-family:'Inter','Estedad',system-ui,sans-serif}

/* ---------- session contents: a disclosure, not a wall (2026-07-28) --------
   Collapsed by default. The list is closed by `.toc-list` being hidden unless
   the panel carries `.toc-open`; desk.js adds that class and the button. With
   JS off neither exists, `.toc-open` is never applied — so the rule below would
   hide the list permanently. That is why the hide is scoped to `:has(.toc-toggle)`:
   the list only collapses once the control that reopens it is actually present.
   Only the CLOSED state is styled. An earlier version also set `display:block`
   for the open state, which quietly flattened the list — its natural layout is
   `display:grid`, so opening it changed the column arrangement. Say nothing
   about the open state and the list keeps whatever the page gave it. */
.toc-panel:has(.toc-toggle):not(.toc-open) .toc-list{display:none}

.toc-panel h2:has(.toc-toggle){margin:0;padding:0;border:0;background:none}
.toc-toggle{display:flex;align-items:center;gap:10px;width:100%;
  min-height:44px;padding:10px 12px;border:1px solid var(--line);border-radius:10px;
  background:var(--paper-mid);color:inherit;font:inherit;text-align:start;cursor:pointer}
.toc-toggle:hover{background:var(--paper-deep)}
.toc-toggle .toc-tt{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap}
/* the count is a Persian numeral in Persian reader-facing chrome */
.toc-toggle .toc-n{flex:none;font-size:.82em;opacity:.7}
.toc-toggle .toc-chev{flex:none;width:18px;height:18px;fill:none;stroke:currentColor;
  stroke-width:2;stroke-linecap:round;stroke-linejoin:round;
  transition:transform .18s ease}
.toc-panel.toc-open .toc-chev{transform:rotate(180deg)}
@media (prefers-reduced-motion:reduce){.toc-toggle .toc-chev{transition:none}}

/* the picker menu */
.rb-fw{position:relative;display:flex;flex:none}
.rb-menu{position:absolute;top:calc(100% + 7px);inset-inline-end:0;z-index:70;
  min-width:11.5rem;padding:5px;background:var(--paper-high);
  border:1px solid var(--line-strong);border-radius:12px;box-shadow:var(--shadow);
  display:none}
.rb-menu.open{display:block}
.rb-menu button{display:flex;align-items:center;justify-content:space-between;gap:10px;
  width:100%;min-height:40px;padding:8px 11px;border:0;border-radius:8px;
  background:transparent;color:var(--ink);font-size:1rem;line-height:1.5;
  cursor:pointer;text-align:start}
.rb-menu button:hover{background:var(--paper-deep)}
.rb-menu button[aria-checked="true"]{background:var(--paper-deep)}
.rb-menu .tk{flex:none;opacity:0;color:var(--c-deep);font:700 13px/1 var(--ff-latin)}
.rb-menu button[aria-checked="true"] .tk{opacity:1}

/* reading progress — same chrome clearance as the reading bar */
.mprog{position:sticky;top:var(--chrome-h,0px);z-index:55;height:2.5px;background:var(--line-cool);
  margin-bottom:-2.5px}
.mprog i{display:block;height:100%;width:0;background:var(--zar);transition:width .12s linear}

/* ---------- collapsed reading-control peek (BS 2026-07-30) ----------------
   Placement: bottom-START (inset-inline-start). On this RTL site that is the
   bottom-right corner — the natural rest zone for a right-hand thumb on a
   375 px phone. Top-start (and especially top-end / top-left) is the hardest
   one-handed reach. `.resume` already occupies bottom-start; when the peek is
   on, resume is lifted so the two never stack on the same 44 px. al-Mizan's
   `.mz-toc` at 375 is a block above the column, not a bottom rail, so it does
   not collide with this corner. */
.rb-peek{
  position:fixed;z-index:60;
  inset-block-end:calc(18px + env(safe-area-inset-bottom,0px));
  inset-inline-start:18px;
  width:44px;height:44px;min-width:44px;min-height:44px;
  display:none;place-items:center;
  padding:0;border:1px solid var(--line-strong);border-radius:999px;
  background:var(--paper-high);color:var(--ink);
  font:700 15px/1 'Inter','Estedad',system-ui,sans-serif;
  box-shadow:var(--shadow);cursor:pointer;
  opacity:0;transform:translateY(8px);pointer-events:none;
  transition:opacity .18s ease,transform .18s ease
}
.rb-peek.is-on{display:grid;opacity:1;transform:none;pointer-events:auto}
.rb-peek:hover{background:var(--paper-deep)}
.rb-peek:focus-visible{outline:2px solid var(--c-deep,var(--zar));outline-offset:2px}
html:has(.rb-peek.is-on) .resume{
  inset-block-end:calc(18px + 44px + 10px + env(safe-area-inset-bottom,0px))
}
@media (prefers-reduced-motion:reduce){
  .rb-peek{transition:none;transform:none}
}
@media print{
  .rb-peek{display:none!important}
}

/* ---------- the bar on a phone (2026-07-27) ------------------------------
   It used to be hidden outright below 62rem, which left a phone reader with no
   size, leading or theme control at all. It is now laid out for the phone rather
   than removed. Four changes, each buying width for a 40 px tap target:
     · the title goes — the page already carries it as <h1>, and being the only
       flexible child it was eating the row;
     · the "mini" rail button goes — below 64rem `.spine` is display:none!important,
       so mini and open render identically; two buttons for one state is a trap;
     · the decorative separators go;
     · `overflow-x:auto` is a safety valve, not the layout: at 375 px the row
       measures ~356 px and does not scroll. Below ~360 px it scrolls INSIDE the
       bar, so the PAGE never gains a sideways scroll.
   `off` is kept because it still does real work here: below 64rem the rail is a
   static block above the text and `off` collapses it. */
@media(max-width:62rem){
  /* gap 2px reads tighter than it looks: the icon is 18 px inside a 40 px target,
     so the visual space between two icons is 2+11+11 = 24 px. The tap target is
     what must not shrink, and it does not. */
  .readbar2{gap:2px;padding:6px;overflow-x:auto;scrollbar-width:none;
    -webkit-overflow-scrolling:touch}
  .readbar2::-webkit-scrollbar{display:none}
  .readbar2 .rb-t{display:none}
  .readbar2 .sep2{display:none}
  /* All three rail buttons go on a phone, and the font button takes their place.
     Below 64rem the rail is not a rail at all — it is a plain block of contents
     sitting above the text — so "open / mini / off" were three controls for a
     thing the reader can already see and scroll past. The last line forces that
     block visible even for a reader whose saved state is `off` from a desktop
     session, so nothing becomes unreachable by removing the buttons.
     This is also what buys the row its width: 6 controls fit at 320 px, where
     the 8 of the previous layout overflowed 375 px by 24 px. */
  .readbar2 [data-r]{display:none}
  .desk[data-rail="off"] .deskrail{display:block}
  /* 44 px floor (accepted mobile target). Was 40 — between 40 and 44 is not
     the floor the owner asked for on this pass. */
  .rb2{width:44px;height:44px}
  .rb2 svg{width:18px;height:18px}
  /* `.fsn2` inherits flex-shrink:1, and with the row at its limit the flex
     algorithm crushed both numerals to 4.3 px — the size and leading VALUES,
     clipped to a sliver. They must not shrink; the 1.1em desktop alignment
     padding is what goes instead (the value is always one digit, 1-4). */
  .readbar2 .fsn2{flex:none;min-width:0}

  /* The font menu must LEAVE the bar on a phone. `overflow-x:auto` above also
     makes overflow-y `auto`, so an absolutely-positioned menu becomes a 172 px
     panel trapped inside a 52 px scrolling strip — measured, fully clipped.
     `position:fixed` escapes that clip (no ancestor sets a transform, which is
     the one thing that would trap it) and a bottom sheet is the honest phone
     shape anyway: always fully on screen wherever the bar has scrolled to. */
  .readbar2 .rb-menu{position:fixed;inset-inline:14px;inset-block-end:14px;
    top:auto;min-width:0;padding:6px;border-radius:14px}
  .readbar2 .rb-menu button{min-height:46px;font-size:1.05rem;padding:10px 13px}
}

/* ---------- بازگشت به موقعیتِ خواندن -----------------------------------
   An offer, not a jump — see the note in reading-desk.js. Sits opposite the
   toTop button so the two never stack. */
.resume{position:fixed;inset-block-end:18px;inset-inline-start:18px;z-index:60;
  padding:9px 15px;border:1px solid var(--line-strong);border-radius:999px;
  background:var(--paper-high);color:var(--ink);font:600 .82rem/1 var(--ff);
  box-shadow:var(--shadow);cursor:pointer;
  opacity:0;transform:translateY(8px);pointer-events:none;
  transition:opacity .22s ease,transform .22s ease}
.resume.in{opacity:1;transform:none;pointer-events:auto}
.resume:hover{background:var(--paper-deep)}
@media(prefers-reduced-motion:reduce){.resume{transition:none}}

/* ---------- the desk shell ---------------------------------------------- */
/* NOTE: no transition on grid-template-columns. Chrome freezes a var()-based track
   list mid-transition and stops re-resolving it, so switching to تیغه left the rail
   at its open width (measured: --rail-w read 3.25rem while the track stayed 304px).
   The rail animates its own width/opacity instead — same feel, no stuck track. */
.desk{--rail-w:19rem;
  display:grid;grid-template-columns:var(--rail-w) minmax(0,1fr);
  gap:clamp(20px,3.4vw,48px);align-items:start;padding-top:var(--s5)}
.desk > .deskrail{order:-1}

/* تیغه — the slim spine */
.desk[data-rail="mini"]{--rail-w:3.25rem}
/* بسته — full width */
.desk[data-rail="off"]{--rail-w:0px;gap:0}
.desk[data-rail="off"] .deskrail{opacity:0;pointer-events:none;overflow:hidden}

.deskrail{position:sticky;top:14px;max-height:calc(100vh - 28px);
  display:flex;flex-direction:column;gap:var(--s3);min-width:0;width:100%;
  transition:opacity .2s ease}
/* the head must be allowed to shrink with the track, or its flex content pins the
   rail open in تیغه */
.railhead,.spine{width:100%;min-width:0;box-sizing:border-box}

/* ---------- rail head ---------------------------------------------------- */
.railhead{display:flex;align-items:center;gap:6px;background:var(--paper-high);
  border:1px solid var(--line);border-radius:12px;padding:5px;box-shadow:var(--shadow)}
.desk[data-rail="mini"] .railhead{display:none}
.rbtn{flex:none;width:34px;height:34px;border-radius:9px;border:1px solid transparent;
  background:transparent;color:var(--ink-faint);display:grid;place-items:center;cursor:pointer;
  transition:background .14s,color .14s}
.rbtn:hover{background:var(--c-wash);color:var(--c-deep)}
.rbtn.on{background:var(--c-wash);color:var(--c-deep);border-color:var(--c-tint)}
.rbtn svg{width:17px;height:17px;fill:none;stroke:currentColor;stroke-width:1.9;
  stroke-linecap:round;stroke-linejoin:round}
.railhead .lbl{font-size:var(--fs-micro);font-weight:600;color:var(--ink-faint);
  margin-inline-end:auto;padding-inline-start:8px;white-space:nowrap}
.desk[data-rail="mini"] .railhead .lbl{display:none}

/* text-size stepper */
.fsx{display:flex;align-items:center;gap:2px;border-inline-start:1px solid var(--line);
  padding-inline-start:5px;margin-inline-start:3px}
.desk[data-rail="mini"] .fsx{border:0;border-top:1px solid var(--line);
  padding:5px 0 0;margin:3px 0 0;flex-direction:column}
.fsx b{font-size:var(--fs-micro);font-weight:700;color:var(--c-deep);
  min-width:1.5em;text-align:center;font-variant-numeric:tabular-nums}
.desk[data-rail="mini"] .fsx b{display:none}

/* ---------- open rail: TOC with position ------------------------------- */
.deskpanels{display:flex;flex-direction:column;gap:var(--s3);overflow:auto;
  min-height:0;scrollbar-width:thin;padding-bottom:4px}
.desk[data-rail="mini"] .deskpanels{display:none}

.dtoc{background:var(--paper-high);border:1px solid var(--line);
  border-radius:var(--radius-lg);box-shadow:var(--shadow);overflow:hidden;flex:none}
.dtoc > h2{font-size:var(--fs-micro);font-weight:700;color:var(--c-deep);
  background:var(--c-wash);border-bottom:1px solid var(--line);padding:9px 15px;
  display:flex;justify-content:space-between;align-items:center}
.dtoc > h2 .of{font-weight:600;opacity:.75}
.dtoc ol{list-style:none;margin:0;padding:6px 0;counter-reset:dt}
.dtoc li{counter-increment:dt}
/* Two columns by default; a third opens only for the entries that carry a session
   range, so the plain tables of contents on other pages are untouched. */
.dtoc a{display:grid;grid-template-columns:1.6em 1fr;gap:9px;align-items:baseline;
  padding:6px 15px;font-size:var(--fs-side);line-height:1.62;color:var(--ink-soft)}
.dtoc a:has(.rng){grid-template-columns:1.6em 1fr auto}
.dtoc a .t{min-width:0;overflow:hidden;text-overflow:ellipsis}
.dtoc a .rng{font-size:var(--fs-micro);color:var(--ink-faint);white-space:nowrap;
  font-variant-numeric:tabular-nums;letter-spacing:0.02em}
.dtoc a:hover .rng,.dtoc a.now .rng{color:var(--c-deep)}
.dtoc a::before{content:counter(dt, persian);font-size:var(--fs-micro);font-weight:600;
  color:var(--c);background:var(--c-wash);border-radius:5px;padding:1px 0;text-align:center}
.dtoc a:hover{background:var(--paper-deep);color:var(--ink);text-decoration:none}
.dtoc a.now{background:var(--c-wash);color:var(--c-deep);font-weight:600;
  box-shadow:inset 2.5px 0 0 var(--c)}
.dtoc a.now::before{background:var(--c);color:var(--paper)}

/* ---------- mini rail: the numbered spine ------------------------------- */
.spine{display:none;flex-direction:column;gap:3px;align-items:center;overflow:auto;
  padding:8px 0;background:var(--paper-high);border:1px solid var(--line);
  border-radius:12px;box-shadow:var(--shadow);scrollbar-width:none}
.spine::-webkit-scrollbar{display:none}
.desk[data-rail="mini"] .spine{display:flex}
.spine a{position:relative;width:30px;height:26px;border-radius:7px;display:grid;
  place-items:center;font-size:var(--fs-micro);font-weight:600;color:var(--ink-faint);
  font-variant-numeric:tabular-nums}
.spine a:hover{background:var(--c-wash);color:var(--c-deep);text-decoration:none}
.spine a.now{background:var(--c);color:var(--paper)}
/* hover reveals the section title without leaving the spine */
.spine a::after{content:attr(data-t);position:absolute;inset-inline-end:calc(100% + 9px);
  top:50%;transform:translateY(-50%) translateX(6px);white-space:nowrap;
  background:var(--ink);color:var(--paper);font-size:var(--fs-micro);font-weight:500;
  padding:5px 11px;border-radius:8px;opacity:0;pointer-events:none;
  transition:opacity .15s,transform .15s;max-width:15rem;overflow:hidden;
  text-overflow:ellipsis;z-index:20;box-shadow:var(--shadow)}
.spine a:hover::after{opacity:1;transform:translateY(-50%) translateX(0)}

/* ---------- reading progress -------------------------------------------- */
.progress{position:sticky;top:var(--chrome-h,0px);z-index:55;height:2.5px;background:var(--line);
  margin-bottom:-2.5px}
.progress i{display:block;height:100%;width:0;background:var(--c);
  transition:width .12s linear}

/* ---------- the reading bar: sticky, between header and text --------------
   Three placements were tried and rejected. A dock pinned to the screen edge read
   as a browser extension bolted onto the page. Inside the سرلوح it scrolled away
   exactly when a long read starts needing it. Floating and centred needed a
   show/hide rule, which meant it was sometimes absent when reached for.

   This is the plain answer: a bar that sits where the reader's eye already goes —
   between the title block and the first line — and then sticks to the top of the
   viewport for the rest of the session. Always there, never in the way, and it
   costs one strip of height instead of hovering over the words. */
.readbar{position:sticky;top:var(--chrome-h,0px);z-index:50;
  display:flex;align-items:center;gap:8px;
  margin:0 0 var(--s4);padding:8px 14px;
  background:color-mix(in oklab, var(--paper) 92%, transparent);
  border:1px solid var(--line);border-radius:12px;
  backdrop-filter:blur(12px) saturate(1.4);-webkit-backdrop-filter:blur(12px) saturate(1.4);
  transition:box-shadow .18s ease, border-color .18s ease}
/* once it has parted from the header it lifts off the page slightly */
.readbar.stuck{border-color:var(--line-strong);
  box-shadow:0 1px 3px rgba(38,33,25,.10), 0 12px 28px -14px rgba(38,33,25,.40)}

.readbar .rb-label{font-size:var(--fs-micro);font-weight:600;color:var(--ink-faint);
  margin-inline-end:auto;white-space:nowrap}
/* the label yields first when space is tight — the controls never wrap */
@media (max-width:34rem){.readbar .rb-label{display:none}}

.rbtn2{width:36px;height:36px;border-radius:9px;border:1px solid transparent;
  background:transparent;color:var(--ink-faint);display:grid;place-items:center;
  cursor:pointer;transition:background .14s,color .14s;flex:none}
.rbtn2:hover{background:var(--c-wash);color:var(--c-deep)}
.rbtn2.on{background:var(--c-wash);color:var(--c-deep);border-color:var(--c-tint)}
.rbtn2:disabled{opacity:.3;cursor:default}
.rbtn2 svg{width:16px;height:16px;fill:none;stroke:currentColor;stroke-width:1.9;
  stroke-linecap:round;stroke-linejoin:round}
/* the A-A size mark is type, so it is filled rather than stroked */
.rmark{width:30px;display:grid;place-items:center;color:var(--ink-faint);flex:none}
.rmark svg{fill:currentColor;stroke:none;width:20px;height:20px}
.readbar .sep{width:1px;height:19px;background:var(--line);margin:0 2px;flex:none}
/* Latin digit: a setting value beside a Latin size mark, not Persian prose */
.readbar .fsn{min-width:1.6em;text-align:center;font:700 12px/1 var(--ff-latin);
  color:var(--c-deep);font-variant-numeric:tabular-nums;direction:ltr}

/* ---------- index / hub pages keep only the theme switch (2026-07-27) ------
   All 58 pages that ship a static `.readbar` are index or hub pages — measured:
   not one of them has a reading column (`.matn-body` / `.prose` / `.matn`). A
   type-size and line-height control on a page with no running text is a control
   over nothing, so those pages keep the page name and the light/dark switch and
   drop the rest. The AA mark and the separators are decoration for controls that
   are no longer there.
   Scoped with `:has()` rather than a flat `.readbar` rule so it corrects itself:
   the moment such a page does gain a reading column the controls come back, and
   on any engine without `:has()` the rule simply does not apply — the failure
   mode is "controls still shown", never "controls wrongly hidden". */
body:not(:has(.matn-body, .prose, .matn)) .readbar :is(
  .rmark, .sep, [data-fs-step], [data-fs-val], [data-lh-step], [data-lh-val]
){display:none}

/* On a phone this bar gets the same 40 px tap target as `.readbar2`, so the two
   toolbars do not disagree about how big a touch control is. The width comes out
   of the decoration, never the controls: `.rmark` is an aria-hidden "AA" glyph,
   the separators are ornamental, and `.fsn`'s 1.6em is desktop alignment padding
   for a value that is always one digit.
   NOTE: this block must stay BELOW the `.rbtn2` / `.rmark` / `.fsn` base rules.
   A media query adds no specificity, so when it sat above them the base
   `width:32px` simply won on document order and the whole block did nothing. */
@media (max-width:34rem){
  .readbar{gap:4px;padding:6px 8px}
  .readbar .rmark{display:none}
  .readbar .sep{display:none}
  .readbar .fsn{min-width:0}
  .rbtn2{width:44px;height:44px}
  .rbtn2 svg{width:18px;height:18px}
}

/* the theme switch joins the other reading settings — it was a lone floating pill
   in the corner, which split one set of controls across two places */
.rbtn2.theme-on .ic-sun{display:none}
.rbtn2 .ic-moon{display:none}
.rbtn2.theme-on .ic-moon{display:block}

@media print{.readbar{display:none!important}}
@media (prefers-reduced-motion:reduce){.readbar{transition:none}}

/* ---------- body measure follows the rail ------------------------------- */
/* The measure grows in step with the reclaimed space, but never past the point
   where a Persian line becomes tiring to track (~52rem ≈ 85 characters). */
.desk .matn{max-width:var(--measure);margin-inline:0}
.desk[data-rail="mini"] .matn{max-width:47rem}
.desk[data-rail="off"] .matn{max-width:52rem;margin-inline:auto}

/* ---------- mobile: the rail becomes a sheet ---------------------------- */
@media (max-width:64rem){
  .desk,.desk[data-rail="mini"],.desk[data-rail="off"]{grid-template-columns:1fr;gap:var(--s4)}
  .deskrail{position:static;max-height:none;opacity:1;pointer-events:auto}
  .desk[data-rail="off"] .deskrail{display:none}
  .desk[data-rail="mini"] .deskpanels{display:flex}
  .desk[data-rail="mini"] .spine{display:none}
  .spine{display:none!important}
  .railpop{inset-inline-start:14px;bottom:16px;top:auto;transform:none}
  .desk .matn,.desk[data-rail="off"] .matn{max-width:none}
  .dtoc{max-height:19rem;display:flex;flex-direction:column}
  .dtoc ol{overflow:auto}
}

@media print{
  .deskrail,.railpop,.progress,.railhead{display:none!important}
  .desk{display:block}
  .desk .matn{max-width:none}
}
@media (prefers-reduced-motion:reduce){
  .desk,.progress i,.spine a::after{transition:none}
}

/* ---------- references index: the entry grid ----------------------------- */
/* layout is [data-view]'s job; these are the reference card's own details */
.refgrid{margin:0 0 var(--s5)}
.rc-n{font-size:var(--fs-side);font-weight:600;color:var(--ink);line-height:1.55}
.rc-m{font-size:var(--fs-micro);color:var(--ink-faint);font-variant-numeric:tabular-nums}
.refcard:hover .rc-n{color:var(--c-deep)}
.h2-count{margin-inline-start:auto;font-size:var(--fs-micro);font-weight:600;
  color:var(--c-deep);background:var(--c-wash);border:1px solid var(--c-tint);
  border-radius:999px;padding:2px 11px;transform:translateY(-3px)}
.matn h2 .h2-count + *{margin:0}
/* the apparatus list reuses .dtoc chrome but keeps its two-line rows */
.appx-in{list-style:none;margin:0;padding:6px 0}
.appx-in a{display:block;padding:7px 15px}
.appx-in a:hover{background:var(--paper-deep);text-decoration:none}
.appx-in .t{display:block;font-size:var(--fs-side);font-weight:600;color:var(--ink)}
.appx-in .m{display:block;font-size:var(--fs-micro);color:var(--ink-faint);
  margin-top:1px;line-height:1.65}


/* ---------- reference sub-groups: no more orphaned labels ----------------
   The archive nests category → sub-group → sub-sub-group («اشخاص» →
   «متفکرین اسلامی و ایرانی» → «حکمت، عرفان و تفسیر»). Rendered as bare headings
   they float between card grids with nothing binding them to what they label.
   Here each sub-group is a bounded band: a tinted strip with a rule that runs to
   the margin and a count chip, and its cards indent under it, so the label
   visibly owns the block beneath it. */
.subgroup{margin:0 0 var(--s4);border-inline-start:2px solid var(--c-tint);
  padding-inline-start:16px}
.subgroup + .subgroup{margin-top:var(--s5)}
.sg-head{display:flex;align-items:center;gap:11px;margin:0 0 11px}
.sg-head .t{font-size:15.5px;font-weight:700;color:var(--c-deep);white-space:nowrap}
.sg-head .rule{flex:1;height:1px;background:var(--line-strong);opacity:.55}
.sg-head .n{flex:none;font-size:var(--fs-micro);font-weight:600;color:var(--c-deep);
  background:var(--c-wash);border:1px solid var(--c-tint);border-radius:999px;padding:2px 10px}
/* third level: quieter, no border, just a small caps-ish label */
.subsub{margin:0 0 var(--s3)}
.subsub + .subsub{margin-top:var(--s4)}
.ss-head{display:flex;align-items:baseline;gap:9px;margin:0 0 8px}
.ss-head .t{font-size:13px;font-weight:600;color:var(--ink-faint);letter-spacing:.01em}
.ss-head .n{font-size:var(--fs-micro);color:var(--ink-faint);opacity:.8}
.ss-head .rule{flex:1;height:1px;background:var(--line);opacity:.7}

/* ---------- فهرست‌های سطری — quieter, more formal than the plate cards -----
   The gate/plate cards were large gradient blocks with the title reversed out of
   a dark field; at 19px on a saturated gradient the Persian title lost contrast
   and the page read as a marketing splash rather than an archive index. These
   rows carry the same information in a fraction of the height: ink on paper for
   the title, the collection colour as a spine and a small chip, the count set as
   a number rather than a display figure. */
.rows{display:flex;flex-direction:column;gap:8px}
/* The box itself wears the collection colour: a wash of it as the fill, a
   stronger cut of the same colour as the border. Flat paper boxes with a 3px
   spine read as lifeless; the wash keeps rows apart at a glance without ever
   competing with the ink. */
.row-item{display:grid;grid-template-columns:3px 4.5rem 1fr auto;gap:16px;align-items:center;
  padding:13px 18px 13px 15px;
  background:color-mix(in srgb, var(--c) 16%, var(--paper-high));
  border:1px solid color-mix(in srgb, var(--c) 24%, var(--paper-high));
  border-radius:12px;transition:background .14s,border-color .14s}
a.row-item:hover{background:color-mix(in srgb, var(--c) 15%, var(--paper-high));
  border-color:color-mix(in srgb, var(--c) 44%, var(--paper-high));text-decoration:none}
.row-item > .spine-i{display:block;width:3px;height:34px;border-radius:2px;background:var(--c)}
.row-item .rt{min-width:0}
.row-item .rt b{display:block;font-size:16px;font-weight:700;color:var(--ink);line-height:1.5}
.row-item .rt span{display:block;font-size:var(--fs-micro);color:var(--ink-faint);
  line-height:1.7;margin-top:1px}
.row-item .rn{text-align:center;white-space:nowrap}
/* A standalone display numeral, not a column of figures: proportional digits with
   a touch of negative tracking sit tight, where tabular spacing splays them apart.
   The small downward nudge seats the numeral toward its «جلسه» label. */
.row-item .rn b{display:block;font-size:20px;font-weight:800;color:var(--c-deep);
  line-height:1;letter-spacing:-.05em;transform:translateY(4px)}
.row-item .rn span{font-size:10.5px;color:var(--ink-faint)}
.row-item .go{font-size:var(--fs-micro);color:var(--c-deep);font-weight:600}
/* ---------- ارقامِ شاخص — stat tiles ----------
   Figures used to sit bare on the paper and read as leftovers. Each one now
   holds a tile: a wash of its colour for the field, a solid bar of it on top,
   the numeral at full depth. Colour here is the spectrum of the archive, one
   collection colour per tile. */
.stat-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));
  gap:9px;margin:26px 0 0}
/* One neutral surface for all four. These are totals about the archive — sessions,
   collections, years, references — not subjects, so colour-coding them said something
   untrue: four different hues implied four different topics. Plain paper, navy figures,
   and the colour system is left to mean what it means everywhere else. */
.stat{padding:13px 16px 12px;border-radius:11px;
  background:var(--paper-mid);border:1px solid var(--line)}
.stat b{display:block;font-size:24px;font-weight:800;color:var(--lajvard-deep);
  line-height:1;letter-spacing:0.02em}
.stat span{display:block;font-size:11.5px;color:var(--ink-soft);margin-top:6px}
/* the per-tile classes stay in the markup and are deliberately inert */
.st-lajvard,.st-zangar,.st-nili,.st-fooladi,.st-boronz{--tc:initial;--tcd:initial}

/* each row carries its own collection colour */
.r-tafsir{--c:var(--lajvard);--c-deep:var(--lajvard-deep);--c-tint:var(--lajvard-tint);--c-wash:var(--lajvard-wash)}
.r-adyan{--c:var(--zangar);--c-deep:var(--zangar-deep);--c-tint:var(--zangar-tint);--c-wash:var(--zangar-wash)}
.r-ravan{--c:var(--nili);--c-deep:var(--nili-deep);--c-tint:var(--nili-tint);--c-wash:var(--nili-wash)}
.r-mawzuat{--c:var(--fooladi);--c-deep:var(--fooladi-deep);--c-tint:var(--fooladi-tint);--c-wash:var(--fooladi-wash)}
.r-sokhan{--c:var(--boronz);--c-deep:var(--boronz-deep);--c-tint:var(--boronz-tint);--c-wash:var(--boronz-wash)}
@media (max-width:34rem){
  .row-item{grid-template-columns:3px 3.2rem 1fr;gap:12px;padding:11px 14px}
  .row-item .go{display:none}
}

/* ---------- سیرِ زمانی in the rail --------------------------------------
   It was a collapsible box in the body first, with its own toggle chevron — a
   second collapse idiom on a site that already has one. Moving it into the rail
   means the hub navigates like every other page: the same باز/تیغه/بسته control
   in the reading bar, the same sticky column, the same spine of numbers when
   narrowed. One pattern, learned once. */
.tl-panel .tl-filter{padding:9px 13px;border-bottom:1px solid var(--line);
  background:var(--paper-mid)}
.tl-panel select{appearance:none;width:100%;font:600 12.5px/1 var(--ff);color:var(--ink);
  background:var(--paper-high);border:1px solid var(--line-strong);border-radius:8px;
  padding:8px 12px 8px 28px;cursor:pointer;
  background-image:linear-gradient(45deg,transparent 50%,var(--ink-faint) 50%),
                   linear-gradient(135deg,var(--ink-faint) 50%,transparent 50%);
  background-position:calc(11px) calc(50% - 1px), calc(16px) calc(50% - 1px);
  background-size:5px 5px,5px 5px;background-repeat:no-repeat}
.tl-panel select:hover{border-color:var(--c-tint)}
.tl-years{list-style:none;margin:0;padding:6px 0;max-height:22rem;overflow:auto;
  scrollbar-width:thin}
.tl-years a{display:block;padding:6px 15px;font-size:var(--fs-side);color:var(--ink-soft);
  font-variant-numeric:tabular-nums}
.tl-years a:hover{background:var(--paper-deep);color:var(--ink);text-decoration:none}
.tl-years a.now{background:var(--c-wash);color:var(--c-deep);font-weight:600;
  box-shadow:inset 2.5px 0 0 var(--c)}
.tl-empty{font-size:var(--fs-side);color:var(--ink-faint);text-align:center;padding:26px 0}
.h2-count.tl-count{font-variant-numeric:tabular-nums}

/* ---------- references index: the entry grid ----------------------------- */
/* layout is [data-view]'s job; these are the reference card's own details */
.refgrid{margin:0 0 var(--s5)}
.rc-n{font-size:var(--fs-side);font-weight:600;color:var(--ink);line-height:1.55}
.rc-m{font-size:var(--fs-micro);color:var(--ink-faint);font-variant-numeric:tabular-nums}
.refcard:hover .rc-n{color:var(--c-deep)}
.h2-count{margin-inline-start:auto;font-size:var(--fs-micro);font-weight:600;
  color:var(--c-deep);background:var(--c-wash);border:1px solid var(--c-tint);
  border-radius:999px;padding:2px 11px;transform:translateY(-3px)}
.matn h2 .h2-count + *{margin:0}
/* the apparatus list reuses .dtoc chrome but keeps its two-line rows */
.appx-in{list-style:none;margin:0;padding:6px 0}
.appx-in a{display:block;padding:7px 15px}
.appx-in a:hover{background:var(--paper-deep);text-decoration:none}
.appx-in .t{display:block;font-size:var(--fs-side);font-weight:600;color:var(--ink)}
.appx-in .m{display:block;font-size:var(--fs-micro);color:var(--ink-faint);
  margin-top:1px;line-height:1.65}


/* ---------- reference sub-groups: no more orphaned labels ----------------
   The archive nests category → sub-group → sub-sub-group («اشخاص» →
   «متفکرین اسلامی و ایرانی» → «حکمت، عرفان و تفسیر»). Rendered as bare headings
   they float between card grids with nothing binding them to what they label.
   Here each sub-group is a bounded band: a tinted strip with a rule that runs to
   the margin and a count chip, and its cards indent under it, so the label
   visibly owns the block beneath it. */
.subgroup{margin:0 0 var(--s4);border-inline-start:2px solid var(--c-tint);
  padding-inline-start:16px}
.subgroup + .subgroup{margin-top:var(--s5)}
.sg-head{display:flex;align-items:center;gap:11px;margin:0 0 11px}
.sg-head .t{font-size:15.5px;font-weight:700;color:var(--c-deep);white-space:nowrap}
.sg-head .rule{flex:1;height:1px;background:var(--line-strong);opacity:.55}
.sg-head .n{flex:none;font-size:var(--fs-micro);font-weight:600;color:var(--c-deep);
  background:var(--c-wash);border:1px solid var(--c-tint);border-radius:999px;padding:2px 10px}
/* third level: quieter, no border, just a small caps-ish label */
.subsub{margin:0 0 var(--s3)}
.subsub + .subsub{margin-top:var(--s4)}
.ss-head{display:flex;align-items:baseline;gap:9px;margin:0 0 8px}
.ss-head .t{font-size:13px;font-weight:600;color:var(--ink-faint);letter-spacing:.01em}
.ss-head .n{font-size:var(--fs-micro);color:var(--ink-faint);opacity:.8}
.ss-head .rule{flex:1;height:1px;background:var(--line);opacity:.7}

/* ---------- فهرست‌های سطری — quieter, more formal than the plate cards -----
   The gate/plate cards were large gradient blocks with the title reversed out of
   a dark field; at 19px on a saturated gradient the Persian title lost contrast
   and the page read as a marketing splash rather than an archive index. These
   rows carry the same information in a fraction of the height: ink on paper for
   the title, the collection colour as a spine and a small chip, the count set as
   a number rather than a display figure. */
.rows{display:flex;flex-direction:column;gap:8px}
/* The box itself wears the collection colour: a wash of it as the fill, a
   stronger cut of the same colour as the border. Flat paper boxes with a 3px
   spine read as lifeless; the wash keeps rows apart at a glance without ever
   competing with the ink. */
.row-item{display:grid;grid-template-columns:3px 4.5rem 1fr auto;gap:16px;align-items:center;
  padding:13px 18px 13px 15px;
  background:color-mix(in srgb, var(--c) 16%, var(--paper-high));
  border:1px solid color-mix(in srgb, var(--c) 24%, var(--paper-high));
  border-radius:12px;transition:background .14s,border-color .14s}
a.row-item:hover{background:color-mix(in srgb, var(--c) 15%, var(--paper-high));
  border-color:color-mix(in srgb, var(--c) 44%, var(--paper-high));text-decoration:none}
.row-item > .spine-i{display:block;width:3px;height:34px;border-radius:2px;background:var(--c)}
.row-item .rt{min-width:0}
.row-item .rt b{display:block;font-size:16px;font-weight:700;color:var(--ink);line-height:1.5}
.row-item .rt span{display:block;font-size:var(--fs-micro);color:var(--ink-faint);
  line-height:1.7;margin-top:1px}
.row-item .rn{text-align:center;white-space:nowrap}
/* A standalone display numeral, not a column of figures: proportional digits with
   a touch of negative tracking sit tight, where tabular spacing splays them apart.
   The small downward nudge seats the numeral toward its «جلسه» label. */
.row-item .rn b{display:block;font-size:20px;font-weight:800;color:var(--c-deep);
  line-height:1;letter-spacing:-.05em;transform:translateY(4px)}
.row-item .rn span{font-size:10.5px;color:var(--ink-faint)}
.row-item .go{font-size:var(--fs-micro);color:var(--c-deep);font-weight:600}
/* each row carries its own collection colour */
.r-tafsir{--c:var(--lajvard);--c-deep:var(--lajvard-deep);--c-tint:var(--lajvard-tint);--c-wash:var(--lajvard-wash)}
.r-adyan{--c:var(--zangar);--c-deep:var(--zangar-deep);--c-tint:var(--zangar-tint);--c-wash:var(--zangar-wash)}
.r-ravan{--c:var(--nili);--c-deep:var(--nili-deep);--c-tint:var(--nili-tint);--c-wash:var(--nili-wash)}
.r-mawzuat{--c:var(--fooladi);--c-deep:var(--fooladi-deep);--c-tint:var(--fooladi-tint);--c-wash:var(--fooladi-wash)}
.r-sokhan{--c:var(--boronz);--c-deep:var(--boronz-deep);--c-tint:var(--boronz-tint);--c-wash:var(--boronz-wash)}
@media (max-width:34rem){
  .row-item{grid-template-columns:3px 3.2rem 1fr;gap:12px;padding:11px 14px}
  .row-item .go{display:none}
}

/* ---------- سیرِ زمانی — the collapsible, filterable timeline -------------- */
.timeline-box{border:1px solid var(--line);border-radius:16px;background:var(--paper-high);
  box-shadow:var(--shadow);overflow:hidden;margin-top:var(--s4)}
.tl-bar{display:flex;align-items:center;gap:14px;padding:13px 18px;
  background:var(--paper-mid);border-bottom:1px solid var(--line);flex-wrap:wrap}
.tl-toggle{display:flex;align-items:center;gap:9px;background:none;border:0;padding:0;
  cursor:pointer;font:700 16px/1.5 var(--ff);color:var(--ink)}
.tl-toggle .chev{width:20px;height:20px;display:grid;place-items:center;color:var(--c-deep);
  transition:transform .2s ease}
.tl-toggle .chev svg{width:13px;height:13px;fill:none;stroke:currentColor;stroke-width:2.2;
  stroke-linecap:round;stroke-linejoin:round}
.timeline-box[data-open="false"] .tl-toggle .chev{transform:rotate(-90deg)}
.tl-count{font-size:var(--fs-micro);font-weight:600;color:var(--ink-faint);
  font-variant-numeric:tabular-nums}
.tl-pick{margin-inline-start:auto;position:relative}
.tl-pick select{appearance:none;font:600 13px/1 var(--ff);color:var(--ink);
  background:var(--paper-high);border:1px solid var(--line-strong);border-radius:9px;
  padding:9px 34px 9px 14px;cursor:pointer;min-width:13rem}
.tl-pick select:hover{border-color:var(--c-tint)}
.tl-pick::after{content:"";position:absolute;inset-inline-start:13px;top:50%;
  width:7px;height:7px;border-inline-end:1.8px solid var(--ink-faint);
  border-block-end:1.8px solid var(--ink-faint);transform:translateY(-70%) rotate(45deg);
  pointer-events:none}
.tl-body{padding:20px 22px 22px;max-height:none;overflow:hidden}
.timeline-box[data-open="false"] .tl-body{display:none}
.tl-empty{font-size:var(--fs-side);color:var(--ink-faint);text-align:center;padding:26px 0}
@media (max-width:34rem){
  .tl-bar{gap:10px}
  .tl-pick{margin-inline-start:0;width:100%}
  .tl-pick select{width:100%}
}

/* ---------- نما: سطری یا موزاییکی ----------------------------------------
   One switch governs every index on the site. Rows are the default because a
   long index is read by scanning down a single column of names — the eye makes
   one pass, and each row has room for the metadata (session count, year, chapter
   count) that a tile has to drop. The mosaic stays available: for the reference
   index at 127 entries, and for the Bible's 66 books, seeing many names at once
   is genuinely faster once you know what you are looking for.

   Both views are the SAME markup. The container carries data-view and the items
   re-flow; nothing is duplicated, so the two can never drift apart. */

/* ── list view (default) ── */
[data-view="list"]{display:flex;flex-direction:column;gap:5px}
[data-view="list"] > *{display:grid;grid-template-columns:1fr auto;gap:14px;
  align-items:center;padding:9px 15px;
  background:color-mix(in srgb, var(--c) 16%, var(--paper-high));
  border:1px solid color-mix(in srgb, var(--c) 22%, var(--paper-high));
  border-radius:9px;min-height:0}
[data-view="list"] > *:hover{background:color-mix(in srgb, var(--c) 14%, var(--paper-high));
  border-color:color-mix(in srgb, var(--c) 42%, var(--paper-high))}
/* the name stays on one line and truncates rather than wrapping the row open */
[data-view="list"] .rc-n,[data-view="list"] .bk-n,[data-view="list"] .nz-nm{
  font-size:14.5px;font-weight:600;color:var(--ink);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
[data-view="list"] .rc-m,[data-view="list"] .bk-c,[data-view="list"] .nz-v{
  font-size:var(--fs-micro);color:var(--ink-faint);white-space:nowrap;
  font-variant-numeric:tabular-nums}
/* nazm rows keep their numeral in a third column */
[data-view="list"] .nz-s{grid-template-columns:auto 1fr auto}

/* ── mosaic view ── */
[data-view="grid"]{display:grid;gap:7px;
  grid-template-columns:repeat(auto-fill,minmax(var(--tile,186px),1fr))}
[data-view="grid"] > *{display:flex;flex-direction:column;gap:3px;padding:10px 13px;
  background:color-mix(in srgb, var(--c) 16%, var(--paper-high));
  border:1px solid color-mix(in srgb, var(--c) 22%, var(--paper-high));border-radius:10px}
[data-view="grid"] > *:hover{background:color-mix(in srgb, var(--c) 14%, var(--paper-high));
  border-color:color-mix(in srgb, var(--c) 42%, var(--paper-high))}
[data-view="grid"] .nz-s{display:grid;grid-template-columns:auto 1fr auto;
  gap:10px;align-items:center}

[data-view] > *{text-decoration:none;transition:background .14s,border-color .14s}
[data-view] > *:hover{text-decoration:none}

/* ── the switch itself ── */
.viewsw{display:inline-flex;gap:3px;padding:3px;background:var(--paper-high);
  border:1px solid var(--line);border-radius:9px}
.viewsw button{width:30px;height:26px;border-radius:6px;border:1px solid transparent;
  background:transparent;color:var(--ink-faint);display:grid;place-items:center;cursor:pointer;
  transition:background .14s,color .14s}
.viewsw button:hover{color:var(--ink)}
.viewsw button.on{background:var(--c-wash);color:var(--c-deep);border-color:var(--c-tint)}
.viewsw svg{width:15px;height:15px;fill:none;stroke:currentColor;stroke-width:1.9;
  stroke-linecap:round;stroke-linejoin:round}
@media (max-width:34rem){
  /* below this width the mosaic is a single column anyway, so the switch is noise */
  .viewsw{display:none}
  [data-view="grid"]{display:flex;flex-direction:column;gap:5px}
}

/* ── the chronology's filter, now a bar above it rather than a rail beside it ── */
.tl-bar2{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin:0 0 var(--s3);
  padding:10px 15px;background:var(--paper-high);border:1px solid var(--line);
  border-radius:12px}
.tl-bar2 .lbl{font-size:var(--fs-micro);font-weight:700;color:var(--c-deep)}
.tl-bar2 .tl-pick{font:600 12.5px/1 var(--ff);color:var(--ink);background:var(--paper);
  border:1px solid var(--line-strong);border-radius:8px;padding:8px 12px;cursor:pointer}
.tl-bar2 .tl-count{margin-inline-start:auto;font-size:var(--fs-micro);color:var(--ink-faint)}

/* ============================================================================
   reader-fix 2026-07-28 — CSS generalisation for three markup families
   desk.js already targets .matn-body / .prose / .matn and writes data-rail on
   .matn-wrap OR the column's parent (.wrap). These rules close the CSS gap only.
   COLOUR and SHOW/HIDE only. font-size / line-height of ayah are LOCKED above.
   ========================================================================= */

/* --- 2-1 · تیغه: default hidden; mini shows it (both containers) --------
   Previously only `.matn-wrap[data-rail="mini"] .toc-spine` existed, and only
   inside surah/styles.css — the 101 `.prose` pages (container `.wrap`, no
   surah/styles) always painted the spine under the open list. */
.toc-spine{display:none;flex-direction:column;gap:3px;align-items:center;
  overflow:auto;padding:8px 0;scrollbar-width:none}
.toc-spine::-webkit-scrollbar{display:none}
.matn-wrap[data-rail="mini"] .toc-spine,
.wrap[data-rail="mini"] .toc-spine{display:flex}
/* mini hides the full list on .wrap the same way .matn-wrap already does */
.wrap[data-rail="mini"] .toc-panel > h2,
.wrap[data-rail="mini"] .toc-list{display:none}
.toc-spine a{position:relative;width:28px;height:25px;border-radius:7px;display:grid;
  place-items:center;font-size:.72rem;font-weight:600;color:var(--ink-faint);
  text-decoration:none;font-variant-numeric:tabular-nums}
.toc-spine a:hover{background:var(--paper-deep);color:var(--ink)}
.toc-spine a.now{background:var(--c,var(--navy,#15294e));color:var(--paper)}
.toc-spine a::after{content:attr(data-t);position:absolute;inset-inline-end:calc(100% + 8px);
  top:50%;transform:translateY(-50%) translateX(6px);white-space:nowrap;
  background:var(--ink);color:var(--paper);font-size:.74rem;font-weight:500;padding:5px 10px;
  border-radius:7px;opacity:0;pointer-events:none;transition:opacity .15s,transform .15s;
  max-width:16rem;overflow:hidden;text-overflow:ellipsis;z-index:30}
.toc-spine a:hover::after{opacity:1;transform:translateY(-50%) translateX(0)}

/* --- 2-2 · text columns take theme tokens, never a fixed white ----------
   .matn-body already looked fine because it sat on a tokenised page ground;
   .prose did not declare ink/paper of its own. Explicit tokens on all three
   families make the contract visible and keep dark/sepia coherent. */
.prose,
.matn-body,
.matn{
  color:var(--ink);
  background-color:var(--paper);
}
/* Inline page styles hardcode light chrome on .toc-panel / .toc-list a /
   details.refblock (white cards on a dark page). Colour-only override; no
   layout change. :root[data-theme] outranks the unthemed inline selectors. */
:root[data-theme="dark"] .toc-panel,
:root[data-theme="sepia"] .toc-panel{
  background:var(--paper-high)!important;
  border-color:var(--line)!important;
  color:var(--ink)!important;
}
:root[data-theme="dark"] .toc-panel h2,
:root[data-theme="sepia"] .toc-panel h2{color:var(--c-deep,var(--ink))!important}
:root[data-theme="dark"] .toc-list a,
:root[data-theme="sepia"] .toc-list a{
  background:var(--paper)!important;
  border-color:var(--line)!important;
  color:var(--ink-soft)!important;
}
:root[data-theme="dark"] .toc-list a:hover,
:root[data-theme="sepia"] .toc-list a:hover,
:root[data-theme="dark"] .toc-list a.now,
:root[data-theme="sepia"] .toc-list a.now{
  background:var(--paper-deep)!important;
  color:var(--ink)!important;
}
:root[data-theme="dark"] details.refblock,
:root[data-theme="sepia"] details.refblock{
  background:var(--paper-high)!important;
  border-color:var(--line)!important;
  color:var(--ink)!important;
}
:root[data-theme="dark"] details.refblock > summary,
:root[data-theme="sepia"] details.refblock > summary{color:var(--ink)!important}

/* --- 2-3 · ayah boxes: theme-aware COLOUR only ---------------------------
   Six classes had zero theme-aware rules. Inline pages pin fixed hex, and on
   almizan the inline gradient is often broken — cream text then sits on cream
   paper in sepia. Restore a navy/gold card and token ink for the quran-block
   family. font-size and line-height are deliberately NOT restated (locked by
   the :root .ay-ar / .ay-fa pins and the page's own 22px/16px rules). */
:root .ayah-box{
  background:
    radial-gradient(120% 80% at 50% -10%, color-mix(in srgb, var(--zar,#B08434) 16%, transparent), transparent 60%),
    var(--navy, var(--c-deep, #15294e)) !important;
  color:var(--paper, #fbf6ec) !important;
}
:root .ay-ar{color:#fdf7ea !important}   /* cream on navy — intentional; size untouched */
:root .ay-fa{color:#dee2ed !important}

:root .quran-block,
:root .matn-body .quran-block,
:root .prose .quran-block{
  background:var(--zar-wash) !important;
  border-color:var(--zar-line) !important;
  color:var(--ink);
}
:root .quran-ar,
:root .matn-body .quran-ar,
:root .prose .quran-ar,
:root .ayah-ar{color:var(--ink) !important}
:root .quran-fa,
:root .matn-body .quran-fa,
:root .prose .quran-fa,
:root .ayah-fa{color:var(--ink-soft) !important}
:root .quran-label,
:root .matn-body .quran-label,
:root .prose .quran-label{color:var(--zar-deep, var(--zar, #6B4E18)) !important}
:root .quran-meta,
:root .matn-body .quran-meta,
:root .prose .quran-meta{
  color:var(--ink-soft) !important;
  border-top-color:var(--zar-line) !important;
}
:root .ayah{
  background:var(--zar-wash);
  border-color:var(--zar-line);
}
