/* ==========================================================================
   Technical AI Governance Forum 2026 — convened by ERA
   Design system + components. No dependencies, no build step.
   ========================================================================== */

/* ---------- 1. Tokens ---------------------------------------------------- */

:root {
  /* Light palette (default). Dark overrides live in §1.1 */
  --paper:        #FBFAF8;
  --paper-2:      #F3F1EC;
  --surface:      #FFFFFF;
  --surface-2:    #F7F5F1;
  --ink:          #0D1117;
  --ink-2:        #48505F;
  --ink-3:        #6F7887;
  --line:         rgba(13, 17, 23, 0.13);
  --line-soft:    rgba(13, 17, 23, 0.07);

  --accent:       #C4342A;   /* ERA red */
  --accent-deep:  #9C2820;
  --accent-tint:  rgba(196, 52, 42, 0.10);
  /* The dark band is dark in BOTH themes, where brand red only reaches 3.6:1.
     This lift clears 5.2:1 while staying recognisably ERA red. */
  --accent-on-band: #E8503F;
  --accent-btn:     #C4342A;   /* filled buttons: label contrasts with the fill */
  --btn-primary-fg: #ffffff;
  --signal:       #B07A0B;   /* amber — deadlines, alerts */
  --signal-tint:  rgba(176, 122, 11, 0.12);
  --cool:         #2C4A6B;   /* slate blue — track tags */
  --cool-tint:    rgba(44, 74, 107, 0.10);

  /* The band: the full-bleed ground used by the hero, page heads, cta and
     footer. Its whole token set is swapped by [data-variant] — see §1.4. */
  --band:         #0B0E13;
  --band-ink:     #F2F1EE;
  --band-ink-2:   #9AA5B4;
  --band-line:    rgba(255, 255, 255, 0.14);
  --band-wash-1:  rgba(232, 80, 63, .22);
  --band-wash-2:  rgba(44, 74, 107, .26);
  --field-dim:    rgba(255, 255, 255, .085);  /* unverified mark */
  --field-lit:    rgba(255, 255, 255, .20);   /* verified mark */
  --notice-fg:    #E5B03A;
  --notice-bg:    rgba(224, 168, 40, .13);
  --notice-bd:    rgba(224, 168, 40, .42);

  --shadow-sm:    0 1px 2px rgba(13, 17, 23, .05), 0 2px 8px rgba(13, 17, 23, .04);
  --shadow-md:    0 2px 6px rgba(13, 17, 23, .06), 0 12px 32px rgba(13, 17, 23, .08);
  --shadow-lg:    0 4px 12px rgba(13, 17, 23, .07), 0 28px 64px rgba(13, 17, 23, .12);

  /* Type */
  --font-display: 'Instrument Serif', 'Iowan Old Style', Georgia, 'Times New Roman', serif;
  --font-sans:    'Instrument Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
  /* No mono. It was carrying 43 selectors, nearly all of them prose labels —
     speaker roles, breadcrumbs, kickers, footer headings — where it was texture
     rather than meaning, and it was the only face in the site the header and
     body never shared. The handful that were genuinely tabular keep their
     alignment through `font-variant-numeric` below instead of through a
     monospaced face. */

  /* Space scale */
  --s1: .25rem; --s2: .5rem;  --s3: .75rem; --s4: 1rem;   --s5: 1.5rem;
  --s6: 2rem;   --s7: 3rem;   --s8: 4rem;   --s9: 6rem;   --s10: 8rem;

  --radius:    4px;
  --radius-lg: 8px;
  --container: 1200px;
  --gutter:    clamp(1.25rem, 4vw, 3rem);

  --ease: cubic-bezier(.22, .61, .36, 1);
  --dur:  .45s;

  color-scheme: light;
}

/* 1.1 Dark — system preference (unless explicitly set to light) */

/* 1.2 Dark — explicit toggle (wins in both directions) */

/* 1.4 Design variants — a review tool. The switcher sets [data-variant] on
   <html>; each variant swaps ONLY the band token set (the full-bleed ground
   used by the hero, page heads, CTA strips and footer), so the page ground
   still follows the light/dark theme independently.

   The set is a 3x2 matrix: {dark, light} x {cool, neutral, warm}.
     dark   — Slate (cool) · Ink (neutral, the :root default) · Oxblood (warm)
     light  — Mist  (cool) · Bone (neutral)                   · Paper   (warm)

   Every combination clears 4.5:1 for band ink, muted ink and accent.
   Remove before launch once a direction is signed off — see README. */

/* Slate — dark ground */
:root[data-variant="slate"] {
  --band: #14212E;
  --band-ink: #EAF0F5;
  --band-ink-2: #9BB0C2;
  --band-line: rgba(255, 255, 255, .15);
  --accent-on-band: #FF6E5C;
  --band-wash-1: rgba(255, 110, 92, .15);
  --band-wash-2: rgba(28, 82, 134, .36);
  --field-dim: rgba(234, 240, 245, .09);
  --field-lit: rgba(234, 240, 245, .22);
  --notice-fg: #E8B84A;
  --notice-bg: rgba(232, 184, 74, .13);
  --notice-bd: rgba(232, 184, 74, .42);
}

/* Oxblood — dark ground */
:root[data-variant="oxblood"] {
  --band: #5E1712;
  --band-ink: #FBF3F1;
  --band-ink-2: #DDB6AE;
  --band-line: rgba(255, 255, 255, .17);
  --accent-on-band: #FFB0A2;
  --band-wash-1: rgba(255, 150, 130, .16);
  --band-wash-2: rgba(96, 18, 60, .36);
  --field-dim: rgba(255, 232, 228, .10);
  --field-lit: rgba(255, 232, 228, .26);
  --notice-fg: #F5C97A;
  --notice-bg: rgba(245, 201, 122, .14);
  --notice-bd: rgba(245, 201, 122, .40);
}

/* Bone — light ground — no dark surface in the light theme */
:root[data-variant="bone"] {
  --band: #EAE7E1;
  --band-ink: #171614;
  --band-ink-2: #5F5B55;
  --band-line: rgba(23, 22, 20, .16);
  --accent-on-band: #A8291F;
  --band-wash-1: rgba(196, 52, 42, .09);
  --band-wash-2: rgba(44, 74, 107, .07);
  --field-dim: rgba(23, 22, 20, .10);
  --field-lit: rgba(23, 22, 20, .26);
  --notice-fg: #7A5205;
  --notice-bg: rgba(176, 122, 11, .12);
  --notice-bd: rgba(176, 122, 11, .40);
}

/* Mist — light ground — no dark surface in the light theme */
:root[data-variant="mist"] {
  --band: #E3E8ED;
  --band-ink: #12191F;
  --band-ink-2: #515F69;
  --band-line: rgba(18, 25, 31, .16);
  --accent-on-band: #A8291F;
  --band-wash-1: rgba(196, 52, 42, .09);
  --band-wash-2: rgba(44, 74, 107, .12);
  --field-dim: rgba(18, 25, 31, .10);
  --field-lit: rgba(18, 25, 31, .26);
  --notice-fg: #7A5205;
  --notice-bg: rgba(176, 122, 11, .12);
  --notice-bd: rgba(176, 122, 11, .40);
}

/* Paper — light ground — no dark surface in the light theme */
:root[data-variant="paper"] {
  --band: #EDE5D7;
  --band-ink: #1B1714;
  --band-ink-2: #635850;
  --band-line: rgba(27, 23, 20, .16);
  --accent-on-band: #A8291F;
  --band-wash-1: rgba(196, 52, 42, .10);
  --band-wash-2: rgba(44, 74, 107, .09);
  --field-dim: rgba(27, 23, 20, .10);
  --field-lit: rgba(27, 23, 20, .26);
  --notice-fg: #8A5A05;
  --notice-bg: rgba(176, 122, 11, .12);
  --notice-bd: rgba(176, 122, 11, .40);
}

/* Art 2 — burgundy and navy, sampled from the two partner marks rather than
   chosen to resemble them: ERA's mark reads #890019 and AIGI's #001D45. The
   ground is cooled against Art's parchment so the burgundy stays burgundy
   and does not drift toward rust.

   The band is LIGHT with dark ink, as Art's is: the illustrated hero needs a
   pale ground for the watercolour to sit on, so these cannot use the dark-band
   structure the other six palettes share. */
:root[data-variant="art2"] {
  --paper:        #F6F2EE;
  --paper-2:      #EDE7E1;
  --surface:      #FCFAF8;
  --surface-2:    #F2ECE6;
  --ink:          #0E2340;
  --ink-2:        #2C3E58;
  --ink-3:        #44566E;
  --line:         rgba(14, 35, 64, .15);
  --line-soft:    rgba(14, 35, 64, .075);

  --accent:       #890019;
  --accent-deep:  #6B0014;
  --accent-tint:  rgba(137, 0, 25, .09);
  --accent-btn:   #890019;
  --btn-primary-fg: #ffffff;
  --signal:       #7A5518;
  --signal-tint:  rgba(122, 85, 24, .12);
  --cool:         #2C4A6B;
  --cool-tint:    rgba(44, 74, 107, .10);

  --accent-on-band: #6B0014;
  --band:         #FBF8F5;
  --band-ink:     #0E2340;
  --band-ink-2:   #2C3E58;
  --band-line:    rgba(14, 35, 64, .16);
  --band-wash-1:  rgba(137, 0, 25, .10);
  --band-wash-2:  rgba(44, 74, 107, .12);
  --field-dim:    rgba(14, 35, 64, .10);
  --field-lit:    rgba(14, 35, 64, .26);
  --notice-fg:    #7A5518;
  --notice-bg:    rgba(122, 85, 24, .12);
  --notice-bd:    rgba(122, 85, 24, .40);

  --shadow-sm:    0 1px 2px rgba(14, 35, 64, .05), 0 2px 8px rgba(14, 35, 64, .05);
  --shadow-md:    0 2px 6px rgba(14, 35, 64, .07), 0 12px 32px rgba(14, 35, 64, .09);
  --shadow-lg:    0 4px 12px rgba(14, 35, 64, .08), 0 28px 64px rgba(14, 35, 64, .13);

  color-scheme: light;
}

/* Art 3 — the warm reading of the same two colours. The ground carries some
   of the burgundy rather than staying neutral, so the page sits inside
   ERA's own hue instead of beside it.

   The band is LIGHT with dark ink, as Art's is: the illustrated hero needs a
   pale ground for the watercolour to sit on, so these cannot use the dark-band
   structure the other six palettes share. */
:root[data-variant="art3"] {
  --paper:        #FDFDFE;
  --paper-2:      #F2F4F6;
  --surface:      #FFFFFF;
  --surface-2:    #F9F9FA;
  --ink:          #001D45;
  --ink-2:        #425875;
  --ink-3:        #596C86;
  --line:         rgba(0, 29, 69, .14);
  --line-soft:    rgba(0, 29, 69, .07);

  --accent:       #890019;
  --accent-deep:  #6B0014;
  --accent-tint:  rgba(137, 0, 25, .09);
  --accent-btn:   #890019;
  --btn-primary-fg: #ffffff;
  /* Three colours means three. The signal tier, which was ochre, and the cool
     tier, which was its own slate, both fold into the two that carry meaning:
     red for anything that wants attention, navy for anything that does not. */
  --signal:       #890019;
  --signal-tint:  rgba(137, 0, 25, .09);
  --cool:         #001D45;
  --cool-tint:    rgba(0, 29, 69, .08);

  --accent-on-band: #890019;
  --band:         #FDFDFE;
  --band-ink:     #001D45;
  --band-ink-2:   #425875;
  --band-line:    rgba(0, 29, 69, .14);
  --band-wash-1:  rgba(137, 0, 25, .07);
  --band-wash-2:  rgba(0, 29, 69, .07);
  --field-dim:    rgba(0, 29, 69, .10);
  --field-lit:    rgba(0, 29, 69, .26);
  --notice-fg:    #890019;
  --notice-bg:    rgba(137, 0, 25, .08);
  --notice-bd:    rgba(137, 0, 25, .35);

  --shadow-sm:    0 1px 2px rgba(0, 29, 69, .05), 0 2px 8px rgba(0, 29, 69, .05);
  --shadow-md:    0 2px 6px rgba(0, 29, 69, .07), 0 12px 32px rgba(0, 29, 69, .09);
  --shadow-lg:    0 4px 12px rgba(0, 29, 69, .08), 0 28px 64px rgba(0, 29, 69, .13);

  color-scheme: light;
}

/* Art 4 — AIGI's navy leads and ERA's burgundy is the single accent. The
   coolest of the three: a blue-grey ground, burgundy used sparingly enough
   that it stays an accent rather than becoming the theme.

   The band is LIGHT with dark ink, as Art's is: the illustrated hero needs a
   pale ground for the watercolour to sit on, so these cannot use the dark-band
   structure the other six palettes share. */
:root[data-variant="art4"] {
  --paper:        #EEF1F5;
  --paper-2:      #E4E9F0;
  --surface:      #F9FBFD;
  --surface-2:    #EDF1F6;
  --ink:          #0A1B33;
  --ink-2:        #27384F;
  --ink-3:        #405066;
  --line:         rgba(10, 27, 51, .15);
  --line-soft:    rgba(10, 27, 51, .075);

  --accent:       #890019;
  --accent-deep:  #6B0014;
  --accent-tint:  rgba(137, 0, 25, .09);
  --accent-btn:   #890019;
  --btn-primary-fg: #ffffff;
  --signal:       #7A5518;
  --signal-tint:  rgba(122, 85, 24, .12);
  --cool:         #23456E;
  --cool-tint:    rgba(35, 69, 110, .10);

  --accent-on-band: #6B0014;
  --band:         #F5F8FB;
  --band-ink:     #0A1B33;
  --band-ink-2:   #27384F;
  --band-line:    rgba(10, 27, 51, .16);
  --band-wash-1:  rgba(137, 0, 25, .09);
  --band-wash-2:  rgba(35, 69, 110, .14);
  --field-dim:    rgba(10, 27, 51, .10);
  --field-lit:    rgba(10, 27, 51, .26);
  --notice-fg:    #7A5518;
  --notice-bg:    rgba(122, 85, 24, .12);
  --notice-bd:    rgba(122, 85, 24, .40);

  --shadow-sm:    0 1px 2px rgba(10, 27, 51, .05), 0 2px 8px rgba(10, 27, 51, .05);
  --shadow-md:    0 2px 6px rgba(10, 27, 51, .07), 0 12px 32px rgba(10, 27, 51, .09);
  --shadow-lg:    0 4px 12px rgba(10, 27, 51, .08), 0 28px 64px rgba(10, 27, 51, .13);

  color-scheme: light;
}

/* 1.8 Art 5 — oxblood and a sharper red. The other art variants centre ERA's
   mark colour #890019, which is deep enough to read as burgundy rather than as
   red. This keeps oxblood #5E1712 as the deep tone for ink and hover, and
   raises the accent to #C10026: same hue family, lightness .38 against .27, so
   it lands as red without going neon. Anything brighter runs out of contrast —
   the sharpest full-saturation red that still clears 4.5:1 on white is #EB001F
   at 4.61, and that reads pillar-box. */
:root[data-variant="art5"],
:root:not([data-variant]) {
  /* #FFFFFF, not the #FDFDFD near-white the other palettes use. Against the
     hero — which is flat white — a two-point-darker page ground drew a seam
     across the top of every page below it. */
  --paper:        #FFFFFF;
  /* White, like the ground it alternates with. .section--alt no longer paints a
     tone; sections are told apart by their own spacing and headings instead. */
  --paper-2:      #FFFFFF;
  --surface:      #FFFFFF;
  --surface-2:    #FBF9F9;
  --ink:          #3D0F0C;
  --ink-2:        #834C49;
  --ink-3:        #92615E;
  --line:         rgba(61, 15, 12, .14);
  --line-soft:    rgba(61, 15, 12, .07);

  --accent:       #C10026;
  --accent-deep:  #5E1712;
  --accent-tint:  rgba(193, 0, 38, .08);
  --accent-btn:   #C10026;
  --btn-primary-fg: #ffffff;
  --signal:       #C10026;
  --signal-tint:  rgba(193, 0, 38, .08);
  --cool:         #5E1712;
  --cool-tint:    rgba(94, 23, 18, .08);

  --accent-on-band: #C10026;
  --band:         #FFFFFF;
  --band-ink:     #3D0F0C;
  --band-ink-2:   #834C49;
  --band-line:    rgba(61, 15, 12, .14);
  --band-wash-1:  rgba(193, 0, 38, .07);
  --band-wash-2:  rgba(94, 23, 18, .07);
  --field-dim:    rgba(61, 15, 12, .10);
  --field-lit:    rgba(61, 15, 12, .26);
  --notice-fg:    #C10026;
  --notice-bg:    rgba(193, 0, 38, .08);
  --notice-bd:    rgba(193, 0, 38, .35);

  --shadow-sm:    0 1px 2px rgba(61, 15, 12, .05), 0 2px 8px rgba(61, 15, 12, .05);
  --shadow-md:    0 2px 6px rgba(61, 15, 12, .07), 0 12px 32px rgba(61, 15, 12, .09);
  --shadow-lg:    0 4px 12px rgba(61, 15, 12, .08), 0 28px 64px rgba(61, 15, 12, .13);

  color-scheme: light;
}


/* Art — the full palette from era-techgov.png. The only variant that moves the
   page ground and the accent as well as the band: warm parchment, deep navy
   ink, terracotta accent, ochre for signals. Colours were sampled from the
   mockup and then darkened along their own hue until every text pairing
   cleared 4.5:1 — illustration colours are not text colours.

   The two muted tiers were then darkened again, because 4.5:1 is a floor for
   legibility, not a target for comfort: ink-2 #42586E -> #293A4C (6.28 -> 9.93
   on paper) and ink-3 #5D6B7B -> #3E4E5E (4.65 -> 7.30). Both keep a navy cast
   rather than going grey, and both stay a readable step away from the near-black
   ink — 1.41 and 1.36 against it, so the hierarchy still reads. The old ink-2
   also FAILED over the darkest part of the hero plate at 3.78:1; it is now
   5.98:1 there. */
:root[data-variant="art"] {
  --paper:        #F4ECE0;
  --paper-2:      #EDE3D4;
  --surface:      #FBF7F0;
  --surface-2:    #F2E9DC;
  --ink:          #0B2038;
  --ink-2:        #293A4C;
  --ink-3:        #3E4E5E;
  --line:         rgba(11, 32, 56, .15);
  --line-soft:    rgba(11, 32, 56, .075);

  --accent:       #A45338;
  --accent-deep:  #85402A;
  --accent-tint:  rgba(164, 83, 56, .11);
  --accent-btn:   #A45338;
  --btn-primary-fg: #ffffff;
  --signal:       #7F5B26;
  --signal-tint:  rgba(127, 91, 38, .12);
  --cool:         #35536F;
  --cool-tint:    rgba(53, 83, 111, .10);

  --accent-on-band: #6E3018;
  --band:         #E9DECB;
  --band-ink:     #0B2038;
  --band-ink-2:   #293A4C;
  --band-line:    rgba(11, 32, 56, .16);
  --band-wash-1:  rgba(164, 83, 56, .12);
  --band-wash-2:  rgba(127, 91, 38, .10);
  --field-dim:    rgba(11, 32, 56, .10);
  --field-lit:    rgba(11, 32, 56, .26);
  --notice-fg:    #7F5B26;
  --notice-bg:    rgba(127, 91, 38, .12);
  --notice-bd:    rgba(127, 91, 38, .40);

  --shadow-sm:    0 1px 2px rgba(11, 32, 56, .05), 0 2px 8px rgba(11, 32, 56, .05);
  --shadow-md:    0 2px 6px rgba(11, 32, 56, .07), 0 12px 32px rgba(11, 32, 56, .09);
  --shadow-lg:    0 4px 12px rgba(11, 32, 56, .08), 0 28px 64px rgba(11, 32, 56, .13);

  color-scheme: light;
}

/* Every light-band variant, not just Paper. The footer shows the reversed
   near-white mark by default, which is right over Ink/Slate/Oxblood and
   invisible over a light band — 1.18:1 on Art's #E9DECB, 1.09:1 on Bone and
   Mist. Art is the shipped default, so this was the ERA logo disappearing from
   the footer of every page. The same switch drives the partner mark
   below: it is navy, so it shows exactly where the red ERA mark does. */
:root[data-variant="art"] .site-footer,
:root[data-variant="art5"] .site-footer,
:root[data-variant="art2"] .site-footer,
:root[data-variant="art3"] .site-footer,
:root[data-variant="art4"] .site-footer,
:root:not([data-variant]) .site-footer,
:root[data-variant="bone"] .site-footer,
:root[data-variant="mist"] .site-footer,
:root[data-variant="paper"] .site-footer { --era-light: block; --era-dark: none; }

.site-footer .era-mark--light { display: var(--era-light, none); }
.site-footer .era-mark--dark { display: var(--era-dark, block); }

/* The AIGI mark is navy on transparent, so it reads wherever the red ERA mark
   does and nowhere else. On a dark band the wordmark stands in — recolouring
   another organisation's logo is not ours to do without their sign-off. */
.site-footer .partner-mark { display: var(--era-light, none); }
.site-footer .partner-wordmark { display: var(--era-dark, block); }
/* The height has to sit on the img, not the anchor: the anchor is an
   inline-flex box and an unconstrained 400x261 image inside it renders at its
   natural width, which is what made the mark tower over ERA's. 2.35rem against
   ERA's 2.6rem because this is a lockup — roundel over two lines of caps —
   and matching the heights exactly would make the wider, denser artwork read
   as the larger of the two. */
.footer-org .partner-mark { display: inline-flex; }
.footer-org .partner-mark .mark { height: 2.35rem; }
/* Same correction, scaled: ERA's mass sits 5.01px low in the footer's box. */
.footer-org .era-mark { transform: translateY(-.31rem); }

/* 1.3 Dark grounds — dark in both themes, so the accent lifts inside them.
   Filled buttons and brand marks opt back out via --accent-btn, since their
   label contrasts with the fill rather than with the band behind it. */
.hero,
.page-head,
.section--band,
.cta-band,
.site-footer {
  --accent:      var(--accent-on-band);
  --accent-tint: rgba(232, 80, 63, 0.15);
}

/* ---------- 2. Reset & base --------------------------------------------- */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: 6rem;
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
}

body {
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: 1rem;
  line-height: 1.65;
  font-feature-settings: 'kern' 1, 'liga' 1;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}

img, svg, video { display: block; max-width: 100%; height: auto; }
button, input, select, textarea { font: inherit; color: inherit; }

a { color: inherit; text-decoration: none; }

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 2px;
}

::selection { background: var(--accent); color: #fff; }

.skip-link {
  position: absolute; left: var(--s4); top: -100%;
  z-index: 200;
  background: var(--accent); color: #fff;
  padding: var(--s3) var(--s5);
  border-radius: var(--radius);
  font-weight: 600; font-size: .9rem;
  transition: top .2s var(--ease);
}
.skip-link:focus { top: var(--s4); }

/* ---------- 3. Typography ------------------------------------------------ */

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 400;
  line-height: 1.08;
  letter-spacing: -0.015em;
  text-wrap: balance;
}

.display-xl { font-size: clamp(2.85rem, 7.4vw, 6rem); line-height: 1.02; letter-spacing: -0.025em; }
.display-lg { font-size: clamp(2.35rem, 5.2vw, 4rem); line-height: 1.06; letter-spacing: -0.02em; }
.display-md { font-size: clamp(1.85rem, 3.4vw, 2.75rem); }
.display-sm { font-size: clamp(1.35rem, 2.2vw, 1.75rem); line-height: 1.2; }

.lede {
  font-size: clamp(1.05rem, 1.55vw, 1.3rem);
  line-height: 1.62;
  color: var(--ink-2);
  max-width: 62ch;
  text-wrap: pretty;
}

p { text-wrap: pretty; }
p + p { margin-top: var(--s4); }

.kicker {
  display: inline-flex; align-items: center; gap: var(--s3);
  font-family: var(--font-sans);
  font-size: .74rem;
  font-weight: 500;
  letter-spacing: .02em;
  color: var(--accent);
}
.kicker::before {
  content: ''; width: 1.75rem; height: 1px;
  background: currentColor; opacity: .6; flex: none;
}
.kicker--plain::before { display: none; }
.kicker--muted { color: var(--ink-3); }
.kicker--band { color: var(--accent); }

/* A subdivision inside a section: the display face one step down from the
   section's own h2, under the short accent rule the fact cells and the plaque
   already use. It marks where one kind of content ends and another begins
   without competing with the heading above it. */
.subhead {
  margin: clamp(2.5rem, 5vw, 4rem) 0 var(--s5);
  color: var(--ink);
}
.subhead::before {
  content: ''; display: block;
  width: 2.5rem; height: 2px;
  background: var(--accent);
  margin-bottom: var(--s3);
}
/* The first one follows .section-head, which already carries the gap. */
.section-head + .subhead { margin-top: 0; }
/* And the block a subhead announces does not add its own lead-in on top. */
.subhead + .showcase--wide { margin-top: 0; }

/* An intro that takes the row rather than a column of it. .lede caps at 62ch
   because it is normally set beside something; on its own row under the
   heading it is the row. */
.lede--row { max-width: none; }

/* Viewfinder corners. Four L brackets and no connecting border, set outside
   the content rather than padded in from it, so the heading keeps its left edge
   with the cards it brackets.

   Drawn as borders on four boxes with only two sides each: two from the block's
   own ::before / ::after, two from the .frame-corners span, which exists
   because one element only has two pseudo-elements.

   Wider than tall, and 2px rather than 1: a small square bracket at a hairline
   read as a stray rule at the size of the block it marks. The horizontal arm
   carries the gesture, the vertical one anchors it — which is how a viewfinder
   mark is drawn. */
.framed { position: relative; }
.frame-corners { position: absolute; inset: 0; pointer-events: none; }
.framed::before,
.framed::after,
.framed .frame-corners::before,
.framed .frame-corners::after {
  content: '';
  position: absolute;
  /* Roughly double again. At 1425px the horizontal arm is 128px against a
     1104px block, so the four of them cover under a quarter of each edge —
     still nowhere near meeting, which is the line to stay on: the moment the
     eye joins them it stops being a viewfinder and becomes a box. */
  width: clamp(4rem, 9vw, 8.5rem);
  height: clamp(2.5rem, 4.5vw, 4.5rem);
  border: 0 solid var(--accent);
  pointer-events: none;
}
/* The inset is negative so the brackets sit off the block's corners.
   1.25rem at the widest, which stays inside the container's own gutter. */
.framed::before {
  top: calc(-1 * clamp(.75rem, 1.4vw, 1.25rem));
  left: calc(-1 * clamp(.75rem, 1.4vw, 1.25rem));
  border-top-width: 2px; border-left-width: 2px;
  transform-origin: top left;
}
.framed .frame-corners::before {
  top: calc(-1 * clamp(.75rem, 1.4vw, 1.25rem));
  right: calc(-1 * clamp(.75rem, 1.4vw, 1.25rem));
  border-top-width: 2px; border-right-width: 2px;
  transform-origin: top right;
}
.framed .frame-corners::after {
  bottom: calc(-1 * clamp(.75rem, 1.4vw, 1.25rem));
  left: calc(-1 * clamp(.75rem, 1.4vw, 1.25rem));
  border-bottom-width: 2px; border-left-width: 2px;
  transform-origin: bottom left;
}
.framed::after {
  bottom: calc(-1 * clamp(.75rem, 1.4vw, 1.25rem));
  right: calc(-1 * clamp(.75rem, 1.4vw, 1.25rem));
  border-bottom-width: 2px; border-right-width: 2px;
  transform-origin: bottom right;
}

/* The brackets draw themselves when the block scrolls in, each opening out
   from its own corner, clockwise from the top left. That is what makes them
   read as a mark being placed rather than a border that was always there, and
   it is the only motion in the section.

   They are painted by default and the animation only runs once .is-visible
   lands, so with the script off or the observer unsupported they are simply
   there. site.js observes .framed alongside .reveal; .framed sets no opacity
   or transform of its own, so nothing but the corners moves. */
@keyframes frame-draw {
  from { transform: scale(.15); opacity: 0; }
  60%  { opacity: 1; }
  to   { transform: scale(1); opacity: 1; }
}
.framed.is-visible::before                { animation: frame-draw .55s var(--ease) both; }
.framed.is-visible .frame-corners::before { animation: frame-draw .55s var(--ease) .09s both; }
.framed.is-visible::after                 { animation: frame-draw .55s var(--ease) .18s both; }
.framed.is-visible .frame-corners::after  { animation: frame-draw .55s var(--ease) .27s both; }
@media (prefers-reduced-motion: reduce) {
  .framed.is-visible::before,
  .framed.is-visible::after,
  .framed.is-visible .frame-corners::before,
  .framed.is-visible .frame-corners::after { animation: none; }
}

/* The join between the hero and the section under it was 216px of white: 96
   from the hero's own bottom padding and 120 from the section's top. Both are
   sized for a band-to-band transition, but here the hero ends on the same white
   as the section begins on, so there is no edge for the space to sit against —
   it just reads as a hole. 56 + 72 keeps the two apart without the gap becoming
   the loudest thing between the plaque and the heading. Scoped to the join, so
   every other section keeps the site's rhythm. */
:root[data-variant="art5"] .hero-inner,
:root:not([data-variant]) .hero-inner { padding-bottom: clamp(2.5rem, 4vw, 3.5rem); }
:root[data-variant="art5"] .hero + .section,
:root:not([data-variant]) .hero + .section { padding-top: clamp(2.5rem, 5vw, 4.5rem); }

/* And the same at every section-to-section join, for the same reason. The
   .section--alt band used to paint a tone that the 120 + 120 of padding sat
   against; with --paper-2 white it paints nothing, so two plain sections meet
   in 240px of undifferentiated white. Halving the upper half leaves 192, which
   still reads as a break.

   .section--band is excluded: it still has a ground of its own, so its edge
   does the separating and the padding is holding the content off that edge
   rather than standing in for it. */
:root[data-variant="art5"] .section + .section:not(.section--band),
:root:not([data-variant]) .section + .section:not(.section--band),
/* The first section on an interior page has the same join: the page head ends
   on white and the section begins on white, so its 72px of bottom padding plus
   120 of section padding was another 192px hole — the one above "Our mission"
   on the About page. */
:root[data-variant="art5"] .page-head + .section:not(.section--band),
:root:not([data-variant]) .page-head + .section:not(.section--band) {
  padding-top: clamp(3rem, 6vw, 4.5rem);
}
/* And the head's own foot, for the same reason: it ends on white. */
:root[data-variant="art5"] .page-head,
:root:not([data-variant]) .page-head {
  padding-bottom: clamp(2rem, 4vw, 3rem);
}

.mono {
  font-family: var(--font-sans);
  font-size: .78rem;
  letter-spacing: .02em;
  font-variant-numeric: tabular-nums;
}

.muted { color: var(--ink-2); }
.text-accent { color: var(--accent); }

/* Text link with animated rule */
/* References inside running prose. Underlined in the accent rather than
   recoloured, so a paragraph carrying four of them still reads as a paragraph
   and the text keeps the body colour it was contrast-checked at. */
.link-inline {
  color: inherit;
  text-decoration: underline;
  text-decoration-color: color-mix(in srgb, var(--accent) 55%, transparent);
  text-decoration-thickness: 1px;
  text-underline-offset: .18em;
  transition: text-decoration-color .2s, color .2s;
}
h2 .link-inline,
h3 .link-inline {
  text-decoration-thickness: 2px;
  text-underline-offset: .12em;
}
.link-inline:hover,
.link-inline:focus-visible {
  color: var(--accent);
  text-decoration-color: var(--accent);
  text-decoration-thickness: 2px;
}

.link {
  display: inline-flex; align-items: center; gap: .45rem;
  font-weight: 550; font-size: .935rem;
  color: var(--ink);
  padding-bottom: 2px;
  background-image: linear-gradient(var(--accent), var(--accent));
  background-size: 100% 1px;
  background-position: 0 100%;
  background-repeat: no-repeat;
  transition: background-size .35s var(--ease), color .2s;
}
.link:hover { color: var(--accent); background-size: 0% 1px; background-position: 100% 100%; }
.link .arrow { transition: transform .35s var(--ease); }
.link:hover .arrow { transform: translateX(4px); }

/* ---------- 4. Layout ---------------------------------------------------- */

.container {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--gutter);
}
.container--narrow { max-width: 860px; }

.section { padding-block: clamp(4rem, 9vw, 7.5rem); }
.section--tight { padding-block: clamp(3rem, 6vw, 5rem); }
.section--band { background: var(--band); color: var(--band-ink); }
.section--band .lede,
.section--band .muted { color: var(--band-ink-2); }
.section--alt { background: var(--paper-2); }

.section-head {
  display: grid;
  gap: var(--s5);
  margin-bottom: clamp(2.5rem, 5vw, 4rem);
}
@media (min-width: 900px) {
  .section-head--split {
    grid-template-columns: minmax(0, 1.1fr) minmax(0, .9fr);
    align-items: end;
    gap: var(--s7);
  }
}
/* The eyebrow labels above these headings are gone, so the margin that seated
   the h2 under them is a gap. Kept only where a lede sits above instead. */
.section-head h2 { margin-top: 0; }

.grid { display: grid; gap: var(--s5); }
.grid-2 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 320px), 1fr)); }
.grid-3 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 285px), 1fr)); }
.grid-4 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 220px), 1fr)); }

.stack { display: grid; gap: var(--s4); }
.stack-lg { display: grid; gap: var(--s6); }
.cluster { display: flex; flex-wrap: wrap; gap: var(--s3); align-items: center; }

.rule { height: 1px; background: var(--line); border: 0; }

/* ---------- 5. Buttons --------------------------------------------------- */

.btn {
  --btn-bg: var(--ink);
  --btn-fg: var(--paper);
  --btn-bd: var(--ink);
  position: relative;
  display: inline-flex; align-items: center; justify-content: center; gap: .55rem;
  padding: .82rem 1.45rem;
  background: var(--btn-bg);
  color: var(--btn-fg);
  border: 1px solid var(--btn-bd);
  border-radius: var(--radius);
  font-size: .915rem; font-weight: 600; letter-spacing: -0.005em;
  cursor: pointer;
  white-space: nowrap;
  transition: transform .2s var(--ease), box-shadow .25s var(--ease), background-color .2s, color .2s, border-color .2s;
}
.btn:hover { transform: translateY(-2px); box-shadow: var(--shadow-md); }
.btn:active { transform: translateY(0); }

.btn--primary {
  --btn-bg: var(--accent-btn);
  --btn-fg: var(--btn-primary-fg);
  --btn-bd: var(--accent-btn);
}
.btn--primary:hover { --btn-bg: var(--accent-deep); --btn-bd: var(--accent-deep); }

.btn--ghost { --btn-bg: transparent; --btn-fg: var(--ink); --btn-bd: var(--line); }
.btn--ghost:hover { --btn-bd: var(--ink); }

.btn--on-band { --btn-bg: transparent; --btn-fg: var(--band-ink); --btn-bd: var(--band-line); }
.btn--on-band:hover { --btn-bg: var(--band-ink); --btn-fg: var(--band); --btn-bd: var(--band-ink); }

.btn--lg { padding: 1rem 1.9rem; font-size: .98rem; }
.btn--sm { padding: .55rem 1rem; font-size: .84rem; }
.btn[disabled] { opacity: .5; pointer-events: none; }

/* ---------- 6. Header ---------------------------------------------------- */

.site-header {
  position: sticky; top: 0; z-index: 100;
  background: color-mix(in srgb, var(--paper) 82%, transparent);
  backdrop-filter: saturate(180%) blur(14px);
  -webkit-backdrop-filter: saturate(180%) blur(14px);
  border-bottom: 1px solid transparent;
  transition: border-color .3s, background-color .3s, box-shadow .3s;
}
.site-header.is-stuck {
  border-bottom-color: var(--line);
  box-shadow: 0 1px 20px rgba(13,17,23,.05);
}

.header-inner {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s5);
  height: 4.75rem;
  transition: height .3s var(--ease);
}
.site-header.is-stuck .header-inner { height: 4rem; }

/* Brand lockup — ERA's mark, a hairline, then the forum wordmark. */
.brand { display: flex; align-items: center; gap: .85rem; flex: none; }
.brand::after {
  content: ''; align-self: stretch; width: 1px; flex: none;
  background: var(--line);
  margin-block: .1rem;
  order: 1;
}
.brand-text { display: grid; line-height: 1.15; order: 2; }

/* ERA mark. Two files: the red original for light grounds, a reversed
   near-white variant for dark ones. Both carry alt text, because whichever is
   display:none is skipped by assistive tech entirely. */
.era-mark { flex: none; order: 0; width: auto; display: block; }
.era-mark--dark { display: none; }

.site-header .era-mark { height: 2.1rem; }

/* The partner mark sits beside ERA's, inside the brand link and before its
   hairline, so the header reads as the co-brand it is. It is an <img> rather
   than its own anchor because anchors cannot nest — aigi.ox.ac.uk is linked
   from the footer and the partners page. alt="" because the brand link already
   carries an aria-label naming both organisations.
   1.9rem against ERA's 2.1rem, the same 0.9 ratio used in the footer: this is a
   lockup, and equal heights would make it read as the larger mark. */
/* The marks are aligned by their SOLID MASS, not their boxes. ERA's mark sits
   4.04px low in its own box — its upper third is the faint comet tail, empty
   space — so box-centring makes everything beside it look high, and chasing it
   downward pushed the AIGI mark away from the wordmark it sits next to. AIGI's
   mass is already centred (+0.29px), so it stays put and ERA comes up instead.
   All three then share a centre: ERA's mass, AIGI's mass and the text. */
.site-header .era-mark { transform: translateY(-.25rem); }
.site-header .header-partner {
  height: 1.9rem; width: auto; order: 0; flex: none;
}
.site-header.is-stuck .header-partner { height: 1.72rem; transition: height .3s var(--ease); }

/* Navy on transparent, so it goes where the red ERA mark goes and nowhere else.
   No reversed variant exists on purpose. */

.site-header.is-stuck .era-mark { height: 1.9rem; transition: height .3s var(--ease); }

/* The footer ground is dark in both themes, so it only needs the reversed file. */
.site-footer .era-mark { height: 2.2rem; }
.site-footer .brand::after { background: var(--band-line); }
.brand-name {
  font-family: var(--font-display);
  font-size: 1.12rem;
  letter-spacing: -.01em;
}
.brand-sub {
  font-family: var(--font-sans);
  font-size: .70rem; letter-spacing: .02em;
  color: var(--ink-3);
}

/* Nav */
.nav { display: flex; align-items: center; gap: var(--s2); }
.nav a {
  padding: .5rem .75rem;
  font-size: .905rem; font-weight: 500;
  color: var(--ink-2);
  border-radius: var(--radius);
  transition: color .2s, background-color .2s;
}
.nav a:hover { color: var(--ink); background: var(--line-soft); }
.nav a[aria-current="page"] { color: var(--ink); font-weight: 600; }
.nav a[aria-current="page"]::after {
  content: ''; display: block; height: 2px; margin-top: 2px;
  background: var(--accent); border-radius: 2px;
}

.header-actions { display: flex; align-items: center; gap: var(--s3); }

/* Theme toggle */
.theme-toggle {
  width: 2.3rem; height: 2.3rem;
  display: grid; place-items: center;
  background: transparent; border: 1px solid var(--line);
  border-radius: var(--radius); cursor: pointer;
  color: var(--ink-2);
  transition: color .2s, border-color .2s, transform .2s;
}
.theme-toggle:hover { color: var(--ink); border-color: var(--ink); transform: rotate(-12deg); }
.theme-toggle .icon-sun { display: none; }

/* Mobile menu button */
.nav-toggle {
  display: none;
  width: 2.3rem; height: 2.3rem;
  place-items: center;
  background: transparent; border: 1px solid var(--line);
  border-radius: var(--radius); cursor: pointer;
}
.nav-toggle .bar {
  display: block; width: 15px; height: 1.5px; background: var(--ink);
  transition: transform .3s var(--ease), opacity .2s;
}
.nav-toggle .bar + .bar { margin-top: 4px; }
.nav-toggle[aria-expanded="true"] .bar:nth-child(1) { transform: translateY(5.5px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] .bar:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded="true"] .bar:nth-child(3) { transform: translateY(-5.5px) rotate(-45deg); }

/* Scroll progress */
.scroll-progress {
  position: absolute; left: 0; bottom: -1px; height: 2px;
  width: 0%;
  background: var(--accent);
  transition: width .1s linear;
}

@media (max-width: 560px) {
  /* Measured: ERA 33px + partner 47px + two 13.6px gaps + hairline + wordmark
     ~200px + menu button ~40px overruns a 360px viewport's 320px of content. */
  .site-header .header-partner { display: none; }
}

@media (max-width: 940px) {
  .nav-toggle { display: grid; }
  .nav {
    position: fixed; inset: 4.75rem 0 auto 0;
    flex-direction: column; align-items: stretch;
    gap: 0;
    background: var(--paper);
    border-bottom: 1px solid var(--line);
    padding: var(--s4) var(--gutter) var(--s6);
    box-shadow: var(--shadow-lg);
    transform: translateY(-6px);
    opacity: 0; pointer-events: none;
    transition: opacity .25s var(--ease), transform .25s var(--ease);
    max-height: calc(100dvh - 4.75rem);
    overflow-y: auto;
  }
  .nav.is-open { opacity: 1; transform: none; pointer-events: auto; }
  .nav a { padding: .85rem .25rem; font-size: 1.05rem; border-bottom: 1px solid var(--line-soft); border-radius: 0; }
  .nav a[aria-current="page"]::after { display: none; }
  .nav .btn { margin-top: var(--s4); }
}


/* ---------- Art 5: an oxblood header ------------------------------------
   The header is the one place this palette puts its deep tone to work rather
   than keeping it for hover. That flips everything inside it: the nav and the
   wordmark go light, and the ERA mark switches to the reversed file, exactly
   as the footer already does on a dark ground.

   The AIGI mark cannot switch — it is navy on transparent and there is no
   reversed version, and recolouring another organisation's logo is not ours to
   do without their sign-off. So it steps aside for their wordmark, which is
   the same choice the footer makes. */
:root[data-variant="art5"] .site-header,
:root:not([data-variant]) .site-header {
  background: #5E1712;
  border-bottom-color: rgba(255, 255, 255, .14);
}
:root[data-variant="art5"] .site-header.is-stuck,
:root:not([data-variant]) .site-header.is-stuck {
  border-bottom-color: rgba(255, 255, 255, .2);
  box-shadow: 0 1px 20px rgba(61, 15, 12, .25);
}
:root[data-variant="art5"] .site-header .brand-name,
:root:not([data-variant]) .site-header .brand-name { color: #FBF6F5; }
:root[data-variant="art5"] .site-header .brand::after,
:root:not([data-variant]) .site-header .brand::after { background: rgba(255, 255, 255, .22); }
:root[data-variant="art5"] .site-header .nav a,
:root:not([data-variant]) .site-header .nav a { color: #EBD9D6; }
:root[data-variant="art5"] .site-header .nav a:hover,
:root:not([data-variant]) .site-header .nav a:hover {
  color: #FFFFFF;
  background: rgba(255, 255, 255, .10);
}
:root[data-variant="art5"] .site-header .nav a[aria-current="page"],
:root:not([data-variant]) .site-header .nav a[aria-current="page"] { color: #FFFFFF; }
:root[data-variant="art5"] .site-header .nav a[aria-current="page"]::after,
:root:not([data-variant]) .site-header .nav a[aria-current="page"]::after { background: #FFFFFF; }
:root[data-variant="art5"] .site-header .btn--ghost,
:root:not([data-variant]) .site-header .btn--ghost {
  --btn-fg: #FFFFFF;
  --btn-bd: rgba(255, 255, 255, .38);
}
:root[data-variant="art5"] .site-header .btn--ghost:hover,
:root:not([data-variant]) .site-header .btn--ghost:hover {
  --btn-bg: #FFFFFF;
  --btn-fg: #5E1712;
  --btn-bd: #FFFFFF;
}
:root[data-variant="art5"] .site-header .nav-toggle .bar,
:root:not([data-variant]) .site-header .nav-toggle .bar { background: #FFFFFF; }
:root[data-variant="art5"] .site-header .nav-toggle,
:root:not([data-variant]) .site-header .nav-toggle { border-color: rgba(255, 255, 255, .38); }
/* the marks, swapped for the dark ground */
:root[data-variant="art5"] .site-header .era-mark--light,
:root:not([data-variant]) .site-header .era-mark--light { display: none; }
:root[data-variant="art5"] .site-header .era-mark--dark,
:root:not([data-variant]) .site-header .era-mark--dark { display: block; }
:root[data-variant="art5"] .site-header .header-partner,
:root:not([data-variant]) .site-header .header-partner { display: none; }
:root[data-variant="art5"] .site-header .header-partner-wordmark,
:root:not([data-variant]) .site-header .header-partner-wordmark { display: block; }

/* Hidden by default; only the oxblood header calls on it. */
.header-partner-wordmark {
  display: none;
  order: 0; flex: none;
  font-family: var(--font-display);
  font-weight: 400; font-size: .74rem; line-height: 1.22;
  /* Two lines, not four: at 9ch this broke after every word and pushed the
     header taller than the 4.75rem the layout allows for it. */
  max-width: 17ch;
  color: #EBD9D6;
}
@media (max-width: 860px) {
  .header-partner-wordmark { display: none !important; }
}
/* The mobile menu drops out of the header, so it keeps the page's own ground. */
@media (max-width: 940px) {
  :root[data-variant="art5"] .site-header .nav,
  :root:not([data-variant]) .site-header .nav { background: #5E1712; }
}

/* ---------- 7. Hero ------------------------------------------------------ */

.hero {
  position: relative;
  background: var(--band);
  color: var(--band-ink);
  overflow: hidden;
  isolation: isolate;
}
.hero::after {
  /* One soft wash only — the attestation field behind it does the work now. */
  content: '';
  position: absolute; inset: 0; z-index: -1;
  background:
    radial-gradient(52rem 34rem at 4% 96%, var(--band-wash-1), transparent 60%),
    radial-gradient(44rem 30rem at 96% 2%, var(--band-wash-2), transparent 58%);
}
.hero-canvas {
  position: absolute; inset: 0; z-index: -1;
  width: 100%; height: 100%;
}
.hero-inner {
  position: relative;
  padding-block: clamp(5rem, 12vw, 10rem) clamp(3.5rem, 7vw, 6rem);
}

/* --- Load sequence. Masked rise, not a fade: the clauses arrive as blocks. --- */
.hero-mask {
  display: block;
  overflow: hidden;
  /* line-height is .98, so ascenders and descenders sit outside the line box.
     Pad the mask and pull the space back so nothing clips. */
  padding-block: .06em .18em;
  margin-block: -.06em -.18em;
}
.hero-mask > span { display: block; }

@keyframes hero-rise { from { transform: translateY(130%); } to { transform: none; } }
@keyframes hero-fade { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }
@keyframes hero-draw { from { transform: scaleX(0); } to { transform: scaleX(1); } }

.hero-mask > span,
.hero-fade { animation-duration: .82s; animation-timing-function: var(--ease); animation-fill-mode: both; }
.hero-mask > span { animation-name: hero-rise; }
.hero-fade { animation-name: hero-fade; }

.hero-h1 .hero-mask:first-of-type > span { animation-delay: .14s; }
.hero-h1 .hero-mask:last-of-type > span { animation-delay: .30s; }
.hero-lede { animation-delay: .58s; }
.hero-cta { animation-delay: .70s; }
.hero-facts { animation-delay: .82s; }

.hero-h1 {
  font-size: clamp(2.25rem, 8vw, 6.5rem);
  line-height: .98;
  letter-spacing: -.032em;
  margin-block: clamp(1.5rem, 3vw, 2.5rem) 0;
  max-width: 15em;
}
.hero-h1 em { font-style: normal; color: var(--accent); }

.hero-rule {
  display: block;
  height: 1px;
  margin-block: clamp(.7rem, 1.5vw, 1.35rem);
  transform-origin: left;
  animation: hero-draw .9s var(--ease) .40s both;
  background: linear-gradient(90deg,
    var(--accent) 0 clamp(3rem, 8vw, 7rem),
    var(--band-line) clamp(3rem, 8vw, 7rem));
}

.hero .lede { color: var(--band-ink-2); max-width: 56ch; margin-top: clamp(1.5rem, 3vw, 2.25rem); }
.hero-cta { margin-top: clamp(2rem, 4vw, 3rem); gap: var(--s4); }

@media (prefers-reduced-motion: reduce) {
  .hero-mask > span, .hero-fade, .hero-rule { animation: none; }
  .hero-rule { transform: none; }
}

/* Fact strip under hero */
/* The hero panel is a plaque, not a rule. It has to hold its own over a flat
   band AND over the Art variant's illustration, so it lays down a near-opaque
   wash of the band colour (flattening whatever is behind it) plus a slight ink
   tint (separating it from the band around it), with a blur for the remainder.
   It carries two rows: the featured speakers, then the fact strip. */
/* The plaque is two boxes, not one: speakers on top, facts beneath. They were a
   single element until the facts had to be able to leave the stack entirely in
   the Art variant. Butted together with a shared hairline, they read as one. */
.hero-panel {
  margin-top: clamp(2.5rem, 5vw, 4rem);
  position: relative;
  isolation: isolate;
  border: 1px solid var(--band-line);
  border-bottom: 0;
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  overflow: hidden;
  background:
    linear-gradient(color-mix(in srgb, var(--band-ink) 7%, transparent),
                    color-mix(in srgb, var(--band-ink) 7%, transparent)),
    color-mix(in srgb, var(--band) 82%, transparent);
  -webkit-backdrop-filter: blur(12px) saturate(150%);
  backdrop-filter: blur(12px) saturate(150%);
  box-shadow: 0 1px 2px color-mix(in srgb, var(--band-ink) 6%, transparent),
              0 12px 32px color-mix(in srgb, var(--band-ink) 9%, transparent);
}
/* Accent tick on the plaque's top edge. */
.hero-panel::before {
  content: ''; position: absolute; left: 0; top: 0; z-index: 1;
  width: clamp(3.5rem, 9vw, 8rem); height: 2px; background: var(--accent);
}

/* --- Featured speakers row --- */
.hero-speakers {
  padding: var(--s5) var(--s5) var(--s5);
  display: grid;
  gap: var(--s4);
}
.hero-speakers-head {
  display: flex; flex-wrap: wrap; align-items: baseline;
  justify-content: space-between; gap: var(--s3);
}
.hero-speakers-head .link { color: var(--band-ink); font-size: .84rem; }
.hero-speaker-list {
  list-style: none; padding: 0; margin: 0;
  display: grid; gap: var(--s4);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 190px), 1fr));
}
.hero-speaker { display: flex; align-items: center; gap: var(--s3); min-width: 0; }
.hero-speaker-avatar {
  width: 2.9rem; height: 2.9rem; flex: none;
  border-radius: 50%;
  display: grid; place-items: center;
  overflow: hidden;
  border: 1px solid var(--band-line);
  background: color-mix(in srgb, var(--band-ink) 8%, transparent);
  font-family: var(--font-sans);
  font-size: .58rem; letter-spacing: .08em;
  color: var(--band-ink-2);
}

.hero-speaker-text { display: grid; gap: 1px; min-width: 0; }
.hero-speaker-name {
  font-family: var(--font-display);
  /* Scales below 1000px too, where the cards are still portrait-beside-name but
     half the width. 1.35rem is the ceiling that keeps the longest affiliation,
     "Panellist &middot; European AI Office", out of its ellipsis at 360px. */
  font-size: clamp(1.15rem, 3vw, 1.35rem); line-height: 1.2; color: var(--band-ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.hero-speaker-role {
  font-family: var(--font-sans);
  font-size: .70rem; font-weight: 600; letter-spacing: .02em;
  line-height: 1.32;
  color: var(--band-ink-2);
  /* Wraps rather than truncating. On one line it clipped from about 500px to
     900px — "Panellist &middot; European AI Office" needs ~175px and the cell
     leaves ~172px once the portrait and the gap are taken out, so it read as
     "European AI Offi…". The name above it keeps the ellipsis: names are short
     and a wrapped one would break the row's baseline. */
}
.hero-speaker--tba .hero-speaker-name { font-style: italic; color: var(--band-ink-2); }
.hero-speaker-avatar--tba {
  border-style: dashed;
  font-size: 1.5rem;
  line-height: 1;
  color: var(--accent);
}

/* --- Fact strip --- */
.hero-facts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 210px), 1fr));
  isolation: isolate;
  overflow: hidden;                     /* clips the trailing cell divider */
  border: 1px solid var(--band-line);
  border-radius: 0 0 var(--radius-lg) var(--radius-lg);
  background:
    linear-gradient(color-mix(in srgb, var(--band-ink) 7%, transparent),
                    color-mix(in srgb, var(--band-ink) 7%, transparent)),
    color-mix(in srgb, var(--band) 82%, transparent);
  -webkit-backdrop-filter: blur(12px) saturate(150%);
  backdrop-filter: blur(12px) saturate(150%);
  box-shadow: 0 12px 32px color-mix(in srgb, var(--band-ink) 9%, transparent);
}
.hero-fact {
  padding: var(--s5);
  /* A shadow rather than a border, so wrapped rows never double up and the
     trailing edge is clipped by the plaque's own overflow. */
  box-shadow: 1px 0 0 var(--band-line);
}
.hero-fact dt {
  font-family: var(--font-sans);
  font-size: .72rem; letter-spacing: .02em;
  color: var(--band-ink-2);
  margin-bottom: var(--s2);
}
.hero-fact dd {
  font-family: var(--font-display);
  font-size: 1.4rem; line-height: 1.22;
  color: var(--band-ink);
}
.hero-fact dd small { display: block; font-family: var(--font-sans); font-size: .8rem; color: var(--band-ink-2); margin-top: 3px; }
@media (max-width: 640px) {
  .hero-fact { box-shadow: 0 1px 0 var(--band-line); }
  .hero-speakers { padding: var(--s4); }
  .hero-speaker-list { gap: var(--s3); }
}

/* Page header (interior pages) */
.page-head {
  background: var(--band); color: var(--band-ink);
  padding-block: clamp(3.5rem, 8vw, 6rem) clamp(3rem, 6vw, 4.5rem);
  position: relative; overflow: hidden; isolation: isolate;
}
.page-head::after {
  content: ''; position: absolute; inset: 0; z-index: -1;
  background: radial-gradient(50rem 30rem at 12% 100%, var(--band-wash-1), transparent 62%),
              radial-gradient(40rem 26rem at 95% 0%, var(--band-wash-2), transparent 60%);
}
/* Same call as the hero's: the band washes are red and oxblood at .07, which
   over a white ground reads as a pink stain in the bottom-left corner of every
   interior page rather than as depth. The other palettes keep theirs, where
   there is a coloured ground for them to modulate. */
:root[data-variant="art5"] .page-head::after,
:root:not([data-variant]) .page-head::after { background: none; }
.page-head h1 { margin-block: var(--s4) var(--s5); }
.page-head .lede { color: var(--band-ink-2); }

.breadcrumb {
  font-family: var(--font-sans); font-size: .76rem;
  letter-spacing: .02em;
  color: var(--band-ink-2);
  display: flex; gap: .6rem; align-items: center;
}
.breadcrumb a:hover { color: var(--accent); }

/* ---------- 7.5 The two editions ------------------------------------------ */
/* One row, two halves: what the forum was, and what it will be. Equal columns,
   because neither is a footnote to the other — the 2025 side is the evidence
   that the 2026 side is worth two days. A hairline between them rather than
   cards, so the row reads as one comparison instead of two boxes. Below 900px
   the rule moves above the second half and they stack. */
.editions {
  display: grid;
  gap: clamp(2.5rem, 5vw, 4.5rem);
  grid-template-columns: 1fr;
}
.edition > * + * { margin-top: var(--s4); }
.edition .lede { font-size: clamp(1rem, 1.35vw, 1.12rem); max-width: 46ch; }
.edition .display-md { margin-top: var(--s3); }
.edition > .link { margin-top: var(--s6); }

.edition-points {
  list-style: none;
  padding: 0;
  display: grid;
  gap: var(--s4);
}
.edition-points li {
  position: relative;
  padding-left: 1.5rem;
  color: var(--ink-2);
  line-height: 1.55;
  max-width: 48ch;
}
.edition-points li::before {
  content: '';
  position: absolute;
  left: 0; top: .62em;
  width: .5rem; height: 1px;
  background: var(--accent);
}
.edition-points strong { color: var(--ink); font-weight: 600; }

@media (min-width: 900px) {
  .editions {
    grid-template-columns: 1fr 1fr;
    gap: clamp(3rem, 6vw, 6rem);
  }
  .editions > .edition + .edition {
    padding-left: clamp(3rem, 6vw, 6rem);
    margin-left: clamp(-3rem, -3vw, -1.5rem);
    border-left: 1px solid var(--line);
  }
}
@media (max-width: 899px) {
  .editions > .edition + .edition {
    padding-top: clamp(2.5rem, 5vw, 4.5rem);
    border-top: 1px solid var(--line);
  }
}

/* ---------- 8. Marquee (partners) ---------------------------------------- */

.marquee {
  border-block: 1px solid var(--line);
  background: var(--surface);
  padding-block: var(--s5);
  overflow: hidden;
  position: relative;
}
.marquee::before, .marquee::after {
  content: ''; position: absolute; top: 0; bottom: 0; width: 8rem; z-index: 2;
  pointer-events: none;
}
.marquee::before { left: 0;  background: linear-gradient(90deg, var(--surface), transparent); }
.marquee::after { right: 0; background: linear-gradient(270deg, var(--surface), transparent); }

.marquee-label {
  font-family: var(--font-sans); font-size: .66rem;
  letter-spacing: .02em; color: var(--ink-3);
  text-align: center; margin-bottom: var(--s4);
}
.marquee-track {
  display: flex; gap: var(--s8); width: max-content;
  animation: marquee 42s linear infinite;
}
.marquee:hover .marquee-track { animation-play-state: paused; }
@keyframes marquee { to { transform: translateX(-50%); } }
/* Three confirmed organisations cannot fill a scrolling track: one set is
   ~694px against a 1440px viewport, so the loop would either show a gap or have
   to repeat the same three names three times across the screen, which reads as
   padding. Until the line-up is deep enough the same strip renders static and
   centred — a deliberate row rather than a thin loop. */
.marquee--still::before,
.marquee--still::after { display: none; }
.marquee--still .marquee-track {
  animation: none;
  width: auto;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--s4) var(--s7);
  padding-inline: var(--gutter);
}

.marquee-item {
  font-family: var(--font-display);
  font-size: 1.15rem;
  color: var(--ink-3);
  white-space: nowrap;
  letter-spacing: -.01em;
  transition: color .25s;
}
.marquee-item:hover { color: var(--ink); }

/* ---------- 9. Cards ----------------------------------------------------- */

.card {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: var(--s6);
  transition: transform .35s var(--ease), box-shadow .35s var(--ease), border-color .3s;
  overflow: hidden;
}
.card--link:hover { transform: translateY(-4px); box-shadow: var(--shadow-md); border-color: color-mix(in srgb, var(--accent) 45%, var(--line)); }
.card h3 { margin-bottom: var(--s3); }
.card p { color: var(--ink-2); font-size: .945rem; }

/* Numbered track card */
.track {
  display: grid;
  /* Three children, and the third row takes the slack: cards in a grid row are
     already equal height, so pinning the link to the foot of that row puts the
     three links on one line instead of each one trailing its own paragraph.
     The fourth track was left over from a numbered card that had an eyebrow. */
  grid-template-rows: auto auto 1fr;
  gap: var(--s3);
  padding: var(--s6) var(--s5) var(--s5);
}
.track > .track-meta { align-self: end; }
.track::before {
  content: ''; position: absolute; inset: 0 auto 0 0; width: 3px;
  background: var(--accent);
  transform: scaleY(0); transform-origin: top;
  transition: transform .4s var(--ease);
}
.track:hover::before { transform: scaleY(1); }
.track h3 { font-size: 1.28rem; margin: 0; }
.track p { font-size: .9rem; line-height: 1.6; }
.track-meta {
  font-family: var(--font-sans); font-size: .74rem; font-weight: 500;
  letter-spacing: .02em;
  color: var(--ink-3);
  padding-top: var(--s3); border-top: 1px solid var(--line-soft);
}

/* Tag / pill */
.tag {
  display: inline-flex; align-items: center; gap: .35rem;
  padding: .24rem .6rem;
  font-family: var(--font-sans);
  font-size: .72rem; font-weight: 500; letter-spacing: .02em;
  border-radius: 100px;
  background: var(--cool-tint); color: var(--cool);
  border: 1px solid color-mix(in srgb, var(--cool) 22%, transparent);
  white-space: nowrap;
}
.tag--accent { background: var(--accent-tint); color: var(--accent); border-color: color-mix(in srgb, var(--accent) 26%, transparent); }
.tag--signal { background: var(--signal-tint); color: var(--signal); border-color: color-mix(in srgb, var(--signal) 26%, transparent); }
.tag--quiet { background: var(--line-soft); color: var(--ink-3); border-color: var(--line); }

/* ---------- 10. Stats ---------------------------------------------------- */

.stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 190px), 1fr));
  gap: 1px;
  background: var(--band-line);
  border: 1px solid var(--band-line);
  border-radius: var(--radius-lg);
  overflow: hidden;
}
.stat { background: var(--band); padding: var(--s6) var(--s5); }
.stat-value {
  font-family: var(--font-display);
  font-size: clamp(2.4rem, 4.5vw, 3.4rem);
  line-height: 1; color: var(--band-ink);
  font-variant-numeric: tabular-nums;
}
.stat-value .suffix { color: var(--accent); }
.stat-label {
  margin-top: var(--s3);
  font-family: var(--font-sans); font-size: .76rem; font-weight: 500;
  letter-spacing: .02em; color: var(--band-ink-2);
}

/* ---------- 11. Speakers ------------------------------------------------- */

.speaker {
  display: grid; gap: var(--s4);
  padding: 0; border: 0; background: none;
  text-align: left; cursor: pointer;
  width: 100%;
}
.speaker-photo {
  position: relative;
  aspect-ratio: 4 / 5;
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: linear-gradient(150deg, var(--surface-2), var(--paper-2));
  border: 1px solid var(--line);
  display: grid; place-items: center;
  transition: transform .4s var(--ease), border-color .3s;
}
.speaker:hover .speaker-photo { transform: translateY(-4px); border-color: color-mix(in srgb, var(--accent) 45%, var(--line)); }
.speaker-initials {
  font-family: var(--font-display);
  font-size: clamp(2.2rem, 4vw, 3rem);
  color: var(--ink-3);
  letter-spacing: -.02em;
  transition: color .3s;
}
.speaker:hover .speaker-initials { color: var(--accent); }
.speaker-photo::after {
  content: ''; position: absolute; inset: auto 0 0 0; height: 3px;
  background: var(--accent);
  transform: scaleX(0); transform-origin: left;
  transition: transform .4s var(--ease);
}
.speaker:hover .speaker-photo::after { transform: scaleX(1); }
.speaker-name { font-family: var(--font-display); font-size: 1.24rem; line-height: 1.2; }
.speaker-role { font-size: .875rem; color: var(--ink-2); line-height: 1.5; margin-top: 2px; }
.speaker-org { font-family: var(--font-sans); font-size: .78rem; font-weight: 500; letter-spacing: .02em; color: var(--ink-3); margin-top: var(--s2); }

/* Modal */
.modal {
  position: fixed; inset: 0; z-index: 300;
  display: grid; place-items: center;
  padding: var(--gutter);
  background: rgba(5, 7, 10, .62);
  backdrop-filter: blur(6px);
  opacity: 0; pointer-events: none;
  transition: opacity .3s var(--ease);
}
.modal.is-open { opacity: 1; pointer-events: auto; }
.modal-panel {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  max-width: 620px; width: 100%;
  max-height: min(85dvh, 760px); overflow-y: auto;
  padding: var(--s7) var(--s6) var(--s6);
  position: relative;
  transform: translateY(12px) scale(.98);
  transition: transform .3s var(--ease);
}
.modal.is-open .modal-panel { transform: none; }
.modal-close {
  position: absolute; top: var(--s4); right: var(--s4);
  width: 2.1rem; height: 2.1rem; display: grid; place-items: center;
  background: transparent; border: 1px solid var(--line); border-radius: var(--radius);
  cursor: pointer; color: var(--ink-2);
  transition: color .2s, border-color .2s;
}
.modal-close:hover { color: var(--ink); border-color: var(--ink); }

/* ---------- 12. Programme / schedule ------------------------------------- */

.tabs {
  display: flex; gap: var(--s2);
  border-bottom: 1px solid var(--line);
  margin-bottom: var(--s6);
  overflow-x: auto;
  scrollbar-width: none;
}
.tabs::-webkit-scrollbar { display: none; }
.tab {
  background: none; border: 0;
  padding: var(--s3) var(--s4) var(--s4);
  font-size: .95rem; font-weight: 550; color: var(--ink-3);
  cursor: pointer; white-space: nowrap;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  transition: color .2s, border-color .2s;
}
.tab:hover { color: var(--ink); }
.tab[aria-selected="true"] { color: var(--ink); border-bottom-color: var(--accent); }
.tab small { display: block; font-family: var(--font-sans); font-size: .72rem; letter-spacing: .02em; color: var(--ink-3); font-weight: 400; margin-top: 2px; }

.tabpanel[hidden] { display: none; }

.session {
  display: grid;
  grid-template-columns: 8.5rem 1fr;
  gap: var(--s5);
  padding-block: var(--s5);
  border-bottom: 1px solid var(--line-soft);
  align-items: start;
}
.session:last-child { border-bottom: 0; }
.session-time {
  font-variant-numeric: tabular-nums;
  font-family: var(--font-sans); font-size: .8rem;
  color: var(--ink-3); font-variant-numeric: tabular-nums;
  padding-top: .2rem;
  position: sticky; top: 6rem;
}
.session-body h3 { font-size: 1.2rem; margin-bottom: var(--s2); }
.session-body p { font-size: .92rem; color: var(--ink-2); }
.session-meta { margin-top: var(--s3); }
.session--break .session-body h3 { font-family: var(--font-sans); font-size: .92rem; font-weight: 600; color: var(--ink-3); letter-spacing: .01em; }
.session--keynote { position: relative; }
.session--keynote .session-body h3::before {
  content: 'Keynote'; display: block;
  font-family: var(--font-sans); font-size: .72rem; letter-spacing: .02em; color: var(--accent); margin-bottom: var(--s2);
}
.parallel {
  display: grid; gap: var(--s3);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 230px), 1fr));
  margin-top: var(--s4);
}
.parallel-item {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--s4);
  background: var(--surface);
}
.parallel-item strong { display: block; font-size: .9rem; margin-bottom: var(--s1); }
.parallel-item span { font-family: var(--font-sans); font-size: .72rem; font-weight: 500; letter-spacing: .02em; color: var(--ink-3); }

@media (max-width: 700px) {
  .session { grid-template-columns: 1fr; gap: var(--s3); }
  .session-time { position: static; }
}

/* ---------- 13. Timeline (dates) ----------------------------------------- */

.timeline { display: grid; gap: 0; counter-reset: tl; }
.timeline-item {
  display: grid;
  grid-template-columns: 1.5rem 1fr;
  gap: var(--s5);
  padding-block: var(--s5);
  position: relative;
}
.timeline-item::before {
  content: ''; position: absolute; left: .68rem; top: 0; bottom: 0;
  width: 1px; background: var(--line);
}
.timeline-item:first-child::before { top: 1.9rem; }
.timeline-item:last-child::before { bottom: calc(100% - 1.9rem); }
.timeline-dot {
  width: 11px; height: 11px; border-radius: 50%;
  background: var(--paper); border: 2px solid var(--line);
  margin-top: 1.35rem; margin-left: 2px;
  position: relative; z-index: 1;
  transition: background-color .3s, border-color .3s, transform .3s;
}
.timeline-item.is-next .timeline-dot { background: var(--accent); border-color: var(--accent); transform: scale(1.25); }
.timeline-item.is-past .timeline-dot { background: var(--line); border-color: var(--line); }
.timeline-date {
  font-variant-numeric: tabular-nums;
  font-family: var(--font-sans); font-size: .78rem; font-weight: 600;
  letter-spacing: .02em; color: var(--ink-3);
  margin-bottom: var(--s1);
}
.timeline-item.is-next .timeline-date { color: var(--accent); }
.timeline-title { font-family: var(--font-display); font-size: 1.3rem; line-height: 1.25; }
.timeline-item.is-past .timeline-title { color: var(--ink-3); text-decoration: line-through; text-decoration-thickness: 1px; text-decoration-color: var(--line); }
.timeline-desc { font-size: .9rem; color: var(--ink-2); margin-top: var(--s2); max-width: 58ch; }

/* Countdown */
.countdown { display: flex; gap: var(--s4); flex-wrap: wrap; }
.countdown-unit {
  min-width: 4.6rem;
  text-align: center;
  border: 1px solid var(--band-line);
  border-radius: var(--radius);
  padding: var(--s4) var(--s3);
}
.countdown-value {
  font-variant-numeric: tabular-nums;
  font-family: var(--font-display);
  font-size: 2.1rem; line-height: 1;
  font-variant-numeric: tabular-nums;
  color: var(--band-ink);
}
.countdown-label {
  font-family: var(--font-sans); font-size: .68rem; font-weight: 500;
  letter-spacing: .02em;
  color: var(--band-ink-2); margin-top: var(--s2);
}

/* ---------- 14. Accordion (FAQ) ------------------------------------------ */

.accordion { border-top: 1px solid var(--line); }
.accordion-item { border-bottom: 1px solid var(--line); }
.accordion-trigger {
  width: 100%;
  display: flex; align-items: flex-start; justify-content: space-between; gap: var(--s5);
  padding: var(--s5) 0;
  background: none; border: 0; cursor: pointer;
  text-align: left;
  font-family: var(--font-display);
  font-size: clamp(1.1rem, 1.7vw, 1.3rem);
  line-height: 1.3;
  color: var(--ink);
  transition: color .2s;
}
.accordion-trigger:hover { color: var(--accent); }
.accordion-icon {
  flex: none; width: 1.4rem; height: 1.4rem; margin-top: .18rem;
  position: relative;
}
.accordion-icon::before, .accordion-icon::after {
  content: ''; position: absolute; inset: 50% 0 auto 0;
  height: 1.5px; background: currentColor;
  transition: transform .3s var(--ease);
}
.accordion-icon::after { transform: rotate(90deg); }
.accordion-trigger[aria-expanded="true"] .accordion-icon::after { transform: rotate(0deg); }
.accordion-panel {
  display: grid; grid-template-rows: 0fr;
  transition: grid-template-rows .35s var(--ease);
}
.accordion-panel > div { overflow: hidden; }
.accordion-item.is-open .accordion-panel { grid-template-rows: 1fr; }
.accordion-panel p { padding-bottom: var(--s5); max-width: 68ch; color: var(--ink-2); font-size: .95rem; }

/* ---------- 15. Forms ---------------------------------------------------- */

.field { display: grid; gap: var(--s2); }
.field label {
  font-family: var(--font-sans); font-size: .74rem; font-weight: 600;
  letter-spacing: .02em; color: var(--ink-3);
}
.field label .req { color: var(--accent); }
.field input, .field select, .field textarea {
  width: 100%;
  padding: .78rem .9rem;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  font-size: .95rem;
  transition: border-color .2s, box-shadow .2s;
}
.field textarea { resize: vertical; min-height: 7rem; line-height: 1.6; }
.field input:focus, .field select:focus, .field textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-tint);
}
.field-hint { font-size: .8rem; color: var(--ink-3); }
.field-error { font-size: .8rem; color: var(--accent); display: none; }
.field.has-error input, .field.has-error select, .field.has-error textarea { border-color: var(--accent); }
.field.has-error .field-error { display: block; }

.form-grid { display: grid; gap: var(--s5); grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr)); }
.form-full { grid-column: 1 / -1; }

.checkbox { display: flex; gap: var(--s3); align-items: flex-start; }
.checkbox input { width: 1.05rem; height: 1.05rem; margin-top: .28rem; accent-color: var(--accent); flex: none; }
.checkbox span { font-size: .89rem; color: var(--ink-2); line-height: 1.55; }

.form-status {
  padding: var(--s4) var(--s5);
  border-radius: var(--radius);
  border: 1px solid;
  font-size: .92rem;
  display: none;
}
.form-status.is-visible { display: block; }
.form-status--ok { background: var(--cool-tint); border-color: color-mix(in srgb, var(--cool) 32%, transparent); color: var(--cool); }

/* Ticket tiers */
.tier {
  display: grid; gap: var(--s4);
  padding: var(--s6);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  background: var(--surface);
  position: relative;
  transition: transform .35s var(--ease), box-shadow .35s var(--ease), border-color .3s;
}
.tier:hover { transform: translateY(-4px); box-shadow: var(--shadow-md); }
.tier--featured { border-color: var(--accent); box-shadow: var(--shadow-md); }
.tier--featured::before {
  content: 'Most common';
  position: absolute; top: -.72rem; left: var(--s6);
  background: var(--accent); color: #fff;
  font-family: var(--font-sans); font-size: .68rem;
  letter-spacing: .02em;
  padding: .28rem .6rem; border-radius: 100px;
}
.tier-price { font-family: var(--font-display); font-size: 2.6rem; line-height: 1; }
.tier-price small { font-family: var(--font-sans); font-size: .82rem; color: var(--ink-3); display: block; margin-top: var(--s2); font-weight: 400; }
.tier-list { list-style: none; padding: 0; display: grid; gap: var(--s3); font-size: .9rem; color: var(--ink-2); }
.tier-list li { display: flex; gap: var(--s3); align-items: flex-start; }
.tier-list li::before {
  content: ''; flex: none; width: 1rem; height: 1rem; margin-top: .22rem;
  background: var(--accent); opacity: .9;
  -webkit-mask: no-repeat center / contain url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M2 8.5l4 4 8-9' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  mask: no-repeat center / contain url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M2 8.5l4 4 8-9' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

/* ---------- 16. Callout / CTA -------------------------------------------- */

/* Cards in a row share their rows, so the bodies start on one line however
   many lines each heading runs to.

   Opt in with .grid--rows rather than selecting on `:has(> .callout)`. That
   heuristic matched any grid with a callout anywhere in it, including the
   deadline grid on posters.html — a timeline beside a four-child callout —
   where forcing the callout to span two rows sized by the timeline stretched
   it from 300px to 938. Three grids qualify: every child a callout, every
   callout the same two children — "Work in progress is welcome" wraps to two
   and the other two do not, which left the three paragraphs stepped. Same
   mechanism as .focus-col: every callout has the same two children, which is
   what makes subgrid safe. Their padding is identical, so the offset it adds
   inside each subgrid is identical too. */
@supports (grid-template-rows: subgrid) {
  .grid--rows { grid-template-rows: repeat(2, auto); }
  .grid--rows > .callout { grid-row: span 2; grid-template-rows: subgrid; }
}
.callout {
  display: grid; gap: var(--s5);
  padding: clamp(1.75rem, 3.5vw, 2.75rem);
  border-radius: var(--radius-lg);
  background: var(--surface-2);
  border: 1px solid var(--line);
}
.callout--band { background: color-mix(in srgb, var(--band-ink) 5%, transparent); border-color: var(--band-line); }

.cta-band {
  background: var(--band); color: var(--band-ink);
  position: relative; overflow: hidden; isolation: isolate;
}
.cta-band::after {
  content: ''; position: absolute; inset: 0; z-index: -1;
  background: radial-gradient(44rem 26rem at 85% 120%, var(--band-wash-1), transparent 62%);
}

/* ---------- 17. Footer --------------------------------------------------- */

.site-footer {
  background: var(--band); color: var(--band-ink);
  border-top: 1px solid var(--band-line);
  padding-block: clamp(3.5rem, 7vw, 5.5rem) var(--s6);
}
.footer-grid {
  display: grid; gap: var(--s7);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 200px), 1fr));
  padding-bottom: var(--s7);
  border-bottom: 1px solid var(--band-line);
}
.footer-brand { grid-column: span 2; max-width: 34ch; }
@media (max-width: 700px) { .footer-brand { grid-column: span 1; } }
.footer-brand p { color: var(--band-ink-2); font-size: .92rem; margin-top: var(--s4); }
.footer-col h4 {
  font-family: var(--font-sans); font-size: .72rem;
  letter-spacing: .02em;
  color: var(--band-ink-2); font-weight: 500;
  margin-bottom: var(--s4);
}
.footer-col ul { list-style: none; padding: 0; display: grid; gap: var(--s3); }
.footer-col a { font-size: .92rem; color: var(--band-ink); opacity: .82; transition: opacity .2s, color .2s; }
.footer-col a:hover { opacity: 1; color: var(--accent); }

.footer-bottom {
  display: flex; flex-wrap: wrap; gap: var(--s4);
  justify-content: space-between; align-items: center;
  padding-top: var(--s5);
  font-size: .82rem; color: var(--band-ink-2);
}
.footer-bottom a:hover { color: var(--accent); }

.social { display: flex; gap: var(--s3); }
.social a {
  width: 2.2rem; height: 2.2rem; display: grid; place-items: center;
  border: 1px solid var(--band-line); border-radius: var(--radius);
  color: var(--band-ink-2);
  transition: color .2s, border-color .2s, transform .2s;
}
.social a:hover { color: var(--band-ink); border-color: var(--band-ink); transform: translateY(-2px); }

/* Convenor & partner lockups above the footer baseline */
.footer-orgs {
  display: flex; flex-wrap: wrap;
  gap: var(--s7) var(--s8);
  padding-block: var(--s6);
  border-bottom: 1px solid var(--band-line);
}
.footer-org { display: grid; gap: var(--s3); align-content: start; }
.footer-org > span {
  font-family: var(--font-sans); font-size: .70rem; font-weight: 500;
  letter-spacing: .02em; color: var(--band-ink-2);
}
.footer-org a { display: inline-flex; transition: opacity .2s; }
.footer-org a:hover { opacity: .75; }
.footer-org .era-mark { height: 2.6rem; }
.footer-org strong {
  font-family: var(--font-display); font-weight: 400;
  font-size: 1.15rem; letter-spacing: -.01em; line-height: 1.2;
  max-width: 18ch;
}

/* ---------- 18. Utilities & motion --------------------------------------- */

.reveal {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity .7s var(--ease), transform .7s var(--ease);
}
.reveal.is-visible { opacity: 1; transform: none; }
.reveal[data-delay="1"] { transition-delay: .07s; }
.reveal[data-delay="2"] { transition-delay: .14s; }
.reveal[data-delay="3"] { transition-delay: .21s; }
.reveal[data-delay="4"] { transition-delay: .28s; }
.reveal[data-delay="5"] { transition-delay: .35s; }
@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1; transform: none; }
}

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

.notice {
  background: var(--signal-tint);
  border: 1px dashed color-mix(in srgb, var(--signal) 45%, transparent);
  color: var(--signal);
  border-radius: var(--radius);
  padding: var(--s3) var(--s4);
  font-size: .82rem;
  display: flex; gap: var(--s3); align-items: flex-start;
}
.notice strong { font-weight: 650; }

.table-wrap { overflow-x: auto; }
table.data {
  width: 100%; border-collapse: collapse; min-width: 520px;
  font-size: .92rem;
}
table.data th, table.data td {
  text-align: left; padding: var(--s4) var(--s4) var(--s4) 0;
  border-bottom: 1px solid var(--line-soft);
  vertical-align: top;
}
table.data th {
  font-family: var(--font-sans); font-size: .72rem;
  letter-spacing: .02em; color: var(--ink-3);
  font-weight: 500; border-bottom-color: var(--line);
}
table.data td { color: var(--ink-2); }
table.data td:first-child { color: var(--ink); font-weight: 550; }

.prose h2 { margin-top: var(--s7); margin-bottom: var(--s4); }
/* The section's own padding already opens the gap above the first heading; the
   3rem on top of it was 216px between "About the forum" and "Our mission". */
.prose > h2:first-child { margin-top: 0; }
.prose h3 { margin-top: var(--s6); margin-bottom: var(--s3); font-size: 1.35rem; }
.prose p, .prose ul { color: var(--ink-2); }
.prose ul { padding-left: 1.15rem; display: grid; gap: var(--s2); margin-top: var(--s4); }
.prose li::marker { color: var(--accent); }

/* ---------- 19. Delegate mix (segmented bars) ---------------------------- */

.mix { display: grid; gap: var(--s5); }
.mix-row { display: grid; gap: var(--s3); }
.mix-head {
  display: flex; justify-content: space-between; align-items: baseline; gap: var(--s4);
}
.mix-name { font-size: .95rem; font-weight: 550; }
.mix-pct {
  font-variant-numeric: tabular-nums;
  font-family: var(--font-sans); font-size: .8rem;
  color: var(--accent); font-variant-numeric: tabular-nums; font-weight: 500;
}
.mix-bar {
  height: 8px; border-radius: 100px;
  background: var(--line-soft);
  overflow: hidden;
}
.mix-fill {
  height: 100%; border-radius: 100px;
  background: var(--accent);
  width: 0;
  transition: width 1.1s var(--ease);
  transition-delay: .1s;
}
.mix-row.is-visible .mix-fill { width: var(--pct); }
.mix-note { font-size: .85rem; color: var(--ink-3); }
.mix-row:nth-child(2) .mix-fill { background: color-mix(in srgb, var(--accent) 78%, var(--cool)); }
.mix-row:nth-child(3) .mix-fill { background: color-mix(in srgb, var(--accent) 56%, var(--cool)); }
.mix-row:nth-child(4) .mix-fill { background: color-mix(in srgb, var(--accent) 36%, var(--cool)); }
.mix-row:nth-child(5) .mix-fill { background: var(--cool); }
.mix-row:nth-child(6) .mix-fill { background: color-mix(in srgb, var(--cool) 55%, var(--ink-3)); }
.section--band .mix-bar { background: rgba(255,255,255,.12); }
.section--band .mix-note { color: var(--band-ink-2); }

/* ---------- 20. Format list ---------------------------------------------- */

.formats {
  display: grid; gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  overflow: hidden;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr));
}
.format {
  background: var(--surface);
  padding: var(--s6) var(--s5);
  display: grid; gap: var(--s3);
  align-content: start;
  transition: background-color .3s;
}
.format:hover { background: var(--surface-2); }
.format-icon {
  width: 2.4rem; height: 2.4rem;
  display: grid; place-items: center;
  border-radius: var(--radius);
  background: var(--accent-tint);
  color: var(--accent);
}
.format h3 { font-size: 1.12rem; }
.format p { font-size: .88rem; color: var(--ink-2); line-height: 1.6; }
.format .tag { align-self: start; }

/* A quiet sentence-case label for a block that needs naming — the same
   treatment as the hero fact labels, rather than the small-caps eyebrow that
   came off every other heading on the site. */
.section-label {
  font-family: var(--font-sans);
  font-size: .82rem;
  font-weight: 500;
  color: var(--ink-3);
}

/* ---------- 20.5 Organiser + contact ------------------------------------- */
/* The contact section is one person and one address, so both are given room:
   a headshot at the same 480px source as the speaker photos, and an email box
   sized off the address itself rather than a fixed type scale — jack.may@
   erafellowship.org is 25 characters, and at display-sm it overflowed a third
   of a three-column grid. */
.organiser {
  display: grid;
  grid-template-columns: 5.5rem 1fr;
  gap: var(--s5);
  align-items: start;
}
.organiser-photo {
  width: 5.5rem; height: 5.5rem;
  border-radius: 50%;
  border: 1px solid var(--line);
  background: var(--surface-2);
}
.organiser-name {
  font-family: var(--font-display);
  font-size: 1.35rem; line-height: 1.2; color: var(--ink);
}
.organiser-role {
  font-family: var(--font-sans);
  font-size: .72rem; font-weight: 500; letter-spacing: .02em; color: var(--ink-3);
  margin-top: .3rem;
}
.organiser-bio {
  color: var(--ink-2);
  font-size: .95rem; line-height: 1.62;
  margin-top: var(--s4);
  max-width: 52ch;
}

.contact-box { display: grid; place-items: center; padding: var(--s6) var(--s5); }
.contact-email {
  font-family: var(--font-display);
  /* Scales down before it can wrap: the address is 25 characters. */
  font-size: clamp(1.05rem, 2.6vw, 1.6rem);
  line-height: 1.25;
  color: var(--band-ink);
  overflow-wrap: anywhere;
  text-align: center;
  background-image: linear-gradient(var(--accent), var(--accent));
  background-size: 100% 1px;
  background-position: 0 100%;
  background-repeat: no-repeat;
  padding-bottom: 3px;
  transition: background-size .35s var(--ease);
}
.contact-email:hover { background-size: 100% 2px; }

/* ---------- 20.7 Focus areas, side by side -------------------------------- */
/* Three columns, so the areas read as the comparison they are instead of three
   sections a reader has to hold in memory across 1,950px of scroll. */
/* The dilemma argues straight into the focus areas — it ends on the premise
   the three of them answer — so the boundary between them should not be a full
   section break. Two stacked paddings put 240px of nothing there. */
#dilemma { padding-bottom: clamp(1.5rem, 3vw, 2.5rem); }

/* The dilemma reads at one left edge with everything below it, so it sits in
   the normal container and takes its reading width from a max-width instead of
   from being centred in a narrower one. */
.focus-intro > * { max-width: 62ch; }
.focus-head-note { color: var(--ink-3); font-size: .92rem; max-width: 62ch; }

.focus-cols {
  display: grid;
  gap: var(--s6);
  grid-template-columns: 1fr;
}
@media (min-width: 900px) {
  /* The dilemma argues straight into the focus areas — it ends on the premise
   the three of them answer — so the boundary between them should not be a full
   section break. Two stacked paddings put 240px of nothing there. */
#dilemma { padding-bottom: clamp(1.5rem, 3vw, 2.5rem); }

/* The dilemma reads at one left edge with everything below it, so it sits in
   the normal container and takes its reading width from a max-width instead of
   from being centred in a narrower one. */
.focus-intro > * { max-width: 62ch; }
.focus-head-note { color: var(--ink-3); font-size: .92rem; max-width: 62ch; }

.focus-cols {
    grid-template-columns: repeat(3, 1fr);
    gap: var(--s7);
    /* The three columns share one set of rows, so every part lines up across
       them: the headings sit on one line whatever length the cause paragraph
       above them runs to, and so do the subtitles, the blurbs and the briefs.
       All three columns have the same seven children, which is what makes
       subgrid safe here. */
    grid-template-rows: repeat(7, auto);
  }
  /* Only the track definition changes. The base .focus-col rule below sets the
     row gap and wins on source order anyway, so the spacing inside a column is
     exactly what it was before the rows were shared. */
.focus-col {
    grid-row: span 7;
    grid-template-rows: subgrid;
  }
}
.focus-col {
  display: grid;
  align-content: start;
  gap: var(--s3);
  padding-top: var(--s5);
  border-top: 2px solid var(--accent);
}
/* Each column runs problem then response, so the two halves need telling
   apart: a quiet label above each, and a rule before the answer. */

.focus-col-cause {
  font-family: var(--font-display);
  font-size: 1.2rem; line-height: 1.25; color: var(--ink);
}
.focus-col-cause-body { color: var(--ink-2); font-size: .92rem; line-height: 1.58; }

.focus-col-title {
  font-family: var(--font-display);
  font-size: 1.6rem; line-height: 1.15;
  /* Opens the second half of each column. The divider used to sit on the
     "What we do about it" label; with that gone it belongs here. */
  margin-top: var(--s5);
  padding-top: var(--s5);
  border-top: 1px solid var(--line);
}
.focus-col-sub {
  font-family: var(--font-sans);
  font-size: .88rem; font-weight: 500; color: var(--ink-3);
}
.focus-col-blurb { color: var(--ink-2); font-size: .94rem; line-height: 1.6; margin-top: var(--s2); }
.focus-col .more { margin-top: var(--s4); }
.focus-col .sources { margin-top: var(--s4); }


/* A clicked subnav link should show you what it landed on. :target does this
   with no script: the element whose id matches the fragment styles itself, and
   it survives a page load, so arriving at focus.html#verifiable from another
   page highlights the same column.

   The three focus columns get a real lift — accent border, tinted ground, a
   shadow — because they sit side by side and the eye needs telling which of the
   three. The full-width sections get a quieter marker, since there is nothing
   beside them to confuse them with. */
.focus-col {
  transition: background-color .4s var(--ease), border-color .3s,
              box-shadow .4s var(--ease), transform .3s var(--ease);
  border-radius: var(--radius-lg);
  padding-inline: var(--s4);
  margin-inline: calc(0px - var(--s4));
}
.focus-col:target {
  background: var(--accent-tint);
  border-top-color: var(--accent);
  border-top-width: 3px;
  box-shadow: var(--shadow-md);
  transform: translateY(-3px);
}
.focus-col:target .focus-col-title { border-top-color: var(--accent); }

.section:target > .container > .section-head::before,
.section:target > .container::before {
  content: '';
  display: block;
  width: 3.5rem; height: 3px;
  background: var(--accent);
  margin-bottom: var(--s4);
  border-radius: 2px;
}
@media (prefers-reduced-motion: reduce) {
  .focus-col { transition: none; }
  .focus-col:target { transform: none; }
}

.brief { display: grid; gap: var(--s4); margin-top: var(--s3); }
.brief-item h4 {
  font-family: var(--font-sans);
  font-size: .84rem; font-weight: 600; color: var(--ink);
  margin-bottom: .3rem;
}
.brief-item p { color: var(--ink-2); font-size: .9rem; line-height: 1.58; }

/* ---------- 21. Quote / testimonial -------------------------------------- */

.quote {
  display: grid; gap: var(--s5);
  padding: clamp(1.75rem, 3.5vw, 2.75rem);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  background: var(--surface);
  position: relative;
}
.quote::before {
  content: '\201C';
  position: absolute; top: -.4rem; left: 1.4rem;
  font-family: var(--font-display); font-size: 4.5rem; line-height: 1;
  color: var(--accent); opacity: .22;
}
.quote blockquote {
  font-family: var(--font-display);
  font-size: clamp(1.15rem, 1.9vw, 1.45rem);
  line-height: 1.42; margin: 0;
  position: relative; z-index: 1;
}
.quote figcaption {
  font-family: var(--font-sans); font-size: .74rem; font-weight: 500;
  letter-spacing: .02em; color: var(--ink-3);
}

/* ---------- 22. Logo wall (partners) ------------------------------------- */

.logo-wall {
  display: grid; gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  overflow: hidden;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 210px), 1fr));
}
/* Marks, where we have them, sit at a common optical height rather than a
   common box height — ERA's is a tall comet, AIGI's a wide lockup. */
.logo-cell .logo-mark,
.logo-cell .era-mark {
  width: auto; max-width: 100%;
  height: auto; max-height: 3rem;
}
.logo-cell .era-mark { max-height: 2.6rem; }
.logo-cell .era-mark--dark { display: none; }

.logo-cell {
  background: var(--surface);
  min-height: 7rem;
  display: grid; place-items: center; text-align: center;
  padding: var(--s5) var(--s4);
  gap: var(--s2);
  transition: background-color .3s;
}
.logo-cell:hover { background: var(--surface-2); }
.logo-cell strong {
  font-family: var(--font-display); font-weight: 400;
  font-size: 1.05rem; line-height: 1.25; letter-spacing: -.01em;
}
.logo-cell span {
  font-family: var(--font-sans); font-size: .68rem; font-weight: 500;
  letter-spacing: .02em; color: var(--ink-3);
}
.logo-cell--empty strong { color: var(--ink-3); font-style: italic; }
.section--band .logo-wall { background: var(--band-line); border-color: var(--band-line); }
.section--band .logo-cell { background: color-mix(in srgb, var(--band-ink) 4%, var(--band)); }
.section--band .logo-cell:hover { background: color-mix(in srgb, var(--band-ink) 8%, var(--band)); }

/* ---------- 23. Step / theory-of-change chain ---------------------------- */

.chain { display: grid; gap: var(--s5); counter-reset: chain; }
@media (min-width: 900px) { .chain { grid-template-columns: repeat(3, 1fr); gap: var(--s5); } }
.chain-step {
  position: relative;
  padding: var(--s6) var(--s5);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  background: var(--surface);
  display: grid; gap: var(--s3); align-content: start;
}
.chain-step h3 { font-size: 1.2rem; }
.chain-step p { font-size: .9rem; color: var(--ink-2); }
.chain-step-tag {
  margin-top: var(--s2);
  font-family: var(--font-sans); font-size: .72rem; font-weight: 500;
  letter-spacing: .02em;
  color: var(--ink-3);
  padding-top: var(--s3); border-top: 1px solid var(--line-soft);
}
@media (min-width: 900px) {
  .chain-step:not(:last-child)::after {
    content: ''; position: absolute; right: calc(0px - var(--s5) - 1px); top: 50%;
    width: var(--s5); height: 1px; background: var(--line);
  }
}

/* ---------- 24. Audience / persona cards --------------------------------- */

.persona {
  display: grid; gap: var(--s4);
  padding: var(--s6);
  border-radius: var(--radius-lg);
  border: 1px solid var(--line);
  background: var(--surface);
  align-content: start;
  transition: transform .35s var(--ease), box-shadow .35s var(--ease), border-color .3s;
}
.persona:hover { transform: translateY(-4px); box-shadow: var(--shadow-md); border-color: color-mix(in srgb, var(--accent) 40%, var(--line)); }
.persona h3 { font-size: 1.3rem; }
.persona ul { list-style: none; padding: 0; display: grid; gap: var(--s2); font-size: .89rem; color: var(--ink-2); }
.persona ul li { padding-left: 1.05rem; position: relative; }
.persona ul li::before {
  content: '—'; position: absolute; left: 0; color: var(--accent); font-family: var(--font-sans); font-size: .75rem;
}

/* ---------- 25. Venue / map block ---------------------------------------- */

.venue-card {
  display: grid; gap: var(--s5);
  border: 1px solid var(--line); border-radius: var(--radius-lg);
  overflow: hidden; background: var(--surface);
}
@media (min-width: 860px) { .venue-card { grid-template-columns: 1.05fr .95fr; gap: 0; align-items: stretch; } }
.venue-body { padding: clamp(1.75rem, 3.5vw, 2.75rem); display: grid; gap: var(--s4); align-content: start; }
.venue-visual {
  min-height: 16rem;
  background:
    linear-gradient(135deg, rgba(196,52,42,.14), transparent 55%),
    repeating-linear-gradient(45deg, var(--surface-2) 0 12px, var(--paper-2) 12px 24px);
  border-left: 1px solid var(--line);
  display: grid; place-items: center; padding: var(--s5);
  position: relative;
}
@media (max-width: 859px) { .venue-visual { border-left: 0; border-top: 1px solid var(--line); min-height: 12rem; } }
.venue-pin {
  font-family: var(--font-sans); font-size: .74rem; font-weight: 500;
  letter-spacing: .02em;
  background: var(--band); color: var(--band-ink);
  padding: var(--s3) var(--s4); border-radius: var(--radius);
  box-shadow: var(--shadow-md);
  text-align: center; line-height: 1.7;
}
.venue-pin strong { display: block; font-family: var(--font-display); font-size: 1.05rem; letter-spacing: -.01em; text-transform: none; }

.travel { display: grid; gap: var(--s3); }
.travel-row {
  display: grid; grid-template-columns: 7.5rem 1fr; gap: var(--s4);
  padding-block: var(--s3);
  border-bottom: 1px solid var(--line-soft);
  font-size: .9rem;
}
.travel-row:last-child { border-bottom: 0; }
.travel-row dt { font-family: var(--font-sans); font-size: .74rem; font-weight: 600; letter-spacing: .02em; color: var(--ink-3); padding-top: .15rem; }
.travel-row dd { color: var(--ink-2); }
@media (max-width: 520px) { .travel-row { grid-template-columns: 1fr; gap: var(--s1); } }

/* ---------- 26. Sticky sub-nav (long pages) ------------------------------ */

.subnav {
  position: sticky; top: 4rem; z-index: 50;
  background: color-mix(in srgb, var(--paper) 88%, transparent);
  backdrop-filter: saturate(180%) blur(12px);
  -webkit-backdrop-filter: saturate(180%) blur(12px);
  border-bottom: 1px solid var(--line);
}
.subnav-inner { display: flex; gap: var(--s2); overflow-x: auto; scrollbar-width: none; padding-block: var(--s3); }
.subnav-inner::-webkit-scrollbar { display: none; }
/* Sans, not mono. These are page links and they sit a few rem below the header
   nav, which is Instrument Sans at .905rem/500 — the mono set them in a face
   the rest of the chrome never uses. .845rem rather than the header's .905
   because there are more of them in a row; the tracking goes back to the face's
   own, since .02em was there to open up mono's already-wide fit. */
.subnav a {
  padding: .4rem .8rem; border-radius: 100px;
  font-family: var(--font-sans); font-size: .845rem; font-weight: 500;
  color: var(--ink-3); white-space: nowrap;
  border: 1px solid transparent;
  transition: color .2s, border-color .2s, background-color .2s;
}
.subnav a:hover { color: var(--ink); background: var(--line-soft); }
.subnav a.is-active { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 32%, transparent); background: var(--accent-tint); }

/* ---------- 27. Announcement bar ----------------------------------------- */

.announce {
  background: var(--accent); color: #fff;
  font-size: .84rem;
  text-align: center;
  padding: .55rem var(--gutter);
}
.announce a { text-decoration: underline; text-underline-offset: 3px; font-weight: 600; }
.announce a:hover { opacity: .85; }

/* ---------- 28. Venue floor plan ----------------------------------------- */

.floorplan-figure { margin: 0; display: grid; gap: var(--s5); }

.floorplan-wrap {
  overflow-x: auto;
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  background: var(--surface);
  padding: clamp(1rem, 2.5vw, 2rem);
}
.floorplan {
  display: block;
  width: 100%;
  min-width: 700px;   /* below this the labels stop being legible — scroll instead */
  height: auto;
  color: var(--ink);
}
.floorplan text {
  font-family: var(--font-sans);
  fill: currentColor;
}
.floorplan .fp-title { font-size: 14px; font-weight: 600; letter-spacing: .1em; }
.floorplan .fp-title-s { font-size: 12px; font-weight: 600; letter-spacing: .09em; }
.floorplan .fp-sub { font-size: 10px; letter-spacing: .04em; opacity: .72; }
.floorplan .fp-when { font-size: 9px;  letter-spacing: .16em; opacity: .58; }
.floorplan .fp-strip { font-size: 10.5px; letter-spacing: .16em; opacity: .68; }
.floorplan .fp-accent { fill: var(--accent); opacity: 1; }

.floorplan-legend {
  display: flex; flex-wrap: wrap; gap: var(--s5);
  font-family: var(--font-sans); font-size: .74rem; font-weight: 500;
  letter-spacing: .02em; color: var(--ink-3);
}
.floorplan-legend span { display: inline-flex; align-items: center; gap: .55rem; }
.floorplan-legend i {
  width: 1.1rem; height: .7rem; border-radius: 2px; flex: none;
  border: 1px solid currentColor;
}
.floorplan-legend .key-prog { color: var(--ink-3); background: color-mix(in srgb, var(--ink) 7%, transparent); }
.floorplan-legend .key-exch { color: var(--accent); background: var(--accent-tint); }
.floorplan-legend .key-flow { color: var(--ink-3); background: transparent; border-style: dashed; }

.floorplan-caption {
  font-size: .9rem; color: var(--ink-2); max-width: 70ch;
}

/* Zone detail list beneath the plan — carries the full information on mobile,
   where the drawing has to be scrolled. */
.zones {
  display: grid; gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  overflow: hidden;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr));
}
.zone {
  background: var(--surface);
  padding: var(--s5);
  display: grid; gap: var(--s2); align-content: start;
}
.zone-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--s3); }
.zone h3 { font-size: 1.08rem; }
.zone p { font-size: .87rem; color: var(--ink-2); line-height: 1.55; }
.zone-when {
  font-variant-numeric: tabular-nums;
  font-family: var(--font-sans); font-size: .68rem; font-weight: 500;
  letter-spacing: .02em; color: var(--ink-3);
  white-space: nowrap;
}
.zone--exchange { background: color-mix(in srgb, var(--accent) 4%, var(--surface)); }
.zone--exchange h3 { color: var(--accent); }

/* ---------- 29. Coordination channel list -------------------------------- */

.channels {
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  background: var(--surface);
  overflow: hidden;
}
.channels-head {
  display: flex; align-items: center; gap: var(--s3);
  padding: var(--s4) var(--s5);
  border-bottom: 1px solid var(--line);
  background: var(--surface-2);
}
.channels-mark {
  width: 1.85rem; height: 1.85rem; flex: none;
  display: grid; place-items: center;
  border-radius: var(--radius);
  background: var(--accent-btn); color: #fff;
  font-family: var(--font-sans); font-size: 1rem; font-weight: 700;
  line-height: 1;
}
.channels-head strong { font-size: .95rem; line-height: 1.2; display: block; }
.channels-head span {
  font-family: var(--font-sans); font-size: .70rem; font-weight: 500;
  letter-spacing: .02em; color: var(--ink-3);
}

.channel {
  display: grid; gap: var(--s1);
  padding: var(--s4) var(--s5);
  border-bottom: 1px solid var(--line-soft);
  transition: background-color .2s;
}
.channel:last-child { border-bottom: 0; }
.channel:hover { background: var(--surface-2); }
.channel-name {
  font-family: var(--font-sans); font-size: .84rem; font-weight: 500;
  display: flex; align-items: baseline; gap: .1rem;
}
.channel-name b { color: var(--accent); font-weight: 500; }
.channel-desc { font-size: .82rem; color: var(--ink-2); line-height: 1.5; }
.channel--muted .channel-name { color: var(--ink-3); }

.section--band .channels { background: color-mix(in srgb, var(--band-ink) 4%, var(--band)); border-color: var(--band-line); }
.section--band .channels-head { background: color-mix(in srgb, var(--band-ink) 7%, var(--band)); border-bottom-color: var(--band-line); }
.section--band .channels-head span { color: var(--band-ink-2); }
.section--band .channel { border-bottom-color: var(--band-line); }
.section--band .channel:hover { background: color-mix(in srgb, var(--band-ink) 8%, var(--band)); }
.section--band .channel-desc { color: var(--band-ink-2); }

/* ---------- 30. Forms and notices on dark bands -------------------------- */

.section--band .field label,
.section--band .field-hint,
.section--band .checkbox span { color: var(--band-ink-2); }
.section--band .field input,
.section--band .field select,
.section--band .field textarea {
  background: color-mix(in srgb, var(--band-ink) 6%, transparent);
  border-color: var(--band-line);
  color: var(--band-ink);
}
.section--band .field input::placeholder,
.section--band .field textarea::placeholder { color: var(--band-ink-2); opacity: .7; }
.section--band .form-status--ok {
  background: color-mix(in srgb, var(--band-ink) 8%, transparent);
  border-color: var(--band-line);
  color: var(--band-ink);
}
.section--band .notice {
  background: var(--notice-bg);
  border-color: var(--notice-bd);
  color: var(--notice-fg);
}

/* ---------- 31. Design variant switcher (REVIEW TOOL — remove at launch) --- */

.variant-bar {
  position: fixed; z-index: 150;
  left: var(--s4); bottom: var(--s4);
  display: flex; align-items: center; flex-wrap: wrap; gap: .2rem;
  padding: .3rem .3rem .3rem .7rem;
  max-width: calc(100vw - var(--s5));
  border-radius: 100px;
  background: color-mix(in srgb, var(--surface) 86%, transparent);
  backdrop-filter: saturate(180%) blur(14px);
  -webkit-backdrop-filter: saturate(180%) blur(14px);
  border: 1px solid var(--line);
  box-shadow: var(--shadow-lg);
}
.variant-label {
  font-family: var(--font-sans); font-size: .58rem;
  letter-spacing: .02em;
  color: var(--ink-3);
  margin-right: .4rem;
  white-space: nowrap;
}
.variant-bar button {
  display: inline-flex; align-items: center; gap: .38rem;
  padding: .34rem .7rem;
  border: 0; border-radius: 100px;
  background: transparent;
  font-family: var(--font-sans); font-size: .62rem;
  letter-spacing: .02em;
  color: var(--ink-3);
  cursor: pointer;
  transition: color .2s, background-color .2s;
}
.variant-bar button:hover { color: var(--ink); background: var(--line-soft); }
.variant-bar button[aria-pressed="true"] { color: var(--ink); background: var(--line-soft); }
.variant-bar button::before {
  content: ''; width: .62rem; height: .62rem; border-radius: 50%;
  border: 1px solid var(--line); flex: none;
  background: var(--swatch);
}
.variant-bar button[data-variant-set="ink"] { --swatch: #0B0E13; }
.variant-bar button[data-variant-set="slate"] { --swatch: #14212E; }
.variant-bar button[data-variant-set="oxblood"] { --swatch: #5E1712; }
.variant-bar button[data-variant-set="bone"] { --swatch: #EAE7E1; }
.variant-bar button[data-variant-set="mist"] { --swatch: #E3E8ED; }
.variant-bar button[data-variant-set="paper"] { --swatch: #EDE5D7; }
.variant-bar button[data-variant-set="art"] { --swatch: linear-gradient(135deg, #E9DECB 0 48%, #A45338 48%); }

@media (max-width: 620px) {
  .variant-bar { left: var(--s3); right: var(--s3); bottom: var(--s3); justify-content: center; max-width: none; }
  .variant-label { display: none; }
}
@media print { .variant-bar { display: none; } }

/* ---------- 32. Art variant — illustrated hero (plate v5) ---------------- */
/* v5 keeps v4's proportions (1672x941) and its composition — scene right, room
   for type left — but the left half is washed rather than blank, and the whole
   plate is warmer and higher in contrast. Two things follow from the wash, both
   measured rather than guessed:

     - the left ramp had to triple. Over v5's darkest wash (#B0ABA0) the
       headline still holds 7.18:1, but the muted colour the lede uses drops to
       3.22:1, and 7% of the text zone falls under 4.5:1. The ramp now runs
       0 -> .55 at 20% -> 1 at 30%, and the whole plate then carries a flat
       opacity of .8 that multiplies through it, so the composited maximum is
       .80 rather than 1. Measured at those composited values: 5.81:1 for the
       muted colour where the lede ends, 4.96:1 at the ramp's knee, and 8.48:1
       for the headline past the column, where nothing else sits;
     - the ground follows the plate up: v5's paper reads #FDF3E5 against v4's
       #F6EDE3, so the hero ramps #FEF6EA -> #FDF2E4 -> #FAE9D6.

   Three rules still hold:

     - the whole plate is always visible. The box carries the plate's own
       1672:941 aspect and the image is `contain`ed in it, so every viewport
       shows the same picture and the edge feathers land on the picture's edges;
     - the drawn half never runs under the type, only the wash does;
     - the ground is the plate's own paper, so the two are one surface.

   v5 has no corner roundel, so tools/patch_plate.py is no longer in the build
   path — it is kept for the next plate that needs it. */

:root[data-variant="art"] .hero,
:root[data-variant="art5"] .hero,
:root[data-variant="art2"] .hero,
:root[data-variant="art3"] .hero,
:root[data-variant="art4"] .hero,
:root:not([data-variant]) .hero {
  /* The facts sit in the right-hand column BELOW the plate and must end no
     lower than the plaque opposite them, so the plate takes what the left
     column leaves: that column measures 639px at 1000px wide rising to 766px
     above 1600px. Enlarging the fact values took the block from 153px to 180px,
     so the plate gives that back: min(67vw, 960px) keeps 15.6px of margin at
     1440px, the tightest width in the range, against 3.9px at 980px. */
  --plate-w: min(60vw, 880px);
  --plate-h: min(33.768vw, 495.3px);
}
:root[data-variant="art"] .hero-canvas,
:root[data-variant="art5"] .hero-canvas,
:root[data-variant="art2"] .hero-canvas,
:root[data-variant="art3"] .hero-canvas,
:root[data-variant="art4"] .hero-canvas,
:root:not([data-variant]) .hero-canvas { display: none; }

/* The plate covers the right two thirds; without this the rest of the hero is
   flat cream and the illustration reads as pasted onto it. These are v5's own
   washes continued outward — its warm bloom means #F7E5D0 and centres at x27%,
   its cool one at x27%/y72% — laid down BEHIND the plate (z-index -2) so they
   show only where the plate's left ramp lets them through, and held to alphas
   where the muted colour still clears 5:1 on top of them.

   art5 and the default are deliberately NOT in this list. Their ground is
   white and their palette is white, red and navy; the terracotta and slate in
   these washes are neither, and over a white ground they read as the cream the
   white was chosen to replace. The plate's own left ramp does the dissolving
   there instead. */
:root[data-variant="art"] .hero::after,
:root[data-variant="art2"] .hero::after,
:root[data-variant="art3"] .hero::after,
:root[data-variant="art4"] .hero::after {
  content: '';
  position: absolute; inset: 0; z-index: -2;
  background:
    radial-gradient(46rem 30rem at 14% 26%, rgba(216, 121, 55, .155), transparent 64%),
    radial-gradient(34rem 26rem at 6% 78%, rgba(93, 124, 158, .12), transparent 62%),
    radial-gradient(30rem 24rem at 34% 62%, rgba(216, 121, 55, .10), transparent 66%);
}

/* The base `.hero::after` still reaches art5 and the default, and it is not
   harmless there: it carries the red and oxblood band washes at z-index -1,
   the plate's own layer, so with the variant rule above no longer overriding
   the stacking it would paint across the artwork rather than behind it. The
   left of the hero is meant to be white, so the wash goes rather than moves. */
:root[data-variant="art5"] .hero::after,
:root:not([data-variant]) .hero::after { background: none; }

:root[data-variant="art"] .hero::before,
:root[data-variant="art5"] .hero::before,
:root[data-variant="art2"] .hero::before,
:root[data-variant="art3"] .hero::before,
:root[data-variant="art4"] .hero::before,
:root:not([data-variant]) .hero::before {
  content: '';
  position: absolute;
  top: 0; right: 0; bottom: auto; left: auto;
  width: var(--plate-w);
  aspect-ratio: 1672 / 941;
  z-index: -1;
  background-repeat: no-repeat;
  background-position: center;
  background-size: contain;            /* fit whole — never crop */
  opacity: .8;                         /* multiplies through the ramp below */
  background-image: url("../img/hero-background.jpg");
  background-image: image-set(
    url("../img/hero-background.webp") type("image/webp"),
    url("../img/hero-background.jpg")  type("image/jpeg"));
  /* Left and bottom edges sit inside the hero, so they are dissolved into the
     ground; the top and right are flush with the hero's own edges.

     The ramp holds at zero to 30% and reaches full strength at 54%. It used to
     start immediately and finish at 46%, which was fine while the lede was
     capped at 44ch and stopped short of the artwork. Now that the lede takes
     the whole column, its last lines end at 35% of the plate, and at the old
     ramp that put body text on a ground of #8A939B — 2.17:1, a failure. Holding
     at zero through 30% puts them back on near-white. The 54% end costs
     nothing: the statue sits at 57%, so it still renders at full strength. */
  -webkit-mask-image:
    linear-gradient(90deg, transparent 0%, transparent 30%, rgba(0, 0, 0, .45) 42%, #000 54%),
    linear-gradient(180deg, transparent 0%, #000 4%, #000 86%, transparent 100%);
  -webkit-mask-composite: source-in;
  mask-image:
    linear-gradient(90deg, transparent 0%, transparent 30%, rgba(0, 0, 0, .45) 42%, #000 54%),
    linear-gradient(180deg, transparent 0%, #000 4%, #000 86%, transparent 100%);
  mask-composite: intersect;
}


/* The hero ground, per variant. The rule above holds the plate geometry, which
   all four share; this is the colour underneath it, which is what makes them
   four palettes rather than one palette four times. */
:root[data-variant="art"] .hero,
:root[data-variant="art5"] .hero,
:root:not([data-variant]) .hero {
  --band: #FDF3E5;
  --band-line: rgba(11, 32, 56, .17);
  background: linear-gradient(178deg, #FEF6EA 0%, #FDF2E4 58%, #FAE9D6 100%);
}
:root[data-variant="art2"] .hero {
  --band: #FBF8F5;
  --band-line: rgba(14, 35, 64, .16);
  background: linear-gradient(178deg, #FDFBF9 0%, #F8F3EF 58%, #F1E9E4 100%);
}
:root[data-variant="art3"] .hero {
  --band: #FDFDFE;
  --band-line: rgba(0, 29, 69, .14);
  background: linear-gradient(178deg, #FFFFFF 0%, #FDFDFE 58%, #F7F9FB 100%);
}
:root[data-variant="art5"] .hero,
:root:not([data-variant]) .hero {
  --band: #FFFFFF;
  --band-line: rgba(61, 15, 12, .14);
  /* Flat white, not a gradient. The 178deg ramp ended on #FAF7F7, which is a
     warm grey, and it was the bottom of the text column — the one part of the
     hero with nothing drawn over it to disguise the drift. */
  background: #FFFFFF;
}
:root[data-variant="art4"] .hero {
  --band: #F5F8FB;
  --band-line: rgba(10, 27, 51, .16);
  background: linear-gradient(178deg, #FAFCFE 0%, #EFF4F9 58%, #E4ECF4 100%);
}

/* The rail sits in flow directly under the plaque, so the only thing that has
   to be reserved is room for the PLATE — which is out of flow and would
   otherwise overhang a short hero. Everything else the column does, it does by
   being tall. */
:root[data-variant="art"] .hero-inner,
:root[data-variant="art5"] .hero-inner,
:root[data-variant="art2"] .hero-inner,
:root[data-variant="art3"] .hero-inner,
:root[data-variant="art4"] .hero-inner,
:root:not([data-variant]) .hero-inner {
  min-height: calc(var(--plate-h) + 3rem);
  /* Art only. The other six variants open on a full-bleed dark band, where the
     generous 10rem lead-in reads as composure; here the plate is anchored to the
     top of the hero, so the same gap just reads as a hole above the headline. */
  padding-top: clamp(1rem, 2.5vw, 2rem);
}
:root[data-variant="art"] .hero-h1,
:root[data-variant="art5"] .hero-h1,
:root[data-variant="art2"] .hero-h1,
:root[data-variant="art3"] .hero-h1,
:root[data-variant="art4"] .hero-h1,
:root:not([data-variant]) .hero-h1 { margin-block: 0; }

/* 44rem, and the plate gave up 7vw to pay for it. The hero is an argument, not
   an illustration with a caption, so the text has to be the larger half: at
   36rem against a 67vw plate the column read as a margin note beside the
   picture. 44rem puts the headline at 704px against the plate's 60vw, and the
   clearance to the drawn half is 80px at 1281px, the tightest width in the
   tier, rising to 340px at 1920. The +15px is a hand adjustment on top of the
   44rem: it is where the headline's second clause stops breaking early. It
   spends 15 of the 80px of clearance and leaves 65.

   The `:root:not([data-variant])` twin on `.hero-inner > *` was missing here
   and in both media tiers below, so on a normal load — where art5 is the
   default and no attribute is set — the hero column had no cap at all and the
   headline ran across the artwork. It only looked right when a variant was
   picked in the switcher, which is why it survived review. */
:root[data-variant="art"] .hero-inner > *,
:root[data-variant="art5"] .hero-inner > *,
:root[data-variant="art2"] .hero-inner > *,
:root[data-variant="art3"] .hero-inner > *,
:root[data-variant="art4"] .hero-inner > *,
:root:not([data-variant]) .hero-inner > *,
:root[data-variant="art"] .hero-panel,
:root[data-variant="art5"] .hero-panel,
:root[data-variant="art2"] .hero-panel,
:root[data-variant="art3"] .hero-panel,
:root[data-variant="art4"] .hero-panel,
:root:not([data-variant]) .hero-panel { max-width: min(100%, calc(44rem + 15px)); }
/* The plaque is the one hero element that is not part of the text column. It
   sits below the plate rather than beside it, so nothing is gained by holding
   it to the column's width — as a full row the three speakers get even cells
   instead of being crowded into the left two thirds. */
:root[data-variant="art5"] .hero-panel,
:root:not([data-variant]) .hero-panel { max-width: 100%; }

/* The mission statement is 14.99em on its longer clause, against 8.94em for the
   headline it replaced. One line per clause would need 2.4rem — a sub-heading,
   not a headline — so it is allowed to wrap two lines per clause at 3.2rem and
   `text-wrap: balance` splits them evenly rather than leaving an orphan. */
:root[data-variant="art"] .hero-h1,
:root[data-variant="art5"] .hero-h1,
:root[data-variant="art2"] .hero-h1,
:root[data-variant="art3"] .hero-h1,
:root[data-variant="art4"] .hero-h1,
:root:not([data-variant]) .hero-h1 {
  /* Raised with the column. 3.2rem in a 36rem measure was a sub-heading beside
     a full-bleed illustration; 3.5rem in 44rem reads as the first thing on the
     page, which is what it is. Each clause still wraps to two balanced lines. */
  font-size: clamp(2rem, 4vw, 3.5rem);
}
.hero-h1 .hero-mask > span { text-wrap: balance; }
/* `balance` splits each clause into two even halves, which is why the headline
   stopped ~180px short of the lede below it even though both are bounded by the
   same 44rem+15px column — even halves are by definition not full lines. The
   headline is the widest thing on the page and should look it, so art5 and the
   default fill the measure and use `pretty` only to keep the second line from
   ending on a single word. */
:root[data-variant="art5"] .hero-h1 .hero-mask > span,
:root:not([data-variant]) .hero-h1 .hero-mask > span { text-wrap: pretty; }
/* 44ch, not 38: the lede grew from 179 to 237 characters, and at 38ch that is
   seven lines of a very narrow measure. Widening it costs a line and still sits
   inside the column.

   art5 and the default are out of this list, and out of the 30ch one in the
   tier below. They let `.hero-inner > *` bound the lede instead, which is the
   same bound the headline has, so the two blocks end on the same edge. They
   stay in the 46ch rule in the stacked tier, where the column is the whole page
   and matching the headline would mean a 95ch measure. */
:root[data-variant="art"] .hero .lede,
:root[data-variant="art2"] .hero .lede,
:root[data-variant="art3"] .hero .lede,
:root[data-variant="art4"] .hero .lede { max-width: 44ch; }

/* The facts sit in the right-hand column, directly under the plate and clear of
   the text column beside it — two by two, on the paper under a hairline each
   rather than as a second card. `top` is driven by the plate's own height, so
   the gap under the picture is fixed; the left edge is the text column's width
   plus a gutter, so the block can never reach back across it. */
:root[data-variant="art"] .hero-facts,
:root[data-variant="art5"] .hero-facts,
:root[data-variant="art2"] .hero-facts,
:root[data-variant="art3"] .hero-facts,
:root[data-variant="art4"] .hero-facts,
:root:not([data-variant]) .hero-facts {
  position: absolute;
  top: calc(var(--plate-h) + 1.5rem);
  left: calc(var(--gutter) + 36rem + 2rem);
  right: var(--gutter);
  bottom: auto;
  max-width: none;
  margin-top: 0;
  grid-template-columns: repeat(2, 1fr);
  gap: 1rem 1.5rem;
  border: 0;
  border-radius: 0;
  background: none;
  box-shadow: none;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  overflow: visible;
}
/* Given a rule of their own rather than a hairline: 2px, accent for the first
   2.5rem then fading to the band line — the same motif as the rule under the
   headline, so the block reads as part of the hero's language rather than as
   leftover metadata. The extra pixel is paid for out of the row gap. */
:root[data-variant="art"] .hero-fact,
:root[data-variant="art5"] .hero-fact,
:root[data-variant="art2"] .hero-fact,
:root[data-variant="art3"] .hero-fact,
:root[data-variant="art4"] .hero-fact,
:root:not([data-variant]) .hero-fact {
  padding: .6rem 0 0;
  box-shadow: none;
  border-top: 0;
  background: linear-gradient(90deg,
                var(--accent) 0 2.5rem,
                var(--band-line) 2.5rem) top left / 100% 2px no-repeat;
}
/* Sized up: this is the only place on the homepage the dates, venue and format
   are stated, and the column has room for them. 1.4rem is the largest the value
   goes before "Talks, panels, workshops, poster hall" wraps in a 236px cell. */
/* Label and value swap roles. The label was mono, uppercase and tracked at
   .185em — the small-caps eyebrow treatment that came off every heading on the
   site — and it was carrying the accent while the value it introduced sat
   quieter. Now the label is a plain sentence-case sans line, deliberately
   recessive, and the value is the loud element. The accent survives only in the
   rule above each cell. */
:root[data-variant="art"] .hero-fact dt,
:root[data-variant="art5"] .hero-fact dt,
:root[data-variant="art2"] .hero-fact dt,
:root[data-variant="art3"] .hero-fact dt,
:root[data-variant="art4"] .hero-fact dt,
:root:not([data-variant]) .hero-fact dt {
  font-family: var(--font-sans);
  font-size: .82rem;
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink-3);
  margin-bottom: var(--s1);
}
/* Scales with the cell: at 1000px the cells are 208px and 1.6rem would set
   "14-15 November 2026" in 204px, four pixels off wrapping. */
:root[data-variant="art"] .hero-fact dd,
:root[data-variant="art5"] .hero-fact dd,
:root[data-variant="art2"] .hero-fact dd,
:root[data-variant="art3"] .hero-fact dd,
:root[data-variant="art4"] .hero-fact dd,
:root:not([data-variant]) .hero-fact dd {
  font-size: clamp(1.35rem, 1.65vw, 1.6rem);
  line-height: 1.2;
  letter-spacing: -.012em;
  font-variant-numeric: tabular-nums;   /* the dates are the point of this block */
}
:root[data-variant="art"] .hero-fact dd small,
:root[data-variant="art5"] .hero-fact dd small,
:root[data-variant="art2"] .hero-fact dd small,
:root[data-variant="art3"] .hero-fact dd small,
:root[data-variant="art4"] .hero-fact dd small,
:root:not([data-variant]) .hero-fact dd small { font-size: .78rem; margin-top: 5px; }

/* Three speakers, three columns — they wrap 2+1 otherwise, which reads as a
   ranking rather than a line-up. A 36rem plaque gives 165px cells, too narrow
   for an avatar and a name side by side, so the card turns vertical: mark on
   top, name, then the affiliation set small enough to wrap to two lines instead
   of being truncated mid-organisation. Reserving those two lines keeps the three
   cards on a shared baseline even though one role is shorter than the others.
   The plaque ends up 251px tall, within 2px of the two-row version it replaces,
   so nothing downstream of it moves. */
@media (min-width: 1000px) {
  :root[data-variant="art"] .hero-speaker-list,
:root[data-variant="art5"] .hero-speaker-list,
:root[data-variant="art2"] .hero-speaker-list,
:root[data-variant="art3"] .hero-speaker-list,
:root[data-variant="art4"] .hero-speaker-list,
:root:not([data-variant]) .hero-speaker-list { grid-template-columns: repeat(3, 1fr); }
  :root[data-variant="art"] .hero-speaker,
:root[data-variant="art5"] .hero-speaker,
:root[data-variant="art2"] .hero-speaker,
:root[data-variant="art3"] .hero-speaker,
:root[data-variant="art4"] .hero-speaker,
:root:not([data-variant]) .hero-speaker {
    flex-direction: column;
    align-items: flex-start;
    gap: .5rem;
  }
  :root[data-variant="art"] .hero-speaker-text,
:root[data-variant="art5"] .hero-speaker-text,
:root[data-variant="art2"] .hero-speaker-text,
:root[data-variant="art3"] .hero-speaker-text,
:root[data-variant="art4"] .hero-speaker-text,
:root:not([data-variant]) .hero-speaker-text { width: 100%; }
  :root[data-variant="art"] .hero-speaker-name,
:root[data-variant="art5"] .hero-speaker-name,
:root[data-variant="art2"] .hero-speaker-name,
:root[data-variant="art3"] .hero-speaker-name,
:root[data-variant="art4"] .hero-speaker-name,
:root:not([data-variant]) .hero-speaker-name { font-size: 1rem; }
  :root[data-variant="art"] .hero-speaker-role,
:root[data-variant="art5"] .hero-speaker-role,
:root[data-variant="art2"] .hero-speaker-role,
:root[data-variant="art3"] .hero-speaker-role,
:root[data-variant="art4"] .hero-speaker-role,
:root:not([data-variant]) .hero-speaker-role {
    /* .555rem was 8.9px — small enough that the affiliation was decoration
       rather than information. .68rem with the weight from the base rule reads
       properly and still wraps to two lines in a 165px cell. */
    font-size: .68rem;
    letter-spacing: .075em;
    line-height: 1.34;
    white-space: normal;
    overflow: visible;
    text-overflow: clip;
    min-height: 2.68em;
  }
}

/* The block above turns each speaker vertical and shrinks the type, because it
   was written for a 36rem plaque with 165px cells. art5 and the default put the
   plaque across the whole container, so the cells are about 355px — wide enough
   to lay the portrait beside the name again, which is what was leaving the row
   looking half empty. The portrait roughly doubles, to 4.5rem, and the
   affiliation goes back to one line since there is room for it. */
@media (min-width: 1000px) {
  :root[data-variant="art5"] .hero-speaker,
  :root:not([data-variant]) .hero-speaker {
    flex-direction: row;
    align-items: center;
    gap: var(--s4);
  }
  :root[data-variant="art5"] .hero-speaker-avatar,
  :root:not([data-variant]) .hero-speaker-avatar {
    width: clamp(3.4rem, 5vw, 4.5rem);
    height: clamp(3.4rem, 5vw, 4.5rem);
  }
  :root[data-variant="art5"] .hero-speaker-avatar--tba,
  :root:not([data-variant]) .hero-speaker-avatar--tba {
    font-size: clamp(1.7rem, 2.6vw, 2.3rem);
  }
  /* The names carry the row — they are the reason anyone reads it — so they
     scale with the portrait rather than staying at the size they had in a 165px
     cell. Capped at 1.55rem: the names are set nowrap with an ellipsis, and
     1.55rem is the largest that still fits "Panellist · European AI Office"
     under it without truncating in the narrowest cell of the tier. */
  :root[data-variant="art5"] .hero-speaker-name,
  :root:not([data-variant]) .hero-speaker-name { font-size: clamp(1.2rem, 1.55vw, 1.55rem); }
  :root[data-variant="art5"] .hero-speaker-role,
  :root:not([data-variant]) .hero-speaker-role {
    font-size: .74rem;
    letter-spacing: .02em;
    line-height: 1.3;
    min-height: 0;
  }
}

/* The plaque can land on the plate's wash as well as on bare paper, so its own
   tint has to carry the contrast rather than borrow it from what is behind:
   .86 is the lowest alpha at which muted labels clear 4.5:1 over v5's darkest
   wash (4.70:1), and it still reads 21.8 luminance points off the ground. */
/* The plaque used to be a hard-coded cream, which was Art's ground and nobody
   else's — on a white palette it read as a tan box floating on white. It is now
   mixed from each variant's own band toward its own ink. 10% reproduces the
   separation the original had: Art's #FDF3E5 against #EBDBC3 is 18.4 luminance
   points, and 10% gives 19.1 on the white ground. */
:root[data-variant="art"] .hero-panel,
:root[data-variant="art5"] .hero-panel,
:root[data-variant="art2"] .hero-panel,
:root[data-variant="art3"] .hero-panel,
:root[data-variant="art4"] .hero-panel,
:root:not([data-variant]) .hero-panel {
  border-bottom: 1px solid var(--band-line);
  border-radius: var(--radius-lg);
  background:
    linear-gradient(color-mix(in srgb, var(--band-ink) 4%, transparent),
                    color-mix(in srgb, var(--band-ink) 4%, transparent)),
    color-mix(in srgb, var(--band-ink) 10%, var(--band));
  -webkit-backdrop-filter: blur(10px) saturate(130%);
  backdrop-filter: blur(10px) saturate(130%);
}

/* art5 and the default take white instead of the 10% ink mix. Their hero ground
   is now white too, so the mix had nothing to separate itself from except the
   white it was mixed toward — it read as a grey box rather than a card. Contrast
   comes from the border and the shadow instead of from the fill. */
:root[data-variant="art5"] .hero-panel,
:root:not([data-variant]) .hero-panel {
  background: var(--surface);
  border: 1px solid var(--line);
  box-shadow: var(--shadow-md);
}

/* Tier 2 — 1000-1280px. The plate stops scaling with the viewport at its cap,
   so the drawn half advances leftward as the screen narrows and the column has
   to give way: 28rem is what clears it at 1000px (32px). */
@media (max-width: 1280px) {
  :root[data-variant="art"] .hero-inner > *,
:root[data-variant="art5"] .hero-inner > *,
:root[data-variant="art2"] .hero-inner > *,
:root[data-variant="art3"] .hero-inner > *,
:root[data-variant="art4"] .hero-inner > *,
:root:not([data-variant]) .hero-inner > *,
:root[data-variant="art"] .hero-panel,
:root[data-variant="art5"] .hero-panel,
:root[data-variant="art2"] .hero-panel,
:root[data-variant="art3"] .hero-panel,
:root[data-variant="art4"] .hero-panel,
:root:not([data-variant]) .hero-panel { max-width: min(100%, 34rem); }
  /* Full row here too — the tier-2 column narrows to clear the plate, but the
     plaque still sits below it and has no reason to follow. */
  :root[data-variant="art5"] .hero-panel,
:root:not([data-variant]) .hero-panel { max-width: 100%; }
  :root[data-variant="art"] .hero-h1,
:root[data-variant="art5"] .hero-h1,
:root[data-variant="art2"] .hero-h1,
:root[data-variant="art3"] .hero-h1,
:root[data-variant="art4"] .hero-h1,
:root:not([data-variant]) .hero-h1 { font-size: clamp(1.9rem, 3.2vw, 2.7rem); }
  :root[data-variant="art"] .hero .lede,
:root[data-variant="art2"] .hero .lede,
:root[data-variant="art3"] .hero .lede,
:root[data-variant="art4"] .hero .lede { max-width: 30ch; }
  :root[data-variant="art"] .hero-facts,
:root[data-variant="art5"] .hero-facts,
:root[data-variant="art2"] .hero-facts,
:root[data-variant="art3"] .hero-facts,
:root[data-variant="art4"] .hero-facts,
:root:not([data-variant]) .hero-facts { left: calc(var(--gutter) + 28rem + 2rem); }
}

/* Tier 3 — below 1000px there is no room beside the drawn half, so the plate
   stops being a backdrop and becomes a band under the content. Fitted by
   height and pulled right, so the crop falls entirely on the blank paper. */
@media (max-width: 999px) {
  :root[data-variant="art"] .hero::before,
:root[data-variant="art5"] .hero::before,
:root[data-variant="art2"] .hero::before,
:root[data-variant="art3"] .hero::before,
:root[data-variant="art4"] .hero::before,
:root:not([data-variant]) .hero::before {
    top: auto; bottom: 0; left: 0; right: 0;
    width: 100%;
    aspect-ratio: auto;
    height: clamp(210px, 50vw, 380px);
    background-size: auto 100%;
    background-position: right center;
    -webkit-mask-image:
      linear-gradient(180deg, transparent 0%, #000 20%),
      linear-gradient(90deg, transparent 0%, #000 12%);
    -webkit-mask-composite: source-in;
    mask-image:
      linear-gradient(180deg, transparent 0%, #000 20%),
      linear-gradient(90deg, transparent 0%, #000 12%);
    mask-composite: intersect;
  }
  :root[data-variant="art"] .hero-inner,
:root[data-variant="art5"] .hero-inner,
:root[data-variant="art2"] .hero-inner,
:root[data-variant="art3"] .hero-inner,
:root[data-variant="art4"] .hero-inner,
:root:not([data-variant]) .hero-inner {
    padding-bottom: calc(clamp(210px, 50vw, 380px) + 2.5rem);
  }
  :root[data-variant="art"] .hero-inner > *,
:root[data-variant="art5"] .hero-inner > *,
:root[data-variant="art2"] .hero-inner > *,
:root[data-variant="art3"] .hero-inner > *,
:root[data-variant="art4"] .hero-inner > *,
:root:not([data-variant]) .hero-inner > *,
:root[data-variant="art"] .hero-panel,
:root[data-variant="art5"] .hero-panel,
:root[data-variant="art2"] .hero-panel,
:root[data-variant="art3"] .hero-panel,
:root[data-variant="art4"] .hero-panel,
:root:not([data-variant]) .hero-panel { max-width: 100%; }
  :root[data-variant="art"] .hero-h1,
:root[data-variant="art5"] .hero-h1,
:root[data-variant="art2"] .hero-h1,
:root[data-variant="art3"] .hero-h1,
:root[data-variant="art4"] .hero-h1,
:root:not([data-variant]) .hero-h1 { font-size: clamp(2.1rem, 6.4vw, 3.4rem); }
  :root[data-variant="art"] .hero .lede,
:root[data-variant="art5"] .hero .lede,
:root[data-variant="art2"] .hero .lede,
:root[data-variant="art3"] .hero .lede,
:root[data-variant="art4"] .hero .lede,
:root:not([data-variant]) .hero .lede { max-width: 46ch; }

  /* No right-hand column here, so the facts go back to being the plaque's
     lower half, in flow beneath the speakers. */
  :root[data-variant="art"] .hero-inner,
:root[data-variant="art5"] .hero-inner,
:root[data-variant="art2"] .hero-inner,
:root[data-variant="art3"] .hero-inner,
:root[data-variant="art4"] .hero-inner,
:root:not([data-variant]) .hero-inner { min-height: 0; }
  :root[data-variant="art"] .hero-panel,
:root[data-variant="art5"] .hero-panel,
:root[data-variant="art2"] .hero-panel,
:root[data-variant="art3"] .hero-panel,
:root[data-variant="art4"] .hero-panel,
:root:not([data-variant]) .hero-panel { border-bottom: 0; border-radius: var(--radius-lg) var(--radius-lg) 0 0; }
  :root[data-variant="art"] .hero-facts,
:root[data-variant="art5"] .hero-facts,
:root[data-variant="art2"] .hero-facts,
:root[data-variant="art3"] .hero-facts,
:root[data-variant="art4"] .hero-facts,
:root:not([data-variant]) .hero-facts {
    position: static;
    max-width: 100%;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 210px), 1fr));
    gap: 0;
    overflow: hidden;
    border: 1px solid var(--band-line);
    border-radius: 0 0 var(--radius-lg) var(--radius-lg);
    background:
      linear-gradient(color-mix(in srgb, var(--band-ink) 7%, transparent),
                      color-mix(in srgb, var(--band-ink) 7%, transparent)),
      color-mix(in srgb, var(--band) 82%, transparent);
    -webkit-backdrop-filter: blur(12px) saturate(150%);
    backdrop-filter: blur(12px) saturate(150%);
    box-shadow: 0 12px 32px color-mix(in srgb, var(--band-ink) 9%, transparent);
  }
  /* The fact rail is the plaque's lower half once the layout stacks, and the
     plaque above it is white — the 7% ink tint made it read as a grey drawer
     hanging off a white card. Same treatment as the plaque: white, with the
     border and the cell dividers doing the separating. */
  :root[data-variant="art5"] .hero-facts,
  :root:not([data-variant]) .hero-facts {
    background: var(--surface);
    border-color: var(--line);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
  :root[data-variant="art"] .hero-fact,
:root[data-variant="art5"] .hero-fact,
:root[data-variant="art2"] .hero-fact,
:root[data-variant="art3"] .hero-fact,
:root[data-variant="art4"] .hero-fact,
:root:not([data-variant]) .hero-fact {
    padding: var(--s5);
    border-top: 0;
    box-shadow: 1px 0 0 var(--band-line);
  }
  :root[data-variant="art"] .hero-fact dd,
:root[data-variant="art5"] .hero-fact dd,
:root[data-variant="art2"] .hero-fact dd,
:root[data-variant="art3"] .hero-fact dd,
:root[data-variant="art4"] .hero-fact dd,
:root:not([data-variant]) .hero-fact dd { font-size: 1.4rem; }
}
@media (max-width: 720px) {
  :root[data-variant="art"] .hero::before,
:root[data-variant="art5"] .hero::before,
:root[data-variant="art2"] .hero::before,
:root[data-variant="art3"] .hero::before,
:root[data-variant="art4"] .hero::before,
:root:not([data-variant]) .hero::before {
    background-image: url("../img/hero-background-900.jpg");
    background-image: image-set(
      url("../img/hero-background-900.webp") type("image/webp"),
      url("../img/hero-background-900.jpg")  type("image/jpeg"));
  }
}

/* Dark theme inverts to navy, where a paper plate cannot sit. */

/* No right-hand column here, so the facts go back to being the plaque's
   lower half, in flow beneath the speakers. */

/* The speaker's role was a pill sitting beside the name, competing with it.
   It now runs as a rule along the top of the card — a coloured hairline with
   the role set into it, so the card is labelled without the label being an
   object of its own.

   In flow, not absolutely positioned. Absolute needed the card's padding-top to
   be hand-matched to the rule's height, and 2.4rem left only 4.25px under a
   34.15px rule — close enough to read as touching, and guaranteed to overlap
   the moment a longer role wrapped to two lines. Bleeding it out to the card
   edges with negative side margins keeps the full-width band while letting the
   rule take its own space; .card's overflow:hidden clips it to the radius. */
.speaker-card { padding-top: 0; }
.speaker-role-rule {
  margin: 0 calc(0px - var(--s6)) var(--s5);
  padding: .55rem var(--s6) .5rem;
  border-bottom: 1px solid color-mix(in srgb, var(--accent) 30%, transparent);
  background: color-mix(in srgb, var(--accent) 8%, transparent);
  font-family: var(--font-sans);
  font-size: .68rem; font-weight: 600; letter-spacing: .02em; color: var(--accent);
}

/* One row: the ask on the left, the action on the right, stacking on narrow
   screens rather than letting the button drift away from its heading. */
.suggest-row {
  display: flex; flex-wrap: wrap; align-items: center;
  justify-content: space-between; gap: var(--s5) var(--s6);
}
.suggest-row .lede { max-width: 46ch; }

/* ---------- 33. Speaker cards with expandable bios ----------------------- */

.speaker-head { display: flex; align-items: flex-start; gap: var(--s4); }
.speaker-avatar {
  width: 3.6rem; height: 3.6rem; flex: none;
  border-radius: 50%;
  display: grid; place-items: center;
  overflow: hidden;
  border: 1px solid var(--line);
  background: var(--surface-2);
  font-family: var(--font-sans);
  font-size: .82rem; letter-spacing: .06em;
  color: var(--ink-3);
}

.speaker-head .speaker-name { display: block; font-size: 1.2rem; }

/* The "more to come" tile. Dashed rather than solid, so it reads as a slot
   waiting to be filled rather than as a person whose photo failed to load. */
.speaker-avatar--tba {
  border-style: dashed;
  font-size: 2rem;
  line-height: 1;
  color: var(--accent);
}
.speaker-card--tba { border-style: dashed; }
.speaker-card--tba .speaker-name { font-style: italic; color: var(--ink-2); }

/* ---------- Images painted as backgrounds -------------------------------
   Every file path the design uses now lives in this one block, so pointing
   the site at uploaded URLs is a handful of edits here rather than one per
   tag across seven pages.

   aspect-ratio is not optional. An <img> derives its width from the file's
   own proportions, so `width: auto` worked; a div has no intrinsic size and
   collapses to zero width without it. The ratios below are the real pixel
   dimensions of each file.

   Where the tag carried real alt text the div carries role="img" and
   aria-label instead, so nothing is lost to a screen reader. Where it carried
   alt="" the div is left unlabelled, which reads the same way. */
.portrait, .shot, .mark {
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}
.mark { background-size: contain; display: block; }

/* The .portrait--* and .shot--* rules are generated into theme.css from the
   photo path on each speaker and each format, so swapping a picture or adding
   a speaker is a field at /admin rather than a field plus a rule here. */
.shot { aspect-ratio: 1100 / 733; width: 100%; }

.mark--era { aspect-ratio: 314 / 320; background-image: url("../img/era-logo.png"); }
.mark--era-reversed { aspect-ratio: 314 / 320; background-image: url("../img/era-logo-reversed.png"); }
.mark--aigi { aspect-ratio: 400 / 261; background-image: url("../img/partner-aigi-mark.webp"); }


.more { margin-top: var(--s3); }
.more summary {
  display: inline-flex; align-items: center; gap: .45rem;
  font-family: var(--font-sans); font-size: .76rem; font-weight: 500;
  letter-spacing: .02em;
  color: var(--accent);
  cursor: pointer; list-style: none; width: fit-content;
}
.more summary::-webkit-details-marker { display: none; }
.more summary::after {
  content: ''; width: .4rem; height: .4rem;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: translateY(-.15em) rotate(45deg);
  transition: transform .25s var(--ease);
}
.more[open] summary::after { transform: translateY(.05em) rotate(-135deg); }
.more summary:hover { text-decoration: underline; text-underline-offset: 3px; }
.more p { font-size: .89rem; color: var(--ink-2); margin-top: var(--s3); }

/* ---------- 34. Photo showcase (2025 event photography) ------------------ */

.showcase {
  display: grid; gap: var(--s5);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 270px), 1fr));
}
.showcase-item {
  display: grid; gap: var(--s4);
  align-content: start;
}
.showcase-media {
  aspect-ratio: 3 / 2;
  border-radius: var(--radius-lg);
  overflow: hidden;
  border: 1px solid var(--line);
  background: var(--surface-2);
  position: relative;
}
.showcase-media .shot {
  width: 100%; height: 100%;
  transition: transform .6s var(--ease);
}
.showcase-item:hover .showcase-media .shot { transform: scale(1.03); }
.showcase-media::after {
  content: ''; position: absolute; inset: auto 0 0 0; height: 3px;
  background: var(--accent);
  transform: scaleX(0); transform-origin: left;
  transition: transform .4s var(--ease);
}
.showcase-item:hover .showcase-media::after { transform: scaleX(1); }
/* On the programme page the grid sits under the eight format cards, so it wants
   to read as a strip of evidence rather than four more cards: wider cells, and
   the caption tucked under the photograph. */
.showcase--wide {
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 220px), 1fr));
  gap: var(--s5) var(--s4);
}
/* The top margin separated the strip from the format cards above it. Those are
   gone and the strip now opens its section, so the margin only applies if
   something actually precedes it. */
.showcase--wide:not(:first-child) { margin-top: clamp(2.5rem, 5vw, 4rem); }
.showcase--wide .showcase-item h3 { font-size: 1.02rem; }
.showcase--wide .showcase-item p { font-size: .84rem; }

/* One photograph, full width of the column, on about.html#2025. */
.edition-photo {
  margin: 0 0 clamp(1.75rem, 3.5vw, 2.75rem);
  border-radius: var(--radius-lg);
  overflow: hidden;
  border: 1px solid var(--line);
  background: var(--surface-2);
}
.edition-photo .shot {
  display: block;
  width: 100%; height: auto;
  aspect-ratio: 3 / 2;
}
.edition-photo figcaption {
  font-size: .82rem;
  color: var(--ink-3);
  padding: var(--s3) var(--s4) var(--s4);
}

.showcase-item h3 { font-size: 1.18rem; }
.showcase-item p { font-size: .89rem; color: var(--ink-2); line-height: 1.6; margin-top: var(--s2); }

/* Source citations under a focus-area brief */
.sources {
  margin-top: var(--s5);
  padding-top: var(--s4);
  border-top: 1px solid var(--line-soft);
}
.sources dt {
  font-family: var(--font-sans); font-size: .70rem; font-weight: 600;
  letter-spacing: .02em; color: var(--ink-3);
  margin-bottom: var(--s3);
}
.sources dd { margin: 0 0 var(--s2); }
.sources a {
  font-size: .85rem; color: var(--ink-2);
  display: inline-flex; align-items: baseline; gap: .35rem;
  border-bottom: 1px solid var(--line);
  transition: color .2s, border-color .2s;
}
.sources a:hover { color: var(--accent); border-bottom-color: var(--accent); }


/* --------------------------------------------------------------------------
   Hero: the plaque can never reach the fact rail
   --------------------------------------------------------------------------
   The rail is positioned against the plate (`top: plate-h + 1.5rem`); the
   plaque is in normal flow after the buttons. Nothing tied the two together,
   so whether they cleared each other depended on how many lines the headline
   happened to take — which changes with the font. With the fallback face they
   missed by 4px at 1000px and by ~50 elsewhere; with Instrument Serif, which
   is narrower, the headline loses a line and the plaque rises into the rail.

   The column now reserves the whole stack — plate, rail, and the plaque under
   it — and the buttons absorb any slack, so the plaque is pushed to the foot
   of that reservation rather than floating up to meet the rail. When the text
   is tall enough on its own the reservation is not reached and nothing moves.
   -------------------------------------------------------------------------- */
@media (min-width: 1000px) {
  :root[data-variant="art5"] .hero-inner,
  :root:not([data-variant]) .hero-inner {
    display: flex;
    flex-direction: column;
    /* plate + 1.5rem to the rail + the rail + 1.5rem + the plaque, plus the
       block's own padding, since box-sizing is border-box here. */
    min-height: calc(var(--plate-h) + 24rem);
  }
  :root[data-variant="art5"] .hero-cta,
  :root:not([data-variant]) .hero-cta { margin-bottom: auto; }
}
