/* ==========================================================================
   Intergalva styles
   Block anatomy throughout: section[data-surface][data-layout] > .container > .inner
   Tokens live in tokens.css. No orphan values here.
   ========================================================================== */

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

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

body {
	margin: 0;
	font-family: 'Interphases', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
	font-size: var(--step-0);
	line-height: 1.65;
	color: var(--ink);
	background: var(--paper);
	-webkit-font-smoothing: antialiased;
}

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

/* Browser surfaces carry the theme. Cheapest signal a page was designed. */
::selection {
	background: var(--accent);
	color: var(--on-accent);
}

:root {
	accent-color: var(--accent);
	caret-color: var(--accent);
}

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

/* --- Typography --------------------------------------------------------- */

h1,
h2,
h3,
h4 {
	color: var(--heading);
	font-weight: 700;
	line-height: 1.08;
	letter-spacing: -0.028em;
	text-wrap: balance;
	margin: 0 0 var(--space-3xs);
}

h1 {
	font-size: var(--step-5);
}
h2 {
	font-size: var(--step-4);
}
h3 {
	font-size: var(--step-2);
	line-height: 1.2;
	letter-spacing: -0.018em;
}
h4 {
	font-size: var(--step-1);
	line-height: 1.3;
	letter-spacing: -0.012em;
}

p,
li {
	text-wrap: pretty;
}

p {
	margin: 0 0 var(--space-s);
	max-width: var(--measure);
}

a {
	color: var(--accent);
	text-decoration-thickness: 1px;
	text-underline-offset: 0.18em;
	transition: color var(--dur-fast) ease;
}

a:hover {
	color: var(--heading);
}

strong {
	font-weight: 700;
	color: var(--heading);
}

.eyebrow {
	display: block;
	font-size: var(--step--1);
	font-weight: 700;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	color: var(--accent);
	margin-bottom: var(--space-s);
}

.lede {
	font-size: var(--step-1);
	line-height: 1.5;
	color: var(--ink-2);
	max-width: 58ch;
}

.num {
	font-variant-numeric: tabular-nums;
	font-feature-settings: 'tnum' 1;
}

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

/* --- Section anatomy ---------------------------------------------------- */

section {
	padding-block: var(--space-2xl);
}

section[data-pad='tight'] {
	padding-block: var(--space-xl);
}

section[data-surface='tint'] {
	background: var(--tint);
}

section[data-surface='soft'] {
	background: var(--paper-2);
}

section[data-surface='ink'] {
	background: var(--ink);
	color: rgba(255, 255, 255, 0.76);
}

section[data-surface='ink'] h2,
section[data-surface='ink'] h3 {
	color: #fff;
}

section[data-surface='accent'] {
	position: relative;
	isolation: isolate;
	background: var(--surface-accent);
	color: rgba(255, 255, 255, 0.85);
}

/* The grain sits on the surface, not over the content. Covering the text with
   a multiply layer would darken the white type and soften its edges; behind
   it, the band reads as galvanized and the copy stays crisp. */
section[data-surface='accent']::before {
	content: '';
	position: absolute;
	inset: 0;
	z-index: 0;
	pointer-events: none;
	opacity: 0.18;
	mix-blend-mode: multiply;
	background-image: var(--grain);
	background-size: 180px 180px;
}

section[data-surface='accent'] > * {
	position: relative;
	z-index: 1;
}

section[data-surface='accent'] h2 {
	color: #fff;
}

section[data-surface='accent'] .eyebrow {
	color: rgba(255, 255, 255, 0.85);
}

.container {
	width: min(100% - (var(--gutter) * 2), var(--container));
	margin-inline: auto;
}

.container--narrow {
	width: min(100% - (var(--gutter) * 2), var(--container-narrow));
	margin-inline: auto;
}

/* --- The 12 column grid ------------------------------------------------- */

.grid {
	display: grid;
	grid-template-columns: repeat(12, minmax(0, 1fr));
	column-gap: var(--grid-gap);
	row-gap: var(--space-xl);
}

/* Everything is full width until a column class says otherwise. */
.grid > * {
	grid-column: 1 / -1;
	min-width: 0;
}

@media (min-width: 40rem) {
	.col-md-6 {
		grid-column: span 6;
	}
}

@media (min-width: 64rem) {
	.col-lg-3 {
		grid-column: span 3;
	}
	.col-lg-4 {
		grid-column: span 4;
	}
	.col-lg-5 {
		grid-column: span 5;
	}
	.col-lg-6 {
		grid-column: span 6;
	}
	.col-lg-7 {
		grid-column: span 7;
	}
	.col-lg-8 {
		grid-column: span 8;
	}
}

/* House editorial index header: H2 left, intro right, both on the grid. */
.section-head {
	row-gap: var(--space-s);
	margin-bottom: var(--space-xl);
	padding-bottom: var(--space-m);
	border-bottom: 1px solid var(--rule);
	align-items: end;
}

.section-head > * {
	margin: 0;
}

/* --- Header ------------------------------------------------------------- */

.utility {
	background: var(--egga-blue);
	color: #fff;
	font-size: var(--step--1);
}

[data-theme='event'] .utility {
	background: var(--ink);
}

.utility .inner {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--space-m);
	min-height: 2.5rem;
	flex-wrap: wrap;
}

.utility__meta {
	display: flex;
	align-items: center;
	gap: var(--space-xs);
	color: rgba(255, 255, 255, 0.78);
}

.utility__meta strong {
	color: #fff;
}

.utility__dot {
	color: var(--accent-2);
}

.utility__social {
	display: flex;
	gap: var(--space-s);
}

.utility__social a {
	color: rgba(255, 255, 255, 0.68);
	display: grid;
	place-items: center;
}

.utility__social a:hover {
	color: #fff;
}

.masthead {
	position: sticky;
	top: 0;
	z-index: 50;
	background: rgba(255, 255, 255, 0.95);
	backdrop-filter: blur(12px);
	border-bottom: 1px solid var(--rule);
}

.masthead .inner {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--space-l);
	min-height: var(--masthead-h);
}

.masthead__logo img {
	height: clamp(2.875rem, 2.28rem + 2.98vw, 5rem);
	width: auto;
}

/* --- Navigation --------------------------------------------------------- */

/* Nav items run the full height of the masthead so an open panel starts exactly
   at the masthead's own rule. Anchoring to the item instead left the rule
   cutting across the open panel. */
.nav {
	display: flex;
	align-self: stretch;
	align-items: stretch;
	gap: clamp(0.25rem, -0.2rem + 1.5vw, 1.25rem);
}

.nav__item {
	position: relative;
	display: flex;
	align-items: center;
}

.nav > .btn {
	align-self: center;
}

.nav__link {
	display: inline-flex;
	align-items: center;
	gap: var(--space-3xs);
	padding: var(--space-xs) var(--space-2xs);
	font-size: var(--step-0);
	font-weight: 700;
	color: var(--egga-blue);
	text-decoration: none;
	letter-spacing: -0.012em;
	border-bottom: 2px solid transparent;
}

.nav__item:hover > .nav__link,
.nav__link[aria-current='page'] {
	color: var(--heading);
	border-bottom-color: var(--accent);
}

.nav__link svg {
	transition: transform var(--dur-ui) var(--ease-out);
}

.nav__item:hover > .nav__link svg {
	transform: rotate(180deg);
}

.nav__panel {
	position: absolute;
	top: 100%;
	left: 50%;
	translate: -50% 0;
	background: #fff;
	border: 1px solid var(--rule);
	border-top: 0;
	box-shadow: 0 20px 44px -16px rgba(6, 54, 75, 0.28);
	padding: var(--space-l);
	display: none;
	min-width: max-content;
}

.nav__item:hover .nav__panel,
.nav__item:focus-within .nav__panel {
	display: block;
}

.nav__panel--wide {
	display: none;
	grid-template-columns: repeat(3, minmax(10.5rem, 1fr));
	gap: var(--space-l) var(--space-xl);
}

.nav__item:hover .nav__panel--wide,
.nav__item:focus-within .nav__panel--wide {
	display: grid;
}

.nav__group-title {
	font-size: var(--step--2);
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: 0.14em;
	color: var(--accent);
	margin: 0 0 var(--space-xs);
	padding-bottom: var(--space-2xs);
	border-bottom: 1px solid var(--rule);
}

.nav__list {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	gap: var(--space-3xs);
}

.nav__list a {
	display: block;
	padding: var(--space-3xs) 0;
	color: var(--ink);
	text-decoration: none;
	line-height: 1.35;
}

.nav__list a:hover {
	color: var(--heading);
	text-decoration: underline;
	text-underline-offset: 0.2em;
}

.nav__years {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-3xs);
	margin-top: var(--space-xs);
	max-width: 15rem;
}

.nav__years a {
	padding: var(--space-3xs) var(--space-2xs);
	border: 1px solid var(--rule);
	border-radius: var(--radius);
	font-size: var(--step--1);
	font-weight: 700;
	color: var(--ink-2);
	text-decoration: none;
	font-variant-numeric: tabular-nums;
}

.nav__years a:hover {
	border-color: var(--accent);
	color: var(--heading);
	background: var(--tint);
}

/* --- Burger --------------------------------------------------------------- */
/* Three bars that morph into a cross. Transform and opacity only, and the
   whole thing is one button so the hit area stays a comfortable 44px. */

/* No keyline: the burger is a mark, not a control in a box. Its glyph is
   right aligned to the container edge so it stacks with the disclosure
   chevrons in the drawer below. The 44px box stays for the hit area and
   simply extends leftward. */
.nav-toggle {
	display: none;
	align-items: center;
	justify-content: flex-end;
	margin-left: auto;
	width: 2.75rem;
	height: 2.75rem;
	padding: 0;
	color: var(--egga-blue);
	background: none;
	border: 0;
	cursor: pointer;
	transition: color var(--dur-fast) ease;
}

.nav-toggle:hover {
	color: var(--heading);
}

.burger {
	position: relative;
	display: block;
	width: 1.25rem;
	height: 0.875rem;
}

.burger span {
	position: absolute;
	left: 0;
	right: 0;
	height: 2px;
	border-radius: 1px;
	background: currentColor;
	transition: transform var(--dur-ui) var(--ease-out), opacity 120ms ease;
}

.burger span:nth-child(1) {
	top: 0;
}

.burger span:nth-child(2) {
	top: calc(50% - 1px);
}

.burger span:nth-child(3) {
	bottom: 0;
}

.nav-toggle[aria-expanded='true'] .burger span:nth-child(1) {
	transform: translateY(calc(0.4375rem - 1px)) rotate(45deg);
}

.nav-toggle[aria-expanded='true'] .burger span:nth-child(2) {
	opacity: 0;
	transform: scaleX(0.3);
}

.nav-toggle[aria-expanded='true'] .burger span:nth-child(3) {
	transform: translateY(calc(-0.4375rem + 1px)) rotate(-45deg);
}

/* --- Panel disclosure ----------------------------------------------------- */
/* Desktop opens panels on hover, so this button is mobile only. It sits beside
   the link rather than replacing it, so the section's own page stays reachable
   instead of the tap being swallowed by the accordion. */

.nav__disclosure {
	display: none;
	align-items: center;
	justify-content: flex-end;
	width: 2.75rem;
	height: 2.75rem;
	padding: 0;
	margin-left: auto;
	color: var(--accent);
	background: none;
	border: 0;
	cursor: pointer;
}

.nav__disclosure svg {
	width: 0.875rem;
	height: 0.875rem;
	transition: transform var(--dur-ui) var(--ease-out);
}

.nav__item.is-open > .nav__disclosure svg {
	transform: rotate(180deg);
}

/* --- Buttons ------------------------------------------------------------ */

.btn {
	display: inline-flex;
	align-items: center;
	gap: var(--space-2xs);
	padding: var(--space-xs) var(--space-m);
	font-size: var(--step-0);
	font-weight: 700;
	line-height: 1.2;
	border-radius: var(--radius);
	border: 2px solid transparent;
	text-decoration: none;
	cursor: pointer;
	transition: background var(--dur-fast) ease, color var(--dur-fast) ease,
		border-color var(--dur-fast) ease, transform var(--dur-fast) var(--ease-out);
}

.btn:active {
	transform: scale(0.97);
}

.btn--primary {
	background: var(--accent);
	color: var(--on-accent);
	border-color: var(--accent);
}

.btn--primary:hover {
	background: var(--heading);
	border-color: var(--heading);
	color: #fff;
}

.btn--ghost {
	color: var(--heading);
	border-color: currentColor;
}

.btn--ghost:hover {
	background: var(--heading);
	color: #fff;
}

.btn--light {
	background: #fff;
	color: var(--heading);
	border-color: #fff;
}

.btn--light:hover {
	background: transparent;
	color: #fff;
	border-color: #fff;
}

.btn--on-dark {
	color: #fff;
	border-color: rgba(255, 255, 255, 0.5);
}

.btn--on-dark:hover {
	background: #fff;
	color: var(--heading);
	border-color: #fff;
}

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

.hero {
	position: relative;
	color: #fff;
	background: var(--ink);
	overflow: hidden;
	padding: 0;
}

.hero__media {
	position: absolute;
	inset: 0;
}

.hero__media img {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.hero__scrim {
	position: absolute;
	inset: 0;
	background: linear-gradient(
		98deg,
		rgba(14, 10, 11, 0.93) 0%,
		rgba(14, 10, 11, 0.78) 38%,
		rgba(14, 10, 11, 0.2) 100%
	);
}

/* Display type needs a wide measure. A narrow column here pushed the strapline
   to six lines and shoved the CTA under the fold. */
.hero .inner {
	position: relative;
	padding-block: var(--space-2xl);
	row-gap: var(--space-s);
}

.hero h1 {
	color: #fff;
	font-size: var(--step-5);
	letter-spacing: -0.035em;
	max-width: 26ch;
}

.hero .eyebrow {
	color: var(--accent-2);
}

.hero__lede {
	font-size: var(--step-1);
	line-height: 1.5;
	color: rgba(255, 255, 255, 0.86);
	margin-top: var(--space-m);
	max-width: 44ch;
}

.hero__actions {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-s);
	margin-top: var(--space-l);
}

/* Key facts sit on the hero's lower edge, rules not boxes. */
.hero__facts {
	position: relative;
	background: rgba(14, 10, 11, 0.55);
	backdrop-filter: blur(6px);
}

/* The bar is a <dl>, and its default 1em bottom margin was sitting inside the
   hero rather than collapsing away, because overflow:hidden makes the hero a
   block formatting context. That left the bar floating off the bottom edge. */
.hero__facts .inner {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-m) var(--space-2xl);
	margin-block: 0;
	padding-block: var(--space-m);
	max-width: none;
}

.fact {
	display: grid;
	gap: 2px;
}

.fact dt {
	font-size: var(--step--2);
	text-transform: uppercase;
	letter-spacing: 0.16em;
	color: rgba(255, 255, 255, 0.6);
}

.fact dd {
	margin: 0;
	font-size: var(--step-1);
	font-weight: 700;
	color: #fff;
	font-variant-numeric: tabular-nums;
}

/* --- Page head ---------------------------------------------------------- */

.pagehead {
	padding-block: var(--space-xl) var(--space-l);
	border-bottom: 1px solid var(--rule);
}

.pagehead h1 {
	max-width: 18ch;
	font-size: var(--step-4);
}

.pagehead .lede {
	margin-top: var(--space-m);
}

.breadcrumb {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--space-2xs);
	font-size: var(--step--1);
	color: var(--ink-3);
	margin-bottom: var(--space-m);
}

.breadcrumb a {
	color: var(--ink-3);
	text-decoration: none;
}

.breadcrumb a:hover {
	color: var(--heading);
	text-decoration: underline;
}

.breadcrumb span[aria-hidden] {
	color: var(--rule);
}

/* --- Icon index --------------------------------------------------------- */
/* The client's own line-icon set. Hairline grid, not cards. */

.icon-index {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(16rem, 100%), 1fr));
	gap: 1px;
	background: var(--rule);
	border: 1px solid var(--rule);
}

.icon-index__item {
	/* Translucent so a surface behind the grid, the sunrise on the homepage,
	   reads through the tiles instead of being boxed out by them. */
	background: color-mix(in srgb, var(--paper) 76%, transparent);
	backdrop-filter: blur(2px);
	padding: var(--space-l) var(--space-m) var(--space-m);
	display: flex;
	flex-direction: column;
	gap: var(--space-xs);
	transition: background var(--dur-ui) ease;
}

.icon-index__item:hover {
	background: color-mix(in srgb, var(--paper) 92%, transparent);
}

.icon-index__icon {
	width: clamp(2.75rem, 2.2rem + 2vw, 3.5rem);
	height: auto;
	aspect-ratio: 1;
	color: var(--accent);
}

.icon-index__item h3 {
	font-size: var(--step-1);
	margin: 0;
}

.icon-index__item ul {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	gap: var(--space-3xs);
}

.icon-index__item a {
	color: var(--ink-2);
	text-decoration: none;
	font-size: var(--step-0);
}

.icon-index__item a:hover {
	color: var(--heading);
	text-decoration: underline;
	text-underline-offset: 0.2em;
}

/* --- Split -------------------------------------------------------------- */

.split {
	align-items: start;
}

.split__media img {
	width: 100%;
	border-radius: var(--radius);
}

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

/* --- Lists -------------------------------------------------------------- */

.ticklist {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	gap: var(--space-xs);
	max-width: var(--measure);
}

.ticklist li {
	position: relative;
	padding-left: var(--space-m);
	color: var(--ink-2);
}

.ticklist li::before {
	content: '';
	position: absolute;
	left: 0;
	top: 0.62em;
	width: 0.4375rem;
	height: 0.4375rem;
	background: var(--accent);
	border-radius: 50%;
}

/* --- Cards -------------------------------------------------------------- */

.cards {
	row-gap: var(--space-l);
}

.card {
	background: none;
	display: flex;
	flex-direction: column;
	gap: var(--space-2xs);
	text-decoration: none;
}

.card__media {
	overflow: hidden;
	border-radius: var(--radius);
	margin-bottom: var(--space-xs);
	background: var(--paper-2);
}

.card__media img {
	width: 100%;
	aspect-ratio: 3 / 2;
	object-fit: cover;
	transition: transform 520ms var(--ease-out);
}

@media (hover: hover) and (pointer: fine) {
	.card:hover .card__media img {
		transform: scale(1.03);
	}

	.card:hover h3 {
		text-decoration: underline;
		text-underline-offset: 0.16em;
	}
}

.card__date {
	font-size: var(--step--1);
	font-weight: 700;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: var(--accent);
	font-variant-numeric: tabular-nums;
}

.card h3 {
	font-size: var(--step-1);
}

.card p {
	color: var(--ink-2);
	margin: 0;
}

/* --- Tables ------------------------------------------------------------- */

.table-wrap {
	overflow-x: auto;
	margin-bottom: var(--space-m);
}

table {
	width: 100%;
	border-collapse: collapse;
	font-variant-numeric: tabular-nums;
}

th,
td {
	text-align: left;
	padding: var(--space-xs) var(--space-s);
	border-bottom: 1px solid var(--rule);
}

thead th {
	font-size: var(--step--1);
	text-transform: uppercase;
	letter-spacing: 0.1em;
	color: #fff;
	background: var(--heading);
	border-bottom: none;
}

tbody tr:nth-child(even) {
	background: var(--tint);
}

td + td,
th + th {
	text-align: right;
}

/* --- Year grid ---------------------------------------------------------- */

.yeargrid {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
	gap: var(--space-2xs);
	list-style: none;
	margin: 0;
	padding: 0;
}

.yeargrid a {
	display: flex;
	align-items: baseline;
	gap: var(--space-2xs);
	padding: var(--space-xs) var(--space-s);
	border: 1px solid var(--rule);
	border-radius: var(--radius);
	text-decoration: none;
	color: var(--ink);
	transition: border-color var(--dur-fast) ease, background var(--dur-fast) ease;
}

.yeargrid a:hover {
	border-color: var(--accent);
	background: var(--tint);
}

.yeargrid b {
	font-variant-numeric: tabular-nums;
	color: var(--heading);
}

.yeargrid span {
	color: var(--ink-3);
	font-size: var(--step--1);
}

/* --- Callout ------------------------------------------------------------ */

.callout {
	position: relative;
	overflow: hidden;
	border: 1px solid var(--rule);
	border-top: 0;
	background: var(--tint);
	padding: calc(var(--space-m) + 3px) var(--space-l) var(--space-m);
	border-radius: var(--radius);
}

.callout::before {
	content: '';
	position: absolute;
	inset: 0 0 auto 0;
	height: 3px;
	background: var(--brand-ramp);
}

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

.callout__label {
	font-size: var(--step--1);
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: 0.14em;
	color: var(--accent);
	display: block;
	margin-bottom: var(--space-2xs);
}

/* ==========================================================================
   Programme
   Day tabs, track filters, search, then time-rowed sessions. The row carries
   a gated download for the paper where one exists.
   ========================================================================== */

.programme__controls {
	display: grid;
	gap: var(--space-m);
	padding-bottom: var(--space-m);
	margin-bottom: var(--space-l);
	border-bottom: 1px solid var(--rule);
}

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

.daytab {
	display: grid;
	gap: 1px;
	padding: var(--space-xs) var(--space-m);
	background: none;
	border: 1px solid var(--rule);
	border-radius: var(--radius);
	font: inherit;
	text-align: left;
	color: var(--ink-2);
	cursor: pointer;
	transition: border-color var(--dur-fast) ease, background var(--dur-fast) ease,
		color var(--dur-fast) ease;
}

.daytab b {
	font-size: var(--step-0);
	color: var(--heading);
	font-variant-numeric: tabular-nums;
}

.daytab span {
	font-size: var(--step--2);
	text-transform: uppercase;
	letter-spacing: 0.12em;
	color: var(--ink-3);
}

.daytab:hover {
	border-color: var(--accent);
}

.daytab[aria-selected='true'] {
	background: var(--heading);
	border-color: var(--heading);
}

.daytab[aria-selected='true'] b,
.daytab[aria-selected='true'] span {
	color: #fff;
}

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

.tracks {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-3xs);
	align-items: center;
}

.track {
	padding: var(--space-3xs) var(--space-s);
	border: 1px solid var(--rule);
	border-radius: 999px;
	background: none;
	font: inherit;
	font-size: var(--step--1);
	color: var(--ink-2);
	cursor: pointer;
	transition: border-color var(--dur-fast) ease, background var(--dur-fast) ease,
		color var(--dur-fast) ease;
}

.track:hover {
	border-color: var(--accent);
	color: var(--heading);
}

.track[aria-pressed='true'] {
	background: var(--accent);
	border-color: var(--accent);
	color: var(--on-accent);
}

.search {
	position: relative;
	flex: 0 1 18rem;
}

.search input {
	width: 100%;
	font: inherit;
	font-size: var(--step-0);
	padding: var(--space-xs) var(--space-s) var(--space-xs) 2.4rem;
	border: 1px solid var(--rule);
	border-radius: var(--radius);
	background: var(--paper);
	color: var(--ink);
}

.search input::placeholder {
	color: var(--ink-3);
}

.search svg {
	position: absolute;
	left: var(--space-xs);
	top: 50%;
	translate: 0 -50%;
	width: 1rem;
	height: 1rem;
	color: var(--ink-3);
	pointer-events: none;
}

.sessionblock {
	margin-bottom: var(--space-xl);
}

.sessionblock__head {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: var(--space-xs) var(--space-m);
	padding-bottom: var(--space-2xs);
	margin-bottom: var(--space-s);
	border-bottom: 2px solid var(--accent);
}

.sessionblock__n {
	font-size: var(--step--1);
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: 0.16em;
	color: var(--accent);
}

.sessionblock__head h3 {
	font-size: var(--step-2);
	margin: 0;
	flex: 1 1 20rem;
}

.sessionblock__room {
	font-size: var(--step--1);
	color: var(--ink-3);
}

.session {
	display: grid;
	gap: var(--space-2xs) var(--space-m);
	padding-block: var(--space-m);
	border-bottom: 1px solid var(--rule);
}

@media (min-width: 46rem) {
	.session {
		grid-template-columns: 7rem minmax(0, 1fr) auto;
		align-items: start;
	}
}

.session__time {
	display: grid;
	gap: 1px;
}

.session__time b {
	font-size: var(--step-1);
	color: var(--heading);
	font-variant-numeric: tabular-nums;
	letter-spacing: -0.01em;
}

.session__time span {
	font-size: var(--step--2);
	text-transform: uppercase;
	letter-spacing: 0.12em;
	color: var(--ink-3);
}

.session__title {
	font-size: var(--step-1);
	color: var(--ink);
	margin: 0 0 var(--space-3xs);
	letter-spacing: -0.012em;
	line-height: 1.3;
}

.session__people {
	margin: 0;
	color: var(--ink-2);
	font-size: var(--step-0);
	max-width: 60ch;
}

.session__people b {
	color: var(--heading);
	font-weight: 700;
}

.session__tag {
	display: inline-block;
	margin-top: var(--space-2xs);
	padding: 2px var(--space-2xs);
	border: 1px solid var(--rule);
	border-radius: 999px;
	font-size: var(--step--2);
	text-transform: uppercase;
	letter-spacing: 0.1em;
	color: var(--ink-3);
}

.session__doc {
	display: inline-flex;
	align-items: center;
	gap: var(--space-2xs);
	padding: var(--space-2xs) var(--space-s);
	border: 1px solid var(--rule);
	border-radius: var(--radius);
	font-size: var(--step--1);
	font-weight: 700;
	color: var(--heading);
	text-decoration: none;
	white-space: nowrap;
	transition: border-color var(--dur-fast) ease, background var(--dur-fast) ease;
}

.session__doc:hover {
	border-color: var(--accent);
	background: var(--tint);
}

.session__doc svg {
	width: 0.875rem;
	height: 0.875rem;
	flex: none;
}

.session__doc[data-locked]::after {
	content: 'Delegates';
	font-weight: 400;
	font-size: var(--step--2);
	text-transform: uppercase;
	letter-spacing: 0.1em;
	color: var(--ink-3);
}

.session[hidden] {
	display: none;
}

.programme__empty {
	padding: var(--space-xl) 0;
	color: var(--ink-3);
	text-align: center;
}

.programme__count {
	font-size: var(--step--1);
	color: var(--ink-3);
	font-variant-numeric: tabular-nums;
}

/* --- Sponsor marquee ---------------------------------------------------- */
/* Duplicated track translated -50% for a seamless loop. Linear, because
   constant motion should not ease. Pauses on hover, stops outright under
   reduced motion. One marquee per page. */

.marquee {
	overflow: hidden;
	mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
	-webkit-mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
}

.marquee__track {
	display: flex;
	width: max-content;
	gap: clamp(2.5rem, 1.8rem + 3.5vw, 5rem);
	align-items: center;
	animation: marquee-scroll 46s linear infinite;
}

@media (hover: hover) and (pointer: fine) {
	.marquee:hover .marquee__track {
		animation-play-state: paused;
	}
}

.marquee img {
	height: clamp(3rem, 2.5rem + 2.25vw, 4.25rem);
	width: auto;
	opacity: 0.55;
	filter: grayscale(1);
	transition: opacity var(--dur-ui) ease, filter var(--dur-ui) ease;
}

@media (hover: hover) and (pointer: fine) {
	.marquee img:hover {
		opacity: 1;
		filter: none;
	}
}

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

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

/* Organiser and host marks sit beside the Intergalva wordmark. */
.footer__brand img {
	height: clamp(2.875rem, 2.4rem + 2.35vw, 4.25rem);
	width: auto;
	margin-bottom: var(--space-s);
}

.footer__orgs {
	display: flex;
	flex-wrap: wrap;
	align-items: flex-end;
	gap: var(--space-m) var(--space-xl);
	margin-top: var(--space-l);
}

.footer__orgs figure {
	margin: 0;
	display: grid;
	gap: var(--space-3xs);
}

.footer__orgs img {
	height: clamp(1.75rem, 1.55rem + 1vw, 2.25rem);
	width: auto;
	margin: 0;
	opacity: 0.9;
}

.footer__orgs figcaption {
	font-size: var(--step--3);
	text-transform: uppercase;
	letter-spacing: 0.16em;
	color: rgba(255, 255, 255, 0.45);
	margin-bottom: var(--space-3xs);
}

.footer {
	background: var(--ink);
	color: rgba(255, 255, 255, 0.7);
	padding-block: var(--space-xl) var(--space-l);
}

.footer__grid {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
	gap: var(--space-l) var(--space-m);
	padding-bottom: var(--space-l);
	border-bottom: 1px solid rgba(255, 255, 255, 0.14);
}

.footer h4 {
	color: #fff;
	font-size: var(--step--2);
	text-transform: uppercase;
	letter-spacing: 0.14em;
	margin-bottom: var(--space-s);
}

.footer ul {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	gap: var(--space-2xs);
}

.footer a {
	color: rgba(255, 255, 255, 0.7);
	text-decoration: none;
}

.footer a:hover {
	color: #fff;
	text-decoration: underline;
}

.footer__legal {
	display: flex;
	flex-wrap: wrap;
	justify-content: space-between;
	gap: var(--space-s);
	padding-top: var(--space-m);
	font-size: var(--step--1);
	color: rgba(255, 255, 255, 0.52);
}

/* --- Newsletter dialog --------------------------------------------------- */
/* A native <dialog>, so focus trapping, Escape and page inertness come from the
   platform rather than script. Centred, slides up on entry, and shown once: a
   dismissal is remembered so it cannot nag. */

.signup {
	width: min(100% - (var(--gutter) * 2), 34rem);
	padding: 0;
	border: 0;
	border-radius: var(--radius);
	background: var(--paper);
	color: var(--ink);
	box-shadow: 0 32px 80px -28px rgba(6, 54, 75, 0.5);
	opacity: 0;
	transform: translateY(20px);
	transition: opacity var(--dur-panel) var(--ease-out),
		transform var(--dur-panel) var(--ease-out);
}

/* Toggled a frame after showModal(). Doing the entry with @starting-style plus
   a discrete display/overlay transition wedged the dialog at opacity 0, because
   display on a <dialog> is owned by the UA stylesheet. A class is deterministic. */
.signup.is-in {
	opacity: 1;
	transform: none;
}

.signup::backdrop {
	background: rgba(10, 7, 8, 0.55);
	opacity: 0;
	transition: opacity var(--dur-panel) var(--ease-out);
}

.signup.is-in::backdrop {
	opacity: 1;
}

.signup__body {
	position: relative;
	padding: calc(var(--space-l) + 3px) var(--space-l) var(--space-l);
}

.signup__body::before {
	content: '';
	position: absolute;
	inset: 0 0 auto 0;
	height: 3px;
	background: var(--brand-ramp);
}

.signup__body h2 {
	font-size: var(--step-3);
	margin-bottom: var(--space-s);
}

.signup__body p {
	color: var(--ink-2);
	margin-bottom: var(--space-m);
	max-width: none;
}

.signup__form {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-2xs);
}

.signup__form input {
	flex: 1 1 13rem;
	min-width: 0;
	font: inherit;
	font-size: var(--step-0);
	padding: var(--space-xs) var(--space-s);
	border: 1px solid var(--rule);
	border-radius: var(--radius);
	background: var(--paper);
	color: var(--ink);
}

.signup__form input::placeholder {
	color: var(--ink-3);
}

.signup__close {
	position: absolute;
	top: var(--space-s);
	right: var(--space-s);
	display: grid;
	place-items: center;
	width: 2rem;
	height: 2rem;
	padding: 0;
	font: inherit;
	font-size: var(--step-1);
	line-height: 1;
	color: var(--ink-3);
	background: none;
	border: 1px solid transparent;
	border-radius: var(--radius);
	cursor: pointer;
	transition: color var(--dur-fast) ease, border-color var(--dur-fast) ease;
}

.signup__close:hover {
	color: var(--heading);
	border-color: var(--rule);
}

.signup__dismiss {
	margin-top: var(--space-m);
	padding: 0;
	font: inherit;
	font-size: var(--step--1);
	color: var(--ink-3);
	background: none;
	border: 0;
	border-bottom: 1px solid var(--rule);
	cursor: pointer;
}

.signup__dismiss:hover {
	color: var(--heading);
	border-bottom-color: var(--accent);
}
/* --- Scroll reveal ------------------------------------------------------ */

[data-reveal] {
	opacity: 0;
	transform: translateY(14px);
	transition: opacity 620ms var(--ease-out), transform 620ms var(--ease-out);
}

[data-reveal].is-in {
	opacity: 1;
	transform: none;
}

/* --- Review-only scaffolding, not part of the theme --------------------- */

.reviewbar {
	background: #0b0709;
	color: #fff;
	font-size: 13px;
	padding: 8px 0;
}

.reviewbar .inner {
	display: flex;
	flex-wrap: wrap;
	gap: 14px;
	align-items: center;
	justify-content: center;
}

.reviewbar a {
	color: rgba(255, 255, 255, 0.6);
	text-decoration: none;
	padding: 3px 10px;
	border-radius: 3px;
}

.reviewbar a:hover {
	color: #fff;
}

.reviewbar a[aria-current] {
	background: rgba(255, 255, 255, 0.15);
	color: #fff;
}

/* --- Mobile nav --------------------------------------------------------- */

@media (max-width: 62rem) {
	.nav-toggle {
		display: flex;
	}

	.nav {
		display: none;
		position: absolute;
		top: 100%;
		left: 0;
		right: 0;
		flex-direction: column;
		align-items: stretch;
		gap: 0;
		background: #fff;
		border-top: 1px solid var(--rule);
		border-bottom: 2px solid var(--accent);
		padding: var(--space-2xs) var(--gutter) var(--space-l);
		max-height: calc(100dvh - 100%);
		overflow-y: auto;
		box-shadow: 0 20px 40px -16px rgba(6, 54, 75, 0.24);
	}

	.nav.is-open {
		display: flex;
	}

	.nav__item {
		position: static;
	}

	.nav__link {
		width: 100%;
		justify-content: space-between;
		padding-block: var(--space-s);
		border-bottom: 1px solid var(--rule);
	}

	.nav__item:hover > .nav__link {
		border-bottom-color: var(--rule);
	}

	.nav__link svg {
		display: none;
	}

	/* Panels are closed until their disclosure is pressed. Hover means nothing
	   on touch, and leaving all three open put 32 links and 1455px of content
	   into a 738px drawer. */
	.nav__panel,
	.nav__panel--wide,
	.nav__item:hover .nav__panel,
	.nav__item:hover .nav__panel--wide,
	.nav__item:focus-within .nav__panel,
	.nav__item:focus-within .nav__panel--wide {
		position: static;
		translate: none;
		display: none;
		grid-template-columns: 1fr;
		gap: var(--space-m);
		min-width: 0;
		padding: 0 0 var(--space-m);
		border: 0;
		box-shadow: none;
		background: none;
	}

	.nav__item.is-open > .nav__panel,
	.nav__item.is-open > .nav__panel--wide {
		display: grid;
	}

	.nav__item {
		flex-wrap: wrap;
	}

	.nav__disclosure {
		display: flex;
	}

	/* The link no longer stretches full width: the disclosure sits beside it. */
	.nav__link {
		width: auto;
		flex: 1 1 auto;
		border-bottom: 0;
	}

	.nav__item {
		border-bottom: 1px solid var(--rule);
	}

	.nav__panel {
		flex-basis: 100%;
	}

	.nav__years {
		max-width: none;
	}

	.nav .btn {
		margin-top: var(--space-m);
		justify-content: center;
	}
}

@media (prefers-reduced-motion: reduce) {
	[data-reveal] {
		transform: none;
		transition: opacity 300ms ease;
	}

	/* Stop the loop outright. Collapsing an infinite animation to 0.01ms would
	   flicker rather than settle, so hand the row to the user to scroll. */
	.marquee__track {
		animation: none !important;
		transform: none;
	}

	.marquee {
		overflow-x: auto;
	}

	.gallery--carousel {
		scroll-behavior: auto;
	}

	/* Reduced motion keeps the fade, drops the travel. */
	.signup,
	.signup.is-in {
		transform: none;
	}

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

/* ==========================================================================
   Content blocks
   The interior-page library. Every block is one <section data-block>, owns its
   own container chain, and takes a width variant, so the build stage maps each
   one to an ACF block with a shared width field.
   ========================================================================== */

/* --- Width variants ----------------------------------------------------- */

section[data-width='narrow'] > .container {
	width: min(100% - (var(--gutter) * 2), var(--container-narrow));
}

section[data-width='wide'] > .container {
	width: min(100% - (var(--gutter) * 2), var(--container));
}

/* --- content: rich text ------------------------------------------------- */

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

.content h2,
.content h3 {
	margin-top: var(--space-l);
	margin-bottom: var(--space-s);
}

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

.content ul,
.content ol {
	max-width: var(--measure);
	padding-left: var(--space-m);
	margin-bottom: var(--space-s);
}

.content li {
	margin-bottom: var(--space-3xs);
}

/* --- columns: two columns of text --------------------------------------- */

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

.columns__col h3 {
	margin-bottom: var(--space-s);
}

/* --- media-columns: text beside an image -------------------------------- */
/* Reversing is a class on the block, never a hand edit to the markup order,
   so the reading order stays correct when the columns stack. */

.media-columns {
	align-items: center;
}

.media-columns--reverse .media-columns__media {
	order: -1;
}

@media (max-width: 63.999rem) {
	.media-columns--reverse .media-columns__media {
		order: 0;
	}
}

.media-columns__media img {
	width: 100%;
	border-radius: var(--radius);
}

.media-columns__body > :last-child {
	margin-bottom: 0;
}

.media-columns figcaption {
	margin-top: var(--space-2xs);
	font-size: var(--step--1);
	color: var(--ink-3);
}

/* --- table -------------------------------------------------------------- */

.table {
	width: 100%;
	overflow-x: auto;
	border: 1px solid var(--rule);
	border-radius: var(--radius);
}

.table table {
	margin: 0;
	min-width: 34rem;
}

.table th,
.table td {
	white-space: nowrap;
}

.table th[scope='row'] {
	white-space: normal;
	min-width: 14rem;
	font-weight: 700;
	color: var(--heading);
}

.table tbody tr:last-child th,
.table tbody tr:last-child td {
	border-bottom: 0;
}

.table__note {
	margin-top: var(--space-s);
	font-size: var(--step--1);
	color: var(--ink-3);
}

/* --- faq ---------------------------------------------------------------- */

.faq {
	border-top: 1px solid var(--rule);
}

.faq__item {
	border-bottom: 1px solid var(--rule);
}

.faq__q {
	display: flex;
	align-items: flex-start;
	justify-content: space-between;
	gap: var(--space-m);
	padding-block: var(--space-m);
	font-size: var(--step-1);
	font-weight: 700;
	line-height: 1.3;
	letter-spacing: -0.012em;
	color: var(--heading);
	cursor: pointer;
	list-style: none;
}

.faq__q::-webkit-details-marker {
	display: none;
}

.faq__q:hover {
	color: var(--accent);
}

.faq__marker {
	flex: none;
	width: 1.25rem;
	height: 1.25rem;
	margin-top: 0.2em;
	color: var(--accent);
	transition: transform var(--dur-ui) var(--ease-out);
}

.faq__item[open] .faq__marker {
	transform: rotate(45deg);
}

.faq__a {
	padding-bottom: var(--space-m);
}

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

/* Animate the open and close where the browser can size it. Everything else
   still opens, just without the travel. */
@supports (interpolate-size: allow-keywords) {
	:root {
		interpolate-size: allow-keywords;
	}

	.faq__item::details-content {
		block-size: 0;
		overflow: hidden;
		transition: block-size var(--dur-panel) var(--ease-out),
			content-visibility var(--dur-panel) allow-discrete;
	}

	.faq__item[open]::details-content {
		block-size: auto;
	}
}

/* --- Block label, review only ------------------------------------------- */

.blocklabel {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: var(--space-2xs) var(--space-s);
	margin-bottom: var(--space-m);
	padding-bottom: var(--space-2xs);
	border-bottom: 1px dashed var(--rule);
	font-size: var(--step--2);
	text-transform: uppercase;
	letter-spacing: 0.14em;
	color: var(--ink-3);
}

.blocklabel code {
	font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
	font-size: var(--step--2);
	letter-spacing: 0;
	text-transform: none;
	color: var(--accent);
}


/* --- content-sidebar ---------------------------------------------------- */
/* Main column on 8, sidebar on 4. The sidebar sticks below the masthead on
   desktop and drops underneath the content when the grid stacks. */

.content-sidebar__main > :last-child {
	margin-bottom: 0;
}

.sidebar {
	display: grid;
	gap: var(--space-l);
	align-content: start;
}

@media (min-width: 64rem) {
	.sidebar {
		position: sticky;
		top: calc(var(--masthead-h) + var(--space-m));
		/* A grid item stretches to the row height by default, which leaves a
		   sticky element no room to travel: it simply scrolls away. */
		align-self: start;
	}
}

.sidebar__panel {
	padding-top: var(--space-s);
	border-top: 3px solid transparent;
	border-image: var(--brand-ramp) 1;
}

.sidebar__panel h3 {
	font-size: var(--step--1);
	text-transform: uppercase;
	letter-spacing: 0.14em;
	color: var(--ink-3);
	margin-bottom: var(--space-s);
}

.sidebar__news {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
}

.sidebar__news li + li {
	margin-top: var(--space-s);
	padding-top: var(--space-s);
	border-top: 1px solid var(--rule);
}

.sidebar__news time {
	display: block;
	font-size: var(--step--2);
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: 0.12em;
	color: var(--accent);
	font-variant-numeric: tabular-nums;
	margin-bottom: 2px;
}

.sidebar__news a {
	color: var(--ink);
	text-decoration: none;
	font-weight: 700;
	line-height: 1.3;
	letter-spacing: -0.012em;
}

.sidebar__news a:hover {
	color: var(--heading);
	text-decoration: underline;
	text-underline-offset: 0.18em;
}

.sidebar__links {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
}

.sidebar__links a {
	display: block;
	padding-block: var(--space-2xs);
	color: var(--ink-2);
	text-decoration: none;
	border-bottom: 1px solid var(--rule);
}

.sidebar__links li:first-child a {
	padding-top: 0;
}

.sidebar__links a:hover {
	color: var(--heading);
}

.sidebar__links a[aria-current='page'] {
	color: var(--heading);
	font-weight: 700;
}

.sidebar__cta {
	margin-top: var(--space-2xs);
}

/* --- winners-grid ------------------------------------------------------- */
/* Image led, unlike the date led news cards. Awards are looked at first and
   read second, so the picture carries the row. */

.winners {
	row-gap: var(--space-xl);
}

.winner {
	display: flex;
	flex-direction: column;
	gap: var(--space-2xs);
	text-decoration: none;
}

.winner__media {
	overflow: hidden;
	border-radius: var(--radius);
	background: var(--paper-2);
	margin-bottom: var(--space-2xs);
}

.winner__media img {
	width: 100%;
	aspect-ratio: 4 / 3;
	object-fit: cover;
	transition: transform 520ms var(--ease-out);
}

@media (hover: hover) and (pointer: fine) {
	.winner:hover .winner__media img {
		transform: scale(1.03);
	}

	.winner:hover h3 {
		text-decoration: underline;
		text-underline-offset: 0.16em;
	}
}

.winner__cat {
	font-size: var(--step--2);
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: 0.12em;
	color: var(--accent);
}

.winner h3 {
	font-size: var(--step-1);
	margin: 0;
}

.winner__loc {
	margin: 0;
	color: var(--ink-3);
	font-size: var(--step-0);
}

.winner[hidden] {
	display: none;
}

/* --- gallery ------------------------------------------------------------ */

.gallery {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(14rem, 100%), 1fr));
	gap: var(--space-2xs);
	margin: 0;
	padding: 0;
	list-style: none;
}

.gallery li {
	margin: 0;
}

.gallery img {
	width: 100%;
	aspect-ratio: 3 / 2;
	object-fit: cover;
	border-radius: var(--radius);
	background: var(--paper-2);
}

/* The opening frame earns the full width. */
.gallery--lead li:first-child {
	grid-column: 1 / -1;
}

.gallery--lead li:first-child img {
	aspect-ratio: 16 / 9;
}

/* --- detail-list -------------------------------------------------------- */

.detail-list {
	margin: 0;
	display: grid;
	gap: 0;
}

.detail-list__row {
	display: grid;
	gap: var(--space-3xs) var(--space-m);
	padding-block: var(--space-xs);
	border-bottom: 1px solid var(--rule);
}

@media (min-width: 40rem) {
	.detail-list__row {
		grid-template-columns: minmax(8rem, 1fr) minmax(0, 2fr);
		align-items: baseline;
	}
}

.detail-list dt {
	font-size: var(--step--1);
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: 0.12em;
	color: var(--ink-3);
}

.detail-list dd {
	margin: 0;
	color: var(--heading);
	font-weight: 700;
}

/* --- gallery, carousel layout ------------------------------------------- */
/* Scroll snap with buttons rather than a drag scroller: no pointer capture,
   so a click on an image is never swallowed, and it is keyboard operable. */

.carousel {
	position: relative;
}

.gallery--carousel {
	display: flex;
	grid-template-columns: none;
	overflow-x: auto;
	scroll-snap-type: x mandatory;
	scroll-behavior: smooth;
	gap: var(--space-2xs);
	scrollbar-width: none;
	padding-bottom: var(--space-3xs);
}

.gallery--carousel::-webkit-scrollbar {
	display: none;
}

.gallery--carousel li {
	flex: 0 0 clamp(15rem, 58vw, 32rem);
	scroll-snap-align: start;
}

.gallery--carousel li:first-child img {
	aspect-ratio: 3 / 2;
}

.carousel__controls {
	display: flex;
	align-items: center;
	justify-content: flex-end;
	gap: var(--space-2xs);
	margin-top: var(--space-s);
}

.carousel__btn {
	display: grid;
	place-items: center;
	width: 2.75rem;
	height: 2.75rem;
	padding: 0;
	color: var(--heading);
	background: none;
	border: 1px solid var(--rule);
	border-radius: var(--radius);
	cursor: pointer;
	transition: border-color var(--dur-fast) ease, background var(--dur-fast) ease,
		opacity var(--dur-fast) ease;
}

.carousel__btn:hover:not([disabled]) {
	border-color: var(--accent);
	background: var(--tint);
}

.carousel__btn[disabled] {
	opacity: 0.3;
	cursor: default;
}

.carousel__btn svg {
	width: 1.125rem;
	height: 1.125rem;
}

/* --- content-details ---------------------------------------------------- */

.content-details__body > :last-child {
	margin-bottom: 0;
}

.content-details .detail-list {
	margin-top: var(--space-2xs);
}

/* --- award-header ------------------------------------------------------- */
/* Title and place on the left, award and year opposite. */

.award-header {
	row-gap: var(--space-m);
	align-items: end;
	padding-bottom: var(--space-m);
	border-bottom: 1px solid var(--rule);
}

.award-header h2 {
	margin-bottom: var(--space-3xs);
}

.award-header__loc {
	margin: 0;
	font-size: var(--step-1);
	color: var(--ink-3);
}

.award-header__meta {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-m) var(--space-l);
}

@media (min-width: 64rem) {
	.award-header__meta {
		justify-content: flex-end;
		text-align: right;
	}
}

.award-header__meta div {
	display: grid;
	gap: 2px;
}

.award-header__meta dt {
	font-size: var(--step--2);
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: 0.14em;
	color: var(--ink-3);
}

.award-header__meta dd {
	margin: 0;
	font-weight: 700;
	color: var(--heading);
	font-variant-numeric: tabular-nums;
}

/* --- entry-nav ---------------------------------------------------------- */

.entry-nav {
	display: grid;
	gap: var(--space-2xs);
	border-top: 1px solid var(--rule);
	padding-top: var(--space-m);
}

@media (min-width: 46rem) {
	.entry-nav {
		grid-template-columns: 1fr 1fr;
		gap: var(--space-m);
	}
}

.entry-nav__link {
	display: flex;
	align-items: center;
	gap: var(--space-s);
	padding: var(--space-s) 0;
	text-decoration: none;
	color: var(--ink);
}

.entry-nav__link--next {
	flex-direction: row-reverse;
	text-align: right;
}

.entry-nav__link svg {
	flex: none;
	width: 1.25rem;
	height: 1.25rem;
	color: var(--accent);
	transition: transform var(--dur-ui) var(--ease-out);
}

@media (hover: hover) and (pointer: fine) {
	.entry-nav__link--prev:hover svg {
		transform: translateX(-4px);
	}

	.entry-nav__link--next:hover svg {
		transform: translateX(4px);
	}
}

.entry-nav__label {
	display: block;
	font-size: var(--step--2);
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: 0.14em;
	color: var(--ink-3);
	margin-bottom: 2px;
}

.entry-nav__title {
	font-weight: 700;
	color: var(--heading);
	line-height: 1.25;
	letter-spacing: -0.012em;
}

.entry-nav__link:hover .entry-nav__title {
	text-decoration: underline;
	text-underline-offset: 0.18em;
}

.entry-nav__link[aria-disabled='true'] {
	opacity: 0.35;
	pointer-events: none;
}

/* --- citation link ------------------------------------------------------ */

.citation-link {
	margin-top: var(--space-m);
}

/* ==========================================================================
   Málaga motif hero
   ATEG's exhibition scheme puts the artwork left and the mark and strapline
   right, flat, on a warm ground. That suits a three colour identity far better
   than a photograph behind a dark scrim, and it needs no overlay to pass
   contrast. Content sits first in the markup so the headline is read first
   when the grid stacks; the art is moved left by order on desktop only.
   ========================================================================== */

.hero--motif {
	background-color: var(--sand);
	color: var(--ink);
}

/* ATEG's artwork is a full bleed scene with the cathedral bottom left and open
   ground to the right, so the type sits in that space rather than in a column
   beside it. Below the breakpoint the art is dropped: at phone widths a cover
   crop puts the cathedral behind the headline. */
@media (min-width: 64rem) {
	.hero--motif {
		background-image: var(--hero-art);
		/* Sized to the hero's height, not cover or contain. Cover crops to
		   whatever aspect the hero happens to be, which blew the tower up at
		   1024 and cut the spire off at 1920. Contain scaled the scene to the
		   full viewport width and pushed it under the fold. Fitting the height
		   and anchoring left keeps the cathedral whole at every width and
		   loses only the empty ground on its right, which is where the type
		   sits anyway. */
		background-size: auto 100%;
		background-position: left bottom;
		background-repeat: no-repeat;
		min-height: min(40rem, 78vh);
		display: flex;
		flex-direction: column;
		justify-content: center;
	}

	.hero--motif .hero__content {
		grid-column: 7 / -1;
	}
}

.hero--motif .inner {
	align-items: center;
	padding-block: var(--space-2xl);
	max-width: none;
}

.hero--motif .hero__content {
	max-width: none;
}

/* Half the grid is a much shorter measure than a full bleed hero, so the
   display size steps down to hold the strapline to two lines. */
.hero--motif h1 {
	color: var(--heading);
	font-size: var(--step-4);
	max-width: 22ch;
}

.hero--motif .eyebrow {
	color: var(--accent);
}

.hero--motif .hero__lede {
	color: var(--ink-2);
}

/* Facts bar reads dark on the warm ground rather than light on a photograph. */
.hero--motif .hero__facts {
	background: var(--sand-deep);
	backdrop-filter: none;
	/* The hero is a centred flex column, so without this the bar floats with
	   the content group and leaves slack beneath it whenever the hero is
	   taller than its contents. Auto margin pins it to the bottom edge. */
	margin-top: auto;
}

/* Equal specificity with .hero--motif .inner meant the motif rule, written
   later, pushed 104px of padding onto this bar. Scoped to beat it. */
.hero--motif .hero__facts .inner {
	padding-block: var(--space-s);
}

.hero--motif .fact dt {
	color: var(--ink-3);
}

.hero--motif .fact dd {
	color: var(--heading);
}

/* --- Sunrise surface ----------------------------------------------------- */
/* ATEG's rising sun, centred on the section's lower edge. The halo in the
   artwork sits at 55% opacity, so it blends into the sand rather than meeting
   it at a hard edge. */

section[data-surface='sunrise'] {
	background-color: var(--sand);
	background-image: url('../img/sun-rise.svg');
	background-repeat: no-repeat;
	background-position: center bottom;
	background-size: clamp(22rem, 46%, 36rem) auto;
	/* The icon grid is opaque and covers most of the section, so without extra
	   room at the foot the sun is clipped to a stray arc. This clears roughly
	   its lower half, which reads as rising from behind the content. */
	padding-bottom: var(--space-3xl);
}

section[data-surface='sunrise'] .lede {
	color: var(--ink-2);
}

/* --- Galvanized surface -------------------------------------------------- */
/* A spangle is a crystalline pattern, not a noise texture. Two very low
   contrast linear gradients at opposing angles read as the facets on a
   galvanized sheet without becoming wallpaper. */

section[data-surface='galv'] {
	background-color: var(--sand);
	background-image: linear-gradient(
			116deg,
			transparent 0 38%,
			color-mix(in srgb, var(--spangle-mid) 22%, transparent) 38% 52%,
			transparent 52%
		),
		linear-gradient(
			214deg,
			transparent 0 44%,
			color-mix(in srgb, var(--spangle-light) 34%, transparent) 44% 61%,
			transparent 61%
		);
	background-size: 22rem 22rem, 31rem 31rem;
}

section[data-surface='galv'] .lede {
	color: var(--ink-2);
}

/* --------------------------------------------------------------------------
   Chassis helpers, restated in the design's tokens.

   The scaffold ships its own .grid on --gutter; this design already owns .grid
   on --grid-gap and every approved layout is written against it, so the design
   wins. The span modifiers below are additive and work unchanged on a twelve
   column grid, so the block machinery keeps them.
   -------------------------------------------------------------------------- */

.block {
	background-color: var(--block-bg);
	color: var(--block-fg);
}

.section__inner {
	width: min(100% - (var(--gutter) * 2), var(--container));
	margin-inline: auto;
}

.grid--2 > * { grid-column: span 6; }
.grid--3 > * { grid-column: span 4; }
.grid--4 > * { grid-column: span 3; }
.grid__aside { grid-column: span 4; }
.grid__main  { grid-column: span 8; }

@media (max-width: 63.999rem) {
	.grid--2 > *,
	.grid--3 > *,
	.grid--4 > *,
	.grid__aside,
	.grid__main { grid-column: 1 / -1; }
}

/*
 * The first and last entries of a year have only one neighbour. The design
 * always drew both, so a lone next link would sit in the left column and read
 * as a previous link that had lost its label.
 */
@media (min-width: 48rem) {
	.entry-nav__link--next:only-child {
		grid-column: 2;
	}
}

/* --------------------------------------------------------------------------
   Partners.

   A logo is not a photograph: it has its own margins and its own aspect, so
   the tile holds it rather than crops it. `contain` on a padded, tinted tile
   gives twenty-five marks of different shapes one shared footprint.
   -------------------------------------------------------------------------- */

/*
 * `[hidden] { display: none }` is a user-agent rule at element specificity, so
 * any class setting `display` outranks it and the element stays on screen while
 * the script believes it is gone. The design carries `.winner[hidden]` and
 * `.session[hidden]` for exactly this, but one rule per filtered thing is a
 * trap the next component falls into — the partners grid did.
 *
 * `!important` is warranted: it restores intended UA behaviour against author
 * rules that were never written with `hidden` in mind.
 */
[hidden] {
	display: none !important;
}

.partners {
	row-gap: var(--space-l);
}

.partner {
	display: flex;
	flex-direction: column;
	gap: var(--space-2xs);
	text-decoration: none;
	color: inherit;
}

.partner__media {
	display: flex;
	align-items: center;
	justify-content: center;
	aspect-ratio: 16 / 10;
	padding: var(--space-m);
	background: var(--paper-2);
	border: 1px solid var(--rule);
	border-radius: var(--radius);
	transition: border-color 0.2s ease;
}

.partner__media img {
	width: 100%;
	height: 100%;
	object-fit: contain;
}

/* No mark on file: initials rather than an empty frame. */
.partner__initials {
	font-size: var(--step-3);
	font-weight: 700;
	color: var(--ink-3);
	text-transform: uppercase;
}

.partner h3 {
	margin: 0;
	font-size: var(--step-0);
	color: var(--heading);
}

.partner__type {
	margin: 0;
	font-size: var(--step--1);
	color: var(--ink-3);
}

@media (hover: hover) {
	.partner:hover .partner__media {
		border-color: var(--accent);
	}

	.partner:hover h3 {
		text-decoration: underline;
		text-underline-offset: 3px;
	}
}

/*
 * A marquee logo that links somewhere needs to say so. The design already
 * lifts a mark out of grayscale on hover; this gives the link the same lift
 * and a focus ring, since the track keeps moving and a keyboard user has to
 * be able to see where they are. Pausing on focus stops the target sliding
 * out from under them.
 */
.marquee__link {
	display: block;
	border-radius: var(--radius);
}

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

.marquee:focus-within .marquee__track {
	animation-play-state: paused;
}

/* Focus is not a pointer state: a keyboard user on a touch device still needs
   the mark to lift, so this sits outside the hover query. */
.marquee__link:focus-visible img {
	opacity: 1;
	filter: none;
}

@media (hover: hover) and (pointer: fine) {
	.marquee__link:hover img {
		opacity: 1;
		filter: none;
	}
}

/*
 * The utility bar on a phone. Left alone, the three parts wrap mid-item into
 * stacked columns with the separating dots orphaned at the end of each. The
 * place is the part to drop: the event logo already reads "14-18 June 2027 |
 * Málaga", so on a narrow screen it is the third time of asking.
 */
@media (max-width: 40rem) {
	.utility .inner {
		justify-content: center;
		gap: var(--space-2xs) var(--space-s);
	}

	.utility__meta {
		flex-wrap: nowrap;
		white-space: nowrap;
	}

	/* Name, dot, dates — then stop. */
	.utility__meta > *:nth-child(n + 4) {
		display: none;
	}
}

/* --------------------------------------------------------------------------
   Announcement band.

   Sits above the utility bar, so it is the first thing on the page without
   displacing the masthead. One at a time, by design: a stack of banners is a
   noticeboard and reads as one.
   -------------------------------------------------------------------------- */

.alert {
	font-size: var(--step--1);
}

.alert--brand {
	background: var(--accent);
	color: #fff;
}

.alert--notice {
	background: var(--tint);
	color: var(--ink);
	border-bottom: 1px solid var(--rule);
}

.alert .inner {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: var(--space-s);
	min-height: 2.75rem;
	padding-block: var(--space-2xs);
}

/*
 * The whole band is the target, not just the words in the middle of it. A
 * full-width bar that only responds to a few centimetres of text reads as
 * not responding at all.
 */
.alert__body {
	display: flex;
	align-items: center;
	justify-content: center;
	flex-wrap: wrap;
	gap: var(--space-2xs) var(--space-s);
	width: 100%;
	padding-block: var(--space-2xs);
	color: inherit;
	text-decoration: none;
	text-align: center;
}

/*
 * The global `a:hover { color: var(--heading) }` is (0,1,1) and outranks the
 * (0,1,0) above, so without this the band's white type turns year-red on a
 * year-red ground the moment the pointer arrives — invisible, and it reads as
 * the hover doing nothing at all.
 */
.alert__body:hover,
.alert__body:focus-visible {
	color: inherit;
}

.alert__message {
	font-weight: 600;
}

.alert__more {
	display: inline-flex;
	align-items: center;
	gap: 0.25rem;
	white-space: nowrap;
	opacity: 0.82;
	text-decoration: underline;
	text-underline-offset: 3px;
	transition: opacity var(--dur-ui) ease;
}

.alert__more svg {
	transition: transform var(--dur-ui) ease;
}

/*
 * Wash the band rather than recolour it: one rule then works on the red tier,
 * the blue tier and the pale notice tone alike, and the text is untouched.
 */
.alert {
	transition: background-image var(--dur-ui) ease;
}

@media (hover: hover) {
	.alert:has(a.alert__body:hover) {
		background-image: linear-gradient(rgba(0, 0, 0, 0.14), rgba(0, 0, 0, 0.14));
	}

	a.alert__body:hover .alert__more {
		opacity: 1;
	}

	a.alert__body:hover .alert__more svg {
		transform: translateX(3px);
	}
}

a.alert__body:focus-visible {
	outline: 2px solid currentColor;
	outline-offset: -4px;
	border-radius: var(--radius);
}

.alert:has(a.alert__body:focus-visible) {
	background-image: linear-gradient(rgba(0, 0, 0, 0.14), rgba(0, 0, 0, 0.14));
}

/* The call to action's body, previously an inline-styled <p>. */
.cta__body {
	margin-top: var(--space-s);
}

.cta__body > * {
	margin-inline: auto;
}

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

/* --- journal archive ---------------------------------------------------- */

/*
 * Issues are the archive's structure, so each gets a named band. The label
 * matches the sponsor tier's: a quiet rule with a small caps heading, so a
 * grouping reads as furniture rather than competing with the article titles.
 */
.journal-issue + .journal-issue {
	margin-top: var(--space-xl);
}

.journal-issue__label {
	margin: 0 0 var(--space-m);
	padding-bottom: var(--space-2xs);
	border-bottom: 1px solid var(--rule);
	font-size: var(--step--1);
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var(--ink-3);
}

/* The card's own heading is an h3; inside an issue it is one level down. */
.journal-issue .card h4 {
	margin: 0;
	font-size: var(--step-1);
	line-height: 1.25;
	color: var(--heading);
}

/* --- sponsors ----------------------------------------------------------- */

/*
 * A sponsor tier is a row of marks, not a card grid: the logos sit on the
 * page's own ground with the tier named above them. Platinum reads larger
 * than gold, which is the point of paying for it.
 */
.sponsor-tier + .sponsor-tier {
	margin-top: var(--space-xl);
}

.sponsor-tier__label {
	margin: 0 0 var(--space-m);
	padding-bottom: var(--space-2xs);
	border-bottom: 1px solid var(--rule);
	font-size: var(--step--1);
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var(--ink-3);
}

.sponsor-tier__list {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--space-l) var(--space-xl);
	margin: 0;
	padding: 0;
	list-style: none;
}

.sponsor img {
	display: block;
	width: auto;
	max-width: 100%;
	height: clamp(2.5rem, 2rem + 1.6vw, 3.5rem);
	object-fit: contain;
}

/* The top tier earns more room. */
.sponsor-tier:first-child .sponsor img {
	height: clamp(3.25rem, 2.5rem + 2.4vw, 5rem);
}

.sponsor__name {
	font-size: var(--step-0);
	font-weight: 700;
	color: var(--heading);
}

/* --- one partner -------------------------------------------------------- */

.partner-contact {
	align-items: start;
	row-gap: var(--space-m);
}

.partner-contact__where {
	margin: 0;
	font-style: normal;
	color: var(--ink-2);
}

.partner-contact__reach {
	margin: 0;
	padding: 0;
	list-style: none;
	display: grid;
	gap: var(--space-2xs);
}

.partner-contact__reach li {
	display: flex;
	align-items: center;
	gap: var(--space-s);
}

.partner-contact__reach svg {
	flex: none;
	color: var(--accent);
}

.partner-contact__mark {
	display: flex;
	align-items: flex-start;
	justify-content: flex-start;
}

@media (min-width: 64rem) {
	.partner-contact__mark {
		justify-content: flex-end;
	}
}

.partner-contact__mark img {
	max-width: min(100%, 15rem);
	height: auto;
	object-fit: contain;
}

.partner-contact__back {
	margin: var(--space-l) 0 0;
}

/* --------------------------------------------------------------------------
   The brand band, for blocks the design never put on it.

   The design used `data-surface="accent"` for one thing, the closing call to
   action, so it set that band's h2 and eyebrow and stopped. The block library
   offers the same surface on every block, and everything else arrived keeping
   its light-tier ink: dark blue headings on dark red, 1.28:1 on the specimen.

   Flip the text roles for the subtree rather than chase each block's own
   selectors, so a block written later is legible here without a new rule.
   -------------------------------------------------------------------------- */

section[data-surface='accent'] {
	--heading: #fff;
	--accent: #fff;
	--ink: rgba(255, 255, 255, 0.92);
	--ink-2: rgba(255, 255, 255, 0.85);
	--ink-3: rgba(255, 255, 255, 0.72);
	--rule: rgba(255, 255, 255, 0.28);
	--rule-soft: rgba(255, 255, 255, 0.18);
}

/*
 * Except where a block lays its own light ground inside that band. Those keep
 * the page's ink, or white type lands on a white tile — the same fault in
 * reverse. The tier aliases keep this correct in red as well as blue.
 *
 * `color` is restated as well as the tokens: the band sets it directly, and
 * inheritance carries that past any token an island redeclares.
 */
section[data-surface='accent'] :is(.icon-index, .callout, .table) {
	--heading: var(--heading-on-light);
	--accent: var(--accent-on-light);
	--ink: #14191f;
	--ink-2: #46535f;
	--ink-3: #6f7d8a;
	--rule: #dfe5ea;
	--rule-soft: #edf1f4;
	color: #14191f;
}

/* A table is only half an island: its stripes are light, its other rows are
   not. Give it a ground so the whole of it is one. */
section[data-surface='accent'] .table {
	background: var(--paper);
}

/* A solid button carries its own ground too, and both read their face from
   the roles flipped above. Without this the light button is white on white. */
section[data-surface='accent'] :is(.btn--light, .btn--primary) {
	--heading: var(--heading-on-light);
	--accent: var(--accent-on-light);
}

/*
 * The icon index declares a Columns option, but its track list is auto-fit, so
 * the width decided the count and the option could never do anything. Honour
 * it once there is room to; below that, auto-fit still reflows.
 */
@media (min-width: 64rem) {
	.icon-index[data-columns='2'] { grid-template-columns: repeat(2, 1fr); }
	.icon-index[data-columns='3'] { grid-template-columns: repeat(3, 1fr); }
	.icon-index[data-columns='4'] { grid-template-columns: repeat(4, 1fr); }
}

/* --------------------------------------------------------------------------
   Editor blocks.

   Interior pages are the client's own paragraphs, pictures, lists and tables,
   written in the block editor and kept as core blocks so they stay editable.
   The design never drew those, so they arrive on WordPress's own defaults:
   8px gutters, square corners, no measure. These map them onto the same
   tokens the designed blocks use, so a page of editor content sits in the
   design rather than beside it.

   Layout still comes from wp-block-library; this is spacing and finish only.
   -------------------------------------------------------------------------- */

.content :where(figure) {
	margin: var(--space-l) 0;
}

.content :where(figure) img {
	border-radius: var(--radius);
}

.content :where(figcaption) {
	margin-top: var(--space-2xs);
	font-size: var(--step--1);
	color: var(--ink-3);
}

/* Galleries and columns inherit the grid gutter rather than the 8px default. */
.content .wp-block-gallery,
.content .wp-block-columns {
	gap: var(--grid-gap);
}

.content .wp-block-gallery img {
	border-radius: var(--radius);
}

.content .wp-block-columns {
	margin-block: var(--space-l);
}

/* A table the client wrote gets the designed table's frame. */
.content .wp-block-table {
	overflow-x: auto;
	border: 1px solid var(--rule);
	border-radius: var(--radius);
}

.content .wp-block-table table {
	margin: 0;
	min-width: 34rem;
}

.content .wp-block-table tbody tr:last-child th,
.content .wp-block-table tbody tr:last-child td {
	border-bottom: 0;
}

/* Embeds and video hold their shape instead of collapsing to nothing. */
.content .wp-block-embed__wrapper,
.content .wp-block-video {
	position: relative;
}

.content .wp-block-embed iframe,
.content .wp-block-video video {
	display: block;
	width: 100%;
	aspect-ratio: 16 / 9;
	border: 0;
	border-radius: var(--radius);
	background: var(--paper-2);
}

/* A file block is a download, so it should read as one. */
.content .wp-block-file {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--space-s);
	margin: var(--space-l) 0;
	padding: var(--space-s) var(--space-m);
	border: 1px solid var(--rule);
	border-radius: var(--radius);
}

.content .wp-block-file__button {
	margin-inline-start: auto;
}

/* Media and text keeps the gutter and the picture's corner. */
.content .wp-block-media-text {
	gap: var(--grid-gap);
	margin-block: var(--space-l);
}

.content .wp-block-media-text img {
	border-radius: var(--radius);
}

/* The fonts now live in the theme, so repoint the two asset URLs. */

/* The "all news" link below the latest-news cards. */
.latest-news__all {
	margin: var(--space-l) 0 0;
}

/*
 * A paper with no time on it. The designed row is time | content | download,
 * and an archive year has no schedule — so without this the title lands in the
 * 7rem time column and is squeezed to a word a line.
 */
@media (min-width: 46rem) {
	.session--untimed {
		grid-template-columns: minmax(0, 1fr) auto;
	}
}

/* --------------------------------------------------------------------------
   Document gate dialog.

   The same shape as the newsletter signup, because it is the same kind of
   interruption: a native <dialog>, so focus trapping, Escape and page
   inertness come from the platform.
   -------------------------------------------------------------------------- */

.gate {
	width: min(100% - 2rem, 30rem);
	padding: 0;
	border: 0;
	border-radius: var(--radius);
	background: var(--paper);
	color: var(--ink);
	opacity: 0;
	transform: translateY(8px);
	transition: opacity var(--dur-ui) ease, transform var(--dur-ui) ease;
}

.gate.is-in {
	opacity: 1;
	transform: none;
}

.gate::backdrop {
	background: rgba(20, 25, 31, 0.55);
}

.gate__body {
	position: relative;
	padding: var(--space-l);
	display: grid;
	gap: var(--space-s);
}

.gate__body h2 {
	margin: 0;
	font-size: var(--step-2);
}

.gate__body p {
	margin: 0;
	color: var(--ink-2);
	font-size: var(--step--1);
}

.gate__close {
	position: absolute;
	top: var(--space-2xs);
	right: var(--space-2xs);
	width: 2.25rem;
	height: 2.25rem;
	border: 0;
	background: none;
	font-size: var(--step-2);
	line-height: 1;
	color: var(--ink-3);
	cursor: pointer;
	border-radius: var(--radius);
}

.gate__close:hover {
	color: var(--heading);
}

.gate form {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-2xs);
	margin: 0;
}

.gate input[type='password'] {
	flex: 1 1 12rem;
	min-width: 0;
	padding: var(--space-2xs) var(--space-s);
	border: 1px solid var(--rule);
	border-radius: var(--radius);
	font: inherit;
	color: var(--ink);
	background: var(--paper);
}

.gate input[type='password']:focus-visible {
	outline: 2px solid var(--accent);
	outline-offset: 1px;
}

.gate__error {
	margin: 0;
	padding: var(--space-2xs) var(--space-s);
	border-radius: var(--radius);
	background: var(--tint);
	color: var(--heading);
	font-size: var(--step--1);
}

/* The lock marker on a paper that still needs a password. */
.session__doc[data-locked]::after {
	content: attr(data-edition);
	margin-left: var(--space-2xs);
	font-size: var(--step--2);
	letter-spacing: 0.1em;
	color: var(--ink-3);
}

/* --- What's on ------------------------------------------------------------
   A column per day. The grid is driven by the number of days rather than a
   column option, because the days are the content: five days make five
   columns, and a sixth would have nowhere sensible to go.

   `auto-fit` with a floor is what lets it fall to three, then two, then one
   without a breakpoint per step. The floor is the measure a four word item
   needs before it starts breaking mid-word.
   -------------------------------------------------------------------------- */

.whatson__intro {
	max-width: var(--measure);
	margin-bottom: var(--space-l);
}

.whatson__intro h2 {
	margin-bottom: var(--space-2xs);
}

.whatson {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	gap: var(--space-s);
	grid-template-columns: repeat(auto-fit, minmax(10.5rem, 1fr));
}

.whatson__day {
	display: flex;
	flex-direction: column;
	gap: var(--space-xs);
	padding: var(--space-m) var(--space-s) var(--space-l);
	background: var(--paper);
	border: 1px solid var(--rule);
	border-radius: var(--radius);
}

.whatson__head {
	display: grid;
	gap: 1px;
	padding-bottom: var(--space-xs);
	border-bottom: 2px solid var(--accent);
}

.whatson__head b {
	font-size: var(--step-1);
	line-height: 1.1;
	color: var(--heading);
	font-variant-numeric: tabular-nums;
}

.whatson__head span {
	font-size: var(--step--2);
	text-transform: uppercase;
	letter-spacing: 0.12em;
	color: var(--ink-3);
}

.whatson__note {
	margin: 0;
	font-size: var(--step--1);
	color: var(--ink-3);
}

.whatson__list {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	gap: var(--space-2xs);
	align-content: start;
}

.whatson__list li {
	font-size: var(--step--1);
	color: var(--ink-2);
}

/* --- An image above a column ---------------------------------------------
   The pair is only even if both columns carry one, so the ratio is fixed
   rather than left to whatever was uploaded.
   -------------------------------------------------------------------------- */

.columns__image {
	display: block;
	width: 100%;
	height: auto;
	aspect-ratio: 16 / 9;
	object-fit: cover;
	border-radius: var(--radius);
	margin-bottom: var(--space-s);
}

/* --- Content with form ----------------------------------------------------
   The block's own layout lives here rather than in forms.css, because
   forms.css only loads on a page Gravity Forms is printing a form on — and a
   block whose form has not been chosen yet still has to hold its shape.
   -------------------------------------------------------------------------- */

.formcols {
	row-gap: var(--space-l);
}

.formcols__intro {
	max-width: var(--measure);
}

.formcols__intro h2 {
	margin-bottom: var(--space-s);
}

.formcols__placeholder {
	margin: 0;
	padding: var(--space-m);
	border: 1px dashed var(--rule);
	border-radius: var(--radius);
	color: var(--ink-3);
	font-size: var(--step--1);
}

/* --- A linked icon-index title --------------------------------------------
   The tile's title became a link to its own section page. The design's
   `.icon-index__item a` was written for the list beneath it, so it painted the
   title grey and dropped it from --step-1 to --step-0 — the title stops
   looking like a title the moment it gains an href.

   `font: inherit` rather than restating the size, so the title keeps following
   its h3 if that ever changes. The hover keeps the underline as the
   affordance, but not the colour shift: the title is already --heading, and
   `.icon-index__item a:hover` would otherwise leave it changing to the colour
   it already is.
   -------------------------------------------------------------------------- */

.icon-index__item h3 a {
	color: inherit;
	font: inherit;
}

.icon-index__item h3 a:hover {
	color: inherit;
	text-decoration: underline;
	text-underline-offset: 0.2em;
}

/* --- People ---------------------------------------------------------------
   Speaker and expert cards. The portrait is a fixed 1:1 so a row of them
   lines up whatever was uploaded — headshots arrive at every ratio, and a
   grid of mixed ones reads as a mistake rather than as variety.

   align-items: start on the grid, so a long biography lengthens its own card
   instead of stretching every card in the row to match.
   -------------------------------------------------------------------------- */

.people {
	list-style: none;
	margin: 0;
	padding: 0;
	align-items: start;
	row-gap: var(--space-xl);
}

.person__photo {
	display: block;
	width: 100%;
	height: auto;
	aspect-ratio: 1;
	object-fit: cover;
	border-radius: var(--radius);
	margin-bottom: var(--space-s);
	background: var(--tint);
}

.person__name {
	font-size: var(--step-1);
	margin: 0 0 var(--space-3xs);
}

.person__role {
	margin: 0 0 var(--space-xs);
	font-size: var(--step--1);
	color: var(--ink-3);
}

.person__role a {
	color: inherit;
	text-decoration: underline;
	text-underline-offset: 0.2em;
}

.person__role a:hover {
	color: var(--heading);
}

/* The sessions someone appears in, as chips rather than a list of links. */
.person__appearances {
	list-style: none;
	margin: 0 0 var(--space-s);
	padding: 0;
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-3xs);
}

.person__appearances li {
	font-size: var(--step--2);
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--ink-2);
	padding: 0.25em 0.7em;
	border: 1px solid var(--rule);
	border-radius: 999px;
}

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

.person__appearances a:hover {
	color: var(--heading);
	text-decoration: underline;
	text-underline-offset: 0.2em;
}

.person__bio {
	color: var(--ink-2);
	font-size: var(--step--1);
}

.person__bio p {
	margin: 0 0 var(--space-xs);
}

.person__bio p:last-child {
	margin-bottom: 0;
}

.person__linkedin {
	display: inline-flex;
	align-items: center;
	gap: var(--space-3xs);
	margin-top: var(--space-s);
	font-size: var(--step--1);
	color: var(--ink-2);
	text-decoration: none;
}

.person__linkedin svg {
	width: 1em;
	height: 1em;
	flex: none;
}

.person__linkedin:hover {
	color: var(--heading);
	text-decoration: underline;
	text-underline-offset: 0.2em;
}

/* --- The ATEG mark in the footer -----------------------------------------
   ATEG's logo is a wide wordmark where EGGA's is close to square, so at a
   shared cap height it reads noticeably larger. Ten per cent down settles the
   pair.

   The shared height moves to a custom property so this is one number scaled,
   not the clamp written out twice — a duplicate would quietly stop agreeing
   with the design's own rule above the first time that changed.
   -------------------------------------------------------------------------- */

.footer__orgs {
	--org-logo-h: clamp(1.75rem, 1.55rem + 1vw, 2.25rem);
}

.footer__orgs img {
	height: var(--org-logo-h);
}

.footer__orgs img[data-logo='ateg'] {
	height: calc(var(--org-logo-h) * 0.9);
}

/* --- The social row, in the footer ---------------------------------------
   Moved down from the header's utility bar, opposite the organising bodies
   it now shares a row with.

   `margin-left: auto` only once there is a row to sit at the end of. Below
   that the group wraps onto its own line, where pushing it right would strand
   it opposite nothing, so it stays with the left edge the logos are on.

   The marks are larger here than the 16px the header gave them. The SVGs
   still carry width and height attributes; a CSS length outranks a
   presentational attribute, so sizing them here is enough.
   -------------------------------------------------------------------------- */

.footer__social {
	display: flex;
	align-items: center;
	gap: var(--space-m);
}

.footer__social a {
	display: grid;
	place-items: center;
	color: rgba(255, 255, 255, 0.68);
	transition: color var(--dur-fast) ease;
}

.footer__social a:hover {
	color: #fff;
}

.footer__social svg {
	width: 1.375rem;
	height: 1.375rem;
}

@media (min-width: 46rem) {
	.footer__social {
		margin-left: auto;
	}
}

/* --- A section intro sits with what it introduces -------------------------
   Three spacings were stacking between the intro and the block under it: the
   section head's own bottom margin, the intro's bottom padding, and the next
   section's top padding. The head's margin exists to separate it from content
   *inside* the same section; as its own block there is nothing below it to
   separate from, so it goes.

   The two paddings only collapse when both sections are on the same surface.
   Enumerated rather than written once, because CSS cannot compare one
   sibling's attribute with another's — and without the match, closing the gap
   would end the intro's colour band hard against its own last line.
   -------------------------------------------------------------------------- */

section[data-block='section-intro']:has(+ section) .section-head {
	margin-bottom: 0;
}

section[data-block='section-intro'][data-surface='paper']:has(+ section[data-surface='paper']),
section[data-block='section-intro'][data-surface='tint']:has(+ section[data-surface='tint']),
section[data-block='section-intro'][data-surface='soft']:has(+ section[data-surface='soft']),
section[data-block='section-intro'][data-surface='sand']:has(+ section[data-surface='sand']),
section[data-block='section-intro'][data-surface='sunrise']:has(+ section[data-surface='sunrise']),
section[data-block='section-intro'][data-surface='accent']:has(+ section[data-surface='accent']) {
	padding-bottom: 0;
}

section[data-block='section-intro'][data-surface='paper'] + section[data-surface='paper'],
section[data-block='section-intro'][data-surface='tint'] + section[data-surface='tint'],
section[data-block='section-intro'][data-surface='soft'] + section[data-surface='soft'],
section[data-block='section-intro'][data-surface='sand'] + section[data-surface='sand'],
section[data-block='section-intro'][data-surface='sunrise'] + section[data-surface='sunrise'],
section[data-block='section-intro'][data-surface='accent'] + section[data-surface='accent'] {
	padding-top: var(--space-l);
}

/* --- The build credit ----------------------------------------------------
   The legal row is set at 0.52 white while .footer a is 0.7, so linking the
   credit lights it brighter than the copyright line beside it and the two
   read as different kinds of text. Inherit the row's colour instead and let
   the hover say it is a link.
   -------------------------------------------------------------------------- */

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

.footer__legal a:hover {
	color: #fff;
	text-decoration: underline;
	text-underline-offset: 0.2em;
}

/* --- Industry diary ------------------------------------------------------
   The design right-aligns every column after the first, which is right for
   the registration fees it was drawn for: the money lines up. The diary's
   columns are an event name and a place, and ragged-right prose pushed to
   the right margin reads as a mistake. Left for this table only, and the
   columns held to sensible proportions so a long conference name does not
   starve the date.
   -------------------------------------------------------------------------- */

section[data-block='industry-diary'] td + td,
section[data-block='industry-diary'] th + th {
	text-align: left;
}

section[data-block='industry-diary'] thead th:first-child {
	width: 22ch;
}

section[data-block='industry-diary'] thead th:last-child {
	width: 24ch;
}

/* A one-line note an editor can add beneath an event. */
.diary__blurb {
	display: block;
	margin-top: var(--space-3xs);
	font-size: var(--step--1);
	color: var(--ink-3);
}

/* --- Plants --------------------------------------------------------------
   A picture beside a specification table. The design's .table is not reused
   here: it sets white-space nowrap and a 34rem minimum, which suit the wide
   registration table it was drawn for but would stop a long "Additional
   Information" value wrapping beside a narrow picture.
   -------------------------------------------------------------------------- */

.plant + .plant {
	margin-top: var(--space-xl);
	padding-top: var(--space-xl);
	border-top: 1px solid var(--rule);
}

.plant__name {
	font-size: var(--step-1);
	margin: 0 0 var(--space-s);
}

.plant__body {
	display: grid;
	gap: var(--space-m);
}

@media (min-width: 48rem) {
	.plant__body {
		grid-template-columns: 16rem 1fr;
		align-items: start;
	}
}

.plant__figure {
	margin: 0;
}

.plant__figure img {
	display: block;
	width: 100%;
	height: auto;
	aspect-ratio: 3 / 2;
	object-fit: cover;
	border-radius: var(--radius);
	background: var(--tint);
}

.plant__specs {
	width: 100%;
	border-collapse: collapse;
}

.plant__specs th,
.plant__specs td {
	vertical-align: top;
	white-space: normal;
}

.plant__specs th[scope='row'] {
	font-weight: 700;
	color: var(--heading);
}

/*
 * Two columns need room. On a phone the labels are long enough ("Photographs
 * /Video permitted") that holding the shape left the values a ~130px ribbon
 * and "Additional Information" wrapped eight lines deep. Below the breakpoint
 * each pair stacks instead, label over value, which is what the rest of the
 * site does rather than squashing.
 */
.plant__specs,
.plant__specs tbody,
.plant__specs tr,
.plant__specs th,
.plant__specs td {
	display: block;
}

.plant__specs tr {
	padding: var(--space-xs) var(--space-s);
	border-bottom: 1px solid var(--rule);
}

.plant__specs th,
.plant__specs td {
	padding: 0;
	border-bottom: 0;
}

.plant__specs th[scope='row'] {
	font-size: var(--step--1);
	margin-bottom: var(--space-3xs);
}

@media (min-width: 48rem) {
	.plant__specs,
	.plant__specs tbody {
		display: table;
		width: 100%;
	}

	.plant__specs tr {
		display: table-row;
		padding: 0;
		border-bottom: 0;
	}

	.plant__specs th,
	.plant__specs td {
		display: table-cell;
		padding: var(--space-xs) var(--space-s);
		border-bottom: 1px solid var(--rule);
	}

	.plant__specs th[scope='row'] {
		width: 16rem;
		font-size: inherit;
		margin-bottom: 0;
	}

	.plant__specs tr:last-child th,
	.plant__specs tr:last-child td {
		border-bottom: 0;
	}
}

.plant__specs tr:nth-child(even) {
	background: var(--tint);
}

.plant__specs tr:last-child {
	border-bottom: 0;
}

.plant__further {
	margin-top: var(--space-s);
	color: var(--ink-2);
}

.plant__site {
	display: inline-block;
	margin-top: var(--space-s);
}

/* --- Tours ---------------------------------------------------------------
   A picture beside the description, with the practical facts — times, price,
   who may book — on one line beneath. The facts wrap rather than scroll:
   they are the part a reader compares between tours.
   -------------------------------------------------------------------------- */

.tour {
	display: grid;
	gap: var(--space-m);
}

.tour + .tour {
	margin-top: var(--space-xl);
	padding-top: var(--space-xl);
	border-top: 1px solid var(--rule);
}

@media (min-width: 48rem) {
	.tour {
		grid-template-columns: 20rem 1fr;
		align-items: start;
	}
}

.tour__figure {
	margin: 0;
}

.tour__figure img {
	display: block;
	width: 100%;
	height: auto;
	aspect-ratio: 3 / 2;
	object-fit: cover;
	border-radius: var(--radius);
	background: var(--tint);
}

.tour__title {
	font-size: var(--step-1);
	margin: var(--space-3xs) 0 var(--space-xs);
}

.tour__body {
	color: var(--ink-2);
}

.tour__facts,
.visit__facts {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-xs) var(--space-l);
	margin: var(--space-s) 0 0;
	padding-top: var(--space-s);
	border-top: 1px solid var(--rule);
}

.tour__facts dt,
.visit__facts dt {
	font-size: var(--step--2);
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--ink-3);
}

.tour__facts dd,
.visit__facts dd {
	margin: 0;
	font-weight: 700;
	color: var(--heading);
}

/* --- Visit groups --------------------------------------------------------
   One card per bookable group: which plants it takes in, then the practical
   facts. The price sits opposite the group number, where a reader comparing
   options looks first.
   -------------------------------------------------------------------------- */

.visits {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	gap: var(--space-m);
}

.visit {
	padding: var(--space-m);
	border: 1px solid var(--rule);
	border-radius: var(--radius);
	background: var(--paper);
}

.visit__head {
	display: flex;
	flex-wrap: wrap;
	justify-content: space-between;
	align-items: baseline;
	gap: var(--space-xs);
}

.visit__group {
	font-size: var(--step-1);
	font-weight: 700;
	color: var(--heading);
}

.visit__price {
	font-weight: 700;
	color: var(--heading);
}

.visit__status {
	display: inline-block;
	margin-left: var(--space-3xs);
	padding: 0.1em 0.5em;
	border-radius: var(--radius-s, 0.25rem);
	background: var(--tint);
	font-style: normal;
	font-size: var(--step--2);
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--ink-3);
}

.visit__plants {
	margin: var(--space-xs) 0 0;
	padding-left: 1.1em;
	color: var(--ink-2);
}

/*
 * What else is included reads as an aside to the plant list, not another
 * entry in it, so it loses the marker and takes the quieter ink.
 */
.visit__notes {
	list-style: none;
	margin: var(--space-2xs) 0 0;
	padding: 0;
	font-size: var(--step--1);
	color: var(--ink-3);
}

.visit__notes li + li {
	margin-top: var(--space-3xs);
}

.visit__facts {
	margin-top: var(--space-s);
}

/* --- Exhibitors ----------------------------------------------------------
   A booth number and a company, in columns that fill the width. Long company
   names are common, so the rows are allowed to wrap rather than being held
   to one line.
   -------------------------------------------------------------------------- */

.exhibitors {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	gap: var(--space-2xs) var(--space-m);
	grid-template-columns: repeat(auto-fill, minmax(18rem, 1fr));
}

.exhibitor {
	display: flex;
	gap: var(--space-xs);
	align-items: baseline;
	padding: var(--space-2xs) 0;
	border-bottom: 1px solid var(--rule);
}

.exhibitor__booth {
	flex: none;
	min-width: 2.5em;
	font-variant-numeric: tabular-nums;
	font-size: var(--step--1);
	color: var(--ink-3);
}

.exhibitor__name {
	color: inherit;
}

/* --- Legal links and the consent banner ----------------------------------
   Vu Legals draws everything from --vul-*, and is set to "theme" style mode so
   it emits none of its own. Mapping them onto the design's tokens means the
   banner follows the two brand tiers: blue on most of the site, the year's red
   inside the event section, without the plugin knowing either exists.
   -------------------------------------------------------------------------- */

:root {
	--vul-bg: var(--paper);
	--vul-fg: var(--ink);
	--vul-muted: var(--ink-3);
	--vul-accent: var(--accent);
	--vul-accent-fg: #fff;
	--vul-border: var(--rule);
	--vul-radius: var(--radius);
	--vul-btn-radius: var(--radius);
	--vul-font: inherit;
	--vul-switch-on: var(--accent);
	--vul-text-size: var(--step--1);
}

/* The policy links read as one row with the copyright, not as a list. */
.footer__policies {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-xs) var(--space-m);
	align-items: baseline;
}

/*
 * The preferences control has to be a button — it opens a panel rather than
 * going anywhere — so it is stripped back to match the links beside it.
 */
.footer__policies button {
	padding: 0;
	border: 0;
	background: none;
	font: inherit;
	color: inherit;
	cursor: pointer;
}

.footer__policies a,
.footer__policies button {
	color: inherit;
	text-decoration: none;
}

.footer__policies a:hover,
.footer__policies button:hover {
	color: #fff;
	text-decoration: underline;
	text-underline-offset: 0.2em;
}

/* --- Legal documents -----------------------------------------------------
   Vu Legals marks each clause up as its own <section>, and the design gives
   every section a full band of padding. Nine numbered clauses plus an intro
   meant roughly 1,400px of dead space down a document that should read as
   continuous prose. The clauses take document rhythm instead; the band of
   padding stays on the one wrapper the page template provides.
   -------------------------------------------------------------------------- */

/*
 * Matched on the prefix rather than the two class names in use today
 * (vul-doc__section on the privacy and terms documents, vul-policy__section
 * on the cookie one). Naming them individually fixed the first document and
 * left the second exactly as broken, which is how this was found.
 */
section[class*='vul-'] {
	padding-top: 0;
	padding-bottom: 0;
}

section[class*='vul-'] + section[class*='vul-'] {
	margin-top: var(--space-l);
}

/* The clause gap is the margin above, not a heading margin on top of it. */
section[class*='vul-'] > h2:first-child,
section[class*='vul-'] > h3:first-child {
	margin-top: 0;
}
