/* ============================================================
   Dark fairy tales — main stylesheet
   ============================================================ */

/* Display face from the Charity Bar campaign */
@font-face {
    font-family: 'SC Jurere';
    src: url('../fonts/SCJurere-Regular.eot');
    src: url('../fonts/SCJurere-Regular.eot?#iefix') format('embedded-opentype'),
         url('../fonts/SCJurere-Regular.woff2') format('woff2'),
         url('../fonts/SCJurere-Regular.woff') format('woff'),
         url('../fonts/SCJurere-Regular.ttf') format('truetype'),
         url('../fonts/SCJurere-Regular.svg#SCJurere-Regular') format('svg');
    font-weight: normal;
    font-style: normal;
    font-display: swap;
}

:root {
    --color-accent: #cc173a;
    --color-accent-rgb: 204, 23, 58;
    --color-bg: #0d0709;
    --color-text: #e8e0da;
    --color-text-muted: #bdbcc9;
    --color-text-muted-rgb: 189, 188, 201;
    /* The tale menu: its own background, and a fixed width that
       holds until the screen is no wider than the panel itself. */
    --color-menu-bg: #181b24;
    --menu-width: 27rem;
    /* The page a tale is read on */
    --color-reader-bg: #eaeaec;
    /* Outer frame, right on the screen edge */
    --frame-width: 5px;
    /* Distance between the outer and inner frames */
    --frame-gap: 7px;
    /* The inner frame carries the ornamental corners.
       The line in corner.svg is 1/60 of its width, so the
       thickness is derived from the corner size. */
    --corner-size: 240px;
    --inner-width: calc(var(--corner-size) / 60);
    --inner-inset: calc(var(--frame-width) + var(--frame-gap));
    /* Corner ornament on the cards — scales with the viewport so it
       stays in proportion as the three columns narrow */
    --card-corner: clamp(52px, 7.5vw, 108px);
    --card-corner-inset: clamp(6px, 1vw, 14px);
    /* The frame line is exactly as thick as the ornament's arm */
    --card-line: calc(var(--card-corner) / 60);
    /* Noto Serif — successor to Droid Serif, same designer */
    --font-serif: 'Noto Serif', 'Droid Serif', 'Georgia', serif;
    --font-display: 'SC Jurere', 'Noto Serif', 'Georgia', serif;
}

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

html {
    scroll-behavior: smooth;
}

/* No link on the site is underlined — they are marked by colour */
a {
    text-decoration: none;
}

body {
    font-family: var(--font-serif);
    color: var(--color-text);
    background-color: var(--color-bg);
    /* Fallback background if the video fails to load */
    background-image: url('../images/bg.png');
    background-size: cover;
    background-position: center;
    background-attachment: fixed;
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    opacity: 0;
    transition: opacity 0.9s ease;
}

/* ------------------------------------------------------------
   Background video
   ------------------------------------------------------------ */

.bg-video-wrap {
    position: fixed;
    inset: 0;
    z-index: -1;
    overflow: hidden;
    /* A frame of the same scene, behind the video while it loads and
       instead of it on a phone */
    background: url('../images/bg-v14.jpg') no-repeat center / cover;
}

.bg-video {
    width: 100%;
    height: 100%;
    object-fit: cover;
    /* Promote the video to its own GPU layer so it is not
       repainted while scrolling — otherwise the motion stutters. */
    transform: translateZ(0);
    will-change: transform;
    /* Decoration, not a player: taps go through it to the page */
    pointer-events: none;
}

/* The lilies live in the left third of the frame. A wide clip cropped
   to a phone's portrait shape keeps only a narrow middle strip, which
   lands on the empty path — so on narrow screens the crop is pulled
   left until the flowers, the part that actually moves, are in shot. */
@media (max-width: 60rem) {
    .bg-video {
        object-position: 22% center;
    }

    .bg-video-wrap {
        background-position: 22% center;
    }
}

/* A phone sees about a quarter of the clip's width, so the whole
   cluster only just fits — this is as far right as it can go with
   every bloom still in frame. */
@media (max-width: 40rem) {
    .bg-video {
        object-position: 18% center;
    }

    .bg-video-wrap {
        background-position: 18% center;
    }
}

/* No video on a touch screen — the still shows through instead */
.bg-video:not([src]) {
    display: none;
}

/* iOS Safari draws its own start button over a video it will not
   autoplay (Low Power Mode, or a server that ignores Range requests),
   and both WebKit and Blink can show a control strip. None of it
   belongs on a background. */
.bg-video::-webkit-media-controls,
.bg-video::-webkit-media-controls-panel,
.bg-video::-webkit-media-controls-panel-container,
.bg-video::-webkit-media-controls-overlay-play-button,
.bg-video::-webkit-media-controls-start-playback-button {
    display: none !important;
    -webkit-appearance: none;
    appearance: none;
    opacity: 0;
}

/* Darkening gradient over the video */
.bg-video-wrap::after {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(rgba(10, 6, 8, 0.2), rgba(10, 6, 8, 0.45));
}

body.is-loaded {
    opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
    body {
        opacity: 1;
        transition: none;
    }
}

/* ============================================================
   Permanent frame around the page
   ============================================================ */

/* Outer frame — solid line along the screen edge */
.site-frame {
    position: fixed;
    inset: 0;
    border: var(--frame-width) solid var(--color-accent);
    pointer-events: none;
    z-index: 990;
}

/* Inner frame — the straight lines between the ornamental corners */
.site-frame::before {
    content: '';
    position: absolute;
    inset: var(--frame-gap);
    border: var(--inner-width) solid var(--color-accent);
}

/* The inner frame's ornamental corners come from
   images/corner.svg. The file is drawn for the top-left corner;
   the other three are mirrored copies. We use a mask so they
   follow the accent colour rather than the colour baked into
   the SVG. */
.frame-corner {
    position: fixed;
    width: var(--corner-size);
    /* SVG aspect ratio: 243.79 / 240.09 */
    height: calc(var(--corner-size) * 1.01541);
    background-color: var(--color-accent);
    -webkit-mask: url('../images/corner.svg') no-repeat center / 100% 100%;
    mask: url('../images/corner.svg') no-repeat center / 100% 100%;
    pointer-events: none;
    z-index: 991;
}

.frame-corner--tl { top: var(--inner-inset); left: var(--inner-inset); }
.frame-corner--tr { top: var(--inner-inset); right: var(--inner-inset); transform: scaleX(-1); }
.frame-corner--br { bottom: var(--inner-inset); right: var(--inner-inset); transform: scale(-1, -1); }
.frame-corner--bl { bottom: var(--inner-inset); left: var(--inner-inset); transform: scaleY(-1); }

/* ============================================================
   Header and navigation
   ============================================================ */

/* The title appears only after scrolling — a red block exactly
   as wide as its text, centred horizontally, starting where the
   second (inner) frame ends. */
.site-header {
    position: fixed;
    top: calc(var(--inner-inset) + var(--inner-width));
    left: 50%;
    display: inline-flex;
    align-items: center;
    width: max-content;
    max-width: calc(100% - 2 * (var(--inner-inset) + var(--inner-width)));
    /* Uppercase text has empty descender space under it, so the ink
       sits high in its line box: a little padding above, more below,
       and the two gaps come out looking equal. Measured, not guessed. */
    padding: 0.25rem 1.9rem 0.7rem;
    background: var(--color-accent);
    opacity: 0;
    transform: translate(-50%, -12px);
    pointer-events: none;
    transition: opacity 0.4s ease, transform 0.4s ease;
    /* above the corner ornament (991) so it is not covered by it */
    z-index: 992;
}

.site-header.is-visible {
    opacity: 1;
    transform: translate(-50%, 0);
    pointer-events: auto;
}

/* Ornaments left and right of the title. They appear together
   with it (inheriting its opacity). decoration.svg is the
   horizontal arm of the corner ornament — same width and same
   line thickness, so it lands exactly on the inner frame. Hence
   the negative top offset: the block starts --inner-width lower
   than the line itself. */
.site-header::before,
.site-header::after {
    content: '';
    position: absolute;
    top: calc(-1 * var(--inner-width));
    width: var(--corner-size);
    /* SVG aspect ratio: 66.21 / 243.79 */
    height: calc(var(--corner-size) * 0.27158);
    background-color: var(--color-accent);
    -webkit-mask: url('../images/decoration.svg') no-repeat center / 100% 100%;
    mask: url('../images/decoration.svg') no-repeat center / 100% 100%;
    pointer-events: none;
}

.site-header::before {
    right: calc(100% + 0.6rem);
}

/* Same ornament on the right, mirrored horizontally */
.site-header::after {
    left: calc(100% + 0.6rem);
    transform: scaleX(-1);
}

.site-logo {
    font-size: 0.92rem;
    font-weight: 600;
    letter-spacing: 0.28em;
    text-transform: uppercase;
    color: var(--color-text);
    /* Typewriter: the text is revealed letter by letter.
       Revealed with clip-path rather than width — the block is
       exactly as wide as its text and the ornaments are pinned to
       its edges, so animating the width would shift them.
       The step count comes from JS, based on the caption length. */
    clip-path: inset(0 100% 0 0);
    /* on hide it resets instantly, with no reverse "un-typing" */
    transition: none;
}

.site-header.is-visible .site-logo {
    clip-path: inset(0 0 0 0);
    /* starts only once the block has faded in */
    transition: clip-path 0.9s steps(var(--type-steps, 14), end) 0.3s;
}

@media (prefers-reduced-motion: reduce) {
    .site-logo {
        clip-path: none;
    }

    .site-header.is-visible .site-logo {
        transition: none;
    }
}

/* ============================================================
   Main content — home page
   ============================================================ */

.site-main {
    flex: 1;
}

.hero-section {
    position: relative;
    min-height: 78vh;
    display: flex;
    align-items: center;
    justify-content: center;
    /* more on top: the frame eats into the gap, so the title
       looked closer to the edge than the paragraph was to the
       cards */
    padding: 4.5rem 3rem 2rem;
    overflow: hidden;
}

.hero {
    position: relative;
    width: 100%;
    max-width: 90%;
    text-align: center;
    z-index: 3;
}

/* ------------------------------------------------------------
   Living atmosphere: mist and embers
   ------------------------------------------------------------ */

/* Pinned to the viewport so it covers the whole page, not just
   the first screen. Sits ABOVE the content (cards included) but
   below the frame and the side buttons. Ignores the mouse. */
.hero-atmosphere {
    position: fixed;
    inset: 0;
    pointer-events: none;
    z-index: 900;
}

/* Embers — small glowing specks drifting upward.
   Created by JS with random positions and speeds. */
.embers {
    position: absolute;
    inset: 0;
}

.ember {
    position: absolute;
    bottom: -12px;
    border-radius: 50%;
    background: radial-gradient(circle, #ffc79a 0%, #cc173a 55%, transparent 72%);
    opacity: 0;
    animation: ember-rise linear infinite;
}

@keyframes ember-rise {
    0% {
        transform: translate(0, 0) scale(1);
        opacity: 0;
    }
    8% {
        opacity: 0.85;
    }
    55% {
        opacity: 0.45;
    }
    100% {
        /* they cross the whole screen, not just the hero's height */
        transform: translate(var(--drift, 0px), -102vh) scale(0.4);
        opacity: 0;
    }
}

@media (prefers-reduced-motion: reduce) {
    .ember {
        display: none;
    }
}

.hero-overline {
    font-size: 1rem;
    letter-spacing: 0.35em;
    text-transform: uppercase;
    color: var(--color-accent);
    margin-bottom: 1.2rem;
}

.hero-title {
    font-family: var(--font-display);
    font-size: clamp(3.2rem, 12vw, 12rem);
    font-weight: 400;
    line-height: 1;
    letter-spacing: 0.03em;
    color: var(--color-text-muted);
    text-shadow: 0 4px 30px rgba(0, 0, 0, 0.8);
    /* The two words and the lily between them, vertically centred */
    display: flex;
    align-items: center;
    justify-content: center;
    flex-wrap: wrap;
}

/* Letters arrive one by one: odd from below, even from above.
   The split into letters is done by JS — if it never runs, the
   words stay visible with the inherited shadow. */
.hero-title__letter {
    display: inline-block;
    opacity: 0;
    translate: 0 var(--from, 1.5rem);
    /* the shadow is inherited from .hero-title */
    transition: opacity 0.5s ease var(--ld, 0s),
                translate 0.6s cubic-bezier(0.2, 0.8, 0.2, 1) var(--ld, 0s);
}

.hero-title.is-in .hero-title__letter {
    opacity: 1;
    translate: 0 0;
}

/* The letters flanking the lily use the muted colour, like the
   rest — we keep them marked so giving them another colour stays
   a one-line change. */
.hero-title__letter--accent {
    color: var(--color-text-muted);
}

/* A few random letters are clipped over the ornament: a solid
   layer in the muted colour sits underneath so the glyph does not
   thin out to transparency over the video, while the ornament
   reads as a pattern across it. */
.hero-title__letter--pattern {
    background-image:
        url('../images/corner.svg'),
        linear-gradient(var(--color-text-muted), var(--color-text-muted));
    background-size: 0.3em 0.3em, 100% 100%;
    background-repeat: repeat, no-repeat;
    background-position: center, center;
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
    -webkit-text-fill-color: transparent;
    /* text-shadow paints ON TOP of the letter's background, not
       under it, and darkens the pattern from within — so drop it here */
    text-shadow: none;
}

@media (prefers-reduced-motion: reduce) {
    .hero-title__letter {
        opacity: 1;
        translate: 0 0;
        transition: none;
    }
}

/* The lily is a little taller than the letters and bites into
   both words via the negative margins. Sized in em so it tracks
   the title's clamp(). */
.hero-title__lily {
    width: 1.5em;
    height: 1.5em;
    margin: 0 -0.18em;
    object-fit: contain;
    /* above the letters so it covers them, not the other way round */
    position: relative;
    z-index: 1;
    pointer-events: none;
}

.hero-text {
    font-size: 12px;
    letter-spacing: 3px;
    text-transform: uppercase;
    line-height: 2;
    color: var(--color-text-muted);
    margin-bottom: 2.5rem;
}

.hero-actions {
    display: flex;
    gap: 1.2rem;
    justify-content: center;
    flex-wrap: wrap;
}

.btn {
    display: inline-block;
    padding: 0.85rem 2.2rem;
    font-family: var(--font-serif);
    font-size: 1.05rem;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    text-decoration: none;
    border: 1px solid var(--color-accent);
    transition: background 0.3s ease, color 0.3s ease;
}

.btn--primary {
    background: var(--color-accent);
    color: #14090a;
}

.btn--primary:hover {
    background: transparent;
    color: var(--color-accent);
}

.btn--ghost {
    background: transparent;
    color: var(--color-accent);
}

.btn--ghost:hover {
    background: var(--color-accent);
    color: #14090a;
}

/* ============================================================
   Search
   ============================================================ */

/* Search lives in the right rail: a circle with a magnifier, and
   the field expands to its left. Smaller than the sound button. */
.search-control {
    position: relative;
    display: flex;
    align-items: center;
}

.search-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 56px;
    height: 56px;
    background: transparent;
    border: 2px solid var(--color-accent);
    border-radius: 50%;
    cursor: pointer;
    transition: transform 0.3s ease;
}

.search-toggle:hover {
    transform: scale(1.06);
}

.search-toggle__icon {
    width: 26px;
    height: 26px;
    fill: none;
    stroke: var(--color-accent);
}

.search-input {
    position: absolute;
    top: 50%;
    right: calc(100% + 0.7rem);
    transform: translateY(-50%);
    width: 0;
    padding: 0.7rem 0;
    opacity: 0;
    pointer-events: none;
    font-family: var(--font-serif);
    font-size: 1.05rem;
    color: var(--color-text);
    background: rgba(13, 7, 9, 0.85);
    border: 1px solid rgba(var(--color-accent-rgb), 0.5);
    outline: none;
    text-align: left;
    transition: width 0.35s ease, padding 0.35s ease,
                opacity 0.3s ease, border-color 0.3s ease;
}

.search-control.is-open .search-input {
    width: 18rem;
    padding: 0.7rem 1rem;
    opacity: 1;
    pointer-events: auto;
}

.search-input::placeholder {
    color: var(--color-text-muted);
    font-style: italic;
}

.search-input:focus {
    border-color: var(--color-accent);
}

/* ============================================================
   The tales
   ============================================================ */

.tales-section {
    padding: 0 3rem 3rem;
    max-width: 72rem;
    margin: 0 auto;
}

/* Three columns for as long as they fit — the cards get narrower
   rather than the count dropping. Two columns only on phones. */
.tales-grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: clamp(0.7rem, 1.8vw, 2rem);
}

/* The card is a solid dark panel with no border and no text —
   just an ornament in one of the four corners and the caption.
   The corner is picked at random by JS. */
/* --py is set from JS: each column moves at a slightly different
   speed while scrolling. It goes through a custom property so it
   does not fight the hover lift. */
.tale-card {
    position: relative;
    aspect-ratio: 2 / 3;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: clamp(0.5rem, 1.4vw, 1.5rem);
    background: var(--color-bg);
    border: none;
    cursor: pointer;
    overflow: hidden;
    transform: translate3d(0, var(--py, 0px), 0);
    will-change: transform;
    transition: none;
}

@media (prefers-reduced-motion: reduce) {
    .tale-card {
        transform: none;
    }
}

/* ------------------------------------------------------------
   Hover frame: an ornament in all four corners and a line
   between them — like the page frame, only scaled down.
   The line draws itself around the card and the corners then
   appear one after another.
   ------------------------------------------------------------ */
/* The frame is always present — only the corner chosen for that
   card is visible. On hover the line draws out from it, travels
   around the card, and only then do the other three corners fade
   in. The delays come from JS via --d and --cd and apply only on
   hover, so nothing replays backwards on mouse-out. */
.tale-card__frame {
    position: absolute;
    inset: var(--card-corner-inset);
    pointer-events: none;
    /* the corners slide inward and emerge from behind the edge */
    overflow: hidden;
}

/* The lines land exactly on the ornament's arm: same thickness
   (1/60 of it) and same axis, so they read as its continuation. */
.tale-card__line {
    position: absolute;
    background: var(--color-accent);
    transition: transform 0.14s linear;
}

.tale-card__line--t {
    top: 0;
    left: 0;
    width: 100%;
    height: var(--card-line);
    transform: scaleX(0);
    transform-origin: left center;
}

.tale-card__line--r {
    top: 0;
    right: 0;
    width: var(--card-line);
    height: 100%;
    transform: scaleY(0);
    transform-origin: center top;
}

.tale-card__line--b {
    bottom: 0;
    right: 0;
    width: 100%;
    height: var(--card-line);
    transform: scaleX(0);
    transform-origin: right center;
}

.tale-card__line--l {
    bottom: 0;
    left: 0;
    width: var(--card-line);
    height: 100%;
    transform: scaleY(0);
    transform-origin: center bottom;
}

.tale-card:hover .tale-card__line--t,
.tale-card:focus-visible .tale-card__line--t,
.tale-card:hover .tale-card__line--b,
.tale-card:focus-visible .tale-card__line--b {
    transform: scaleX(1);
    transition-delay: var(--d, 0s);
}

.tale-card:hover .tale-card__line--r,
.tale-card:focus-visible .tale-card__line--r,
.tale-card:hover .tale-card__line--l,
.tale-card:focus-visible .tale-card__line--l {
    transform: scaleY(1);
    transition-delay: var(--d, 0s);
}

/* All corners share one size — at rest and on hover alike */
.tale-card__fc {
    position: absolute;
    width: var(--card-corner);
    /* SVG aspect ratio: 243.79 / 240.09 */
    height: calc(var(--card-corner) * 1.01541);
    background-color: var(--color-accent);
    -webkit-mask: url('../images/corner.svg') no-repeat center / 100% 100%;
    mask: url('../images/corner.svg') no-repeat center / 100% 100%;
    opacity: 0;
    transition: opacity 0.28s ease,
                translate 0.38s cubic-bezier(0.2, 0.8, 0.2, 1);
}

/* The mirroring lives in transform and the slide in translate,
   because they are separate properties and do not fight. translate
   is applied before transform, so the mirror never reverses the
   slide direction. */
.tale-card__fc--tl { top: 0; left: 0; translate: -1.2rem -1.2rem; }
.tale-card__fc--tr { top: 0; right: 0; transform: scaleX(-1); translate: 1.2rem -1.2rem; }
.tale-card__fc--br { bottom: 0; right: 0; transform: scale(-1, -1); translate: 1.2rem 1.2rem; }
.tale-card__fc--bl { bottom: 0; left: 0; transform: scaleY(-1); translate: -1.2rem 1.2rem; }

/* The corner the line starts from stays put and is always
   visible. Declared after the rules above so it overrides them. */
.tale-card__fc--start {
    opacity: 1;
    translate: 0 0;
}

.tale-card:hover .tale-card__fc,
.tale-card:focus-visible .tale-card__fc {
    opacity: 1;
    translate: 0 0;
    transition-delay: var(--cd, 0s);
}

/* A card that has been opened looks exactly like one that has not:
   the ornament, the drawn rectangle and the label all stay at full
   strength. Which tales have been read still decides which one comes
   up next — it just no longer shows on the card. */

.tale-card__label {
    font-size: clamp(0.66rem, 1.45vw, 1.15rem);
    font-weight: 600;
    letter-spacing: clamp(0.06em, 0.35vw, 0.22em);
    line-height: 1.6;
    text-align: center;
    text-transform: uppercase;
    color: var(--color-accent);
    transition: color 0.3s ease;
}


.tales-status {
    text-align: center;
    padding: 2rem 0 0;
    font-size: 1.1rem;
    font-style: italic;
    color: var(--color-text-muted);
}

/* ============================================================
   Reading a tale
   ============================================================ */

/* In reading mode the menu is part of the layout rather than an
   overlay: it stays open, and the content takes what is left. */
body.is-reading .tale-menu {
    transform: none;
    visibility: visible;
    /* Visible from the first frame, so the panel is seen sliding in
       rather than appearing once it has arrived */
    transition: transform 0.45s cubic-bezier(0.2, 0.8, 0.2, 1),
                visibility 0s;
}

body.is-reading .site-main {
    margin-left: var(--menu-width);
}

/* The trigger is pointless while the menu is pinned open — but it
   comes back once the reader collapses the menu away. */
body.is-reading .menu-toggle {
    display: none;
}

body.is-reading.menu-collapsed .menu-toggle {
    display: inline-flex;
}

/* Collapsed: the panel slides away and the reader takes the width */
body.is-reading.menu-collapsed .tale-menu {
    transform: translateX(-100%);
    visibility: hidden;
    /* Hidden only once it is off screen */
    transition: transform 0.45s cubic-bezier(0.2, 0.8, 0.2, 1),
                visibility 0s linear 0.45s;
}

body.is-reading.menu-collapsed .site-main {
    margin-left: 0;
}

/* The X is available wherever the panel is: over the overlay, and
   over the pinned column while reading. */
.tale-menu.is-open ~ .menu-close,
body.is-reading:not(.menu-collapsed) .menu-close {
    display: inline-flex;
}

/* The site title belongs to the home page; while a tale is open the
   tale's own heading is the title on screen. */
body.is-reading .site-header {
    display: none;
}

/* Paper and ink go through variables so night mode swaps both, and
   everything inside — bar, panel, rules — follows automatically. */
.reader {
    --paper: var(--color-reader-bg);
    --ink: var(--color-bg);
    --reader-size: 18px;
    min-height: 100vh;
    padding: 0 4rem calc(var(--inner-inset) + var(--inner-width) + 4rem);
    background: var(--paper);
    color: var(--ink);
    /* Deters casual selecting and copying of the tales. Note this is
       cosmetic only — the text is still in the page source. Use
       user-select rather than pointer-events, which would also kill
       the back link and scrolling. */
    -webkit-user-select: none;
    user-select: none;
}

.reader__inner {
    max-width: 600px;
    margin: 0 auto;
}

/* Sticky rather than fixed: it keeps its place in the column, so no
   extra top padding has to be guessed, and it needs no width of its
   own. The background hides the prose passing underneath. */
.reader__bar {
    position: sticky;
    top: 0;
    z-index: 5;
    padding-top: calc(var(--inner-inset) + var(--inner-width) + 1.6rem);
    padding-bottom: 1.2rem;
    margin-bottom: 1.5rem;
    background: var(--paper);
    /* the link on one side, the settings button on the other */
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 1rem;
}

/* Plain sentence case, no underline, arrow leading the text */
.reader__back {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 1rem;
    color: var(--color-accent);
    text-decoration: none;
}

.reader__back__arrow {
    width: 18px;
    height: 18px;
    flex: none;
    fill: none;
    stroke: currentColor;
    transition: transform 0.25s ease;
}

.reader__back:hover .reader__back__arrow {
    transform: translateX(-3px);
}

.reader__title {
    font-family: var(--font-display);
    font-size: clamp(2.6rem, 6vw, 4rem);
    font-weight: 400;
    line-height: 1.05;
    /* SC Jurere carries very wide spaces; pull the words together
       here only, leaving the hero title as it is. */
    word-spacing: -0.22em;
    color: var(--color-accent);
}

.reader__author {
    margin-top: 0.75rem;
    margin-bottom: 2.5rem;
    font-style: italic;
    font-size: 1.05rem;
    color: var(--ink);
}

.reader__body {
    font-size: var(--reader-size);
    line-height: 1.8;
    color: var(--ink);
}

/* Indented first lines, the way prose is set in print. The opening
   paragraph is left flush, as is conventional. */
.reader__body p + p {
    text-indent: 2rem;
}

/* ------------------------------------------------------------
   Reading settings
   ------------------------------------------------------------ */

.reader__tools-toggle {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    padding: 0.35rem 0.8rem;
    font-family: inherit;
    font-size: 0.9rem;
    color: var(--color-accent);
    background: transparent;
    border: 2px solid var(--color-accent);
    cursor: pointer;
    transition: border-color 0.25s ease;
}

.reader__tools-toggle:hover,
.reader__tools-toggle[aria-expanded="true"] {
    border-color: var(--color-accent);
}

.reader__tools-icon {
    width: 17px;
    height: 17px;
    fill: none;
    stroke: currentColor;
}

/* Sits inside the sticky bar, so the settings stay reachable while
   reading rather than scrolling away with the top of the tale. */
.reader__tools {
    flex: 1 0 100%;
    padding: 1rem 1.1rem 0.6rem;
    border: 2px solid var(--ink);
    background: var(--paper);
}

.reader__tools[hidden] {
    display: none;
}

.reader__tool {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.5rem 0;
}

.reader__tool-name {
    font-size: 0.95rem;
    color: var(--ink);
}

.reader__tool-set {
    display: inline-flex;
    gap: 0.4rem;
}

.reader__chip {
    min-width: 2.2rem;
    padding: 0.25rem 0.5rem;
    font-family: inherit;
    font-size: 0.95rem;
    color: var(--color-accent);
    background: transparent;
    border: 2px solid var(--ink);
    cursor: pointer;
}

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

/* A plain two-state switch; aria-pressed carries the real state */
.reader__switch {
    position: relative;
    width: 44px;
    height: 24px;
    padding: 0;
    background: transparent;
    border: 2px solid var(--ink);
    border-radius: 999px;
    cursor: pointer;
    transition: background 0.25s ease, border-color 0.25s ease;
}

.reader__switch-dot {
    position: absolute;
    top: 50%;
    left: 2px;
    width: 16px;
    height: 16px;
    background: var(--color-accent);
    border-radius: 50%;
    transform: translateY(-50%);
    transition: transform 0.25s ease, background 0.25s ease;
}

.reader__switch[aria-pressed="true"] {
    background: var(--color-accent);
    border-color: var(--color-accent);
}

.reader__switch[aria-pressed="true"] .reader__switch-dot {
    background: var(--paper);
    transform: translate(20px, -50%);
}

.reader__tools-close {
    display: block;
    width: 100%;
    margin-top: 0.4rem;
    padding: 0.6rem 0;
    font-family: inherit;
    font-size: 0.9rem;
    color: var(--color-accent);
    background: transparent;
    border: none;
    border-top: 2px solid var(--ink);
    cursor: pointer;
}

/* Night: only the two variables change, everything else follows */
.reader--night {
    --paper: #14161c;
    --ink: #e7e7ec;
}

/* Andika is SIL's literacy typeface — wide apertures and letterforms
   that cannot be mistaken for one another — and one of the very few
   with Cyrillic (OpenDyslexic, Lexend and Atkinson Hyperlegible have
   none). The spacing carries the rest: tracking, words and lines
   further apart. Andika is already roomy, so this stays light. */
.reader--dyslexic .reader__body,
.reader--dyslexic .reader__author {
    font-family: 'Andika', 'Noto Sans', 'Segoe UI', sans-serif;
    letter-spacing: 0.02em;
    word-spacing: 0.12em;
    line-height: 1.95;
}

/* The author's spelling is left as written, and the reader is told so
   before the first line rather than after the last. */
.reader__note {
    margin-bottom: 2.5rem;
    font-size: 0.9rem;
    font-style: italic;
    font-weight: 700;
    line-height: 1.6;
    color: var(--ink);
}

/* Bionic: JS wraps the opening letters of each word in <b> */
.reader--bionic .reader__body b {
    font-weight: 700;
}

.reader__body b {
    font-weight: inherit;
}

/* A change of scene: centred, with air either side of it.
   Scoped under .reader__body so it outranks the `p + p` rules above,
   which would otherwise reimpose the paragraph margin and indent. */
.reader__body .reader__scene {
    margin: 3.5rem 0;
    text-align: center;
    letter-spacing: 0.6em;
    /* the letter-spacing would otherwise push it off centre */
    text-indent: 0.6em;
    color: var(--color-accent);
}

/* The paragraph opening a new scene starts flush, like the first one */
.reader__body .reader__scene + p {
    text-indent: 0;
}

.reader__body p + p {
    margin-top: 0.35rem;
}

/* ============================================================
   Campaign and contact
   ============================================================ */

/* Solid dark band across the full width. The top margin is
   larger than the inner padding to separate it from the cards. */
/* Dark rule across the full width, exactly as thick as the outer
   frame. It carries the ornaments above it and stands off the band
   below — both gaps match the distance between the page's two
   frames. */
.page-hem {
    position: relative;
    height: var(--frame-width);
    margin-top: 13rem;
    margin-bottom: var(--frame-gap);
    background: var(--color-bg);
}

/* The two halves of the ornament meet exactly at the centre: the
   left one as drawn, the right one mirrored. Both are flipped
   vertically too, so their line sits at the bottom — where the
   rule is. */
.page-hem::before,
.page-hem::after {
    content: '';
    position: absolute;
    bottom: calc(100% + var(--frame-gap));
    width: var(--corner-size);
    /* SVG aspect ratio: 66.21 / 243.79 */
    height: calc(var(--corner-size) * 0.27158);
    background-color: var(--color-bg);
    -webkit-mask: url('../images/decoration.svg') no-repeat center / 100% 100%;
    mask: url('../images/decoration.svg') no-repeat center / 100% 100%;
    pointer-events: none;
}

/* The halves overlap by exactly one line width (1/60 of the
   ornament, same as the inner frame) so no double stroke shows
   up in the middle. */
.page-hem::before {
    right: calc(50% - var(--inner-width) / 2);
    transform: scaleY(-1);
}

.page-hem::after {
    left: calc(50% - var(--inner-width) / 2);
    transform: scale(-1, -1);
}

/* The gap down to the footer lives here, not in the footer */
.contact-section {
    padding: 120px 3rem 110px;
    background: var(--color-bg);
}

/* Two columns: text on the left, the right one left empty for now */
/* The wide gap only applies once there is room for it — see the
   media queries at the end of the file, where it narrows and the
   two columns eventually stack. */
.contact-inner {
    max-width: 74rem;
    margin: 0 auto;
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 16rem;
    align-items: start;
    text-align: left;
}

.contact-title {
    font-size: 1.6rem;
    font-weight: 600;
    letter-spacing: 0.15em;
    text-transform: uppercase;
    color: var(--color-accent);
    margin-bottom: 1.5rem;
}

.contact-text {
    font-size: 1.02rem;
    line-height: 1.7;
    color: var(--color-text-muted);
    margin-bottom: 1.5rem;
}

.contact-line {
    font-size: 1rem;
    color: var(--color-text-muted);
}

/* Second-level heading in the campaign column, smaller than the
   section title and set off from the block above it. */
.contact-subtitle {
    font-size: 1.15rem;
    font-weight: 600;
    letter-spacing: 0.15em;
    text-transform: uppercase;
    color: var(--color-accent);
    margin-top: 2.5rem;
    margin-bottom: 1rem;
}

/* No underlines anywhere on the site — links are marked by colour,
   and lift slightly on hover. */
.contact-main a,
.contact-line a {
    color: var(--color-accent);
    text-decoration: none;
    transition: opacity 0.25s ease;
}

.contact-main a:hover,
.contact-line a:hover {
    opacity: 0.72;
}

/* ------------------------------------------------------------
   Newsletter sign-up — right column
   ------------------------------------------------------------ */

/* The column is kept to the width of the email field, so the book,
   the text and the field all share one measure. */
.contact-aside {
    max-width: 22rem;
}

/* The mockup carries its own transparency and shadow, so it needs
   no frame or background of its own. */
.book-cover {
    display: block;
    width: 100%;
    max-width: 320px;
    height: auto;
    /* centred within its column */
    margin: 0 auto 1.5rem;
}

.subscribe-text {
    font-size: 1.02rem;
    line-height: 1.7;
    color: var(--color-text-muted);
    margin-bottom: 1.25rem;
}

/* The label is for screen readers; on screen the placeholder shows */
.subscribe__label {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

/* The button sits INSIDE the field, so the row is positioned
   relatively and the input reserves room via padding-right */
.subscribe__row {
    position: relative;
    display: block;
    max-width: 22rem;
}

.subscribe__input {
    width: 100%;
    padding: 0.85rem 3.6rem 0.85rem 1.1rem;
    font-family: var(--font-serif);
    font-size: 1rem;
    color: var(--color-text);
    background: rgba(var(--color-text-muted-rgb), 0.06);
    border: 2px solid var(--color-accent);
    outline: none;
    transition: border-color 0.3s ease;
}

.subscribe__input::placeholder {
    color: var(--color-text-muted);
    font-style: italic;
    opacity: 0.7;
}

.subscribe__input:focus {
    border-color: var(--color-text-muted);
}

/* The centring translate has to be repeated in the hover rule,
   otherwise scaling would drop the button out of the field. */
.subscribe__send {
    position: absolute;
    top: 50%;
    right: 0.5rem;
    transform: translateY(-50%);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    background: var(--color-accent);
    border: none;
    border-radius: 50%;
    cursor: pointer;
    transition: transform 0.25s ease;
}

.subscribe__send:hover,
.subscribe__send:focus-visible {
    transform: translateY(-50%) scale(1.15);
}

.subscribe__send[disabled] {
    opacity: 0.5;
    cursor: default;
    transform: translateY(-50%);
}

.subscribe__icon {
    width: 17px;
    height: 17px;
    fill: none;
    stroke: #fff;
}

.subscribe__note {
    margin-top: 0.75rem;
    font-size: 0.92rem;
    line-height: 1.5;
    min-height: 1.4em;
    color: var(--color-text-muted);
}

.subscribe__note--error {
    color: var(--color-accent);
}

/* ============================================================
   Music button
   ============================================================ */

/* The right rail: sound on top, search below. The two buttons
   are centred vertically as a group and stand 2rem off the
   frame's inner line. */
.side-controls {
    position: fixed;
    top: 50%;
    right: calc(var(--inner-inset) + var(--inner-width) + 2rem);
    transform: translateY(-50%);
    z-index: 995;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1.1rem;
}

/* Round button — outline and icon only, no fill and no shadow */
.sound-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 84px;
    height: 84px;
    background: transparent;
    border: 2px solid var(--color-accent);
    border-radius: 50%;
    cursor: pointer;
    transition: transform 0.3s ease;
}

.sound-toggle:hover {
    transform: scale(1.06);
}

.sound-toggle__icon {
    width: 38px;
    height: 38px;
    fill: var(--color-accent);
    stroke: var(--color-accent);
    transition: fill 0.3s ease, stroke 0.3s ease;
}

/* Menu trigger — same circle as the search, sitting below it */
.menu-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 56px;
    height: 56px;
    background: transparent;
    border: 2px solid var(--color-accent);
    border-radius: 50%;
    cursor: pointer;
    transition: transform 0.3s ease;
}

.menu-toggle:hover {
    transform: scale(1.06);
}

.menu-toggle__icon {
    width: 26px;
    height: 26px;
    fill: none;
    stroke: var(--color-accent);
}

/* ============================================================
   The menu of all tales
   ============================================================ */

/* Slides in from the left, full height, and sits below the page
   frame so the frame keeps drawing over it. The padding clears the
   frame on the top, bottom and left, so no text ever runs under it. */
.tale-menu {
    position: fixed;
    top: 0;
    left: 0;
    width: var(--menu-width);
    max-width: 100%;
    height: 100%;
    /* The top clears the frame line, the corner ornament's dense motif
       AND the close button, which is fixed over this same corner. */
    padding: calc(var(--inner-inset) + var(--inner-width) + 7.5rem)
             3.5rem
             calc(var(--inner-inset) + var(--inner-width) + 5rem)
             calc(var(--inner-inset) + var(--inner-width) + 5rem);
    background: var(--color-menu-bg);
    overflow-y: auto;
    overscroll-behavior: contain;
    /* Scrolls, but without a visible bar */
    scrollbar-width: none;
    -ms-overflow-style: none;
    transform: translateX(-100%);
    visibility: hidden;
    transition: transform 0.45s cubic-bezier(0.2, 0.8, 0.2, 1),
                visibility 0s linear 0.45s;
    z-index: 980;
}

.tale-menu::-webkit-scrollbar {
    width: 0;
    height: 0;
}

.tale-menu.is-open {
    transform: translateX(0);
    visibility: visible;
    transition: transform 0.45s cubic-bezier(0.2, 0.8, 0.2, 1),
                visibility 0s;
}

/* Lives outside the panel (see header.php) so this really is fixed to
   the viewport and stays put while the list scrolls beneath it.
   Centred horizontally; only shown once the menu is full width. */
.menu-close {
    display: none;
    position: fixed;
    top: calc(var(--inner-inset) + var(--inner-width) + 1.5rem);
    left: calc(var(--menu-width) / 2);
    transform: translateX(-50%);
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    background: var(--color-menu-bg);
    border: 2px solid var(--color-accent);
    border-radius: 50%;
    cursor: pointer;
    z-index: 981;
}

.menu-close__icon {
    width: 20px;
    height: 20px;
    fill: none;
    stroke: var(--color-accent);
}

.tale-menu__list {
    list-style: none;
}

/* A 50px rule between items, with room either side of it */
.tale-menu__item + .tale-menu__item::before {
    content: '';
    display: block;
    width: 50px;
    height: 1px;
    background: var(--color-accent);
    margin: 2rem 0;
}

.tale-menu__link {
    display: block;
    text-decoration: none;
}

.tale-menu__title {
    display: block;
    font-size: 1.25rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--color-accent);
    transition: opacity 0.25s ease;
}

.tale-menu__author {
    display: block;
    margin-top: 0.35rem;
    font-size: 0.95rem;
    font-style: italic;
    color: var(--color-text-muted);
}

.tale-menu__link:hover .tale-menu__title,
.tale-menu__link:focus-visible .tale-menu__title {
    opacity: 0.7;
}

/* Sound off: a cross instead of the waves */
.sound-toggle .sound-toggle__waves { display: none; }
.sound-toggle .sound-toggle__cross { display: block; }

.sound-toggle.is-on .sound-toggle__waves { display: block; }
.sound-toggle.is-on .sound-toggle__cross { display: none; }

/* ============================================================
   Back-to-top button
   ============================================================ */

.to-top {
    /* Sits in the rail, under the menu button, at the same width as
       it and the search — so it lines up rather than floating. */
    width: 56px;
    height: 56px;
    font-family: var(--font-serif);
    font-size: 1.4rem;
    line-height: 1;
    color: var(--color-accent);
    background: rgba(13, 7, 9, 0.8);
    border: 1px solid var(--color-accent);
    border-radius: 50%;
    cursor: pointer;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.4s ease, background 0.3s ease, transform 0.3s ease;
}

.to-top:hover {
    transform: scale(1.06);
}

.to-top.is-visible {
    opacity: 1;
    pointer-events: auto;
}

.to-top:hover {
    background: var(--color-accent);
    color: #14090a;
    transform: scale(1.06);
}

/* ============================================================
   Footer
   ============================================================ */

/* Continues the campaign band — same background, no gap between
   the two, so they read as one block. */
.site-footer {
    /* Hairline across the full width — the footer is a direct child
       of body and stretches edge to edge, so its border reaches the
       end. The top padding keeps the text off the line. */
    border-top: 1px solid rgba(var(--color-text-muted-rgb), 0.3);
    /* Add the frame's thickness at the bottom: it is pinned to the
       viewport and covers the last --inner-inset + --inner-width
       pixels, so otherwise the gap below the text looks smaller
       than the one above it. */
    padding: 2rem 3rem calc(2rem + var(--inner-inset) + var(--inner-width));
    background: var(--color-bg);
    text-align: center;
    font-size: 13px;
    color: var(--color-text-muted);
    letter-spacing: 0.05em;
}

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

/* Below the container's full width there is no room for a 16rem
   gutter — it would squeeze both columns instead of separating them. */
@media (max-width: 1280px) {
    .contact-inner {
        gap: 8rem;
    }
}

@media (max-width: 900px) {
    /* Frames and corners shrink together so they stay aligned */
    :root {
        --frame-width: 4px;
        --frame-gap: 6px;
        --corner-size: 180px;
    }

    .contact-inner {
        gap: 4rem;
    }
}

/* Below 1200px there is no longer room for a pinned menu and a
   readable column side by side, so the panel floats over the reader
   instead of pushing it aside. Open and closed stay the same state as
   on a wide screen — only the reader's width stops depending on it. */
@media (max-width: 75rem) {
    body.is-reading .site-main {
        margin-left: 0;
    }

    .reader {
        padding-left: 2rem;
        padding-right: 2rem;
    }
}

/* Once the screen is no wider than the panel there is nothing left
   to click beside it, so it covers everything and gains a close button. */
@media (max-width: 30rem) {
    .tale-menu {
        width: 100%;
    }

    /* Full-width panel, so centre the X on the screen instead */
    .menu-close {
        left: 50%;
    }
}

/* One column, with the sign-up under the campaign text */
@media (max-width: 700px) {
    .contact-inner {
        grid-template-columns: minmax(0, 1fr);
        gap: 3rem;
    }
}

@media (max-width: 640px) {
    :root {
        --frame-width: 3px;
        --frame-gap: 4px;
        --corner-size: 120px;
    }

    .site-header {
        padding: 0.2rem 0.85rem 0.5rem;
    }

    /* On narrow screens the ornaments do not fit beside the block */
    .site-header::before,
    .site-header::after {
        display: none;
    }

    .hero-section,
    .tales-section,
    .contact-section {
        padding-left: 1.5rem;
        padding-right: 1.5rem;
    }

    /* On a phone the rail moves off the right edge and sits along the
       bottom instead: a column of buttons beside the text either
       covers it or forces an off-centre gutter. Along the bottom the
       content keeps its full width and stays centred. */
    .side-controls {
        top: auto;
        bottom: calc(var(--inner-inset) + var(--inner-width) + 0.75rem);
        /* Stretched and centred rather than shifted by a transform: a
           transform would become the containing block for the fixed
           back-to-top button inside it, and its offsets would be read
           from this row instead of from the screen. */
        left: 0;
        right: 0;
        transform: none;
        flex-direction: row;
        align-items: center;
        justify-content: center;
        gap: 0.75rem;
        /* Stretched edge to edge, it would otherwise intercept taps
           across the whole strip; only the buttons should. */
        pointer-events: none;
    }

    .side-controls > * {
        pointer-events: auto;
    }

    /* The field opens above the row rather than beside it, so it
       cannot run off the side of a narrow screen. */
    .search-control {
        position: static;
    }

    .search-input {
        right: auto;
        left: 50%;
        top: auto;
        bottom: calc(100% + 0.85rem);
        transform: translateX(-50%);
        text-align: left;
    }

    .search-control.is-open .search-input {
        width: 68vw;
    }

    /* Room under the last line so the row never covers it */
    .site-footer {
        padding-bottom: calc(var(--inner-inset) + var(--inner-width) + 5.5rem);
    }

    .sound-toggle { width: 44px; height: 44px; }
    .sound-toggle__icon { width: 20px; height: 20px; }
    .search-toggle { width: 34px; height: 34px; }
    .search-toggle__icon { width: 16px; height: 16px; }
    .menu-toggle { width: 40px; height: 40px; }
    .menu-toggle__icon { width: 19px; height: 19px; }
/* was width: 9rem, which overrode the 68vw rule above in the same media query and left the field too narrow to type into */

    /* The title reads better stacked once the two words no longer
       sit side by side; the lily bites into both, as it does across.
       Stacking frees a lot of width, so both grow here. */
    .hero-title {
        flex-direction: column;
        flex-wrap: nowrap;
        font-size: clamp(3.9rem, 21vw, 6.5rem);
    }

    .hero-title__lily {
        width: 2.05em;
        height: 2.05em;
        /* overlap grows with the flower, so the bite stays the same */
        margin: -0.46em 0;
    }

    /* Let the line break fall where it wants */
    .hero-text__break {
        display: none;
    }

    .site-logo {
        font-size: 0.74rem;
        letter-spacing: 0.2em;
    }

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

    /* On a phone the rail lies along the bottom, so the button leaves
       it and goes back to the right edge, just above the corner
       ornament and clear of the row. */
    .to-top {
        position: fixed;
        right: 1.5rem;
        bottom: calc(var(--corner-size) + 1rem);
        width: 48px;
        height: 48px;
        z-index: 993;
    }

    /* Solid buttons read better against a photographic background at
       this size than an outline with the scene showing through. */
    .sound-toggle,
    .search-toggle,
    .menu-toggle,
    .to-top {
        background: var(--color-accent);
        border-color: var(--color-accent);
        color: #fff;
    }

    .sound-toggle__icon {
        fill: #fff;
        stroke: #fff;
    }

    .search-toggle__icon,
    .menu-toggle__icon,
    .menu-close__icon {
        stroke: #fff;
    }

    .to-top:hover {
        background: var(--color-accent);
        color: #fff;
    }

    .menu-close {
        background: var(--color-accent);
    }

    /* 6 — the tales no longer stand so far off the campaign band */
    .page-hem {
        margin-top: 5rem;
    }

    /* 5 — shorter, and set in from the edges by the same 2rem the
       reader uses on a phone */
    .contact-section {
        padding: 4rem 2rem 3.5rem;
    }

    .site-footer {
        padding-left: 2rem;
        padding-right: 2rem;
    }

    /* The row of buttons floats over the panel down here, so the last
       tale in the list needs to clear it */
    .tale-menu {
        padding-bottom: calc(var(--inner-inset) + var(--inner-width) + 9rem);
    }

    /* 1 — the reading-mode button loses its outline on a phone */
    .reader__tools-toggle {
        border: none;
        padding-left: 0;
        padding-right: 0;
    }
}


/* ============================================================
   Search: clears the field, and marks matches in the tale menu
   ============================================================ */

.search-clear {
    position: absolute;
    top: 50%;
    right: calc(100% + 1.3rem);
    transform: translateY(-50%);
    width: 44px;               /* a real touch target, not a hairline glyph */
    height: 44px;
    display: none;
    align-items: center;
    justify-content: center;
    padding: 0;
    background: none;
    border: 0;
    cursor: pointer;
    color: var(--color-text-muted);
    z-index: 3;
}

.search-control.is-open .search-clear:not([hidden]) {
    display: flex;
}

.search-clear svg {
    width: 20px;
    height: 20px;
    stroke: currentColor;
}

.search-clear:hover,
.search-clear:focus-visible {
    color: var(--color-accent);
}

/* A tale the term matched: lifted to the top of the list and marked */
.tale-menu__item.is-match .tale-menu__link {
    background: rgba(var(--color-accent-rgb), 0.10);
}

.tale-menu__item.is-dim {
    opacity: 0.35;
}

.tale-menu__hit {
    background: rgba(var(--color-accent-rgb), 0.30);
    color: inherit;
    border-radius: 2px;
    padding: 0 0.1em;
}




/* ============================================================
   Client-side routing: the home view steps aside while a tale is
   open, so the page never reloads and the music keeps playing
   ============================================================ */

body.is-reading .hero-section,
body.is-reading .tales-section,
body.is-reading .page-hem,
body.is-reading .subscribe-section {
    display: none;
}

#reader-slot:empty {
    display: none;
}

/* While a tale is being fetched, so a slow connection shows something */
body.is-loading-tale {
    cursor: progress;
}


/* ============================================================
   Phones: the search field is pinned to the bottom of the screen,
   full width, with the clear button inside it. Within thumb reach,
   and clear of the side rail. Desktop keeps the sliding field.
   ============================================================ */

@media (max-width: 640px) {
    .search-control.is-open .search-input,
    .search-input {
        position: fixed;
        left: 0.75rem;
        right: 0.75rem;
        bottom: 0.9rem;
        top: auto;
        width: auto;            /* left+right decide the width, not a vw guess */
        height: 3.25rem;
        transform: none;
        /* room on the right for the clear button */
        padding: 0 3.6rem 0 1rem;
        text-align: left;
        z-index: 60;
    }

    /* Closed: still pinned, just not visible or reachable */
    .search-input {
        opacity: 0;
        pointer-events: none;
    }

    .search-control.is-open .search-input {
        opacity: 1;
        pointer-events: auto;
    }

    /* Same height and same bottom edge as the field, so it sits centred
       inside it without depending on the field's line height */
    .search-clear,
    .search-control.is-open .search-clear:not([hidden]),
    .search-control.is-open .search-clear[hidden] {
        position: fixed;
        right: 0.75rem;
        left: auto;
        bottom: 0.9rem;
        top: auto;
        width: 3.25rem;
        height: 3.25rem;
        transform: none;
        z-index: 61;
    }

    /* On a phone it is always there while the field is open: with no
       keyboard Escape and no room beside the field, it is the way out. */
    .search-control.is-open .search-clear,
    .search-control.is-open .search-clear[hidden] {
        display: flex;
    }

    .search-control:not(.is-open) .search-clear {
        display: none;
    }

    .search-clear svg {
        width: 24px;
        height: 24px;
    }
}
