/* Belfast History Festival · placeholder site
 * Brand: McCadden "Brand Concepts v1", design option 1 (street-name tile).
 * Colours are the option-1 vibrant palette, sampled from the concepts PDF.
 * Type: Barlow / Barlow Condensed (OFL) stand in for the wordmark lettering
 * until the brand typeface is confirmed and licensed.
 */

@font-face {
    font-family: "Barlow";
    src: url("assets/fonts/barlow-400.woff2") format("woff2");
    font-weight: 400;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: "Barlow";
    src: url("assets/fonts/barlow-600.woff2") format("woff2");
    font-weight: 600;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: "Barlow Condensed";
    src: url("assets/fonts/barlow-condensed-600.woff2") format("woff2");
    font-weight: 600;
    font-style: normal;
    font-display: swap;
}

:root {
    /* Option-1 palette */
    --charcoal: #404040;
    --yellow: #f5f23c;
    --yellow-tint: #faf99e;
    --mint: #1cfcb2;
    --mint-tint: #8efed9;
    --red: #ff3e24;
    --red-tint: #ffcfc8;
    --purple: #8f58fc;
    --purple-tint: #e3d5fe;
    --blue: #1170e8;
    --blue-tint: #c4dbf9;
    --stone: #d6cac1;
    --off-white: #f8f8f8;

    /* Roles */
    --field: var(--yellow-tint);
    --plate: var(--off-white);
    --ink: var(--charcoal);
    --ink-pressed: #262626;
    --paper: var(--off-white);
    --focus: var(--charcoal);

    /* Enamel plates: a charcoal plate with a thin line set in from the edge,
     * like the frame lines of the logo's tile. The keyline and the plate's
     * text are always the colour of the surface the plate sits on (--surface):
     * the field on yellow sections, the paper on off-white reading areas, so
     * the colour picker changes the field ones too. Buttons use these, and
     * .home-invite swaps them for a yellow button on its charcoal plate. */
    --plate-bg: var(--ink);
    --plate-bg-hover: var(--ink-pressed);
    /* The colour of the surface each plate sits on. Field by default; the
     * off-white reading areas set it to --paper (see .prose, .programme,
     * .home-section below). The derived tokens re-resolve only where --surface
     * is set, because a var() reference is computed on the element where its
     * property is declared, so those surfaces redeclare them alongside it. */
    --surface: var(--field);
    --plate-fg: var(--surface);
    --keyline: var(--surface);
    --plate-line: var(--keyline);
    /* How far the enamel line is set in from the plate's edge. */
    --plate-inset: 0.5rem;

    /* Tile outlines for buttons, hand-set from the logo's frame tiles: chipped
     * corners, edges that are not quite straight, no two corners alike. The
     * second is the first turned over, so neighbouring buttons differ. Offsets
     * stay in pixels so the chips look the same on any button size. */
    --tile-a: polygon(0 5px, 3px 1px, 14px 0, 45% 1px, calc(100% - 22px) 0,
        calc(100% - 4px) 2px, 100% 7px, calc(100% - 1px) calc(100% - 9px),
        calc(100% - 6px) calc(100% - 3px), calc(100% - 20px) 100%,
        55% calc(100% - 1px), 12px 100%, 2px calc(100% - 4px), 0 calc(100% - 12px));
    --tile-b: polygon(6px 0, calc(100% - 15px) 1px, calc(100% - 3px) 0,
        100% 6px, calc(100% - 1px) 40%, 100% calc(100% - 7px),
        calc(100% - 4px) calc(100% - 1px), calc(100% - 26px) 100%,
        50% calc(100% - 2px), 9px 100%, 1px calc(100% - 5px), 0 55%, 1px 12px);

    /* A smaller hand-cut chip, for the date tiles of the news list: the same
     * chipped corners as the buttons, scaled to a small tile. */
    --tile-chip: polygon(0 4px, 7px 1px, 30% 0, calc(100% - 15px) 0,
        calc(100% - 2px) 2px, 100% 5px, calc(100% - 1px) calc(100% - 6px),
        calc(100% - 4px) calc(100% - 1px), calc(100% - 18px) 100%,
        40% calc(100% - 1px), 8px 100%, 1px calc(100% - 5px), 0 5px);

    --font-body: "Barlow", "Helvetica Neue", Arial, sans-serif;
    --font-sign: "Barlow Condensed", "Arial Narrow", sans-serif;

    /* 4px spacing scale */
    --space-1: 0.25rem;
    --space-2: 0.5rem;
    --space-3: 0.75rem;
    --space-4: 1rem;
    --space-5: 1.5rem;
    --space-6: 2rem;
    --space-7: 3rem;
    --space-8: 4rem;

    --radius: 4px;
    --control-height: 3.25rem;
    --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
    /* The sticky header's height, for scroll-padding-top. Phones don't stick
     * the header (it would cover a fifth or more of the screen), so nothing
     * to clear there; the wider breakpoint below sets it. */
    --head-height: 0rem;
}

/* Off-white reading areas sit their plates on paper, so a plate's keyline and
 * text turn off-white there. Each surface sets --surface and redeclares the
 * derived plate tokens alongside it (a var() reference is computed where its
 * property is declared, so re-setting --surface alone would not update them). */
.prose,
.programme,
.home-section {
    --surface: var(--paper);
    --plate-fg: var(--surface);
    --keyline: var(--surface);
    --plate-line: var(--keyline);
}

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

html {
    -webkit-text-size-adjust: 100%;
    text-size-adjust: 100%;
    /* In-page anchors, the skip link and keyboard focus land below the sticky
     * header, never under it (WCAG 2.4.11). --head-height is the bar's height
     * per breakpoint, with a little breathing room (see below). */
    scroll-padding-top: var(--head-height);
}

body {
    margin: 0;
    min-height: 100vh;
    min-height: 100svh;
    display: flex;
    flex-direction: column;
    /* Charcoal behind everything: the canvas shows through wherever the page
     * is shorter than the screen (iOS Safari's top and bottom bars take their
     * tint from it), and it matches the header and footer bands. The yellow
     * field is painted by main instead. */
    background: var(--ink);
    color: var(--ink);
    font-family: var(--font-body);
    font-size: 1.125rem;
    line-height: 1.5;
}

/* Main fills the height between band and footer, so short pages keep the
 * footer at the bottom and their last section stretches to meet it. */
body > main {
    flex: 1;
    display: flex;
    flex-direction: column;
    background: var(--field);
}

img,
svg {
    display: block;
    max-width: 100%;
}

/* Component display rules must never un-hide something marked hidden. */
[hidden] {
    display: none !important;
}

a {
    color: inherit;
    text-decoration-thickness: 1px;
    text-underline-offset: 0.2em;
    transition: text-decoration-thickness 240ms var(--ease-out), text-underline-offset 240ms var(--ease-out);
}

a:hover {
    text-decoration-thickness: 2px;
    text-underline-offset: 0.32em;
}

/* The contact address is one unbreakable 34-character word: let it wrap at
 * narrow widths, zoom and increased text spacing instead of forcing a scroll. */
a[href^="mailto:"] {
    overflow-wrap: anywhere;
}

:focus-visible {
    outline: 3px solid var(--focus);
    outline-offset: 3px;
}

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

.skip-link {
    position: absolute;
    left: var(--space-4);
    top: -10rem;
    padding: var(--space-2) var(--space-4);
    background: var(--ink);
    color: var(--field);
    font-weight: 600;
    z-index: 10;
}

.skip-link:focus {
    top: var(--space-4);
}

/* Skip-link targets take focus only so the next Tab starts there; no ring needed. */
#content:focus {
    outline: none;
}

/* ------------------------------------------------------------------ */
/* Site head: a charcoal street-sign band naming where you are          */
/* ------------------------------------------------------------------ */

.site-head {
    background: var(--ink);
    color: var(--paper);
    padding: var(--space-3) var(--space-4);
}

/* From tablet width up, the bar sticks to the top as the reader scrolls.
 * Not on phones: there the logo sits above the menu and the bar is 150px or
 * more, a fifth to a quarter of the screen, so it scrolls away as normal.
 * Above page content but below the skip link (z-index 10) and the colour
 * picker tab (z-index 30). --head-height is its measured height here (one
 * row, about 5.6rem) plus a little breathing room. */
@media (min-width: 33rem) {
    :root {
        --head-height: 6rem;
    }

    .site-head {
        position: sticky;
        top: 0;
        z-index: 5;
    }
}

.site-head__inner {
    max-width: 68rem;
    margin-inline: auto;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2) var(--space-6);
}

.site-head__home {
    display: block;
    padding: var(--space-1) 0;
    /* The hit zones are positioned against this box, not the band. */
    position: relative;
}

.site-head__home .nameplate {
    display: block;
    width: 4.5rem;
    /* Hung from one screw near the top: it tips away from the side the pointer
     * approaches from and, on leaving, settles back level. */
    transform-origin: 50% 12%;
    transition: transform 480ms var(--ease-out);
}

/* Two invisible halves over the plate (and the tile, below) carry the hover:
 * each is exactly half of its logo's box and, being empty and aria-hidden,
 * adds no tab stop, name or click target of its own. */
.tilt-zone {
    position: absolute;
    width: 50%;
}

.tilt-zone--left {
    left: 0;
}

.tilt-zone--right {
    right: 0;
}

/* The plate is inset from the link by its vertical padding, so the halves are
 * inset by the same amount and cover the plate, not the padded link. */
.site-head__home .tilt-zone {
    top: var(--space-1);
    bottom: var(--space-1);
}

/* Without :has(), the plate simply tips left wherever it's hovered. */
@media (hover: hover) {
    .site-head__home:hover .nameplate {
        transform: rotate(-1.5deg);
        transition: transform 360ms cubic-bezier(0.34, 1.56, 0.64, 1);
    }
}

/* Where :has() is understood, the hovered half sets the direction: the left
 * half tips the bottom right and the right half tips it left, so the plate
 * leans away from the side the pointer entered from. Crossing the middle
 * swings it over on the same springy transition. */
@supports selector(:has(*)) {
    @media (hover: hover) {
        .site-head__home:has(.tilt-zone--left:hover) .nameplate {
            transform: rotate(-1.5deg);
            transition: transform 360ms cubic-bezier(0.34, 1.56, 0.64, 1);
        }

        .site-head__home:has(.tilt-zone--right:hover) .nameplate {
            transform: rotate(1.5deg);
            transition: transform 360ms cubic-bezier(0.34, 1.56, 0.64, 1);
        }
    }
}

.site-head__home:focus-visible .nameplate {
    transform: rotate(-1.5deg);
}

.site-nav {
    min-width: 0;
    max-width: 100%;
}

/* Links carry their own side padding for the plate, so the list steps out by
 * the same amount to keep the lettering aligned with the band's edges. */
.site-nav ul {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1);
    margin: 0 calc(-1 * var(--space-3));
    padding: 0;
    list-style: none;
}

/* Sign lettering: condensed tracked caps. The right padding gives back the
 * trailing tracking so the letters sit centred on the plate. */
.site-nav a {
    display: block;
    padding: 0.625rem calc(var(--space-3) - 0.12em) 0.625rem var(--space-3);
    border-radius: var(--radius);
    font-family: var(--font-sign);
    font-weight: 600;
    font-size: 1.125rem;
    line-height: 1.1;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    text-decoration: none;
    transition: background-color 240ms var(--ease-out), color 240ms var(--ease-out);
}

/* Hover: a faint plate. The current page: a full off-white plate, like a
 * small street sign. */
@media (hover: hover) {
    .site-nav a:hover {
        background: rgba(248, 248, 248, 0.14);
    }
}

.site-nav a[aria-current] {
    background: var(--plate);
    color: var(--ink);
}

@media (hover: hover) {
    .site-nav a[aria-current]:hover {
        background: var(--plate);
        text-decoration: underline;
        text-underline-offset: 0.22em;
    }
}

.site-nav a:active {
    background: var(--field);
    color: var(--ink);
}

.site-nav a:focus-visible {
    outline-offset: 1px;
}

/* Phones: slimmer plates, so the links take as few rows as they can. */
@media (max-width: 29.99rem) {
    .site-nav ul {
        gap: 0;
        margin-inline: calc(-1 * var(--space-2));
    }

    .site-nav a {
        padding-inline: var(--space-2) calc(var(--space-2) - 0.12em);
    }
}

/* At the narrowest reflow width, pair the signs deliberately. */
@media (max-width: 22.49rem) {
    .site-nav ul {
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: var(--space-1) var(--space-2);
    }
}

.site-head :focus-visible {
    outline-color: var(--paper);
}

/* ------------------------------------------------------------------ */
/* Page opening: the page's name on the yellow-tint field               */
/* ------------------------------------------------------------------ */

/* A thin course of the logo's own tiles hangs under the charcoal band, the
 * joints between the tiles showing the field: the sign continues into the
 * page as tilework. Decorative; dropped for forced colours and print. */
.page-intro::before {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    top: 0;
    height: 1.125rem;
    background: var(--ink);
    -webkit-mask: url("assets/logos/tile-joints.svg") left bottom / 18rem 100% repeat-x;
    mask: url("assets/logos/tile-joints.svg") left bottom / 18rem 100% repeat-x;
    pointer-events: none;
}

.page-intro {
    position: relative;
    background: var(--field);
    padding: var(--space-8) var(--space-4) var(--space-7);
}

.page-intro__inner {
    max-width: 40rem;
    margin-inline: auto;
}

.page-title {
    margin: 0;
    font-family: var(--font-sign);
    font-weight: 600;
    font-size: clamp(2.25rem, 1.6rem + 2.4vw, 3.25rem);
    line-height: 1.05;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    text-wrap: balance;
    overflow-wrap: anywhere;
}

/* Article titles are sentences: set them as reading type, not as a sign. */
.page-title--article {
    font-family: var(--font-body);
    font-size: clamp(1.875rem, 1.45rem + 1.5vw, 2.5rem);
    line-height: 1.15;
    letter-spacing: 0;
    text-transform: none;
}

.page-intro p {
    margin: var(--space-4) 0 0;
    font-size: 1.25rem;
    line-height: 1.45;
}

.page-intro .meta {
    font-size: 1rem;
}

/* A link with the weight of the signup button, for each page's main action. */
.button {
    display: inline-flex;
    align-items: center;
    min-height: var(--control-height);
    padding: var(--space-2) var(--space-6);
    border: 2px solid var(--ink);
    border-radius: var(--radius);
    background: var(--plate-bg);
    color: var(--plate-fg);
    box-shadow: inset 0 0 0 3px var(--plate-bg), inset 0 0 0 4.5px var(--plate-line);
    clip-path: var(--tile-a);
    font-family: var(--font-sign);
    font-weight: 600;
    font-size: 1.25rem;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    text-decoration: none;
    text-align: center;
    overflow-wrap: anywhere;
    min-width: 0;
    max-width: 100%;
    transition: background-color 240ms var(--ease-out), transform 240ms var(--ease-out);
}

/* A clipped box would hide its own focus ring, so the focused button squares
 * off while the ring shows. */
.button:focus-visible,
.signup__button:focus-visible {
    clip-path: none;
}

@media (hover: hover) {
    .button:hover {
        --plate-bg: var(--plate-bg-hover);
        transform: translateY(-1px);
    }
}

/* Pressed in: the plate takes its pressed colour and sinks below its resting
 * line, quickly, then springs back on the usual 240ms when released. The
 * pressed colour is set here too, not only on hover, so a tap on a touch
 * screen shows it. */
.button:active {
    --plate-bg: var(--plate-bg-hover);
    transform: translateY(1px) scale(0.98);
    transition-duration: 60ms;
}

/* ------------------------------------------------------------------ */
/* Landing: the yellow-tint field                                       */
/* ------------------------------------------------------------------ */

.landing {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--space-7);
    padding: var(--space-8) var(--space-4) var(--space-7);
    text-align: center;
}

.landing__logo {
    margin: 0;
}

/* The logo is two stacked layers, the B tile and the wordmark (both built from
 * logo.svg by scripts/build_logo_layers.py), so the tile can lift on its own. */
.logo-lockup {
    display: grid;
    /* Width follows the height cap too, so the box always has the logo's
     * proportions and the two layers can't drift apart. */
    width: min(88vw, 40rem, 44vh * 627 / 396);
    width: min(88vw, 40rem, 44svh * 627 / 396);
    aspect-ratio: 627 / 396;
    margin-inline: auto;
    /* The tile is set into place. */
    animation: set-in 450ms var(--ease-out) both;
}

.logo-lockup img {
    grid-area: 1 / 1;
    width: 100%;
    height: 100%;
}

/* The tile layer is only as wide as the tile (285 of the logo's 627 units),
 * so only the tile answers to hover. It is wrapped so the hit zones can sit
 * over the tile alone, not the wordmark, which stays painted on top and lets
 * the mouse through. */
.logo-lockup__tile-wrap {
    grid-area: 1 / 1;
    position: relative;
    width: calc(100% * 284.86 / 626.62);
    justify-self: start;
}

/* The tile wrapper is the full tile, so its halves cover it edge to edge. */
.logo-lockup__tile-wrap .tilt-zone {
    top: 0;
    bottom: 0;
}

.logo-lockup__wordmark {
    pointer-events: none;
}

/* The 404 page's logo is a link home. */
.landing__logo a {
    display: block;
}

/* On hover the B tile tips like a sign hung from one screw at its top centre,
 * where the notch is. The wordmark stays painted on. Hover devices only, so a
 * tap doesn't leave it tilted. */
.logo-lockup__tile {
    transform-origin: 50% 3%;
    transition: transform 480ms var(--ease-out);
}

/* Without :has(), the tile simply tips right wherever it's hovered. */
@media (hover: hover) {
    .logo-lockup__tile-wrap:hover .logo-lockup__tile {
        transform: rotate(1.5deg);
        transition: transform 360ms cubic-bezier(0.34, 1.56, 0.64, 1);
    }
}

/* Where :has() is understood, the hovered half sets the direction: the left
 * half tips the bottom right and the right half tips it left, so the tile
 * leans away from the side the pointer entered from. Crossing the middle
 * swings it over on the same springy transition. */
@supports selector(:has(*)) {
    @media (hover: hover) {
        .logo-lockup:has(.tilt-zone--left:hover) .logo-lockup__tile {
            transform: rotate(-1.5deg);
            transition: transform 360ms cubic-bezier(0.34, 1.56, 0.64, 1);
        }

        .logo-lockup:has(.tilt-zone--right:hover) .logo-lockup__tile {
            transform: rotate(1.5deg);
            transition: transform 360ms cubic-bezier(0.34, 1.56, 0.64, 1);
        }
    }
}

a:focus-visible .logo-lockup__tile {
    transform: rotate(1.5deg);
}

@keyframes set-in {
    from {
        opacity: 0;
        transform: scale(0.97);
    }
}

/* Shrinkable tracks and word breaks keep enlarged text and long addresses
 * inside the narrow landing column, including the confirmation and gate. */
.landing__body {
    width: 100%;
    max-width: 34rem;
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    overflow-wrap: anywhere;
    gap: var(--space-5);
}

.dateline {
    margin: 0;
    font-family: var(--font-sign);
    font-weight: 600;
    font-size: clamp(1.5rem, 1rem + 2vw, 2.25rem);
    line-height: 1.1;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    text-wrap: balance;
    /* Optical correction: trailing tracking pushes centred caps left. */
    margin-right: -0.14em;
    /* The date becomes readable immediately, alongside the short logo entrance. */
    animation: fade-in 300ms ease-out both;
}

@keyframes fade-in {
    from {
        opacity: 0;
    }
}

/* The not-found and under-construction messages sit on the same enamel plate
 * as the home invite: a charcoal panel with the yellow line set in from the
 * edge. The page stays centred; the plate carries the message alone. */
.landing__text {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-4);
    padding: var(--space-6) var(--space-5);
    border: 2px solid var(--ink);
    border-radius: var(--radius);
    background: var(--ink);
    color: var(--paper);
    box-shadow: inset 0 0 0 var(--plate-inset) var(--ink),
        inset 0 0 0 calc(var(--plate-inset) + 2px) var(--keyline);
}

/* A charcoal ring would vanish on the plate, so focus here rings in the
 * field colour too. */
.landing__text :focus-visible {
    outline-color: var(--field);
}

.lede,
.landing__text p {
    margin: 0;
    font-size: 1.25rem;
    line-height: 1.45;
    text-wrap: balance;
}

/* ------------------------------------------------------------------ */
/* Signup form                                                          */
/* ------------------------------------------------------------------ */

/* The quiet line that sits above the form while sign-ups are still closed. */
.signup__note {
    margin: 0;
    font-size: 1rem;
    line-height: 1.45;
    text-wrap: balance;
}

.signup {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-4);
    text-align: left;
}

.signup__label {
    font-weight: 600;
    font-size: 1rem;
}

.signup__row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
}

.signup__input {
    flex: 1 1 14rem;
    min-width: 0;
    height: var(--control-height);
    padding: 0 var(--space-4);
    border: 2px solid var(--ink);
    border-radius: var(--radius);
    background: var(--paper);
    color: var(--ink);
    font: inherit;
    transition: box-shadow 300ms var(--ease-out);
}

/* A soft halo under the focus ring, eased in. */
.signup__input:focus {
    box-shadow: 0 0 0 0.3rem rgba(64, 64, 64, 0.16);
}

.signup__input::placeholder {
    color: #5c5c5c;
}

.signup__input[aria-invalid="true"] {
    border-width: 3px;
    padding-inline: calc(var(--space-4) - 1px);
}

.signup__button {
    flex: 0 0 auto;
    height: var(--control-height);
    padding: 0 var(--space-6);
    border: 2px solid var(--ink);
    border-radius: var(--radius);
    background: var(--plate-bg);
    color: var(--plate-fg);
    box-shadow: inset 0 0 0 3px var(--plate-bg), inset 0 0 0 4.5px var(--plate-line);
    clip-path: var(--tile-b);
    font-family: var(--font-sign);
    font-weight: 600;
    font-size: 1.25rem;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    cursor: pointer;
    transition: background-color 240ms var(--ease-out), transform 240ms var(--ease-out);
}

@media (hover: hover) {
    .signup__button:hover {
        --plate-bg: var(--plate-bg-hover);
        transform: translateY(-1px);
    }
}

.signup__button:active {
    --plate-bg: var(--plate-bg-hover);
    transform: translateY(1px) scale(0.98);
    transition-duration: 60ms;
}

.signup__button[aria-disabled="true"] {
    cursor: progress;
    --plate-bg: var(--plate-bg-hover);
}

.signup__button[aria-disabled="true"]:hover,
.signup__button[aria-disabled="true"]:active,
.signup__button:disabled:hover,
.signup__button:disabled:active {
    transform: none;
}

.signup__button:disabled {
    cursor: not-allowed;
    --plate-bg: var(--plate-bg-hover);
}

.signup__consent {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    gap: var(--space-3);
    align-items: start;
    font-size: 1rem;
    line-height: 1.45;
}

/* 24px: the WCAG 2.2 minimum target size. */
.signup__consent input {
    width: 1.5rem;
    height: 1.5rem;
    margin: 0;
    accent-color: var(--ink);
    cursor: pointer;
}

.signup__consent input[aria-invalid="true"] {
    outline: 3px solid var(--ink);
    outline-offset: 2px;
}

.signup__consent label {
    cursor: pointer;
}

.signup__status {
    display: flex;
    gap: var(--space-2);
    align-items: flex-start;
    margin: 0;
    font-weight: 600;
    font-size: 1rem;
}

.signup__status:not([hidden]) {
    animation: appear 360ms var(--ease-out) both;
}

@keyframes appear {
    from {
        opacity: 0;
        transform: translateY(-0.25rem);
    }
}

.signup__status svg {
    flex: 0 0 auto;
    width: 1.25rem;
    height: 1.25rem;
    margin-top: 0.1rem;
}

/* Honeypot: off-screen for people, still in the DOM for bots. */
.signup__trap {
    position: absolute;
    left: -10000px;
    width: 1px;
    height: 1px;
    overflow: hidden;
}

.signup-success {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-3);
    padding: var(--space-5);
    border: 2px solid var(--ink);
    border-radius: var(--radius);
    background: var(--paper);
    text-align: left;
}

.signup-success:focus {
    outline: none;
}

.signup-success:focus-visible {
    outline: 3px solid var(--focus);
    outline-offset: 3px;
}

.signup-success h2 {
    margin: 0;
    font-family: var(--font-sign);
    font-weight: 600;
    font-size: 1.75rem;
    line-height: 1.1;
    letter-spacing: 0.1em;
    text-transform: uppercase;
}

.signup-success p {
    margin: 0;
}

/* Drawn once the panel has settled. A 24-unit dash covers the ~20-unit path. */
.signup-success__tick {
    display: inline-block;
    width: 1.2em;
    height: 1.2em;
    margin-right: 0.3em;
    vertical-align: -0.15em;
    fill: none;
    stroke: currentColor;
    stroke-width: 3.2;
    stroke-linecap: round;
    stroke-linejoin: round;
    stroke-dasharray: 24;
    animation: draw 800ms var(--ease-out) 450ms both;
}

@keyframes draw {
    from {
        stroke-dashoffset: 24;
    }

    to {
        stroke-dashoffset: 0;
    }
}

.signup-success.is-entering {
    animation: settle 600ms var(--ease-out) both;
}

@keyframes settle {
    from {
        opacity: 0;
        transform: translateY(0.5rem);
    }
}

/* ------------------------------------------------------------------ */
/* Pre-launch gate: the quiet password door on the holding page         */
/* ------------------------------------------------------------------ */

.gate {
    justify-self: center;
    width: 100%;
    margin-top: var(--space-4);
}

.gate summary {
    width: fit-content;
    margin-inline: auto;
    padding: var(--space-2) var(--space-3);
    font-size: 1rem;
    text-decoration: underline;
    text-underline-offset: 0.2em;
    cursor: pointer;
}

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

/* The open gate panel: the password form on the same enamel plate, with the
 * button swapped to yellow as on the home invite. */
.gate__form {
    margin-top: var(--space-4);
    padding: var(--space-5);
    border: 2px solid var(--ink);
    border-radius: var(--radius);
    background: var(--ink);
    color: var(--paper);
    box-shadow: inset 0 0 0 var(--plate-inset) var(--ink),
        inset 0 0 0 calc(var(--plate-inset) + 2px) var(--keyline);
}

/* The plate colours are set on the container, not the button, so the
 * button's own :hover and :active can still swap in the pressed colour. */
.gate__form {
    --plate-bg: var(--field);
    --plate-bg-hover: var(--paper);
    --plate-fg: var(--ink);
    --plate-line: transparent;
}

.gate__form .signup__button {
    border-color: var(--field);
}

/* A charcoal ring would vanish on the plate, so focus here rings in the
 * field colour too. */
.gate__form :focus-visible {
    outline-color: var(--field);
}

/* ------------------------------------------------------------------ */
/* Home: sections below the first screen                                */
/* ------------------------------------------------------------------ */

.home-section {
    background: var(--paper);
    padding: var(--space-8) var(--space-4);
}

.home-section + .home-section {
    padding-top: 0;
}

/* Each section opens under a charcoal rule, like the frame line of a sign. */
.home-section__inner {
    max-width: 68rem;
    margin-inline: auto;
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    overflow-wrap: anywhere;
    gap: var(--space-4) var(--space-7);
    padding-top: var(--space-5);
    border-top: 2px solid var(--ink);
}

.home-section h2,
.home-invite h2 {
    margin: 0;
    font-family: var(--font-sign);
    font-weight: 600;
    font-size: clamp(1.75rem, 1.3rem + 1.6vw, 2.5rem);
    line-height: 1.05;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    text-wrap: balance;
}

.home-section__body {
    min-width: 0;
    max-width: 40rem;
}

.home-section__body > * {
    margin: 0 0 var(--space-4);
}

.home-section__body > :last-child {
    margin-bottom: 0;
}

.home-about__lede {
    font-size: 1.375rem;
    line-height: 1.4;
}

/* The one call to act below the fold: back on the yellow-tint field. */
.home-invite {
    background: var(--field);
    padding: var(--space-8) var(--space-4);
}

/* ...as a street-name plate: a charcoal panel with a yellow line set in from
 * its edge, the heading in sign lettering, and a yellow button on it. */
.home-invite__inner {
    max-width: 68rem;
    margin-inline: auto;
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    overflow-wrap: anywhere;
    gap: var(--space-5);
    justify-items: start;
    padding: var(--space-7) var(--space-6);
    border: 2px solid var(--ink);
    border-radius: var(--radius);
    background: var(--ink);
    color: var(--paper);
    box-shadow: inset 0 0 0 var(--plate-inset) var(--ink),
        inset 0 0 0 calc(var(--plate-inset) + 2px) var(--keyline);
}

.home-invite h2 {
    color: var(--field);
}

.home-invite :focus-visible {
    outline-color: var(--field);
}

.home-invite p {
    max-width: 40rem;
    margin: 0;
    font-size: 1.25rem;
    line-height: 1.45;
}

/* Keep the partnership invitation visible without a scroll-driven reveal. */

/* The plate colours are set on the container, not the button, so the
 * button's own :hover and :active can still swap in the pressed colour. */
.home-invite {
    --plate-bg: var(--field);
    --plate-bg-hover: var(--paper);
    --plate-fg: var(--ink);
    --plate-line: transparent;
}

.home-invite .button {
    border-color: var(--field);
}

@media (min-width: 48rem) {
    .home-invite__inner {
        padding: var(--space-8) var(--space-8);
    }
}

/* ------------------------------------------------------------------ */
/* News list: dated entries between rules                               */
/* ------------------------------------------------------------------ */

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

.news-list li {
    padding: var(--space-5) 0;
    border-bottom: 1px solid var(--ink);
}

.news-list li:first-child {
    padding-top: 0;
}

/* Dates set as small hand-cut tiles: a chip of enamel with sign lettering in
 * the field colour, as the buttons carry theirs. A quiet marker of the tile
 * vocabulary; it touches no text. */
.news-list time {
    display: inline-block;
    margin-bottom: var(--space-3);
    padding: 0.2em 0.7em;
    background: var(--ink);
    color: var(--field);
    box-shadow: inset 0 0 0 2px var(--ink), inset 0 0 0 3px var(--plate-line);
    clip-path: var(--tile-chip);
    font-family: var(--font-sign);
    font-weight: 600;
    font-size: 1rem;
    line-height: 1.4;
    letter-spacing: 0.1em;
    text-transform: uppercase;
}

.news-list h3 {
    margin: 0 0 var(--space-2);
    font-size: 1.375rem;
    line-height: 1.25;
    font-weight: 600;
}

.news-list h3 a {
    text-decoration: none;
}

.news-list h3 a:hover {
    text-decoration: underline;
}

.news-list p {
    margin: 0;
}

/* Inside the reading column, the list keeps its own spacing, not the prose
 * list's indent and item gaps. */
.prose .news-list,
.home-section__body .news-list {
    margin: 0 0 var(--space-5);
    padding: 0;
}

.prose .news-list li + li {
    margin-top: 0;
}

.prose .news-list h3 {
    margin: 0 0 var(--space-2);
    font-size: 1.375rem;
}

.prose .news-list p {
    margin: 0;
}

/* ------------------------------------------------------------------ */
/* Footer: a plain charcoal band, centred                              */
/* ------------------------------------------------------------------ */

.site-footer {
    /* The joint between the tile row and the footer: as wide as the logo's
     * joints, and showing the page's own colour. */
    --joint: 0.1875rem;
    position: relative;
    background: var(--ink);
    color: var(--paper);
    padding: var(--space-6) var(--space-4) var(--space-5);
}

/* Tile row: a course of the logo's own tiles above the footer, separated from
 * it by a joint, as the logo separates its rings. It sits over the foot of the
 * page above, so the joints, and the gap beneath, show that page's colour. */
.site-footer::before {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: calc(100% + var(--joint));
    height: 1.125rem;
    background: var(--ink);
    -webkit-mask: url("assets/logos/tile-joints.svg") left bottom / 18rem 100% repeat-x;
    mask: url("assets/logos/tile-joints.svg") left bottom / 18rem 100% repeat-x;
    pointer-events: none;
}

.site-footer__inner {
    max-width: 68rem;
    margin-inline: auto;
    display: grid;
    justify-items: center;
    gap: var(--space-4);
    text-align: center;
}

/* The BHF plate in the band. Letters and frame lines are holes in the plate,
 * so the charcoal shows through. */
.nameplate {
    aspect-ratio: 574.86 / 396.27;
    background: var(--plate);
    -webkit-mask: url("assets/logos/nameplate.svg") center / contain no-repeat;
    mask: url("assets/logos/nameplate.svg") center / contain no-repeat;
}

.site-footer__row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-4) var(--space-6);
    align-items: center;
    justify-content: center;
}

.social {
    display: flex;
    gap: var(--space-2);
    margin: 0;
    padding: 0;
    list-style: none;
}

.social a {
    display: grid;
    place-items: center;
    width: 2.75rem;
    height: 2.75rem;
    border-radius: var(--radius);
}

.social a:hover {
    background: rgba(248, 248, 248, 0.12);
}

.social svg {
    width: 1.375rem;
    height: 1.375rem;
    fill: currentColor;
}

/* Placeholder profiles: shown so the layout is real, but inert until a
 * URL is set. Remove aria-disabled when the href is filled in. */
.social a[aria-disabled="true"] {
    opacity: 0.55;
    pointer-events: none;
}

.site-footer__links {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: var(--space-2) var(--space-5);
    margin: 0;
    padding: 0;
    list-style: none;
    font-size: 1rem;
}

.site-footer__legal {
    margin: 0;
    font-size: 0.875rem;
    line-height: 1.5;
    color: var(--stone);
}

.site-footer__credit {
    margin: var(--space-2) 0 0;
    font-size: 0.875rem;
    line-height: 1.5;
    color: var(--stone);
}

.site-footer :focus-visible {
    outline-color: var(--paper);
}

/* ------------------------------------------------------------------ */
/* Reading pages: a calm off-white column                               */
/* ------------------------------------------------------------------ */

.prose {
    flex: 1;
    background: var(--paper);
    padding: var(--space-7) var(--space-4) var(--space-8);
}

.prose__inner {
    max-width: 40rem;
    margin-inline: auto;
    overflow-wrap: anywhere;
}

.prose__inner > :first-child {
    margin-top: 0;
}

.prose h2 {
    margin: var(--space-7) 0 var(--space-3);
    font-family: var(--font-sign);
    font-weight: 600;
    font-size: 1.625rem;
    line-height: 1.15;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

.prose h3 {
    margin: var(--space-6) 0 var(--space-2);
    font-size: 1.25rem;
    line-height: 1.3;
    font-weight: 600;
}

.prose h2 + h3 {
    margin-top: var(--space-4);
}

.prose p,
.prose ul {
    margin: 0 0 var(--space-4);
}

/* CMS images carry width and height (no layout shift while loading); height:
 * auto keeps their proportions when the column is narrower. */
.prose img {
    height: auto;
}

/* No single word stranded on a paragraph's last line. */
.prose p,
.prose li {
    text-wrap: pretty;
}

/* Names and roles, one per row between rules. */
.prose .people {
    padding: 0;
    list-style: none;
    border-top: 1px solid var(--ink);
}

.prose .people li {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    gap: 0 var(--space-4);
    margin: 0;
    padding: var(--space-3) 0;
    border-bottom: 1px solid var(--ink);
}

@media (max-width: 35.99rem) {
    .prose .people li {
        display: grid;
        gap: 0;
    }
}

.people strong {
    font-weight: 600;
}

.prose .back-link {
    margin-top: var(--space-7);
    font-weight: 600;
}

.prose ul {
    padding-left: 1.25rem;
}

.prose li + li {
    margin-top: var(--space-2);
}

.prose .meta {
    color: #555;
    font-size: 1rem;
}

.placeholder {
    background: var(--yellow);
    padding: 0 0.25em;
    font-weight: 600;
}

/* ------------------------------------------------------------------ */
/* Partners: "In partnership with", logos on a charcoal plate           */
/* ------------------------------------------------------------------ */

/* The banner closes the page opening: still on the yellow-tint field, an
 * enamel plate as wide as the introduction above it, the logos in off-white
 * like the lettering of the band and footer. */
.partners {
    background: var(--field);
    padding: 0 var(--gutter) clamp(2.5rem, 5vw, 4rem);
}

.partners__inner {
    max-width: var(--width-reading);
    margin-inline: auto;
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-5);
    padding: var(--space-6) var(--space-5);
    border: 2px solid var(--ink);
    border-radius: var(--radius);
    background: var(--ink);
    color: var(--paper);
    box-shadow: inset 0 0 0 var(--plate-inset) var(--ink),
        inset 0 0 0 calc(var(--plate-inset) + 2px) var(--keyline);
    overflow-wrap: anywhere;
}

/* A charcoal ring would vanish on the plate, so focus here rings in the
 * field colour too. */
.partners :focus-visible {
    outline-color: var(--field);
}

.partners__head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3) var(--space-5);
}

.partners__title {
    margin: 0;
    color: var(--surface);
    font-family: var(--font-sign);
    font-weight: 600;
    font-size: 1.25rem;
    line-height: 1.2;
    letter-spacing: 0.08em;
    text-transform: uppercase;
}

/* Shown only while the logos move (see below): with nothing moving there is
 * nothing to pause. The control is a single icon button in the plate's
 * top-right corner — a native checkbox kept invisible inside the label, drawn
 * over a 44px target. Its accessible name is the visually hidden text, and the
 * icon follows the plate's text colour (--surface, like the title beside it). */
.partners__pause {
    position: relative;
    display: none;
    flex: none;
    width: 2.75rem;
    height: 2.75rem;
    color: var(--surface);
    cursor: pointer;
    border-radius: var(--radius);
}

/* The checkbox is invisible but still the control: the label is the click
 * target, and keyboard focus lands here (the ring is drawn on the label). */
.partners__pause input {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    margin: 0;
    opacity: 0;
    cursor: pointer;
}

/* Two vertical bars (pause) while the logos scroll; a right-pointing triangle
 * (play) once ticked. A currentColor SVG, so it always matches the title. */
.partners__pause-icon {
    position: absolute;
    top: 50%;
    left: 50%;
    width: 1.5rem;
    height: 1.5rem;
    transform: translate(-50%, -50%);
    fill: currentColor;
}

.partners__pause-play {
    display: none;
}

/* Still, by default: the logos wrap onto as many rows as they need. */
.partners__list {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: var(--space-4);
    margin: 0;
    padding: 0;
    list-style: none;
}

.partners__list--copy {
    display: none;
}

/* Each logo on a small tile of its own, outlined faintly on the plate. A
 * partner without a logo shows its name in sign lettering instead. */
.partners__tile {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 9rem;
    min-height: 4.5rem;
    height: 100%;
    padding: var(--space-3);
    border: 1px solid rgba(248, 248, 248, 0.24);
    border-radius: var(--radius);
    font-family: var(--font-sign);
    font-weight: 600;
    font-size: 1rem;
    line-height: 1.2;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    text-align: center;
    text-decoration: none;
    transition: border-color 240ms var(--ease-out);
}

@media (hover: hover) {
    a.partners__tile:hover {
        border-color: rgba(248, 248, 248, 0.6);
    }
}

/* Logos in one colour, whatever they were uploaded in: every pixel turned
 * black, then inverted to off-white. Needs a transparent background; an
 * opaque one would become a white block. */
.partners__tile img {
    width: auto;
    max-width: 100%;
    height: 3rem;
    object-fit: contain;
    filter: brightness(0) invert(0.97);
}

@media (max-width: 29.99rem) {
    .partners__tile {
        width: 8rem;
        min-height: 4rem;
    }
}

/* Moving, where motion is welcome and the browser can read the pause control
 * (:has). The track holds the list twice and slides by one list's width, so
 * the loop has no seam. It pauses while the box is ticked, under a hovering
 * mouse and while anything in the banner has focus. Screen only, so print
 * gets the still rows. */
@media screen and (prefers-reduced-motion: no-preference) {
    @supports selector(:has(*)) {
        .partners__pause {
            display: block;
        }

        /* Ticked: swap the pause bars for the play triangle. */
        .partners:has(.partners__pause input:checked) .partners__pause-bars {
            display: none;
        }

        .partners:has(.partners__pause input:checked) .partners__pause-play {
            display: block;
        }

        /* The ring draws around the icon button that holds the hidden checkbox. */
        .partners__pause:has(input:focus-visible) {
            outline: 3px solid var(--field);
            outline-offset: 3px;
        }

        .partners__window {
            overflow: hidden;
        }

        .partners__track {
            display: flex;
            width: max-content;
            animation: partners-scroll 45s linear infinite;
        }

        /* Each list ends with one gap, so the copy follows on evenly. */
        .partners__list {
            flex: none;
            flex-wrap: nowrap;
            padding-right: var(--space-4);
        }

        .partners__list--copy {
            display: flex;
        }

        .partners:has(.partners__pause input:checked) .partners__track,
        .partners:focus-within .partners__track {
            animation-play-state: paused;
        }

        @media (hover: hover) {
            .partners:hover .partners__track {
                animation-play-state: paused;
            }

            .partners__pause:hover {
                background: rgba(248, 248, 248, 0.12);
            }
        }

        /* Focus on a logo link: paused, it could be anywhere along the track,
         * even out of the window, so the row settles back into the still
         * layout and the focused logo stays in view. */
        .partners__window:focus-within {
            overflow: visible;
        }

        .partners__window:focus-within .partners__track {
            display: block;
            width: auto;
            animation: none;
        }

        .partners__window:focus-within .partners__list {
            flex-wrap: wrap;
            padding-right: 0;
        }

        .partners__window:focus-within .partners__list--copy {
            display: none;
        }
    }
}

@keyframes partners-scroll {
    to {
        transform: translateX(-50%);
    }
}

@media (max-width: 29.99rem) {
    .page-intro {
        padding-block: var(--space-7) 2.5rem;
    }

    .button {
        padding-inline: var(--space-4);
        font-size: 1.125rem;
        letter-spacing: 0.08em;
    }

    .signup__button {
        width: 100%;
    }
}

/* Phones on their side: tighten the vertical rhythm so the form comes up sooner. */
@media (orientation: landscape) and (max-height: 30rem) {
    .landing {
        padding-top: var(--space-6);
        gap: var(--space-5);
    }
}

/* Wide screens: section titles in a left column, text beside them. */
@media (min-width: 48rem) {
    .home-section__inner {
        grid-template-columns: minmax(0, 1fr) minmax(0, 2fr);
        align-items: start;
    }
}

/* Refinement · existing festival layouts, welcoming tone, yellow anchor.
 * Hallmark pre-emit critique: P5 H4 E4 S5 R5 V4.
 * Shared dimensions and quiet tile edges preserve the McCadden identity. */
:root {
    --width-site: 68rem;
    --width-reading: 40rem;
    --gutter: clamp(1rem, 4vw, 2.5rem);
    --section-space: clamp(3rem, 6vw, 5rem);
    --rule-soft: rgba(64, 64, 64, 0.24);
    --ink-secondary: #555;
    --tile-a: polygon(0 2px, 3px 0, calc(100% - 3px) 0,
        100% 3px, 100% calc(100% - 2px), calc(100% - 3px) 100%,
        2px 100%, 0 calc(100% - 3px));
    --tile-b: var(--tile-a);
    --tile-chip: var(--tile-a);
}

.site-head,
.page-intro,
.landing,
.home-section,
.home-invite,
.prose,
.site-footer {
    padding-inline: var(--gutter);
}

.site-head__inner,
.home-section__inner,
.home-invite__inner,
.site-footer__inner {
    max-width: var(--width-site);
}

.page-intro__inner,
.home-section__body {
    max-width: var(--width-reading);
}

/* Long-form copy needs a shorter measure; introductions and home sections
 * retain their existing width and alignment. */
.prose__inner {
    max-width: 36rem;
}

.site-head {
    padding-block: var(--space-4);
}

.site-head__inner {
    gap: var(--space-4) var(--space-6);
}

.site-nav a {
    min-height: 2.75rem;
    display: flex;
    align-items: center;
    letter-spacing: 0.08em;
    padding-right: calc(var(--space-3) - 0.08em);
    overflow-wrap: anywhere;
}

/* The opening meets the header cleanly; tilework is reserved for the footer. */
.page-intro::before {
    content: none;
}

.page-intro {
    padding-block: var(--section-space) clamp(2.5rem, 5vw, 4rem);
}

.page-title {
    letter-spacing: 0.035em;
    line-height: 1.1;
}

.page-title--article {
    letter-spacing: -0.015em;
    line-height: 1.2;
}

.page-intro p {
    margin-top: var(--space-5);
    line-height: 1.6;
    text-wrap: pretty;
}

.page-intro .meta {
    margin-top: var(--space-4);
}

.landing {
    padding-block: clamp(2.5rem, 5vw, 4rem) var(--section-space);
    gap: clamp(2rem, 4vw, 3rem);
}

.landing__body {
    gap: var(--space-5);
}

.lede {
    max-width: 33rem;
    margin-inline: auto;
    line-height: 1.55;
}

.signup {
    margin-top: var(--space-2);
    row-gap: var(--space-3);
}

.signup__consent {
    margin-top: var(--space-2);
    line-height: 1.55;
}

.button,
.signup__button {
    justify-content: center;
    letter-spacing: 0.07em;
    box-shadow: inset 0 0 0 3px var(--plate-bg), inset 0 0 0 4px var(--plate-line);
}

.home-section,
.home-invite {
    padding-block: var(--section-space);
}

.home-section + .home-section {
    padding-top: 0;
}

.home-section__inner {
    padding-top: var(--space-6);
    border-top-width: 1px;
    border-top-color: var(--rule-soft);
    column-gap: var(--space-8);
}

.home-section h2,
.home-invite h2 {
    letter-spacing: 0.04em;
    line-height: 1.15;
}

.home-about__lede {
    line-height: 1.5;
}

.home-invite__inner {
    padding: clamp(2rem, 5vw, 4rem);
    gap: var(--space-4);
}

.home-invite .button {
    margin-top: var(--space-3);
}

.prose {
    padding-block: clamp(2.5rem, 5vw, 4rem) var(--section-space);
    line-height: 1.65;
}

.prose h2 {
    margin-top: var(--space-8);
    letter-spacing: 0.035em;
    line-height: 1.2;
}

.prose h2 + h3 {
    margin-top: var(--space-4);
}

.prose .people,
.prose .people li,
.news-list li {
    border-color: var(--rule-soft);
}

.people span {
    color: var(--ink-secondary);
}

.news-list li {
    padding-block: var(--space-6);
}

.news-list time {
    padding: 0.15em 0.5em;
    margin-bottom: var(--space-3);
    font-size: 0.9375rem;
    letter-spacing: 0.05em;
    background: var(--field);
    color: var(--ink);
    box-shadow: none;
}

.news-list h3,
.prose .news-list h3 {
    font-size: 1.5rem;
    line-height: 1.3;
    margin-bottom: var(--space-3);
}

.news-list p {
    line-height: 1.6;
}

.site-footer {
    --joint: 0.125rem;
    padding-block: var(--space-7) var(--space-6);
}

/* A small centred maker's detail replaces the full-width decorative course. */
.site-footer::before {
    left: 50%;
    right: auto;
    width: 9rem;
    height: 0.375rem;
    transform: translateX(-50%);
    -webkit-mask-size: 9rem 100%;
    mask-size: 9rem 100%;
}

.site-footer__inner {
    gap: var(--space-3);
}

.site-footer__updates {
    margin: 0 0 var(--space-4);
    font-size: 1.125rem;
}

.site-footer__links a {
    display: inline-block;
    padding-block: var(--space-2);
}

.site-footer__credit {
    margin-top: 0;
}

@media (max-width: 29.99rem) {
    .site-nav a {
        padding-right: calc(var(--space-2) - 0.08em);
    }

    .button {
        padding-inline: var(--space-4);
        font-size: 1.0625rem;
        letter-spacing: 0.04em;
    }
}

/* Editorial layouts: image spaces are explicit placeholders until the
 * festival supplies cleared archive material and captions. */
.editorial-figure {
    margin: 0;
    min-width: 0;
}

.image-placeholder {
    display: grid;
    place-items: center;
    width: 100%;
    min-width: 0;
    min-height: 14rem;
    padding: 2rem;
    background: var(--stone);
    color: var(--ink);
    border: 1px solid var(--rule-soft);
    text-align: center;
    overflow-wrap: anywhere;
}

.image-placeholder span {
    padding: 1.25rem;
    border-block: 1px solid currentColor;
    font-family: var(--font-sign);
    font-size: clamp(1.5rem, 3vw, 2.25rem);
    line-height: 1.25;
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

.image-placeholder small {
    display: inline-block;
    margin-top: 0.5rem;
    font-family: var(--font-body);
    font-size: 1rem;
    letter-spacing: 0;
    text-transform: none;
}

.image-placeholder--wide { aspect-ratio: 2.4 / 1; min-height: 0; }
.image-placeholder--portrait { aspect-ratio: 4 / 5; }

.editorial-figure figcaption {
    max-width: 44rem;
    margin-top: 0.75rem;
    font-size: 0.9375rem;
    line-height: 1.5;
    color: var(--ink-secondary);
}

.home-editorial__inner {
    border-top: 0;
    padding-top: 0;
    row-gap: 2.5rem;
}

.home-editorial .home-about__lede {
    font-size: clamp(1.5rem, 2.4vw, 2.125rem);
    line-height: 1.35;
}

.home-editorial__image { grid-column: 1 / -1; }

.home-news .home-news__inner {
    display: block;
}

.home-news .home-section__body { max-width: none; }
.home-news .news-list { margin-top: 2rem; }
.home-news .news-list li { border-top: 1px solid var(--rule-soft); }

.about-opening__inner,
.about-story,
.about-people__inner {
    width: 100%;
    max-width: var(--width-site);
    margin-inline: auto;
    overflow-wrap: anywhere;
}

.about-opening__inner {
    display: grid;
    gap: 2rem;
}

.about-opening .page-title {
    font-size: clamp(3.5rem, 7vw, 6rem);
}

.about-opening p {
    max-width: 38rem;
    margin: 0;
    font-size: clamp(1.375rem, 2.2vw, 1.875rem);
    line-height: 1.45;
}

.about-story {
    max-width: none;
    padding: var(--section-space) var(--gutter);
    background: var(--paper);
}

.about-story__image,
.about-story__columns {
    max-width: var(--width-site);
    margin-inline: auto;
}

.about-story__columns {
    display: grid;
    gap: 3rem;
    margin-top: var(--section-space);
}

.about-story__copy { padding: 0; min-width: 0; }
.about-story__copy .prose__inner { margin-inline: 0; }
.about-story__aside { min-width: 0; }

.about-people {
    padding: var(--section-space) var(--gutter);
    background: var(--field);
}

.about-people__heading {
    display: grid;
    gap: 1.5rem;
    margin-bottom: 3rem;
}

.about-people h2 {
    margin: 0;
    font-family: var(--font-sign);
    font-size: clamp(2rem, 3vw, 3rem);
    line-height: 1.15;
    text-transform: uppercase;
    letter-spacing: 0.035em;
}

.about-people__heading p { max-width: 38rem; margin: 0; }
.about-people__list {
    display: grid;
    gap: 1.5rem 2.5rem;
    list-style: none;
    margin: 0;
    padding: 0;
}

.about-people__list li { border-top: 1px solid var(--ink); padding-top: 1.25rem; }
.about-people__list strong { display: block; font-size: 1.5rem; }
.about-people__list span { display: block; margin-top: 0.375rem; }

@media (min-width: 48rem) {
    .home-news .news-list {
        display: grid;
        grid-template-columns: repeat(3, minmax(0, 1fr));
        gap: 2rem;
    }
    .home-news .news-list li { padding-block: 1.5rem; border-bottom: 0; }
    .about-opening__inner,
    .about-people__heading { grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); gap: 4rem; }
    .about-story__columns { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); gap: 5rem; }
    .about-story__aside { padding-top: 5rem; }
    .about-people__list { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* ------------------------------------------------------------------ */
/* Programme and event pages                                            */
/* ------------------------------------------------------------------ */

/* The programme sits on the off-white reading surface, as wide as the page
 * opening, so the day headings line up under the title. */
.programme {
    flex: 1;
    background: var(--paper);
    padding: clamp(2.5rem, 5vw, 4rem) var(--gutter) var(--section-space);
}

.programme__inner {
    max-width: var(--width-reading);
    margin-inline: auto;
    overflow-wrap: anywhere;
}

.programme__inner > p {
    margin: 0;
}

/* Day headings in sign lettering, like the reading pages' section heads. */
.programme__day {
    margin: var(--space-8) 0 0;
    font-family: var(--font-sign);
    font-weight: 600;
    font-size: 1.625rem;
    line-height: 1.2;
    letter-spacing: 0.035em;
    text-transform: uppercase;
}

.programme__day:first-child {
    margin-top: 0;
}

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

/* Events between soft rules, as the news list is. On phones the image leads;
 * on wider screens it sits in a narrow column beside the text. */
.event-card {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-4);
    padding-block: var(--space-6);
    border-bottom: 1px solid var(--rule-soft);
}

.event-card .event-image {
    order: -1;
}

@media (min-width: 40rem) {
    .event-card {
        grid-template-columns: 12rem minmax(0, 1fr);
        column-gap: var(--space-5);
        align-items: start;
    }

    .event-card .event-image {
        grid-column: 1;
        grid-row: 1;
    }

    .event-card__body {
        grid-column: 2;
        grid-row: 1;
    }
}

.event-card__body > * {
    margin: 0;
}

.event-card__body > * + * {
    margin-top: var(--space-2);
}

.event-card h3 {
    font-size: 1.5rem;
    line-height: 1.3;
    font-weight: 600;
}

.event-card h3 a {
    text-decoration: none;
}

.event-card h3 a:hover {
    text-decoration: underline;
}

.event-card__when {
    font-weight: 600;
}

.event-card__where,
.event-card__price {
    color: var(--ink-secondary);
}

.event-card__summary {
    line-height: 1.6;
}

.event-card__body > .event-label,
.event-card__body > .event-book {
    margin-top: var(--space-4);
}

/* Images fill a 3:2 frame. The responsive-images transform swaps the <img>
 * for a <picture>, so the frame is styled rather than the image's own class. */
.event-image {
    aspect-ratio: 3 / 2;
    overflow: hidden;
    border-radius: var(--radius);
}

.event-image picture,
.event-image img {
    display: block;
    width: 100%;
    height: 100%;
}

.event-image img {
    object-fit: cover;
}

/* No image: the BHF plate on a charcoal enamel plate, with the yellow line
 * set in from the edge as on the home invite. Decorative. */
.event-image--plate {
    display: grid;
    place-items: center;
    border: 2px solid var(--ink);
    background: var(--ink);
    box-shadow: inset 0 0 0 var(--plate-inset) var(--ink),
        inset 0 0 0 calc(var(--plate-inset) + 2px) var(--keyline);
}

.event-image--plate .nameplate {
    width: 42%;
}

/* On phones, where the image spans the column, the plate is a long street
 * sign instead, so three of them don't fill the screen. */
@media (max-width: 39.99rem) {
    .event-card .event-image--plate {
        aspect-ratio: 3 / 1;
    }

    .event-card .event-image--plate .nameplate {
        width: 26%;
    }
}

/* On the event page the plate is a long street sign, so it doesn't outweigh
 * the details below it. */
.prose .event-image {
    margin-bottom: var(--space-6);
}

.prose .event-image--plate {
    aspect-ratio: 3 / 1;
}

.prose .event-image--plate .nameplate {
    width: 26%;
}

/* Booking states as quiet yellow-tint chips, like the news dates; a status
 * that stops booking (Sold out, Cancelled, Postponed) on charcoal enamel,
 * lettered in the surface's colour like the buttons. */
.event-label {
    width: fit-content;
    padding: 0.15em 0.5em;
    background: var(--field);
    color: var(--ink);
    clip-path: var(--tile-chip);
    font-family: var(--font-sign);
    font-weight: 600;
    font-size: 1rem;
    line-height: 1.4;
    letter-spacing: 0.05em;
    text-transform: uppercase;
}

/* On the yellow-tint opening the quiet chip turns off-white to stand clear. */
.page-intro .event-label {
    background: var(--paper);
    font-size: 1.0625rem;
    line-height: 1.4;
}

.event-label--status,
.page-intro .event-label--status {
    background: var(--ink);
    color: var(--surface);
}

/* Format, venue, price and access, one row each between soft rules. */
.event-facts {
    margin: 0 0 var(--space-4);
    border-top: 1px solid var(--rule-soft);
}

.event-facts div {
    padding-block: var(--space-3);
    border-bottom: 1px solid var(--rule-soft);
}

.event-facts dt {
    font-weight: 600;
}

.event-facts dd {
    margin: 0;
}

@media (min-width: 36rem) {
    .event-facts div {
        display: grid;
        grid-template-columns: 7rem minmax(0, 1fr);
        gap: var(--space-4);
    }
}

/* Speakers use the team list's rules, with the one-line biography under the
 * name rather than across from it. */
.prose .people--speakers li {
    display: grid;
    gap: 0;
}

.prose .event-calendar {
    margin-bottom: var(--space-6);
}

.event-calendar a {
    font-weight: 600;
}

/* Programme: dates anchor a wider editorial grid; the booking column on an
 * event page stays in normal flow, so long access notes never get trapped. */
.programme-opening__inner,
.event-opening__inner,
.event-detail__inner {
    max-width: var(--width-site);
    margin-inline: auto;
    overflow-wrap: anywhere;
}

.programme-opening__inner { display: grid; gap: 2rem; }
.programme-opening .page-title { font-size: clamp(3rem, 6vw, 5rem); }
.programme-opening p { margin: 0; max-width: 34rem; font-size: clamp(1.25rem, 2vw, 1.625rem); }
.programme__inner { max-width: var(--width-site); }
.programme-day { display: grid; gap: 2rem; padding-block: 2.5rem; border-top: 1px solid var(--ink); }
.programme-day:first-child { padding-top: 0; border-top: 0; }
.programme-day .programme__day { margin: 0; font-size: 2rem; }
.programme-day .event-list { display: grid; gap: 2.5rem; }
.programme-day .event-card { display: flex; flex-direction: column; align-items: stretch; min-width: 0; padding: 0 0 2rem; gap: 1.5rem; }
.event-card .event-figure { order: -1; }
.event-card__body { display: flex; flex-direction: column; flex: 1; min-width: 0; }
.event-card__details { display: flex; flex-wrap: wrap; gap: 0.5rem 1rem; padding-block: 0.75rem; border-bottom: 1px solid var(--rule-soft); }
.event-card__details p { margin: 0; }
.event-card__price { font-weight: 600; }
.event-card__body > .event-card__summary { margin-block: 1rem 1.5rem; }
.event-card__body > .event-book,
.event-card__body > .event-label { margin-top: auto; align-self: start; }

.editorial-image { overflow: hidden; }
.editorial-image picture,
.editorial-image img { display: block; width: 100%; height: 100%; }
.editorial-image img { object-fit: cover; }
.editorial-image--wide { aspect-ratio: 2.4 / 1; }
.editorial-image--portrait { aspect-ratio: 4 / 5; }
.editorial-image--event,
.image-placeholder--event { aspect-ratio: 3 / 2; min-height: 0; }
.event-figure .image-placeholder { padding: 1.5rem; }
.event-figure .image-placeholder span { font-size: clamp(1.25rem, 2vw, 1.75rem); }

.event-opening .event-back { margin: 0 0 2rem; font-size: 1rem; }
.event-opening .event-opening__date { margin: 0 0 1rem; font-family: var(--font-sign); font-size: 1.25rem; letter-spacing: 0.04em; text-transform: uppercase; }
.event-opening .page-title { max-width: 24ch; font-size: clamp(2.25rem, 4.5vw, 4rem); }
.event-opening p:last-child { max-width: 42rem; }
.event-detail {
    --surface: var(--paper);
    --plate-fg: var(--surface);
    --plate-line: var(--surface);
    background: var(--paper);
    padding: var(--section-space) var(--gutter);
}
.event-detail__inner { display: grid; gap: 3rem; }
.event-details { min-width: 0; align-self: start; border-top: 3px solid var(--ink); padding-top: 1.5rem; }
.event-details h2 { margin: 0 0 1.5rem; font-family: var(--font-sign); font-size: 2rem; line-height: 1.15; text-transform: uppercase; }
.event-details .event-facts div { display: block; }
.event-details .event-facts dd { margin-top: 0.25rem; }
.event-details__booking > * { margin: 1.5rem 0 0; }
.event-details .event-calendar { font-size: 1rem; line-height: 1.5; margin: 1.25rem 0 0; }
.event-story { min-width: 0; }
.event-story__copy { padding: 2.5rem 0 0; }
.event-story__copy .prose__inner { margin-inline: 0; }

@media (min-width: 48rem) {
    .programme-opening__inner { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); align-items: start; gap: 4rem; }
    .programme-day .event-list { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (min-width: 64rem) {
    .programme-day { grid-template-columns: minmax(0, 1fr) minmax(0, 4fr); gap: 3rem; }
    .programme-day .programme__day { font-size: 1.625rem; }
    .programme__day time { display: block; }
    .event-detail__inner { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); column-gap: 4rem; }
    .event-story { grid-column: 1; grid-row: 1; }
    .event-details { grid-column: 2; grid-row: 1; }
}

/* Visitors whose system asks for more contrast: darker ink, heavier borders and
 * underlines, and full-strength text in the footer. */
@media (prefers-contrast: more) {
    :root {
        --ink: #1a1a1a;
        --ink-pressed: #000;
        --focus: #000;
    }

    a {
        text-decoration-thickness: 2px;
    }

    .signup__input,
    .signup__button,
    .signup-success {
        border-width: 3px;
    }

    .landing__text,
    .gate__form,
    .partners__inner {
        border-width: 3px;
    }

    .site-footer__legal,
    .site-footer__credit,
    .prose .meta,
    .people span {
        color: inherit;
    }

    .button {
        border-width: 3px;
    }

    .social a[aria-disabled="true"] {
        opacity: 0.8;
    }

    /* Keep the sign and plate edges unambiguous when extra contrast is asked
     * for; the tile silhouettes are decorative. */
    .page-intro::before,
    .site-footer::before {
        display: none;
    }

    .button,
    .signup__button,
    .news-list time,
    .event-label {
        clip-path: none;
    }

    .landing__text,
    .gate__form,
    .home-invite__inner,
    .partners__inner,
    .event-image--plate {
        box-shadow: none;
    }

    .event-card__where,
    .event-card__price {
        color: inherit;
    }
}

/* Colour picker (colours.js): pre-launch only, for colleagues past the gate.
 * A tab in the bottom corner that opens a panel of palette swatches. It's a
 * review tool, so it stays out of the brand surface language: plain dark panel,
 * same as the emailed colour-options preview. */
.colour-picker {
    position: fixed;
    right: var(--space-4);
    bottom: var(--space-4);
    z-index: 30;
    max-width: calc(100vw - 2 * var(--space-4));
    border-radius: var(--radius);
    background: var(--ink-pressed);
    color: var(--paper);
    font: 600 0.875rem/1.35 var(--font-body);
    box-shadow: 0 0.25rem 1rem rgba(0, 0, 0, 0.25);
}

.colour-picker summary {
    padding: var(--space-2) var(--space-4);
    cursor: pointer;
}

.colour-picker[open] summary {
    border-bottom: 1px solid rgba(248, 248, 248, 0.2);
}

.colour-picker :focus-visible {
    outline-color: var(--paper);
}

.colour-picker__panel {
    display: grid;
    gap: var(--space-3);
    width: 28rem;
    max-width: 100%;
    max-height: 70vh;
    overflow-y: auto;
    padding: var(--space-3) var(--space-4) var(--space-4);
}

.colour-picker__row {
    display: grid;
    gap: var(--space-2);
}

.colour-picker__swatches {
    display: flex;
    flex-wrap: wrap;
    gap: 0.375rem;
}

.colour-picker__swatches button {
    width: 1.75rem;
    height: 1.75rem;
    padding: 0;
    border: 2px solid rgba(248, 248, 248, 0.35);
    border-radius: var(--radius);
    background: var(--swatch, transparent);
    cursor: pointer;
}

.colour-picker__swatches button[aria-pressed="true"] {
    border-color: var(--paper);
    outline: 2px solid var(--paper);
    outline-offset: 2px;
}

.colour-picker p {
    margin: 0;
    font-weight: 400;
}

.colour-picker__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
}

.colour-picker__actions button {
    padding: 0.375rem 0.75rem;
    border: 2px solid var(--paper);
    border-radius: var(--radius);
    background: var(--paper);
    color: var(--ink-pressed);
    font: inherit;
    cursor: pointer;
}

.colour-picker__actions button + button {
    background: transparent;
    color: var(--paper);
}

@media (max-width: 29.99rem) {
    .colour-picker {
        right: var(--space-2);
        bottom: var(--space-2);
        max-width: calc(100vw - 2 * var(--space-2));
    }
}

/* Windows High Contrast and other forced-colour modes drop background colours.
 * The charcoal logo would vanish on a dark theme, so it keeps a light backing;
 * the plate (a CSS mask over a background) is redrawn in the text colour. */
@media (forced-colors: active) {
    .logo-lockup {
        forced-color-adjust: none;
        background: var(--off-white);
        padding: var(--space-2);
    }

    .logo-lockup img {
        forced-color-adjust: none;
    }

    .nameplate {
        forced-color-adjust: none;
        background: CanvasText;
    }

    /* Purely decorative tile row: leave it out. */
    .site-footer::before {
        display: none;
    }

    /* Same for the tile course under the head, and the clip on the date chip. */
    .page-intro::before {
        display: none;
    }

    .news-list time,
    .event-label {
        clip-path: none;
        box-shadow: none;
        border: 1px solid CanvasText;
    }

    .button,
    .signup__button {
        clip-path: none;
        box-shadow: none;
    }

    .landing__text,
    .gate__form,
    .home-invite__inner,
    .partners__inner,
    .event-image--plate {
        box-shadow: none;
    }

    /* Partner logos are drawn off-white for the charcoal plate, which forced
     * colours remove: the tile keeps a charcoal backing, and the logo keeps
     * the filter that draws it light (off the image, so the backing is never
     * run through it). */
    .partners__tile {
        forced-color-adjust: none;
        background: var(--ink);
    }

    .partners__tile img {
        forced-color-adjust: none;
    }

    /* The pause icon is a currentColor SVG, so in forced colours it follows the
     * system text colour like the plate's other lettering. */
    .partners__pause {
        color: CanvasText;
    }

    /* The swatches are the point of the colour picker: keep their colours. */
    .colour-picker__swatches button {
        forced-color-adjust: none;
    }

    /* The current page's plate is a background, which forced colours remove:
     * underline instead. */
    .site-nav a[aria-current] {
        text-decoration: underline 3px;
        text-underline-offset: 0.3em;
    }
}

/* Print, mainly for the privacy notice: black on white, no decoration, and
 * external link addresses written out so they survive on paper or in a PDF. */
@media print {
    body,
    .page-intro,
    .prose,
    .landing,
    .home-section,
    .home-invite {
        background: #fff;
        color: #000;
    }

    body {
        font-size: 11pt;
    }

    .skip-link,
    .site-head,
    .button,
    .nameplate,
    .social,
    .signup,
    .preview-banner,
    .options-bar,
    .colour-picker {
        display: none !important;
    }

    .page-intro,
    .prose,
    .home-section,
    .home-invite {
        padding: 0 0 1rem;
    }

    /* The page-intro tile course prints as a solid black band, and the
     * enamelled message panel as an ink slab: drop the decoration, keep the
     * words. (The gate form is a .signup and is hidden with the form.) */
    .page-intro::before,
    .site-footer::before {
        display: none !important;
    }

    .landing__text {
        padding: 0;
        border: 0;
        background: none;
        box-shadow: none;
        color: #000;
    }

    .news-list time,
    .event-label,
    .page-intro .event-label--status {
        padding: 0;
        background: none;
        box-shadow: none;
        clip-path: none;
        color: #000;
    }

    /* The image-less plate is decoration; a real image prints. */
    .event-image--plate {
        display: none !important;
    }

    .programme {
        background: #fff;
        padding: 0 0 1rem;
    }

    .button,
    .signup__button {
        clip-path: none;
    }

    .home-invite__inner {
        padding: 0;
        border: 0;
        background: none;
        box-shadow: none;
        color: #000;
        animation: none;
    }

    .home-invite h2 {
        color: #000;
    }

    /* Partners print still (the motion is screen only, and so is the pause
     * control), as black logos and names on the paper. */
    .partners {
        background: none;
        padding: 0 0 1rem;
    }

    .partners__inner {
        padding: 0;
        border: 0;
        background: none;
        box-shadow: none;
        color: #000;
    }

    .partners__title {
        color: #000;
    }

    .partners__tile {
        border-color: #000;
    }

    .partners__tile img {
        filter: brightness(0);
    }

    .prose h2 {
        margin-top: 1.5rem;
        break-after: avoid;
    }

    .prose li,
    .prose p {
        break-inside: avoid;
    }

    .prose a[href^="http"]::after {
        content: " (" attr(href) ")";
        font-size: 0.9em;
    }

    .placeholder {
        background: none;
        border: 1px solid #000;
    }

    .site-footer {
        background: none;
        color: #000;
        padding: 1rem 0 0;
        border-top: 1px solid #000;
    }

    .site-footer__legal,
    .site-footer__credit {
        color: #000;
    }
}

/* ------------------------------------------------------------------ */
/* Cross-document view transitions: pages crossfade into one another   */
/* ------------------------------------------------------------------ */

/* On same-site navigation the outgoing and incoming pages crossfade, subtly.
 * The header keeps a persistent name and no animation, so the bar stays put
 * while the content fades. Browsers without support just navigate normally.
 * Only where motion is welcome, so reduced-motion visitors get a plain,
 * instant page change. */
@media (prefers-reduced-motion: no-preference) {
    @view-transition {
        navigation: auto;
    }

    ::view-transition-old(root),
    ::view-transition-new(root) {
        animation-duration: 200ms;
        animation-timing-function: var(--ease-out);
    }

    .site-head {
        view-transition-name: site-head;
    }

    ::view-transition-group(site-head) {
        animation: none;
    }
}

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

    /* Anything with a delay or a hidden starting frame simply appears. */
    .logo-lockup,
    .dateline,
    .signup__status,
    .signup-success__tick,
    .home-invite__inner {
        animation: none;
    }

    .signup__button:hover,
    .button:hover,
    .signup__button:active,
    .button:active {
        transform: none;
    }
}

/* Hallmark · genre: editorial · macrostructure: dated index / reading page
 * Existing Programme and About system · pre-emit critique: P5 H4 E4 S5 R5 V4 */
.involvement,
.news-index {
    --surface: var(--paper);
    --plate-fg: var(--surface);
    --plate-line: var(--surface);
    background: var(--paper);
    padding: var(--section-space) var(--gutter);
}

.involvement__inner,
.news-index__inner {
    max-width: var(--width-site);
    margin-inline: auto;
    min-width: 0;
    overflow-wrap: anywhere;
}

.involvement__inner { display: grid; gap: 3rem; }
.involvement__copy { padding: 0; min-width: 0; }
.involvement__copy .prose__inner { margin-inline: 0; }
.involvement__contact { min-width: 0; align-self: start; border-top: 3px solid var(--ink); padding-top: 1.5rem; }
.involvement__contact h2,
.news-index h2 {
    margin: 0 0 1.5rem;
    font-family: var(--font-sign);
    font-size: clamp(2rem, 3vw, 2.5rem);
    line-height: 1.2;
    letter-spacing: 0.035em;
    text-transform: uppercase;
}

.news-index__list { margin: 0; padding: 0; list-style: none; }
.news-index__list li { display: grid; gap: 1rem; padding-block: 2.5rem; border-bottom: 1px solid var(--rule-soft); }
.news-index__list li:first-child { padding-top: 0; }
.news-index__list li > div { min-width: 0; }
.news-index__list time { font-family: var(--font-sign); font-size: 1.25rem; letter-spacing: 0.04em; text-transform: uppercase; }
.news-index h2 { max-width: 30ch; margin-bottom: 1rem; }
.news-index h2 a { text-decoration: none; }
.news-index h2 a:hover { text-decoration: underline; }
.news-index__list p { margin: 0; max-width: 38rem; line-height: 1.65; }

@media (min-width: 48rem) {
    .news-index__list li { grid-template-columns: minmax(0, 1fr) minmax(0, 3fr); gap: 4rem; }
}

@media (min-width: 64rem) {
    .involvement__inner { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); gap: 4rem; }
}

/* Partnership detail and continuous logo band, in the existing brand palette. */
:root { --partners-surface: var(--stone); }
.involvement__aside { min-width: 0; }
.involvement__image { margin: 0 0 2.5rem; }
.news-article__image { margin: 0 0 2.5rem; }
.partners {
    --surface: var(--partners-surface);
    background: var(--partners-surface);
    color: var(--ink);
    padding: 2.5rem 0 3rem;
}
.partners__inner {
    max-width: none;
    padding: 0;
    border: 0;
    border-radius: 0;
    background: transparent;
    color: inherit;
    box-shadow: none;
    gap: 2rem;
}
.partners__head {
    width: 100%;
    max-width: calc(var(--width-site) + 2 * var(--gutter));
    margin-inline: auto;
    padding-inline: var(--gutter);
}
.partners__title,
.partners__pause { color: var(--ink); }
.partners :focus-visible,
.partners__pause:has(input:focus-visible) { outline-color: var(--ink); }
.partners__tile {
    width: 10rem;
    min-height: 5rem;
    border: 0;
    border-radius: 0;
    color: var(--ink);
}
.partners__tile img { filter: brightness(0); height: 3.5rem; }
a.partners__tile:hover { text-decoration: underline; }
.partners__pause:hover { background: transparent; }

@media screen and (prefers-reduced-motion: no-preference) {
    @supports selector(:has(*)) {
        .partners__track { min-width: 200%; }
        .partners__list { flex: 1 0 auto; justify-content: space-around; }
    }
}

:root { --image-shadow: 0 0.5rem 1.5rem rgb(0 0 0 / 0.1); }
.editorial-image--shadow { box-shadow: var(--image-shadow); }

/* Programme announcement: centred festival identity and signup. */
.programme-announcement {
    --surface: var(--field);
    --plate-fg: var(--surface);
    --plate-line: var(--surface);
    background: var(--field);
    padding: var(--section-space) var(--gutter) clamp(4rem, 8vw, 8rem);
    text-align: center;
}
.programme-announcement__inner {
    max-width: var(--width-site);
    margin-inline: auto;
}
.programme-announcement__copy { min-width: 0; }
.programme-announcement__heading {
    margin: 0 0 2.5rem;
    font-family: var(--font-sign);
    font-size: 1.5rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
}
.programme-announcement__brand {
    display: grid;
    max-width: 35rem;
    margin-inline: auto;
    align-items: center;
}
.programme-announcement__brand img { grid-area: 1 / 1; display: block; width: 100%; height: auto; }
.programme-announcement__brand .programme-announcement__tile { width: calc(100% * 284.86 / 626.62); }
.programme-announcement__message {
    max-width: 36rem;
    margin: 2.5rem auto 2rem;
    font-size: clamp(1.25rem, 2vw, 1.625rem);
    line-height: 1.55;
}

/* The holding page meets its charcoal footer without a decorative band. */
body:has(.programme-announcement) { background: var(--ink); }
body:has(.programme-announcement) .site-footer::before { content: none; }

body > main:has(.programme-announcement) { background: var(--field); }
.programme-announcement { flex: 1; }

/* Section colours share the festival palette; reading surfaces stay paper. */
.section-about { --field: var(--purple-tint); }
.section-involvement { --field: var(--stone); }
.section-programme { --field: var(--blue-tint); }
.section-news { --field: var(--yellow-tint); }
