/* ==========================================================================
   1 · The system
   --------------------------------------------------------------------------
   A warm ground, white cards on a stone line, the navy for anything a reader
   can act on, and a deep red kept for the one thing that is theirs alone: the
   place they marked. Nothing else in the interface may use that red. The one
   exception is not interface: the house's own mark (D55) draws its full moon
   and the line beneath it in that red, because the logo was drawn from this
   palette. Nothing a reader can press borrows it.

   Two faces, on purpose. Amiri carries the book's own words — its title, its
   sayings, the headings of its contents. IBM Plex Sans Arabic carries the
   interface around them. A count, a date, a button is not part of the book
   and should not be set as though it were.
   ========================================================================== */

:root {
    color-scheme: light;

    /* Ink, from the text of a page down to a timestamp. */
    --ink: #1d2b36;
    --ink-strong: #1b3648;
    --ink-soft: #5a6875;
    --ink-faint: #8d9399;

    /* The accent, and the wash it leaves behind wherever something is chosen. */
    --navy: #2c546e;
    --navy-deep: #1b3648;
    --navy-wash: #eaf0f4;

    /* Surfaces: the ground everything sits on, the cards, the insets in them. */
    --ground: #f7f4ed;
    --surface: #fff;
    --surface-soft: #fbfaf6;
    --surface-warm: #f6f4ec;

    /* Lines: a card's edge, a divider within it, a control's edge, a field in use. */
    --line: #e6e3d8;
    --line-soft: #eeece3;
    --field: #dfe0d8;
    --field-strong: #c9cdc4;

    /* The book itself: the stage behind the paper, the paper, its edge. */
    --stage: #efece1;
    --paper: #fffdf7;
    --paper-edge: #ded9cb;
    /* the grey bars of a sheet that has not arrived yet */
    --paper-lines: #ddd7c7;

    /* What the reader makes: the place kept, the words found. */
    --keep: #8a2b2b;
    --mark: #f6e2a8;
    --sample-bg: #f3ece1;
    --sample-ink: #7a5a22;

    /* An answer: the code taken, the code refused. */
    --ok: #2f6b4f;
    --ok-wash: #e8f2ec;
    --error: #7a1c26;
    --error-wash: #fbeaec;
    --error-line: #f0cdd2;

    --radius-card: 12px;
    --radius: 8px;
    --radius-sm: 7px;
    --radius-pill: 999px;

    --shadow-card: 0 2px 10px rgb(29 43 54 / 10%);
    --shadow-panel: 0 6px 24px rgb(29 43 54 / 14%);
    --shadow-float: 0 10px 34px rgb(29 43 54 / 22%);

    --font-ui: "IBM Plex Sans Arabic", "Noto Sans Arabic", system-ui, sans-serif;
    --font-book: "Amiri", "Noto Naskh Arabic", "Geeza Pro", serif;

    /* The reader's fixed bands. */
    --site-header: 4.25rem;
    --bar-height: 3.5rem;
    /* The band above it, which says which book you are in. It holds one line of small text, so
       it is sized to that line and not the other way about: what keeps the title's حركات off
       the clipping edge is the leading and padding on the name itself, which come to 2rem. */
    --banner-height: 2.4rem;
    --rail-width: 4.25rem;
}

/* ==========================================================================
   2 · The faces
   --------------------------------------------------------------------------
   All self-hosted, all under the SIL Open Font License: no third party sees
   who is reading what (D32). Amiri's licence is in assets/fonts/Amiri-OFL.txt,
   Plex's in IBMPlexSansArabic-OFL.txt, Kufam's in Kufam-OFL.txt. Kufam is the
   logo's, not the interface's: it sets the logo's line and nothing else.

   Plex ships as two subsets per weight so a page never downloads the Arabic to
   render a Latin word, or the reverse; unicode-range decides.
   ========================================================================== */

@font-face {
    font-family: "Amiri";
    src: url("../fonts/Amiri-Regular-qwrUNNP.ttf") format("truetype");
    font-weight: 400;
    font-display: swap;
}

@font-face {
    font-family: "Amiri";
    src: url("../fonts/Amiri-Bold-QkbyJaA.ttf") format("truetype");
    font-weight: 700;
    font-display: swap;
}

/* Kufam 500, Arabic only: the logo's line in Arabic and Farsi, and nothing else (D55). */
@font-face {
    font-family: "Kufam";
    src: url("../fonts/Kufam-500-arabic-Y3oIZqK.woff2") format("woff2");
    font-weight: 500;
    font-display: swap;
}

/* 200, Latin only: the wordmark's «Books» and nothing else, so no Arabic subset is shipped for it. */
@font-face {
    font-family: "IBM Plex Sans Arabic";
    src: url("../fonts/IBMPlexSansArabic-200-latin-7Ne0lgF.woff2") format("woff2");
    font-weight: 200;
    font-display: swap;
}

/* 300: the home page's headlines (ticket 62), light, in both scripts. */
@font-face {
    font-family: "IBM Plex Sans Arabic";
    src: url("../fonts/IBMPlexSansArabic-300-arabic-UfEDR4n.woff2") format("woff2");
    font-weight: 300;
    font-display: swap;
    unicode-range: U+0600-06FF, U+0750-077F, U+0870-088E, U+0890-0891, U+0897-08E1, U+08E3-08FF, U+200C-200E, U+2010-2011, U+204F, U+2E41, U+FB50-FDFF, U+FE70-FE74, U+FE76-FEFC;
}

@font-face {
    font-family: "IBM Plex Sans Arabic";
    src: url("../fonts/IBMPlexSansArabic-300-latin-_Ahq-Ve.woff2") format("woff2");
    font-weight: 300;
    font-display: swap;
}

@font-face {
    font-family: "IBM Plex Sans Arabic";
    src: url("../fonts/IBMPlexSansArabic-400-arabic-16QeH4Z.woff2") format("woff2");
    font-weight: 400;
    font-display: swap;
    unicode-range: U+0600-06FF, U+0750-077F, U+0870-088E, U+0890-0891, U+0897-08E1, U+08E3-08FF, U+200C-200E, U+2010-2011, U+204F, U+2E41, U+FB50-FDFF, U+FE70-FE74, U+FE76-FEFC;
}

@font-face {
    font-family: "IBM Plex Sans Arabic";
    src: url("../fonts/IBMPlexSansArabic-400-latin-r09p1Xl.woff2") format("woff2");
    font-weight: 400;
    font-display: swap;
}

@font-face {
    font-family: "IBM Plex Sans Arabic";
    src: url("../fonts/IBMPlexSansArabic-500-arabic-14fYqZz.woff2") format("woff2");
    font-weight: 500;
    font-display: swap;
    unicode-range: U+0600-06FF, U+0750-077F, U+0870-088E, U+0890-0891, U+0897-08E1, U+08E3-08FF, U+200C-200E, U+2010-2011, U+204F, U+2E41, U+FB50-FDFF, U+FE70-FE74, U+FE76-FEFC;
}

@font-face {
    font-family: "IBM Plex Sans Arabic";
    src: url("../fonts/IBMPlexSansArabic-500-latin-E9hEdTo.woff2") format("woff2");
    font-weight: 500;
    font-display: swap;
}

@font-face {
    font-family: "IBM Plex Sans Arabic";
    src: url("../fonts/IBMPlexSansArabic-600-arabic-FZc01yX.woff2") format("woff2");
    font-weight: 600;
    font-display: swap;
    unicode-range: U+0600-06FF, U+0750-077F, U+0870-088E, U+0890-0891, U+0897-08E1, U+08E3-08FF, U+200C-200E, U+2010-2011, U+204F, U+2E41, U+FB50-FDFF, U+FE70-FE74, U+FE76-FEFC;
}

@font-face {
    font-family: "IBM Plex Sans Arabic";
    src: url("../fonts/IBMPlexSansArabic-600-latin-Vr6doLc.woff2") format("woff2");
    font-weight: 600;
    font-display: swap;
}

@font-face {
    font-family: "IBM Plex Sans Arabic";
    src: url("../fonts/IBMPlexSansArabic-700-arabic-PYYKMut.woff2") format("woff2");
    font-weight: 700;
    font-display: swap;
    unicode-range: U+0600-06FF, U+0750-077F, U+0870-088E, U+0890-0891, U+0897-08E1, U+08E3-08FF, U+200C-200E, U+2010-2011, U+204F, U+2E41, U+FB50-FDFF, U+FE70-FE74, U+FE76-FEFC;
}

@font-face {
    font-family: "IBM Plex Sans Arabic";
    src: url("../fonts/IBMPlexSansArabic-700-latin-Hnc3V6d.woff2") format("woff2");
    font-weight: 700;
    font-display: swap;
}

/* ==========================================================================
   3 · Ground rules
   --------------------------------------------------------------------------
   The direction comes from the dir attribute base.html.twig sets per language
   (ticket 41). Hard-coding it here overrode that attribute and laid the
   English pages out right to left.
   ========================================================================== */

body {
    margin: 0;
    background: var(--ground);
    color: var(--ink);
    font-family: var(--font-ui);
    font-size: 0.95rem;
    line-height: 1.7;
}

/* The book's own words. Applied by class, never inherited, so that nothing in
   the interface picks up a book face by accident. */
.is-book-text {
    font-family: var(--font-book);
}

/* English has no book of its own here, and Amiri's Latin is a companion to its
   Arabic rather than a text face in its own right, so English prose takes a
   serif of its own while the interface stays on Plex's Latin. */
body.lang-en {
    --font-book: ui-serif, Georgia, "Times New Roman", serif;
}

/* …but a book's own title stays in the book's face on an English page: «جواهر الكلام» is Arabic
   whatever the page around it is */
body.lang-en [lang="ar"] {
    --font-book: "Amiri", "Noto Naskh Arabic", "Geeza Pro", serif;
}

a {
    color: var(--navy);
}

a:hover {
    color: var(--navy-deep);
}

:focus-visible {
    outline: 2px solid var(--navy);
    outline-offset: 2px;
}

.visually-hidden,
/* In reading mode the rail keeps its icons and loses its words (see §12). Hidden this way and
   not with `display: none`, because the word is what gives each tab its name: taken out of the
   document it would leave four buttons that a screen reader could only call «button». */
.reader-shell.is-bare .reader__tab-label {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

/* ==========================================================================
   4 · The shared controls
   --------------------------------------------------------------------------
   One square button, one field, one pill. Everything that looks like a button
   anywhere in the app is one of these three, so a change of mind is a change
   in one place.
   ========================================================================== */

.button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.4rem;
    min-height: 2.5rem;
    padding: 0.55rem 1.15rem;
    border: 1px solid var(--field);
    border-radius: var(--radius);
    background: var(--surface);
    color: var(--navy);
    font: inherit;
    font-size: 0.95rem;
    font-weight: 500;
    text-decoration: none;
    cursor: pointer;
}

.button:hover {
    border-color: var(--navy);
    background: var(--navy-wash);
    color: var(--navy-deep);
}

.button--primary {
    border-color: var(--navy);
    background: var(--navy);
    color: #fff;
    font-weight: 600;
}

.button--primary:hover {
    border-color: var(--navy-deep);
    background: var(--navy-deep);
    color: #fff;
}

/* Not a control: something the app will do later, drawn so it cannot be pressed. */
.button--soon {
    border-style: dashed;
    border-color: #cfccc0;
    background: transparent;
    color: var(--ink-soft);
    cursor: default;
}

.button--soon:hover {
    border-color: #cfccc0;
    background: transparent;
    color: var(--ink-soft);
}

/* A field, wherever one is typed into. */
.field {
    box-sizing: border-box;
    width: 100%;
    min-height: 2.25rem;
    padding: 0.4rem 0.7rem;
    border: 1px solid var(--field);
    border-radius: var(--radius);
    background: var(--surface-soft);
    color: var(--ink);
    font: inherit;
    font-size: 0.9rem;
}

.field:focus {
    border-color: var(--field-strong);
    background: var(--surface);
}

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

/* A label on a thing rather than on a control: the free pages, the soon, the count. */
.badge {
    display: inline-flex;
    align-items: center;
    padding: 0.1rem 0.55rem;
    border-radius: var(--radius-pill);
    background: var(--sample-bg);
    color: var(--sample-ink);
    font-size: 0.7rem;
    font-weight: 600;
    vertical-align: middle;
    margin-inline-start: 0.4rem;
}

/* ==========================================================================
   5 · The site's own chrome
   ========================================================================== */

.site {
    min-height: 100dvh;
    display: flex;
    flex-direction: column;
    background: var(--ground);
    color: var(--ink);
}

.site__header {
    position: relative;
    /* the language menu drops out of the header over whatever is below it */
    z-index: 10;
    display: flex;
    align-items: center;
    gap: 1.5rem;
    box-sizing: border-box;
    min-height: var(--site-header);
    padding: 0 1.25rem;
    background: var(--surface);
    border-block-end: 1px solid var(--line);
}

.site__brand {
    display: inline-flex;
    align-items: center;
    color: var(--ink);
    text-decoration: none;
    font-size: 1.6rem;
    white-space: nowrap;
}

/* the Arabic and Farsi name answers the pointer; the English one stays as drawn */
[dir="rtl"] .site__brand:hover .brand__books {
    color: var(--navy-deep);
}

/* The logo, variation K (D55): three phases of the moon, the name — «تمام» drawn heavy in Arabic
   and Farsi, «Tamam» set heavy in English, both in the ink — and «Books» thin in the navy; then a
   hairline and the logo's line in the red, Kufam in Arabic and Farsi, Plex in English. The
   lockup runs in the page's direction. Sized in ems from the name, as the design draws it, so one
   font-size scales it; the line alone is set in rem: at the design's own proportion it would be
   thirteen pixels. */
.brand {
    display: inline-flex;
    align-items: center;
    gap: 0.4em;
    line-height: 1;
}

.brand__mark {
    flex: 0 0 auto;
    width: 1.9em;
    height: auto;
    overflow: visible;
}

.brand__full {
    fill: var(--keep);
}

.brand__ring {
    fill: none;
    stroke: var(--navy);
    stroke-width: 2.5;
}

.brand__lit {
    fill: var(--navy);
}

/* «Books» stands on the foot of «تمام», as the design aligns them; in English the two words
   meet, one name */
.brand__word {
    display: inline-flex;
    align-items: flex-end;
    gap: 0.19em;
}

[dir="ltr"] .brand__word {
    align-items: baseline;
    gap: 0;
}

.brand__tamam {
    width: 2.26em;
    height: 1em;
    fill: var(--ink);
}

/* the name in English, where it is a word to read rather than a word drawn */
.brand__latin {
    color: var(--ink);
    font-family: var(--font-ui);
    font-weight: 700;
    letter-spacing: -0.03em;
}

.brand__books {
    color: var(--navy);
    font-family: var(--font-ui);
    font-weight: 200;
    letter-spacing: -0.02em;
}

.brand__line {
    display: inline-flex;
    align-items: center;
    gap: 0.75rem;
    margin-inline-start: 0.3rem;
    color: var(--keep);
    font-family: "Kufam", var(--font-book);
    font-size: 0.9rem;
    font-weight: 500;
    line-height: 1.3;
}

/* in English the line is plain: the interface face, a step smaller */
[dir="ltr"] .brand__line {
    font-family: var(--font-ui);
    font-size: 0.85rem;
    font-weight: 500;
}

/* the hairline between the name and its line; in the line's own box, so it goes when the line does */
.brand__line::before {
    content: "";
    flex: 0 0 1px;
    height: 1.9rem;
    background: var(--ink-soft);
    opacity: 0.45;
}

/* The header is the brand at one edge and the person at the other: who is looking, and in which
   language. The two sit in one group so the gap between them is a hand's width. The site's own
   three places (ticket 62) stand beside the person, on the same far side — nothing of a book's
   hangs here. */
.site__nav {
    display: flex;
    align-items: center;
    gap: 0.25rem;
    margin-inline-start: auto;
    font-family: var(--font-ui);
}

.site__nav a {
    position: relative;
    display: inline-flex;
    align-items: center;
    min-height: 2.25rem;
    padding: 0 0.75rem;
    border-radius: var(--radius);
    color: var(--ink-soft);
    font-size: 0.9rem;
    font-weight: 500;
    text-decoration: none;
    white-space: nowrap;
}

.site__nav a:hover {
    background: var(--surface-warm);
    color: var(--ink);
}

.site__nav a[aria-current="page"] {
    color: var(--ink-strong);
    font-weight: 600;
}

/* the page you are on, underlined where the header meets the page */
.site__nav a[aria-current="page"]::after {
    content: "";
    position: absolute;
    inset-inline: 0.75rem;
    bottom: calc((var(--site-header) - 2.25rem) / -2);
    height: 2px;
    border-radius: 2px;
    background: var(--navy);
}

.site__end {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

/* ==========================================================================
   5b · Who is looking
   --------------------------------------------------------------------------
   A guest is offered the one door there is, drawn like the language circle —
   the accent in a line, not a block of it. Someone signed in is named, and
   the name is the handle: it opens the account's three places.
   ========================================================================== */

.who {
    position: relative;
}

.who__sign-in,
.who__current {
    display: flex;
    align-items: center;
    box-sizing: border-box;
    height: 2rem;
    border: 1px solid transparent;
    border-radius: var(--radius-pill);
    /* the interface face, as everything in the header around the brand */
    font-family: var(--font-ui);
    font-size: 0.85rem;
    text-decoration: none;
    cursor: pointer;
    /* the disclosure triangle, in both the places a browser draws it */
    list-style: none;
}

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

.who__current::marker {
    content: "";
}

.who__sign-in {
    gap: 0.45rem;
    padding-inline: 0.85rem;
    border-color: var(--navy);
    color: var(--navy);
    font-weight: 600;
}

.who__sign-in:hover {
    background: var(--navy-wash);
    color: var(--navy-deep);
}

/* Signed in, the control carries no border of its own until it is pressed or pointed at: the
   name is already a shape in the header, and a second outlined pill beside the circle would
   make the quietest corner of the page the loudest. */
.who__current {
    gap: 0.45rem;
    padding-inline-start: 0.25rem;
    padding-inline-end: 0.5rem;
    color: var(--ink-strong);
}

.who__current:hover,
.who[open] .who__current {
    border-color: var(--line);
    background: var(--surface-warm);
}

/* The initial, in the book's own face — the same mark the brand wears at the other edge. */
.who__face {
    display: grid;
    place-items: center;
    flex: 0 0 auto;
    width: 1.6rem;
    height: 1.6rem;
    border-radius: 50%;
    background: var(--navy-wash);
    color: var(--navy);
    font-family: var(--font-book);
    font-size: 0.95rem;
    line-height: 1;
}

.who__name {
    max-width: 11rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-weight: 500;
}

.who__chevron {
    flex: 0 0 auto;
    color: var(--ink-faint);
    transition: transform 0.15s ease;
}

.who[open] .who__chevron {
    transform: rotate(180deg);
}

/* The language: a disclosure, not a row of three. It is chosen once, so it should not hold a
   permanent row of choices in every header — the circle says which language you are in, and
   pressing it offers the others. */
.languages {
    position: relative;
}

.languages__current {
    display: flex;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
    width: 2rem;
    height: 2rem;
    /* Drawn rather than filled: the accent in a line round the circle instead of a solid disc
       of it. Filled, the one thing in the header a reader is least often after was the one
       thing that carried a block of colour. */
    border: 1px solid var(--navy);
    border-radius: 50%;
    background: transparent;
    color: var(--navy);
    /* The interface face, not the book's: a short label has to sit in the middle of a circle in
       three scripts, and Plex gives ع, EN and فا the same metrics to centre against. */
    font-family: var(--font-ui);
    font-size: 0.85rem;
    font-weight: 600;
    cursor: pointer;
    /* the disclosure triangle, in both the places a browser draws it */
    list-style: none;
}

/* the line box is what flex centres, so it has to be the glyph's own height and no more */
.languages__current > span[aria-hidden] {
    display: block;
    line-height: 1;
}

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

.languages__current::marker {
    content: "";
}

.languages__current:hover {
    background: var(--navy-wash);
    color: var(--navy-deep);
}

.languages__menu,
.who__menu {
    position: absolute;
    top: calc(100% + 0.5rem);
    inset-inline-end: 0;
    z-index: 20;
    min-width: 11rem;
    margin: 0;
    padding: 0.35rem;
    list-style: none;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-card);
    box-shadow: var(--shadow-float);
}

.languages__row,
.who__row {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.45rem 0.6rem;
    border-radius: var(--radius);
    color: var(--ink);
    text-decoration: none;
    font-size: 0.85rem;
}

.languages__row > span:first-child {
    flex: 1 1 auto;
}

.languages__row:hover,
.who__row:hover {
    background: var(--surface-warm);
    color: var(--ink);
}

.languages__row.is-here {
    background: var(--navy-wash);
    color: var(--ink-strong);
    font-weight: 600;
}

.languages__code {
    flex: 0 0 auto;
    min-width: 1.5rem;
    text-align: center;
    padding: 0.05rem 0.45rem;
    border-radius: 6px;
    background: var(--surface-warm);
    color: var(--ink-soft);
    font-size: 0.7rem;
}

.languages__row.is-here .languages__code {
    background: #dbe6ee;
    color: var(--navy);
}

/* The menu itself is the language menu's panel: one dropdown in the header, drawn once. */
.who__menu {
    min-width: 12rem;
    padding-block-end: 0.35rem;
}

.who__row {
    gap: 0.6rem;
    width: 100%;
    box-sizing: border-box;
    /* a form's button and a link read as one list of rows */
    border: 0;
    background: none;
    font: inherit;
    font-family: var(--font-ui);
    text-align: start;
    cursor: pointer;
}

.who__row svg {
    flex: 0 0 auto;
    color: var(--ink-faint);
}

.who__row:hover svg {
    color: var(--navy);
}

/* Leaving is set apart by a line and not by a colour: the red belongs to the place a reader
   marked, and nothing else in the interface may borrow it. */
.who__out {
    margin-block-start: 0.35rem;
    padding-block-start: 0.35rem;
    border-block-start: 1px solid var(--line-soft);
}

.site__footer {
    margin-top: auto;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem 1.5rem;
    padding: 1.25rem;
    border-top: 1px solid var(--line);
    background: var(--surface-soft);
    color: var(--ink-faint);
    font-size: 0.8rem;
}

.site__footer-nav {
    display: flex;
    flex-wrap: wrap;
    gap: 1rem;
}

.site__footer-nav a {
    color: var(--ink-soft);
    text-decoration: none;
}

.site__footer-nav a:hover {
    color: var(--navy);
}

/* ==========================================================================
   6 · The landing page, and the site's own pages
   --------------------------------------------------------------------------
   The library rather than one book (ticket 62): whose works these are, then
   a shelf of every book there is and the one that is coming, then how they
   read. «عن المؤلف» and «تواصل معنا» share the page head and the width.
   ========================================================================== */

.home,
.site-page {
    width: 100%;
    max-width: 64rem;
    margin: 0 auto;
    padding: 0 1.25rem 3rem;
    box-sizing: border-box;
}

.home__hero {
    display: grid;
    gap: 0.9rem;
    max-width: 40rem;
    padding-block: 3.25rem 2.25rem;
}

/* the line above the title, with a hairline after it: Plex, not upper-cased, not spaced out —
   Arabic has no capitals, and tracking pulls its joined letters apart */
.home__kicker,
.site-page__kicker {
    display: flex;
    align-items: center;
    gap: 0.85rem;
    margin: 0;
    color: var(--keep);
    font-family: var(--font-ui);
    font-size: 0.95rem;
    font-weight: 500;
}

.home__kicker::after {
    content: "";
    flex: 0 0 3.5rem;
    height: 1px;
    background: var(--ink-soft);
    opacity: 0.45;
}

/* The home page's headlines are the interface face, light (Mhmd, 2026-10-02, over Amiri and
   Naskh): the library speaks in the site's voice and leaves the book's face to the books' pages.
   The site's other pages head themselves in the book's face, as their mock drew them. */
.home__title {
    margin: 0;
    color: var(--ink-strong);
    font-family: var(--font-ui);
    font-size: clamp(1.9rem, 3.6vw, 2.6rem);
    font-weight: 300;
    line-height: 1.45;
    text-wrap: balance;
}

.site-page__title {
    margin: 0;
    color: var(--ink-strong);
    font-family: var(--font-book);
    font-size: 2.2rem;
    font-weight: 700;
    line-height: 1.3;
    text-wrap: balance;
}

.home__intro,
.site-page__lead {
    max-width: 34rem;
    margin: 0;
    color: var(--ink-soft);
    font-size: 1.05rem;
    line-height: 1.8;
}

.library__head {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.5rem 1rem;
    margin-bottom: 1.1rem;
    padding-bottom: 0.65rem;
    border-bottom: 1px solid var(--line);
}

.library__head h2 {
    margin: 0;
    color: var(--ink-strong);
    font-size: 1.05rem;
    font-weight: 600;
}

.library__head span {
    color: var(--ink-faint);
    font-size: 0.85rem;
}

.library__books {
    display: grid;
    grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
    gap: 1.1rem;
    /* the cards of a row stand as tall as each other */
    align-items: stretch;
}

/* until one opens its details: then it grows alone, and its neighbour keeps its own height */
.library__books:has(.is-open) {
    align-items: start;
}

.library__book {
    display: grid;
    grid-template-columns: 8.5rem minmax(0, 1fr);
    /* no gap between rows: the folded details are a row of nothing, and must take no room */
    gap: 0 1.25rem;
    align-items: start;
    padding: 1.25rem;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-card);
}

/* the book's picture: its cover, the first page a visitor may open, or a drawn one */
.library__cover,
.library__sample img {
    display: block;
    width: 100%;
    height: auto;
    background: var(--paper);
    border: 1px solid var(--paper-edge);
    border-radius: 2px;
    box-shadow: 0 8px 22px rgb(29 43 54 / 18%), 0 2px 6px rgb(29 43 54 / 8%);
    transition: transform 200ms ease-out;
}

.library__sample:hover img {
    transform: translateY(-3px);
}

.library__drawn {
    position: relative;
    display: grid;
    place-items: center;
    aspect-ratio: 2 / 3;
    padding: 0.9rem;
    box-sizing: border-box;
    border-radius: 4px 8px 8px 4px;
    background: var(--navy-deep);
    box-shadow: 0 6px 18px rgb(29 43 54 / 22%), inset 6px 0 0 rgb(0 0 0 / 18%);
    color: var(--mark);
    font-family: var(--font-book);
    font-size: 0.95rem;
    font-weight: 700;
    line-height: 1.5;
    text-align: center;
}

.library__drawn::before {
    content: "";
    position: absolute;
    inset: 9px 9px 9px 13px;
    border: 1px solid rgb(246 226 168 / 55%);
    border-radius: 3px;
}

.library__drawn span {
    position: relative;
}

.library__drawn--soon {
    background: var(--surface-warm);
    box-shadow: inset 0 0 0 1px var(--line);
    color: var(--ink-soft);
}

.library__drawn--soon::before {
    border: 1px dashed var(--field-strong);
}

.library__body {
    display: grid;
    gap: 0.6rem;
    min-width: 0;
}

.library__status {
    justify-self: start;
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.1rem 0.65rem;
    border-radius: var(--radius-pill);
    font-size: 0.75rem;
    font-weight: 600;
}

.library__status--now {
    background: var(--ok-wash);
    color: var(--ok);
}

.library__status--now::before {
    content: "";
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: currentcolor;
}

.library__status--soon {
    background: var(--sample-bg);
    color: var(--sample-ink);
}

.library__title {
    margin: 0;
    color: var(--ink-strong);
    font-family: var(--font-ui);
    font-size: 1.45rem;
    font-weight: 300;
    line-height: 1.45;
    text-wrap: balance;
}

.library__about {
    display: -webkit-box;
    overflow: hidden;
    margin: 0;
    color: var(--ink-soft);
    font-size: 0.93rem;
    line-height: 1.8;
    /* the card gives the opening; the details give the whole of it */
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 3;
    line-clamp: 3;
}

/* the book's sizes, as a row of small facts rather than a bulleted list */
.library__facts {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

.library__facts li {
    padding: 0.15rem 0.65rem;
    border: 1px solid var(--line);
    border-radius: var(--radius-pill);
    background: var(--surface-warm);
    color: var(--ink-soft);
    font-size: 0.8rem;
    font-variant-numeric: tabular-nums;
}

.library__actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-top: 0.25rem;
}

/* «Details» unfolds the rest of the book under the card, across both its columns. The fold is
   a grid row going from nothing to its content's height, which is the one height that can be
   animated without knowing it. */
.library__more {
    grid-column: 1 / -1;
    display: grid;
    grid-template-rows: 0fr;
    transition: grid-template-rows 260ms ease-out;
}

.library__book.is-open .library__more {
    grid-template-rows: 1fr;
}

.library__more-inner {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.2fr);
    gap: 1.5rem;
    align-items: start;
    min-height: 0;
    overflow: hidden;
}

.library__book.is-open .library__more-inner {
    margin-top: 1.25rem;
    padding-top: 1rem;
    border-block-start: 1px solid var(--line-soft);
}

.library__details {
    margin: 0;
    font-size: 0.88rem;
}

.library__details > div {
    display: flex;
    justify-content: space-between;
    gap: 0.75rem;
    padding: 0.45rem 0;
    border-block-end: 1px solid var(--line-soft);
}

.library__details > div:last-child {
    border-block-end: 0;
}

.library__details dt {
    flex: 0 0 auto;
    color: var(--ink-soft);
}

.library__details dd {
    margin: 0;
    text-align: end;
    font-variant-numeric: tabular-nums;
}

.library__more-side {
    display: grid;
    gap: 1rem;
    min-width: 0;
}

.library__blurb {
    margin: 0;
    font-family: var(--font-book);
    font-size: 1rem;
    line-height: 1.95;
    color: #23313c;
    white-space: pre-line;
}

/* the opening of the description says nothing the open details do not say in full */
.library__book.is-open .library__about {
    display: none;
}

.button__chevron {
    width: 0.7rem;
    height: 0.7rem;
    transition: transform 200ms ease-out;
}

[aria-expanded="true"] > .button__chevron {
    transform: rotate(180deg);
}

@media (prefers-reduced-motion: reduce) {
    .library__more,
    .button__chevron {
        transition: none;
    }
}

.features {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 1.25rem;
    padding-block: 2.25rem 0.5rem;
}

.feature h2 {
    margin: 0 0 0.3rem;
    color: var(--ink-strong);
    font-size: 1rem;
    font-weight: 500;
}

.feature p {
    margin: 0;
    color: var(--ink-soft);
    font-size: 0.9rem;
    line-height: 1.85;
}

.home__teaser {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: 1rem 1.5rem;
    align-items: center;
    margin-top: 2rem;
    padding: 1.35rem 1.5rem;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-card);
}

.home__teaser h2 {
    margin: 0 0 0.25rem;
    color: var(--ink-strong);
    font-family: var(--font-ui);
    font-size: 1.3rem;
    font-weight: 300;
}

.home__teaser p {
    margin: 0;
    color: var(--ink-soft);
    font-size: 0.92rem;
}

/* --- «عن المؤلف» and «تواصل معنا» ---------------------------------------- */

.site-page__head {
    display: grid;
    gap: 0.5rem;
    padding-block: 2.75rem 1.5rem;
}

.about,
.contact {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 17rem;
    gap: 2rem;
    align-items: start;
}

/* the admin's words, in the book's face: a page to read, not a form to scan */
.prose {
    display: grid;
    gap: 0.9rem;
    max-width: 40rem;
    color: var(--ink);
    font-family: var(--font-book);
    font-size: 1.15rem;
    line-height: 2;
}

.prose p,
.prose h2 {
    margin: 0;
}

.prose h2 {
    margin-top: 0.75rem;
    color: var(--ink-strong);
    font-size: 1.35rem;
    font-weight: 700;
    line-height: 1.5;
}

.about__empty {
    color: var(--ink-faint);
    font-family: var(--font-ui);
    font-size: 0.95rem;
}

.about__side,
.contact__side {
    display: grid;
    gap: 0.9rem;
}

.about__portrait {
    display: block;
    width: 100%;
    height: auto;
    border-radius: var(--radius-card);
    border: 1px solid var(--line);
}

.about__books,
.contact__card {
    display: grid;
    gap: 0.5rem;
    padding: 1rem;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: 10px;
}

.about__books h2,
.contact__card h2 {
    margin: 0;
    color: var(--ink-soft);
    font-size: 0.85rem;
    font-weight: 600;
}

.about__books ul {
    display: grid;
    gap: 0.5rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

.about__books li {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.5rem;
}

.about__books li a,
.about__books li span {
    font-family: var(--font-book);
    font-size: 1.02rem;
    font-weight: 700;
    text-decoration: none;
}

.about__books li span {
    color: var(--ink-soft);
}

.about__books small {
    color: var(--ink-faint);
    font-size: 0.72rem;
    white-space: nowrap;
}

.contact__card p {
    margin: 0;
    color: var(--ink-soft);
    font-size: 0.88rem;
    line-height: 1.8;
}

.contact__form,
.contact__sent {
    display: grid;
    gap: 1rem;
    padding: 1.5rem;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-card);
}

.contact__pair {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 0.9rem;
}

.contact__message {
    min-height: 9rem;
    resize: vertical;
    line-height: 1.7;
}

.contact__form .field[readonly] {
    background: var(--surface-warm);
    color: var(--ink-soft);
}

/* no person sees it: off the page, not display: none, which some robots know to skip */
.contact__trap {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

.contact__foot {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
}

.contact__sent {
    justify-items: start;
}

.contact__sent p {
    margin: 0;
    color: var(--ink-soft);
}

.contact__ok {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.6rem 0.85rem;
    border-radius: var(--radius);
    background: var(--ok-wash);
    color: var(--ok) !important;
    font-weight: 600;
}

/* the same tick as the code page's */
.contact__ok::before {
    content: "";
    flex: 0 0 auto;
    width: 1.35rem;
    height: 1.35rem;
    border-radius: 50%;
    background: var(--ok) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 22 22'%3E%3Cpath d='M6.5 11.5l3 3 6-6.5' fill='none' stroke='%23fff' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / 100% no-repeat;
}

/* ==========================================================================
   7 · The long pages: contents, search, account, bookmarks
   --------------------------------------------------------------------------
   All four are one column of cards on the ground, so they share a shell.
   ========================================================================== */

.toc {
    max-width: 48rem;
    width: 100%;
    margin: 0 auto;
    padding: 2rem 1.25rem 3.5rem;
    box-sizing: border-box;
}

.toc__book {
    margin: 0;
    font-family: var(--font-book);
    font-size: 1.75rem;
    font-weight: 700;
    color: var(--ink-strong);
}

.toc__heading {
    margin: 0.35rem 0 1.75rem;
    color: var(--ink-soft);
    font-size: 0.9rem;
}

/* Why most of this index is plain text, said once at the head of it rather than on each of the
   hundred-odd rows it is true of (ticket 55). */
.toc__note {
    margin: -1.25rem 0 1.75rem;
    padding: 0.6rem 0.85rem;
    border-inline-start: 2px solid var(--sample-ink);
    border-radius: var(--radius-sm);
    background: var(--surface-warm);
    color: var(--ink-soft);
    font-size: 0.85rem;
    line-height: 1.7;
}

.toc__note a {
    color: var(--navy);
    white-space: nowrap;
}

.toc__volume {
    margin-bottom: 1.5rem;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-card);
    overflow: hidden;
}

.toc__volume h2 {
    margin: 0;
    padding: 0.8rem 1rem;
    border-bottom: 1px solid var(--line-soft);
    background: var(--surface-soft);
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--ink-soft);
}

.toc__list {
    list-style: none;
    margin: 0;
    padding: 0.4rem;
}

.toc__row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.5rem 0.75rem;
    border-radius: var(--radius-sm);
}

.toc__row:hover {
    background: var(--surface-warm);
}

.toc__row.is-current {
    background: var(--navy-wash);
    box-shadow: inset 3px 0 0 var(--navy);
}

.toc__row a {
    color: var(--ink);
    text-decoration: none;
    font-family: var(--font-book);
    font-size: 1rem;
}

.toc__row a:hover {
    color: var(--navy);
}

/* A section this viewer may not open: the title is still there, in full, because the index is
   an index of titles — it simply leads nowhere, and says so by not pretending to be a link. */
.toc__row--locked {
    color: var(--ink-soft);
}

.toc__row--locked:hover {
    background: none;
}

.toc__title {
    font-family: var(--font-book);
    font-size: 1rem;
}

.toc__pages {
    flex: 0 0 auto;
    white-space: nowrap;
    color: var(--ink-soft);
    font-size: 0.8rem;
    font-variant-numeric: tabular-nums;
}

/* A run of pages open to everyone, marked down its edge rather than by a pill on each of its
   rows: the badge states the fact once, at the head of the run, and the rule carries it to the
   rest. Repeated on every row it read as several different facts about several different runs. */
.toc__row--free,
.toc-tree__row--free {
    border-inline-start: 2px solid var(--sample-ink);
    padding-inline-start: 0.6rem;
}

.toc__row--free a .badge {
    margin-inline-start: 0.4rem;
}

/* ==========================================================================
   8 · The whole-book search page
   ========================================================================== */

.search__form {
    margin: 0 0 1.5rem;
    padding: 1rem;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-card);
}

.search__row {
    display: flex;
    gap: 0.6rem;
}

.search__input {
    flex: 1 1 auto;
    min-width: 0;
    box-sizing: border-box;
    padding: 0.65rem 0.95rem;
    border: 1px solid var(--field-strong);
    border-radius: var(--radius);
    background: var(--surface-soft);
    color: var(--ink);
    font: inherit;
    font-family: var(--font-book);
    font-size: 1.15rem;
}

.search__filters {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem 1.25rem;
    margin-top: 0.85rem;
    font-size: 0.85rem;
    color: var(--ink-soft);
}

.search__filters label {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
}

.search__filters select {
    padding: 0.35rem 0.6rem;
    border: 1px solid var(--field);
    border-radius: var(--radius-sm);
    background: var(--surface);
    color: var(--ink);
    font: inherit;
    font-size: 0.85rem;
    max-width: 16rem;
}

.search__results {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
}

.search__hit {
    display: flex;
    align-items: flex-start;
    gap: 0.6rem;
    padding: 0.85rem 1rem;
    background: var(--surface);
    border: 1px solid var(--line-soft);
    border-radius: var(--radius-card);
}

.search__hit:hover {
    border-color: var(--line);
    box-shadow: var(--shadow-card);
}

.search__link {
    flex: 1 1 auto;
    min-width: 0;
    display: block;
    color: inherit;
    text-decoration: none;
}

.search__text {
    margin: 0 0 0.45rem;
    font-family: var(--font-book);
    font-size: 1.15rem;
    line-height: 2;
    color: #23313c;
}

.search__text mark,
.found__text mark {
    background: var(--mark);
    color: var(--ink);
    padding: 0 0.1em;
    border-radius: 2px;
}

.search__meta {
    margin: 0;
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem 1.25rem;
    color: var(--ink-soft);
    font-size: 0.8rem;
    font-variant-numeric: tabular-nums;
}

.search__paging {
    display: flex;
    justify-content: center;
    align-items: center;
    gap: 1.5rem;
    padding: 1.5rem 0;
    color: var(--ink-soft);
    font-size: 0.85rem;
}

/* Keeping a saying straight from a result: the same round mark as the kept list's bin. */
.search__keep button {
    display: grid;
    place-items: center;
    width: 2rem;
    height: 2rem;
    border: 1px solid #dfe5ea;
    border-radius: 50%;
    background: var(--surface);
    color: #9aa7b1;
    font: inherit;
    line-height: 1;
    cursor: pointer;
}

.search__keep button:hover,
.search__keep button.is-kept {
    border-color: var(--keep);
    color: var(--keep);
}

/* A person's own last searches, offered back under the box (ticket 27). */
.search__recent {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    margin: 0 0 1.25rem;
}

.search__recent-label {
    color: var(--ink-soft);
    font-size: 0.8rem;
}

.search__recent ul {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

/* The chip is the term plus its dismiss button, sharing one border. */
.search__chip,
.find__chip {
    display: inline-flex;
    align-items: center;
    /* a chip is a flex item twice over, and both times it must agree to be narrower than the
       term it holds, or one long search pushes the whole panel sideways */
    min-width: 0;
    max-width: 100%;
    border: 1px solid var(--field);
    border-radius: var(--radius-pill);
    overflow: hidden;
    background: var(--surface-soft);
}

.search__chip:hover,
.find__chip:hover {
    border-color: var(--navy);
}

.search__chip a,
.find__again {
    /* the wide side is the one away from the ×, which is the start in Arabic and the left in
       English — physical padding put it on the wrong side of the chip in the reader */
    min-width: 0;
    padding-block: 0.15rem;
    padding-inline: 0.75rem 0.3rem;
    border: 0;
    background: none;
    color: var(--navy);
    text-decoration: none;
    /* a term too long for the panel ends in an ellipsis; the title attribute still has all of it */
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font: inherit;
    font-family: var(--font-book);
    font-size: 0.95rem;
    cursor: pointer;
}

.search__chip form {
    display: flex;
    flex: 0 0 auto;
}

.search__chip button,
.find__forget {
    display: grid;
    place-items: center;
    /* whatever the term does, forgetting it stays the same size and stays reachable */
    flex: 0 0 auto;
    width: 1.3rem;
    height: 1.3rem;
    margin-inline-end: 0.2rem;
    border: 0;
    border-radius: 50%;
    background: none;
    color: #9aa0a6;
    font: inherit;
    font-size: 0.9rem;
    line-height: 1;
    cursor: pointer;
}

.search__chip button:hover,
.find__forget:hover {
    background: var(--surface-warm);
    color: var(--keep);
}

/* ==========================================================================
   9 · Sign in, account, the kept list, errors
   ========================================================================== */

.auth {
    max-width: 26rem;
    width: 100%;
    margin: 8vh auto;
    padding: 1.75rem;
    box-sizing: border-box;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-card);
}

.auth h1 {
    margin: 0 0 0.75rem;
    color: var(--ink-strong);
    font-size: 1.3rem;
    font-weight: 600;
}

.auth__form {
    display: grid;
    gap: 0.9rem;
    margin-top: 1.25rem;
}

.auth__form label {
    display: grid;
    gap: 0.35rem;
    font-size: 0.85rem;
    color: var(--ink-soft);
}

.auth__form input {
    box-sizing: border-box;
    width: 100%;
    padding: 0.6rem 0.75rem;
    border: 1px solid var(--field);
    border-radius: var(--radius);
    background: var(--surface-soft);
    color: var(--ink);
    font: inherit;
    font-size: 1.05rem;
}

.auth__form input:focus {
    border-color: var(--field-strong);
    background: var(--surface);
}

.auth__code {
    text-align: center;
    letter-spacing: 0.5rem;
    font-size: 1.6rem !important;
    font-variant-numeric: tabular-nums;
}

/* --------------------------------------------------------------------------
   The six boxes (ticket 61). The script shows them and hides the one field
   and the button; without it, the field and the button are the page. Left to
   right in every language: the code is typed in the order the mail prints it.
   The tick, the reason and the waiting are said in the line under the boxes,
   which a screen reader hears as the page's status.
   -------------------------------------------------------------------------- */

.auth__form [hidden] {
    display: none;
}

.otp {
    display: grid;
    gap: 0.35rem;
}

.otp__label {
    font-size: 0.85rem;
    color: var(--ink-soft);
}

.otp__row {
    display: grid;
    grid-template-columns: repeat(6, minmax(0, 1fr));
    gap: 0.5rem;
}

.auth__form .otp__box {
    min-width: 0;
    aspect-ratio: 5 / 6;
    padding: 0;
    border-radius: 10px;
    caret-color: var(--navy);
    text-align: center;
    font-family: var(--font-ui);
    font-size: 1.6rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    transition: border-color 0.15s, background-color 0.15s, transform 0.15s;
}

.auth__form .otp__box:focus {
    outline: none;
    border-color: var(--navy);
    background: var(--surface);
    box-shadow: 0 0 0 3px var(--navy-wash);
}

.auth__form .otp__box--filled {
    border-color: var(--field-strong);
    background: var(--surface);
}

.otp[data-state="checking"] .otp__box {
    border-color: var(--navy);
    background: var(--navy-wash);
    color: var(--navy-deep);
    animation: otp-wait 0.9s infinite;
}

.otp[data-state="checking"] .otp__box:nth-child(2) { animation-delay: 0.08s; }
.otp[data-state="checking"] .otp__box:nth-child(3) { animation-delay: 0.16s; }
.otp[data-state="checking"] .otp__box:nth-child(4) { animation-delay: 0.24s; }
.otp[data-state="checking"] .otp__box:nth-child(5) { animation-delay: 0.32s; }
.otp[data-state="checking"] .otp__box:nth-child(6) { animation-delay: 0.4s; }

.otp[data-state="valid"] .otp__box {
    border-color: var(--ok);
    background: var(--ok-wash);
    color: var(--ok);
}

.otp[data-state="wrong"] .otp__box {
    border-color: var(--error-line);
    background: var(--error-wash);
    color: var(--error);
}

.otp--shake .otp__row {
    animation: otp-shake 0.4s;
}

.otp__status {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    min-height: 2.75rem;
    margin: 0;
    box-sizing: border-box;
    border-radius: var(--radius);
    color: var(--ink-faint);
    font-size: 0.9rem;
}

.otp__status[data-state="checking"] {
    color: var(--navy);
}

.otp__status[data-state="checking"]::before {
    content: "";
    flex: 0 0 auto;
    width: 1rem;
    height: 1rem;
    box-sizing: border-box;
    border: 2px solid var(--navy-wash);
    border-top-color: var(--navy);
    border-radius: 50%;
    animation: otp-spin 0.7s linear infinite;
}

.otp__status[data-state="valid"] {
    padding: 0.6rem 0.75rem;
    background: var(--ok-wash);
    color: var(--ok);
    font-weight: 600;
}

/* the tick: a disc with a check drawn on it */
.otp__status[data-state="valid"]::before {
    content: "";
    flex: 0 0 auto;
    width: 1.35rem;
    height: 1.35rem;
    border-radius: 50%;
    background: var(--ok) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 22 22'%3E%3Cpath d='M6.5 11.5l3 3 6-6.5' fill='none' stroke='%23fff' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / 100% no-repeat;
    animation: otp-pop 0.25s ease-out;
}

.otp__status[data-state="wrong"] {
    padding: 0.6rem 0.75rem;
    border: 1px solid var(--error-line);
    background: var(--error-wash);
    color: var(--error);
}

@keyframes otp-wait {
    50% { transform: translateY(-3px); }
}

@keyframes otp-shake {
    20%, 60% { transform: translateX(-6px); }
    40%, 80% { transform: translateX(6px); }
}

@keyframes otp-spin {
    to { transform: rotate(360deg); }
}

@keyframes otp-pop {
    from { transform: scale(0.6); opacity: 0; }
}

.auth__form button,
.account__logout button,
.account__device button {
    justify-self: start;
    padding: 0.6rem 1.25rem;
    border: 1px solid var(--navy);
    border-radius: var(--radius);
    background: var(--navy);
    color: #fff;
    font: inherit;
    font-weight: 600;
    cursor: pointer;
}

.auth__form button:hover,
.account__logout button:hover,
.account__device button:hover {
    background: var(--navy-deep);
    border-color: var(--navy-deep);
}

.auth__error,
.auth__notice {
    margin: 0 0 0.75rem;
    padding: 0.6rem 0.85rem;
    border-radius: var(--radius);
    font-size: 0.9rem;
}

.auth__error {
    background: var(--error-wash);
    color: var(--error);
    border: 1px solid var(--error-line);
}

.auth__notice {
    background: #fdf4dd;
    color: #6a5410;
    border: 1px solid #ecdcae;
}

/* Registration asks for a profile, which wants two columns: the sign-in card, wider. */
.auth--wide {
    max-width: 44rem;
}

.auth__register {
    display: grid;
    gap: 1.25rem;
    margin-top: 1.25rem;
}

.auth__register > .button {
    justify-self: start;
}

.auth__aside {
    margin: 1.5rem 0 0;
    font-size: 0.85rem;
}

.account__hint {
    margin: 0 0 0.75rem;
    color: var(--ink-soft);
    font-size: 0.85rem;
}

/* The profile's one card: the initial, the name the licence is in, the address a code is sent
   to, and the way through to the shelf. The same disc as the header wears, at reading size. */
.account__card {
    display: flex;
    align-items: center;
    gap: 1rem;
    margin: 0 0 1.75rem;
    padding: 1.1rem 1.25rem;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-card);
    box-shadow: var(--shadow-card);
}

.account__face {
    display: grid;
    place-items: center;
    flex: 0 0 auto;
    width: 3rem;
    height: 3rem;
    border-radius: 50%;
    background: var(--navy-wash);
    color: var(--navy);
    font-family: var(--font-book);
    font-size: 1.6rem;
    line-height: 1;
}

.account__who {
    flex: 1 1 auto;
    min-width: 0;
    display: grid;
    gap: 0.15rem;
}

.account__who strong {
    color: var(--ink-strong);
    font-size: 1.05rem;
}

/* How many books are on the shelf, in a shape of its own on the way through to it. */
.account__count {
    min-width: 1.4rem;
    padding: 0.05rem 0.4rem;
    border-radius: var(--radius-pill);
    background: var(--navy-wash);
    color: var(--navy);
    font-size: 0.78rem;
    font-weight: 600;
    text-align: center;
}

/* The address is written left to right whatever the page is written in, but its box still
   begins where the name's does: shrunk to its content rather than stretched across the row,
   or an Arabic page would leave it stranded at the far side of the card. */
.account__email {
    justify-self: start;
    max-width: 100%;
    color: var(--ink-soft);
    font-size: 0.85rem;
    overflow: hidden;
    text-overflow: ellipsis;
}

.account__device {
    align-items: center;
}

.account__device small {
    display: block;
    color: var(--ink-soft);
    font-size: 0.75rem;
}

.account__device button {
    padding: 0.3rem 0.85rem;
    font-size: 0.8rem;
    font-weight: 500;
}

.account__this {
    margin-inline-start: 0.5rem;
    padding: 0.1rem 0.5rem;
    border-radius: var(--radius-pill);
    background: var(--navy-wash);
    color: var(--navy);
    font-size: 0.7rem;
    font-weight: 600;
}

.account__logout {
    margin-top: 2rem;
}

/* Under a card's heading, a hint sits in the card's margin and not against its edge. */
.toc__volume > .account__hint {
    margin: 0;
    padding: 0.75rem 1rem 0;
}

.account__notice {
    margin: 0 0 1rem;
    padding: 0.6rem 0.85rem;
    border: 1px solid #cfe0d6;
    border-radius: var(--radius);
    background: #eef6f1;
    color: #24543a;
    font-size: 0.9rem;
}

.account__ways {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}

.account__ways .button {
    min-height: 2.25rem;
    padding: 0.4rem 0.9rem;
    font-size: 0.9rem;
}

/* ==========================================================================
   The profile: facts to read, and the same facts as a form
   ========================================================================== */

/* Read, two to a row: a label above its answer, so a long answer never pushes its label off
   the line, and an unanswered one is a dash rather than a gap that looks like a bug. */
.facts {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1rem 1.5rem;
    margin: 0;
    padding: 1rem;
}

.facts > div {
    min-width: 0;
}

.facts--wide {
    grid-column: 1 / -1;
}

.facts dt {
    color: var(--ink-faint);
    font-size: 0.78rem;
}

.facts dd {
    margin: 0.15rem 0 0;
    color: var(--ink-strong);
    overflow-wrap: anywhere;
}

.facts dd small {
    display: block;
    margin-top: 0.15rem;
    color: var(--ink-faint);
    font-size: 0.75rem;
}

.profile-form__body {
    padding: 1rem;
}

.profile-form__actions {
    display: flex;
    gap: 0.6rem;
}

/* Asked, two to a row on a wide screen, one on a phone. The inputs are the site's own `.field`. */
.fields {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1rem 1.25rem;
}

.form-field--wide {
    grid-column: 1 / -1;
}

.form-field {
    display: grid;
    align-content: start;
    gap: 0.35rem;
    min-width: 0;
    margin: 0;
    padding: 0;
    border: 0;
}

.form-field__label {
    display: flex;
    align-items: baseline;
    gap: 0.4rem;
    padding: 0;
    color: var(--ink-soft);
    font-size: 0.85rem;
}

.form-field__optional {
    color: var(--ink-faint);
    font-size: 0.72rem;
}

/* the site's field, a little taller here: a form filled in once deserves room to type in */
.form-field .field {
    min-height: 2.6rem;
    font-size: 0.95rem;
}

.form-field .field:focus {
    border-color: var(--navy);
    outline: 2px solid var(--navy-wash);
}

.form-field__hint {
    color: var(--ink-faint);
    font-size: 0.75rem;
}

/* A wrong field says so in the error colour the sign-in form already uses, and in words. */
.form-field.is-wrong .field {
    border-color: #d9a3ab;
    background: #fdf6f7;
}

.form-field__error {
    color: #7a1c26;
    font-size: 0.78rem;
}

/* Two answers, both on show: a pair of pills rather than a menu with one of them hidden. */
.form-field__choices {
    display: flex;
    gap: 0.5rem;
}

.choice {
    flex: 1 1 0;
    position: relative;
}

.choice input {
    position: absolute;
    opacity: 0;
    pointer-events: none;
}

.choice span {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 2.6rem;
    border: 1px solid var(--field);
    border-radius: var(--radius);
    background: var(--surface-soft);
    color: var(--ink);
    cursor: pointer;
}

.choice input:checked + span {
    border-color: var(--navy);
    background: var(--navy-wash);
    color: var(--navy-deep);
    font-weight: 600;
}

.choice input:focus-visible + span {
    outline: 2px solid var(--navy);
    outline-offset: 2px;
}

.form-field--choice.is-wrong .choice span {
    border-color: #d9a3ab;
}

/* ==========================================================================
   The shelf: the books this account holds
   --------------------------------------------------------------------------
   Spines, not rows. A book is its cover, its size and the three doors an owner
   wants from it — where they stopped, the contents, what they kept.
   ========================================================================== */

.shelf {
    max-width: 52rem;
    width: 100%;
    margin: 0 auto;
    padding: 2rem 1.25rem 3.5rem;
    box-sizing: border-box;
}

.shelf__heading {
    margin: 0 0 1.75rem;
    font-family: var(--font-book);
    font-size: 1.75rem;
    font-weight: 700;
    color: var(--ink-strong);
}

.shelf__list {
    display: grid;
    gap: 1rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

.shelf__book {
    display: flex;
    align-items: flex-start;
    gap: 1.25rem;
    padding: 1.25rem;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-card);
    box-shadow: var(--shadow-card);
}

/* The cover sits on the stage the reader's paper sits on, so a page with a white margin does
   not bleed into the card around it. */
.shelf__cover {
    flex: 0 0 auto;
    display: block;
    width: 7.5rem;
    border-radius: var(--radius);
    background: var(--stage);
    overflow: hidden;
    line-height: 0;
}

.shelf__cover img {
    width: 100%;
    height: auto;
    border: 1px solid var(--paper-edge);
    border-radius: var(--radius);
    box-sizing: border-box;
}

.shelf__about {
    flex: 1 1 auto;
    min-width: 0;
}

.shelf__title {
    margin: 0;
    font-family: var(--font-book);
    font-size: 1.3rem;
    font-weight: 700;
    line-height: 1.5;
}

.shelf__title a {
    color: var(--ink-strong);
    text-decoration: none;
}

.shelf__title a:hover {
    color: var(--navy);
}

.shelf__facts {
    margin: 0.2rem 0 0;
    color: var(--ink-soft);
    font-size: 0.85rem;
}

.shelf__actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.6rem;
    margin-top: 1rem;
}

.shelf__actions .button {
    min-height: 2.25rem;
    padding: 0.4rem 0.9rem;
    font-size: 0.9rem;
}

/* The one line on this page that is the house's business and not the reader's. */
.shelf__licence {
    margin: 0.9rem 0 0;
    color: var(--ink-faint);
    font-size: 0.78rem;
}

/* How far in they already are: the reader's own bar, drawn under the one door the card offers. */
.shelf__progress {
    margin-top: 1rem;
}

.shelf__progress-track {
    display: block;
    height: 4px;
    border-radius: var(--radius-pill);
    background: var(--line-soft);
    overflow: hidden;
}

.shelf__progress-fill {
    display: block;
    height: 100%;
    border-radius: var(--radius-pill);
    background: var(--navy);
}

.shelf__read {
    margin: 0.4rem 0 0;
    color: var(--ink-soft);
    font-size: 0.78rem;
}

/* The bin that gives a kept place back, in the side menu where the list lives. */
.kept__bin {
    display: grid;
    flex: 0 0 auto;
    place-items: center;
    width: 2rem;
    height: 2rem;
    border: 1px solid #dfe5ea;
    border-radius: 50%;
    background: var(--surface);
    color: #9aa7b1;
    cursor: pointer;
}

.kept__bin:hover {
    border-color: var(--keep);
    color: var(--keep);
}

/* A page that will not open, a day's limit reached, a route that is not there. */
.error {
    max-width: 32rem;
    width: 100%;
    margin: 12vh auto;
    padding: 2rem;
    box-sizing: border-box;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-card);
    text-align: center;
}

.error h1 {
    margin: 0 0 0.75rem;
    font-size: 1.3rem;
    font-weight: 600;
    color: var(--ink-strong);
}

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

.error button {
    padding: 0.5rem 1.25rem;
    border: 1px solid var(--field);
    border-radius: var(--radius);
    background: var(--surface);
    color: var(--navy);
    font: inherit;
    cursor: pointer;
}

.error button:hover {
    border-color: var(--navy);
    background: var(--navy-wash);
}

.locked__citation {
    margin: 0 0 0.5rem;
    color: var(--ink-faint);
    font-size: 0.8rem;
    font-variant-numeric: tabular-nums;
}

.locked__links {
    display: flex;
    flex-wrap: wrap;
    gap: 0.6rem;
    justify-content: center;
    margin-top: 1.5rem;
}

.locked__links a {
    display: inline-flex;
    align-items: center;
    padding: 0.5rem 1.15rem;
    border: 1px solid var(--navy);
    border-radius: var(--radius);
    background: var(--navy);
    color: #fff;
    text-decoration: none;
    font-size: 0.9rem;
}

.locked__links a:hover {
    background: var(--navy-deep);
    border-color: var(--navy-deep);
    color: #fff;
}

/* ==========================================================================
   10 · The reader: the shell and its bands
   ========================================================================== */

.reader-shell {
    display: grid;
    grid-template-rows: auto minmax(0, 1fr);
    height: 100dvh;
    overflow: hidden;
    background: var(--ground);
}

/* Reading mode: the site taken from around the book, so the window holds the book and nothing
   else. It is the page's own doing and not the browser's — the tab strip and the address bar
   stay — and the tool that turns it on stays on the bar to turn it off. */
.reader-shell.is-bare .site__header {
    display: none;
}

/* A sheet fits itself to the window less the bands above it, and one of them has just gone.
   0px rather than 0: it is read inside a calc, where a bare zero is not a length. */
.reader-shell.is-bare {
    --site-header: 0px;
    /* and the rail loses its words with it: reading mode is for giving the page the room, and
       four icons a reader has already met do not need naming a second time. The words are taken
       off the screen rather than out of the document — the rule is with `.visually-hidden` in
       §2 — so the menu still reads aloud as four named tabs. */
    --rail-width: 3.1rem;
}

.reader-shell.is-bare .reader__tab {
    padding: 0.5rem 0.2rem;
}

.reader {
    display: grid;
    /* two places, neither floating over the other: the side menu, then the book */
    grid-template-columns: auto minmax(0, 1fr);
    min-height: 0;
    overflow: hidden;
    /* the gap between two sheets of the scroll, and the line that says how far through you are */
    --sheet-gap: 1.25rem;
    --strip-height: 3px;
    --panel-width: min(26rem, 80vw);
}

.reader__book {
    position: relative;
    display: grid;
    /* which book, the bar, how far through you are, then the two panes */
    grid-template-rows: var(--banner-height) var(--bar-height) var(--strip-height) minmax(0, 1fr);
    /* How much of the width the words take. It is declared here, where the panes controller
       writes it: declared on `.reader__panes` it beat its own inherited value, which is why
       the divider moved for a whole ticket without the panes moving with it. */
    --text-share: 50%;
    min-width: 0;
    overflow: hidden;
    background: var(--stage);
}

/* The book's own bar: what you are reading, where you are in it, how you see it. */
.reader__top {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
    align-items: center;
    gap: 1rem;
    padding: 0 1.25rem;
    background: var(--surface);
    border-block-end: 1px solid var(--line);
    white-space: nowrap;
}

/* Which book, on a band above the bar. Its own row and not a second line inside the first
   cell: stacked there it was the only cell of the three standing two lines tall, and the page
   controls beside it had to centre against something half again their height. Both lines are
   the book's own words, so both keep its face (D43); the name is the quieter of the two,
   being the one that does not change as you read. */
.reader__banner {
    display: flex;
    /* centred and not on a baseline: the band has a height of its own, and baseline alignment
       would put the group at the top of it rather than in the middle */
    align-items: center;
    gap: 0.4rem;
    box-sizing: border-box;
    height: var(--banner-height);
    padding-inline: 1.25rem;
    background: var(--surface);
    border-block-end: 1px solid var(--line-soft);
}

/* The word, set in the interface face and not the book's (D43): it is the band's own label
   rather than part of the title it introduces, and it never shortens — a long name is the only
   thing there is any point in cutting. */
.reader__banner-label {
    flex: 0 0 auto;
    font-family: var(--font-ui);
    font-size: 0.7rem;
    color: var(--ink-faint);
}

.reader__book-name {
    flex: 0 1 auto;
    min-width: 0;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    font-family: var(--font-book);
    font-size: 0.85rem;
    /* Leading, not a tight box. The ellipsis wants `overflow: hidden`, which makes this span's
       own box the thing that clips, and Amiri setting a vocalised title overruns its em box by
       more than most faces do — first a line-height of 1 took the حركات off the top, then 1.6
       still caught them. The padding is the belt to that brace: it holds the clipping edge off
       the glyphs without making the line itself any taller. */
    line-height: 2;
    padding-block: 0.15rem;
    color: var(--ink-soft);
}

.reader__named {
    grid-column: 1;
    display: flex;
    align-items: baseline;
    gap: 0.6rem;
    min-width: 0;
    justify-self: start;
}

.reader__title {
    flex: 0 1 auto;
    min-width: 0;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    font-family: var(--font-book);
    font-size: 1.25rem;
    font-weight: 700;
    color: var(--ink-strong);
}

/* The one badge that says what you are holding: a reading copy, not the book. */
.reader__badge {
    flex: 0 0 auto;
    padding: 0.1rem 0.55rem;
    border-radius: var(--radius-pill);
    background: var(--sample-bg);
    color: var(--sample-ink);
    font-size: 0.7rem;
    font-weight: 600;
}

/* The page controls (ticket 43). A picture of a control, not a sentence: the
   arrangement is fixed left to right and does not flip with the language. */
.reader__where {
    grid-column: 2;
    direction: ltr;
    display: flex;
    align-items: center;
    gap: 0.35rem;
    justify-self: center;
}

.reader__step {
    display: grid;
    place-items: center;
    width: 2rem;
    height: 2rem;
    border: 1px solid var(--field);
    border-radius: var(--radius);
    background: var(--surface);
    color: var(--navy);
    text-decoration: none;
    font-size: 1.1rem;
    line-height: 1;
}

.reader__step:hover {
    border-color: var(--navy);
    background: var(--navy-wash);
    color: var(--navy-deep);
}

/* Dimmed and inert: the flow turns these on and off as the reader moves, and an arrow with
   nowhere to go must not be clickable while it is still in the document (ticket 53). */
.reader__step.is-disabled {
    opacity: 0.3;
    pointer-events: none;
}

.reader__go {
    display: flex;
    align-items: center;
    gap: 0.35rem;
}

/* The page box: the number, and what the volume runs to, in one field. */
.reader__go-page {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    box-sizing: border-box;
    height: 2rem;
    padding: 0 0.6rem;
    border: 1px solid var(--field-strong);
    border-radius: var(--radius);
    background: var(--surface-soft);
}

/* the arrows either side are how a page is stepped, so the box itself has no stepper */
.reader__go input[name="page"] {
    width: 2.8rem;
    border: 0;
    padding: 0;
    background: transparent;
    color: var(--ink);
    font: inherit;
    font-size: 1rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    text-align: center;
}

.reader__go input[name="page"]:focus {
    outline: none;
}

.reader__go-page:focus-within {
    border-color: var(--navy);
}

.reader__divider {
    width: 1px;
    height: 1.35rem;
    margin: 0 0.35rem;
    background: var(--line);
}

/* The volume chooser. The label draws the control and the select fills it completely, so
   there is no inner box to show: a select left at its own size sits inside the border as a
   second shape, with the arrows stranded outside it. Anything an engine still insists on
   drawing is clipped to the label's own edge. */
.reader__go--volume label {
    position: relative;
    display: inline-flex;
    align-items: stretch;
    height: 2rem;
    border: 1px solid var(--field);
    border-radius: var(--radius);
    background: var(--surface);
    overflow: hidden;
}

.reader__go--volume label:hover {
    border-color: var(--navy);
}

/* our own two arrows: a select's are the browser's and cannot be made to match the bar */
.reader__go--volume label::before {
    content: "⇅";
    position: absolute;
    inset-inline-start: 0.55rem;
    top: 50%;
    transform: translateY(-50%);
    color: var(--ink-soft);
    font-size: 0.75rem;
    pointer-events: none;
}

.reader__go select {
    appearance: none;
    -webkit-appearance: none;
    height: 100%;
    margin: 0;
    border: 0;
    border-radius: inherit;
    /* room at the start for the arrows the label draws */
    padding-inline: 1.7rem 0.6rem;
    background: transparent;
    box-shadow: none;
    color: var(--ink);
    font: inherit;
    font-size: 0.85rem;
    cursor: pointer;
}

/* What this volume's printed numbers run between, shown while the box is in use. */
.reader__range {
    position: absolute;
    top: calc(100% + 0.5rem);
    left: 50%;
    z-index: 7;
    transform: translateX(-50%);
    border-radius: var(--radius-sm);
    padding: 0.3rem 0.65rem;
    background: var(--navy-deep);
    color: #fff;
    font-size: 0.75rem;
    white-space: nowrap;
    opacity: 0;
    pointer-events: none;
    transition: opacity 120ms ease;
}

.reader__range::before {
    content: "";
    position: absolute;
    bottom: 100%;
    left: 50%;
    border: 0.3rem solid transparent;
    border-bottom-color: var(--navy-deep);
    transform: translateX(-50%);
}

.reader__go-page:hover .reader__range,
.reader__go-page:focus-within .reader__range {
    opacity: 1;
}

/* How you see the page, as against where you are in it (ticket 45). */
.reader__tools {
    grid-column: 3;
    display: flex;
    align-items: center;
    gap: 0.45rem;
    justify-self: end;
}


.reader__tool {
    display: grid;
    place-items: center;
    min-width: 2rem;
    height: 2rem;
    border: 1px solid var(--field);
    border-radius: var(--radius);
    background: var(--surface);
    color: var(--navy);
    font: inherit;
    font-size: 1rem;
    line-height: 1;
    cursor: pointer;
}

.reader__tool:hover,
.reader__zoom-level:hover {
    border-color: var(--navy);
    background: var(--navy-wash);
}

/* Out of room to give: the zoom at its limits, the words at their largest or smallest. Shown
   rather than silently doing nothing, which is what a button that still looks live does. */
.reader__tool[disabled] {
    opacity: 0.4;
    cursor: default;
}

.reader__tool[disabled]:hover {
    background: var(--surface);
}

.reader__tool--first {
    border-start-end-radius: 0;
    border-end-end-radius: 0;
}

.reader__tool--last {
    border-start-start-radius: 0;
    border-end-start-radius: 0;
}

/* The zoom floats over the page it changes rather than sitting in the bar (D44). Bottom, on
   the side away from the side menu — the left in Arabic, the right in English — and clear of
   the chevrons, which sit at the middle of each edge.

   It stands as a column since ticket 49: bigger above, smaller below. A row of three lay
   across the one axis the scroll uses, so reaching for the zoom meant reaching into the swipe. */
.reader__zoom,
.reader__size {
    position: absolute;
    z-index: 4;
    inset-block-end: 1rem;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    border-radius: var(--radius);
    background: var(--surface);
    box-shadow: var(--shadow-card);
}

/* Neither column is held to the bar's 2rem: they float over a page, they are the controls a
   reader reaches for again and again, and on a touchscreen they are reached for with a thumb. */
.reader__zoom .reader__tool,
.reader__size .reader__tool {
    height: 2.4rem;
    font-size: 1.2rem;
}

/* The zoom group carries dir="ltr" of its own — the amount is written in Latin per cent signs
   whatever the page — so a logical inset here would resolve against that and not against the
   page. The side is taken from the page's direction instead: away from the side menu, which
   is the left in Arabic and the right in English. */
[dir="rtl"] .reader__zoom,
[dir="rtl"] .reader__size {
    left: 1rem;
}

[dir="ltr"] .reader__zoom,
[dir="ltr"] .reader__size {
    right: 1rem;
}

/* Upright, the joins are top and bottom rather than start and end. */
.reader__zoom .reader__tool--first,
.reader__size .reader__tool--first {
    border-radius: var(--radius) var(--radius) 0 0;
}

.reader__zoom .reader__tool--last,
.reader__size .reader__tool--last {
    border-radius: 0 0 var(--radius) var(--radius);
}

/* The size of the words, beside the words (ticket 49). Two buttons and no readout: the sizes
   are five steps of a reader's own comfort, and a number would invite reading it as a fact. */
.reader__size {
    width: 2.4rem;
}

/* The readout is the fit state written out, and pressing it goes back to fitted. */
.reader__zoom-level {
    width: 100%;
    height: 2rem;
    border: 1px solid var(--field);
    border-block: 0;
    background: var(--surface-soft);
    color: var(--ink-soft);
    font: inherit;
    font-size: 0.8rem;
    font-variant-numeric: tabular-nums;
    cursor: pointer;
}

.reader__tool[aria-pressed="true"] {
    border-color: var(--navy);
    background: var(--navy);
    color: #fff;
}

/* ==========================================================================
   11 · The reader: the two panes
   --------------------------------------------------------------------------
   The print and the page's own words, side by side, with a boundary between
   them (ticket 46). Which of the two is shown is the viewer's choice; the
   panes controller writes it, the stylesheet only draws it.
   ========================================================================== */

.reader__panes {
    display: flex;
    min-height: 0;
    min-width: 0;
    overflow: hidden;
}

.reader__image {
    position: relative;
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    min-width: 0;
    min-height: 0;
    overflow: hidden;
}

.reader__image[hidden] {
    display: none;
}

/* The words of the page: a column of sayings, each with its number and its tools. Like the
   print, it is a pane holding a scroll, so that a control can float over the words (ticket 49). */
.reader__text {
    position: relative;
    flex: 0 0 var(--text-share);
    display: flex;
    flex-direction: column;
    min-width: 0;
    min-height: 0;
    box-sizing: border-box;
    overflow: hidden;
    background: #fbfaf4;
    border-inline-start: 1px solid var(--line);
    /* how large the words are set, five steps from 0.85 to 1.5 (ticket 49) */
    --text-scale: 1;
}

.reader__scroll {
    /* the flow measures a sheet's place against its scroller, as the stage does for the print */
    position: relative;
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
}

.reader__text[hidden] {
    display: none;
}

/* Alone, the text is the whole of the book's place and reads as a column, not a sidebar. */
.reader__book:not(.is-dual) .reader__text {
    flex: 1 1 auto;
    border-inline-start: 0;
}

.reader__text-none {
    margin: 0;
    color: var(--ink-soft);
    font-size: 0.85rem;
}

/* The boundary between the panes, draggable and nudgeable. */
.reader__split {
    flex: 0 0 auto;
    display: grid;
    place-items: center;
    width: 7px;
    background: #e6e2d5;
    cursor: col-resize;
    touch-action: none;
}

.reader__split[hidden] {
    display: none;
}

.reader__split > span {
    width: 3px;
    height: 2.2rem;
    border-radius: 2px;
    background: #c8c9bd;
}

.reader__split:hover > span,
.reader__split:focus-visible > span,
.reader__split.is-held > span {
    background: var(--navy);
}

/* Which of the panes you want: one group of three, only one of them on. */
.reader__views {
    display: flex;
    border: 1px solid var(--field);
    border-radius: var(--radius);
    overflow: hidden;
}

.reader__view {
    height: 2rem;
    padding: 0 0.7rem;
    border: 0;
    border-inline-start: 1px solid var(--field);
    background: var(--surface);
    color: var(--ink-soft);
    font: inherit;
    font-size: 0.75rem;
    cursor: pointer;
}

.reader__view:first-child {
    border-inline-start: 0;
}

.reader__view:hover {
    background: var(--surface-warm);
}

.reader__view.is-chosen {
    background: var(--navy);
    color: #fff;
    font-weight: 600;
}

.entries {
    margin: 0;
    padding: 0;
    list-style: none;
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
}

.entry {
    padding: 0.85rem 1rem;
    background: var(--surface);
    border: 1px solid var(--line-soft);
    border-radius: var(--radius-card);
}

/* The saying a result sent the reader to, told apart by its edge rather than by its colour. */
.entry.is-found {
    border-color: #e2cfcf;
    background: #fdfaf7;
}

.entry__head {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 0.55rem;
}

.entry__number {
    display: grid;
    place-items: center;
    min-width: 1.75rem;
    height: 1.4rem;
    padding: 0 0.45rem;
    border-radius: var(--radius-pill);
    background: var(--navy-wash);
    color: var(--navy);
    font-size: 0.7rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

.entry__why {
    color: var(--ink-soft);
    font-size: 0.7rem;
}

.entry__gap {
    flex: 1 1 auto;
}

.entry__keep {
    display: flex;
}

.entry__tool {
    display: grid;
    place-items: center;
    width: 1.65rem;
    height: 1.65rem;
    border: 0;
    border-radius: var(--radius-sm);
    background: transparent;
    color: #a8a396;
    cursor: pointer;
}

.entry__tool:hover {
    background: var(--surface-warm);
    color: var(--ink-soft);
}

.entry__tool.is-kept,
.entry__tool.is-kept:hover {
    color: var(--keep);
}

/* A copy that said nothing would look like a copy that failed. */
.entry__tool.is-done {
    background: var(--navy-wash);
    color: var(--navy);
}

/* A page that prints no saying prints prose — the two introductions and the indexes (08b).
   It is one block of running text: no number beside it, no actions, nothing to keep. Set like
   a saying, because it is the same book in the same face, and unselectable for the same reason
   (D49): a highlight will name the word it means by index rather than by a drag. */
.prose {
    display: flex;
    flex-direction: column;
    gap: 0.9rem;
    margin: 0;
    user-select: none;
    -webkit-user-select: none;
    font-family: var(--font-book);
    font-size: calc(1.1rem * var(--text-scale, 1));
    line-height: 2.05;
    color: #23313c;
}

.prose__paragraph {
    margin: 0;
    text-align: justify;
}

/* The page's own heading — «مقدمة المحقق» — centred as the page centres it. */
.prose__heading {
    margin: 0.4rem 0 0.2rem;
    font-size: calc(1.15rem * var(--text-scale, 1));
    font-weight: 600;
    text-align: center;
    color: var(--navy);
}

/* A row of the book's own printed contents: the title, then the page it points at, with the
   rule between them doing what the print's leader dots do — carry the eye across. Dots set as
   text only line up at the width they were set at; a rule lines up at every width, and it
   holds when the reader makes the words larger. The row is not a link: the app has its own
   contents (ticket 13), and this is the book's, printed. */
.prose__row {
    display: flex;
    align-items: baseline;
    gap: 0.5rem;
    margin: 0;
    line-height: 1.9;
}

.prose__title {
    flex: 0 1 auto;
}

.prose__row::after {
    content: "";
    flex: 1 1 auto;
    /* sits on the baseline rather than mid-line, where a leader belongs */
    align-self: flex-end;
    margin-bottom: 0.35em;
    border-bottom: 1px dotted var(--line);
}

.prose__page {
    flex: 0 0 auto;
    color: var(--ink-soft);
    font-variant-numeric: tabular-nums;
}

.entry__words {
    margin: 0;
    /* D49: the words cannot be selected. A highlight will name the word it means by its index
       (every word has one, and a box on the print to go with it), so selection is no longer
       what says which text a reader meant, and dragging across a page stops being a way to
       lift it. The copy button is unaffected — it reads the text, not the selection — and a
       screen reader is unaffected, which is why this is not the thing D41 refused. */
    user-select: none;
    -webkit-user-select: none;
    font-family: var(--font-book);
    font-size: calc(1.1rem * var(--text-scale, 1));
    line-height: 2.05;
    color: #23313c;
}

.entry__words mark {
    background: var(--mark);
    color: var(--ink);
    padding: 0 0.1em;
    border-radius: 2px;
}

.entry__where {
    margin: 0.5rem 0 0;
    color: var(--ink-soft);
    font-size: 0.7rem;
    font-variant-numeric: tabular-nums;
}

/* ==========================================================================
   11b · The reader: the stage and the page
   ========================================================================== */

.reader__stage {
    position: relative;
    overflow-x: hidden;
    overflow-y: auto;
    overscroll-behavior: contain;
    touch-action: pan-y;
    user-select: none;
    -webkit-user-select: none;
    background: var(--stage);
    display: flex;
    flex: 1 1 auto;
    min-height: 0;
    flex-direction: column;
    box-sizing: border-box;
}

.reader__stage.is-zoomed {
    overflow: hidden;
    touch-action: none;
    /* zoomed, the page is bigger than the window and dragging is the only way round it, so the
       pointer says so before the reader has to find out by trying (ticket 49) */
    cursor: grab;
}

.reader__stage.is-zoomed:active {
    cursor: grabbing;
}

/* ==========================================================================
   11c · The reader: the flow, and one sheet of it
   --------------------------------------------------------------------------
   The book as a scroll (ticket 49). A flow holds one sheet per page this
   viewer may open; the sheet being read is `.is-here`. In مزدوج the flow
   shows that one sheet and hides the rest, which is the spread.
   ========================================================================== */

.reader__flow {
    /* the flow corrects the scroll itself when a sheet above the reader changes height; the
       browser's own anchoring would correct for the same change again, and twice is a jump */
    overflow-anchor: none;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--sheet-gap);
    /* a book shorter than the stage sits in the middle of it, not against the bar */
    justify-content: safe center;
    min-height: 100%;
    box-sizing: border-box;
    padding: 1rem 0;
}

.reader__flow--text {
    padding-inline: 1rem;
}

/* The page is paper on a stage, with an edge of its own: it is a sheet, not the window. */
.reader__sheet {
    box-sizing: border-box;
    /* Fit to width on phones; on wide screens fit the whole page to the height instead. */
    width: min(100%, calc((100dvh - var(--site-header) - var(--banner-height) - var(--bar-height) - var(--strip-height) - 2rem) / var(--page-aspect)));
    flex: 0 0 auto;
    position: relative;
    z-index: 2;
    transform-origin: 0 0;
    background: var(--paper);
    border: 1px solid var(--paper-edge);
    box-shadow: var(--shadow-card);
}

/* A sheet of words takes **the same box as the print** and none of its furniture: no paper, no
   border, no shadow — it is the text of a page, not a picture of one. Same width and the page's
   own shape as a floor, so that scrolling نص is scrolling pages rather than one long column,
   and so that the reader can see where one page ends and the next begins.
   The floor is a floor and not a height: the words are set at whatever size the reader chose,
   so a page of them can run longer than the page that printed them and must not be clipped. */
.reader__sheet--text {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    align-content: start;
    /* a little inset, so the words are not flush with the page's own edge */
    padding: 0 0.4rem 1.5rem;
    background: none;
    border: 0;
    box-shadow: none;
}

.reader__sheet--text > * {
    grid-column: 1;
}

/* the page's own height, as an empty item the words share a row with: the row takes the taller
   of the two, so a short page still reads as a page and a long one simply runs on.

   It shares the cell with the sayings and is painted after them, so without this it lies over
   every one of them: in نص the copy and the keep took no press and the words took no selection,
   because the thing being pressed was this floor. It measures a row; it is not there to be hit. */
.reader__book.is-flowing .reader__sheet--text::after {
    content: "";
    grid-row: 2;
    grid-column: 1;
    aspect-ratio: 1 / var(--page-aspect, 1.33);
    pointer-events: none;
}

.reader__sheet--text > .entries,
.reader__sheet--text > .prose,
.reader__sheet--text > .reader__text-none {
    grid-row: 2;
}

/* Which page these words are printed on, between one sheet and the next: in نص there is no
   printed page number to read, and the bar alone cannot say where a page ends. */
.reader__sheet-mark {
    grid-row: 1;
    /* above the sweep that passes over a sheet still waiting */
    position: relative;
    z-index: 2;
    display: flex;
    align-items: center;
    gap: 0.7rem;
    /* the tag's own height, carried whether or not there is a tag: a sheet still waiting has
       no page id to keep and so no tag, and without this the words stepped down as it arrived */
    min-height: 1.5rem;
    padding-block: 0.9rem 1.1rem;
    color: var(--ink-soft);
    font-size: 0.7rem;
    font-variant-numeric: tabular-nums;
}

.reader__sheet-mark::before,
.reader__sheet-mark::after {
    content: "";
    flex: 1 1 auto;
    height: 1px;
    background: var(--line);
}

/* Keeping the page, from the words. نص has no page to hang a ribbon from, so the marker
   carries it: the one thing on a sheet of words that is about the page and not about a saying. */
.reader__mark-keep {
    flex: 0 0 auto;
    margin-inline-start: -0.3rem;
}

.reader__mark-tag {
    display: grid;
    place-items: center;
    width: 1.5rem;
    height: 1.5rem;
    border: 0;
    border-radius: 50%;
    background: none;
    color: var(--ink-soft);
    cursor: pointer;
}

.reader__mark-tag:hover {
    background: var(--navy-wash);
    color: var(--navy);
}

.reader__mark-tag.is-kept {
    color: var(--keep);
}

/* In مزدوج the marker keeps the page and says nothing else. The two panes face one page and
   the bar already says which, so the citation would be saying it a second time; the rule and
   the tag stay, because a reader with their eyes on the words should not have to cross to the
   other pane — and in مزدوج the print's ribbon can be scrolled out from under them.
   (The page-shaped floor is already نص's alone: it would put empty room under a short page.) */
.reader__book:not(.is-flowing) .reader__sheet-said {
    display: none;
}

/* Carrying nothing — a sheet still waiting, a sample, someone signed out — it would be a rule
   drawn across the top of the words for no reason. Hidden rather than dropped, so the words sit
   where they will sit once it has something to say. */
.reader__book:not(.is-flowing) .reader__sheet-mark:not(:has(.reader__mark-keep)) {
    visibility: hidden;
}

/* Waiting for its parts: paper with grey bars where the lines will be, at the page's own shape,
   so that filling it in moves nothing. Drawn rather than loaded — a placeholder that fetched
   something would be the thing it stands in for.

   A light passes over it while it waits. Still bars look like a page that has arrived and is
   simply blank; the sweep is what says the page is on its way. */
.reader__sheet[data-state="pending"] {
    overflow: hidden;
    aspect-ratio: 1 / var(--page-aspect, 1.33);
    /* `center`, not `8% 9%`: a background percentage aligns that point of the image with the
       same point of the box, so with an image 84% as wide the offset it actually gives is
       8% × 16% — a hair over one per cent, and the bars sat against the left edge. Centred, the
       same size leaves the 8% and 9% margins that were meant all along. */
    background:
        repeating-linear-gradient(to bottom, transparent 0 1.1rem, var(--paper-lines) 1.1rem 1.7rem)
            center / 84% 82% no-repeat,
        var(--paper);
}

/* A sheet of words waiting: the same bars, no paper under them, and its own height comes from
   the floor every text sheet has rather than from this rule. */
.reader__sheet--text[data-state="pending"] {
    aspect-ratio: auto;
    background: none;
}

.reader__sheet--text[data-state="pending"] > .reader__sheet-mark {
    opacity: 0.55;
}

/* The bars ride on the floor the rule above draws — and that floor is only drawn in a scroll,
   so in مزدوج this said `background` to a pseudo-element that was never generated: a page of
   words loaded there with nothing to show for itself but a dimmed citation. A placeholder is
   wanted wherever a page is waited for, so it asks for the floor itself rather than borrowing
   one, and in a scroll it asks for exactly what is already there. */
.reader__sheet--text[data-state="pending"]::after {
    content: "";
    grid-row: 2;
    grid-column: 1;
    aspect-ratio: 1 / var(--page-aspect, 1.33);
    background:
        repeating-linear-gradient(to bottom, transparent 0 1.1rem, var(--paper-lines) 1.1rem 1.7rem)
            0 0 / 100% 100% no-repeat;
}

/* Only the sheets actually being fetched sweep. A book is laid out as a thousand placeholders
   at once, and a thousand infinite animations is a thousand things for the browser to keep
   painting; the rest are simply pages not asked for yet, which is a different thing from
   loading and should not claim to be one. */
.reader__sheet[data-state="pending"].is-waiting::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 1;
    background: linear-gradient(105deg, transparent 38%, rgb(255 255 255 / 60%) 50%, transparent 62%);
    animation: reader-waiting 1.5s linear infinite;
}

@keyframes reader-waiting {
    from { transform: translateX(-100%); }
    to { transform: translateX(100%); }
}

/* a sweep is a nice-to-have; for anyone who has asked for less movement it is a plain dim */
@media (prefers-reduced-motion: reduce) {
    .otp__box,
    .otp--shake .otp__row,
    .otp__status::before {
        animation: none !important;
        transition: none;
    }

    .reader__sheet[data-state="pending"].is-waiting::before {
        animation: none;
        background: none;
    }

    .reader__sheet[data-state="pending"] {
        opacity: 0.75;
    }

}

/* the page's own number, the one thing about it that is known before it arrives. The words
   carry theirs in the marker between sheets, so it is the print that wants this. */
.reader__sheet:not(.reader__sheet--text)[data-state="pending"]::after {
    content: attr(data-label);
    position: absolute;
    inset-inline: 0;
    bottom: 0.9rem;
    text-align: center;
    color: var(--ink-soft);
    font-size: 0.7rem;
    opacity: 0.5;
}

.reader__sheet img {
    display: block;
    width: 100%;
    height: auto;
    pointer-events: none;
}

.reader__sheet.is-animating {
    transition: transform 200ms ease-out;
}

.reader__sheet.is-gesturing {
    will-change: transform;
}

/* Both together is one page at a time (ticket 49): the spread shows the sheet being read and
   nothing above or below it, so the two panes always face the same page. */
.reader__book:not(.is-flowing) .reader__sheet:not(.is-here) {
    display: none;
}

/* Zooming isolates the sheet, or dragging to pan and scrolling to turn would want the same
   gesture and the sheets around it would disagree in size. */
.reader__stage.is-zoomed .reader__flow {
    justify-content: flex-start;
    padding: 0;
}

.reader__stage.is-zoomed .reader__sheet:not(.is-here) {
    display: none;
}

.reader__stage.is-zoomed .reader__sheet {
    border: 0;
    box-shadow: none;
}

/* The book goes on that way, and not for this reader: paper that can be reached, never opened. */
.reader__sheet--locked {
    aspect-ratio: 1 / var(--page-aspect, 1.33);
    display: flex;
    align-items: center;
    justify-content: center;
    background:
        repeating-linear-gradient(to bottom, transparent 0 22px, rgb(44 84 110 / 10%) 22px 30px) 0 18% / 70% 60% no-repeat,
        var(--paper);
}

.reader__lock {
    max-width: 70%;
    padding: 0.9rem 1.1rem;
    background: rgb(255 255 255 / 92%);
    border: 1px solid var(--line);
    border-radius: var(--radius-card);
    color: var(--ink-strong);
    text-align: center;
    line-height: 1.8;
    font-size: 0.9rem;
}

.reader__lock::before {
    content: "🔒";
    display: block;
    font-size: 1.5rem;
    margin-bottom: 0.3rem;
}


/* The page arrows: ‹ › when a page is turned, and the same two chevrons turned a quarter to
   point down and up when it is scrolled to — turned rather than swapped for ⌄ ⌃, which are two
   drawings of unequal weight in most typefaces and looked it. Each keeps its slot, so forward is
   always in the same place whichever way the book is being moved through. */
.reader__arrow {
    display: block;
    line-height: 1;
}

.reader__book.is-flowing .reader__arrow {
    transform: rotate(-90deg);
}


/* Keeping a place (ticket 39): a ribbon hanging from the page's top corner, the way a ribbon
   marks a book. Solid once the page — or the saying marked on it — is in the reader's list.
   It sits inside .reader__sheet, so it travels with the page as it slides. */
.reader__ribbon {
    position: absolute;
    top: 0;
    left: 6%;
    z-index: 3;
}

.reader__ribbon-tag {
    display: flex;
    align-items: flex-start;
    justify-content: center;
    width: 1.35rem;
    height: 2.2rem;
    padding: 0.2rem 0 0;
    border: 0;
    background: rgb(138 43 43 / 30%);
    color: #fff;
    font: inherit;
    font-size: 0.8rem;
    line-height: 1;
    cursor: pointer;
    /* the swallowtail that makes it read as a ribbon rather than a button */
    clip-path: polygon(0 0, 100% 0, 100% 100%, 50% 78%, 0 100%);
    transition: background 150ms ease;
}

.reader__ribbon-tag:hover {
    background: rgb(138 43 43 / 60%);
}

.reader__ribbon-tag.is-kept {
    background: var(--keep);
}

/* zoomed, the page's corner can be off-screen, and the hints hide for the same reason */
.reader:has(.reader__stage.is-zoomed) .reader__ribbon {
    opacity: 0;
    pointer-events: none;
}

/* Kept out of flow-positioning on purpose: an absolutely positioned wrapper would be its own
   compositing layer and the words' multiply blend would not reach the page image beneath
   (found by Mhmd). The words position against .reader__sheet directly. */
.reader__marks {
    pointer-events: none;
}

/* The words marked on the print: the ones a search found, or — where nothing was searched for
   — every word of the saying a kept place points at. Translucent, so the ink shows through
   wherever blending is unavailable; multiply on top where it is.

   A marker over the words rather than a box round them: the box was drawn from the saying's
   recorded outline and sat visibly off the ink, while the word boxes are the text's own and
   follow it line by line. */
.reader__word {
    position: absolute;
    background: rgb(246 226 168 / 60%);
    mix-blend-mode: multiply;
    border-radius: 3px;
    padding: 0;
    animation: reader-pin-in 300ms ease-out;
}

/* A place that was kept, not a result. The same marker in the rose of the card the saying gets
   in the words (.entry.is-found), so the two read as one thing seen twice — and so the reader
   can tell at a glance which of the two panels sent them here. */
.reader__word--kept {
    background: rgb(234 186 186 / 58%);
}

@keyframes reader-pin-in {
    from { opacity: 0; }
    to { opacity: 1; }
}




/* How far through the book you are (ticket 49): one line the width of the book, directly under
   the bar that says which page you are on. The sentence it replaces — «٧ من ١٣١٢ · ٣٪» — said
   the same thing twice and took a band of its own to do it, and the percentage that stood at the
   line's end said it a third time. All of it stays as the bar's accessible text, where it costs
   no room; what is left is the line, on no band and in no box of its own. */
.reader__progress {
    height: var(--strip-height);
}

.reader__progress-track {
    display: block;
    height: 100%;
}

.reader__progress-fill {
    display: block;
    height: 100%;
    /* where you are, in the one colour nothing else in the reader may use */
    background: var(--keep);
    transition: width 200ms ease-out;
}

/* ==========================================================================
   12 · The reader: the side menu
   --------------------------------------------------------------------------
   Four sections on a rail, one open at a time, in one of three widths: the
   rail alone, a panel docked beside the page, or a panel floating over it
   (ticket 44). Docked, the rail and the panel are flush columns of the same
   white as the bars above them — one surface, not cards on a ground.
   ========================================================================== */

.reader__sidebar {
    position: relative;
    display: flex;
    align-items: stretch;
    min-height: 0;
    background: var(--surface);
}

.reader__rail {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.25rem;
    width: var(--rail-width);
    flex: 0 0 auto;
    box-sizing: border-box;
    padding: 0.6rem 0.35rem;
    background: var(--surface);
    border-inline-start: 1px solid var(--line);
}

.reader__tab {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.15rem;
    width: 100%;
    border: 0;
    border-radius: 9px;
    padding: 0.45rem 0.2rem;
    background: transparent;
    color: var(--ink-soft);
    font: inherit;
    font-size: 0.625rem;
    line-height: 1.4;
    text-align: center;
    cursor: pointer;
}

.reader__tab:hover {
    background: var(--surface-warm);
    color: var(--ink-strong);
}

.reader__tab.is-open {
    background: var(--navy-wash);
    color: var(--navy);
    font-weight: 600;
}

.reader__tab-icon {
    display: flex;
}

/* A section offered but not open (ticket 55). The tab still opens — what is behind it is the
   offer rather than the thing — so it reads as quieter, not as broken. */
.reader__tab.is-shut {
    color: var(--ink-soft);
}

.reader__tab.is-shut .reader__tab-icon {
    opacity: 0.55;
}

.reader__tab.is-shut.is-open .reader__tab-icon {
    opacity: 1;
}

.reader__tab-lock {
    position: absolute;
    inset-block-start: 0.3rem;
    inset-inline-end: 0.3rem;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 15px;
    height: 15px;
    border-radius: 50%;
    background: var(--surface);
    color: var(--sample-ink);
}

.reader__tab.is-open .reader__tab-lock {
    background: var(--navy-wash);
}

/* the label is always there, under its icon, so the rail reads without being explored */
.reader__tab-label {
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* How much menu you want: only a question once something is open. */
.reader__rail-tools {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    width: 100%;
    margin-block-start: auto;
}

/* the hidden attribute loses to a display of our own, so it has to be said again */
.reader__rail-tools[hidden] {
    display: none;
}

.reader__rail-tool {
    display: grid;
    place-items: center;
    width: 100%;
    height: 2.2rem;
    border: 0;
    border-radius: 9px;
    background: transparent;
    color: var(--ink-soft);
    cursor: pointer;
}

.reader__rail-tool:hover {
    background: var(--surface-warm);
    color: var(--ink-strong);
}

.reader__rail-tool.is-on {
    background: var(--navy-wash);
    color: var(--navy);
}

/* the chevrons point at the page, which is the other way round in English */
[dir="ltr"] .reader__mirror {
    transform: scaleX(-1);
}

.reader__panels {
    display: flex;
    pointer-events: auto;
}

.reader__panel {
    display: flex;
    flex-direction: column;
    width: var(--panel-width);
    box-sizing: border-box;
    overflow: hidden;
    background: var(--surface);
    border-inline-start: 1px solid var(--line);
}

.reader__panel[hidden] {
    display: none;
}

/* Every panel opens the same way: what it is, then how many, then the thing itself. */
.reader__panel-head {
    flex: 0 0 auto;
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.75rem;
    padding: 0.8rem 0.9rem 0.7rem;
    border-block-end: 1px solid var(--line-soft);
}

.reader__panel-name {
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--ink-strong);
}

.reader__panel-note {
    color: var(--ink-soft);
    font-size: 0.7rem;
    font-variant-numeric: tabular-nums;
}

.reader__panel-body {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: 0.8rem 0.9rem 1rem;
}

.reader__panel-title {
    margin: 0 0 0.15rem;
    font-family: var(--font-book);
    font-size: 1.25rem;
    font-weight: 700;
    line-height: 1.5;
    color: var(--ink-strong);
}

.reader__panel-by {
    margin: 0 0 0.5rem;
    color: var(--ink-soft);
    font-size: 0.75rem;
}

.reader__panel-tags {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem;
    margin: 0 0 0.25rem;
}

.reader__panel-tags .reader__badge {
    margin-inline-start: 0;
}

.reader__panel-soon {
    margin: 0;
    color: var(--ink-soft);
    font-size: 0.85rem;
}

/* What a visitor finds behind a shut tab: the offer, and the one door that opens it. */
.reader__locked {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.5rem;
    padding: 1.75rem 0.5rem;
    text-align: center;
}

.reader__locked-mark {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 48px;
    height: 48px;
    border-radius: 50%;
    background: var(--surface-warm);
    color: var(--sample-ink);
}

.reader__locked-title {
    margin: 0.25rem 0 0;
    color: var(--ink-strong);
    font-family: var(--font-book);
    font-size: 1rem;
    font-weight: 600;
}

.reader__locked-text {
    margin: 0;
    max-width: 28ch;
    color: var(--ink-soft);
    font-size: 0.85rem;
    line-height: 1.8;
}

.reader__locked-action {
    margin-block-start: 0.5rem;
    padding: 0.45rem 1.1rem;
    border-radius: var(--radius-sm);
    background: var(--navy);
    color: #fff;
    font-size: 0.85rem;
    text-decoration: none;
}

.reader__locked-action:hover {
    background: var(--ink-strong);
}

.reader__panel-count {
    margin: 0 0 0.6rem;
    color: var(--ink-soft);
    font-size: 0.75rem;
    font-variant-numeric: tabular-nums;
}

/* The boundary with the page, draggable and nudgeable. Only the docked panel has one: a
   floating panel is over the page rather than beside it, so there is nothing to drag. */
.reader__grip {
    flex: 0 0 auto;
    display: grid;
    place-items: center;
    width: 7px;
    background: #f1eee4;
    border-inline: 1px solid var(--line);
    cursor: col-resize;
    touch-action: none;
}

.reader__grip[hidden] {
    display: none;
}

.reader__grip > span {
    width: 3px;
    height: 2.2rem;
    border-radius: 2px;
    background: #cfd2c8;
}

.reader__grip:hover > span,
.reader__grip:focus-visible > span,
.reader__grip.is-held > span {
    background: var(--navy);
}

/* Floating takes the panel out of the sidebar's column altogether — absolutely placed past
   its inline-end edge, which is the side the book is on — so the column collapses back to the
   rail and the page does not move. */
.reader__sidebar.is-floating .reader__panels {
    position: absolute;
    inset-block: 0.75rem;
    inset-inline-start: calc(100% + 0.75rem);
    z-index: 3;
}

.reader__sidebar.is-floating .reader__panel {
    max-height: 100%;
    border: 1px solid #dcd9cc;
    border-radius: var(--radius-card);
    box-shadow: var(--shadow-float);
}

/* ==========================================================================
   13 · What is in the panels
   ========================================================================== */

/* — About the book ——————————————————————————————————————————————— */

.reader__cover {
    display: block;
    width: 8rem;
    max-width: 55%;
    margin: 0.6rem 0 0.9rem;
    border: 1px solid var(--paper-edge);
    border-radius: 3px;
    box-shadow: var(--shadow-card);
}

.reader__facts {
    margin: 0.9rem 0 0;
    font-size: 0.8rem;
}

.reader__facts > div {
    display: flex;
    justify-content: space-between;
    gap: 0.75rem;
    padding: 0.5rem 0;
    border-block-start: 1px solid var(--line-soft);
}

.reader__facts dt {
    flex: 0 0 auto;
    color: var(--ink-soft);
}

.reader__facts dd {
    margin: 0;
    text-align: end;
    font-variant-numeric: tabular-nums;
}

.reader__blurb {
    margin: 1rem 0 0;
    font-family: var(--font-book);
    font-size: 0.95rem;
    line-height: 1.95;
    color: #23313c;
}

/* Where you are in the book (ticket 38), as a bar rather than a sentence. */
.reader__place {
    margin-top: 1rem;
    padding: 0.75rem;
    border: 1px solid var(--line-soft);
    border-radius: 9px;
    background: var(--surface-soft);
}

.reader__place-label {
    margin: 0 0 0.45rem;
    color: var(--ink-soft);
    font-size: 0.7rem;
}

.reader__place-bar {
    display: block;
    height: 6px;
    border-radius: 3px;
    background: #e3e0d3;
    overflow: hidden;
}

.reader__place-bar > span {
    display: block;
    height: 6px;
    background: var(--navy);
}

.reader__place-text {
    margin: 0.5rem 0 0;
    font-size: 0.75rem;
    font-variant-numeric: tabular-nums;
}

.reader__buy {
    display: grid;
    place-items: center;
    width: 100%;
    box-sizing: border-box;
    min-height: 2.5rem;
    margin-top: 0.9rem;
    border: 1px dashed #cfccc0;
    border-radius: 9px;
    color: var(--ink-soft);
    font-size: 0.8rem;
    text-align: center;
}

/* — The contents tree ————————————————————————————————————————————— */

.toc-tree__filter input {
    box-sizing: border-box;
    width: 100%;
    margin-bottom: 0.75rem;
    padding: 0.4rem 0.7rem;
    border: 1px solid var(--field);
    border-radius: var(--radius);
    background: var(--surface-soft);
    color: var(--ink);
    font: inherit;
    font-size: 0.8rem;
}

.toc-tree__empty {
    margin: 0 0 0.6rem;
    color: var(--ink-soft);
    font-size: 0.85rem;
}

.toc-tree__volume {
    margin-bottom: 0.25rem;
}

.toc-tree__volume > summary {
    display: flex;
    align-items: center;
    padding: 0.45rem 0.7rem;
    border-radius: var(--radius-sm);
    color: var(--ink-strong);
    font-size: 0.8rem;
    font-weight: 600;
    cursor: pointer;
}

.toc-tree__volume > summary:hover {
    background: var(--surface-warm);
}

.toc-tree__volume[open] > summary {
    background: var(--surface-warm);
}

.toc-tree__list {
    margin: 0.2rem 0 0.4rem;
    padding: 0;
    list-style: none;
}

.toc-tree__row {
    display: flex;
    align-items: center;
    gap: 0.4rem;
}

.toc-tree__row[hidden] {
    display: none;
}

.toc-tree__row > a {
    display: flex;
    flex: 1 1 auto;
    min-width: 0;
    align-items: center;
    gap: 0.4rem;
    box-sizing: border-box;
    padding: 0.4rem 0.75rem;
    border-inline-start: 3px solid transparent;
    border-radius: var(--radius-sm);
    color: #3c4a55;
    text-decoration: none;
}

.toc-tree__row > a:hover {
    background: var(--surface-warm);
}

.toc-tree__label {
    flex: 0 1 auto;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-family: var(--font-book);
    font-size: 0.95rem;
}

/* The printed index's leader, kept: it is what tells a title from its page number. */
.toc-tree__leader {
    flex: 1 1 auto;
    min-width: 0.75rem;
    align-self: center;
    border-bottom: 1px dotted rgb(90 104 117 / 35%);
}

.toc-tree__page {
    flex: 0 0 auto;
    color: var(--ink-soft);
    font-size: 0.7rem;
    font-variant-numeric: tabular-nums;
}

.toc-tree__row.is-here > a {
    background: var(--navy-wash);
    border-inline-start-color: var(--navy);
    color: var(--ink-strong);
    font-weight: 500;
}

.toc-tree__row.is-here .toc-tree__page {
    color: var(--navy);
}

.toc-tree__row--free .badge {
    flex: 0 0 auto;
}

/* A shut row keeps the shape of a row of an index — title, leader, page — and loses only the
   things that promise it can be followed (ticket 55). */
.toc-tree__shut {
    display: flex;
    flex: 1 1 auto;
    min-width: 0;
    align-items: center;
    gap: 0.4rem;
    box-sizing: border-box;
    padding: 0.4rem 0.75rem;
    border-inline-start: 3px solid transparent;
    color: var(--ink-soft);
}

.toc-tree__note {
    margin: 0 0 0.6rem;
    padding: 0.5rem 0.6rem;
    border-inline-start: 2px solid var(--sample-ink);
    border-radius: var(--radius-sm);
    background: var(--surface-warm);
    color: var(--ink-soft);
    font-size: 0.75rem;
    line-height: 1.65;
}

.toc-tree__note a {
    color: var(--navy);
    white-space: nowrap;
}

/* — Searching inside the book ————————————————————————————————————— */

.find__form {
    display: flex;
    gap: 0.4rem;
    margin-bottom: 0.75rem;
}

.find__form label {
    flex: 1 1 auto;
    min-width: 0;
}

.find__form input {
    box-sizing: border-box;
    width: 100%;
    height: 2.25rem;
    padding: 0 0.7rem;
    border: 1px solid var(--field-strong);
    border-radius: var(--radius);
    background: var(--surface-soft);
    color: var(--ink);
    font: inherit;
    font-family: var(--font-book);
    font-size: 1rem;
}

.find__form button {
    flex: 0 0 auto;
    height: 2.25rem;
    padding: 0 0.85rem;
    border: 1px solid var(--navy);
    border-radius: var(--radius);
    background: var(--navy);
    color: #fff;
    font: inherit;
    font-size: 0.8rem;
    font-weight: 600;
    cursor: pointer;
}

.find__form button:hover {
    background: var(--navy-deep);
    border-color: var(--navy-deep);
}

/* The last few searches, above the results in the panel. */
.find__recent {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.35rem;
    margin-bottom: 0.85rem;
    padding-block-end: 0.75rem;
    border-block-end: 1px solid var(--line-soft);
}

/* The panel is too narrow to share a line between the caption and the terms, so the caption
   takes one of its own and the chips get the whole width underneath it. */
.find__recent-label {
    flex: 1 0 100%;
    color: var(--ink-soft);
    font-size: 0.7rem;
}

.find__again {
    font-size: 0.9rem;
}

.found {
    margin: 0;
    padding: 0;
    list-style: none;
    display: flex;
    flex-direction: column;
    gap: 0.45rem;
}

.found__row > a {
    display: block;
    padding: 0.6rem 0.7rem;
    border: 1px solid var(--line-soft);
    border-radius: 9px;
    background: var(--surface);
    color: #243745;
    text-decoration: none;
}

.found__row > a:hover {
    border-color: var(--line);
    background: var(--surface-soft);
}

.found__text {
    display: block;
    font-family: var(--font-book);
    font-size: 0.95rem;
    line-height: 1.95;
}

.found__where {
    display: block;
    margin-top: 0.3rem;
    color: var(--ink-soft);
    font-size: 0.7rem;
    font-variant-numeric: tabular-nums;
}

.found__more {
    margin: 0.85rem 0 0;
    text-align: center;
    font-size: 0.8rem;
}

/* — The reader's own work: kept places and notes ————————————————— */

.research__tabs {
    display: flex;
    margin-block-end: 0.85rem;
    border: 1px solid var(--field);
    border-radius: var(--radius);
    overflow: hidden;
}

.research__tab {
    flex: 1 1 0;
    border: 0;
    border-inline-start: 1px solid var(--field);
    padding: 0.45rem 0.3rem;
    background: var(--surface);
    color: var(--ink-soft);
    font: inherit;
    font-size: 0.75rem;
    cursor: pointer;
}

.research__tab:first-child {
    border-inline-start: 0;
}

.research__tab:hover {
    background: var(--surface-warm);
}

.research__tab.is-shown {
    background: var(--navy);
    color: #fff;
    font-weight: 600;
}

.kept {
    margin: 0;
    padding: 0;
    list-style: none;
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
}

.kept__row {
    display: flex;
    align-items: flex-start;
    gap: 0.5rem;
    padding: 0.55rem 0.6rem;
    border: 1px solid var(--line-soft);
    border-radius: 9px;
}

.kept__row.is-here {
    border-color: #dde7ec;
    background: #f2f6f8;
}

.kept__row > a {
    flex: 1 1 auto;
    min-width: 0;
    color: #243745;
    text-decoration: none;
}

.kept__text {
    display: block;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-family: var(--font-book);
    font-size: 0.95rem;
}

.kept__where {
    display: block;
    color: var(--ink-soft);
    font-size: 0.7rem;
    font-variant-numeric: tabular-nums;
}

/* When it was kept. Its own line, large enough to read at a glance, and kept
   quiet by its colour rather than by its size. */
.kept__when {
    display: block;
    margin-top: 0.15rem;
    color: var(--ink-faint);
    font-size: 0.82rem;
    font-variant-numeric: tabular-nums;
}

.kept__bin {
    width: 1.75rem;
    height: 1.75rem;
}

/* ==========================================================================
   13b · Notes (ticket 47, D57)
   --------------------------------------------------------------------------
   One note to a page, written in the side menu. The reader's own words are
   set in the interface's face, not the book's: they are not part of the
   book. Only a saying cited into a note is set in Amiri, because it is.
   ========================================================================== */

/* Everything here that the script shows and hides has a display of its own, which would
   otherwise outrank the `hidden` attribute and leave it showing. */
.reader__note[hidden],
.note-here [hidden],
.note-list [hidden] {
    display: none;
}

/* The way into a page's note, beside the control that keeps the page. Navy and never the
   kept red: a note is something written, not a place marked. */
.reader__note {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    height: 1.6rem;
    padding: 0 0.55rem;
    border: 1px dashed var(--field-strong);
    border-radius: var(--radius-pill);
    background: rgb(255 255 255 / 85%);
    color: var(--ink-soft);
    font: inherit;
    font-size: 0.7rem;
    line-height: 1;
    white-space: nowrap;
    cursor: pointer;
}

.reader__note:hover {
    border-color: var(--navy);
    color: var(--navy);
}

.reader__note.has-note {
    border-style: solid;
    border-color: #c9d8e2;
    background: var(--navy-wash);
    color: var(--navy);
    font-weight: 600;
}

/* on the print it hangs beside the ribbon, and like the ribbon it goes while the page is zoomed */
.reader__note--print {
    position: absolute;
    top: 0.45rem;
    left: calc(6% + 1.9rem);
    z-index: 3;
}

.reader:has(.reader__stage.is-zoomed) .reader__note--print {
    opacity: 0;
    pointer-events: none;
}

.reader__note--words {
    flex: 0 0 auto;
}

/* Moving to another page's note. While it is asked for, what is shown dims and the sheets' own
   sweep passes over it, so it reads as on its way rather than gone; when it arrives it fades in
   rather than cutting. A quick answer never shows the loading at all (`LOADING_MS`). */
.note-page {
    position: relative;
}

.note-page.is-loading > * {
    opacity: 0.45;
    transition: opacity 150ms ease;
}

.note-page.is-loading::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 5;
    border-radius: 10px;
    background: linear-gradient(105deg, transparent 38%, rgb(255 255 255 / 70%) 50%, transparent 62%) 0 0 / 250% 100% no-repeat;
    /* the light moves, not the layer: a moving layer would spill out of the panel */
    animation: note-waiting 1.5s linear infinite;
    pointer-events: none;
}

@keyframes note-waiting {
    from { background-position: 100% 0; }
    to { background-position: 0 0; }
}

.note-page.is-arriving {
    animation: note-arrive 180ms ease-out;
}

@keyframes note-arrive {
    from { opacity: 0.35; }
    to { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
    .note-page.is-loading::before {
        animation: none;
        background: none;
    }

    .note-page.is-arriving {
        animation: none;
    }
}

/* The panel: this page's note, then the book's. */
.note-here {
    display: flex;
    flex-direction: column;
    gap: 0.55rem;
    margin-block-end: 1.1rem;
}

.note-here__head {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.note-here__name {
    color: var(--ink-strong);
    font-size: 0.8rem;
    font-weight: 600;
}

.note-here__where {
    padding: 0.05rem 0.5rem;
    border-radius: var(--radius-pill);
    background: var(--navy-wash);
    color: var(--navy);
    font-size: 0.7rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

.note-start {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.6rem;
    padding: 1.1rem 0.9rem;
    border: 1px dashed var(--field-strong);
    border-radius: 10px;
    background: var(--surface-soft);
    text-align: center;
}

.note-start__none {
    margin: 0;
    color: var(--ink-soft);
    font-size: 0.82rem;
}

.note-start__write {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    min-height: 2.5rem;
    padding: 0 1rem;
    border: 0;
    border-radius: var(--radius);
    background: var(--navy);
    color: #fff;
    font: inherit;
    font-size: 0.82rem;
    font-weight: 600;
    cursor: pointer;
}

.note-start__write:hover {
    background: var(--navy-deep);
}

.note-editor {
    position: relative;
    display: flex;
    flex-direction: column;
    border: 1px solid var(--field-strong);
    border-radius: 10px;
    background: var(--surface);
}

.note-editor:focus-within {
    border-color: var(--navy);
}

.note-editor__tools {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.1rem;
    padding: 0.3rem 0.35rem;
    border-bottom: 1px solid var(--line);
    border-radius: 10px 10px 0 0;
    background: var(--surface-soft);
}

.note-editor__divider {
    width: 1px;
    height: 1.1rem;
    margin: 0 0.25rem;
    background: var(--field);
}

.note-editor__gap {
    flex: 1 1 auto;
}

.note-editor__marks {
    display: inline-flex;
    align-items: center;
    gap: 0.2rem;
    margin-inline-end: 0.2rem;
}

.note-tool {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.25rem;
    min-width: 1.9rem;
    height: 1.9rem;
    padding: 0 0.3rem;
    border: 0;
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--ink-soft);
    font: inherit;
    font-size: 0.72rem;
    cursor: pointer;
}

.note-tool:hover:not(:disabled) {
    background: var(--surface-warm);
    color: var(--ink-strong);
}

.note-tool.is-on {
    background: var(--navy-wash);
    color: var(--navy);
}

.note-tool:disabled {
    color: var(--field-strong);
    cursor: default;
}

.note-tool--cite {
    color: var(--navy);
    font-weight: 600;
}

/* the colour the highlight will lay down, under its pen */
.note-tool__ink {
    position: absolute;
    bottom: 0.25rem;
    left: 50%;
    width: 0.85rem;
    height: 0.2rem;
    border-radius: 2px;
    transform: translateX(-50%);
}

.note-swatch {
    width: 1.05rem;
    height: 1.05rem;
    padding: 0;
    border: 1px solid var(--field-strong);
    border-radius: 50%;
    cursor: pointer;
}

.note-swatch[aria-pressed="true"] {
    outline: 2px solid var(--navy);
    outline-offset: 1px;
}

/* the three colours, and only these: none of them is the red that marks a kept place */
.note-tool__ink[data-colour="yellow"],
.note-swatch[data-colour="yellow"],
.note-body mark,
.note-body mark[data-colour="yellow"] {
    background: var(--mark);
}

.note-tool__ink[data-colour="green"],
.note-swatch[data-colour="green"],
.note-body mark[data-colour="green"] {
    background: #d6e7da;
}

.note-tool__ink[data-colour="blue"],
.note-swatch[data-colour="blue"],
.note-body mark[data-colour="blue"] {
    background: #d7e4ef;
}

.note-editor__body {
    min-height: 9rem;
    max-height: 26rem;
    overflow-y: auto;
}

/* the note itself, in the editor and shown without one */
.note-body {
    padding: 0.75rem 0.9rem 0.5rem;
    color: var(--ink);
    font-family: var(--font-ui);
    font-size: 0.88rem;
    line-height: 1.85;
    overflow-wrap: anywhere;
}

.note-editor__prose {
    min-height: 8rem;
    outline: none;
}

.note-body p,
.note-body ul,
.note-body ol,
.note-body blockquote,
.note-body figure {
    margin: 0 0 0.5rem;
}

.note-body h3 {
    margin: 0 0 0.25rem;
    color: var(--ink-strong);
    font-size: 1rem;
    font-weight: 600;
}

.note-body ul,
.note-body ol {
    padding-inline-start: 1.2rem;
}

.note-body li p {
    margin: 0;
}

.note-body blockquote {
    padding-inline-start: 0.75rem;
    border-inline-start: 2px solid var(--field-strong);
    color: var(--ink-soft);
}

.note-body mark {
    padding: 0 0.1em;
    border-radius: 2px;
    color: inherit;
}

/* a saying cited into the note: the book's words in the book's face, and where they are */
.note-body figure {
    padding: 0.45rem 0.75rem;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--surface-soft);
}

.note-body figure blockquote {
    margin: 0;
    padding: 0;
    border: 0;
    color: #23313c;
    font-family: var(--font-book);
    font-size: 1.02rem;
    line-height: 1.9;
}

.note-body figcaption {
    font-size: 0.72rem;
    font-weight: 600;
}

.note-body figcaption a {
    color: var(--navy);
    text-decoration: none;
}

.note-body figure.ProseMirror-selectednode {
    outline: 2px solid var(--navy);
    outline-offset: 1px;
}

.note-editor__prose p.is-editor-empty:first-child::before {
    content: attr(data-placeholder);
    float: inline-start;
    height: 0;
    color: var(--ink-faint);
    pointer-events: none;
}

.note-editor__foot {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    min-height: 2.1rem;
    padding: 0.15rem 0.35rem 0.15rem 0.75rem;
    border-top: 1px solid var(--line-soft);
    color: var(--ink-soft);
    font-size: 0.72rem;
}

[dir="ltr"] .note-editor__foot {
    padding: 0.15rem 0.75rem 0.15rem 0.35rem;
}

/* قول: the sayings this page prints, over the note */
.note-picker {
    position: absolute;
    top: 2.7rem;
    inset-inline: 0.35rem;
    z-index: 4;
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    max-height: 16rem;
    overflow-y: auto;
    padding: 0.35rem;
    border: 1px solid var(--line);
    border-radius: 10px;
    background: var(--surface);
    box-shadow: 0 8px 24px rgb(27 54 72 / 14%);
}

.note-picker__option {
    display: flex;
    align-items: baseline;
    gap: 0.55rem;
    padding: 0.35rem 0.5rem;
    border: 0;
    border-radius: var(--radius);
    background: transparent;
    color: var(--ink);
    font: inherit;
    text-align: start;
    cursor: pointer;
}

.note-picker__option:hover,
.note-picker__option:focus-visible {
    background: #f2f6f8;
}

.note-picker__number {
    flex: 0 0 auto;
    min-width: 1.75rem;
    padding: 0.05rem 0.4rem;
    border-radius: var(--radius-pill);
    background: var(--navy-wash);
    color: var(--navy);
    font-size: 0.65rem;
    font-weight: 600;
    text-align: center;
    font-variant-numeric: tabular-nums;
}

.note-picker__words {
    font-family: var(--font-book);
    font-size: 0.95rem;
    line-height: 1.8;
}

/* The book's notes, under the page's */
.note-list__filter {
    display: flex;
    align-items: center;
    gap: 0.45rem;
    height: 2.3rem;
    margin-block-end: 0.7rem;
    padding: 0 0.6rem;
    border: 1px solid var(--field);
    border-radius: var(--radius);
    color: var(--ink-faint);
}

.note-list__filter:focus-within {
    border-color: var(--navy);
}

.note-list__filter input {
    flex: 1 1 auto;
    min-width: 0;
    border: 0;
    outline: none;
    background: transparent;
    color: var(--ink);
    font: inherit;
    font-size: 0.82rem;
}

.note-list__volume + .note-list__volume {
    margin-block-start: 0.8rem;
}

.note-list__volume-name {
    margin: 0 0 0.35rem;
    color: var(--ink-faint);
    font-size: 0.7rem;
    font-weight: 600;
}

.note-row__title {
    display: block;
    overflow: hidden;
    color: #243745;
    font-size: 0.85rem;
    font-weight: 500;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.note-row__opening {
    display: block;
    overflow: hidden;
    color: var(--ink-soft);
    font-size: 0.78rem;
    line-height: 1.6;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* On a phone the panel lies over the book (section 14), and the tools are for a thumb. */
@media (max-width: 48rem) {
    .note-tool {
        min-width: 2.75rem;
        height: 2.75rem;
    }

    .note-swatch {
        width: 1.6rem;
        height: 1.6rem;
    }

    /* two rows rather than a row that scrolls: a tool off the edge is a tool nobody finds */
    .note-editor__tools {
        position: sticky;
        top: 0;
        z-index: 3;
    }

    .note-picker {
        top: 6.4rem;
    }

    .note-body {
        font-size: 0.95rem;
    }
}

/* ==========================================================================
   14 · Narrow screens
   --------------------------------------------------------------------------
   A phone has no width to give away, so the menu lies over the book rather
   than beside it, and the rail goes along the top.
   ========================================================================== */

@media (max-width: 48rem) {
    .library__books,
    .features,
    .about,
    .contact,
    .contact__pair {
        grid-template-columns: minmax(0, 1fr);
    }

    .library__book {
        grid-template-columns: 5.5rem minmax(0, 1fr);
        column-gap: 0.9rem;
        padding: 0.9rem;
    }

    .library__more-inner {
        grid-template-columns: minmax(0, 1fr);
        gap: 1rem;
    }

    .library__drawn {
        font-size: 0.7rem;
    }

    .home__hero {
        padding-top: 2rem;
    }

    .home__teaser {
        grid-template-columns: minmax(0, 1fr);
    }

    .site__header {
        flex-wrap: wrap;
        gap: 0.75rem 1rem;
        padding: 0.75rem 1rem 0;
    }

    /* the three places take a row of their own under the brand and the person */
    .site__nav {
        order: 3;
        width: 100%;
        overflow-x: auto;
        margin-inline: -0.5rem;
        padding-bottom: 0.35rem;
    }

    /* with the three places on their own row, the person keeps the far edge of the first */
    .site__end {
        margin-inline-start: auto;
    }

    .site__nav a[aria-current="page"]::after {
        bottom: -0.35rem;
    }

    /* The line goes and the name stays: beside the account and the language there is room for
       the mark, not for a sentence after it. The home page still opens with it. */
    .brand__line {
        display: none;
    }

    .site__brand {
        font-size: 1.35rem;
    }

    /* The name goes and the initial stays. At this width the header is three things, and a
       full name is the one of them that can run to half a line; the disc and the chevron still
       say that there is a person here and that pressing them opens something. */
    .who__name {
        display: none;
    }

    .who__current {
        padding-inline-end: 0.25rem;
    }

    .shelf__book {
        flex-direction: column;
        align-items: stretch;
    }

    .shelf__cover {
        width: 6.5rem;
    }

    .fields,
    .facts {
        grid-template-columns: minmax(0, 1fr);
    }

    .account__card {
        flex-wrap: wrap;
    }

    /* the sign-in and registration cards keep a gutter rather than meeting the screen's edge */
    .auth {
        width: calc(100% - 2rem);
        margin-block: 1.5rem;
        padding: 1.25rem;
    }
}

/* **The `40rem` here is `NARROW` in `panes_controller.js` and has to stay it**: the stylesheet
   takes the مزدوج button away at this width and the controller stops using مزدوج at the same
   one, so that the bar cannot offer a view the book will not show or show one it does not offer. */
@media (max-width: 40rem) {
    /* A phone gives the page the whole width, and the side menu the foot of it: a rail across
       the bottom is where a thumb already is, and it is where every reading app the audience
       uses puts one. Above the page it took the top of the screen from the book twice over,
       once for the site's header and once for itself. */
    .reader {
        grid-template-columns: minmax(0, 1fr);
        grid-template-rows: minmax(0, 1fr) auto;
    }

    .reader__book {
        grid-row: 1;
    }

    /* Reversed rather than reordered: the rail is the first child, so laying the column from
       the bottom puts it on the edge and opens the panel upward over the book. The document
       order is left alone with it — a tab still comes before the panel it opens, which is the
       order a keyboard wants whichever end of the screen the two are drawn at. */
    .reader__sidebar {
        grid-row: 2;
        flex-direction: column-reverse;
        border-block-start: 1px solid var(--line);
    }

    .reader__rail {
        flex-direction: row;
        width: auto;
        border-inline-start: 0;
        padding: 0.35rem 0.5rem;
    }

    .reader__tab {
        width: auto;
        flex: 1 1 0;
        padding: 0.35rem 0.5rem;
    }

    /* Neither tool has anything to offer here. Floating wins nothing where the panel is already
       the whole width — the rules below say as much — and collapsing is what pressing the open
       tab does, on a phone exactly as on a desktop: the one gesture this menu has ever had.
       Two buttons restating it on the rail with the least room of any is two thumbs' width
       taken from the four tabs that go somewhere. */
    .reader__rail-tools {
        display: none;
    }

    /* The whole width, whatever is in it. `auto` here meant the panel was a flex item sized by
       its own contents, so البحث filled the screen and الكتاب stood in a column as wide as the
       longest line it happened to hold — four panels of four widths, none of them the phone's. */
    .reader__panel {
        width: 100%;
        max-height: 55dvh;
        border-inline-start: 0;
        border-block-end: 1px solid var(--line-soft);
    }

    /* the panel is already the whole width here, so there is nothing for floating to win */
    .reader__sidebar.is-floating .reader__panels {
        position: static;
        inset: auto;
    }

    .reader__sidebar.is-floating .reader__panel {
        border: 0;
        border-block-end: 1px solid var(--line-soft);
        border-radius: 0;
        box-shadow: none;
    }

    .reader__grip {
        display: none;
    }

    /* Three groups and the width for two, so the bar folds into four cells. What you are
       reading takes the first line with the one control that is about the window rather than
       the book; where you are in it and how you see it share the second.

       Both used to sit on that second line together, which came to some 400px of controls in
       a 344px line on a 360px phone — and the bar is `white-space: nowrap`, so it did not wrap,
       it simply ran off the end and took the volume chooser with it. */
    .reader {
        --bar-height: 5.5rem;
    }

    .reader__banner {
        padding-inline: 0.7rem;
    }

    .reader__top {
        grid-template-columns: minmax(0, 1fr) auto;
        grid-template-rows: auto auto;
        gap: 0.4rem 0.6rem;
        padding: 0.5rem 0.7rem;
        align-content: center;
    }

    .reader__named {
        grid-area: 1 / 1 / 2 / 2;
    }

    .reader__title {
        font-size: 1.05rem;
    }

    .reader__where {
        grid-area: 2 / 1 / 3 / 2;
        justify-self: start;
        min-width: 0;
    }

    /* the two it holds are wanted on different lines, so the box round them stands aside and
       lets each take a cell of its own */
    .reader__tools {
        display: contents;
    }

    .reader__tools > .reader__tool {
        grid-area: 1 / 2 / 2 / 3;
        justify-self: end;
    }

    .reader__views {
        grid-area: 2 / 2 / 3 / 3;
        justify-self: end;
    }

    /* and what is left is trimmed to the line it now has: the same controls, closer together */
    .reader__where,
    .reader__go {
        gap: 0.25rem;
    }

    .reader__go-page {
        padding: 0 0.45rem;
    }

    .reader__go input[name="page"] {
        width: 2.2rem;
    }

    .reader__divider {
        margin: 0 0.15rem;
    }

    .reader__go select {
        padding-inline: 1.45rem 0.45rem;
        font-size: 0.8rem;
    }

    .reader__go--volume label::before {
        inset-inline-start: 0.45rem;
    }

    .reader__view {
        padding: 0 0.55rem;
        font-size: 0.7rem;
    }

    .reader__zoom {
        inset-block-end: 0.75rem;
    }

    [dir="rtl"] .reader__zoom {
        left: 0.75rem;
    }

    [dir="ltr"] .reader__zoom {
        right: 0.75rem;
    }

    /* no width for two panes at once: whichever is shown takes the whole of it */
    .reader__panes {
        --text-share: 100%;
    }

    .reader__split {
        display: none;
    }

    /* مزدوج is the print beside its words, and there is room here for one of the two, so it
       is not offered. The controller stops using it at the same width, which is what makes this
       a choice withdrawn rather than a button that does nothing. */
    .reader__view[data-mode="dual"] {
        display: none;
    }

    .toc {
        padding-inline: 1rem;
    }
}
