/* Generated by tools/brand/fetch-fonts.mjs. Do not edit by hand.
   Regenerate with: node tools/brand/fetch-fonts.mjs */

@font-face {
  font-family: 'Playfair';
  font-style: italic;
  font-weight: 400 500;
  font-display: swap;
  src: url('/fonts/playfair-latin-ext-italic.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Playfair';
  font-style: italic;
  font-weight: 400 500;
  font-display: swap;
  src: url('/fonts/playfair-latin-italic.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Playfair';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/fonts/playfair-latin-ext-normal.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Playfair';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/fonts/playfair-latin-normal.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Source Serif 4';
  font-style: italic;
  font-weight: 300 700;
  font-display: swap;
  src: url('/fonts/source-serif-4-latin-ext-italic.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Source Serif 4';
  font-style: italic;
  font-weight: 300 700;
  font-display: swap;
  src: url('/fonts/source-serif-4-latin-italic.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Source Serif 4';
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url('/fonts/source-serif-4-latin-ext-normal.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Source Serif 4';
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url('/fonts/source-serif-4-latin-normal.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url('/fonts/inter-latin-ext-normal.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url('/fonts/inter-latin-normal.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Literata';
  font-style: italic;
  font-weight: 400 700;
  font-display: swap;
  src: url('/fonts/literata-latin-ext-italic.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Literata';
  font-style: italic;
  font-weight: 400 700;
  font-display: swap;
  src: url('/fonts/literata-latin-italic.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Literata';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/fonts/literata-latin-ext-normal.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Literata';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/fonts/literata-latin-normal.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'EB Garamond';
  font-style: italic;
  font-weight: 400 700;
  font-display: swap;
  src: url('/fonts/eb-garamond-latin-ext-italic.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'EB Garamond';
  font-style: italic;
  font-weight: 400 700;
  font-display: swap;
  src: url('/fonts/eb-garamond-latin-italic.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'EB Garamond';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/fonts/eb-garamond-latin-ext-normal.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'EB Garamond';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/fonts/eb-garamond-latin-normal.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Scheherazade New';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/scheherazade-new-arabic-normal-400.woff2') format('woff2');
  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, U+102E0-102FB, U+10E60-10E7E, U+10EC2-10EC4, U+10EFC-10EFF, U+1EE00-1EE03, U+1EE05-1EE1F, U+1EE21-1EE22, U+1EE24, U+1EE27, U+1EE29-1EE32, U+1EE34-1EE37, U+1EE39, U+1EE3B, U+1EE42, U+1EE47, U+1EE49, U+1EE4B, U+1EE4D-1EE4F, U+1EE51-1EE52, U+1EE54, U+1EE57, U+1EE59, U+1EE5B, U+1EE5D, U+1EE5F, U+1EE61-1EE62, U+1EE64, U+1EE67-1EE6A, U+1EE6C-1EE72, U+1EE74-1EE77, U+1EE79-1EE7C, U+1EE7E, U+1EE80-1EE89, U+1EE8B-1EE9B, U+1EEA1-1EEA3, U+1EEA5-1EEA9, U+1EEAB-1EEBB, U+1EEF0-1EEF1;
}

@font-face {
  font-family: 'Noto Nastaliq Urdu';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/noto-nastaliq-urdu-arabic-normal-400.woff2') format('woff2');
  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, U+102E0-102FB, U+10E60-10E7E, U+10EC2-10EC4, U+10EFC-10EFF, U+1EE00-1EE03, U+1EE05-1EE1F, U+1EE21-1EE22, U+1EE24, U+1EE27, U+1EE29-1EE32, U+1EE34-1EE37, U+1EE39, U+1EE3B, U+1EE42, U+1EE47, U+1EE49, U+1EE4B, U+1EE4D-1EE4F, U+1EE51-1EE52, U+1EE54, U+1EE57, U+1EE59, U+1EE5B, U+1EE5D, U+1EE5F, U+1EE61-1EE62, U+1EE64, U+1EE67-1EE6A, U+1EE6C-1EE72, U+1EE74-1EE77, U+1EE79-1EE7C, U+1EE7E, U+1EE80-1EE89, U+1EE8B-1EE9B, U+1EEA1-1EEA3, U+1EEA5-1EEA9, U+1EEAB-1EEBB, U+1EEF0-1EEF1;
}

@font-face {
  font-family: 'Honorifics';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/honorifics.woff2') format('woff2');
}

@font-face {
  font-family: 'OpenDyslexic';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/opendyslexic-normal.woff2') format('woff2');
}

@font-face {
  font-family: 'OpenDyslexic';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/opendyslexic-italic.woff2') format('woff2');
}

@font-face {
  font-family: 'OpenDyslexic';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('/fonts/opendyslexic-bold.woff2') format('woff2');
}

/* ==========================================================================
   site.css - the public side of The Muslim Page.
   ==========================================================================

   THIS IS THE SECOND REDESIGN OF 19 AUGUST 2026, and it is a rewrite rather
   than a revision. The first one kept the live site's kit and gave it new
   motion; Aamir said so, and lifted the constraint that had been holding the
   kit in place, in these words: do not follow any of the previous site's CSS
   guidelines, use new colours, new format, full redesign as you wish.

   So nothing below is carried across from the WordPress era. There are no gold
   ruled labels, no pill buttons and no bands of alternating ground colour.
   Sections are numbered and ruled off with a single hairline, and the type does
   the work that ornament used to do. That is still the design.

   THE PALETTE HAS NOW MOVED TWICE AND THE DESIGN HAS NOT MOVED WITH IT, which
   is the point of the token block below. It was a near black with a trace of
   green; it became a deep midnight blue with warm ivory on it and a soft amber
   accent; and on 21 AUGUST 2026 it became this, on Aamir's instruction: a light
   blue, gold and white scheme, open and airy. Each time the layout, the
   spacing, the motion and the drawing were left exactly where they were.

   THE ONE THING THAT COULD NOT BE REPOINTED is how a cover is separated from
   the page. On ink, artwork was lifted off the ground by a hairline of the
   page's own light, because a dark shadow on a dark ground is nothing at all.
   On paper it casts a real shadow, because that is what an object resting on
   paper does. Everything else in this file, including the whole loading
   animation, changed by the token block and nothing more.

   THE COVERS ARE THE COLOUR. That is the one idea the whole scheme rests on,
   and it survived the inversion unchanged. Nine pieces of commissioned artwork
   in nine different palettes cannot all be framed by a site with a loud palette
   of its own without something clashing somewhere. A ground this pale and this
   unsaturated has almost nothing to clash with, and it gives the artwork the
   one thing the dark ground could not: a shadow, which is what makes a cover
   read as a physical object rather than as a picture of one.

   This is NOT the reading stylesheet. A chapter's own words get their own
   scoped rules in read.css, because the reader's font scale must apply to the
   content region and to nothing else. On the live site that separation is made
   by excluding four page identifiers from every rule, which is fragile; here
   the two never meet in the first place.

   Every colour is a token and every rule uses the token. That has not changed
   and must not, and this file is now the proof of it three times over: the
   loading animation has been repointed through three complete palettes, forest
   and gold, then ivory and amber, then navy and gold on daylight, without one
   line of the drawing being touched.

   MOTION, AND THE THREE KINDS OF IT. This stylesheet moves things in three
   ways, they fail in three different ways, and so they are kept apart:

     1. TRANSITIONS on hover and focus. Universal, and nothing depends on them.
     2. REVEAL ON SCROLL, driven by a class the script adds. Section 15. If the
        script never runs, nothing is ever hidden, so there is nothing to
        reveal and the page is simply there.
     3. SCROLL DRIVEN ANIMATION, driven by the browser's own scroll timeline
        with no script at all. Section 16. Every one of these sits behind a
        support query AND behind a reduced-motion query, and every one has a
        resting state that is correct on its own.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Tokens
   -------------------------------------------------------------------------- */

:root {
  /* THE GROUND. Daylight, not night, and that is the change of 21 August 2026:
     Aamir asked for a light blue, gold and white scheme, open and airy, in
     place of the midnight blue the site opened with.

     IT WAS TOO FAINT, and that is the second change of 21 August 2026. He
     looked at the front page on a phone and said the light blue was barely
     there, and asked for it to be concentrated a little, pointing at the
     Mahmud al-Ihsan cover for the colour he meant. So every one of the four
     steps moved the same distance towards that cover's own blue: the page is
     no longer white with a hint of blue in it, it is a pale blue page, and the
     raised surface and the tint moved with it so the three stay a scale rather
     than becoming three shades of the same thing.

     FOUR STEPS AND NO MORE. The page itself, which is a light blue rather than
     a white with a suggestion of one; a raised surface, which is that blue one
     step deeper and is what a section is lifted on; a tint one step further
     down for the box a cover sits in before its image arrives and for a hover
     fill; and pure white for anything that has to read as a sheet laid on top,
     which means the fields, the panels and the reader's rail. A scheme goes
     wrong when it has eight of these, because none of them is far enough from
     the next to read as a decision.

     WHITE IS NOW WORTH MORE THAN IT WAS, and that is the one thing deepening
     the ground bought for nothing. On a near white page a white field is an
     outline; on this one it is a step, so every control on the site says what
     it is without being drawn a heavier box.

     THE COVERS ARE STILL THE COLOUR, which is the idea the whole scheme rests
     on and is the reason these four are as quiet as they are. Nine pieces of
     commissioned artwork in nine different palettes cannot all be framed by a
     site with a loud palette of its own without something clashing somewhere.
     What changes on a light ground is how a cover is separated from the page:
     see --cover-edge at the foot of this block. */
  --ground: #e6f0fb;
  --ground-raised: #d3e5f8;
  --ground-tint: #b9d4ef;
  --sheet: #ffffff;

  /* The ground again at two alpha values, so the header can arrive over the
     hero without either of them being written out as a literal in a keyframe
     where nothing would ever find it again. */
  --ground-veil: rgba(230, 240, 251, 0.82);
  --ground-veil-0: rgba(230, 240, 251, 0);

  /* THE DARK HALF OF THE SCHEME, and it is new on 21 August 2026. Aamir asked
     for some darker areas on the front page, naming the sliding covers as the
     one he wanted first, and the same instruction answers two other things he
     said in the same breath. A light blue page with nothing but light blue on
     it has no register to change into, so every section arrives at the same
     weight; and gold has nowhere on it to look like gold, because a gold
     readable against a pale ground is a dark ochre and reads as brass. Navy is
     where gold is gold. So the page now has two grounds rather than one, the
     pale one carries the reading and the deep one carries the moments, and the
     accent belongs to the deep one.

     IT WAS NEARLY BLACK AND IT IS A BLUE NOW, and that is the fifth round of
     the same day. Aamir looked at the front page on a phone and said the dark
     part was a bit too dark, and told me to make it work even if that meant
     putting the light back. Two things were wrong and only one of them was
     this value.

     THE VALUE: at #0d2039 there was almost no blue left in it, so the band was
     a hole punched in the page rather than the same page in a lower register.
     It is now a true navy, about twice as light, and it reads as the scheme
     turned down instead of switched off.

     AND HOW MUCH OF THE PAGE WAS DARK, which is the half this block cannot
     fix. On a phone there was a dark panel in the hero and a dark band under
     it with a hand's width of pale blue between them, and two dark blocks
     either side of a sliver read as a stripe however well each one is drawn.
     The covers came off their dark panel and onto a white shelf for it
     (section 8), so the page now changes register once, at the extract, which
     is the one place the change buys anything.

     TWO STEPS AND NO MORE, for the reason the pale ground has four and no
     more: --deep is the surface, --deep-2 is the same colour with the light
     taken out of it, and the two exist so a dark panel can be lit from a
     corner instead of being a flat rectangle. They are the ink's own hue taken
     down rather than a second blue, so the dark bands belong to the page they
     interrupt.

     Measured on --deep: --on-deep is 10.8:1, --on-deep-dim 6.4:1 and
     --gold-bright 6.7:1. Every one of them clears AA at any size, which is
     what lets the leaf gold carry words here and nowhere else. All three came
     DOWN when the ground came up, and that is the price of the lighter navy
     paid in the open: the margin is smaller and it is still a comfortable one.

     The two hairlines went the other way. A line of light has to work harder
     on a ground that has more light in it already. */
  --deep: #17355a;
  --deep-2: #122a49;
  --on-deep: #e6f0fb;
  --on-deep-dim: rgba(230, 240, 251, 0.72);
  --line-deep: rgba(230, 240, 251, 0.2);
  --line-deep-soft: rgba(230, 240, 251, 0.11);

  /* THE INK ON IT. A deep navy rather than black, for two reasons. Black on a
     tinted ground reads as a hole punched in the page, and the type belongs to
     the same family as the ground it sits on or the two look like an accident.

     The secondary tone is the same hue with the light let into it, so it
     recedes into the page rather than sitting on top of it as a grey would.
     The faint tone is the ink itself at an alpha, which is what keeps it in
     the family whatever ground it is drawn on.

     THE FAINT TONE WENT UP FROM 0.65 TO 0.7 when the ground was concentrated
     on 21 August 2026, and that is the whole cost of the deeper blue: the
     alpha that cleared AA against a near white page did not clear it against a
     pale blue one. It is the same colour doing the same job, held to the same
     standard rather than allowed to drift under it.

     Measured on --ground: --ink is 13.5:1, --ink-dim is 5.7:1 and --ink-faint
     is 5.5:1. On --ground-raised, which is the darkest thing any of them is
     ever drawn on, they are 12.1:1, 5.2:1 and 5.1:1. All six clear AA at any
     size, and the first two clear AAA. */
  --ink: #12253f;
  --ink-dim: #4a5f7a;
  --ink-faint: rgba(18, 37, 63, 0.7);

  /* THE ONE ACCENT, for section names, categories, numerals and the reading
     progress line. Gold, which is what Aamir asked for.

     IT WAS READING AS BRASS, and he said so on 21 August 2026 in the same
     breath as asking for the ground to be concentrated: make the blue deeper
     and the gold can be a proper gold. The second half of that does not follow
     from the first, and it is worth being exact about why rather than quietly
     doing something else. A gold light enough to LOOK like gold is around 3:1
     against any pale ground, which is under the standard for text; deepening
     the page from near white to pale blue takes the ground DOWN, so it makes
     that worse rather than better, not better. The readable gold could not go
     up. So what changed is the part that was actually wrong: the old value was
     only 79 per cent saturated, which on a warm hue is what reads as brass
     rather than as metal. It is now 92 per cent at almost the same lightness,
     which is the same weight of colour with the mud taken out of it, and it is
     a shade deeper so that it still clears AA on the deeper raised ground.

     AND THE LEAF GOLD DOES MORE OF THE WORK, which is the other half of the
     answer and the half a reader actually sees as gold. It went up in both
     saturation and lightness, and it is now on the hero's light and on the
     deck's own marker as well as on the loader's nib. The rule under it has
     not moved an inch: it never carries a word.

     AND THE ANSWER TO IT ARRIVED ON 21 AUGUST 2026, in the same round as the
     darker areas, because it is the same answer. Aamir said the gold still
     read as brass, and that a gold tint over the light blue looked wrong. Both
     are true and neither can be fixed by moving this value: a warm mid-dark on
     a cool pale ground is muddy however it is mixed, and that is what the two
     complaints have in common. What changed instead is WHERE THE GOLD IS. The
     page now has a deep navy ground (see --deep above), and gold on navy is
     gold: the leaf value carries the words on every dark band, at nearly nine
     to one, and it is the same colour that used to be allowed on the pale page
     as a haze and is not any more. The gold wash over the hero's blue is gone
     with it.

     THE READABLE ONE MOVED AS FAR AS IT COULD, which is not far and is worth
     being exact about. Its lightness is fixed by the standard: at 4.5:1 on a
     pale blue there is one band of warm colours available and nothing outside
     it. What was free to move is the HUE, and that is what was actually wrong.
     Brass is a yellow with the green left in it; gold is a yellow with the red
     left in it. The old value sat at hue 41 and the new one sits at 32, at the
     same saturation and near enough the same lightness, which is the whole
     difference between a dull yellow and an old gold on this ground.

     THERE ARE THREE OF IT AND EACH HAS ITS GROUND. --gold is the readable one,
     5.2:1 on the page, 4.7:1 on a raised section and 6:1 on white, and it is
     for small capitals and numerals on the PALE grounds and on the cards.
     --gold-dark is the same hue further down, for the hover state of anything
     filled in gold. --gold-bright is the leaf gold, and it went up again here:
     it carries words on the DEEP grounds, where it is 6.7:1, and it is
     decoration and never a word on the pale ones, where it is 1.6:1 and is a
     watermark, a marker or a hairline. */
  --gold: #96520a;
  --gold-dark: #7a4108;
  --gold-bright: #e0bb52;

  /* THE ONE STATE COLOUR, and it is added grudgingly. Everything else on this
     site is the ground, the ink and the one gold, and the rule in
     DESIGN-CONSISTENCY.md section 5.1 is that a strong colour does not go back
     into the shell.

     A form is the exception the rule did not cover. A field that has been
     refused has to be findable at a glance among five others, and marking it
     in the same gold that already carries every section name and every
     category means the mark says nothing: the reader has been trained by four
     screens of it that gold is decoration. A deep rose is far enough from the
     gold to read as different at a glance and desaturated enough not to shout
     on this ground.

     It appears in exactly two places, both on the contact form: the border of
     a refused field and the sentence under it. THE COLOUR IS NEVER THE MESSAGE
     on its own, because about one man in twelve cannot tell these two hues
     apart; the sentence under the field is what says what is wrong.

     6.2:1 on the ground and 5.8:1 on a raised section, so it carries small
     text with no qualification. */
  --warn: #a3392f;

  /* Hairlines. Two weights, both drawn in the page's own ink rather than in a
     grey, so they sit ON the ground instead of being a stripe of a different
     colour laid over it. They are lighter than the dark scheme's were, because
     a line at the same weight on a pale ground is a fence: the whole point of
     this palette is air, and a rule is there to separate two things rather
     than to be looked at. The third is the same line at nothing, for the
     header arriving over the hero. */
  --line: rgba(18, 37, 63, 0.13);
  --line-soft: rgba(18, 37, 63, 0.07);
  --line-0: rgba(18, 37, 63, 0);

  /* THE FACES, AND THE ONE RULE ABOUT THEM.

     Inter carries the whole site: the wordmark, the menu, the headlines, the
     titles, the metadata, the actions. Source Serif carries THE WORDS OF THE
     BOOKS and nothing else, which on this page means the quoted passage, and
     which means the chapters everywhere else.

     That is a different rule from the one this site used to keep, and a
     sharper one. The old rule was 'serif for anything read, sans for anything
     operated', which put the site's own headings in a display serif and left
     the line somewhere in the middle of the page. This one puts the line
     exactly where the AUTHORSHIP changes: the serif means you are reading a
     book, and everything the site says about itself is set in the other face.
     A serif heading is now as much a bug as a sans passage, and the shell
     tests assert both halves of it.

     Playfair is no longer used by any of this. It stays declared in fonts.css
     and stays the intended face for a chapter title, which is a book's words
     rather than the site's. It is no longer preloaded, because a preloaded
     file the page does not use costs more than it saves. */
  --ui: 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --read: 'Source Serif 4', Georgia, 'Times New Roman', serif;

  /* Layout. --wrap is the outer measure for site furniture; --column is the
     narrow measure for anything meant to be read as prose. */
  --wrap: 78rem;
  --column: 34rem;
  --gutter: clamp(1.25rem, 5vw, 3.5rem);

  /* One vertical rhythm for every section, so the page has a beat. It is
     LARGER THAN IT WAS, by about a fifth at both ends, and that is part of the
     same instruction: air is what makes a light scheme read as open rather
     than as bare, and the space between the sections is where most of it
     lives. */
  --band: clamp(5rem, 11vw, 10.5rem);

  /* The header's height, stated once. Two separate things have to clear it:
     the hero is laid out under a header that floats over it, and anything
     sticky stops below it. A height written down in one place and cleared in
     another drifts apart the first time either is touched. */
  --head: 4.5rem;

  /* One curve for anything that ARRIVES, one for anything that merely
     responds. The first decelerates hard at the end, which is what makes a
     reveal read as considered rather than as a fade. */
  --ease: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-soft: cubic-bezier(0.4, 0, 0.2, 1);

  /* THE GRAIN.

     THE TESSELLATED STAR IS OFF THE PAGE AGAIN, and this time it is off for a
     stated reason rather than by drift. It went on 19 August 2026, came back on
     21 August 2026 when Aamir asked for texture and named the Mahmud al-Ihsan
     cover for the weight he meant, and went again the same day when he saw it
     on a phone: do not have the star in the background as a texture, think of
     another way to add texture that is better. So this file's standing rule
     holds in both directions, and it is worth writing down plainly: A MOTIF ON
     A GROUND IS A DECISION TO BE ASKED FOR, and a repeated shape is a motif
     however faintly it is drawn. At any weight where a star is visible at all,
     the eye finds it, starts reading the grid, and is looking at the wall
     instead of at the nine covers hanging on it.

     WHAT REPLACES IT IS PAPER RATHER THAN PATTERN. Fine grain, drawn in the
     page's own ink, with no shape in it to find and nothing to line up with
     anything else. It is the texture the scheme was already describing itself
     as having: light from above, artwork resting on a sheet, a shadow under
     every cover. A sheet has a tooth, and this is it.

     IT IS GENERATED RATHER THAN DRAWN, which is what makes it cost nothing.
     The cell is one SVG rect through a turbulence filter, so the whole texture
     is a few hundred bytes of instructions instead of an image, it costs no
     request, it cannot go missing, and there is no artwork anywhere that has
     to be kept in step with it. The cell is large, at 300px, because the one
     way a grain gives itself away is by repeating, and it carries no feature
     big enough to recognise across that distance.

     THE STRENGTH IS INSIDE THE DRAWING, exactly as it was for the tile. The
     alpha comes out of the noise itself and peaks at seventeen per cent over a
     mean nearer four, so any surface can take it as a background image and get
     the right weight, and there is one number to turn if it is ever wrong
     rather than one per surface. The hero is the only place that touches it,
     and only because the grain has to fade out down that screen. */
  --grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='300' height='300'%3E%3Cfilter id='g' x='0' y='0' width='100%25' height='100%25'%3E%3CfeTurbulence type='turbulence' baseFrequency='0.85' numOctaves='4' seed='11' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0.071 0 0 0 0 0.145 0 0 0 0 0.247 0.17 0 0 0 0'/%3E%3C/filter%3E%3Crect width='300' height='300' filter='url(%23g)'/%3E%3C/svg%3E");
  /* The same tooth, drawn in the page's light instead of its ink, for the deep
     grounds. A dark grain on a dark ground is nothing at all, which is the
     same argument --cover-edge has always made about a shadow. It is drawn a
     shade weaker than the dark one, because a highlight reads stronger than a
     shadow at equal strength. */
  --grain-light: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='300' height='300'%3E%3Cfilter id='g' x='0' y='0' width='100%25' height='100%25'%3E%3CfeTurbulence type='turbulence' baseFrequency='0.85' numOctaves='4' seed='11' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0.902 0 0 0 0 0.941 0 0 0 0 1 0.13 0 0 0 0'/%3E%3C/filter%3E%3Crect width='300' height='300' filter='url(%23g)'/%3E%3C/svg%3E");
  --grain-size: 300px 300px;

  /* ON A PALE GROUND A COVER CASTS A REAL SHADOW, and this is the one part of
     the scheme that had to be rebuilt rather than repointed. The dark scheme
     separated a cover from the page with a hairline of the page's own light,
     because a dark shadow on a dark ground is nothing at all. Here the
     opposite is true: light comes from above, the artwork is a physical object
     resting on paper, and the shadow is what says so. Both are drawn in the
     ink rather than in black, so the shadow belongs to the page's own colour
     instead of greying it. */
  --cover-edge: 0 1px 2px rgba(18, 37, 63, 0.07), 0 10px 24px rgba(18, 37, 63, 0.09);
  --cover-lift: 0 2px 6px rgba(18, 37, 63, 0.1), 0 30px 60px rgba(18, 37, 63, 0.2);

  /* A CARD RESTS ON THE PAGE RATHER THAN BEING DRAWN ON IT, which is the whole
     difference between the cards that arrived on 21 August 2026 and the ones
     this design threw out. It is a fraction of the cover's shadow, because a
     sheet of paper with words on it is a millimetre off the desk and a book is
     a centimetre off it, and the two must not be lit as though they were the
     same object. */
  --card-edge: 0 1px 2px rgba(18, 37, 63, 0.05), 0 10px 24px rgba(18, 37, 63, 0.06);
}

/* --------------------------------------------------------------------------
   2. Reset and base
   -------------------------------------------------------------------------- */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
  background: var(--ground);
  /* An in-page jump lands softly rather than teleporting. The reduced-motion
     block in section 14 turns it off, which is what makes it safe to set. */
  scroll-behavior: smooth;
}

body {
  margin: 0;
  background: var(--ground);
  color: var(--ink);
  font-family: var(--ui);
  font-size: 16px;
  line-height: 1.6;
  font-synthesis-weight: none;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  /* Several things here are deliberately allowed to tilt or drift out of their
     own column. None of them may turn into a sideways scrollbar.

     CLIP, NOT HIDDEN, and the difference is the whole reason this needs a
     comment. `overflow-x: hidden` would make the body a scroll container, and
     a scroll container is exactly what `position: sticky` measures itself
     against: everything sticky on the site would quietly stop sticking, on
     every page, with nothing to say why. `clip` cuts the overflow off without
     creating one. A browser that does not know the value ignores the line,
     which leaves things as they were before it was added. */
  overflow-x: clip;
}

img,
svg,
picture {
  display: block;
  max-width: 100%;
}

a {
  color: inherit;
}

h1,
h2,
h3,
h4 {
  font-family: var(--ui);
  margin: 0;
  font-weight: 600;
  letter-spacing: -0.02em;
  text-wrap: balance;
}

p {
  margin: 0;
}

ol,
ul {
  margin: 0;
  padding: 0;
  list-style: none;
}

/* A visible focus ring on every interactive thing. The ink, because on this
   ground the browser's own blue is a fourth colour arriving from nowhere, and
   because the ink is the one colour on the site that is never decorative. */
a:focus-visible,
button:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 4px;
  border-radius: 1px;
}

.tmp-skip {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  background: var(--ink);
  color: var(--ground);
  padding: 0.75rem 1.25rem;
  font-size: 0.875rem;
  font-weight: 600;
}

.tmp-skip:focus {
  left: 0.5rem;
  top: 0.5rem;
}

/* Present for screen readers, absent on screen. */
.tmp-sr {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* --------------------------------------------------------------------------
   3. Measure

   The banded grounds are gone. There is ONE ground for the whole site, so a
   section no longer declares a colour, only its padding and its measure.
   `.tmp-raised` is the single exception and lifts a section by one step, which
   is used once, for the passage. Since 21 August 2026 it carries the grain as
   well as the colour: the hero and this are the only two surfaces on the site
   that are ground and nothing else, and a raised section with the colour of
   the scheme but none of its texture read as a flat panel dropped onto a
   textured page. It takes the drawing as it is, with no layer of its own.
   -------------------------------------------------------------------------- */

.tmp-band {
  padding-inline: var(--gutter);
}

.tmp-wrap {
  max-width: var(--wrap);
  margin-inline: auto;
}

.tmp-pad {
  padding-block: var(--band);
}

/* The hero draws the grain through a masked layer of its own, because there it
   has to fade out down the screen. Here it does not, so it is simply a
   background image laid over the colour. */
.tmp-raised {
  background-color: var(--ground-raised);
  background-image: var(--grain);
  background-size: var(--grain-size);
}

/* --------------------------------------------------------------------------
   THE SHELF. The covers in the hero stand on this.

   IT WAS A DARK PANEL FOR AN EVENING, and it is white now at Aamir's asking on
   21 August 2026: the dark part was a bit too dark, and make it work even if
   that means making it light again. What he asked for the round before, that
   the sliding covers get a backdrop of their own rather than floating on the
   hero, is kept. What is gone is the colour of it, and the argument is in
   section 1 beside the value it used to be drawn in.

   WHITE RATHER THAN THE RAISED BLUE, and that is a decision rather than the
   absence of one. The page is a pale blue and the raised step is the next blue
   down, so a shelf drawn in it is a panel a reader has to look for. White is a
   step UP off this ground, which is the whole of what --sheet is for, and it
   is the brightest thing on the page, which is the plainest answer there is to
   a page that was too dark.

   IT TAKES THE GRAIN for the reason .tmp-raised does. A white rectangle with
   no tooth in it, dropped on a page that has one, reads as a hole in the paper
   rather than as a sheet laid on it.
   -------------------------------------------------------------------------- */

.tmp-shelf {
  background-color: var(--sheet);
  background-image: var(--grain);
  background-size: var(--grain-size);
}

/* --------------------------------------------------------------------------
   THE LIGHT BAR BETWEEN THE SECTIONS, asked for by Aamir on 21 August 2026 in
   those words.

   It is a bar and not a hairline, which is the whole of the idea: where one
   section ends and the next begins there is a band of light across the page.
   It earns its keep hardest where the page changes register, because a pale
   section meeting a deep one edge to edge is two colours touching with nothing
   to say which of them the page is; the bar is that join, drawn.

   IT IS AN ELEMENT OF ITS OWN AND NOT A BORDER ON A SECTION, and it has to be.
   A deep band repoints --line and --sheet on itself, so a border drawn by
   either of the two sections it separates would take that section's colours
   and would change value depending on which of the two it was attached to.
   Standing between them, it is always the page's own light.

   It is empty and hidden from assistive technology in the markup, because it
   says nothing that the heading of the section under it does not say better.
   -------------------------------------------------------------------------- */

.tmp-rule {
  height: clamp(0.25rem, 1vw, 0.4375rem);
  background: var(--sheet);
  border-block: 1px solid var(--line);
}

/* --------------------------------------------------------------------------
   A DEEP BAND, and it is the one thing this stylesheet has that a change of
   palette could not give it: a second register.

   ASKED FOR ON 21 AUGUST 2026. Aamir asked for some darker areas on the front
   page and named the sliding covers as the one he wanted first. What follows
   here is more than a background colour, and deliberately so.

   IT REPOINTS THE TOKENS RATHER THAN RESTATING THE RULES. Every rule in this
   file draws in --ink, --ink-dim, --line and --gold and none of them names a
   colour, which is the discipline section 1 has kept through three complete
   palettes. That buys exactly this: a band that redefines those five tokens on
   itself recolours everything inside it, at any depth, with no rule anywhere
   needing to know it is on a dark ground. A section head, an onward link, a
   numbered list, a cover and a solid action all arrive correct.

   SO A NEW PART NEEDS NOTHING ADDING HERE. If it draws in the tokens it works
   on both grounds already, and if it does not, that is the bug rather than
   this being incomplete.

   THE ACCENT CHANGES VALUE HERE AND THAT IS THE POINT. --gold on the pale page
   is a dark ochre, because a gold light enough to look like gold cannot carry
   words against a pale ground. On this one it is the leaf gold at nearly nine
   to one. The gold on this site looks like gold on the dark bands and nowhere
   else, which is why they exist.
   -------------------------------------------------------------------------- */

.tmp-deep {
  --ink: var(--on-deep);
  --ink-dim: var(--on-deep-dim);
  --ink-faint: var(--on-deep-dim);
  --line: var(--line-deep);
  --line-soft: var(--line-deep-soft);
  /* --line-0 is NOT repointed and must not be. It is the hairline at nothing,
     for the header arriving over the hero, and a transparent line is the same
     transparent line whatever colour it is nominally drawn in. Moving it would
     be a token to keep in step for no effect anywhere. */
  --gold: var(--gold-bright);
  --gold-dark: #f0d489;
  --ground: var(--deep);
  --ground-raised: #21446e;
  --ground-tint: #2a5182;
  --sheet: #21446e;
  /* A shadow on a dark ground has to be nearer black than the ground is, or
     there is nothing under the cover at all. The hairline of light along the
     top is what the dark scheme used before the palette turned over, and it is
     right again for the same reason. */
  --cover-edge: 0 1px 2px rgba(0, 0, 0, 0.4), 0 14px 34px rgba(0, 0, 0, 0.45);
  --cover-lift: 0 2px 6px rgba(0, 0, 0, 0.45), 0 34px 66px rgba(0, 0, 0, 0.55);
  --card-edge: 0 1px 2px rgba(0, 0, 0, 0.3), 0 12px 28px rgba(0, 0, 0, 0.32);
  position: relative;
  isolation: isolate;
  color: var(--on-deep);
  background-color: var(--deep);
  background-image:
    radial-gradient(78% 120% at 12% 0%, rgba(120, 172, 232, 0.16), transparent 62%),
    radial-gradient(64% 110% at 92% 100%, rgba(224, 187, 82, 0.09), transparent 66%),
    var(--grain-light),
    linear-gradient(168deg, var(--deep) 0%, var(--deep-2) 100%);
  background-size: auto, auto, var(--grain-size), auto;
}

/* --------------------------------------------------------------------------
   4. Type

   Three sizes carry the whole page: the headline, the section heading and the
   work title. Everything else is metadata at one of two small sizes. A near
   monochrome scheme has no colour to make hierarchy with, so the hierarchy has
   to be in the size and the weight, and the steps between them are large on
   purpose.
   -------------------------------------------------------------------------- */

/* THE HEADLINE IS SIZED FROM ITS COLUMN, NOT FROM THE VIEWPORT, and that is
   what keeps it on the two lines it is written as.

   The break after 'Islamic works' is in the markup because Aamir wrote it as
   two lines. The second line, 'Translated into English', is the longer of the
   two, and whether it fits on one line depends on how wide its COLUMN is, not
   on how wide the window is. Those two part company at 74rem, where the hero
   becomes two columns and the text loses 24rem of its width to the covers in
   one step: sized in vw the headline would be at its largest exactly where its
   column had just become narrowest, and the second line would break in a
   different place at every width.

   `cqi` is one per cent of the container's inline size, so this tracks the
   column itself and the break stays where it was put. 8.6 is the largest value
   at which the longest line still fits, measured rather than guessed, with a
   little left over for a face that renders a shade wider.

   The vw line above it is not a leftover. A browser that does not understand
   `cqi` throws the whole declaration away, so the first one is what it keeps,
   and it is deliberately a size at which the line wraps tidily rather than one
   that is nearly right. On a phone the wrap is unavoidable at any readable
   size and the floor takes over: three lines there is correct. */
.tmp-h1 {
  font-size: clamp(2.5rem, 7.4vw, 4.25rem);
  font-size: min(clamp(2.5rem, 8.6cqi, 5.75rem), 13vw);
  font-weight: 700;
  line-height: 0.96;
  letter-spacing: -0.038em;
}

.tmp-h2 {
  font-size: clamp(2rem, 5.2vw, 3.5rem);
  font-weight: 600;
  line-height: 1.04;
  letter-spacing: -0.03em;
}

/* The small caption over a headline. It replaces the old gold label with its
   leading rule: no rule, and set in the gold itself at a size and a tracking
   that read as a caption rather than as a heading that failed. */
.tmp-eyebrow {
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--gold);
  margin-bottom: clamp(1.5rem, 4vw, 2.5rem);
}

/* --------------------------------------------------------------------------
   5. Section heads

   Every section opens the same way: one hairline across the full measure, the
   section's number and name under it in the gold, and the heading below.
   The number is what makes them read as a sequence rather than as three
   unrelated blocks. It is an aria-hidden span in the markup rather than a list
   counter, because these are sections and not a list.
   -------------------------------------------------------------------------- */

.tmp-sec {
  border-top: 1px solid var(--line);
  padding-top: 1.25rem;
  margin-bottom: clamp(2.5rem, 6vw, 4.5rem);
  display: grid;
  gap: 1.25rem 3rem;
}

@media (min-width: 48rem) {
  .tmp-sec {
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: end;
  }

  .tmp-sec-name {
    grid-column: 1 / -1;
  }
}

.tmp-sec-name {
  display: flex;
  align-items: baseline;
  gap: 0.875rem;
  font-family: var(--ui);
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--gold);
  margin: 0;
}

.tmp-sec-n {
  font-variant-numeric: tabular-nums;
  color: var(--ink-faint);
  letter-spacing: 0.1em;
}

/* --------------------------------------------------------------------------
   6. Actions and links

   The pill buttons are gone. The primary action is a hard edged slab of the
   ink that empties out on hover; the secondary is a label in a hairline box.
   Both are square, because a corner radius is the single strongest signal of
   the kit this design replaces.
   -------------------------------------------------------------------------- */

.tmp-act {
  display: inline-flex;
  align-items: center;
  gap: 0.75rem;
  font-size: 0.9375rem;
  font-weight: 600;
  letter-spacing: -0.005em;
  line-height: 1;
  padding: 1.125rem 1.75rem;
  text-decoration: none;
  border: 1px solid transparent;
  transition:
    background-color 0.3s var(--ease-soft),
    color 0.3s var(--ease-soft),
    border-color 0.3s var(--ease-soft);
}

.tmp-act svg {
  flex: none;
  transition: transform 0.4s var(--ease);
}

.tmp-act:hover svg {
  transform: translateX(5px);
}

.tmp-act-solid {
  background: var(--ink);
  color: var(--ground);
}

.tmp-act-solid:hover {
  background: transparent;
  color: var(--ink);
  border-color: var(--ink);
}

.tmp-act-plain {
  color: var(--ink-dim);
  border-color: var(--line);
}

.tmp-act-plain:hover {
  color: var(--ink);
  border-color: var(--ink-faint);
}

/* An onward text link: a label over a hairline that a line of the ink grows
   across, and an arrow that steps forward. */
.tmp-onward {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 0.625rem;
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--ink-dim);
  text-decoration: none;
  padding-bottom: 0.5rem;
  border-bottom: 1px solid var(--line);
  transition: color 0.3s var(--ease-soft);
}

.tmp-onward::after {
  content: '';
  position: absolute;
  left: 0;
  bottom: -1px;
  width: 100%;
  height: 1px;
  background: var(--ink);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 0.5s var(--ease);
}

.tmp-onward:hover {
  color: var(--ink);
}

.tmp-onward:hover::after,
.tmp-onward:focus-visible::after {
  transform: scaleX(1);
}

.tmp-onward svg {
  flex: none;
  transition: transform 0.4s var(--ease);
}

.tmp-onward:hover svg {
  transform: translateX(5px);
}

/* --------------------------------------------------------------------------
   7. Site header

   In view at all times, because the library is the thing every visitor is
   looking for and it should never be more than one glance away.

   IT HAS TWO MODES. Everywhere it is a bar in the normal flow with a hairline
   under it. On the front page it FLOATS OVER the hero, so nothing cuts across
   the opening screen, and it settles into the bar as the reader scrolls off.
   That settle is the browser's own scroll timeline, in section 15, with no
   script involved.

   It is far simpler than the version it replaces, and that is the dividend of
   one ground for the whole site. The old header had to cross fade four
   registered colour properties from a light-on-dark set to a dark-on-light
   set, because it floated over a green hero and landed on parchment. Here the
   type is the ink in both states and only the ground arrives behind it, so it
   is two ordinary properties and no @property at all.
   -------------------------------------------------------------------------- */

.tmp-header {
  position: sticky;
  top: 0;
  z-index: 50;
  padding-inline: var(--gutter);
  background: var(--ground);
  border-bottom: 1px solid var(--line);
}

@supports (backdrop-filter: blur(1px)) {
  .tmp-header {
    background: var(--ground-veil);
    backdrop-filter: blur(16px) saturate(1.3);
  }
}

/* The floating mode. Fixed rather than sticky, because a sticky element still
   occupies its space in the flow and the hero has to start at the very top of
   the page. */
.tmp-header-overlay {
  position: fixed;
  inset-inline: 0;
  top: 0;
  background: transparent;
  border-bottom-color: transparent;
  backdrop-filter: none;
}

.tmp-header-inner {
  position: relative;
  max-width: var(--wrap);
  margin-inline: auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 0.75rem 1.5rem;
  min-height: var(--head);
}

/* The reading progress line along the header's bottom edge. It rests at zero
   width, so a browser that cannot drive it from the scroll position never
   draws it and there is nothing to see.

   It is a child of the HEADER and not of the inner row, so that it runs the
   full width of the screen: the containing block of an absolutely positioned
   child is the padding box of its positioned ancestor, and the header's
   padding box is the whole bar. Inside the inner row it would stop at the
   measure and read as a bar that had broken. */
.tmp-progress {
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  height: 1px;
  background: var(--gold);
  transform: scaleX(0);
  transform-origin: left center;
  pointer-events: none;
}

.tmp-brand {
  display: inline-flex;
  align-items: center;
  gap: 0.625rem;
  text-decoration: none;
  color: var(--ink);
  flex: none;
  min-width: 0;
}

/* `width: auto` is doing real work and must not be dropped. The mark carries
   width and height attributes so the header cannot jump while it loads, and
   those attributes map to the CSS width and height properties. Setting only
   the height leaves the width at the attribute's value, and because an SVG
   letterboxes inside its box rather than stretching, the mark then draws small
   and off centre in a box the wrong shape. */
.tmp-brand-mark {
  height: 1.875rem;
  width: auto;
  flex: none;
  transition: transform 0.5s var(--ease);
}

.tmp-brand:hover .tmp-brand-mark {
  transform: translateY(-2px);
}

/* The name as text. The negative tracking is not decoration: Inter at this
   weight sets loosely for a logo, and closing it up is the difference between
   three words and one name. */
.tmp-brand-name {
  font-family: var(--ui);
  font-weight: 700;
  font-size: clamp(1.125rem, 0.95rem + 0.9vw, 1.375rem);
  letter-spacing: -0.028em;
  line-height: 1;
  white-space: nowrap;
}

/* --------------------------------------------------------------------------
   The menu button

   Hidden outright until the script that drives it has marked the document
   (see NAV_ARM in shell.js), and hidden again as soon as there is room for the
   links themselves. So it is only ever on screen when it both works and is
   needed.
   -------------------------------------------------------------------------- */

.tmp-nav-toggle {
  display: none;
  align-items: center;
  justify-content: center;
  width: 2.75rem;
  height: 2.75rem;
  margin-inline-end: -0.625rem;
  padding: 0;
  background: transparent;
  border: 0;
  color: var(--ink);
  cursor: pointer;
  transition: color 0.3s var(--ease-soft);
}

.tmp-nav-toggle:hover {
  color: var(--gold);
}

/* One glyph at a time. Both are in the markup, so the swap costs nothing and
   the button never changes width. */
.tmp-nav-shut { display: none; }
.tmp-nav-toggle[aria-expanded='true'] .tmp-nav-open { display: none; }
.tmp-nav-toggle[aria-expanded='true'] .tmp-nav-shut { display: block; }

.tmp-nav {
  display: flex;
  align-items: center;
  gap: clamp(1.5rem, 4vw, 2.5rem);
}

.tmp-nav a {
  position: relative;
  font-family: var(--ui);
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--ink-dim);
  text-decoration: none;
  padding-block: 0.375rem;
  transition: color 0.3s var(--ease-soft);
}

.tmp-nav a:hover,
.tmp-nav a[aria-current='page'] {
  color: var(--ink);
}

/* The current page is marked with a dot rather than an underline. An underline
   under a menu item is the pattern this design is getting away from, and a dot
   is unmistakable at a glance without adding a second line to a bar that
   already has one. */
.tmp-nav a[aria-current='page']::before {
  content: '';
  position: absolute;
  left: 50%;
  /* UNDER the label, not over it. Above, it clears the link's padding and ends
     up nearer the top edge of the bar than the word it belongs to, where it
     reads as a speck of dust on the screen rather than as a marker. */
  bottom: -0.375rem;
  width: 3px;
  height: 3px;
  border-radius: 50%;
  background: var(--gold);
  transform: translateX(-50%);
}

/* Below 48rem the wordmark and the button are the whole header bar, and the
   links drop into a panel underneath it.

   Every rule here is behind `.js-nav`, which only exists once the script has
   run. With no script the button stays hidden and the links stay in the flow,
   wrapping onto a second line under the wordmark: smaller than the design
   intends, and completely usable, which is the right way round. */
@media (max-width: 47.999rem) {
  .js-nav .tmp-nav-toggle {
    display: inline-flex;
  }

  .js-nav .tmp-nav {
    display: none;
    /* Out of the header bar's flex row and across the full width of the band,
       so the panel's edges line up with the header's own border rather than
       with the wordmark. */
    position: absolute;
    inset-inline: calc(var(--gutter) * -1);
    top: 100%;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding-inline: var(--gutter);
    /* Opaque, and one step up from the ground rather than transparent: on the
       front page the bar above it may still be transparent over the hero, and
       a panel that let the covers show through would be a menu nobody could
       read. */
    background: var(--ground-raised);
    border-bottom: 1px solid var(--line);
  }

  .js-nav .tmp-nav.is-open {
    display: flex;
  }

  .js-nav .tmp-nav a {
    padding-block: 1.0625rem;
    font-size: 1.0625rem;
    border-bottom: 1px solid var(--line-soft);
  }

  .js-nav .tmp-nav a:last-child {
    border-bottom: 0;
  }

  /* In the panel the dot would sit above the link's own text with a full width
     divider under it, which reads as a stray speck. Colour alone marks it. */
  .js-nav .tmp-nav a[aria-current='page']::before {
    display: none;
  }
}

/* --------------------------------------------------------------------------
   8. Hero

   Full height, so the front page opens on one statement and the reader has to
   move to find the library.

   THE GROUND CARRIES DEPTH AND, SINCE 21 AUGUST 2026, A TEXTURE. One soft
   gold light behind the deck, a broader blue one low on the left, and a wash
   of the light blue at the top of the screen clearing to the page's own colour
   about two thirds of the way down. Over all of it, the grain from section 1.

   THE TEXTURE IS GRAIN AND NOT A TILE, since later the same day. A tessellated
   star stood here for a few hours, at Aamir's asking and drawn as faintly as
   it could be drawn; he saw it on a phone and asked it off again, and asked
   for a better way to give the page a texture. Section 1 argues what replaced
   it. What matters here is that the grain has no shape in it to find, so it
   can be stronger than the star ever could be and still stay behind the words:
   it is masked away down the screen so it never reaches them, and nothing on
   top of it moves.

   NOTHING IN THE HERO MAY BE WIDER THAN THE HERO, and that is a rule rather
   than a note, because breaking it is silent. The section clips its own
   overflow, so a child that grows past the screen does not announce itself
   with a scrollbar: it simply takes the headline off the right hand edge and
   pushes the deck out of sight, which is exactly what a phone showed on 21
   August 2026. The deck's track is a flex row of five fixed width cards, which
   is a min-content of about a thousand pixels, and the two things standing
   between that number and the layout are the `minmax(0, 1fr)` on the grid and
   the `min-width: 0` on everything between it and the track. Neither is
   decoration and neither is to be tidied away.

   IT IS LIT FROM THE TOP, which is the whole difference between the pale
   scheme and the dark one it replaces. On ink the page grew lighter towards
   the top because the light was coming from somewhere behind it; on paper the
   colour is heaviest at the top and falls away, the way daylight does across a
   sheet lying on a desk.
   -------------------------------------------------------------------------- */

.tmp-hero {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  display: flex;
  align-items: center;
  padding-inline: var(--gutter);
  /* svh, not vh: on a phone vh is the height with the browser's own bars
     retracted, so a full height hero measured in vh is always a little taller
     than the screen actually is, and the foot of it is cut off on arrival. */
  min-height: 100vh;
  min-height: 100svh;
  /* THE GOLD HAZE IS GONE, on 21 August 2026 and at Aamir's asking: a tint of
     gold over the light blue does not look good, and he is right. A warm wash
     at low alpha over a cool pale ground does not read as light, it reads as
     dirt on the glass, because there is no value in it dark enough for the eye
     to take it as a shadow or light enough to take it as a highlight. What
     stood there is now plain daylight, which is what the wash was drawing, and
     the gold has moved to the deep panel under it where it is gold rather than
     a stain. */
  background:
    radial-gradient(56% 50% at 78% 20%, rgba(255, 255, 255, 0.85), transparent 70%),
    radial-gradient(62% 58% at 0% 96%, rgba(84, 142, 212, 0.3), transparent 72%),
    linear-gradient(180deg, #c9dff6 0%, var(--ground) 66%);
}

/* The grain over the hero's own ground.

   A LAYER OF ITS OWN RATHER THAN A FOURTH BACKGROUND, and it has to be: the
   grain must fade out down the screen so that it is at its strongest where
   there is nothing but ground and gone by the time it is behind the headline,
   and a background layer cannot be masked on its own.

   NEGATIVE Z, NOT ZERO. The hero sets `isolation: isolate`, so a z-index of
   -1 is trapped inside the hero rather than dropping behind the page: it
   paints over the hero's own ground and under everything in the hero's flow,
   which is exactly where a texture belongs and is one line rather than
   positioning every other child to get above it. */
.tmp-hero::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background-image: var(--grain);
  background-size: var(--grain-size);
  mask-image: linear-gradient(180deg, #000 0%, rgba(0, 0, 0, 0.55) 42%, transparent 78%);
}

/* THE HAIRLINE THAT USED TO CLOSE THE HERO IS GONE, and what closes it now is
   the light bar in section 3. A hairline and a bar within a few pixels of each
   other is one line too many, and the bar is the one that was asked for. */

.tmp-hero-inner {
  width: 100%;
  /* THE FLEX ITEM MUST NOT BE SIZED BY WHAT IS INSIDE IT. `width: 100%` is
     only the preferred size; a flex item's automatic MINIMUM size is its
     content's, and the deck's track is a row of five fixed width cards. Where
     a browser does not zero the min-content of a scroll container, that
     minimum wins over the hundred per cent, the hero's contents are laid out
     at about a thousand pixels on a phone, and the section quietly clips the
     lot. This one line is what holds the layout to the screen. */
  min-width: 0;
  /* THE TOP CAME DOWN ON 21 AUGUST 2026. Aamir looked at the front page on a
     phone and said there was too much space above the headline and asked for
     it to move up. Three numbers were paying for that and all three came down
     together: this padding, the gap between the words and the artwork, and the
     margin over the actions further down. It is the first of them that did
     most of it, and it is worth knowing that the arithmetic is halved: the
     block is centred in a full height hero, so taking an inch off the top of a
     centred block moves what is inside it up by half an inch, not by an inch.

     The header still floats over this, so what is left has to clear it, and
     that is what --head is doing in the sum rather than a number typed twice.

     THE BOTTOM STAYS SMALLER THAN THE TOP, which it has since the covers were
     first drawn on a phone. A full screen hero carrying artwork has to find
     the height somewhere, and the emptiest part of it is the strip between the
     last thing on the screen and the bottom edge. */
  padding-block: calc(var(--head) + clamp(0.75rem, 3vw, 2rem)) clamp(2rem, 8vw, 6rem);
  display: grid;
  /* `minmax(0, 1fr)` and not the implicit `auto`, for the same reason as the
     minimum above: an `auto` track is allowed to grow to its content's
     min-content size, and the deck's is a thousand pixels wide. */
  grid-template-columns: minmax(0, 1fr);
  gap: clamp(2.25rem, 5.5vw, 4rem);
  align-items: center;
}

/* The container the headline measures itself against. Nothing else on the page
   needs one, and this one exists only so that .tmp-h1 can be sized in `cqi`. */
.tmp-hero-text {
  container-type: inline-size;
  max-width: 52rem;
}

.tmp-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
  gap: 0.75rem;
  /* Down from 2.5rem to 3.75rem on 21 August 2026, with the hero's own top
     padding and for the same reason. */
  margin-top: clamp(1.75rem, 4.5vw, 3rem);
}

/* The scroll cue: a hairline with a bead falling down it. It says nothing, so
   it is hidden from assistive technology, and it is not drawn on a short or
   narrow screen, where a full height hero is obviously scrollable already and
   the cue would only be in the way. */
.tmp-cue {
  display: none;
  position: absolute;
  left: 50%;
  bottom: 2.25rem;
  z-index: 2;
  width: 1px;
  height: 3.5rem;
  background: var(--line);
  overflow: hidden;
}

/* IT IS DRAWN ONLY WHERE THE DECK HAS A COLUMN OF ITS OWN, which is the width
   at which the hero becomes two. Below it the shelf is under the words and
   bleeds to both edges of the screen, and the cue stands exactly where the
   shelf's own foot is: a hairline and a falling bead drawn down the middle of
   five book covers. It went unnoticed while the shelf was near black and the
   cue was near invisible on it, and it would not go unnoticed on white. */
@media (min-height: 40rem) and (min-width: 74rem) {
  .tmp-cue { display: block; }
}

.tmp-cue::after {
  content: '';
  position: absolute;
  left: -1px;
  width: 3px;
  height: 1.25rem;
  background: linear-gradient(180deg, transparent, var(--gold));
  animation: tmp-cue-fall 2.8s var(--ease-soft) infinite;
}

@keyframes tmp-cue-fall {
  0%   { transform: translateY(-130%); opacity: 0; }
  25%  { opacity: 1; }
  75%  { opacity: 1; }
  100% { transform: translateY(340%); opacity: 0; }
}

/* --------------------------------------------------------------------------
   The deck: the books in the hero

   THIS REPLACED THE FAN ON 21 AUGUST 2026, at Aamir's asking, and it is a
   change of kind rather than of arrangement. The fan and the flat trio were
   both DECORATION made of real covers: three books, chosen because they came
   first in the display order, carrying colour into the hero and saying nothing
   about themselves. He asked for a card the reader can move through, about
   five books, with a small onward link under it, moving on by itself every few
   seconds. That is not a decorated hero, it is the library offered on the
   opening screen, so every cover now carries its own name, its own author and
   its own way in.

   IT IS A REAL SCROLLER AND NOT A SLIDESHOW, which is the whole reason it can
   be this small. The track is an ordinary overflow box with scroll snapping on
   it, so a thumb swipes it, a trackpad swipes it, a keyboard reaches it and the
   arrow keys move it, and every one of those works with no script running at
   all. The script adds two things and neither is load bearing: the markers
   under it, and the advance every few seconds. With the script gone the deck is
   a row of five books somebody can push along, which is a finished thing rather
   than a broken one, and it is the same bargain the menu, the reveal and the
   reader's tools all make.

   THE SLIDES ARE CENTRED BY PADDING, not by a transform and not by a
   measurement taken at runtime. The track is padded on both sides by exactly
   half its own width less half a slide, so the first slide and the last one sit
   in the middle of the box the same way every one between them does, and the
   neighbours show at both edges, which is what tells the reader there is more
   of this than they can see.

   EVERY COVER STANDS AT FULL STRENGTH and none of them is set back. The two
   either side used to be pushed into the distance, first by darkening them
   while the shelf was a dark panel and then, once it turned white, by taking
   the colour out of them and letting the ground through at half. Aamir asked
   on 21 August 2026 for the original colour of everything on the shelf to
   stand, with the white ground as the only change, and he is right: nine
   covers were painted for these books, and a rule here was repainting five of
   them every few seconds. What says which book is in front is that it is whole
   and in the middle while its neighbours are cut off by the edge of the
   screen, which is the deck's own shape saying it rather than a filter.
   -------------------------------------------------------------------------- */

.tmp-deck {
  /* Two numbers the whole thing is built from. The slide is sized off the
     viewport until it has a column of its own, and then it is set. */
  --slide: min(58vw, 13.5rem);
  --deck-gap: clamp(1rem, 4vw, 1.75rem);
  /* The third place the hero's width rule is enforced. See .tmp-hero-inner. */
  min-width: 0;
  /* THE SHELF. Asked for on 21 August 2026: put the sliding covers on a
     backdrop of their own, and a bit lower so there is more space above them.
     The class on the element is .tmp-shelf, so the ground and the grain come
     from section 3 rather than from here; what is left for this rule is the
     shape of it and the two hairlines that close it top and bottom.

     IT WAS A DARK PANEL FOR ONE EVENING. Section 3 carries the argument and it
     is Aamir's: the dark was a bit too dark, and a dark panel in the hero with
     a dark band underneath it was striping the page.

     IT BLEEDS TO THE EDGE OF THE SCREEN while the deck is under the words, and
     it is the gutter it is cancelling rather than an arbitrary number, so the
     panel finishes exactly where the page's own margin does and no scrollbar
     can appear. Above 74rem the deck has a column of its own and the bleed is
     turned off with it, because a panel that reached the edge from a column
     would run under the headline. */
  margin-top: clamp(1.75rem, 6vw, 3.25rem);
  margin-inline: calc(var(--gutter) * -1);
  padding: clamp(1.5rem, 4vw, 2.25rem) var(--gutter) clamp(1.25rem, 3.5vw, 1.75rem);
  border-block: 1px solid var(--line);
}

.tmp-deck-track {
  display: flex;
  gap: var(--deck-gap);
  min-width: 0;
  /* Half the box less half a slide: this is what centres the first and the
     last as well as the middle three.

     THE FLOOR OF ZERO IS NOT DECORATION. This padding is a percentage of the
     track's own width, so if the track is ever narrower than one slide the sum
     goes negative, and a negative padding is thrown away rather than clamped,
     taking the centring of every slide with it. */
  padding-inline: max(0px, calc(50% - var(--slide) / 2));
  /* Room at the foot for the covers' own shadow, which an overflow box would
     otherwise cut off along the bottom edge. */
  padding-block: 0.5rem 1.25rem;
  margin: 0;
  overflow-x: auto;
  /* A swipe that runs off the end of the deck must not become a swipe on the
     page behind it, which on a phone is how a carousel steals a scroll. */
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  /* No bar. The markers under it say where the reader is, and a scrollbar
     drawn across the front page's hero is furniture nobody asked for. The
     reduced-motion block turns the smooth scrolling off with everything else,
     because it sets scroll-behavior on the universal selector. */
  scrollbar-width: none;
}

.tmp-deck-track::-webkit-scrollbar {
  display: none;
}

.tmp-deck-slide {
  flex: 0 0 var(--slide);
  scroll-snap-align: center;
  /* One at a time. Without this a fast swipe crosses three of the five books
     and lands wherever the momentum ran out. */
  scroll-snap-stop: always;
}

.tmp-deck-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  text-decoration: none;
  color: inherit;
}

.tmp-deck-cover {
  width: 100%;
}

.tmp-deck-card:hover .tmp-cover,
.tmp-deck-card:focus-visible .tmp-cover {
  transform: translateY(-8px);
  box-shadow: var(--cover-lift);
}

.tmp-deck-meta {
  display: block;
  margin-top: 1.125rem;
}

.tmp-deck-cat {
  display: block;
  font-size: 0.625rem;
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--gold);
  margin-bottom: 0.5rem;
}

.tmp-deck-title {
  display: block;
  font-size: 1.0625rem;
  font-weight: 600;
  line-height: 1.25;
  letter-spacing: -0.018em;
  text-wrap: balance;
}

.tmp-deck-by {
  display: block;
  font-size: 0.8125rem;
  line-height: 1.45;
  color: var(--ink-dim);
  margin-top: 0.4375rem;
}

/* The row under the deck: the markers on the left, the way into the rest of
   the library on the right. The markers are drawn by the script, so on a page
   where none ran this row holds the onward link alone and it stays where it
   was. */
.tmp-deck-foot {
  display: flex;
  align-items: center;
  gap: 1rem;
  margin-top: 0.25rem;
}

.tmp-deck-all {
  margin-left: auto;
  font-size: 0.8125rem;
}

.tmp-deck-dots {
  display: flex;
  align-items: center;
  gap: 0.375rem;
}

/* A short rule rather than a dot, because the site has exactly one round thing
   in it and this is not it. The button is 24px tall so it can be hit, and the
   rule itself is the two pixels in the middle: the padding is the target and
   the content box is the drawing. */
.tmp-deck-dot {
  appearance: none;
  border: 0;
  width: 1.125rem;
  height: 1.5rem;
  padding-block: 0.6875rem;
  background: var(--line);
  background-clip: content-box;
  cursor: pointer;
  transition:
    width 0.45s var(--ease),
    background-color 0.3s var(--ease-soft);
}

.tmp-deck-dot:hover {
  background-color: var(--ink-faint);
}

.tmp-deck-dot.is-on {
  width: 2.25rem;
  background-color: var(--gold);
}

/* The deck gets a column of its own at the width the hero becomes two, which
   is the rule the fan followed and for the same reason: there is no width at
   which it has a column and is still under the words. */
@media (min-width: 74rem) {
  .tmp-hero-inner {
    grid-template-columns: minmax(0, 1fr) 26rem;
  }

  .tmp-deck {
    --slide: 13.5rem;
    /* Its own column, so the bleed comes off and the shelf is a shelf. The top
       margin stays and does the other half of what was asked for: the deck
       sits a little below the middle of the hero rather than level with the
       headline, which is what gives it the air above it on a wide screen that
       the extra space gives it on a phone. */
    margin-inline: 0;
    padding-inline: clamp(1.25rem, 2.5vw, 2rem);
    /* AND IT CLOSES ON FOUR SIDES HERE, where against the screen edge it closes
       on two. A white rectangle standing in the middle of a pale ground with a
       line along the top and the bottom and nothing down either side is a
       panel that has come apart; against the edge of the screen there are no
       sides to draw, and drawing them would be two lines running off the
       glass. The lift is the card's and not the cover's, because a shelf is a
       sheet lying on the page and the books on it are the things standing up
       off it. */
    border: 1px solid var(--line);
    box-shadow: var(--card-edge);
  }
}

/* --------------------------------------------------------------------------
   9. Covers

   ONE RULE, USED BY EVERY COVER THE SITE DRAWS: the deck in the hero, the book
   beside the passage, the Library's grid and a book's own page.

   THE LIBRARY SECTION THAT USED TO LIVE HERE IS GONE, asked off the front page
   by Aamir on 21 August 2026. It held one book at full size under the heading
   'Available to read soon', and the deck in the hero now offers five of them
   with the same information and a way into each, so the section had become a
   smaller version of what the screen above it already said. Its rules went
   with it rather than being left behind for something to inherit by accident.
   -------------------------------------------------------------------------- */

/* A cover, drawn as an object rather than as a picture of one.

   On paper the SHADOW is what does that, and it is in --cover-edge in section
   1 rather than here, so that the whole scheme could be inverted without this
   rule being touched. Over the face go two gradients: a narrow dark band with a
   paler one just inside it along the leading edge, which is the shadow in the
   gutter and the light catching the first millimetre of the board, and one wide
   diagonal sheen. Neither is strong enough to notice alone, and together they
   are the difference between a cover and a thumbnail.

   THE SHEEN IS LIGHTER THAN IT WAS. On a dark page a highlight has to be strong
   to be seen at all; on a pale one the same strength reads as a smear of fog
   across the artwork, because the eye is already adapted to the white around
   it. */
.tmp-cover {
  position: relative;
  display: block;
  /* The supplied artwork is 1060 by 1484, so the ratio is stated rather than
     approximated with a padding hack, and the box is reserved before the image
     arrives. Nothing on the page jumps as the covers load. */
  aspect-ratio: 1060 / 1484;
  background: var(--ground-tint);
  overflow: hidden;
  box-shadow: var(--cover-edge);
  transition: transform 0.6s var(--ease), box-shadow 0.6s var(--ease);
}

.tmp-cover::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    linear-gradient(
      90deg,
      rgba(0, 0, 0, 0.34) 0,
      rgba(0, 0, 0, 0.07) 1.4%,
      rgba(255, 255, 255, 0.13) 3.2%,
      rgba(255, 255, 255, 0) 8%
    ),
    linear-gradient(112deg, rgba(255, 255, 255, 0.07) 0, rgba(255, 255, 255, 0) 46%);
}

.tmp-cover img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* --------------------------------------------------------------------------
   10. The passage

   The one place on the front page set in the reading serif, and the one place
   a visitor is asked to read rather than scan. Those are the same fact: the
   serif means the words are a book's rather than the site's.

   REDRAWN TWICE ON 21 AUGUST 2026, and this is the second of them. In the
   morning it was a passage across the full measure with a small cover and a
   line of type under it, which read as a caption stuck under a photograph; by
   the afternoon it was two columns, the book standing on the left at twice
   that size with the quotation beside it. Aamir asked for it again in the
   evening: design it much better, the cover a bit bigger, the quotation in the
   middle.

   SO IT IS A CENTRED COMPOSITION ON THE DEEP GROUND, and every part of that
   sentence is one of the things he asked for. The section is one of the darker
   areas he asked for; the book stands at the top of it, centred, half again
   the size it was; the quotation is under it, centred, on the reading measure;
   and the way in is centred under that. Nothing is beside anything, so there
   is no second column for the eye to leave the sentence for, which is what a
   passage meant to be READ actually wants.

   IT IS THE ONE PLACE THE SITE QUOTES A BOOK, and on the dark ground it now
   reads as one: white serif on navy, the mark and the chapter in the leaf
   gold, and the artwork lit rather than laid on a pale sheet.

   THE MARKUP ORDER IS THE QUOTATION, ITS SOURCE, AND THEN THE WAY ON, which is
   what a figure and its caption mean and is the order it is read out in. The
   grid lifts the caption above the quotation on the screen without moving it
   in the document, which is the same trick the two column version used.

   THE QUOTATION MARK is a pseudo-element and not text: it hangs above the
   first line, in the gold, large enough to read as a mark and quiet enough not
   to be read as a character. It is the one piece of ornament on the front
   page, and it is allowed because a quotation is the one thing on the page
   that has a conventional mark of its own.
   -------------------------------------------------------------------------- */

.tmp-passage {
  /* CENTRED IN THE MEASURE AND NOT ONLY IN ITSELF. The figure is capped well
     inside the page's own width and centred in what is left, so the air is
     around the composition rather than gathered at one edge of it. */
  margin: 0 auto;
  max-width: 52rem;
  display: grid;
  justify-items: center;
  text-align: center;
  gap: clamp(1.75rem, 4vw, 2.5rem);
}

/* The book: the artwork, then the title, the author and the chapter under it.
   It is the first row on the screen and the second in the document. */
.tmp-passage-by {
  grid-row: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.tmp-passage-text {
  grid-row: 2;
  position: relative;
  margin: 0;
  max-width: 38rem;
  font-family: var(--read);
  font-size: clamp(1.375rem, 3vw, 2.125rem);
  font-weight: 400;
  line-height: 1.42;
  letter-spacing: -0.012em;
  color: var(--ink);
  text-wrap: pretty;
}

.tmp-passage-link {
  grid-row: 3;
}

/* Hung above the first line rather than beside it. Beside it, the mark either
   pushes the passage out of the column or sits in the gutter, and at this size
   the gutter is not wide enough to hold it on a phone. */
/* IT WAS A BOX AND A LETTER FOR A DAY, and Aamir saw it on a phone on 21
   August 2026. The mark had been written as the CSS escape for a left double
   quotation mark, and something that rewrote this file read its digits as an
   octal number instead: what was left was U+0081, a control character no font
   can draw, followed by the capital C the escape ended with. It is the literal
   character now, which has no digits in it for anything to misread, and
   shell.test.js refuses a stylesheet with a control character anywhere in it,
   so the next one of these is caught here rather than on a phone. */
.tmp-passage-text::before {
  content: '“';
  display: block;
  font-size: 3em;
  line-height: 0.6;
  color: var(--gold);
  opacity: 0.85;
  margin-bottom: 0.1em;
}

/* A BIT BIGGER, at Aamir's asking, and it is the whole reason the composition
   changed shape: at this size the cover cannot stand beside a passage without
   one of the two being cramped, so it stands above it instead. */
.tmp-passage-cover {
  display: block;
  width: clamp(8.5rem, 30vw, 15rem);
  margin-bottom: 1.5rem;
}

.tmp-passage-meta {
  display: block;
  font-size: 0.875rem;
  line-height: 1.55;
  color: var(--ink-dim);
}

.tmp-passage-meta b {
  display: block;
  font-family: var(--ui);
  font-weight: 600;
  font-size: clamp(1.125rem, 2.4vw, 1.375rem);
  line-height: 1.3;
  letter-spacing: -0.018em;
  color: var(--ink);
  margin-bottom: 0.375rem;
}

.tmp-passage-meta span {
  display: block;
}

/* The chapter, under the author. It takes the gold because it is the one line
   in the block that names the thing the link goes to. */
.tmp-passage-meta span + span {
  margin-top: 0.5rem;
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--gold);
}

/* --------------------------------------------------------------------------
   11. A numbered list of things, in cards

   THE CARDS ARE BACK, and that is a reversal, so it is written down rather
   than quietly done. This file has said since 19 August 2026 that a bordered
   white card is the single strongest signal of the kit this design replaces,
   and the rows with a hairline between them were what replaced them. Aamir
   looked at the objectives on 21 August 2026 and asked for the opposite, in
   these words: for the text in the objectives and other places, have cards
   that they can sit in, so the overall design is much better, and on the About
   page too. That is the whole of the argument. A rule this file makes for
   itself loses to the person the site is for.

   AND THE CARD EARNS ITS PLACE NOW IN A WAY IT DID NOT THEN. The reason the
   old ones read as furniture is that they were white boxes on a white page,
   which is a border drawn around nothing. The page is a light blue since 21
   August 2026, so a card in the sheet white is a step UP off the ground rather
   than an outline on it, and the ground has a texture for it to be lifted off.
   It is the same thing --sheet did for the fields and the panels when the
   ground was deepened, arriving here.

   THEY SIT SIDE BY SIDE WHERE THERE IS ROOM. The rows were full measure, one
   under another, which is what a list of five paragraphs wants; three
   objectives, each two sentences, are a set rather than a sequence and read as
   one across a screen. The track floor is what decides how many fit, so a list
   of three and a list of five both come out right with nothing counted here.

   THE NUMERAL STAYS AND IS STILL WHAT MAKES THEM A SEQUENCE. It moves from
   beside the text to above it, in the accent, over a short gold rule. It is
   aria-hidden in the markup: it is a position on a page, not a piece of the
   sentence.

   THE CARD TAKES ITS COLOURS FROM THE TOKENS, so it works on the pale ground,
   on a raised band and inside a deep one with nothing added. That is section
   3's bargain and this is the first part written after it.
   -------------------------------------------------------------------------- */

.tmp-list {
  display: grid;
  gap: clamp(0.875rem, 2vw, 1.25rem);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr));
}

.tmp-list-item {
  display: flex;
  flex-direction: column;
  padding: clamp(1.5rem, 3.2vw, 2.25rem);
  background: var(--sheet);
  border: 1px solid var(--line-soft);
  box-shadow: var(--card-edge);
}

/* Tabular figures so I, II and III sit on the same left edge as IV and V. */
.tmp-list-n {
  display: block;
  font-size: 1rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  font-variant-numeric: tabular-nums;
  color: var(--gold);
  line-height: 1;
  padding-bottom: 1.125rem;
  margin-bottom: 1.125rem;
  border-bottom: 1px solid var(--line);
}

.tmp-list-title {
  font-size: clamp(1.1875rem, 2.2vw, 1.4375rem);
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: -0.022em;
  text-wrap: balance;
}

.tmp-list-body {
  max-width: var(--column);
  margin-top: 0.875rem;
  font-size: 1rem;
  line-height: 1.7;
  color: var(--ink-dim);
}

/* A CARD FOR A SINGLE PARAGRAPH, for the one section whose whole content is
   one. It is the same sheet, the same hairline and the same lift as a row of
   them, so the About page reads as one design rather than as a page of cards
   with a loose paragraph in the middle of it. */
.tmp-card {
  padding: clamp(1.75rem, 4vw, 3rem);
  background: var(--sheet);
  border: 1px solid var(--line-soft);
  box-shadow: var(--card-edge);
}

.tmp-card > :first-child {
  margin-top: 0;
}

/* --------------------------------------------------------------------------
   12. Footer
   -------------------------------------------------------------------------- */

.tmp-footer {
  position: relative;
  padding-inline: var(--gutter);
  border-top: 1px solid var(--line);
}

.tmp-footer-inner {
  max-width: var(--wrap);
  margin-inline: auto;
  padding-block: clamp(3.5rem, 8vw, 6rem);
  display: grid;
  gap: clamp(2.5rem, 5vw, 4rem);
}

@media (min-width: 46rem) {
  .tmp-footer-inner {
    grid-template-columns: minmax(0, 1.6fr) repeat(2, minmax(0, 1fr));
  }
}

/* The mark is inline SVG in the current colour, so on this ground it is simply
   told to be the ink. It used to be an image put through a stack of four
   filters pretending forest green was parchment. */
.tmp-footer-brand {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-bottom: 1.5rem;
  color: var(--ink);
}

.tmp-footer-mark {
  height: 2.5rem;
  flex: none;
}

.tmp-footer-mark svg {
  height: 100%;
  width: auto;
}

.tmp-footer-name {
  font-weight: 700;
  font-size: 1.25rem;
  letter-spacing: -0.028em;
  line-height: 1;
}

.tmp-footer-about {
  font-size: 0.9375rem;
  line-height: 1.7;
  color: var(--ink-dim);
  max-width: 24rem;
}

.tmp-footer h2 {
  font-family: var(--ui);
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--gold);
  margin: 0 0 1.25rem;
}

.tmp-footer ul {
  display: grid;
  gap: 0.75rem;
}

.tmp-footer a {
  font-family: var(--ui);
  color: var(--ink-dim);
  text-decoration: none;
  font-size: 0.9375rem;
  display: inline-block;
  transition: color 0.3s var(--ease-soft), transform 0.4s var(--ease);
}

.tmp-footer a:hover {
  color: var(--ink);
  transform: translateX(5px);
}

.tmp-footer-base {
  max-width: var(--wrap);
  margin-inline: auto;
  border-top: 1px solid var(--line-soft);
  padding-block: 1.5rem 2.5rem;
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.5rem;
  justify-content: space-between;
  font-size: 0.75rem;
  letter-spacing: 0.02em;
  color: var(--ink-faint);
}

/* --------------------------------------------------------------------------
   13. Interior pages

   The shell used by anything that is not the front page, and, in 12b to 12e,
   the parts the About and Contact pages are built from. Those two are BUILT
   pages and not holding ones since 19 August 2026: they open on their own hero
   rather than on the plain heading below, so they use the shell in 12b instead
   of `.tmp-page`. What is left using `.tmp-page` is the holding Library page,
   the per-book pages and the not-found page.
   -------------------------------------------------------------------------- */

.tmp-page {
  max-width: 44rem;
  margin-inline: auto;
  padding-block: calc(var(--band) * 0.8) var(--band);
  padding-inline: var(--gutter);
}

.tmp-page h1 {
  font-size: clamp(2.25rem, 6vw, 3.75rem);
  font-weight: 700;
  line-height: 1.02;
  letter-spacing: -0.034em;
}

.tmp-page h1::after {
  content: '';
  display: block;
  width: 100%;
  height: 1px;
  margin-top: clamp(1.75rem, 4vw, 2.5rem);
  background: var(--line);
}

.tmp-page > * + * {
  margin-top: 1.25rem;
}

.tmp-page p {
  color: var(--ink-dim);
  line-height: 1.7;
}

.tmp-page a {
  color: var(--ink);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.2em;
}

.tmp-lede {
  font-size: clamp(1.125rem, 2.4vw, 1.375rem);
  line-height: 1.55;
  letter-spacing: -0.014em;
  color: var(--ink);
  max-width: var(--column);
}

.tmp-page .tmp-lede {
  margin-top: 2rem;
  color: var(--ink);
}

.tmp-note {
  color: var(--ink-faint);
}

/* The holding library list. Deliberately plain: it is a list of what is
   coming, not the Library page, and it should not be mistaken for it. */
.tmp-page-books {
  margin: 2.5rem 0 0;
}

.tmp-page-books li {
  padding-block: 1.125rem;
  border-bottom: 1px solid var(--line-soft);
}

.tmp-page-books strong {
  display: block;
  font-family: var(--ui);
  font-weight: 600;
  font-size: 1.0625rem;
  line-height: 1.25;
  letter-spacing: -0.018em;
  color: var(--ink);
}

.tmp-page-books span {
  font-size: 0.8125rem;
  color: var(--ink-dim);
}

/* The separator is spaced with a MARGIN and not with spaces inside the
   generated content. A trailing space at the end of an inline box is collapsed
   away, so a content of space, dot, space renders as a space and a dot and
   then nothing, which sets the dot hard against the word after it. */
.tmp-page-books span + span::before {
  content: '\00B7';
  margin-inline: 0.45em;
  color: var(--ink-faint);
}

/* --------------------------------------------------------------------------
   12b. The interior hero

   The front page's hero in every respect but height, and it is shared code
   rather than a resemblance: the eyebrow, the word by word rise, the actions
   and the accent all come out of the same rules.

   IT IS NOT FULL HEIGHT, and that is the one deliberate difference. The front
   page takes the whole screen because it has one statement to make and the
   reader should have to move to find the library. An interior page has the
   thing the visitor came for under the fold, and holding a form or an account
   of the project a full screen away is theatre at their expense. It opens on
   about two thirds of the screen, which is enough to be a beginning and not
   enough to be a wait.

   The header floats over it, as on the front page, so the ground reaches the
   top edge of the screen. Every page that opens on this passes `overlay`, and
   a page that does NOT open on one must not: a floating header over a heading
   on the flat ground is a header over nothing.

   The ground carries depth and no motif, the same rule as the front page. It
   is lit from the other side, so the two pages are recognisably the same site
   without being the same picture: the broad light sits high on the left here
   and behind the covers on the front page.
   -------------------------------------------------------------------------- */

.tmp-phero {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  display: flex;
  align-items: flex-end;
  padding-inline: var(--gutter);
  min-height: 62vh;
  min-height: 62svh;
  /* THE GOLD HAZE IS GONE HERE TOO, and it should have gone at the same time.
     Aamir said on 21 August 2026 that a tint of gold over the light blue does
     not look good, the front page's hero lost it that afternoon, and this one
     kept it: a warm wash at low alpha over a cool pale ground reads as dirt on
     the glass rather than as light, and it read that way on the About page for
     the same reason it read that way on the front page. What stands there now
     is the daylight the wash was drawing, lit from the same corner and in the
     same two colours as the front page's, so the two heroes are one design at
     two heights instead of two designs. */
  background:
    radial-gradient(52% 56% at 80% 14%, rgba(255, 255, 255, 0.8), transparent 70%),
    radial-gradient(56% 54% at 4% 92%, rgba(84, 142, 212, 0.26), transparent 74%),
    linear-gradient(180deg, #d8e8f8 0%, var(--ground) 76%);
}

/* THE HAIRLINE THAT USED TO CLOSE IT IS GONE, exactly as the front page's is,
   and for the same reason: the light bar in section 3 stands there now, and a
   hairline a few pixels above a bar is one line too many. */

/* The container the headline measures itself against. Same reason as the front
   page's: a headline sized from the viewport is at its largest exactly where
   its column is narrowest. */
.tmp-phero-inner {
  container-type: inline-size;
  width: 100%;
  padding-block: calc(var(--head) + clamp(3rem, 8vw, 5.5rem)) clamp(3.5rem, 8vw, 6rem);
}

/* Smaller than the front page's headline, because these are SENTENCES and that
   one is a title. 'An effort to make classical Islamic knowledge accessible in
   English' at 5.75rem would be five lines of display type before the page has
   said anything. The floor is still large enough to be the biggest thing on
   the screen. */
.tmp-ph1 {
  font-size: clamp(2.125rem, 5.6vw, 3.75rem);
  font-size: clamp(2.125rem, 6.4cqi, 4.25rem);
  font-weight: 700;
  line-height: 1.02;
  letter-spacing: -0.032em;
  max-width: 22ch;
}

/* A phrase lifted out of a headline, in the one accent the site has.

   The old About page set its equivalent in italic. Italic in the interface
   face at headline size reads as a slip rather than as emphasis, and the site
   already has a colour that means 'this is the important part': it is on every
   section name and every category on the front page. */
.tmp-hl {
  color: var(--gold);
}

.tmp-phero-lede {
  max-width: var(--column);
  margin-top: clamp(1.75rem, 4vw, 2.5rem);
  font-size: clamp(1.0625rem, 2vw, 1.25rem);
  line-height: 1.65;
  color: var(--ink-dim);
}

/* One paragraph set at statement size rather than at body size, for a section
   whose whole content is that paragraph. At body size it reads as a footnote
   under its own heading. */
.tmp-statement {
  max-width: 42rem;
  font-size: clamp(1.125rem, 2.4vw, 1.5rem);
  line-height: 1.6;
  letter-spacing: -0.014em;
  color: var(--ink-dim);
  text-wrap: pretty;
}

/* The closing line about Ṣadaqah Jāriyah, under the reasons to write.

   IT WAS SET AT STATEMENT SIZE and it read as though the page had started a
   new section rather than finished one: a line half again the size of the
   five paragraphs above it, in the same face, with nothing between them but
   air. It is a closing note on a list, so it is drawn as one: a short rule in
   the accent above it, the text one step up from the list's own body rather
   than three, and the same measure as the rows it closes. The rule is what
   separates it, which is what the size was being asked to do and could not. */
.tmp-sadaqah {
  max-width: var(--column);
  margin-top: clamp(2rem, 4vw, 2.75rem);
  padding-top: 1.5rem;
  font-size: 1.0625rem;
  line-height: 1.65;
  color: var(--ink);
  text-wrap: pretty;
  position: relative;
}

.tmp-sadaqah::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  width: 2.5rem;
  height: 1px;
  background: var(--gold);
}

/* --------------------------------------------------------------------------
   12d. A disclosure

   A section folded away behind a bar the visitor can open. Used once, for the
   reasons to write on the Contact page: the form is what that page is for, so
   the reasons sit above it as one closed line rather than as a section the
   visitor has to scroll past to reach the box.

   IT IS A REAL `details`, so it opens with no script at all, and the bar is a
   `summary`, which is a control the keyboard reaches and which a screen reader
   announces as collapsed or expanded without being told to. All this file does
   is take the browser's own triangle off and draw the site's own bar in its
   place.

   THE BAR IS A SECTION HEAD THAT HAPPENS TO OPEN: the same hairline, the same
   numeral in the accent, the same small capitals. A folded section still reads
   as one of the page's sections rather than as a widget dropped on top of the
   design.
   -------------------------------------------------------------------------- */

/* Tighter than a full band. The whole point of folding this away is that the
   form stays on the first screen, and a band of the usual rhythm round one
   closed line would spend most of what the fold saved. */
.tmp-open-band {
  padding-block: clamp(2rem, 4vw, 3rem);
}

.tmp-open {
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line-soft);
}

.tmp-open-bar {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: 0.375rem 1.5rem;
  padding-block: 1.125rem;
  cursor: pointer;
  /* Both halves of taking the browser's own marker off: Firefox and the
     standard property draw it from the list style, Safari and Chrome from
     their own pseudo-element. */
  list-style: none;
}

.tmp-open-bar::-webkit-details-marker {
  display: none;
}

.tmp-open-bar:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 4px;
}

/* Placed from the bar rather than on their own, because the bar's heading also
   carries `.tmp-sec-name`, which a section head stretches across its own grid
   at 48rem. Two rules of equal weight in different places is the sort of thing
   that comes apart the next time either is touched. */
.tmp-open-bar .tmp-open-name {
  grid-column: 1;
  grid-row: 1;
}

/* Not a heading and not a label: one line saying what is behind the bar, so
   the visitor can decide whether to open it without opening it. */
.tmp-open-bar .tmp-open-hint {
  grid-column: 1;
  grid-row: 2;
  max-width: var(--column);
  font-size: 0.9375rem;
  line-height: 1.55;
  color: var(--ink-dim);
}

.tmp-open-bar .tmp-open-mark {
  grid-column: 2;
  grid-row: 1 / -1;
  color: var(--gold);
  transition: transform 0.35s var(--ease-soft);
}

.tmp-open[open] .tmp-open-mark {
  transform: rotate(180deg);
}

.tmp-open-bar:hover .tmp-open-mark {
  color: var(--ink);
}

/* The panel cannot animate its height without a script, and it does not try
   to. What it does is arrive rather than appear: the content rises the same
   short distance a revealed section does, so opening the bar reads as part of
   the same design. Under reduced motion the blanket rule at the foot of
   section 14 cuts the duration to nothing and it is simply there. */
.tmp-open-body {
  padding-block: 0.5rem clamp(1.5rem, 4vw, 2.5rem);
  animation: tmp-unfold 0.45s var(--ease) both;
}

@keyframes tmp-unfold {
  from {
    opacity: 0;
    transform: translateY(12px);
  }
}

/* THE RULE THAT STOOD HERE IS GONE with the rows it was about. It took the
   hairline off the last row inside a panel, because the disclosure has its own
   along the bottom a panel's padding away and the two together were a pair of
   rules with nothing between them. The rows are cards since 21 August 2026 and
   a card is bordered on all four sides by definition, so there is no last row's
   rule left to take off. */

/* --------------------------------------------------------------------------
   12e. The duʿā

   The one moment on the site that asks the reader for something rather than
   offering them something, so it is the one place given a whole screen with
   nothing else on it.

   THE MARK IS DRAWN BEHIND IT, large and very faint. It is the same inline
   drawing the header and the footer use, in the current colour, so it needs no
   file and cannot be the wrong colour when the palette next changes. It sits
   behind the words rather than above them because it is a watermark and not an
   illustration: at this opacity it is texture, and the moment it is strong
   enough to look at, it is competing with the sentence.

   IT IS DRAWN IN THE LEAF GOLD, which is the one place on the site that colour
   appears at any size. It carries no text and never will, which is the whole
   condition on it in section 1, and a gold watermark on a pale blue page is
   the closest this design comes to an illumination.
   -------------------------------------------------------------------------- */

.tmp-dua {
  position: relative;
  isolation: isolate;
  display: grid;
  place-items: center;
  padding-block: clamp(2rem, 6vw, 4rem);
  text-align: center;
}

.tmp-dua-mark {
  position: absolute;
  z-index: -1;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: clamp(14rem, 34vw, 22rem);
  color: var(--gold-bright);
  /* Up from 0.22 on 21 August 2026, when the section moved onto the deep
     ground. The strength was set against a pale blue, where a fifth of the leaf
     gold was as much as could be laid on without it reading as a stain; over
     navy the same fifth is barely there, and gold on navy has no such ceiling
     in the first place. */
  opacity: 0.3;
}

.tmp-dua-mark svg {
  width: 100%;
  /* The mark carries width and height attributes so the header cannot jump
     while it loads, and those attributes map to the CSS properties. Setting
     only the width would letterbox it inside a box the wrong shape. */
  height: auto;
}

.tmp-dua-text {
  max-width: 40rem;
  font-size: clamp(1.1875rem, 2.8vw, 1.75rem);
  line-height: 1.6;
  letter-spacing: -0.016em;
  color: var(--ink);
  text-wrap: pretty;
}

/* The band that hands a page on to another one. No section number: it is the
   page finishing rather than another part of what it had to say. */
.tmp-cta {
  border-top: 1px solid var(--line);
  padding-top: clamp(2.5rem, 6vw, 4rem);
}

.tmp-cta-text {
  max-width: 30rem;
  font-size: clamp(1.375rem, 3.4vw, 2.25rem);
  font-weight: 600;
  line-height: 1.15;
  letter-spacing: -0.028em;
  color: var(--ink);
}

.tmp-cta .tmp-actions {
  margin-top: clamp(2rem, 5vw, 2.75rem);
}

/* --------------------------------------------------------------------------
   12f. The contact form

   Two columns above 62rem: the form, and beside it the address and what to
   expect. The second column is NOT a card. It is a column with a hairline down
   its inner edge, which separates it without drawing a box round it, and the
   rule moves to the top of the block when the two stack.

   THE CONTROLS ARE DRAWN THE WAY THE REST OF THE SITE IS: square, white
   against the page's faint blue, with a hairline that becomes the ink on focus.
   A form is the part of any design most often left as the browser drew it, and
   a rounded grey box with the browser's own blue focus ring in the middle of
   this page would undo the whole scheme.
   -------------------------------------------------------------------------- */

.tmp-contact {
  display: grid;
  gap: clamp(2.5rem, 6vw, 4rem);
  align-items: start;
}

@media (min-width: 62rem) {
  .tmp-contact {
    grid-template-columns: minmax(0, 1fr) 18rem;
    gap: clamp(3rem, 6vw, 5rem);
  }
}

.tmp-form {
  display: grid;
  gap: 1.5rem;
  max-width: 40rem;
}

.tmp-field-pair {
  display: grid;
  gap: 1.5rem;
}

@media (min-width: 34rem) {
  .tmp-field-pair {
    grid-template-columns: 1fr 1fr;
  }
}

.tmp-field label {
  display: block;
  font-size: 0.8125rem;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-dim);
  margin-bottom: 0.625rem;
}

/* The controls. The face and the size are STATED and not inherited, because a
   form control inherits neither: left alone it is drawn at the browser's own
   13px in the system interface face, and a form set in a different typeface
   from the page around it is the commonest way a dark design comes apart. */
.tmp-input {
  font-family: var(--ui);
  font-size: 1rem;
  line-height: 1.5;
  display: block;
  width: 100%;
  padding: 0.875rem 1rem;
  color: var(--ink);
  background: var(--sheet);
  border: 1px solid var(--line);
  border-radius: 0;
  /* Safari draws its own inner shadow and its own corner radius on an input
     whatever the border says. */
  appearance: none;
  transition:
    border-color 0.3s var(--ease-soft),
    background-color 0.3s var(--ease-soft);
}


.tmp-input::placeholder {
  color: var(--ink-faint);
}

.tmp-input:hover {
  border-color: var(--ink-faint);
}

/* The focus ring is drawn on the control's own border rather than as an
   outline offset away from it, because these boxes sit close together and an
   offset ring on a two column pair overlaps its neighbour. It is the ink,
   which is the site's focus colour everywhere else, and it is a border change
   AND a shadow so that it is still visible in forced colours. */
.tmp-input:focus-visible {
  outline: none;
  border-color: var(--ink);
  box-shadow: 0 0 0 1px var(--ink);
}

textarea.tmp-input {
  resize: vertical;
  min-height: 10rem;
}

/* The select's own arrow, drawn rather than left to the browser. `appearance:
   none` above takes the native one away, and without a replacement there is
   nothing to say the field opens. It is inline SVG in a data URI, so it costs
   no request, and it is drawn in the secondary ink so it sits back. The
   colour is written out rather than read from a token, because a data URI is a
   string and cannot hold a custom property: it is the one value in this file
   that has to be moved by hand when the palette moves. */
select.tmp-input {
  padding-right: 2.75rem;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8' fill='none'%3E%3Cpath d='M1 1.5L6 6.5L11 1.5' stroke='%234a5f7a' stroke-width='1.4' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 1rem center;
}

/* The option list is drawn by the operating system and takes almost nothing
   from this stylesheet. What it does take is these two, without which the list
   is white text on white on some platforms. */
select.tmp-input option {
  background: var(--sheet);
  color: var(--ink);
}

.tmp-field.is-bad .tmp-input {
  border-color: var(--warn);
}

.tmp-field-error {
  margin-top: 0.5rem;
  font-size: 0.875rem;
  color: var(--warn);
}

.tmp-field-hint {
  margin-bottom: 0.625rem;
  font-size: 0.875rem;
  color: var(--ink-dim);
}

/* What happened to the last attempt. It is the first thing in the form rather
   than the last thing after the button, so an answer cannot arrive below the
   fold on a phone, and it is a live region in the markup so the enhanced
   version, which never reloads the page, still announces it. */
.tmp-form-status {
  padding: 1rem 1.25rem;
  font-size: 0.9375rem;
  line-height: 1.6;
  border-left: 2px solid var(--line);
  background: var(--ground-raised);
}


/* THE TWO OUTCOMES ARE TOLD APART BY MORE THAN THE COLOUR, because a colour on
   its own is not a message: about one man in twelve cannot read the difference
   between these two hues, and the sentence inside is what actually says what
   happened. The colour is the confirmation, not the statement. */
.tmp-form-status.is-ok {
  border-left-color: var(--gold);
  color: var(--ink);
}

.tmp-form-status.is-bad {
  border-left-color: var(--warn);
  color: var(--ink);
}

/* The sentence explaining a form that arrived already filled in, from a link
   somewhere else on the site. */
.tmp-form-prefill {
  padding: 1rem 1.25rem;
  font-size: 0.9375rem;
  line-height: 1.6;
  color: var(--ink-dim);
  border-left: 2px solid var(--line);
}

.tmp-form-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1.25rem 1.75rem;
  margin-top: 0.5rem;
}

.tmp-form-note {
  font-size: 0.875rem;
  color: var(--ink-dim);
}

.tmp-form button[disabled] {
  opacity: 0.55;
  cursor: progress;
}

/* THE HONEYPOT, and why it is positioned away rather than hidden.

   A field set to `display: none`, or carrying the `hidden` attribute, is
   invisible to the crude bots as well, and they know to skip it. This one is
   in the layout and in the markup exactly like a real field, and simply
   painted off the page. The markup keeps a keyboard visitor out of it with
   `tabindex="-1"` and a screen reader out of it with `aria-hidden`, so the one
   thing that ever fills it in is something filling in every field it finds.

   `position: absolute` and not a negative margin: a negative margin would
   still take part in the layout and could drag the field below it upwards. */
.tmp-hp {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* The column beside the form. A hairline and not a box: on a phone the rule
   moves to the top, where it separates the two without pretending to be a
   panel. */
.tmp-contact-side {
  border-top: 1px solid var(--line);
  padding-top: 1.75rem;
}

@media (min-width: 62rem) {
  .tmp-contact-side {
    border-top: 0;
    border-left: 1px solid var(--line);
    padding-top: 0;
    padding-left: clamp(2rem, 4vw, 3rem);
  }
}

.tmp-contact-side h3 {
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--gold);
}

.tmp-contact-side h3 + p {
  margin-top: 0.75rem;
}

.tmp-contact-side p {
  font-size: 0.9375rem;
  line-height: 1.65;
  color: var(--ink-dim);
}

.tmp-contact-side p + h3 {
  margin-top: 2.25rem;
}

.tmp-contact-side a {
  color: var(--ink);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.2em;
  overflow-wrap: anywhere;
}

/* --------------------------------------------------------------------------
   12g. The Library page

   The bar, and the works.

   THERE ARE NO CARDS IN THE GRID, in the sense the live page meant by a card:
   no white panel, no border, no corner radius, no shadow drawn round the
   words. Nine pieces of commissioned artwork are the only colour on this site
   and a box drawn around each of them is a box competing with the thing it
   contains. A work is its cover standing on the ground, with its own edge and
   its own sheen from section 9, and three lines of type under it.

   THE BAR IS ONE ROW OF THREE BUTTONS. A round glass on the left that opens
   a search field the width of the bar, and on the right one button holding
   everything that narrows the library and one holding everything that orders
   it. Both are `details` elements, so they open with nothing running, and both
   panels are lifted out of the flow so that opening one does not push the nine
   covers down the page.

   The glass is THE ONE ROUND THING IN THIS DESIGN and it is round on purpose.
   Everywhere else a corner radius is refused, because it is the strongest
   single signal of the kit this design replaces; an icon on its own with no
   word beside it is the one shape that is read faster as a circle, and it is
   the shape the same control has in the other project. Everything with a word
   in it stays square.

   The rest is built out of the page's existing vocabulary rather than out of
   new furniture: the label above a group of chips is the numbered list's label
   column in 12c, the chosen chip is the primary action in section 6 at small
   size, and the count sits in the secondary ink like every other piece of
   metadata.
   -------------------------------------------------------------------------- */

/* NO HAIRLINE OF ITS OWN. The section head directly above has already ruled
   this section off, and a second line a heading's height below it was the
   first of the three stacked rules Aamir asked to be thinned out on 19 August
   2026. The bar's own line is the one UNDER it, which is the line that does
   real work: it separates the controls from the covers. */
.tmp-lib-filters {
  /* TWO NUMBERS NAMED ONCE, because two rules have to agree about them. The
     first is the gap between the bar and the covers. The second is the exact
     height the search field occupies when it is open, and the rule under this
     one and the field itself are the two places it is used: the field is drawn
     exactly this tall, and the space under the bar grows by exactly this much
     to hold it. Written out twice they would drift, and the way that failure
     shows is text on top of artwork. */
  --tmp-lib-gap: clamp(2.5rem, 6vw, 4rem);
  --tmp-find-h: 3.5rem;
  margin-bottom: var(--tmp-lib-gap);
}

/* THE SEARCH FIELD IS OUT OF THE FLOW, LIKE THE TWO MENUS, AND UNLIKE THEM IT
   HAS NO BOX OF ITS OWN, so on a phone it was being drawn straight over the
   first row of covers: the word SEARCH and the placeholder sat on the artwork
   with nothing between them and it. The menus get away with hanging over the
   page because each is an opaque panel a reader has this moment opened and
   will shut again in a moment. The field is meant to read as part of the bar,
   and part of the bar cannot float over the page.

   So while it is open the gap under the bar grows by exactly the height of the
   field, and the covers move down out of its way. The covers move, which the
   note on the panels above says they must not: that rule is about a menu
   opening over a list somebody is reading, and this is the bar getting taller
   by one row of itself, which is the one case where the list should move. */
.tmp-lib-filters:has(.tmp-lib-find[open]) {
  margin-bottom: calc(var(--tmp-lib-gap) + var(--tmp-find-h));
}

/* The bar. It is the containing block for the panels as well as for itself,
   which is what lets the search field span the whole width of the bar while
   the two menus on the right hang under their own buttons.

   THE THREE CONTROLS SHARE ONE ROW AT EVERY WIDTH, which is Aamir's decision
   of 19 August 2026 after seeing the bar break in two on a phone. It used to
   be one wrapping flex row, and on a narrow screen the count in the middle
   pushed Filter and Sort by onto a second line, so the three controls that are
   meant to read as one bar read as two rows of furniture.

   So below 52rem it is a two row grid and the ROW IS DECIDED rather than left
   to wrapping: the glass and the two menus take the first row, the count and
   the reset link take the second. From 52rem, which is the width at which the
   grid below goes to three columns, everything fits on one line and it goes
   back to being a single flex row. */
.tmp-lib-bar {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: 0.625rem 1rem;
  padding-block: 0.875rem;
  border-bottom: 1px solid var(--line-soft);
}

/* Stretched, not sat at the left: the whole point of the pill is that the gap
   between the search and the two menus is closed. */
.tmp-lib-bar .tmp-lib-find {
  grid-area: 1 / 1;
  justify-self: stretch;
  min-width: 0;
}

.tmp-lib-bar .tmp-lib-menus {
  grid-area: 1 / 2;
}

.tmp-lib-bar .tmp-lib-count {
  grid-area: 2 / 1;
}

.tmp-lib-bar .tmp-lib-reset {
  grid-area: 2 / 2;
  justify-self: end;
}

/* While the search is open, the field's own hairline is sitting a row below
   this one, so the bar stops drawing a second rule across the middle of the
   two. The colour goes rather than the border, so nothing moves. A browser
   without `:has` simply keeps both lines, which is a line too many and not a
   control that does nothing: that is the difference between using `:has` here
   and refusing it on the chips in the panel. */
.tmp-lib-bar:has(.tmp-lib-find[open]) {
  border-bottom-color: transparent;
}

/* Pinned right, which is where Aamir asked for them. They never wrap against
   each other: two buttons stacked in a corner is the same break in miniature. */
.tmp-lib-menus {
  display: flex;
  flex-wrap: nowrap;
  gap: 0.5rem;
  min-width: 0;
}

@media (min-width: 52rem) {
  .tmp-lib-bar {
    display: flex;
    flex-wrap: nowrap;
  }

  /* It takes the slack on this layout too, but not all of it: a pill running
     the whole way to the count would leave the count hard against the Filter
     button, and the search would be the largest thing on a bar whose subject
     is nine covers. */
  .tmp-lib-find {
    flex: 1 1 auto;
    min-width: 0;
    max-width: 22rem;
  }

  .tmp-lib-menus {
    margin-left: auto;
  }
}

/* Only the two on the right are positioned, so their panels hang under their
   own buttons. The search deliberately is NOT, so its panel resolves against
   the bar above and comes out the full width of it. */
.tmp-lib-menus .tmp-lib-menu {
  position: relative;
}

/* --- the search ---
   The one round thing in the design, and the reason is at the head of this
   section. It began as a glass with nothing in it and is a PILL as of 19
   August 2026, on Aamir's word, so that it fills the space left over beside
   the two menus instead of leaving a gap in the middle of the bar. Stretching
   a circle is the one change that keeps the reason the shape was allowed:
   round because it carries a drawing rather than a label, and it is still the
   only thing on the site with a radius on it.

   Which of the two icons inside it is showing is decided by the open state, in
   this stylesheet, so the button says what pressing it will do whether or not
   anything is running. */
.tmp-lib-glass {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  min-width: 2.375rem;
  min-height: 2.375rem;
  padding-inline: 0.8125rem;
  font-size: 0.8125rem;
  font-weight: 500;
  line-height: 1.4;
  border: 1px solid var(--line);
  border-radius: 999px;
  color: var(--ink-dim);
  cursor: pointer;
  /* Both halves of taking the browser's own marker off, as on the disclosure
     bars in section 12d. */
  list-style: none;
  transition:
    background-color 0.3s var(--ease-soft),
    color 0.3s var(--ease-soft),
    border-color 0.3s var(--ease-soft);
}

.tmp-lib-glass::-webkit-details-marker {
  display: none;
}

.tmp-lib-glass:hover {
  color: var(--ink);
  border-color: var(--ink-faint);
}

.tmp-lib-glass:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 3px;
}

/* Open, or holding a search that is narrowing the library. Solid, because
   this is the one control on the bar with no words on it to carry a state. */
.tmp-lib-find[open] .tmp-lib-glass,
.tmp-lib-find.is-on .tmp-lib-glass {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--ground);
}

.tmp-lib-find:not([open]) .tmp-i-close,
.tmp-lib-find[open] .tmp-i-search {
  display: none;
}

/* The word beside the drawing, and the first thing to go when the pill has no
   room for it: under 23rem the two menus leave a gap the width of the glass
   itself, and a pill that has to cut a five letter word in half is worse than
   the glass it came from. */
.tmp-lib-glass-word {
  display: none;
}

@media (min-width: 23rem) {
  .tmp-lib-glass-word {
    display: inline;
  }
}

/* --- the two buttons ---
   The chip's own shape at the size of a control rather than of a choice: same
   hairline, same weight, same square corners. Open is a tinted fill and a
   darker edge rather than the chip's solid inversion, because these two carry
   a gold tally and a gold order name inside them and neither reads on a slab
   of the ink. */
.tmp-lib-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5625rem 0.875rem;
  font-size: 0.8125rem;
  font-weight: 500;
  line-height: 1.4;
  color: var(--ink-dim);
  border: 1px solid var(--line);
  cursor: pointer;
  white-space: nowrap;
  list-style: none;
  transition:
    background-color 0.3s var(--ease-soft),
    color 0.3s var(--ease-soft),
    border-color 0.3s var(--ease-soft);
}

.tmp-lib-btn::-webkit-details-marker {
  display: none;
}

.tmp-lib-btn:hover {
  color: var(--ink);
  border-color: var(--ink-faint);
}

.tmp-lib-btn:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 3px;
}

.tmp-lib-menu[open] .tmp-lib-btn {
  background: var(--ground-tint);
  color: var(--ink);
  border-color: var(--ink-faint);
}

/* The chevron is the same one the About page's folded sections use, so it has
   to be turned here as well: the rule that turns it there is scoped to that
   bar, and two rules of equal weight in different places is the sort of thing
   that comes apart the next time either is touched. */
.tmp-lib-btn .tmp-open-mark {
  color: var(--gold);
  transition: transform 0.35s var(--ease-soft);
}

.tmp-lib-menu[open] .tmp-lib-btn .tmp-open-mark {
  transform: rotate(180deg);
}

/* How many choices are narrowing the library, on the face of the Filter
   button. It is there so that a library quietly showing four of nine can never
   look like a library of four. */
.tmp-lib-tally {
  min-width: 1.25rem;
  padding-inline: 0.25rem;
  font-size: 0.6875rem;
  font-weight: 600;
  line-height: 1.25rem;
  text-align: center;
  color: var(--ground);
  background: var(--gold);
  font-variant-numeric: tabular-nums;
}

/* And the order the library is in, on the face of the Sort by button, so the
   one thing a closed menu ought to say is the one thing it says.

   It is the one piece of the bar that stands down on a phone, and it is the
   right piece to lose: the order is the only thing behind either button that
   changes nothing about WHICH works are on the page, so a reader who cannot
   see it is not being kept from anything. The tally on Filter never stands
   down for exactly that reason, because a library quietly showing four of nine
   must always say so. */
.tmp-lib-chosen {
  display: none;
  color: var(--gold);
}

@media (min-width: 52rem) {
  .tmp-lib-chosen {
    display: inline;
  }
}

.tmp-lib-tally[hidden] {
  display: none;
}

/* --- the panels ---
   Lifted out of the flow, over the grid rather than pushing it down: nine
   covers moving half a screen because somebody opened a menu is the page
   losing the reader's place to answer a question they have not asked yet. */
.tmp-lib-panel {
  position: absolute;
  z-index: 30;
  top: calc(100% + 0.6rem);
  min-width: 14rem;
  max-width: min(22rem, calc(100vw - 2 * var(--gutter)));
  padding: 1.125rem 1.25rem 1.25rem;
  background: var(--sheet);
  border: 1px solid var(--line);
  box-shadow: 0 2px 6px rgba(18, 37, 63, 0.06), 0 24px 48px rgba(18, 37, 63, 0.16);
  display: grid;
  gap: 1.125rem;
  animation: tmp-unfold 0.3s var(--ease) both;
}

/* Anchored to the right edge of its own button, because these two are pinned
   right and a panel opening rightwards would open off the screen. */
.tmp-lib-panel-end {
  right: 0;
}

/* The search is not a panel hanging off a button, it is the bar's second row:
   flush under it, the full width of it, and reading as part of the bar rather
   than as something floating over the page. */
.tmp-lib-panel-find {
  left: 0;
  right: 0;
  top: 100%;
  /* Drawn to the height the rule above reserves for it, rather than to
     whatever its contents come out at, so that the two can never disagree. */
  height: var(--tmp-find-h);
  max-width: none;
  padding: 0.875rem 0 1rem;
  /* The page's own ground rather than nothing at all. It looks the same,
     because the ground under it is the same colour, and it is what stands
     between the field and a cover if the space above is ever not reserved. */
  background: var(--ground);
  border: 0;
  border-bottom: 1px solid var(--line-soft);
  box-shadow: none;
}

.tmp-lib-field {
  display: flex;
  align-items: baseline;
  gap: 1rem;
  /* The line the label and the field sit on, fixed, because the panel's height
     is fixed and the two are the same fact stated at both ends. */
  min-height: 1.625rem;
}

/* The field carries no box of its own. The bar's own hairline under it is the
   line it sits on, which is one piece of furniture instead of two. */
.tmp-lib-field input {
  flex: 1;
  min-width: 0;
  /* A search input is a box with a shape of its own on iOS, taller than the
     line it holds and carrying its own clear button. The design already has a
     way to clear and close, on the pill, and a box here would be the second
     piece of furniture the note above refuses. */
  appearance: none;
  -webkit-appearance: none;
  padding: 0;
  background: none;
  border: 0;
  color: var(--ink);
  font-family: var(--ui);
  font-size: 1.0625rem;
  line-height: 1.5;
}

.tmp-lib-field input::placeholder {
  color: var(--ink-faint);
}

.tmp-lib-field input:focus {
  outline: none;
}

/* One question inside a panel: its label, then its choices. */
.tmp-lib-group {
  display: grid;
  gap: 0.625rem;
}

.tmp-lib-label {
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--gold);
}

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

/* A CHOICE IS A REAL RADIO BUTTON with the box drawn on the span beside it,
   and that is worth being exact about, because the obvious way to write this
   is wrong in two directions.

   Styling the label on `:has(input:checked)` reads better and is what the live
   page does. A browser without `:has` then draws no chosen state at all, so
   the bar works and shows nothing about what it is showing. The adjacent
   sibling has worked everywhere since forever.

   And the input is moved off the box rather than given `display: none`, which
   would take it out of the tab order and leave the bar unreachable from a
   keyboard. It stays in the layout at one pixel with no opacity, so it is
   focusable, and the focus ring is drawn on the span next to it. */
.tmp-chip {
  position: relative;
  display: inline-flex;
}

.tmp-chip input {
  position: absolute;
  top: 0;
  left: 0;
  width: 1px;
  height: 1px;
  margin: 0;
  opacity: 0;
}

.tmp-chip span {
  display: inline-block;
  padding: 0.5rem 0.9375rem;
  font-size: 0.8125rem;
  font-weight: 500;
  line-height: 1.4;
  color: var(--ink-dim);
  border: 1px solid var(--line);
  cursor: pointer;
  transition:
    background-color 0.3s var(--ease-soft),
    color 0.3s var(--ease-soft),
    border-color 0.3s var(--ease-soft);
}

.tmp-chip:hover span {
  color: var(--ink);
  border-color: var(--ink-faint);
}

.tmp-chip input:checked + span {
  background: var(--ink);
  color: var(--ground);
  border-color: var(--ink);
}

.tmp-chip input:focus-visible + span {
  outline: 2px solid var(--ink);
  outline-offset: 3px;
}

/* Counted at the moment the page is drawn, never typed into a sentence.
   Tabular figures so the number does not jog the words beside it as the
   filters change. */
.tmp-lib-count {
  font-size: 0.8125rem;
  color: var(--ink-dim);
  font-variant-numeric: tabular-nums;
}

/* The whole foot is the submit button, and it goes only once the script has
   said it is running. It is the control a visitor with no script uses, so
   hiding it in the stylesheet and revealing it by script would be the one
   arrangement that leaves a broken page: the same bargain the reveal system
   makes in section 14. */
.tmp-lib-foot {
  padding-top: 1.25rem;
}

.js-lib .tmp-lib-foot {
  display: none;
}

.tmp-lib-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(2.25rem, 5vw, 3.5rem) clamp(1.25rem, 3vw, 2.5rem);
}

/* Three columns from 52rem and no more than three at any width. The library
   is nine works, so three columns is three full rows: a fourth column would
   leave a row of one, and the covers would be small enough to be thumbnails,
   which is the format this design took the front page out of. */
@media (min-width: 52rem) {
  .tmp-lib-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

/* A filtered row is hidden with the attribute rather than a class, so the
   browser does it and nothing has to run. This says the same thing the user
   agent already says, and is here because a grid item with a display of its
   own would otherwise ignore it. */
.tmp-lib-item[hidden],
.tmp-lib-reset[hidden],
.tmp-lib-empty[hidden] {
  display: none;
}

.tmp-lib-card {
  display: block;
  text-decoration: none;
  color: inherit;
}

.tmp-lib-cover {
  display: block;
  margin-bottom: 1.125rem;
}

.tmp-lib-card:hover .tmp-cover {
  transform: translateY(-10px);
  box-shadow: var(--cover-lift);
}

.tmp-lib-cat {
  display: block;
  font-size: 0.625rem;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--gold);
  margin-bottom: 0.5rem;
}

.tmp-lib-title {
  font-size: clamp(1rem, 1.7vw, 1.1875rem);
  font-weight: 600;
  line-height: 1.25;
  letter-spacing: -0.02em;
  text-wrap: pretty;
  transition: color 0.3s var(--ease-soft);
}

.tmp-lib-by {
  display: block;
  margin-top: 0.4375rem;
  font-size: 0.8125rem;
  line-height: 1.5;
  color: var(--ink-dim);
}

/* The empty state. It happens: every work in the library is a translation
   today, so asking for the original works is a fair question with nothing to
   answer it. The words are the live page's own. */
.tmp-lib-empty {
  padding-block: clamp(3rem, 8vw, 5rem);
  text-align: center;
  font-size: 1.125rem;
  color: var(--ink-faint);
}

/* --------------------------------------------------------------------------
   14. Reveal on scroll

   Progressive enhancement in the strict sense: the rule that hides an element
   only applies once the script has marked the document, so with JavaScript
   off, or if the script fails, every element is simply visible. Hiding first
   and revealing with script is how a broken script turns into a blank page.

   THE STAGGER IS A NUMBER ON THE ELEMENT, --d, and not a class per step.
   -------------------------------------------------------------------------- */

.js-reveal .tmp-reveal {
  opacity: 0;
  transform: translateY(26px);
  transition:
    opacity 0.9s var(--ease),
    transform 0.9s var(--ease);
  transition-delay: calc(var(--d, 0) * 70ms);
}

.js-reveal .tmp-reveal.is-in {
  opacity: 1;
  transform: none;
}

/* THE QUICK LANE, added 20 August 2026.

   Aamir asked for it about the contents pages: people scroll a list of
   chapters fast, and the reveal above is nine tenths of a second with a stagger
   on top of it, so a fast scroller meets rows that are still on their way in.
   A row that is not there yet is worse than no animation at all.

   So a long list takes this instead: opacity only, a fifth of a second, no
   movement and no stagger. It is small enough to be felt rather than watched,
   and the observer in shell.js starts it well before the row reaches the screen
   rather than as it crosses the edge, so by the time a row is under the eye it
   has almost always finished.

   It is a modifier rather than a second system: the hiding rule, the marking
   class and the reduced-motion escape are all the ones above, so a page whose
   script never ran is still simply visible. */
.js-reveal .tmp-reveal.is-quick {
  transform: none;
  transition: opacity 0.2s linear;
  transition-delay: 0s;
}

/* THE HEADLINE, WORD BY WORD.

   Each word sits in its own box with the overflow taken away and rises from
   under its own baseline. The box carries a little padding at the foot and an
   equal negative margin, so the mask clears the descenders without moving the
   line. The words are separate elements, but the text nodes are unchanged and
   the spaces between them are real spaces, so the heading reads, wraps and
   selects exactly as one line of prose. */
.tmp-w {
  display: inline-block;
  overflow: hidden;
  vertical-align: bottom;
  padding-bottom: 0.14em;
  margin-bottom: -0.14em;
}

.tmp-w > span {
  display: inline-block;
}

/* The headline is observed like everything else, but it is the WORDS that
   move rather than the block, so the block's own fade is turned back off. */
.js-reveal .tmp-headline {
  opacity: 1;
  transform: none;
}

.js-reveal .tmp-headline .tmp-w > span {
  transform: translateY(105%);
  transition: transform 1.05s var(--ease);
  transition-delay: calc(var(--d, 0) * 80ms);
}

.js-reveal .tmp-headline.is-in .tmp-w > span {
  transform: none;
}

/* Motion is a preference the reader has already expressed to their operating
   system. Honour it: no reveal, no lift, no drift, no cue, no smooth scroll. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }

  .js-reveal .tmp-reveal,
  .js-reveal .tmp-headline .tmp-w > span {
    opacity: 1;
    transform: none;
  }

  .tmp-cue { display: none; }
}

/* --------------------------------------------------------------------------
   15. Scroll driven animation

   No script at all: these are driven by the browser's own scroll and view
   timelines. Every one is behind BOTH a support query and a reduced-motion
   query, and every one has a resting state that is correct by itself, so a
   browser without them and a reader who has asked for less motion both get a
   page that is finished rather than one with something missing.

   The reduced-motion block above cannot be relied on to switch these off, and
   that is why they sit inside a no-preference query rather than merely being
   overridden later: a scroll driven animation takes its progress from the
   scroll position rather than from a clock, so the 0.01ms that stops every
   other animation would leave these running at whatever fraction it implies.
   -------------------------------------------------------------------------- */

@supports (animation-timeline: scroll()) {
  @media (prefers-reduced-motion: no-preference) {
    /* The reading progress line, across the whole document. */
    .tmp-progress {
      animation: tmp-progress linear both;
      animation-timeline: scroll(root block);
    }

    /* The floating header settling into the bar. The range is the first few
       centimetres of scroll, so it has finished long before the hero has left
       the screen. Only the ground and the hairline arrive: the type is the
       ink in both states, which is what makes this two ordinary properties
       rather than four registered colours cross fading. */
    .tmp-header-overlay {
      animation: tmp-head linear both;
      animation-timeline: scroll(root block);
      animation-range: 0 5rem;
    }
  }
}

@keyframes tmp-progress {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}

@keyframes tmp-head {
  from {
    background-color: var(--ground-veil-0);
    border-bottom-color: var(--line-0);
  }
  to {
    background-color: var(--ground-veil);
    border-bottom-color: var(--line);
  }
}

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    /* THE DRIFTS THIS FILE HAS CARRIED HAVE ALL MOVED ON, and the reason is
       the same one every time: the thing being drifted stopped existing or
       stopped being something safe to move. The hero's fan became the deck,
       which is a scroller and must not be shifted under a thumb that is aiming
       at it. The library section came off the front page. The drawing of the
       reader went with the Reading section on 21 August 2026.

       What is left is the cover over the extract, and it is the right thing
       for this: it is an image rather than a control and nothing about it is a
       target. It stands centred above the quotation since the section was
       redrawn on 21 August 2026, so what the drift moves it against is the air
       around it rather than a column of type. It is held to wide screens all
       the same: on a phone the whole composition is one narrow stack, and a
       piece of it sliding against the rest of that stack is movement with
       nowhere to go.

       It is moved with the `translate` PROPERTY rather than with a transform,
       and that is the trick worth keeping from the fan: translate is applied
       before transform in the same matrix, so a drift composes with whatever
       transform the element already has instead of replacing it. That matters
       here, because the cover inside it lifts on hover. */
    @media (min-width: 52rem) {
      .tmp-passage-cover {
        animation: tmp-drift linear both;
        animation-timeline: view();
        animation-range: entry 0% exit 100%;
        --drift: 1.25rem;
      }
    }
  }
}

@keyframes tmp-drift {
  from { translate: 0 var(--drift, 2rem); }
  to   { translate: 0 calc(var(--drift, 2rem) * -1); }
}

/* --------------------------------------------------------------------------
   16. The brand loader, and the cover over a cold arrival

   The drawing lives in server/src/brand-loader.js, which is where the reasons
   for every phase of it are written down. Nothing here moves anything: this is
   the palette the drawing takes, plus the cover it sits on. Every colour is a
   token, which is exactly why the whole scheme could be repointed from
   parchment and forest, to ivory and amber, and then to navy and gold on
   daylight, without one line of the drawing being touched.

   THE ONE THING THAT DID CHANGE IS WHICH WAY ROUND THE HOT BEAD GOES, and it
   is the only place in this file where the inversion was more than a token. On
   ink, a light source is a warm halo round a PALE core, because the brightest
   thing in a dark picture is the light itself. On paper the brightest thing is
   the paper, so a hot bead is a pale halo round a DARK core, and the two are
   swapped below.
   -------------------------------------------------------------------------- */

.tmp-loader {
  /* The nib's glow and its sparks fly outside the mark's own box. */
  overflow: visible;
}

/* The mark itself is drawn in the page's own ink: it is being drawn on a very
   pale ground, so it is the darkest thing on the screen. */
.tmp-loader-ink { fill: var(--ink); }
.tmp-loader-bloom { stroke: var(--gold-bright); }

/* The nib, as the note at the head of this section explains: a pale halo round
   a dark core, which is what a hot point looks like on paper. The sparks go the
   same way, the hot one being the darker of the two. */
.tmp-loader-halo { fill: var(--gold-bright); }
.tmp-loader-nib { fill: var(--gold-bright); }
.tmp-loader-core { fill: var(--gold); }
.tmp-loader-spark { fill: var(--gold-bright); }
.tmp-loader-spark-hot { fill: var(--gold); }

/* One pass of light across the finished mark, with nothing showing at either
   edge so the band has no hard end. It is the PAGE's colour rather than the
   ink's, because a pass of light over a dark mark on white paper is the paper
   showing through it. */
.tmp-loader-light-edge { stop-color: var(--ground); stop-opacity: 0; }
.tmp-loader-light-mid { stop-color: var(--ground); stop-opacity: 0.55; }

/* The cover is DISPLAY NONE until its script has marked the document, which is
   the same bargain the menu and the reveal make: a visitor with JavaScript
   off, and a crawler, never meet it, and a script that failed to run cannot
   leave anybody behind a cover that nothing removes. */
.tmp-splash {
  display: none;
}

.js-splash .tmp-splash {
  display: flex;
  position: fixed;
  inset: 0;
  /* Above the header, which is the highest thing on the page. */
  z-index: 200;
  align-items: center;
  justify-content: center;
  background: var(--ground);
  opacity: 1;
  /* This duration and the one the script waits before it removes the cover are
     the same number in two places. Move them together. */
  transition: opacity 420ms ease;
}

/* Nothing scrolls underneath a cover. */
.js-splash,
.js-splash body {
  overflow: hidden;
}

.js-splash .tmp-splash.is-leaving {
  opacity: 0;
}

.tmp-splash-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  /* NO GAP HERE, AND THE NAME IS PULLED UP INSTEAD. The mark's own artwork
     carries about a seventh of its height as empty space below the book,
     because the nib's glow and its sparks fly outside the mark and a filter
     region clipped at the edge shows a hard corner. So a gap measured between
     the two boxes reads as roughly twice itself between the two things a
     reader actually sees. Any retuning of BOX in brand-loader.js changes what
     this has to cancel. */
  gap: 0;
  /* The name is set nowrap and starts the animation spaced wide apart, so it
     is briefly at its widest on the narrowest screen. */
  padding-inline: var(--gutter);
  /* A shade above the middle. Dead centre reads as low, because the eye puts
     the optical centre of a page above its geometric one. */
  transform: translateY(-4%);
}

.tmp-splash-mark {
  width: clamp(8rem, 34vw, 11.5rem);
  height: auto;
}

/* The name, larger than anywhere else on the site: this is the one place where
   it is the whole page rather than a label in a bar. */
.tmp-splash-name {
  /* Up into the mark's own bottom padding, not into the mark. Scaled off the
     mark's width so it tracks the artwork on every screen. */
  margin: calc(clamp(8rem, 34vw, 11.5rem) * -0.04) 0 0;
  font-family: var(--ui);
  font-weight: 700;
  font-size: clamp(1.5rem, 7vw, 2.5rem);
  letter-spacing: -0.028em;
  line-height: 1.1;
  color: var(--ink);
  white-space: nowrap;
}

/* It ARRIVES WITH THE DOME rather than sitting there from the first frame: the
   letters come up from under the mark, spaced apart and closing to their set
   width, so the mark is drawn and then named. The delay is set on the element
   itself, in brand-loader.js, because the drawing is what decides when the
   name is due.

   `both` matters twice over. It holds the first frame through the delay, so
   the name is not visible before its turn, and it holds the last one after, so
   it does not snap back when the animation ends. And this is qualified by
   .js-splash like everything else on the cover: the name on a page whose
   script never ran is simply there. */
.js-splash .tmp-splash-name {
  animation: tmp-name-in 900ms var(--ease) both;
}

@keyframes tmp-name-in {
  from {
    opacity: 0;
    transform: translateY(0.6rem);
    letter-spacing: 0.14em;
  }
  to {
    opacity: 1;
    transform: none;
    letter-spacing: -0.028em;
  }
}

/* --------------------------------------------------------------------------
   17. Print

   MUCH SMALLER THAN IT WAS, and that is a dividend of the pale scheme rather
   than a corner cut. Printing the dark site meant inverting the whole of it,
   ground by ground and colour by colour, because a black page empties a
   cartridge and prints white type as nothing at all. The screen is now already
   dark type on a near white page, so all that is left to do is take the
   furniture off, flatten the two tinted grounds to plain white so the printer
   does not lay ink down over a whole sheet, and stop the hero reserving a
   screen's worth of height on paper that has no screen.
   -------------------------------------------------------------------------- */

@media print {
  .tmp-header,
  .tmp-footer,
  .tmp-cue,
  .tmp-deck-foot,
  .tmp-progress,
  .tmp-rule {
    display: none;
  }

  html,
  body,
  .tmp-hero,
  .tmp-phero,
  .tmp-raised,
  .tmp-shelf {
    background: #fff;
  }

  /* A DEEP BAND PRINTS AS PAPER. It is a section that repoints the ink, the
     rules and the accent onto a dark ground (section 3), so left alone it
     would come out of a printer as white type on white paper, or as a page of
     solid navy on a printer told to print backgrounds. Every token it moved is
     moved back, which is the whole of the fix: the rules inside it are the
     same rules the rest of the site uses and they take these values. */
  .tmp-deep {
    --ink: #000;
    --ink-dim: #000;
    --ink-faint: #000;
    --line: rgba(0, 0, 0, 0.3);
    --line-soft: rgba(0, 0, 0, 0.15);
    --gold: #000;
    --gold-dark: #000;
    --ground: #fff;
    --ground-raised: #fff;
    --ground-tint: #fff;
    --sheet: #fff;
    --card-edge: none;
    --cover-edge: none;
    --cover-lift: none;
    background: #fff;
    color: #000;
  }

  /* A card is a box on paper and nothing else. The lift is a screen idea and
     comes out of a printer as a grey smudge along two edges. */
  .tmp-list-item,
  .tmp-card {
    box-shadow: none;
    border-color: rgba(0, 0, 0, 0.25);
  }

  .tmp-hero {
    min-height: 0;
  }

  /* The secondary ink is a mid blue on screen, which is right there and grey
     and weak on paper. Prose printed off this site comes out in the one ink. */
  .tmp-work-by,
  .tmp-passage-meta,
  .tmp-page p,
  .tmp-lede,
  .tmp-statement,
  .tmp-list-body {
    color: #000;
  }
}

/* ==========================================================================
   read.css - the reading surface, and the pages that lead to it.
   ==========================================================================

   THE SHEET. Aamir asked on 19 August 2026 for the reading part of the site to
   be light with dark text on it, at a time when everything around it was
   midnight blue. The site itself became light on 21 August 2026, so the sheet
   is no longer the one lit thing on a dark page; it is a sheet of paper laid on
   a pale blue desk, which is what it was always meant to look like.

   THE SEPARATION IS STILL REAL AND IS NOW MADE THREE WAYS, none of which is
   brightness. The paper is WARM and the site around it is COOL, so the two are
   different colours rather than two shades of one. The paper casts a SHADOW,
   which is what says it is an object resting on something. And the ground it
   rests on is the light blue rather than the page's white, which is set on
   `.tmp-chapter` in section 3 and is the reason a chapter page is a shade bluer
   than the rest of the site. A reader should be able to see where the site
   stops and the book starts without being told.

   WHY THE BOOK IS ON PAPER AT ALL is unchanged and is the point of the design.
   Dark type on light paper is what four centuries of setting long-form text has
   settled on: it is what the eye tracks best over an hour, it is what every
   printed edition of these same works looks like, and it is what the PDF and
   the paperback of this text will be. A reader who moves between the web
   chapter and the printed one should not be moving between two different books.

   THE SEPARATION IS BY SCOPE, not by exception. Everything in section 3 below
   lives inside `.tmp-read`, which wraps the formatted chapter and nothing else.
   That matters for the reader's font scale: DESIGN-CONSISTENCY section 2.3
   records that the live site achieves the same separation by excluding four
   page identifiers from every rule, which breaks the day a fifth page is added.
   Here the two never meet: no rule in site.css reaches inside `.tmp-read`, and
   no rule here reaches outside it.

   WHERE THE VALUES COME FROM. Sections 1 to 4 of DESIGN-CONSISTENCY.md are the
   specification for this surface, extracted from the live site's own
   stylesheet, and every proportion below is theirs. ONE THING IS DELIBERATELY
   DIFFERENT and it is recorded there: the live site sets its body text at 14px,
   and this sets it between 17px and 19px. 14px is small for continuous reading
   on a phone and it is the size the live site's own reader tools exist to
   escape from. Every other size is expressed as a multiple of the body size, in
   `em`, at exactly the ratio the live stylesheet uses, so the whole scale moves
   together and the reader's scale is one token.

   THE PALETTE IS THE PAPER'S, not the site's, and that is still true now that
   both are light. The paper's ink is a warm near black and the site's is a
   navy; they are close in weight and different in temperature, which is the
   same distinction the two grounds make. The one thing the two palettes now
   SHARE is the gold: the site's accent is dark enough to carry small text on
   white, so the footnote markers, the chapter links and the reading progress
   are all one colour across the whole site. They were two before, because an
   accent drawn to carry on a midnight ground had 1.7:1 on ivory.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Tokens
   -------------------------------------------------------------------------- */

:root {
  /* THE PAPER. The site's own page colour since 21 August 2026: a white with
     enough blue in it to be a colour rather than an absence, which is what the
     library and the book pages are read on, so a chapter no longer changes
     shade the moment it is opened. Not pure white, because pure white at this
     size over this many words is glare. The warm white this used to be is
     still a choice a reader can make, under the name Ivory, and section 5.1
     holds it with the rest of the tints. ONE value, not a set: a reading
     surface with three shades of paper on it is a reading surface with panels
     on it, and the only thing that separates the notes from the text is a
     hairline.

     IT MOVED WITH THE SITE LATER THE SAME DAY. Aamir said the light blue was
     too faint and asked for it to be concentrated, so the page went from a
     white with a hint of blue in it to a pale blue page. The rule above is
     what made this follow it: the value is not a colour chosen for a chapter,
     it is the colour of the page the chapter was opened from, and a reading
     surface left on the old white would have been the one part of the site
     that ignored the instruction. 14.3:1 against the ink, so it still clears
     AAA at every size. */
  --paper: #e6f0fb;

  /* THE INK ON IT. A very dark warm grey rather than black, because the maximum
     contrast is not the most readable contrast over a long passage, and because
     a warm ink on warm paper is one decision rather than two. 15.8:1 on the
     paper, so it clears AAA at every size on the page.

     The dim tone carries the captions and the sign-offs, which are attributions
     rather than the text itself. 7.4:1, which clears AAA at the sizes it is
     used at and AA everywhere. */
  --read-ink: #21201d;
  --read-dim: #57534a;

  /* The quoted translation. Between the two: it is the text, but it is a
     quotation of it, and it is set italic and centred so it needs to be a
     shade quieter than the body without receding to a caption. 10.8:1. */
  --read-quote: #3f3b34;

  /* Hairlines, drawn in the ink rather than in a grey, so they sit ON the
     paper the way the site's are drawn in its own ink. */
  --read-rule: rgba(33, 32, 29, 0.13);
  --read-rule-soft: rgba(33, 32, 29, 0.07);

  /* THE ACCENT ON PAPER, AND IT IS NOW THE SITE'S OWN GOLD. It used to be a
     colour of its own, because the site's accent was an amber drawn to carry on
     a midnight ground and had 1.7:1 here, which cannot carry a footnote marker
     or a link. The palette of 21 August 2026 is a gold chosen to carry small
     text on white, so there is one accent for the whole site again.

     IT MOVED WITH THE SITE'S GOLD TWICE ON 21 AUGUST 2026. Aamir said the gold
     was reading as brass, so --gold first went up in saturation from 79 per
     cent to 92; he said it again that evening, and the second answer was the
     hue rather than the purity, from 41 to 32, which is a yellow with the red
     left in it rather than the green. The sentence above is what makes both of
     them follow: one accent for the whole site is not one accent if the two
     files hold different values for it. 5.8:1 on this paper, which clears AA at
     any size and AAA at the sizes it is used at, which are a superscript number
     and a link.

     THE OTHER HALF OF THAT EVENING'S ANSWER DOES NOT REACH HERE, and it should
     not. What made the gold look like gold on the front page is that the site
     grew a deep navy ground for it to sit on. A chapter is a sheet of paper
     with words on it and has no dark bands in it, so the paper keeps the
     readable value and nothing else changes. */
  --read-accent: #96520a;
  --read-accent-soft: rgba(150, 82, 10, 0.14);

  /* THE GLOSSARY MARK. The accent at just over a third, which is the faintest
     a 1px dotted line can be drawn on this paper and still be seen when it is
     looked for. It is a token rather than a literal because it is used in two
     places, the mark on the word and the hairline on the bubble that opens
     from it, and those two must not drift apart. */
  --read-term-line: rgba(150, 82, 10, 0.38);

  /* THE BODY SIZE, and the one place the reading scale is set. Everything in
     section 3 is an `em` multiple of this, at the ratios the live stylesheet
     uses at its level 3, so the whole page moves when this does.

     17px on a phone, 19px on a wide screen. */
  --read-size: clamp(1.0625rem, 1rem + 0.35vw, 1.1875rem);

  /* THE READER'S OWN SCALE, sitting on top of the size above, and the three
     leadings that move with it. These are the resting values, which are
     level 3. Section 6 is where the other four levels change them, and they
     change nothing else in this file: that is the whole reason the sizes in
     section 3 are `em` multiples rather than absolute. DESIGN-CONSISTENCY.md
     section 2.3 is the specification and records what was chosen where the
     live stylesheet left a gap. */
  --read-scale: 1;
  --read-lead: 1.75;
  --read-lead-ar: 2.1;
  --read-lead-ur: 3;

  /* THE FACE'S OWN CORRECTION, one for each of the five reading faces, set by
     section 5.1 and resting at 1 for the default serif. Apparent size is
     x-height rather than em size, and the five are far apart on it, so without
     this a step on the scale above would mean a different size in every face. */
  --read-face: 1;

  /* The measure. 34rem at the body size above is a little over 70 characters,
     which is the middle of the range long-form text is comfortable at. It is
     the same token site.css uses for prose, restated here in the reading
     surface's own terms so the two can be moved apart if they ever need to be.

     IT GROWS WITH THE READING SCALE, above the default and only above it, which
     it did not before 20 August 2026 and has to now. A measure is a count of
     CHARACTERS, not a width, and the slider added that day reaches 2.187 times
     the default size: held at 34rem, the largest step would put about twenty
     six characters on a line, which is a newspaper column rather than a book.
     The growth is damped to 0.6 of the scale's own, so the line does get a
     little shorter as the type gets larger, which is what a large-print edition
     does too. Below the default nothing moves: `max()` holds the factor at 1,
     because a reader who has chosen small type wants more words on the screen
     and not a narrower ribbon of them.

     The sheet is drawn from this as well, so the paper widens with the words
     rather than the words outgrowing the paper. */
  --read-measure: 34rem;
  --read-column: calc(var(--read-measure) * max(1, 1 + (var(--read-scale) - 1) * 0.6));

  /* The paper's own inset, which is larger than the site's gutter: a sheet
     needs a margin or the type runs into the edge and stops reading as a page. */
  --read-pad: clamp(1.5rem, 6vw, 4.5rem);
}

/* --------------------------------------------------------------------------
   2. The book page
   -------------------------------------------------------------------------- */

/* ---- 2.0 The trail ------------------------------------------------------

   Where this page sits in the site, as a row of links back up it. Asked for on
   23 August 2026, and it is on the two pages a stranger arrives at from a
   search result: a book and a chapter.

   IT IS THE EYEBROW TREATMENT AND NOT A NEW ONE. The category over a book's
   title and the book's name over a chapter's title were already the same thing
   to the pixel: the interface face at 0.6875rem, semibold, tracked out to
   0.16em, in small capitals. The trail takes exactly that, so it reads as the
   line that was already there rather than as a strip of navigation bolted onto
   the top of the design. The only difference is the colour, and that is what
   keeps the hierarchy: the trail is faint, and the one thing on the row that
   may take the gold is the last step of a chapter's trail, which is the book,
   because that is the line the gold belonged to before the trail existed.

   NO RULE UNDER IT AND NO BAR BEHIND IT. DESIGN-CONSISTENCY section 5.4 allows
   one hairline to a boundary and this is not a boundary: it is the first line
   of the page's own opening block, sitting inside it.

   IT WRAPS RATHER THAN SCROLLS. A book with a long title on a phone would
   otherwise put the whole trail on a sideways scroller, which is a thing to
   discover rather than a thing to read, and CLAUDE.md's own rule about the body
   never scrolling sideways is the same instinct. Wrapped, the worst case is two
   short lines of small capitals. */

.tmp-crumbs {
  margin-bottom: 0.85rem;
}

.tmp-crumb-list {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem 0.55rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.tmp-crumb-item {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  /* The list is an ordered list, so a browser that draws counters on a flex
     item has nothing to draw here. Said explicitly because the reset does it
     for `ul` and this is an `ol`. */
  list-style: none;
}

.tmp-crumb {
  font-family: var(--ui);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-faint);
  text-decoration: none;
  border-bottom: 1px solid transparent;
  transition:
    color 0.25s var(--ease-soft),
    border-color 0.25s var(--ease-soft);
}

.tmp-crumb:hover,
.tmp-crumb:focus-visible {
  color: var(--gold);
  border-bottom-color: var(--gold);
}

/* The last step of a chapter's trail: the book, in the gold it stood in before
   the trail was drawn around it. The book's own page passes no emphasis, so
   nothing there takes this. */
.tmp-crumb.is-lead {
  color: var(--gold);
}

.tmp-crumb.is-lead:hover,
.tmp-crumb.is-lead:focus-visible {
  border-bottom-color: var(--gold);
}

/* The separator. It belongs to the step it stands in front of, so it inherits
   nothing from the link beside it and is always the faintest thing on the row. */
.tmp-crumb-mark {
  flex: none;
  color: var(--ink-faint);
  opacity: 0.55;
}


/* NO CLOSING HAIRLINE. The Contents head directly below opens with one of its
   own, and the two were a rule, a screen's worth of nothing, and another rule.
   The section head's line is the one that stays, because it is the line that
   says what is starting rather than what has stopped. */
.tmp-bhero {
  padding-block: calc(var(--head) + clamp(2.5rem, 7vw, 5rem)) clamp(2.5rem, 6vw, 4.5rem);
  /* `.tmp-wrap` sets a measure and `.tmp-band` sets the gutter, and they are
     two separate classes in site.css. This section uses the first for its
     inner element, so the gutter has to come from here: without it the cover
     and the type run off both edges of a phone. */
  padding-inline: var(--gutter);
}

.tmp-bhero-inner {
  display: grid;
  gap: clamp(2rem, 5vw, 3.5rem);
  align-items: center;
}

@media (min-width: 46rem) {
  .tmp-bhero-inner {
    grid-template-columns: minmax(0, 15rem) minmax(0, 1fr);
    gap: clamp(2.5rem, 5vw, 4.5rem);
  }
}

/* The cover, at the size it deserves on the one page that is about this book
   and nothing else. It keeps the shadow the library grid gives it, which is
   --cover-edge in site.css section 1 and is the one thing in that whole scheme
   that had to be rebuilt rather than repointed when the site went pale. */
.tmp-bhero-cover {
  max-width: 15rem;
  border-radius: 2px;
  overflow: hidden;
  box-shadow: var(--cover-edge);
}

.tmp-bhero-cover img {
  display: block;
  width: 100%;
  height: auto;
}

.tmp-bhero-cat {
  font-family: var(--ui);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--gold);
}

/* THE BOOK'S TITLE IS SET IN THE READING SERIF, not in the interface face and
   not word by word like the site's own headlines. Two reasons, and the second
   is the load-bearing one. It is the book's words rather than the site's, which
   is the line site.css draws between its two faces. And the site's headline
   treatment splits a heading into one box per word for the staggered rise,
   which pages/parts.js says in terms is only ever safe on constants written in
   this project: a book title arrives from a record and may hold anything. */
.tmp-bh1 {
  margin-top: 0.75rem;
  font-family: var(--read);
  font-size: clamp(2rem, 5.5vw, 3.25rem);
  font-weight: 600;
  line-height: 1.08;
  letter-spacing: -0.02em;
  color: var(--ink);
  text-wrap: balance;
}

.tmp-bhero-sub {
  margin-top: 0.6rem;
  font-family: var(--read);
  font-style: italic;
  font-size: clamp(1.0625rem, 2vw, 1.25rem);
  color: var(--ink-dim);
}

.tmp-bhero-by {
  margin-top: 1.25rem;
  font-family: var(--ui);
  font-size: 0.875rem;
  color: var(--ink);
}

.tmp-bhero-blurb {
  margin-top: 1.25rem;
  max-width: var(--column);
  font-size: 1rem;
  line-height: 1.7;
  color: var(--ink-dim);
}

.tmp-bhero .tmp-actions {
  margin-top: 2rem;
}

/* ---- The contents list ---------------------------------------------------

   Rows with a hairline between them, not cards. The same decision the library
   grid takes and for the same reason: a border drawn around a row is furniture
   competing with the words inside it.

   THE WHOLE ROW IS THE LINK, so the target is the full width of the measure
   rather than the length of a title. On a phone that is the difference between
   a comfortable tap and an accurate one. */

/* The section head is doing the separating here, and the hero above it has
   already ruled itself off, so this section takes about two thirds of the
   site's usual band. A full band between a book's cover and its contents is a
   screen of nothing on the one page a reader came to a list for. */
.tmp-book-contents {
  padding-block: clamp(3rem, 7vw, 5rem) var(--band);
}

/* The contents opens on no rule of its own, for the reason the numbered list
   in site.css does not: the Contents head above it has already drawn one, and
   the chapters are told apart by the rule between them. */
.tmp-toc {
  margin-top: 2.5rem;
  list-style: none;
}

.tmp-toc-item {
  border-bottom: 1px solid var(--line-soft);
}

.tmp-toc-link {
  display: grid;
  grid-template-columns: 2.75rem minmax(0, 1fr) 1.25rem;
  align-items: baseline;
  gap: 0.5rem 1rem;
  padding-block: clamp(1rem, 2.5vw, 1.5rem);
  text-decoration: none;
  color: inherit;
  transition: background-color 0.25s var(--ease-soft);
}

.tmp-toc-link:hover {
  background: var(--ground-raised);
}

/* The number is drawn, not counted by the list, because it is the chapter's
   position among the ones that can be READ rather than its position in the
   book. Aria-hidden for the same reason the section numbers on the front page
   are: it is a position on a page, not part of the sentence. */
.tmp-toc-n {
  font-family: var(--ui);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  color: var(--gold);
  padding-inline-start: clamp(0rem, 2vw, 1rem);
}

.tmp-toc-title {
  font-family: var(--read);
  font-size: clamp(1.0625rem, 2vw, 1.25rem);
  font-weight: 500;
  line-height: 1.35;
  color: var(--ink);
  transition: color 0.25s var(--ease-soft);
}

/* The opening sentence of the chapter, held to a readable measure. The row
   itself runs the full width of the page, which is what makes the whole row a
   comfortable target, but a line of prose 1100 pixels long is a line nobody
   finishes: the eye loses the start of the next one. The title above it may
   run as wide as it likes, because a title is scanned rather than read. */
.tmp-toc-sum {
  grid-column: 2;
  max-width: 46rem;
  font-size: 0.875rem;
  line-height: 1.6;
  color: var(--ink-faint);
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
}

.tmp-toc-go {
  color: var(--ink-faint);
  justify-self: end;
  padding-inline-end: clamp(0rem, 2vw, 1rem);
  transition: transform 0.25s var(--ease-soft), color 0.25s var(--ease-soft);
}

.tmp-toc-link:hover .tmp-toc-go {
  color: var(--gold);
  transform: translateX(3px);
}

/* ---- What is inside a chapter, folded away under it ----------------------

   Added 20 August 2026, when Aamir asked for the contents pages to carry the
   levels the live site's book pages have. There every chapter's own headings
   are listed under it in grey, always visible, and on the book with fourteen
   chapters that is two hundred and forty-five lines of grey between the reader
   and the fourteenth. So they are here, and they fold.

   A REAL `details`, styled the same way the disclosure in site.css is: the
   browser's own triangle taken off both ways it can be drawn, the site's own
   chevron in its place, and the chevron turned over when the panel opens.

   THE BAR IS QUIET ON PURPOSE. It sits under a chapter's title and it is not
   competing with it: small capitals in the interface face, the site's faint
   tone, and the count in the accent. The thing a reader came for is the
   chapter, and this is the way to look inside it without going in. */

/* Everything in the fold hangs off the title's column, so a section lines up
   under the chapter it belongs to rather than under its number. It is the
   number's column plus the gap between the two, which is what the row's own
   grid puts the title at. */
.tmp-toc-fold {
  --toc-indent: 3.75rem;
  padding-bottom: 0.5rem;
}

.tmp-toc-fold-bar {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  padding-block: 0.5rem;
  padding-inline-start: var(--toc-indent);
  cursor: pointer;
  /* Both halves of taking the browser's own marker off: Firefox and the
     standard property draw it from the list style, Safari and Chrome from
     their own pseudo-element. */
  list-style: none;
}

.tmp-toc-fold-bar::-webkit-details-marker {
  display: none;
}

.tmp-toc-fold-bar:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 4px;
}

.tmp-toc-fold-name {
  font-family: var(--ui);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-faint);
  transition: color 0.25s var(--ease-soft);
}

.tmp-toc-fold-n {
  font-family: var(--ui);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  color: var(--gold);
}

.tmp-toc-fold-bar .tmp-open-mark {
  color: var(--ink-faint);
  transition: transform 0.35s var(--ease-soft), color 0.25s var(--ease-soft);
}

.tmp-toc-fold[open] .tmp-open-mark {
  transform: rotate(180deg);
}

.tmp-toc-fold-bar:hover .tmp-toc-fold-name,
.tmp-toc-fold-bar:hover .tmp-open-mark {
  color: var(--ink);
}

/* The list itself. A hairline down the left of it, in the way an outline is
   ruled off in a printed contents, so a long fold reads as one thing that
   belongs to the chapter above rather than as loose rows between two chapters.

   It cannot animate its height without a script and does not try to. What it
   does is arrive rather than appear, the same short rise the disclosure on the
   Contact page uses, so the two read as one design. Under reduced motion the
   blanket rule in site.css section 13 cuts the duration to nothing and it is
   simply there. */
.tmp-toc-sub {
  margin-inline-start: var(--toc-indent);
  padding-inline-start: 1rem;
  border-inline-start: 1px solid var(--line-soft);
  list-style: none;
  animation: tmp-unfold 0.4s var(--ease) both;
}

/* The nested level. No rule of its own: one hairline down the fold is the
   spine, and a second one inside it would draw a diagram of the nesting rather
   than showing it. The indent and the quieter tone are what say 'inside'. */
.tmp-toc-sub-deep {
  margin-inline-start: 0;
  padding-inline-start: 1rem;
  border-inline-start: none;
  animation: none;
}

.tmp-toc-sub-link {
  display: block;
  padding-block: 0.3125rem;
  /* Held to the same measure the chapter's opening sentence is held to. Most
     headings are three or four words, but a book that sets an attribution as a
     heading has one that is a full line, and a line of prose eleven hundred
     pixels wide is a line the eye loses the end of. */
  max-width: 46rem;
  /* THE BOOK'S OWN WORDS, so the reading serif, which is the line the site
     draws between its two faces. A heading inside a chapter is the author's
     sentence and not a label this site put on it. */
  font-family: var(--read);
  font-size: 0.9375rem;
  line-height: 1.5;
  color: var(--ink-dim);
  text-decoration: none;
  transition: color 0.2s var(--ease-soft);
}

.tmp-toc-sub-deep .tmp-toc-sub-link {
  font-size: 0.875rem;
  color: var(--ink-faint);
}

.tmp-toc-sub-link:hover,
.tmp-toc-sub-link:focus-visible {
  color: var(--gold);
}

/* A front matter row carries no number, so its gutter is empty. Nothing has to
   be done to draw that, and the class is here so the row can be recognised
   from the stylesheet without reading the markup: a foreword, a preface or an
   endorsement is not chapter one, and content/structure.js is where that is
   decided. */
.tmp-toc-item.is-matter .tmp-toc-title {
  font-weight: 400;
}

/* ---- A chapter that is not written yet ----------------------------------

   Listed, numbered, and plainly not available. Aamir asked on 19 August 2026
   for these to be shown rather than left out, so a book's contents is the whole
   book and a reader can see what is coming.

   It is drawn as a row that is present but inactive rather than as a row with
   something wrong with it: no strike-through, no warning colour, no icon. One
   book is 89 of these in a row, and anything louder than this would turn a plan
   into ninety complaints. */

.tmp-toc-link.is-waiting {
  cursor: default;
}

.tmp-toc-link.is-waiting:hover {
  background: none;
}

.tmp-toc-link.is-waiting .tmp-toc-n {
  color: var(--ink-faint);
}

.tmp-toc-link.is-waiting .tmp-toc-title {
  color: var(--ink-dim);
  font-weight: 400;
}

/* The state, in the arrow's column, so it reads as what is in the place where
   the way onward would be. On a narrow screen it drops under the title, because
   at that width it and the title cannot both have room. */
.tmp-toc-state {
  grid-column: 2;
  font-family: var(--ui);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-faint);
  align-self: center;
}

@media (min-width: 42rem) {
  .tmp-toc-link.is-waiting {
    grid-template-columns: 2.75rem minmax(0, 1fr) auto;
  }

  .tmp-toc-state {
    grid-column: 3;
    justify-self: end;
    padding-inline-end: clamp(0rem, 2vw, 1rem);
  }
}

.tmp-toc-more {
  margin-top: 2rem;
  font-size: 0.9375rem;
  color: var(--ink-faint);
  max-width: var(--column);
}

/* --------------------------------------------------------------------------
   3. The chapter
   -------------------------------------------------------------------------- */

/* ---- The header band, and the desk the sheet lies on ---------------------

   THE CHAPTER PAGE TAKES THE LIGHT BLUE rather than the site's white, and it is
   the one page on the site that does. It is what the sheet rests on: white
   paper on a white page is one flat surface with a shadow drawn on it for no
   reason, and the whole handover from the site to the book depends on being
   able to see where one stops. Everything else on the page, the header band and
   the two navigation rows, is the site speaking and belongs on the site's own
   ground, which is exactly what this is.

   THE BAND ITSELF IS THE MOMENT OF HANDOVER: above it the site is speaking,
   below it the book is. The live site drew this as a forest green panel with
   rounded corners and a gold gradient hairline; here it is the ground itself,
   ruled off, because a panel floating on a page that is already this colour is
   a box for the sake of a box. */

.tmp-chapter {
  background: var(--ground-raised);
}

.tmp-ch-head {
  padding-block: clamp(2.25rem, 6vw, 4rem) clamp(1.75rem, 4vw, 2.75rem);
}

/* ALIGNED WITH THE SHEET BELOW IT, edge to edge, rather than with the site's
   own measure. The sheet is the reading column plus its inset either side, so
   the same expression here puts the chapter title's left edge exactly above
   the paper's left edge, and the handover reads as one object rather than as
   two blocks that nearly line up. */
.tmp-ch-inner {
  max-width: calc(var(--read-column) + var(--read-pad) * 2);
  margin-inline: auto;
}

.tmp-ch-book {
  display: inline-block;
  font-family: var(--ui);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--gold);
  text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: border-color 0.25s var(--ease-soft);
}

.tmp-ch-book:hover {
  border-bottom-color: var(--gold);
}

/* THE CHAPTER TITLE IS THE ONE THING ON THIS SITE SET IN PLAYFAIR. It is the
   book's own words at their largest, it is what DESIGN-CONSISTENCY section 4
   specifies, and site.css records Playfair as being kept for exactly this. */
.tmp-ch-title {
  margin-top: 0.9rem;
  font-family: 'Playfair', Georgia, serif;
  font-size: clamp(1.875rem, 5vw, 3rem);
  font-weight: 500;
  line-height: 1.12;
  letter-spacing: -0.012em;
  color: var(--ink);
  text-wrap: balance;
}

.tmp-ch-where {
  margin-top: 1rem;
  font-family: var(--ui);
  font-size: 0.75rem;
  letter-spacing: 0.06em;
  color: var(--ink-faint);
}

/* ---- The navigation, above and below ------------------------------------

   Both ends, which is Aamir's instruction of 19 August 2026 and is also what
   the live site does. A reader who has finished a chapter should not have to
   scroll back to the top to find the next one, and a reader who has arrived
   from a link should not have to reach the bottom to find the contents.

   AN UNAVAILABLE DIRECTION IS SHOWN, NOT HIDDEN, so the row keeps its shape on
   the first and last chapters of a book. It is rendered as a span rather than a
   link, so there is nothing to focus and nothing to press, which is what makes
   it disabled rather than merely grey. */

.tmp-ch-nav {
  max-width: calc(var(--read-column) + var(--read-pad) * 2);
  margin-inline: auto;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.75rem;
  padding-block: clamp(1.25rem, 3vw, 2rem);
}

.tmp-ch-nav-top {
  border-bottom: 1px solid var(--line-soft);
}

/* THE PAGE ENDS HERE, so the bottom row buys its own white space.
   A chapter carries no site footer, and the footer's own padding is what used
   to keep the last row clear of the bottom edge of the screen. Without it the
   way on to the next chapter would sit flush against the edge, which reads as a
   page that has been cut off rather than one that has finished. */
.tmp-ch-nav-foot {
  border-top: 1px solid var(--line-soft);
  padding-block-end: clamp(3rem, 8vw, 5.5rem);
}

@media (min-width: 42rem) {
  .tmp-ch-nav {
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
    gap: 1.5rem;
  }
}

.tmp-ch-step {
  display: block;
  padding: 0.75rem 1rem;
  border: 1px solid var(--line-soft);
  border-radius: 3px;
  text-decoration: none;
  color: inherit;
  transition: border-color 0.25s var(--ease-soft), background-color 0.25s var(--ease-soft);
}

.tmp-ch-step:hover {
  border-color: var(--line);
  background: var(--ground-raised);
}

.tmp-ch-next {
  text-align: right;
}

.tmp-ch-dir {
  display: block;
  font-family: var(--ui);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--gold);
}

.tmp-ch-name {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  /* Three lines rather than two, because these titles are long: 'Chapter Two:
     Signs of Arrogance' is three lines in half the width of a phone, and two
     would cut it in the middle of the phrase that says which chapter it is. */
  -webkit-line-clamp: 3;
  overflow: hidden;
  margin-top: 0.35rem;
  font-family: var(--read);
  font-size: 0.9375rem;
  line-height: 1.4;
  color: var(--ink);
}

/* THE TOP ROW IS THE DIRECTIONS ALONE ON A PHONE, and this is the one place
   the two navigation rows differ.

   Aamir asked for the navigation at the top and at the bottom, and it is at
   both. But a phone is 844 points tall, and a header bar, an eyebrow, a
   three-line title, a position and two boxes carrying full chapter titles come
   to more than that: the reader would arrive at a chapter and have to scroll
   before meeting a single word of it. Stripping the titles from the TOP row
   only costs nothing, because the reader is about to read this chapter rather
   than choose between them, and the row at the foot, which is where a reader
   IS choosing, keeps them in full.

   From 42rem there is room for everything and both rows are the same. */
@media (max-width: 41.999rem) {
  .tmp-ch-nav-top {
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
    gap: 0.5rem;
  }

  .tmp-ch-nav-top .tmp-ch-name {
    display: none;
  }

  .tmp-ch-nav-top .tmp-ch-step {
    padding: 0.6rem 0.75rem;
    text-align: center;
  }

  /* THE ROW IS NAMED AS WELL AS THE COLUMN, and it has to be. Auto-placement
     fills left to right and the cursor never goes backwards, so an item that
     asks for column 2 AFTER one that took column 3 is placed on a second row.
     Naming the row is what keeps all three on one line. */
  .tmp-ch-nav-top .tmp-ch-toc {
    grid-row: 1;
    grid-column: 2;
    padding-inline: 0.9rem;
  }

  .tmp-ch-nav-top .tmp-ch-prev {
    grid-row: 1;
    grid-column: 1;
  }

  .tmp-ch-nav-top .tmp-ch-next {
    grid-row: 1;
    grid-column: 3;
  }
}

/* Disabled. Half the light and no interaction, and it still occupies its
   column, which is the whole reason it is drawn at all. */
.tmp-ch-step.is-off {
  opacity: 0.32;
  border-style: dashed;
}

.tmp-ch-step.is-off .tmp-ch-name {
  color: var(--ink-dim);
}

/* The contents link in the middle. On a phone it takes the full width under
   the two steps, because a third column at that width leaves three things that
   are all too narrow to read. */
.tmp-ch-toc {
  grid-column: 1 / -1;
  justify-self: center;
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.6rem 1.1rem;
  font-family: var(--ui);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-dim);
  text-decoration: none;
  border: 1px solid var(--line-soft);
  border-radius: 999px;
  transition: color 0.25s var(--ease-soft), border-color 0.25s var(--ease-soft);
}

.tmp-ch-toc:hover {
  color: var(--ink);
  border-color: var(--line);
}

@media (min-width: 42rem) {
  /* The row is named for the reason given above: without it the middle item
     lands under the other two rather than between them. */
  .tmp-ch-toc {
    grid-row: 1;
    grid-column: 2;
  }
  .tmp-ch-prev {
    grid-row: 1;
    grid-column: 1;
  }
  .tmp-ch-next {
    grid-row: 1;
    grid-column: 3;
  }
}

/* ---- The sheet -----------------------------------------------------------

   The paper the words are read on. It runs the full width of the band on a
   phone, where a margin either side would be wasted width, and becomes a sheet
   with its own edge from the width at which there is room for one.

   The shadow is what makes it a sheet rather than a panel, and it is drawn in
   the site's ink rather than in black so it belongs to the colour of the page
   it is lying on. */

.tmp-sheet {
  background: var(--paper);
  color: var(--read-ink);
  padding-block: clamp(2.5rem, 7vw, 4.5rem);
  padding-inline: var(--read-pad);
}

@media (min-width: 52rem) {
  .tmp-sheet {
    max-width: calc(var(--read-column) + var(--read-pad) * 2);
    margin-inline: auto;
    border-radius: 3px;
    box-shadow: 0 2px 6px rgba(18, 37, 63, 0.06), 0 26px 60px rgba(18, 37, 63, 0.14);
  }
}

.tmp-read {
  max-width: var(--read-column);
  margin-inline: auto;
  font-family: var(--read);
  font-size: calc(var(--read-size) * var(--read-scale) * var(--read-face));
  line-height: var(--read-lead);
  color: var(--read-ink);
  /* The transliteration diacritics and the Arabic both benefit, and the body
     face has real oldstyle figures that would otherwise never be used. */
  font-variant-numeric: oldstyle-num;
  text-rendering: optimizeLegibility;
}

/* Anything the reader lands on from a heading link clears the sticky header
   instead of hiding underneath it. */
.tmp-read [id],
.tmp-notes[id],
.tmp-ch-head {
  scroll-margin-top: calc(var(--head) + 1rem);
}

/* ---- The blocks ----------------------------------------------------------

   One rule per style in the corpus, at DESIGN-CONSISTENCY section 2.1's own
   proportions. The sizes are `em` of the body size above, so the whole scale
   moves as one. */

.tmp-read > * + * {
  margin-top: 1.15em;
}

.tmp-read > :first-child {
  margin-top: 0;
}

.tmp-p {
  text-wrap: pretty;
}

/* Arabic. Always in Arabic script, never transliterated (CLAUDE.md section
   2.4), centred, inset from both edges, and given the leading that fully
   vocalised naskh needs: the marks sit above and below the letters, so a line
   of Quranic text is physically taller than a line of Latin at the same size. */
.tmp-ar {
  font-family: 'Scheherazade New', serif;
  font-size: 1.35em;
  line-height: var(--read-lead-ar);
  text-align: center;
  margin-block: 1.75em;
  margin-inline: 6%;
  color: var(--read-ink);
}

/* Urdu, in nastaliq, which slopes down to the left and needs close to three
   times its size in leading before the lines stop colliding. */
.tmp-ur {
  font-family: 'Noto Nastaliq Urdu', 'Scheherazade New', serif;
  font-size: 1.07em;
  line-height: var(--read-lead-ur);
  text-align: center;
  margin-block: 1.75em;
  margin-inline: 6%;
  color: var(--read-ink);
}

/* The translation of a quoted passage. Italic by definition, which is why the
   importer drops the whole-paragraph emphasis 741 chapters' worth of it carried:
   the italic is the style, not something the text has to ask for. */
.tmp-qt {
  font-size: 0.93em;
  line-height: 1.75;
  font-style: italic;
  text-align: center;
  color: var(--read-quote);
  margin-inline: 8%;
}

/* The attribution under a verse or a hadith. Never under dialogue and never
   under a long extract (CLAUDE.md section 2.5). */
.tmp-cap {
  font-size: 0.8em;
  line-height: 1.6;
  font-weight: 600;
  text-align: center;
  color: var(--read-dim);
  margin-top: 0.5em;
}

/* Dialogue or a long extract. Inset from the left only, with no border and no
   quotation mark: the inset is the signal, and a vertical rule beside it is the
   kind of ornament this design is trying not to have. */
.tmp-dlg {
  margin-inline-start: 5%;
  color: var(--read-quote);
}

.tmp-sign {
  font-size: 0.86em;
  line-height: 1.6;
  font-weight: 600;
  text-align: right;
  color: var(--read-dim);
}

/* CONSECUTIVE SIBLINGS OF THE SAME STYLE TIGHTEN, and DESIGN-CONSISTENCY
   section 2.1 calls this the single thing that makes a page of poetry or a
   stacked sign-off read correctly. Two Arabic blocks in a row are one passage
   broken across lines, not two passages, and the full gap between them says the
   opposite. */
.tmp-ar + .tmp-ar,
.tmp-ur + .tmp-ur {
  margin-top: 0.5em;
}

.tmp-qt + .tmp-qt,
.tmp-cap + .tmp-cap,
.tmp-sign + .tmp-sign,
.tmp-dlg + .tmp-dlg {
  margin-top: 0.4em;
}

/* ---- Headings ------------------------------------------------------------

   The chapter's own headings, at the levels the book uses. One book nests to
   level 5 and one uses no headings at all, which is why the schema stores a
   level rather than assuming one.

   They are set in the READING serif, not the interface face: they are the
   book's words. The chapter title above is the one that takes Playfair. */

.tmp-h {
  font-family: var(--read);
  font-weight: 600;
  color: var(--read-ink);
  line-height: 1.3;
  text-wrap: balance;
}

h2.tmp-h {
  font-size: 1.6em;
  margin-top: 2.4em;
  margin-bottom: 0.7em;
}

h3.tmp-h {
  font-size: 1.35em;
  margin-top: 2em;
  margin-bottom: 0.6em;
}

h4.tmp-h {
  font-size: 1.14em;
  margin-top: 1.75em;
  margin-bottom: 0.5em;
}

h5.tmp-h {
  font-size: 1em;
  margin-top: 1.5em;
  margin-bottom: 0.4em;
}

/* Level 6 is a label rather than a heading: letter spaced and in the dim tone,
   which is what DESIGN-CONSISTENCY section 2.2 specifies.

   IT IS NOT SET IN CAPITALS, and it was until 22 August 2026. This is the
   book's own heading, not a piece of the interface, and the house style forbids
   whole words in capitals anywhere in a book's text (Kube section 2.9, adopted
   in docs/HOUSE-STYLE.md). The weight, the tracking and the dim tone are what
   make it read as a label now, and the capitals were never carrying that on
   their own. The interface's own small uppercase labels are untouched: they are
   furniture, not text somebody reads. */
h6.tmp-h {
  font-size: 0.85em;
  font-weight: 700;
  letter-spacing: 0.045em;
  color: var(--read-dim);
  margin-top: 1.5em;
  margin-bottom: 0.4em;
}

/* A heading is usually preceded by a paragraph, and the gap above it has to be
   larger than the gap below it or the heading reads as belonging to the text it
   follows rather than to the text it introduces. `* + *` above would give both
   the same, so these win. The first thing in a chapter takes nothing. */
.tmp-read > .tmp-h:first-child {
  margin-top: 0;
}

/* ---- Lists and tables ---------------------------------------------------- */

/* THE MARKERS ARE PUT BACK, and this is not a detail. site.css strips
   `list-style` from every list on the site, because every list OUTSIDE a
   chapter is a set of navigation links or a row of metadata where a bullet
   would be furniture. Inside a chapter the opposite is true: a numbered list is
   numbered because the author counted, and a passage reading 'and within
   necessity there are also degrees:' followed by four unnumbered lines has lost
   the thing it was saying. */
ol.tmp-list-read {
  list-style: decimal;
}

ul.tmp-list-read {
  list-style: disc;
}

.tmp-list-read {
  padding-inline-start: 1.6em;
}

.tmp-list-read li + li {
  margin-top: 0.5em;
}

.tmp-list-read li::marker {
  color: var(--read-dim);
}

/* A table of five columns cannot be made to fit a phone, so it scrolls inside
   its own box rather than making the whole page scroll sideways. */
.tmp-table-wrap {
  overflow-x: auto;
  margin-block: 1.75em;
  border-top: 1px solid var(--read-rule);
  border-bottom: 1px solid var(--read-rule);
}

.tmp-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.86em;
  font-variant-numeric: tabular-nums;
}

.tmp-table th,
.tmp-table td {
  padding: 0.6em 0.9em;
  text-align: left;
  vertical-align: top;
  border-bottom: 1px solid var(--read-rule-soft);
}

.tmp-table th {
  font-weight: 600;
  white-space: nowrap;
  color: var(--read-dim);
  font-size: 0.9em;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.tmp-table tbody tr:last-child td {
  border-bottom: 0;
}

/* ---- Inline --------------------------------------------------------------- */

.tmp-read em {
  font-style: italic;
}

.tmp-read strong {
  font-weight: 700;
}

.tmp-read a {
  color: var(--read-accent);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.18em;
}

.tmp-read ::selection {
  background: var(--read-accent-soft);
}

/* THE HONORIFIC. A single letter set in the Honorifics face, which draws the
   whole invocation as one glyph. It is a key into a font and not a word, which
   is why it takes no colour of its own and why it is silent to a screen reader
   (see format/web.js).

   Raised very slightly and given a hair of space either side: the glyph is
   drawn to sit beside a name rather than inside a word. */
.tmp-hon {
  font-family: 'Honorifics', serif;
  font-size: 1.1em;
  line-height: 1;
  display: inline-block;
  vertical-align: -0.02em;
  margin-inline: 0.1em;
  color: inherit;
  /* It must never be italicised or emboldened by the run it sits inside: the
     face has one weight and one style, and a browser asked for the others
     synthesises them by slanting and smearing the glyph. */
  font-style: normal;
  font-weight: 400;
}

.tmp-ar-inline {
  font-family: 'Scheherazade New', serif;
  font-size: 1.15em;
  line-height: 1;
}

/* ---- The glossary mark, on a term in the text ---------------------------- */

/* A TERM IS A LINK AND IT IS DRAWN AS ALMOST NOTHING.

   Aamir's words on 21 August 2026 were that it should be very, very slightly
   noticeable, and a faint dotted line under the word. That is the whole brief
   and it is the right one: a transliterated term appears on EVERY occurrence
   and not only the first (CLAUDE.md section 2.3), so a treatment loud enough to
   notice once is a treatment that stripes the page by the third paragraph. It
   takes NO COLOUR OF ITS OWN, because the site's gold on every occurrence of
   `nafs` in a chapter that says it eighty-seven times would be a different
   page.

   THE LINE IS `text-decoration` AND NOT A BORDER, so it clears the descenders
   of a `j` or a `y` instead of striking through them, and so a term that wraps
   across two lines is underlined on both without the box drawing a side.

   THE MARK IS WHAT THE READER PRESSES, and it is a real link to the term's row
   on the book's glossary page. reader.js turns the press into a bubble instead;
   with no script it simply goes there. */
.tmp-read .tmp-term-link {
  color: inherit;
  text-decoration: underline;
  text-decoration-style: dotted;
  text-decoration-color: var(--read-term-line);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.22em;
  cursor: help;
  transition:
    text-decoration-color 0.2s var(--ease-soft),
    color 0.2s var(--ease-soft);
}

/* A CAPITALISED TERM IS SET UPRIGHT and keeps everything else: the dotted line,
   the link, the bubble. The house style does not italicise a transliterated
   term that carries a capital (Kube section 2.10, adopted in
   docs/HOUSE-STYLE.md), and the terms this reaches are the names of Allāh the
   glossary defines and the two Unseen things. The formatter decides which
   those are, by asking the glossary rather than by reading the sentence, and
   says so with this class. */
.tmp-read .tmp-term-upright {
  font-style: normal;
}

/* Under the pointer, and under the keyboard, it becomes an ordinary link for
   as long as it is being addressed. This is where the accent is allowed in:
   one word at a time, and only while somebody is asking about it. */
.tmp-read .tmp-term-link:hover,
.tmp-read .tmp-term-link:focus-visible,
.tmp-read .tmp-term-link.is-open {
  color: var(--read-accent);
  text-decoration-color: var(--read-accent);
}

/* The focus ring is the site's, not the browser's default box, which would be
   drawn around an italic word in the middle of a sentence. */
.tmp-read .tmp-term-link:focus-visible {
  outline: 2px solid var(--read-accent);
  outline-offset: 2px;
  border-radius: 2px;
}

/* ---- Footnotes ----------------------------------------------------------- */

.tmp-fn-ref {
  font-size: 0.7em;
  line-height: 0;
  vertical-align: super;
}

.tmp-fn-ref a {
  color: var(--read-accent);
  text-decoration: none;
  padding-inline: 0.15em;
  font-variant-numeric: lining-nums;
}

.tmp-fn-ref a:hover {
  text-decoration: underline;
}

/* The divider above the notes is this border and nothing else. The corpus
   carries a separator block for it and the importer drops it, because a
   chapter that stored its own divider could end up with a divider and no
   notes. */
.tmp-notes {
  margin-top: 3.5em;
  padding-top: 1.75em;
  border-top: 1px solid var(--read-rule);
}

.tmp-notes-head {
  font-family: var(--ui);
  font-size: 0.7em;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--read-dim);
}

.tmp-fn-list {
  margin-top: 1.25em;
  list-style: none;
}

.tmp-fn {
  display: grid;
  grid-template-columns: 1.75em minmax(0, 1fr);
  gap: 0.5em;
  font-size: 0.86em;
  line-height: 1.6;
  color: var(--read-quote);
}

.tmp-fn + .tmp-fn {
  margin-top: 0.9em;
}

/* The number IS the way back. One control rather than a number and a separate
   arrow beside it, and the target is the whole numeral rather than a glyph. */
.tmp-fn-back {
  font-variant-numeric: lining-nums;
  font-weight: 600;
  color: var(--read-accent);
  text-decoration: none;
}

.tmp-fn-back:hover {
  text-decoration: underline;
}

/* A note that has just been jumped to is marked for a moment, so a reader who
   pressed a marker can see which of eleven notes answered. It fades rather than
   staying, because a permanent highlight on one note is a page that looks
   wrong to the next reader who scrolls past it. */
.tmp-fn:target .tmp-fn-body {
  animation: tmp-fn-found 2.4s var(--ease-soft) both;
}

@keyframes tmp-fn-found {
  0%,
  45% {
    background: var(--read-accent-soft);
    box-shadow: 0 0 0 0.35em var(--read-accent-soft);
    border-radius: 2px;
  }
  100% {
    background: transparent;
    box-shadow: 0 0 0 0.35em transparent;
    border-radius: 2px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .tmp-fn:target .tmp-fn-body {
    animation: none;
    background: var(--read-accent-soft);
  }
}

/* ---- The glossary, as a chapter ------------------------------------------

   The page at the back of the book, drawn by server/src/format/glossary.js. It
   lies on the same sheet as a chapter and inside the same reading scale, which
   is the point: it is a chapter of the book and not a reference screen bolted
   on beside it.

   A DESCRIPTION LIST, laid out as a two column grid on a wide screen and
   stacked on a phone. The term sits in its own column so the eye can run down
   the list of words without reading the meanings, which is what somebody
   scanning a glossary is doing. On a phone there is no room for two columns and
   the term simply sits above its meaning. */

.tmp-gl-lead {
  font-size: 0.9em;
  line-height: 1.65;
  color: var(--read-dim);
  font-style: italic;
  margin-bottom: 2em;
}

/* The letter row. Every letter the glossary actually has, and nothing else: a
   full alphabet with two thirds of it dead is a row of disabled controls. */
.tmp-gl-jump {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25em;
  padding-bottom: 1.75em;
  border-bottom: 1px solid var(--read-rule);
}

.tmp-gl-jump a {
  font-family: var(--ui);
  font-size: 0.72em;
  font-weight: 600;
  line-height: 1;
  min-width: 2.1em;
  padding: 0.55em 0.4em;
  text-align: center;
  text-decoration: none;
  color: var(--read-dim);
  border: 1px solid var(--read-rule);
  border-radius: 4px;
  transition:
    color 0.2s var(--ease-soft),
    border-color 0.2s var(--ease-soft);
}

.tmp-gl-jump a:hover,
.tmp-gl-jump a:focus-visible {
  color: var(--read-accent);
  border-color: var(--read-accent);
}

.tmp-gl-letter {
  margin-top: 2.5em;
}

/* The initial is set larger and quieter than a heading of the same level would
   be, because it is a divider rather than a title: nobody reads 'D', they use
   it to find where D starts. */
.tmp-gl-initial.tmp-h {
  font-size: 1.5em;
  color: var(--read-accent);
  letter-spacing: 0.04em;
  padding-bottom: 0.35em;
  border-bottom: 1px solid var(--read-rule-soft);
}

.tmp-gl-list {
  margin-top: 1.5em;
}

.tmp-gl-entry + .tmp-gl-entry {
  margin-top: 1.6em;
}

.tmp-gl-term {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.5em 0.6em;
}

/* The term is set the way it is set in the text: emphasised, in the reading
   face. A reader who followed a mark down to here should recognise the word
   they pressed rather than meet a differently dressed version of it. */
.tmp-gl-word {
  font-style: italic;
  font-weight: 600;
  font-size: 1.05em;
}

.tmp-gl-en {
  font-family: var(--ui);
  font-size: 0.72em;
  font-weight: 500;
  letter-spacing: 0.02em;
  color: var(--read-dim);
}

.tmp-gl-script {
  font-family: 'Scheherazade New', serif;
  font-size: 1.05em;
  line-height: 1;
  color: var(--read-dim);
}

.tmp-gl-mean {
  margin-top: 0.4em;
  font-size: 0.94em;
  line-height: var(--read-lead);
  color: var(--read-quote);
}

.tmp-gl-eg {
  margin-top: 0.4em;
  font-style: italic;
  color: var(--read-dim);
}

/* Two columns once there is room for them. The term column is fixed rather
   than sized to content, so every meaning on the page starts at the same
   place and the list reads as a column instead of a ragged edge. */
@media (min-width: 46rem) {
  .tmp-gl-entry {
    display: grid;
    grid-template-columns: 13rem minmax(0, 1fr);
    gap: 0 2em;
  }

  .tmp-gl-term {
    flex-direction: column;
    align-items: flex-start;
    gap: 0.15em;
  }

  .tmp-gl-mean {
    margin-top: 0;
  }
}

/* An entry that has just been jumped to is marked for a moment, exactly as a
   footnote is, and for the same reason: somebody has arrived here from a word
   in the middle of a chapter and needs to see which of a hundred rows answered
   them. */
.tmp-gl-entry:target {
  animation: tmp-fn-found 2.4s var(--ease-soft) both;
  border-radius: 3px;
}

@media (prefers-reduced-motion: reduce) {
  .tmp-gl-entry:target {
    animation: none;
    background: var(--read-accent-soft);
  }
}

/* --------------------------------------------------------------------------
   4. The gate
   --------------------------------------------------------------------------

   One password in front of every book, and since 20 August 2026 rather more
   than that. The door names the book and the chapter the reader was opening,
   says why it is shut, offers to write to them when it opens and offers a way
   to ask for early access. The password comes last, under a rule, because
   almost nobody who reaches this page has one.

   IT IS STILL A NARROW COLUMN AND NOT A CARD. The site draws no cards anywhere
   else, and a box floated in the middle of the ground would be the one piece of
   furniture on the site borrowed from the kit this design replaced. The order
   down the column is the hierarchy; the hairlines are the only division. */

.tmp-gate {
  max-width: 30rem;
  margin-inline: auto;
  padding-block: calc(var(--head) + clamp(3rem, 10vw, 6rem)) var(--band);
  padding-inline: var(--gutter);
  text-align: center;
}

.tmp-gate-mark {
  width: 3rem;
  margin-inline: auto;
  color: var(--gold);
}

.tmp-gate-mark svg {
  width: 100%;
  height: auto;
}

.tmp-gate h1 {
  margin-top: 1.75rem;
  /* Inter, not the reading serif. This heading is the SITE speaking, not a
     book: the serif on this site means you are reading a book, and a door is
     the one thing on the page that is certainly not one. */
  font-family: var(--ui);
  font-size: clamp(1.75rem, 5vw, 2.5rem);
  letter-spacing: -0.024em;
  font-weight: 600;
  line-height: 1.15;
  letter-spacing: -0.018em;
  color: var(--ink);
}

.tmp-gate-lede {
  margin-top: 1rem;
  font-size: 1rem;
  line-height: 1.65;
  color: var(--ink-dim);
}

.tmp-gate-form {
  margin-top: 1.5rem;
  display: grid;
  gap: 0.75rem;
}

/* The invitation above the field reads as small print, so it is centred with
   the rest of it, and the label below it starts the form proper. */
.tmp-gate-form .tmp-gate-fine {
  margin-top: 0;
  margin-bottom: 0.5rem;
}

.tmp-gate-form label {
  text-align: left;
  font-family: var(--ui);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-dim);
}

.tmp-gate-form input {
  width: 100%;
  padding: 0.85rem 1rem;
  font-family: var(--ui);
  font-size: 1rem;
  color: var(--ink);
  background: var(--sheet);
  border: 1px solid var(--line);
  border-radius: 3px;
  transition: border-color 0.25s var(--ease-soft);
}

.tmp-gate-form input:focus-visible {
  outline: none;
  border-color: var(--gold);
}

.tmp-gate-form .tmp-act {
  justify-content: center;
  margin-top: 0.5rem;
}

/* The refusal. Marked in the same rose the contact form uses, and the SENTENCE
   is what says what is wrong: about one man in twelve cannot tell the rose from
   the amber, so the colour is never the message on its own. */
.tmp-gate-form.is-wrong input {
  border-color: var(--warn);
}

.tmp-gate-wrong {
  font-size: 0.9375rem;
  color: var(--warn);
  text-align: left;
}

/* The book, above the chapter. Same eyebrow as every section on the site, so a
   reader who has seen the front page already knows what a line like this is. */
.tmp-gate-eyebrow {
  margin-top: 1.75rem;
  font-family: var(--ui);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--gold);
}

/* With an eyebrow above it the heading no longer needs the space of its own. */
.tmp-gate-eyebrow + h1 {
  margin-top: 0.75rem;
}

/* --- The waiting list ---------------------------------------------------- */

.tmp-gate-ask {
  margin-top: 2.25rem;
  padding-top: 2rem;
  border-top: 1px solid var(--line);
  text-align: left;
}

.tmp-gate-label {
  display: block;
  font-family: var(--ui);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-dim);
  text-align: center;
}

/* The field and the button on one line above 30rem and stacked below it. The
   button is `flex: none` so it keeps the width of its own words: a Notify me
   that grows and shrinks with the viewport reads as a different button on every
   screen. */
.tmp-gate-row {
  display: flex;
  gap: 0.5rem;
  margin-top: 0.75rem;
}

.tmp-gate-row input {
  flex: 1;
  min-width: 0;
  width: 100%;
  padding: 0.85rem 1rem;
  font-family: var(--ui);
  font-size: 1rem;
  color: var(--ink);
  background: var(--sheet);
  border: 1px solid var(--line);
  border-radius: 3px;
  transition: border-color 0.25s var(--ease-soft);
}

.tmp-gate-row input::placeholder {
  color: var(--ink-faint);
}

.tmp-gate-row input:focus-visible {
  outline: none;
  border-color: var(--gold);
}

.tmp-gate-row .tmp-act {
  flex: none;
  justify-content: center;
}

.tmp-gate-row.is-wrong input {
  border-color: var(--warn);
}

@media (max-width: 30rem) {
  .tmp-gate-row {
    display: grid;
  }
}

/* What the address is for, and the invitation above the password. One class for
   both, because they are the same voice: the site's small print. */
.tmp-gate-fine {
  margin-top: 0.75rem;
  font-size: 0.8125rem;
  line-height: 1.55;
  color: var(--ink-faint);
  text-align: center;
}

/* The answer to a posted address. The SENTENCE is what says what happened: about
   one man in twelve cannot tell the rose from the amber, so the colour never
   carries the message on its own. It is focusable so that a reader with no
   script is brought to it rather than left at the top of a page that looks
   unchanged. */
.tmp-gate-said {
  margin-top: 1.25rem;
  font-size: 0.9375rem;
  line-height: 1.6;
  color: var(--ink-dim);
}

.tmp-gate-said:focus-visible {
  outline: none;
}

.tmp-gate-said.is-ok {
  color: var(--ink);
}

.tmp-gate-said.is-wrong {
  color: var(--warn);
}

/* --- Asking for the way in ----------------------------------------------- */

.tmp-gate-request {
  margin-top: 1.75rem;
}

/* --- The rule the password sits under ------------------------------------ */

.tmp-gate-or {
  display: flex;
  align-items: center;
  gap: 0.875rem;
  margin-top: 2.5rem;
}

.tmp-gate-or::before,
.tmp-gate-or::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--line);
}

.tmp-gate-or span {
  font-family: var(--ui);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.tmp-gate-note {
  margin-top: 2rem;
  font-size: 0.875rem;
  color: var(--ink-faint);
}

.tmp-gate-note a {
  color: var(--ink-dim);
}

/* --------------------------------------------------------------------------
   5. The reader's tools
   --------------------------------------------------------------------------

   The type scale, the paper tint, the dyslexia face, focus mode, the bookmarks
   and the reading place. reader.js is the behaviour; every size, colour and
   position is here, and that split is what makes a change to the reading scale
   a one-file change (CLAUDE.md section 3).

   THEY ARE THE SITE SPEAKING, NOT THE BOOK, and the design says so on purpose.
   Everything in section 3 is warm paper, warm ink and Source Serif, because it
   is a printed page. Every control below is the site's own white, its navy ink
   and Inter, because it is the site's furniture resting on top of that page.
   site.css states the rule the two halves of this file already keep: the serif
   means you are reading a book, and anything the site says about itself takes
   the other face. A panel of settings set in the reading serif on the reading
   paper would read as part of the chapter.

   ONE LAYOUT AT EVERY WIDTH, which is the second shape these tools have had.
   The first put the rail at the bottom right on a phone and in the middle of
   the right margin on a laptop, and opened each panel from the bottom edge or
   beside the button that called it. Aamir asked on 20 August 2026 for the live
   site's arrangement instead: the rail held against the TOP RIGHT with a tab
   that folds it away, and the panels in the MIDDLE of the screen rather than
   along its bottom edge, narrower than they were. So there is one rail
   position, one panel position, and the breakpoints below are only about how
   much room each has. The live site's tools were hidden outright above 768px;
   DESIGN-CONSISTENCY.md section 3 records that as a limitation of injecting
   into a theme rather than a decision, and somebody reading a long chapter on a
   laptop wants larger type as much as somebody on a phone does.

   NOTHING IS DRAWN UNTIL THE SCRIPT SAYS SO. Every rule that shows a control
   is written under `.js-reader`, which only the arming script in shell.js ever
   adds. So a browser that never runs the script gets a chapter with no
   controls rather than a chapter with controls that do nothing, and that is
   the same bargain site.css makes for the menu and for the reveal.
   -------------------------------------------------------------------------- */

/* ---- 5.1 The settings, applied to the sheet -----------------------------

   THE READING SCALE IS ONE MULTIPLIER, not a table of sizes. The live site
   sets forty-odd absolute pixel values per level, which is why its scale has
   holes in it: a style nobody remembered to list at level 4 simply does not
   move. Here section 3 is already `em` multiples of one body size, so the whole
   page scales from a single number and no style can be left behind.

   THIRTY-ONE STEPS, NOT FIVE, since 20 August 2026. It was five named levels,
   XS to XL, and Aamir asked for two things at once: for XL to go further than
   it did, and for a slider under the five that carries on past both ends. So
   the five names are still there and are still what most readers will use, but
   they are now POSITIONS ON A SCALE rather than the whole of it. XS is step 0,
   the default is step 10, XL is step 20, and the slider runs from -5 to 25:
   five steps below the smallest named size and five above the largest.

   THE NUMBERS BELOW ARE GENERATED, not typed. The five named levels are the
   anchors, and every step between them is a geometric interpolation of the
   scale with a linear one of the three leadings; the ten steps outside the
   named range carry the end segment's own ratio onward, so the slider's extra
   travel feels like the same scale continuing rather than a different one
   bolted on. The generator is recorded in the change log entry for 20 August
   2026; this table is its output, kept here because the stylesheet is where
   every size on this site lives (CLAUDE.md section 3) and because one attribute
   is then all the arming script in shell.js has to set before the first paint.

   THE ANCHORS. The live site's own levels are 11, 12, 14, 17 and 22 pixels
   against a default of 14, which is 0.79, 0.86, 1, 1.21 and 1.57. This site's
   default is 17px to 19px rather than 14px, because 14px is small for
   continuous reading and is the size the live site's reader tools exist to
   escape from. The four lower anchors are unchanged from the five-level scale
   this replaces, so nobody's saved size moves under them: 0.8, 0.89, 1 and 1.2.
   XL WAS 1.45 AND IS NOW 1.62, which is what Aamir asked for, and the slider
   reaches 2.187 above it: about 41px on a wide screen, which is a large-print
   edition and is meant to be.

   THE LEADING GOES THE OTHER WAY at the top of the scale, and that is not a
   slip. Leading is a proportion of the size, so type set half as large again at
   the same ratio gets half as much air again between the lines, which is too
   much: the lines stop reading as a paragraph. The live stylesheet does the
   same thing at the same place, taking Arabic from 2.4 at level 3 down to 2.0
   at level 4, and DESIGN-CONSISTENCY.md section 2.3 records that as deliberate
   rather than as an error. Latin body text is the exception and grows very
   slightly throughout, which is what the live site does as well.

   The Urdu leading is the one that cannot be cut far: nastaliq slopes down to
   the left, and below about 2.5 its lines collide with each other. So it is
   held at 2.5 across the top of the slider rather than being allowed to follow
   the slope down.

   Step 10 is the default and carries no rule at all, which is why reader.js
   removes the attribute rather than setting it to 10. Its values are the tokens
   in section 1. */

:root[data-read-step='-5'] { --read-scale: 0.719; --read-lead: 1.68; --read-lead-ar: 1.9; --read-lead-ur: 2.65; }
:root[data-read-step='-4'] { --read-scale: 0.735; --read-lead: 1.68; --read-lead-ar: 1.91; --read-lead-ur: 2.67; }
:root[data-read-step='-3'] { --read-scale: 0.75; --read-lead: 1.69; --read-lead-ar: 1.92; --read-lead-ur: 2.69; }
:root[data-read-step='-2'] { --read-scale: 0.767; --read-lead: 1.69; --read-lead-ar: 1.93; --read-lead-ur: 2.71; }
:root[data-read-step='-1'] { --read-scale: 0.783; --read-lead: 1.7; --read-lead-ar: 1.94; --read-lead-ur: 2.73; }
:root[data-read-step='0'] { --read-scale: 0.8; --read-lead: 1.7; --read-lead-ar: 1.95; --read-lead-ur: 2.75; }
:root[data-read-step='1'] { --read-scale: 0.817; --read-lead: 1.7; --read-lead-ar: 1.96; --read-lead-ur: 2.77; }
:root[data-read-step='2'] { --read-scale: 0.835; --read-lead: 1.71; --read-lead-ar: 1.97; --read-lead-ur: 2.79; }
:root[data-read-step='3'] { --read-scale: 0.853; --read-lead: 1.71; --read-lead-ar: 1.98; --read-lead-ur: 2.81; }
:root[data-read-step='4'] { --read-scale: 0.871; --read-lead: 1.72; --read-lead-ar: 1.99; --read-lead-ur: 2.83; }
:root[data-read-step='5'] { --read-scale: 0.89; --read-lead: 1.72; --read-lead-ar: 2; --read-lead-ur: 2.85; }
:root[data-read-step='6'] { --read-scale: 0.911; --read-lead: 1.73; --read-lead-ar: 2.02; --read-lead-ur: 2.88; }
:root[data-read-step='7'] { --read-scale: 0.932; --read-lead: 1.73; --read-lead-ar: 2.04; --read-lead-ur: 2.91; }
:root[data-read-step='8'] { --read-scale: 0.954; --read-lead: 1.74; --read-lead-ar: 2.06; --read-lead-ur: 2.94; }
:root[data-read-step='9'] { --read-scale: 0.977; --read-lead: 1.74; --read-lead-ar: 2.08; --read-lead-ur: 2.97; }
:root[data-read-step='11'] { --read-scale: 1.037; --read-lead: 1.76; --read-lead-ar: 2.07; --read-lead-ur: 2.94; }
:root[data-read-step='12'] { --read-scale: 1.076; --read-lead: 1.77; --read-lead-ar: 2.04; --read-lead-ur: 2.88; }
:root[data-read-step='13'] { --read-scale: 1.116; --read-lead: 1.78; --read-lead-ar: 2.01; --read-lead-ur: 2.82; }
:root[data-read-step='14'] { --read-scale: 1.157; --read-lead: 1.79; --read-lead-ar: 1.98; --read-lead-ur: 2.76; }
:root[data-read-step='15'] { --read-scale: 1.2; --read-lead: 1.8; --read-lead-ar: 1.95; --read-lead-ur: 2.7; }
:root[data-read-step='16'] { --read-scale: 1.274; --read-lead: 1.81; --read-lead-ar: 1.93; --read-lead-ur: 2.67; }
:root[data-read-step='17'] { --read-scale: 1.353; --read-lead: 1.82; --read-lead-ar: 1.91; --read-lead-ur: 2.64; }
:root[data-read-step='18'] { --read-scale: 1.437; --read-lead: 1.83; --read-lead-ar: 1.89; --read-lead-ur: 2.61; }
:root[data-read-step='19'] { --read-scale: 1.526; --read-lead: 1.84; --read-lead-ar: 1.87; --read-lead-ur: 2.58; }
:root[data-read-step='20'] { --read-scale: 1.62; --read-lead: 1.85; --read-lead-ar: 1.85; --read-lead-ur: 2.55; }
:root[data-read-step='21'] { --read-scale: 1.72; --read-lead: 1.86; --read-lead-ar: 1.83; --read-lead-ur: 2.52; }
:root[data-read-step='22'] { --read-scale: 1.827; --read-lead: 1.87; --read-lead-ar: 1.81; --read-lead-ur: 2.5; }
:root[data-read-step='23'] { --read-scale: 1.94; --read-lead: 1.88; --read-lead-ar: 1.79; --read-lead-ur: 2.5; }
:root[data-read-step='24'] { --read-scale: 2.06; --read-lead: 1.89; --read-lead-ar: 1.77; --read-lead-ur: 2.5; }
:root[data-read-step='25'] { --read-scale: 2.187; --read-lead: 1.9; --read-lead-ar: 1.75; --read-lead-ur: 2.5; }

/* THE TINT IS THE PAPER, and it is scoped to the sheet rather than set on the
   root. `--paper` is used by exactly one rule outside this section, the sheet's
   own background, so redefining it on that element is the whole of the change
   and it cannot leak on to a page that has no sheet on it.

   THE DEFAULT IS THE SITE'S OWN PAGE COLOUR SINCE 21 AUGUST 2026, and the warm
   white it used to be is still here, one place to the right, under its own
   name. Aamir asked for the change when the light blue scheme landed: the
   library, the book pages and the home page are all read on the page's own
   colour, and a chapter opening on a warmer sheet than the page that led to it
   makes the two look like different sites rather than one. It is a blue with a
   great deal of light in it rather than pure white, so the argument against
   glare that chose the ivory in the first place still holds.

   THE VALUE IS WRITTEN OUT HERE RATHER THAN NAMED AFTER THE SITE'S, and that
   is worth knowing when it next moves. site.css and read.css are two files and
   neither can read the other's tokens, so when the page was concentrated on 21
   August 2026 this and --paper above both had to be moved by hand to the same
   new value. The test in reader.test.js that compares the two is what makes
   sure they were.

   Five tints, retuned rather than copied across. The live site's are laid
   over a white page; the ivory is already warm, so the warm tint has to go
   further to read as a change from it at all, and the cool one has to stay
   close or the sheet stops looking like paper and starts looking like the site.
   Each is held above 13:1 against the ink, so no tint costs a reader any
   contrast worth the name.

   THE VALUE IS NAMED ON THE ROOT AND HANDED DOWN, which is a change made on 20
   August 2026 for the focus beam below. The beam washes the page in the colour
   of the paper it is lying on, and it is drawn by an element the old tint rules
   could not reach. One named value read in two places cannot drift; two hex
   codes for one colour would. */

:root { --read-wash: #e6f0fb; }
:root[data-read-tint='ivory'] { --read-wash: #fdfbf7; }
:root[data-read-tint='warm'] { --read-wash: #f7ecd3; }
:root[data-read-tint='cool'] { --read-wash: #eef1f4; }
:root[data-read-tint='sage'] { --read-wash: #ecf1ea; }

.tmp-sheet {
  --paper: var(--read-wash);
}

/* ---- The reading faces ---------------------------------------------------

   FIVE, SINCE 20 AUGUST 2026, where there were two, because Aamir asked for
   more. The set is chosen so that each is a different KIND of face rather than
   a different version of the same one: a transitional serif, a screen serif, an
   old style serif, a sans, and the dyslexia face.

   EACH IS NUDGED BY ITS OWN X-HEIGHT. Apparent size is x-height, not em size,
   and these are far apart on it: measured off the fonts themselves, Source
   Serif 4 is 0.475 of the em, Literata 0.507, EB Garamond 0.400 and Inter
   0.546. Set at one font size, EB Garamond reads a fifth smaller than Inter,
   and a step on the reading scale would then mean something different for every
   face. So each carries a factor, applied on top of the reader's chosen step,
   at about two thirds of the full correction: correcting the whole way makes
   the five faces the same size and takes their character with it.

   THE STACK BEHIND EACH ONE IS THE DEFAULT SERIF, not a system font, and that
   is what covers U+02BE and U+02BF for the dyslexia face, which does not draw
   them and which the corpus uses about three thousand times. The Latin faces
   here were each checked codepoint by codepoint against the unsubsetted file
   before being added, the way Playfair was: the dot-below letters, the macron
   vowels and the two marks are present in all of them. */

:root[data-read-font='book'] .tmp-read {
  --read-face: 0.96;
  font-family: 'Literata', var(--read);
}

:root[data-read-font='garamond'] .tmp-read {
  --read-face: 1.12;
  font-family: 'EB Garamond', var(--read);
}

/* The sans. It is the site's own interface face, so it costs a reader nothing
   to choose: every chapter has already loaded it for the header and the
   navigation. */
:root[data-read-font='sans'] .tmp-read {
  --read-face: 0.92;
  font-family: var(--ui);
}

/* THE DYSLEXIA FACE. OpenDyslexic, self hosted with everything else; the live
   site pulls it off a public CDN on every chapter view.

   The three settings move together because that is the finding they come from:
   the face alone is only part of it, and loosening the letters, the words and
   the lines is the rest. The leading is added to whatever the reader's chosen
   step already gives, so the two settings compose instead of one overwriting
   the other.

   THE ARABIC AND THE URDU ARE PUT BACK. Their own rules already name their own
   faces, so the family never reaches them, but letter spacing and word spacing
   are inherited, and spacing forced between the letters of a joined script
   breaks the joins: a line of Arabic would come apart into separate letters.

   TWO CHARACTERS FALL THROUGH TO THE SERIF, U+02BE and U+02BF, the hamza and
   the ayn, which the face does not draw and which the corpus uses about three
   thousand times between them. That is what the second name in the stack is
   for, and it is why there is no unicode-range on the @font-face; the reasons
   are in tools/brand/fetch-fonts.mjs. */

:root[data-read-font='dyslexic'] .tmp-read {
  font-family: 'OpenDyslexic', var(--read);
  letter-spacing: 0.012em;
  word-spacing: 0.14em;
  line-height: calc(var(--read-lead) + 0.15);
}

:root[data-read-font='dyslexic'] .tmp-ar,
:root[data-read-font='dyslexic'] .tmp-ur,
:root[data-read-font='dyslexic'] .tmp-ar-inline {
  letter-spacing: normal;
  word-spacing: normal;
}

/* ONLY THE LATIN IS SWAPPED, and no rule here is needed to make that true.
   `.tmp-ar`, `.tmp-ur` and `.tmp-ar-inline` each name their own face in section
   3, so a family set on `.tmp-read` never reaches a verse: a sans or an old
   style serif has nothing to say about either script, and those two faces are
   the only ones here that draw vocalised Arabic properly at all (CLAUDE.md
   section 2.4). The dyslexia rule above has to put the letter and word spacing
   back only because spacing IS inherited where a family is not. */

/* ---- Focus mode ----------------------------------------------------------

   TWO SHAPES SINCE 20 AUGUST 2026, AND THE READER CHOOSES. It was one: the
   block at the reading line stayed lit and every other block was dimmed. Aamir
   asked for a line by line guide as well, and for that to be the default,
   because a paragraph in these books is often the length of a screen and
   dimming everything except a screenful of text is not focus.

   BY THE PARAGRAPH is the original, and it is opacity rather than a lighter
   ink, so it takes the whole block with it, including an Arabic passage and a
   footnote marker, and so it costs one composited property rather than a
   repaint per paragraph.

   0.28 is far enough down that the eye stops trying to read the neighbours and
   near enough that the shape of the page is still there: a reader has to be
   able to see that there is more, or the setting reads as a fault. */

:root[data-read-focus='on'][data-read-beam='para'] .tmp-read > * {
  opacity: 0.28;
  transition: opacity 0.35s var(--ease-soft);
}

:root[data-read-focus='on'][data-read-beam='para'] .tmp-read > .is-lit {
  opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
  :root[data-read-focus='on'][data-read-beam='para'] .tmp-read > * {
    transition: none;
  }
}

/* BY THE LINE is a beam: two washes of the paper's own colour laid over the
   sheet with a gap between them, and the gap is as many lines tall as the
   reader has asked for.

   IT IS A WASH RATHER THAN A CUT because the rest of the page has to be dimmed,
   not hidden, for the same reason the paragraph above is dimmed rather than
   hidden. 0.82 of the paper leaves the words underneath as a ghost.

   IT IS DRAWN INSIDE THE SHEET, positioned against it, and that is what keeps
   it honest at no cost. It inherits the paper's colour including the reader's
   chosen tint, it stops at the sheet's own edges so the site's own ground and
   its header are never washed, it takes the sheet's corner radius, and it
   scrolls with the page rather than having to be repositioned every frame.
   `pointer-events: none` so a reader can still select the words through it.

   THE TWO HEIGHTS ARE THE ONLY THING THE SCRIPT SETS, as custom properties in
   the sheet's own coordinates, because they are the one part that cannot be
   known here: where a line box falls depends on the face, the step on the
   scale, the width of the window and where the reader has scrolled to.
   server/public/reader.js measures the real line boxes and hands the answer
   over. */

.tmp-sheet {
  position: relative;
}

.tmp-beam {
  display: none;
}

:root[data-read-focus='on'][data-read-beam='lines'] .tmp-beam {
  display: block;
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  border-radius: inherit;
  overflow: hidden;
  /* Held back until the script has measured a first band. Without it the two
     washes meet at the top of the sheet for one frame and the whole chapter
     flashes as focus mode is switched on. */
  visibility: hidden;
}

:root[data-read-focus='on'][data-read-beam='lines'] .tmp-beam.is-set {
  visibility: visible;
}

/* MOVED BY `transform`, NOT BY `top` AND `height`, AND WITH NO TRANSITION WHILE
   THE PAGE IS SCROLLING. Both halves of that are the fix for the beam trailing
   behind the words, reported 21 August 2026.

   The transition was the larger half. An eased move is the right answer when a
   thing moves once; the beam moves on every frame of every scroll, so a 0.18s
   ease meant the band was always showing where the reader WAS about a fifth of
   a second ago, and reading quickly or flicking down a page left it visibly
   chasing. The ease is kept for the one case it was written for, a setting
   being changed, and reader.js puts `is-eased` on for the length of that move
   only.

   Growing a band by its `height` is the smaller half: it is a layout on the
   sheet every frame. Each band is instead the FULL HEIGHT of the sheet and is
   slid into place, the top one up until its lower edge lands on the first lit
   line and the bottom one down until its upper edge lands past the last. A
   percentage in `translateY` is a share of the element's own height, and the
   element's own height is the sheet's, so the two calculations below need
   nothing measured to be exact. Transform costs neither layout nor a repaint of
   what is underneath. */

.tmp-beam-top,
.tmp-beam-bot {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  height: 100%;
  background: var(--paper);
  opacity: 0.82;
}

.tmp-beam-top {
  transform: translateY(calc(var(--beam-top, 0px) - 100%));
}

.tmp-beam-bot {
  transform: translateY(var(--beam-bot, 100%));
}

@media (prefers-reduced-motion: no-preference) {
  .tmp-beam.is-eased .tmp-beam-top,
  .tmp-beam.is-eased .tmp-beam-bot {
    transition: transform 0.18s var(--ease-soft);
  }
}


/* ---- 5.2 The rail --------------------------------------------------------

   Three buttons: the reading settings, the bookmarks, and the chapter with the
   progress ring drawn around it. The third is the live site's progress circle,
   which was display only, finally given something to do. Above them sits the
   tab that folds the three away and brings them back.

   IT IS STICKY, SINCE 21 AUGUST 2026, where it was fixed. Fixed meant the rail
   was pinned under the header from the first paint, hanging over the chapter's
   title and the navigation buttons before there was anything to read. Aamir
   asked for it to start where the reading starts, so it is now docked in the
   flow of the page at the top of the paper and sticks from there. What made
   sticky look wrong the first time was putting it INSIDE the sheet, where it
   would take the paper's colour and stop at the paper's foot; the dock is a
   sibling of the sheet instead, so the rail still belongs to the page rather
   than to the sheet and still travels the whole chapter. */

.tmp-rail,
.tmp-rail-dock,
.tmp-panel,
.tmp-scrim,
.tmp-pop,
.tmp-toast {
  display: none;
}

/* THE DOCK HAS NO HEIGHT AND DRAWS NOTHING. It is a hook in the flow, put
   between the navigation row and the sheet, and the rail hangs off it. Zero
   height is what lets it sit there without moving the rule above it or the
   first line below it by a pixel.

   `top` is the sticky offset and it clears the header rather than guessing at
   it: `--head` is the one place the header's height is written down (site.css
   section 1), so the rail moves with it instead of drifting the first time the
   header is touched. The header is z-index 50 and this is 45, so the two never
   fight: on a page scrolled to the top the rail is simply underneath it, which
   is where the header belongs.

   THE GAP IS ON THE RAIL AND NOT ON THE DOCK, since 21 August 2026. The dock
   sticks flush to the header and the rail hangs `--rail-drop` below it, which
   comes to the same offset once the page is scrolled and is the whole point at
   the top of it: docked, the rail used to start level with the rule under the
   navigation buttons and looked stuck to it. Move the gap and it clears the
   rule instead. The two numbers are written as one so they cannot drift: change
   `--rail-drop` and the resting gap and the scrolled offset move together. */
.js-reader .tmp-rail-dock {
  --rail-drop: 0.6rem;
  display: block;
  position: sticky;
  z-index: 45;
  top: var(--head);
  height: 0;
}

/* HELD AGAINST THE RIGHT, as a card whose right edge is the screen's own,
   which is the live site's arrangement and is what Aamir asked for. It is a
   column, at every width: the tab has to sit above what it folds, and three
   buttons in a column against the right edge cover a strip of margin rather
   than a band across the words.

   Hung from the dock above, which is what carries it down the page.

   The unrounded right side is not a saving. A card that meets the edge of the
   screen reads as attached to it, which is what makes the tab beside it look
   like a thing that slides rather than a fourth button. */

.js-reader .tmp-rail {
  position: absolute;
  top: var(--rail-drop, 0.6rem);
  right: 0;
  display: flex;
  flex-direction: column;
  /* FOLDED, THERE IS NO CARD AT ALL. Aamir, 22 August 2026: folded away, the
     tools should be a thin flat strip along the right edge, so that they are
     not standing beside the words. The padding, the hairline, the paper and the
     shadow therefore all belong to the unfolded state below; at rest this
     element draws nothing whatever, and the strip inside it is the whole of
     what is on the screen. The safe area is still honoured, or the strip lands
     under the rounded corner of a phone held sideways. */
  align-items: flex-end;
  padding: 0;
  padding-right: env(safe-area-inset-right, 0px);
  border: 0;
  background: none;
  box-shadow: none;
  transition: padding 0.24s var(--ease), border-radius 0.24s var(--ease),
    background 0.24s var(--ease-soft), box-shadow 0.24s var(--ease-soft);
}

/* FOLDED IS THE RESTING STATE AND IT IS WRITTEN AS THE RESTING STATE, not as an
   attribute laid over an unfolded default. Every chapter now opens with the
   tools folded, so writing it the other way round would mean the rail was drawn
   unfolded and then folded again by the script, which is a flicker on the first
   paint of every chapter.

   Unfolded, and only then, the buttons are held in a card:

   THE CARD IS WHITE AND THE BUTTONS IN IT ARE TINTED. What matters is that the
   buttons and the card they sit in are one step apart, or the four are outlines
   on one flat shape; which of the two is the lighter follows from the scheme,
   and on a pale scheme it is the card.

   The unrounded right side is not a saving. A card that meets the edge of the
   screen reads as attached to it, which is what makes the strip above it look
   like something that slides rather than a fifth button. */
:root[data-read-tools='open'] .tmp-rail {
  align-items: center;
  padding: 0.4rem;
  padding-right: calc(0.4rem + env(safe-area-inset-right, 0px));
  border: 1px solid var(--line);
  border-right: 0;
  border-radius: 1.75rem 0 0 1.75rem;
  background: var(--sheet);
  box-shadow: -4px 8px 24px rgba(18, 37, 63, 0.14);
}

/* THE STRIP, AND THE TAB IT BECOMES.
   ..........................................................................

   FOLDED IT IS A FLAT BAR HELD AGAINST THE RIGHT EDGE, which is what Aamir
   asked for on 22 August 2026: folded away, the tools were still a rounded tab
   the width of a button sitting beside the text, and the point of folding them
   is to have nothing standing next to the words. No card, no padding, no
   hairline and no shadow is as little as a control can be and still be a
   control: it is a rule in the margin, of the kind that is read as a handle.

   IT IS ONE FLAT SHORT BAR IN THE SITE'S NAVY, AND NOTHING IS DONE TO IT. Aamir
   settled the shape over four passes on 22 and 23 August 2026: a six pixel line,
   a solid navy bar the full height of the unfolded card, the same bar cut to
   half that height and a tenth narrower and made of pale blue glass, and then,
   looking at the glass: not reflective, and the colour is mine to choose. So the
   size he settled stays and everything that made it shine is gone. No gradient,
   no highlight, no blur taking the page up through it and no shadow lifting it
   off the paper: a shine on a bar eighteen pixels wide is not read as glass, it
   is read as the page being slightly dirty in one place.

   THE COLOUR IS --deep, WHICH IS THE SITE'S OWN NAVY. It is the surface the dark
   bands on the front page are made of and the navy the tab icon is cut from, so
   the handle is the same blue as the other places this site goes dark, rather
   than a fifth blue invented for one control. The pale blues in the scheme were
   the other candidate and they are the wrong end of it: --ground-tint on
   --ground is a step and a half apart, which is enough to shade a box that is
   already there and nowhere near enough to make eighteen pixels in the margin
   look like something to press. A control has to be seen before it can be quiet.

   It still starts at the top of the rail, where the tab is when the card is
   open, so the fold still grows out of the handle.

   THE HEIGHT IS HALF THE CARD'S HEIGHT, WRITTEN AS HALF OF THE CARD'S PARTS. It
   is a sum and not a number: half the padding twice, half the tab, half the
   tab's own gap, two buttons for four, one and a half gaps for three, and one
   hairline for two. A single figure would be right today and wrong the first
   time a fifth button arrives, and a handle that no longer measures the thing it
   opens is exactly the kind of wrong that nothing on the screen complains
   about. The test in `reader.test.js` recomputes the card from the buttons
   actually in the rail and halves it.

   THE CHEVRON STILL GOES WITH THE CARD. A glyph in an eighteen pixel column is a
   smudge, so folded there is no glyph, and the bar is the whole message.

   AT THIS SIZE IT NO LONGER BORROWS THE PAGE. The bar used to be six pixels, so
   the thing a finger actually hit was an invisible box reaching a centimetre
   leftwards over the paper. A bar of this height is found without help, and that
   reach is now a sliver: on a phone the paper runs nearly to the edge of the
   screen, and fifteen rems of press target lying over the ends of the lines is
   a press landing on somebody's last word all the way down the chapter.

   UNFOLDED IT IS THE TAB AGAIN: wide as a button and about two thirds as tall,
   so it reads as a handle on the card rather than as another control competing
   with the four. The chevron points right, the way the buttons go when they
   fold away against the edge. */
.tmp-rail-pull {
  position: relative;
  width: 1.125rem;
  /* Half the card's height, as half of the card's parts. See the note above:
     half the padding twice, half the tab, half the tab's gap, two buttons of
     the four, one and a half of the three gaps, one of the two hairlines. */
  height: calc(0.4rem + 0.875rem + 0.2rem + 2 * 2.75rem + 1.5 * 0.5rem + 1px);
  margin-bottom: 0;
  display: grid;
  place-items: center;
  padding: 0;
  border: 0;
  border-radius: 0.3rem 0 0 0.3rem;
  /* One colour, laid on flat. See the note above: the site's own navy, and
     nothing over it. */
  background: var(--deep);
  color: var(--ink-dim);
  cursor: pointer;
  flex-shrink: 0;
  transition: width 0.24s var(--ease), height 0.24s var(--ease),
    border-radius 0.24s var(--ease), background 0.2s var(--ease-soft),
    color 0.2s var(--ease-soft), margin-bottom 0.24s var(--ease);
}

/* The target, which is a little wider than the bar and no taller. `content` and
   nothing else visible: no colour, no size on the page, and no effect on
   anything around it. */
.tmp-rail-pull::after {
  content: '';
  position: absolute;
  top: 0;
  right: -0.5rem;
  bottom: 0;
  left: -0.35rem;
}

/* Folded, hovering thickens the bar rather than tinting it. It is already the
   full navy, so there is nowhere darker for it to go, and growing is what says
   the bar is a handle rather than a border. */
.tmp-rail-pull:hover {
  width: 1.35rem;
}

.tmp-rail-pull:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 2px;
}

.tmp-rail-pull svg {
  display: block;
  rotate: 180deg;
  /* Folded there is no room for it, so it is not merely small, it is gone: a
     glyph scaled down into an eighteen pixel column draws as a speck. */
  opacity: 0;
  scale: 0.5;
  transition: rotate 0.24s var(--ease), opacity 0.18s var(--ease-soft),
    scale 0.18s var(--ease-soft);
}

:root[data-read-tools='open'] .tmp-rail-pull {
  width: 2.75rem;
  height: 1.75rem;
  margin-bottom: 0.4rem;
  border-radius: 0.7rem;
  background: var(--ground-raised);
}

/* Unfolded, the whole tab is the target, so the box below is not wanted: left
   in place it would swallow presses on the button underneath it. */
:root[data-read-tools='open'] .tmp-rail-pull::after {
  display: none;
}

:root[data-read-tools='open'] .tmp-rail-pull:hover {
  width: 2.75rem;
  background: var(--ground-tint);
  color: var(--ink);
}

:root[data-read-tools='open'] .tmp-rail-pull svg {
  rotate: 0deg;
  opacity: 1;
  scale: 1;
}

/* WHAT FOLDS. `max-height` rather than `display`, so there is something to
   animate, and `visibility` alongside it so that folded buttons are out of the
   tab order and out of a screen reader's way rather than merely invisible. The
   visibility is delayed by exactly the length of the fold on the way out and
   immediate on the way in, which is the whole reason it is written twice.

   THE UNFOLDED HEIGHT HAS TO CLEAR THE BUTTONS, and it stopped doing so the
   moment the dictionary made a fourth of them on 22 August 2026: four buttons
   of 2.75rem with three 0.5rem gaps between them come to 12.5rem, and the 12rem
   this used to allow would have cut the last one in half. It is written with
   room to spare rather than to the millimetre, because the number is a ceiling
   for an animation and not a size. */
.tmp-rail-btns {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  overflow: hidden;
  max-height: 0;
  opacity: 0;
  pointer-events: none;
  visibility: hidden;
  transition: max-height 0.28s var(--ease), opacity 0.2s var(--ease-soft),
    visibility 0s 0.28s;
}

:root[data-read-tools='open'] .tmp-rail-btns {
  max-height: 16rem;
  opacity: 1;
  pointer-events: auto;
  visibility: visible;
  transition: max-height 0.28s var(--ease), opacity 0.2s var(--ease-soft),
    visibility 0s;
}

@media (prefers-reduced-motion: reduce) {
  .js-reader .tmp-rail,
  .tmp-rail-pull,
  .tmp-rail-pull svg,
  .tmp-rail-btns,
  :root[data-read-tools='open'] .tmp-rail-btns {
    transition-duration: 0s;
    transition-delay: 0s;
  }
}

.tmp-rail-btn {
  position: relative;
  width: 2.75rem;
  height: 2.75rem;
  display: grid;
  place-items: center;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: var(--ground-raised);
  color: var(--ink);
  font-family: var(--ui);
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  cursor: pointer;
  /* NO SHADOW OF THEIR OWN ANY MORE. They used to carry a real one, because
     they floated free over the sheet and a hairline disappears against paper.
     The card they are now inside carries that shadow instead, and a shadow
     drawn in here would be cut off square by the clipping that lets the buttons
     fold. */
  transition: background 0.2s var(--ease-soft), color 0.2s var(--ease-soft),
    border-color 0.2s var(--ease-soft);
}

.tmp-rail-btn:hover {
  background: var(--ground-tint);
  border-color: var(--ink-faint);
}

/* THE OPEN STATE IS THE ACCENT, which is the one strong colour this design
   allows itself (site.css section 1). It is the only place on a chapter page
   where the gold is a ground rather than type, and that is what makes it read
   as 'this one is on' at a glance from the far side of a phone. The label and
   the progress ring on it are the page's own white, at 5.1:1. */
.tmp-rail-btn.is-on {
  background: var(--gold);
  border-color: var(--gold);
  color: var(--ground);
}

.tmp-rail-btn:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 3px;
}

.tmp-rail-btn svg {
  display: block;
}

/* The ring. It is drawn behind the label rather than around the button, so the
   progress reads as belonging to the control, and it is turned a quarter so
   that nothing starts at three o'clock. */
.tmp-ring {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  rotate: -90deg;
  pointer-events: none;
}

.tmp-ring-track {
  fill: none;
  stroke: var(--line);
  stroke-width: 2;
}

.tmp-ring-fill {
  fill: none;
  stroke: var(--gold);
  stroke-width: 2;
  stroke-linecap: round;
  /* 2πr at r = 15.5, which reader.js computes for itself. It rests fully
     offset, so a browser running no script draws an empty ring rather than a
     full one claiming the chapter has been read. */
  stroke-dasharray: 97.39;
  stroke-dashoffset: 97.39;
  transition: stroke-dashoffset 0.15s linear;
}

.tmp-rail-btn.is-on .tmp-ring-track {
  stroke: rgba(255, 255, 255, 0.35);
}

.tmp-rail-btn.is-on .tmp-ring-fill {
  stroke: var(--ground);
}

.tmp-ring-pct {
  position: relative;
  font-size: 0.5625rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}

/* ---- 5.3 The panels ------------------------------------------------------

   One panel at a time, IN THE MIDDLE OF THE SCREEN at every width, which is
   what Aamir asked for on 20 August 2026 and is the second arrangement these
   have had. They used to rise from the bottom edge on a phone and open beside
   the rail button that called them on a laptop. Two things were wrong with
   that. A sheet along the bottom edge is where a phone puts a share menu, and
   it put the settings furthest from the eye and covered the passage a reader
   had just been looking at; and a card beside the rail had to be nudged back
   into the viewport by script whenever the button that opened it sat low.
   Centred, neither problem exists and no script decides anything.

   NARROWER THAN IT WAS, at 18rem against the old 20.5rem, which is also what
   he asked for. Nothing in a panel is a paragraph: the widest thing any of
   them holds is a row of five size dots and a bookmark's one line of quoted
   words, and both sit inside 18rem comfortably. The chapter's heading list is
   the one thing that would take more, and a heading that runs on wraps, which
   is better than a panel wide enough to cover the page it navigates.

   THE SCRIM IS NOW AT EVERY WIDTH, and it has to be. A panel over the middle
   of a laptop screen is over the words, so the chapter behind it is not being
   read and pretending otherwise would leave a card floating in the middle of a
   fully lit page with nothing saying which of the two is being addressed. This
   is what makes the panels modal in earnest, and it is why they became
   dialogues that hold focus; server/src/pages/reader.js records the change. */

.js-reader .tmp-scrim {
  position: fixed;
  inset: 0;
  z-index: 44;
  display: none;
  background: rgba(18, 37, 63, 0.45);
  cursor: pointer;
}

.js-reader.is-panel-open .tmp-scrim {
  display: block;
}

/* CENTRED WITH `translate` RATHER THAN A TRANSFORM, so the opening animation
   can take `scale` and `opacity` without either of them having to restate the
   centring. The two are separate properties and they compose; one `transform`
   shorthand carrying both would have to repeat the offset in every keyframe,
   and the day somebody changed the offset in one place it would jump. */
.js-reader .tmp-panel {
  position: fixed;
  z-index: 46;
  top: 50%;
  left: 50%;
  translate: -50% -50%;
  display: flex;
  flex-direction: column;
  width: min(18rem, calc(100vw - 2.5rem));
  max-height: min(78vh, 34rem);
  background: var(--sheet);
  color: var(--ink);
  font-family: var(--ui);
  border: 1px solid var(--line);
  border-radius: 6px;
  box-shadow: 0 2px 8px rgba(18, 37, 63, 0.08), 0 26px 60px rgba(18, 37, 63, 0.22);
}

.js-reader .tmp-panel[hidden] {
  display: none;
}

/* The panel takes focus when it opens and must not draw a ring for it: it is
   focused because a keyboard is being put inside it, not because anybody
   pressed it. Its own controls still show theirs. */
.js-reader .tmp-panel:focus {
  outline: none;
}

@media (prefers-reduced-motion: no-preference) {
  .js-reader .tmp-panel.is-open {
    animation: tmp-panel-in 0.18s var(--ease) both;
  }
}

@keyframes tmp-panel-in {
  from { opacity: 0; scale: 0.96; }
  to   { opacity: 1; scale: 1; }
}

.tmp-panel-head {
  display: flex;
  align-items: flex-start;
  gap: 1rem;
  padding: 0.9rem 1.1rem 0.85rem;
  border-bottom: 1px solid var(--line-soft);
  flex-shrink: 0;
}

.tmp-panel-head > div {
  flex: 1;
  min-width: 0;
}

.tmp-panel-eyebrow {
  display: block;
  font-size: 0.625rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--gold);
}

.tmp-panel-title {
  display: block;
  margin-top: 0.2rem;
  font-size: 0.9375rem;
  font-weight: 600;
  line-height: 1.3;
  color: var(--ink);
}

.tmp-panel-shut {
  width: 1.875rem;
  height: 1.875rem;
  flex-shrink: 0;
  display: grid;
  place-items: center;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: transparent;
  color: var(--ink-dim);
  cursor: pointer;
  transition: color 0.2s var(--ease-soft), border-color 0.2s var(--ease-soft);
}

.tmp-panel-shut:hover {
  color: var(--ink);
  border-color: var(--ink-faint);
}

.tmp-panel-body {
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
}

.tmp-panel-foot {
  flex-shrink: 0;
  padding: 0.8rem 1.1rem;
  border-top: 1px solid var(--line-soft);
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}

/* ---- 5.4 Inside the panels ---------------------------------------------- */

.tmp-set {
  padding: 0.9rem 1.1rem;
  border-bottom: 1px solid var(--line-soft);
}

.tmp-set-name {
  display: block;
  margin-bottom: 0.65rem;
  font-size: 0.625rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-dim);
}

/* THE FIVE NAMED SIZES, drawn as five dots at five sizes. A row of the letters
   XS to XL says the same thing in words the reader has to translate; five dots
   say it in the shape of the thing being changed. The live site does this, and
   it is the one part of its reader tools kept unchanged.

   THEY ARE NOW SHORTCUTS RATHER THAN THE WHOLE SCALE. Since 20 August 2026 the
   slider below them carries thirty-one steps and the five dots sit on five of
   them, so a dot is lit only when the slider is exactly on its step. Pressing
   one moves the slider to it. */
.tmp-sizes {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 0.25rem;
}

.tmp-size {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.45rem;
  padding: 0.4rem 0.1rem;
  border: 0;
  border-radius: 3px;
  background: transparent;
  color: var(--ink-dim);
  font-family: var(--ui);
  font-size: 0.5625rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  cursor: pointer;
}

.tmp-size-dot {
  border-radius: 50%;
  background: var(--ink-faint);
  transition: background 0.2s var(--ease-soft), scale 0.2s var(--ease-soft);
}

.tmp-size[data-size='1'] .tmp-size-dot { width: 0.4rem; height: 0.4rem; }
.tmp-size[data-size='2'] .tmp-size-dot { width: 0.55rem; height: 0.55rem; }
.tmp-size[data-size='3'] .tmp-size-dot { width: 0.7rem; height: 0.7rem; }
.tmp-size[data-size='4'] .tmp-size-dot { width: 0.875rem; height: 0.875rem; }
.tmp-size[data-size='5'] .tmp-size-dot { width: 1.05rem; height: 1.05rem; }

.tmp-size:hover .tmp-size-dot {
  background: var(--ink-dim);
}

.tmp-size.is-on {
  color: var(--gold);
}

.tmp-size.is-on .tmp-size-dot {
  background: var(--gold);
  scale: 1.1;
}

/* ---- The fine slider ----------------------------------------------------

   UNDER THE FIVE DOTS AND NOT INSTEAD OF THEM, which is what Aamir asked for on
   20 August 2026: the named sizes for the reader who wants one press, and a
   slider under them for the reader for whom none of the five is quite it. It
   runs five steps past the smallest and five past the largest, so it is also
   how a reader gets type smaller than XS or larger than XL.

   IT IS A REAL `input type=range`, not a track and a knob built out of divs. It
   arrives already operable by arrow key, Home, End, Page Up and Page Down, it
   announces its own value, it is draggable by touch without a single line of
   script, and every one of those is something a hand built slider gets wrong.
   The appearance is reset to none and the track and thumb are drawn here,
   because the two vendors draw them differently and a control that is a
   different shape in Safari than in Firefox is the site speaking with two
   voices.

   THE READOUT BESIDE IT NAMES THE SIZE rather than counting steps. 'Step 17' is
   a number about the implementation; 'Between L and XL' is about the type. */

.tmp-scale {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  margin-top: 0.7rem;
}

.tmp-scale-range {
  flex: 1;
  min-width: 0;
  height: 1.5rem;
  margin: 0;
  padding: 0;
  background: transparent;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
}

.tmp-scale-range:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 3px;
  border-radius: 3px;
}

.tmp-scale-range::-webkit-slider-runnable-track {
  height: 3px;
  border-radius: 2px;
  background: var(--line);
}

.tmp-scale-range::-moz-range-track {
  height: 3px;
  border-radius: 2px;
  background: var(--line);
}

.tmp-scale-range::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 0.95rem;
  height: 0.95rem;
  /* The track is 3px and the thumb is a good deal taller, so it has to be
     lifted by half the difference or it hangs off the bottom of the track in
     every WebKit browser. Firefox centres it for us, which is why there is no
     equivalent line in the rule below. */
  margin-top: -0.4rem;
  border: 0;
  border-radius: 50%;
  background: var(--gold);
  box-shadow: 0 1px 3px rgba(18, 37, 63, 0.3);
}

.tmp-scale-range::-moz-range-thumb {
  width: 0.95rem;
  height: 0.95rem;
  border: 0;
  border-radius: 50%;
  background: var(--gold);
  box-shadow: 0 1px 3px rgba(18, 37, 63, 0.3);
}

/* Fixed width and tabular figures, so the row does not shuffle sideways as the
   reader drags: a readout that moves the slider it is reporting on is a readout
   that is hard to aim. */
.tmp-scale-now {
  flex: none;
  width: 5.5rem;
  font-family: var(--ui);
  font-size: 0.625rem;
  font-weight: 500;
  letter-spacing: 0.04em;
  text-align: right;
  color: var(--ink-dim);
  font-variant-numeric: tabular-nums;
}

/* The tints and the faces, each a set of choices where exactly one is on.
   They are buttons rather than radio inputs because the choice takes effect the
   moment it is made and there is no form to submit; `aria-pressed` carries the
   state, and reader.js sets it on every one of them, so a screen reader hears
   which is chosen rather than only which was pressed. */
/* THE FACES OUTGREW A ROW on 20 August 2026, at five rather than two, and the
   tints followed them on 21 August when the site's own page colour was added as
   a fifth. Both wrap into a grid of three, and the row of four the tints used
   to be is gone with the fourth tint. Three across rather than four, because a
   face's name has to be set in the face to be worth showing and 'Dyslexic' at a
   quarter of a narrow panel is four letters and an ellipsis. */
.tmp-choices-wrap {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0.5rem;
}

.tmp-tint,
.tmp-face {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.4rem;
  padding: 0.55rem 0.3rem;
  border: 1px solid var(--line);
  border-radius: 3px;
  background: transparent;
  color: var(--ink-dim);
  font-family: var(--ui);
  font-size: 0.6875rem;
  font-weight: 500;
  cursor: pointer;
  transition: border-color 0.2s var(--ease-soft), color 0.2s var(--ease-soft);
}

.tmp-tint:hover,
.tmp-face:hover {
  border-color: var(--ink-faint);
  color: var(--ink);
}

.tmp-tint.is-on,
.tmp-face.is-on {
  border-color: var(--gold);
  color: var(--gold);
}

/* The swatch IS the paper it selects, drawn at the value the sheet will take,
   so the choice is made by looking rather than by reading a word for a
   colour. */
.tmp-swatch {
  width: 1.375rem;
  height: 1.375rem;
  border-radius: 50%;
  border: 1px solid rgba(18, 37, 63, 0.25);
}

.tmp-tint[data-tint=''] .tmp-swatch { background: #f6f9fc; }
.tmp-tint[data-tint='ivory'] .tmp-swatch { background: #fdfbf7; }
.tmp-tint[data-tint='warm'] .tmp-swatch { background: #f7ecd3; }
.tmp-tint[data-tint='cool'] .tmp-swatch { background: #eef1f4; }
.tmp-tint[data-tint='sage'] .tmp-swatch { background: #ecf1ea; }

/* Each face sets its own name in itself, which is the whole of the preview a
   reader needs and is more honest than a sentence describing it. */
.tmp-face-eg {
  font-size: 1.0625rem;
  line-height: 1;
  color: var(--ink);
}

.tmp-face[data-face=''] .tmp-face-eg { font-family: var(--read); }
.tmp-face[data-face='book'] .tmp-face-eg { font-family: 'Literata', var(--read); }
.tmp-face[data-face='garamond'] .tmp-face-eg { font-family: 'EB Garamond', var(--read); }
.tmp-face[data-face='sans'] .tmp-face-eg { font-family: var(--ui); }
.tmp-face[data-face='dyslexic'] .tmp-face-eg { font-family: 'OpenDyslexic', var(--read); }

/* A switch row: a name, a sentence saying what it does, and the switch itself.
   The sentence is the part the live site's panel got right. */
.tmp-switch {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  width: 100%;
  padding: 0.9rem 1.1rem;
  border: 0;
  background: transparent;
  color: var(--ink);
  font-family: var(--ui);
  text-align: left;
  cursor: pointer;
}

.tmp-switch-text {
  flex: 1;
  min-width: 0;
}

.tmp-switch-title {
  display: block;
  font-size: 0.8125rem;
  font-weight: 600;
  line-height: 1.3;
}

.tmp-switch-note {
  display: block;
  margin-top: 0.15rem;
  font-size: 0.6875rem;
  line-height: 1.4;
  color: var(--ink-dim);
}

.tmp-switch-pill {
  position: relative;
  flex-shrink: 0;
  width: 2.125rem;
  height: 1.25rem;
  border-radius: 0.625rem;
  background: rgba(18, 37, 63, 0.2);
  transition: background 0.2s var(--ease-soft);
}

.tmp-switch-pill::after {
  content: '';
  position: absolute;
  top: 0.1875rem;
  left: 0.1875rem;
  width: 0.875rem;
  height: 0.875rem;
  border-radius: 50%;
  /* THE KNOB IS WHITE IN BOTH STATES, which it was not before: it took the
     ground colour when the switch was on, and on the dark scheme the ground was
     the dark thing. Here the knob has to be the lightest part of the control
     whichever way it is thrown, and the small shadow is what keeps it visible
     against the off state's own pale track. */
  background: #fff;
  box-shadow: 0 1px 2px rgba(18, 37, 63, 0.35);
  transition: translate 0.2s var(--ease-soft);
}

.tmp-switch.is-on .tmp-switch-pill {
  background: var(--gold);
}

.tmp-switch.is-on .tmp-switch-pill::after {
  translate: 0.875rem 0;
}

/* ---- What focus mode does -----------------------------------------------

   THE OPTIONS UNDER THE SWITCH, added on 20 August 2026 when Aamir asked for a
   line by line guide beside the paragraph one. They are HIDDEN UNTIL THE SWITCH
   IS ON, by the `hidden` attribute rather than by a class, because settings for
   a thing that is turned off are noise: the panel is short, and every row in it
   that does nothing is a row the reader has to rule out. `hidden` is also what
   keeps them out of a screen reader's reach, which a class could not do.

   INDENTED AND ON A QUIETER GROUND, so the rows read as belonging to the switch
   above rather than as two more settings beside it.

   The pills are the same shape as the tint and face choices, in miniature: one
   vocabulary for 'exactly one of these', whether the choice is a paper colour
   or a number of lines. */

.tmp-sub {
  padding: 0 1.1rem 0.9rem 1.1rem;
  display: grid;
  gap: 0.7rem;
}

/* THE OPTIONS ANNOUNCE THEMSELVES WHEN THE SWITCH IS TURNED ON, added 21 August
   2026. They sit at the bottom of a panel that is usually already scrolled to
   its end by the time anybody reaches the switch, so a reader who did not
   already know they were there had no way of finding out: the switch went on
   and, as far as the screen was concerned, nothing else happened. reader.js
   scrolls the panel down to them and puts this class on for the length of the
   move, so they arrive rather than merely being there. */
@media (prefers-reduced-motion: no-preference) {
  .tmp-sub.is-new {
    animation: tmp-sub-in 0.32s var(--ease) both;
  }
}

@keyframes tmp-sub-in {
  from { opacity: 0; translate: 0 -0.35rem; }
  to   { opacity: 1; translate: 0 0; }
}

.tmp-sub-row {
  display: grid;
  gap: 0.4rem;
}

/* A CLASS THAT SETS A DISPLAY BEATS THE BROWSER'S OWN RULE FOR `hidden`, so
   both of the above have to switch themselves off again or the attribute means
   nothing. This failure has happened on this site before, which is why the
   Library page carries three rules of the same kind and why there is a test
   that walks the markup looking for it. */
.tmp-sub[hidden],
.tmp-sub-row[hidden] {
  display: none;
}

.tmp-sub-name {
  font-family: var(--ui);
  font-size: 0.625rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-dim);
}

.tmp-pills {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
}

.tmp-pill {
  flex: 1;
  min-width: 2.25rem;
  padding: 0.4rem 0.5rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: transparent;
  color: var(--ink-dim);
  font-family: var(--ui);
  font-size: 0.6875rem;
  font-weight: 500;
  text-align: center;
  cursor: pointer;
  transition: border-color 0.2s var(--ease-soft), color 0.2s var(--ease-soft);
}

.tmp-pill:hover {
  border-color: var(--ink-faint);
  color: var(--ink);
}

.tmp-pill.is-on {
  border-color: var(--gold);
  color: var(--gold);
}

/* THE LINE COUNTS ARE A GRID, NOT A WRAPPING ROW, so all six sit on one line at
   equal widths. Left to wrap they came out five and one, which reads as five
   choices and a mistake rather than as a scale from one to six. */
.tmp-pills-num {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
}

.tmp-pills-num .tmp-pill {
  min-width: 0;
  padding-inline: 0.2rem;
  font-variant-numeric: tabular-nums;
}

/* The two buttons every panel foot is built from. The filled one is the thing
   the panel is for; the quiet one is everything else. */
.tmp-do,
.tmp-quiet {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.45rem;
  width: 100%;
  padding: 0.65rem 0.9rem;
  border-radius: 3px;
  font-family: var(--ui);
  font-size: 0.8125rem;
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
  transition: background 0.2s var(--ease-soft), color 0.2s var(--ease-soft),
    border-color 0.2s var(--ease-soft);
}

.tmp-do {
  border: 1px solid var(--gold);
  background: var(--gold);
  color: var(--ground);
}

.tmp-do:hover {
  background: var(--gold-dark);
  border-color: var(--gold-dark);
}

.tmp-quiet {
  border: 1px solid var(--line);
  background: transparent;
  color: var(--ink-dim);
  font-weight: 500;
}

.tmp-quiet:hover {
  color: var(--ink);
  border-color: var(--ink-faint);
}

/* THIS SITE HAS NO GLOBAL `[hidden]` RESET and it is not getting one here: the
   Library page states the same rule for its own three, and a blanket
   `[hidden] { display: none !important }` would be a rule that quietly wins
   arguments nobody knew they were having.

   It is needed because these two set a display of their own, and an author's
   class rule beats the browser's own `[hidden]`. The Carry on button on a book
   page starts hidden and would otherwise be a button offering to resume a book
   nobody has opened. */
.tmp-do[hidden],
.tmp-quiet[hidden] {
  display: none;
}

/* ---- The bookmarks panel ------------------------------------------------ */

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

.tmp-mark {
  display: flex;
  align-items: stretch;
  border-bottom: 1px solid var(--line-soft);
}

.tmp-mark:last-child {
  border-bottom: 0;
}

.tmp-mark-go {
  flex: 1;
  min-width: 0;
  display: block;
  padding: 0.7rem 0.5rem 0.7rem 1.1rem;
  text-decoration: none;
  color: var(--ink);
}

.tmp-mark-go:hover {
  background: var(--ground-tint);
}

.tmp-mark-ch {
  display: block;
  font-size: 0.75rem;
  font-weight: 600;
  line-height: 1.35;
  color: var(--ink);
}

/* THE EXCERPT IS SET IN THE READING SERIF and it is one of only two places in
   all this furniture that is. It is the book's own words quoted back to the
   reader, and it is what tells them which bookmark this is: a line of Inter
   here would look like another label.

   Two lines and then it stops. A bookmark on a long passage would otherwise be
   a paragraph inside a list of paragraphs. */
.tmp-mark-text {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  margin-top: 0.15rem;
  font-family: var(--read);
  font-size: 0.75rem;
  font-style: italic;
  line-height: 1.45;
  color: var(--ink-dim);
}

.tmp-mark-when {
  display: block;
  margin-top: 0.25rem;
  font-size: 0.625rem;
  letter-spacing: 0.04em;
  color: var(--ink-faint);
}

/* A bookmark in the chapter being read is marked in the accent down its edge,
   so the panel answers 'which of these is on this page' without a word. */
.tmp-mark.is-here .tmp-mark-go {
  box-shadow: inset 2px 0 0 var(--gold);
}

.tmp-mark-del {
  flex-shrink: 0;
  width: 2.25rem;
  display: grid;
  place-items: center;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--ink-faint);
  cursor: pointer;
  transition: color 0.2s var(--ease-soft);
}

.tmp-mark-del:hover {
  color: var(--warn);
}

.tmp-none {
  margin: 0;
  padding: 1.5rem 1.1rem;
  text-align: center;
  font-size: 0.75rem;
  line-height: 1.6;
  color: var(--ink-dim);
}

/* ---- The chapter panel -------------------------------------------------- */

.tmp-nav-pct {
  display: block;
  padding: 0.85rem 1.1rem;
  border-bottom: 1px solid var(--line-soft);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--gold);
  font-variant-numeric: tabular-nums;
}

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

.tmp-chtoc a {
  display: block;
  padding: 0.6rem 1.1rem;
  border-bottom: 1px solid var(--line-soft);
  font-size: 0.75rem;
  line-height: 1.45;
  color: var(--ink);
  text-decoration: none;
}

.tmp-chtoc a:hover {
  background: var(--ground-tint);
  color: var(--gold);
}

/* A heading nested inside another is indented by its level, so the panel shows
   the shape of the chapter rather than a flat list. One of the nine books
   nests heavily (CLAUDE.md section 2.5) and this is the screen where that
   shows. */
.tmp-chtoc [data-level='3'] a { padding-left: 2rem; color: var(--ink-dim); }
.tmp-chtoc [data-level='4'] a { padding-left: 2.75rem; color: var(--ink-dim); }
.tmp-chtoc [data-level='5'] a,
.tmp-chtoc [data-level='6'] a { padding-left: 3.5rem; color: var(--ink-dim); }

.tmp-jump {
  display: flex;
  gap: 0.5rem;
}

.tmp-jump .tmp-quiet {
  flex: 1;
}

/* ---- 5.5 The passage control, the flash and the note -------------------- */

/* Select some words and this appears above them. It is the one gesture the
   live site got right, and it is the difference between a bookmark that says
   'you were about here' and one that says 'this sentence'. */
.js-reader .tmp-pop {
  position: fixed;
  z-index: 47;
  display: flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.45rem 0.8rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--sheet);
  color: var(--ink);
  font-family: var(--ui);
  font-size: 0.75rem;
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
  box-shadow: 0 2px 6px rgba(18, 37, 63, 0.1), 0 10px 24px rgba(18, 37, 63, 0.2);
}

.js-reader .tmp-pop[hidden] {
  display: none;
}

.js-reader .tmp-toast {
  position: fixed;
  z-index: 48;
  left: 50%;
  bottom: calc(1.5rem + env(safe-area-inset-bottom, 0px));
  translate: -50% 0.5rem;
  padding: 0.55rem 1.1rem;
  border-radius: 999px;
  background: var(--sheet);
  border: 1px solid var(--line);
  color: var(--ink);
  font-family: var(--ui);
  font-size: 0.75rem;
  font-weight: 500;
  box-shadow: 0 2px 6px rgba(18, 37, 63, 0.1), 0 10px 28px rgba(18, 37, 63, 0.2);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.25s var(--ease-soft), translate 0.25s var(--ease-soft);
}

.js-reader .tmp-toast.is-up {
  opacity: 1;
  translate: -50% 0;
}

/* Landing on a bookmark. The passage is marked for a couple of seconds and the
   mark then fades, which is the least a reader needs to be told 'this is the
   bit'. It is a wash in the reading accent rather than a highlighter yellow,
   because it is on paper and because it is temporary. */
.tmp-flash {
  animation: tmp-flash 2.4s var(--ease-soft) both;
  border-radius: 3px;
}

@keyframes tmp-flash {
  0%, 55% { background-color: var(--read-accent-soft); }
  100% { background-color: rgba(138, 100, 16, 0); }
}

@media (prefers-reduced-motion: reduce) {
  .tmp-flash {
    animation: none;
    background-color: var(--read-accent-soft);
  }
}

/* ---- 5.6 The banner on a book page --------------------------------------

   What the live site put above a book's contents, which offered the single
   most recent bookmark. This offers the READING PLACE, which is what somebody
   opening a book they are part way through actually wants, and which is
   recorded without their ever having asked for it.

   IT IS HIDDEN IN THE MARKUP AND SHOWN BY THE SCRIPT, which is the opposite of
   the rule everywhere else on this site and is right here: there is nothing to
   show until the browser has been asked what it remembers, so a banner that
   was visible by default would be an empty box on every first visit. */

.tmp-resume {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem 1.25rem;
  margin-bottom: 1.75rem;
  padding: 0.95rem 1.15rem;
  border: 1px solid var(--line);
  border-left: 2px solid var(--gold);
  border-radius: 3px;
  background: var(--ground-raised);
}

.tmp-resume[hidden] {
  display: none;
}

.tmp-resume-text {
  flex: 1;
  min-width: 12rem;
}

.tmp-resume-label {
  display: block;
  font-family: var(--ui);
  font-size: 0.625rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--gold);
}

.tmp-resume-where {
  display: block;
  margin-top: 0.3rem;
  font-family: var(--ui);
  font-size: 0.9375rem;
  font-weight: 600;
  line-height: 1.35;
  color: var(--ink);
}

.tmp-resume-meta {
  display: block;
  margin-top: 0.2rem;
  font-family: var(--ui);
  font-size: 0.75rem;
  color: var(--ink-dim);
}

.tmp-resume-meta > span:not([hidden]) + span:not([hidden])::before {
  content: ' · ';
}

.tmp-resume-acts {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

.tmp-resume-acts .tmp-do,
.tmp-resume-acts .tmp-quiet {
  width: auto;
}

/* ---- 5.7 The bookmarks page ---------------------------------------------

   The centralised place Aamir asked for on 20 August 2026. Everything a reader
   has saved, in one list, across every book, with the reading places above it.

   It is on the SITE's ground rather than on paper, because nothing on it is a
   book: it is a set of pointers into books. The only reading serif on the page
   is the excerpt in each row, for the same reason it is the only one in the
   panel. */

/* The page's own sections. `.tmp-page` in site.css sets the h1, the measure and
   the rhythm, and stops there; these are the three headings under it and the
   fold the carrying tools sit behind. */

.tmp-msec {
  margin-top: clamp(2.75rem, 7vw, 4rem);
}

.tmp-msec-head {
  margin-bottom: 1.25rem;
  padding-bottom: 0.6rem;
  border-bottom: 1px solid var(--line);
  font-family: var(--ui);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--gold);
}

.tmp-msec[hidden] {
  display: none;
}

.tmp-mopen {
  margin-top: 1.5rem;
  border: 1px solid var(--line);
  border-radius: 3px;
}

.tmp-mopen > summary {
  padding: 0.8rem 1rem;
  font-family: var(--ui);
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--ink);
  cursor: pointer;
}

.tmp-mopen[open] > summary {
  border-bottom: 1px solid var(--line);
}

.tmp-mopen-body {
  padding: 1rem;
}

.tmp-places {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 0.75rem;
}

@media (min-width: 46rem) {
  .tmp-places {
    grid-template-columns: repeat(auto-fill, minmax(19rem, 1fr));
  }
}

.tmp-place-go {
  display: flex;
  gap: 0.9rem;
  align-items: center;
  height: 100%;
  padding: 0.85rem 1rem;
  border: 1px solid var(--line);
  border-radius: 3px;
  background: var(--sheet);
  text-decoration: none;
  transition: border-color 0.2s var(--ease-soft), background 0.2s var(--ease-soft);
}

.tmp-place-go:hover {
  border-color: var(--ink-faint);
  background: var(--ground-tint);
}

.tmp-place-text {
  min-width: 0;
}

.tmp-place-book {
  display: block;
  font-family: var(--ui);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--gold);
}

.tmp-place-ch {
  display: block;
  margin-top: 0.25rem;
  font-family: var(--ui);
  font-size: 0.875rem;
  font-weight: 600;
  line-height: 1.35;
  color: var(--ink);
}

.tmp-place-pct {
  display: block;
  margin-top: 0.2rem;
  font-family: var(--ui);
  font-size: 0.6875rem;
  color: var(--ink-dim);
}

.tmp-mcover {
  flex-shrink: 0;
  width: 3.5rem;
  height: auto;
  border-radius: 2px;
  box-shadow: var(--cover-edge);
}

.tmp-mcover.is-blank {
  width: 3.5rem;
  height: 5.25rem;
  background: var(--ground-tint);
}

.tmp-mgroup {
  margin-top: 2.5rem;
}

.tmp-mgroup:first-child {
  margin-top: 0;
}

.tmp-mgroup-head {
  display: flex;
  align-items: center;
  gap: 0.9rem;
  padding-bottom: 0.85rem;
  border-bottom: 1px solid var(--line);
}

.tmp-mgroup-text {
  flex: 1;
  min-width: 0;
}

.tmp-mgroup-title {
  margin: 0;
  font-family: var(--ui);
  font-size: 1.0625rem;
  font-weight: 600;
  line-height: 1.3;
  color: var(--ink);
}

.tmp-mgroup-count {
  margin: 0.15rem 0 0;
  font-family: var(--ui);
  font-size: 0.75rem;
  color: var(--ink-dim);
}

.tmp-mgroup-clear,
.tmp-marks-tool {
  flex-shrink: 0;
  padding: 0.45rem 0.85rem;
  border: 1px solid var(--line);
  border-radius: 3px;
  background: transparent;
  color: var(--ink-dim);
  font-family: var(--ui);
  font-size: 0.75rem;
  cursor: pointer;
  transition: color 0.2s var(--ease-soft), border-color 0.2s var(--ease-soft);
}

.tmp-mgroup-clear:hover,
.tmp-marks-tool:hover {
  color: var(--ink);
  border-color: var(--ink-faint);
}

/* ARMED, AND SAYING SO IN THE ONE COLOUR THIS SITE KEEPS FOR A WARNING. A
   button that has become its own confirmation has to look different from the
   button it was a moment ago, or the second press is made without the reader
   noticing that the first changed anything. */
.tmp-mgroup-clear.is-armed,
.tmp-marks-tool.is-armed {
  border-color: var(--warn);
  color: var(--warn);
}

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

.tmp-mrow {
  display: flex;
  align-items: stretch;
  border-bottom: 1px solid var(--line-soft);
}

.tmp-mrow-go {
  flex: 1;
  min-width: 0;
  padding: 0.85rem 0.5rem 0.85rem 0;
  text-decoration: none;
}

.tmp-mrow-go:hover .tmp-mrow-ch {
  color: var(--gold);
}

.tmp-mrow-ch {
  display: block;
  font-family: var(--ui);
  font-size: 0.875rem;
  font-weight: 600;
  line-height: 1.35;
  color: var(--ink);
  transition: color 0.2s var(--ease-soft);
}

.tmp-mrow-text {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  margin-top: 0.25rem;
  font-family: var(--read);
  font-size: 0.875rem;
  font-style: italic;
  line-height: 1.5;
  color: var(--ink-dim);
}

.tmp-mrow-when {
  display: block;
  margin-top: 0.3rem;
  font-family: var(--ui);
  font-size: 0.6875rem;
  letter-spacing: 0.04em;
  color: var(--ink-faint);
}

.tmp-mrow-del {
  flex-shrink: 0;
  width: 2.5rem;
  display: grid;
  place-items: center;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--ink-faint);
  cursor: pointer;
  transition: color 0.2s var(--ease-soft);
}

.tmp-mrow-del:hover {
  color: var(--warn);
}

/* Carrying them to another device. Folded away in a disclosure because it is
   the rarest thing on the page and the most alarming looking: a box of raw
   text is not what anybody came here for. */
.tmp-marks-carry {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  align-items: center;
}

.tmp-marks-paste {
  width: 100%;
  min-height: 5.5rem;
  padding: 0.65rem 0.8rem;
  border: 1px solid var(--line);
  border-radius: 3px;
  background: var(--sheet);
  color: var(--ink-dim);
  font-family: ui-monospace, 'Cascadia Mono', 'Consolas', monospace;
  font-size: 0.6875rem;
  line-height: 1.5;
  resize: vertical;
}

.tmp-marks-paste:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 2px;
}

.tmp-marks-note {
  margin: 0.85rem 0 0;
  font-family: var(--ui);
  font-size: 0.8125rem;
  color: var(--gold);
}

/* THE COPY STAGE, which exists for a fraction of a millisecond and is never
   seen. When a reader copies a passage, reader.js section 8 clones the
   selection into this element, swaps each honorific letter for the invocation
   it draws, and reads the result back as text.

   IT HAS TO BE IN THE PAGE TO BE READ. `innerText` is the only property that
   knows a paragraph from a line, and it only knows it of an element the browser
   has laid out; asked of a loose element it returns every paragraph run
   together. So this is attached, read and removed within one turn of the event
   loop, before anything is painted. It is given a full width so that nothing
   about the layout is unusual, and clipped to a single line so that nothing
   about the page moves in the instant it is there.

   `display: none` and `visibility: hidden` would both defeat the whole purpose,
   because an element that is not rendered has no `innerText`. */
.tmp-copy-stage {
  position: fixed;
  inset-block-start: 0;
  inset-inline-start: 0;
  inline-size: 100%;
  block-size: 1px;
  overflow: hidden;
  opacity: 0;
  pointer-events: none;
  z-index: -1;
}

/* The stylesheet must not rewrite the words on their way to the clipboard. One
   rule in this file would: a table heading is drawn in capitals, and `innerText`
   reports text as it is drawn, so a copied table arrives SHOUTING.

   IT NEEDS THE FORCE, which is the whole reason this comment is longer than the
   rule. `.tmp-copy-stage *` scores one class, and `.tmp-table th` scores a class
   and an element, so the ordinary rule loses to the very rule it is here to
   overturn. Half a table copied out of a chapter came away in sentence case and
   a whole one came away in capitals, which is exactly the kind of fault nobody
   reports. */
.tmp-copy-stage * {
  text-transform: none !important;
}

/* ---- 5.8 The two bubbles -------------------------------------------------

   Asked for on 21 August 2026, both of them in one breath: a small window that
   opens by a marked term and shows what it means, and a second one that opens
   by a footnote number and shows the note, each with a button carrying the
   reader on to the full entry. Aamir asked for the two to be told apart at a
   glance, so they are.

   WHAT MAKES THEM ONE THING. Both hang off a REAL LINK that works with no
   script at all: the term links to its row on the glossary page, the marker
   links to the note at the foot of the chapter. reader.js intercepts the press
   and opens the bubble instead, and the bubble's own button is that same link.
   So the feature is an improvement on a page that was already complete, which
   is the bargain every other script on this site makes.

   WHAT TELLS THEM APART.

     - THE FOOTNOTE BUBBLE HAS A TAIL, a small triangle pointing back at the
       number that was pressed. Aamir's own description was a speech coming off
       the number, and a tail is what makes a bubble read as coming FROM
       something rather than merely being near it. A note belongs to one exact
       place in one sentence, so pointing at that place is telling the truth.
     - THE GLOSSARY BUBBLE HAS NO TAIL and carries a gold rule along its top
       edge instead. A definition does not belong to the occurrence that was
       pressed: the same words answer all eighty-seven occurrences of the word
       in the chapter, so a bubble that pinned itself to one of them would be
       making a smaller claim than it should.

   NOT MODAL, and this is the difference from the panels in 5.3. A panel is a
   place a reader goes; a bubble is an aside. It takes no scrim, it does not
   trap focus, and it closes on the next press anywhere, on Escape, and on
   anything that reflows the page under it.

   POSITIONED ABSOLUTELY IN THE DOCUMENT, not fixed to the viewport, so it
   travels with the paragraph it belongs to. A fixed bubble would slide off its
   own word the moment the page moved a pixel, and on a phone a press very often
   moves the page a pixel. */

.tmp-bubble {
  position: absolute;
  z-index: 48;
  width: min(21rem, calc(100vw - 2rem));
  padding: 0.9rem 1rem 0.75rem;
  background: var(--sheet);
  color: var(--ink);
  font-family: var(--ui);
  border: 1px solid var(--line);
  border-radius: 6px;
  box-shadow: 0 2px 8px rgba(18, 37, 63, 0.08), 0 18px 40px rgba(18, 37, 63, 0.18);
}

.tmp-bubble[hidden] {
  display: none;
}

@media (prefers-reduced-motion: no-preference) {
  .tmp-bubble {
    animation: tmp-bubble-in 0.15s var(--ease) both;
  }
}

/* Rises a few pixels into place from the side it is on, so a bubble under a
   word appears to come up out of it and one above a word to come down. The
   distance is deliberately small: this is a hint that something opened, not a
   thing to watch. */
@keyframes tmp-bubble-in {
  from {
    opacity: 0;
    scale: 0.98;
    translate: 0 var(--bubble-rise, 4px);
  }
  to {
    opacity: 1;
    scale: 1;
    translate: 0 0;
  }
}

.tmp-bubble-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.75rem;
  margin-bottom: 0.35rem;
  padding-right: 1.25rem;
}

/* THE HEADING IS FURNITURE AND TAKES INTER, which is the site's rule that the
   reading serif belongs to the words of the books and to nothing else
   (shell.test.js holds it). It is tempting to set the term in the face it wears
   in the sentence, and it would be wrong: the same element reads 'Note 3' on
   the other bubble, and a bubble is the site speaking about the book rather
   than the book speaking. Italic is what carries the term instead, which is how
   a transliteration is marked everywhere else anyway.

   The glossary PAGE is the other way round. Its terms sit inside `.tmp-read`
   and inherit the reading serif from it, because there the term IS the text. */
.tmp-bubble-term {
  font-style: italic;
  font-weight: 600;
  font-size: 0.95rem;
  color: var(--ink);
}

.tmp-bubble-label {
  font-size: 0.625rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-dim);
  white-space: nowrap;
}

/* The body of a footnote arrives as markup taken from the notes already on the
   page, so it can carry emphasis, an honorific and a short Arabic phrase. Those
   have to keep working in here. */
.tmp-bubble-body {
  font-size: 0.8125rem;
  line-height: 1.6;
  color: var(--ink-dim);
  /* A very long note is scrolled inside the bubble rather than making a bubble
     as tall as the screen. Six lines or so is where a note stops being an aside
     and becomes something to read at the foot of the page, which is where the
     button goes. */
  max-height: 11rem;
  overflow-y: auto;
  overscroll-behavior: contain;
}

.tmp-bubble-body em {
  font-style: italic;
}

.tmp-bubble-body .tmp-hon {
  font-family: 'Honorifics', serif;
  font-size: 1.1em;
  line-height: 1;
}

.tmp-bubble-body .tmp-ar-inline {
  font-family: 'Scheherazade New', serif;
  font-size: 1.15em;
}

/* A term inside a bubble is not itself a mark. Nesting a definition inside a
   definition is a rabbit hole with no bottom, and reader.js opens no bubble
   from inside one, so this is the belt to that braces. */
.tmp-bubble-body .tmp-term-link {
  text-decoration: none;
  color: inherit;
  pointer-events: none;
}

.tmp-bubble-go {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  margin-top: 0.7rem;
  padding: 0.35rem 0;
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--gold);
  border: 0;
  background: none;
  cursor: pointer;
}

.tmp-bubble-go:hover,
.tmp-bubble-go:focus-visible {
  text-decoration: underline;
  text-underline-offset: 0.25em;
}

.tmp-bubble-shut {
  position: absolute;
  top: 0.35rem;
  right: 0.35rem;
  display: grid;
  place-items: center;
  width: 1.75rem;
  height: 1.75rem;
  color: var(--ink-dim);
  border: 0;
  background: none;
  border-radius: 4px;
  cursor: pointer;
}

.tmp-bubble-shut:hover {
  color: var(--ink);
}

/* ---- What tells the two apart -------------------------------------------- */

/* The glossary bubble: a gold rule along the top edge, no tail. */
.tmp-bubble-gl {
  border-top: 2px solid var(--gold);
  border-radius: 5px 5px 6px 6px;
}

/* The footnote bubble: a tail, pointing back at the number that was pressed.
   Two triangles, one drawing the border and one the fill a pixel inside it, so
   the tail has the same hairline as the box it comes off.

   `--tail` is the distance from the bubble's left edge to the number, written
   by reader.js. It is clamped in the script rather than here, because a bubble
   pushed against the edge of a phone screen can sit a long way from the word
   it belongs to, and a tail hanging off the end of the box would be worse than
   no tail at all. */
.tmp-bubble-fn::before,
.tmp-bubble-fn::after {
  content: '';
  position: absolute;
  left: var(--tail, 1.5rem);
  width: 0;
  height: 0;
  border-inline: 8px solid transparent;
}

.tmp-bubble-fn.is-below::before {
  bottom: 100%;
  border-bottom: 8px solid var(--line);
}

.tmp-bubble-fn.is-below::after {
  bottom: calc(100% - 1px);
  border-bottom: 8px solid var(--sheet);
}

.tmp-bubble-fn.is-above::before {
  top: 100%;
  border-top: 8px solid var(--line);
}

.tmp-bubble-fn.is-above::after {
  top: calc(100% - 1px);
  border-top: 8px solid var(--sheet);
}

/* The marker that opened a bubble is held lit while it is open, so a reader
   looking at a bubble can see which of eleven numbers it came from. */
.tmp-read .tmp-fn-ref a.is-open {
  text-decoration: underline;
  text-underline-offset: 0.25em;
}


/* ---- 5.9 The dictionary --------------------------------------------------

   AAMIR ASKED FOR IT ON 22 AUGUST 2026: a fourth button under the progress
   circle, for a reader who meets an English word they do not know. Press it,
   choose the word, and its meaning is on the screen with an example of it in
   use. server/src/dictionary.js is where the meaning comes from and why that
   service; server/public/reader.js is how a word is picked off the page.

   THREE PIECES ARE DRAWN HERE. The panel, which is wider than the other three
   because it holds sentences rather than rows of controls. The line along the
   foot of the screen that says a word is being chosen, which is the only thing
   telling a reader that a press on the chapter now means something different.
   And the chapter itself while that is true, which changes its cursor and
   stops the browser selecting words as they are pressed. */

/* WIDER THAN THE OTHER THREE, at 24rem against 18rem. Nothing in the settings
   panel is a sentence; everything in this one is. A definition set in an 18rem
   column wraps every four or five words, which is unreadable in the way a
   newspaper column set too narrow is unreadable. */
.js-reader .tmp-panel.is-wide {
  width: min(24rem, calc(100vw - 2.5rem));
}

/* The field, held at the top of the panel body while the answer under it
   scrolls, so looking up a second word never means scrolling back up to find
   where to type it. */
.tmp-word-ask {
  position: sticky;
  top: 0;
  z-index: 1;
  display: flex;
  gap: 0.4rem;
  padding: 0.8rem 1.1rem;
  border-bottom: 1px solid var(--line-soft);
  background: var(--sheet);
}

.tmp-word-in {
  flex: 1;
  min-width: 0;
  padding: 0.5rem 0.7rem;
  border: 1px solid var(--line);
  border-radius: 3px;
  background: var(--ground);
  color: var(--ink);
  font-family: var(--ui);
  font-size: 0.8125rem;
  /* The one thing a search field must not do on a phone: 16px or larger, or
     iOS zooms the whole page in the moment it is focused and leaves the reader
     looking at a magnified panel they then have to pinch back out of. */
  font-size: max(0.8125rem, 16px);
}

.tmp-word-in:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 1px;
}

.tmp-word-go {
  width: 2.25rem;
  flex-shrink: 0;
  display: grid;
  place-items: center;
  padding: 0;
  border: 1px solid var(--gold);
  border-radius: 3px;
  background: var(--gold);
  color: var(--ground);
  cursor: pointer;
  transition: background 0.2s var(--ease-soft), border-color 0.2s var(--ease-soft);
}

.tmp-word-go:hover {
  background: var(--gold-dark);
  border-color: var(--gold-dark);
}

.tmp-word-go:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 2px;
}

/* THE WORD ITSELF IS SET IN THE READING FACE, not in the interface face, which
   is the one place this panel borrows from the paper beside it. It is a word
   out of the chapter and it is set the way the chapter sets it, so the reader
   can see it is the same word. Everything under it is interface. */
.tmp-word-head {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0.5rem;
  padding: 0.9rem 1.1rem 0.5rem;
}

.tmp-word-word {
  font-family: var(--read);
  font-size: 1.25rem;
  font-weight: 600;
  line-height: 1.2;
  color: var(--ink);
}

.tmp-word-sound {
  font-family: var(--ui);
  font-size: 0.75rem;
  color: var(--ink-dim);
}

/* A word looked up in a form the dictionary does not hold, answered under the
   form it does. Saying so is the difference between an answer and a mistake. */
.tmp-word-from {
  width: 100%;
  font-family: var(--ui);
  font-size: 0.6875rem;
  line-height: 1.5;
  color: var(--ink-dim);
}

.tmp-word-part {
  display: block;
  padding: 0.7rem 1.1rem 0.35rem;
  font-size: 0.625rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--gold);
}

.tmp-word-senses {
  margin: 0;
  padding: 0 1.1rem 0.3rem 2rem;
  font-size: 0.8125rem;
  line-height: 1.6;
  color: var(--ink);
}

.tmp-word-senses li {
  margin-bottom: 0.5rem;
}

.tmp-word-senses li::marker {
  color: var(--ink-dim);
  font-size: 0.75rem;
}

/* The example, which is the half of a definition that actually teaches the
   word. Set apart from the sense above it by a rule in the margin rather than
   by italics alone, so it reads as a quotation and not as emphasis. */
.tmp-word-eg {
  display: block;
  margin-top: 0.3rem;
  padding-left: 0.6rem;
  border-left: 2px solid var(--line);
  font-style: italic;
  color: var(--ink-dim);
}

.tmp-word-syn {
  display: block;
  margin-top: 0.3rem;
  font-size: 0.75rem;
  color: var(--ink-dim);
}

/* Wiktionary is shared under a licence that asks to be named, and naming it is
   the least this can do for a service it uses free of charge. */
.tmp-word-src {
  margin: 0;
  padding: 0.8rem 1.1rem 1rem;
  font-size: 0.6875rem;
  line-height: 1.5;
  color: var(--ink-dim);
}

.tmp-word-src a {
  color: var(--ink-dim);
  text-underline-offset: 0.2em;
}

.tmp-word-src a:hover {
  color: var(--ink);
}

/* WHILE THE ANSWER IS ON ITS WAY. A word in a book is not a search result and
   this is not a search page: there is no spinner, only the word being asked
   about and a line saying it is being looked up, which is what is actually
   happening. */
.tmp-word-wait {
  margin: 0;
  padding: 1.2rem 1.1rem;
  text-align: center;
  font-size: 0.75rem;
  color: var(--ink-dim);
}

/* ---- Choosing the word ---------------------------------------------------

   THE MODE HAS TO BE VISIBLE. Pressing the dictionary button changes what a
   press on the chapter does, and a mode nobody can see they are in is a trap:
   the next press on a footnote marker would look up a word instead of opening
   the note, with nothing on the screen to explain it. So the mode says it is
   on, in a sentence, along the foot of the screen where a phone's own bars sit,
   with the way out of it beside the sentence. */
.js-reader .tmp-look-bar {
  position: fixed;
  z-index: 47;
  left: 50%;
  bottom: calc(1.5rem + env(safe-area-inset-bottom, 0px));
  translate: -50% 0;
  display: flex;
  align-items: center;
  gap: 0.7rem;
  max-width: calc(100vw - 2rem);
  padding: 0.45rem 0.45rem 0.45rem 1rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--sheet);
  color: var(--ink);
  font-family: var(--ui);
  font-size: 0.75rem;
  font-weight: 500;
  box-shadow: 0 2px 6px rgba(18, 37, 63, 0.1), 0 10px 28px rgba(18, 37, 63, 0.2);
}

.js-reader .tmp-look-bar[hidden] {
  display: none;
}

.tmp-look-say {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.tmp-look-done {
  flex-shrink: 0;
  padding: 0.35rem 0.8rem;
  border: 0;
  border-radius: 999px;
  background: var(--gold);
  color: var(--ground);
  font-family: var(--ui);
  font-size: 0.75rem;
  font-weight: 600;
  cursor: pointer;
}

.tmp-look-done:hover {
  background: var(--gold-dark);
}

.tmp-look-done:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 2px;
}

/* THE CHAPTER, WHILE A WORD IS BEING CHOSEN. The cursor says a press means
   something, and the text stops being selectable so that pressing a word on a
   phone shows its meaning rather than raising the system's own copy and share
   menu over the top of the answer.

   THE LINKS KEEP THEIRS. A footnote marker and a glossary term are still
   controls; what a press on one does while the dictionary is armed is decided
   in the script, and a cursor promising otherwise would be a lie. */
:root[data-read-look='on'] .tmp-read {
  cursor: cell;
  user-select: none;
  -webkit-user-select: none;
}

:root[data-read-look='on'] .tmp-read a {
  cursor: pointer;
}

/* The word that was looked up, held lit in the chapter until the reader is
   done with it, so that closing the panel does not leave them hunting for
   where they were. The same wash as a bookmark landing, and for the same
   reason: it is a mark on paper and it is temporary. */
.tmp-read .tmp-word-lit {
  border-radius: 3px;
  background: var(--read-accent-soft);
  box-shadow: 0 0 0 2px var(--read-accent-soft);
}

/* --------------------------------------------------------------------------
   6. Print
   --------------------------------------------------------------------------

   A chapter printed from the browser is not the print EDITION, which is a
   different renderer over the same segments and is not built yet. This is the
   ordinary courtesy of a reader pressing print: the site's furniture goes, the
   sheet loses its shadow and its inset, and the words are left on white.
   -------------------------------------------------------------------------- */

@media print {
  /* The trail is a set of links up the site. Paper cannot be pressed, so it
     goes with the navigation rows for exactly the reason they do. */
  .tmp-crumbs,
  .tmp-ch-nav,
  .tmp-ch-where,
  .tmp-rail,
  .tmp-rail-dock,
  .tmp-panel,
  .tmp-scrim,
  .tmp-pop,
  .tmp-toast,
  .tmp-look-bar,
  .tmp-beam,
  .tmp-resume,
  .tmp-bubble,
  .tmp-gl-jump {
    display: none !important;
  }

  /* A chapter printed while focus mode is on would come out with one paragraph
     readable and the rest at a quarter of the ink, or with two washes of paper
     laid over most of it. The setting is about a screen being scrolled; paper
     is not scrolled. The beam goes with the furniture above; the paragraph
     dimming is opacity on the blocks themselves, so it is put back here. */
  :root[data-read-focus='on'] .tmp-read > * {
    opacity: 1;
  }

  /* And it prints at the size the book is set at rather than at whatever the
     reader has the screen turned up to. A type scale is a property of a
     screen, and a page coming out of the printer in 29pt because somebody had
     chosen extra large last week would be a surprise at the paper tray. */
  .tmp-read {
    font-size: var(--read-size);
    line-height: 1.75;
  }

  .tmp-chapter,
  .tmp-sheet {
    background: #fff;
  }

  .tmp-sheet {
    max-width: none;
    margin: 0;
    padding: 0;
    box-shadow: none;
    border-radius: 0;
  }

  .tmp-read {
    max-width: none;
    color: #000;
  }

  .tmp-ch-title,
  .tmp-ch-book {
    color: #000;
  }

  /* A footnote marker means nothing on paper if it is a link to a place the
     reader cannot press, so it is left as the number it already is. Notes
     print at the end of the chapter, where they already are. */
  .tmp-fn-ref a,
  .tmp-fn-back {
    color: #000;
    text-decoration: none;
  }

  /* THE GLOSSARY MARK COMES OFF ON PAPER, for exactly that reason. A dotted
     line under a word invites a press, and a printed page cannot be pressed;
     left in, it reads as an underline somebody forgot to take out. The glossary
     itself still prints, at the back of the book where it belongs, and its
     letter row goes with the furniture above because it is a set of jump
     links. */
  .tmp-read .tmp-term-link {
    color: #000;
    text-decoration: none;
  }

  .tmp-gl-initial.tmp-h,
  .tmp-gl-word {
    color: #000;
  }
}
