/* ===================================================================
   John W. Fisher — A Life in Words, Music, and Memory
   Hand-built. No template, no component library, no card system.

   The art direction has to carry the site on one photograph, so the
   visual weight is carried by type, by the two real book covers at
   large size, by rules and dates, and by full-bleed colour. Nothing
   here depicts an event that did not happen.
   =================================================================== */

/* Lora is self-hosted and subset to the characters this page uses: 70KB for
   both cuts, one origin, no third-party request, and it renders identically
   whether or not Google Fonts is reachable. The supporting face is the
   platform's own UI sans, which is San Francisco on Apple, Segoe on Windows.
   Better than shipping a generic geometric webfont, and it costs nothing. */
@font-face{
    font-family:'Lora'; src:url('../fonts/lora.woff2') format('woff2');
    font-weight:400 700; font-style:normal; font-display:swap;
}
@font-face{
    font-family:'Lora'; src:url('../fonts/lora-italic.woff2') format('woff2');
    font-weight:400 700; font-style:italic; font-display:swap;
}
:root{
    --ink:#131C27;
    --navy:#1B3149;
    --navy-deep:#0F2032;
    --blue:#2E5C7E;
    --blue-soft:#7FA0BA;
    --brass:#876931;      /* labels on light grounds, 4.56:1 on ivory */
    --brass-light:#C9A868; /* labels on navy, 7.29:1 */
    --brass-rule:#A8823C;  /* hairlines and marks, decorative only */
    --ivory:#F6F1E7;
    --paper:#FCFAF7;
    --rule:#DCD2C2;
    --muted:#5C6B7A;

    --display:'Lora', 'Iowan Old Style', Georgia, 'Times New Roman', serif;
    --body:-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Helvetica Neue', Helvetica, Arial, sans-serif;

    --rail:96px;
    --gutter:clamp(20px, 5vw, 88px);
}

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

html{ scroll-behavior:smooth; }
@media (prefers-reduced-motion: reduce){ html{ scroll-behavior:auto; } }

body{
    margin:0;
    background:var(--paper);
    color:var(--ink);
    font-family:var(--body);
    font-size:18px;
    line-height:1.72;
    -webkit-font-smoothing:antialiased;
    overflow-x:clip;
}

/* The blanket height:auto exists because an HTML height attribute otherwise
   wins over width:100% and stretches covers. But it also defeats every
   object-fit:cover image, which needs a real height to crop against — that
   is why the hero photograph collapsed to its own aspect ratio instead of
   filling the viewport. Exempt the elements that are deliberately sized. */
img{ max-width:100%; height:auto; display:block; }
.hero-art img,
.spread-figure img,
.overlay > img,
.quote-plate > img,
.plate-tall img{ height:100%; }
a{ color:inherit; }

h1,h2,h3,h4{ font-family:var(--display); font-weight:400; margin:0; line-height:1.06; }

/* Paper grain. Two pixels of noise, not a texture image. */
body::before{
    content:""; position:fixed; inset:0; pointer-events:none; z-index:1; opacity:.5;
    background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='.035'/%3E%3C/svg%3E");
}

/* ---------- shared editorial atoms ---------- */

.eyebrow{
    font-family:var(--body); font-size:12.5px; font-weight:500;
    letter-spacing:.24em; text-transform:uppercase; color:var(--brass);
    display:flex; align-items:center; gap:14px; margin:0 0 26px;
}
.eyebrow::after{ content:""; height:1px; flex:1; background:var(--rule); }
.eyebrow.center{ justify-content:center; }
.eyebrow.center::before{ content:""; height:1px; width:70px; background:var(--rule); }
.eyebrow.center::after{ width:70px; flex:0 0 70px; }

.lede{ font-size:clamp(19px,1.6vw,24px); line-height:1.7; color:var(--muted); max-width:56ch; }
.body-copy p{ margin:0 0 1.35em; max-width:62ch; }
.body-copy p:last-child{ margin-bottom:0; }

.caption{
    font-size:12.5px; letter-spacing:.15em; text-transform:uppercase;
    color:var(--muted); margin-top:14px; display:block;
}
.caption b{ color:var(--ink); font-weight:500; letter-spacing:.1em; }

.wrap{ max-width:1320px; margin:0 auto; padding-inline:var(--gutter); }
.wrap-narrow{ max-width:880px; margin:0 auto; padding-inline:var(--gutter); }

section{ position:relative; }
.band-ivory{ background:var(--ivory); }
.band-navy{ background:var(--navy-deep); color:#EFE7DA; }
.band-navy h2,.band-navy h3{ color:#fff; }
.band-navy .lede{ color:#B9C6D4; }
.band-navy .eyebrow{ color:var(--brass-light); }
.band-navy .eyebrow::after,.band-navy .eyebrow::before{ background:rgba(255,255,255,.22); }

/* =================================================================
   RAIL — narrow, quiet, no icon circles
   ================================================================= */
.rail{
    position:fixed; left:0; top:0; bottom:0; width:var(--rail); z-index:40;
    background:var(--navy-deep); color:#EFE7DA;
    display:flex; flex-direction:column; align-items:center;
    padding:26px 0; gap:34px;
}
.mark{
    font-family:var(--display); font-size:19px; letter-spacing:.16em;
    color:#fff; text-decoration:none; font-weight:500;
}
.mark span{ display:block; height:1px; width:26px; background:var(--brass-rule); margin:9px auto 0; }

.rail nav{ display:flex; flex-direction:column; gap:2px; width:100%; }
.rail nav a{
    display:block; text-align:center; text-decoration:none;
    font-size:12px; letter-spacing:.17em; text-transform:uppercase;
    color:rgba(239,231,218,.62); padding:13px 4px; position:relative;
    transition:color .3s ease;
    min-height:44px;
}
.rail nav a::before{
    content:""; position:absolute; left:0; top:50%; transform:translateY(-50%) scaleY(0);
    width:2px; height:26px; background:var(--brass-rule); transition:transform .3s ease;
}
.rail nav a:hover{ color:#fff; }
.rail nav a.on{ color:#fff; }
.rail nav a.on::before{ transform:translateY(-50%) scaleY(1); }

.rail-foot{
    margin-top:auto; font-size:12px; letter-spacing:.2em; text-transform:uppercase;
    color:rgba(239,231,218,.62); writing-mode:vertical-rl; transform:rotate(180deg);
}

.page{ margin-left:var(--rail); position:relative; z-index:2; }

/* mobile bar and drawer: both are off entirely on desktop. The drawer was
   previously only styled inside the narrow media query, which left it
   rendered and clickable over the hero at every wider size. */
.bar{ display:none; }
.drawer{ display:none; }

/* =================================================================
   HERO — the photograph is the subject, type sits with it
   ================================================================= */
.hero{
    min-height:100vh; display:grid; align-items:stretch;
    grid-template-columns:1.08fr 1fr; background:var(--ivory);
}
.hero-art{ position:relative; overflow:hidden; background:var(--navy-deep); }
.hero-art img{
    width:100%; height:100%; object-fit:cover; object-position:50% 22%;
    filter:saturate(.92) contrast(1.03);
}
.hero-art::after{
    content:""; position:absolute; inset:0;
    background:linear-gradient(to right, rgba(15,32,50,.40), rgba(15,32,50,0) 46%),
               linear-gradient(to top, rgba(15,32,50,.62), rgba(15,32,50,0) 34%);
}
.hero-frame{
    position:absolute; inset:26px; border:1px solid rgba(255,255,255,.26);
    pointer-events:none;
}
.hero-stamp{
    position:absolute; left:44px; bottom:40px; z-index:2;
    font-size:12px; letter-spacing:.2em; text-transform:uppercase;
    color:rgba(255,255,255,.78);
}
.hero-stamp b{ display:block; color:#fff; font-weight:500; margin-bottom:5px; }

.hero-text{
    display:flex; flex-direction:column; justify-content:center;
    padding:clamp(40px,7vw,104px) clamp(26px,6vw,92px);
}
.hero-text h1{
    font-size:clamp(52px,7.2vw,116px); letter-spacing:-.025em;
    font-weight:400; margin-bottom:26px;
}
.hero-text h1 em{
    display:block; font-style:italic; font-weight:400;
    color:var(--blue);
}
.roles{
    display:flex; flex-wrap:wrap; gap:10px 16px; margin:0 0 30px; padding:0; list-style:none;
    font-size:12px; letter-spacing:.2em; text-transform:uppercase; color:var(--muted);
}
.roles li{ display:flex; align-items:center; gap:16px; }
.roles li+li::before{ content:""; width:4px; height:4px; border-radius:50%; background:var(--brass-rule); }
.hero-line{
    font-family:var(--display); font-size:clamp(19px,1.75vw,25px);
    line-height:1.55; font-weight:400; max-width:30ch; margin:0 0 40px; color:var(--ink);
}
.cta-row{ display:flex; flex-wrap:wrap; gap:14px; }
.btn{
    display:inline-flex; align-items:center; gap:11px;
    font-size:12px; letter-spacing:.16em; text-transform:uppercase; font-weight:500;
    padding:17px 28px; text-decoration:none; border:1px solid var(--ink);
    min-height:44px; transition:background .3s ease,color .3s ease,border-color .3s ease;
}
.btn-solid{ background:var(--ink); color:var(--paper); }
.btn-solid:hover{ background:var(--blue); border-color:var(--blue); }
.btn-ghost:hover{ background:var(--ink); color:var(--paper); }
.btn i{ font-style:normal; transition:transform .3s ease; }
.btn:hover i{ transform:translateX(4px); }

/* =================================================================
   STATEMENT — oversized type, the first big moment
   ================================================================= */
.statement{ padding:clamp(90px,13vw,190px) 0; background:var(--ivory); overflow:hidden; }
.statement h2{
    font-size:clamp(52px,10.5vw,168px); font-weight:400; letter-spacing:-.03em;
    line-height:.92; margin-bottom:clamp(40px,6vw,74px);
}
.statement h2 em{ font-style:italic; color:var(--blue); }
.making{
    list-style:none; margin:0; padding:0;
    display:grid; grid-template-columns:repeat(auto-fit,minmax(150px,1fr));
    border-top:1px solid var(--rule);
}
.making li{
    font-family:var(--display); font-size:clamp(21px,2.1vw,32px); font-weight:400;
    padding:26px 0 0; border-right:1px solid var(--rule);
    padding-right:20px;
}
.making li:last-child{ border-right:0; }
.making li span{
    display:block; font-family:var(--body); font-size:12px; letter-spacing:.2em;
    text-transform:uppercase; color:var(--brass); margin-bottom:12px;
}

/* =================================================================
   CHAPTERS
   ================================================================= */
.chapter{ padding:clamp(96px,14vw,210px) 0; }
.chapter-head{ display:flex; align-items:baseline; gap:22px; margin-bottom:44px; }
.chapter-num{
    font-family:var(--display); font-size:clamp(58px,7vw,116px); font-weight:400;
    line-height:.8; color:var(--rule); letter-spacing:-.03em;
}
.band-navy .chapter-num{ color:rgba(255,255,255,.30); }
.chapter-title{ }
.chapter-title .kicker{
    font-size:12px; letter-spacing:.24em; text-transform:uppercase;
    color:var(--brass); display:block; margin-bottom:10px;
}
/* The dark brass is calibrated for ivory and paper. On the navy band it read
   3.22:1, under the 4.5:1 floor; --brass-light is the navy-ground twin. */
.band-navy .chapter-title .kicker{ color:var(--brass-light); }
.chapter-title h2{ font-size:clamp(42px,5.8vw,84px); font-weight:400; letter-spacing:-.02em; }

.split{ display:grid; grid-template-columns:1fr 1fr; gap:clamp(34px,5vw,84px); align-items:center; }
.split.wide-left{ grid-template-columns:1.25fr 1fr; }
.split.wide-right{ grid-template-columns:1fr 1.25fr; }

/* pull quote */
.pull{
    font-family:var(--display); font-size:clamp(30px,3.8vw,56px); font-weight:400;
    font-style:italic; line-height:1.28; letter-spacing:-.015em;
    border-left:2px solid var(--brass-rule); padding-left:clamp(20px,3vw,40px);
    margin:0; max-width:24ch;
}
.pull cite{
    display:block; font-family:var(--body); font-style:normal; font-size:12px;
    letter-spacing:.2em; text-transform:uppercase; color:var(--muted); margin-top:22px;
}

/* a document-like block: the archival voice, no fake photo */
.doc{
    background:var(--paper); border:1px solid var(--rule); padding:clamp(26px,3.4vw,44px);
    position:relative;
}
.band-navy .doc{ background:rgba(255,255,255,.045); border-color:rgba(255,255,255,.16); }
.doc::before{
    content:""; position:absolute; left:-1px; top:26px; width:3px; height:44px; background:var(--brass-rule);
}
.doc .stamp{
    font-size:12px; letter-spacing:.22em; text-transform:uppercase;
    color:var(--brass); margin-bottom:16px; display:block;
}
.band-navy .doc .stamp{ color:var(--brass-light); }   /* was 2.85:1 on navy */
.doc h3{ font-size:clamp(24px,2.2vw,33px); font-weight:400; margin-bottom:14px; }
.doc p{ margin:0; font-size:15.5px; line-height:1.7; color:var(--muted); }
.band-navy .doc p{ color:#AFC0D0; }

/* the ledger: dates as an archival index, not a timeline widget */
.ledger{ list-style:none; margin:0; padding:0; border-top:1px solid var(--rule); }
.band-navy .ledger{ border-color:rgba(255,255,255,.2); }
.ledger li{
    display:grid; grid-template-columns:118px 1fr; gap:clamp(16px,3vw,44px);
    padding:24px 0; border-bottom:1px solid var(--rule);
    transition:background .35s ease;
}
.band-navy .ledger li{ border-color:rgba(255,255,255,.14); }
.ledger li:hover{ background:rgba(168,130,60,.05); }
.ledger .yr{
    font-family:var(--display); font-size:clamp(17px,1.5vw,22px); font-weight:400;
    color:var(--brass); letter-spacing:.01em;
}
.ledger h4{ font-family:var(--display); font-size:clamp(21px,1.9vw,28px); font-weight:400; margin-bottom:7px; }
.ledger p{ margin:0; font-size:15px; line-height:1.68; color:var(--muted); max-width:64ch; }
.band-navy .ledger p{ color:#AFC0D0; }

/* =================================================================
   SERMON SONG — the one idea that is entirely his
   ================================================================= */
.sermon{ padding:clamp(90px,13vw,180px) 0; }
.sermon h2{
    font-size:clamp(44px,8vw,132px); font-weight:400; letter-spacing:-.03em; line-height:.95;
    margin-bottom:34px;
}
.sermon h2 em{ font-style:italic; color:var(--brass-light); }
.staff{
    height:1px; background:rgba(255,255,255,.2); margin:0 0 10px;
    box-shadow:0 8px 0 rgba(255,255,255,.2), 0 16px 0 rgba(255,255,255,.2),
               0 24px 0 rgba(255,255,255,.2), 0 32px 0 rgba(255,255,255,.2);
}
.staff-wrap{ margin:clamp(40px,6vw,70px) 0 0; padding-bottom:42px; }

/* =================================================================
   FEATURED BOOK — publisher spread
   ================================================================= */
.feature{ padding:clamp(96px,14vw,220px) 0; }
.feature-grid{ display:grid; grid-template-columns:1fr 1fr; gap:clamp(36px,6vw,96px); align-items:center; }
.book-plate{ position:relative; }
.book-plate::before{
    content:""; position:absolute; left:8%; top:7%; width:86%; height:93%;
    background:linear-gradient(160deg, rgba(46,92,126,.16), rgba(168,130,60,.13));
}
.book-plate img{
    position:relative; width:100%; height:auto; max-width:430px; margin-inline:auto;
    box-shadow:
        0 2px 0 rgba(0,0,0,.10),
        22px 30px 60px rgba(19,28,39,.30);
    transform:perspective(1400px) rotateY(-7deg);
    transition:transform .6s cubic-bezier(.2,.7,.3,1), box-shadow .6s ease;
}
.book-plate:hover img{
    transform:perspective(1400px) rotateY(-3deg) translateY(-6px);
    box-shadow:0 2px 0 rgba(0,0,0,.10), 26px 38px 74px rgba(19,28,39,.36);
}
@media (prefers-reduced-motion: reduce){
    .book-plate img,.book-plate:hover img{ transform:none; transition:none; }
}
.feature h2{ font-size:clamp(44px,6.2vw,96px); font-weight:400; letter-spacing:-.025em; margin-bottom:8px; }
.feature h2 em{ font-style:italic; display:block; color:var(--blue); }
.byline{
    font-size:12px; letter-spacing:.2em; text-transform:uppercase; color:var(--muted);
    margin:0 0 30px;
}
.specs{ list-style:none; margin:32px 0 34px; padding:0; border-top:1px solid var(--rule); }
.specs li{
    display:grid; grid-template-columns:132px 1fr; gap:18px;
    padding:13px 0; border-bottom:1px solid var(--rule); font-size:14.5px;
}
.specs dt,.specs .k{
    font-size:12px; letter-spacing:.19em; text-transform:uppercase; color:var(--muted);
    padding-top:3px;
}
.avail{ font-size:14.5px; color:var(--muted); margin:0 0 26px; max-width:52ch; }

/* =================================================================
   THE BOOKS — a shelf, not a card grid
   ================================================================= */
.shelf{ padding:clamp(80px,11vw,150px) 0; }
.shelf-list{ margin-top:clamp(40px,5vw,70px); }
.vol{
    display:grid; grid-template-columns:clamp(150px,20vw,290px) 1fr auto; gap:clamp(24px,4vw,64px);
    align-items:start; padding:clamp(30px,4vw,52px) 0; border-top:1px solid var(--rule);
}
.vol:last-child{ border-bottom:1px solid var(--rule); }
.vol-cover img{
    width:100%; height:auto; box-shadow:14px 18px 36px rgba(19,28,39,.20);
    transition:transform .5s ease, box-shadow .5s ease;
}
.vol:hover .vol-cover img{ transform:translateY(-5px); box-shadow:18px 26px 46px rgba(19,28,39,.26); }
@media (prefers-reduced-motion: reduce){ .vol:hover .vol-cover img{ transform:none; } }
.vol-kind{
    font-size:12px; letter-spacing:.2em; text-transform:uppercase; color:var(--brass);
    display:block; margin-bottom:12px;
}
.vol h3{ font-family:var(--display); font-size:clamp(28px,3.1vw,46px); font-weight:400; margin-bottom:14px; letter-spacing:-.015em; }
.vol p{ margin:0; color:var(--muted); font-size:15.5px; max-width:58ch; }
.vol-meta{ text-align:right; min-width:150px; }
.vol-status{
    font-size:12px; letter-spacing:.18em; text-transform:uppercase;
    padding:7px 13px; border:1px solid var(--rule); display:inline-block; color:var(--muted);
    white-space:nowrap;
}
.vol-status.live{ border-color:var(--brass); color:var(--brass); }
.vol-isbn{ display:block; font-size:12.5px; letter-spacing:.06em; color:var(--muted); margin-top:14px; }

/* =================================================================
   ARCHIVE — only real artifacts, honestly captioned
   ================================================================= */
.archive{ padding:clamp(96px,14vw,210px) 0; }
.plates{
    display:grid; gap:clamp(20px,2.6vw,38px);
    grid-template-columns:repeat(12,1fr); margin-top:clamp(40px,5vw,66px);
}
.plate{ position:relative; }
/* Book covers must never be cropped: a cover is the artwork, not a texture.
   Photographs may crop to fill. */
.plate img{ width:100%; height:auto; display:block; }
.plate-tall img{ height:100%; object-fit:cover; }
.plate-a{ grid-column:span 5; }
.plate-b{ grid-column:span 3; }
.plate-c{ grid-column:span 4; }
.plate-wide{ grid-column:span 7; }
.plate-tall{ grid-column:span 5; }
.plate figcaption{
    font-size:12px; letter-spacing:.16em; text-transform:uppercase; color:var(--muted);
    margin-top:13px; display:block;
}
.plate figcaption b{ color:var(--ink); font-weight:500; }
.plate-note{
    display:flex; flex-direction:column; justify-content:center;
    border:1px solid var(--rule); padding:clamp(22px,2.6vw,34px); background:var(--paper);
}
.plate-note .n{
    font-family:var(--display); font-size:clamp(42px,5.2vw,80px); font-weight:400;
    color:var(--brass); line-height:1; margin-bottom:12px;
}
.plate-note p{ margin:0; font-size:14.5px; color:var(--muted); }

/* =================================================================
   CONTACT
   ================================================================= */
.contact{ padding:clamp(80px,11vw,150px) 0; }
.purposes{
    display:grid; grid-template-columns:repeat(3,1fr); gap:0;
    margin:clamp(40px,5vw,66px) 0 clamp(50px,6vw,80px);
    border-top:1px solid rgba(255,255,255,.2); border-bottom:1px solid rgba(255,255,255,.2);
}
.purpose{
    padding:clamp(26px,3.4vw,44px) clamp(20px,2.6vw,38px);
    border-right:1px solid rgba(255,255,255,.2);
}
.purpose:last-child{ border-right:0; }
.purpose h3{ font-size:clamp(23px,2.2vw,31px); font-weight:400; margin-bottom:12px; }
.purpose p{ margin:0 0 20px; font-size:15px; color:#AFC0D0; }
.purpose a{
    font-size:12.5px; letter-spacing:.16em; text-transform:uppercase;
    color:var(--brass-light); text-decoration:none;
    display:inline-flex; align-items:center; gap:9px; min-height:44px;
}
.purpose a i{ font-style:normal; transition:transform .3s ease; }
.purpose a:hover i{ transform:translateX(4px); }

.form-grid{ display:grid; grid-template-columns:1fr 1fr; gap:clamp(30px,5vw,80px); align-items:start; }
.field{ margin-bottom:22px; }
.field label{
    display:block; font-size:12px; letter-spacing:.19em; text-transform:uppercase;
    color:#AFC0D0; margin-bottom:9px;
}
.field input,.field textarea{
    width:100%; background:transparent; border:0; border-bottom:1px solid rgba(255,255,255,.28);
    color:#fff; font-family:var(--body); font-size:16px; padding:11px 2px; min-height:44px;
    transition:border-color .3s ease;
}
.field textarea{ resize:vertical; min-height:110px; }
.field input:focus,.field textarea:focus{ border-bottom-color:var(--brass-light); }
.field input:focus-visible,.field textarea:focus-visible{
    outline:2px solid var(--brass-light); outline-offset:3px;
}
.btn-send{
    background:var(--brass); color:var(--navy-deep); border:1px solid var(--brass);
    font-family:var(--body); cursor:pointer;
}
.btn-send:hover{ background:var(--brass-light); border-color:var(--brass-light); }

.details{ list-style:none; margin:0; padding:0; }
.details li{ padding:20px 0; border-bottom:1px solid rgba(255,255,255,.16); }
.details .k{
    font-size:12px; letter-spacing:.2em; text-transform:uppercase; color:var(--brass-light);
    display:block; margin-bottom:8px;
}
.details a{ color:#EFE7DA; text-decoration:none; }
.details a:hover{ color:#fff; text-decoration:underline; }
.socials{ display:flex; flex-wrap:wrap; gap:10px 26px; margin-top:8px; }
.socials a{ font-size:13px; min-height:44px; display:inline-flex; align-items:center; }

.colophon{
    padding:44px 0 60px; font-size:13.5px; line-height:1.85; color:#8FA2B4;
    border-top:1px solid rgba(255,255,255,.14); margin-top:clamp(50px,6vw,80px);
}
.colophon a{ color:#B9C6D4; }

/* =================================================================
   REVEAL — CSS defaults to visible; JS opts in.
   A script failure costs an animation, never the content.
   ================================================================= */
.rv{ opacity:1; transform:none; }
html.anim .rv{ opacity:0; transform:translateY(22px); transition:opacity .9s ease, transform .9s cubic-bezier(.2,.7,.3,1); }
html.anim .rv.in{ opacity:1; transform:none; }
@media (prefers-reduced-motion: reduce){
    html.anim .rv{ opacity:1 !important; transform:none !important; transition:none !important; }
}

*:focus-visible{
    outline:2px solid var(--brass); outline-offset:3px;
}
.band-navy *:focus-visible{ outline-color:var(--brass-light); }

.skip{
    position:absolute; left:-9999px; top:0; background:var(--ink); color:#fff;
    padding:14px 22px; z-index:100; text-decoration:none; font-size:13px;
}
.skip:focus{ left:var(--rail); }

/* =================================================================
   RESPONSIVE
   ================================================================= */
@media (max-width: 1100px){
    .vol{ grid-template-columns:150px 1fr; }
    .vol-meta{ grid-column:2; text-align:left; margin-top:16px; }
    .purposes{ grid-template-columns:1fr; }
    .purpose{ border-right:0; border-bottom:1px solid rgba(255,255,255,.2); }
    .purpose:last-child{ border-bottom:0; }
}

@media (max-width: 900px){
    :root{ --rail:0px; }
    .rail{ display:none; }
    .page{ margin-left:0; padding-top:62px; }
    .skip:focus{ left:12px; }

    .bar{
        display:flex; position:fixed; top:0; left:0; right:0; z-index:50; height:62px;
        background:var(--navy-deep); color:#fff; align-items:center;
        justify-content:space-between; padding:0 18px;
    }
    .bar .mark{ font-size:17px; }
    .bar .mark span{ display:none; }
    .bar button{
        background:none; border:0; color:#fff; font-family:var(--body);
        font-size:12px; letter-spacing:.18em; text-transform:uppercase;
        min-width:44px; min-height:44px; cursor:pointer; display:flex;
        align-items:center; gap:9px;
    }
    .bar-lines{ display:inline-block; width:20px; }
    .bar-lines::before,.bar-lines::after{
        content:""; display:block; height:1.5px; background:#fff; margin:4px 0;
    }
    .drawer{
        display:flex;
        position:fixed; inset:62px 0 0; background:var(--navy-deep); z-index:49;
        transform:translateY(-14px); opacity:0; pointer-events:none;
        transition:opacity .3s ease, transform .3s ease;
        display:flex; flex-direction:column; justify-content:center; gap:6px; padding:0 26px;
    }
    .drawer.open{ opacity:1; transform:none; pointer-events:auto; }
    .drawer a{
        font-family:var(--display); font-size:29px; font-weight:400; color:#EFE7DA;
        text-decoration:none; padding:13px 0; border-bottom:1px solid rgba(255,255,255,.12);
        min-height:44px;
    }

    .hero{ grid-template-columns:1fr; min-height:0; }
    .hero-art{ height:58vh; min-height:340px; }
    .hero-text{ padding:44px 26px 60px; }
    .hero-frame{ inset:16px; }
    .hero-stamp{ left:30px; bottom:28px; }

    .split,.split.wide-left,.split.wide-right,.feature-grid,.form-grid{ grid-template-columns:1fr; }
    .chapter-head{ flex-direction:column; align-items:flex-start; gap:8px; }
    .making li{ border-right:0; border-bottom:1px solid var(--rule); padding-bottom:20px; }
    .making li:last-child{ border-bottom:0; }

    .plates{ grid-template-columns:repeat(6,1fr); }
    .plate-a,.plate-b,.plate-c,.plate-wide,.plate-tall{ grid-column:span 6; }
    .plate-b,.plate-c{ grid-column:span 3; }

    .ledger li{ grid-template-columns:1fr; gap:6px; }
    .vol{ grid-template-columns:170px 1fr; gap:26px; }
    .specs li{ grid-template-columns:1fr; gap:4px; }
    .specs .k{ padding-top:0; }
}

@media (max-width: 480px){
    body{ font-size:16px; }
    .vol{ grid-template-columns:1fr; }
    .vol-cover img{ max-width:180px; }
    .plate-b,.plate-c{ grid-column:span 6; }
    .hero-art{ height:52vh; min-height:290px; }
    .roles{ gap:8px 12px; font-size:12px; }
}

/* The record block sits beside body copy, so it needs a little more air and
   room for the run of bolded labels. */
.doc p b{ color:var(--ink); font-weight:500; }
.band-navy .doc p b{ color:#fff; }
.doc p{ line-height:1.95; }

/* ---------------------------------------------------------------
   Touch targets the audit caught.
   Contact links rendered 19px tall, the TikTok link 37px wide, and the
   rail wordmark 41x30. All are real targets people press.
   --------------------------------------------------------------- */
.details a{
    display:inline-flex; align-items:center;
    min-height:44px; min-width:44px; padding:4px 0;
}
.socials a{ min-width:60px; padding:0 2px; }
.mark{
    display:inline-flex; flex-direction:column; align-items:center; justify-content:center;
    min-width:44px; min-height:44px;
}

/* Slightly more air now that the labels are larger. */
.eyebrow{ letter-spacing:.2em; }
.vol-kind,.hero-stamp,.doc .stamp,.chapter-title .kicker{ letter-spacing:.18em; }
.rail nav a{ letter-spacing:.14em; }

/* ============================================================
   17. EDITORIAL PHOTOGRAPHY
   A photograph is set as a document plate, not a card: a hairline
   above it, the image itself, then a caption in the same brass
   small-caps used for every other label on the page. No shadow,
   no rounded corner, no hover lift — those read as UI, and this
   is meant to read as print.
   ============================================================ */
.photo{ margin:clamp(46px,7vw,92px) 0 0; }
.photo img{
    display:block; width:100%; height:auto;
    border-top:1px solid var(--rule);
    border-bottom:1px solid var(--rule);
}
.band-navy .photo img{ border-color:rgba(201,168,104,.34); }

.photo figcaption{
    display:flex; gap:14px; align-items:baseline;
    margin-top:14px;
    font-size:12.5px; line-height:1.5; letter-spacing:.1em;
    text-transform:uppercase; color:var(--brass);
}
.band-navy .photo figcaption{ color:var(--brass-light); }
.photo figcaption b{
    font-weight:600; white-space:nowrap;
    border-right:1px solid var(--rule); padding-right:14px;
}
.band-navy .photo figcaption b{ border-color:rgba(201,168,104,.4); }
.photo figcaption span{
    letter-spacing:.02em; text-transform:none; font-size:13.5px;
    color:var(--muted); font-style:italic;
}
.band-navy .photo figcaption span{ color:rgba(246,241,231,.72); }

/* Full-bleed variant: escapes .wrap and runs edge to edge.
   Only used where the source file is genuinely wide enough. */
/* transform:translateX(-50%) leaves the untransformed box sticking out to the
   right and adds it to the document's scroll width — the desktop audit caught
   768px of horizontal overflow from exactly that. Margin-only bleed has no
   phantom box. body uses overflow-x:clip rather than hidden because clip does
   not create a scroll container, so the sticky rail nav keeps working. */
.photo-bleed{
    /* The bleed target is the .page column, not the viewport: the fixed rail
       occupies var(--rail) on the left, so a plain 100vw ran 96px past the
       right edge (the audit read 48px of it at every desktop width). --rail
       collapses to 0 under 900px, so one formula covers every viewport. */
    --bleed:calc(100vw - var(--rail));
    width:var(--bleed); max-width:var(--bleed);
    margin-left:calc(50% - var(--bleed) / 2);
    margin-right:calc(50% - var(--bleed) / 2);
}
.photo-bleed figcaption{
    max-width:1320px; margin-left:auto; margin-right:auto;
    padding-inline:var(--gutter);
}
.photo-bleed img{ max-height:74vh; object-fit:cover; object-position:center 32%; }

/* Paired with body copy rather than standing alone. */
.photo-inset{ margin-top:clamp(34px,5vw,58px); }

@media (max-width:900px){
    .photo figcaption{ flex-direction:column; gap:6px; }
    /* nowrap keeps the plate label on one line beside the note on wide screens,
       but at 280px "Plate III - The Sermon Song Singers" is 292px wide and
       pushed the whole document 32px sideways. Once the caption stacks there is
       nothing left to keep on one line, so let it wrap. */
    .photo figcaption b{ border-right:0; padding-right:0; white-space:normal; }
    .photo-bleed img{ max-height:none; }
}

/* ============================================================
   18. LAYOUT VARIETY
   Eight photographs all set as identical full-bleed plates read
   as one template repeated. These are the alternative settings:
   a half-and-half split, a photograph carrying overlaid display
   type, and a photograph paired with a verified quote. The rule
   for the page is simply that no two consecutive sections use
   the same one.
   ============================================================ */

/* --- TYPE B: image 50% of the viewport, text in the other half --- */
.spread{
    --bleed:calc(100vw - var(--rail));
    width:var(--bleed); max-width:var(--bleed);
    margin-left:calc(50% - var(--bleed) / 2);
    margin-right:calc(50% - var(--bleed) / 2);
    display:grid; grid-template-columns:1fr 1fr; align-items:stretch;
    margin-top:clamp(46px,7vw,92px);
}
.spread-figure{ margin:0; position:relative; overflow:hidden; min-height:clamp(420px,72vh,840px); }
.spread-figure img{
    width:100%; height:100%; object-fit:cover; display:block;
    transition:transform .9s cubic-bezier(.2,.7,.3,1);
}
.spread:hover .spread-figure img{ transform:scale(1.02); }
.spread-body{
    display:flex; flex-direction:column; justify-content:center;
    padding:clamp(34px,5vw,86px); background:var(--ivory);
}
.band-ivory .spread-body{ background:var(--paper); }
.spread-body .eyebrow{ margin-bottom:18px; }
.spread-body h3{
    font-family:var(--display); font-weight:400; letter-spacing:-.02em;
    font-size:clamp(31px,3.9vw,60px); line-height:1.07; margin:0 0 22px;
}
.spread-body p{ font-size:clamp(17px,1.35vw,19.5px); line-height:1.75; color:var(--muted); max-width:44ch; margin:0 0 1.1em; }
.spread-flip .spread-figure{ order:2; }

/* --- TYPE C: the photograph carries the headline --- */
.overlay{
    --bleed:calc(100vw - var(--rail));
    position:relative; width:var(--bleed); max-width:var(--bleed);
    margin-left:calc(50% - var(--bleed) / 2);
    margin-right:calc(50% - var(--bleed) / 2);
    min-height:clamp(560px,92vh,1040px);
    display:flex; align-items:flex-end;
    overflow:hidden; isolation:isolate;
}
.overlay > img{
    position:absolute; inset:0; width:100%; height:100%;
    object-fit:cover; object-position:center 34%; z-index:-2;
}
/* A single gradient, not a flat scrim: the type stays legible at the
   foot of the frame while the photograph keeps its own light at the top. */
.overlay::after{
    content:""; position:absolute; inset:0; z-index:-1;
    background:
      linear-gradient(to top,
        rgba(15,32,50,.94) 0%, rgba(15,32,50,.78) 24%,
        rgba(15,32,50,.34) 52%, rgba(15,32,50,.06) 76%),
      linear-gradient(to right,
        rgba(15,32,50,.62) 0%, rgba(15,32,50,.22) 38%, rgba(15,32,50,0) 66%);
}
.overlay-inner{ padding:clamp(34px,6vw,96px); max-width:1320px; width:100%; margin:0 auto; }
.overlay .eyebrow{ color:var(--brass-light); }
.overlay h2{
    font-family:var(--display); font-weight:400; color:#fff;
    font-size:clamp(48px,8.2vw,140px); line-height:.95; letter-spacing:-.035em;
    margin:14px 0 0; text-wrap:balance;
}
.overlay .stat{
    display:flex; align-items:baseline; gap:18px; margin-top:clamp(22px,3vw,40px);
    border-top:1px solid rgba(201,168,104,.4); padding-top:20px; max-width:520px;
}
.overlay .stat b{
    font-family:var(--display); font-weight:400; color:var(--brass-light);
    font-size:clamp(48px,6vw,96px); line-height:1; letter-spacing:-.035em;
}
.overlay .stat span{
    font-size:14px; letter-spacing:.14em; text-transform:uppercase;
    color:rgba(246,241,231,.82); line-height:1.5;
}
.overlay .credit{
    position:absolute; right:clamp(14px,2vw,26px); bottom:clamp(10px,1.4vw,16px);
    font-size:11.5px; letter-spacing:.08em; color:rgba(246,241,231,.62);
    z-index:1; margin:0;
}

/* --- TYPE D: photograph as the ground for a verified quote --- */
.quote-plate{
    --bleed:calc(100vw - var(--rail));
    position:relative; width:var(--bleed); max-width:var(--bleed);
    margin:clamp(46px,7vw,92px) calc(50% - var(--bleed) / 2) 0;
    min-height:clamp(500px,80vh,880px);
    display:grid; place-items:center; overflow:hidden; isolation:isolate;
}
.quote-plate > img{
    position:absolute; inset:0; width:100%; height:100%;
    object-fit:cover; object-position:center 30%; z-index:-2;
}
.quote-plate::after{ content:""; position:absolute; inset:0; z-index:-1; background:rgba(15,32,50,.72); }
.quote-plate blockquote{
    margin:0; padding:clamp(30px,5vw,72px); max-width:22ch; text-align:center;
    font-family:var(--display); font-style:italic; font-weight:400; color:#fff;
    font-size:clamp(30px,4.8vw,74px); line-height:1.14; letter-spacing:-.018em;
}
.quote-plate cite{
    display:block; margin-top:26px; font-style:normal; font-family:var(--body);
    font-size:12.5px; letter-spacing:.18em; text-transform:uppercase;
    color:var(--brass-light);
}

@media (max-width:900px){
    .spread{ grid-template-columns:1fr; }
    .spread-flip .spread-figure{ order:0; }
    .spread-figure{ min-height:clamp(280px,52vh,420px); }
    .overlay{ min-height:clamp(440px,74vh,620px); }
    .overlay h2{ font-size:clamp(38px,10vw,64px); }
    .quote-plate blockquote{ max-width:none; }
}

/* ============================================================
   19. THE SERMON SONG — words becoming notation
   Two stacked layers cross-faded on scroll: the words of the
   reading, then the staff they turned into. The notation is the
   resting state, so if the script never runs, or motion is
   reduced, the section still shows the finished idea rather
   than a blank box.
   ============================================================ */
.sermon-lede{ max-width:34ch; color:#AFC0D0 !important; margin-bottom:clamp(30px,4vw,54px); }
.sermon-lede + .morph{ margin-top:0; }

.morph{
    position:relative; margin:clamp(34px,5vw,70px) 0;
    padding:clamp(26px,4vw,52px) 0;
    border-top:1px solid rgba(201,168,104,.26);
    border-bottom:1px solid rgba(201,168,104,.26);
    min-height:clamp(150px,20vw,220px);
    display:grid; place-items:center;
}
.morph-words, .morph-staff{ grid-area:1 / 1; width:100%; }

.morph-words{
    display:flex; flex-wrap:wrap; justify-content:center;
    gap:.32em clamp(14px,2vw,30px);
    font-family:var(--display); font-style:italic; font-weight:400;
    font-size:clamp(24px,3.6vw,54px); line-height:1.2; color:#F6F1E7;
    text-align:center;
}
.morph-staff{ color:var(--brass-light); max-width:840px; opacity:0; }

/* Resting state when nothing is driving the animation. */
.morph-staff{ opacity:1; }
.morph-words{ opacity:1; }

/* Only once the script marks the section as animatable do the two
   layers become a cross-fade rather than an overlay. */
.js-morph .morph-staff{ opacity:0; transform:translateY(8px); }
.js-morph .morph .ms-notes g{ opacity:0; transform:translateY(6px); }
.js-morph .morph.is-lit .morph-words{ opacity:0; transform:translateY(-10px); }
.js-morph .morph.is-lit .morph-staff{ opacity:1; transform:none; }
.js-morph .morph.is-lit .ms-notes g{ opacity:1; transform:none; }

.js-morph .morph-words{ transition:opacity .7s ease .15s, transform .7s ease .15s; }
.js-morph .morph-staff{ transition:opacity .8s ease .45s, transform .8s ease .45s; }
.js-morph .ms-notes g{ transition:opacity .5s ease, transform .5s ease; }
.js-morph .morph.is-lit .ms-notes g:nth-child(1){ transition-delay:.75s; }
.js-morph .morph.is-lit .ms-notes g:nth-child(2){ transition-delay:.86s; }
.js-morph .morph.is-lit .ms-notes g:nth-child(3){ transition-delay:.97s; }
.js-morph .morph.is-lit .ms-notes g:nth-child(4){ transition-delay:1.08s; }
.js-morph .morph.is-lit .ms-notes g:nth-child(5){ transition-delay:1.19s; }
.js-morph .morph.is-lit .ms-notes g:nth-child(6){ transition-delay:1.30s; }

.morph-cap{
    grid-area:1 / 1; align-self:end; justify-self:center;
    margin:0; transform:translateY(clamp(34px,5vw,60px));
    font-size:12px; letter-spacing:.2em; text-transform:uppercase;
    color:rgba(201,168,104,.85);
}

@media (prefers-reduced-motion: reduce){
    .js-morph .morph-words{ opacity:0; transition:none; }
    .js-morph .morph-staff, .js-morph .morph .ms-notes g{ opacity:1; transform:none; transition:none; }
}

/* Small print under a split-spread body, for the generated-image note. */
.credit-note{
    margin-top:auto; padding-top:22px;
    font-size:12px !important; letter-spacing:.09em; text-transform:uppercase;
    color:var(--brass) !important;
}
.band-navy .credit-note{ color:var(--brass-light) !important; }

/* Featured book: the cover is the hero of this section, so let it run
   large and give it real physical weight rather than a card border. */
.feature-grid{ grid-template-columns:0.92fr 1fr; gap:clamp(36px,6vw,110px); }
.book-plate img{
    max-width:none; width:100%;
    box-shadow:0 2px 4px rgba(19,28,39,.10), 0 26px 60px -18px rgba(19,28,39,.42);
}
.buy-row{ display:flex; flex-wrap:wrap; gap:14px; margin-top:30px; }
.avail{ margin-top:16px; font-size:13.5px; color:var(--muted); max-width:46ch; }

@media (max-width:900px){
    .feature-grid{ grid-template-columns:1fr; }
    .book-plate img{ max-width:340px; margin:0 auto; }
}

/* Two failures the contrast audit caught after the layout change.

   1. .spread-body paints itself ivory, but inside the navy band the text
      colour is still inherited white — "The reading comes first." measured
      1.13:1. Inside a dark band the panel has to be dark too.
   2. .overlay relied entirely on the photograph and its gradient for the
      dark ground under white type. If that image 404s or is still decoding,
      the type is white on ivory and invisible. A base colour underneath
      makes the section legible before, and without, the photograph. */
.overlay{ background:var(--navy-deep); color:#fff; }
.quote-plate{ background:var(--navy-deep); }

.band-navy .spread-body{ background:#16293D; }
.band-navy .spread-body h3{ color:#F6F1E7; }
.band-navy .spread-body p{ color:#AFC0D0; }
.band-navy .spread-body .eyebrow{ color:var(--brass-light); }

/* Purchase actions live with each title rather than in a separate row, so a
   reader deciding on a book acts where they are. Only the two titles with a
   verified retailer listing get a button; the rest keep their status label
   and nothing that looks clickable. */
.vol-meta{ display:flex; flex-direction:column; align-items:flex-end; gap:12px; }
.vol-buy{
    display:inline-flex; align-items:center; gap:9px; max-width:100%;
    padding:12px 20px; background:var(--ink); color:var(--paper);
    font-size:12.5px; letter-spacing:.12em; text-transform:uppercase;
    text-decoration:none; white-space:nowrap;
    transition:background .3s ease, transform .3s ease;
}
.vol-buy:hover{ background:var(--blue); transform:translateY(-2px); }
.vol-pub{
    display:inline-flex; align-items:center; min-height:44px; padding:0 2px;
    font-size:12px; letter-spacing:.1em; text-transform:uppercase;
    color:var(--brass); text-decoration:none;
    box-shadow:inset 0 -1px 0 currentColor;
}
.vol-pub:hover{ color:var(--blue); }
@media (prefers-reduced-motion: reduce){ .vol-buy:hover{ transform:none; } }
/* The status/buy column is a third grid track. Below 700px there is no room
   for three tracks, and leaving it to auto-place pushed it into an implicit
   column 59px past the viewport — which then stretched the fixed drawer to
   the document's scroll width and failed every mobile viewport at once.
   Stacking the whole row removes the third track entirely. */
@media (max-width:700px){
    .vol{ grid-template-columns:1fr; gap:22px; }
    .vol-cover{ max-width:220px; }
    .vol-meta{ flex-direction:row; align-items:center; justify-content:flex-start; flex-wrap:wrap; }
}

/* ============================================================
   20. MOTION
   Everything here is opacity and transform only, so nothing
   triggers layout. The resting state of every element is
   *visible*: the script adds .js-motion and only then are the
   start states applied. A failed script therefore costs an
   animation and never costs content.
   ============================================================ */

/* --- hero entrance: image uncovers, then name, roles, line, buttons --- */
.js-motion .hero-art img{ clip-path:inset(0 0 100% 0); transform:scale(1.06); }
.js-motion .hero-art.in img{
    clip-path:inset(0 0 0 0); transform:scale(1);
    transition:clip-path 1s cubic-bezier(.22,.7,.25,1), transform 1.4s cubic-bezier(.22,.7,.25,1);
}
.js-motion .hero-text > *{ opacity:0; transform:translateY(18px); }
.js-motion .hero-text.in > *{
    opacity:1; transform:none;
    transition:opacity .7s ease, transform .7s cubic-bezier(.22,.7,.25,1);
}
.js-motion .hero-text.in > *:nth-child(1){ transition-delay:.20s; }
.js-motion .hero-text.in > *:nth-child(2){ transition-delay:.34s; }
.js-motion .hero-text.in > *:nth-child(3){ transition-delay:.46s; }
.js-motion .hero-text.in > *:nth-child(4){ transition-delay:.58s; }

/* --- editorial mask reveal on the major photographs --- */
.js-motion .spread-figure img,
.js-motion .overlay > img,
.js-motion .quote-plate > img{ clip-path:inset(0 0 100% 0); }
.js-motion .in-view .spread-figure img,
.js-motion .overlay.in-view > img,
.js-motion .quote-plate.in-view > img{
    clip-path:inset(0 0 0 0);
    transition:clip-path 1.05s cubic-bezier(.22,.7,.25,1);
}
/* The body copy beside a photograph follows it rather than arriving together. */
.js-motion .spread-body > *{ opacity:0; transform:translateY(16px); }
.js-motion .in-view .spread-body > *{
    opacity:1; transform:none;
    transition:opacity .65s ease, transform .65s cubic-bezier(.22,.7,.25,1);
}
.js-motion .in-view .spread-body > *:nth-child(1){ transition-delay:.26s; }
.js-motion .in-view .spread-body > *:nth-child(2){ transition-delay:.36s; }
.js-motion .in-view .spread-body > *:nth-child(3){ transition-delay:.46s; }
.js-motion .in-view .spread-body > *:nth-child(4){ transition-delay:.56s; }

/* --- photograph hover: restrained, and only where a pointer exists --- */
@media (hover:hover) and (pointer:fine){
    .overlay > img, .quote-plate > img{ transition:transform 1.1s cubic-bezier(.2,.7,.3,1); }
    .overlay:hover > img, .quote-plate:hover > img{ transform:scale(1.03); }
}

/* --- the timeline draws itself as it is read --- */
.ledger{ position:relative; }
.ledger::before{
    content:""; position:absolute; left:0; top:0; bottom:0; width:1px;
    background:var(--brass-rule); opacity:.5;
    transform:scaleY(0); transform-origin:top;
}
.js-motion .ledger.in-view::before{
    transform:scaleY(1); transition:transform 1.5s cubic-bezier(.3,.6,.3,1);
}
.js-motion .ledger li{ opacity:0; transform:translateX(-14px); }
.js-motion .ledger.in-view li{
    opacity:1; transform:none;
    transition:opacity .55s ease, transform .55s cubic-bezier(.22,.7,.25,1);
}
.js-motion .ledger.in-view li:nth-child(1){ transition-delay:.20s; }
.js-motion .ledger.in-view li:nth-child(2){ transition-delay:.31s; }
.js-motion .ledger.in-view li:nth-child(3){ transition-delay:.42s; }
.js-motion .ledger.in-view li:nth-child(4){ transition-delay:.53s; }
.js-motion .ledger.in-view li:nth-child(5){ transition-delay:.64s; }
.js-motion .ledger.in-view li:nth-child(6){ transition-delay:.75s; }
.js-motion .ledger.in-view li:nth-child(7){ transition-delay:.86s; }
.js-motion .ledger.in-view li:nth-child(8){ transition-delay:.97s; }

/* Not every honour carries the same weight. The four the brief names are
   raised; the rest recede rather than being deleted. */
.ledger li.major h4{ font-size:clamp(24px,2.4vw,36px); }
.ledger li.major .yr{ color:var(--brass); font-size:clamp(19px,1.8vw,26px); }
.ledger li.major{ padding-block:clamp(20px,2.4vw,34px); }
.ledger li.major::marker{ content:none; }
.ledger li:not(.major) h4{ font-size:clamp(17px,1.4vw,20px); color:var(--muted); }
.ledger li:not(.major) p{ font-size:14px; }

/* --- book hover: lift, and the actions arrive with it --- */
@media (hover:hover) and (pointer:fine){
    .vol-meta .vol-buy, .vol-meta .vol-pub{
        opacity:.55; transition:opacity .35s ease, background .3s ease, transform .3s ease, color .3s ease;
    }
    .vol:hover .vol-buy, .vol:hover .vol-pub, .vol:focus-within .vol-buy, .vol:focus-within .vol-pub{ opacity:1; }
    .vol:hover .vol-cover img{ transform:translateY(-7px) scale(1.02); }
}

/* --- parallax, desktop only, capped at 26px --- */
.js-motion .hero-art img{ will-change:transform; }

@media (prefers-reduced-motion: reduce){
    .js-motion .hero-art img,
    .js-motion .hero-text > *,
    .js-motion .spread-figure img,
    .js-motion .overlay > img,
    .js-motion .quote-plate > img,
    .js-motion .spread-body > *,
    .js-motion .ledger li{
        opacity:1 !important; transform:none !important; clip-path:none !important;
        transition:none !important;
    }
    .js-motion .ledger::before{ transform:scaleY(1); transition:none; }
}

/* Archive: a collection laid out on a table, not a row of equal cards.
   The lead cover runs larger than the rest and the second overlaps it
   slightly, which is what stops the grid reading as a card list. */
/* Two clean rows of twelve. span 6 + span 4 left a 2-column remainder that
   pulled the notes and the portrait into a ragged third row. */
.plate-lead{ grid-column:span 7; }
.plate-lead img{ box-shadow:0 3px 6px rgba(19,28,39,.12), 0 30px 64px -20px rgba(19,28,39,.44); }
.plate-lap{ grid-column:span 5; align-self:end; }
.plate-lap img{ box-shadow:0 2px 5px rgba(19,28,39,.10), 0 22px 48px -18px rgba(19,28,39,.38); }
@media (min-width:901px){
    .plate-lap{ margin-left:-9%; margin-bottom:6%; z-index:2; position:relative; }
    .plate-b{ align-self:center; }
}
.plate figcaption b{ color:var(--brass); letter-spacing:.16em; }

/* Row two: portrait, then the two figures. */
.plates .plate-tall{ grid-column:span 5; }
.plates .plate-b{ grid-column:span 3; }
.plates .plate-wide{ grid-column:span 4; }

/* ============================================================
   21. FINAL POLISH
   ============================================================ */

/* The closing portrait is the emotional end of the story, so it runs taller
   than the working overlays and reveals more slowly than anything else. */
.overlay-close{ min-height:clamp(600px,96vh,1120px); }
.js-motion .overlay-close > img{ transform:scale(1.05); }
.js-motion .overlay-close.in-view > img{
    transform:scale(1);
    transition:clip-path 1.5s cubic-bezier(.22,.7,.25,1), transform 2.4s cubic-bezier(.22,.7,.25,1);
}

/* Hover affordance on the covers that lead somewhere. It is a label, not a
   button: the whole title row is already the link, and adding a second
   control would say "shop" where the page is trying to say "library". */
.vol-cover{ position:relative; }
.vol-peek{
    position:absolute; left:50%; bottom:14px; transform:translate(-50%,10px);
    z-index:3; opacity:0; pointer-events:none; white-space:nowrap;
    padding:9px 16px; background:rgba(19,28,39,.92); color:var(--paper);
    font-size:11.5px; letter-spacing:.14em; text-transform:uppercase;
    transition:opacity .35s ease, transform .35s cubic-bezier(.22,.7,.25,1);
}
@media (hover:hover) and (pointer:fine){
    .vol:hover .vol-peek, .vol:focus-within .vol-peek{ opacity:1; transform:translate(-50%,0); }
}

/* A life unfolding rather than a list of credentials: the four milestones
   that matter get room around them and a mark on the rule. */
.ledger li.major{ position:relative; }
.ledger li.major::before{
    content:""; position:absolute; left:-4px; top:calc(clamp(20px,2.4vw,34px) + 12px);
    width:7px; height:7px; border-radius:50%; background:var(--brass);
}
.ledger li.major + li:not(.major){ padding-top:clamp(18px,2vw,28px); }
.ledger li.major p{ font-size:15.5px; max-width:52ch; }

@media (prefers-reduced-motion: reduce){
    .vol-peek{ transition:none; }
    .js-motion .overlay-close > img{ transform:none; transition:none; }
}

/* Book covers measured 0x0 at every width up to 700px — the entire catalogue
   was invisible on phones and small tablets, while the titles beside it
   rendered normally, so nothing looked broken.

   Cause: once the row stacks, .vol-cover has no definite width, and its only
   child is an <img width:100%>. A percentage against an indefinite parent
   resolves to auto, the parent then sizes to its content, and the two agree
   on zero. Giving the cover a real width breaks the circle. The audit missed
   it because a 0x0 image is neither overflowing nor broken — naturalWidth was
   600 the whole time. */
@media (max-width:700px){
    /* Five separate media blocks set grid-template-columns on .vol, and the one
       that won left a zero-width first track, so every book cover measured 0x0
       from 700px down — the whole catalogue invisible on phones while the
       titles beside it rendered normally. Rather than add a sixth column rule
       and hope, take the row out of grid entirely below 700px: display:block
       has no tracks to collapse, and .shelf-list .vol outranks every plain
       .vol rule in the file. The cover is then sized absolutely with max-width
       cleared — the global img{max-width:100%} was resolving against the
       zero-width parent and clamping the image back to nothing. */
    .shelf-list .vol{ display:block; }
    .shelf-list .vol > *{ margin-bottom:20px; }
    .shelf-list .vol > *:last-child{ margin-bottom:0; }
    .vol-cover{ width:auto; max-width:none; }
    .vol-cover img{ width:clamp(130px,40vw,220px); height:auto; max-width:none; }
}
