/*
 * The story page and the reading view.
 *
 * The chapter text is the only thing on the page that isn't chrome, so it gets
 * the serif, the measure and the size control, and everything else stays out of
 * its way.
 */

/* Story page ------------------------------------------------------------ */

.story-head {
    margin: 0 0 var(--space-6);
    text-align: center;
}

.story-head__title {
    margin-bottom: var(--space-1);
}

/*
 * On a chapter the title links back to the contents, but it is still the page's
 * name rather than a thing to click - so it keeps the text colour and says what
 * it is on hover.
 */
.story-head__title a {
    color: inherit;
}

.story-head__byline {
    font-size: 1.125rem;
    color: var(--color-muted);
}

/* One dim line under the details: where else the story lives. */
.story-head__elsewhere {
    margin: 0.5rem 0 0;
    color: var(--color-muted);
}

/* The block is what moves away from the byline; the rows inside it keep the
   tight spacing they are given elsewhere. */
.story-head .details-block {
    margin-top: var(--space-3);
}

.story-head .details {
    justify-content: center;
}

/* Chapter navigation, in the flow. Replaced by the bar along the bottom on a
   phone, where a fixed row is worth the space it takes and a pair of rows in
   the column is not. */
.chapter-nav {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-end;
    gap: var(--space-2);
    margin: 0 0 var(--space-5);
}

/* The row after the text wants its air above it rather than below. */
.chapter-text + .chapter-nav {
    margin: var(--space-7) 0 0;
}

/* Quieter than the two beside it: wanted once, where they are wanted every
   time. Still a button, because it does something. */
.chapter-nav__settings {
    border-color: transparent;
    background: none;
    font-size: 0.875rem;
    color: var(--color-muted);
}

.chapter-nav__settings:hover {
    background: var(--color-button-hover-background);
    color: var(--color-foreground);
}

/* Names the chapter, under the story it belongs to - part of the same block, so
   it sits with the byline rather than a heading's worth of space away. */
.chapter-title {
    margin-top: var(--space-3);
    font-size: 1.375rem;
}

.story-head__summary {
    margin-top: var(--space-4);
    text-align: left;
}

.story-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
    justify-content: center;
    margin: var(--space-6) 0;
}

.chapter-list {
    margin: 0;
    padding: 0;
    list-style: none;
    border-top: 1px solid var(--color-rule);
}

.chapter-list__item {
    border-bottom: 1px solid var(--color-rule);
}

.chapter-list__item a {
    display: flex;
    gap: var(--space-3);
    align-items: baseline;

    min-height: var(--tap-target);
    padding: var(--space-2) 0;
}

.chapter-list__number {
    flex: none;
    min-width: 2em;
    font-variant-numeric: tabular-nums;
    text-align: right;
    color: var(--color-muted);
}

.chapter-list__item a[aria-current='page'] {
    font-weight: 500;
}

/* Chapter view ---------------------------------------------------------- */

/*
 * Everything in the reading view lines up with the text: the navigation
 * brackets it rather than sitting out at the window's edges, which at 1440px
 * put Previous and Next about 700px apart from anything they related to.
 */
.reading-column {
    max-width: var(--reading-measure);
    margin: 0 auto;
}

/*
 * What the settings actually set. The attributes are written on <html> before
 * first paint, so a reader's choices are in place by the time anything renders
 * rather than being applied over the top of the defaults a moment later.
 */
:root {
    --reading-face: var(--font-serif);
    --reading-size: 1rem;
    --reading-leading: 1.65;
    --reading-measure: 50rem;
}

:root[data-reading-face='sans'] {
    --reading-face: var(--font-sans);
}

:root[data-reading-face='dyslexic'] {
    --reading-face: var(--font-dyslexic);
}

/* 14px at the usual root size - what the old archive set its body text in. */
:root[data-reading-size='small'] {
    --reading-size: 0.875rem;
}

:root[data-reading-size='large'] {
    --reading-size: 1.15rem;
}

:root[data-reading-leading='tight'] {
    --reading-leading: 1.4;
}

:root[data-reading-leading='loose'] {
    --reading-leading: 1.8;
}

:root[data-reading-width='narrow'] {
    --reading-measure: 42.5rem;
}

:root[data-reading-width='wide'] {
    --reading-measure: 57.5rem;
}

:root[data-reading-width='full'] {
    --reading-measure: none;
}

/*
 * Full means the window, not the 1130px the rest of the site is held to - so
 * the page column that holds the chapter gives up its own limit as well. Only
 * the gutter is kept, because text against the edge of the glass is unreadable
 * whatever width you asked for.
 *
 * Matched by what it contains rather than by a class the template sets, since
 * the reading column is the only thing this applies to and the state driving it
 * already lives on the root element.
 */
:root[data-reading-width='full'] .container:has(> .reading-column) {
    max-width: none;
}

.chapter-text {
    font-family: var(--reading-face);
    font-size: var(--reading-size);
    line-height: var(--reading-leading);
    text-wrap: pretty;
}

.chapter-text p {
    margin: 1em 0;
}

.chapter-text hr {
    margin: 2em auto;
    border: 0;
    border-top: 1px solid var(--color-rule);
}

.chapter-text blockquote {
    margin: 1em 0;
    padding-left: var(--space-4);
    border-left: 2px solid var(--color-rule);
}

/*
 * Headings inside a story's own markup. Size and spacing mark them out; the
 * weight is left to inherit, so they sit at 400 like every other heading on the
 * site rather than being the one place a heading is set heavier.
 */
.chapter-text h1,
.chapter-text h2,
.chapter-text h3,
.chapter-text h4 {
    margin: 1.5em 0 0.5em;
    font-size: 1.125em;
}

/*
 * Justified, and hyphenated because justification without it spreads the slack
 * across too few words and opens rivers - most visible on a phone, where the
 * measure is narrowest and there is least room to hide them. Asked rather than
 * assumed: it is the default because it is what the archive has always looked
 * like, and the reader who finds the spacing uneven can say so.
 */
:root[data-reading-align='justify'] .chapter-text {
    text-align: justify;
    hyphens: auto;
}

/*
 * Except in OpenDyslexic, which is chosen by people for whom uneven word
 * spacing is exactly the problem - justifying it would undo the reason for
 * picking it. Ragged-right whatever is set, and the group that sets it is not
 * drawn, so nothing in the dialog offers a choice that this then ignores.
 */
:root[data-reading-face='dyslexic'] .chapter-text {
    text-align: left;
    hyphens: none;
}

:root[data-reading-face='dyslexic'] .settings__group--align {
    display: none;
}

/* The settings dialog --------------------------------------------------- */

/*
 * A native <dialog>, so the focus trap, Escape and inertness behind it are the
 * browser's job rather than ours. Nothing in it works without JavaScript, so
 * without JavaScript the button that opens it is not drawn either.
 */
.settings {
    width: min(30rem, calc(100vw - 2 * var(--space-4)));
    padding: 0;

    /* Restores what the reset takes away: a modal dialog is centred by the
       user agent's own margin: auto, which `* { margin: 0 }` overrides. */
    margin: auto;

    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    background: var(--color-section-background);
    color: var(--color-foreground);
    box-shadow: var(--shadow-overlay);
}

/*
 * Deliberately neither dimmed nor blurred. Every control in this dialog changes
 * the text behind it, and judging whether the change helps means being able to
 * read that text - a scrim would hide the only thing worth looking at.
 */
.settings::backdrop {
    background: transparent;
}

.settings__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2);

    padding: var(--space-3) var(--space-3) var(--space-3) var(--space-4);
    border-bottom: 1px solid var(--color-rule);
}

.settings__title {
    font-size: 1.125rem;
}

.settings__close {
    min-width: var(--tap-target);
    min-height: var(--tap-target);
    font-size: 1.5rem;
    line-height: 1;
}

.settings__body {
    max-height: min(70vh, 34rem);
    overflow-y: auto;
    padding: var(--space-2) var(--space-4) var(--space-4);
}

.settings__foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    padding-bottom: calc(var(--space-3) + env(safe-area-inset-bottom));
    border-top: 1px solid var(--color-rule);
}

/* Name on the left, choices on the right. Wrapping, because the fonts name
   themselves in their own faces and OpenDyslexic is wide enough that on a
   narrow screen its bar takes the line below rather than being squeezed. */
.settings__group {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2) var(--space-4);

    margin: 0;
    padding: var(--space-3) 0;
    border-bottom: 1px solid var(--color-rule);
}

.settings__group:last-child {
    border-bottom: 0;
}

.settings__label {
    flex: none;
    padding: 0;
    font-weight: 500;
}

/* One joined bar rather than separate buttons, so the group reads as a single
   choice with one answer showing. */
.settings__options {
    display: flex;
    flex: 1;
    justify-content: flex-end;

    border: 1px solid var(--color-border);
    border-radius: var(--radius-small);

    /* The segments square off against this, so their corners have to be cut
       back to it or they paint over the rounding. */
    overflow: hidden;
}

.settings__option {
    display: flex;
    flex: 1;
    align-items: center;
    justify-content: center;

    min-height: var(--control-height);
    padding: 0 var(--space-3);

    white-space: nowrap;
    text-align: center;
    cursor: pointer;
}

.settings__option + .settings__option {
    border-left: 1px solid var(--color-border);
}

.settings__option:has(:checked) {
    background: var(--color-primary-background);
    color: var(--color-primary-foreground);
}

.settings__option:hover:not(:has(:checked)) {
    background: var(--color-button-hover-background);
}

/* The input it belongs to is hidden, so the ring has to be drawn on the
   segment - inside its edge, or the joined bar clips it away. */
.settings__option:has(:focus-visible) {
    outline: 2px solid var(--color-accent);
    outline-offset: -2px;
}

/* Each font names itself in itself - the quickest way to tell whether one
   suits you is to see it. */
.settings__option--serif {
    font-family: var(--font-serif);
}

.settings__option--sans {
    font-family: var(--font-sans);
}

.settings__option--dyslexic {
    font-family: var(--font-dyslexic);
}

.chapter-notice {
    margin: 0 auto var(--space-5);
    padding: var(--space-3) var(--space-4);

    border: 1px solid var(--color-border);
    border-radius: var(--radius-small);

    font-size: 0.9375rem;
    color: var(--color-muted);
}

/* When the notice is a paragraph, a list and a paragraph, they sit close. */
.chapter-notice > p,
.chapter-notice > ul {
    margin: 0;
}

.chapter-notice > ul {
    padding-left: 1.25rem;
    margin: 0.3rem 0;
}

/* Where the text came from: one dim line under it. */
.provenance {
    margin: var(--space-4) auto 0;
    font-size: 0.9375rem;
    color: var(--color-muted);
}

/* Report a problem: folded under the chapter, opened only when wanted. */
.report {
    margin: var(--space-4) auto var(--space-5);
    font-size: 0.9375rem;
    color: var(--color-muted);
}

.report summary {
    cursor: pointer;
}

.report__form {
    display: grid;
    gap: var(--space-2);
    justify-items: start;
    margin-top: var(--space-3);
    color: var(--color-foreground);
}

.report__form textarea {
    width: 100%;
    max-width: 40rem;
    padding: var(--space-2);
    border: 1px solid var(--color-field-border);
    border-radius: var(--radius-small);
    background: var(--color-field-background);
}

/* The honeypot is off the page for people, and the page for machines. */
.report__trap {
    position: absolute;
    left: -10000px;
    width: 1px;
    height: 1px;
    overflow: hidden;
}

/*
 * On a phone the dialog docks to the bottom rather than sitting in the middle:
 * it comes from the corner the Aa is in, it is where a thumb already is, and a
 * centred box would cover the very lines you are judging the change against.
 */
@media (max-width: 700px) {
    /* Tighter, so four labels fit a narrow screen without shortening. */
    .reading-bar__item {
        padding: 0 var(--space-2);
        font-size: 0.875rem;
    }

    .settings {
        width: 100%;
        max-width: none;
        margin: auto auto 0;

        border-radius: var(--radius) var(--radius) 0 0;
        border-bottom: 0;
    }

    /*
     * A strip of the chapter left showing, rather than a share of the screen
     * taken. 30rem is what the groups need; the 9rem is the header and about
     * three lines of the text being adjusted, which is the least worth judging
     * a change against.
     *
     * A fraction was the wrong measure: what the sheet holds does not shrink
     * with the display it is on, and 60% of an SE2 with the toolbars up is
     * 332px against 382px of groups - so the first row sat above the fold of a
     * sheet whose whole point is not being one you scroll.
     *
     * svh rather than vh: vh is the viewport with the browser's toolbars hidden,
     * so a sheet sized against it is taller than the screen actually shows for
     * as long as those toolbars are up - which, on the phone this was found on,
     * left the sheet running from under the header to the bottom of the display
     * with nothing to look at behind it.
     *
     * On [open] only: a dialog is hidden by the user agent's display: none, and
     * an unconditional display would draw the sheet on every chapter page.
     */
    .settings[open] {
        display: flex;
        flex-direction: column;
        max-height: min(30rem, calc(100svh - 9rem));
    }

    /* The form wraps all three parts, so it has to carry the column too - left
       as a block it was the dialog's only flex item, and the body's flex
       below applied to nothing.

       Basis auto rather than the usual flex: 1, whose basis of zero asks a
       dialog the user agent sizes to fit-content to size itself from items
       that claim no size - which can leave the sheet with no height at all.
       From auto they start at their content and shrink to the cap instead. */
    .settings[open] > form {
        display: flex;
        flex: 1 1 auto;
        flex-direction: column;
        min-height: 0;
    }

    /* The part that gives, so the head and foot stay put and the submit is
       never a scroll away. min-height: 0 or a flex item refuses to shrink
       below its content and the cap does nothing. */
    .settings__body {
        flex: 1 1 auto;
        min-height: 0;
        max-height: none;
    }

    /*
     * The head, dropped. A sheet that rises from the Aa, holds nothing but
     * reading options and names each of its groups does not also need a title
     * saying so, and the × it carried is the third way out of a dialog that
     * already closes on Escape, on the backdrop and on Done. The height it was
     * spending goes to the font group below. The title stays in the markup and
     * still names the dialog through aria-labelledby, which reads it whether or
     * not it is drawn.
     */
    .settings__head {
        display: none;
    }

    /* Tighter, to spend the smaller height on options rather than on gaps.
       The rows themselves stay a full tap target. */
    .settings__foot {
        padding-top: var(--space-2);
        padding-bottom: var(--space-2);
    }

    .settings__foot {
        padding-bottom: calc(var(--space-2) + env(safe-area-inset-bottom));
    }

    .settings__group {
        padding: var(--space-2) 0;
    }

    /*
     * OpenDyslexic, on a line of its own. It names itself in its own face, which
     * is wide, so sharing a line with the other two left all three squeezed to
     * the point of being hard to read - and reading the name is how you tell
     * whether the face suits you. The room the head gave up pays for the row.
     */
    .settings__group:has(.settings__option--dyslexic) .settings__options {
        flex-wrap: wrap;
    }

    /* Full width below the other two, with the joining rule turned through a
       right angle: on its own row it is under them rather than beside them. */
    .settings__option + .settings__option--dyslexic {
        flex-basis: 100%;
        border-left: 0;
        border-top: 1px solid var(--color-border);
    }

    /*
     * Column width, dropped. The narrowest measure on offer is 42.5rem, and a
     * 700px screen has 676px to give once the gutter is taken - so every option
     * in this group draws the same column, and the group asks a question the
     * screen has already answered. It comes back the moment there is room for
     * the answers to differ.
     */
    .settings__group--wide-only {
        display: none;
    }
}

/* The reading bar ------------------------------------------------------- */

/*
 * Thin, along the bottom, and the only chrome the reading view has. Fixed
 * rather than in the flow: navigation you might want at any point in a story
 * has no business being somewhere you have to scroll to.
 */
.reading-bar {
    /* Shown only where it replaces the rows in the column. */
    display: none;

    position: fixed;
    inset: auto 0 0;
    z-index: 90;

    align-items: stretch;
    justify-content: center;

    /* One row, always, and exactly the height the page reserves below. The
       border is inside it, box-sizing being border-box throughout. */
    height: calc(var(--reading-bar-height) + env(safe-area-inset-bottom));

    /* The same edge as the header's, drawn the same way: the bar is the same
       dark furniture, and in a dark theme it needs the same help to be seen
       against the page it sits over. */
    border-top: 1px solid var(--color-header-edge);
    background: var(--color-header-background);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);

    padding-bottom: env(safe-area-inset-bottom);
    padding-left: env(safe-area-inset-left);
    padding-right: env(safe-area-inset-right);
}

.reading-bar__item {
    display: flex;
    align-items: center;
    justify-content: center;

    flex: 1;
    min-width: 0;
    max-width: 12rem;
    padding: 0 var(--space-3);

    /* Never two lines: a label that wrapped made the bar taller than the space
       the page had set aside for it, and the footer went back underneath. It
       shortens instead, which costs a word rather than the whole arrangement. */
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;

    border: 0;
    background: none;

    font-size: 0.9375rem;
    color: var(--color-header-foreground);
    text-align: center;
}

/* One button from the next. Four labels along a phone's width sit close enough
   together that only a rule tells you where the tap target you are aiming at
   actually starts. */
.reading-bar__item + .reading-bar__item {
    border-left: 1px solid var(--color-header-rule);
}

.reading-bar__item:hover {
    background: var(--color-header-active-background);
    color: var(--color-header-active-foreground);
    text-decoration: none;
}

/*
 * The first chapter has no previous and the last has no next. Kept as space
 * rather than removed, so Contents and Aa stay where they were on the chapter
 * before - a bar whose buttons move as you read is a bar you have to look at.
 */
.reading-bar__item--spent {
    visibility: hidden;
}

/*
 * Room for the bar at the end of the document, not just at the end of the text.
 *
 * Padding the reading column only moved the chapter: the footer comes after it,
 * and the theme switch sat behind the bar with nothing to say it was there.
 * Whatever the page ends with has to clear it.
 *
 * The same expression as the bar's own height, so the two cannot drift: reserving
 * a fixed 44px left the footer covered again the moment a label wrapped, or the
 * reader's default text size grew.
 */
@media (max-width: 700px) {
    /*
     * The bar takes over and the rows in the column stand down. Below the rule
     * that hides the bar rather than above it: both are one class deep, so the
     * one written later is the one that applies.
     */
    .reading-bar {
        display: flex;
    }

    .chapter-nav {
        display: none;
    }

    body:has(.reading-bar) {
        padding-bottom: calc(var(--reading-bar-height) + env(safe-area-inset-bottom));
    }
}

/* Nothing in the settings dialog works without JavaScript, so without it the
   control that opens it is not drawn at all rather than drawn and dead. */
html:not(.js) [data-reading-settings-trigger] {
    display: none;
}
