/* ==========================================================================
   Exhale — exhalehardcore.com
   Palette sampled from the Death Pool artwork.
   ========================================================================== */

@font-face {
    font-family: "Pirata One";
    src: url("../fonts/pirata-one-latin.woff2") format("woff2");
    font-weight: 400;
    font-style: normal;
    font-display: swap;
}

:root {
    --ink: #1d1e1b;
    --ink-lift: #24251f;
    --bone: #e0d9a8;
    --blush: #f5bcb8;
    --paper: #ede9dc;

    --font-display: "Pirata One", Luminari, "UnifrakturCook", serif;
    --font-body: ui-sans-serif, system-ui, -apple-system, "Helvetica Neue", Arial, sans-serif;

    --frame-inset: clamp(0.75rem, 2.5vw, 1.75rem);
    --shell-max: 46rem;
}

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

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

body {
    margin: 0;
    background-color: var(--ink);
    /* Only visible when the WebGL canvas is absent, so the no-WebGL fallback
       keeps the same lit-from-the-centre feel. */
    background-image: radial-gradient(ellipse at center, transparent 35%, rgba(0, 0, 0, 0.55) 100%);
    background-attachment: fixed;
    color: var(--paper);
    font-family: var(--font-body);
    font-size: 1rem;
    line-height: 1.6;
    letter-spacing: 0.01em;
}

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

/* --------------------------------------------------------------------------
   Photocopy grain — a single inline SVG, no image request
   -------------------------------------------------------------------------- */

/* Animated grain and haze, behind everything. Falls back to the static .grain
   overlay below when WebGL is unavailable. */
.fx {
    position: fixed;
    inset: 0;
    z-index: 0;
    display: block;
    width: 100%;
    height: 100%;
    pointer-events: none;
}

/* The current sleeve, blurred past reading, sitting between the shader and the
   grain. It is colour rather than picture: at that radius there is no artwork
   left, only the bloom off the middle of it — a cast the palette, sampled off
   the near-black Death Pool sleeve, never had of its own. Which cast depends on
   the record: Silent Cordon puts a cold green over the page where Calling of
   the Void put a warm one, and that is the point of hanging it off the sleeve.
   On body::before rather than an element of its own so /riders picks it up
   without any markup, and so the url stays relative to the stylesheet and
   resolves from both depths.

   --bg-artwork is the dial. Much past 0.25 the bloom starts competing with the
   copy over it; at 0 the layer is simply gone. */
:root {
    --bg-artwork: 0.1;
}

body::before {
    content: "";
    position: fixed;
    inset: 0;
    z-index: 1;
    pointer-events: none;
    /* Versioned like the stylesheet tags are, and for the same reason: the file
       is served `access plus 30 days` and the next sleeve replaces it at this
       same path, so a returning visitor would keep the old record's colour for
       a month. Bump this whenever make-page-bg.sh is re-run. */
    background: url("../img/bg-artwork.jpg?v=20260903") center / cover no-repeat;
    opacity: var(--bg-artwork);
}

.grain {
    position: fixed;
    inset: 0;
    z-index: 9;
    pointer-events: none;
    opacity: 0.1;
    mix-blend-mode: overlay;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* --------------------------------------------------------------------------
   Ornamental frame
   -------------------------------------------------------------------------- */

.frame {
    position: relative;
    z-index: 1;
    min-height: 100vh;
    min-height: 100svh;
    margin: var(--frame-inset);
    padding: clamp(1.75rem, 6vw, 4.5rem) clamp(1rem, 4vw, 3rem) clamp(1.25rem, 3vw, 2rem);
    border: 1px solid color-mix(in srgb, var(--bone) 55%, transparent);
    outline: 1px solid color-mix(in srgb, var(--bone) 22%, transparent);
    outline-offset: 5px;
    display: flex;
    flex-direction: column;
    gap: clamp(2rem, 5vw, 3.5rem);
}

/* corner marks, echoing the woodcut border of the artwork */
.frame::before,
.frame::after {
    content: "";
    position: absolute;
    width: 22px;
    height: 22px;
    border: 1px solid var(--bone);
    opacity: 0.7;
    pointer-events: none;
}

.frame::before {
    top: 9px;
    left: 9px;
    border-right: 0;
    border-bottom: 0;
}

.frame::after {
    right: 9px;
    bottom: 9px;
    border-top: 0;
    border-left: 0;
}

.shell {
    width: 100%;
    max-width: var(--shell-max);
    margin-inline: auto;
    flex: 1;
}

.skip-link {
    position: absolute;
    left: -9999px;
    top: 0;
    z-index: 20;
    padding: 0.6rem 1rem;
    background: var(--bone);
    color: var(--ink);
    font-weight: 700;
}

.skip-link:focus {
    left: 0;
}

/* names a link's target for a screen reader without repeating it on screen */
.visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

/* --------------------------------------------------------------------------
   Hero
   -------------------------------------------------------------------------- */

.hero {
    text-align: center;
    padding-block: clamp(1rem, 5vw, 3rem) clamp(1.5rem, 4vw, 2.5rem);
}

.hero__mark {
    margin: 0;
    line-height: 0;
}

/* on /riders/ the mark is a link home; an <a> is inline by default, which
   would leave a text baseline gap under the logo */
.hero__mark-link {
    display: block;
    line-height: 0;
}

.hero__mark img {
    width: min(100%, 30rem);
    /* logo-white.png is generated from brand/logo-original.png — see README */
    filter: drop-shadow(0 0 26px rgba(245, 188, 184, 0.14));
}

.hero__tagline {
    margin: clamp(1rem, 3vw, 1.75rem) 0 0;
    font-family: var(--font-display);
    font-size: clamp(1.05rem, 3.2vw, 1.4rem);
    letter-spacing: 0.22em;
    text-transform: lowercase;
    color: var(--bone);
}

/* --------------------------------------------------------------------------
   Sections
   -------------------------------------------------------------------------- */

/* The gap belongs to the section above rather than to the one below, because a
   section still waiting on its release date sits on display:none: margin-top on
   whatever follows it would be a gap around a block nobody can see, while
   margin-bottom on the hidden section itself is simply never drawn — and that
   holds wherever in the run that section happens to sit. */
.section:has(+ .section) {
    margin-bottom: clamp(2rem, 5vw, 3rem);
}

.section__title {
    margin: 0 0 1.25rem;
    font-family: var(--font-display);
    font-size: clamp(1.5rem, 5vw, 2.1rem);
    font-weight: 400;
    line-height: 1.1;
    letter-spacing: 0.04em;
    color: var(--bone);
    text-align: center;
}

.section__intro {
    margin: -0.6rem 0 1.5rem;
    text-align: center;
    font-size: 0.94rem;
    color: color-mix(in srgb, var(--paper) 68%, transparent);
}

.rule {
    width: 100%;
    max-width: 14rem;
    margin: clamp(2.25rem, 6vw, 3.25rem) auto;
    border: 0;
    border-top: 1px solid color-mix(in srgb, var(--bone) 40%, transparent);
    position: relative;
}

.rule::after {
    content: "";
    position: absolute;
    top: -3px;
    left: 50%;
    width: 6px;
    height: 6px;
    transform: translateX(-50%) rotate(45deg);
    background: var(--bone);
    opacity: 0.75;
}

/* --------------------------------------------------------------------------
   Band photo
   -------------------------------------------------------------------------- */

.photo {
    position: relative;
    margin: clamp(1.75rem, 5vw, 2.75rem) 0 0;
    padding: 6px;
    border: 1px solid color-mix(in srgb, var(--bone) 32%, transparent);
    background: color-mix(in srgb, var(--bone) 4%, transparent);
}

.photo img {
    display: block;
    width: 100%;
    height: auto;
    /* pull the yellow back a touch so it sits with the bone and ink */
    filter: saturate(0.88) contrast(1.04);
}

/* The WebGL pass draws over the photo. The <img> stays in the flow so it keeps
   dictating the height, and remains the fallback whenever the canvas is absent. */
.photo__fx {
    position: absolute;
    top: 6px;
    left: 6px;
    display: block;
    /* a canvas is a replaced element: with only insets it would fall back to its
       intrinsic pixel size, so the box is stated explicitly */
    width: calc(100% - 12px);
    height: calc(100% - 12px);
    filter: saturate(0.88) contrast(1.04);
}

.photo.is-fx img {
    visibility: hidden;
}

/* --------------------------------------------------------------------------
   Video
   -------------------------------------------------------------------------- */

/* The run of sessions, newest first. Each one keeps the full column so the
   player it swaps in is the same size as the poster it replaces; a session
   still waiting on its date sits on hidden, and the gap belongs to the item
   above it for the same reason the sections do. */
.videos {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: clamp(1.75rem, 4vw, 2.5rem);
}

.videos__title {
    margin: 0 0 0.75rem;
    font-family: var(--font-display);
    font-size: clamp(1.15rem, 3.4vw, 1.4rem);
    font-weight: 400;
    line-height: 1.15;
    letter-spacing: 0.04em;
    color: var(--bone);
    text-align: center;
}

/* Same press as the band photo: a hairline box with the still inset inside it.
   Nothing is requested from YouTube until the poster is clicked, so the page
   still costs one document and its own assets to anyone who never plays it. */
.video {
    position: relative;
    padding: 6px;
    border: 1px solid color-mix(in srgb, var(--bone) 32%, transparent);
    background: var(--ink-lift);
}

/* the poster is the play control: clicking it swaps in the player, in place */
.video__trigger {
    display: block;
    width: 100%;
    margin: 0;
    padding: 0;
    border: 0;
    background: transparent;
    color: var(--paper);
    font: inherit;
    cursor: pointer;
}

/* the play mark centres on the still, not on the still plus its caption */
.video__stage {
    position: relative;
    display: block;
}

.video__still {
    display: block;
    width: 100%;
    height: auto;
    /* matches the band photo and the press tiles */
    filter: saturate(0.88) contrast(1.04);
    transition: filter 0.18s ease;
}

/* the play mark: the frame's vocabulary rather than a rounded platform button */
.video__play {
    position: absolute;
    top: 50%;
    left: 50%;
    display: grid;
    place-items: center;
    width: clamp(3.25rem, 9vw, 4.25rem);
    aspect-ratio: 1;
    transform: translate(-50%, -50%);
    border: 1px solid color-mix(in srgb, var(--paper) 65%, transparent);
    background: color-mix(in srgb, var(--ink) 55%, transparent);
    color: var(--paper);
    transition: border-color 0.18s ease, background-color 0.18s ease, color 0.18s ease;
}

.video__play svg {
    width: 40%;
    height: 40%;
}

/* the caption is a separate link: it leaves for YouTube instead of playing here */
.video__bar {
    display: flex;
    align-items: baseline;
    gap: 0.6rem;
    padding: 0.6rem 0.35rem 0.15rem;
    color: var(--paper);
    text-decoration: none;
    transition: color 0.18s ease;
}

.video__label {
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    font-size: 0.78rem;
}

.video__meta {
    margin-left: auto;
    font-size: 0.74rem;
    letter-spacing: 0.04em;
    color: color-mix(in srgb, var(--paper) 55%, transparent);
}

.video__trigger:hover .video__still,
.video__trigger:focus-visible .video__still {
    filter: saturate(1) contrast(1.04);
}

.video__trigger:hover .video__play,
.video__trigger:focus-visible .video__play {
    border-color: var(--blush);
    background: color-mix(in srgb, var(--ink) 70%, transparent);
    color: var(--blush);
}

.video__trigger:focus-visible {
    outline: 2px solid var(--blush);
    outline-offset: 3px;
}

.video__bar:hover,
.video__bar:focus-visible {
    color: var(--blush);
}

.video__bar:hover .video__meta,
.video__bar:focus-visible .video__meta {
    color: inherit;
}

.video__bar:focus-visible {
    outline: 2px solid var(--blush);
    outline-offset: 3px;
}

/* the player takes the poster's place once it is asked for */
.video__frame {
    display: block;
    width: 100%;
    aspect-ratio: 16 / 9;
    border: 0;
}

/* --------------------------------------------------------------------------
   Spotify
   -------------------------------------------------------------------------- */

/* The embed comes as a rounded platform card, so it gets the same hairline
   press as the video and the band photo — the page's own frame around it is
   what keeps it from reading as a widget dropped on top of the page.

   Unlike the video this one is not a facade: there is nothing to click through
   to, the point of it is that the music is already there. It costs a request to
   Spotify on every visit, which is the trade. */
/* The session sits between the release title and the record. Its own bottom
   margin, rather than a top margin on .player, so the gap is never drawn while
   the block is still waiting on its release date. */
.release-video {
    margin: 0 0 1.5rem;
}

.player {
    margin: 0 0 1.5rem;
    padding: 6px;
    border: 1px solid color-mix(in srgb, var(--bone) 32%, transparent);
    background: var(--ink-lift);
}

/* 352 px, and it has to be 352 px. Anything under it — 340 included — trips the
   embed into a cramped layout of its own where the title sits over the transport
   bar and the track list goes, and it still does not fill the shorter box. So
   the tail of empty sleeve colour under a one-track single is the price of the
   layout that reads properly; a record with a real track list will use it up.
   The height is repeated on the iframe itself for the moment before the CSS
   lands. */
.player iframe {
    display: block;
    width: 100%;
    height: 352px;
    border: 0;
}

/* --------------------------------------------------------------------------
   Link buttons
   -------------------------------------------------------------------------- */

/* .section__sub carries no bottom margin: everywhere else on the site a note
   sits under it and supplies the gap. Above the socials there is no note, so
   the heading would land straight on the first button — the gap is owned here,
   by the one pairing that needs it. */
.section__sub:has(+ .links) {
    margin-bottom: 0.9rem;
}

/* Two columns as soon as two fit and not a pixel sooner. A fixed breakpoint
   put the second column in at 34rem, where a row still needs about 18rem to
   set its label and its handle on one line, so the pair overflowed the shell
   between there and roughly 37rem. auto-fit reads that width off the track
   instead of guessing it, and minmax's floor is the real one: 0 rather than
   auto, so a track can never be forced wider than its share. */
.links {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: 0.7rem;
    grid-template-columns: repeat(auto-fit, minmax(min(18rem, 100%), 1fr));
}

.btn {
    display: flex;
    align-items: center;
    gap: 0.85rem;
    width: 100%;
    /* a flex item defaults to refusing to shrink below its content; without
       this a long handle would push the row past its track */
    min-width: 0;
    padding: 0.95rem 1.1rem;
    background: var(--ink-lift);
    border: 1px solid color-mix(in srgb, var(--bone) 32%, transparent);
    color: var(--paper);
    text-decoration: none;
    transition: border-color 0.18s ease, color 0.18s ease, background-color 0.18s ease, transform 0.18s ease;
}

.btn__icon {
    flex: none;
    width: 22px;
    height: 22px;
    color: var(--bone);
    transition: color 0.18s ease;
}

.btn__label {
    flex: none;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    font-size: 0.86rem;
}

/* the label names the thing and the handle only confirms it, so when a row is
   too narrow for both the handle is the half that gives way */
.btn__meta {
    min-width: 0;
    margin-left: auto;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 0.78rem;
    letter-spacing: 0.04em;
    color: color-mix(in srgb, var(--paper) 55%, transparent);
}

.btn:hover,
.btn:focus-visible {
    background: color-mix(in srgb, var(--blush) 8%, var(--ink-lift));
    border-color: var(--blush);
    color: var(--blush);
    transform: translateY(-1px);
}

.btn:hover .btn__icon,
.btn:focus-visible .btn__icon {
    color: var(--blush);
}

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

/* not yet available */
.btn--soon {
    cursor: not-allowed;
    opacity: 0.45;
    border-style: dashed;
}

.btn--soon .btn__meta {
    color: var(--bone);
    text-transform: uppercase;
    font-size: 0.7rem;
    letter-spacing: 0.12em;
}

/* the zip takes both columns: it is the one link that covers the other four */
.links__full {
    grid-column: 1 / -1;
}

.btn--kit {
    border-color: color-mix(in srgb, var(--bone) 55%, transparent);
}

/* --------------------------------------------------------------------------
   Shows
   -------------------------------------------------------------------------- */

.gigs {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: 0.7rem;
}

.gig {
    display: grid;
    gap: 0.85rem 1.1rem;
    align-items: center;
    padding: 0.95rem 1.1rem;
    background: var(--ink-lift);
    border: 1px solid color-mix(in srgb, var(--bone) 32%, transparent);
    /* stacked on a phone: the date sits beside the town, everything else below */
    grid-template-columns: auto 1fr;
    grid-template-areas:
        "date where"
        "what what"
        "cta  cta";
}

/* one line per show once there is room for four columns */
@media (min-width: 42rem) {
    .gig {
        grid-template-columns: 3.75rem minmax(7rem, 1fr) minmax(9rem, 1.15fr) auto;
        grid-template-areas: "date where what cta";
    }
}

.gig[hidden] {
    display: none;
}

/* date */
.gig__date {
    grid-area: date;
    margin: 0;
    text-align: center;
}

.gig__day {
    display: block;
    font-family: var(--font-display);
    font-size: 2.1rem;
    line-height: 0.95;
    color: var(--bone);
}

.gig__month {
    display: block;
    margin-top: 0.2rem;
    font-size: 0.68rem;
    font-weight: 700;
    letter-spacing: 0.2em;
    text-transform: uppercase;
}

.gig__year {
    display: block;
    font-size: 0.66rem;
    letter-spacing: 0.14em;
    color: color-mix(in srgb, var(--paper) 45%, transparent);
}

/* city and venue */
.gig__where {
    grid-area: where;
}

.gig__city {
    margin: 0;
    font-weight: 600;
    font-size: 0.86rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

.gig__venue {
    margin: 0.15rem 0 0;
    font-size: 0.8rem;
    color: color-mix(in srgb, var(--paper) 60%, transparent);
}

/* the bill: what the night is called, plus anything worth flagging */
.gig__what {
    grid-area: what;
}

.gig__event {
    margin: 0;
    font-family: var(--font-display);
    font-size: 1.1rem;
    line-height: 1.2;
    letter-spacing: 0.03em;
    color: var(--bone);
}

.gig__note {
    margin: 0.15rem 0 0;
    font-size: 0.74rem;
    letter-spacing: 0.04em;
    color: color-mix(in srgb, var(--paper) 50%, transparent);
}

.gig__tags {
    margin: 0.4rem 0 0;
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem;
}

.tag {
    display: inline-block;
    padding: 0.15rem 0.5rem;
    border: 1px solid color-mix(in srgb, var(--bone) 40%, transparent);
    font-size: 0.64rem;
    font-weight: 700;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--bone);
}

.tag--free {
    border-color: color-mix(in srgb, var(--blush) 60%, transparent);
    background: color-mix(in srgb, var(--blush) 10%, transparent);
    color: var(--blush);
}

/* the ticket link is a .btn, but sized to its own text instead of the row */
.btn--ticket {
    grid-area: cta;
    width: auto;
    justify-content: center;
    padding: 0.65rem 1rem;
    background: color-mix(in srgb, var(--bone) 12%, var(--ink));
    border-color: color-mix(in srgb, var(--bone) 55%, transparent);
}

/* a show that has been played keeps its row but loses the sales pitch */
.gig--past {
    opacity: 0.5;
}

.gig--past .btn--ticket,
.gig--past .gig__note,
.gig--past .gig__tags {
    display: none;
}

.gigs__empty {
    margin: 0;
    padding: 1.4rem 1rem;
    border: 1px dashed color-mix(in srgb, var(--bone) 30%, transparent);
    text-align: center;
    font-size: 0.9rem;
    color: color-mix(in srgb, var(--paper) 60%, transparent);
}

.gigs__empty[hidden] {
    display: none;
}

/* past-shows toggle */
.gigs__foot {
    margin: 1rem 0 0;
    text-align: center;
}

.toggle {
    display: inline-flex;
    align-items: center;
    gap: 0.55rem;
    padding: 0.5rem 0.9rem;
    background: transparent;
    border: 1px dashed color-mix(in srgb, var(--bone) 35%, transparent);
    color: color-mix(in srgb, var(--paper) 70%, transparent);
    font-family: inherit;
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    cursor: pointer;
    transition: border-color 0.18s ease, color 0.18s ease;
}

.toggle__count {
    padding: 0 0.4rem;
    border: 1px solid currentColor;
    font-size: 0.64rem;
    line-height: 1.45;
}

/* there is nothing in the archive yet — the control stays visible so it is
   obvious that past shows are kept, and enables itself once one exists */
.toggle:disabled {
    opacity: 0.4;
    cursor: not-allowed;
}

.toggle:not(:disabled):hover,
.toggle:not(:disabled):focus-visible {
    border-color: var(--blush);
    color: var(--blush);
}

.toggle:focus-visible {
    outline: 2px solid var(--blush);
    outline-offset: 3px;
}

/* --------------------------------------------------------------------------
   Press photos
   -------------------------------------------------------------------------- */

.section__sub {
    margin: clamp(1.75rem, 4vw, 2.25rem) 0 0;
    font-family: var(--font-display);
    font-size: clamp(1.15rem, 3.5vw, 1.45rem);
    font-weight: 400;
    letter-spacing: 0.04em;
    color: var(--bone);
    text-align: center;
}

.section__note {
    margin: 0.35rem 0 1.1rem;
    text-align: center;
    font-size: 0.84rem;
    color: color-mix(in srgb, var(--paper) 55%, transparent);
}

/* the only inline link on the site sits in a note on /riders/ */
.section__note a {
    color: var(--bone);
    text-underline-offset: 0.2em;
    text-decoration-color: color-mix(in srgb, var(--bone) 45%, transparent);
    transition: color 0.18s ease, text-decoration-color 0.18s ease;
}

.section__note a:hover,
.section__note a:focus-visible {
    color: var(--blush);
    text-decoration-color: var(--blush);
}

.shots {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: 0.7rem;
    grid-template-columns: 1fr;
    /* the two landscape shots share a row, then the two portraits do, so the
       tiles line up without anything forcing a common height */
    align-items: start;
}

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

.shot {
    display: block;
    padding: 6px;
    border: 1px solid color-mix(in srgb, var(--bone) 32%, transparent);
    background: var(--ink-lift);
    color: var(--paper);
    text-decoration: none;
    transition: border-color 0.18s ease, color 0.18s ease, transform 0.18s ease;
}

.shot img {
    display: block;
    width: 100%;
    height: auto;
    filter: saturate(0.88) contrast(1.04);
    transition: filter 0.18s ease;
}

/* the two portrait originals differ by 21 px in height, which left the tiles
   uneven; pin them to a common ratio and crop the overflow */
.shot--portrait img {
    height: auto;
    aspect-ratio: 3 / 4;
    object-fit: cover;
    object-position: center;
}

.shot__bar {
    display: flex;
    align-items: baseline;
    gap: 0.6rem;
    padding: 0.6rem 0.35rem 0.15rem;
}

.shot__label {
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    font-size: 0.78rem;
}

.shot__meta {
    margin-left: auto;
    font-size: 0.74rem;
    letter-spacing: 0.04em;
    color: color-mix(in srgb, var(--paper) 55%, transparent);
}

.shot:hover,
.shot:focus-visible {
    border-color: var(--blush);
    color: var(--blush);
    transform: translateY(-1px);
}

.shot:hover img,
.shot:focus-visible img {
    filter: saturate(1) contrast(1.04);
}

.shot:focus-visible {
    outline: 2px solid var(--blush);
    outline-offset: 3px;
}

/* --------------------------------------------------------------------------
   Contact
   -------------------------------------------------------------------------- */

.contact {
    margin-top: clamp(1.75rem, 4vw, 2.5rem);
    border: 1px solid color-mix(in srgb, var(--bone) 32%, transparent);
    background: color-mix(in srgb, var(--bone) 4%, transparent);
    display: grid;
    grid-template-columns: 1fr;
}

.contact__item {
    padding: clamp(1.25rem, 4vw, 1.6rem);
    text-align: center;
}

/* hairline between the two blocks: horizontal when stacked, vertical side by side */
.contact__item + .contact__item {
    border-top: 1px solid color-mix(in srgb, var(--bone) 22%, transparent);
}

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

    .contact__item + .contact__item {
        border-top: 0;
        border-left: 1px solid color-mix(in srgb, var(--bone) 22%, transparent);
    }
}

.contact__label {
    margin: 0 0 0.5rem;
    font-size: 0.72rem;
    letter-spacing: 0.24em;
    text-transform: uppercase;
    color: var(--bone);
}

.contact__mail {
    display: inline-block;
    font-family: var(--font-display);
    font-size: clamp(1.05rem, 3.6vw, 1.35rem);
    color: var(--paper);
    text-decoration: none;
    border-bottom: 1px solid color-mix(in srgb, var(--blush) 55%, transparent);
    padding-bottom: 0.1em;
    word-break: break-word;
    transition: color 0.18s ease, border-color 0.18s ease;
}

.contact__mail:hover,
.contact__mail:focus-visible {
    color: var(--blush);
    border-color: var(--blush);
}

.contact__mail:focus-visible {
    outline: 2px solid var(--blush);
    outline-offset: 4px;
}

.contact__note {
    margin: 0.6rem 0 0;
    font-size: 0.8rem;
    letter-spacing: 0.08em;
    color: color-mix(in srgb, var(--paper) 50%, transparent);
}

/* --------------------------------------------------------------------------
   Footer
   -------------------------------------------------------------------------- */

.foot {
    margin-top: clamp(2.5rem, 6vw, 4rem);
    padding-top: clamp(1.5rem, 4vw, 2.25rem);
    border-top: 1px solid color-mix(in srgb, var(--bone) 22%, transparent);
}

.foot p {
    margin: 0;
}

.foot__top {
    width: 100%;
    max-width: var(--shell-max);
    margin-inline: auto;
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    justify-content: space-between;
    gap: clamp(1.5rem, 4vw, 2.5rem);
}

.foot__title {
    font-family: var(--font-display);
    font-size: 1.15rem;
    letter-spacing: 0.14em;
    text-transform: lowercase;
    color: var(--bone);
}

.lineup {
    list-style: none;
    margin: 0.75rem 0 0;
    padding: 0;
    display: grid;
    gap: 0.3rem;
    font-size: 0.88rem;
    line-height: 1.35;
}

.lineup__name {
    color: var(--paper);
}

.lineup__role {
    color: color-mix(in srgb, var(--paper) 45%, transparent);
}

/* the dash lives in CSS so the markup stays two clean spans */
.lineup__role::before {
    content: "— ";
}

.foot__social {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    gap: 1.15rem;
}

.social {
    display: block;
    color: color-mix(in srgb, var(--paper) 55%, transparent);
    transition: color 0.18s ease;
}

.social svg {
    display: block;
    width: 21px;
    height: 21px;
}

.social:hover,
.social:focus-visible {
    color: var(--bone);
}

.foot__legal {
    margin-top: clamp(2.5rem, 5vw, 3.25rem);
    text-align: center;
    font-size: 0.74rem;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: color-mix(in srgb, var(--paper) 40%, transparent);
}

@media (max-width: 33rem) {
    .foot__top {
        flex-direction: column;
        align-items: center;
        text-align: center;
    }
}

/* --------------------------------------------------------------------------
   Motion preferences
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        transition-duration: 0.01ms !important;
        animation-duration: 0.01ms !important;
    }

    .btn:hover,
    .btn:focus-visible,
    .shot:hover,
    .shot:focus-visible {
        transform: none;
    }
}
