/* ============================================================================
   quran.css -- the surah index and the study page.

   Loaded after base.css, which owns every token this file uses. No colour is
   written here as a literal, and no rule asks which theme is running: dark mode
   works by value substitution in base.css section 2 alone.

   Read top to bottom: shell, identity, chrome, contents, then the verse and its
   apparatus in the order they appear, then the tajweed map, then the width
   breakpoints at the end. There are two, and section 17 says why they cannot be
   one: 600px is where the chrome has a little more room to spend, and 62rem is
   where the viewport is wide enough to be cut in half and still hold two
   columns worth reading. Everything else is the narrow case.
   ========================================================================= */


/* ----------------------------------------------------------------------------
   0. The Typeset face

   Amiri Quran, self-hosted and open-licensed. The UI is system stacks only; this
   is one of the two deliberate webfont exceptions, and it is not decoration: the
   system Arabic faces do not position the full Uthmani annotation set, and
   several marks land as dotted-circle placeholders without it.

   font-display: swap, unlike the QCF faces in base.css section 17, which block.
   Real Uthmani text in a fallback face is readable if badly marked; a QCF glyph
   code in any other font is garbage. The honest-reveal argument applies only
   where the fallback would be meaningless.
   ------------------------------------------------------------------------- */
@font-face {
  font-family: "Amiri Quran";
  src: url("../fonts/quran/AmiriQuran-Regular.woff2") format("woff2");
  font-display: swap;
}


/* ----------------------------------------------------------------------------
   1. Shell
   ------------------------------------------------------------------------- */
.quran .wrap { max-width: var(--wrap); }

/* The surah index, narrower than the shell it sits in.

   Measured against the corpus rather than chosen: the widest row wants about
   40px of number, 212px of names -- "The Rivalry in world increase" is the
   longest meaning -- 68px of Arabic, 144px of facts, plus gaps and padding.
   That is 524px, or 32.8rem. In the shell's 68rem the four columns take their
   authored widths and the 1fr swallows the remaining 564px, all of it landing
   in one gap between a surah's meaning and its Arabic name, so more than half
   of every row is empty space the eye has to cross.

   36rem leaves that track about 52px, which reads as a column gutter rather
   than a void, and keeps the spread layout doing the job it was introduced
   for: four columns lining up down all 114 rows. This is the same complaint
   the centred mobile layout was rebalanced to answer in the first place, met
   again at the other end of the scale.

   Narrower than the study page's --measure on purpose. A measure is for prose,
   where the line length is about the reader's eye; this is a list, where the
   width is about what the columns hold. */
.quran .surahs .wrap { max-width: 36rem; }

/* The reading column, and the reason this selector carries .quran when the
   rule below it does not.

   .surahbody alone is one class and loses to .quran .wrap above, which is two.
   So the max-width written here has never once applied: the study page has
   been reading at --wrap, 68rem, while the stylesheet said 42.5rem. Nothing
   reports a rule that parses and is simply outranked, which is the same shape
   as the fault recorded in section 14 of the brain -- an override standing
   over a declaration that is no longer there. The evidence is only ever
   visual, and here it was a line of English running past a hundred characters.

   42.5rem is --measure, which the whole site already uses for prose. At this
   size the card's text is about 72 characters, inside the 45-to-75 band that
   is comfortable to read; at 68rem it was near 120. Deliberately a length and
   not a percentage: a share of the viewport is a different measure on every
   screen, which is the one thing a measure exists not to be. */
.quran .surahbody {
  max-width: var(--measure);
}

.surahbody {
  margin-inline: auto;
  padding-block-end: var(--space-8);
}


/* ----------------------------------------------------------------------------
   1b. The header stays put

   Everything a reader wants mid-surah is up here: which surah this is, the two
   either side of it, the display settings and the contents. Scrolling that off
   the screen would mean scrolling back to the top to use any of it, and the
   contents especially is a thing you reach for from the middle of a long surah,
   not from its first line.

   z-index clears the tafsir panel's 90 so the header's controls stay reachable
   while a commentary is open beside the verse. That is the same call the
   display panel already made for itself, made once here instead: the sticky
   header is a stacking context, so the panels inside it now resolve against
   this number rather than against the panel.
   ------------------------------------------------------------------------- */
.quran .masthead {
  position: sticky;
  inset-block-start: 0;
  z-index: 92;
}

/* ----------------------------------------------------------------------------
   1b. Tucking the header away while the reader is reading forward

   On a phone the header was 266px of a 780px screen, 34% of it, standing there
   for the whole length of a surah. Scrolling DOWN is reading, and reading is
   the one activity that wants the screen, so scrolling down takes the header
   off it; scrolling UP is looking for something, and what you are looking for
   is in the header, so any upward scroll brings it back. That gesture is the
   one every mobile reader already has from Safari, Chrome and every reading
   app, which is why it is this rather than a timer: a header that leaves while
   you sit still, and returns whenever you move, is restless on a page whose
   whole job is to be read.

   What stays is .surahtuck, a 28px strip carrying the name, so the reader is
   never unsure which surah they are in. It is a separate fixed element rather
   than a surviving slice of the header, which keeps it independent of how tall
   the header happens to be at a given width.

   Only below the split's breakpoint. Above it the header is one short row on a
   screen with height to spare, and taking it away would buy nothing.

   static/js/header.js owns the class and lists the conditions that forbid the
   tuck: a panel hanging open from the header, focus inside it, the top of the
   page. It writes no CSS; both states below are classes.
   ------------------------------------------------------------------------- */
@media (max-width: 61.999rem) {
  .quran-surah .masthead {
    transition: transform var(--dur-slow) var(--ease-calm);
  }

  .quran-surah.is-tucked .masthead {
    transform: translateY(-100%);
  }

  .surahtuck {
    position: fixed;
    inset-block-start: 0;
    inset-inline: 0;
    /* Under the header, so the header slides over it on the way out rather
       than the strip appearing to punch through it. Above the tafsir panel's
       90 is NOT wanted: the sheet covers the page and this is part of it. */
    z-index: 91;
    display: flex;
    align-items: center;
    justify-content: center;
    block-size: 28px;
    padding-inline: var(--gutter);
    border-block-end: var(--hair) solid var(--rule);
    background: var(--paper);
    transform: translateY(-100%);
    transition: transform var(--dur-slow) var(--ease-calm);
  }

  .quran-surah.is-tucked .surahtuck { transform: none; }
}

/* The strip is a phone and tablet affordance. Above the breakpoint the header
   never tucks, so the element must not be able to appear at all. */
@media (min-width: 62rem) {
  .surahtuck { display: none; }
}

.surahtuck__name {
  display: inline-flex;
  align-items: baseline;
  gap: var(--space-2);
  overflow: hidden;
  white-space: nowrap;
}

.surahtuck__arabic {
  font-family: "Amiri Quran", var(--font-arabic);
  font-size: 0.95rem;
  line-height: 1;
  color: var(--ink);
}

.surahtuck__latin {
  font-family: var(--font-serif);
  font-size: var(--fs-caption);
  color: var(--ink-soft);
}

/* Both of these are properties of the viewport, which takes them from the root
   element, so neither can be written against the body class the page carries.

   scroll-padding: an anchor jumped to by the browser lands under a sticky
   header unless the space is reserved. header.js measures the header and
   replaces this with the real height, which is what actually drives it; this is
   the floor for a page where that script never runs, and it is deliberately
   generous because too much leaves a gap and too little hides the heading.

   scroll-behavior: the site scrolls smoothly, which is right for the landing
   page, where every anchor is a screen or two away. A surah is upwards of
   130,000px tall and the contents jumps most of that, so the same setting turns
   one navigation into several seconds of blur. Measured 2026-08-19: a jump to
   the twenty-eighth heading of Al Imran had still not arrived after three. */
:root:has(.quran-surah) {
  scroll-padding-block-start: 12rem;
  scroll-behavior: auto;
}


/* ----------------------------------------------------------------------------
   2. The surah bar

   A second header row carrying everything that used to stand above the text:
   the surah's identity and the step either side of it. The Arabic is still the
   largest thing on the page, so the surah is still announced, but announcing it
   no longer costs a screen of height before the first verse.
   ------------------------------------------------------------------------- */
.surahbar {
  border-block-start: var(--hair) solid var(--rule-soft);
  background: var(--paper);
}

/* Three rows: the name with an arrow either side of it, what the surah IS
   beneath it, and the ways into it below that. The lower two span the full
   width so they centre on the bar rather than on the name's column.

   Two rows until 2026-08-21, when the bottom one was carrying five things of
   two different kinds: the name in English, the verse count and the revelation
   place, then Topics, Reflections and Lectures. Descriptions and controls, all
   in one line, separated by the same dot. The split now runs between the kinds
   -- row two says what this surah is, row three says where you can go -- which
   is a cut a reader can feel without being told.

   The arrows are auto columns, so they take only what their glyph and label
   need and the name gets the rest. That is what let the narrow-width restack
   go: the two steps used to carry surah names, could not fit beside the name
   below 40rem, and were given a row of their own that cost 53px. An arrow
   fits at 320px. */
.surahbar__inner {
  display: grid;
  grid-template-columns: auto 1fr auto;
  grid-template-areas:
    "prev  title next"
    "about about about"
    "meta  meta  meta";
  align-items: center;
  gap: 0.15rem var(--space-2);
  padding-block: var(--space-1);
  /* The containing block for the Topics drop below, which is centred in THIS
     rather than on its own trigger -- the reasoning is at that rule. Nothing
     else in the bar is positioned, so this introduces no other change. */
  position: relative;
}

.surahbar__title {
  grid-area: title;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: center;
  gap: 0 var(--space-2);
  margin: 0;
  min-width: 0;
  text-align: center;
}

/* 1.25 rather than the 1.5 this started at. The Arabic keeps its size, which is
   what gives the surah its posture, but a display line does not need a body
   line-height, and the name now costs a row of its own. */
.surahbar__arabic {
  font-family: "Amiri Quran", var(--font-arabic);
  font-size: 1.65rem;
  line-height: 1.25;
  font-weight: 400;
  color: var(--ink);
}

.surahbar__latin {
  font-family: var(--font-serif);
  font-size: var(--fs-body-lg);
  font-weight: 400;
  color: var(--ink);
}

.surahbar__meta {
  grid-area: meta;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 0 var(--space-2);
  min-width: 0;
}

.surahbar__meaning,
.surahbar__facts {
  font-family: var(--font-sans);
  font-size: var(--fs-caption);
  font-weight: 400;
  color: var(--ink-faint);
}

/* The description row: the meaning and the two facts, centred under the name.
   A flex row rather than plain inline text so the pieces wrap as units on a
   narrow screen, and the margin reset is what a paragraph needs in a grid
   row. */
.surahbar__about {
  grid-area: about;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: baseline;
  gap: 0 var(--space-2);
  margin: 0;
  min-width: 0;
}

/* Only between the two runs of text, and the gap above supplies its other
   side. Nothing separates this row from the controls below it but the line
   break, which is the whole point of the split: punctuation is for items of
   the same kind, and the row beneath is a different kind. */
.surahbar__facts::before {
  content: "·";
  margin-inline-end: var(--space-2);
  color: var(--rule-strong);
}

/* The way to the neighbouring surah: a glyph and a faint word, on the side the
   surah lies. The label is not the target's name, which was the old shape and
   is what cost the row; it is the direction, which is what the reader is
   choosing. The name is on the link's aria-label and so is still announced. */
/* The whole step is the target: chevron, direction and the neighbour's name
   are one object to point at and one to press, rather than a word with a
   picture next to it. The padding is what makes that legible -- without it
   the hover lands tight on the glyphs and reads as two marks lighting up. */
.surahbar__step {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-block-size: 44px;
  min-width: 0;
  padding-inline: var(--space-2);
  border-radius: var(--radius-control);
  font-family: var(--font-sans);
  text-decoration: none;
  color: var(--ink-soft);
}

.surahbar__step[href]:hover {
  background: var(--paper-sunk);
  color: var(--accent-strong);
}

/* The surah waiting on that side. It came off this bar once already, when the
   two steps were buttons printing a name and could not fit beside the identity
   below 40rem; the name went to the aria-label and the visible label became
   the direction alone. It is back because the direction alone answers "where
   does this go" with "onwards", which a reader who knows the order does not
   need and a reader who does not cannot use.

   Inboard of the direction word on both sides -- after it on the left, before
   it on the right -- so the chevrons stay on the outer edges pointing away and
   the two names sit either side of the one they lead from. That is the shape
   of a book's running heads, and it is why these belong on the identity row
   rather than in the caption line below it: that line is what this surah IS,
   and these are the way out of it. */
.surahbar__near {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  font-size: var(--fs-body-sm);
  color: var(--ink);
}

/* The measurement that took the names away in the first place still holds, so
   below it they go again and the direction carries the step alone. 52rem is
   where the bar has room for two names either side of the longest surah title
   without the identity giving way. */
@media (max-width: 51.999rem) {
  .surahbar__near { display: none; }
}

.surahbar__step--prev { grid-area: prev; justify-self: start; }
.surahbar__step--next { grid-area: next; justify-self: end; }

/* Holds its column at the two ends of the corpus, so surah 1 and 114 keep the
   name centred on the bar instead of letting it slide into the empty side. */
.surahbar__step--empty { pointer-events: none; }

.surahbar__step:hover { background: var(--paper-sunk); color: var(--ink); }

/* The glyph is the single-angle quotation mark, which is a chevron of the right
   weight in every system face here. Not an arrow character, which is heavier
   than this bar wants, and not a generated one: content on a pseudo-element
   would put the mark in the stylesheet where a screen reader can still reach
   it in some browsers, and this pair is decorative by design. */
.surahbar__arrow {
  font-size: 1.15rem;
  line-height: 1;
  color: var(--ink-soft);
}

.surahbar__dir {
  font-size: var(--fs-label);
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

/* The label is the first thing to go when the name needs the room. Below 22rem
   the chevron carries the direction alone, and the accessible name is
   untouched either way. */
@media (max-width: 22rem) {
  .surahbar__dir { display: none; }
}

/* The narrow-width restack that used to live here is gone, deleted 2026-08-20.
   It existed because the two steps carried surah NAMES, could not fit beside
   the identity below 40rem, and were being squeezed to 16px wide; giving them
   a row of their own fixed that and cost 53px of a phone's header. The names
   are on the aria-labels now and the steps are chevrons, which fit beside the
   name at 320px, so the row they were given is no longer owed to them. */


/* ----------------------------------------------------------------------------
   3. The chrome row

   Previous, the index, next. Since the surah identity moved into the header
   this row survives only at the foot of the surah, where it is the way on
   rather than the way around. Three columns so the index stays optically
   centred even when a neighbour's name is long, and the empty spans at the
   ends of the corpus hold their column rather than letting the row re-centre
   on surah 1 and 114.

   Restored 2026-08-19. Moving the identity into the header deleted this block
   and left only its overrides behind, and an override of a layout that is no
   longer declared does nothing at all: grid-template-columns with no grid, a
   flex-direction with no flex, a min-height on what had become an inline box.
   The row had been three bare text links, roughly 20px tall, at the foot of
   every surah.

   The base is the narrow shape, per section 17: one line per control, the
   neighbour names truncating rather than wrapping. The breakpoint gives back
   the two-line shape. Base is 44px rather than the 40px the overrides had
   chosen, because that 40px was bought to save height in a header this row no
   longer lives in.
   ------------------------------------------------------------------------- */
.chrome {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: stretch;
  gap: var(--space-1);
  margin-block-start: var(--space-4);
  font-family: var(--font-sans);
  text-align: start;
}

.chrome--foot { margin-block-start: var(--space-7); }

.chrome__step,
.chrome__all {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: var(--space-1);
  min-height: 44px;
  padding: var(--space-1) var(--space-2);
  border: var(--hair) solid var(--rule);
  border-radius: var(--radius-control);
  background: var(--paper-raised);
  font-size: var(--fs-caption);
  text-decoration: none;
  color: var(--ink);
}

.chrome__step--next { justify-content: flex-end; text-align: end; }
.chrome__step--empty { border-color: transparent; background: none; }

.chrome__all { justify-content: center; color: var(--ink-soft); }

/* The label stays a word at every width, just a small one. An earlier version
   replaced it with a chevron via ::before; the escape did not survive being
   written through a shell heredoc and rendered a literal letter beside the
   word. A generated glyph was never worth that. */
.chrome__dir {
  flex: none;
  font-size: var(--fs-label);
  letter-spacing: 0.09em;
  text-transform: uppercase;
  line-height: 1.2;
  color: var(--ink-faint);
}

.chrome__name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.chrome__step:hover,
.chrome__all:hover { border-color: var(--rule-strong); }


/* ----------------------------------------------------------------------------
   4. Topics

   The section index of THIS surah, so it hangs off the surah's own identity
   rather than standing in the site header beside "All surahs", where it read
   as an index of the site. It drops over the text like the display panel does,
   so opening it never moves the verses.
   ------------------------------------------------------------------------- */
/* Deliberately NOT position:relative. The list below is centred in the bar's
   inner grid instead, and a positioned ancestor here would take that job back
   and clip the list off the left again. */
.surahtoc { font-family: var(--font-sans); }

.surahtoc__trigger {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  min-block-size: 44px;
  padding: 0.2rem var(--space-2);
  border: var(--hair) solid transparent;
  border-radius: var(--radius-pill);
  font-size: var(--fs-caption);
  color: var(--ink-soft);
  cursor: pointer;
  list-style: none;
  white-space: nowrap;
}

.surahtoc__trigger::-webkit-details-marker { display: none; }

.surahtoc__trigger:hover {
  border-color: var(--rule);
  background: var(--paper-raised);
  color: var(--ink);
}

.surahtoc[open] > .surahtoc__trigger {
  border-color: var(--accent);
  background: var(--accent-tint);
  color: var(--accent-strong);
}

.surahtoc__trigger:focus-visible {
  outline: var(--focus-width) solid var(--accent-strong);
  outline-offset: var(--focus-offset);
}

.surahtoc__lines { flex: none; color: var(--ink-faint); }
.surahtoc__trigger:hover .surahtoc__lines,
.surahtoc[open] .surahtoc__lines { color: currentColor; }

.surahtoc__count {
  padding-inline: 0.4rem;
  border-radius: var(--radius-pill);
  background: var(--paper-sunk);
  font-size: var(--fs-label);
  color: var(--ink-faint);
}

.surahtoc__chev {
  flex: none;
  color: var(--ink-faint);
  transition: transform var(--dur) var(--ease-calm);
}

.surahtoc[open] .surahtoc__chev { transform: rotate(180deg); color: currentColor; }

/* CENTRED IN THE BAR, NOT ON THE TRIGGER, and that is the fix for a list whose
   left half hung off the screen.

   It was centred on the trigger, "because the trigger sits mid-header under a
   centred name" -- which was true only at full width with no panel open. The
   trigger is the FIRST item of a centred row, so the narrower the bar the
   closer to its start edge it sits, and a list centred on it reaches back past
   that edge. Measured on quranstudy.app/quran/2: with a panel at 60% the bar
   was 576px, the trigger sat 53px in, and the 480px list started at -127px.
   On a 390px phone it started at -49px. Reported by the owner as the topics
   being cut off on the left, on both.

   The width was never the problem -- 100cqi below already keeps it inside the
   bar. Only the anchor was. So the list is centred in .surahbar__inner, which
   is the box the surah name is centred in: that honours what the old comment
   was actually asking for, and it cannot overflow at any width, because a box
   narrower than its container and centred in it has nowhere to hang off.

   inset-inline: 0 with margin-inline: auto is how an absolutely positioned box
   is centred; the pair replaces the 50%-and-translate, so there is no transform
   here any more and the list is not a containing block for anything.

   inset-block-start is now 100% of the BAR rather than of the trigger, so the
   list drops from the foot of the whole header band -- which is where the
   other drop panels in the masthead already come from. */
.surahtoc .contents__list {
  position: absolute;
  inset-block-start: calc(100% + var(--space-2));
  inset-inline: 0;
  margin-inline: auto;
  z-index: 94;
  /* 100cqi for the reason .qsearch__under gives: this list drops out of the
     surah bar, which renders INSIDE the masthead, which stands in half the
     page once a panel is open. The window was never the measurement. */
  width: min(30rem, calc(100cqi - 2 * var(--gutter)));
  /* Two declarations, and the second is not a duplicate. On a phone 100vh is
     the tall viewport, the one with the browser's toolbar retracted, so a panel
     sized in vh while the toolbar is showing runs underneath it and its last
     rows cannot be reached. dvh is the viewport as it actually is. The vh line
     stays underneath as the fallback for anything that does not know dvh, where
     it is simply ignored. This pattern is used at all three drop panels. */
  max-height: min(28rem, calc(100vh - 10rem));
  max-height: min(28rem, calc(100dvh - 10rem));
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: var(--space-3);
  border: var(--hair) solid var(--rule-strong);
  border-radius: var(--radius);
  background: var(--paper-raised);
  box-shadow: var(--shadow-soft);
  text-align: start;
}

/* The list is the dropdown itself now, not the body of a card, so the divider
   and insets that separated it from a summary above it are gone. */
.contents__list {
  margin: 0;
  list-style: none;
}

.contents__item a {
  display: flex;
  align-items: center;
  min-block-size: 44px;
  padding-block: var(--space-1);
  font-size: var(--fs-body-sm);
  line-height: var(--lh-body);
  color: var(--ink-soft);
  text-decoration: none;
}

.contents__item a:hover { color: var(--accent-strong); text-decoration: underline; }
.contents__item--subtopic a { padding-inline-start: var(--space-4); color: var(--ink-faint); }

/* The touch sizes above are the default and a cursor gets the condensed ones,
   the same inversion the display panel uses. It matters most here: this is the
   surah's own index, reached from the middle of a long surah, and on a phone
   its rows were 30px in a list that scrolls under the thumb doing the reading.
   The list is its own scroller, so the height these rows gain is free. */
@media (pointer: fine) {
  .surahtoc__trigger { min-block-size: 0; }
  .contents__item a { display: block; min-block-size: 0; }
}


/* ----------------------------------------------------------------------------
   5. Bismillah

   Carries .verse-list so the tajweed map and the style class flips reach it,
   but it is a centred header line, so the list's column flex is undone here.
   ------------------------------------------------------------------------- */
/* .verse-list below sets a column flex, and at equal specificity source order
   would win, stacking the bismillah one word per line. Qualifying with both
   classes is what actually undoes it. */
.verse-bismillah.verse-list { display: block; }

.verse-bismillah {
  margin: var(--space-6) 0 var(--space-5);
  font-family: "Amiri Quran", var(--font-arabic);
  font-size: calc(var(--fs-h1) * var(--ar-scale, 1));
  line-height: 2.2;
  text-align: center;
  color: var(--ink);
}

.verse-bismillah.arstyle-mushaf { line-height: var(--lh-arabic-mushaf); }


/* ----------------------------------------------------------------------------
   6. Sections and headings
   ------------------------------------------------------------------------- */
.study-topic,
.study-sub {
  margin: var(--space-7) 0 var(--space-3);
  font-family: var(--font-serif);
  color: var(--ink);
  scroll-margin-top: var(--space-5);
}

.study-topic {
  font-size: var(--fs-h2);
  line-height: var(--lh-heading);
  text-align: center;
}

/* A hairline ornament under a topic, the same device the landing page uses to
   close a section without drawing a box. */
.study-topic::after {
  content: "";
  display: block;
  width: 3rem;
  margin: var(--space-3) auto 0;
  border-block-start: var(--hair) solid var(--rule-strong);
}

.study-sub {
  font-size: var(--fs-h3);
  line-height: var(--lh-heading);
  color: var(--ink-soft);
}

.study-group {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}


/* ----------------------------------------------------------------------------
   7. The verse
   ------------------------------------------------------------------------- */
.verse-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.verse {
  padding: var(--space-5);
  border: var(--hair) solid var(--rule);
  border-radius: var(--radius);
  background: var(--paper-raised);
}

/* The verse's own line: its number, and the control that plays it.

   A flex row rather than an inline-block with a button dropped into it. The
   button is taller than the type beside it, and the old arrangement pulled it
   back into the line with a negative margin computed from the two heights --
   a number that was correct for one font size and silently wrong for the
   next. Aligning the row's items costs nothing and cannot go stale.

   The number is deliberately larger than caption type. It is the verse's
   address, the thing a reader says out loud to another reader and the label
   they scan a long surah for, and at 0.78rem it was the quietest thing on a
   card it ought to lead. */
.verse__num {
  display: flex;
  align-items: center;
  /* The disc carries its own transparent margin inside a 44px box, so the gap
     between the ink and the ring is wider than this number: at space-1 the two
     read as one object rather than as an address and a control beside it. */
  gap: var(--space-3);
  margin: 0 0 var(--space-2);
  font-family: var(--font-sans);
  font-size: 1.55rem;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  color: var(--ink-faint);
}

.verse__arabic {
  margin: 0;
  font-family: "Amiri Quran", var(--font-arabic);
  font-size: calc(var(--fs-display) * var(--ar-scale, 1));
  line-height: var(--lh-arabic-typeset);
  color: var(--ink);
  text-align: right;
}

/* The end-of-ayah ornament. Amiri draws it a touch wide, so it is squeezed to
   read as a round medallion. Typeset only: the Mushaf styles swap in the
   calligrapher's own glyph, whose width is not ours to correct. */
.verse__end {
  display: inline-block;
  transform: scaleX(0.78);
  transform-origin: center;
}

/* Mushaf metrics. The QCF page faces carry the printed mushaf's own tall
   vertical metrics, so the leading that suits Amiri gaps them apart, and mushaf
   type reads better one step larger. Tuned by eye; do not "correct" these. */
.verse-list.arstyle-mushaf .verse__arabic {
  font-size: calc(var(--fs-display) * 1.125 * var(--ar-scale, 1));
  line-height: var(--lh-arabic-mushaf);
}

.verse-list.arstyle-mushaf .verse__end { transform: none; }

/* Word spacing, and why it is a subtraction.

   The gap between two words is a literal U+0020 in the markup, and it is drawn
   by the element's own family rather than by the page face bound to the words
   either side of it -- so it is Amiri Quran's space, 292/1000 em, read out of
   the hmtx table of static/fonts/quran/AmiriQuran-Regular.woff2. That is the
   right space for Amiri and much too wide for the QCF glyphs, which are cut for
   the printed page and sit tight.

   quran.com has no space character at all: its words are flex items and the gap
   is margin-inline-end: 0.375rem, flat, so it does not grow with the type. This
   matches that number exactly -- take Amiri's space away, put 0.375rem back --
   at every one of the five sizes and on all three surfaces, whose base sizes
   differ. Removing the space instead would have been closer to quran.com's
   structure and would have broken two things that depend on it: the shadow span
   mushaf.js builds from textContent, and a partial selection copied to the
   clipboard.

   The 0.292 is only correct while Amiri Quran is the first family here. If that
   font is ever replaced, re-read the new one's space advance. */
.verse-list.arstyle-mushaf .verse__arabic,
.verse-bismillah.arstyle-mushaf,
.qs-sample.arstyle-mushaf {
  word-spacing: calc(0.375rem - 0.292em);
}

/* The gap between words is not the gap inside one. 198 words carry a real
   U+0020 within their own glyph code -- the rub el hizb ornament stored
   together with the word that follows it, 195 of them at position 1 of a verse
   -- and word-spacing inherits, so the subtraction above reaches inside the
   span. The V4 faces draw that space themselves at 100/2500 em, which the
   subtraction would turn negative and pull the ornament into the word.

   nowrap for the same 198: without it a line can break at that internal space
   and strand the ornament. quran.com carries it on every word for this reason. */
.arstyle-mushaf .qword,
.arstyle-mushaf .verse__end {
  word-spacing: normal;
  white-space: nowrap;
}


/* The reveal. A glyph code drawn in any other font is garbage rather than a
   fallback, so a word CARRYING A GLYPH stays invisible until its own page face
   has resolved. .qf-glyph is the mark that mushaf.js has swapped the word's
   text for its code: a word without it is still the server's typeset Arabic,
   which is a perfectly good fallback and must stay visible while the faces
   load -- hiding every word here regardless, as this once did, blanked whole
   surahs on slow connections. Only the classes are written by JavaScript;
   these two rules are the whole mechanism, and the is-ready rule must stay
   AFTER the hide rule, which it beats on source order at equal specificity. */
.verse-list.arstyle-mushaf .qword.qf-glyph,
.verse-list.arstyle-mushaf .verse__end.qf-glyph,
.verse-bismillah.arstyle-mushaf .qword.qf-glyph { visibility: hidden; }

.verse-list.arstyle-mushaf .qword.is-ready,
.verse-list.arstyle-mushaf .verse__end.is-ready,
.verse-bismillah.arstyle-mushaf .qword.is-ready { visibility: visible; }


/* ----------------------------------------------------------------------------
   8. Translations

   Every layer is an equal peer: none is subordinate to another, because which
   translation is primary is the reader's choice, not the page's.
   ------------------------------------------------------------------------- */
.verse__translit {
  margin: var(--space-4) 0 0;
  font-family: var(--font-serif);
  font-style: italic;
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  color: var(--ink-soft);
}

.verse__translation {
  margin: var(--space-5) 0 0;
  font-family: var(--font-serif);
  font-size: var(--fs-body-lg);
  line-height: var(--lh-reading);
  color: var(--ink);
}

/* Rizvi's italics are the translator's supplied words. They are content, not
   emphasis, which is why they are toned rather than merely slanted. */
.verse__translation--rizvi i,
.verse__translation--rizvi em {
  font-style: italic;
  color: var(--ink-soft);
}

/* The attribution sits inside its translation paragraph, so hiding a layer
   hides its credit with no separate wiring. No dash prefix: the design brief
   rules out em dashes in copy, and generating one from CSS is still copy. */
.verse__tr-src {
  display: block;
  margin-block-start: var(--space-1);
  font-family: var(--font-sans);
  font-size: var(--fs-caption);
  font-style: normal;
  color: var(--ink-faint);
}


/* ----------------------------------------------------------------------------
   9. Commentary, footnotes, citations
   ------------------------------------------------------------------------- */
.study-note {
  margin-block-start: var(--space-4);
  padding-inline-start: var(--space-4);
  border-inline-start: var(--emph) solid var(--accent-tint);
  font-family: var(--font-serif);
  font-size: var(--fs-body);
  line-height: var(--lh-reading);
  color: var(--ink-soft);
}

.study-note p { margin: 0 0 var(--space-2); }
.study-note p:last-child { margin-block-end: 0; }

.study-note--footnote {
  border-inline-start-color: var(--rule);
  font-size: var(--fs-body-sm);
  color: var(--ink-faint);
}

/* The study shelf: every way deeper into this verse, in one row under it.

   At the foot of the verse and not the head. The offer to go deeper is a next
   step, so it belongs after the thing it is about: above the Arabic it would
   arrive before the reader has met the verse, and it would push the script --
   which has to stay the first and largest thing on the page -- down by a row on
   every verse in the surah.

   Aligned to the start edge and not the end. Every English line in the card
   begins at that margin and the eye returns to it after each one, so that is
   where the next step is already being looked for. A row hanging off the right
   would be the only thing in the column that does, and against left-aligned
   prose it reads as chrome bolted onto the card rather than as the verse's own
   apparatus. Right alignment is the grammar of dismiss and confirm, not of a
   way in to more reading.

   GROUPED, AND WHY THE BOXES CAME OFF
   This row began as three commentaries and is now four kinds of thing, with
   more coming. Eight bordered chips in a wrapping row is a wall: every item
   claims the same weight as the verse's own translation, the eye has no way to
   tell a commentary from a dictionary without reading all eight labels, and
   the shelf ends up the loudest thing in the card -- which is exactly backwards
   for an apparatus whose whole job is to sit under the text and wait.

   So the boxes come off and the structure goes in. A category is one icon and
   the members that follow it; categories are separated by a wide gap, with the
   next icon marking where the next one starts; and the members inside a
   category are separated by an interpunct, because they are alternatives
   rather than separate offers. Nothing is drawn at rest except the words
   themselves and four small marks, and the row's own hairline above is what
   holds it together as a shelf rather than as loose text at the bottom of the
   card. The fill arrives on hover, where it says what is pressable.

   Every separator here is wrap-safe, and that is a requirement rather than a
   nicety: this shelf wraps at the reading measure on every verse that has all
   four categories. See .cites__icon for the rule that was tried and removed,
   and the interpunct below for why it trails rather than leads.

   NO COLOUR PER CATEGORY, AND NO COLOUR PER SOURCE
   The site's rule, stated at length in section 10 for tajweed and again in
   section 13 for the tabs: colour here never carries identity, because a
   reader who cannot separate two hues would then have no way to read what the
   colour was saying. Accent means one thing on this page -- you can press this
   -- and the icons and dividers are the only things carrying category. Both
   survive greyscale, and both are readable when the icons do not load.

   THE 44px FLOOR IS KEPT
   Quiet does not mean small. Every item still stands 44px tall; what changed
   is that the box around it is drawn only under the pointer. */
.cites {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  /* Wide, because this gap IS the boundary between categories; see the note on
     .cites__icon for why there is no rule drawn in it. */
  column-gap: var(--space-5);
  row-gap: 0;
  margin-block-start: var(--space-4);
  /* Clears the rule above, so a hover fill never sits on the hairline. */
  padding-block-start: var(--space-2);
  border-block-start: var(--hair) solid var(--rule-soft);
}

/* Every item on this verse switched off in the display panel. Without this the
   empty row would still spend its margin, its padding and its rule on nothing.
   A descendant match rather than a child one now: the items sit inside their
   groups. */
.cites:not(:has(.cite:not([hidden]))) { display: none; }

/* One category. Wraps as a unit, so a narrow screen breaks the shelf between
   categories before it breaks one open. */
.cites__group {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-1);
}

/* A category whose every member the reader has switched off. Hidden here and
   not in script: static/js/settings.js writes hidden on the members and knows
   nothing about the grouping. */
.cites__group:not(:has(> .cite:not([hidden]))) { display: none; }

/* The category's mark, once for the group rather than once per member. Quiet,
   because it is a label and not a control: the accent in this row means only
   that a thing can be pressed.

   THE ICON IS THE DIVIDER, AND WHY THERE IS NO RULE
   This row was drawn first with a hairline rule standing in each gap, which is
   what a divided row usually means. It cannot work here, and the reason is
   worth writing down so it is not tried again: at the 42.5rem reading measure
   this shelf ALWAYS wraps. Three commentary names, Reflections, Dictionary &
   Grammar and Lectures come to roughly 860px of content in about 615px of
   column, and on a phone it wraps three or four times. A rule drawn on a
   group's leading edge then lands at the START of a wrapped line, dividing it
   from nothing and reading as a stripe down the card's margin -- the one mark
   this site never uses. CSS cannot ask whether an element begins a line, so
   there is no selector that would suppress it.

   So the boundary is carried by the gap and by the mark that opens each group.
   An icon at the head of a run of links is a strong enough left edge to read as
   "a new kind starts here", it costs nothing when a line wraps, and it is the
   same information the rule was carrying.

   INK-SOFT AND NOT INK-FAINT, AND STILL NOT ACCENT
   One step up from the faintest ink on the card. At --ink-faint these were the
   palest thing in the verse, and a mark that has to be READ -- it is carrying
   the category now that no rule does -- cannot also be the quietest thing on
   screen. It stops short of accent deliberately: accent on this page means you
   can press this, the links have it, and a mark that is not pressable must not
   borrow it. Colour per category was asked for and declined; the reasoning is
   in PROJECT_BRAIN.md under this date, and it comes down to the verse above
   these icons already spending colour on tajweed, where colour means
   something. */
.cites__icon {
  width: 15px;
  height: 15px;
  flex: none;
  color: var(--ink-soft);
}

/* The item slot. The paragraph stays in the markup rather than the link taking
   its classes, because static/js/settings.js hides a source by putting hidden
   on .cite--<slug> and static/js/tafsir.js reads .cite--tafsir a[href]: both
   want the wrapper and the link to be two elements. Flex so the interpunct
   below sits on the text's own line. */
.cite {
  display: flex;
  align-items: center;
  margin: 0;
  font-family: var(--font-sans);
  font-size: var(--fs-body-sm);
}

/* An author rule that sets display outranks the user agent's [hidden] rule,
   which is only display:none, so the line above silently disables the reader's
   own switches: settings.js writes hidden and nothing moves. This row carried
   no display at all before the categories arrived, precisely so that it never
   had to say this. It does now, so it says it. */
.cite[hidden] { display: none; }

/* Between two commentaries on the same verse, and only between. A separator
   and not a bullet, so the three read as alternatives rather than as a list.

   TRAILING AND NOT LEADING
   Written as "every showing item that still has a showing item after it",
   rather than the shorter "every showing item after the first". The two select
   the same set until the row wraps, and this shelf wraps constantly: a leading
   dot lands at the START of the new line, where it sits in the card's margin
   pointing at nothing. A trailing one lands at the end of the line above,
   where a separator left hanging reads as "continues" -- which is true.

   The :not([hidden]) on both sides is load-bearing for the reader's switches:
   turning the last source off must not leave a dot trailing the row, and
   turning a middle one off must not leave two dots together. */
.cites__group--tafsir > .cite:not([hidden]):has(~ .cite:not([hidden]))::after {
  content: "\00B7";
  margin-inline-start: var(--space-1);
  color: var(--ink-faint);
}

/* The launcher, in both of its forms. The tafsir and reflections items are
   anchors carrying a real href to the publisher, so they survive a middle
   click, a long press and a page with no JavaScript, where the panel does not
   exist and the source still has to be reachable. Word study and lectures are
   buttons, because there is no publisher on the other end of them and an href
   would be promising something that does not exist. They are dressed
   identically and said once, rather than a button ruleset repeating an anchor
   ruleset in another section and drifting from it. */
.cites .cite > a,
.cites button.cite {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding-inline: var(--space-2);
  border: 0;
  border-radius: var(--radius-control);
  background: none;
  color: var(--accent-strong);
  font-family: var(--font-sans);
  font-size: var(--fs-body-sm);
  text-decoration: none;
  cursor: pointer;
  transition: background-color var(--dur) var(--ease-calm);
}

/* The fill replaces the underline, and is the whole of the hover state now
   that there is no border to tint. */
.cites .cite > a:hover,
.cites button.cite:hover {
  background: var(--accent-tint);
}


/* ----------------------------------------------------------------------------
   10. Tajweed, thirteen rules

   Colour applies only while the list carries .tajweed-on. The markup always
   carries the runs, so turning colour off is a class flip and never a re-render.

   Thirteen rules cannot be separated by colour: measured on this palette, the
   closest pair sits at deltaE 1.6 under deuteranopia, which is identical. That
   is not a fault of these particular values, it is what asking colour to carry
   thirteen categories means. Section 11 is therefore not a nicety.
   ------------------------------------------------------------------------- */
.verse__arabic tajweed,
.verse-bismillah tajweed { color: inherit; }

.verse-list.tajweed-on tajweed.ham_wasl,
.verse-list.tajweed-on tajweed.slnt,
.verse-list.tajweed-on tajweed.laam_shamsiyah { color: var(--tj-silent); }
.verse-list.tajweed-on tajweed.madda_normal { color: var(--tj-madd-normal); }
.verse-list.tajweed-on tajweed.madda_permissible { color: var(--tj-madd-permissible); }
.verse-list.tajweed-on tajweed.madda_necessary,
.verse-list.tajweed-on tajweed.madda_obligatory { color: var(--tj-madd-necessary); }
.verse-list.tajweed-on tajweed.qalaqah { color: var(--tj-qalqalah); }
.verse-list.tajweed-on tajweed.ikhafa { color: var(--tj-ikhfa); }
.verse-list.tajweed-on tajweed.ikhafa_shafawi { color: var(--tj-ikhfa-shafawi); }
.verse-list.tajweed-on tajweed.idgham_ghunnah { color: var(--tj-idgham-ghunnah); }
.verse-list.tajweed-on tajweed.idgham_wo_ghunnah { color: var(--tj-idgham-plain); }
.verse-list.tajweed-on tajweed.idgham_shafawi { color: var(--tj-idgham-shafawi); }
.verse-list.tajweed-on tajweed.idgham_mutajanisayn,
.verse-list.tajweed-on tajweed.idgham_mutaqaribayn { color: var(--tj-idgham-close); }
.verse-list.tajweed-on tajweed.iqlab { color: var(--tj-iqlab); }
.verse-list.tajweed-on tajweed.ghunnah { color: var(--tj-ghunnah); }


/* ----------------------------------------------------------------------------
   11. Tajweed without colour, the second channel

   Added by .tj-shapes on the list. Each rule FAMILY takes an underline style,
   which is also how the rules are taught: madd is one thing with three lengths,
   ikhfa is one thing with two places, idgham is one thing with four.

   The offset is generous because Arabic descends well below the baseline; a
   default underline would strike through the script rather than sit under it.
   Off by default, because a reader who can see the colours should not have to
   look at both.
   ------------------------------------------------------------------------- */
.verse-list.tj-shapes tajweed {
  text-decoration-line: underline;
  text-underline-offset: 0.42em;
  text-decoration-thickness: from-font;
}

/* Silent letters are not pronounced, so the absence of a mark is the mark. */
.verse-list.tj-shapes tajweed.ham_wasl,
.verse-list.tj-shapes tajweed.slnt,
.verse-list.tj-shapes tajweed.laam_shamsiyah { text-decoration-line: none; }

/* Madd: held. A solid line, doubling as the length grows. */
.verse-list.tj-shapes tajweed.madda_normal { text-decoration-style: solid; }
.verse-list.tj-shapes tajweed.madda_permissible { text-decoration-style: double; }
.verse-list.tj-shapes tajweed.madda_necessary,
.verse-list.tj-shapes tajweed.madda_obligatory {
  text-decoration-style: double;
  text-decoration-thickness: 2px;
}

/* Qalqalah: an echo. A wavy line. */
.verse-list.tj-shapes tajweed.qalaqah { text-decoration-style: wavy; }

/* Ikhfa: hidden. Dotted, the quietest mark. */
.verse-list.tj-shapes tajweed.ikhafa,
.verse-list.tj-shapes tajweed.ikhafa_shafawi { text-decoration-style: dotted; }

/* Idgham: merged. Dashed, the mark of two things becoming one. */
.verse-list.tj-shapes tajweed.idgham_ghunnah,
.verse-list.tj-shapes tajweed.idgham_wo_ghunnah,
.verse-list.tj-shapes tajweed.idgham_shafawi,
.verse-list.tj-shapes tajweed.idgham_mutajanisayn,
.verse-list.tj-shapes tajweed.idgham_mutaqaribayn { text-decoration-style: dashed; }

/* Iqlab: converted. Wavy, thicker, distinct from qalqalah by weight. */
.verse-list.tj-shapes tajweed.iqlab {
  text-decoration-style: wavy;
  text-decoration-thickness: 2px;
}

/* Ghunnah: nasal, held in the nose. Dotted and heavier than ikhfa. */
.verse-list.tj-shapes tajweed.ghunnah {
  text-decoration-style: dotted;
  text-decoration-thickness: 2px;
}

/* Where the platform has taken colour away entirely, the shapes are not
   optional. */
@media (forced-colors: active) {
  .verse-list tajweed { text-decoration-line: underline; text-underline-offset: 0.42em; }
}


/* ----------------------------------------------------------------------------
   12. The surah index
   ------------------------------------------------------------------------- */
.surahs { padding-block: var(--space-5) var(--space-8); }

/* The list's top margin exists to clear the heading above it. On the all-surahs
   view that heading is now carried for assistive technology only and takes no
   space, so the margin was separating the list from nothing and the page opened
   with 48px of empty parchment. The ?q= view still prints its heading, and the
   adjacency below is what tells the two apart without a second class. */
.visually-hidden + .surahlist { margin-block-start: 0; }

.surahlist {
  margin: var(--space-5) 0 0;
  padding: 0;
  list-style: none;
  border-block-start: var(--hair) solid var(--rule-soft);
}

.surahrow { border-block-end: var(--hair) solid var(--rule-soft); }

/* The row's three parts sit together in the middle rather than being pushed to
   the two ends of it.

   They used to be spread by a 1fr names column, which made the space between
   the transliteration and the Arabic the widest thing in the row: measured at
   390px, "Al-Fatihah" ended at x=170 and the Arabic began at x=323, so 150px
   of nothing stood between the two names of the same surah. The edges were
   uneven with it -- the number is right-aligned in its column, so the first ink
   sat 41px inside the row's own hairline while the Arabic sat 8px from the
   other end. Every track is content-sized now and the group is centred, which
   closes the gap and makes the two margins equal by construction rather than by
   a number chosen to look equal.

   The tracks are AUTHORED widths rather than content widths, and that is the
   part that matters. Each row is its own grid, so sizing tracks to their own
   content centres each row on its own name: measured over the first twenty
   rows, the number's left edge wandered across 45px and the list stopped
   reading as a list. Fixed tracks are identical in every row, so the columns
   line up down the page AND the group is centred, and the two margins are
   equal because the centring puts them there, not because a number was chosen
   to make them look it.

   10rem holds the longest transliteration and the longest meaning, both 156px
   at this size; 4.25rem holds the widest Arabic name, 65px. The middle track
   is a minmax so it gives way first on a 320px screen instead of pushing the
   row wider than the page. The breakpoint takes the spread layout back, where
   there is width enough for the columns to be a table and the facts to have
   somewhere to live. */
.surahrow__link {
  display: grid;
  grid-template-columns: 1.75rem minmax(0, 10rem) 4.25rem;
  justify-content: center;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3);
  text-decoration: none;
  color: var(--ink);
}

.surahrow__link:hover { background: var(--paper-sunk); }

/* Aligned to the start, so a single digit begins where "114" begins and the
   first ink in the row is the same distance from the edge on every row. Ending
   it, which is the book-index convention and what the spread layout uses,
   right-aligns the digit inside its track and leaves a hole in front of it: a
   21px one for surahs 1 to 9, which is most of what a reader sees first, and
   the hole is the whole complaint this layout was rebalanced to answer. */
.surahrow__num {
  font-family: var(--font-sans);
  font-size: var(--fs-caption);
  font-variant-numeric: tabular-nums;
  color: var(--ink-faint);
  text-align: start;
}

.surahrow__names { display: flex; flex-direction: column; }

.surahrow__name {
  font-family: var(--font-serif);
  font-size: var(--fs-body-lg);
  line-height: var(--lh-tight);
}

.surahrow__meaning {
  font-family: var(--font-sans);
  font-size: var(--fs-caption);
  color: var(--ink-faint);
}

.surahrow__arabic {
  font-family: "Amiri Quran", var(--font-arabic);
  font-size: var(--fs-h3);
  line-height: 1.6;
  color: var(--ink);
}

.surahrow__facts {
  display: none;
  font-family: var(--font-sans);
  font-size: var(--fs-caption);
  color: var(--ink-faint);
}


/* ----------------------------------------------------------------------------
   14. Display settings

   Insert this section BEFORE section 13, so the one width breakpoint stays the
   last thing in the file. Nothing here needs a width query: the panel widens on
   auto-fit tracks, which respond to the space they are actually given.

   Every visual state the panel produces is a class or the hidden attribute,
   because no JavaScript on this page may write a CSS declaration. Under
   default-src 'self' a <style> element is blocked, and so is sheet.insertRule()
   on an empty one, silently, leaving element.sheet null. The header of
   static/js/mushaf.js records how that was found out. static/js/settings.js
   therefore flips class names and attributes and nothing else, the Arabic size
   included.
   ------------------------------------------------------------------------- */

/* The trigger this section used to style sat in the chrome row. It moved into
   the masthead when the surah identity did, and is styled there as
   .masthead__display in base.css; the rules for the old one were deleted on
   2026-08-19 once nothing carried the class. */

/* The panel drops from the button that opens it and floats over the verses,
   rather than sitting in the page and pushing them down. That is the whole
   point: a reader changing a switch is looking at the text it changes, and a
   panel that shoves the text off screen makes them adjust blind.

   Anchored to .masthead__actions, which is positioned for exactly this. It
   never pushes anything, so the layout below is identical open or closed. */
.qs-panel {
  position: absolute;
  inset-block-start: calc(100% + var(--space-2));
  inset-inline-end: 0;
  z-index: 95;                 /* within the sticky header, which is at 92 */
  /* --qs-pagew and not 100vw. This panel is 54rem, absolutely positioned, and
     anchored to the inline END of the masthead's action strip, so everything
     it occupies lies to its START side. A panel open beside the page pads
     <body> out of the way and the strip's end edge comes with it -- at 1400
     that edge lands at 668, and 864px of panel hung 196px off the left of the
     window, taking THEME, TRANSLATION and DISPLAY & AUDIO with it. Reported
     2026-08-23, and reachable from all four panels since each pads <body> the
     same way. The window was never the measurement; the page is. */
  width: min(54rem, calc(var(--qs-pagew, 100vw) - 2 * var(--gutter)));

  /* No fixed cap paired with the viewport one. 34rem was under the height of
     the five groups, so the panel scrolled on every window rather than only a
     short one, and a reader looking for a switch had to find it twice. The
     groups are laid out and spaced below to clear this on a laptop; overflow
     stays as the last resort for a window shorter than any layout can serve. */
  /* See the note at .contents__list for why this is written twice. */
  max-height: calc(100vh - 6rem);
  max-height: calc(100dvh - 6rem);
  overflow-y: auto;
  overscroll-behavior: contain;
  margin: 0;
  padding: var(--space-4);
  border: var(--hair) solid var(--rule-strong);
  border-radius: var(--radius);
  background: var(--paper-raised);
  box-shadow: var(--shadow-soft);
  font-family: var(--font-sans);
  text-align: start;

  /* The drop. transform and opacity only, so nothing below is ever reflowed. */
  transform: translateY(-0.4rem);
  opacity: 0;
  transition: transform var(--dur) var(--ease-calm), opacity var(--dur) var(--ease-calm);
}

/* settings.js clears the hidden attribute, then a frame later adds is-open, so
   the transition has a state to run from. */
.qs-panel.is-open { transform: none; opacity: 1; }

.qs-panel__head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-4);
  padding-block-end: var(--space-2);
  border-block-end: var(--hair) solid var(--rule-soft);
}

.qs-panel__title {
  flex: 1 1 auto;
  margin: 0;
  font-family: var(--font-sans);
  font-size: var(--fs-label);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--accent-strong);
}

/* The two modes are one control, not two buttons. They share a single outline
   with a divider between them, which is the shape a reader already reads as
   "pick one of these", and only the running one is filled. That fill is the
   only solid colour in the head, so which mode is on is answerable without
   reading anything.

   Neither is filled when the switches are neither preset, which is the state
   the page ships in and the state a reader lands in the moment they touch a
   checkbox. That is a third thing worth showing, and showing it costs nothing:
   an empty track reads as "neither", where a stuck highlight would read as a
   promise the page is not keeping. */
.qs-modes {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
}

.qs-modes__label {
  font-size: var(--fs-label);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.qs-modes__track {
  position: relative;
  display: inline-flex;
  padding: 2px;
  border: var(--hair) solid var(--rule);
  border-radius: var(--radius-pill);
  background: var(--paper-sunk);
}

/* The divider, which speaks only while the track is empty: two names sharing a
   groove could be one label wrapped, and a line between them makes it a fork.
   It is drawn on the track rather than on a segment, because a segment is a
   pill and an inset edge drawn on a pill radius comes out as an arc. Once
   either mode is filled the fill draws that edge, so the line retires. Both
   segments are min-width equal, so the centre is the seam. */
.qs-modes__track::before {
  content: "";
  position: absolute;
  inset-block: 22%;
  inset-inline-start: 50%;
  width: 1px;
  background: var(--rule-strong);
}

.qs-modes__track:has(.qs-mode[aria-pressed="true"])::before { content: none; }

.qs-mode {
  /* Both segments are the same width whichever is on, so the pressed weight
     below cannot shuffle the head sideways as the reader switches modes. */
  min-width: 5rem;
  min-height: 44px;
  padding-inline: var(--space-3);
  border: 0;
  border-radius: var(--radius-pill);
  background: none;
  font-family: var(--font-sans);
  font-size: var(--fs-body-sm);
  color: var(--ink-soft);
  cursor: pointer;
}

.qs-mode:hover { color: var(--ink); }

.qs-mode[aria-pressed="true"] {
  background: var(--accent);
  color: var(--paper-raised);
  font-weight: 600;
}

.qs-btn {
  min-height: 44px;
  padding-inline: var(--space-4);
  border: var(--hair) solid var(--rule);
  border-radius: var(--radius-pill);
  background: var(--paper-sunk);
  font-family: var(--font-sans);
  font-size: var(--fs-body-sm);
  color: var(--ink);
  cursor: pointer;
}

.qs-btn:hover { border-color: var(--rule-strong); }

/* Reset is the one destructive control in the panel, so it is the quietest. */
.qs-btn--quiet {
  border-color: transparent;
  background: none;
  color: var(--ink-soft);
}

.qs-btn--quiet:hover { border-color: var(--rule); }


/* Five fieldsets down as many columns as the panel has room for. Columns, not
   a grid of tracks: a grid puts each fieldset in a cell of its own, so five of
   them across four tracks leaves one alone on a second row and every track as
   tall as the tallest thing in it. Flowed columns pack the groups end to end
   and balance the heights, which is what takes the panel under the height of a
   laptop window and stops it scrolling.

   This still answers the width the panel actually has rather than the width of
   the window, so section 14 adds nothing to the breakpoint. */
.qs-groups {
  column-width: 14rem;
  column-gap: var(--space-5);
  margin-block-start: var(--space-3);
}

.qs-group {
  min-width: 0;
  margin: 0 0 var(--space-3);
  padding: 0;
  border: 0;

  /* Without this a column break can fall between a legend and its switches,
     leaving the heading at the foot of one column and what it heads at the top
     of the next. */
  break-inside: avoid;
}

/* The flow has already spaced the groups; the last one in each column must not
   push the panel's own padding down as well. */
.qs-group:last-child { margin-block-end: 0; }

.qs-group__legend {
  padding: 0;
  font-size: var(--fs-label);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.qs-row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-height: 44px;
  font-size: var(--fs-body-sm);
  line-height: var(--lh-body);
  color: var(--ink);
  cursor: pointer;
}

/* The dependent row is hidden rather than disabled, and the rule above sets
   display, so the attribute needs saying twice to be obeyed. */
.qs-row[hidden] { display: none; }

.qs-row input {
  flex: none;
  width: 1.05rem;
  height: 1.05rem;
  margin: 0;
  accent-color: var(--accent);
  cursor: pointer;
}


/* The size stepper, and the live sample under it. Under rather than beside:
   the sample is a line of Qur'anic script and the column is 14rem wide, so
   sharing the line left it about 150px to show three words at reading size.
   Stacked it gets the column's full width, which is the width the stepper is
   actually changing. */
.qs-size {
  display: flex;
  flex-direction: column;
  align-items: start;
  gap: var(--space-2);
  margin-block-start: var(--space-3);
}

.qs-stepper {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
}

.qs-step {
  min-width: 44px;
  min-height: 44px;
  border: var(--hair) solid var(--rule);
  border-radius: var(--radius-control);
  background: var(--paper-sunk);
  font-family: var(--font-serif);
  font-size: var(--fs-body);
  color: var(--ink);
  cursor: pointer;
}

.qs-step:hover { border-color: var(--rule-strong); }

/* aria-disabled, not disabled: a button that disables itself at the end of the
   range throws focus back to the document and strands the keyboard. */
.qs-step[aria-disabled="true"] {
  border-color: var(--rule-soft);
  color: var(--ink-faint);
  cursor: default;
}

.qs-level {
  min-width: 2ch;
  font-size: var(--fs-body-sm);
  font-variant-numeric: tabular-nums;
  color: var(--ink-soft);
  text-align: center;
}

/* No display property: an empty slot on a surah served without word data is
   closed by the hidden attribute. */
.qs-sample-slot {
  /* Stretch, not a flex basis: the parent is a column now, so a basis would be
     read as a height and cap the sample rather than widen it. */
  align-self: stretch;
  min-width: 0;
}

/* The sample carries .verse-list and a font base, so QSMushaf.apply drives it
   through the same glyph swap, reveal and tajweed colouring as the verses. Its
   base size is a panel size rather than a verse size, but it multiplies by the
   same --ar-scale, so a step of the stepper is shown in proportion. */
.qs-sample.verse-list {
  /* .verse-list is a column flex, which on a line of words would stack them one
     per line. The same correction .verse-bismillah makes, for the same reason. */
  display: block;
  margin: 0;
  font-family: "Amiri Quran", var(--font-arabic);
  font-size: calc(var(--fs-h2) * var(--ar-scale, 1));
  line-height: var(--lh-arabic-typeset);
  color: var(--ink);
}

.qs-sample.arstyle-mushaf { line-height: var(--lh-arabic-mushaf); }


/* The five Arabic sizes. --ar-scale is set here and only here: JavaScript
   chooses which class is on and never what it means, because it may not write
   a declaration at all. The class lands on every .verse-list, which is the
   bismillah, the study list and the panel's sample, so all three step together.
   The steps are 0.85, 1, 1.15, 1.3 and 1.5, level 2 being the shipped size. */
.ar-1 { --ar-scale: 0.85; }
.ar-2 { --ar-scale: 1; }
.ar-3 { --ar-scale: 1.15; }
.ar-4 { --ar-scale: 1.3; }
.ar-5 { --ar-scale: 1.5; }


/* Grouping off. The headings go, and the section stops being a box of its own,
   so every verse is a direct child of the list's column again and regains its
   own card and the list's own spacing. */
.verse-list.no-grouping .study-topic,
.verse-list.no-grouping .study-sub { display: none; }

.verse-list.no-grouping .study-group { display: contents; }


/* The tajweed legend. Shown only while a tajweed style is running; settings.js
   closes it with the hidden attribute, and nothing here sets display on the
   details itself. */
.qs-legend {
  margin-block-start: var(--space-3);
  padding-block-start: var(--space-2);
  border-block-start: var(--hair) solid var(--rule-soft);
  font-size: var(--fs-body-sm);
}

.qs-legend > summary {
  display: flex;
  align-items: center;
  min-height: 44px;
  color: var(--ink-soft);
  cursor: pointer;
  list-style: none;
}

.qs-legend > summary::-webkit-details-marker { display: none; }

/* The list carries .verse-list.tajweed-on so that section 10 colours it. The
   legend then reads the mapping the verses read, rather than a second copy of
   it that can drift. */
.qs-legend__list.verse-list {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: var(--space-1) var(--space-4);
  margin: 0;
  padding-block: var(--space-1) var(--space-2);
}

.qs-legend__item {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-height: 2rem;
  color: var(--ink-soft);
}

/* A run of tatweel, which is a joining stroke and not a letter. A real word
   would claim that this rule falls on that word; a stroke claims only its
   colour, which is all the legend is for. */
.qs-legend__swatch {
  flex: none;
  width: 2.25rem;
  font-family: "Amiri Quran", var(--font-arabic);
  font-size: var(--fs-body-lg);
  line-height: 1;
  text-align: center;
}

.qs-legend__note {
  margin-block-start: var(--space-2);
  font-size: var(--fs-caption);
  line-height: var(--lh-body);
  color: var(--ink-faint);
}


/* Every control in the panel is a 44px target, which is the right size under a
   thumb and a wasteful one under a cursor. At 44px the five groups stand taller
   than a laptop window and the panel goes back to scrolling, and hunting a
   switch through a scroller costs a reader far more than a tight row does. So
   the touch size stays the default and only a fine pointer gets the condensed
   one. Nothing here changes what a control is or where it sits, only how much
   room it takes: the hit area of a row still spans the panel's full column,
   because the label is part of the label element. */
@media (pointer: fine) {
  .qs-row { min-height: 1.9rem; }
  .qs-size { margin-block-start: var(--space-2); }
  .qs-step { min-width: 2.25rem; min-height: 2.25rem; }
  .qs-btn { min-height: 2.25rem; }
  .qs-mode { min-height: 2.25rem; }
  .qs-legend > summary { min-height: 2rem; }
  .qs-legend__item { min-height: 1.7rem; }
}

/* ----------------------------------------------------------------------------
   Word by word: the hover highlight and the tooltip

   One floating piece serves the whole page rather than one per word: the
   tooltip, position: fixed and moved by writing left and top from
   static/js/words.js. Those two declarations are the only CSS that file
   writes, and they are unavoidable: a viewport-positioned element has no other
   way to be placed, and the numbers are measured from a particular word under
   a particular scroll position, so no stylesheet could hold them. Every other
   state it takes is a class, for the reason recorded at the top of
   static/js/mushaf.js: this policy blocks a stylesheet assembled in
   JavaScript, and blocks it silently.

   position: fixed also means no ancestor of this element may carry a
   transform, a filter or a perspective, which is why the markup for it sits
   at the end of the content block rather than inside the reading column.

   The element is .wbw-panel and not the more obvious .wbw-tip because
   static/js/settings.js puts .wbw-tip on the verse list itself, as the state
   class for the transliteration line. Under the shorter name every rule below
   would have landed on the list: the whole surah would have become a fixed
   20rem box. Keep these two namespaces apart.
   ------------------------------------------------------------------------- */

/* The display rule below outranks the user agent's own [hidden] rule, so
   hiding has to be restated here or the tooltip never goes away. */
.wbw-panel[hidden] { display: none; }

/* Only a word that carries a clip is a target, so the cursor never promises
   something the bismillah or the ayah medallion cannot do. */
.verse-list.wbw-on .qword[data-a] { cursor: pointer; }

/* The listening highlight. A background and never a colour: in the Mushaf
   styles the glyph colour comes from inside the QCF font, as COLR layers over
   CPAL palette 0, and CSS color cannot reach it, so a colour-based highlight
   would be invisible in the default reading style. No padding and no border
   either, because the word must not change size as it starts and stops.

   Not behind .wbw-on, unlike the hover rule below it. This mark now has two
   sources: a word tapped for its own clip, which only happens while word by
   word is on, and a verse being recited, which has nothing to do with that
   switch -- a reader listening to a surah with the glosses turned off must
   still see where the reciter is. The narrower selector was correct while
   there was one source and would have made the recitation highlight vanish
   for anyone who had turned the tooltips off. */
.verse-list .qword.is-playing {
  background: var(--accent-tint);
  border-radius: var(--radius-control);
  box-decoration-break: clone;
  -webkit-box-decoration-break: clone;
}

/* The hover highlight, and the reason there is no longer a disc lying on the
   word. A reader sweeping a line wants to know which word the tooltip is
   describing, and the word itself can say so: this is the same treatment as
   .is-playing above, for the same COLR/CPAL reason -- a background, never a
   colour -- one step fainter, so a word being read aloud still outranks a word
   merely under the pointer.

   Drawn by the stylesheet on :hover rather than by a class from words.js. It
   costs no script, it cannot lag behind the pointer, and it survives the
   150ms the tooltip deliberately waits before opening: the word answers at
   once, the gloss follows when the reader has settled.

   Behind hover: hover because a touch screen keeps :hover on the last thing
   tapped, which would leave a word highlighted for the rest of the surah. */
@media (hover: hover) {
  .verse-list.wbw-on .qword[data-a]:hover {
    background: var(--accent-wash);
    border-radius: var(--radius-control);
    box-decoration-break: clone;
    -webkit-box-decoration-break: clone;
  }

  /* A word that is sounding keeps its own, stronger mark while hovered. */
  .verse-list .qword.is-playing:hover { background: var(--accent-tint); }
}

.wbw-panel {
  position: fixed;
  inset-block-start: 0;
  inset-inline-start: 0;
  z-index: 61;
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  max-inline-size: min(20rem, calc(100vw - (var(--gutter) * 2)));
  padding: var(--space-2) var(--space-3);
  border: var(--hair) solid var(--rule-strong);
  border-radius: var(--radius-control);
  background: var(--paper-raised);
  box-shadow: var(--shadow-soft);
  font-family: var(--font-sans);
  line-height: var(--lh-body);
  text-align: start;
  /* A hover tooltip must not stand between the pointer and the text under it.
     The touch panel below takes the pointer back, because there it is the only
     thing carrying a control. */
  pointer-events: none;

  /* The edge nearest the word carries the accent. This is what ties the box to
     the word it is about, and it survives the horizontal clamp that a pointing
     tail would not: a clamped tail points at the wrong word, which is worse
     than no tail at all. */
  border-block-end-width: var(--emph);
  border-block-end-color: var(--accent);
}

/* Flipped below the word when there was no room above. The accent moves to the
   other edge, and the two border widths simply trade places, so the box is the
   same height in both states. static/js/words.js relies on that: it measures
   once and does not re-measure after the flip. */
.wbw-panel--below {
  border-block-start-width: var(--emph);
  border-block-start-color: var(--accent);
  border-block-end-width: var(--hair);
  border-block-end-color: var(--rule-strong);
}

.wbw-panel__gloss {
  font-size: var(--fs-body-sm);
  color: var(--ink);
}

/* Latin transliteration inside an otherwise unmarked box that may sit beside
   right-to-left text. */
.wbw-panel__tl {
  font-size: var(--fs-caption);
  letter-spacing: 0.02em;
  color: var(--ink-faint);
  direction: ltr;
}

/* The play button inside the panel exists only on touch, where there is no
   hover for the floating control to follow. It is a full 44px target, unlike
   the control, which is a pointer affordance and is never tapped. */
.wbw-panel__play {
  /* A flex item, so inline-flex would be blockified to flex anyway. Written as
     what it computes to, rather than as something the cascade then changes. */
  display: none;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-block-size: 44px;
  margin-block-start: var(--space-1);
  padding-inline: var(--space-3);
  border: var(--hair) solid var(--rule);
  border-radius: var(--radius-control);
  background: var(--paper-sunk);
  color: var(--accent-strong);
  font-family: var(--font-sans);
  font-size: var(--fs-caption);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  cursor: pointer;
}

.wbw-panel--touch { pointer-events: auto; }
.wbw-panel--touch .wbw-panel__play { display: flex; }

/* The icon inside the panel's own play button, which is a real 44px tap
   target on touch and the only way to hear a word where there is no hover. */
.wbw-panel__icon { flex: none; }

/* ----------------------------------------------------------------------------
   13. The tafsir panel

   A citation opens the commentary beside the verse rather than over it. From
   62rem up the panel takes half the viewport and <body> is padded into the
   other half, so the surah is pushed rather than covered and stays scrollable,
   selectable and clickable throughout. That threshold is the split's own and is
   not the 600px the rest of this file widens at; section 17 says why.

   Below it there is no half worth pushing into: a 50vw panel on a 390px phone
   is 195px, and on a 768px tablet it leaves the Qur'an 320px, narrower than the
   phone gives it. Neither is a column anybody can read a tafsir in. So the
   panel rises from the foot of the screen instead and covers the page and the
   sticky header both, stopping one --space-7 short of the top. That strip is
   the scrim showing through, and it is the second way out: it is tappable, it
   clears the touch floor at 48px, and it keeps the page visible behind the
   sheet so the reader can see what they are on top of rather than losing the
   surah entirely.

   The root spans the viewport so the panel can be anchored against it, and
   takes no pointer events at all; the panel, and on a sheet the scrim, put them
   back. That is what leaves the left half live.

   CLOSED IS visibility, SO IS THE INACTIVE PANE, AND NEITHER MAY BECOME
   display:none. The Al-Mizan pane holds a cross-origin iframe whose scroll
   offset can be neither read nor written, so it cannot be saved and put back:
   the only way to keep the reader's place is never to destroy the frame's
   layout box. display:none destroys it, and so does unmounting or moving the
   element. visibility: hidden suppresses painting and hit testing and leaves
   the box, its size and its scroll offset alone, which is the entire reason it
   is spelled that way here. See the head of static/js/tafsir.js.

   visibility is inherited, and a descendant declaring visible overrides a
   hidden ancestor. So the two states are combined in the selectors rather than
   stacked: a pane is visible only when it is the active pane of an open panel.
   ------------------------------------------------------------------------- */
.tafsir {
  position: fixed;
  inset: 0;
  /* Above the word-by-word floats, which sit at 60 and 61. While the panel is
     open it is the foreground surface, and a tooltip drawn over it reads as a
     rendering fault rather than as a layer.

     94 rather than 90 because the sheet has to cover the sticky masthead, which
     is 92 and would otherwise sit on top of a surface that is meant to be the
     whole screen. The display and search panels are numbered above this, but
     they are numbered INSIDE the masthead's stacking context, so the header's
     92 is the only figure that competes and 94 clears it. The breakpoint puts
     this back to 90: beside a split the header must stay reachable. */
  z-index: 94;
  pointer-events: none;
}

/* The page behind the sheet must not scroll out from under it. Set on <body>
   rather than on the root because <html> declares no overflow of its own, so
   this propagates to the viewport; the scroll offset is kept, because a
   scroll container that becomes hidden holds its position. If a rule is ever
   added that gives <html> an overflow, this stops working silently.

   The split undoes it in the breakpoint block, where the half beside the panel
   is meant to go on scrolling. */
body.tafsir-open { overflow: hidden; }

/* The veil under the sheet. --paper-sunk is the darkest surface token in both
   themes, so this reads as the desk the sheet is lying on in light and as a
   blackout in dark, with no rule asking which theme is running. */
.tafsir__scrim {
  position: absolute;
  inset: 0;
  background: var(--paper-sunk);
  opacity: 0;
  transition: opacity var(--dur-slow) var(--ease-calm);
}

.tafsir.is-open .tafsir__scrim {
  opacity: 0.92;
  pointer-events: auto;
}

.tafsir__panel {
  position: absolute;
  /* The strip at the top is the scrim showing through, and the way out for a
     thumb. The breakpoint closes it up: a split has no strip. */
  inset-block-start: var(--space-7);
  inset-block-end: 0;
  inset-inline-end: 0;
  inline-size: 100%;
  display: flex;
  flex-direction: column;
  background: var(--paper);
  /* The sheet's lip, under the strip. The split moves this rule to the inline
     start, where the panel meets the page rather than the scrim. */
  border-block-start: var(--hair) solid var(--rule);
  box-shadow: var(--shadow-soft);
  pointer-events: auto;
  visibility: hidden;
  /* The sheet rises from the foot of the screen; 101% keeps the shadow off the
     page while it is away. Above the breakpoint it arrives from the right
     instead, which is where the panel is anchored and where the half it takes
     is: no logical form of a translation exists, and the document is LTR. */
  transform: translateY(101%);
  /* Opening flips visibility in the same frame, so focus can be moved into the
     panel at once. Closing holds it until the slide has finished. */
  transition: transform var(--dur-slow) var(--ease-calm),
              visibility 0s linear var(--dur-slow);
}

/* none rather than a zero translation on either axis, so ONE open state serves
   the sheet and the split and only the closed state has to be re-aimed at the
   breakpoint. It is also what keeps a viewport crossing the breakpoint while
   the panel is open from animating between two different zero points. */
.tafsir.is-open .tafsir__panel {
  visibility: visible;
  transform: none;
  transition: transform var(--dur-slow) var(--ease-calm),
              visibility 0s;
}


/* The bar: the two sources, and the way out. */
.tafsir__bar {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex: none;
  min-block-size: var(--panel-bar-min, 44px);
  padding-inline: var(--space-3);
  border-block-end: var(--hair) solid var(--rule);
  background: var(--paper-raised);
}

.tafsir__tabs {
  display: flex;
  gap: var(--space-1);
  flex: 1 1 auto;
  min-inline-size: 0;
  overflow-x: auto;
}

/* One tab is filled and the others are not. Deliberately not a colour per
   source: the tab already carries the source's name, so a palette would ask the
   reader to learn three colour-to-name mappings that pay nothing back, it would
   make colour the thing that says which commentary this is, which is exactly
   what a colour-blind reader cannot use, and it would need three tints that
   hold up in both schemes. The strip has one question to answer, "which am I
   reading", and one filled tab answers it. Three filled tabs answer nothing.

   The top corners are rounded and the bottom two are not, so the filled tab
   reads as continuous with the pane under it rather than as a loose chip. */
.tafsir__tab {
  flex: none;
  /* Named rather than left to the button default. It was never a decision
     that these read lighter than the other three panels' nameplates: nothing
     here set a weight, so they took 400 from the user agent while the word
     study tab carried a considered 600. Same row, same job, same weight. */
  font-weight: 600;
  min-block-size: 44px;
  padding-inline: var(--space-3);
  border: 0;
  border-block-end: var(--emph) solid transparent;
  border-start-start-radius: var(--radius-control);
  border-start-end-radius: var(--radius-control);
  background: none;
  color: var(--ink-soft);
  font-family: var(--font-sans);
  font-size: var(--fs-body-sm);
  white-space: nowrap;
  cursor: pointer;
  transition: background-color var(--dur) var(--ease-calm),
              color var(--dur) var(--ease-calm);
}

/* An unchosen tab lights on hover, which is what says the strip can be flipped
   through rather than merely labelled. */
.tafsir__tab:hover { background: var(--paper-sunk); color: var(--ink); }

/* The tab carries both names and shows one. Measured on a 390px sheet: the bar
   gives the strip 314px once the close button has its 44, and the three full
   titles need 397, so the third was cut mid-word and had to be scrolled to.
   The short forms need 252 and all three stand in the open.

   Which name shows is a width question, so the stylesheet answers it; the
   full name is on the button's aria-label either way, so nothing a screen
   reader hears depends on how wide the screen is. Both spans are always in the
   DOM: display:none on the one not in use is safe here, because unlike the
   panes below there is no cross-origin frame whose place it could destroy. */
.tafsir__tab-short { display: none; }

@media (max-width: 40rem) {
  .tafsir__tab-full { display: none; }
  .tafsir__tab-short { display: inline; }

  /* And the tabs sit closer together, which is the last 24px. With the short
     names alone the strip needed 251px against the 244 a 320px screen gives
     it, so the third tab was still seven pixels short of standing in the open.
     The button keeps its 44px height, so the target is untouched. */
  .tafsir__tab { padding-inline: var(--space-2); }
}

/* The chosen tab is marked three ways: the fill, the tone and the rule beneath
   it. The rule is what carries the choice for a reader who cannot separate the
   two tints, so it stays even now that there is a fill. */
.tafsir__tab[aria-selected="true"] {
  background: var(--accent-tint);
  color: var(--accent-strong);
  border-block-end-color: var(--accent);
}

/* Hover must not overrule the choice: without this the pointer resting on the
   chosen tab would strip its fill and leave the strip looking as though nothing
   were selected. */
.tafsir__tab[aria-selected="true"]:hover {
  background: var(--accent-tint);
  color: var(--accent-strong);
}

/* The way out, and on a phone the only one that is always in front of the
   reader: there is no Escape key under a thumb and the scrim is a strip rather
   than a whole page. So it is a full touch target, and it is a mark rather than
   the word it used to be, because the bar it shares is 320px wide at its worst
   and three source tabs have to fit beside it.

   The mark is the multiplication sign, U+00D7. Not a letter x, which is a
   different shape and reads as text, and not an icon font or an emoji, neither
   of which this project uses. The button carries an aria-label, so the glyph
   itself is decorative and the control is named for anything not looking at
   it. */
.tafsir__close {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-block-size: 44px;
  min-inline-size: 44px;
  padding-inline: var(--space-2);
  border: var(--hair) solid var(--rule);
  border-radius: var(--radius-pill);
  background: var(--paper);
  color: var(--ink-soft);
  font-family: var(--font-sans);
  /* The glyph is small in most system faces, so it is set larger than the
     caption type it replaces and given a flat line box to centre in. */
  font-size: 1.25rem;
  line-height: 1;
  cursor: pointer;
}

.tafsir__close:hover {
  border-color: var(--rule-strong);
  color: var(--ink);
}

/* 44px under a thumb, condensed under a cursor: the same inversion the display
   panel's rows use, and for the same reason. A pointer query is not a width
   query, so section 17's one-breakpoint rule is untouched. */
@media (pointer: fine) {
  .tafsir__close {
    min-block-size: 36px;
    min-inline-size: 36px;
    font-size: 1.1rem;
  }
}


/* Both panes are laid out at all times, stacked on the same box. */
.tafsir__panes {
  position: relative;
  flex: 1 1 auto;
  min-block-size: 0;
}

.tafsir__pane {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  visibility: hidden;
}

.tafsir.is-open .tafsir__pane.is-active { visibility: visible; }

/* The panes are clipped, so their focus ring is drawn inside them. */
.tafsir__pane:focus-visible { outline-offset: calc(var(--focus-width) * -1); }

/* What the pane is holding: the verse it was opened from, the citation's own
   label, and the way out to the source, which is the only route left if the
   publisher refuses to be framed. */
.tafsir__ref {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: var(--space-1) var(--space-3);
  flex: none;
  margin: 0;
  padding: var(--space-3) var(--space-4);
  border-block-end: var(--hair) solid var(--rule-soft);
  background: var(--paper);
  font-family: var(--font-sans);
  font-size: var(--fs-caption);
  color: var(--ink-faint);
}

.tafsir__ref-verse {
  font-variant-numeric: tabular-nums;
  color: var(--accent-strong);
}

.tafsir__ref-label {
  min-inline-size: 0;
  color: var(--ink-soft);
}

.tafsir__out {
  margin-inline-start: auto;
  white-space: nowrap;
  color: var(--accent-strong);
}

/* Al-Mizan arrives as the publisher's own page, so it is given the pane whole
   and scrolls itself. --paper-raised behind it so a slow load is a sheet
   rather than a hole. */
.tafsir__frame {
  flex: 1 1 auto;
  min-block-size: 0;
  inline-size: 100%;
  border: 0;
  background: var(--paper-raised);
}

/* The Enlightening pane is our own DOM, and this is its scroller: the one whose
   position JavaScript saves and restores across a tab switch. */
.tafsir__doc {
  flex: 1 1 auto;
  min-block-size: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: var(--space-5) var(--space-4) var(--space-7);
  font-family: var(--font-serif);
  font-size: var(--fs-body);
  line-height: var(--lh-reading);
  /* This is somebody else's prose, and on a phone it is being poured into a
     column about 300px wide. One long transliteration or a bare URL with no
     break in it would otherwise set the width of the whole sheet and scroll
     the reader sideways to follow a line. */
  overflow-wrap: break-word;
  color: var(--ink);
}

/* The prose of a commentary this project holds. The markup reaching here has
   already been normalised against a tag allowlist at import time, so this
   styles a known and small set: paragraphs, emphasis, lists, the occasional
   table, and the indent that the source's obsolete <dir> tag becomes. */
.tafsir__doc > :first-child { margin-block-start: 0; }
.tafsir__doc > :last-child { margin-block-end: 0; }

.tafsir__doc p { margin-block: 0 var(--space-3); }

.tafsir__doc ul,
.tafsir__doc ol { margin-block: 0 var(--space-3); padding-inline-start: var(--space-5); }

.tafsir__doc li { margin-block-end: var(--space-1); }

.tafsir__doc a { color: var(--accent-strong); }

/* <dir> was a list tag the source uses purely to step a passage in. Rendering
   it as an indented block is what it was always being used to mean. */
.tafsir-indent {
  margin-block: 0 var(--space-3);
  padding-inline-start: var(--space-4);
  border-inline-start: var(--hair) solid var(--rule);
}

.tafsir__doc table {
  inline-size: 100%;
  margin-block: 0 var(--space-3);
  border-collapse: collapse;
  font-size: var(--fs-caption);
}

.tafsir__doc td,
.tafsir__doc th {
  padding: var(--space-1) var(--space-2);
  border: var(--hair) solid var(--rule);
  text-align: start;
  vertical-align: top;
}

.tafsir__pending {
  max-inline-size: var(--measure);
  margin-inline: auto;
  padding-inline-start: var(--space-4);
  border-inline-start: var(--emph) solid var(--accent-tint);
}

.tafsir__pending-title {
  font-family: var(--font-sans);
  font-size: var(--fs-label);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--accent-strong);
}

.tafsir__pending-body {
  margin-block-start: var(--space-2);
  color: var(--ink-soft);
}

.tafsir__pending-link {
  display: inline-block;
  margin-block-start: var(--space-3);
  font-family: var(--font-sans);
  font-size: var(--fs-body-sm);
}

/* The card a pane wears before anything has been opened into it. It is the last
   child of the pane, so it covers the frame beneath rather than displacing it,
   and it steps aside by visibility for the same reason everything else here
   does. */
.tafsir__empty {
  position: absolute;
  inset: 0;
  display: grid;
  align-content: center;
  justify-items: center;
  gap: var(--space-2);
  padding: var(--space-6);
  background: var(--paper);
  text-align: center;
}

.tafsir__pane:not(.is-empty) .tafsir__empty { visibility: hidden; }

.tafsir__empty-title {
  font-family: var(--font-sans);
  font-size: var(--fs-label);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--accent-strong);
}

.tafsir__empty-body {
  max-inline-size: 24rem;
  font-family: var(--font-serif);
  font-size: var(--fs-body-sm);
  line-height: var(--lh-body);
  color: var(--ink-faint);
}


/* ----------------------------------------------------------------------------
   16. Vertical compression

   The reader should be at the first verse without scrolling, so the chrome
   above it is measured rather than eyeballed. On a 1440x1000 viewport the first
   verse began 674px down: the chrome row was taking 172px because the settings
   trigger sat on a row of its own, and the first topic heading added a 48px top
   margin meant for separating sections from the one before it, of which there
   is none at the top of a surah.
   ------------------------------------------------------------------------- */

/* The first heading in a surah has nothing above it to be separated from. */
.study-list > .study-topic:first-child,
.study-list > .study-sub:first-child { margin-block-start: var(--space-2); }

/* The bismillah already provides the breathing room the topic margin was for. */
.verse-bismillah + .study-topic { margin-block-start: var(--space-3); }

.surahhead { padding-block: var(--space-4) var(--space-2); }

.contents { margin-block-start: var(--space-3); }
.verse-bismillah { margin-block: var(--space-4) var(--space-3); }

/* The chrome row's own narrow case moved back into section 3 on 2026-08-19,
   where the layout it modifies is declared. It was compressing a grid that no
   longer existed at this point in the file, which is why the footer row had
   become three bare links. */


/* ----------------------------------------------------------------------------
   17. The width breakpoints, of which there are two

   base.css has exactly one and defends the choice. This file had none of its
   own until 2026-08-20: every rule above is the narrow case, and the widening
   lives here.

   The second one exists because the two questions are not the same question.
   600px is where the CHROME has room to spread out: buttons take their words
   back, a verse gets more padding, a surah row gains a column. Every one of
   those asks "is there a little more room", and the answer at 600px is yes.

   The split asks something else entirely. It does not use the extra room, it
   HALVES what is there and asks whether both halves are still a column worth
   reading. At 600px that answer is plainly no, and it was shipping as yes:
   measured with the panel open, an iPad in portrait at 768px gave the Qur'an
   320px, which is NARROWER than the same surah gets on a 390px phone, and the
   masthead's search collapsed to nothing and left its empty pill sitting over
   the "All surahs" link, because every query in this file is written against
   the viewport while the masthead actually stands in half of it.

   So the split waits for 62rem, where the reading column comes back to 436px
   and the search is a search again. Below that the sheet does the job, and
   the sheet is a better tablet answer than a bad split was.
   ------------------------------------------------------------------------- */
@media (min-width: 600px) {
  .surahhead { padding-block: var(--space-5) var(--space-3); }

  /* Three columns, and the children auto-place into them in source order. The
     fourth column and its explicit grid areas went with the settings trigger
     when that moved into the masthead. */
  .chrome { gap: var(--space-2); }

  /* Room again for the words, and for the two-line shape that reads better.
     This justify-content beats .chrome__step--next's flex-end above at equal
     specificity by source order, which is what re-centres the two lines once
     they stack; the base rule's text-align: end still holds them to the right. */
  .chrome__step, .chrome__all {
    flex-direction: column;
    align-items: stretch;
    justify-content: center;
    padding: var(--space-2) var(--space-3);
    font-size: var(--fs-body-sm);
  }
  .chrome__all { align-items: center; }

  .verse { padding: var(--space-6); }

  /* The spread layout comes back where there is room for it: four columns that
     line up down the list, with the facts at the end. justify-content returns
     to its default so the 1fr track can do the spreading again. */
  .surahrow__link {
    grid-template-columns: 2.5rem 1fr auto 9rem;
    justify-content: normal;
    padding-inline: var(--space-2);
  }
  /* The book-index alignment comes back with the table: units under units, so
     1, 11 and 114 read as a column of numbers rather than a ragged edge. */
  .surahrow__num { text-align: end; }
  .surahrow__facts { display: block; text-align: end; }
}


/* The second breakpoint, and the only thing it carries. See the note above for
   why the split cannot share the chrome's 600px: it halves the viewport rather
   than spending it, so it has to wait for twice the room.

   62rem is 992px. Measured with the panel open: the reading column is 436px,
   which is wider than the 350px a 390px phone gives it, and the masthead's
   search survives at a usable width instead of collapsing to zero. Below this
   the sheet handles it, tablets included. */
@media (min-width: 62rem) {
  /* The split. The page is pushed into the left half rather than covered, so
     nothing the reader was looking at goes behind the panel. The push is not
     transitioned: animating padding on <body> relayouts every verse on the
     page, and surah 2 is 286 of them. The panel's slide carries the motion.

     The narrow scroll lock is lifted for the same reason there is no scrim
     here: the half beside the panel is meant to go on scrolling. */

  /* ONE width, for all four panels, and it is a custom property whose fallback
     is the half this file has always specified. --qs-panew is declared in no
     stylesheet: panel-resize.js sets it on the root element and removes it
     again, so a reader who never drags -- or who has JavaScript off, or the
     flag off -- gets byte-for-byte the 50/50 that shipped.

     Eleven declarations have to agree on this number, because the panel is an
     overlay and the "left column" is only <body> padded out of its way: the
     four panel/padding pairs (here, reflections, word study, lectures), the
     recitation strip in two rules, and the word study return pill. They are
     one decision, so they read one property. */
  body.tafsir-open {
    padding-inline-end: var(--qs-panew, 50vw);
    overflow: visible;
    /* How much page there is left, which is not 100vw once a panel
       has taken half of it. Read by anything that drops out of the
       masthead: those are anchored inside this padding and cannot
       see it. Unset when no panel is open, and the fallback at each
       reader is the whole window, which is what it was. */
    --qs-pagew: calc(100vw - var(--qs-panew, 50vw));
  }

  /* Back under the masthead. The sheet claimed 94 in order to cover it; a
     split leaves it in place, and its controls have to stay reachable while a
     commentary is open beside the verse. */
  .tafsir { z-index: 90; }

  .tafsir__panel {
    inline-size: var(--qs-panew, 50vw);
    /* No strip beside a split: the panel takes the full height of its half. */
    inset-block-start: 0;
    /* Closed waits at the right edge here rather than below the fold. Only the
       closed state is re-aimed; the open state is transform: none in both. */
    transform: translateX(101%);
    /* The edge that meets the page rather than the one that met the strip. */
    border-block-start: 0;
    border-inline-start: var(--hair) solid var(--rule);
  }

  /* No veil beside a split: the half that is not the panel stays live. */
  .tafsir__scrim { display: none; }

  /* The reflections panel's half is NOT declared here. It is declared in its
     own copy of this query at the end of section 18, because that section is
     below this point in the file and a base rule that comes after a media block
     of equal specificity wins over it. Putting them here made the panel full
     width at every size, with the page still padded into half the viewport. */
}

/* ----------------------------------------------------------------------------
   9. The surah search

   Ported from Manzar, whose typeahead has been in daily use. It sits in the
   middle of the masthead's first row, which on the surah page costs NOTHING in
   height: that row is 76px because the Display button is 44px, so any control
   up to 44px rides for free. Measured 2026-08-19 on /quran/3 at 390, 640, 768
   and 1440.

   The form is a real GET form to /quran?q= and works with no JavaScript.
   search.js upgrades it in place.
   ------------------------------------------------------------------------- */

/* Three columns rather than space-between, because space-between only centres
   a middle child when the flanks are equal and here they are not: the wordmark
   is 143px and the actions 178px. Scoped to .quran so the landing page, whose
   row has a fourth child carrying the only filled CTA on the site, keeps its
   flex layout. min-width:0 on every track is load-bearing; without it the row
   overflows and the DOCUMENT scrolls sideways, measured at 24px on a 360px
   viewport. */
.quran .masthead__inner {
  display: grid;
  /* max-content floors, not 0. With minmax(0, 1fr) the flanking tracks are free
     to shrink below their contents, and between roughly 700 and 780px that
     squeezed the wordmark to 112px and wrapped "Quran Study" onto two lines,
     taking the row from 76px to 88px. Measured 2026-08-19. The floors also keep
     the centring: equal 1fr tracks resolve equal wherever there is room, and
     only drift once the flanks genuinely need more than their share. */
  grid-template-columns:
    minmax(max-content, 1fr) minmax(0, 24rem) minmax(max-content, 1fr);
  justify-items: center;
}

/* Belt and braces for the same wrap: the wordmark is a two-word phrase and a
   narrow cell is the only thing that would ever break it. */
.quran .wordmark { white-space: nowrap; }

.quran .masthead__inner > .wordmark { justify-self: start; }
.quran .masthead__inner > .masthead__actions { justify-self: end; }

/* ONE FIELD, ONE WIDTH, AND THE INDEX NO LONGER HAS ITS OWN.

   The rule that stood here gave this page a 36rem middle track while the
   landing page, the surah page and the root page all took the base rule's
   24rem -- so the same control was 576px on /quran and 384px everywhere else,
   and crossing between them resized the box a reader was about to type into.
   The owner, on seeing all four: "the search bar on the top is not consistent
   width across the different pages -- can you please make sure the width is
   constant". Deleting the override is the whole change; `.quran`'s 24rem
   above is now the one number, and it is the number three of the four pages
   already agreed on.

   SUPERSEDED, and worth keeping because it was not a careless width. The
   argument was that the surah list is 36rem and centred, so a field of the
   same width directly above it makes one column down the page -- the thing
   you type into and the thing it filters sharing an edge. That is a real
   alignment and it is what this costs: at 24rem the field is centred on the
   list without matching its edges. What the argument undervalued is that the
   field is CHROME, not part of the list. It stands in the same place, at the
   same size, on every page of this site, and a reader crossing from /quran to
   a surah met the one control they use everywhere changing shape under them.
   A component that belongs to the masthead is measured against the masthead.

   Its own predecessor is recorded with it: before that, the field sat beside
   the wordmark, which was wrong because this page carries no actions -- the
   gateway points HERE -- so the third track was 0px and a "centred" field was
   centred against nothing. That objection survives both rewrites and is still
   answered: the flanking tracks below hold their max-content floors, so the
   centring stays real whatever is or is not in them.

   The overflow lesson survives too, and is now moot rather than fixed. A
   percentage inside a track resolves against the whole grid rather than
   against what the flanks have left, so `min(36rem, 100%)` held 576px
   whatever the row could afford and the DOCUMENT scrolled sideways from 641
   to 831px -- 103px at 672, 71px at 704, 7px at 768, clean at 832, measured
   2026-08-25. The `minmax(0, 24rem)` this page now inherits has the yielding
   floor that fixed it AND a ceiling small enough that the band never binds.
   test_no_masthead_overflows_its_document_sideways still sweeps it. */

/* Two columns and no middle BELOW 62rem, where this page's field is display:
   none. Without this the wordmark and the actions would take columns one and
   TWO of the inherited three and the actions would sit in the middle.

   The field came back above 62rem on 2026-08-24; the rule that restores the
   third track is with the tucking header's own query further down, because
   62rem is that query's threshold and not a second number. */
.quran-surah .masthead__inner {
  grid-template-columns: 1fr auto;
}

/* The field is in the markup at every width and hidden here, rather than being
   left out of the template above a width Jinja cannot see. display:none and
   not visibility, because a hidden-but-laid-out form would still be spending
   the 40px row the 2026-08-20 measurement reclaimed -- which was the whole of
   that objection. It leaves the accessibility tree with it, which is correct:
   there is no way to reach a control that is not drawn. */
.quran-surah .qsearch { display: none; }

/* Above 62rem the header stops tucking and is one short row on a screen with
   height to spare, which is where a field is affordable again. The same
   threshold, deliberately: the width at which this header is cheap is the
   width at which it can carry something more. */
@media (min-width: 62rem) {
  .quran-surah .masthead__inner {
    grid-template-columns:
      minmax(max-content, 1fr) minmax(0, 24rem) minmax(max-content, 1fr);
  }

  .quran-surah .qsearch { display: flex; }
}

/* The search bar's own styles live in base.css section 23: the bar stands
   in the landing hero as well as this masthead, and the landing page does
   not load this file. What stays here is the masthead GRID the bar sits in
   on the Qur'an pages, above, and the phone rows below. */

/* --- the ?q= view on the index ------------------------------------------- */

.surahlist__back,
.surahlist__empty {
  margin: 0 0 var(--space-4);
  font-family: var(--font-sans);
  font-size: var(--fs-body-sm);
  color: var(--ink-faint);
  text-align: center;
}

.surahlist__back a { color: var(--accent-strong); }

/* Below this the wordmark's text has to go so the field keeps a usable width:
   at 390px there is only 29px of free space between the wordmark and the
   actions, measured. The mark alone still links home, and on these pages the
   surah's own name is directly beneath it. */
/* row-gap is var(--space-3) and was var(--space-1). The argument is in
   base.css section 24, where the landing page's copy of this restack sits:
   4px under a 44px control, inside 16px of frame, read as crushed rather than
   as spaced. All three copies of this block carry the same number, and a test
   holds the media rung and its container twin to identical declarations. */
@media (max-width: 40rem) {
  .quran .masthead__inner {
    grid-template-columns: 1fr auto;
    grid-template-areas:
      "brand  actions"
      "search search";
    row-gap: var(--space-3);
  }

  .quran .masthead__inner > .wordmark { grid-area: brand; justify-self: start; }
  .quran .masthead__inner > .masthead__actions { grid-area: actions; }
  .qsearch { grid-area: search; }

  /* 40px rather than 44 here. The control no longer has to match the Display
     button's height because it is no longer beside it, and on a 664px-tall
     phone the header is the scarcest thing on the page. */
  .qsearch__input { block-size: 40px; }

  /* The index keeps ONE row here rather than taking the stacked pair above.
     The wordmark is its mark alone at this width, 22px, so the field fits
     beside it with room to spare, and the row the stack would have cost is
     the same 44px the surah page just stopped spending. */
  .quran-index .masthead__inner {
    grid-template-columns: auto minmax(0, 1fr) auto;
    grid-template-areas: "brand search actions";
    row-gap: 0;
  }

  /* The surah page has no field to place any more, so it has no second row to
     leave standing empty either. */
  .quran-surah .masthead__inner {
    grid-template-columns: 1fr auto;
    grid-template-areas: "brand actions";
    row-gap: 0;
  }
}


/* --- the same rungs, asked of the BAR rather than of the window ----------- */

/* The container twin of the block above, and it exists because that block
   cannot see the case it was written for. Every rule up there reads the
   viewport; this bar stands in half the page whenever a panel is open, and the
   viewport does not move when it does. Measured 2026-08-25 on /quran/96 with
   the word panel at the shipped half: a 992px window leaves the bar 496px and
   the field's track 63px, a 1024px window 512px, a 1114px window 557px. All
   three are narrower than the 640px this file already calls a phone, on
   windows this file calls a desktop.

   Placed after the 62rem block deliberately. That block sets the surah page's
   field to display: flex on any window above 62rem, which with a panel open is
   exactly the case that must not draw one, so the twin has to come later to
   put it back. Same specificity, later position.

   No number here is new. 40rem is the restack's own, and what changes is only
   which box is asked for it. */
@container masthead (max-width: 39.999rem) {
  .quran .masthead__inner {
    grid-template-columns: 1fr auto;
    grid-template-areas:
      "brand  actions"
      "search search";
    row-gap: var(--space-3);
  }

  .quran .masthead__inner > .wordmark { grid-area: brand; justify-self: start; }
  .quran .masthead__inner > .masthead__actions { grid-area: actions; }
  .qsearch { grid-area: search; }

  .quran-index .masthead__inner {
    grid-template-columns: auto minmax(0, 1fr) auto;
    grid-template-areas: "brand search actions";
    row-gap: 0;
  }

  /* The field goes rather than becoming a sliver. This is the 2026-08-24
     decision -- "where the header is cheap the field is affordable; where the
     header had to be reclaimed it is not" -- finally asked of the header
     rather than of the screen the header happens to be on. Above this rung a
     panel-narrowed bar still holds a whole field: at a 1400px window with the
     seam at the half the bar is 700px, the mark stands alone, and the field
     resolves to its full 24rem cap. */
  .quran-surah .masthead__inner {
    grid-template-columns: 1fr auto;
    grid-template-areas: "brand actions";
    row-gap: 0;
  }

  .quran-surah .qsearch { display: none; }
}


/* RUNG: even the index's single row stops fitting, so it takes the stacked
   pair after all.

   The block above keeps /quran on one row below 40rem, on the argument that
   the wordmark is its mark alone there and the field fits beside it "with room
   to spare". That was true of a row whose only other tenant was 22px of mark.
   It is still nearly true, and it runs out at the bottom of the range, where
   the sample's tail clips -- the Arabic, which is the half the placeholder
   exists to teach.

   WHERE IT RUNS OUT IS NOT A ROUND NUMBER, because two of the three costs are
   themselves fractions of the bar. Below a 600px viewport the gutter is 20px
   and the column gap is 4cqi, so for a bar of C the row has C - 40 of inner
   and spends 0.08C on its two gaps and 22px on the mark. The field wants 276px
   to show the whole sample, which solves to C = 367. A first pass put the rung
   at 23rem on an estimate that used the desktop's fixed 24px gap; the sweep
   caught it at exactly 368px, clipped by 3.4px, which is what the estimate was
   wrong by.

   32rem AND NOT 24rem, which is where this rung first shipped. 24rem was the
   width below which the field could not hold its sample beside the MARK; this
   is the width below which it cannot hold it beside the NAME, which is
   143px rather than 22. Solving the same way gives 499px, so 32rem carries
   13px. Raising it is what lets this page keep its name at every width it is
   ever drawn at -- stacked, row one holds the wordmark and nothing else, since
   this page has no actions, and 143px fits in 280px of inner at 320.

   THE FLOOR OF THE WHOLE LADDER IS 320px, where the field is the entire row
   and the only costs left are its two paddings: 276px of content against a
   187.6px sample, 4px spare. It was 0.0px spare for one sweep, which is what
   took the mark's cut from 3.25rem to 3rem -- a floor measured at exactly zero
   is not a floor. 4px is still thin: a system face 3% wider than the one
   measured on clips the sample's tail at 320px, and the answer then is a
   shorter sample rather than a narrower rung.

   No media twin. /quran never has a panel beside it, so its bar is always the
   window and the container rung is the only one that can fire; an engine
   without @container keeps exactly the row it has today. */
@container masthead (max-width: 31.999rem) {
  .quran-index .masthead__inner {
    grid-template-columns: 1fr auto;
    grid-template-areas:
      "brand  actions"
      "search search";
    row-gap: var(--space-3);
  }
}


/* ----------------------------------------------------------------------------
   18. The reflections panel

   The second panel to take the right half, and the first that is not a
   commentary. It shares the tafsir panel's shell -- the same anchoring, the same
   sheet below 62rem and split above it, the same visibility discipline -- and
   deliberately repeats it rather than sharing a base class. Extracting one would
   mean reworking shipped tafsir markup and CSS to serve a base with exactly two
   clients, the second of them a day old. The panel after this, for video
   lectures, is the third client and the moment to do it.

   What differs is the inside. The tafsir panel is a tab bar over panes, because
   a reader compares three commentaries on one verse. This is a list over a
   reader, because these are one publisher's essays, and what a reader does with
   a list of essays is browse it, open one, and come back.

   The visibility rules here are load-bearing for the reason section 13 gives:
   the reader view holds a cross-origin iframe whose scroll offset cannot be read
   back, so none of them may be shortened to display:none.
   ------------------------------------------------------------------------- */
.reflections {
  position: fixed;
  inset: 0;
  z-index: 94;
  pointer-events: none;
}

body.reflections-open { overflow: hidden; }

.reflections__scrim {
  position: absolute;
  inset: 0;
  background: var(--paper-sunk);
  opacity: 0;
  transition: opacity var(--dur-slow) var(--ease-calm);
}

.reflections.is-open .reflections__scrim {
  opacity: 0.92;
  pointer-events: auto;
}

.reflections__panel {
  position: absolute;
  inset-block-start: var(--space-7);
  inset-block-end: 0;
  inset-inline-end: 0;
  inline-size: 100%;
  display: flex;
  flex-direction: column;
  background: var(--paper);
  border-block-start: var(--hair) solid var(--rule);
  box-shadow: var(--shadow-soft);
  pointer-events: auto;
  visibility: hidden;
  transform: translateY(101%);
  transition: transform var(--dur-slow) var(--ease-calm),
              visibility 0s linear var(--dur-slow);
}

.reflections.is-open .reflections__panel {
  visibility: visible;
  transform: none;
  transition: transform var(--dur-slow) var(--ease-calm),
              visibility 0s;
}

.reflections__bar {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex: none;
  min-block-size: var(--panel-bar-min, 44px);
  padding-inline: var(--space-3);
  border-block-end: var(--hair) solid var(--rule);
  background: var(--paper-raised);
}

/* The heading takes the middle and the two controls the ends, so Back and Close
   stay where a thumb last found them whichever view is showing. */
/* THE PANEL'S NAMEPLATE, and the same object as the commentary strip's chosen
   tab and the word study strip's: the topmost row of the panel says what the
   panel is, in one treatment, in all four. It was a line of bold text here and
   a filled tab there, which read as two different kinds of thing occupying the
   same slot.

   Not a control and never has been -- there is one view, so there is nothing
   to choose between -- but it wears the chosen tab's fill because that is what
   this position means in this app, and a reader who has learned it in the
   commentary panel should not have to learn it again here. `.wstudy__tab` made
   the same call, in a span, for the same reason.

   `flex: none` and the slack pushed after it: as a stretched item its fill ran
   the width of the bar, which is a banner rather than a nameplate, and the
   ring it takes when the panel opens and moves focus here ran the width too.
   Back and Close still sit at the ends of the bar, which is the promise the
   old rule was written to keep. */
.reflections__heading {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  flex: none;
  margin: 0;
  margin-inline-end: auto;
  min-block-size: 44px;
  padding-inline: var(--space-3);
  border-block-end: var(--emph) solid var(--accent);
  border-start-start-radius: var(--radius-control);
  border-start-end-radius: var(--radius-control);
  background: var(--accent-tint);
  overflow: hidden;
  font-family: var(--font-sans);
  font-size: var(--fs-body-sm);
  font-weight: 600;
  white-space: nowrap;
  text-overflow: ellipsis;
  color: var(--accent-strong);
}

/* The mark this kind wears everywhere else it is offered -- under a verse and
   in the surah bar -- at the nameplate's size. It names nothing on its own and
   is hidden from the accessible tree; the word beside it is the name. */
.reflections__heading__icon {
  flex: none;
}

/* Focused when the panel opens, so a screen reader lands on the panel's name
   rather than wherever the click left it. It is not a control and must not wear
   a control's ring when it is reached that way. */
.reflections__heading:focus { outline: none; }
.reflections__heading:focus-visible { outline: var(--focus-width) solid var(--accent); }

.reflections__back,
.reflections__close {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  flex: none;
  min-block-size: 36px;
  padding-inline: var(--space-2);
  border: 0;
  border-radius: var(--radius-control);
  background: none;
  color: var(--ink-soft);
  font-family: var(--font-sans);
  font-size: var(--fs-body-sm);
  cursor: pointer;
}

.reflections__close { font-size: var(--fs-body); }

/* The display rule above outranks the user agent's own [hidden] rule, so
   hiding these has to be said here. Without it the Back button stands in the
   bar while the list is showing, offering to go back from the place the reader
   is already at, and the surah bar's own button -- which wears
   .surahtoc__trigger and its display -- appears for a reader who has no
   JavaScript to open the panel with. Both are the same trap section 12
   documents for the word-by-word controls. */
.reflections__back[hidden],
.reflections__open[hidden] { display: none; }

.reflections__back:hover,
.reflections__close:hover {
  background: var(--paper-sunk);
  color: var(--ink);
}

/* Both views lie over one another and are swapped by visibility. Absolute
   rather than a swap in flow, so the frame keeps its box, its size and its
   scroll offset while the list is showing. */
.reflections__views {
  position: relative;
  flex: 1 1 auto;
  min-block-size: 0;
}

.reflections__list,
.reflections__reader {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  visibility: hidden;
}

.reflections.is-open:not(.is-article) .reflections__list { visibility: visible; }
.reflections.is-open.is-article .reflections__reader { visibility: visible; }

.reflections__list {
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: var(--space-4) var(--space-3) var(--space-6);
}

.reflections__group { margin-block-end: var(--space-4); }

.reflections__grouptitle {
  margin: 0 0 var(--space-2);
  padding-inline: var(--space-1);
  font-family: var(--font-sans);
  font-size: var(--fs-label);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--accent-strong);
}

.reflections__items {
  margin: 0;
  padding: 0;
  list-style: none;
}

.reflections__item + .reflections__item { margin-block-start: var(--space-2); }

/* The whole row is the target, not the title alone: these are read on a phone
   as often as not, and a two-line title whose first line is the control is a
   control that gets missed. */
.reflections__article {
  display: block;
  min-block-size: 44px;
  padding: var(--space-3);
  border: var(--hair) solid var(--rule);
  border-radius: var(--radius-control);
  background: var(--paper-raised);
  text-decoration: none;
}

.reflections__article:hover { border-color: var(--accent); }

.reflections__title {
  display: block;
  font-family: var(--font-serif);
  font-size: var(--fs-body);
  line-height: var(--lh-tight);
  color: var(--ink);
}

.reflections__meta {
  display: flex;
  gap: var(--space-2);
  margin-block-start: var(--space-1);
  font-family: var(--font-sans);
  font-size: var(--fs-caption);
  color: var(--ink-faint);
}

.reflections__covers { color: var(--ink-soft); }

/* A ring, never a tint and never a bar down the edge. A tinted row reads as a
   different KIND of row rather than as the one being pointed at, and a stripe
   on the leading edge reads as a nesting level. The ring says "this one" and
   nothing else. */
.reflections__item.is-current .reflections__article {
  border-color: var(--accent);
  box-shadow: 0 0 0 var(--emph) var(--accent);
}

.reflections__credit {
  margin: 0;
  padding-inline: var(--space-1);
  font-family: var(--font-sans);
  font-size: var(--fs-caption);
  color: var(--ink-faint);
}

.reflections__credit a { color: var(--accent-strong); }

.reflections__ref {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
  flex: none;
  margin: 0;
  padding: var(--space-2) var(--space-3);
  border-block-end: var(--hair) solid var(--rule);
  font-family: var(--font-sans);
  font-size: var(--fs-caption);
  color: var(--ink-soft);
}

/* The verse leads the line and keeps its full width; the title is what gives
   way when the panel is narrow. Which verse you are reading about is the part a
   reader cannot reconstruct from the article, since the panel may have been
   opened from a different verse entirely. */
.reflections__ref-verse {
  flex: none;
  padding-inline-end: var(--space-2);
  border-inline-end: var(--hair) solid var(--rule);
  color: var(--accent-strong);
  font-weight: 600;
}

.reflections__ref-verse[hidden] { display: none; }

.reflections__ref-title {
  min-inline-size: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

/* Standing there from the start rather than appearing on failure: whether a
   publisher refused to be framed cannot be detected from this side, so the way
   out has to be permanent. */
.reflections__out {
  margin-inline-start: auto;
  white-space: nowrap;
  color: var(--accent-strong);
}

/* --paper-raised behind it, so a slow load is a sheet rather than a hole. */
.reflections__frame {
  flex: 1 1 auto;
  min-block-size: 0;
  inline-size: 100%;
  border: 0;
  background: var(--paper-raised);
}

/* The count beside the shelf's Reflections entry, for the verses two authors
   have both written on.

   A hairline ring and no fill. It used to be filled with --accent-tint, which
   was distinct while the entry sat in a --paper-raised chip; section 9's hover
   is now that same tint across the whole entry, so a filled badge would
   dissolve into the hover state exactly when the reader is looking at it. A
   ring survives both states, and is the same choice the site makes everywhere
   else it marks one thing among others -- never a fill, never a bar. */
.cite__count {
  margin-inline-start: var(--space-1);
  padding-inline: 0.4em;
  border: var(--hair) solid var(--rule-strong);
  border-radius: var(--radius-pill);
  color: var(--ink-soft);
  font-size: var(--fs-label);
}

/* The split, on the same terms as the tafsir panel's and at the same 62rem.

   In its own copy of the query rather than in section 17's block, and this is
   load-bearing: this section is below that block, so its base rules would win
   over an equal-specificity rule up there. Declared there first, the panel came
   out full width at every size while <body> was still padded into half the
   viewport, which reads as the page having been eaten rather than as a panel.
   A rule for this section belongs after this section. */
@media (min-width: 62rem) {
  /* The two panels are mutually exclusive in JavaScript, so <body> can never
     carry both classes and the padding is never applied twice. */
  body.reflections-open {
    padding-inline-end: var(--qs-panew, 50vw);
    overflow: visible;
    /* How much page there is left, which is not 100vw once a panel
       has taken half of it. Read by anything that drops out of the
       masthead: those are anchored inside this padding and cannot
       see it. Unset when no panel is open, and the fallback at each
       reader is the whole window, which is what it was. */
    --qs-pagew: calc(100vw - var(--qs-panew, 50vw));
  }

  /* Back under the masthead, whose controls stay reachable beside a split. */
  .reflections { z-index: 90; }

  .reflections__panel {
    inline-size: var(--qs-panew, 50vw);
    /* No strip beside a split: the panel takes the full height of its half. */
    inset-block-start: 0;
    /* Closed waits at the right edge rather than below the fold. Only the
       closed state is re-aimed; the open state is transform: none in both. */
    transform: translateX(101%);
    /* The edge that meets the page rather than the one that met the strip. */
    border-block-start: 0;
    border-inline-start: var(--hair) solid var(--rule);
  }

  /* No veil beside a split: the half that is not the panel stays live. */
  .reflections__scrim { display: none; }
}

/* ----------------------------------------------------------------------------
   19. Recitation: the play disc on a verse, and the player strip

   Two pieces. A disc in every verse's number line, which starts the recitation
   at that verse, and one strip fixed to the foot of the viewport that stands
   there for as long as something is playing.

   WHAT MARKS WHAT, AND WHY THEY DIFFER
   Three states are visible at once while a surah is being recited, and they
   must not be confusable:

     the word being recited   a tint    .is-playing, section 12
     the word under the pointer a wash  :hover, section 12
     the verse being recited  a ring    .verse__play.is-active, below

   A word takes a background because it is a run of text and a background is
   the only mark that survives the Mushaf faces, where the glyph colour comes
   from inside the QCF font as COLR layers over CPAL palette 0 and CSS colour
   cannot reach it. A CONTROL takes a ring, because a tinted control reads as a
   different kind of control rather than as the one in use. Section 18's
   reflections list makes the same distinction for the same reason.

   THE STRIP IS AN EDGE AND NOT A CARD
   It sits on the bottom rim of the viewport, so it takes a hairline rule and
   no shadow. A shadow says an object is floating above the page; this one is
   attached to it. The word-by-word tooltip does carry a shadow, and that is
   the distinction rather than an inconsistency: the tooltip floats over the
   text, and this is a rail the page ends at.

   WHY 88
   The panels are 90 at the split and 94 below it, the header is 92, and the
   word-by-word floats are 60 and 61. The strip must clear the reading column
   and lose to everything that is deliberately modal, so it goes under all of
   them at 88. On a phone the commentary sheet therefore covers it while the
   recitation goes on playing, which is right: the sheet is modal there, and
   the reader can still reach the transport through the lock screen.

   The strip is fixed, so it is unaffected by the header's tuck transform, and
   nothing here needs to know about it.
   ------------------------------------------------------------------------- */

/* The companion to [hidden]. Both display rules below outrank the user agent's
   own, so hiding has to be restated or neither piece ever goes away. This trap
   has now been paid for three times in this stylesheet. */
.recite[hidden],
.recite__icon[hidden] { display: none; }

/* ---- The disc in the number line --------------------------------------- */

/* Hidden by the stylesheet rather than by a hidden attribute on each button.
   A surah can carry 286 verses, and the alternative is the template shipping
   286 attributes for a script to remove one at a time; static/js/recitation.js
   writes one class on the list instead. A reader with no JavaScript is left
   with no control that would do nothing, which is the same outcome. */
.verse__play { display: none; }
.verse-list.recite-on .verse__play { display: inline-flex; }

/* The disc IS the target now, where it used to be a small mark inside a 44px
   box of transparent padding. At this size the two are the same thing, which
   is why the pointer: fine condensation that used to sit at the foot of this
   section is gone: it existed to stop a 44px tap area dwarfing a 22px mark
   for a reader with a mouse, and there is no longer a gap to close.

   No negative margin either. The row aligns its own items. */
.verse__play {
  align-items: center;
  justify-content: center;
  flex: none;
  padding: 0;
  border: 0;
  background: none;
  color: var(--ink-faint);
  cursor: pointer;
}

/* 22px of glyph in 10px of padding: a 44px disc, which is the touch floor met
   by the visible control rather than by an invisible box around it. */
.verse__play > svg {
  flex: none;
  padding: 10px;
  border: var(--hair) solid var(--rule);
  border-radius: var(--radius-pill);
  background: var(--paper-raised);
  box-sizing: content-box;
}

.verse__play:hover { color: var(--accent-strong); }
.verse__play:hover > svg { border-color: var(--accent); }

/* The verse this recitation is on. A ring, per the note at the head of this
   section: the disc is a control, and a control says "this one" with an edge
   rather than by changing colour. */
.verse__play.is-active { color: var(--accent-strong); }
.verse__play.is-active > svg {
  border-color: var(--accent);
  box-shadow: 0 0 0 var(--emph) var(--accent);
}

/* ---- Taking the verse away ---------------------------------------------- */

/* Hidden by the stylesheet and revealed by one class on the list, exactly as
   the play disc above is, and for the same arithmetic: a surah carries up to
   286 verses, and the alternative is the template shipping 286 hidden
   attributes for a script to remove one at a time. A reader with no JavaScript
   is left with no control that would do nothing. */
.verse__copy { display: none; }
.verse-list.copy-on .verse__copy { display: inline-flex; }

/* The number line is already a flex row and already the verse's action gutter,
   so the copy reaches the right edge by taking the space between rather than
   by a position: absolute that would have to be told where that edge is. It
   therefore stays at the right edge at every measure the panel can be dragged
   to, including the ones where the pane is narrower than the queries. */
.verse__copy {
  align-items: center;
  justify-content: center;
  flex: none;
  margin-inline-start: auto;
  padding: 0;
  border: 0;
  background: none;
  color: var(--ink-faint);
  cursor: pointer;
}

/* The play disc's box to the pixel: 22px of glyph in 10px of padding, a 44px
   target met by the visible control rather than by an invisible box around it.
   Two controls sharing one row must be one size, or they read as two sets of
   one thing instead of one set of two. */
.verse__copy > svg {
  flex: none;
  padding: 10px;
  border: var(--hair) solid var(--rule);
  border-radius: var(--radius-pill);
  background: var(--paper-raised);
  box-sizing: content-box;
}

.verse__copy:hover { color: var(--accent-strong); }
.verse__copy:hover > svg { border-color: var(--accent); }

/* The answer, which is paint and never geometry: all three marks are cut on the
   same 24 viewBox and drawn in the same 22px box, so nothing on the row moves
   when the state flips and the verse below does not shift under a reader who
   has just pressed something. */
.verse__copy-done,
.verse__copy-fail { display: none; }

.verse__copy.is-done .verse__copy-mark,
.verse__copy.is-failed .verse__copy-mark { display: none; }
.verse__copy.is-done .verse__copy-done { display: block; }
.verse__copy.is-failed .verse__copy-fail { display: block; }

.verse__copy.is-done { color: var(--accent-strong); }
.verse__copy.is-done > svg { border-color: var(--accent); }

/* A failure is not a quieter success and must not wear the accent, which on
   this page means a thing that worked. It gets its own mark -- a cross, not a
   dimmer check -- at full ink on the strong hairline, and the live region says
   so in words. There is no warning colour in the system and this is not the
   place to invent one: a reader who cannot see the difference in tone can
   still see that the mark is a different mark. */
.verse__copy.is-failed { color: var(--ink); }
.verse__copy.is-failed > svg { border-color: var(--rule-strong); }

/* ---- The reader's own door, in the gutter -------------------------------- */

/* Hidden by the stylesheet and revealed by its module, the same bargain the
   two discs above make and for the same reason: a note is written through a
   fetch carrying a CSRF header, so there is nothing an href could promise a
   reader with no JavaScript.

   Unlike those two it is revealed one at a time rather than by a class on the
   list, because notebook.js already walked this collection to reveal the shelf
   entry this replaces and the walk is what it kept. */
.verse__notebook {
  display: none;
  align-items: center;
  justify-content: center;
  flex: none;
  /* The pair reaches the right edge together: this takes the slack and Copy
     follows it, so the gutter reads [key] [play] ....... [pen] [copy] at every
     measure the split can be dragged to. */
  margin-inline-start: auto;
  padding: 0;
  border: 0;
  background: none;
  color: var(--ink-faint);
  cursor: pointer;
}

.verse__notebook:not([hidden]) { display: inline-flex; }

/* Copy's own auto margin would otherwise put the whole gap between the two
   marks and split what is one set of two. */
.verse__notebook:not([hidden]) ~ .verse__copy { margin-inline-start: 0; }

/* THE DISC, to the same pixel as the other two. See the comment above the copy
   disc: three controls sharing one row must be one size. */
.verse__notebook > svg {
  flex: none;
  padding: 10px;
  border: var(--hair) solid var(--rule);
  border-radius: var(--radius-pill);
  background: var(--paper-raised);
  box-sizing: content-box;
}

.verse__notebook:hover { color: var(--accent-strong); }
.verse__notebook:hover > svg { border-color: var(--accent); }

/* WHETHER THERE IS ANYTHING HERE, and it is paint. A verse already written on
   inks its pen; one that has never been written on keeps the faint ink every
   other resting control on this row wears. Nothing about the box changes, so a
   verse gaining its first note does not move the line it sits on -- the rule
   the copy disc's three marks already follow.

   Not a badge. A count in the quietest row of the page reports, one press
   early, something the panel says better; the aria-label carries it in words
   for the reader who has no mark to look at. */
.verse__notebook.is-inked { color: var(--accent-strong); }
.verse__notebook.is-inked > svg { border-color: var(--accent); }

@media (forced-colors: active) {
  /* Both states resolve to the same system colour here, so the difference has
     to be carried by something forced colours keeps. The border does. */
  .verse__notebook.is-inked > svg { border-width: var(--emph); }
}

/* ---- The strip ---------------------------------------------------------- */

.recite {
  position: fixed;
  inset-inline: 0;
  inset-block-end: 0;
  z-index: 88;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-3) var(--gutter) var(--space-4);
  /* An emphatic rule rather than a hairline. This is a control surface a
     reader drives, not a divider between two pieces of reading, and at one
     hairline it read as the foot of the page rather than as an instrument
     standing in front of it. Still a rule and not a shadow: the strip is
     anchored to an edge, and an edge takes a line. The presence comes from
     size and contrast instead, which is the house way of getting it. */
  border-block-start: var(--emph) solid var(--rule-strong);
  background: var(--paper-raised);
}

/* ---- Row one: the scrubber and its two clocks -------------------------- */

.recite__progress {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.recite__clock {
  flex: none;
  font-family: var(--font-sans);
  font-size: var(--fs-body-sm);
  /* The digits change every second and the strip must not twitch with them. */
  font-variant-numeric: tabular-nums;
  color: var(--ink-faint);
}

/* The project's first range input, so everything below is written from
   nothing rather than inherited from a base rule.

   appearance: none removes the platform widget, which is the only way to
   reach the track and the thumb at all -- and it has to be undone for forced
   colours, where the platform widget is the one that follows the user's own
   palette. The track is painted with a gradient rather than by a second
   element, because a filled-progress element would have to be sized from
   JavaScript, and no script in this project writes a CSS declaration. */
.recite__bar {
  -webkit-appearance: none;
  appearance: none;
  flex: 1 1 auto;
  min-inline-size: 0;
  /* A generous hit area around a hairline track: the visible line is 3px and
     the graspable band is the full height, which clears a thumb on a phone. */
  block-size: 28px;
  margin: 0;
  padding: 0;
  background: none;
  cursor: pointer;
}

.recite__bar::-webkit-slider-runnable-track {
  block-size: 5px;
  border-radius: 3px;
  background: var(--rule);
}

.recite__bar::-moz-range-track {
  block-size: 5px;
  border-radius: 3px;
  background: var(--rule);
}

/* Firefox paints the filled part for us; Chromium does not, and giving it a
   gradient would need the played fraction, which only a script knows. So the
   fill is Firefox-only and the track reads the same in both: a line with a
   thumb standing on it. This is a deliberate difference, not an oversight. */
.recite__bar::-moz-range-progress {
  block-size: 5px;
  border-radius: 3px;
  background: var(--accent);
}

.recite__bar::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  inline-size: 16px;
  block-size: 16px;
  /* The thumb is laid out against the TRACK, not the input, so it has to be
     lifted by half its own overhang or it rides along the top edge. */
  margin-block-start: -5.5px;
  border: 0;
  border-radius: var(--radius-pill);
  background: var(--accent);
}

.recite__bar::-moz-range-thumb {
  inline-size: 16px;
  block-size: 16px;
  border: 0;
  border-radius: var(--radius-pill);
  background: var(--accent);
}

.recite__bar:focus-visible::-webkit-slider-thumb {
  box-shadow: 0 0 0 var(--emph) var(--paper-raised), 0 0 0 4px var(--accent);
}

.recite__bar:focus-visible::-moz-range-thumb {
  box-shadow: 0 0 0 var(--emph) var(--paper-raised), 0 0 0 4px var(--accent);
}

/* ---- Row two: who is reading, the transport, the way back --------------- */

/* Three tracks so the transport is centred on the STRIP rather than on
   whatever room is left beside the reciter's name. The third is empty and
   exists only to balance the first. */
.recite__row {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: var(--space-2);
}

.recite__who {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
  min-inline-size: 0;
}

.recite__transport {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.recite__control {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  inline-size: 52px;
  block-size: 52px;
  padding: 0;
  border: 0;
  border-radius: var(--radius-control);
  background: none;
  color: var(--ink-soft);
  cursor: pointer;
}

.recite__control:hover { color: var(--accent-strong); }

/* The one control that is doing the work. It is bigger than its neighbours
   and it is the only one that carries a ring, so the eye finds play without
   reading six icons -- the same argument as the ayah medallion, which is the
   one mark on a verse card that is allowed to be an object. */
.recite__control--play {
  inline-size: 60px;
  block-size: 60px;
  border: var(--hair) solid var(--rule);
  border-radius: var(--radius-pill);
  background: var(--paper);
  color: var(--accent-strong);
}

.recite__control--play:hover { border-color: var(--accent); }

.recite__icon { flex: none; }

/* The reciter's name gives way first. Al-Minshawi's full name, six controls
   and a verse key do not fit a 320px sheet, and of those three the name is
   the one a listener already knows: they chose it. */
.recite__name {
  min-inline-size: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  font-family: var(--font-sans);
  font-size: var(--fs-body-sm);
  color: var(--ink-soft);
}

/* The way back. With no follow-along scrolling, this is how a listener who
   went to read a commentary returns to the verse being recited. */
.recite__verse {
  flex: none;
  font-family: var(--font-sans);
  font-size: var(--fs-body-sm);
  font-variant-numeric: tabular-nums;
  color: var(--accent-strong);
  text-decoration: none;
  border-block-end: var(--hair) solid var(--rule);
}

.recite__verse:hover { border-block-end-color: var(--accent); }

/* ---- The settings menu -------------------------------------------------- */

/* Placed by the stylesheet alone. It is absolutely positioned inside the
   strip, which is itself fixed, so there is nothing to measure and therefore
   none of the .style writing this project's policy refuses. It rises FROM the
   menu button rather than covering the transport, because the transport is
   what a reader reaches for next. */
/* The wrapper is what makes the menu placeable without measuring: it is the
   dots button's own containing block, so "above the dots" is inset-block-end
   on a static offset rather than a coordinate somebody had to work out. */
.recite__menuwrap {
  position: relative;
  display: inline-flex;
  flex: none;
}

.recite__menu {
  position: absolute;
  inset-block-end: calc(100% + var(--space-2));
  inset-inline-start: 0;
  z-index: 1;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  inline-size: max-content;
  /* Measured against the viewport rather than the strip, because the menu now
     starts wherever the dots are rather than at a known edge. 3rem covers the
     inset on the narrowest sheet with room to spare, and at every width from
     320px up the menu lands inside the screen without a second rule. */
  max-inline-size: min(22rem, calc(100vw - 3rem));
  max-block-size: min(60vh, 30rem);
  overflow-y: auto;
  padding: var(--space-3);
  border: var(--hair) solid var(--rule-strong);
  border-radius: var(--radius-control);
  background: var(--paper-raised);
}

/* The companion to [hidden], for the fourth time in this stylesheet: the
   display rule above outranks the user agent's own, so hiding has to be
   restated or the menu never goes away. */
.recite__menu[hidden] { display: none; }

/* A copy of the Display panel's group rules rather than a shared class. The
   two are the same idea at different sizes and the panel's own section owns
   its version; if either is restyled, look at the other. */
.recite__group {
  margin: 0;
  padding: 0;
  border: 0;
}

.recite__group + .recite__group {
  padding-block-start: var(--space-3);
  border-block-start: var(--hair) solid var(--rule);
}

/* The rate beside its name, so "Normal" and "1x" read as one row rather than
   as two columns that have to be lined up. */
.recite__rate {
  margin-inline-start: var(--space-2);
  font-variant-numeric: tabular-nums;
  color: var(--ink-faint);
}

/* ---- Narrow, fine, and forced ------------------------------------------- */

/* Below 40rem the menu spans the strip instead of hanging off its start edge:
   at 320px a max-content menu and a 24px inset leave the last option cramped
   against the rim. */
/* On a phone the row becomes two rows.

   Measured rather than guessed: six controls at the 44px touch floor is 264px
   before a single gap, and a 320px sheet has about 272px between its gutters.
   Squeezing them beside the reciter's name left the name at nothing and still
   overflowed. Stacking gives the transport the whole width, where it centres
   with room to spare, and gives the name its own line above.

   The touch floor is the one thing that does not give way here: this is the
   surface most likely to be driven with a thumb. */
@media (max-width: 39.999rem) {
  .recite__spacer { display: none; }

  .recite__row {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
  }

  .recite__who {
    justify-content: center;
    inline-size: 100%;
  }

  .recite__transport {
    justify-content: center;
    inline-size: 100%;
    gap: var(--space-1);
  }

  .recite__control {
    inline-size: 44px;
    block-size: 44px;
  }

  .recite__control--play {
    inline-size: 52px;
    block-size: 52px;
  }

  /* The two rows are taller than one, so the page owes the strip more. */
  body.recite-active { padding-block-end: 11rem; }

  body.recite-active .wstudy__returnpill { --wstudy-returnlift: 11rem; }

  /* The menu spans the strip on a phone instead of hanging off the dots.

     Centring it on the dots was the previous attempt and it ran off the left
     edge, which is the fault this replaces: the dots are the FIRST control in
     a centred transport, so their middle sits about 48px from the start of a
     320px sheet, and half of a 288px menu is 144px. It was off the screen by
     roughly a hundred pixels before it had drawn anything.

     Making the wrapper static is what fixes it, and it is worth understanding
     rather than copying: an absolutely positioned element is placed against
     its nearest POSITIONED ancestor, so with the wrapper relative the menu
     could only ever be measured from a 44px button. Standing the wrapper down
     hands that job to .recite, which is the full width of the screen, and the
     menu can then simply span it. */
  .recite__menuwrap { position: static; }

  .recite__menu {
    inline-size: auto;
    inset-inline: var(--space-3);
    max-inline-size: none;
  }
}

/* No pointer: fine condensation on these. The controls elsewhere in this
   stylesheet shrink for a mouse because they are incidental marks that only
   need to clear a thumb; this is the instrument the reader is driving, and it
   should be as findable with a mouse as with a finger. */

/* The thumb, the accent fill and the tint all vanish under forced colours, so
   the scrubber goes back to the platform widget, which follows the user's own
   palette by construction. */
@media (forced-colors: active) {
  .recite__bar {
    -webkit-appearance: auto;
    appearance: auto;
  }

  .recite__control--play { border: 1px solid ButtonText; }
  .recite__menu { border: 1px solid ButtonText; }
}

/* The strip is two rows now, so the page owes it more room. Measured at the
   shipped sizes: 24px scrubber + 44px controls + padding and the hairline
   comes to just under 6rem, and the last verse must clear it whether or not
   the foot navigation is in view. */
body.recite-active { padding-block-end: 8.5rem; }

@media (prefers-reduced-motion: no-preference) {
  .recite { transition: transform 160ms ease-out; }
}

/* The ring and the tint both disappear under forced colours, so the disc needs
   an edge that is drawn from the system palette. */
@media (forced-colors: active) {
  .verse__play > svg { border: 1px solid ButtonText; }
  .verse__play.is-active > svg { border: 2px solid Highlight; }
}

/* Rules for this section, after this section: the two panels pad <body> by
   50vw at the split, and a fixed element does not move with that padding, so
   the strip would otherwise run underneath an open commentary. */
@media (min-width: 62rem) {
  body.tafsir-open .recite,
  body.reflections-open .recite { inset-inline-end: var(--qs-panew, 50vw); }
}


/* ----------------------------------------------------------------------------
   20. Word study

   The Dictionary & Grammar panel, and its two ways in: the acts row inside the
   word-by-word tooltip, and the chip in a verse's citation row. The third
   panel to take the right half; the shell below is the tafsir and reflections
   shell repeated once more, deliberately -- the brain's extraction trigger has
   fired and the extraction is its own commit, not a rider on this one.

   Unlike those two, the panes here hold no cross-origin iframe, so nothing in
   this section is bound to the visibility discipline sections 13 and 18
   defend. The two tab panes still swap by visibility rather than display, but
   for a cheaper reason: display:none zeroes a scroll box, and a reader who
   flips to Grammar and back should find the concordance where they left it.

   COLOUR IS PERMITTED IN EXACTLY ONE PLACE. The segment decomposition in the
   Grammar pane is our own corpus text rendered in Amiri, so CSS color reaches
   it; the mushaf text out on the page is COLR/CPAL territory, which is why
   the in-text .is-studied mark below is a background and must stay one, the
   same rule .is-playing follows in section 12.
   ------------------------------------------------------------------------- */
.wstudy {
  position: fixed;
  inset: 0;
  z-index: 94;
  pointer-events: none;
}

body.wstudy-open { overflow: hidden; }

.wstudy__scrim {
  position: absolute;
  inset: 0;
  background: var(--paper-sunk);
  opacity: 0;
  transition: opacity var(--dur-slow) var(--ease-calm);
}

.wstudy.is-open .wstudy__scrim {
  opacity: 0.92;
  pointer-events: auto;
}

.wstudy__panel {
  position: absolute;
  inset-block-start: var(--space-7);
  inset-block-end: 0;
  inset-inline-end: 0;
  inline-size: 100%;
  display: flex;
  flex-direction: column;
  background: var(--paper);
  border-block-start: var(--hair) solid var(--rule);
  box-shadow: var(--shadow-soft);
  pointer-events: auto;
  visibility: hidden;
  transform: translateY(101%);
  transition: transform var(--dur-slow) var(--ease-calm),
              visibility 0s linear var(--dur-slow);
}

.wstudy.is-open .wstudy__panel {
  visibility: visible;
  transform: none;
  transition: transform var(--dur-slow) var(--ease-calm),
              visibility 0s;
}

/* The bar carries the TRAIL and the way out, and nothing else. It held the
   subject and four controls in one flat row with a single uniform gap until
   2026-08-21, which made proximity lie: the play button sat against the root
   and read as belonging to it. Identity moved to .wstudy__subject below.

   Deliberately left to right, like every other piece of chrome in this app
   and like corpus.quran.com's and quran.com's. The Arabic inside it is
   isolated per run by dir="rtl", so the letters read right to left inside
   furniture that reads left to right. The old right-shove was nobody's
   decision: the word was the only flex: 1 item, so it absorbed the slack and
   pushed everything after it to the end of the bar. */
.wstudy__bar {
  display: flex;
  align-items: center;
  /* WRAPS, since the search box moved in beside the nameplate on 2026-08-22.
     At a sheet's width the name, a box and the way out do not fit on one
     line, and this bar has been overcrowded before -- it once held 361px of
     fixed width in a 320px viewport and pushed the close button off the
     screen with the only way out on it. The box takes the second line rather
     than squeezing the two things that must never move. */
  flex-wrap: wrap;
  gap: var(--space-2);
  flex: none;
  min-block-size: var(--panel-bar-min, 44px);
  padding: var(--space-1) var(--space-3);
  border-block-end: var(--hair) solid var(--rule);
  background: var(--paper-raised);
  /* What the way back asks before it takes a place here; see .wstudy__came. */
  container: wstudy-bar / inline-size;
}

/* ---- Zone 2: the trail -------------------------------------------------
   A row of its own, gone entirely when there is nowhere to go back to.
   Sharing the bar with the tabs would leave Back no room to name its
   destination at 320px, which is the whole point of Back here. */
/* ---- The word tabs, which replaced the stack ---------------------------
   Each is one question the reader asked. The active one is where they are;
   every other is a place they can return to exactly as they left it. A Back
   button and an origin line stood here for a day and still left readers
   unlocated, because a stack is invisible and models drilling-and-returning
   while what a student does is COMPARE.

   Shaped like a BROWSER's tabs rather than as pills. A capsule floating on a
   bar reads as a chip -- a thing you toggle on and off -- and these are
   places you stand in. So the strip is recessed, an unchosen tab is a hole
   cut in it, and the chosen one is the same sheet of paper as the band it
   opens onto, square at the foot because it does not end there: the content
   below it does. That outline is what carries the mark, which is why no
   accent FILL is needed here -- the solid-fill rule that governs a chosen
   row in a list is answering a different question, "which of these did I
   pick", where a tab answers "where am I standing". */
.wstudy__tabrow {
  display: flex;
  align-items: stretch;
  gap: var(--space-2);
  flex: none;
  min-inline-size: 0;
  /* Nothing at the foot. The tabs stand ON the rule and the chosen one
     breaks it, which is the whole trick and needs them flush. */
  padding: var(--space-1) var(--space-2) 0;
  border-block-end: var(--hair) solid var(--rule);
  background: var(--paper-sunk);
}

.wstudy__tabrow[hidden] { display: none; }

/* The way home is a line of prose, not a tab, so it does not take a tab's
   full height when the row stretches to hold them. */

/* The strip scrolls rather than squeezing: the way out never yields, and
   neither does a tab's own name. */
.wstudy__wordtabs {
  display: flex;
  /* Touching, the way a browser's own strip runs. Neighbours meet and their
     side hairlines collapse into one shared rule, so what stands between two
     tabs is a single divider rather than a pair with a gutter down the middle.
     A 2px gap here read as five loose words, not as a strip. */
  gap: 0;
  flex: 1 1 auto;
  min-inline-size: 0;
  overflow-x: auto;
  scrollbar-width: none;
  /* Room at the sides and top for a focus ring the scroller would otherwise
     clip; and one hairline BELOW the row's content, so the strip sits on the
     rule and the chosen tab's ground breaks it. The bleed is on this box and
     not on each tab: overflow-x makes overflow-y compute to auto, and a tab
     hanging past its own scroller would raise a vertical scrollbar. */
  padding: 2px 2px 0;
  margin: -2px -2px calc(var(--hair) * -1);
}

.wstudy__wordtabs::-webkit-scrollbar { display: none; }

/* THE STRIP SAYS WHEN IT HOLDS MORE THAN IT SHOWS. At eight tabs the row runs
   to two or three strip widths, and it hides its scrollbar in both engines --
   so without this a reader has no way to know the tabs they cannot see exist.
   A fade at the trailing edge costs no height, no control and no tab stop.

   It needs no overflow detection and no class from the module, because the
   tabs are content-sized and packed to the start: when they do NOT overflow
   there is bare strip at the trailing edge and the fade falls on nothing.
   It only becomes visible when there is a tab under it, which is exactly
   when it is telling the truth. */
.wstudy__wordtabs {
  mask-image: linear-gradient(to right, #000 calc(100% - 2.5rem), transparent);
}

.wstudy__wordtab {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  flex: none;
  max-inline-size: 13rem;
  min-block-size: 40px;
  padding: 3px var(--space-2);
  /* Every tab keeps its shape, chosen or not. An outline only on the chosen
     one made the other four read as loose words lying on a bar, and a place
     you can return to has to look like a place while you are away from it.
     The chosen tab is still told apart three ways the others are not: the
     raised ground, the crown, and the rule broken beneath it.

     --rule-strong and not --rule: measured on the strip, a --rule hairline
     on --paper-sunk is two steps of the same beige and vanishes at arm's
     length, which is a shape only a colour picker can see. */
  border: var(--hair) solid var(--rule-strong);
  border-block-end: 0;
  border-start-start-radius: var(--radius-control);
  border-start-end-radius: var(--radius-control);
  /* Each tab sits ON the side rule of the tab before it, so two neighbours
     show one hairline between them: the vertical line a browser draws. */
  margin-inline-start: calc(var(--hair) * -1);
  background: none;
  color: var(--ink-soft);
  font-family: var(--font-sans);
  font-size: var(--fs-caption);
  line-height: var(--lh-tight);
  white-space: nowrap;
  cursor: pointer;
}

.wstudy__wordtab:first-child { margin-inline-start: 0; }

.wstudy__wordtab:hover { background: var(--paper); color: var(--ink); }

/* The one you are in is the sheet of paper the band below is printed on --
   read by being continuous with that band rather than by a fill of its own,
   which is what makes it a tab and not a chip. It is raised above its
   neighbours so the shared side rules and the row's rule are its to break.

   There was a 2px accent crown here until 2026-08-22. It went because it was
   a third mark on a thing already carrying two, and because the browser this
   strip is imitating does not draw one: what says "you are here" in Chrome is
   the raised sheet running into the page, and it says it without colour. */
.wstudy__wordtab.is-active {
  z-index: 1;
  background: var(--paper-raised);
  color: var(--ink);
  font-weight: 600;
}

.wstudy__wordtab-body {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 1px;
  min-inline-size: 0;
}

/* The line that truncates. Both halves of it are one nowrap run, so a long
   word eats into its own name and never into the close beside it. */
.wstudy__wordtab-line {
  display: block;
  max-inline-size: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* The verse reference comes back HERE and only here. It left the header
   because it answered "which verse is this?" from inside that verse; on a
   tab it is navigation, which is what a tab label is for. */
.wstudy__wordtab-ref {
  margin-inline-end: var(--space-1);
  font-variant-numeric: tabular-nums;
}

/* The Search tab, which names a question rather than a place: the bar's own
   glyph and the chrome's own word for it, so the reader recognises the tab
   before reading it. It is renamed into a word or a root the moment a result
   is chosen, and then wears the ordinary dress above. */
.wstudy__wordtab-name {
  margin-inline-start: var(--space-1);
  font-size: var(--fs-body-sm);
  vertical-align: middle;
}

.wstudy__wordtab-name + svg,
.wstudy__wordtab-line > svg { vertical-align: middle; }

.wstudy__wordtab-ar {
  font-family: "Amiri Quran", serif;
  font-size: var(--fs-body);
  /* Never the 600 the chosen tab sets. Amiri Quran ships no bold face, so
     asking for one makes the browser smear the glyphs into a synthetic
     weight -- and the marks are the first thing that smearing costs. */
  font-weight: 400;
  /* Room for the marks above an alif, which a tighter tab line would clip. */
  line-height: 1.4;
  color: var(--ink);
}

/* Quiet, because it is the line you read only when the Arabic has not told
   you yet -- which for this reader is often, and is the point. */
.wstudy__wordtab-en {
  max-inline-size: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: var(--fs-label);
  font-weight: 400;
  letter-spacing: 0.01em;
  color: var(--ink-faint);
}

.wstudy__wordtab.is-active .wstudy__wordtab-en { color: var(--ink-soft); }

.wstudy__wordtab-x {
  flex: none;
  align-self: center;
  opacity: 0.55;
  font-size: var(--fs-body);
  line-height: 1;
}

.wstudy__wordtab-x:hover { opacity: 1; }

@media (forced-colors: active) {
  /* Outlines survive forced colours where backgrounds do not, so the strip
     keeps its shapes; the chosen tab is then told by its crown, which needs
     the adjust turned off to keep the Highlight it is drawn in. */
  .wstudy__wordtab { border-color: CanvasText; }
  .wstudy__wordtab.is-active {
    forced-color-adjust: none;
    border-color: Highlight;
    background: Canvas;
    color: CanvasText;
  }
  .wstudy__wordtab.is-active .wstudy__wordtab-en { color: CanvasText; }
}


/* ---- Zone 3: the subject ----------------------------------------------
   One shape for all three kinds: eyebrow, the big thing, one line describing
   it, then its place and its door. Whitespace carries the structure here --
   the brief's rule -- so this block holds no boxes except the one door,
   which is a box because you can walk through it. */
/* ---- The header: the word, and what it IS ------------------------------
   Two blocks side by side: the word in the TEXT on the left, and its grammar
   -- which had a tab of its own until 2026-08-21 and describes nothing but
   that word -- on the right. Narrow panes stack them; the content is the
   same either way.

   THE SPLIT IS FIXED, at two parts word to three parts grammar. It was
   `flex: 0 1 auto` against `flex: 1 1 22rem`, so both halves sized to their
   own contents and the ratio moved with the window: measured at 42/49 on a
   1280 laptop and 41/52 at 1500, with the seven to nine percent that neither
   half claimed opening as a gutter down the middle of the word's column.
   Grammar takes the larger part because it holds the most -- a sentence, a
   decomposition, a line per segment and two links, against one word.

   Both halves STRETCH to the taller of them, which is what lets the word
   card push its neighbours to its own foot. */
/* The container the step labels ask about; see .wstudy__wordstep-scope. */
.wstudy__head {
  container: wstudy-head / inline-size;
  display: grid;
  /* 4fr/5fr since 2026-08-22, and the number is the dictionary's. The lower
     half became a menu beside its results, and that seam is a hairline in the
     same column of pixels as this one -- two vertical rules 27px apart read
     as a mistake, not as two decisions. So the panel keeps ONE ratio and one
     seam from the word down to the verses. Identity is compact and Lane's
     opening words need measure, which is what the 2fr/3fr said; at 4fr/5fr
     the entry gains 27px and Lane's one-line taste loses them, and the taste
     is a taste. */
  /* 3fr/4fr since 2026-08-23, and the number is still shared by all three
     grids that carry it -- this header, the root card, and the dictionary --
     so their seams keep landing in one column of pixels.

     MEASURED before it moved, because the owner asked how much narrower this
     column could comfortably go. At a half-width panel the binding constraint
     is the derived forms' English in the menu's middle track, and it fails
     suddenly rather than gradually: 4fr/5fr and 3fr/4fr both hold it to two
     lines, 2fr/3fr takes it to three -- the regression this file already
     recorded and reversed once -- and 1fr/2fr to six. So 3fr/4fr is the whole
     of what is free here, worth about 12px to the verse column. A reader who
     wants materially more room widens the PANEL, which is worth ten times as
     much: the verse column goes 389px to 501 between a 750 panel and a 950. */
  grid-template-columns: 3fr 4fr;
  /* ONE ROW, EXACTLY THIS BOX'S HEIGHT. An auto row sizes to its content,
     so both columns kept their full height and the HEADER clipped them --
     which means neither column could report its own overrun and the two
     ladders had nothing to measure. minmax(0, 1fr) makes the row the
     container, so each column is clipped by its own hidden overflow and
     says so. */
  grid-template-rows: minmax(0, 1fr);
  align-items: stretch;
  column-gap: var(--space-5);
  flex: none;
  padding: var(--space-4);
  border-block-end: var(--hair) solid var(--rule);
  background: var(--paper-raised);
  /* LOCKED, not merely capped. The header grew with the number of segments
     in the word's grammar -- measured at 294px for a one-segment word and
     471px for a five-segment one at the same 1280 window -- so the root, the
     related words and the verses jumped down the pane at every step to the
     next word. The thing a reader lands on cannot be the thing that moves.

     24rem covers 90% of words at the tightest two-column pane and 97% at
     1600. Locking to the TRUE maximum was measured and rejected: 495px is 53%
     of a 940px-tall viewport, and it is asked for by 44 words out of 77,429 --
     the rows below would begin off the screen on a laptop to spare 0.06% of
     words a short scroll.

     SUPERSEDED 2026-08-23: the sentence here used to end "the deepest 1%
     overrun and scroll here". They no longer overrun. The grammar beside the
     word was rebuilt to fit the lock rather than to scroll inside it -- three
     doors on one row with rules between, and one line per segment with its
     features separated the same way -- which took the worst word in the
     corpus from 511px to 351 in a 351px box. Those 44 words are still the
     measure; they are simply drawn to fit now. See the overflow rule below,
     and the pins that hold it.

     min(), so a short window still gets a header proportional to it rather
     than one that eats the whole pane.

     --qs-headh, when panel-resize.js sets it, can only ever LOWER this lock:
     the script clamps to this same min() before writing, and the 46vh arm
     here catches anything a stale localStorage value could smuggle in on a
     shorter window. So every measurement above still describes the ceiling,
     and a reader who has never dragged sees exactly it. */
  block-size: min(var(--qs-headh, 24rem), 46vh);
  /* A FLEX ITEM WILL NOT GO UNDER ITS CONTENT UNLESS TOLD TO. min-block-size
     defaults to auto for a flex item, which resolves to the min-content
     height, and that silently outranks the block-size above: with the grammar
     of a deep word inside, the header simply refused to shrink past about
     360px however small --qs-headh was set. It also hid the overflow from the
     ladder, which decides its rung by asking whether the content fits. */
  min-block-size: 0;
  /* NO SCROLLER, and that is a decision rather than a tidy-up: a scrollbar has
     no business inside a header that is the panel's own fixed furniture. What
     used to need it was rebuilt to fit -- see the note above. hidden and not a
     suppressed bar, so that a regression clips where a pin can see it instead
     of quietly growing the scrollbar back. */
  overflow: hidden;
}

/* One column when there is no grammar to stand beside, and no lock either:
   a verse subject's header is a single eyebrow, and holding 24rem open above
   the list the reader actually came for is a screen of nothing. */
.wstudy__head:has(> .wstudy__gram[hidden]) {
  grid-template-columns: 1fr;
  block-size: auto;
  /* dvh second, for the reason recorded at .wstudy__lanebox: on Android vh is
     the viewport with the URL bar hidden, so a cap in vh reserves more of the
     screen than the reader can see while the bar is down. */
  max-block-size: 46vh;
  max-block-size: 46dvh;
}

/* The word's own card: a fixed two fifths, a flex column so that the
   neighbours at its foot can be pushed there, and centred throughout --
   which it can afford to be now that its width no longer depends on what is
   standing in it. */
.wstudy__subject {
  display: flex;
  flex-direction: column;
  min-inline-size: 0;
  /* Its own overflow, so the card's ladder can be measured against the card
     rather than against the header both halves share. Without this the column
     stretches to the grid row and reports scrollHeight === clientHeight while
     its content is visibly clipped, which is how one ladder came to drop
     grammar to fix a card that was the thing overflowing. */
  min-block-size: 0;
  overflow: hidden;
  padding-inline-end: var(--space-5);
  /* The separation between the halves, in the brief's own structure
     vocabulary: a hairline, never a fill or a shadow. It turns with the
     layout -- see the narrow query, where it becomes the rule above the
     grammar instead of the rule beside it. */
  border-inline-end: var(--hair) solid var(--rule);
  text-align: center;
}

/* Nothing to divide from, and nothing to make room for: a verse subject
   carries no grammar, so the rule and its gutter would be dividing the
   block from empty space. */
.wstudy__head:has(> .wstudy__gram[hidden]) > .wstudy__subject {
  padding-inline-end: 0;
  border-inline-end: 0;
}

/* The grammar of the word beside it, in the larger share -- and the part
   that scrolls when a word runs deeper than the locked height. The header
   was the scroller, which meant the 1% of words deep enough to overrun it
   scrolled the WORD CARD away: the one thing the lock exists to hold still.
   The grammar is what overruns, so the grammar is what moves. */
.wstudy__gram {
  min-inline-size: 0;
  min-block-size: 0;
  /* A column, so the doors out of the grammar can sit at its FOOT -- on the
     same line as the word's own neighbours across the header, which is where
     this half's apparatus already lives. See .wstudy__gram > .wstudy__links. */
  display: flex;
  flex-direction: column;
  /* See the header's own note: this half is built to FIT rather than to
     scroll, so what would have overflowed is clipped where a pin can see it. */
  overflow: hidden;
  /* Its own colours, hoisted from the decomposition strip they used to sit
     on: the segment lines below are siblings of that strip, not its
     children, so a variable declared there could never reach them. */
  --wstudy-prefix: var(--tj-madd-normal);
  --wstudy-stem: var(--accent-strong);
  --wstudy-suffix: var(--tj-qalqalah);
}

/* THE CARD'S CHILDREN KEEP THEIR OWN HEIGHT TOO, for the same reason as the
   grammar's below: a flex column shrinks its items, so a squeezed card was
   crushed rather than overflowing and reported scrollHeight === clientHeight
   while the word itself was visibly gone. .wstudy__ident is the exception --
   it is the one box meant to take the leftover space, which is what centres
   the word at full height. */
.wstudy__subject > *:not(.wstudy__ident) { flex: none; }

/* GROW BUT NEVER SHRINK. The identity block takes the leftover space, which is
   what centres the word at full height, and it kept `1 1 auto` -- so under
   pressure it was the one box that gave way, crushing the word and the gloss
   inside itself where the column could not see it. The card's ladder then had
   nothing to measure and left the word clipped. `1 0 auto` keeps the centring
   and makes the overrun the column's, where it is read. */
.wstudy__ident { flex: 1 0 auto; }

/* THE CHILDREN KEEP THEIR OWN HEIGHT. A flex column shrinks its items by
   default, so when the header was squeezed the segment list and the doors were
   crushed rather than overflowing -- which looked like clipping and, worse,
   made the overflow undetectable: scrollHeight stayed equal to clientHeight
   while the content visibly vanished, so the ladder in panel-resize.js could
   never tell that it needed to drop a rung.

   flex: none, so what does not fit OVERFLOWS, the hidden overflow clips it,
   and the measurement that decides the rung is finally true. */
.wstudy__gram > * { flex: none; }

.wstudy__gram[hidden] { display: none; }

/* THE DOORS SIT AT THE FOOT. The three of them -- the classical i'rab, the
   whole verse word by word, and the glossary -- are the apparatus of this
   half, and apparatus belongs under what it is about rather than trailing the
   last segment line by twelve pixels. It lands them on the row the word's own
   NEXT and PREVIOUS keep across the header, so the two halves agree about
   where a foot is.

   Exactly ONE box may take the leftover space, which is the rule this panel
   learnt the expensive way: nothing above this carries flex: 1, so the auto
   margin gets all of it. The padding is what keeps a gap when a deep word
   fills the column and there is no slack left to take. */
.wstudy__gram > .wstudy__links {
  margin-block-start: auto;
  /* Its own trailing margin would hold it 12px off the foot it is being sent
     to, and the steps across the header sit flush with theirs. */
  margin-block-end: 0;
  padding-block-start: var(--space-3);
}

/* display: grid above outranks the user agent's [hidden], so hiding the
   header on a root subject has to be restated here. */
.wstudy__head[hidden] { display: none; }

.wstudy__gramtitle {
  margin: 0 0 var(--space-1);
  font-family: var(--font-sans);
  font-size: var(--fs-label);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

@media (max-width: 61.99rem) {
  /* Stacked: one column, and the rule between the halves turns with them --
     a vertical rule beside the grammar becomes a horizontal one above it. */
  .wstudy__head {
    grid-template-columns: 1fr;
    row-gap: var(--space-3);
    /* NOT locked here, and no longer capped either. Stacked, the header is
       the word card AND the grammar, so a height that held the deepest word
       would leave the root and the verses below the fold of a 640px screen on
       every shallow one -- the failure this pane was already measured making
       once. It was capped at 52vh with its own inner scroll because it was a
       FIXED sibling above a pane that scrolled separately; the sheet is one
       scroller now, so the rows below stay reachable by scrolling to them and
       a second scrollbar inside the first is only a trap. */
    block-size: auto;
    max-block-size: none;
    overflow: visible;
    padding: var(--space-3);
  }

  /* AND THE GRAMMAR GIVES UP ITS SCROLLER TOO, which the rule above always
     meant and never said. The header was released to the sheet, but the box
     INSIDE it kept `overflow-y: auto` and `overscroll-behavior: contain` from
     its base rule -- and on a touch screen that is enough to swallow a flick
     whether or not there is anything to scroll: `contain` stops the gesture
     chaining out to the sheet, so a finger starting anywhere on the grammar
     simply held still while the same finger on the root card below moved the
     page. Reported exactly that way.

     THE INVARIANT IS "NO DESCENDANT IS A SCROLL CONTAINER", not "no descendant
     overflows". An earlier pass here measured the second and found one
     scroller, concluded the sheet was healthy, and missed this: a container
     with nothing to scroll still owns the gesture. */
  .wstudy__gram {
    overflow: visible;
    overscroll-behavior: auto;
  }

  .wstudy__subject {
    padding-inline-end: 0;
    border-inline-end: 0;
    border-block-end: var(--hair) solid var(--rule);
  }

  /* Nothing beneath it to divide from. */
  .wstudy__head:has(> .wstudy__gram[hidden]) > .wstudy__subject {
    border-block-end: 0;
  }

  /* Stacked, the card no longer has a grammar column setting its height, so
     there is no space to push the neighbours into. They take a plain margin
     and stay directly under the word they step from. */
  .wstudy__steps { margin-block-start: var(--space-3); }

  .wstudy__segments {
    margin-block-end: var(--space-1);
    font-size: var(--fs-body-lg);
    line-height: 1.7;
  }
}

/* The sole owner of the classic eyebrow: uppercase, tracked, tiny. Ink-soft
   rather than accent, because accent in this panel now means only "you can
   press this". Four other roles wore this exact treatment in accent, which
   is why nothing stood out from anything else. */
.wstudy__kind {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  margin: 0 0 var(--space-1);
  font-family: var(--font-sans);
  font-size: var(--fs-label);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-soft);
  text-align: center;
}

.wstudy__kind[hidden] { display: none; }

/* WHERE the subject is, on the eyebrow rather than beside the word: the word
   stands alone on its line so that it sits on the axis its gloss and
   transliteration share, and anything next to it drags it off that axis --
   which is why the reference left the header in the first place.

   It is a verse chip, so it inherits the chip's dress and its behaviour
   whole; only the eyebrow's own uppercase and tracking are undone, because
   "23:96" is an address and not a label. */
.wstudy__vchip--head {
  letter-spacing: normal;
  text-transform: none;
  font-weight: 400;
}

.wstudy__vchip--head[hidden] { display: none; }

/* What the word IS, taking whatever height the grammar beside it sets and
   centring inside it. Without this the identity sat hard against the top of
   a stretched card and the whole difference opened as a hole above the
   neighbours -- the card was as tall as the grammar and mostly empty.

   THREE TRACKS, AND THE MIDDLE ONE IS THE WORD. Its two neighbours flank it
   again, as they did until 2026-08-21, and the objection that retired them is
   answered in the tracks rather than argued with: `minmax(0, 1fr)` on each
   side keeps the sides EQUAL whatever stands in them, so the word holds the
   column's own axis -- which content-sized tracks could not do, because two
   neighbours of unequal width drag the middle one around with them. A missing
   neighbour costs the axis nothing, for the same reason.

   Rows under it, both spanning: the English, then how it sounds. That order
   is the panel's own and does not change with the rung. */
.wstudy__ident {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: center;
  /* The rows sit together in the middle of whatever height the grammar beside
     them sets, rather than spreading through it. */
  align-content: center;
  column-gap: var(--space-2);
  /* NO `flex` HERE. It is declared once, up beside .wstudy__subject, as
     `1 0 auto` -- grow but never shrink -- and this block used to restate it
     as `1 1 auto` four rules later in the same file. Same specificity, later
     rule, so the fix that note records was never once in force. */
  min-block-size: 0;
}

/* The word, in the middle track. It is centred by the TRACKS and not by what
   stands beside it: the old box holding `word + gap + button` centred the
   pair, which stood the word 12px right of the axis its gloss sat on. That is
   why the band gives the speaker a track of its own on this row rather than
   putting it back inside this one. */
.wstudy__wordline { grid-area: 1 / 2; margin: 0; }

.wstudy__word {
  min-inline-size: 0;
  font-family: "Amiri Quran", serif;
  font-size: var(--fs-display);
  line-height: 1.9;
  color: var(--ink);
}

/* The pronunciation, written and heard, on one line: they are the same
   claim in two forms, and a control belongs with the thing it renders. */
.wstudy__say {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-1);
  margin: var(--space-1) 0 0;
}

.wstudy__say[hidden] { display: none; }

/* A SPEAKER, not a play triangle. A circled triangle is the mark for "a
   timeline starts" -- and this panel already spends a circled triangle on
   the lectures button, where a timeline genuinely does. The question a
   reader asks here is how the word sounds, which every dictionary answers
   with a small speaker on the pronunciation line.

   No box: accent already says "you can press this", the root steps' rule.
   The 44px floor is kept as hit area rather than as a visible edge, so the
   glyph can read at 16px without the target shrinking with it. */
.wstudy__play {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  max-inline-size: 100%;
  min-inline-size: 0;
  min-block-size: 44px;
  padding: var(--space-1) var(--space-3);
  border: 0;
  border-radius: var(--radius-control);
  background: none;
  color: var(--accent-strong);
  cursor: pointer;
  transition: background-color var(--dur) var(--ease-calm);
}

/* The whole line lights, not the glyph: it is one control, and a hover that
   covers only the icon says the words beside it are inert. */
.wstudy__play:hover { background: var(--paper-sunk); }

.wstudy__play:hover .wstudy__translit { color: var(--ink-soft); }

.wstudy__play[hidden] { display: none; }

/* The two neighbours FLANK the word rather than standing under it, NEXT on
   the left because Arabic runs right to left and the word before this one
   stands to its right.

   The paragraph itself lays out nothing: `display: contents` hands its two
   buttons to .wstudy__ident's grid, which is where the row is. That keeps the
   markup's own reading order -- word, English, sound, then the ways onwards
   -- while the grid frames the word with them. The rule that used to run
   above this block went with the foot: a hairline between an entry and the
   two arrows that walk away from it separates nothing, which is the reasoning
   the root card recorded when it deleted its own. */
.wstudy__steps { display: contents; }

/* `hidden` is a user-agent rule of the lowest specificity and any author
   display rule beats it, so the display above has to be said again here. */
.wstudy__steps[hidden] { display: none; }

/* The root steps' dress: NO BOX. Accent already says "you can press this",
   and these wore bordered pills while the arrows on the row below wore
   none, so one row of the same panel contradicted the next. */
.wstudy__wordstep {
  /* The row's left-hand side, and its far end: the pair FRAMES the word,
     which is the root card's own arrangement below. */
  grid-area: 1 / 1;
  justify-self: start;
  /* WITH the justify-self, and not decoration: a grid item stretches to its
     track by default, and one that opts out is sized to its CONTENT -- which
     is how the root card's own second arrow came to stand 124px wide inside a
     58px column and draw across the arrow beside it. Bounded here, the
     ellipsis rules below do what they already intend to. */
  max-inline-size: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  min-inline-size: 0;
  min-block-size: 44px;
  padding: var(--space-1);
  border: 0;
  border-radius: var(--radius-control);
  background: none;
  color: var(--accent-strong);
  font-family: var(--font-sans);
  cursor: pointer;
}

.wstudy__wordstep--prev {
  grid-area: 1 / 3;
  justify-self: end;
  max-inline-size: 100%;
}

.wstudy__wordstep:hover { background: var(--paper-sunk); }

.wstudy__wordstep[hidden] { display: none; }

/* Which way, in words. The flanking arrangement made the arrows unambiguous
   by shape alone; at the card's foot the shape no longer explains itself, so
   the words have to.

   NOT the eyebrow's dress. `--fs-label` / 600 / 0.12em / uppercase belongs to
   exactly one role in this panel, and PREVIOUS/NEXT wearing it was one of the
   six shouts that left nothing standing out from anything else. */
.wstudy__wordstep-way {
  font-size: var(--fs-label);
  line-height: var(--lh-tight);
  color: var(--ink-faint);
  /* Two lines, and the break is DECLARED rather than left to the width. These
     buttons are sized to their content, so a longer label makes a wider
     button instead of a taller one -- it would never wrap on its own, it
     would just push the word in the middle of the row narrower. Saying where
     the line falls costs the header a few pixels of height, which the band
     has, and keeps the word its room. */
  text-align: center;
}

/* WHICH next word, and WHICH previous. "Next word" alone is ambiguous in a
   panel that also walks roots and occurrences: the reader could reasonably
   read it as the next word in the CONCORDANCE, which is a different journey
   entirely. It is the next word in this verse, and now it says so.

   ON ONE LINE, THOUGH THE OWNER OFFERED A SECOND. "ok to put in verse on a
   2nd line and push the actual arabic down a bit if needed, we have space in
   that box" -- and the box turned out to have none. It is locked to the line
   the masthead ends on, which is the owner's own earlier requirement and is
   pinned by a test measuring the two edges against each other. Measured, a
   second line takes the button from 41px to 54px, and the band cannot grow to
   meet it, so the LADDER pays: at a narrow panel the rung it reached for is
   .wstudy--card2, the one that takes the speaker away. Losing the way to hear
   a word in order to say which word comes next is a bad exchange.

   So the words go sideways instead, where they cost nothing. nowrap because a
   wrap is the same second line arriving by accident at exactly the widths
   least able to afford it; the button is already bounded and already
   ellipsises. */
/* "in verse" IS A CLARIFICATION, AND A CLARIFICATION IS WHAT GOES FIRST.

   The words are worth having: "Next word" alone leaves a reader three
   reasonable answers in a panel that also walks roots and occurrences. But
   the band they sit in is locked to the line the masthead ends on, so the
   extra line they cost has to come from somewhere -- and measured, at a panel
   under about 38rem the ladder pays it by reaching for .wstudy--card2, which
   is the rung that TAKES THE SPEAKER AWAY. Losing the way to hear a word in
   order to say which word comes next is a bad exchange.

   So the clarification is shown where there is room for it and dropped where
   there is not, which is the ladder's own principle applied one step earlier.
   The button still says "Next word", the accessible name is untouched, and
   the speaker stays.

   47rem IS WHERE THE LONGER OF THE TWO FITS ON ONE LINE, and that is the
   threshold rather than where it merely stops costing the speaker. It is
   measured against PREVIOUS and not against NEXT, because the two are not
   the same length and the shorter one fitting proves nothing about its
   neighbour: at 45.9rem of head, Next stood on one line at 41px while
   Previous wrapped to 54 and became the tallest thing in a row it is
   supposed to flank. A wrapped label is
   90px of text in an 88px column, so both buttons clamp to the column and
   come out the SAME width -- and, being two lines, they stand taller than the
   word they flank and start above it. Two pins caught exactly that: one
   proving the word stays centred when its neighbours differ, and one proving
   the neighbours sit below the word's top. Neither was wrong. The label was.

   So it appears only where it costs nothing at all -- not a line, not a
   column, not a rung -- and below that the row is byte-for-byte what it was.

   THE HEAD IS THE MEASUREMENT, not the window. The panes below make the same
   argument for the same reason: a window width answers the wrong question
   when the reader can drag the seam. Inline-size containment only, and safe
   here for the panes' own reason -- this element's width comes from the panel
   and never from what is inside it. */
.wstudy__wordstep-scope {
  display: none;
  white-space: nowrap;
}

@container wstudy-head (min-width: 47rem) {
  .wstudy__wordstep-scope { display: inline; }
}

.wstudy__wordstep-line {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.2rem;
  max-inline-size: 100%;
  min-inline-size: 0;
}

/* The neighbour's own text, which is what says where the arrow goes. It
   floors at body size: this is pointed Arabic and the marks are the first
   thing to go when it shrinks, unlike the bare radicals on the root steps.
   A long neighbour gives up its tail rather than its column's width. */
.wstudy__wordstep-ar {
  display: block;
  min-inline-size: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-family: "Amiri Quran", serif;
  font-size: var(--fs-body);
  line-height: 1.6;
  color: var(--ink);
}

/* The one italic in the panel, which is what makes it unmistakable at a
   glance: the traditional dress of a translation gloss. */
/* Clear of the MARKS, not of the line box. Amiri's diacritics reach above
   the box the Arabic reserves for itself -- a superscript meem on a word
   like نَفْعًا landed on top of the gloss -- so the gap is measured against
   the ink rather than against the metrics. */
/* AND IT CARRIES WEIGHT, asked for on 2026-08-29. It is the one thing on this
   card that a reader who cannot read Arabic opened the panel to get, and it
   was set in the quietest ink the panel has -- a supporting caption under the
   word rather than the answer to the question. Semibold, in full ink, still
   italic: the italic is what says "translation" and is not up for trade. */
.wstudy__gloss {
  grid-column: 1 / -1;
  margin: var(--space-4) 0 0;
  font-family: var(--font-serif);
  font-size: var(--fs-body-lg);
  font-style: italic;
  font-weight: 600;
  line-height: var(--lh-body);
  color: var(--ink);
  text-align: center;
}

.wstudy__gloss[hidden] { display: none; }

/* How the word sounds, directly under what it means. It spent a day in a
   meta row beside a verse chip, where it read as one item of navigation
   among others; Arabic, then English, then how to say it, is the order a
   reader takes them in. The quietest tier: it supports the Arabic above it
   and competes with nothing.

   It shares its line with the speaker now, so the spacing above belongs to
   the row rather than to the text. */
.wstudy__translit {
  min-inline-size: 0;
  overflow: hidden;
  /* AND THE NOWRAP THAT MAKES THE ELLIPSIS REAL. It was declared without one
     from the day this line was built, which makes it inert -- text-overflow
     acts on a line that overflows its box, and text allowed to wrap never
     does. Invisible while the line had room to spare; the moment the band gave
     it 63px, "l-rahimi" broke across two lines inside a one-line row and took
     the row's height with it, which is the shape of every rule that has been
     dead long enough to look load-bearing. */
  white-space: nowrap;
  text-overflow: ellipsis;
  font-family: var(--font-sans);
  font-size: var(--fs-caption);
  color: var(--ink-faint);
}

.wstudy__origin {
  display: block;
  margin-inline: auto;
}

/* ---- The root's own type, wherever the root column puts it -------------
   The cluster that used to stand in the subject block -- label, radicals,
   count, and for one afternoon a door reading "Dictionary entry" -- is a
   COLUMN now. What survives is the type: the radicals large, the two arrows
   small beside them. */
.wstudy__rootar {
  font-family: "Amiri Quran", serif;
  font-size: var(--fs-h2);
  line-height: 1.25;
  color: var(--ink);
  /* THE RADICALS ARE ONE LINE. `spaced()` puts a real space between them --
     "أ م ن", the dictionary tradition's own presentation -- and a space is a
     break opportunity, so once the mark gave this span a visible ground the
     column could drop the last radical onto a second line. With
     box-decoration-break: clone each fragment then draws its own tint AND its
     own accent edge, which is why the underline appeared beneath the noon
     alone while the letters before it kept the tint: two fragments, two
     marks, and only the lower one's edge in view. */
  white-space: nowrap;
}

/* ---- Search, in the chrome --------------------------------------------- */
.wstudy__find {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  margin-inline-start: auto;
  min-block-size: 44px;
  min-inline-size: 44px;
  border: 0;
  border-radius: var(--radius-pill);
  background: none;
  color: var(--ink-soft);
  cursor: pointer;
}

.wstudy__find:hover { background: var(--paper-sunk); color: var(--ink); }

/* The magnifier carries no state of its own any more: it opened a strip and
   wore aria-expanded for it, and it opens a TAB now. Which tab is live is
   the strip's job to say, and it says it for every tab in one vocabulary. */

/* How the reader got here, and one tap home from any depth. Only from the
   second move on: at the first, Back names the same place. */
.wstudy__origin {
  display: inline-flex;
  align-items: center;
  min-block-size: 32px;
  margin-block-start: var(--space-2);
  padding: 0;
  border: 0;
  background: none;
  color: var(--accent-strong);
  font-family: var(--font-sans);
  font-size: var(--fs-caption);
  text-decoration: underline;
  text-underline-offset: 0.2em;
  cursor: pointer;
}

.wstudy__origin[hidden] { display: none; }


/* The subject's verse chip is gone. It answered "which verse is this?" from
   inside that very verse, and its one other job -- saying when a step
   crossed into the next verse -- belongs to Back, which names where the
   reader came from. The concordance rows keep their own chips: there, the
   verse is genuinely news. */

.wstudy__word[hidden] { display: none; }



.wstudy__close {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-block-size: 44px;
  min-inline-size: 44px;
  padding-inline: var(--space-2);
  border: var(--hair) solid var(--rule);
  border-radius: var(--radius-pill);
  background: var(--paper);
  color: var(--ink-soft);
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  line-height: 1;
  cursor: pointer;
}

.wstudy__close:hover { background: var(--paper-sunk); color: var(--ink); }

/* ---- The way back ------------------------------------------------------

   A verse chip moves the reading page, and until now nothing brought the
   reader back: same-surah jumps offered nothing at all and cross-surah ones
   offered a link in the tab strip, which on a phone goes down with the sheet
   the chip closes. One idiom, one place, both cases.

   It is a PRESSABLE, so it takes the accent as a solid fill -- the panel's
   rule that accent means "you can press this", and section 10's that a fill
   and not a ring is what marks a thing. Bottom-centre of the visible reading
   column, above the recitation strip and clear of the home indicator. */
.wstudy__returnpill {
  position: fixed;
  inset-block-end: calc(var(--wstudy-returnlift, 0px)
                        + max(var(--space-4), env(safe-area-inset-bottom)));
  inset-inline: 0;
  z-index: 92;
  display: flex;
  justify-content: center;
  margin: 0;
  /* The row spans the column so the pill can centre in it; only the pill
     itself takes presses, so the reading under the rest of the row is live. */
  pointer-events: none;
}

/* The display rule above outranks the user agent's [hidden], for the fifth
   time in this stylesheet, so hiding has to be restated. */
.wstudy__returnpill[hidden] { display: none; }

/* Beside a split the panel owns the right half, so the pill centres in the
   half that is still reading -- the same correction .recite takes.

   The pill still exists on a desktop with the panel SHUT: a reader can travel
   and close. Only while the panel is open does the strip inside it take the
   job over, which is the rule in the split's own block below. */
body.wstudy-open .wstudy__returnpill { inset-inline-end: var(--qs-panew, 50vw); }

/* A playing recitation puts a strip across the foot of the page, and the page
   already owes it room -- body.recite-active reserves exactly this much. One
   number for how tall the strip is, not a second measurement of it. */
body.recite-active .wstudy__returnpill { --wstudy-returnlift: 8.5rem; }

/* ---- Where the reader came from, inside the panel ------------------------

   The desktop half of the way back. It states the same fact as the pill and
   wears the walked root card's idiom rather than the pill's fill: a recessed
   ground and a named way out. The panel then has ONE vocabulary for "you have
   moved from somewhere, and here is the way back" -- the card uses it for a
   root, this uses it for a verse -- instead of a quiet link in one place and
   a floating filled capsule in another.

   Hidden below the split, where the sheet is deliberately CLOSED at the moment
   a verse chip fires and the pill is the only thing that can speak. */
/* IT WAS A ROW AND IT IS A CHIP. The strip stood under the bar with its own
   ground and its own hairline, and it cost the panel 54px of height on every
   arrival -- pushing the word, the grammar and everything under them down the
   screen to carry one 114px link. The owner reported watching the content
   move.

   So it moved into the bar and gave up everything that made it a row: the
   block padding, the paper ground, the seam at its foot. What is left is the
   bubble, which was always the part carrying the meaning; the shelf it stood
   on went with the row. Nothing else in the panel moved, and the header now
   begins where the chrome ends.

   flex: none against two neighbours that both carry min-inline-size: 0, so a
   narrow panel takes the room out of the nameplate and the search box -- the
   arrangement this bar already had for the box, applied to one more item. */
.wstudy__came {
  display: none;
  align-items: center;
  flex: none;
  gap: var(--space-2);
  margin: 0;
  padding: 0;
}

.wstudy__came[hidden] { display: none; }

/* The word the reader came from, in the chip beside its verse. Quieter than
   the verse it qualifies -- it is the reminder, not the destination -- and
   set in the Arabic face at the size the chrome uses, because a mushaf face
   at label size in a bar is a different kind of thing from the word standing
   in the header. */
.wstudy__came-ar {
  font-family: var(--font-arabic);
  font-size: var(--fs-body);
  line-height: 1;
  color: var(--ink-faint);
}

/* THE SAME BUBBLE, for the same reason: the reading page has moved to a verse
   the reader followed, and this is how they get back. One dress for "you have
   wandered and here is the way home", whether the wandering was in the lexicon
   or on the page -- so a reader learns the mark once. */
.wstudy__came-go {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  min-inline-size: 0;
  /* Pressing room spent as padding rather than as a visible edge, so the strip
     stays the height of its one line of type. The inline padding also draws
     the bubble. */
  padding-block: var(--space-2);
  padding-inline: var(--space-3);
  border-radius: var(--radius-pill);
  background: var(--caution-tint);
  color: var(--caution);
  font-family: var(--font-sans);
  font-size: var(--fs-caption);
  text-decoration: none;
}

.wstudy__came-go:hover {
  background: var(--caution);
  color: var(--paper);
}

@media (forced-colors: active) {
  .wstudy__came-go { border: 1px solid ButtonText; }
}

.wstudy__came-go svg { flex: none; }

.wstudy__came-said {
  min-inline-size: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* .wstudy__came-off is gone, and so is the button. It dismissed the strip,
   and it existed because a strip in the way is worth putting away; a chip in
   the chrome is in nobody's way. The pill below keeps ITS dismiss -- that one
   floats over the reading page on a phone and genuinely can be in the way.
   Both still answer data-wstudy-returnoff in word-study.js, which no longer
   has a second carrier to serve here. */

.wstudy__returnpill-go,
.wstudy__returnpill-off {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-block-size: 44px;
  border: 0;
  background: var(--accent-strong);
  color: var(--paper);
  font-family: var(--font-sans);
  font-size: var(--fs-body-sm);
  text-decoration: none;
  cursor: pointer;
  pointer-events: auto;
  box-shadow: var(--shadow-soft);
}

.wstudy__returnpill-go {
  padding-inline: var(--space-4);
  border-start-start-radius: var(--radius-pill);
  border-end-start-radius: var(--radius-pill);
}

/* Its own hit area, so dismissing is never a mis-tap of going back. */
.wstudy__returnpill-off {
  min-inline-size: 44px;
  padding-inline: var(--space-2);
  border-inline-start: var(--hair) solid var(--paper);
  border-start-end-radius: var(--radius-pill);
  border-end-end-radius: var(--radius-pill);
  font-size: var(--fs-body);
  line-height: 1;
}

.wstudy__returnpill-go:hover,
.wstudy__returnpill-off:hover { background: var(--accent); }

/* Author backgrounds are discarded under forced colours, and the fill is the
   whole of the marking, so it is restated in system terms. */
@media (forced-colors: active) {
  .wstudy__returnpill-go,
  .wstudy__returnpill-off {
    background: Highlight;
    color: HighlightText;
    forced-color-adjust: none;
  }
}

/* The two tabs, in the tafsir strip's dress so a reader who has used one
   panel has used them all. */
/* A root subject has no grammar, so the tablist is hidden there rather than
   offering a tab that opens onto nothing. The restatement is load bearing:
   `hidden` is a UA rule of the lowest specificity and `display: flex` below
   beats it outright -- the same trap every other [hidden] restatement in
   this section exists for. */
.wstudy__tabs[hidden] { display: none; }

.wstudy__tabs::-webkit-scrollbar { display: none; }

.wstudy__tabs {
  display: flex;
  align-items: stretch;
  gap: var(--space-1);
  margin: 0;
  /* The tabs absorb a narrow bar, never the way out: adding the word
     "Close" pushed the close button 29px off a 320px screen, and a close
     button off the screen on a sheet with no Escape key is a trap. They
     shrink and scroll instead.

     AND THEY GROW, which is load-bearing and was briefly taken away. This
     block's spare width is what stands the search box off to the right, where
     its leading edge lines up with the grammar column in the band below --
     an alignment nobody wrote down and everybody could see. Stopping the
     growth so the way back could sit beside the nameplate moved the box left
     and broke it, and capping the box to repair THAT moved it again. The way
     back is a child of this block now instead: it sits against the name, and
     the spare width stays exactly where it was.

     A BASIS OF THE NAMEPLATE, and that is the half that makes it true.

     `auto` takes the basis from the CONTENT, so a way back inside this block
     grew the block and pushed the search box 76px right -- the same fault as
     before, arriving by the other road. Zero is no better in the other
     direction: the block then shares free space from nothing and the box came
     out 84px wider than it had ever been.

     10.5rem is the nameplate's own width, and it is allowed to be a number
     here because the nameplate is a CONSTANT: one tab, one string, written
     into the template. The block therefore distributes exactly as it did
     before the way back existed, whether the way back is there or not, and
     the chip spends the slack this block already had. The box does not know
     whether it came or went. */
  flex: 1 1 10.5rem;
  min-inline-size: 0;
  overflow-x: auto;
  scrollbar-width: none;
  /* No border and no background of its own. It carried both while it was a
     strip below the bar; inside the bar they drew a second hairline that
     stopped short of the magnifier, so the rule under the bar appeared to
     break off partway across. The bar owns the seam. */
}

/* WHERE THE BAR IS TOO NARROW TO LEND THE SLACK, THE BOX GIVES IT INSTEAD.

   The chip rides inside the nameplate's block, whose basis is fixed to the
   nameplate so that nothing in there can move the search box. That block has
   slack to lend on a wide panel and none on a narrow one -- and a chip wider
   than its block is not squeezed but CUT, because the block scrolls. A
   control half off the edge of a scroller is the one outcome worth avoiding
   at any price.

   So below 48rem of bar the block goes back to sizing itself from its
   contents. The chip stays whole, the search box loses the width the chip
   needs, and its edge stops lining up with the grammar column. That is the
   right way round: the alignment is a courtesy the wide case can afford, and
   a way back you cannot read is not a way back. Above 48rem nothing here
   applies and the box is where it has always been.

   Not the pill instead, though it was tried: the pill is a sibling of the
   panel rather than a descendant of the bar, so no container query on the bar
   can ever reach it. */
@container wstudy-bar (max-width: 47.999rem) {
  .wstudy__tabs { flex-basis: auto; }
}

.wstudy__tab {
  flex: none;
  /* inline-flex, not the button's default inline-block: the nameplate is a
     span now, and a pure inline box ignores min-block-size -- which is what
     makes this the same height as the commentary pane's tabs and what gives
     the rule beneath it something to sit on. */
  display: inline-flex;
  align-items: center;
  /* 600 at rest as well as selected: selecting must not reflow the strip,
     and the weight is what separates a tab from Back in the row below. */
  font-weight: 600;
  min-block-size: 44px;
  padding-inline: var(--space-3);
  border: 0;
  border-block-end: var(--emph) solid transparent;
  border-start-start-radius: var(--radius-control);
  border-start-end-radius: var(--radius-control);
  background: none;
  color: var(--ink-soft);
  font-family: var(--font-sans);
  font-size: var(--fs-body-sm);
  white-space: nowrap;
  cursor: pointer;
  transition: background-color var(--dur) var(--ease-calm),
              color var(--dur) var(--ease-calm);
}

.wstudy__tab:hover { background: var(--paper-sunk); color: var(--ink); }

/* The chosen tab is marked three ways -- the fill, the tone and the rule
   beneath it -- exactly as the commentary strip marks its own. The rule is
   what carries the choice for a reader who cannot separate the two tints, so
   it stays even though there is a fill.

   .is-active as well as aria-selected: the panel's own tab is a nameplate
   rather than a control, so it carries no tab role to be selected within,
   but it is the active view and has to look it. */
.wstudy__tab[aria-selected="true"],
.wstudy__tab[aria-selected="true"]:hover,
.wstudy__tab.is-active {
  background: var(--accent-tint);
  color: var(--accent-strong);
  border-block-end-color: var(--accent);
}

/* Both panes lie over one another and swap by visibility, so each keeps its
   own scroll offset while the other is showing. */
/* The phone's scroller, and nothing at all on a desktop: display: contents
   leaves the header and the panes as the panel's own flex items, so the
   fixed-header-over-scrolling-pane model above the split is unchanged. */
.wstudy__scroll { display: contents; }

.wstudy__panes {
  position: relative;
  flex: 1 1 auto;
  min-block-size: 0;
  /* THE PANE IS THE MEASUREMENT, not the window. The dictionary's lower half
     becomes two columns on a wide enough PANE, and the pane is 50vw of the
     window at the split and the whole of a sheet below it -- so a window
     width answers the wrong question. Inline-size containment only, and safe
     here: this element's width comes from the panel and never from what is
     inside it, at either width. */
  container: wstudy-pane / inline-size;
}

.wstudy__pane {
  position: absolute;
  inset: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: var(--space-4) var(--space-3) var(--space-6);
  visibility: hidden;
}

.wstudy.is-open .wstudy__pane.is-active { visibility: visible; }

/* ---- The tooltip, now that it is not a menu ------------------------------

   There was a Dictionary & Grammar row here until 2026-08-21. The tooltip
   kept pointer-events: none so hover-reading survived, and that row was the
   one child taking events back. Touching the word is the way in now, so the
   surface is a gloss again and nothing in it is pressable except the play
   button a touch reader gets. */

/* ---- The study shelf, without a word study entry -------------------------

   There was a Dictionary & Grammar button in the shelf under every verse
   until 2026-08-21, switched off by the reader's wbw-study class on the list
   rather than by [hidden] on itself -- which is why it needed rules here at
   all, since a selector cannot ask about that class from inside a :has()
   about children. Both it and the shelf-closing rule that special-cased it
   are gone with the button. The words of the verse are directly above the
   shelf, and touching one opens the panel about it. */

/* Nothing further is needed here. Section 9 divides categories by the gap and
   the mark at the head of each, not by a rule between them, so a category that
   comes and goes takes its own boundary with it and leaves no separator
   stranded behind. The note at .cites__icon says why that shelf carries no
   rule; this entry appearing and disappearing under the reader's switch is
   part of the reason. */

/* ---- The subject word, out in the text ----------------------------------- */

/* A background and never a colour, the section 12 COLR/CPAL rule. Distinct
   from .is-playing's plain tint: the tint plus an accent bottom edge reads as
   an underline, which is the mark of the word being STUDIED rather than the
   word sounding. Both are backgrounds, so the two can even coexist.

   ONE DRESS, THREE CARRIERS, and that is the whole of the idea: the word in
   the text, the word at the head of the panel, and the radicals it is built
   on all wear the same mark, so a reader can see at a glance that the three
   are one thing. The chain is what carries the state -- step off to a
   neighbouring root and the radicals lose the mark while the two words keep
   it, so the break is VISIBLE rather than stated. No caution colour is
   needed, and none exists in this palette: reading a neighbour's entry is the
   dictionary working, not an error.

   The radicals are excluded on a ROOT subject as well. There the root is the
   subject rather than a link in a chain, and a mark with nothing to chain to
   is decoration. */
.verse-list .qword.is-studied,
.wstudy__word,
.wstudy__rootcard:not(.is-walked):not(.is-subject) .wstudy__rootar {
  background: linear-gradient(to top,
    var(--accent) 0 var(--emph),
    var(--accent-tint) var(--emph) 100%);
  border-radius: var(--radius-control);
  box-decoration-break: clone;
  -webkit-box-decoration-break: clone;
}

/* The two panel carriers are single spans rather than words in a running
   line, so the tint would sit hard against the glyphs without this. The
   mushaf word is left alone: it has the verse's own word-spacing around it,
   and padding there would reopen the gap this file measured to 6px. */
.wstudy__word,
.wstudy__rootcard .wstudy__rootar { padding-inline: 0.15em; }

/* THE HEAD WORD'S MARK IS A BOX, not the font's content area, and that is what
   inline-block buys. An INLINE box paints its background over the font's own
   ascent and descent, which Amiri Quran reports as 73px and 25px at this size
   -- 98px of paint inside a 60px line on a phone. So the tint ran 19px past
   the line at both ends: over the WORD eyebrow above it, and across the
   English gloss below, where the mark's 2px accent edge landed through the
   middle of the word and read as a strikethrough. Reported from 76:1.

   Blockified, the background follows the line box and this padding, both of
   which are ours to size. The end padding is the deeper of the two on purpose,
   and asked for: Arabic descends, so a mark that clears the letters above
   still crowds the tail of a kasra or a final noon. */
.wstudy__word {
  display: inline-block;
  padding-block: 0.08em 0.55em;
}

/* THE MARK HAS TO ENCLOSE THE LETTERS, and a line box does not. Measured in
   Amiri Quran at this size: the box is 29px while the radicals' ink runs to
   36px for ء م ن and 31px for ص ل ح, and the font's own ascent (42px) is far
   larger than its ink ascent (24px), so half-leading drops the baseline low
   in the box and the descenders of ح, ج and ع fall about 12px past the bottom
   edge. That edge is where the mark's 2px accent line is drawn -- so it cut
   ACROSS the letters instead of sitting under them, which is what was seen
   and reported as a line under ص ل ح.

   Padding and not a taller line-height: containing the descender by leading
   alone needs about 2.5, and because the drop is asymmetric that would open
   18px of dead space above the letters to buy 3px below them. This is the
   same trade the count of ink and box says it is, and it is constant in every
   state, so the card's height does not depend on which root is open. */
.wstudy__rootcard .wstudy__rootar { padding-block: 0.15em 0.85em; }

/* Forced colours discard author backgrounds, and the mark above is entirely
   background, so without this the studied word is indistinguishable from
   every other word on the page -- the one thing the mark exists to prevent.
   Restated from the system palette, and forced-color-adjust turned off so
   the fill is kept rather than thrown away with it. `color` is deliberately
   NOT set: the mushaf faces paint their letterforms from a palette inside
   the font and would ignore it, exactly as they do outside forced colours. */
@media (forced-colors: active) {
  .verse-list .qword.is-studied {
    background: Highlight;
    forced-color-adjust: none;
  }

  /* The other two carriers of the same mark. These DO take a colour, unlike
     the mushaf word above: they are set in plain Amiri Quran rather than in a
     tajweed face that paints its own letterforms from a palette inside the
     font, so text left at CanvasText on a Highlight ground would be the
     unreadable pair the rule above avoids by saying nothing. */
  .wstudy__word,
  .wstudy__rootcard:not(.is-walked):not(.is-subject) .wstudy__rootar {
    background: Highlight;
    color: HighlightText;
    forced-color-adjust: none;
  }
}

/* ---- Dictionary pane ----------------------------------------------------- */

/* ---- Search, in the chrome and always on screen -------------------------

   It was a magnifier opening a TAB whose content was a centred column: the
   input, the keyboard and the results all inside the pane. That made search
   a place you went rather than a thing you did, and a door you had to know
   to open. The box stands in the bar now beside the panel's own name, and
   what it finds falls OVER the instrument rather than replacing it.

   The block is the dropdown's positioning context, which is why it is
   relative and why the two things that fall out of it -- the keyboard and the
   results -- are absolute against it rather than against the panel. */
/* NO GAP, since the keyboard's door moved into the field on 2026-08-28: the
   input is the only in-flow child left -- the label and the live region are
   both visually-hidden, which is position: absolute -- so there is nothing
   left for a gap to separate, and one left standing here would read as a
   spacing decision that no longer applies to anything. The flex row stays
   because it is what makes that one child fill the block. */
.wstudy__search {
  position: relative;
  flex: 1 1 12rem;
  min-inline-size: 0;
  display: flex;
  align-items: center;
}

/* The sample query. Faint, so it reads as an example and not as a value
   already typed. */
.wstudy__search-input::placeholder {
  color: var(--ink-faint);
  opacity: 1;
}


.wstudy__search-input::-webkit-search-cancel-button { display: none; }

.wstudy__search-input {
  appearance: none;
  -webkit-appearance: none;
  flex: 1 1 auto;
  min-inline-size: 0;
  min-block-size: 34px;
  /* Trailing room for the keyboard's cap, which stands INSIDE the field from
     2026-08-28 -- 38px of cap plus 6 of clearance. Unconditional, unlike the
     masthead's `:has(:not([hidden]))` twin: that button ships hidden because
     it can do nothing before search.js runs, and this one has never shipped
     hidden, because the panel it lives in is drawn by script or not at all. */
  padding-inline: var(--space-3) 2.75rem;
  border: var(--hair) solid var(--rule-strong);
  border-radius: var(--radius-control);
  background: var(--paper-raised);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  /* THE BOX STAYS IN THE CHROME'S DIRECTION WHILE THE TEXT RUNS IN ITS OWN,
     and this is the masthead's bug, not a precaution: dir="auto" flips the
     ELEMENT to rtl the moment Arabic is typed, padding-inline resolves against
     the element, and the 2.75rem cut for the cap moves to the LEFT -- putting
     the typed word underneath the button with 44px of nothing on the far side.
     Measured there 2026-08-25 with سلمون in the field, and this copy inherits
     it the instant it gains a trailing cut of its own.

     plaintext keeps what dir="auto" was wanted for: the paragraph's direction
     is still detected per content, so Arabic still orders and aligns right.
     The attribute stays in the markup as the no-CSS answer. */
  direction: ltr;
  unicode-bidi: plaintext;
}

.wstudy__search-input:focus-visible {
  outline: var(--focus-width) solid var(--accent);
}

/* EVERYTHING THAT FALLS OUT OF THE BOX, in one column: the keyboard, then
   what was found. They used to hang from this same anchor at the same
   offset, two absolute boxes in one rectangle, so the keyboard covered the
   results it existed to find. One positioned parent puts them in flow with
   each other and the overlap cannot come back.

   The keyboard is FIRST and that is not a preference. Its height is fixed
   and the list's changes with every letter, so keys-then-list means the keys
   never move under the finger tapping them; list-then-keys would slide the
   whole keyboard down the moment a search narrowed. */
.wstudy__under {
  position: absolute;
  /* Anchored to the box's END and allowed to reach back past its start: the
     box is about 150px in a 615px pane and a result carries Arabic, what kind
     of thing it is and a count. A list as narrow as its own input would wrap
     every row. It cannot overflow the panel, because the box never sits more
     than a close button away from that edge. The 100% is the search block's
     own width -- the box plus the keyboard's door -- which is the width the
     keys were always drawn at; the minimum only takes over in a pane too
     cramped to give the results a readable line. */
  inset-inline-end: 0;
  inset-inline-start: auto;
  inline-size: 100%;
  min-inline-size: min(22rem, 78vw);
  inset-block-start: calc(100% + var(--space-1));
  /* ABOVE THE PANEL'S TWO DRAG GRIPS, which sit at 4 and say in their own
     comment that they belong below the bar's dialogs. At 4 as well they did
     not: equal z-index is settled by markup order and both grips are written
     after the bar, so the horizontal one drew its hairline straight across an
     open keyboard, and on a sheet -- where this column spans the whole panel
     -- the vertical one crossed it too. A handle hidden under a dialog the
     reader just opened is the right way round; the dialog closes. */
  z-index: 5;
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  /* The COLUMN's own ceiling, and the only thing it is for is the foot of the
     window: the list carries its own cap below, so this bites only when a
     short screen cannot hold the keyboard and a full list together.

     THE 10rem IS THE HEAD THIS HANGS FROM, not a margin of taste. On the
     sheet the bar wraps and puts the box on a line of its own, which starts
     this column about 143px down; a plain 80vh measured from the top of the
     window instead, and on a 360x640 phone the last results sat 15px below
     the fold. Subtracting a fixed head is what makes the rule true at both
     shapes -- the same figure and the same reasoning as .qs-drop above.

     Two declarations, and the second is not a duplicate: on a phone 100vh is
     the TALL viewport, the one with the browser's toolbar retracted, so a
     column sized in vh while the toolbar is showing runs underneath it. dvh
     is the viewport as it actually is, and the vh line stays as the fallback
     for anything that does not know dvh. */
  max-block-size: calc(100vh - 10rem);
  max-block-size: calc(100dvh - 10rem);
}

/* WHAT IT FOUND, over the pane and never pushing it. The panel is a fixed
   column: a list that moved the instrument under it would make choosing a
   word cost a re-read of where everything went. Capped and scrolling, because
   a lookup can match more than a panel's height and the bar it hangs from is
   not a scroller. */
.wstudy__drop {
  /* THE LIST KEEPS ITS OWN CAP whether the keyboard is open or not, so the
     keys cost it nothing on any screen tall enough to hold both -- the column
     simply grows downward. It was the pair that was capped for one draft, and
     the effect was that opening the keyboard silently halved the number of
     matches a reader could see, which is the opposite of what the keyboard is
     for. The column's ceiling above is the backstop for short screens.

     min-block-size:0 is what lets the shrinking happen when that backstop
     does bite: a flex item's floor is its content, so without it the list
     refuses to give way and overflows the column instead of scrolling. */
  flex: 0 1 auto;
  min-block-size: 0;
  max-block-size: min(28rem, 62vh);
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: var(--space-2);
  border: var(--hair) solid var(--rule-strong);
  border-radius: var(--radius-control);
  background: var(--paper-raised);
  box-shadow: var(--shadow-soft);
}

.wstudy__drop[hidden] { display: none; }

.wstudy__results {
  margin: 0;
  padding: 0;
  list-style: none;
}

/* COZY, because the list is what a reader reads WHILE typing and every row
   it cannot fit is a match they will not see. The height came off three
   places and none of them was the type: the block padding halves, the 44px
   touch floor goes to the sheet where fingers are (beside the other floors,
   below), and the Arabic gets a line height instead of Amiri Quran's own,
   which is nearly twice its size. Side padding is untouched -- the row is
   long and narrow, so its air belongs at the ends, not the top. */
.wstudy__match {
  display: flex;
  align-items: baseline;
  gap: var(--space-3);
  inline-size: 100%;
  margin-block-start: var(--space-1);
  padding: var(--space-1) var(--space-3);
  border: var(--hair) solid var(--rule);
  border-radius: var(--radius-control);
  background: var(--paper-raised);
  font-family: var(--font-sans);
  text-align: start;
  cursor: pointer;
}

.wstudy__match:hover { border-color: var(--accent); }

/* THE LINE HEIGHT IS WHAT MAKES THE ROW SHORT. Amiri Quran's own line box is
   nearly twice its font size, so an unconstrained span was spending about
   14px a row on nothing -- across a full list, two or three matches' worth of
   panel. 1.6 and not the 1.25 the root walk uses: a match is POINTED Arabic
   and the marks sit above the letters, so this needs the figure
   .wstudy__wordstep-ar already carries for the same reason. */
.wstudy__match-ar {
  font-family: "Amiri Quran", serif;
  font-size: var(--fs-body-lg);
  line-height: 1.6;
  color: var(--ink);
}

.wstudy__match-label {
  font-size: var(--fs-caption);
  color: var(--ink-faint);
}


/* A caption over a run of results, not a result: it says which of the two
   kinds the rows under it are, and only when both kinds are present. Never
   pressable and never focusable, which is why it is a plain li carrying
   role="presentation" while every real row is a button. */
.wstudy__matchhead {
  margin-block-start: var(--space-2);
  padding-inline: var(--space-3);
  font-family: var(--font-sans);
  font-size: var(--fs-caption);
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

/* A surah row is the same row with a number where the Arabic goes: this list
   has one shape, and a second one would say the two kinds of answer are
   different KINDS of thing rather than two answers to one question. The
   number is tabular so a two-digit and a three-digit surah line up. */
.wstudy__match-num {
  flex: none;
  min-inline-size: 2rem;
  font-size: var(--fs-caption);
  font-variant-numeric: tabular-nums;
  color: var(--ink-faint);
  text-align: end;
}

.wstudy__match--surah .wstudy__match-label { color: var(--ink); }

.wstudy__noresults,

.wstudy__noresults,
.wstudy__verseprompt,
.wstudy__empty {
  margin: var(--space-3) 0;
  font-family: var(--font-sans);
  font-size: var(--fs-body-sm);
  color: var(--ink-soft);
}

/* The way out of the gap, beside the sentence that states it. */
.wstudy__empty + .wstudy__out { margin-inline-start: var(--space-2); }
/* Section headings inside a pane, in the site's OWN heading voice: serif,
   fs-h3, sentence case, ink. They were tiny uppercase accent labels -- the
   same treatment worn by the search label, the root pill, the PREVIOUS/NEXT
   buttons and the kind eyebrow, five roles in one costume, and the loudest
   non-Arabic voice in the panel. Nothing could stand out because everything
   was shouting. Size carries the structure here instead of colour, and the
   accent goes back to meaning "you can press this". */
/* The rhythm between sections, which is what carries the structure here:
   the brief's rule is that whitespace does this work, not boxes and rules.
   This rule was lost when the root card was deleted from the head of its
   selector list, and "In the Qur'an" sat straight on top of the cut buttons
   above it. */
.wstudy__conc,
.wstudy__lane {
  margin-block-end: var(--space-6);
}

.wstudy__title {
  margin: 0 0 var(--space-2);
  font-family: var(--font-serif);
  font-size: var(--fs-h3);
  font-weight: 400;
  color: var(--ink);
}

/* ---- The cascade: ROOT over RELATED WORDS over VERSES -------------------

   Arabic nests root > headword > inflected form > token. THE STACKED LADDER
   BELOW IS THE BASE, and above a wide enough pane the lower two rungs turn
   into a MENU and its RESULTS -- see the @container block at the end of this
   section for the two-column half.

   THREE COLUMNS were tried on 2026-08-21 and measured out: the panel is 50vw,
   so at the split the pane is about 640px on a 1280 laptop while three needed
   736px. They appeared only above roughly a 1900px window -- the exception
   dressed as the rule -- and a translation at 264px of column ran to about
   thirty-eight characters a line. TWO columns at the root card's own 2fr/3fr
   need 608px of pane and engage on that same 1280 baseline, which is the
   whole difference. Under it, and on every sheet, these stacked rules are
   what runs.

   THE TWO UPPER ROWS ARE FIXED AND ONLY THE VERSES SCROLL. That is the fixed
   space per level, and it is the intent this block has stated since it was
   written: a reader clicks between the related words and watches the verses
   change, with the choice never leaving the screen. Stacked, it was never
   true of a rich root -- 22 entries push the verses off the fold and every
   change of cut costs a scroll down and a scroll back. The two-column half is
   where it finally holds. */
/* The bands are a LADDER and no longer a budget. They divided a fixed height
   between them and each kept a scrollbar of its own, so a reader met the
   derived forms through a 9rem window and the verses through whatever was
   left -- two scrollbars nested inside the pane's own. The PANE is the one
   scroller HERE, and each band is as tall as what it holds.

   Above the split each column scrolls itself again, and the difference from
   the retired budget is the whole of why: nothing is dealt a 9rem slice --
   each column takes the full height the pane has left under the root card. */
.wstudy__dict {
  display: flex;
  flex-direction: column;
  block-size: auto;
}

.wstudy__band { flex: none; }

/* The seam between tiers is the TITLE's rule now, and no longer a border
   here. It carried one for two days and could not do the job: base.css names
   three rule weights and calls them "the whole vocabulary for separating
   things", and this band seam and the KWIC rows inside it were both --rule at
   a hairline. One weight doing two jobs is why neither read as either -- the
   owner's report that the sections have no presence. The vocabulary is spent
   properly now: --rule-strong separates SECTIONS, --rule is a component's own
   edge, --rule-soft separates ROWS inside a section. */
/* AND THE RHYTHM SAYS IT TOO. Between bands is the largest gap in the pane,
   larger than any gap inside one, so grouping reads by proximity before a
   reader has parsed a single word. It was --space-5, which is also the gap
   the root card puts between its own halves: a boundary between SECTIONS
   measuring the same as a boundary inside one is the same fault as a rule
   weight doing two jobs. */
.wstudy__band + .wstudy__band { margin-block-start: var(--space-6); }

/* In flow with the rest of the ladder: the pane scrolls, not the band. */
.wstudy__band--verse { display: block; }

/* THE SECTION HEADER: a name, a rule running out from it, and at the far end
   a live fact about what the section holds. Presence comes from FULL WIDTH
   rather than from weight or from fill, which is what the brief's "whitespace
   and rhythm carry structure" allows and its anti-pattern list -- no tints, no
   accent bars, one filled accent control per view -- does not. */
/* THE LINE CARRIES THE QUIET DRESS and the name overrides it. It used to be
   the other way round -- the whole row was an 11px uppercase label and the
   fact reset three declarations to escape it -- which is why the apparatus
   inside this band and the name OF the band arrived at one volume. */
.wstudy__bandtitle {
  display: flex;
  /* Baseline and not centre: a heading and a caption-sized fact are two type
     sizes and have to sit on one line, not two centres. */
  align-items: baseline;
  gap: var(--space-3);
  /* PADDING and not margin, on all three alike, because the verse band's
     title pins itself and a background does not paint a margin: rows would
     scroll through the gap under a stuck strip. Uniform here so the pinned
     one is not the odd header out when it is resting. */
  margin: 0;
  padding-block: var(--space-2);
  font-family: var(--font-sans);
  font-size: var(--fs-caption);
  font-weight: 400;
  color: var(--ink-soft);
}

/* THE NAME IS A HEADING, in the site's own heading voice -- the dress
   .wstudy__title wears, and the one the 2026-08-21 pass gave every section
   heading in this panel before these three bands were built without it.

   Three levels of organisation were speaking at one volume: the band name,
   the family headings inside the rail, and the row labels were all small
   uppercase sans, so nothing outranked anything and the reader could not tell
   a section from a group inside it. Size carries the hierarchy; the family
   headings keep the label voice and become the second level by contrast
   rather than by shouting less. */
.wstudy__bandtitle-name {
  flex: none;
  /* A HEADING DOES NOT WRAP. In the two-column layout the derived-forms band
     is about 250px wide and "Derived forms" broke across two lines with its
     own fact breaking across two more -- four lines of chrome above a rail
     that is often two rows tall. The fact yields instead, which is what every
     other supplementary line in this panel does. */
  white-space: nowrap;
  font-family: var(--font-serif);
  font-size: var(--fs-h3);
  font-weight: 400;
  line-height: var(--lh-heading);
  color: var(--ink);
}

/* The rule itself. A minimum so it never vanishes when a long fact and a
   narrow pane meet; centred against a baseline-aligned row. */
.wstudy__bandtitle-rule {
  flex: 1;
  min-inline-size: var(--space-4);
  align-self: center;
  border-block-start: var(--hair) solid var(--rule-strong);
}

/* The live fact, in a sentence's dress and not the eyebrow's. Every reset
   here is load-bearing: the parent carries uppercase, 0.12em and 600, and
   without them "five of دفع" arrives as a shouted label rather than as the
   line of prose it is. */
/* The live fact, in a sentence's dress -- which is now simply the line's own,
   so the three resets it used to need to escape a shouting parent are gone
   with the shout. */
.wstudy__bandtitle-fact {
  min-inline-size: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* THE WAY BACK, in the slot the other two bands give to a live fact. It wears
   the alphabet walk's dress rather than a fill: NEXT, PREVIOUS and this are
   one apparatus -- the two that step off and the one that returns -- and a
   filled pill made the undo louder than the doing.

   That retires the second filled accent this view used to carry. The panel is
   back to one, which is what section 3 asks for; the walked ground below is
   what says the reader is away, and this says how to stop being.

   Every reset is load-bearing, as on the fact beside it: the parent carries
   uppercase, 0.12em and 600. */
.wstudy__bandtitle-back {
  display: inline-flex;
  align-items: baseline;
  gap: 0.3rem;
  flex: none;
  min-inline-size: 0;
  /* The target is paid for in padding and given back in margin, so pressing
     room never makes this row taller than the same row on a band that shows
     only a fact -- and the card below it never moves when this appears. */
  padding: var(--space-2) var(--space-3);
  margin-block: calc(-1 * var(--space-2));
  border: 0;
  /* A BUBBLE, and in the caution pair rather than the accent. This is the one
     control in the panel that exists to be UNDONE: the lexicon is standing at
     a root the word above does not belong to, and everything else on the card
     is quiet enough that a reader can walk three roots without noticing. The
     accent would have said "you can press this" and nothing more.
     --caution-tint carries the nudge and the pill shape makes it an object
     rather than a line of text, at no cost in row height: the padding that
     draws the bubble is given back in the negative block margin above. */
  border-radius: var(--radius-pill);
  background: var(--caution-tint);
  color: var(--caution);
  font-family: var(--font-sans);
  font-size: var(--fs-caption);
  font-weight: 400;
  letter-spacing: normal;
  text-transform: none;
  /* Measured, not guessed: this row is 17.94px of content, and the caption's
     default 1.55 line box is 19.3px -- which grew the title by 4px on a walk
     even after the Arabic beside it was tamed. Both halves of the label have
     to be quieter than the line they join. */
  line-height: 1.25;
  cursor: pointer;
}

.wstudy__bandtitle-back[hidden] { display: none; }

/* Louder on approach, and only then: the bubble is already carrying the
   nudge, so hovering deepens it rather than changing what it is. */
.wstudy__bandtitle-back:hover {
  background: var(--caution);
  color: var(--paper);
}

/* Author colours go under forced colours and this bubble is entirely colour,
   so the edge is what survives -- the convention .recite__control--play sets. */
@media (forced-colors: active) {
  .wstudy__bandtitle-back { border: 1px solid ButtonText; }
}

/* The arrow keeps its size when the Arabic beside it is long. */
.wstudy__bandtitle-back svg { flex: none; }

.wstudy__bandtitle-back-said { white-space: nowrap; }

/* Bare radicals, at the walk's own size -- see .wstudy__rootstep-ar for why
   an unpointed root reads at a size the mushaf could not.

   THE LINE HEIGHT IS WHAT KEEPS THIS ROW FROM GROWING. Amiri Quran's own line
   box is nearly twice its size, so an unconstrained Arabic span made the title
   17px taller the moment a reader stepped off a root -- the exact shift this
   whole change exists to remove, reintroduced by the control that announces
   it. 1.25 is the figure .wstudy__rootar already uses and is safe for the same
   stated reason: bare radicals carry no diacritics, so there is nothing above
   the letters for a tight line to clip. */
.wstudy__bandtitle-back-ar {
  font-family: "Amiri Quran", serif;
  font-size: var(--fs-body-sm);
  line-height: 1.25;
}

/* THE CUT IN FORCE, PINNED. Deep in a 383-occurrence list the reader still
   has to be able to see WHICH cut they are reading -- the phone learnt that
   first, on the line this fact replaces, and the desktop never had it at all.

   It sticks to whichever element scrolls: .wstudy__pane above the split,
   .wstudy__scroll below it. Nothing between this and either of them clips
   overflow, and the containing block is the SECTION -- which is why the title
   has to stay the section's direct child. Moved inside .wstudy__bandbody it
   would unpin the moment the body's own top scrolled past.

   The inline margin pulls the strip out to the pane's edges and the matching
   padding puts the text back where it was, so the paper covers the full
   width while nothing moves. */
.wstudy__band--verse .wstudy__bandtitle {
  position: sticky;
  inset-block-start: 0;
  z-index: 1;
  margin-inline: calc(-1 * var(--space-3));
  padding-inline: var(--space-3);
  background: var(--paper);
}

/* THE ROOT CARD, in the WORD header's own anatomy: the entry centre stage on
   the left with its walk at the foot, a hairline, and what is KNOWN about it
   on the right. It was three stacked rows, and beside the word card above it
   that still read loose -- which is what the owner named.

   TWO PARTS TO THREE, fixed, and for the reason the header records: halves
   that size to their own contents let the split drift with the window and
   open a gutter down the middle. Identity is compact; Lane's opening words
   are what need measure. */
.wstudy__band--root > .wstudy__bandbody { display: block; }

/* ---- The derived forms are a MENU, and they stand on a menu's ground -----

   The rail chooses which verses the band below it shows; it is apparatus, and
   it sat on the same paper as the content it drives, which is why the owner
   read it as floating with nothing anchoring it. The app already owns a
   vocabulary for "machinery you operate": the recessed strip, which is what
   the tab row is and what a walked root card takes. Neutral ground, not a
   tint -- section 10 forbids an ACCENT tint used to mark state, and this
   marks a role and is the same paper-sunk every hover in the panel uses.

   The chosen row's solid accent fill reads harder against it, not softer,
   which is the answer to the only real objection. */
.wstudy__band--word > .wstudy__bandbody {
  padding: var(--space-3);
  border-radius: var(--radius-control);
  background: var(--paper-sunk);
}

/* AND THE BAND GOES AWAY ENTIRELY WHEN THERE IS NO ROOT TO DERIVE FROM.

   word-study.js has set `is-rootless` on the panel since the rootless words
   were given a concordance, and until 2026-08-30 no rule anywhere read it --
   so the class was written on every pronoun and every opening letter and
   changed nothing. What the reader got was the empty half of this band: a
   heading saying "Derived forms" over the sunk ground above, holding nothing,
   permanently. Reported by the owner against alladhina, a relative pronoun,
   where it reads as a panel still loading and it is not.

   Always empty rather than sometimes: the rail is filled from `lemmas`, and
   the route sends lemmas only when there is a root. A rootless word cannot
   have derived forms to miss.

   The other two bands stay. Root carries the sentence that says the corpus
   records none -- which is the answer to "why is there no root", and deleting
   it would leave the question. Verse is fed by the word rather than the root,
   and it is the sixteen occurrences of yaqub. */
/* The band KEEPS ITS PLACE and says why it is empty, which is the Root band's
   own arrangement a few hundred lines above. Hiding it was tried first and
   made things worse: the Verse band took the full width in its absence, so the
   panel changed shape from word to word and a reader stepping through a verse
   watched the columns rearrange under them. A layout that depends on the
   subject is a layout that never settles.

   The rail is hidden rather than left as an empty sunk box, because the ground
   is what read as "still loading"; the sentence stands in its place. */
.wstudy__dict [data-wstudy-noforms] { display: none; }
.wstudy__dict.is-rootless [data-wstudy-rail] { display: none; }
.wstudy__dict.is-rootless [data-wstudy-noforms] { display: block; }

/* --paper-sunk is also how a row says "hover", so inside the sunk rail the
   rows take the ground the rail no longer leaves them -- the identical
   correction the walked root card records, for the identical reason: a
   control that stops answering the pointer exactly where the reader is being
   asked to look is worse than no ground at all.

   :not(.is-active) IS LOAD-BEARING and was learnt the hard way. This selector
   carries three classes and a pseudo-class, so without it it outranks
   .wstudy__lemma.is-active and repaints the CHOSEN row --paper while its text
   is still flipped to --paper for the accent fill: white on white. The row a
   reader had just pressed went blank under their own pointer and came back
   when they moved the mouse away, which is exactly how it was reported. */
.wstudy__band--word > .wstudy__bandbody .wstudy__lemma:not(.is-active):hover,
.wstudy__band--word > .wstudy__bandbody .wstudy__exact:not(.is-active):hover {
  background: var(--paper);
}

/* A FOCUS RING THE GEOMETRY CANNOT EAT. The site's ring is 2px at +3px offset,
   a 5px halo outside the box; a rail row already bleeds 8px past its column
   for its fill, and above the split that column is a scroller whose clip edge
   is exactly that 8px out. So a keyboard reader arrowing down the rail saw
   the ring cut off at the start edge, or missing.

   Drawn INSIDE the row instead. This is not the banned 2px accent ring: that
   rule is about marking WHICH ROW IS CHOSEN, which is still the solid fill --
   this answers "where is my keyboard", a different question, and every row can
   be focused while only one can be chosen. */
.wstudy__lemma:focus-visible,
.wstudy__exact:focus-visible { outline-offset: -2px; }

/* WHAT IS PRESSABLE, WHERE THE SYSTEM DISCARDS FILLS. Forced colours throw
   author backgrounds away, so the rail's rows -- whose whole affordance is a
   ground that appears on hover and a fill when chosen -- arrive as plain text
   in a list. The file's own convention for this is a drawn edge: see
   .recite__control--play. The rows carry a 26px/44px floor and the reset is
   border-box, so the border costs no height. */
@media (forced-colors: active) {
  .wstudy__lemma,
  .wstudy__exact { border: 1px solid ButtonText; }
}

.wstudy__rootcard {
  display: grid;
  /* The same 4fr/5fr the word header and the two columns below both take --
     see .wstudy__head for why the panel keeps one ratio. */
  grid-template-columns: 3fr 4fr;
  align-items: stretch;
  column-gap: var(--space-5);
  /* THE INSET IS PAID FOR ALWAYS, walked or home, so the walked ground below
     is a change of PAINT and never of geometry. It used to arrive with
     .is-walked, which meant stepping off a root moved every row beneath it --
     the reader looked away from the thing they had just pressed to watch the
     page settle. Nothing here may become conditional again. */
  margin-inline: calc(-1 * var(--space-2));
  padding: var(--space-2);
  border-radius: var(--radius-control);
}

/* A rootless word -- a particle, a pronoun -- has no entry and no apparatus.
   The card collapses rather than ruling off an empty line. */
.wstudy__rootcard:not(:has(.wstudy__rootar:not(:empty))) { display: none; }

/* PROMOTED: the subject IS this root, so the card stands where the word card
   stands and wears its dress. The header above is hidden on a root, so this
   is the header -- one card, one markup, a class rather than a second copy. */
.wstudy__rootcard.is-subject {
  margin-inline: calc(-1 * var(--space-3));
  margin-block-start: calc(-1 * var(--space-3));
  padding: var(--space-4) var(--space-3);
  background: var(--paper-raised);
  border-block-end: var(--hair) solid var(--rule);
}

/* WALKED: the lexicon is open at a root the word above does not belong to.

   A DELIBERATE EXCEPTION to design-brief section 10, which forbids tinted
   shading, taken on the owner's call of 2026-08-22: without it the only sign
   of having stepped off is text, and the reader had no way to see they were
   reading someone else's family. It is --paper-sunk, RECESSED, against the
   promoted card's raised ground, so the two never read alike -- and they can
   never co-occur anyway, because walking from a root subject is a real
   navigation rather than a walk. The stated line and the way back carry the
   meaning; the ground only makes it visible at a glance.

   PAINT ONLY. The inset and the radius are on the base rule, unconditionally,
   so this state changes one declaration and moves nothing. */
.wstudy__rootcard.is-walked { background: var(--paper-sunk); }

/* --paper-sunk is also what these two use to say "hover", so inside a walked
   card they take the ground the card no longer has. A control that stops
   answering the pointer exactly where the reader is being asked to look is
   worse than no ground at all. */
.wstudy__rootcard.is-walked .wstudy__lanedoor:hover,
.wstudy__rootcard.is-walked .wstudy__rootstep:hover { background: var(--paper); }

/* The identity half: a flex column so the walk can sit at its foot, and
   centred throughout, which it can afford now that its width no longer
   depends on what is standing in it.

   The separation between the halves, in the brief's own structure vocabulary:
   a hairline, never a fill or a shadow. It turns with the layout -- see the
   narrow query, where it becomes the rule above the right half instead of
   the rule beside it. */
.wstudy__rootcard-id {
  display: flex;
  flex-direction: column;
  min-inline-size: 0;
  padding-inline-end: var(--space-5);
  border-inline-end: var(--hair) solid var(--rule);
  text-align: center;
}

/* Takes the slack, so the walk lands at the foot because nothing is left
   below it rather than by being pushed there. Two things competing for the
   same leftover space would split it between them. */
.wstudy__rootident {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  justify-content: center;
  /* The radicals HUG their own letters. A span in a flex column is blockified
     and stretches the full cross axis, which nobody sees until the span is
     given a ground: the studied-word mark then painted a slab the width of the
     whole half, and its 2px accent edge drew a rule straight back across the
     card -- the same line deleted from .wstudy__rootsteps just above. A mark
     that means "this is the word you are reading" must be the size of the
     word. */
  align-items: center;
  margin: 0;
}

/* STRUCTURED, like the head above it: rows from the top on an authored gap,
   not a block centred in whatever height the half happens to have. Centring
   meant the count and the door hung at a different place on a tall card than
   on a short one, so two roots side by side in a walk never agreed on where
   their own apparatus lived. */
.wstudy__rootcard-more {
  min-inline-size: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  justify-content: flex-start;
}

/* Ends on the card's own right edge, with every other count in this pane. */
.wstudy__rootcount {
  margin: 0;
  font-family: var(--font-sans);
  font-size: var(--fs-body-sm);
  color: var(--ink-soft);
}

/* The way out of the entry, at the foot -- two halves of one line, which is
   the dress the word card's own neighbours wear. */
/* NO RULE ABOVE IT. A hairline here was the third weight of separation inside
   one card -- the band's own rule above, the halves' rule beside, and then a
   line between an entry and the two arrows that walk away from it, which are
   not two parts of anything: they are the entry and its apparatus. Whitespace
   says that, and the brief asks for whitespace first.

   --space-5 and not --space-4: the line it replaces sat in 24px of padding and
   margin, so a smaller gap would read as the separation being REMOVED rather
   than restated. In the two-column layout the identity block's slack sets this
   distance anyway; the number is what the stacked phone gets. */
.wstudy__rootsteps {
  display: grid;
  grid-template-columns: 1fr 1fr;
  align-items: center;
  gap: var(--space-2);
  margin: var(--space-5) 0 0;
}

/* The second half reads to its own end, so the pair frames the row.

   max-inline-size WITH the justify-self, and it is not decoration. A grid item
   stretches to its track by default, which is why the first of these two is
   exactly its column wide however long its root is. justify-self opts OUT of
   that stretch, and an item that is not stretched is sized to its content --
   so this one stayed 124px inside a 58px column and hung 58px back across the
   arrow beside it. Measured on ر ق ب at a 384px panel: the two labels drew on
   top of each other, and still overlapped by 8px at 608.

   Invisible until a panel could be narrowed by hand, because the pair only
   gets tight below about 650px of panel and a split gave that no window.
   100% of the track, so it is end-aligned AND bounded, and the overflow rule
   above it takes the tail exactly as that rule already intends. */
.wstudy__rootstep--prev {
  justify-self: end;
  max-inline-size: 100%;
}

/* At two fifths of a ~600px card each step has about 110px, which is the same
   squeeze the word card measured at 233px and answered the same way: a long
   neighbour gives up its tail rather than its column's width. */
.wstudy__rootstep {
  min-inline-size: 0;
  overflow: hidden;
}

.wstudy__rootstep-ar {
  min-inline-size: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* The derived forms: an INDEX, flowed into columns. Each entry is a full row
   -- Arabic, kind, count -- and the rows carry AUTHORED tracks, so the counts
   line up down each column and can be compared at a glance. The surah index
   learned this the hard way: tracks sized to their own content centre every
   row on itself and the list stops reading as a list.

   Multicol rather than a grid, because a grid lays rows ACROSS and a reader
   comparing a family reads DOWN. 43% of roots have one lemma and the median
   is two, so most roots are one short column; قوم at 22 is five columns of
   five on a wide pane and one long list on a phone.

   The column narrowed from 15rem and the gutter from 32px to 24px when the
   rows gained a second line of English. A row is 5.5rem of Arabic, a label
   and a count, and it read at 13rem before the gloss arrived -- so the width
   was never earning its keep, and spending it buys the wide pane a fifth
   column, which is what pays for the line. Measured on قوم, the longest
   family in the corpus: 641px before the gloss, 1010px with it at the old
   density, 780px at this one.

   The columns are on this WRAPPER and not on the rail itself, so that the
   widest cut can stand outside them. "All forms" is one row and multicol gave
   it a whole column of its own on every root -- a third of the rail spent on
   a single line. It stays inside the rail because the rail is the radiogroup
   and the widest cut is one of the radios; only the column flow starts here. */
.wstudy__families {
  columns: 13rem;
  column-gap: var(--space-5);
}

/* The narrowest cut: a toggle, not a fourth radio, because it narrows the
   word already chosen rather than replacing it. */
/* A SUB-ROW of the entry it narrows, on that entry's own tracks and indented
   under it. It was a pill standing alone in the verse band -- the heaviest
   thing there, a band away from the other cuts although it is one of them. It
   keeps the rail's grid so its count lands on the same right rail, and takes
   the first track as an indent because containment is what the indent says. */
.wstudy__exact {
  inline-size: 100%;
  display: grid;
  /* The same THREE PARTS as every entry above it -- written form, what it
     is, its count -- so it reads as one more cut of the family rather than as
     a different kind of object. The count still lands on the shared rail.

     The first track is content-sized here where its siblings' is authored,
     and the difference is the indent: 32px comes off this row's width, and
     an 88px Arabic track then left the label about 70px in a real column --
     "only this spelling" truncated to "only this...", losing the noun the
     row is about. This row is one per parent and never a column of its own,
     so nothing wanders when it sizes to its word. */
  grid-template-columns: auto 1fr auto;
  align-items: baseline;
  gap: var(--space-2);
  min-inline-size: 0;
  min-block-size: 26px;
  /* The indent AFTER the shorthand, which would otherwise reset it. */
  padding: 1px var(--space-2);
  padding-inline-start: var(--space-6);
  margin-inline: calc(-1 * var(--space-2));
  /* The stick below hangs off this box. */
  position: relative;
  border: 0;
  border-radius: var(--radius-control);
  background: none;
  color: var(--ink-soft);
  font-family: var(--font-sans);
  font-size: var(--fs-caption);
  text-align: start;
  white-space: nowrap;
  cursor: pointer;
  break-inside: avoid;
}

/* THE STICK that joins it to the entry above. Indentation alone read as a row
   floating for no reason -- the owner's report -- because the rail's rows are
   otherwise all flush and nothing said this one hangs off its neighbour. It is
   a tree elbow: up into the row above, then across to this row's own Arabic.

   It was drawn on 2026-08-22 and did not work, for a reason that was
   geometric rather than aesthetic and outlived two reports of the same fault.
   The parent's Arabic was right-aligned in its 5.5rem track, so the vertical
   arm rose into EMPTY SPACE beside a headword rather than under it; the
   horizontal arm stopped 12px short of this row's own Arabic; and it was
   drawn in --rule, the faintest weight on the page. It joined nothing to
   nothing, faintly. Left-aligning the rail is what makes it true: the
   parent's word now begins directly above this arm.

   Measured, not guessed. The border box starts at the column's left edge
   minus 8px (the negative inline margin), so an arm at 12px lands 4px inside
   the column -- under the parent's first glyph -- and this row's own Arabic
   begins at 32px - 8px = 24px in. The horizontal arm runs to 4px short of it.

   --rule-strong, because this is not a divider between siblings but a
   statement of descent, and the faintest weight cannot carry a statement. It
   is decoration and carries no meaning a screen reader needs -- the row's
   aria-label already names the entry it narrows. */
.wstudy__exact::before {
  content: "";
  position: absolute;
  inset-inline-start: var(--space-3);
  inset-block-start: 0;
  /* Up to this row's own top edge, where the parent's bottom edge is -- the
     rows stack flush -- and down to its middle, where the elbow turns. */
  block-size: 50%;
  inline-size: calc(var(--space-6) - var(--space-3) - var(--space-1));
  border-inline-start: var(--hair) solid var(--rule-strong);
  border-block-end: var(--hair) solid var(--rule-strong);
  border-end-start-radius: 3px;
}

/* The stick belongs to the pair, not to the state: a lit sub-row still hangs
   off the same entry. On the fill it takes the fill's own ink. */
.wstudy__exact.is-active::before {
  border-color: var(--paper);
  opacity: 0.5;
}

@media (forced-colors: active) {
  .wstudy__exact::before { border-color: CanvasText; }
  .wstudy__exact.is-active::before { border-color: HighlightText; }
}

/* The label track, in the dress its siblings' labels wear. */
.wstudy__exact-name {
  min-inline-size: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}

.wstudy__exact:hover { background: var(--paper-sunk); }

.wstudy__exact[hidden] { display: none; }

.wstudy__exact-ar {
  /* Left, with its siblings above -- see .wstudy__lemma-ar for why it is
     justify-self and not text-align. */
  justify-self: start;
  font-family: "Amiri Quran", serif;
  font-size: var(--fs-body);
  color: var(--ink);
}

/* The one filled control in the view moves HERE when the spelling is pressed;
   its parent keeps the radio selection and says so by a change of type, which
   is the brief's own named alternative to a second fill. */
.wstudy__exact.is-active {
  background: var(--accent-strong);
  color: var(--paper);
}

.wstudy__exact-count {
  justify-self: end;
  font-size: var(--fs-caption);
  font-variant-numeric: tabular-nums;
  color: var(--ink-faint);
}

/* The entry a pressed spelling belongs to. Never a second fill and never a
   ring: weight on the LABEL only, because Amiri ships no bold face and asking
   for one smears the Arabic's marks before anything else. */
.wstudy__lemma.is-active.is-narrowed { background: none; color: var(--ink); }

.wstudy__lemma.is-active.is-narrowed .wstudy__lemma-ar,
.wstudy__lemma.is-active.is-narrowed .wstudy__lemma-name,
.wstudy__lemma.is-active.is-narrowed .wstudy__lemma-gloss,
.wstudy__lemma.is-active.is-narrowed .wstudy__lemma-count { color: var(--ink); }

.wstudy__lemma.is-active.is-narrowed .wstudy__lemma-label {
  color: var(--ink);
  font-weight: 600;
  opacity: 1;
}

.wstudy__exact.is-active .wstudy__exact-ar,
.wstudy__exact.is-active .wstudy__exact-count { color: var(--paper); }

.wstudy__exact.is-active .wstudy__exact-count { opacity: 0.78; }

/* ---- Lane's door, and Lane's entry ------------------------------------
   Lane defines ROOTS, so he belongs to this column -- but he is REFERENCE
   rather than a level of the cascade: consulted, read, and left. A
   definition wants sixty-odd characters of measure and this column has
   about twenty, so the column carries his name and his opening words and
   the entry opens where it can be read. */
/* At the row's end, sized to itself. It was a full-width block with a rule
   above it when the root stood in a 136px column and a door had nowhere else
   to go; in a full-width band that shape read as a section rather than as
   the one pressable thing in the band. At 320px it wraps to its own row. */
/* ONE LINE: the name, the taste, and the volume on the rail. It was a name
   stacked over a taste, which made a two-line block of the row that has the
   least to say -- and broke the rhythm the tier above and below it keeps. */
.wstudy__lanedoor {
  /* ONE LINE, and it does not grow into whatever height the card happens to
     have. It was flex: 1 1 auto against a centred column, which was harmless
     only while the card was short: once the radicals' mark made the card
     taller the door absorbed the difference and drew at 66px -- a one-line
     control three lines tall, and its name floating in the middle of it. */
  flex: none;
  display: flex;
  align-items: baseline;
  gap: var(--space-3);
  min-inline-size: 0;
  padding: var(--space-1) var(--space-2);
  margin-inline: calc(-1 * var(--space-2));
  border: 0;
  border-radius: var(--radius-control);
  background: none;
  text-align: start;
  cursor: pointer;
}

.wstudy__lanedoor:hover { background: var(--paper-sunk); }

.wstudy__lanedoor[hidden] { display: none; }

/* THE SAME SLOT, UNHELD. It takes the door's box exactly -- one line, the same
   padding, the same three parts on the same axis -- so the half below it does
   not move when a walk crosses from a root Lane covers to one he does not.
   Sharing the door's declarations rather than restating a measured height is
   what keeps that true when the door's own dress changes. */
.wstudy__lanegap {
  flex: none;
  display: flex;
  align-items: baseline;
  gap: var(--space-3);
  min-inline-size: 0;
  padding: var(--space-1) var(--space-2);
  margin: 0;
}

.wstudy__lanegap[hidden] { display: none; }

/* The name in ink and not in accent: nothing here is pressable except the way
   out at the end, and accent means "you can press this". */
.wstudy__lanegap-name {
  flex: none;
  font-family: var(--font-serif);
  font-size: var(--fs-body);
  color: var(--ink-soft);
}

/* What is known, in the taste's place and with the taste's manners: it is the
   part that yields, because the way out must not be the thing that clips. */
.wstudy__lanegap-said {
  min-inline-size: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-family: var(--font-serif);
  font-size: var(--fs-body-sm);
  color: var(--ink-faint);
}

.wstudy__lanegap .wstudy__out {
  flex: none;
  margin-inline-start: auto;
  /* The way out never wraps: it is the one part of this row that must stay a
     single pressable line, so the sentence beside it yields instead. */
  white-space: nowrap;
}

.wstudy__lanedoor-name {
  flex: none;
  font-family: var(--font-serif);
  font-size: var(--fs-body);
  color: var(--accent-strong);
}

/* Enough of the entry to say whether it is worth opening, which is what a
   door owes a reader -- and the one part of the row that yields, because the
   name is the control and the volume is a citation. */
.wstudy__lanedoor-taste {
  min-inline-size: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-family: var(--font-serif);
  font-size: var(--fs-body-sm);
  color: var(--ink-soft);
}

.wstudy__lanedoor-vol {
  flex: none;
  margin-inline-start: auto;
  font-family: var(--font-sans);
  font-size: var(--fs-caption);
  font-variant-numeric: tabular-nums;
  color: var(--ink-faint);
}

/* The entry itself. A native <dialog>, so the top layer clears every
   z-index in play without renegotiating one, and escapes the pane's
   overflow:hidden which would clip anything positioned inside it. */
.wstudy__lanebox,
.wstudy__termsbox {
  inline-size: min(38rem, calc(100vw - 2 * var(--space-4)));
  /* vh FIRST AND dvh SECOND, the pattern this file already uses in five other
     places. On Android Chrome vh is the URL-bar-HIDDEN viewport, so a box
     measured in it stands taller than the screen actually showing while the
     bar is down: the foot of Lane's entry -- and the end of its scroller --
     then sits under the bar, unreachable, which reads as a scroll that has
     stuck rather than as a box that is too tall. Browsers without dvh keep
     the first line. */
  max-block-size: min(80vh, 44rem);
  max-block-size: min(80dvh, 44rem);
  padding: 0;
  border: var(--hair) solid var(--rule);
  border-radius: var(--radius);
  background: var(--paper);
  color: var(--ink);
  box-shadow: var(--shadow-soft);
  overflow: hidden;
}

.wstudy__lanebox::backdrop,
.wstudy__termsbox::backdrop { background: rgba(22, 19, 15, 0.55); }

.wstudy__lanebox[open],
.wstudy__termsbox[open] {
  display: flex;
  flex-direction: column;
}

.wstudy__lanebox-bar {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex: none;
  padding: var(--space-1) var(--space-3);
  border-block-end: var(--hair) solid var(--rule);
  background: var(--paper-raised);
}

.wstudy__lanebox-title {
  flex: 1 1 auto;
  margin: 0;
  font-family: var(--font-serif);
  font-size: var(--fs-h3);
  color: var(--ink);
}

.wstudy__lanebox-root {
  margin-inline-start: var(--space-2);
  font-family: "Amiri Quran", serif;
  font-size: var(--fs-body-lg);
  color: var(--ink-soft);
}

/* The one place in this feature with a reading measure, which is the whole
   reason the entry left the column. */
.wstudy__lanebox-body {
  min-block-size: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: var(--space-4) var(--space-4) var(--space-5);
}

@media (forced-colors: active) {
  .wstudy__exact.is-active {
    background: Highlight;
    color: HighlightText;
    forced-color-adjust: none;
  }
  .wstudy__exact.is-active .wstudy__exact-ar,
  .wstudy__exact.is-active .wstudy__exact-count { color: HighlightText; }
  /* The narrowed parent gives its fill back under forced colours too, or the
     view shows two Highlights and neither says which is the cut in force. */
  .wstudy__lemma.is-active.is-narrowed {
    background: Canvas;
    color: CanvasText;
  }
  .wstudy__lemma.is-active.is-narrowed .wstudy__lemma-ar,
  .wstudy__lemma.is-active.is-narrowed .wstudy__lemma-name,
  .wstudy__lemma.is-active.is-narrowed .wstudy__lemma-count,
  .wstudy__lemma.is-active.is-narrowed .wstudy__lemma-gloss,
  .wstudy__lemma.is-active.is-narrowed .wstudy__lemma-label { color: CanvasText; }
}

/* Every WORD row is the same kind of thing, because every one does the same
   thing: choose which word of this root the verse column is about. */
/* Rows, not cards. The brief's rule is that whitespace and rhythm carry
   structure instead of boxes and rules, and three columns of bordered cards
   is the opposite of it: the eye spends itself on the edges rather than on
   the words. The one that is chosen takes a solid fill, which is the whole
   of the marking. */
/* A FAMILY of the root: verbs, nouns, verbal nouns or participles, kept whole.
   It is a block for two reasons. It groups what the corpus's own band order
   already grouped, so a reader comparing verbs is not reading past nouns to do
   it -- and it is what holds a headword and its spelling sub-row together,
   which as two loose siblings in a multicol flow could be dealt into separate
   columns, putting the narrowest cut under a word it had nothing to do with. */
.wstudy__family {
  break-inside: avoid;
  margin-block-end: var(--space-2);
}

.wstudy__family:last-child { margin-block-end: 0; }

/* A CATEGORY, and it reads as one: the family's name at body size in
   sentence case with how many of the root's occurrences it holds. Rendered
   only where there is more than one family to tell apart, which is 47% of
   roots.

   It was label-sized and uppercase, which put it in the band eyebrow's own
   costume one level down and left the entries under it looking like a
   continuous list rather than a group. Body size against 0.88rem rows makes
   it plainly a heading; sentence case and the sans face keep it plainly
   BELOW the band header above, which stays this column's only eyebrow. One
   treatment per role, two levels apart.

   The end padding is zero so the count lands on the same right rail every
   row below it uses. */
.wstudy__family-title {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
  margin: var(--space-3) 0 var(--space-1);
  padding-inline: var(--space-2) 0;
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  font-weight: 600;
  color: var(--ink);
}

/* The first heading needs no air above it: the band's own header is there. */
.wstudy__family:first-child > .wstudy__family-title { margin-block-start: 0; }

.wstudy__family-count {
  margin-inline-start: auto;
  font-size: var(--fs-body-sm);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--ink-soft);
}

/* THE ENTRIES SIT INSIDE THEIR CATEGORY, and the number is arithmetic rather
   than the indent you would guess. A row already carries margin-inline: -8px,
   so its fill bleeds 8px past its own text for the hover and active states;
   its own 8px padding puts the text back on the container's edge. Setting
   this to 8px rather than 16px therefore moves the TEXT 16px in while leaving
   the bleed intact -- write 16px here and the fill starts exactly at the
   text, which loses the inset the pressed state is drawn with.

   The exact-spelling sub-row rides along with its parent: its elbow is drawn
   against its own box, so the pair moves together and stays joined. */
.wstudy__family > .wstudy__lemma,
.wstudy__family > .wstudy__exact {
  margin-inline-start: var(--space-2);
}

/* One row each, on three authored tracks: the entry, what kind of word it is,
   and how many times it occurs. The 44px floor is a TOUCH rule and stays
   where fingers are -- see the narrow block below -- but with a mouse it only
   spent the pane's height on air.

   The Arabic track is authored rather than content-sized so that every count
   in a column lands on one edge. A lemma wider than the track overflows it
   into the label's space rather than moving the column, which is the trade
   the surah index also took: an occasional collision beats a wandering rail. */
.wstudy__lemma {
  inline-size: 100%;
  display: grid;
  /* THE ENTRY STACKS AND THE MIDDLE IS THE MEANING.

     The word sits on line one with its kind directly under it, because those
     two are one fact -- which word, and what kind of word -- and the English
     is a different fact that deserves its own measure. Measured before it was
     changed: the Arabic ink runs 14-34px inside an authored 88px track, so
     27-38% of every row was dead space, and the gloss was pushed onto a line
     of its own beneath.

     The first track is authored rather than content-sized, and that is the
     surah index's lesson: tracks that size to their own content centre every
     row on itself and the list stops reading as a list. 5.5rem and not less,
     measured: at 4.5rem four of ق و م's kinds truncated -- "Active, form IV"
     came out "Active, f..." -- and a kind that cannot be read is worse than
     the width it saves. */
  grid-template-columns: 5.5rem minmax(0, 1fr) auto;
  align-items: baseline;
  /* No ROW gap: the kind belongs to the word directly above it, and 8px of
     air there would set the two lines of one entry as far apart as two
     entries. The tracks still need their 8px between columns. */
  gap: 0 var(--space-2);
  min-inline-size: 0;
  min-block-size: 26px;
  padding: 1px var(--space-2);
  margin-inline: calc(-1 * var(--space-2));
  border: 0;
  border-radius: var(--radius-control);
  background: none;
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: var(--fs-body-sm);
  text-align: start;
  white-space: nowrap;
  cursor: pointer;
  /* Multicol may not split a row between two columns. */
  break-inside: avoid;
}

/* The widest cut has no Arabic to show, so its name takes the entry's track
   and the label's both: "All forms" is the whole of what it says.

   It is sized to ITS OWN CONTENT and not to the rail. Standing outside the
   column flow it was full width, and a full-width solid accent -- the state
   this row is in by default on every root page -- is a slab rather than a
   row. Capping it to a column's width was the other candidate and it wanders:
   multicol balances, so the real column measured 216px, 296px and 232px at
   three pane widths, and any fixed cap puts this count off the rail its
   neighbours land on. Hugging its own words implies no rail at all, which is
   honest for the one row that has nobody to line up with. */
/* IT KEEPS HUGGING ITS OWN WORDS, and the attempt to put its count on the
   shared rail was REVERTED on 2026-08-23 within the hour. Sizing it to the
   column does align the count -- and makes this row, which is the checked one
   by default on every root that still shows it, a full-width solid accent
   slab. That is the thing `test_all_forms_no_longer_costs_a_column` was
   written to prevent and the thing section 10 objects to hardest.

   Dropping the chip on single-entry roots removed the emptiest version of that
   slab but not the common one, so the trade did not become worth taking. A
   count that does not line up is a smaller cost than a block of colour the
   reader did not ask for: this row has nobody to line up with anyway, which
   is what hugging says. */
.wstudy__lemma--all {
  display: inline-grid;
  inline-size: auto;
  grid-template-columns: auto auto;
  column-gap: var(--space-4);
  /* THE DEEPEST BOUNDARY TAKES THE WIDEST GAP, and this one had the rail's
     tightest. Measured before it changed: 0 between entries, 4px from a family
     heading to its own first entry, 20px between families -- and 8px under the
     one row that stands ABOVE every family, which is the widest cut of all.
     The rhythm said the opposite of the structure. Whitespace carries
     structure here, so the number has to agree with the hierarchy. */
  margin-block-end: var(--space-5);
}

.wstudy__lemma:hover { background: var(--paper-sunk); }

/* LEFT, which is what gives the row a left edge at all. The span carries
   dir="rtl", so a stretched grid item aligns its text to the RIGHT of the
   5.5rem track: a short headword floated away from the column's edge and the
   gloss beneath it, which is left-aligned English, started nowhere near it.
   The owner reported that as the gloss line not working, and it was the row's
   alignment rather than the gloss's.

   justify-self and not text-align: `start` inside an rtl span means right, so
   only a physical value would do there, while justify-self resolves against
   the GRID's own direction. Do not "simplify" this to text-align: start.

   The authored tracks are untouched, so every count still stacks. One trade
   flips and it flips the right way: a lemma wider than the track now spills
   into the label's space rather than out toward the column gutter. */
.wstudy__lemma-ar {
  grid-area: 1 / 1;
  justify-self: start;
  font-family: "Amiri Quran", serif;
  /* THE SIZE IS h3 AND NOT body, and the reason is the face rather than the
     row. Amiri Quran spends most of its em on the marks: measured on canvas
     at the 16px this used to be, the bare LETTERFORMS of a word are 12px tall
     while the vocalised word's whole ink is 23.6, so two thirds of what the
     eye is given is diacritics and the word itself reads smaller than the
     14px "Noun" sitting under it. At h3 the letterforms are ~14.6px and the
     entry finally leads its own row.

     h3 rather than a new number: .wstudy__vword-ar already sets Arabic in a
     list at exactly this size, so the panel keeps one answer for "Arabic in
     a list" instead of two.

     NOT BOLD, and this was tried. Only the 400 of this face is loaded, so a
     700 is synthesised by the browser, and synthesis thickens the marks with
     the letters -- a shadda and a kasra become blobs, which loses precisely
     the detail that tells them apart. The size is what buys presence here.

     AND THE LINE BOX IS LEFT ALONE. Tightening it to 1.15 to win back the
     height looked free and was not: the descent is 9.6px at this size, and
     the kasra under the word cut straight through the "Noun" beneath it. */
  font-size: var(--fs-h3);
  color: var(--ink);
}

/* Directly under the word it describes, sharing its track and its left edge:
   one entry reads as two lines rather than as a row of three unrelated
   things. It still yields before the Arabic or the count, neither of which
   may ever be clipped. */
.wstudy__lemma-label {
  grid-area: 2 / 1;
  min-inline-size: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  font-size: var(--fs-caption);
  color: var(--ink-faint);
}

/* The corpus dictionary's OWN English for this entry, held verbatim: "to
   announce, to proclaim". Never ours -- see data/corpus/README.md for why a
   computed one was refused.

   It spans all three tracks on an IMPLICIT second grid row, which is what
   lets it exist without touching the three authored ones: the Arabic still
   sits in 5.5rem and every count still lands on the shared rail. And because
   min-block-size is a floor rather than a height, a row with no gloss -- two
   in three of them, since their pages gloss the verbs and leave the nominals
   bare -- is exactly the height it was before this line existed.

   It WRAPS, against the row's own nowrap, and is the only part of the row
   that may: the Arabic and the count must never be clipped, and clipping the
   English would lose a sense rather than a character. Nine in ten glosses fit
   one line at this column width; the long ones take two and the ladder goes
   a little ragged, which is what a list of words is allowed to do.

   IT TAKES THE MIDDLE, beside the stacked entry rather than under it, and it
   is what the dead space in the old Arabic track paid for. Two rows tall, so
   a long gloss uses the height the kind line already spends rather than
   adding a third line to the row; its first line shares the word's baseline,
   which is what says the two belong together. */
.wstudy__lemma-gloss {
  grid-area: 1 / 2 / span 2 / 3;
  min-inline-size: 0;
  font-size: var(--fs-caption);
  line-height: 1.35;
  color: var(--ink-faint);
  white-space: normal;
  /* A two-line gloss breaks where the measure runs out, which on a narrow
     middle track leaves a full line above a single orphaned word. `pretty` asks
     the browser to settle the rag instead, and is ignored where it is not
     understood -- three other places in base.css lean on it the same way. */
  text-wrap: pretty;
}

/* The right rail, shared with the root's count above and the verse rows'
   English below. Tabular figures so the digits stack rather than shimmy. */
.wstudy__lemma-count {
  /* On the WORD's line and on the right rail: a count is a fact about the
     entry, so it reads across from the entry rather than from its meaning. */
  grid-area: 1 / 3;
  justify-self: end;
  font-size: var(--fs-caption);
  font-variant-numeric: tabular-nums;
  color: var(--ink-faint);
}

/* The widest cut has no Arabic to show -- it is every spelling of the root at
   once -- so its name slot is English in the sans face. Same chip, same
   group, same fill when chosen: only the name is of a different kind. */
.wstudy__lemma-name {
  font-family: var(--font-sans);
  font-size: var(--fs-body-sm);
  color: var(--ink);
}

/* The chosen row is a SOLID FILL in the accent with its text flipped to
   --paper, which is the accent's opposite in both themes so one declaration
   covers each. It was a 2px accent ring until 2026-08-21, and the design
   brief section 10 names exactly that treatment as the one that failed: it
   measured a perfectly good 10.1:1 and still read as invisible, because the
   failure was area rather than contrast. Not a tint and not a leading-edge
   bar either -- the same section forbids both. */
.wstudy__lemma.is-active {
  border-color: var(--accent-strong);
  background: var(--accent-strong);
  color: var(--paper);
}

/* Every child that sets a colour of its own has to be told. */
.wstudy__lemma.is-active .wstudy__lemma-ar,
.wstudy__lemma.is-active .wstudy__lemma-name,
.wstudy__lemma.is-active .wstudy__lemma-count,
.wstudy__lemma.is-active .wstudy__lemma-gloss,
.wstudy__lemma.is-active .wstudy__lemma-label { color: var(--paper); }

.wstudy__lemma.is-active .wstudy__lemma-label,
.wstudy__lemma.is-active .wstudy__lemma-gloss,
.wstudy__lemma.is-active .wstudy__lemma-count { opacity: 0.78; }

/* Author backgrounds are discarded under forced colours, so the state is
   restated in system terms, the way the search dropdown restates its own. */
/* Author backgrounds are discarded under forced colours, and both marks ARE
   backgrounds. Mark/MarkText is the system pair that exists for exactly this
   -- not Highlight, which this panel reserves for the chosen control. */
@media (forced-colors: active) {
  /* The THIRD rail joined these two on 2026-08-29. It had carried the same
     tint since it was built and was never restated here, so in forced colours
     it was the one mark of the three that simply vanished. */
  .wstudy__vmark,
  .wstudy__rowgloss-mark,
  .wstudy__rowsound-mark {
    background: Mark;
    color: MarkText;
    forced-color-adjust: none;
  }
}

@media (forced-colors: active) {
  .wstudy__lemma.is-active {
    background: Highlight;
    color: HighlightText;
    forced-color-adjust: none;
  }
  .wstudy__lemma.is-active .wstudy__lemma-ar,
  .wstudy__lemma.is-active .wstudy__lemma-name,
  .wstudy__lemma.is-active .wstudy__lemma-count,
  .wstudy__lemma.is-active .wstudy__lemma-label { color: HighlightText; }
}

/* The scope note -- how many THIS cut holds, as against the root's own total
   in the subject block above -- is the VERSE header's own fact since
   2026-08-22, so it has no block of its own any more. It stood under the
   section title saying nearly what the title said, quieter than it, and
   scrolled away on a desktop. See .wstudy__band--verse .wstudy__bandtitle. */

/* The line NAMES its cut, so it carries Arabic in a sans-faced sentence.
   Amiri at the sentence's own size, because a name read as a word rather
   than as a label is the whole point of naming it. */
.wstudy__count-ar {
  font-family: "Amiri Quran", serif;
  font-size: var(--fs-body-sm);
  color: var(--ink-soft);
}

/* KWIC rows: chip, matched word, its own gloss, one line of translation. */
.wstudy__verses {
  margin: 0;
  padding: 0;
  list-style: none;
}

.wstudy__row {
  padding: var(--space-2) 0;
  /* --rule-soft: a row inside a section, which is the lightest of the three
     jobs the weights divide. It was --rule, the same hairline the band seam
     carried, so a section boundary and a row boundary were indistinguishable
     -- and the section, being the rarer of the two, lost. */
  border-block-end: var(--hair) solid var(--rule-soft);
}

/* KWIC: keyword in context, on the instrument's own two rails. The reference
   starts on the left rail with the root's radicals and every lemma above it;
   the English ends on the right rail with the root's count and every form's
   total. Between them the phrase the word actually sits in.

   A summary laid out with grid loses its native marker, so the affordance is
   drawn: a chevron that turns when the row opens. */
.wstudy__rowhead {
  display: grid;
  /* THIRD TRACK IS THE TRANSLITERATION, `auto` so it is the size of the word
     it says and nothing on a row that has none. Every row carries it since
     2026-08-30; it was an [open]-only track for an afternoon and the three
     copies of that rule are gone with it. */
  grid-template-columns: 0.9rem 3.4rem auto minmax(0, 1fr) minmax(0, 1fr);
  align-items: baseline;
  gap: var(--space-2);
  margin: 0;
  list-style: none;
  cursor: pointer;
}

/* THE PHRASE AND ITS ENGLISH ARE PLACED, not auto-flowed. A row whose word
   has no transliteration appends no paragraph for it -- and auto-placement
   would then slide the phrase up into the transliteration's `auto` track,
   where an Arabic window sizes to its own content instead of to the room left
   over, and a long verse blows the row open. Two stated columns cost nothing
   and cannot drift; the narrow layouts restate the English's, which spans. */
.wstudy__snip { grid-column: 4; }
.wstudy__rowgloss { grid-column: 5; }

.wstudy__rowhead::-webkit-details-marker { display: none; }

.wstudy__rowhead::before {
  content: "›";
  justify-self: center;
  color: var(--ink-faint);
  font-family: var(--font-sans);
  line-height: 1;
  transition: transform var(--dur-fast) var(--ease-calm);
}

.wstudy__kwic[open] > .wstudy__rowhead::before { transform: rotate(90deg); }

.wstudy__rowhead:hover::before { color: var(--accent-strong); }

/* THE WINDOWS, both of them: three parts on one line that clips rather than
   wraps -- a concordance is scanned down its rails, and a row that grows to
   two lines breaks the scan.

   THE MIDDLE PART NEVER YIELDS. A single run of text ellipsizes at its end
   and the matched word sits in the middle, so on a narrow column the one
   thing the line exists to show would be the part cut off. The lead gives up
   its head, the tail gives up its tail, and the mark keeps its width. */
.wstudy__snip,
.wstudy__rowgloss {
  min-inline-size: 0;
  display: flex;
  align-items: baseline;
  white-space: nowrap;
}

/* The lead is clipped at its FAR end. text-overflow can only ever cut the end
   a line is read towards, which here is the end touching the mark -- exactly
   the words a concordance exists to show. Pushing an inner run to the main
   axis end hides the far side instead, and does it in both scripts: flex-end
   is the left in the Arabic line and the right in the English one. */
.wstudy__snip-lead,
.wstudy__rowgloss-lead {
  flex: 0 1 auto;
  min-inline-size: 0;
  display: flex;
  justify-content: flex-end;
  overflow: hidden;
}

.wstudy__snip-run,
.wstudy__rowgloss-run {
  flex: none;
  white-space: nowrap;
}

.wstudy__snip-tail,
.wstudy__rowgloss-tail {
  flex: 1 1 auto;
  min-inline-size: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}

.wstudy__snip {
  font-family: "Amiri Quran", serif;
  font-size: var(--fs-body);
  line-height: 1.9;
  color: var(--ink-soft);
}

/* The English of the SAME words, and the matched one IS marked -- the word
   layer holds one gloss per position for every word of the text, so the mark
   asserts that layer's own claim rather than one made here. Its predecessor,
   a window of the running translation, could not be marked at all: nobody
   aligns a sentence of Qarai to an Arabic position. */
.wstudy__rowgloss {
  font-family: var(--font-serif);
  font-size: var(--fs-body-sm);
  color: var(--ink-soft);
}

/* The same mark the Arabic match wears, so the two rails mark one word. */
.wstudy__rowgloss-mark {
  flex: none;
  border-radius: var(--radius-control);
  padding-inline: 0.2em;
  background: var(--accent-tint);
  color: var(--ink);
}

/* 24px is the AA floor and this chip sat exactly on it, in a list meant to
   be walked with a thumb. It buys height without buying weight: the row's
   own rhythm is unchanged because the chip shares its line with taller
   things. */
.wstudy__vchip {
  flex: none;
  display: inline-flex;
  align-items: center;
  /* The address and its arrow, which says a press goes there. */
  gap: 3px;
  min-block-size: 32px;
  padding-inline: var(--space-2);
  border: var(--hair) solid var(--rule);
  border-radius: var(--radius-pill);
  background: var(--paper);
  color: var(--accent-strong);
  font-family: var(--font-sans);
  font-size: var(--fs-caption);
  text-decoration: none;
}

.wstudy__vchip:hover { border-color: var(--accent); background: var(--accent-tint); }

/* The matched word is marked by background, as every in-text mark here is. */
/* A button CONTAINING a marked word. The tint alone said "this is the
   matched word", which is true and is not an affordance: on touch, with no
   hover and no cursor, nothing said it could be pressed at all. The border
   is the affordance that hover cannot be. */
.wstudy__cword {
  /* An anchor while the tab strip is parked and a button while it is on, so
     both are dressed here: an anchor brings underline and inherited link
     colour with it, and this is a marked word in a phrase, not a link in
     prose. */
  display: inline-flex;
  align-items: center;
  gap: 2px;
  border: var(--hair) solid var(--rule);
  padding-inline: var(--space-1);
  border-radius: var(--radius-control);
  background: var(--accent-tint);
  color: var(--ink);
  text-decoration: none;
  font-family: "Amiri Quran", serif;
  font-size: var(--fs-body-lg);
  cursor: pointer;
}

.wstudy__cword:hover { background: var(--accent-wash); }

/* THE MARK FOR "THIS TAKES YOU SOMEWHERE", on the reference and on the word
   alike, because since 2026-08-22 they do the one thing. Quiet on purpose:
   it is a hint about what a press costs, not a control, and it sits inside
   two things a reader is trying to READ -- an address and a word of the
   Qur'an. Drawn at 10px in the faint ink and never in colour.

   It is inside the flow rather than absolutely placed so it can never sit on
   top of a letter; in the RTL word it lands at the run's end, which is the
   left, and that is correct rather than a bug. */
.wstudy__goes {
  flex: none;
  color: var(--ink-faint);
}

/* On the pressed row the fill takes both, and a faint ink over an accent is
   the one unreadable combination in this panel. */
.wstudy__row .is-active .wstudy__goes,
.wstudy__cword:hover .wstudy__goes { color: currentColor; }

/* Held for every word in the corpus and shown until now only on the subject.
   Quieter than the gloss beside it: it says how the word SOUNDS, which is a
   smaller claim than what it means. */
.wstudy__rowtranslit {
  font-family: var(--font-sans);
  font-size: var(--fs-caption);
  font-style: italic;
  color: var(--ink-faint);
}

.wstudy__rowgloss {
  font-family: var(--font-sans);
  font-size: var(--fs-caption);
  color: var(--ink-soft);
}

/* What the row opens onto: the whole verse with the word marked where it
   actually stands, how it sounds and means here, and the whole translation.
   Indented past the chevron and the reference so it reads as this row's
   answer rather than as the next row beginning. */
.wstudy__rowfull {
  margin-block-start: var(--space-2);
  padding-inline-start: calc(0.9rem + 3.4rem + 2 * var(--space-2));
}

.wstudy__rowverse {
  margin: 0 0 var(--space-2);
  font-family: "Amiri Quran", serif;
  font-size: var(--fs-body-lg);
  line-height: 2.1;
  color: var(--ink);
}

/* The gap is the space character now, not a margin, because a margin is not a
   break opportunity -- see the loop in word-study.js that writes it. Which
   means this surface joins the one section 1b settles at length: the space is
   drawn by Amiri Quran and is 292/1000 em, so the same subtraction puts
   quran.com's flat 0.375rem back and this verse spaces exactly like the verse
   on the reading page. The formula cancels the font size, so it needs no
   second value here, and the 0.292 holds for as long as Amiri Quran is the
   first family in the rule above. */
.wstudy__rowverse { word-spacing: calc(0.375rem - 0.292em); }

/* The same mark every in-text match in this panel wears, on a span that is
   not a control: in the whole verse the word is being POINTED AT, and the
   thing that navigates is the one in the line above. */
.wstudy__vmark {
  border-radius: var(--radius-control);
  background: var(--accent-tint);
  box-decoration-break: clone;
  -webkit-box-decoration-break: clone;
}

/* BESIDE THE REFERENCE, ON EVERY ROW, since 2026-08-30. It spent a week at
   the foot of the OPEN row -- under the whole verse, two paragraphs from the
   address it belongs to -- and then an afternoon here but only while the row
   was open, which meant the one thing a reader scanning a concordance wants
   at a glance cost a press per row to see.

   WHAT PAID FOR IT WAS DROPPING THE GLOSS FROM THIS RAIL. It read
   `transliteration · word_gloss`, and the gloss is the SAME English already
   marked in the word-by-word rail directly below -- now ringed there, which is
   what made the repeat visible as a repeat. Sounding the word is this rail's
   whole job. It costs about 55px of a row's Arabic window rather than the 150
   the pair wanted, which is what makes it affordable on every row instead of
   on one.

   The window is a window: it gives up its lead by design, and the right rail
   the whole concordance is read down is untouched, because the Arabic is
   end-aligned. */
.wstudy__rowsound {
  margin: 0;
  /* ROOM FOR THE RING. The mark's box-shadow is painted 1px outside its own
     border box, and this paragraph is exactly the mark's width -- an `auto`
     track sized to its content -- so with the clip hard against the mark the
     ring came out cut off at both ends and along the top. Reported as a
     broken circle. The padding is what the clip needs to have something to
     spare; the clip itself has to stay, because it is what lets the rail give
     up its tail rather than take a second line. */
  padding: var(--hair);
  min-inline-size: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  font-family: var(--font-sans);
  font-size: var(--fs-caption);
  color: var(--ink-faint);
}

/* The third rail, and it wears the mark the other two wear. An open row shows
   the same word three times -- marked in the Arabic verse, marked in the
   English above it, and here, where it is transliterated -- and this was the
   one left plain, which read as though the line belonged to something else.
   It does not: it is the same word said aloud.

   On the span and never on the paragraph. The paragraph runs the width of the
   row, so a background there is a bar across the row rather than a mark on a
   word, and this panel points at words. box-decoration-break so a wrap at a
   narrow pane gives two marked pieces rather than one box around both. */
.wstudy__rowsound-mark {
  border-radius: var(--radius-control);
  padding-inline: 0.2em;
  background: var(--accent-tint);
  color: var(--ink);
  box-decoration-break: clone;
  -webkit-box-decoration-break: clone;
}

/* ---- THE THREE RAILS OF AN OPEN ROW WEAR ONE MARK -----------------------
   Asked for on 2026-08-29: the three had presence enough to be found and not
   enough to be the point of the row. An open row is a page of prose -- a
   whole verse, a whole translation, a rail of glosses -- and the one word it
   is all about was a pale tint somewhere inside it.

   A RING, AND NOT THE FOOT THE SUBJECT WORD WEARS, and the difference is
   measured rather than chosen. The panel's mark elsewhere is a tint with a
   2px accent edge along its foot; that mark needs clear space UNDER the word,
   which a card gives it and a line of running text does not. Photographed on
   وَلِيٍّ at 2:107: the edge landed across the tail of the ya, which is the
   same fault this file already recorded on the root card's radicals, and the
   only way to clear it is padding that makes the marked word taller than the
   line holding it -- so the verse opens a gap around whichever line it falls
   on. Measured: the paragraph goes 75px to 78 or 79 for every padding deep
   enough to matter.

   A ring has no such problem in either script and costs no layout at all: a
   box-shadow is paint. So the rule is about the SETTING rather than about the
   script -- a mark standing alone keeps the foot, a mark inside running text
   takes the ring -- and the two English rails take the ring as well, so an
   open row marks one word one way three times.

   THE WEIGHT IS ONLY ON THE ENGLISH, and that is the font and not a
   preference: Amiri Quran ships one face, so `font-weight: 600` on the Arabic
   is a browser's synthetic emboldening, which thickens the diacritics along
   with the letters. The ring is what carries that one. */
.wstudy__rowgloss-mark,
.wstudy__rowsound-mark,
.wstudy__vmark {
  /* The ring is drawn ON the mark's own edge, so the padding that used to be
     invisible breathing room is now the distance between a letter and a line
     around it. 0.2em, which is what the two English marks already carried. */
  padding-inline: 0.2em;
  background: var(--accent-tint);
  box-shadow: 0 0 0 var(--hair) var(--accent);
}

.wstudy__rowgloss-mark,
.wstudy__rowsound-mark {
  font-weight: 600;
  color: var(--ink);
}

/* THE TWO ENGLISHES, EACH NAMED. One treatment, because they are one role:
   saying which source a piece of English came from. They are named because a
   row shows both at once and they are not two lengths of one text -- the rail
   in the summary is the word layer's gloss, position by position, and the
   paragraph below is a translator's sentence. Unnamed, the second read as the
   first's full version.

   THE PANEL'S LABEL TREATMENT, not the page's credit treatment. Under a verse
   a credit only has to be quieter than the translation above it, and
   .verse__tr-src earns that with a smaller sans face in a fainter ink. That
   is not enough here: the rail this credit ends is ITSELF small faint sans,
   so one step of ink was the only thing separating a label from the text it
   labels, and the label read as more of the sentence. Reported the same day
   the naming shipped.

   So they take the shape this panel already gives a label -- caps, tracked,
   600, the .wstudy__gramtitle idiom -- one step fainter because a credit is
   smaller than a section title. Caps and tracking are not a decoration here:
   they are the one axis the surrounding text does not use, so the label is
   legible as a label at a glance and at any size. The DOM keeps the true
   casing, so a copied line still says "Ali Quli Qarai". */
.wstudy__rowgloss-src,
.wstudy__rowtr-src {
  font-family: var(--font-sans);
  font-size: var(--fs-label);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

/* At the end of the rail and never shrinking, so the tail beside it gives up
   its own last words first -- the same order of sacrifice the window already
   uses, where the mark never yields. Where the rail wraps (a phone, and the
   results column) this simply follows the last word.

   The space before it is TEXT, because the line is copied out and read aloud
   as well as looked at and a margin is neither of those -- windowLine's own
   reasoning about its joins. The padding beside it is for the eye only, and
   supplements that space rather than standing in for it: one word space at
   0.68rem is not enough gap to read a label as a separate thing.

   nowrap so the label never breaks across two lines. Where the rail itself
   wraps -- a phone, and the results column -- the label goes to the next line
   whole, which reads as a caption under the text it names. */
.wstudy__rowgloss-src {
  flex: none;
  padding-inline-start: 0.4em;
  white-space: nowrap;
}

/* Block, so it sits under the sentence it credits rather than trailing it
   into the margin. Same as the credit under a verse. */
.wstudy__rowtr-src {
  display: block;
  margin-block-start: var(--space-1);
}

.wstudy__rowwait {
  margin: 0;
  font-family: var(--font-sans);
  font-size: var(--fs-caption);
  color: var(--ink-faint);
}

.wstudy__rowtr {
  margin: var(--space-1) 0 0;
  font-family: var(--font-serif);
  font-size: var(--fs-body-sm);
  line-height: var(--lh-reading);
  color: var(--ink-soft);
}

.wstudy__more {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-block-size: 44px;
  margin-block-start: var(--space-3);
  padding-inline: var(--space-4);
  border: var(--hair) solid var(--rule);
  border-radius: var(--radius-pill);
  background: var(--paper-raised);
  color: var(--accent-strong);
  font-family: var(--font-sans);
  font-size: var(--fs-body-sm);
  cursor: pointer;
}

.wstudy__more:hover { border-color: var(--accent); background: var(--accent-tint); }

/* hidden is a user-agent rule of the lowest specificity, and ANY author
   display rule beats it whatever its own specificity. Both of these set one,
   so both have to say it again. This is the fifth time in this stylesheet. */
.wstudy__more[hidden],
.wstudy__rootstep[hidden] { display: none; }

/* The two arrows that walk the dictionary alphabet. NO BOX: accent already
   says "you can press this", and a border around it says the same thing a
   second time -- two bordered pills stacked under the radicals read as a
   pair of unrelated objects rather than one walk in two directions. This is
   the trail's own Back dress, which is borderless for the same reason.

   The touch floor is kept, as height and hit area rather than as a visible
   edge. */
.wstudy__rootstep {
  display: inline-flex;
  align-items: baseline;
  gap: 0.3rem;
  flex: none;
  min-block-size: 28px;
  padding-inline: var(--space-1);
  border: 0;
  border-radius: var(--radius-control);
  background: none;
  color: var(--accent-strong);
  font-family: var(--font-sans);
  font-size: var(--fs-caption);
  cursor: pointer;
}

/* Written, not implied. A chevron beside three radicals is not a direction
   anyone reads, and "ح ق ق" alone announces a destination and never a way. */
/* The same correction as the word's, and the same treatment. It said NEXT and
   PREVIOUS, which name a direction and not a destination -- in a panel whose
   row above walks words and whose band below walks occurrences, the reader had
   to infer what was being stepped through. It steps through roots.

   The uppercase and the letter-spacing go with the change, so that the two
   rows of steps in this panel wear one dress rather than two: they answer the
   same question about different things, and a reader should not have to learn
   the mark twice. It also buys back the width the longer word costs -- capital
   letters and 0.08em of tracking are expensive, and "PREVIOUS ROOT" would not
   have fitted its column. */
.wstudy__rootstep-way {
  font-size: var(--fs-label);
  line-height: var(--lh-tight);
  color: var(--ink-faint);
}

.wstudy__rootstep:hover .wstudy__rootstep-way { color: var(--accent-strong); }

.wstudy__rootstep:hover { background: var(--paper-sunk); }

/* Bare radicals carry no diacritics, so they read at a size pointed Arabic
   could not: this is "س م و", not a word of the mushaf. Smaller than the
   entry above it by a clear step, because that is what says which is which. */
.wstudy__rootstep-ar {
  font-family: "Amiri Quran", serif;
  font-size: var(--fs-body-sm);
  line-height: 1.5;
  color: var(--ink-soft);
}

/* ---- The entry and its walk on ONE ROW, where the pane can hold it -------

   The identity half was a stack: the radicals, then the two arrows under them
   at its foot. That is 104px of a card whose other half -- the count and
   Lane's opening words -- wants about 60, so the card was as tall as its
   emptier side. On one row it is 52, and the band above and Lane's line
   beside it both come up to meet it. Asked for on 2026-08-29, and it is the
   word header's own shape one section up: the subject in the middle, a way
   out in each equal side track.

   THE PANE IS THE MEASUREMENT, and 38rem is the threshold this panel already
   keeps -- the width at which the cascade below turns into a menu beside its
   results. Under it the identity half is about 144px where the three want
   190, so the stack stays: a reader who has dragged the panel to its floor
   has height to spend and no width at all, and a phone has the same shape for
   the same reason. A window media query would answer the wrong question here;
   see .wstudy__panes for why the container is the pane. */
@container wstudy-pane (min-width: 38rem) {
  .wstudy__rootcard-id {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
    align-items: center;
    /* One row, centred in whatever height the half beside it sets. */
    align-content: center;
    column-gap: var(--space-2);
  }

  .wstudy__rootident { grid-area: 1 / 2; }

  /* The paragraph lays out nothing; its two buttons ARE the row's side
     tracks. The word card's own neighbours do exactly this. */
  .wstudy__rootsteps { display: contents; }

  /* STACKED, so they fit beside the entry rather than instead of it: on one
     line each arrow is about 110px and the three want 291 of the 253 a
     half-split gives. The way above, the arrow and its radicals below.

     A GRID RATHER THAN A WRAPPER SPAN, because the chevron is OUTBOARD in
     both -- next reads "< q w y" and previous "q w l >" -- so the two cannot
     share one nested box without turning one of them around. The markup
     stays as it is and the tracks place its three children. */
  .wstudy__rootstep {
    grid-area: 1 / 1;
    justify-self: start;
    /* The root card's own recorded trap: an item that opts out of the
       stretch is sized to its CONTENT and will hang out of its track. */
    max-inline-size: 100%;
    display: grid;
    grid-template-columns: auto auto;
    justify-content: center;
    justify-items: center;
    align-items: center;
    gap: 0 0.3rem;
  }

  .wstudy__rootstep--prev {
    grid-area: 1 / 3;
    justify-self: end;
  }

  .wstudy__rootstep .wstudy__rootstep-way { grid-area: 1 / 1 / auto / span 2; }
  .wstudy__rootstep > svg { grid-row: 2; grid-column: 1; }
  .wstudy__rootstep .wstudy__rootstep-ar { grid-row: 2; grid-column: 2; }

  .wstudy__rootstep--prev > svg { grid-column: 2; }
  .wstudy__rootstep--prev .wstudy__rootstep-ar { grid-column: 1; }
}

.wstudy__lanetext {
  font-family: var(--font-serif);
  font-size: var(--fs-body);
  line-height: var(--lh-reading);
  color: var(--ink);
}

.wstudy__lanetext p { margin: 0 0 var(--space-2); }

/* The provenance line is a caveat, not a credit: Lane through a digitization
   that can hold scan errors, said next to the text it qualifies. */
/* Colophon voice: a licence line and a scan-error caveat are book small
   print, and serif at caption size is what that sounds like. */
.wstudy__provenance {
  margin: 0 0 var(--space-1);
  font-family: var(--font-serif);
  font-size: var(--fs-caption);
  color: var(--ink-faint);
}

.wstudy__out { color: var(--accent-strong); }
.wstudy__out[hidden] { display: none; }

.wstudy__inpane {
  border: 0;
  padding: 0;
  background: none;
  color: var(--accent-strong);
  font-family: var(--font-sans);
  font-size: inherit;
  text-decoration: underline;
  cursor: pointer;
}





/* The on-screen Arabic keyboard. A grid that fits its own keys to whatever
   width it is given, which is what keeps one layout honest from a 320px
   sheet to a half-desktop pane without a breakpoint.

   It falls out of the search block like the results do, and for the same
   reason: it is a way of typing into the box, so it belongs against the box
   and over the instrument rather than pushing the panel down. Its row
   wrapper went with the search view -- the toggle is IN the field now,
   because a way of typing belongs with the thing typed into. */
/* IN THE FIELD, at the trailing end, from 2026-08-28 -- the masthead's own
   arrangement, and this copy is now the same control rather than a cousin of
   it. It stood beside the box as a bordered pill carrying the words "Arabic
   keyboard", on the argument that the panel's bar had a floor the masthead's
   capped track did not. True, and beside the point: two doors onto one
   keyboard that answer to one name should LOOK like one thing, and a reader
   who learns the mark in the bar should not meet a differently dressed
   control down here.

   .wstudy__search is the positioned ancestor, and it already was -- it is
   what .wstudy__under hangs from. The input is the only in-flow child left
   once this box leaves the row (the label and the live region are both
   visually-hidden, which is position: absolute), so it fills the block and
   this cap lands on the field's own trailing edge.

   Flush with that edge and not inset from it, which is the masthead's note
   verbatim: when the keyboard is open the cap fills with accent and its two
   end corners are rounded to CONTINUE the field, and an inset fill stops
   short of the edge it is meant to finish. So the trailing room is padding
   INSIDE the cap -- the box moves, the target does not. */
.wstudy__keytoggle {
  position: absolute;
  inset-block: 0;
  inset-inline-end: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  inline-size: 38px;
  /* The clearance from the FIELD's edge, and it is the cap that is sized to
     it rather than the mark: at 0.8rem the three letters are 29px wide and
     will not give any of that back without becoming small type in a small
     box. So the cap is 38 rather than square with the 34px field, which puts
     the mark's edge 8.5px inside the field's own. Measured; the square cap
     left it 5 and the mark read as jammed against the border.

     The 2.75rem the input cuts for this is the 38 plus 6, which is where the
     typed text stops -- 6 from the cap, and therefore 6 from the mark. */
  padding: 0 8px 0 0;
  border: 0;
  /* The field's corner, not the pill the standalone control used to wear:
     this box is the end of the field now, so it finishes the field's own
     radius rather than drawing a second shape against it. */
  border-start-end-radius: var(--radius-control);
  border-end-end-radius: var(--radius-control);
  background: none;
  color: var(--ink-faint);
  cursor: pointer;
}

.wstudy__keytoggle:hover { color: var(--accent-strong); }

/* OPEN IS A FILL, the masthead's state exactly. The bordered pill said "open"
   by changing its border colour, which is the weakest signal this stylesheet
   owns and was invisible against a field that borders itself. */
.wstudy__keytoggle[aria-expanded="true"] {
  background: var(--accent-strong);
  color: var(--paper);
}

/* Drawn INSIDE the cap. A positive offset would ring the field's own border
   from the outside and read as the field being focused, which it is not. */
.wstudy__keytoggle:focus-visible {
  outline: var(--focus-width) solid var(--accent-strong);
  outline-offset: calc(-1 * (var(--focus-width) + var(--hair)));
}

/* Author backgrounds are discarded under forced colours, so the open state
   has to restate itself in system colours or it vanishes. */
@media (forced-colors: active) {
  .wstudy__keytoggle[aria-expanded="true"] {
    background: Highlight;
    color: HighlightText;
    forced-color-adjust: none;
  }
}

/* Type in a key, not a drawing; the twin rule in base.css carries the whole
   argument -- why the border is currentColor, why the radius is written
   rather than tokened, why the padding is uneven.

   It takes the cap's own colour now and no longer holds one of its own. The
   --ink-faint it carried was there to sit a step under the words "Arabic
   keyboard" beside it -- the word being the label and the mark the kind, the
   gear's relationship with "Display" in the masthead. With the word gone the
   mark IS the control, and a control that paints itself fainter than itself
   is just a faint control. The two rules that lifted it back to currentColor
   on hover and while open retire with it.

   A shade smaller than the masthead's, and now for a measured reason rather
   than a compositional one: that cap stands in a 44px field and this one in a
   34px field, so the mark steps down with the box around it. */
.wstudy__keymark {
  flex: none;
  font-family: var(--font-arabic);
  font-size: 0.8rem;
  line-height: 1;
  border: var(--hair) solid currentColor;
  border-radius: 4px;
  padding: 2px 4px 4px;
}

.wstudy__keys {
  /* In flow inside .wstudy__under, which is what carries the whole column
     over the instrument. It keeps its full height whatever the cap: the list
     below is the part that scrolls, because a keyboard with rows cut off the
     bottom is a keyboard missing letters. */
  flex: 0 0 auto;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(2.5rem, 1fr));
  gap: var(--space-1);
  padding: var(--space-2);
  border: var(--hair) solid var(--rule-strong);
  border-radius: var(--radius-control);
  background: var(--paper-raised);
  box-shadow: var(--shadow-soft);
}

.wstudy__keys[hidden] { display: none; }

.wstudy__key {
  /* The panel's touch floor. These are the smallest targets in the feature
     and the ones most often pressed in a row, on a phone, by someone who has
     no Arabic keyboard -- exactly the case that cannot afford a near miss. */
  min-block-size: 44px;
  border: var(--hair) solid var(--rule);
  border-radius: var(--radius-control);
  background: var(--paper);
  color: var(--ink);
  font-family: "Amiri Quran", serif;
  font-size: var(--fs-body-lg);
  line-height: 1.4;
  cursor: pointer;
}

.wstudy__key:hover { border-color: var(--accent); background: var(--accent-tint); }

.wstudy__key:active { background: var(--accent-wash); }

/* Space and Delete are words, not letters, so they take the UI face and the
   room two columns give them. */
/* See the twin in base.css section 23: the grid runs right to left with its
   letters, and these two keys carry English words, so they turn back. */
.wstudy__key--wide {
  grid-column: span 2;
  direction: ltr;
  font-family: var(--font-sans);
  font-size: var(--fs-caption);
  color: var(--ink-soft);
}

/* Capped, because a long result list inside a foot section would otherwise
   push the credits far below the fold. */

/* The license's attribution, rendered where the licensed data renders. */
.wstudy__credits {
  padding-block-start: var(--space-3);
  border-block-start: var(--hair) solid var(--rule);
  font-family: var(--font-sans);
  font-size: var(--fs-caption);
  color: var(--ink-faint);
}

.wstudy__credits p { margin: 0 0 var(--space-1); }
.wstudy__credits a { color: var(--accent-strong); }

/* ---- Grammar pane -------------------------------------------------------- */

/* The decomposition. Our own rendered corpus text in Amiri, which is why
   colour is safe here and nowhere out on the page; the three tokens alias
   theme-aware colours already used as text on --paper, so both schemes clear
   4.5:1 without a dark block of their own: the tajweed blue and red are text
   colours in the Typeset styles, and --accent-strong is text sitewide. */
/* The decomposition: the corpus's own segment forms, tiling the corpus's own
   word, coloured per part. THE ONE PLACE COLOUR IS DATA in this panel -- the
   three tokens alias theme-aware colours already used as text on --paper, so
   both schemes clear 4.5:1 without a dark block of their own. The variables
   themselves are declared on .wstudy__gram, so the lines below can reach
   them too; declared here they could not, being that strip's siblings. */
.wstudy__segments {
  margin: 0 0 var(--space-1);
  font-family: "Amiri Quran", serif;
  font-size: var(--fs-h2);
  line-height: 1.9;
  color: var(--ink);
  /* PHYSICAL left, deliberately. The paragraph must be dir="rtl" so the
     segments lay out in the corpus's own order, but that also drives it to
     the far edge of an otherwise left-aligned English block, where it
     floated alone with the segment lines beneath it starting at the other
     side. The characters keep their direction; the run keeps the column. */
  text-align: left;
}

.wstudy__seg--prefix { color: var(--wstudy-prefix); }
.wstudy__seg--stem { color: var(--wstudy-stem); }
.wstudy__seg--suffix { color: var(--wstudy-suffix); }

.wstudy__summary {
  margin: 0 0 var(--space-2);
  font-family: var(--font-serif);
  font-size: var(--fs-body-sm);
  line-height: var(--lh-reading);
  color: var(--ink);
}

/* WHEN THE LINE HAS A TAIL BEHIND IT. Set by word-study.js, which measures --
   the clamp only exists above 62rem and only bites on the longer sentences,
   so this is a state and never a shape.

   The ellipsis is the resting hint and needs no help: it is the universal
   mark for "this continues". What is missing at rest is any sign that the
   continuation is REACHABLE, which is a question a reader only asks with a
   pointer already on the line -- so the answer arrives with the pointer.
   `help` is the cursor for exactly that, and the dotted underline that comes
   with it is the panel's own "explains itself" mark, borrowed from
   .wstudy__term on the row directly beneath. Resting, the sentence stays
   plain prose: a dotted rule under a full line of it, above a segment row
   that is already busy, would be the loudest thing in the half.

   NOT a text-decoration at rest and therefore no reflow when it appears:
   underlines are painted, not laid out. State is paint. */
.wstudy__summary.is-clipped { cursor: help; }

.wstudy__summary.is-clipped:hover,
.wstudy__summary.is-clipped:focus-visible {
  color: var(--accent-strong);
  text-decoration: underline dotted;
  text-underline-offset: 0.2em;
}

/* The tab stop this gains while it is clipped is a stop on a paragraph, so
   the ring has nothing of its own to sit on: give it the control radius the
   rest of the panel's focus rings take. */
.wstudy__summary.is-clipped:focus-visible {
  outline: var(--focus-width) solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--radius-control);
}

/* One line a segment. They were cards -- a bordered box apiece for a form,
   a part of speech and two features -- which spent four rules of chrome on
   three short facts. The colour of the Arabic says which part it is, so the
   PREFIX/STEM/SUFFIX label the box carried is gone with the box. */
.wstudy__seglist {
  /* No trailing margin: the links row below carries its own leading, and the
     header is measured to the pixel. */
  margin: 0;
  padding: 0;
  list-style: none;
}

.wstudy__segline {
  /* The frame the term tooltip is placed in: it is absolutely positioned
     inside the line it belongs to, so it travels with that line when the
     grammar block scrolls. See showTerm in static/js/word-study.js. */
  position: relative;
  display: flex;
  align-items: baseline;
  /* NOWRAP, and the features run along the line with rules between them. A
     five-segment word is 44 words out of 77,429 and it is the one the header
     is measured against: wrapping, each of its rows took two lines at the
     tightest pane and the list alone came to 256px. The row now holds one
     line and the tail is clipped by the list's own overflow rule rather than
     folding the header open.

     line-height tight for the same reason: this Arabic is Amiri Quran, whose
     line box is close to twice its letterforms, and five of those boxes at
     reading leading is most of the overflow on its own. */
  flex-wrap: nowrap;
  gap: var(--space-1);
  padding-block: 2px;
  line-height: var(--lh-tight);
  font-family: var(--font-sans);
  font-size: var(--fs-caption);
  color: var(--ink-soft);
}

/* The rule between two features on one line, on the item so a row never opens
   with one. Same device as the links row above it. */
.wstudy__segline > * + *::before {
  content: "";
  display: inline-block;
  inline-size: var(--hair);
  block-size: 0.8em;
  margin-inline-end: var(--space-1);
  vertical-align: -0.05em;
  background: var(--rule);
}

/* What the row gives up when it will not fit: its tail, not the header's
   shape. The form and the part of speech lead the line, so what a squeeze
   takes is the last of the features rather than which segment this is. */
.wstudy__segline > * {
  min-inline-size: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.wstudy__segline + .wstudy__segline {
  border-block-start: var(--hair) solid var(--rule);
}

.wstudy__segform {
  font-family: "Amiri Quran", serif;
  font-size: var(--fs-body);
  color: var(--ink);
}

.wstudy__segline--prefix .wstudy__segform { color: var(--wstudy-prefix); }
.wstudy__segline--stem .wstudy__segform { color: var(--wstudy-stem); }
.wstudy__segline--suffix .wstudy__segform { color: var(--wstudy-suffix); }

.wstudy__segpos { color: var(--ink); }

/* A family heading that explains itself keeps the HEADING's ink. --ink-soft is
   right for a term standing inside a line of prose, where it should not outrank
   the sentence; it is wrong for the name of a section, which would then be the
   only quiet heading in the rail. The dotted underline alone says pressable,
   and that is what the dress is for. */
/* Both kinds of heading that explain themselves keep the HEADING's ink and
   the heading's face: --ink-soft is right for a term standing inside a line of
   prose, where it must not outrank the sentence, and wrong for the name of a
   section. `font: inherit` on .wstudy__term already carries the serif and the
   size down from the band title; only the colour needs saying. The dotted
   underline alone marks it pressable, which is what the dress is for. */
.wstudy__family-title .wstudy__term,
.wstudy__bandtitle-name .wstudy__term { color: inherit; }

/* A HOST FOR THE DEFINITION, and it has to be a positioned one. The tip is
   absolutely placed inside whichever line raised it, and a line that is not
   positioned hands it to some ancestor far up the tree: measured on a phone,
   a family heading sitting 591px down the sheet raised a box at -22px, off the
   top of the screen entirely.

   The family title escaped this above the split only because it is sticky
   there, which is positioned by accident of another job -- exactly the kind of
   thing that works until the layout it depends on is not the one running. */
.wstudy__bandtitle,
.wstudy__family-title { position: relative; }

.wstudy__term {
  border: 0;
  padding: 0;
  background: none;
  color: var(--ink-soft);
  font: inherit;
  text-decoration: underline dotted;
  text-underline-offset: 0.2em;
  cursor: pointer;
}

/* Hovered, or standing open: the term is marked while its definition is on
   screen, which is the only mark a touch reader gets that the box below
   belongs to the word they pressed. */
.wstudy__term:hover,
.wstudy__term[aria-describedby] { color: var(--accent-strong); }

/* ---- What a term means, said where the term stands ------------------------
   A definition used to live only in the glossary at the foot of the pane, and
   pressing a term scrolled the reader there and rang the entry. The sentence
   is eight words long and the pane is 20rem wide, so it comes to the term
   instead, and the glossary stays as the reference list it always was.

   Same box as the word-by-word tooltip, and for the same reasons: an accent
   edge on the side nearest the thing it explains, and NO pointing tail --
   the box is clamped to the line's width and a clamped tail points at the
   wrong word, which is worse than no tail at all. */
.wstudy__tip {
  position: absolute;
  z-index: 2;
  /* Under the line it explains, and never wider than that line: the grammar
     block scrolls in both axes -- overflow-y: auto computes overflow-x to
     auto as well -- so a box that overhung it would raise a scrollbar there
     rather than simply hanging over. Shrink to the sentence, stop at the
     line. Every edge here is a class, because this panel's JavaScript writes
     no style; see showTerm in static/js/word-study.js. */
  inset-block-start: 100%;
  inset-inline-start: 0;
  inline-size: max-content;
  max-inline-size: 100%;
  margin-block-start: var(--space-1);
  padding: var(--space-2) var(--space-3);
  border: var(--hair) solid var(--rule-strong);
  border-block-start-width: var(--emph);
  border-block-start-color: var(--accent);
  border-radius: var(--radius-control);
  background: var(--paper-raised);
  box-shadow: var(--shadow-soft);
  font-family: var(--font-serif);
  font-size: var(--fs-body-sm);
  line-height: var(--lh-reading);
  color: var(--ink);
  /* It must not stand between the pointer and the term beneath it, or
     leaving the term through the box would flicker it open and shut. */
  pointer-events: none;
}

/* Leaning to the side of the line the term stands on. */
.wstudy__tip--end {
  inset-inline-start: auto;
  inset-inline-end: 0;
}

/* Flipped above the line when the block had no room below it. The accent
   edge moves with it, so it is always the edge nearest the term. */
.wstudy__tip--above {
  inset-block-start: auto;
  inset-block-end: 100%;
  margin-block-start: 0;
  margin-block-end: var(--space-1);
  border-block-start-width: var(--hair);
  border-block-start-color: var(--rule-strong);
  border-block-end-width: var(--emph);
  border-block-end-color: var(--accent);
}

/* HUNG OFF THE PANEL INSTEAD OF OFF THE LINE, which is what the grammar
   summary needs and nothing else here does. That line stands inside a header
   locked to a measured height with `overflow: hidden`, so a tip hosted beside
   it is cut rather than flipped. Measured at a 1400 window: the sentence wants
   67px and there are 63 under it. Hosted on .wstudy__panel it hangs over the
   pane below, where the room is.

   THE THREE NUMBERS COME FROM SCRIPT AND NOTHING ELSE DOES. word-study.js
   measures where the line was and writes it into these properties; every edge,
   colour, padding, shadow and bound above is still this file's. That is the
   same division panel-resize.js takes with --qs-headh, and it is the only form
   in which the panel's modules are allowed to touch geometry.

   The fallbacks are not decoration either: a property that failed to be set
   would otherwise resolve to nothing and drop the box at the panel's top-left
   corner at full width, which reads as a bug in the tip rather than as a
   missing measurement. 0/0 puts it there deliberately and 100% keeps it inside
   the panel while it is wrong. */
.wstudy__tip--free {
  inset-block-start: var(--wstudy-tip-y, 0);
  inset-inline-start: var(--wstudy-tip-x, 0);
  inset-inline-end: auto;
  max-inline-size: var(--wstudy-tip-w, 100%);
}

/* ONE ROW, separated by rules rather than by line breaks. Stacked, these three
   doors cost 89px of a header that has 351 to give the whole grammar -- and
   the deepest words in the corpus wanted 511. A door is a short phrase and
   three of them read perfectly well along a line with a rule between; three
   lines of their own was the header spending a quarter of its height on the
   things it is NOT about.

   wrap, so a narrow pane takes two rows instead of clipping, and the rules
   ride on the items rather than being drawn between them, so a wrapped row
   never begins with one. */
.wstudy__links {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-1) var(--space-2);
  margin: var(--space-2) 0 0;
  font-family: var(--font-sans);
  font-size: var(--fs-caption);
}

.wstudy__links > * + *::before {
  content: "";
  display: inline-block;
  inline-size: var(--hair);
  block-size: 0.85em;
  margin-inline-end: var(--space-2);
  vertical-align: -0.1em;
  background: var(--rule-strong);
}

/* The whole-verse view: one row per word, each a way into that word. */
.wstudy__verselist {
  margin: 0;
  padding: 0;
  list-style: none;
}

.wstudy__verselist[hidden],
.wstudy__dict[hidden] { display: none; }

.wstudy__vword {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: var(--space-1);
  inline-size: 100%;
  margin-block-end: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border: var(--hair) solid var(--rule);
  border-radius: var(--radius-control);
  background: var(--paper-raised);
  text-align: start;
  cursor: pointer;
}

.wstudy__vword:hover { border-color: var(--accent); }

.wstudy__vword-ar {
  font-family: "Amiri Quran", serif;
  font-size: var(--fs-h3);
  line-height: 1.7;
  color: var(--ink);
}

.wstudy__vword-translit {
  font-family: var(--font-sans);
  font-size: var(--fs-caption);
  font-style: italic;
  color: var(--ink-faint);
}

.wstudy__vword-gloss {
  font-family: var(--font-sans);
  font-size: var(--fs-caption);
  color: var(--ink-soft);
}

.wstudy__vword-summary {
  font-family: var(--font-serif);
  font-size: var(--fs-body-sm);
  line-height: var(--lh-reading);
  color: var(--ink-soft);
}

/* The glossary: grammar as a field, never a claim about a verse. */
.wstudy__glossary {
  margin-block-start: var(--space-4);
  padding: var(--space-2) var(--space-3);
  border: var(--hair) solid var(--rule);
  border-radius: var(--radius-control);
  background: var(--paper-raised);
}

.wstudy__glossary summary {
  min-block-size: 36px;
  display: flex;
  align-items: center;
  font-family: var(--font-sans);
  font-size: var(--fs-body-sm);
  font-weight: 600;
  color: var(--ink);
  cursor: pointer;
}

.wstudy__terms {
  margin: var(--space-2) 0 0;
}

.wstudy__terms dt {
  margin-block-start: var(--space-2);
  padding-inline: var(--space-1);
  font-family: var(--font-sans);
  font-size: var(--fs-body-sm);
  font-weight: 600;
  color: var(--ink);
}

.wstudy__terms dd {
  margin: 0 0 var(--space-1);
  padding-inline: var(--space-1);
  font-family: var(--font-serif);
  font-size: var(--fs-body-sm);
  line-height: var(--lh-reading);
  color: var(--ink-soft);
}

.wstudy__glossary-note {
  margin: var(--space-2) 0 0;
  font-family: var(--font-sans);
  font-size: var(--fs-caption);
  color: var(--ink-faint);
}

/* ---- The header's grip -----------------------------------------------------

   Off by default and turned on in the split's block below, which is
   .wstudy__came's arrangement and for the same reason: a sheet has no halves
   to move. Below 62rem the panel covers the surah entirely, the header gives
   up its own scroller so that nothing inside the sheet is a scroll container,
   and a reader dragging its foot would be resizing a thing with no bottom.
   Nothing about the phone changes, and none of the rules below can reach it.

   Everything a grip does is PAINT. It costs no pixel of layout at any
   position: this one cancels its own height with negative margins, and the
   line it shows on hover is a pseudo-element that was already there in
   transparent. A control that reflows the thing it is measuring cannot be
   dragged accurately.

   The SPLIT's grip left this section on 2026-08-30, when the other five panels
   grew one and it stopped being this panel's to describe. It is section 30 at
   the foot of this file. This one stays because the header it divides is this
   panel's alone, and so is the ladder below it. */
.wstudy__headgrip { display: none; }

/* The split, on the tafsir panel's terms and at its 62rem, in this section's
   OWN copy of the query -- the recorded lesson at the end of section 18: a
   base rule below section 17's block would outrank anything declared up
   there, so a rule for this section belongs after this section. */
@media (min-width: 62rem) {
  /* The panels are mutually exclusive through QSPanels, so <body> never
     carries two of these classes and the padding is never applied twice. */
  body.wstudy-open {
    padding-inline-end: var(--qs-panew, 50vw);
    overflow: visible;
    /* How much page there is left, which is not 100vw once a panel
       has taken half of it. Read by anything that drops out of the
       masthead: those are anchored inside this padding and cannot
       see it. Unset when no panel is open, and the fallback at each
       reader is the whole window, which is what it was. */
    --qs-pagew: calc(100vw - var(--qs-panew, 50vw));
  }

  /* Back under the masthead, whose controls stay reachable beside a split. */
  .wstudy { z-index: 90; }

  /* THE STRIP TAKES OVER FROM THE PILL, and only here. Beside a split the
     reader's eyes are in the panel -- they have just pressed a verse row in
     it -- while the pill sits at the foot of the other half, which is the
     owner's report that nobody finds it. Below this width the sheet is shut
     the moment a chip fires, so the pill is the only thing that can speak and
     this rule never applies.

     They are never both visible: the strip is display:none by default and
     turns on here, where the pill turns off. Both stay UNHIDDEN in the DOM so
     a reader dragging across the breakpoint keeps the way back either way. */
  .wstudy__came { display: flex; }

  /* The strip took this over above 62rem on 2026-08-23: beside a split the
     reader's eyes are in the panel and the pill sits at the foot of the other
     half, where the owner reported nobody finds it.

     It comes back when the bar is too narrow to hold the chip whole -- see
     .wstudy__came's container query. The two are never both shown: that rule
     hides the chip below 48rem of bar and this one yields the pill at the
     same point, so whichever can be seen properly is the one that speaks. */
  body.wstudy-open .wstudy__returnpill { display: none; }

  .wstudy__panel {
    inline-size: var(--qs-panew, 50vw);
    /* No strip beside a split: the panel takes the full height of its half. */
    inset-block-start: 0;
    /* Closed waits at the right edge rather than below the fold. Only the
       closed state is re-aimed; the open state is transform: none in both. */
    transform: translateX(101%);
    /* The edge that meets the page rather than the one that met the strip. */
    border-block-start: 0;
    border-inline-start: var(--hair) solid var(--rule);
  }

  /* No veil beside a split: the half that is not the panel stays live. */
  .wstudy__scrim { display: none; }

  /* Section 19's rule, extended for the third panel: the strip is fixed and
     does not move with the body padding, so it must be pulled clear of an
     open panel here as it is for the other two. */
  body.wstudy-open .recite { inset-inline-end: var(--qs-panew, 50vw); }

  /* ---- THE TWO CHROMES END ON ONE LINE ------------------------------------

     Beside a split, the page's masthead and the panel's bar are two bands at
     the top of one screen, and they ended 23px apart -- 76px against 53 --
     which reads as a mistake rather than as two panels. The owner's words were
     that it "looks strange side by side".

     76 is not a magic number: .masthead__inner is padding-block: 1rem around a
     2.75rem row, and this is the same arithmetic stated as a floor. All four
     panels take it, since all four sit beside that masthead. Below the split
     there is no masthead beside anything and the sheet keeps its own 44px.
     tests/test_browser_panel_resize.py measures the two against each other so
     a change to either is caught rather than noticed.

     DECLARED AS A PROPERTY rather than as four selectors, and that is the fix
     for how this broke. It was four selectors here, and the lectures panel is
     written at the foot of this stylesheet -- after them. A media query adds
     no specificity, so source order decided it and the lectures bar's own
     44px floor simply won: three chromes ended on the masthead's line and the
     fourth ended 32px short of it. A property the four base rules read cannot
     be beaten by a later rule that never mentions it, so a fifth panel takes
     the floor by being written like the others rather than by being
     remembered here. */
  :root { --panel-bar-min: calc(2.75rem + 2rem); }

  .wstudy__headgrip {
    display: block;
    position: relative;
    z-index: 4;
    flex: none;
    block-size: 12px;
    /* The height it costs the column, which must be none: the header's lock is
       measured to the pixel and a grip that pushed the panes down by twelve
       would falsify it. Negative margins straddle the header's own border
       rather than adding a band under it. */
    margin-block: -6px;
    cursor: row-resize;
    touch-action: none;
  }

  /* The line the grip shows, present at every state and only ever repainted.
     Growing it on hover would move the seam under the reader's pointer at the
     moment they are aiming at it. */
  .wstudy__headgrip::after {
    content: "";
    position: absolute;
    background: transparent;
    transition: background var(--dur) var(--ease-calm);
    inset-inline: 0;
    inset-block-start: 5px;
    block-size: 2px;
  }

  /* THE GRIP THE READER CAN SEE BEFORE THEY TOUCH IT, and the reason this
     exists is that the line above says nothing until hovered -- the seams were
     draggable for a day and nobody could tell. A cursor is a reward for
     already guessing.

     A short pill centred on the seam, which is the split-view convention
     (VS Code, Figma, the Finder's columns) and reads as "take hold here"
     without a rule drawn the length of the panel. Rejected: thickening the
     whole divider, which puts a heavy band between the halves permanently to
     teach a gesture once; and helper text, which is an admission that the
     affordance failed.

     Paint only, like everything else on these grips: it is out of flow, so
     neither its resting state nor its accent costs the layout a pixel. */
  .wstudy__headgrip::before {
    content: "";
    position: absolute;
    border-radius: 2px;
    background: var(--ink-faint);
    transition: background var(--dur) var(--ease-calm);
    inset-inline-start: 50%;
    inset-block-start: 4px;
    inline-size: 2.25rem;
    block-size: 4px;
    transform: translateX(-50%);
  }

  /* Accent, because a grip is a pressable and this stylesheet spends accent on
     nothing else. Focus-visible included: a keyboard reader moving the seam
     with the arrow keys needs to see which seam is listening. The pill takes
     the same three states as the line, so the two never disagree. */
  .wstudy__headgrip:hover::after,
  .wstudy__headgrip:focus-visible::after { background: var(--accent); }

  .wstudy__headgrip:hover::before,
  .wstudy__headgrip:focus-visible::before { background: var(--accent); }

  .wstudy__headgrip:active::after { background: var(--accent-strong); }

  .wstudy__headgrip:active::before { background: var(--accent-strong); }

  .wstudy__headgrip:focus-visible { outline: none; }

  /* Nothing to compress. A verse subject's header is one eyebrow and gives up
     the lock entirely a few hundred lines above; a root subject has no header
     at all. Either way there is no ceiling for the grip to move under, and a
     control that does nothing is worse than an absent one.

     By adjacency, which is why the markup puts the grip immediately after the
     header with no comment node between them. */
  .wstudy__head:has(> .wstudy__gram[hidden]) + .wstudy__headgrip,
  .wstudy__head[hidden] + .wstudy__headgrip { display: none; }

  /* ---- TWO LADDERS, NOT ONE ----------------------------------------------

     The header has two halves with different budgets, and one ladder over both
     was the fault the owner saw as white space: the word card would overflow
     first, the single ladder dropped a rung to fix it, and that rung took
     GRAMMAR with it that had 107px of room to sit in. Measured on reopening
     the panel at 2:3 -- the grammar showed a summary and nothing else with a
     third of its column empty beneath.

     So the card sheds on the card's own overflow and the grammar on the
     grammar's, each measured against its own column in panel-resize.js. What
     is left here is only what each rung hides or redresses.

     The head's own density follows the CARD, since the card is what sets how
     tight the header reads. */
  /* ---- RUNG ONE IS A DESIGN; RUNGS TWO AND THREE ARE ITS VALVES ----------

     The ladder used to shed its way down to a strip: air, then the
     transliteration, then the stack itself, and on the grammar's side the
     doors, the decomposition and its heading. At the floor -- which measures
     104px, so 87px of content -- every word in the corpus reached the bottom
     rung, and what stood there was a fifth of what the header holds.

     Since 2026-08-25 the header does not move (QURAN_PANEL_HEAD_FIXED), so
     that bottom rung is not a degradation any more, it is THE LAYOUT, and it
     has to carry everything. So rung one is the band: both halves become the
     same grid, an eyebrow beside its content, rules between things of like
     weight, and the two redundancies pay for the rest -- the verse chip, whose
     address the doors already offer to travel to, and the coloured strip,
     which is the same word drawn a second time above the rows that decompose
     it. What is left needs 80px on the left and 72 on the right.

     Rungs two and three are what remains of the ladder, and they are now
     valves rather than steps: nothing reaches them at a pane the split can
     give, and the deepest words in the corpus at the tightest one still can.
     Rung ZERO is untouched -- the tall two-column header, which is what the
     reader gets back the moment the grip returns. */
  .wstudy--card1 .wstudy__head {
    padding: var(--space-2) var(--space-3);
    column-gap: var(--space-4);
  }

  /* ---- The band's left half: the card stops being a stack ----------------
     Four stacked lines -- eyebrow, word, English, arrows -- cost 168px, and
     the line this header stops at is the masthead's, which is 104. So the
     eyebrow, the word, its English and how it sounds share a row with rules
     between them, the way the doors and the segment features already do, and
     the arrows give up the touch height they only ever needed on a phone:
     this surface is pointer-only, above 62rem, where WCAG 2.2 asks 24px
     rather than 44. */
  .wstudy--card1 .wstudy__subject {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    /* PACKED TO THE TOP, not spread through the slack: a band whose two rows
       drift apart when the grammar beside it happens to be short is the same
       hole this ladder was built to close. */
    align-content: start;
    row-gap: var(--space-1);
    padding-inline-end: var(--space-4);
    /* CENTRED, like every other rung. This read from the start for eight
       days, while the two arrows were packed at the start under it and the
       card was a left-hand column of small print. The arrows frame the word
       again, so the card has an axis again, and the English under it belongs
       on that axis rather than on the column's left edge. */
    text-align: center;
  }

  /* THE EYEBROW STANDS DOWN, and what pays for it is that its one job is
     already done in words on the row beneath. It names what the two arrows
     step -- WORD here, ROOT on the row below the header -- so that an arrow
     beside a root is never mistaken for one that moves a word. In the band
     those arrows are labelled "Next word" and "Previous word" outright, and
     they are labelled at every rung, so the eyebrow is the same noun a second
     time.

     It costs 63px of a 282px column, which is a fifth of the half and the
     whole of the difference between the English reading and reading as "the
     Most Gr...". Measured at a half-split 1400 window, which is the width this
     app is built for.

     WORD SUBJECTS ONLY, which is what makes this safe: a verse or a root
     carries no grammar, so its header is auto-height, no rung is ever reached,
     and its eyebrow is untouched -- which matters, because there the eyebrow
     is the only thing that says which of the two the reader is looking at. */
  .wstudy--card1 .wstudy__kind { display: none; }

  /* THE ADDRESS GOES, and it is the first of the band's two redundancies. The
     chip named the verse this word is in; the doors across the header offer to
     TAKE the reader there, on a row that survives every rung, and one of them
     says so in words. A citation that is also a door is worth its line in a
     header 24rem tall and is not worth it in one of 6.5.

     Hidden rather than dropped from the markup: word-study.js still fills it,
     the phone sheet below 62rem still shows it, and rung zero still carries
     it, so nothing about the chip is parked with the drag. */
  .wstudy--card1 .wstudy__vchip--head { display: none; }

  /* A FOURTH TRACK, FOR THE SPEAKER. The band's row is the word's two
     neighbours framing the word, and the speaker belongs beside the word
     rather than on a line of its own -- which is what the transliteration's
     line was, and this rung has already put that down. So the middle of the
     three tracks becomes two: the word, then the control that sounds it.

     The word sits a hair off the column's axis for it, and the English under
     it follows the word rather than the axis -- see .wstudy--card1
     .wstudy__gloss below for the 16px and where it is taken from. */
  .wstudy--card1 .wstudy__ident {
    /* The speaker's whole box, stated ONCE and read in three places: the
       track it stands in, the glyph inside it, and the offset the English is
       shifted by to sit under the word rather than under the pair. A 20px
       glyph in 4px of padding either side. */
    --wstudy-say-glyph: 20px;
    --wstudy-say-w: calc(var(--wstudy-say-glyph) + 2 * var(--space-1));
    grid-template-columns: minmax(0, 1fr) auto auto minmax(0, 1fr);
    column-gap: var(--space-1);
  }

  .wstudy--card1 .wstudy__wordstep--prev { grid-area: 1 / 4; }

  .wstudy--card1 .wstudy__word {
    font-size: var(--fs-h2);
    line-height: 1.45;
  }

  /* A ROW OF ITS OWN, under the word and running the whole card. It shared
     the word's line for eight days with a hairline standing between them, and
     the price was that the English -- the one thing here a reader with no
     Arabic opened the panel for -- got whatever width was left once the word
     and the speaker had taken theirs. On this row it has the card.

     It still gives up its tail rather than taking a second line: the band is
     locked at 104px, and a wrap here is a rung rather than a wrap. */
  .wstudy--card1 .wstudy__gloss {
    /* CLEAR OF THE WORD'S MARKS, and by more than the line box alone gives.
       This was zero on the reasoning that the row above is a 47px line box
       around a 23px word, so the clearance was already paid -- true of the
       metrics and not of what a reader sees, because Amiri Quran's ink sits
       low in that box and the gap read as the English being tucked under the
       word. Asked for on 2026-08-30. Eight pixels, which the band can afford:
       the card measures 83px against the 87 the lock gives it, so no rung is
       reached for it -- measured after, not estimated before. */
    margin: var(--space-2) 0 0;
    min-inline-size: 0;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
  }

  /* UNDER THE WORD, NOT UNDER THE PAIR, asked for on 2026-08-29: "can the
     english be centered underneath the arabic word, not underneath the arabic
     word + speaker icon combo".

     The row centres `word + gap + speaker`, so the word itself stands 16px
     left of the card's axis -- half of the 32px the speaker and its gap add
     to the right of it. This row spans the whole card and centres in it, so
     it was landing on the axis and not on the word.

     PAID FOR OUT OF THE ENGLISH'S OWN ROW, which is what makes it affordable.
     The counterweight this replaces -- an empty track opposite the speaker,
     so the word is centred outright -- was measured and rejected: it takes 32
     px out of the row the two neighbours share, which is 16 apiece, and at
     the panel's 24rem floor they have 25px each to start with. Nine pixels is
     less than one chevron. Here the whole cost falls on a line that has 240px
     for about 150 of text at a half split, and only bites at that same floor,
     where the English gives up two more characters of a tail it is already
     giving up.

     CONDITIONAL ON THE SPEAKER BEING THERE, and asked TWO ways because
     neither implies the other: `[hidden]` is how the script says this word
     has no sound to offer, and .wstudy--card2 is how the ladder says it has
     taken the speaker away for room. Either way the track collapses, the word
     is already on the axis, and the shift would be the very error it exists
     to correct.

     Both asked in ONE selector rather than in a rule and a rule undoing it.
     The reset was written first and lost: `:has()` takes the specificity of
     its argument, so the rule below counts five classes where a
     `.wstudy--card2 .wstudy__ident .wstudy__gloss` reset counts three. A
     correction that cannot outrank what it corrects is not a correction. */
  .wstudy--card1:not(.wstudy--card2) .wstudy__ident:has(> .wstudy__say:not([hidden])) .wstudy__gloss {
    padding-inline-end: calc(var(--wstudy-say-w) + var(--space-1));
  }

  /* HOW IT SOUNDS JOINS THE ROW. It used to be the first thing the ladder
     dropped, on the argument that a word's sound matters less than what it
     is -- true of a line that costs 44px under the word, and not true of one
     that costs nothing beside it. The row was already there. */

  /* IT NO LONGER SHARES THE SQUEEZE, because nothing is left on this row to
     squeeze it against: the English moved to a row of its own on 2026-08-29,
     and what remains here is the word and the speaker. The rule that made
     both shrink together was written when the two competed for one line, and
     at the 24rem floor it was the difference between a truncated English
     beside a truncated sound and one of each. Neither truncates the other
     now. */
  .wstudy--card1 .wstudy__say {
    grid-area: 1 / 3;
    margin: 0;
    min-inline-size: 0;
  }

  /* THE SPEAKER STAYS AND THE SPELLING OF THE SOUND STANDS DOWN. Three things
     want this row -- the word, its English and how it sounds -- and at the
     panel's own half width, 282px, they want 329 between them. Something goes,
     and the panel's own order of claims says which: Arabic, then English, then
     how to say it.

     What goes is the WRITING of the sound, not the sound: the speaker keeps
     its place beside the English, and pressing it still plays the word. That
     is the arrangement every dictionary uses on a line too short for a
     phonetic respelling, and the button keeps a label for the reader who
     cannot see it. Truncating instead was tried and is worse than either: at
     this width it renders "the Mos..." beside "l-r...", which is two facts
     spoiled to keep one. */
  .wstudy--card1 .wstudy__translit { display: none; }

  /* NO HAIRLINES BETWEEN THE PARTS. Two stood on this row while it held the
     word, the English and the sound in a run -- a rule apiece to say where
     one fact ended and the next began. The row is the word and its speaker
     now, framed by the two ways out, with the English on a row of its own:
     the arrangement says what the rules were saying, so drawing them as well
     is one weight of separation too many inside one card. */

  /* The 44px floor is a TOUCH target, and there is no touch here: this whole
     block is inside a 62rem query, where the pointer is a mouse and WCAG 2.2
     asks 24. The same trade the two arrows make below. */
  /* The 44px floor is a TOUCH target, and there is no touch here: this whole
     block is inside a 62rem query, where the pointer is a mouse and WCAG 2.2
     asks 24. The same trade the two arrows make below. With the spelling of
     the sound put down, the padding that framed a whole line is framing a
     16px glyph, and every pixel of it is one the English is asking for. */
  .wstudy--card1 .wstudy__play {
    min-block-size: 28px;
    min-inline-size: 0;
    padding: 0 var(--space-1);
  }

  /* THE GLYPH TAKES THE ROOM THE SPELLING GAVE UP. 16px is the size a speaker
     is drawn at when it stands beside a word -- a mark against copy, sized to
     the copy. With .wstudy--card1 .wstudy__translit put down, this control is
     the glyph and nothing else, and a 16px icon alone on a row beside a
     23px word reads as a stray rather than as the third thing the row offers.

     20 and not more because the button is 28px tall and that is a height the
     ladder must not be given a reason to remeasure: the row above is
     baseline-aligned, so an icon whose box grows past the word's own ascent
     starts adding pixels to a header locked at 104. At 20 the box is 28 and
     unchanged, which is the whole budget this bump has to stay inside. */
  .wstudy--card1 .wstudy__play svg {
    inline-size: var(--wstudy-say-glyph);
    block-size: var(--wstudy-say-glyph);
  }

  /* THE COLUMN SHAPE IS WHAT LETS THEM STAND BESIDE THE WORD, and it is the
     shape this card wears at every other rung: the way above, the arrow and
     its Arabic below. On one line each button wants about 110px, and two of
     those plus the word want 259 of the 240 a half-split gives -- which is
     the width that sent them under the card in the first place. Stacked, each
     is about 60 and the three want 160.

     THE TOUCH FLOOR STANDS DOWN, as it does for the speaker beside them: this
     whole block is inside a 62rem query, where the pointer is a mouse and
     WCAG 2.2 asks 24 rather than 44. */
  .wstudy--card1 .wstudy__wordstep {
    min-block-size: 28px;
    padding: 0 var(--space-1);
  }

  /* AND THE WAY MAY WRAP AGAIN. It was pinned to one line while it stood
     BESIDE the arrow, where a break after "Previous" put a two-line label in
     a one-line row and took the band's height with it. Above the arrow it is
     already a line of its own, so a break is the label using two of its own
     rather than pushing anything -- and at the 24rem floor, where the column
     is 130px, wrapping is what keeps the direction readable at all. */
  .wstudy--card1 .wstudy__wordstep-line { min-inline-size: 0; }

  /* ---- The band's right half, built to the same drawing -------------------
     An eyebrow in the first column, its content in the second, and the rows
     under them running the width -- which is the left half's shape exactly.
     That is what makes the two halves read as one band rather than as two
     panels that happen to be adjacent. */
  .wstudy--gram1 .wstudy__gram {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    align-content: start;
    column-gap: var(--space-2);
    row-gap: var(--space-1);
  }

  .wstudy--gram1 .wstudy__gramtitle {
    grid-column: 1;
    grid-row: 1;
    margin: 0;
  }

  /* ONE LINE, and this is not a rung dropping the tail of a sentence -- it is
     the only height the sentence has. Two lines cost 48px of the 87 this half
     is given, which leaves the decomposition and the doors 39 between them and
     they need 44. There is no pane the split can give where a two-line summary
     and both rows beneath it fit, so the clamp is the band's shape rather than
     a loss it takes under pressure.

     What the clamp cuts is also the one thing here that is said twice: the
     sentence names the part of speech and the features that the row beneath it
     spells out per segment. The root is the exception, and it has a section of
     its own directly below the header. */
  .wstudy--gram1 .wstudy__summary {
    grid-column: 2;
    grid-row: 1;
    margin: 0;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 1;
    overflow: hidden;
  }

  /* THE SECOND REDUNDANCY, and the larger one: the strip is the word drawn a
     second time, directly above the rows that take it apart. Its one job that
     the rows do not do is colour, and the rows carry the same three colours on
     the same three parts -- they are why the variables were hoisted to
     .wstudy__gram in the first place. 44px for a repeat. */
  .wstudy--gram1 .wstudy__segments { display: none; }

  /* THE DECOMPOSITION RUNS ALONG A LINE instead of down five. Stacked, the
     deepest word in the corpus wanted 100px here and the shallowest 40, in a
     half that has 87 for three rows; along the line the same five segments
     wrap into two rows of 20. The reading order is unchanged -- prefix, stem,
     suffix, left to right, which is the order the list was already in. */
  .wstudy--gram1 .wstudy__seglist {
    grid-column: 1 / -1;
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    column-gap: var(--space-2);
    row-gap: 0;
  }

  /* A STEP DOWN FOR THE FORM, and it is the line box being bought rather than
     the letters: Amiri Quran's box is close to twice its letterforms, so the
     16px form set a 22px row and two rows of them are half of what this half
     has. At 14px the row is 19 and the decomposition costs 38 instead of 44 --
     which is the difference between the doors below it fitting and not.
     Through the SIZE and never the leading: tightening line-height clips the
     marks above an alif, which is the one thing this Arabic may not do. */
  .wstudy--gram1 .wstudy__segform { font-size: var(--fs-body-sm); }

  .wstudy--gram1 .wstudy__segline {
    display: inline-flex;
    /* So a segment wider than the half ellipsises its own tail rather than
       running under the seam. The children already know how. */
    max-inline-size: 100%;
    min-inline-size: 0;
    padding-block: 0;
  }

  /* The rule that separated two stacked segments turns with them. */
  .wstudy--gram1 .wstudy__segline + .wstudy__segline {
    border-block-start: 0;
  }

  /* STRONGER THAN THE ONE BETWEEN TWO FEATURES, because it divides more: this
     is where one segment ends and the next begins, and inside each of them the
     quieter rule is already at work. Two weights doing two jobs on one line. */
  .wstudy--gram1 .wstudy__segline + .wstudy__segline::before {
    content: "";
    display: inline-block;
    inline-size: var(--hair);
    block-size: 0.8em;
    margin-inline-end: var(--space-1);
    background: var(--rule-strong);
  }

  .wstudy--gram1 .wstudy__gram > .wstudy__links {
    grid-column: 1 / -1;
    /* The auto margin sent this to the foot of a column that had a foot to be
       sent to. The band's rows pack to the top and there is no slack to take,
       so the doors sit under the decomposition they belong to. */
    margin: 0;
    padding-block-start: 0;
    /* Tighter than the row they keep in the tall header, on both sides of each
       rule. Three doors and two rules across a half of 343px at the window
       this app is measured on: the labels are 310 of it and the rules were
       spending 34 of the 33 that were left. */
    column-gap: var(--space-1);
  }

  .wstudy--gram1 .wstudy__links > * + *::before {
    margin-inline-end: var(--space-1);
  }

  /* WHAT EACH DOOR GIVES STAYS; WHERE IT GIVES IT FROM STANDS DOWN. Stacked
     over two rows these three cost 41px of the 87 this half has, and the row
     is what the ladder would drop next -- all three doors, to save a tail that
     names a host and a participle. "Classical i'rab" and "Grammar terms" are
     still doors with their destinations on them; the tall header, the phone
     sheet and every screen reader keep the whole label. */
  .wstudy--gram1 .wstudy__linktail { display: none; }

  /* ---- The valves ---------------------------------------------------------

     Nothing reaches these at a pane the split can give. What reaches them is
     the 44 words of five segments at the 24rem floor, and a window short
     enough that 46vh is under the masthead's line.

     THE EXPENSIVE ROW GIVES UP ITS DUPLICATED HALF BEFORE ANYTHING IS LOST,
     and the census is what says so. Segments per word across the corpus: one
     45.6%, two 44.1%, three 9.3%, four 0.9%, five 0.06%. The band holds the
     first two outright, which is 89.8% of every word in the Qur'an. What was
     shedding at three -- one word in ten, not a rounding error -- was the
     whole decomposition.

     It does not have to be. The summary above it IS the stem segment's row
     written as a sentence: "An adjective (صفة), masculine singular, genitive
     (مجرور), from the root ر ح م" against a row reading adjective (صفة) |
     masculine singular | genitive. Checked across imperatives, imperfects,
     nouns and adjectives, the sentence is generated from the stem's own
     morphology and always carries it. The prefix and suffix rows are the part
     the sentence never mentions -- a resumption particle, a vocative ya, an
     attached pronoun and its person -- so they are the part worth the pixels.

     So the first valve takes the stem's features and nothing else, which is
     19px and takes three-segment words to 85 in 91: 99% of the corpus keeps
     its whole decomposition, and the 1% that cannot has the sentence and the
     doors. The doors never go at all. They are a fixed 21px, and an overflow
     made of the decomposition was never theirs to fix -- ordering it that way
     lost the doors AND the rows to solve a problem only the second was
     causing. */
  .wstudy--card2 .wstudy__say { display: none; }

  .wstudy--gram2 .wstudy__segline--stem .wstudy__term,
  .wstudy--gram2 .wstudy__segline--stem .wstudy__termplain { display: none; }

  .wstudy--card3 .wstudy__head { padding: var(--space-1) var(--space-3); }

  .wstudy--card3 .wstudy__word {
    font-size: var(--fs-body-lg);
    line-height: 1.35;
  }

  .wstudy--gram3 .wstudy__seglist { display: none; }
}

/* The grips are a seam, and a seam in forced colours is a border or it is
   nothing: the pseudo-element's accent background is one of the colours the
   mode discards. */
@media (forced-colors: active) {
  .panel__splitgrip:hover::after,
  .panel__splitgrip:focus-visible::after,
  .panel__splitgrip:active::after {
    background: ButtonText;
    forced-color-adjust: none;
  }

  .wstudy__headgrip:hover::after,
  .wstudy__headgrip:focus-visible::after,
  .wstudy__headgrip:active::after {
    background: ButtonText;
    forced-color-adjust: none;
  }

  /* The pills are the resting affordance, so they must survive here too --
     an author background is one of the things this mode discards. */
  .panel__splitgrip::before,
  .wstudy__headgrip::before {
    background: ButtonText;
    forced-color-adjust: none;
  }
}

/* ---- The sheet: what a phone gets ----------------------------------------

   Below the split the panel is a sheet over the reading page, so the subject
   block is spending a phone's whole screen rather than the top of a tall
   column. Everything here buys back vertical room without taking anything
   away: the same blocks, closer together.

   The measured problem: on a 360x780 phone the subject block ran to about
   330px before "In the Qur'an" appeared, so a reader who tapped a word to
   see its occurrences got the identity and nothing else. */
@media (max-width: 61.99rem) {
  .wstudy__subject {
    padding-block: var(--space-3) var(--space-2);
  }



  .wstudy__word { line-height: 1.5; }

  .wstudy__gloss { margin-block-start: var(--space-1); }

  /* ONE scroller, with the bar and the tab strip pinned above it. They are
     the panel's only other flex children and take flex: none, so pinning
     costs no sticky offset that has to be kept in step with a height. */
  .wstudy__scroll {
    display: block;
    flex: 1 1 auto;
    min-block-size: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    /* The sheet runs to inset-block-end: 0, which on an iPhone is under the
       home indicator. The last row has to clear it. */
    padding-block-end: max(var(--space-6), env(safe-area-inset-bottom));
  }

  /* In flow, both of them: the fixed-band budget is what collapsed the verse
     list to nothing here, and a phone has no height to divide three ways. */
  .wstudy__panes {
    position: static;
    flex: none;
    min-block-size: 0;
  }

  .wstudy__pane {
    position: static;
    block-size: auto;
    overflow-y: visible;
    /* The pane's own padding, which on a sheet is the page margin. */
    padding-block: var(--space-3) 0;
  }

  /* Stacked: one column, and the rule between the halves turns with them --
     a vertical rule beside what is known becomes a horizontal one above it,
     exactly as the word header's does. Two 300px halves do not fit 390px. */
  .wstudy__rootcard { grid-template-columns: 1fr; row-gap: var(--space-3); }

  .wstudy__rootcard-id {
    padding-inline-end: 0;
    border-inline-end: 0;
    border-block-end: var(--hair) solid var(--rule);
    padding-block-end: var(--space-3);
  }

  /* Stacked, the identity half no longer has a taller half beside it setting
     its height, so there is no slack for the walk to be pushed into. */
  .wstudy__rootident { flex: none; }

  /* 44px is a TOUCH floor. The rows are compact where a mouse points and
     full-size where a finger presses -- the same rule, read on the device it
     was written for. Every row of the instrument that can be pressed. */
  .wstudy__lemma,
  .wstudy__exact,
  .wstudy__rootstep,
  /* Lane's door lost its floor when it flattened from a stacked block to one
     line: it drew at 27px here, under the rule, on the device the rule is
     for. The line is what changed, not the reachability. */
  .wstudy__lanedoor { min-block-size: 44px; }

  .wstudy__lanedoor { align-items: center; }

  .wstudy__lemma,
  .wstudy__exact { align-items: center; }

  /* The KWIC line has four tracks and a phone has room for two. The reference
     and the phrase share the first line; the English takes the second, where
     it can be read rather than clipped to five words. */
  .wstudy__rowhead {
    grid-template-columns: 0.9rem 3.4rem auto minmax(0, 1fr);
    padding-block: var(--space-1);
  }

  /* The English takes a line of its own here, where it can be read rather
     than clipped to five words -- so it wraps, and its three parts stop
     competing for one line's width. */
  .wstudy__rowgloss {
    grid-column: 2 / -1;
    display: block;
    white-space: normal;
    overflow: visible;
  }

  .wstudy__rowgloss-lead,
  .wstudy__rowgloss-tail {
    display: inline;
    overflow: visible;
    white-space: normal;
  }

  .wstudy__rowgloss-run { white-space: normal; }

  /* Aligned with the line above it, not with the row's edge. In this compact
     shape the chevron owns track one alone and EVERYTHING else -- the verse
     chip, and the English that wrapped to a line of its own -- begins at track
     two. The expanded verse used to start back at the row's edge, 23px to the
     start side of both, so opening a row visibly stepped left. One track, and
     the same value the head's own grid puts there. */
  .wstudy__rowfull { padding-inline-start: calc(0.9rem + var(--space-2)); }

  /* One column at a phone's width: two 13rem columns do not fit 320px, and a
     flow that silently drops to one anyway may as well say so. */
  .wstudy__families { columns: 1; }

  /* The pinned cut used to live here, on .wstudy__count, and only here. It is
     the verse band's own header now and pins at BOTH widths -- the reason it
     was written for a phone was never a phone's reason. */

  /* The search box takes a line of its own here: the bar wraps, and the name
     and the way out keep the first line to themselves. Full width, so its
     dropdown is the panel's width too and cannot reach past the edge. */
  .wstudy__search {
    flex: 1 0 100%;
    order: 3;
  }

  .wstudy__under {
    inset-inline: 0;
    min-inline-size: 0;
  }

  /* 44px is a hit floor, not a visible edge: the pill and the chip keep the
     size they are drawn at and grow the area a finger has to find. */
  .wstudy__exact { min-block-size: 44px; }

  /* A search result is drawn cozy above, where the pointer is a mouse and the
     list is competing with the keyboard for the panel's height. Here it is a
     row in a sheet being tapped, and it takes the floor back. */
  .wstudy__match { min-block-size: 44px; }

  .wstudy__vchip {
    min-block-size: 32px;
    position: relative;
  }

  .wstudy__vchip::after {
    content: "";
    position: absolute;
    inset-inline: 0;
    inset-block: calc((44px - 32px) / -2);
  }
}

/* At 320px the bar no longer needs saving from itself. It once held Back,
   the word, the verse chip, the root and four controls -- 361px of fixed
   width in a 320px viewport, which pushed the close button 41px past the
   edge and took the only way out with it. It now holds Back and close, and
   the identity that used to crowd it has a block of its own that wraps. */
@media (max-width: 22.5rem) {
  .wstudy__word { font-size: 1.75rem; }

  /* The arrows give up their padding before the root above them gives up any
     of its size: the root is what the card is about. */
  .wstudy__rootsteps { gap: var(--space-1); }

  .wstudy__rootstep { padding-inline: 0; }
}

/* ---- The dictionary as a browser: a menu beside its results ---------------

   Everything above this block is the STACKED LADDER, which is what a narrow
   pane and every phone sheet get. Here the lower two rungs turn side by side:
   the derived forms become a menu on the left at the root card's own identity
   width, the verses become its results on the right at the card's facts
   width, and pressing a form changes the list BESIDE the menu rather than
   below it. That is the sentence the cascade comment has stated since the
   bands were designed and the ladder could not keep on a rich root.

   TWO GATES, and both are needed.

   The MEDIA gate keeps every sheet stacked. A phone in landscape has a sheet
   wide enough to pass the container test, and columns inside a sheet a thumb
   is scrolling are not what any of this is for.

   The CONTAINER gate is the real measurement, and it asks the PANE rather
   than the window -- the pane is 50vw at the split, so a window width answers
   a different question. 38rem of pane engages from about a 1216px window,
   which takes in the 1280 laptop this project measures everything against.
   That is the whole difference from the three columns retired on 2026-08-21:
   they needed 736px and appeared only above ~1900px. */
@media (min-width: 62rem) {
  @container wstudy-pane (min-width: 38rem) {
    /* THE HEIGHT CHAIN, and every link is a definite size or a share of one.
       No viewport arithmetic and no chrome height anybody has to keep in step
       with -- the recorded lesson from the sheet's pinned bar.

         .wstudy__panes  flex: 1 1 auto; min-block-size: 0   (already)
         .wstudy__pane   position: absolute; inset: 0        (already, definite)
         .wstudy__dict   min-block-size: 100%                (here)
         row 2           minmax(12rem, 1fr)                  (here)
         column bodies   flex: 1 1 auto; min-block-size: 0   (here)

       The pane KEEPS its own overflow. At rest the section fills exactly one
       pane height, which is what "fits on a page" means; the treebank link,
       the glossary and the corpus credits sit below it and stay reachable by
       the pane's own scroll. Moving them inside the results column was the
       other candidate and it deletes them from the whole-verse and search
       views, which show corpus content with this block hidden -- and the
       credits are a licence condition, not a footer.

       The 12rem floor is the graceful way out: on a window too short to hold
       the section it refuses to shrink further, the dict outgrows the pane,
       and the pane scrolls. Stacked behaviour returning by degrees rather
       than an instrument crushed to nothing. */
    .wstudy__dict {
      display: grid;
      /* The panel's OWN ratio, twice over: the word header and the root card
         both split 2fr/3fr, so this seam lands on the same x as the hairline
         inside the card above it. The owner asked for the menu to match "the
         left part of the root column", and that is what it is. */
      /* THE PANEL'S OWN RATIO, which this layout is why: the word header and
         the root card both split 4fr/5fr, so this seam falls in the same
         column of pixels as their hairlines and the panel reads as one
         instrument rather than three boxes.

         It was 2fr/3fr for both until the menu's rows took a gloss into their
         middle track: at 2fr/3fr that middle measured 79px, three lines for
         "to stand up, to rise, to establish". Moving the constant to 4fr/5fr
         buys the menu 27px and costs the results 27px, which the results can
         afford -- they wrap the phone's own KWIC shape, and the phone does it
         in 320px of sheet. */
      grid-template-columns: minmax(0, 3fr) minmax(0, 4fr);
      grid-template-rows: auto minmax(12rem, 1fr);
      column-gap: var(--space-5);
      row-gap: var(--space-5);
      /* block-size and NOT min-block-size, which was the first attempt and is
         a floor rather than a height: a grid whose own height is auto
         resolves 1fr to max-content, so the row grew to the list and the dict
         came out 2617px tall inside an 803px pane. A definite height is what
         gives 1fr a remainder to divide. */
      block-size: 100%;
    }

    /* minmax(0, ...) above and min-block-size: 0 here are both load-bearing.
       A grid item's automatic minimum is its content, so nowrap rail rows
       would push the left track past 2fr and a long list would push row 2
       past 1fr -- the column would grow the pane instead of scrolling, which
       is this layout's one silent failure. */
    .wstudy__band--word,
    .wstudy__band--verse {
      display: flex;
      flex-direction: column;
      min-block-size: 0;
      min-inline-size: 0;
    }

    .wstudy__band--root { grid-column: 1 / -1; }

    /* row-gap owns the seam between the root and the columns now. */
    .wstudy__band + .wstudy__band { margin-block-start: 0; }

    /* The seam between the two halves CONTINUES the root card's own internal
       rule -- same x, same weight. --rule and not --rule-strong deliberately:
       it reads as one line with the card's hairline above it, and two weights
       meeting at a joint read as a mistake. The section headers keep saying
       "section" in --rule-strong on their own. */
    .wstudy__band--word {
      padding-inline-end: var(--space-5);
      border-inline-end: var(--hair) solid var(--rule);
    }

    .wstudy__band--word > .wstudy__bandbody,
    .wstudy__band--verse > .wstudy__bandbody {
      flex: 1 1 auto;
      min-block-size: 0;
      overflow-y: auto;
      /* A flick that reaches the end of one column does not then scroll the
         pane out from under the reader; .wstudy__gram's own rule. */
      overscroll-behavior: contain;
      /* Windows draws a classic scrollbar, and 15px out of a 240px menu is a
         rail that moves when a list gets long. Stable keeps the cost paid
         whether or not the bar is there. */
      scrollbar-gutter: stable;
      padding-block-end: var(--space-4);
    }

    /* The rail's rows bleed 8px past their column for the hover fill, which
       inside a scroller is start-edge overflow and gets clipped where nothing
       can reach it. The pad-and-pull pair moves the clip edge out by exactly
       that bleed and puts the content back, so the fill survives and the left
       rail does not move. */
    .wstudy__band--word > .wstudy__bandbody {
      padding-inline: var(--space-2);
      /* AIR BETWEEN THE COUNTS AND THE SCROLLBAR. The rail's counts sit on the
         far rail (justify-self: end) and the scrollbar's gutter is reserved at
         this same edge, so the two met with nothing between them. The end
         padding grows without a matching negative margin, which is what moves
         the content in rather than moving the box out. */
      padding-inline-end: var(--space-4);
      margin-inline: calc(-1 * var(--space-2));
      /* AND THE CARD'S END EDGE LANDS ON THE HEADER'S HAIRLINE. The band holds
         24px of end padding, so the menu's recessed card stopped 18px short of
         the seam above it and the two read as two different widths -- the
         owner's note that the vertical line "doesn't match up". Cancelling
         exactly that padding puts the card's edge on the same x as the word
         header's rule. The content stays where it was: the 16px of end padding
         above still holds the counts off the scrollbar. */
      margin-inline-end: calc(-1 * var(--space-5));
      /* ROOM FOR THE PINNED HEADING. The family titles below stick opaquely
         to this scroller's top, so anything scrolled to by the BROWSER rather
         than by a finger -- a Tab into a row below the fold, an arrow walking
         the rail, the restore that puts a returning tab back on its lit row --
         landed underneath one and looked like it had gone nowhere.
         scroll-padding is the one channel that covers all three at once; the
         page's own masthead uses it for the same reason. Sized to the title:
         fs-body at 1.55 plus its 12px top margin and 4px bottom. */
      scroll-padding-block-start: 2.75rem;
    }

    /* One column needs no columns. Multicol is what the stacked ladder uses
       to spend a full-width band; here the menu IS the column. */
    .wstudy__families { columns: auto; }

    /* PINNED BY ARCHITECTURE, which is better than pinned by sticky: the
       header is a flex sibling ABOVE the scroller, so it cannot move and
       needs no offset kept in step with anything. Sticky would be worse than
       redundant here -- with the pane scrolled toward the credits, a sticky
       title would detach from its own column and float over a list that is
       moving without it. */
    .wstudy__band--verse .wstudy__bandtitle {
      position: static;
      margin-inline: 0;
      padding-inline: 0;
      background: none;
    }

    /* The results column is about 360px at the 1280 baseline, and the four
       track KWIC row does not fit in it. This is the shape the phone already
       uses, restated for a column -- the reference and the phrase on one
       line, the English on its own beneath, where it can be read rather than
       clipped to five words. Its twin lives in the sheet block above; this
       stylesheet keeps a query's own copy rather than sharing one, and the
       two are cross-referenced so a change to either finds the other. */
    .wstudy__rowhead {
      grid-template-columns: 0.9rem 3.4rem auto minmax(0, 1fr);
      padding-block: var(--space-1);
    }

    .wstudy__rowgloss {
      grid-column: 2 / -1;
      display: block;
      white-space: normal;
      overflow: visible;
    }

    .wstudy__rowgloss-lead,
    .wstudy__rowgloss-tail {
      display: inline;
      overflow: visible;
      white-space: normal;
    }

    .wstudy__rowgloss-run { white-space: normal; }

    /* The twin of the rule in the sheet block above, on the same reasoning:
       the chevron owns track one alone, the chip and the English both begin at
       track two, and so does the expansion. */
    .wstudy__rowfull { padding-inline-start: calc(0.9rem + var(--space-2)); }

    /* A family heading stays with its own family while that family scrolls
       past. Its containing block is the .wstudy__family block, so it pins for
       exactly as long as its own entries last and then leaves with them --
       the grouped-list idiom, and the reason the menu can be scrolled without
       losing which family the rows under the pointer belong to. */
    .wstudy__family-title {
      position: sticky;
      /* FLUSH WITH THE TOP OF THE MENU, not with its content edge. A sticky
         element's constraint rectangle is the scrollport reduced by the scroll
         container's own padding, so `0` pinned this heading 12px down -- the
         rail's padding -- and entries stayed visible in the strip above it,
         sliding behind a heading that did not reach the edge. Measured at
         exactly the padding: 12px, so the offset is the padding, negated. */
      inset-block-start: calc(-1 * var(--space-3));
      z-index: 1;
      /* THE RAIL'S OWN GROUND, not the page's. A pinned strip has to be
         opaque or rows scroll through it, and while the rail stood on paper
         that was what --paper meant. On the recessed menu ground it drew a
         lighter band across the rail instead -- a highlight nobody asked for,
         on the one row that is a heading rather than a choice. */
      background: var(--paper-sunk);
      /* PADDING, NOT MARGIN, and it covers the rows' bleed as well. A
         background does not paint a margin, so this heading pinned with a 12px
         transparent gap above it and a 4px gap below: entries scrolled THROUGH
         those gaps and were drawn over the heading, half a row at a time, with
         their glosses appearing beside a family name they did not belong to.
         Reported exactly that way.

         .wstudy__bandtitle carries this same correction and says so in its own
         comment -- it was made for the verse band's pinned strip and never
         reached the family headings, which pin for the same reason.

         The inline pair covers the 8px each row bleeds past this column for
         its fill, so no uncovered strip is left down either edge; content
         still starts and ends exactly where the rows' does, so the counts stay
         on the shared rail. */
      margin-block: 0;
      padding-block: var(--space-3) var(--space-1);
      margin-inline: calc(-1 * var(--space-2));
      padding-inline: var(--space-2);
    }

    /* The first heading still needs no air above it, and now that the air is
       padding the base rule's margin reset no longer reaches it. */
    .wstudy__family:first-child > .wstudy__family-title {
      padding-block-start: 0;
    }

    @media (forced-colors: active) {
      .wstudy__family-title { background: Canvas; }
    }
  }
}

/* A way in for a recitation that has no verses to start from. Hidden in the
   markup and revealed by static/js/recitation.js only when the chosen reciter
   has no timings on this surah; the verse discs go dark at the same moment, so
   there is exactly one control offering exactly what it can do. Marked with a
   ring rather than a fill, like everything else that is merely available. */
.surahplay {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-1);
  margin: 0 0 var(--space-3);
  text-align: center;
}

/* Paired with the display above, and not optional. The hidden attribute is
   display: none in the user agent sheet, and ANY author rule that sets display
   beats it whatever its specificity, so a flex container with hidden on it
   stays on screen. Without this the banner showed under every voice including
   the timed ones, which said the opposite of the truth. Every other togglable
   block here carries the same pair; see .qs-row[hidden] and .wbw-panel[hidden]. */
.surahplay[hidden] { display: none; }

.surahplay__button {
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  font: inherit;
  font-size: var(--fs-body-sm);
  padding: var(--space-1) var(--space-3);
  color: var(--ink);
  background: none;
  border: 1px solid var(--rule);
  border-radius: 2rem;
  cursor: pointer;
}

.surahplay__button:hover,
.surahplay__button:focus-visible {
  box-shadow: inset 0 0 0 1px currentColor;
}

.surahplay__note {
  font-size: var(--fs-body-sm);
  color: var(--ink-soft);
  /* Narrower than the reading measure on purpose: it is a note under a
     control, and a line as long as the verses would read as body text. */
  max-width: 26rem;
  text-wrap: balance;
}

/* The word beside the mark. A bare multiplication sign is only a close
   button to someone who already knows the convention; the three panes now
   say it. The aria-label still names WHICH panel and begins with "Close",
   so the visible text is contained in the accessible name. */
.tafsir__close-label,
.reflections__close-label,
.wstudy__close-label,
.lectures__close-label,
.hadith__close-label {
  font-family: var(--font-sans);
  font-size: var(--fs-body-sm);
}

.tafsir__close,
.reflections__close,
.wstudy__close,
.lectures__close,
.hadith__close {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  inline-size: auto;
  min-inline-size: 0;
  padding-inline: var(--space-3);
}


/* ----------------------------------------------------------------------------
   21. The video lectures panel

   The fourth panel to take the right half, and for now the one with nothing in
   it: no lecture is registered anywhere yet, so it opens on a sentence saying
   so. It exists this early because the study shelf in section 9 is what is
   being designed, and a category that will arrive shortly is what proves the
   shelf holds four rather than three.

   THE SHELL IS REPEATED FOR THE FOURTH TIME
   Section 18 said the panel after reflections would be the third client and
   the moment to extract a common shell. Word study came instead and repeated
   it, and this is the fourth copy. The debt is real and is not paid here: a
   base class now means reworking three shipped panels to serve a stub, and the
   stub is the one client whose requirements are still unknown. When this panel
   gets real content -- a list, a player, whatever the recordings turn out to
   need -- that is the moment, and by then there will be a fourth set of actual
   requirements to design the base against rather than three and a guess.

   Nothing here is load-bearing in the way section 18's visibility rules are.
   That panel holds a cross-origin iframe whose scroll offset cannot be read
   back, so its views may never be display:none. This one holds two paragraphs.
   ------------------------------------------------------------------------- */
.lectures {
  position: fixed;
  inset: 0;
  z-index: 94;
  pointer-events: none;
}

body.lectures-open { overflow: hidden; }

.lectures__scrim {
  position: absolute;
  inset: 0;
  background: var(--paper-sunk);
  opacity: 0;
  transition: opacity var(--dur-slow) var(--ease-calm);
}

.lectures.is-open .lectures__scrim {
  opacity: 0.92;
  pointer-events: auto;
}

.lectures__panel {
  position: absolute;
  inset-block-start: var(--space-7);
  inset-block-end: 0;
  inset-inline-end: 0;
  inline-size: 100%;
  display: flex;
  flex-direction: column;
  background: var(--paper);
  border-block-start: var(--hair) solid var(--rule);
  box-shadow: var(--shadow-soft);
  pointer-events: auto;
  visibility: hidden;
  transform: translateY(101%);
  transition: transform var(--dur-slow) var(--ease-calm),
              visibility 0s linear var(--dur-slow);
}

.lectures.is-open .lectures__panel {
  visibility: visible;
  transform: none;
  transition: transform var(--dur-slow) var(--ease-calm),
              visibility 0s;
}

.lectures__bar {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex: none;
  min-block-size: var(--panel-bar-min, 44px);
  padding-inline: var(--space-3);
  border-block-end: var(--hair) solid var(--rule);
  background: var(--paper-raised);
}

/* THE PANEL'S NAMEPLATE, and the same object as the commentary strip's chosen
   tab and the word study strip's: the topmost row of the panel says what the
   panel is, in one treatment, in all four. It was a line of bold text here and
   a filled tab there, which read as two different kinds of thing occupying the
   same slot.

   Not a control and never has been -- there is one view, so there is nothing
   to choose between -- but it wears the chosen tab's fill because that is what
   this position means in this app, and a reader who has learned it in the
   commentary panel should not have to learn it again here. `.wstudy__tab` made
   the same call, in a span, for the same reason.

   `flex: none` and the slack pushed after it: as a stretched item its fill ran
   the width of the bar, which is a banner rather than a nameplate, and the
   ring it takes when the panel opens and moves focus here ran the width too.
   Back and Close still sit at the ends of the bar, which is the promise the
   old rule was written to keep. */
.lectures__heading {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  flex: none;
  margin: 0;
  margin-inline-end: auto;
  min-block-size: 44px;
  padding-inline: var(--space-3);
  border-block-end: var(--emph) solid var(--accent);
  border-start-start-radius: var(--radius-control);
  border-start-end-radius: var(--radius-control);
  background: var(--accent-tint);
  overflow: hidden;
  font-family: var(--font-sans);
  font-size: var(--fs-body-sm);
  font-weight: 600;
  white-space: nowrap;
  text-overflow: ellipsis;
  color: var(--accent-strong);
}

/* The mark this kind wears everywhere else it is offered -- under a verse and
   in the surah bar -- at the nameplate's size. It names nothing on its own and
   is hidden from the accessible tree; the word beside it is the name. */
.lectures__heading__icon {
  flex: none;
}

/* Focused when the panel opens, so a screen reader lands on the panel's name
   rather than wherever the click left it. It is not a control and must not
   wear a control's ring when it is reached that way. */
.lectures__heading:focus { outline: none; }
.lectures__heading:focus-visible { outline: var(--focus-width) solid var(--accent); }

.lectures__close {
  flex: none;
  min-block-size: 36px;
  border: 0;
  border-radius: var(--radius-control);
  background: none;
  color: var(--ink-soft);
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  cursor: pointer;
}

/* The opener out in the surah bar, on exactly the terms section 18 sets out for
   the reflections one: it wears .surahtoc__trigger and inherits that display,
   which outranks the user agent's [hidden] rule, so without this the button
   stands in the bar for a reader who has no JavaScript to open the panel with.
   test_every_hidden_block_that_styles_display_also_hides_itself caught this the
   moment the button was added, which is the second time in one day that an
   author display rule quietly beat [hidden] -- see .cite[hidden] in section 9. */
.lectures__open[hidden] { display: none; }

.lectures__body {
  flex: 1 1 auto;
  min-block-size: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: var(--space-5) var(--space-4) var(--space-6);
}

/* Which verse this is about, in the panel's own eyebrow style: a label, so
   ink-soft and not accent. Section 20 made the same correction for the same
   reason -- accent in a panel means only that a thing can be pressed. */
.lectures__ref {
  margin: 0 0 var(--space-3);
  font-family: var(--font-sans);
  font-size: var(--fs-label);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

.lectures__soon {
  margin: 0 0 var(--space-3);
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  color: var(--ink);
}

.lectures__note {
  margin: 0;
  max-width: 34rem;
  font-family: var(--font-sans);
  font-size: var(--fs-body-sm);
  line-height: 1.6;
  color: var(--ink-soft);
}

/* How much is in the panel, said before the list rather than discovered by
   scrolling it: al-Baqarah holds 221 talks from fifteen teachers. */
.lectures__count {
  margin: 0 0 var(--space-4);
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  color: var(--ink);
}

/* One row per lecturer, closed. The hairline between them is what separates
   two series at a glance; a card would box every one of the fifteen on
   al-Baqarah and turn the panel into a stack of containers. */
.lectures__series + .lectures__series {
  border-block-start: var(--hair) solid var(--rule);
}

/* The row that opens a series. A grid and not a flex row so the name, the
   count and the span hold their columns down the list and the eye can run
   straight down any one of them. */
.lectures__speaker {
  display: grid;
  grid-template-columns: 1.4rem 1fr auto;
  gap: 0 var(--space-2);
  align-items: baseline;
  padding: var(--space-3) var(--space-2);
  min-block-size: 44px;
  cursor: pointer;
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  color: var(--ink);
  list-style: none;
  transition: background-color var(--dur-fast) var(--ease-calm);
}

/* Safari still paints its own triangle without this, beside the one below. */
.lectures__speaker::-webkit-details-marker { display: none; }

.lectures__speaker:hover { background: var(--paper-sunk); }

.lectures__speaker:focus { outline: none; }

.lectures__speaker:focus-visible {
  outline: var(--focus-width) solid var(--accent);
  outline-offset: -2px;
}

/* The one thing on the row that says it can be pressed, so it carries the
   accent: that is what the accent marks in this project. Drawn rather than
   typed, because the guillemet and the triangle both sit off the baseline at
   this size and neither can be nudged reliably across the three platforms. */
.lectures__marker {
  inline-size: 0.46rem;
  block-size: 0.46rem;
  align-self: center;
  justify-self: center;
  /* Nudged back onto the optical centre: a chevron rotated about its own box
     hangs left of where the eye puts it. */
  margin-inline-start: -0.12rem;
  border-inline-end: 2.5px solid var(--accent);
  border-block-end: 2.5px solid var(--accent);
  transform: rotate(-45deg);
  transform-origin: center;
  transition: transform var(--dur-fast) var(--ease-calm);
}

.lectures__series[open] .lectures__marker { transform: rotate(45deg); }

.lectures__name { font-weight: 600; }

/* The name follows the marker into the accent on hover, so the whole row reads
   as one control rather than as a chevron beside some text. */
.lectures__speaker:hover .lectures__name { color: var(--accent); }

@media (prefers-reduced-motion: reduce) {
  .lectures__marker { transition: none; }
}

/* The count and the span never carry the accent: in this project the accent
   marks what can be pressed, and these are labels on a row that is itself the
   control. */
.lectures__tally {
  font-size: var(--fs-body-sm);
  color: var(--ink-soft);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* THE FACE COLUMN
   A fourth column, and only on a panel that has faces to put in it. The row is
   a grid, so a column the template leaves unfilled is not a blank gutter -- it
   is a column the name slides left into. With QURAN_LECTURER_PORTRAITS off the
   body carries no modifier, the template draws no cell, and the row is exactly
   the three columns it shipped as.

   The portrait is 34px because that is the largest disc that keeps the row on
   the 44px minimum it already had: bigger and every row in the list grows, and
   al-Baqarah's fifteen lecturers push the talks below the fold. */
.lectures__body--faces .lectures__speaker {
  grid-template-columns: 1.4rem 2.125rem 1fr auto;
}

.lectures__body--faces .lectures__span { grid-column: 3 / -1; }

.lectures__face {
  inline-size: 2.125rem;
  block-size: 2.125rem;
  /* The row is baseline-aligned so its three text cells sit on one line. A
     circle has no baseline worth aligning and drops below the row when it is
     asked for one. */
  align-self: center;
  border-radius: 50%;
  /* Their originals are 4:3, 3:4 and square, and the crop to a square happens
     in scripts/fetch_lecturer_portraits.py rather than here. This is the guard
     for the day one arrives that is not square: cover crops, where the default
     would squash a face. */
  object-fit: cover;
  /* A hairline and not a shadow. Several of these portraits have pale or blown
     backgrounds and dissolve into the paper without an edge; a ring states the
     edge without adding a second treatment to a row that already has one.
     --paper-sunk shows through before the image decodes, so a slow load is a
     quiet disc rather than a hole in the list. */
  border: var(--hair) solid var(--rule);
  background: var(--paper-sunk);
}

/* Fourteen of the forty-eight lecturers are published by nobody with a
   photograph. Their initials, in the same circle at the same size, so the
   column stays even and an absent portrait reads as a person rather than as a
   missing file. services/lectures.py takes the letters, and takes the honorific
   off first: sixteen of these names begin "Shaykh" and nine begin "Dr.", and
   left on, half the discs in the panel would read alike. */
.lectures__face--mono {
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-sans);
  font-size: var(--fs-body-sm);
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--ink-soft);
  /* Never --accent, on hover or otherwise. In this project the accent marks
     what can be pressed; the chevron carries it for this row and the name
     follows it. A face is not a second control. */
}

/* Under the name and in its column, never under the marker: the marker's
   column is the gutter that makes the list read as a list. */
.lectures__span {
  grid-column: 2 / -1;
  margin-block-start: 0.15rem;
  font-size: var(--fs-body-sm);
  color: var(--ink-soft);
  font-variant-numeric: tabular-nums;
}

/* The talks, indented into the marker's gutter so the list reads as belonging
   to the lecturer above it rather than as a continuation of the panel. The
   rule down the left is the thread back to that name, which matters on the
   long series: Bahmanpour's 121 talks on al-Baqarah scroll well past it. */
.lectures__items {
  margin: 0 0 var(--space-3) 1.4rem;
  padding: 0 0 0 var(--space-2);
  border-inline-start: var(--hair) solid var(--rule);
  list-style: none;
}

.lectures__item + .lectures__item { margin-block-start: var(--space-1); }

/* The whole row is the target, on the same terms as .reflections__article:
   a series is scanned quickly and a link the width of its title is a small
   thing to hit on a phone. */
/* One line per lecture: what it is on the left, what it covers on the right.
   The whole row is the target, on the same terms as .reflections__article -- a
   series is scanned quickly and a link the width of its title is a small thing
   to hit on a phone. */
.lectures__link {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 0 var(--space-3);
  align-items: baseline;
  padding: 0.45rem var(--space-2);
  border-radius: var(--radius-control);
  text-decoration: none;
  color: inherit;
}

.lectures__link:hover { background: var(--paper-sunk); }

.lectures__link:focus { outline: none; }

.lectures__link:focus-visible {
  outline: var(--focus-width) solid var(--accent);
  outline-offset: 2px;
}

.lectures__title {
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  line-height: 1.4;
  color: var(--accent);
}

/* The range column. Right-aligned so the numbers stack into a column the eye
   can run down, which is the whole reason it is a column and not a second
   line. */
.lectures__covers {
  font-family: var(--font-sans);
  font-size: var(--fs-body-sm);
  color: var(--ink-soft);
  font-variant-numeric: tabular-nums;
  text-align: end;
  white-space: nowrap;
}

/* Below the split the panel is a full-width sheet on a phone, where a long
   caption and a range cannot share a line. */
@media (max-width: 32rem) {
  .lectures__link { grid-template-columns: 1fr; }
  .lectures__covers { text-align: start; margin-block-start: 0.1rem; }
}

/* The split, on the same terms as sections 13 and 18 and at the same 62rem,
   and in its own copy of the query for the reason section 18 gives at length:
   this section sits below section 17, so a rule declared up there would lose
   to these base rules and the panel would come out full width while <body>
   was already padded into half the viewport. */
@media (min-width: 62rem) {
  body.lectures-open {
    padding-inline-end: var(--qs-panew, 50vw);
    overflow: visible;
    /* How much page there is left, which is not 100vw once a panel
       has taken half of it. Read by anything that drops out of the
       masthead: those are anchored inside this padding and cannot
       see it. Unset when no panel is open, and the fallback at each
       reader is the whole window, which is what it was. */
    --qs-pagew: calc(100vw - var(--qs-panew, 50vw));
  }

  /* Back under the masthead, whose controls stay reachable beside a split. */
  .lectures { z-index: 90; }

  .lectures__panel {
    inline-size: var(--qs-panew, 50vw);
    inset-block-start: 0;
    transform: translateX(101%);
    border-block-start: 0;
    border-inline-start: var(--hair) solid var(--rule);
  }

  /* No veil beside a split: the half that is not the panel stays live. */
  .lectures__scrim { display: none; }
}


/* ----------------------------------------------------------------------------
   22. The hadith panel

   The fifth panel to take the right half, and the first that answers a question
   about a verse and a question about the surah in the same list. Two doors lead
   here: the entry on a verse's study shelf, which narrows the list to that
   verse, and the button in the surah bar, which opens it whole.

   NARROWING, NOT PINNING, AND WHY THE DIFFERENCE IS STRUCTURAL
   Section 18's panel answers the same pair of questions by MOVING rows: those
   covering the reader's verse are lifted into a pinned section and the rest sit
   below. That works there because its list is flat. This list is grouped by the
   book each narration sits in, and the grouping is the substance -- a reader
   looks for a narration by knowing al-Kafi, or Nahj al-Balagha -- so a row
   lifted out of its book loses the one fact it most needed to carry. So nothing
   moves here. Rows that do not cite the verse take [hidden], books left holding
   none take it too, and one control puts them all back. Every rule below that
   concerns narrowing is therefore a plain [hidden], with no visibility dance:
   unlike section 18 this panel holds no cross-origin iframe whose scroll offset
   would be lost to display:none.

   THE SHELL IS REPEATED FOR THE FIFTH TIME
   Section 18 named the third panel as the moment to extract a common shell;
   word study was the third, this is the fifth, and the debt has now outlived
   three chances to say no to it. It is still not paid in this section, and the
   reason is unchanged and getting weaker: a base now means reworking four
   shipped panels, tafsir's tab and fetch machinery among them, inside the
   commit that introduces a sixth thing to test. PROJECT_BRAIN.md carries it as
   named debt with an owner rather than as a note that keeps being deferred.
   ------------------------------------------------------------------------- */
.hadith {
  position: fixed;
  inset: 0;
  z-index: 94;
  pointer-events: none;
}

body.hadith-open { overflow: hidden; }

.hadith__scrim {
  position: absolute;
  inset: 0;
  background: var(--paper-sunk);
  opacity: 0;
  transition: opacity var(--dur-slow) var(--ease-calm);
}

.hadith.is-open .hadith__scrim {
  opacity: 0.92;
  pointer-events: auto;
}

.hadith__panel {
  position: absolute;
  inset-block-start: var(--space-7);
  inset-block-end: 0;
  inset-inline-end: 0;
  inline-size: 100%;
  display: flex;
  flex-direction: column;
  background: var(--paper);
  border-block-start: var(--hair) solid var(--rule);
  box-shadow: var(--shadow-soft);
  pointer-events: auto;
  visibility: hidden;
  transform: translateY(101%);
  transition: transform var(--dur-slow) var(--ease-calm),
              visibility 0s linear var(--dur-slow);
}

.hadith.is-open .hadith__panel {
  visibility: visible;
  transform: none;
  transition: transform var(--dur-slow) var(--ease-calm),
              visibility 0s;
}

.hadith__bar {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex: none;
  min-block-size: var(--panel-bar-min, 44px);
  padding-inline: var(--space-3);
  border-block-end: var(--hair) solid var(--rule);
  background: var(--paper-raised);
}

/* The nameplate, on exactly the terms section 21 sets out: the topmost row of
   a panel says what the panel is, in one treatment, in all five. */
.hadith__heading {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  flex: none;
  margin: 0;
  margin-inline-end: auto;
  min-block-size: 44px;
  padding-inline: var(--space-3);
  border-block-end: var(--emph) solid var(--accent);
  border-start-start-radius: var(--radius-control);
  border-start-end-radius: var(--radius-control);
  background: var(--accent-tint);
  overflow: hidden;
  font-family: var(--font-sans);
  font-size: var(--fs-body-sm);
  font-weight: 600;
  white-space: nowrap;
  text-overflow: ellipsis;
  color: var(--accent-strong);
}

/* The mark this kind wears everywhere else it is offered -- under a verse and
   in the surah bar -- at the nameplate's size. Decorative in all three. */
.hadith__icon { flex: none; }

/* Focused when the panel opens, so a screen reader lands on the panel's name.
   It is not a control and must not wear a control's ring when reached that
   way. */
.hadith__heading:focus { outline: none; }
.hadith__heading:focus-visible { outline: var(--focus-width) solid var(--accent); }

.hadith__close {
  flex: none;
  min-block-size: 36px;
  border: 0;
  border-radius: var(--radius-control);
  background: none;
  color: var(--ink-soft);
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  cursor: pointer;
}

/* The opener out in the surah bar, on the terms sections 18 and 21 both set
   out: it wears .surahtoc__trigger and inherits that display, which outranks
   the user agent's [hidden] rule, so without this the button stands in the bar
   for a reader who has no JavaScript to open the panel with. */
.hadith__open[hidden] { display: none; }

.hadith__body {
  flex: 1 1 auto;
  min-block-size: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: var(--space-5) var(--space-4) var(--space-6);
  /* A QUERY CONTAINER, so an opened narration measures the PANE and not the
     window. The recorded trap, from the word study panel and from the resize
     work: a reader on a 27-inch monitor can drag this pane down to a third of
     it, and a width media query would still read 2560px and lay two columns
     into 400. The panel's own floor is 38rem and nothing here may assume more.
     Named rather than anonymous so a future container inside it cannot capture
     these queries by accident. */
  container-type: inline-size;
  container-name: hadith-pane;
}

/* Which surah, and which verse when the reader came from one. An eyebrow: a
   label, so ink-soft and not accent, because accent in a panel means only that
   a thing can be pressed. */
.hadith__ref {
  margin: 0 0 var(--space-3);
  font-family: var(--font-sans);
  font-size: var(--fs-label);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

/* How much is in the panel, said before the list rather than discovered by
   scrolling it: al-Baqarah holds 403 narrations from 21 books. Rewritten by
   the script when the list narrows, so the sentence always describes the list
   under it. */
.hadith__count {
  margin: 0 0 var(--space-4);
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  color: var(--ink);
}

/* THE TWO DOORS. Two buttons that change how the same narrations are listed,
   so they are pressables and carry the accent when chosen -- the active one
   takes a SOLID accent fill with --paper text, which is how this project marks
   a chosen row and never a tint or a leading stripe. Hidden while the list is
   narrowed, when there is nothing left to re-sort. */
.hadith__doors {
  display: flex;
  gap: var(--space-1);
  margin: 0 0 var(--space-4);
}

.hadith__doors[hidden] { display: none; }

.hadith__door {
  min-block-size: 44px;
  padding-inline: var(--space-3);
  border: var(--hair) solid var(--rule-strong);
  border-radius: var(--radius-control);
  background: none;
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: var(--fs-body-sm);
  cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease-calm);
}

.hadith__door:hover { background: var(--paper-sunk); }

.hadith__door[aria-pressed="true"] {
  border-color: var(--accent);
  background: var(--accent);
  color: var(--paper);
}

.hadith__door:focus { outline: none; }

.hadith__door:focus-visible {
  outline: var(--focus-width) solid var(--accent);
  outline-offset: 2px;
}

/* The verse door's own list. */
.hadith__grid[hidden] { display: none; }

.hadith__gridnote {
  margin: 0 0 var(--space-3);
  font-family: var(--font-sans);
  font-size: var(--fs-body-sm);
  color: var(--ink-soft);
}

/* A grid and not a column, which is the entire reason this door exists:
   al-Baqarah is cited on 147 verses, and 147 disclosure rows would be a longer
   list than the one being made scannable. Laid out by auto-fill so the same
   rule serves a half-viewport split and a phone sheet, and the gaps in the
   sequence are themselves information -- they show where the surah is not
   cited. */
.hadith__chips {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(4.4rem, 1fr));
  gap: var(--space-1);
  margin: 0 0 var(--space-4);
  padding: 0;
  list-style: none;
}

/* The verse number leads and the count follows it, quieter and smaller: the
   number is what the reader is looking for and the count is why they might
   stop. Both in tabular figures so the columns line up down the grid. */
/* A verse that IS cited. The light fill is the map's ink: see the template for
   why a tint is right here and still wrong for marking a chosen thing. */
.hadith__chip {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 0.35em;
  inline-size: 100%;
  min-block-size: 44px;
  padding-inline: var(--space-1);
  border: var(--hair) solid var(--rule);
  border-radius: var(--radius-control);
  background: var(--accent-tint);
  cursor: pointer;
  font-family: var(--font-sans);
  font-variant-numeric: tabular-nums;
  transition: background-color var(--dur-fast) var(--ease-calm);
}

/* Hover has to beat a chip that is already filled, so it deepens the fill
   rather than introducing one. */
.hadith__chip:hover {
  border-color: var(--accent);
  background: var(--accent);
}

.hadith__chip:hover .hadith__chipverse,
.hadith__chip:hover .hadith__chipcount { color: var(--paper); }

.hadith__chip:hover .hadith__chipcount { border-color: var(--paper); }

/* A verse nothing cites. It holds its place so the runs and the gaps are
   legible as shape, and it is quiet enough that the filled chips are what the
   eye lands on. No border and no fill: an outline here would draw 139 boxes
   around nothing and the map would read as a grid of cells rather than as
   coverage. */
.hadith__gap {
  display: flex;
  align-items: center;
  justify-content: center;
  min-block-size: 44px;
  font-family: var(--font-sans);
  font-size: var(--fs-body-sm);
  font-variant-numeric: tabular-nums;
  color: var(--ink-faint);
}

/* Under forced colours an author background is discarded, so the one thing
   this grid means -- cited against not -- would vanish. Restated in the system
   palette, where the filled chips keep a border the gaps do not have. */
@media (forced-colors: active) {
  .hadith__chip {
    border: 1px solid CanvasText;
    forced-color-adjust: none;
    background: Canvas;
  }
  .hadith__chip:hover { background: Highlight; }
  .hadith__chip:hover .hadith__chipverse,
  .hadith__chip:hover .hadith__chipcount { color: HighlightText; }
  .hadith__gap { border: 0; color: GrayText; }
}

.hadith__chip:focus { outline: none; }

.hadith__chip:focus-visible {
  outline: var(--focus-width) solid var(--accent);
  outline-offset: 2px;
}

.hadith__chipverse {
  font-size: var(--fs-body);
  color: var(--accent);
}

/* Rendered only where a verse is cited more than once; see the template. A
   pill rather than a bare numeral, so the one place two numbers do sit side by
   side they cannot be read as one -- the same badge the study shelf's own
   counts wear. */
.hadith__chipcount {
  padding-inline: 0.4em;
  border: var(--hair) solid var(--rule-strong);
  border-radius: var(--radius-pill);
  font-size: var(--fs-label);
  color: var(--ink-soft);
}

.hadith__booklist[hidden] { display: none; }

/* The way back out of a narrowed list. A real button and not a link: it
   changes what this panel shows and goes nowhere. */
.hadith__widen { margin: 0 0 var(--space-4); }

.hadith__widen button {
  min-block-size: 44px;
  padding-inline: var(--space-3);
  border: var(--hair) solid var(--rule-strong);
  border-radius: var(--radius-control);
  background: none;
  color: var(--accent-strong);
  font-family: var(--font-sans);
  font-size: var(--fs-body-sm);
  cursor: pointer;
  transition: background-color var(--dur) var(--ease-calm);
}

.hadith__widen button:hover { background: var(--accent-tint); }

.hadith__widen button:focus { outline: none; }

.hadith__widen button:focus-visible {
  outline: var(--focus-width) solid var(--accent);
  outline-offset: 2px;
}

.hadith__widen[hidden] { display: none; }

.hadith__empty {
  margin: 0 0 var(--space-4);
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  color: var(--ink-soft);
}

.hadith__empty[hidden] { display: none; }

.hadith__note {
  margin: var(--space-4) 0 0;
  max-width: 34rem;
  font-family: var(--font-sans);
  font-size: var(--fs-body-sm);
  line-height: 1.6;
  color: var(--ink-soft);
}

/* One row per book, closed. The hairline between them separates two
   collections at a glance; a card would box every one of al-Baqarah's 21 and
   turn the panel into a stack of containers. */
.hadith__book + .hadith__book {
  border-block-start: var(--hair) solid var(--rule);
}

/* A book the narrowed list left holding nothing. An author rule that sets
   display would outrank the user agent's [hidden], and this one does set it,
   so it says so -- the same correction .cite[hidden] makes in section 9. */
.hadith__book[hidden] { display: none; }

/* The row that opens a book. A grid and not a flex row so the name, the count
   and the span hold their columns down the list. */
.hadith__booksummary {
  display: grid;
  grid-template-columns: 1.4rem 1fr auto;
  gap: 0 var(--space-2);
  align-items: baseline;
  padding: var(--space-3) var(--space-2);
  min-block-size: 44px;
  cursor: pointer;
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  color: var(--ink);
  list-style: none;
  transition: background-color var(--dur-fast) var(--ease-calm);
}

/* Safari still paints its own triangle without this, beside the one below. */
.hadith__booksummary::-webkit-details-marker { display: none; }

.hadith__booksummary:hover { background: var(--paper-sunk); }

.hadith__booksummary:focus { outline: none; }

.hadith__booksummary:focus-visible {
  outline: var(--focus-width) solid var(--accent);
  outline-offset: -2px;
}

/* The one thing on the row that says it can be pressed, so it carries the
   accent. Drawn rather than typed, for the reason section 21 gives. */
.hadith__marker {
  inline-size: 0.46rem;
  block-size: 0.46rem;
  align-self: center;
  justify-self: center;
  margin-inline-start: -0.12rem;
  border-inline-end: 2.5px solid var(--accent);
  border-block-end: 2.5px solid var(--accent);
  transform: rotate(-45deg);
  transform-origin: center;
  transition: transform var(--dur-fast) var(--ease-calm);
}

.hadith__book[open] .hadith__marker { transform: rotate(45deg); }

.hadith__name { font-weight: 600; }

/* The name follows the marker into the accent on hover, so the whole row reads
   as one control rather than a chevron beside some text. */
.hadith__booksummary:hover .hadith__name { color: var(--accent); }

@media (prefers-reduced-motion: reduce) {
  .hadith__marker { transition: none; }
}

/* Labels on a row that is itself the control, so never the accent. */
.hadith__tally {
  font-size: var(--fs-body-sm);
  color: var(--ink-soft);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* Under the name and in its column, never under the marker: the marker's
   column is the gutter that makes the list read as a list. */
.hadith__span {
  grid-column: 2 / -1;
  margin-block-start: 0.15rem;
  font-size: var(--fs-body-sm);
  color: var(--ink-soft);
  font-variant-numeric: tabular-nums;
}

/* The narrations, indented into the marker's gutter so the list reads as
   belonging to the book above it. The rule down the left is the thread back to
   that name, which matters where a book contributes many. */
.hadith__items {
  margin: 0 0 var(--space-3) 1.4rem;
  padding: 0 0 0 var(--space-2);
  border-inline-start: var(--hair) solid var(--rule);
  list-style: none;
}

.hadith__item + .hadith__item { margin-block-start: var(--space-1); }

/* A row the narrowed list is not showing. Sets display, so it hides itself for
   the same reason .hadith__book[hidden] does. */
.hadith__item[hidden] { display: none; }

/* One line per narration: what it is on the left, which verse on the right.
   The whole row is the target, on the same terms as .lectures__link. */
.hadith__link {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 0 var(--space-3);
  align-items: baseline;
  padding: 0.45rem var(--space-2);
  border-radius: var(--radius-control);
  text-decoration: none;
  color: inherit;
}

.hadith__link:hover { background: var(--paper-sunk); }

.hadith__link:focus { outline: none; }

.hadith__link:focus-visible {
  outline: var(--focus-width) solid var(--accent);
  outline-offset: 2px;
}

/* Their chapter headings are descriptive sentences and some run past two
   hundred characters, so the title is clamped rather than allowed to become a
   paragraph inside a list row. Three lines, because the useful part of a long
   heading is at its front and the rest is qualification. The whole heading is
   still on the page it opens. */
.hadith__title {
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  line-height: 1.4;
  color: var(--accent);
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  line-clamp: 3;
  overflow: hidden;
}

/* The verse column. Right-aligned so the numbers stack into a column the eye
   can run down, which is the whole reason it is a column and not a second
   line. */
.hadith__covers {
  font-family: var(--font-sans);
  font-size: var(--fs-body-sm);
  color: var(--ink-soft);
  font-variant-numeric: tabular-nums;
  text-align: end;
  white-space: nowrap;
}

/* Below the split the panel is a full-width sheet on a phone, where a long
   heading and a verse number cannot share a line. */
@media (max-width: 32rem) {
  .hadith__link { grid-template-columns: 1fr; }
  .hadith__covers { text-align: start; margin-block-start: 0.1rem; }
}

/* ---- an opened narration ---------------------------------------------------

   Where this machine holds the text a row is a <details> instead of a link, and
   the summary keeps the link's shape exactly: the same two columns, the same
   padding, the same clamp on the heading. A reader must not have to learn a new
   row because a file was copied onto the server.

   The publisher's own reading page is the model -- the chain of narration set
   quietly above the saying, and the two languages side by side. Two departures,
   both forced by where this lives:

     the columns   are a CONTAINER query, not a media query. Their page is a
                   full window; this is a pane a reader can drag narrow on a
                   wide screen, and two columns in 400px of pane would be two
                   ~200px columns of Arabic.

     the Arabic    is var(--font-arabic), never "Amiri Quran". That face carries
                   Qur'anic orthography and this is not the Qur'an -- a hadith
                   set in the mushaf's own hand would claim something about it
                   that nobody has claimed. The verse above it keeps that face
                   and the difference is the point. */
.hadith__narration {
  border-radius: var(--radius-control);
}

.hadith__summary {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 0 var(--space-3);
  align-items: baseline;
  padding: 0.45rem var(--space-2);
  border-radius: var(--radius-control);
  cursor: pointer;
  list-style: none;
}

.hadith__summary::-webkit-details-marker { display: none; }

.hadith__summary:hover { background: var(--paper-sunk); }

.hadith__summary:focus { outline: none; }

.hadith__summary:focus-visible {
  outline: var(--focus-width) solid var(--accent);
  outline-offset: 2px;
}

/* Open, the heading is the reader's place in a long panel and is no longer a
   thing to skim, so the clamp comes off and it is allowed its full length. */
.hadith__narration[open] > .hadith__summary { background: var(--paper-sunk); }

.hadith__narration[open] > .hadith__summary .hadith__title {
  -webkit-line-clamp: unset;
  line-clamp: unset;
  display: block;
}

.hadith__reading:not(:empty) {
  padding: var(--space-3) var(--space-2) var(--space-2);
}

/* Stacked by default, which is what a pane narrower than about 46rem gets --
   and what a phone gets, where the panel is a sheet. */
.hadith__side + .hadith__side { margin-block-start: var(--space-3); }

/* Who reported it. Quiet, because it is the route to the saying rather than
   the saying, and their page makes the same distinction the same way. */
.hadith__sanad {
  margin: 0 0 var(--space-2);
  font-family: var(--font-serif);
  font-size: var(--fs-body-sm);
  line-height: 1.65;
  color: var(--ink-soft);
}

.hadith__matn {
  margin: 0;
  font-family: var(--font-serif);
  font-size: var(--fs-body);
  line-height: 1.75;
  color: var(--ink);
}

.hadith__side--ar .hadith__sanad,
.hadith__side--ar .hadith__matn {
  font-family: var(--font-arabic);
  /* Arabic at the same nominal size reads smaller than Latin, and these are
     long paragraphs rather than the single line a verse chip carries. */
  font-size: calc(var(--fs-body) * 1.15);
  line-height: 2.1;
  text-align: start;
}

/* The control that brings the Arabic in, at the TOP of the reading rather than
   the foot: an English passage runs to fifteen lines here and a control below
   it is a control nobody finds. Right-aligned so it sits out of the way of the
   text's own left edge and reads as a tool rather than as a first line.

   Outlined and in the accent, which in this project means exactly one thing --
   this can be pressed. No fill: a filled control would mean a CHOSEN thing, and
   what is chosen here is said by the label rather than by paint. */
.hadith__controls {
  margin: 0 0 var(--space-3);
  display: flex;
  justify-content: flex-end;
}

.hadith__toggle {
  font-family: var(--font-sans);
  font-size: var(--fs-body-sm);
  color: var(--accent);
  background: none;
  border: var(--hair) solid var(--accent);
  border-radius: var(--radius-control);
  padding: 0.2rem 0.6rem;
  cursor: pointer;
  /* The label swaps between "Show Arabic" and "Hide Arabic", which are
     different widths, and a control that resizes as it is pressed makes the
     text under it jump. Sized for the longer of the two and left alone. */
  min-inline-size: 7.5rem;
}

.hadith__toggle:hover { background: var(--paper-sunk); }

.hadith__toggle:focus { outline: none; }

.hadith__toggle:focus-visible {
  outline: var(--focus-width) solid var(--accent);
  outline-offset: 2px;
}

/* WHERE THE QUR'AN IS INSIDE A NARRATION.

   The same mark the Dictionary & Grammar panel puts under a studied root and
   its words -- the accent as a 2px edge with the tint above it -- because it is
   the same claim in both places: THIS is the thing the panel is about. A reader
   who has used one panel already knows what the green means in the other.

   Two kinds wear one mark on purpose. The reference "(2:255)" and the verse
   quoted just before it are not two facts; they are one -- here is the Qur'an
   in this narration -- and giving them separate treatments would say there is a
   difference to notice when there is not.

   It is a <mark>, so the meaning survives without the colour: read aloud, or in
   forced colours, or by a reader who cannot tell the green from the ink, the
   element still says this text is set apart for reference.

   A quotation is only ever marked where our own translation of the cited verse
   agrees it is that verse -- services/hadith.py refuses the rest, because a
   narration quoting the IMAM and then citing a verse would otherwise wear the
   colour this project uses for revelation. */
.hadith__qref {
  /* A SOLID fill, not the studied word's 2px edge under a tint.

     The accent mark was the first cut and it was reported as hard to find,
     which is the ring's lesson from section 13 arriving again: what a mark in a
     wall of running text needs is AREA. A studied word sits alone in a panel
     with nothing competing; this phrase sits inside fifteen hundred words of
     somebody else's prose, and the eye has to catch it without being told where
     to look. So the whole run of text is filled rather than underlined, and the
     colour is the palette's one highlighter rather than its accent -- green is
     what this project uses for "you may press this", and nothing here is
     pressable. */
  background: var(--mark);
  color: var(--mark-ink);
  /* Half a step of weight. Not bold: at bold the marked words start to read as
     a heading inside the sentence they belong to. */
  font-weight: 500;
  border-radius: var(--radius-control);
  box-decoration-break: clone;
  -webkit-box-decoration-break: clone;
  padding-inline: 0.2em;
  padding-block: 0.05em;
}

/* Forced colours throw author backgrounds away, and the mark above is entirely
   background -- so without this the cited verse is indistinguishable from the
   prose around it. Restated from the system palette, on the same terms and for
   the same reason as the studied word in section 18. */
@media (forced-colors: active) {
  .hadith__qref {
    background: Highlight;
    color: HighlightText;
    forced-color-adjust: none;
  }
}

/* Whose English this is. Named on every narration and not once per panel: a
   collection can be translated by several hands, and the credit belongs beside
   the words it is credit for. */
.hadith__translator {
  margin: var(--space-3) 0 0;
  font-family: var(--font-sans);
  font-size: var(--fs-body-sm);
  color: var(--ink-soft);
}

.hadith__waiting,
.hadith__failed {
  margin: 0;
  font-family: var(--font-sans);
  font-size: var(--fs-body-sm);
  color: var(--ink-soft);
}

/* The way back to the source, on every row whether or not the text loaded. It
   is the whole rights position as much as it is a courtesy: what is shown here
   is somebody else's translation and the page it came from is one press away. */
.hadith__source {
  margin: var(--space-2) 0 0;
  padding-inline: var(--space-2);
  font-family: var(--font-sans);
  font-size: var(--fs-body-sm);
}

.hadith__source a { color: var(--accent); }

/* Side by side, once the PANE is genuinely wide enough for two columns of
   prose. 46rem and not the panel's 38rem floor: at 38 each column would be
   about 18rem, which is roughly 40 Latin characters a line and reads as a
   newspaper column rather than a page. Above it the Arabic takes the right,
   the English the left, exactly as their own page sets them. */
@container hadith-pane (min-width: 46rem) {
  /* is-bilingual, not :not(:empty): the Arabic is hidden until a reader asks
     for it, and splitting the pane in two while one half is empty would leave
     the English in a 22rem column beside 22rem of nothing. The class is set by
     hadith.js when the Arabic is actually on screen. */
  .hadith__reading.is-bilingual {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0 var(--space-5);
    align-items: start;
  }

  /* The control spans both columns and keeps ROW 1, where it was before the
     second column appeared. Explicit rows on all three, because placing only
     the two sides -- on row 1 -- left the control to be auto-placed onto row 2,
     which put the button that HIDES the Arabic below 1,800px of Arabic. A
     control must not move when it is pressed. Pinned in
     tests/test_browser_hadith.py. */
  .hadith__reading.is-bilingual .hadith__controls {
    grid-column: 1 / -1;
    grid-row: 1;
  }

  /* The English is first in the DOM, so a STACKED pane shows the translation
     before the Arabic -- see hadith.js. Side by side that would put Arabic on
     the left, so both sides are placed explicitly here instead: English left,
     Arabic right, which is the publisher's own arrangement. */
  .hadith__side--ar { grid-column: 2; grid-row: 2; }
  .hadith__side--en { grid-column: 1; grid-row: 2; }
  .hadith__side + .hadith__side { margin-block-start: 0; }

  .hadith__translator { grid-column: 1 / -1; grid-row: 3; }
}

/* The split, on the same terms as sections 13, 18 and 21 and at the same 62rem,
   and in its own copy of the query for the reason section 18 gives at length:
   this section sits below section 17, so a rule declared up there would lose to
   these base rules and the panel would come out full width while <body> was
   already padded into half the viewport. */
@media (min-width: 62rem) {
  body.hadith-open {
    padding-inline-end: var(--qs-panew, 50vw);
    overflow: visible;
    /* How much page there is left, which is not 100vw once a panel has taken
       half of it. Read by anything that drops out of the masthead. */
    --qs-pagew: calc(100vw - var(--qs-panew, 50vw));
  }

  /* Back under the masthead, whose controls stay reachable beside a split. */
  .hadith { z-index: 90; }

  .hadith__panel {
    inline-size: var(--qs-panew, 50vw);
    inset-block-start: 0;
    transform: translateX(101%);
    border-block-start: 0;
    border-inline-start: var(--hair) solid var(--rule);
  }

  /* No veil beside a split: the half that is not the panel stays live. */
  .hadith__scrim { display: none; }
}

/* ----------------------------------------------------------------------------
   23. The root page

   The word study instrument as a page, at /quran/root/<radicals>. Section 20
   builds it as a fixed overlay that arrives from an edge; here it is simply
   the document, so what these rules do is UNDO the overlay -- position, the
   transform it waits at, the visibility that hides it, the veil, the pushing
   of a page that is not there -- and nothing else. Every rule inside the panel
   is section 20's still, which is the point: there is one instrument.

   The narrow-sheet rules at the foot of section 20 already put the panel's
   internals into normal flow, and they are written against the pane rather
   than the window, so on a phone this page needs nothing of its own.
   ------------------------------------------------------------------------- */

.wstudy-page .wstudy {
  position: static;
  inset: auto;
  z-index: auto;
  pointer-events: auto;
}

/* A reading measure, not the monitor. The cascade is a column -- root, then
   derived forms, then the concordance -- and a 2560px line of KWIC rows is
   further than an eye tracks back. Wider than --measure because three bands
   sit side by side above the rows at this width, and section 20's own
   container query is what decides that; this is the width that lets it. */
.wstudy-page .wstudy__panel {
  position: static;
  inset: auto;
  inline-size: auto;
  max-inline-size: 68rem;
  margin-inline: auto;
  min-block-size: 60vh;
  /* The overlay's own hiding and arrival, both undone. Left in place, the
     panel would sit one screen below itself, invisible, on a page with
     nothing else in it. */
  visibility: visible;
  transform: none;
  transition: none;
  /* Hairlines on all four sides now that it is a card in a page rather than a
     pane against an edge. */
  border: var(--hair) solid var(--rule);
  border-radius: var(--radius);
  box-shadow: none;
}

/* THE PAGE SCROLLS AND THE PANE DOES NOT.

   Section 20's pane is position: absolute; inset: 0 inside a panel that is
   the window, which is right for an overlay and wrong for a document. Here it
   meant the pane contributed no height, so the panel came out at its 60vh
   floor whatever root was in it, everything below the tab strip scrolled
   inside that box, and the DOCUMENT never grew past one screen -- which is
   why the colophon stood at the foot of the window on every root and read as
   a fixed bar rather than as the end of a page. The corpus credit line, which
   is a licence condition, was below the fold of a scroller most readers had
   no reason to think was one.

   Undone the same way the rest of this section undoes the overlay: the pane
   is a block in normal flow, the panel is as tall as what is in it, and the
   page scrolls like every other page in this project. min-block-size on the
   panel above stays -- it is the floor the shell holds before the fetch
   lands, not a ceiling on anything.

   flex: none on the panes for the reason the sheet's own copy of this gives:
   1 1 auto against a panel with a 60vh floor would stretch the box and hang
   the cascade off the top of a taller-than-content pane. */
.wstudy-page .wstudy__panes {
  position: static;
  flex: none;
  min-block-size: 0;
}

.wstudy-page .wstudy__pane {
  position: static;
  block-size: auto;
  overflow: visible;
}

/* Below 62rem the sheet block makes .wstudy__scroll the one scroller. Same
   argument, same answer: on a page there is nothing above it to pin. */
.wstudy-page .wstudy__scroll { overflow: visible; }

/* THE TWO COLUMNS KEEP THEIR SCROLLERS, which is the whole point of the
   cascade -- the derived forms and the concordance are meant to be read
   against each other, and a root with 26 occurrences must not push the
   forms a screen away from them.

   What changes is where their height comes from. Section 22's chain ends in
   `.wstudy__dict { block-size: 100% }`, a share of a pane that was the
   window; with the pane in flow there is no such share to take, and 1fr in an
   auto-height grid resolves to max-content -- the exact failure that rule's
   own comment records, a 2617px column. So row 2 is content-sized and the
   ceiling moves onto the scrollers themselves, where it is a number rather
   than an inheritance.

   min(60vh, 32rem): 32rem is the reading height this page settles at on a
   laptop, and the vh term is what keeps it from filling a short window
   entirely. Stated once, for both columns, so the seam between them stays a
   straight line. A root with three forms and five verses spends less than
   either and the panel simply comes out shorter, which is the behaviour the
   fixed pane could never give. */
@media (min-width: 62rem) {
  @container wstudy-pane (min-width: 38rem) {
    .wstudy-page .wstudy__dict {
      block-size: auto;
      grid-template-rows: auto auto;
    }

    .wstudy-page .wstudy__band--word > .wstudy__bandbody,
    .wstudy-page .wstudy__band--verse > .wstudy__bandbody {
      max-block-size: min(60vh, 32rem);
    }
  }
}

/* The identity block above the instrument: the page's own subject, server
   rendered. Centred on the same measure the panel takes. */
.rootpage__inner {
  max-inline-size: 68rem;
  margin-inline: auto;
  padding-block: var(--space-5) var(--space-4);
}

/* The subject and its count on ONE left-to-right line, root first.

   The heading is dir="rtl" and has to be -- three Arabic radicals -- but a
   block-level rtl heading also takes rtl's ALIGNMENT, which parked the root
   at the far right of a page whose every other line starts at the left. As
   flex items both boxes shrink to their contents and sit at the start edge in
   markup order, so the direction of the letters and the direction of the page
   stop being the same decision.

   Baselines, not centres: the count is 0.88rem beside a 1.85rem heading, and
   centring two type sizes leaves neither sitting on a line. wrap so a long
   count drops under the root on a phone rather than squeezing it. */
.rootpage__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-1) var(--space-4);
  margin-block-start: var(--space-1);
}

.rootpage__title {
  margin: 0;
  font-family: "Amiri Quran", var(--font-arabic);
  font-size: var(--fs-h1);
  /* Amiri Quran's own line box is nearly twice its font size, so the figure
     is stated here for the reason the root walk states it: pointed Arabic
     needs room above the letters and nothing like that much. */
  line-height: 1.5;
  color: var(--ink);
}

.rootpage__count {
  margin: 0;
  font-family: var(--font-sans);
  font-size: var(--fs-body-sm);
  color: var(--ink-soft);
}

.rootpage__lane {
  margin: var(--space-3) 0 0;
  max-inline-size: var(--measure);
  color: var(--ink-soft);
}

.rootpage__provenance,
.rootpage__noscript {
  margin: var(--space-1) 0 0;
  max-inline-size: var(--measure);
  font-family: var(--font-sans);
  font-size: var(--fs-caption);
  color: var(--ink-faint);
}


/* --- the name, shed against whatever shares its row ----------------------- */

/* The surah page has two rows to answer for and they have different budgets,
   so it has two rungs rather than the one blanket number this shipped with on
   2026-08-25. SUPERSEDES that number for these pages; base.css section 24
   records why one rung could not serve three rows.

   The single-row rung is WRAPPED IN THE 62rem MEDIA QUERY, which is not
   decoration: whether this page draws a field at all is a viewport decision,
   not a bar one, and without the wrapper the rung shed the name at 640 to
   700px of window -- where there is no field on the row for it to be competing
   with. Caught by the probe, not by reasoning.

   SINGLE ROW, 40rem to 45rem. Above 40rem of bar this page draws a field, and
   the name then has to share the row with it and with a 178px actions cluster.
   143 + 24 + 276 + 24 + 178 needs 645px of inner, a 709px bar, so between the
   restack and 45rem the name is what gives. This is the only band on the site
   where it still does, and it is reachable only with a panel open -- at a
   1400px window with the seam at the half the bar is 700px and lands in it.
   The field is kept and the words go, rather than the reverse, because the
   words have a mark standing in for them that still links home and still
   carries the accessible name, and the field has nothing standing in for it.

   The stacked rung is .quran-surah and not .quran. The index has no actions
   at all, so its row one carries the wordmark and nothing else and 143px fits
   in the 280px of inner a 320px screen gives -- it keeps its name at every
   width it is ever drawn at.

   STACKED, below 25rem. With no field on the row the name competes only with
   All surahs and Display: 143 + 24 + 178 needs 345px of inner, a 385px bar at
   the phone's 20px gutter. 25rem is 400px. Below it the mark stands alone,
   which is the 2026-08-20 measurement that first put this rule here -- 321px
   of wordmark and actions in a 320px row spilled 5px and scrolled the whole
   document sideways. That case is unchanged; what changed is that it stopped
   being applied 240px too early. */
@media (min-width: 62rem) {
@container masthead (min-width: 40rem) and (max-width: 44.999rem) {
  .quran-surah .wordmark__text {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
  }
}
}

@container masthead (max-width: 24.999rem) {
  .quran-surah .wordmark__text {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
  }
}

/* The fallback for an engine with no container queries. It is the phone case
   only, which is the one that overflows a document if it is got wrong; every
   other rung above is a refinement an old engine can do without. */
@media (max-width: 24.999rem) {
  .quran-surah .wordmark__text {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
  }
}


/* ----------------------------------------------------------------------------
   24. The notebook panel

   The sixth panel to take the right half, and the first built after the shell
   was extracted. Its JAVASCRIPT half is panel-shell.js's -- the peers contract,
   the sheet below 62rem, the inerting, the place-holding, Escape, the history
   entry -- so what is repeated below is only the CSS.

   THAT REPETITION IS DELIBERATE AND THE DEBT IS STILL OPEN. Sections 18, 20,
   21 and 22 each carry their own copy of this block, and they are not
   interchangeable: the split rules must follow their own base rules, because a
   later base rule of equal specificity beats an earlier media block, and
   section 18's visibility rules are load-bearing in a way none of the others'
   are. Extracting five shipped sections of a 10,000-line stylesheet is its own
   piece of work with its own way of going wrong, and it was not taken in the
   same commit as a feature. The trigger is unchanged.

   WHAT IS DIFFERENT HERE. This is the only panel a reader WRITES in. That puts
   a textarea, and on a phone a keyboard, inside a sheet. The composer scrolls
   with the body rather than being pinned to the foot of the panel: a fixed
   footer above a virtual keyboard is the arrangement that goes wrong on iOS,
   and it goes wrong silently.

   WHAT IS RESTATED FROM static/css/notebook.css, and why that list keeps
   growing: it grew from the entry card to the whole rail-and-page layout on
   2026-08-29, and grew again on 2026-09-01 to the book itself. nbbook,
   nbhead, nbturn and nbfoot joined nbrail, nbpage, nbentry and nbwrite once
   the panel started wearing the same bound-book chrome the notebook's own
   pages wear -- a frame with a spine, a head band with its own steps, and a
   foot that will turn the page. The rail, the page, the sitting and the
   writing line are all written twice -- there in Jinja, here in DOM nodes --
   so a rule that drifts between the two copies shows up as the same object
   wearing two dresses on the two surfaces, which is precisely the fault the
   shared layout exists to remove. The pages load notebook.css and this page
   does not, which is the whole reason for the duplication and has not
   changed.
   ---------------------------------------------------------------------------- */
.notebook {
  position: fixed;
  inset: 0;
  z-index: 94;
  pointer-events: none;
}

body.notebook-open { overflow: hidden; }

.notebook__scrim {
  position: absolute;
  inset: 0;
  background: var(--paper-sunk);
  opacity: 0;
  transition: opacity var(--dur-slow) var(--ease-calm);
}

.notebook.is-open .notebook__scrim {
  opacity: 0.92;
  pointer-events: auto;
}

.notebook__panel {
  position: absolute;
  inset-block-start: var(--space-7);
  inset-block-end: 0;
  inset-inline-end: 0;
  inline-size: 100%;
  display: flex;
  flex-direction: column;
  background: var(--paper);
  border-block-start: var(--hair) solid var(--rule);
  box-shadow: var(--shadow-soft);
  pointer-events: auto;
  visibility: hidden;
  transform: translateY(101%);
  transition: transform var(--dur-slow) var(--ease-calm),
              visibility 0s linear var(--dur-slow);
}

.notebook.is-open .notebook__panel {
  visibility: visible;
  transform: none;
  transition: transform var(--dur-slow) var(--ease-calm),
              visibility 0s;
}

.notebook__bar {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex: none;
  min-block-size: var(--panel-bar-min, 44px);
  padding-inline: var(--space-3);
  border-block-end: var(--hair) solid var(--rule);
  background: var(--paper-raised);
}

/* The nameplate, the same object as the other five panels' -- the topmost row
   of a panel says what the panel is, in one treatment, everywhere. */
.notebook__heading {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin: 0;
  font-family: var(--font-sans);
  font-size: var(--fs-body-sm);
  font-weight: 600;
  letter-spacing: 0.01em;
  color: var(--ink);
}

.notebook__icon { flex: none; }

.notebook__close {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  margin-inline-start: auto;
  min-block-size: 44px;
  padding-inline: var(--space-2);
  font: inherit;
  font-size: var(--fs-body-sm);
  color: var(--ink-soft);
  background: none;
  border: 0;
  cursor: pointer;
}

.notebook__close:hover,
.notebook__close:focus-visible { color: var(--ink); }

.notebook__body {
  flex: 1;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: var(--space-4);
}

/* ---- the notebook, restated from static/css/notebook.css -----------------

   The notebook's own pages load that file and this page does not, so the
   book, the rail, the page and the sitting are written twice. Change one and
   change the other; the markup is built to one shape by two files -- Jinja
   there, DOM nodes here -- so a rule that drifts shows up as the same object
   wearing two dresses on the two surfaces, which is the fault the shared
   chrome exists to remove.

   THE PANEL FITS TWO PANES BY ARITHMETIC, not by hope. Above the split the
   pane cannot be dragged narrower than the 38rem floor panel-resize.js
   enforces. Below the split the panel is a full-width sheet. Either way the
   rail here lies DOWN -- a scrolling strip above the page rather than a column
   beside it -- because even half of a wide window is narrower than the page
   surface this layout was drawn for, and a 9rem column out of it would leave
   the note itself under the reading measure. The rail is the same control
   turned through ninety degrees, not a second one.

   THE SPINE SITS ON THE INLINE-START HERE, the mirror of the pages' own
   book. The mockup drew it there: the tabs are on the top edge in the panel
   rather than the fore-edge, so the binding side is free and left is where
   the approved drawing put it. */
.notebook .nbbook {
  display: block;
}

.notebook .nbbook__frame {
  display: flex;
  min-inline-size: 0;
  border: var(--hair) solid var(--rule);
  border-radius: var(--radius);
  background: var(--paper-raised);
  box-shadow: var(--shadow-soft);
  overflow: hidden;
}

.notebook .nbbook__col {
  flex: 1;
  min-inline-size: 0;
  display: flex;
  flex-direction: column;
}

.notebook .nbbook__spine {
  flex: none;
  inline-size: 10px;
  align-self: stretch;
  border-inline-end: var(--hair) solid var(--rule-soft);
  background-color: var(--paper-sunk);
  background-image: repeating-linear-gradient(to bottom,
      var(--rule-strong) 0 8px, transparent 8px 26px);
  background-size: 2px 100%;
  background-repeat: no-repeat;
  background-position: 4px 18px;
}

/* ---- the head band, restated from static/css/notebook.css ----------------

   Only the padding differs from the pages' own dress, shrunk to match the
   panel's own narrower body. THE TITLE ROW IS IDENTICAL to the pages' own,
   not a panel variant. A flex row with justify-content: space-between was
   tried here first and described as "left-set, steps right" -- it was
   neither: an absent step is still a zero-width flex child, so it still
   claims its edge in the space-between gap math and the title lands off
   centre, never left-set, and with BOTH steps absent (the case
   test_the_only_surah_written_on_gets_no_steps_at_all covers) it lands dead
   centre. The grid the pages already use holds the title in a centred column
   with each step owning an outer column whether or not it exists, which is
   correct for every combination of present/absent steps with no `order` hack
   to split visual order from focus order. Restating the pages' own rule here
   removes a divergence between the two copies rather than adding one, which
   is what this section's duplication is supposed to do. */
.notebook .nbhead {
  padding: var(--space-2) var(--space-4) 0;
  border-block-end: var(--hair) solid var(--rule-soft);
}

.notebook .nbhead__row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}

.notebook .nbhead__row--title {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
}

.notebook .nbhead__home {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-block-size: 44px;
  padding-inline: var(--space-2);
  margin-inline-start: calc(var(--space-2) * -1);
  border-radius: var(--radius-control);
  color: var(--accent-strong);
  font-family: var(--font-sans);
  font-size: var(--fs-caption);
  font-weight: 600;
  text-decoration: none;
  transition: background-color var(--dur-fast) var(--ease-calm);
}

.notebook .nbhead__home:hover { background: var(--accent-tint); }
.notebook .nbhead__mark { flex: none; color: var(--ink-faint); }
.notebook .nbhead__home:hover .nbhead__mark { color: var(--accent-strong); }

.notebook .nbhead__eyebrow {
  display: inline-flex;
  align-items: center;
  min-block-size: 44px;
  font-family: var(--font-sans);
  font-size: var(--fs-label);
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.notebook .nbhead__count {
  font-family: var(--font-sans);
  font-size: var(--fs-caption);
  color: var(--ink-faint);
}

.notebook .nbhead__title {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: var(--space-3);
  margin: 0;
  font-size: var(--fs-h2);
  line-height: var(--lh-heading);
}

.notebook .nbhead__arabic {
  font-family: var(--font-arabic);
  font-size: 1.55rem;
  line-height: 1.25;
  color: var(--ink);
}

.notebook .nbhead__slot { min-inline-size: 0; }
.notebook .nbhead__slot--next { justify-self: end; text-align: end; }

.notebook .nbhead__step {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-block-size: 44px;
  padding-inline: var(--space-2);
  border-radius: var(--radius-control);
  color: var(--ink-soft);
  font-family: var(--font-sans);
  text-decoration: none;
  transition: background-color var(--dur-fast) var(--ease-calm);
}

.notebook .nbhead__step:hover { background: var(--accent-wash); }

.notebook .nbhead__steptext { display: flex; flex-direction: column; gap: 1px; align-items: flex-start; }
.notebook .nbhead__step--next .nbhead__steptext { align-items: flex-end; }

.notebook .nbhead__dir {
  font-size: var(--fs-label);
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  line-height: var(--lh-tight);
  color: var(--ink-faint);
}

.notebook .nbhead__stepname { font-size: var(--fs-body-sm); color: var(--accent-strong); line-height: var(--lh-tight); }

/* ---- the fore-edge tabs, re-dressed as top-edge tabs for the panel --------

   The desktop rail beside the pages' own frame is a sticky column; the panel
   has no room for a column, so it wears the same top-edge tab dress the
   pages themselves fall back to below 46rem -- static rather than sticky,
   because the panel's body scrolls as a whole and there is no page column
   beside the rail for it to track. */
.notebook .nbrail {
  position: static;
  display: flex;
  align-items: flex-end;
  gap: var(--space-1);
  margin: 0;
  padding: var(--space-2) var(--space-4) 0;
  border-block-end: var(--hair) solid var(--rule);
  background: none;
  overflow-x: auto;
  scrollbar-width: none;
}

.notebook .nbrail::-webkit-scrollbar {
  display: none;
}

/* The eyebrow is a column head, and lying down there is no column. */
.notebook .nbrail__head {
  display: none;
}

.notebook .nbrail__page {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  flex: none;
  min-block-size: 44px;
  max-inline-size: 13rem;
  margin-block-end: -1px;
  padding-inline: var(--space-3);
  border: var(--hair) solid var(--rule);
  border-start-start-radius: var(--radius-control);
  border-start-end-radius: var(--radius-control);
  background: var(--paper-sunk);
  color: var(--ink-soft);
  font-family: var(--font-sans);
  font-size: var(--fs-body-sm);
  white-space: nowrap;
  cursor: pointer;
}

/* Hover SCOPED AWAY from the chosen row, or the pointer paints --paper text on
   a --paper ground and the row the reader is standing in vanishes under their
   own cursor. admin.css has paid for this once already. */
.notebook .nbrail__page:not(.is-active):hover,
.notebook .nbrail__page:not(.is-active):focus-visible {
  background: var(--paper-raised);
  color: var(--ink);
}

.notebook .nbrail__page.is-active {
  border-color: var(--accent-strong);
  background: var(--accent-strong);
  color: var(--paper);
  z-index: 1;
}

.notebook .nbrail__name {
  overflow: hidden;
  text-overflow: ellipsis;
}

.notebook .nbrail__count {
  font-variant-numeric: tabular-nums;
  color: var(--ink-faint);
}

.notebook .nbrail__page.is-active .nbrail__count {
  color: var(--paper);
  opacity: 0.78;
}

.notebook .nbrail__page:focus {
  outline: none;
}

.notebook .nbrail__page:focus-visible {
  outline: var(--focus-width) solid var(--accent);
  outline-offset: 2px;
}

@media (forced-colors: active) {
  .notebook .nbrail__page.is-active {
    forced-color-adjust: none;
    background: Highlight;
    color: HighlightText;
  }

  .notebook .nbrail__page.is-active .nbrail__count {
    color: HighlightText;
    opacity: 1;
  }
}

/* ---- the open page ------------------------------------------------------ */

/* nbpages owns the one inset the visible leaf sits in. Do not also pad
   .nbpage: static/css/notebook.css's own narrow layout does that below
   46rem, padding .nbpages AND the leaf both, which doubles the inset on the
   one page actually showing. The panel has no narrow break of its own to
   repeat that in -- it is already the narrow dress at every width -- so
   there is only the one place to decide, and this is it. */
.notebook .nbpages {
  padding: var(--space-4);
}

.notebook .nbpage {
  min-inline-size: 0;
}

.notebook .nbpage__title {
  margin: 0;
  font-family: var(--font-serif);
  font-size: var(--fs-h2);
  line-height: var(--lh-heading);
  color: var(--ink);
}

.notebook .nbpage__verse {
  margin-block: var(--space-3) 0;
  font-family: var(--font-arabic);
  font-size: 1.45rem;
  line-height: var(--lh-arabic-typeset);
  color: var(--ink);
}

.notebook .nbpage__gloss {
  margin-block: var(--space-2) 0;
  font-size: var(--fs-body-sm);
  color: var(--ink-soft);
}

.notebook .nbpage__rule {
  margin-block: var(--space-4);
  border: 0;
  border-block-start: var(--hair) solid var(--rule);
}

.notebook .nbsittings {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
}

/* ---- one sitting, and the note IS the editor ---------------------------- */

/* White means you can type here, and a written note is not white. See the
   same rule in notebook.css. */
.notebook .nbentry {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-3);
  border: var(--hair) solid var(--rule);
  border-radius: var(--radius-control);
  background: var(--paper-sunk);
}

.notebook .nbentry__head {
  display: flex;
  align-items: baseline;
  gap: var(--space-3);
  margin: 0;
}

.notebook .nbentry__time {
  font-family: var(--font-sans);
  font-size: var(--fs-caption);
  font-variant-numeric: tabular-nums;
  color: var(--ink-faint);
}

.notebook .nbentry__edited {
  font-family: var(--font-sans);
  font-size: var(--fs-caption);
  font-style: italic;
  color: var(--ink-faint);
}

/* The negative inline margin gives the padding back, so the measure and the
   left edge are identical at rest, on hover and while editing -- nothing
   shifts under the press that caused it. */
.notebook .nbentry__body {
  margin-inline: calc(var(--space-2) * -1);
  padding: var(--space-2);
  border-radius: 6px;
  line-height: var(--lh-reading);
  cursor: text;
}

.notebook .nbentry__body > :first-child { margin-block-start: 0; }
.notebook .nbentry__body > :last-child { margin-block-end: 0; }

.notebook .nbentry__body p {
  margin-block: 0 var(--space-3);
}

/* base.css resets every list to list-style: none, which is right for the
   navigation rows that are nearly all of them and wrong for the one place a
   READER typed the list. */
.notebook .nbentry__body ul,
.notebook .nbentry__body ol {
  margin-block: 0 var(--space-3);
  padding-inline-start: var(--space-5);
  list-style: revert;
}

.notebook .nbentry__body li {
  margin-block-end: var(--space-1);
}

.notebook .nbentry__body[tabindex]:hover {
  background: var(--paper);
}

.notebook .nbentry__body[tabindex]:focus {
  outline: none;
}

.notebook .nbentry__body[tabindex]:focus-visible {
  outline: var(--focus-width) solid var(--accent);
  outline-offset: 0;
}

.notebook .nbentry__body.is-editing {
  background: var(--paper-raised);
  box-shadow: inset 0 -2px 0 0 var(--accent);
}

@media (forced-colors: active) {
  .notebook .nbentry__body.is-editing {
    forced-color-adjust: none;
    box-shadow: inset 0 -2px 0 0 Highlight;
  }
}

.notebook .nbentry__edit {
  display: block;
  inline-size: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  line-height: var(--lh-reading);
  resize: none;
  overflow: hidden;
}

.notebook .nbentry__edit:focus {
  outline: none;
}

.notebook .nbentry__tools {
  display: flex;
  gap: var(--space-3);
  margin: 0;
}

.notebook .nbentry__tool {
  min-block-size: 2.25rem;
  padding: 0;
  border: 0;
  background: none;
  color: var(--ink-faint);
  font-family: var(--font-sans);
  font-size: var(--fs-caption);
  text-decoration: underline;
  cursor: pointer;
}

.notebook .nbentry__tool:hover {
  color: var(--ink);
}

.notebook .nbentry__tool--danger.is-armed {
  color: var(--caution);
  font-weight: 600;
}

/* ---- writing: a box, standing open -------------------------------------- */

.notebook .nbwrite {
  margin: 0;
}

.notebook .nbwrite[hidden] {
  display: none;
}

/* The surah bar's own trigger ships hidden and its module reveals it, so the
   attribute has to be said again against .surahtoc__trigger's display. A test
   walks every template for exactly this. */
.notebook__open[hidden] {
  display: none;
}

/* See the note on the same class in notebook.css: this was a faint line for one
   day and use retired it. A thing you write in should look like one. */
.notebook .nbwrite__box {
  display: block;
  inline-size: 100%;
  padding: var(--space-3);
  border: var(--hair) solid var(--rule-strong);
  border-radius: var(--radius-control);
  background: var(--paper-raised);
  color: var(--ink);
  font-family: var(--font-serif);
  font-size: var(--fs-body);
  line-height: var(--lh-reading);
  resize: none;
  overflow: hidden;
}

.notebook .nbwrite__box::placeholder {
  color: var(--ink-faint);
  font-style: italic;
  opacity: 1;
}

.notebook .nbwrite__box:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: inset 0 0 0 1px var(--accent);
}

/* See "Saving, said out loud" in notebook.css: blur-saving works and cannot
   be seen, so the button appears with something to save and goes with it. */
.notebook .nbwrite__row,
.notebook .nbentry__row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin-block: var(--space-2) 0;
  min-block-size: 2.25rem;
}

.notebook .nbsave[hidden] {
  display: none;
}

.notebook .nbsave {
  min-height: 2.5rem;
  padding-inline: var(--space-4);
}

.notebook .nbsay {
  margin: 0;
  font-family: var(--font-sans);
  font-size: var(--fs-caption);
  color: var(--ink-faint);
}

.notebook .nbsay:empty {
  display: none;
}

/* ---- the foot: turning a page, and the way out --------------------------- */

.notebook .nbfoot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  padding: var(--space-1) var(--space-2);
  border-block-start: var(--hair) solid var(--rule-soft);
  font-family: var(--font-sans);
  font-size: var(--fs-caption);
}

.notebook .nbfoot__slot { min-inline-size: 0; }
.notebook .nbfoot__slot--next { text-align: end; }
.notebook .nbfoot__open { flex: none; }

.notebook .nbturn__step {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  min-block-size: 44px;
  padding-inline: var(--space-2);
  border: 0;
  border-radius: var(--radius-control);
  background: none;
  color: var(--accent-strong);
  font-family: var(--font-sans);
  font-size: var(--fs-caption);
  cursor: pointer;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.notebook .nbturn__step:hover { background: var(--accent-wash); }

@media (min-width: 62rem) {
  body.notebook-open {
    padding-inline-end: var(--qs-panew, 50vw);
    overflow: visible;
    --qs-pagew: calc(100vw - var(--qs-panew, 50vw));
  }

  /* Back under the masthead, whose controls stay reachable beside a split. */
  .notebook { z-index: 90; }

  .notebook__panel {
    inline-size: var(--qs-panew, 50vw);
    inset-block-start: 0;
    transform: translateX(101%);
    border-block-start: 0;
    border-inline-start: var(--hair) solid var(--rule);
  }

  /* No veil beside a split: the half that is not the panel stays live. */
  .notebook__scrim { display: none; }

  /* Above the split the verse is already beside the panel, in the reading
     column the panel sits next to -- the Arabic inside a leaf that also
     carries a translation would be the same words twice. The script marks
     that leaf; the sheet below this width covers the reading column, so both
     belong there and neither is hidden. */
  .notebook .nbpage--grounded .nbpage__verse { display: none; }

  /* The gloss grounds the leaf once the Arabic above is hidden -- the same
     .nbpage__gloss the pages dress quietly, promoted here to lead in the
     Arabic's place. Only the dress changes with the split; the element, and
     its order after the verse, are the one object both surfaces build. */
  .notebook .nbpage--grounded .nbpage__gloss {
    font-size: var(--fs-body-lg);
    line-height: var(--lh-reading);
    color: var(--ink);
  }
}


/* ----------------------------------------------------------------------------
   25. The seam every panel is dragged by

   ONE grip, written once, for all six panels. The width it moves was always
   shared -- every panel's own block reads var(--qs-panew, 50vw) and has since
   the split shipped on 2026-08-23 -- but the handle existed only in the word
   panel, whose markup happened to hold it. So a reader with the commentary
   open could see the seam, could see the panel obeying a width, and had
   nothing to take hold of. Reported by the owner on 2026-08-30, in the same
   breath as asking why.

   WRITTEN AT THE FOOT OF THE FILE ON PURPOSE, and this is the whole reason it
   is safe to share. Sections 18, 20, 21, 22 and 24 each carry their own copy
   of the split block, and the recorded failure of that arrangement is at the
   head of section 20's `--panel-bar-min`: four selectors were beaten by the
   lectures panel's later base rule because a media query adds no specificity
   and source order decided it. A class no per-panel section mentions, defined
   after all of them, cannot lose that argument -- there is no equal-specificity
   rule anywhere to lose it to. The alternative, six copies of these rules,
   would be the same debt again with a new way to drift.

   This does NOT close the CSS half of the panel-shell debt in section 24. It
   is one sliver of it, taken because the seam is one control and could not go
   on being six absences and one presence.

   Off by default, on above 62rem. Below that the panel covers the surah
   entirely and there are no halves to move. */
.panel__splitgrip { display: none; }

@media (min-width: 62rem) {
  /* A child of the panel rather than of its wrapper, so it inherits the
     panel's pointer-events:auto out of a container that has none, travels
     with the panel's transform when it is shut, and inherits the
     visibility:hidden that makes it unfocusable then. No panel section sets
     overflow, so hanging six pixels past the inline start is not clipped in
     any of the six.

     It is also the section's FIRST CHILD, which panel-resize.js depends on:
     with six grips the file can no longer name one .wstudy__panel, so each
     grip's parentElement is how it learns whose edge it is.

     Twelve pixels of hit for a one-pixel hairline. The pointer target for a
     drag is not the thing being dragged: the hairline is the panel's edge and
     is the right width for an edge, and the grip is the reader's aim, which
     wants a finger's tolerance. Centred on the line rather than beside it, so
     the pointer does not have to choose a side. */
  .panel__splitgrip {
    display: block;
    position: absolute;
    inset-block: 0;
    inset-inline-start: -6px;
    inline-size: 12px;
    /* Above the panel's own content, below the bar's dialogs. Audited across
       all six on 2026-08-30: nothing inside any panel exceeds 2 except
       .wstudy__under at 5, which is the Arabic keyboard and is deliberately
       above this -- the recorded decision of 2026-08-23. */
    z-index: 4;
    cursor: col-resize;
    /* The browser must not claim the gesture for a pan before the handler
       sees it; without this a touch drag scrolls the page instead. */
    touch-action: none;
  }

  /* The line the grip shows, present at every state and only ever repainted.
     Growing it on hover would move the seam under the reader's pointer at the
     moment they are aiming at it. */
  .panel__splitgrip::after {
    content: "";
    position: absolute;
    background: transparent;
    transition: background var(--dur) var(--ease-calm);
    inset-block: 0;
    /* On the panel's own hairline, which sits at the grip's inline end. */
    inset-inline-start: 5px;
    inline-size: 2px;
  }

  /* THE GRIP THE READER CAN SEE BEFORE THEY TOUCH IT. The line above says
     nothing until hovered -- the seams were draggable for a day and nobody
     could tell -- and a cursor is a reward for already guessing.

     A short pill centred on the seam, which is the split-view convention and
     reads as "take hold here" without a rule drawn the length of the panel.
     Paint only, like the line: out of flow, so neither its resting state nor
     its accent costs the layout a pixel. */
  .panel__splitgrip::before {
    content: "";
    position: absolute;
    border-radius: 2px;
    background: var(--ink-faint);
    transition: background var(--dur) var(--ease-calm);
    inset-block-start: 50%;
    /* On the hairline the ::after lights, and inside the panel: the grip
       itself hangs six pixels past the panel's edge, and a pill out there
       would sit over the reading page rather than on the seam. */
    inset-inline-start: 4px;
    inline-size: 4px;
    block-size: 2.25rem;
    transform: translateY(-50%);
  }

  /* Accent, because a grip is a pressable and this stylesheet spends accent on
     nothing else. Focus-visible included: a keyboard reader moving the seam
     with the arrow keys needs to see which seam is listening. The pill takes
     the same three states as the line, so the two never disagree. */
  .panel__splitgrip:hover::after,
  .panel__splitgrip:focus-visible::after { background: var(--accent); }

  .panel__splitgrip:hover::before,
  .panel__splitgrip:focus-visible::before { background: var(--accent); }

  .panel__splitgrip:active::after { background: var(--accent-strong); }

  .panel__splitgrip:active::before { background: var(--accent-strong); }

  .panel__splitgrip:focus-visible { outline: none; }
}
