/* ==========================================================================
   القرآن الكريم — reader
   Blue + gold theme, left control rail, mushaf sheets
   ========================================================================== */

/* ── KFGQPC mushaf typefaces ───────────────────────────────────────────────
   The two Quran faces are QCF V1 and V2, page fonts with one file per mushaf
   page (public/fonts/v1, public/fonts/v2). A page's font is registered from
   JavaScript as it is needed — 604 @font-face rules per version would mean
   604 rules the browser has to keep, and only a handful are ever used.
   Only the ornamental surah-header face is global. */

@font-face {
  font-family: 'QCF Surah Names';
  src: url(../fonts/sura-names.woff2) format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: block;
}

:root {
  --primary:       #1a6fa3;
  --primary-dark:  #145a87;
  --primary-light: #2d8cc4;
  --primary-soft:  rgba(26, 111, 163, 0.10);

  --gold:      #c9a84c;

  --bg:          #eef4fa;
  --surface:     #ffffff;
  --surface-2:   #f5f9fd;
  --paper:       #fffdf7;

  --text:      #16283a;
  --text-mute: #6a869b;
  --on-dark:   #ffffff;

  --line:      #dce8f2;

  --sh-1: 0 1px 2px rgba(20, 60, 95, 0.06);
  --sh-2: 0 4px 16px rgba(20, 60, 95, 0.10);
  --sh-3: 0 12px 40px rgba(15, 55, 90, 0.18);

  /* The width two facing pages need. CSS cannot read a custom property inside
     a media query, so this is stated twice on purpose: the @media below must
     use the same number. JS reads this one to decide when to drop a spread. */
  --spread-min: 900px;

  /* The lane kept clear beside the page for the turn buttons. It is padding on
     the scroll container, not a number subtracted from the type size, so the
     page cannot reach into it however it is sized or zoomed. */
  --turn-lane: 96px;

  --rail-w:    62px;
  --sidebar-w: 280px;
  --r-sm: 8px;
  --r-md: 12px;
  --r-lg: 18px;

  --arabic-font:  "Amiri", serif;
  --display-font: "Reem Kufi", "Amiri", serif;
  --ui-font:      "Inter", system-ui, -apple-system, sans-serif;

  --quran-scale: 1;
  /* What the height bound is allowed to grow by. One page scrolls, so zoom may
     carry it past the screen; two facing pages have nowhere to scroll, so the
     spread is pinned to a fit and zoom stops once the page fills the screen. */
  --fit-scale: var(--quran-scale);
  --quran-stroke: 0;
  /* Width of a sheet's text block at 100%. Zoom scales it. */
  --page-measure: 620px;
  /* A sheet's padding, and everything it takes vertically besides its lines
     (padding, footer, gap). Kept tight: every pixel here is a pixel of type
     the reader does not get. Both feed the page fit. */
  /* One size for the running head and the folio, so top and bottom match. */
  --folio-size: 0.95rem;
  --sheet-pad-x: 26px;
  --sheet-pad-t: 12px;
  --sheet-pad-b: 6px;
  --sheet-chrome: 92px;
  --screen-h: 100dvh;
  /* A line's height, as a multiple of the type size, and the mushaf's line
     grid. The grid is fixed at 15: the framed opening spread has only 8 lines
     but is set in the same type, so it must not be sized off its own count. */
  --m-line-ratio: 1.92;
  --m-grid: 15;

  --ease: cubic-bezier(0.4, 0, 0.2, 1);
  --t: 0.18s var(--ease);
}

body.dark-mode {
  --primary:       #3f9bd1;
  --primary-dark:  #2d8cc4;
  --primary-light: #63b4e2;
  --primary-soft:  rgba(99, 180, 226, 0.14);

  --gold:      #d9b95f;

  --bg:        #0a141d;
  --surface:   #101d29;
  --surface-2: #142433;
  --paper:     #111f2c;

  --text:      #e3edf5;
  --text-mute: #7c9ab0;

  --line:      #1d3143;

  --sh-1: 0 1px 2px rgba(0, 0, 0, 0.35);
  --sh-2: 0 4px 16px rgba(0, 0, 0, 0.40);
  --sh-3: 0 12px 40px rgba(0, 0, 0, 0.55);
}

* { box-sizing: border-box; margin: 0; padding: 0; }

html, body { height: 100%; overflow: hidden; }

body {
  font-family: var(--ui-font);
  background: var(--bg);
  color: var(--text);
  -webkit-font-smoothing: antialiased;
}

/* The dimmer for night reading. It cannot touch the device backlight, so it
   lays a veil over everything instead — rail, index and panels included, not
   just the page. A veil rather than a filter on purpose: `filter` makes its
   element a containing block for fixed children, which knocks the panels off
   the viewport edge. This costs no layout at all. */
/* The canvas colour is taken from here, not propagated up from body — that
   propagation is what let an undimmed strip show through behind the app. */
html { background: var(--bg); }

html::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 9999;
  pointer-events: none;
  background: #000;
  opacity: calc(1 - var(--page-brightness, 1));
  transition: opacity var(--t);
}

[hidden] { display: none !important; }

/* Keyboard focus was invisible everywhere: the reset removed the browser's
   outline and nothing replaced it. Only :focus-visible, so a mouse click does
   not leave a ring behind. */
:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
  border-radius: var(--r-sm);
}

.page-ribbon:focus-visible { outline-offset: -2px; }

body[data-lang="ar"] .lang-en { display: none !important; }
body[data-lang="en"] .lang-ar { display: none !important; }

.ic {
  width: 20px;
  height: 20px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
  flex-shrink: 0;
}

/* #app is RTL in both languages, so the rail always sits on the right */
#app {
  display: flex;
  height: 100dvh;
  direction: rtl;
}

/* --- sidebar handle ---
   A tab on the sidebar's outer edge that opens and closes it. It rides the
   edge: `right` follows the sidebar's width, so it slides with it and stays
   reachable when the index is shut. */

#sidebar-handle {
  position: fixed;
  top: 50%;
  right: calc(var(--rail-w) + var(--sidebar-w));
  transform: translateY(-50%);
  z-index: 170;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 74px;
  padding: 0;
  border: 1px solid var(--line);
  border-right: none;
  border-radius: var(--r-sm) 0 0 var(--r-sm);
  background: var(--surface);
  color: var(--text-mute);
  cursor: pointer;
  box-shadow: -2px 0 8px rgba(20, 60, 95, 0.08);
  transition: right var(--t), color var(--t), background var(--t), transform var(--t);
}

/* Scaled rather than widened: animating width relays out the page on every
   frame of the hover, and this sits beside the whole reading area. */
#sidebar-handle:hover {
  color: var(--primary);
  background: var(--surface-2);
  transform: translateY(-50%) scaleX(1.35);
}
#sidebar-handle .ic { width: 14px; height: 14px; transition: transform var(--t); }

/* Shut: the tab sits against the rail, and its chevron turns to point the
   way it will open. */
#sidebar.hidden ~ #sidebar-handle { right: var(--rail-w); }
#sidebar.hidden ~ #sidebar-handle .ic { transform: rotate(180deg); }

/* ==========================================================================
   Left rail
   ========================================================================== */

/* Never a scroll container: the tooltips sit outside the rail, and any
   overflow other than visible would clip them. */
#rail {
  width: var(--rail-w);
  flex-shrink: 0;
  background: var(--surface);
  border-left: 1px solid var(--line);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 12px 0 14px;
  /* Above the sidebar, the overlay and the panels. The rail sits beside all of
     them so they never overlap, but its tooltips reach out over them — and a
     z-index here makes this a stacking context, so the tooltips can climb no
     higher than the rail itself. It also keeps the buttons clickable while a
     panel's overlay is up. */
  z-index: 210;
}

.rail-btn {
  position: relative;
  width: 40px;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: none;
  border-radius: var(--r-md);
  color: var(--text-mute);
  cursor: pointer;
  transition: background var(--t), color var(--t), transform var(--t);
}

.rail-btn:hover {
  background: var(--primary-soft);
  color: var(--primary);
  transform: translateY(-1px);
}

.rail-btn:active { transform: translateY(0) scale(0.94); }

.rail-btn.on {
  background: var(--primary);
  color: var(--on-dark);
}

.rail-btn.sm { width: 34px; height: 34px; }
.rail-btn.sm .ic { width: 16px; height: 16px; }

.rail-btn.txt {
  font-family: var(--ui-font);
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.04em;
}

/* tooltip */
.rail-btn::after {
  content: attr(data-tip);
  position: absolute;
  right: calc(100% + 10px);
  top: 50%;
  transform: translateY(-50%) scale(0.96);
  padding: 5px 10px;
  border-radius: var(--r-sm);
  background: var(--text);
  color: var(--bg);
  font-size: 0.72rem;
  font-family: var(--ui-font);
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--t), transform var(--t);
  z-index: 60;
}

.rail-btn:hover::after { opacity: 1; transform: translateY(-50%) scale(1); }

.rail-sep {
  width: 22px;
  height: 1px;
  background: var(--line);
  margin: 6px 0;
}

.rail-spacer { flex: 1; }

/* A readout, not a control — the + and - either side of it do the work. */
#font-level {
  font-size: 0.62rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--text-mute);
  user-select: none;
}

/* like the language button, the theme button shows what you switch to */
body.light-mode .ic-sun  { display: none; }
body.dark-mode  .ic-moon { display: none; }

/* ==========================================================================
   Surah index
   ========================================================================== */

#sidebar {
  width: var(--sidebar-w);
  flex-shrink: 0;
  background: var(--surface-2);
  border-left: 1px solid var(--line);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  transition: width var(--t), opacity var(--t);
}

#sidebar.hidden { width: 0; opacity: 0; }

body[data-lang="ar"] #sidebar { direction: rtl; }

#sidebar-header {
  padding: 12px;
  flex-shrink: 0;
  border-bottom: 1px solid var(--line);
}

.search-wrap {
  position: relative;
  display: flex;
  align-items: center;
}

.search-ic {
  position: absolute;
  inset-inline-start: 10px;
  width: 15px;
  height: 15px;
  color: var(--text-mute);
  pointer-events: none;
}

#surah-search {
  width: 100%;
  padding: 7px 12px;
  padding-inline-start: 32px;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface);
  color: var(--text);
  font-size: 0.85rem;
  font-family: var(--ui-font);
  outline: none;
  transition: border-color var(--t), box-shadow var(--t);
}

#surah-search:focus {
  border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-soft);
}

#surah-list {
  flex: 1;
  overflow-y: auto;
  padding: 6px 8px 20px;
  overscroll-behavior: contain;
  /* LTR here parks the index scrollbar against the rail, so it does not end
     up shoulder to shoulder with the reading scrollbar */
  direction: ltr;
  scrollbar-width: thin;
  scrollbar-color: rgba(26, 111, 163, 0.22) transparent;
}

body[data-lang="ar"] #surah-list > * { direction: rtl; }

#surah-list::-webkit-scrollbar { width: 8px; }
#surah-list::-webkit-scrollbar-track { background: transparent; }
#surah-list::-webkit-scrollbar-thumb {
  background: rgba(26, 111, 163, 0.22);
  border-radius: 99px;
  border: 2px solid transparent;
  background-clip: content-box;
}
#surah-list::-webkit-scrollbar-thumb:hover {
  background: rgba(26, 111, 163, 0.45);
  background-clip: content-box;
}

body.dark-mode #surah-list { scrollbar-color: rgba(99, 180, 226, 0.24) transparent; }
body.dark-mode #surah-list::-webkit-scrollbar-thumb {
  background: rgba(99, 180, 226, 0.24);
  background-clip: content-box;
}

.juz-group { margin-bottom: 2px; }

.juz-label {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 8px 6px;
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-mute);
  user-select: none;
}

.juz-label::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--line);
}

.surah-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 7px 9px;
  border-radius: var(--r-md);
  cursor: pointer;
  transition: background var(--t), color var(--t);
}

.surah-item:hover { background: var(--primary-soft); }

.surah-item.active {
  background: var(--primary);
  color: var(--on-dark);
  box-shadow: var(--sh-1);
}

.surah-num {
  width: 25px;
  height: 25px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  border-radius: 50%;
  background: var(--surface);
  border: 1px solid var(--line);
  color: var(--text-mute);
  font-size: 0.66rem;
  font-weight: 600;
}

.surah-item.active .surah-num {
  background: rgba(255, 255, 255, 0.18);
  border-color: transparent;
  color: var(--on-dark);
}

.surah-names { flex: 1; min-width: 0; }

.surah-name-ar {
  display: block;
  font-family: var(--arabic-font);
  font-size: 1.02rem;
  line-height: 1.3;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.surah-name-en {
  display: block;
  font-size: 0.65rem;
  color: var(--text-mute);
}

.surah-item.active .surah-name-en { color: rgba(255, 255, 255, 0.75); }

.surah-ayahs-count {
  font-size: 0.63rem;
  color: var(--text-mute);
  flex-shrink: 0;
  font-variant-numeric: tabular-nums;
}

.surah-item.active .surah-ayahs-count { color: rgba(255, 255, 255, 0.7); }

/* ==========================================================================
   Reading surface
   ========================================================================== */

#content-area {
  flex: 1;
  min-width: 0;
  padding-inline: var(--turn-lane);
  direction: ltr;          /* keeps the scrollbar on the right edge */
  overflow-y: auto;
  /* Reserved on both sides, so the page stays centred in the box the turners
     are centred in — otherwise the scrollbar pushes it off by its own width
     and the two gaps come out uneven. It also stops the page shifting when a
     scrollbar appears. */
  scrollbar-gutter: stable both-edges;
  overflow-x: hidden;
  background: var(--bg);
  scroll-behavior: smooth;
  overscroll-behavior: contain;
}

/* The scrollbar is styled through the WebKit pseudo-elements only. Setting
   scrollbar-width/-color as well would make Chrome fall back to its own
   renderer and ignore the width below. */

/* Only while a drag is actually running — a permanent grab cursor over the
   whole page reads as "this is draggable" at every moment, which is noise. */
#content-area.dragging { cursor: grabbing; user-select: none; }

/* Held through the glide as well: per-frame scrolling and smooth scrolling
   fight each other. */
#content-area.free { scroll-behavior: auto; }

#content-area::-webkit-scrollbar { width: 14px; }
#content-area::-webkit-scrollbar-track { background: transparent; }
#content-area::-webkit-scrollbar-thumb {
  background: rgba(26, 111, 163, 0.38);
  border-radius: 99px;
  border: 3px solid transparent;
  background-clip: content-box;
  min-height: 44px;
}
#content-area::-webkit-scrollbar-thumb:hover { background: rgba(26, 111, 163, 0.62); background-clip: content-box; }
#content-area::-webkit-scrollbar-thumb:active { background: var(--primary); background-clip: content-box; }

body.dark-mode #content-area::-webkit-scrollbar-thumb {
  background: rgba(99, 180, 226, 0.40);
  background-clip: content-box;
}
body.dark-mode #content-area::-webkit-scrollbar-thumb:hover {
  background: rgba(99, 180, 226, 0.66);
  background-clip: content-box;
}

/* Only the splash. #reading-area must keep the ltr it inherits from
   #content-area: the spread lays its leaves out with row-reverse, which
   resolves against this direction, so flipping it swaps the two pages — and
   with them the gutter, the page thickness and the ribbon. */
body[data-lang="ar"] #welcome-screen { direction: rtl; }

/* Kept out of flow; it only defines the icon symbols. */
#icon-sprite { position: absolute; }

/* --- the opening screen ---
   Held only while the index and page layout load, then a surah opens over it.
   Styled so that moment looks like the mushaf, not like a blank page. */

#welcome-screen {
  min-height: calc(var(--screen-h) - 40px);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
}

.welcome-card {
  max-width: 460px;
  padding: 40px 44px 34px;
  text-align: center;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: var(--sh-2);
  animation: welcome-in 0.5s var(--ease) both;
}

.welcome-bismillah {
  font-family: var(--arabic-font);
  font-size: 1.9rem;
  line-height: 1.9;
  color: var(--primary);
  direction: rtl;
}

.welcome-card h1 {
  margin: 0;
  font-family: var(--display-font);
  font-size: 1.5rem;
  font-weight: 500;
  color: var(--text);
}

.welcome-card p {
  margin: 6px 0 0;
  font-size: 0.9rem;
  color: var(--text-mute);
}

/* A gold rule broken by a star, as a mushaf divides its headings. */
.orn-divider {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 6px 0 14px;
  color: var(--gold);
}
.orn-divider::before,
.orn-divider::after {
  content: "";
  flex: 1;
  height: 1px;
  background: linear-gradient(to right, transparent, var(--gold), transparent);
}
.orn-divider span { font-size: 0.85rem; line-height: 1; }

.welcome-dots { display: flex; justify-content: center; gap: 6px; margin-top: 20px; }
.welcome-dots i {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--primary);
  animation: welcome-dot 1.1s ease-in-out infinite;
}
.welcome-dots i:nth-child(2) { animation-delay: 0.15s; }
.welcome-dots i:nth-child(3) { animation-delay: 0.3s; }

.welcome-retry {
  margin-top: 18px;
  padding: 8px 20px;
  border: none;
  border-radius: var(--r-sm);
  background: var(--primary);
  color: var(--on-dark);
  font: inherit;
  font-size: 0.88rem;
  cursor: pointer;
}
.welcome-retry:hover { background: var(--primary-dark); }

@keyframes welcome-in { from { opacity: 0; transform: translateY(8px); } }
@keyframes welcome-dot { 0%, 100% { opacity: 0.25; } 50% { opacity: 1; } }

@media (prefers-reduced-motion: reduce) {
  .welcome-card, .welcome-dots i { animation: none; }
}

/* --- pages --- */

#reading-area {
  max-width: 100%;
  margin: 0 auto;
  padding: 8px 20px 56px;
}

#ayahs-container {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;

  /* 100cqw below resolves against this box's width. */
  container-type: inline-size;
}

.page-section {
  position: relative;
  width: 100%;

  /* Type size for this sheet — the smallest of the three things that bound it:

       zoom   the size the reader asked for: a line is --m-base ems wide (from
              the data, one scale for the whole mushaf), so the wanted measure
              divided by it is the size.
       width  the same, against the width actually on screen. This is the cap
              that used to be missing, which let lines run past the sheet.
       height one whole page on screen at 100%; zoom multiplies it.

     The 13px floor guards only the height bound: on a very short window it
     would otherwise shrink the type past reading size, and a page that scrolls
     beats one that cannot be read. It sits inside the min() so the width bound
     still overrides it — a line that does not fit across the screen cannot be
     drawn any larger, floor or no floor. */
  --m-size: min(
    var(--page-measure) * var(--quran-scale) / var(--m-base, 15.98),
    (100cqw / var(--m-cols, 1) - var(--sheet-pad-x) * 2) / var(--m-base, 15.98),
    max(
      (var(--screen-h) - var(--sheet-chrome)) * var(--fit-scale, 1)
        / (var(--m-grid) * var(--m-line-ratio)),
      13px
    )
  );

  max-width: calc(var(--m-size) * var(--m-base, 15.98) + var(--sheet-pad-x) * 2);
  flex: 0 1 auto;

  padding: var(--sheet-pad-t) var(--sheet-pad-x) var(--sheet-pad-b);
  border-radius: var(--r-lg);
  /* clips the corner banner to the sheet's rounded edge */
  overflow: hidden;
  background: var(--paper);
  border: 1px solid var(--line);
  box-shadow: var(--sh-2);
  /* A turned page lands at the top of the screen, clear by the same margin the
     reading area leaves above it. */
  scroll-margin-top: 8px;
}

/* --- running head: juz, surah, folio ---
   Built like the footer: labels with a fading rule filling the space between
   them, so top and bottom of the sheet read as one frame. */

.page-head {
  /* The sheet sits in an LTR scroller, so the head sets its own direction.
     A grid rather than a flex row, so the name is centred on the sheet and not
     merely between its neighbours. */
  direction: rtl;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 10px;
  margin-bottom: 3px;
}

.ph-juz  { justify-self: start; }
.ph-page { justify-self: end; }

/* --- bookmark ribbon ---
   A banner across the top corner at 45 degrees, clipped by the sheet so it
   ends flush with the rounded edge. It lives in the corner the running head
   leaves free, costs no page height, and never reaches the type. */

.page-ribbon {
  position: absolute;
  top: 9px;
  left: -28px;
  width: 86px;
  height: 16px;
  padding: 0;
  border: none;
  cursor: pointer;
  z-index: 2;
  transform: rotate(-45deg);
  background: linear-gradient(90deg, var(--primary-light), var(--primary) 55%, var(--primary-dark));
  opacity: 0.3;
  transition: opacity var(--t);
}

.page-ribbon:hover { opacity: 0.85; }

.page-section.saved .page-ribbon {
  opacity: 1;
  box-shadow: 0 1px 5px rgba(26, 111, 163, 0.45);
}

/* --- the mushaf sheet ---------------------------------------------------- */

.mushaf {
  --m-line-h: calc(var(--m-line-ratio) * 1em);
  direction: rtl;
  font-size: var(--m-size);
  color: var(--text);
  -webkit-text-stroke: var(--quran-stroke) currentColor;
  margin-bottom: 2px;

  /* Every line is one line tall, so the sheet is simply its line count. The
     shell keeps that height with no lines in it, so the scroll holds when a
     page is dropped. */
  min-height: calc(var(--m-lines, 15) * var(--m-line-h));

  contain: layout style;
}

/* Until the page's font is registered the glyph codes would show as tofu, so
   the lines are held invisible — still taking their space, so nothing jumps. */
.mushaf .m-line { visibility: hidden; }
.mushaf.ready .m-line { visibility: visible; }

/* A page that cannot be drawn says so. Blank sheets are the one outcome worth
   avoiding: the fonts are not in git, so a checkout that skipped the fetch
   would otherwise show nothing and explain nothing. */
.mushaf.font-missing,
.mushaf.failed { position: relative; }

.mushaf.font-missing::after,
.mushaf.failed::after {
  content: "خط هذه الصفحة غير موجود — شغّل npm run fetch:fonts";
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 24px;
  font-family: var(--ui-font);
  font-size: 0.82rem;
  line-height: 1.7;
  text-align: center;
  color: var(--text-mute);
}

body[data-lang="en"] .mushaf.font-missing::after {
  content: "This page's font is missing — run npm run fetch:fonts";
}

.mushaf.failed::after { content: "تعذّر رسم هذه الصفحة — أعد التحميل"; }
body[data-lang="en"] .mushaf.failed::after {
  content: "This page could not be drawn — reload";
}

.m-line {
  display: flex;
  align-items: baseline;
  /* Flush both margins: the leftover space goes between the words. V2 needs
     almost none of this — it draws its lines to the full measure already. */
  justify-content: space-between;
  height: var(--m-line-h);
  line-height: var(--m-line-h);
  white-space: nowrap;
}

/* A line that stops short of the margin is centred rather than pulled apart —
   every line of the framed opening spread, whose ornamental border leaves only
   a narrow column, and the odd short line elsewhere. mushaf.js picks them, and
   counts the gap below against the measure: keep the two in step. */
.m-line.m-short { justify-content: center; gap: 0.32em; }

.m-word { flex: 0 0 auto; }

/* The gap inside a two-part word, drawn rather than spaced — see mushaf.js. */
.m-gap { display: inline-block; height: 1px; }

.m-line.m-blank { visibility: hidden !important; }

/* --- ornamental lines --- */

/* A centred run rather than a row of words, so centred in the line box instead
   of sat on its baseline. Otherwise an ordinary line, the same height as any
   other. */
.m-line.m-surah,
.m-line.m-basmalah { align-items: center; justify-content: center; }

/* A break is only drawn when it names a surah, and the name must not spill. */
.m-line.m-surah { overflow: hidden; }

/* The Basmalah. It always gets a line of its own now, so it is sized for
   reading rather than for squeezing in beside a header. Its own line-height,
   so the box does not change with the line it sits on. */
/* Its own line-height, so its box does not change with the line it sits on. */
.m-basmalah-run {
  color: var(--primary);
  font-size: 0.86em;
  line-height: 1;
  white-space: pre;
}

body.dark-mode .m-basmalah-run { color: var(--gold); }

/* --- folio --- */

.page-footer {
  display: flex;
  align-items: center;
  justify-content: center;
  padding-top: 6px;
}

/* Juz, surah and folio all wear this, top and bottom alike. */
.page-label {
  flex: 0 0 auto;
  font-family: var(--arabic-font);
  font-size: var(--folio-size);
  font-weight: 700;
  line-height: 1.35;
  white-space: nowrap;
  color: var(--primary);
  padding: 1px 16px;
  border: 1px solid var(--line);
  border-radius: 99px;
  background: var(--surface-2);
}

body[data-lang="en"] .page-label:not(.ph-surah) { font-family: var(--ui-font); }

/* The name in the mushaf's ornamental face — worn by the running head, and by
   a surah break that has to name itself partway down a page. */
/* Calligraphy: a weight it has no cut for would only be faked by the browser. */
.ph-surah {
  font-family: 'QCF Surah Names', serif;
  font-size: calc(var(--folio-size) * 1.5);
  font-weight: 400;
  line-height: 1.1;
  padding: 0 14px;
}

body.dark-mode .ph-surah { color: var(--gold); }

.page-section.saved .page-label {
  color: #c0392b;
  border-color: rgba(192, 57, 43, 0.4);
}

/* --- surah nav --- */

#reading-nav {
  display: flex;
  gap: 12px;
  margin-top: 26px;
}

.nav-btn {
  flex: 1;
  padding: 12px 18px;
  border-radius: var(--r-md);
  background: var(--surface);
  border: 1px solid var(--line);
  color: var(--primary);
  font-family: var(--arabic-font);
  font-size: 0.95rem;
  font-weight: 600;
  cursor: pointer;
  transition: background var(--t), color var(--t), transform var(--t), box-shadow var(--t);
}

.nav-btn:hover:not(:disabled) {
  background: var(--primary);
  color: var(--on-dark);
  border-color: transparent;
  transform: translateY(-1px);
  box-shadow: var(--sh-2);
}

.nav-btn:disabled { opacity: 0.35; cursor: not-allowed; }

/* ==========================================================================
   Saved pages panel
   ========================================================================== */

.panel {
  position: fixed;
  top: 0;
  bottom: 0;
  right: var(--rail-w);
  width: 340px;
  z-index: 200;
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border-left: 1px solid var(--line);
  box-shadow: var(--sh-3);
  animation: slideIn 0.22s var(--ease) both;
}

body[data-lang="ar"] .panel { direction: rtl; }

.panel-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 14px 16px;
  border-bottom: 1px solid var(--line);
  flex-shrink: 0;
}

.panel-header h2 {
  font-family: var(--display-font);
  font-size: 1rem;
  font-weight: 500;
}

.ghost-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border: none;
  border-radius: var(--r-sm);
  background: transparent;
  color: var(--text-mute);
  cursor: pointer;
  transition: background var(--t), color var(--t);
}

.ghost-btn:hover { background: var(--primary-soft); color: var(--primary); }

.panel-section {
  padding: 14px 14px 6px;
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-mute);
  flex-shrink: 0;
}

/* Page dimmer, sat under the theme toggle. Vertical, because the rail is. */
#brightness-wrap {
  position: relative;
  display: flex;
  justify-content: center;
  padding: 8px 0 4px;
}

#brightness {
  writing-mode: vertical-lr;
  direction: rtl;              /* full at the top, dim at the bottom */
  width: 4px;
  height: 76px;
  appearance: none;
  border-radius: 99px;
  background: linear-gradient(to top, var(--line), var(--primary));
  cursor: pointer;
}

#brightness::-webkit-slider-thumb {
  appearance: none;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: var(--primary);
  border: 2px solid var(--surface);
  box-shadow: var(--sh-1);
}

#brightness::-moz-range-thumb {
  width: 12px;
  height: 12px;
  border: 2px solid var(--surface);
  border-radius: 50%;
  background: var(--primary);
}

/* Same tooltip treatment as the rail buttons. */
#brightness-wrap::after {
  content: attr(data-tip);
  position: absolute;
  right: calc(100% + 6px);
  top: 50%;
  transform: translateY(-50%) scale(0.96);
  padding: 5px 10px;
  border-radius: var(--r-sm);
  background: var(--text);
  color: var(--bg);
  font-size: 0.72rem;
  font-family: var(--ui-font);
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--t), transform var(--t);
  z-index: 60;
}

#brightness-wrap:hover::after { opacity: 1; transform: translateY(-50%) scale(1); }

#bookmarks-list {
  flex: 1;
  overflow-y: auto;
  padding: 10px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.bookmark-card {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 12px;
  border-radius: var(--r-md);
  background: var(--surface-2);
  border: 1px solid var(--line);
  cursor: pointer;
  transition: border-color var(--t), transform var(--t), box-shadow var(--t);
}

.bookmark-card:hover {
  border-color: var(--primary);
  transform: translateY(-1px);
  box-shadow: var(--sh-1);
}

.bpn {
  display: flex;
  flex-direction: column;
  align-items: center;
  min-width: 44px;
  padding: 4px;
  border-radius: var(--r-sm);
  background: rgba(192, 57, 43, 0.1);
  color: #c0392b;
  flex-shrink: 0;
}

.bpn-value { font-family: var(--arabic-font); font-size: 1rem; font-weight: 700; line-height: 1.1; }
.bpn-label { font-size: 0.53rem; letter-spacing: 0.06em; text-transform: uppercase; opacity: 0.8; }

.bookmark-info { flex: 1; min-width: 0; }

.bookmark-surah {
  font-family: var(--arabic-font);
  font-size: 1rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.bookmark-detail { font-size: 0.7rem; color: var(--text-mute); margin-top: 1px; }

.bookmark-delete {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  border: none;
  border-radius: var(--r-sm);
  background: transparent;
  color: var(--text-mute);
  cursor: pointer;
  transition: background var(--t), color var(--t);
}

.bookmark-delete:hover { background: rgba(192, 57, 43, 0.12); color: #c0392b; }

.panel-body { flex: 1; overflow-y: auto; padding-bottom: 8px; }

.keys {
  margin: 0 12px;
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 7px 12px;
  align-items: center;
  font-size: 0.8rem;
}

.keys dt { display: flex; gap: 4px; }
.keys dd { margin: 0; color: var(--text-mute); }

kbd {
  font-family: var(--ui-font);
  font-size: 0.7rem;
  line-height: 1.5;
  padding: 1px 7px;
  border: 1px solid var(--line);
  border-bottom-width: 2px;
  border-radius: 5px;
  background: var(--surface-2);
  color: var(--text);
  white-space: nowrap;
}

.hints {
  margin: 0 12px;
  padding-inline-start: 18px;
  font-size: 0.8rem;
  line-height: 1.65;
  color: var(--text-mute);
}

.hints li { margin-bottom: 3px; }

.panel-footer { padding: 12px; border-top: 1px solid var(--line); flex-shrink: 0; }

.danger-btn {
  width: 100%;
  padding: 9px;
  border: 1px solid rgba(192, 57, 43, 0.45);
  border-radius: var(--r-sm);
  background: transparent;
  color: #c0392b;
  font-family: var(--ui-font);
  font-size: 0.85rem;
  cursor: pointer;
  transition: background var(--t), color var(--t);
}

.danger-btn:hover { background: #c0392b; color: #fff; }

#overlay {
  position: fixed;
  inset: 0;
  z-index: 150;
  background: rgba(8, 22, 34, 0.45);
  backdrop-filter: blur(2px);
  animation: fade 0.2s var(--ease) both;
}

/* while picking a typeface the pages must stay plainly visible */
#overlay.clear {
  background: transparent;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  animation: none;
}

.empty-state { text-align: center; padding: 48px 20px; color: var(--text-mute); }
.empty-state .ic { width: 34px; height: 34px; color: var(--line); margin-bottom: 10px; }
.empty-state p { font-size: 0.88rem; }

.no-data-msg {
  text-align: center;
  padding: 40px 20px;
  color: var(--text-mute);
  font-size: 0.9rem;
  line-height: 1.9;
}

/* ==========================================================================
   Motion
   ========================================================================== */

@keyframes rise    { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
@keyframes slideIn { from { opacity: 0; transform: scale(0.98); } to { opacity: 1; transform: none; } }
@keyframes fade    { from { opacity: 0; } to { opacity: 1; } }

/* --- page turner ---
   Flanking the page rather than in a corner: the same reach whichever mode is
   on, and always inside the lane #content-area holds open (--turn-lane), so a
   turner never sits on the type. The mushaf reads right to left, so "next"
   takes the left edge. */

#page-nav {
  position: fixed;
  top: 50%;
  left: 0;
  right: var(--rail-w);
  transform: translateY(-50%);
  z-index: 120;
  display: none;
  /* Centred on the page rather than the window, so the buttons stay beside the
     sheet instead of drifting out to the screen edge. --sheet-w is published by
     the app after each fit: the sheet's width comes from a container query that
     only resolves inside #ayahs-container, so it cannot be recomputed here.
     Each button then lands in the lane #content-area already holds open, which
     is what keeps it off the page whatever the sheet turns out to be. */
  max-width: calc(var(--sheet-w, var(--page-measure)) + var(--turn-lane) * 2);
  margin-inline: auto;
  justify-content: space-between;
  pointer-events: none;
}

body.is-reading #page-nav { display: flex; }

body.side-open #page-nav { right: calc(var(--rail-w) + var(--sidebar-w)); }

#page-nav button {
  width: 60px;
  height: 60px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: color-mix(in srgb, var(--surface) 92%, transparent);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  color: var(--primary);
  cursor: pointer;
  pointer-events: auto;
  box-shadow: var(--sh-2);
  transition: background var(--t), color var(--t), transform var(--t);
}

#page-nav .ic { width: 26px; height: 26px; }

/* The chevron points the way the page moves: up and down when one page
   scrolls, left and right when two face each other and turn as a leaf.
   #i-chev points left, so the rotations are from there. */
#page-nav #btn-page-prev .ic { transform: rotate(90deg); }    /* up */
#page-nav #btn-page-next .ic { transform: rotate(-90deg); }   /* down */

body[data-mode="spread"] #page-nav #btn-page-prev .ic { transform: rotate(180deg); }  /* right */
body[data-mode="spread"] #page-nav #btn-page-next .ic { transform: none; }            /* left */

/* The help panel names the keys for the mode you are in, not both. */
.k-spread { display: none; }
body[data-mode="spread"] .k-pages { display: none; }
body[data-mode="spread"] .k-spread { display: inline; }

#page-nav button:hover { background: var(--primary); color: var(--on-dark); transform: scale(1.07); }
#page-nav button:active { transform: scale(0.95); }

/* A turner with nowhere to go goes invisible but keeps its place: dropping it
   out of the flow lets space-between slide the other one across the screen. */
#page-nav button.gone { visibility: hidden; }

/* The label sits outward, into the margin beside the page — never over type. */
#page-nav button::after {
  content: attr(data-tip);
  position: absolute;
  top: 50%;
  transform: translateY(-50%) scale(0.96);
  padding: 5px 10px;
  border-radius: var(--r-sm);
  background: var(--text);
  color: var(--bg);
  font-family: var(--ui-font);
  font-size: 0.72rem;
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--t), transform var(--t);
}

#page-nav button { position: relative; }
#page-nav #btn-page-next::after { right: calc(100% + 10px); }
#page-nav #btn-page-prev::after { left: calc(100% + 10px); }
#page-nav button:hover::after { opacity: 1; transform: translateY(-50%) scale(1); }

/* --- reading modes -------------------------------------------------------
   pages   the default: one sheet after another, scrolled
   spread  two facing pages, turned two at a time, nothing to scroll        */

/* Only the icon for the mode in force. Both rules carry the id, or the hide
   would outrank the show and the button would come out empty. */
#btn-mode .ic { display: none; }
body[data-mode="pages"]  #btn-mode .ic-mode-pages,
body[data-mode="spread"] #btn-mode .ic-mode-spread { display: block; }

/* --- spread --- */

body[data-mode="spread"] {
  --fit-scale: 1;
}

body[data-mode="spread"] #ayahs-container {
  --m-cols: 2;
  /* row-reverse puts the odd page on the right, where the mushaf opens it. */
  flex-direction: row-reverse;
  align-items: stretch;
  justify-content: center;
  /* No gap: the two leaves meet at the spine. */
  gap: 0;
}

body[data-mode="spread"] .page-section { display: none; }
body[data-mode="spread"] .page-section.in-spread { display: block; }

/* Nothing to scroll: the spread is the screen. */
body[data-mode="spread"] #content-area { overflow-y: hidden; }
body[data-mode="spread"] #reading-nav { display: none; }

/* --- the bound book ---
   The leaves join rather than float apart: square where they meet, rounded on
   the outer edges, each shaded into the spine so the paper looks like it turns
   into the binding, and each throwing its shadow outward. */

body[data-mode="spread"] .spread-right,
body[data-mode="spread"] .spread-left { border: none; }

/* The gutter: paper curving down into the binding on both sides, deepest at
   the seam. Painted rather than shadowed, so it reads as the page itself
   turning rather than as something cast onto it. */
body[data-mode="spread"] .spread-right {
  border-radius: 0 var(--r-lg) var(--r-lg) 0;
  background-image: linear-gradient(to right,
    rgba(20, 60, 95, 0.20) 0,
    rgba(20, 60, 95, 0.07) 10px,
    rgba(20, 60, 95, 0.02) 26px,
    transparent 46px);
  /* The block of leaves under this side, then the shadow the book casts. */
  box-shadow:
    2px 0 0 var(--paper), 3px 0 0 var(--line),
    5px 0 0 var(--paper), 6px 0 0 var(--line),
    8px 0 0 var(--paper), 9px 0 0 var(--line),
    14px 6px 26px -10px rgba(20, 60, 95, 0.34);
}

body[data-mode="spread"] .spread-left {
  border-radius: var(--r-lg) 0 0 var(--r-lg);
  background-image: linear-gradient(to left,
    rgba(20, 60, 95, 0.20) 0,
    rgba(20, 60, 95, 0.07) 10px,
    rgba(20, 60, 95, 0.02) 26px,
    transparent 46px);
  box-shadow:
    -2px 0 0 var(--paper), -3px 0 0 var(--line),
    -5px 0 0 var(--paper), -6px 0 0 var(--line),
    -8px 0 0 var(--paper), -9px 0 0 var(--line),
    -14px 6px 26px -10px rgba(20, 60, 95, 0.34);
}

body.dark-mode[data-mode="spread"] .spread-right {
  box-shadow:
    2px 0 0 var(--paper), 3px 0 0 var(--line),
    5px 0 0 var(--paper), 6px 0 0 var(--line),
    8px 0 0 var(--paper), 9px 0 0 var(--line);
}

body.dark-mode[data-mode="spread"] .spread-left {
  box-shadow:
    -2px 0 0 var(--paper), -3px 0 0 var(--line),
    -5px 0 0 var(--paper), -6px 0 0 var(--line),
    -8px 0 0 var(--paper), -9px 0 0 var(--line);
}

/* The ribbon belongs on a leaf's outer corner. On the right-hand leaf that is
   the top right; leaving it at the top left would bury it in the gutter. */
body[data-mode="spread"] .spread-right .page-ribbon {
  left: auto;
  right: -28px;
  transform: rotate(45deg);
  background: linear-gradient(270deg, var(--primary-light), var(--primary) 55%, var(--primary-dark));
}

/* ==========================================================================
   Responsive
   ========================================================================== */

@media (max-width: 900px) {
  :root {
    --rail-w: 54px; --sidebar-w: 260px;
    --sheet-pad-x: 14px; --sheet-pad-t: 10px; --sheet-pad-b: 5px;
    --sheet-chrome: 78px; --m-line-ratio: 1.86;
  }

  #sidebar {
    position: fixed;
    top: 0;
    bottom: 0;
    right: var(--rail-w);
    z-index: 160;
    box-shadow: var(--sh-3);
  }

  #sidebar.hidden { width: 0; border: none; }

  #reading-area { padding: 6px 10px 12px; }

  /* A narrower lane, and smaller buttons to sit in it: still beside the page,
     just closer in. */
  :root { --turn-lane: 64px; }
  #page-nav button { width: 44px; height: 44px; }
  #page-nav .ic { width: 20px; height: 20px; }
  #page-nav button::after { display: none; }

  /* Two facing pages need width a phone does not have. The mode itself is
     dropped to one page in JS, so nothing here has to pretend — and the
     control that offers it is taken away rather than left to do nothing. */
  body.no-spread #btn-mode { display: none; }
  /* Nothing flanks the page here — the turners drop below it. */
  #ayahs-container { gap: 10px; }

  .page-section { border-radius: var(--r-md); }

  .mushaf { margin-bottom: 6px; }

  .panel { width: calc(100% - var(--rail-w)); }

  .rail-btn::after, #brightness-wrap::after { display: none; }
  #font-level { display: none; }
  #brightness { height: 56px; }
}

/* Too narrow to stand anything beside the page. Rather than put the turners on
   the type, take them away — scrolling, dragging and the index all still move
   the reader, and the arrow keys still work. */
@media (max-width: 480px) {
  :root { --turn-lane: 0px; }
  body.is-reading #page-nav { display: none; }
}

@media (min-width: 1400px) {
  :root {
    --page-measure: 720px; --sheet-pad-x: 40px; --sheet-pad-t: 14px;
    --sheet-pad-b: 8px; --sheet-chrome: 98px;
  }
}

@media (prefers-reduced-motion: reduce) {
  #content-area { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}
