/* ============================================================
   JEREMY MOEBEL — piano arrangements
   Set in Newsreader and IBM Plex Mono.
   Design contract: docs/plans/2026-07-31-editorial-redesign-design.md
   Enforced by: tests/test_design_contract.py
   ============================================================ */

/* ---------- 1. FONTS ---------- */

@font-face {
    font-family: 'Newsreader';
    src: url('fonts/newsreader-wght-normal.woff2') format('woff2-variations');
    font-weight: 200 800;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: 'Newsreader';
    src: url('fonts/newsreader-wght-italic.woff2') format('woff2-variations');
    font-weight: 200 800;
    font-style: italic;
    font-display: swap;
}

/* Newsreader has no Greek, and two titles open with a Greek capital: Σ. MOROSE,
   Γ. Mosaïque Solitaire. This fills only that range, from Source Serif 4, whose
   cap height and stroke contrast match Newsreader's and whose weights are
   re-mapped to Newsreader's stems (build_greek_font.py). Without it the browser
   falls back to whatever serif it has, mid-title. */
@font-face {
    font-family: 'Newsreader';
    src: url('fonts/newsreader-greek-normal.woff2') format('woff2-variations');
    font-weight: 200 800;
    font-style: normal;
    font-display: swap;
    unicode-range: U+0370-03FF;
}

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

@font-face {
    font-family: 'Plex Mono';
    src: url('fonts/plex-mono-500.woff2') format('woff2');
    font-weight: 500;
    font-style: normal;
    font-display: swap;
}

/* ---------- 2. TOKENS ---------- */

:root {
    --paper:      #F7F4ED;
    --paper-deep: #EFEAE0;
    --ink:        #1A1814;
    --ink-soft:   #5C554A;
    --rule:        #D8D0C2;  /* decorative separators only */
    --rule-strong: #8F8471;  /* form field boundaries — 3.4:1, WCAG 1.4.11 */
    --rubric:      #9E2B1F;

    /* Type ramp. Every font-size in this file is one of these nine steps. */
    --t-label:    11px;
    --t-fine:     14px;
    --t-small:    16px;
    --t-body:     18px;
    --t-lead:     20px;
    --t-title:    26px;
    --t-figure:   32px;
    --t-headline: clamp(2rem, 5vw, 2.6rem);
    --t-display:  clamp(2.4rem, 7vw, 3.5rem);

    --serif: 'Newsreader', Georgia, 'Times New Roman', serif;
    --mono:  'Plex Mono', ui-monospace, SFMono-Regular, monospace;

    --measure: 62ch;
    --gutter: clamp(1.25rem, 4vw, 3.5rem);
    /* Wide enough for six covers across at a size where their titles read.
       Prose keeps its own measure, so only the shelf and the work page use it. */
    --page: 76rem;

    /* Vertical rhythm. Fluid for the same reason --gutter is: 3rem of section
       padding is right above a 68rem page and half the first screen of a phone.
       Four steps, and every section on the site reaches for one, so the whole
       page tightens by the same proportion instead of one block at a time. */
    --space-section:        clamp(1.75rem, 6vw, 3rem);
    --space-section-end:    clamp(2.25rem, 8vw, 4rem);
    --space-section-end-lg: clamp(2.75rem, 10vw, 5rem);
    --space-block:          clamp(1.1rem, 4.5vw, 2.5rem);
    --ease: cubic-bezier(.2, 0, 0, 1);
    --dur: 150ms;
}

/* ---------- 3. RESET & BASE ---------- */

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

html {
    -webkit-text-size-adjust: 100%;
}

body {
    margin: 0;
    background: var(--paper);
    color: var(--ink);
    font-family: var(--serif);
    font-size: var(--t-body);
    line-height: 1.55;
    font-synthesis-weight: none;
    text-rendering: optimizeLegibility;
    -webkit-font-smoothing: antialiased;
}

img {
    max-width: 100%;
    height: auto;
    display: block;
}

a {
    color: inherit;
    text-decoration-thickness: 1px;
    text-underline-offset: .2em;
}

h1, h2, h3 {
    font-weight: 400;
    line-height: 1.15;
    margin: 0;
    letter-spacing: -.005em;
}

p {
    margin: 0;
}

button {
    font: inherit;
    color: inherit;
}

/* Focus is never removed. It is the only way a keyboard user can see where
   they are. */
:focus-visible {
    outline: 2px solid var(--rubric);
    outline-offset: 3px;
}

.page {
    max-width: var(--page);
    margin: 0 auto;
    padding: 0 var(--gutter);
}

.visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
}

/* ---------- 4. THE TWO RECURRING MOTIFS ---------- */

/* Critical apparatus: catalogue numbers, prices, nav, buttons, captions.
   Every small uppercase thing in the site is this one class. */
.label {
    font-family: var(--mono);
    font-size: var(--t-label);
    font-weight: 400;
    font-style: normal;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--ink-soft);
    line-height: 1.4;
}

/* A staff, not an <hr>. */
.rule-double {
    border: 0;
    border-top: 1px solid var(--ink);
    border-bottom: 1px solid var(--ink);
    height: 3px;
    margin: 0;
    padding: 0;
}

.rule-single {
    border: 0;
    border-top: 1px solid var(--rule);
    margin: 0;
}

/* ---------- 5. HEADER ---------- */

.masthead {
    padding: clamp(1rem, 4vw, 1.6rem) 0 1rem;
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    /* The row gap only applies once the nav drops below the name, which is a
       phone. 1.5rem there left the language switcher stranded. */
    gap: clamp(.5rem, 2.5vw, 1.5rem) var(--gutter);
    flex-wrap: wrap;
}

.masthead-name {
    font-family: var(--serif);
    font-size: var(--t-lead);
    font-weight: 400;
    letter-spacing: .16em;
    text-transform: uppercase;
    text-decoration: none;
    white-space: nowrap;
}

.masthead-nav {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    /* Fluid rather than a breakpoint: the row tightens as the screen narrows and
       reflows whole items when it finally has to. */
    gap: .55rem clamp(.85rem, 3.4vw, 1.75rem);
    margin: 0;
    padding: 0;
    list-style: none;
}

/* A navigation item is one unit. Without this, "À propos" breaks after the "À"
   and "Panier (1)" drops its count to a second line on a phone. */
.masthead-nav li,
.colophon-nav li {
    white-space: nowrap;
}

.masthead-nav a {
    text-decoration: none;
    transition: color var(--dur) var(--ease);
}

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

#cart-count {
    font-variant-numeric: tabular-nums;
}

.cart-link.has-items #cart-count {
    color: var(--rubric);
}

/* Language switcher. The current language is stated, not offered — it reads as
   ink; the one you can move to reads as a link. */
.lang-switch {
    display: flex;
    align-items: baseline;
    gap: .4rem;
}

.lang-switch span {
    color: var(--rule-strong);
}

.lang-switch a {
    text-decoration: none;
    transition: color var(--dur) var(--ease);
}

.lang-switch a:hover {
    color: var(--ink);
}

.lang-switch a.is-current {
    color: var(--ink);
    cursor: default;
}

/* ---------- 6. IMPRINT LINE (home) ---------- */

.imprint {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem var(--gutter);
    flex-wrap: wrap;
    padding: 1.1rem 0;
}

.imprint-descriptor {
    font-size: var(--t-body);
    font-style: italic;
    color: var(--ink-soft);
}

/* ---------- 7. SEARCH ---------- */

.search {
    position: relative;
    min-width: min(20rem, 100%);
}

.search-form {
    display: flex;
    align-items: baseline;
    gap: .6rem;
    border-bottom: 1px solid var(--rule-strong);
    padding-bottom: .3rem;
    transition: border-color var(--dur) var(--ease);
}

.search-form:focus-within {
    border-bottom-color: var(--rubric);
}

.search-input {
    flex: 1;
    border: 0;
    background: none;
    padding: 0;
    font-family: var(--serif);
    font-size: var(--t-small);
    color: var(--ink);
    min-width: 0;
}

.search-input::placeholder {
    color: var(--ink-soft);
    opacity: .75;
}

/* No `outline: none` here. The underline turning rubric on :focus-within is a
   nice extra cue, but the field must carry the same ring as every other
   control — .search-input:focus would out-specify :focus-visible and win. */

.search-submit {
    border: 0;
    background: none;
    padding: 0;
    cursor: pointer;
}

/* ---------- 8. THE COVER ---------- */
/* One series design for every piece, the way Henle has bound every Urtext in
   the same blue since 1948 (templates/_cover.html). The cover is markup, not an
   image, and every size inside it is in container query units: a fraction of
   the cover's own width. So it is the same object at 180px on the shelf, 136px
   beside a title and 64px in the cart. The cqi sizes are the cover's own type
   scale, as em is the drop cap's: they follow the cover, not the page. */

.cover {
    container-type: inline-size;
    position: relative;
    aspect-ratio: 1000 / 1416;
    background: var(--paper-deep);
    color: var(--ink);
    border: 1px solid var(--rule);
    border-radius: 2px;
    overflow: hidden;
}

.cover-in {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    padding: 11cqi 8cqi 8cqi;
}

/* The series colour: one red line per cover, as Henle sets its titles in ochre. */
.cover-artist {
    font-size: 6cqi;
    line-height: 1.3;
    letter-spacing: .16em;
    /* letter-spacing also follows the last letter, which pulls centred text
       left by half a step; the same amount on the left puts it back. */
    padding-left: .16em;
    text-transform: uppercase;
    color: var(--rubric);
}

.cover-artist span {
    white-space: nowrap;
}

.cover-middle {
    margin: auto 0;
}

.cover-title {
    font-weight: 300;
    line-height: 1.04;
    letter-spacing: -.01em;
    text-wrap: balance;
}

.cover[data-length='s'] .cover-title {
    font-size: 18cqi;
}

.cover[data-length='m'] .cover-title {
    font-size: 12.5cqi;
}

.cover[data-length='l'] .cover-title {
    font-size: 10cqi;
}

.cover[data-length='xl'] .cover-title {
    font-size: 8cqi;
}

.cover-for {
    margin-top: 4cqi;
    font-size: 6cqi;
    font-style: italic;
}

.cover-foot {
    width: 100%;
}

/* The opening bars, printed onto the cover's paper the way the plates print
   onto the page. The cover is its own stacking context (container-type), so
   multiply finds the cover's ground rather than the page's. */
.cover-incipit {
    width: 100%;
    margin-bottom: 5cqi;
    mix-blend-mode: multiply;
}

/* The site's staff, at the cover's scale. */
.cover-rule {
    border-top: 1px solid currentColor;
    border-bottom: 1px solid currentColor;
    height: 3px;
}

.cover-imprint {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    margin-top: 3cqi;
    font-size: 5cqi;
}

.cover-number {
    font-family: var(--mono);
    font-size: 4.2cqi;
    letter-spacing: .1em;
}

/* ---------- 9. THE SHELF ---------- */
/* Six covers across, so the catalogue is in view at once. The plates all look
   alike at catalogue size, and Baymard's list research finds that when images
   do not tell products apart people read the titles instead; the cover makes
   the title the image. */

.shelf {
    display: grid;
    grid-template-columns: repeat(6, minmax(0, 1fr));
    gap: 2.4rem 1.4rem;
    padding: var(--space-section) 0 var(--space-section-end);
}

.book[hidden] {
    display: none;
}

.book-link {
    position: relative;
    display: block;
    text-decoration: none;
}

/* Looking inside: page 1 over the cover while the pointer rests on it.
   script.js fetches the plate on the first approach and marks it ready once it
   has loaded, so a hover never shows an empty page. */
.book-peek {
    position: absolute;
    inset: 0;
    background: var(--paper);
    border: 1px solid var(--rule);
    border-radius: 2px;
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--dur) var(--ease);
}

.book-peek img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: top;
    mix-blend-mode: multiply;
}

.book-link:hover .book-peek.is-ready,
.book-link:focus-visible .book-peek.is-ready {
    opacity: 1;
}

/* Baymard's list-item research puts price among the few attributes a visitor
   refuses to click without. A figure, in the serif and in ink, beside the page
   count set as apparatus. */
.book-meta {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: .6rem;
    margin-top: .7rem;
}

.book-price {
    font-size: var(--t-body);
    color: var(--ink);
    font-feature-settings: 'tnum';
    line-height: 1;
}

.book-for {
    margin-top: .3rem;
    color: var(--ink);
}

.catalogue-empty {
    padding: var(--space-section) 0 var(--space-section-end-lg);
    font-size: var(--t-lead);
    color: var(--ink-soft);
}

.catalogue-empty[hidden] {
    display: none;
}

/* ---------- 10. BUTTONS ---------- */

.btn {
    font-family: var(--mono);
    font-size: var(--t-label);
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--ink);
    background: none;
    border: 1px solid var(--ink);
    border-radius: 0;
    padding: .8rem 1.4rem;
    cursor: pointer;
    text-decoration: none;
    display: inline-block;
    text-align: center;
    transition: background-color var(--dur) var(--ease), color var(--dur) var(--ease);
}

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

.btn[disabled] {
    border-color: var(--rule);
    color: var(--ink-soft);
    background: none;
    cursor: default;
}

.btn-block {
    display: block;
    width: 100%;
}

/* The one filled button on a page, for the action that sells. Its hover is the
   outline button's rest state: the same gesture as .btn, reversed. */
.btn-solid {
    background: var(--ink);
    color: var(--paper);
}

.btn-solid:hover {
    background: none;
    color: var(--ink);
}

/* ---------- 11. WORK DETAIL ---------- */
/* Most visitors land here from the video, so the first screen is the whole
   sale: a small cover beside the title, the price and the buttons under them,
   and page 1 of the music beside it all. On a phone the same order stacks, with
   the price and Buy above the plate. */

.crumb {
    display: inline-flex;
    align-items: center;
    gap: .5rem;
    padding-top: 1.2rem;
    text-decoration: none;
    transition: color var(--dur) var(--ease);
}

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

/* Drawn rather than typed: Plex Mono, as the site ships it, has no arrows. */
.crumb svg {
    width: 1rem;
    height: .65rem;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.2;
}

.work {
    display: grid;
    grid-template-columns: 8.5rem minmax(0, 1fr) minmax(0, 1.15fr);
    grid-template-areas:
        "cover  head   score"
        "buy    buy    score"
        "listen listen score";
    grid-template-rows: auto auto 1fr;
    column-gap: 1.6rem;
    padding: 1.4rem 0 var(--space-section-end);
}

.work-cover {
    grid-area: cover;
    align-self: start;
}

.work-head {
    grid-area: head;
    align-self: center;
}

.work-title {
    font-size: var(--t-display);
    font-weight: 300;
    line-height: 1.05;
    margin-top: .4rem;
    text-wrap: balance;
}

.work-composers {
    font-size: var(--t-lead);
    margin-top: .55rem;
}

.work-for {
    font-style: italic;
    color: var(--ink-soft);
}

.work-buy {
    grid-area: buy;
    margin-top: 1.8rem;
    padding-top: 1.3rem;
    border-top: 1px solid var(--rule);
}

.work-price {
    font-size: var(--t-figure);
    line-height: 1;
    font-feature-settings: 'tnum';
}

.work-actions {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: .7rem;
    margin-top: 1.2rem;
}

.work-actions form {
    margin: 0;
}

.work-terms {
    margin-top: .9rem;
    color: var(--ink-soft);
    font-size: var(--t-small);
}

.work-score {
    grid-area: score;
    align-self: start;
    margin: 0 0 0 2rem;
}

.work-plate {
    width: 100%;
    aspect-ratio: 1000 / 1416;
    object-fit: cover;
    object-position: top center;
    mix-blend-mode: multiply;
}

.work-listen {
    grid-area: listen;
    margin-top: 2.6rem;
}

.work-listen > h2 {
    margin-bottom: .7rem;
}

.work-note {
    padding-top: 2rem;
    max-width: var(--measure);
}

.work-note p {
    margin-top: .8rem;
    color: var(--ink-soft);
}

/* More by the same artist, and the artist's set. */
.more {
    padding-bottom: var(--space-section-end);
}

.more-head {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 1rem 2rem;
    flex-wrap: wrap;
    padding-top: 1.1rem;
}

.more-title {
    font-size: var(--t-title);
}

.set-offer {
    display: flex;
    align-items: baseline;
    gap: .8rem 1.2rem;
    flex-wrap: wrap;
    margin: 0;
}

.set-offer p {
    font-size: var(--t-small);
    color: var(--ink-soft);
}

.shelf-row {
    padding: 1.6rem 0 0;
}

/* ---------- 12. VIDEO FACADE ---------- */
/* Nothing is requested from YouTube until the visitor asks for it. */

.video-facade {
    position: relative;
    display: block;
    width: 100%;
    padding: 0;
    border: 1px solid var(--rule);
    border-radius: 2px;
    background: var(--paper-deep);
    cursor: pointer;
    overflow: hidden;
    aspect-ratio: 16 / 9;
}

.video-facade img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: filter var(--dur) var(--ease);
}

.video-facade:hover img {
    filter: brightness(.85);
}

.video-facade .label {
    position: absolute;
    left: .8rem;
    bottom: .7rem;
    color: var(--paper);
}

/* A play mark drawn in CSS: the site's Plex Mono has no triangle, and a glyph
   borrowed from whatever font the system falls back to would not match. */
.video-play {
    display: inline-flex;
    align-items: center;
    gap: .6em;
}

.video-play::before {
    content: '';
    border-left: .62em solid currentColor;
    border-top: .38em solid transparent;
    border-bottom: .38em solid transparent;
}

.video-frame {
    width: 100%;
    aspect-ratio: 16 / 9;
    border: 0;
    border-radius: 2px;
}

/* ---------- 13. PROSE ---------- */

.prose {
    max-width: var(--measure);
    padding: var(--space-section) 0 1rem;
    font-size: var(--t-lead);
}

.prose h1 {
    font-size: var(--t-headline);
    font-weight: 300;
    margin-bottom: 1.8rem;
}

.prose p + p {
    margin-top: 1.4em;
}

.prose .lede {
    font-style: italic;
    color: var(--ink-soft);
    margin-bottom: 1.4em;
}

/* Rubrication. Applied to an explicit class, never to :first-of-type — the
   first paragraph is a one-word greeting and a drop cap on it looks broken. */
.prose .rubricated::first-letter {
    float: left;
    font-size: 3.4em;
    line-height: .82;
    padding: .06em .1em 0 0;
    color: var(--rubric);
    font-weight: 300;
}

.frontispiece {
    margin: 0;
    padding: clamp(2rem, 7vw, 3.5rem) 0 1rem;
}

.frontispiece img {
    width: 100%;
    border-radius: 2px;
}

.frontispiece figcaption {
    margin-top: .7rem;
}

/* ---------- 14. CART ---------- */
/* The cart is also the checkout: the pieces, the total, the waiver and one
   button to Stripe, which asks for the address the sheets go to. */

.cart {
    padding: var(--space-section) 0 var(--space-section-end);
    max-width: 46rem;
}

.section-title {
    font-size: var(--t-headline);
    font-weight: 300;
    margin-bottom: 2rem;
}

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

.cart-row {
    display: grid;
    grid-template-columns: 4rem minmax(0, 1fr) auto auto;
    align-items: center;
    gap: 1.2rem;
    padding: 1.1rem 0;
    border-top: 1px solid var(--rule);
}

.cart-cover {
    display: block;
    width: 4rem;
}

.cart-row-title {
    font-size: var(--t-body);
}

.cart-row-title a {
    text-decoration: none;
}

.cart-row-composers {
    font-size: var(--t-fine);
    color: var(--ink-soft);
}

/* A figure, as on the shelf and the work page: one register for every price. */
.cart-row-price {
    font-size: var(--t-body);
    font-feature-settings: 'tnum';
}

.cart-remove {
    border: 0;
    background: none;
    padding: .3rem;
    cursor: pointer;
    color: var(--ink-soft);
    font-family: var(--mono);
    font-size: var(--t-small);
    line-height: 1;
    transition: color var(--dur) var(--ease);
}

.cart-remove:hover {
    color: var(--rubric);
}

.cart-set {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 1rem;
    padding: .9rem 0;
    border-top: 1px solid var(--rule);
    font-size: var(--t-small);
    color: var(--ink-soft);
}

.cart-set-saving {
    color: var(--ink);
    font-feature-settings: 'tnum';
}

.cart-total {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 1rem;
    border-top: 1px solid var(--rubric);
    margin-top: .5rem;
    padding-top: .9rem;
}

.cart-total-amount {
    font-size: var(--t-title);
    font-feature-settings: 'tnum';
    line-height: 1;
}

.checkout-form {
    max-width: 30rem;
    margin: 0;
}

.checkout-form .btn {
    margin-top: 1.4rem;
}

.cart-back {
    display: inline-block;
    margin-top: 2rem;
    text-decoration: none;
}

.cart-back:hover {
    color: var(--ink);
}

.cart-empty {
    padding: var(--space-section) 0 var(--space-section-end-lg);
    max-width: var(--measure);
}

.cart-empty p {
    font-size: var(--t-lead);
    color: var(--ink-soft);
    margin-bottom: 1.8rem;
}

/* ---------- 15. FORMS & CHECKOUT ---------- */

.form-page {
    padding: var(--space-section) 0 var(--space-section-end);
    max-width: 34rem;
}

.field {
    margin-bottom: 1.9rem;
}

.field label {
    display: block;
    margin-bottom: .45rem;
}

.field input,
.field textarea {
    width: 100%;
    border: 0;
    /* rule-strong, not rule: this line is the only thing marking the field. */
    border-bottom: 1px solid var(--rule-strong);
    background: none;
    padding: .45rem 0;
    font-family: var(--serif);
    font-size: var(--t-body);
    color: var(--ink);
    border-radius: 0;
    transition: border-color var(--dur) var(--ease);
}

.field textarea {
    resize: vertical;
    min-height: 8rem;
    line-height: 1.5;
}

.field input:focus,
.field textarea:focus {
    outline: none;
    border-bottom-color: var(--rubric);
}

.field input::placeholder,
.field textarea::placeholder {
    color: var(--ink-soft);
    opacity: .6;
}

.required {
    color: var(--rubric);
}

/* A correction returned in the margin, which is what red means on a proof.
   The browser's own bubble is suppressed with novalidate, so this is the only
   thing the visitor sees — it has to carry the whole message. */
.field-error {
    display: block;
    margin-top: .55rem;
    color: var(--rubric);
}

.field-error[hidden] {
    display: none;
}

/* :focus already turns this rule rubric, so weight is what separates "you are
   typing here" from "this needs fixing" — and the sentence underneath means the
   state is never carried by colour alone. The padding keeps the field from
   shifting by the pixel the rule grows. */
.field input[aria-invalid='true'] {
    border-bottom-width: 2px;
    border-bottom-color: var(--rubric);
    padding-bottom: calc(.45rem - 1px);
}

/* A correction that belongs to the whole form rather than to one field. */
.form-error {
    margin: 0 0 1.6rem;
}

/* The withdrawal waiver, and below it the optional "email me" box, which wears
   the same drawing. Drawn rather than left to the OS: a native control would
   arrive in the system's blue with the system's radius, which is the one thing
   this paper cannot carry. Square,
   one hairline, no fill until it is ticked. Set in --t-small, never .label: a
   sentence that has to constitute express consent cannot be set in a face
   chosen to resist reading. */
.waiver {
    display: flex;
    align-items: flex-start;
    gap: .7rem;
    margin-top: 1.6rem;
    font-size: var(--t-small);
    cursor: pointer;
}

.waiver input[type='checkbox'] {
    appearance: none;
    -webkit-appearance: none;
    flex: 0 0 auto;
    width: 1.05em;
    height: 1.05em;
    /* Aligns the box to the cap height of the first line, not to its top. */
    margin: .28em 0 0;
    border: 1px solid var(--rule-strong);
    border-radius: 0;
    background: none;
    cursor: pointer;
    transition: background var(--dur) var(--ease),
                border-color var(--dur) var(--ease);
}

.waiver input[type='checkbox']:checked {
    background: var(--ink);
    border-color: var(--ink);
}

/* The tick is two borders rotated, not a glyph: at this size a font's checkmark
   is whatever the system happens to have, and it would not be Newsreader. */
.waiver input[type='checkbox']:checked::after {
    content: '';
    display: block;
    width: .3em;
    height: .58em;
    margin: -.06em 0 0 .3em;
    border: solid var(--paper);
    border-width: 0 1.5px 1.5px 0;
    transform: rotate(45deg);
}

.waiver input[type='checkbox'][aria-invalid='true'] {
    border-color: var(--rubric);
}

/* The optional box sits close under the waiver: one group of two questions,
   not two sections. */
.waiver.optin {
    margin-top: .9rem;
}

/* What the pay button accepts. Baymard finds visitors abandon when they cannot
   tell whether their method works; this answers that in the same material as
   the catalogue numbers rather than in seven borrowed logos. */
.payment-accepts {
    margin: .7rem 0 0;
    line-height: 1.9;
    text-align: center;
}

.payment-accepts span {
    display: block;
}

.fineprint {
    margin-top: 1.6rem;
    color: var(--ink-soft);
}

.fineprint a {
    color: inherit;
}

/* ---------- 16. CONFIRMATION PAGES ---------- */

.notice {
    padding: 5rem 0 6rem;
    max-width: var(--measure);
}

.notice h1 {
    font-size: var(--t-headline);
    font-weight: 300;
    margin: 1.6rem 0 1.2rem;
}

.notice p {
    font-size: var(--t-lead);
    color: var(--ink-soft);
    margin-bottom: 2rem;
}

/* The files, on the thank-you page. */
.downloads {
    list-style: none;
    margin: 0 0 2rem;
    padding: 0;
}

.download-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: .8rem 1.5rem;
    flex-wrap: wrap;
    padding: .9rem 0;
    border-top: 1px solid var(--rule);
}

.download-row:last-child {
    border-bottom: 1px solid var(--rule);
}

.download-title {
    font-size: var(--t-lead);
}

/* ---------- 17. FOOTER ---------- */

.colophon {
    margin-top: 4rem;
    padding-bottom: 3rem;
}

.colophon-inner {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 1.5rem var(--gutter);
    flex-wrap: wrap;
    padding-top: 1.2rem;
}

.colophon-nav {
    display: flex;
    flex-wrap: wrap;
    gap: .55rem clamp(.85rem, 3.4vw, 1.6rem);
    margin: 0;
    padding: 0;
    list-style: none;
}

.colophon-nav a {
    text-decoration: none;
}

.colophon-nav a:hover {
    color: var(--ink);
}

.social {
    display: flex;
    gap: 1rem;
    align-items: center;
}

.social a {
    display: block;
    color: var(--ink-soft);
    transition: color var(--dur) var(--ease);
}

.social a:hover {
    color: var(--ink);
}

/* One box, one stroke weight, one colour for all three marks. Each icon is a
   24x24 stroked glyph, so they read at the same optical size. */
.social svg {
    display: block;
    width: 20px;
    height: 20px;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.6;
    stroke-linecap: round;
    stroke-linejoin: round;
}

.colophon-note {
    padding-top: 1.4rem;
    font-style: italic;
    font-size: var(--t-fine);
    color: var(--ink-soft);
    max-width: var(--measure);
}

/* ---------- 18. RESPONSIVE ---------- */

@media (max-width: 1100px) {
    .shelf {
        grid-template-columns: repeat(4, minmax(0, 1fr));
    }
}

/* Below this the work page stacks: the cover shrinks to a thumbnail beside the
   title, then the price and Buy, then page 1, so a phone shows the button on
   its first screen. */
@media (max-width: 900px) {
    .work {
        grid-template-columns: 6.5rem minmax(0, 1fr);
        grid-template-areas:
            "cover  head"
            "buy    buy"
            "score  score"
            "listen listen";
        column-gap: 1.1rem;
        padding-top: .9rem;
    }

    .work-head {
        align-self: start;
    }

    .work-title {
        font-size: var(--t-headline);
        margin-top: .2rem;
    }

    .work-buy {
        margin: 1.3rem 0 2rem;
    }

    .work-score {
        margin-left: 0;
    }

    .shelf-row {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }
}

@media (max-width: 720px) {
    .shelf,
    .shelf-row {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 1.8rem 1rem;
    }

    .book-price {
        font-size: var(--t-small);
    }

    .work-composers {
        font-size: var(--t-body);
    }

    /* Side by side, "Ajouter au panier" wraps to two lines on a phone and the
       pair stops lining up. Stacked, both read on one line, Buy first. */
    .work-actions {
        grid-template-columns: 1fr;
    }

    /* Price and the remove mark stay on the row, beside each other. */
    .cart-row {
        grid-template-columns: 3rem minmax(0, 1fr) auto auto;
        gap: .9rem;
    }

    .cart-cover {
        width: 3rem;
    }

    .masthead {
        padding-bottom: .8rem;
    }
}

/* ---------- 19. MOTION ---------- */

/* Clicking a cover carries it to the work page. Browsers without cross-document
   view transitions simply navigate. The one movement on the site, and slower
   than the 150ms of a colour change because it is a move, not a tint. */
@view-transition {
    navigation: auto;
}

::view-transition-group(*) {
    animation-duration: 380ms;
    animation-timing-function: var(--ease);
}

@media (prefers-reduced-motion: reduce) {
    @view-transition {
        navigation: none;
    }

    *,
    *::before,
    *::after {
        transition-duration: 0.01ms !important;
        animation-duration: 0.01ms !important;
    }
}

/* ---------- 20. PRINT ---------- */

@media print {
    .masthead-nav,
    .search,
    .crumb,
    .work-actions,
    .more,
    .colophon {
        display: none;
    }
}

/* The search field on the 404 page. Narrower than the prose measure so it does
   not read as a second paragraph, and given room below before the button. */
.notice-search {
    max-width: 26rem;
    margin-bottom: 2.5rem;
}
