/* INUGSC site styles, used by every page. Every value here comes from DESIGN.md;
   add new values there first. */

/* ---------- Type ---------- */

@font-face {
    font-family: "Assistant";
    src: url(/font/Assistant.ttf) format("truetype");
    font-weight: 200 800;
    font-display: swap;
}

/* Libre Baskerville: the typeface of the INUGSC lockup (SIL Open Font Licence, see font/) */
@font-face {
    font-family: "Libre Baskerville";
    src: url(/font/LibreBaskerville-latin-400-normal.woff2) format("woff2");
    font-weight: 400;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: "Libre Baskerville";
    src: url(/font/LibreBaskerville-latin-500-normal.woff2) format("woff2");
    font-weight: 500;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: "Libre Baskerville";
    src: url(/font/LibreBaskerville-latin-400-italic.woff2) format("woff2");
    font-weight: 400;
    font-style: italic;
    font-display: swap;
}

/* ---------- Tokens ---------- */

:root {
    --navy: #1d1d5f;
    --deep-navy: #0e0e33;
    --blue-text: #1d12b2;
    --accent: #8fd0f5;
    --page: #f6f6f6;
    --band: #e1e8f0;
    --white: #ffffff;
    --ink: #14142f;
    --on-dark-muted: rgba(255, 255, 255, 0.72);
    --scrim: rgba(10, 12, 48, 0.62);
    --hairline-light: rgba(29, 29, 95, 0.18);
    --hairline-dark: rgba(255, 255, 255, 0.24);
    --map-base: #d3d8e8;

    --display: "Libre Baskerville", Georgia, serif;
    --text: "Assistant", "Helvetica Neue", Arial, sans-serif;

    --gutter: 4rem;
    --section: 6rem;
    --measure-panel: 32rem;
    --measure-centred: 44rem;

    --header-full: 7.5rem;
    --header-compact: 3.75rem;
    --seal-full: 5.5rem;
    --seal-compact: 2.75rem;

    color-scheme: light;
}

/* ---------- Base ---------- */

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

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

body {
    margin: 0;
    background: var(--page);
    color: var(--ink);
    font-family: var(--text);
    font-size: 1.0625rem;
    font-weight: 300;
    line-height: 1.6;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-rendering: optimizeLegibility;
}

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

h1,
h2,
h3 {
    font-family: var(--display);
    font-weight: 400;
    letter-spacing: 0.01em;
    margin: 0;
}

p {
    margin: 0 0 1rem;
}

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

b,
strong {
    font-weight: 500;
}

a {
    color: inherit;
}

[hidden] {
    display: none !important;
}

:focus-visible {
    outline: 2px solid currentColor;
    outline-offset: 3px;
}

[id] {
    scroll-margin-top: var(--header-compact);
}

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

.skip_link {
    position: fixed;
    left: 1rem;
    top: -4rem;
    z-index: 200;
    padding: 0.75rem 1rem;
    background: var(--white);
    color: var(--ink);
    font-weight: 600;
    border-radius: 2px;
}

.skip_link:focus {
    top: 1rem;
}

/* ---------- Surfaces: neighbouring bands never share a colour ---------- */

.band_deep {
    background: var(--deep-navy);
    color: var(--white);
}

.band_navy {
    background: var(--navy);
    color: var(--white);
}

.band_light {
    background: var(--band);
    color: var(--blue-text);
}

.band_white {
    background: var(--white);
    color: var(--blue-text);
}

/* ---------- Actions: one solid button per view, everything else is a text link ---------- */

.button {
    display: inline-block;
    padding: 0.95rem 1.6rem;
    border-radius: 2px;
    font-family: var(--text);
    font-size: 1rem;
    font-weight: 600;
    line-height: 1;
    text-decoration: none;
    transition: background-color 0.2s ease;
}

.button_on_dark {
    background: var(--white);
    color: var(--ink);
}

.button_on_dark:hover {
    background: var(--band);
}

.button_on_light {
    background: var(--navy);
    color: var(--white);
}

.button_on_light:hover {
    background: var(--deep-navy);
}

.text_link {
    font-weight: 500;
    text-decoration: none;
    border-bottom: 1px solid currentColor;
    padding-bottom: 2px;
    transition: opacity 0.2s ease;
}

.text_link:hover {
    opacity: 0.7;
}

/* ---------- Header: full size at the top, condensing as you scroll ---------- */

.site_header {
    position: fixed;
    inset: 0 0 auto 0;
    z-index: 100;
    display: flex;
    align-items: center;
    gap: 2rem;
    height: var(--header-full);
    padding: 0 var(--gutter);           /* the seal and the last link sit on the page's gutter lines */
    background: var(--navy);
    color: var(--white);
}

.site_brand {
    display: flex;
    align-items: center;
    gap: 1.1rem;
    flex-shrink: 0;
    color: inherit;
    text-decoration: none;
}

.site_seal {
    width: var(--seal-full);
    height: var(--seal-full);
    clip-path: circle();
}

.site_lockup {
    font-family: var(--display);
    font-size: 1rem;
    font-weight: 500;
    letter-spacing: 0.07em;
    line-height: 1.45;
    white-space: nowrap;
}

.site_nav {
    margin-left: auto;
}

.site_nav ul {
    display: flex;
    gap: 2rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

.site_nav a {
    font-size: 1.0625rem;
    font-weight: 400;
    text-decoration: none;
    white-space: nowrap;
    transition: opacity 0.2s ease;
}

.site_nav a:hover {
    opacity: 0.7;
}

.site_menu_button {
    display: none;
}

main {
    padding-top: var(--header-full);
}

/* Only where scroll timelines exist: elsewhere the header simply stays full size */
@supports (animation-timeline: scroll()) {
    .site_header,
    .site_seal,
    .site_lockup {
        animation-timing-function: linear;
        animation-fill-mode: both;
        animation-timeline: scroll(root block);
        animation-range: 0 12rem;
    }

    .site_header {
        animation-name: header-condense;
    }

    .site_seal {
        animation-name: seal-condense;
    }

    .site_lockup {
        animation-name: lockup-condense;
    }
}

@keyframes header-condense {
    to {
        height: var(--header-compact);
    }
}

@keyframes seal-condense {
    to {
        width: var(--seal-compact);
        height: var(--seal-compact);
    }
}

@keyframes lockup-condense {
    to {
        font-size: 0.74rem;
    }
}

/* ---------- First view ---------- */

.first_view {
    position: relative;
    display: flex;
    align-items: flex-end;
    height: calc(100svh - var(--header-full));
    min-height: 34rem;
    overflow: hidden;
    background: var(--deep-navy);
    color: var(--white);
    view-timeline-name: --first-view;
}

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

.first_view_media img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center 40%;
}

/* Only where view timelines exist: the end state of these is off screen or invisible */
@supports (animation-timeline: view()) {
    .first_view_media img {
        animation: first-view-drift linear both;
        animation-timeline: --first-view;
        animation-range: exit 0% exit 100%;
    }

    .first_view_content {
        animation: first-view-lift linear both;
        animation-timeline: --first-view;
        animation-range: exit 0% exit 70%;
    }
}

.first_view_media::after {
    content: "";
    position: absolute;
    inset: 0;
    background: var(--scrim);
}

.first_view_content {
    position: relative;
    max-width: 78rem;
    padding: 0 var(--gutter) 5.5rem;
}

.first_view_eyebrow {
    margin: 0 0 1rem;
    font-family: var(--display);
    font-size: 1.15rem;
    font-style: italic;
    letter-spacing: 0.03em;
    color: rgba(255, 255, 255, 0.85);
}

.first_view_date {
    font-size: clamp(2.8rem, 5.4vw, 5.6rem);
    line-height: 1.05;
}

/* On the home page the heading holds the conference's name (as the eyebrow) and the date */
.first_view_title {
    font-weight: inherit;
}

.first_view_title > span {
    display: block;
}

.first_view_venue {
    max-width: 40rem;
}

.first_view_venue,
.first_view_lead {
    margin: 1.2rem 0 2.4rem;
    font-size: clamp(1.1rem, 1.7vw, 1.45rem);
    letter-spacing: 0.02em;
    color: rgba(255, 255, 255, 0.9);
}

/* Inner pages open with a shorter version of the first view */
.first_view_page {
    height: clamp(26rem, 62svh, 40rem);
    min-height: 0;
}

.first_view_title {
    font-size: clamp(2.4rem, 5.4vw, 4.8rem);
    line-height: 1.05;
}

.first_view_lead {
    max-width: 40rem;
    margin-bottom: 0;
    line-height: 1.45;
}

.first_view_actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 1rem 2rem;
}

/* ---------- The venue: a fly-in from space to UCL East (home page; see flyin.js) ---------- */

/* The media is Google Earth Studio footage. Google's attribution is part of every frame and
   must stay on screen, so the posters crop towards it and flyin.js never draws it away.
   Without the fly-in (no script, reduced motion, Save-Data, no AVIF) the section is one
   screen showing the flight's last frame. */
.flyin {
    position: relative;
    height: calc(100svh - var(--header-compact));
    min-height: 30rem;
    overflow: hidden;
    background: #000;
    color: var(--white);
}

.flyin_stage {
    position: relative;
    display: flex;
    width: 100%;
    height: 100%;
}

.flyin_media {
    position: absolute;
    inset: 0;
    background: #000;
}

.flyin_media picture {
    display: contents;
}

.flyin_media img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: 80% 85%;           /* flyin.js aligns its frames the same way */
}

/* From 4:3 the frame can sit further right, clear of the text, and still show the attribution */
@media (min-aspect-ratio: 4/3) {
    .flyin_media img {
        object-position: 55% 85%;
    }
}

/* A shade behind the text, in the scrim's colour over the still of UCL East. Once the video
   has taken over it is a softer black, which fades with the text when the flight begins. It
   stops short of the attribution in the bottom right. */
.flyin_media::after {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(90deg, rgba(10, 12, 48, 0.86), rgba(10, 12, 48, 0.62) 30%, rgba(10, 12, 48, 0) 62%);
}

.flyin_drawn .flyin_media::after {
    background: linear-gradient(90deg, rgba(0, 0, 0, 0.62), rgba(0, 0, 0, 0) min(36rem, 52%));
    transition: opacity 0.9s ease;
}

/* On wide screens the text is a column at the left, beside the globe */
.flyin_content {
    position: relative;
    align-self: center;
    width: calc(var(--gutter) + 24vw);
    min-width: calc(var(--gutter) + 17rem);
    padding: 0 0 0 var(--gutter);
}

.flyin_heading {
    font-size: clamp(2.6rem, 4.4vw, 4.6rem);
    line-height: 1.05;
}

/* On tall screens the text sits at the top, above the globe */
@media (max-aspect-ratio: 9/10) {
    .flyin_media img {
        object-position: 50% 75%;
    }

    .flyin_media::after {
        background: linear-gradient(180deg, rgba(10, 12, 48, 0.86), rgba(10, 12, 48, 0.6) 26%, rgba(10, 12, 48, 0) 50%);
    }

    .flyin_drawn .flyin_media::after {
        background: linear-gradient(180deg, rgba(0, 0, 0, 0.7), rgba(0, 0, 0, 0) 46%);
    }

    .flyin_content {
        align-self: flex-start;
        width: 100%;
        min-width: 0;
        padding: 1.5rem var(--gutter);
    }

    .flyin_heading {
        font-size: clamp(2.2rem, 9vw, 3.4rem);
    }
}

/* flyin.js sizes and places the video like the poster, keeping the attribution on the stage */
.flyin_video {
    position: absolute;
    top: 0;
    left: 0;
    display: block;
    max-width: none;
    background: #000;
    visibility: hidden;
}

.flyin_labels {
    display: none;
}

/* With the fly-in, the stage is pinned under the condensed header from the moment it comes
   into view, and the page moves past it: About slides up off it, the flight plays while the
   stage stays for another 100svh of scrolling, and Date and venue slides up over it. The
   section starts a screen early, under About, so the stage never moves, and neither do
   Google's attribution or the heading, which therefore never cross each other. */
.flyin_on .flyin {
    height: calc(3 * (100svh - var(--header-compact)) + 100svh);
    min-height: 0;
    margin-top: calc(var(--header-compact) - 100svh);
    overflow: clip;
}

/* Every other section passes over the pinned stage */
.flyin_on main > section:not(.flyin) {
    position: relative;
    z-index: 1;
}

.flyin_on .flyin + section {
    margin-top: calc(var(--header-compact) - 100svh);
}

.flyin_on .flyin_stage {
    position: sticky;
    top: var(--header-compact);
    height: calc(100svh - var(--header-compact));
    min-height: 30rem;
    overflow: hidden;
}

/* As the flight begins, the heading lifts away and the shade goes with it */
.flyin_on .flyin_content {
    transition: opacity 0.9s ease, transform 0.9s ease, visibility 0s;
}

.flyin_playing .flyin_content {
    opacity: 0;
    transform: translateY(-3rem);
    visibility: hidden;
    transition: opacity 0.9s ease, transform 0.9s ease, visibility 0s linear 0.9s;
}

.flyin_playing .flyin_media::after {
    opacity: 0;
}

.flyin_drawn .flyin_video {
    visibility: visible;
}

.flyin_drawn .flyin_poster {
    visibility: hidden;                 /* the video has taken over */
}

.flyin_label {
    transition: opacity 0.6s ease;
}

/* While the flight holds the page, a fling on a touch screen is stopped (see flyin.js) */
@media (pointer: coarse) {
    .flyin_hold {
        overflow: hidden;
    }
}

/* Shown if a visitor tries to scroll on while the flight holds the page */
.flyin_hint {
    position: absolute;
    top: 1.4rem;
    left: var(--gutter);
    z-index: 2;
    margin: 0;
    color: #fff;
    font-size: 0.9rem;
    text-shadow: 0 0 2px rgba(0, 0, 0, 0.55), 0 1px 14px rgba(0, 0, 0, 0.6);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.4s ease;
}

.flyin_hinted .flyin_hint {
    opacity: 0.85;
}

.flyin_on .flyin_labels {
    display: block;
    position: absolute;
    inset: 0;
    pointer-events: none;
}

.flyin_label {
    position: absolute;
    top: 0;
    left: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    margin: 0;
    opacity: 0;
    white-space: nowrap;
    color: var(--white);
    text-shadow: 0 0 2px rgba(0, 0, 0, 0.55), 0 1px 14px rgba(0, 0, 0, 0.6);
    translate: -50% calc(-100% - 0.5rem);
}

/* A label near the right edge reads leftwards from its line */
.flyin_label_end {
    align-items: flex-end;
    text-align: right;
    translate: calc(-100% + 0.5px) calc(-100% - 0.5rem);
}

/* A hairline from the name down to the roof it names */
.flyin_label::after {
    content: "";
    width: 1px;
    height: 2.75rem;
    margin-top: 0.6rem;
    background: rgba(255, 255, 255, 0.8);
    box-shadow: 0 0 6px rgba(0, 0, 0, 0.45);
}

.flyin_label_name {
    font-family: var(--display);
    font-size: 1.25rem;
}

.flyin_label_use {
    margin-top: 0.3rem;
    font-size: 1rem;
    color: rgba(255, 255, 255, 0.9);
}

@keyframes first-view-drift {
    from {
        transform: translateY(0) scale(1.06);
    }

    to {
        transform: translateY(12vh) scale(1.12);
    }
}

@keyframes first-view-lift {
    from {
        opacity: 1;
        transform: none;
    }

    to {
        opacity: 0;
        transform: translateY(-4rem);
    }
}

/* ---------- Split sections: a text panel beside a photo that drifts as you scroll ---------- */

.split {
    display: flex;
    min-height: 36rem;
}

.split_panel {
    flex: 0 0 44%;
    display: flex;
    align-items: center;
    padding: var(--section) var(--gutter);
}

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

.split_text_right .split_panel {
    order: 2;
}

.split_photo {
    position: relative;
    flex: 1;
    overflow: hidden;
    background: var(--deep-navy);
    view-timeline-name: --photo;
}

.split_photo img {
    position: absolute;
    top: -10vh;
    left: 0;
    width: 100%;
    height: calc(100% + 20vh);
    object-fit: cover;
    animation: photo-drift linear both;
    animation-timeline: --photo;
}

@keyframes photo-drift {
    from {
        transform: translateY(-10vh);
    }

    to {
        transform: translateY(10vh);
    }
}

.panel_heading {
    margin: 0 0 1rem;
    font-size: clamp(2rem, 3.1vw, 2.75rem);
    line-height: 1.15;
}

.panel_sub {
    margin-bottom: 1.6rem;
    font-size: 1.4rem;
    line-height: 1.35;
}

.panel_sub.accent {
    font-family: var(--display);
    font-style: italic;
    font-size: 1.5rem;
    color: var(--accent);
}

.panel_link {
    margin-top: 2rem;
}

/* ---------- Date and venue ---------- */

#venue .split_panel {
    padding-top: 5rem;
    padding-bottom: 5rem;
}

.split_map {
    flex: 1;
    display: flex;
    background: var(--map-base);
}

.split_map iframe {
    flex: 1;
    width: 100%;
    min-height: 30rem;
    border: 0;
}

.details_list {
    display: grid;
    grid-template-columns: max-content 1fr;
    gap: 1rem 2.2rem;
    margin: 1.8rem 0 0;
}

.details_list dt {
    font-weight: 600;
}

.details_list dd {
    margin: 0;
    line-height: 1.5;
}

.details_list a {
    text-decoration: none;
    border-bottom: 1px solid currentColor;
}

/* ---------- Numbers ---------- */

/* figures sit on the left of their columns, starting on the gutter line like the rest of the page */
.numbers {
    padding: 5.5rem var(--gutter);
}

.numbers_heading {
    margin: 0 0 3rem;
    font-size: clamp(2rem, 3.1vw, 2.75rem);
    line-height: 1.15;
}

.numbers_list {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: minmax(0, 1fr);
    margin: 0;
    padding: 0;
    list-style: none;
}

.numbers_list > li {
    display: flex;
    flex-direction: column;
    padding: 0.4rem 2.5rem 0.6rem;
    border-left: 1px solid var(--hairline-dark);
}

.numbers_list > li:first-child {
    padding-left: 0;
    border-left: 0;
}

.numbers_figure {
    font-family: var(--display);
    font-size: clamp(2.8rem, 6vw, 4.5rem);
    line-height: 1;
    letter-spacing: 0.01em;
}

.numbers_label {
    max-width: 16rem;
    margin-top: 1.1rem;
    color: var(--on-dark-muted);
    line-height: 1.45;
}

.numbers_source {
    max-width: var(--measure-centred);
    margin-top: 3rem;
    font-size: 0.875rem;
    color: var(--on-dark-muted);
}

.numbers_source a {
    text-decoration: none;
    border-bottom: 1px solid currentColor;
}

/* ---------- Text band: a heading column beside a reading column ---------- */

.text_band {
    display: grid;
    grid-template-columns: 44% minmax(0, 1fr);
    padding: var(--section) 0;
}

.text_band_head {
    padding: 0 var(--gutter);
}

.text_band_head .panel_sub {
    max-width: var(--measure-panel);
    margin-bottom: 0;
}

/* the reading column starts on the same line as the photos in split sections */
.text_band_body {
    max-width: calc(36rem + var(--gutter));
    padding-right: var(--gutter);
}

.text_band_body .details_list {
    margin-top: 2rem;
}

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

/* ---------- Year seals ---------- */

.seals {
    padding: 3.5rem var(--gutter);
}

.seal_row {
    display: flex;
    justify-content: center;
    gap: clamp(1rem, 3.2vw, 3.25rem);
    margin: 0;
    padding: 0;
    list-style: none;
}

.seal_row img {
    width: clamp(3.4rem, 10vw, 8.5rem);
    height: auto;
    aspect-ratio: 1;
    clip-path: circle();
}

/* ---------- Delegates ---------- */

.delegates {
    padding: var(--section) var(--gutter) 5rem;
    text-align: center;
}

.delegates_text {
    max-width: var(--measure-centred);
    margin: 0 auto;
}

.band_heading {
    margin: 0 0 1rem;
    font-size: clamp(2rem, 3.3vw, 2.9rem);
    line-height: 1.15;
}

.delegates_map {
    position: relative;
    max-width: 1100px;
    margin: 2rem auto 0;
    view-timeline-name: --dotmap;
}

svg.dotmap {
    width: 100%;
    height: auto;
}

/* every dot on the map is the same size, lit or not */
svg.dotmap path {
    fill: none;
    stroke-linecap: round;
    stroke-width: 4.4;
}

path.dotmap_base {
    stroke: var(--map-base);
}

path.dotmap_hl {
    stroke: var(--blue-text);
    transition: stroke 0.2s ease;
}

g.dotmap_country {
    animation: dotmap-light linear both;
    animation-timeline: --dotmap;
}

/* Hovering (or tapping) near a lit country names it; site.js finds the nearest one. */
g.dotmap_country.is_active path.dotmap_hl {
    stroke: var(--navy);
}

.map_label {
    position: absolute;
    left: 0;
    top: 0;
    z-index: 2;
    margin: 0;
    padding: 0.45rem 0.75rem;
    border-radius: 2px;
    background: var(--navy);
    color: var(--white);
    font-size: 0.875rem;
    font-weight: 600;
    line-height: 1.2;
    white-space: nowrap;
    pointer-events: none;
    opacity: 0;
    transform: translate(-50%, calc(-100% - 0.35rem));
    transition: opacity 0.15s ease;
}

.map_label.is_visible {
    opacity: 1;
}

@keyframes dotmap-light {
    from {
        opacity: 0;
    }

    to {
        opacity: 1;
    }
}

/* ---------- University belt: two rows of names under the map, drifting slowly in opposite directions ---------- */

/* the belt runs edge to edge, past the band's side padding */
.belt {
    margin: 4.5rem calc(-1 * var(--gutter)) 0;
    overflow: hidden;
}

.belt_intro {
    margin: 0 0 1.75rem;
    font-family: var(--display);
    font-size: 1.15rem;
    font-style: italic;
}

.belt_row {
    display: flex;
    width: max-content;
    margin: 0;
    padding: 0;
    list-style: none;
    /* each row holds its names twice, so moving it by half its width loops without a seam */
    animation: belt-drift 120s linear infinite;
}

/* pointing at the belt holds it still, so a name can be read */
.belt:hover .belt_row {
    animation-play-state: paused;
}

.belt_row + .belt_row {
    margin-top: 1.1rem;
}

.belt_row li {
    padding: 0.2rem 2.25rem;
    border-left: 1px solid var(--hairline-light);
    font-family: var(--display);
    font-size: clamp(1.15rem, 1.9vw, 1.6rem);
    line-height: 1.3;
    white-space: nowrap;
}

.belt_row_reverse {
    animation-direction: reverse;
    animation-duration: 135s;
}

@keyframes belt-drift {
    from {
        transform: translateX(0);
    }

    to {
        transform: translateX(-50%);
    }
}

/* ---------- Testimonials: real answers from the feedback form, each under the question it answers ---------- */

/* on desktop the heading stays in view while the answers rise past it */
.voices .text_band_head {
    position: sticky;
    top: calc(var(--header-compact) + 3rem);
    align-self: start;
}

.quote {
    margin: 0;
}

.quote + .quote {
    margin-top: 3rem;
    padding-top: 3rem;
    border-top: 1px solid var(--hairline-light);
}

.quote_prompt {
    margin: 0 0 1rem;
    font-size: clamp(1.1rem, 1.7vw, 1.45rem);
    line-height: 1.45;
    letter-spacing: 0.02em;
}

.quote blockquote {
    margin: 0;
    font-family: var(--display);
    font-size: clamp(1.5rem, 2.6vw, 2rem);
    font-style: italic;
    line-height: 1.35;
    quotes: "\201C" "\201D";
}

/* the opening mark hangs outside the column, so the words line up with the question above */
.quote blockquote p {
    text-indent: -0.44em;
}

.quote blockquote p::before {
    content: open-quote;
}

.quote blockquote p::after {
    content: close-quote;
}

.quote figcaption {
    margin-top: 1.25rem;
    font-weight: 600;
    line-height: 1.4;
}

/* ---------- Speakers and workshops, coming soon ---------- */

.coming_soon {
    padding: 18vh var(--gutter) 20vh;
    text-align: center;
}

.coming_soon_pair {
    display: grid;
    grid-template-columns: 1fr 1fr;
    max-width: 72rem;
    margin: 0 auto;
}

.coming_soon_item {
    padding: 0.5rem 2rem;
}

.coming_soon_item + .coming_soon_item {
    border-left: 1px solid var(--hairline-dark);
}

.coming_soon_item h2 {
    font-size: clamp(2.4rem, 5.4vw, 4.8rem);
    line-height: 1.05;
}

.coming_soon_item p {
    margin-top: 1.1rem;
    font-size: clamp(1.1rem, 1.8vw, 1.4rem);
    color: var(--on-dark-muted);
}

.coming_soon_line {
    margin: 12vh 0 0;
    font-family: var(--display);
    font-size: clamp(2rem, 4.8vw, 3.8rem);
    font-style: italic;
    color: var(--accent);
}

/* "Coming soon." letters rise in one after another (site.js splits the line into letters) */
.coming_soon_line.letters_ready .coming_soon_char {
    display: inline-block;
    opacity: 0;
    transform: translateY(0.45em);
    filter: blur(8px);
    transition: opacity 0.9s cubic-bezier(0.2, 0.7, 0.2, 1),
                transform 0.9s cubic-bezier(0.2, 0.7, 0.2, 1),
                filter 0.9s cubic-bezier(0.2, 0.7, 0.2, 1);
    transition-delay: calc(var(--i) * 60ms);
}

.coming_soon_line.letters_in .coming_soon_char {
    opacity: 1;
    transform: none;
    filter: none;
}

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

.sponsors {
    padding: 5.5rem var(--gutter) 6.5rem;
    color: var(--ink);
    text-align: center;
}

.sponsor_grid {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 3rem 0;
    max-width: 72rem;
    margin: 3.5rem auto 0;
    padding: 0;
    list-style: none;
}

.sponsor_grid li {
    display: flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 calc(100% / 6);
    height: 4.5rem;
    padding: 0 1.25rem;
}

/* Logos are trimmed to their edges, then sized so each covers about the same area:
   a long wordmark comes out wide and low, a square mark small and tall. site.js sets --aspect
   (width / height) once each logo loads. Browsers without sqrt() keep the plain max-height rule. */
.sponsor_grid img {
    --logo-size: 4rem;
    --logo-max-height: 3rem;
    width: auto;
    width: min(100%, calc(var(--logo-size) * sqrt(var(--aspect, 3))), calc(var(--logo-max-height) * var(--aspect, 3)));
    max-width: 100%;
    height: auto;
    max-height: var(--logo-max-height);
    object-fit: contain;
    filter: grayscale(1) contrast(1.05);
    opacity: 0.78;
}

.sponsor_grid img.smaller {
    --logo-size: 3.4rem;
}

/* ---------- Committee: square portraits on the page grid, in the order of people.txt ---------- */

/* an inner page that opens on navy alone, with no photograph behind the title */
.first_view_plain {
    height: clamp(20rem, 48svh, 30rem);
}

.committee {
    padding: var(--section) var(--gutter);
}

/* a wrapping row rather than a grid, so a last row that isn't full sits in the centre */
.committee_grid {
    --columns: 4;
    --column-gap: 2rem;
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 3.5rem var(--column-gap);
    margin: 0;
    padding: 0;
    list-style: none;
}

.person {
    width: calc((100% - (var(--columns) - 1) * var(--column-gap)) / var(--columns));
}

/* the directors take two columns each, so the first row is the two of them */
.person_lead {
    width: calc((100% - var(--column-gap)) / 2);
}

.person_photo {
    aspect-ratio: 1;
    background: var(--band);
}

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

.person_name {
    margin-top: 1.1rem;
    font-size: 1.3rem;
    line-height: 1.25;
    color: var(--ink);
}

.person_lead .person_name {
    font-size: clamp(1.5rem, 2.2vw, 2rem);
}

.person_role {
    margin: 0.35rem 0 0;
    font-weight: 500;
    line-height: 1.35;
}

.person_course {
    margin: 0.15rem 0 0;
    font-size: 0.95rem;
    line-height: 1.4;
    opacity: 0.75;
}

.site_nav a[aria-current="page"] {
    border-bottom: 1px solid currentColor;
    padding-bottom: 2px;
}

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

.site_footer {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem 2rem;
    padding: 2.5rem var(--gutter) 3rem;
    background: var(--page);
    color: var(--blue-text);
    font-size: 0.875rem;
    font-weight: 400;
}

.site_footer p {
    margin: 0;
}

.site_footer ul {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem 1.75rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

.site_footer a {
    text-decoration: none;
    border-bottom: 1px solid var(--hairline-light);
    transition: border-color 0.2s ease;
}

.site_footer a:hover,
.site_footer a[aria-current="page"] {
    border-bottom-color: currentColor;
}

/* ---------- Reveal on scroll ---------- */

.reveal {
    animation: reveal linear both;
    animation-timeline: view();
    animation-range: entry 10% cover 40%;
}

@keyframes reveal {
    from {
        opacity: 0;
        transform: translateY(3rem);
    }

    to {
        opacity: 1;
        transform: none;
    }
}

/* ---------- Laptops: a narrower gutter, and the header kept on one line ---------- */

@media (min-width: 1001px) and (max-width: 1340px) {
    :root {
        --gutter: 3rem;
    }

    .site_header {
        gap: 1.5rem;
    }

    .site_nav ul {
        gap: 1.4rem;
    }

    .site_nav a {
        font-size: 1rem;
    }
}

@media (min-width: 1001px) and (max-width: 1180px) {
    :root {
        --gutter: 2.5rem;
    }

    .site_nav ul {
        gap: 0.8rem;
    }

    .site_nav a {
        font-size: 0.86rem;
    }

    .site_lockup {
        font-size: 0.86rem;
    }
}

/* ---------- Tablets and phones ---------- */

@media (max-width: 1000px) {
    :root {
        --gutter: 1.5rem;
        --section: 3.5rem;
        --header-full: 5rem;
        --header-compact: 3.5rem;
        --seal-full: 3.5rem;
        --seal-compact: 2.25rem;
    }

    /* the menu lines sit 0.6rem inside their button, so the button reaches past the gutter by that much */
    .site_header {
        gap: 1rem;
        padding: 0 calc(var(--gutter) - 0.6rem) 0 var(--gutter);
    }

    .site_brand {
        gap: 0.8rem;
    }

    .site_lockup {
        font-size: 0.74rem;
        letter-spacing: 0.05em;
    }

    @keyframes lockup-condense {
        to {
            font-size: 0.66rem;
        }
    }

    .site_menu_button {
        position: relative;
        display: block;
        width: 2.75rem;
        height: 2.75rem;
        margin-left: auto;
        padding: 0;
        border: 0;
        background: none;
        color: var(--white);
        cursor: pointer;
    }

    .menu_lines,
    .menu_lines::before,
    .menu_lines::after {
        position: absolute;
        left: 0.6rem;
        right: 0.6rem;
        height: 1.5px;
        background: currentColor;
        transition: transform 0.25s ease, opacity 0.25s ease;
    }

    .menu_lines {
        top: 50%;
    }

    .menu_lines::before,
    .menu_lines::after {
        content: "";
        left: 0;
        right: 0;
    }

    .menu_lines::before {
        top: -0.42rem;
    }

    .menu_lines::after {
        top: 0.42rem;
    }

    .menu_open .menu_lines {
        background: transparent;
    }

    .menu_open .menu_lines::before {
        transform: translateY(0.42rem) rotate(45deg);
    }

    .menu_open .menu_lines::after {
        transform: translateY(-0.42rem) rotate(-45deg);
    }

    .site_nav {
        position: absolute;
        top: 100%;
        left: 0;
        right: 0;
        max-height: 0;
        overflow: hidden;
        margin: 0;
        background: var(--navy);
        transition: max-height 0.3s ease;
    }

    .menu_open .site_nav {
        max-height: 24rem;
    }

    .site_nav ul {
        flex-direction: column;
        gap: 0;
        padding: 0 1rem 1rem;
    }

    .site_nav a {
        display: block;
        padding: 0.9rem 0;
        border-top: 1px solid var(--hairline-dark);
        font-size: 1.1rem;
    }

    .first_view {
        min-height: 30rem;
    }

    .first_view_content {
        padding: 0 var(--gutter) 3rem;
    }

    .first_view_actions {
        flex-direction: column;
        align-items: flex-start;
    }

    .split {
        flex-direction: column;
        min-height: 0;
    }

    .split_panel {
        flex: none;
        padding: 3rem var(--gutter);
    }

    #venue .split_panel {
        padding-top: 3rem;
        padding-bottom: 3rem;
    }

    .split_text_right .split_panel {
        order: 0;
    }

    .split_photo {
        order: -1;
        flex: none;
        height: 40vh;
    }

    .split_map iframe {
        min-height: 20rem;
    }

    .details_list {
        grid-template-columns: 1fr;
        gap: 0.2rem;
    }

    .details_list dd {
        margin-bottom: 0.9rem;
    }

    .numbers {
        padding: 3.5rem var(--gutter);
    }

    .numbers_list {
        grid-auto-flow: row;
        grid-template-columns: 1fr 1fr;
    }

    .numbers_list > li {
        padding: 1.6rem 0 1.6rem 1.25rem;
    }

    .numbers_list > li:nth-child(odd) {
        padding-left: 0;
        border-left: 0;
    }

    .numbers_list > li:nth-child(n + 3) {
        border-top: 1px solid var(--hairline-dark);
    }

    .numbers_list > li:nth-child(-n + 2) {
        padding-top: 0.4rem;
    }

    /* an odd last figure takes the full width rather than sitting alone in a half */
    .numbers_list > li:last-child:nth-child(odd) {
        grid-column: 1 / -1;
    }

    .numbers_label {
        margin-top: 0.7rem;
        font-size: 0.95rem;
    }

    .numbers_heading {
        margin-bottom: 2rem;
    }

    .text_band {
        grid-template-columns: 1fr;
        gap: 1.25rem;
        padding: 3.5rem var(--gutter);
    }

    .text_band_head,
    .text_band_body {
        padding: 0;
    }

    .seals {
        padding: 2.5rem var(--gutter);
    }

    .seal_row {
        flex-wrap: wrap;
        gap: 1.25rem 1.5rem;
        max-width: 20rem;
        margin: 0 auto;
    }

    .seal_row img {
        width: 5rem;
    }

    .delegates {
        padding: 4rem 1.25rem 3.5rem;
    }

    .delegates_map {
        margin-top: 1.75rem;
    }

    .voices .text_band_head {
        position: static;
    }

    .belt {
        margin: 3rem -1.25rem 0;
    }

    .belt_intro {
        margin-bottom: 1.25rem;
    }

    .belt_row li {
        padding: 0.15rem 1.4rem;
    }

    .quote + .quote {
        margin-top: 2.25rem;
        padding-top: 2.25rem;
    }

    svg.dotmap path {
        stroke-width: 5;
    }

    .coming_soon {
        padding: 14vh var(--gutter) 16vh;
    }

    .coming_soon_pair {
        grid-template-columns: 1fr;
    }

    .coming_soon_item {
        padding: 2.5rem 0;
    }

    .coming_soon_item + .coming_soon_item {
        border-left: 0;
        border-top: 1px solid var(--hairline-dark);
    }

    .coming_soon_line {
        margin-top: 6vh;
    }

    .sponsors {
        padding: 4rem var(--gutter) 4.5rem;
    }

    .sponsor_grid {
        gap: 2rem 0;
        margin-top: 2.5rem;
    }

    .sponsor_grid li {
        flex-basis: calc(100% / 3);
        height: 3.5rem;
        padding: 0 0.9rem;
    }

    .sponsor_grid img {
        --logo-size: 2.4rem;
        --logo-max-height: 2.2rem;
    }

    .sponsor_grid img.smaller {
        --logo-size: 2rem;
    }

    .site_footer {
        flex-direction: column;
        padding: 2rem var(--gutter) 2.5rem;
    }

    .first_view_plain {
        height: auto;
        min-height: 0;
        padding-top: 5rem;
    }

    .committee_grid {
        --columns: 3;
        --column-gap: 1.25rem;
        row-gap: 2.5rem;
    }

    .person_lead {
        width: calc((100% - (var(--columns) - 1) * var(--column-gap)) / var(--columns));
    }

    .person_lead .person_name {
        font-size: 1.3rem;
    }

    .site_nav a[aria-current="page"] {
        border-bottom: 0;
        padding-bottom: 0.9rem;
        font-weight: 500;
    }
}

@media (max-width: 640px) {
    .committee_grid {
        --columns: 2;
        --column-gap: 1rem;
        row-gap: 2rem;
    }

    .person_name,
    .person_lead .person_name {
        margin-top: 0.8rem;
        font-size: 1.1rem;
    }

    .person_role {
        font-size: 0.95rem;
    }

    .person_course {
        font-size: 0.85rem;
    }
}

/* ---------- INUGSC, 2011 to 2027: editions told as you scroll (story.js) ---------- */

/* Without story.js, or with reduced motion: a plain list of editions */
.story {
    padding: var(--section) var(--gutter);
}

.story_heading {
    margin: 0 0 2.5rem;
    font-size: clamp(2rem, 3.1vw, 2.75rem);
    line-height: 1.15;
}

.story_steps {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 3rem 4rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

.story_year {
    margin: 0;
    font-family: var(--display);
    font-size: clamp(2.4rem, 4vw, 3.4rem);
    line-height: 1;
    font-variant-numeric: lining-nums;
}

.story_edition {
    margin: 0.8rem 0 0;
    font-family: var(--display);
    font-style: italic;
    font-size: 1.1rem;
    color: rgba(255, 255, 255, 0.85);
}

.story_body {
    max-width: 30rem;
    margin: 0.9rem 0 0;
    font-size: clamp(1.05rem, 1.35vw, 1.25rem);
    line-height: 1.5;
    color: rgba(255, 255, 255, 0.9);
}

.story_seal {
    display: block;
    width: 4.5rem;
    height: auto;
    margin-top: 1.4rem;
    clip-path: circle(48.5%);           /* some seals come on a white square */
}

.story_numbers {
    display: flex;
    flex-wrap: wrap;
    gap: 1rem 3rem;
    margin: 1.8rem 0 0;
    padding: 0;
    list-style: none;
    font-size: 1rem;
    color: rgba(255, 255, 255, 0.85);
}

.story_figure {
    display: block;
    margin-bottom: 0.3rem;
    font-family: var(--display);
    font-size: clamp(2rem, 3.2vw, 2.8rem);
    line-height: 1;
    color: var(--white);
}

.story_rail {
    display: none;
}

/* With story.js: pinned, one screen of scrolling per edition */
.story_on .story {
    height: calc(100svh - var(--header-compact) + var(--story-steps, 9) * 55svh);
    padding: 0;
}

.story_on .story_stage {
    position: sticky;
    top: var(--header-compact);
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    height: calc(100svh - var(--header-compact));
    min-height: 32rem;
    overflow: hidden;
}

.story_on .story_text {
    display: flex;
    flex-direction: column;
    min-height: 0;
    padding: 4rem var(--gutter) 2.6rem;
}

.story_on .story_heading {
    margin: 0;
    font-size: clamp(1.4rem, 2vw, 1.75rem);
    color: rgba(255, 255, 255, 0.85);
}

.story_on .story_steps {
    position: relative;
    flex: 1;
    display: block;
}

.story_on .story_step {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    justify-content: center;
    opacity: 0;
    will-change: opacity, transform;
}

.story_on .story_year {
    font-size: clamp(5.5rem, 11vw, 11rem);
    letter-spacing: -0.01em;
}

.story_on .story_edition {
    margin-top: 1.2rem;
    font-size: clamp(1.15rem, 1.6vw, 1.4rem);
}

.story_on .story_seal {
    width: 5.5rem;
}

.story_on .story_rail {
    position: relative;
    display: flex;
    justify-content: space-between;
    gap: 0.8rem;
    margin: 0;
    padding: 1rem 0 0;
    list-style: none;
    border-top: 1px solid rgba(255, 255, 255, 0.22);
    font-size: 0.95rem;
    font-variant-numeric: lining-nums tabular-nums;
    color: rgba(255, 255, 255, 0.45);
}

/* The line fills as the story goes on */
.story_on .story_rail::before {
    content: "";
    position: absolute;
    top: -1px;
    left: 0;
    width: calc(var(--story-progress, 0) * 100%);
    height: 1px;
    background: var(--white);
}

.story_on .story_rail .story_rail_active {
    color: var(--white);
}

/* The right half: one panel per edition, each wiping up over the last as you scroll */
.story_on .story_panels {
    position: relative;
    display: block;
    overflow: hidden;
    background: var(--deep-navy);
}

.story_on .story_panel {
    position: absolute;
    inset: 0;
    margin: 0;
    overflow: hidden;
    clip-path: inset(100% 0 0 0);
    will-change: clip-path;
}

.story_on .story_panel:first-child {
    clip-path: none;
}

/* A photograph from that year's conference, drifting up within its frame */
.story_panel_photo img {
    position: absolute;
    top: -6%;
    left: 0;
    width: 100%;
    height: 112%;
    object-fit: cover;
    will-change: transform;
}

.story_panel figcaption {
    position: absolute;
    left: 1.4rem;
    bottom: 1.4rem;
    padding: 0.45rem 0.75rem;
    font-size: 0.9rem;
    color: var(--white);
    background: var(--deep-navy);
}

/* Years without photographs in the archive: the theme and that year's seal */
.story_panel_card {
    display: flex;
    flex-direction: column;
    justify-content: center;
    padding: 3rem clamp(2rem, 5vw, 5.5rem);
    color: var(--navy);
    background: var(--band);
}

.story_card_title {
    max-width: 13ch;
    margin: 0;
    font-family: var(--display);
    font-size: clamp(2.6rem, 5vw, 5.2rem);
    line-height: 1.08;
}

.story_card_line {
    margin: 1.3rem 0 0;
    font-family: var(--display);
    font-style: italic;
    font-size: clamp(1.05rem, 1.4vw, 1.25rem);
    color: var(--blue-text);
}

.story_card_seal {
    width: 8rem;
    height: auto;
    margin-top: 2.8rem;
    clip-path: circle(48.5%);
}

/* 2027: the committee who are organising it, in a grid around a square holding the seal and
   the caption. The seams are a solid colour, so the panel underneath never shows through. */
.story_on .story_panel_mosaic {
    display: grid;
    grid-template-columns: repeat(5, minmax(0, 1fr));
    grid-template-rows: repeat(5, minmax(0, 1fr));
    gap: 2px;
    background: var(--deep-navy);
}

/* Every portrait is cropped with the face the same size and its centre here
   (src/story/committee_crops.py), so the faces line up in tiles of any shape */
.story_panel_mosaic img {
    width: 100%;
    height: 100%;
    min-height: 0;
    object-fit: cover;
    object-position: 50% 42%;
}

.story_panel_mosaic .story_mosaic_seal,
.story_panel_mosaic figcaption {
    grid-column: 1 / 3;
    grid-row: 1 / 3;
}

.story_panel_mosaic .story_mosaic_seal {
    box-sizing: border-box;
    padding: 13% 24% 25%;
    object-fit: contain;
    background: var(--navy);
}

.story_panel_mosaic figcaption {
    position: relative;
    z-index: 1;
    inset: auto;
    align-self: end;
    justify-self: center;
    margin: 0 0.75rem 9%;
    padding: 0;
    text-align: center;
    background: none;
}

.story_panels {
    display: none;
}

@media (max-width: 1000px) {
    .story_steps {
        grid-template-columns: 1fr;
    }

    .story_on .story_stage {
        grid-template-columns: 1fr;
        grid-template-rows: 32% minmax(0, 1fr);
    }

    .story_on .story_heading,
    .story_on .story_numbers {
        display: none;
    }

    .story_on .story_panels {
        grid-row: 1;
    }

    .story_on .story_panel_card {
        padding: 1.4rem var(--gutter);
    }

    .story_on .story_card_title {
        max-width: none;
        font-size: clamp(1.6rem, 7vw, 2.4rem);
    }

    .story_on .story_card_line {
        margin-top: 0.5rem;
        font-size: 0.95rem;
    }

    .story_on .story_card_seal {
        display: none;
    }

    .story_panel figcaption {
        left: 0.75rem;
        bottom: 0.75rem;
        font-size: 0.78rem;
    }

    /* The panel is a short strip here: the committee in three rows of seven, with the caption
       in a band beneath them instead of the seal */
    .story_on .story_panel_mosaic {
        grid-template-columns: repeat(7, minmax(0, 1fr));
        grid-template-rows: repeat(3, minmax(0, 1fr)) auto;
    }

    .story_panel_mosaic .story_mosaic_seal {
        display: none;
    }

    .story_panel_mosaic figcaption {
        inset: auto;
        grid-column: 1 / -1;
        grid-row: 4;
        align-self: stretch;
        justify-self: stretch;
        margin: 0;
        padding: 0.4rem 0.75rem;
        text-align: left;
    }

    .story_on .story_text {
        grid-row: 2;
        padding: 1.6rem var(--gutter) 1.6rem;
    }

    .story_on .story_year {
        font-size: clamp(4.2rem, 19vw, 6rem);
    }

    .story_on .story_seal {
        width: 3.2rem;
        margin-top: 0.9rem;
    }

    .story_on .story_rail {
        gap: 0.3rem;
        font-size: 0.72rem;
    }

    .story_on .story_numbers {
        margin-top: 1rem;
        gap: 0.6rem 2rem;
    }
}

/* ---------- Reduced motion: everything sits still in its final place ---------- */

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

    .site_header,
    .site_seal,
    .site_lockup,
    .first_view_media img,
    .first_view_content,
    .split_photo img,
    g.dotmap_country,
    .reveal,
    .belt_row {
        animation: none;
    }

    .belt_row {
        flex-wrap: wrap;
        justify-content: center;
        width: auto;
        padding: 0 var(--gutter);
    }

    .belt_row + .belt_row {
        margin-top: 0.6rem;
    }

    .belt_row [aria-hidden="true"] {
        display: none;
    }

    .coming_soon_line.letters_ready .coming_soon_char {
        opacity: 1;
        transform: none;
        filter: none;
        transition: none;
    }

    .menu_lines,
    .menu_lines::before,
    .menu_lines::after,
    .site_nav,
    .map_label,
    path.dotmap_hl {
        transition: none;
    }
}
