:root {
    /* Partner logo strip, shared by the header and the footer so the two match.
       The marks vary wildly in aspect ratio (1:1 for the wheel up to 5.6:1 for
       the IGG lockup), so a height cap alone lets the widest one dominate the
       row: --logo-strip-w reins that in without shrinking the others. */
    --logo-strip-h: 56px;
    /* A plain length, not min(…, 100%): a percentage max-width on a flex item's
       image resolves against a width that is itself derived from the image, so
       the item box keeps the uncapped intrinsic width while only the image
       shrinks — leaving phantom space beside the widest logo. */
    --logo-strip-w: 260px;
    --logo-strip-center-h: 46px;
    --logo-strip-gap: 32px;
    /* A stacked lockup — emblem over a line or two of type — is close to
       square, so the height that suits the wide horizontal marks renders it
       at a fraction of their optical size. It gets a taller cap, derived from
       the same base so the two never drift apart. */
    --logo-strip-stacked-scale: 1.3;

    --color-text: #323232;
    --color-muted: #4a4a4a;
    --color-primary: #007f40;
    --color-surface: #ffffff;
    --color-surface-alt: #f6f7f9;
    --color-footer-bar: #eaeaea;
    --color-border: rgba(35, 35, 35, 0.12);
    --font-family-base: 'Open Sans', sans-serif;
    --font-family-nav: 'Noto Sans', sans-serif;

    /* Type scale — 1rem = 16px (browser default, so Bootstrap's rem-based
       spacing/gutter utilities resolve to their documented values) */
    --font-size-body: 1.0625rem;  /* 17px */
    --font-size-small: 0.875rem;  /* 14px */
    --font-size-h1: 3rem;         /* 48px */
    --font-size-h2: 2rem;         /* 32px */
    --font-size-h3: 1.5rem;       /* 24px */
    --font-size-h4: 1.25rem;      /* 20px */
    --font-size-h5: 1.125rem;     /* 18px */
    --font-size-h6: 1rem;         /* 16px */

    /* Design leading: a flat 46px across h1–h3, expressed as ratios so it
       scales with the responsive font sizes below. */
    --line-height-h1: 0.958;
    --line-height-h2: 1.438;
    --line-height-h3: 1.917;
    --line-height-heading: 1.2;
    --line-height-body: 1.4;

    /* -2% tracking (the px values in the design are all -0.02em) */
    --letter-spacing-heading: -0.02em;
}

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

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

body {
    margin: 0;
    min-height: 100%;
    font-family: var(--font-family-base);
    font-size: var(--font-size-body);
    font-style: normal;
    font-weight: 400;
    line-height: var(--line-height-body);
    color: var(--color-text);
    background-color: var(--color-surface);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

/* Open Sans everywhere — form controls do not inherit font by default */
button,
input,
select,
optgroup,
textarea {
    font-family: inherit;
    font-size: inherit;
    line-height: inherit;
}

h1,
h2,
h3,
h4,
h5,
h6,
p,
ul,
ol,
figure,
blockquote {
    margin: 0;
}

h1,
h2,
h3,
h4,
h5,
h6 {
    font-family: var(--font-family-base);
    font-style: normal;
    font-weight: 700;
    color: var(--color-text);
}

h1 {
    font-size: var(--font-size-h1);
    line-height: var(--line-height-h1);
    letter-spacing: var(--letter-spacing-heading);
}

h2 {
    font-size: var(--font-size-h2);
    line-height: var(--line-height-h2);
    letter-spacing: var(--letter-spacing-heading);
}

h3 {
    font-size: var(--font-size-h3);
    line-height: var(--line-height-h3);
    letter-spacing: var(--letter-spacing-heading);
}

h4 {
    font-size: var(--font-size-h4);
    line-height: var(--line-height-heading);
}

h5 {
    font-size: var(--font-size-h5);
    line-height: var(--line-height-heading);
}

h6 {
    font-size: var(--font-size-h6);
    line-height: var(--line-height-heading);
}

p,
li {
    font-size: var(--font-size-body);
    font-style: normal;
    font-weight: 400;
    line-height: var(--line-height-body);
}

p {
    color: var(--color-muted);
}

small,
.text-small {
    font-size: var(--font-size-small);
    line-height: var(--line-height-body);
}

strong,
b {
    font-weight: 700;
}

/*------------------------------------*\
    SCROLL ANIMATIONS (AOS)
\*------------------------------------*/

/* aos.css sets `opacity: 0` on every [data-aos] element as soon as it loads. If
   its JavaScript never runs — blocked, errored, or a slow connection that times
   out — that content stays permanently invisible. So the hiding is gated behind
   a class only JS can add: no .aos-ready means everything renders normally.
   Specificity (0,2,1) beats AOS's own [data-aos^=fade][data-aos^=fade] (0,2,0),
   and !important covers the per-animation transform rules too. */
html:not(.aos-ready) [data-aos] {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
}

/* AOS ships a 100px travel, which is far too much for a subtle reveal. */
html.aos-ready [data-aos="fade-up"] {
    transform: translate3d(0, 18px, 0);
}

html.aos-ready [data-aos="fade-down"] {
    transform: translate3d(0, -18px, 0);
}

html.aos-ready [data-aos="fade-right"] {
    transform: translate3d(-18px, 0, 0);
}

html.aos-ready [data-aos="fade-left"] {
    transform: translate3d(18px, 0, 0);
}

html.aos-ready [data-aos="zoom-in"] {
    transform: scale(0.97);
}

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

a {
    color: var(--color-text);
    text-decoration: none;
    transition: opacity 200ms ease, color 200ms ease;
}

a:hover,
a:focus {
    opacity: 0.8;
}

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

/* Bootstrap owns .container's box model (padding via --bs-gutter-x, auto
   margins). We only pin the max-width — Bootstrap would widen it to 1320px
   at xxl. 30px gutter keeps the original 15px each side. */
.container,
.container-fluid {
    --bs-gutter-x: 1.875rem;
}

.container {
    max-width: 1035px;
}


/* The menu bar stays on screen for the whole page. Rather than pinning the
   header at full height — which would park the tall partner-logo strip across
   the top for the entire visit — the header is pinned with a negative offset
   equal to that strip's height. The strip scrolls away exactly as it did, the
   bar comes to rest against the top of the window, and there it stays. JS keeps
   --header-strip-h in step; below xl the strip is display:none, it measures 0,
   and this is identical to the top: 0 the header already had there.

   z-index clears the hero: its marker panel sits at 25. */
.site-header {
    position: sticky;
    top: calc(-1 * var(--header-strip-h, 0px));
    width: 100%;
    background-color: var(--color-surface);
    border-bottom: 1px solid rgba(0, 0, 0, 0.10);
    z-index: 40;
}

/* Once the bar is resting on the top of the window it is floating over the
   page rather than sitting in the flow, so it casts. The bar keeps its height
   throughout: shrinking it on stick would change the offset every element
   below is measured against, and the hero would jog by the difference each
   time the class toggled. */
.header-bar {
    transition: box-shadow 220ms ease;
}

.site-header.is-stuck .header-bar {
    box-shadow: 0 10px 24px rgba(0, 0, 0, 0.09);
}

/* Anchored links (the hero's "read more" lands on /about/#text-figure) would
   otherwise scroll their target up underneath the pinned bar. */
html {
    scroll-padding-top: calc(var(--header-bar-h, 0px) + 16px);
}

/* Vertical padding lives on the wrappers, never on the .container element
   itself — a `padding: 18px 0` shorthand there zeroes Bootstrap's gutter and
   the bar goes flush to the viewport edge. */
.header-top {
    padding-top: 18px;
    padding-bottom: 18px;
}

.header-bar {
    padding-top: 14px;
    padding-bottom: 14px;
}

/* Compact brand mark — hidden at xl by .d-xl-none */
.header-brand {
    display: block;
    flex-shrink: 0;
    margin-right: 16px;
}

.header-brand img {
    max-height: 34px;
    width: auto;
}

.header-logos {
    gap: var(--logo-strip-gap);
}

/* The header strip only renders from xl up (see header.php), so it needs no
   responsive sizing of its own. Logos are sized by height rather than by equal
   flex columns — the old `flex: 1 1 130px` squashed the wide lettered marks
   into the same width as the round ones, shrinking them to half height. */
.header-logo {
    display: flex;
    align-items: center;
    justify-content: center;
    flex: 0 1 auto;
    min-width: 0;
}

.header-logo img {
    max-height: var(--logo-strip-h);
    max-width: var(--logo-strip-w);
    width: auto;
    object-fit: contain;
    display: block;
}

.header-logo.logo-center img {
    max-height: var(--logo-strip-center-h);
}

.header-logo.logo-stacked img {
    max-height: calc(var(--logo-strip-h) * var(--logo-strip-stacked-scale));
}

/* Layout comes from Bootstrap utilities in the markup
   (d-flex align-items-center justify-content-between) */
.header-inner {
    gap: 24px;
}

.site-nav {
    margin-left: auto;
    margin-right: auto;
}

.site-nav > ul {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    align-items: center;
    gap: 60px;
}

.site-nav li {
    position: relative;
    font-size: inherit;
}

.site-nav a {
    color: var(--color-text);
    font-family: var(--font-family-nav);
    font-size: var(--font-size-small);
    font-weight: 600;
    line-height: 1.2;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    display: inline-block;
    padding: 6px 0;
}

.site-nav a:hover,
.site-nav a:focus {
    color: var(--color-primary);
}

.site-nav .menu-item-has-children > a:hover::after,
.site-nav .menu-item-has-children > a:focus::after {
    color: var(--color-primary);
}

.site-nav .menu-item-has-children > a::after {
    /* use svg icon for dropdown indicator */
    content: '';
    display: inline-block;
    width: 14px;
    height: 10px;
    margin-left: 8px;
    vertical-align: middle;
    background-image: url('../img/icon-dropdown.svg');
    background-repeat: no-repeat;
    background-size: contain;
    opacity: 0.9;
    transition: transform 180ms ease, opacity 180ms ease;
}

.site-nav .sub-menu {
    display: block;
    position: absolute;
    top: calc(100% + 25px);
    padding: 27px 20px;
    left: 0;
    min-width: 300px;
    width: 100%;
    max-width: 320px;
    background: #ffffff;
    box-shadow: 0 20px 50px rgba(0, 0, 0, 0.08);
    border-radius: 12px;
    overflow: hidden;
    opacity: 0;
    visibility: hidden;
    transform: translateY(10px);
    transition: opacity 240ms ease, visibility 240ms ease, transform 240ms ease;
    z-index: 10;
    white-space: normal;
    box-sizing: border-box;
}

.site-nav .menu-item-has-children:hover > .sub-menu,
.site-nav .menu-item-has-children.sub-menu-active > .sub-menu {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
}

.site-nav .sub-menu > li {
    width: 100%;
    display: block;
    clear: both;
}

.site-nav .sub-menu a {
    display: block;
    padding: 12px 22px;
    font-size: var(--font-size-small);
    font-style: normal;
    font-weight: 600;
    line-height: 1.3;
    letter-spacing: normal;
    text-align: center;
    text-transform: none;
    color: var(--color-text);
    white-space: normal;
}

.site-nav .sub-menu li:last-child a {
    border-bottom: none;
}

button,
.btn {
    font-family: var(--font-family-base);
    font-size: var(--font-size-small);
    font-weight: 600;
    border-radius: 999px;
    border: none;
    cursor: pointer;
    transition: transform 200ms ease, opacity 200ms ease;
}

button:hover,
.btn:hover {
    transform: translateY(-1px);
    opacity: 0.92;
}

/* --- Burger toggle --- */

/* Visible by default; .d-xl-none hides it once the inline menu takes over */
.navbar-toggle {
    display: block;
    position: relative;
    width: 28px;
    height: 20px;
    padding: 0;
    border: none;
    border-radius: 0;
    background: transparent;
    cursor: pointer;
    flex-shrink: 0;
    z-index: 21;
}

.navbar-toggle:hover,
.navbar-toggle:focus {
    transform: none;
    opacity: 1;
}

.navbar-toggle span {
    position: absolute;
    left: 0;
    display: block;
    width: 100%;
    height: 2px;
    border-radius: 999px;
    background: var(--color-text);
    transition: top 260ms ease, transform 260ms ease, opacity 180ms ease, background-color 200ms ease;
}

.navbar-toggle span:nth-child(1) { top: 0; }
.navbar-toggle span:nth-child(2) { top: 9px; }
.navbar-toggle span:nth-child(3) { top: 18px; }

.navbar-toggle.navActive span:nth-child(1) {
    top: 9px;
    transform: rotate(45deg);
}

.navbar-toggle.navActive span:nth-child(2) {
    opacity: 0;
    transform: scaleX(0.2);
}

.navbar-toggle.navActive span:nth-child(3) {
    top: 9px;
    transform: rotate(-45deg);
}

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

/* Catches taps outside the panel to dismiss it. Deliberately transparent — the
   design darkens nothing, so this only needs to be hittable, not visible. */
.nav-overlay {
    position: fixed;
    inset: 0;
    background: transparent;
    opacity: 0;
    visibility: hidden;
    transition: visibility 300ms ease;
    z-index: 18;
}

.nav-overlay.navActive {
    opacity: 1;
    visibility: visible;
}

.site-footer {
    background-color: var(--color-surface);
}

/* --- Footer logo strip (white) --- */

.footer-top {
    padding: 56px 0 48px;
}

.footer-logos {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 24px 56px;
    /* Set on the strip rather than the image so each breakpoint restates one
       number and the stacked cap follows it. */
    --footer-logo-h: 69px;
}

.footer-logo {
    display: flex;
    align-items: center;
    justify-content: center;
    /* Lets a wide logo scale down instead of forcing the strip to wrap. */
    min-width: 0;
}

.footer-logo a {
    display: block;
    min-width: 0;
}

.footer-logo img {
    max-height: var(--footer-logo-h);
    max-width: 100%;
    width: auto;
    object-fit: contain;
    transition: opacity 240ms ease;
}

.footer-logo.logo-stacked img {
    max-height: calc(var(--footer-logo-h) * var(--logo-strip-stacked-scale));
}

.footer-logo-center img {
    max-height: 50px;
}

/* Desktop: keep the strip on one line, at the same sizes as the header strip.
   nowrap comes from the .flex-lg-nowrap utility in the markup — Bootstrap's
   flex utilities are !important, so it cannot be set from here. */
@media only screen and (min-width: 992px) {
    .footer-logos {
        gap: var(--logo-strip-gap);
        --footer-logo-h: var(--logo-strip-h);
    }

    .footer-logo {
        flex: 0 1 auto;
    }

    .footer-logo img {
        max-width: var(--logo-strip-w);
    }

    .footer-logo-center img {
        max-height: var(--logo-strip-center-h);
    }
}

.footer-logo a:hover img,
.footer-logo a:focus img {
    opacity: 0.75;
}

/* --- Footer bottom bar (light grey) --- */

.footer-bottom {
    background-color: var(--color-footer-bar);
    padding: 14px 0;
}

.footer-bottom-inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px 32px;
    flex-wrap: wrap;
}

.footer-copyright {
    margin: 0;
    color: var(--color-text);
    font-size: var(--font-size-small);
    font-weight: 400;
    line-height: 1.4;
}

.footer-sep {
    display: inline-block;
    padding: 0 6px;
    color: var(--color-text);
}

.footer-meta {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-left: auto;
}

.footer-social {
    display: inline-flex;
    align-items: center;
    color: var(--color-text);
    line-height: 0;
}

.footer-social-icon {
    display: block;
    width: 22px;
    height: 22px;
}

.footer-social:hover,
.footer-social:focus {
    color: var(--color-primary);
    opacity: 1;
}

.footer-nav a {
    color: var(--color-text);
    font-size: var(--font-size-small);
    font-weight: 400;
    line-height: var(--line-height-body);
}

.footer-nav a:hover,
.footer-nav a:focus {
    color: var(--color-primary);
    opacity: 1;
}

/*------------------------------------*\
    HOMEPAGE HERO — SCROLL ZOOM
\*------------------------------------*/

/* The runway. Its height is the scroll distance the reader travels while the
   hero is pinned; the sticky child is what they actually look at. Nothing in
   this chain may carry `overflow` other than `visible`, or position:sticky
   silently stops working. */
/* --hero-runway is a unitless count of viewport heights, set inline from ACF.
   Multiplying it here rather than printing a `vh` length inline is what lets a
   breakpoint shorten the run — an inline style would outrank a media query. */
.hero-zoom {
    position: relative;
    height: calc(var(--hero-runway, 420) * 1vh);
    /* No background of its own. The pinned frame inside carries the dark, and
       leaving the runway transparent means the strip below the frame shows the
       page surface — the same light the following section sits on — so the gap
       reads as the page continuing rather than as a black bar under the hero. */

    /* Tuning knobs. JS reads these once per resize, so the whole animation can
       be retimed from CSS without touching a line of script. */
    --hero-bg: #050a08;
    --hero-green: #00d46b;

    /* Where the lake sits on screen, and the box a layer occupies at scale 1.
       A layer is square, so one length covers both axes. */
    --anchor-x: 58%;
    --anchor-y: 47%;
    --layer-base: max(100vw, 100vh);

    /* How much of the window the pinned hero occupies. */
    --hero-view: 90vh;

    /* The camera pull-back at each end of the scroll, as multipliers on
       --layer-base. 0.27 opens on a globe filling about a quarter of the frame,
       per the design. 2.2 settles on a view roughly 420km across, so the lake
       reads whole with room around it rather than running off the edges. */
    --fill-start: 0.27;
    --fill-end: 2.2;

    /* Depth reached at the end of the scroll, in octaves below layer one.
       Matches the closest layer's own depth, so the run ends on that layer's
       native resolution rather than pushing past it into mush. */
    --zoom-end: 3.8;

    /* How long a layer takes to fade in, in octaves, once it is big enough to
       cover the frame. This is the sharpness dial — a layer is crispest the
       moment it covers and only gets more upscaled after, so a shorter fade
       means a sharper composite. Below about 0.3 the hand-over reads as a cut. */
    --fade-octaves: 0.5;

    /* The ground tilts away as the camera descends, so the last stretch reads
       as flying down toward the lake rather than scaling a photograph. It stays
       flat while the globe is still the subject — a tilted planet just looks
       wrong — and eases in over the second half of the run.

       Anchoring survives it: the tilt rotates each layer about its own centre,
       which is the same point the scale pivots on, and the perspective origin
       sits on that point too. A point at the origin with no depth projects to
       itself, so the lake does not move. */
    --tilt-max: 12deg;
    --hero-perspective: 130vh;

    /* How the scroll is spent. 1 gives a constant zoom rate, which is
       geometrically correct but rushes the part that carries the idea — the
       globe hanging in black, growing as you fall toward it. At 1.7 that
       approach takes roughly half the run, matching the reference recording.
       Higher lingers on the planet, lower gets to the ground sooner. */
    --zoom-gamma: 1.7;

    /* Camera drift across the approach, as fractions of --layer-base at the
       peak of a half-sine over --pan-settle (positive being right and down).
       Held at zero: an arcing camera swung the globe left and then back right
       on the way in, and the drift read as the subject wandering rather than as
       a camera move. The descent is dead straight, so the globe stays put and
       only grows. The mechanism is still here — give either axis a value like
       0.10 to bring the arc back. */
    --pan-x-start: 0;
    --pan-y-start: 0;
    --pan-settle: 0.45;
}

/* The header is not sticky, so for the first couple of hundred pixels of scroll
   the hero shares the viewport with it. Sizing to the space actually left over
   — JS keeps --hero-offset in step — means the scroll cue and the credit line
   are on screen from the first paint rather than hidden below the fold, and the
   hero grows to full height as the header leaves. */
.hero-zoom-sticky {
    position: sticky;
    /* Rests against the underside of the pinned menu bar, not the window. */
    top: var(--header-bar-h, 0px);
    /* Deliberately short of the full viewport, so the band underneath tells the
       reader the page continues rather than presenting a wall. Subtracting the
       header gap keeps the bottom edge at --hero-view measured from the top of
       the window, whether or not the header is still on screen.

       It also buys a beat at the end: the run reaches full zoom while the hero
       is still pinned, and the leftover 10vh of scroll walks the next section
       up into frame underneath it. */
    height: calc(
        var(--hero-view, 90vh) - max(var(--hero-offset, 0px), var(--header-bar-h, 0px))
    );
    overflow: hidden;
    background: var(--hero-bg);
    isolation: isolate;
}

/* Legibility scrim behind the copy. Sits above the imagery and below the
   markers, and only earns its opacity as the view brightens — see heroRender. */
.hero-zoom-sticky::after {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 1;
    pointer-events: none;
    background: linear-gradient(
        100deg,
        rgba(2, 8, 5, 0.92) 0%,
        rgba(2, 8, 5, 0.55) 34%,
        rgba(2, 8, 5, 0) 62%
    );
    opacity: var(--scrim-o, 0);
}

/* --- The layer stack --- */

.hero-zoom-stage {
    position: absolute;
    inset: 0;
    z-index: 0;
    perspective: var(--hero-perspective, 130vh);
    perspective-origin: var(--anchor-x) var(--anchor-y);
}

/* Each layer is square and centred on the lake, so transform-origin 50% 50%
   plus translate(-50%, -50%) parks the lake on the anchor at every scale. That
   identity is the whole mechanism — see the note in template-home.php. */
/* The global `img { max-width: 100% }` would silently clamp a layer to the
   stage width. On a landscape viewport --layer-base already equals that, so the
   bug hides; in portrait it halves the layer and the framing collapses. */
.hero-layer {
    position: absolute;
    left: var(--anchor-x);
    top: var(--anchor-y);
    width: var(--layer-base);
    max-width: none;
    height: auto;
    transform-origin: 50% 50%;
    /* The pan sits outermost so it reads as a screen-space camera move rather
       than sliding the image inside its own frame. The markers carry the same
       offset, so the pin does not come off the lake. */
    transform:
        translate(var(--pan-x, 0px), var(--pan-y, 0px))
        translate(-50%, -50%)
        rotateX(var(--tilt, 0deg))
        scale(var(--s, 1));
    opacity: var(--o, 0);
    pointer-events: none;
    user-select: none;
    will-change: transform, opacity;
}

/* No JS, or reduced motion: the closest layer stands in as a still hero, so the
   section is never blank. JS adds .is-live and takes over from there. */
.hero-zoom:not(.is-live) .hero-layer--final {
    --s: 1.9;
    --o: 1;
}

/* --- Mongolia --- */

/* Sits over the imagery and under the markers. Deliberately outside the tilted
   stage: the border is reprojected point by point in JS, tilt included, so
   letting CSS tilt it as well would bend it twice and thin the stroke as the
   ground leans away. It carries the same pan the markers do, for the same
   reason — it has to travel with the ground, not with the frame. */
.hero-outline {
    position: absolute;
    inset: 0;
    z-index: 1;
    width: 100%;
    height: 100%;
    overflow: visible;
    pointer-events: none;
    opacity: var(--outline-o, 0);
    transform: translate(var(--pan-x, 0px), var(--pan-y, 0px));
}

/* Two strokes, not one. A single line vanishes wherever the terrain beneath it
   happens to match — and over a whole country it will match somewhere. The dark
   casing underneath gives the bright line something to read against on snow,
   steppe and water alike. */
/* A wash rather than a colour. Enough to read the country as one piece at a
   glance, light enough that the terrain inside it is still the subject. */
.hero-outline-fill {
    fill: var(--hero-green, #00d46b);
    fill-opacity: 0.10;
    stroke: none;
}

.hero-outline-casing {
    stroke: rgba(0, 0, 0, 0.55);
    stroke-width: 6;
    stroke-linejoin: round;
    stroke-linecap: round;
}

.hero-outline-line {
    stroke: #ffffff;
    stroke-width: 2;
    stroke-linejoin: round;
    stroke-linecap: round;
}

/* No JS: nothing has projected the path, so there is nothing to show. */
.hero-zoom:not(.is-live) .hero-outline {
    display: none;
}

/* --- Markers --- */

/* Markers live outside the stage so they are never clipped by a layer, and are
   placed in px from the anchor by JS rather than in percentages of an image. */
.hero-zoom-markers {
    position: absolute;
    inset: 0;
    z-index: 2;
    pointer-events: none;
    /* Same camera move as the layers — see .hero-layer. */
    transform: translate(var(--pan-x, 0px), var(--pan-y, 0px));
}

.hero-glow,
.hero-marker {
    position: absolute;
    left: var(--anchor-x);
    top: var(--anchor-y);
    transform: translate(var(--mx, 0px), var(--my, 0px));
    opacity: var(--mo, 1);
}

/* Zero-size anchor: the marker's point lands exactly here, and the button is
   offset from it so the pin tip rather than the label sits on the spot. */
.hero-marker {
    width: 0;
    height: 0;
    pointer-events: auto;
}

.hero-marker[hidden] {
    display: none;
}

/* Without JS nothing has placed the markers, so every one of them would sit on
   the anchor in a heap. Only the primary marker is meaningful in that state —
   it is the one the anchor belongs to. */
.hero-zoom:not(.is-live) .hero-marker--secondary,
.hero-zoom:not(.is-live) .hero-glow ~ .hero-glow {
    display: none;
}

/* The glow scales with the zoom so it reads as light on the ground rather than
   a sticker on the glass. */
.hero-glow {
    width: 400px;
    height: 400px;
    margin: -200px 0 0 -200px;
    border-radius: 50%;
    background: radial-gradient(50% 50% at 50% 50%, rgba(0, 212, 107, 0.50) 0%, rgba(0, 212, 107, 0.00) 100%);
    transform: translate(var(--mx, 0px), var(--my, 0px)) scale(var(--gs, 1));
    pointer-events: none;
    z-index: 1;
}

.hero-marker-btn {
    position: absolute;
    left: 0;
    bottom: 0;
    display: flex;
    align-items: center;
    gap: 10px;
    /* negative half the icon width — centres the pin on the x coordinate */
    margin-left: calc(var(--marker-size, 44px) / -2);
    padding: 0;
    border: none;
    border-radius: 999px;
    background: transparent;
    white-space: nowrap;
    text-align: left;
    transition: transform 200ms ease;
}

.hero-marker--city .hero-marker-btn {
    gap: 4px;
}

button.hero-marker-btn {
    cursor: pointer;
}

button.hero-marker-btn:hover,
button.hero-marker-btn:focus-visible {
    transform: translateY(-2px);
    opacity: 1;
}

.hero-marker-icon,
.hero-marker-icon iconify-icon {
    display: block;
    width: var(--marker-size, 44px);
    height: var(--marker-size, 44px);
    font-size: 24px;
}

.hero-marker--pin .hero-marker-icon iconify-icon {
    font-size: 44px;
}

.hero-marker-icon {
    flex-shrink: 0;
    color: var(--hero-green);
    filter: drop-shadow(0 5px 10px rgba(0, 0, 0, 0.55));
}

.hero-marker-label {
    color: #ffffff;
    font-size: var(--font-size-h5);
    font-weight: 700;
    line-height: 1.2;
    text-shadow: 0 2px 10px rgba(0, 0, 0, 0.7);
}

/* The city marker is centred on its point rather than hanging above it */
.hero-marker--city {
    --marker-size: 26px;
}

.hero-marker--city .hero-marker-btn {
    transform: translateY(50%);
}

.hero-marker--city .hero-marker-icon {
    color: #ffffff;
    filter: drop-shadow(0 2px 6px rgba(0, 0, 0, 0.6));
}

.hero-marker--city .hero-marker-label {
    font-size: var(--font-size-h6);
    font-weight: 600;
}

/* Pulse ring, centred on the pin head — the marker glyph's circle sits at
   9/24 of the icon box, so it tracks --marker-size. */
.hero-marker--pin .hero-marker-btn::before {
    content: '';
    position: absolute;
    left: calc(var(--marker-size, 44px) / 2);
    top: calc(var(--marker-size, 44px) * 0.375);
    width: calc(var(--marker-size, 44px) * 0.5);
    height: calc(var(--marker-size, 44px) * 0.5);
    transform: translate(-50%, -50%);
    border-radius: 50%;
    background: var(--hero-green);
    opacity: 0.35;
    animation: heroPulse 2.4s ease-out infinite;
    pointer-events: none;
}

@keyframes heroPulse {
    0%   { transform: translate(-50%, -50%) scale(0.6); opacity: 0.45; }
    70%  { transform: translate(-50%, -50%) scale(2.6); opacity: 0; }
    100% { transform: translate(-50%, -50%) scale(2.6); opacity: 0; }
}

/* --- Marker panel --- */

.hero-marker-panel {
    position: absolute;
    left: 18px;
    top: 14px;
    width: 260px;
    padding: 18px 20px;
    background: #ffffff;
    border-radius: 12px;
    box-shadow: 0 18px 44px rgba(0, 0, 0, 0.32);
    z-index: 3;
}

.hero-marker-panel[hidden] {
    display: none;
}

.hero-marker-panel-title {
    margin-bottom: 8px;
    font-size: var(--font-size-h6);
    line-height: 1.25;
    letter-spacing: normal;
}

.hero-marker-panel p {
    font-size: var(--font-size-small);
    line-height: 1.45;
}

.hero-marker-panel-link {
    display: inline-block;
    margin-top: 12px;
    color: var(--color-primary);
    font-size: var(--font-size-small);
    font-weight: 700;
}

/* --- Copy --- */

.hero-zoom-copy {
    position: absolute;
    left: 0;
    right: 0;
    top: 50%;
    transform: translateY(-50%);
    z-index: 3;
    pointer-events: none;
}

.hero-zoom-copy a,
.hero-zoom-copy button {
    pointer-events: auto;
}

.hero-title {
    line-height: 1.25;
    color: #ffffff;
    text-shadow: 0 2px 24px rgba(0, 0, 0, 0.6);
}

.hero-title-main,
.hero-title-accent {
    display: block;
}

.hero-title-accent {
    color: var(--hero-green);
    font-style: italic;
}

.hero-eyebrow {
    display: flex;
    align-items: center;
    gap: 16px;
    margin-top: 18px;
    margin-bottom: 0;
    color: rgba(255, 255, 255, 0.72);
    font-size: var(--font-size-small);
    font-weight: 700;
    letter-spacing: 0.18em;
    text-transform: uppercase;
}

.hero-eyebrow-rule {
    display: block;
    width: 56px;
    height: 2px;
    flex-shrink: 0;
    background: var(--hero-green);
}

/* --- Chrome: cue, reset, credit --- */

.hero-zoom-cue {
    position: absolute;
    left: 50%;
    bottom: 0;
    transform: translateX(-50%);
    margin: 0;
    z-index: 3;
    color: rgba(255, 255, 255, 0.6);
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.22em;
    text-transform: uppercase;
    text-align: center;
    pointer-events: none;
    opacity: var(--cue-o, 1);
    transition: opacity 300ms ease;
}

/* The rule under the cue doubles as the "keep going" gesture. */
.hero-zoom-cue::after {
    content: '';
    display: block;
    width: 1px;
    height: 54px;
    margin: 14px auto 0;
    background: linear-gradient(to bottom, rgba(255, 255, 255, 0.55), rgba(255, 255, 255, 0));
}

/* Bottom left. It used to hang off the anchor, which put it in the middle of
   the picture and moved it whenever the composition was retuned. The corner is
   out of the way of the subject, and the other two corners are taken — the
   credit sits bottom right and the cue is centred between them. */
.hero-zoom-reset {
    position: absolute;
    left: 18px;
    bottom: 16px;
    z-index: 4;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 52px;
    height: 52px;
    padding: 0;
    border: 1px solid rgba(255, 255, 255, 0.22);
    border-radius: 50%;
    background: rgba(0, 0, 0, 0.42);
    backdrop-filter: blur(6px);
    color: #ffffff;
    cursor: pointer;
    opacity: 0;
    transition: opacity 260ms ease, background-color 200ms ease, transform 200ms ease;
}

.hero-zoom-reset[hidden] {
    display: none;
}

.hero-zoom-reset.is-shown {
    opacity: 1;
}

.hero-zoom-reset:hover,
.hero-zoom-reset:focus-visible {
    background: rgba(0, 0, 0, 0.66);
    transform: scale(1.06);
}

.hero-zoom-credit {
    position: absolute;
    right: 14px;
    bottom: 10px;
    margin: 0;
    z-index: 3;
    color: rgba(255, 255, 255, 0.45);
    font-size: 0.6875rem;
    line-height: 1.3;
    pointer-events: none;
}

/* --- Reduced motion --- */

/* No pinning, no runway, no zoom: the closest layer becomes a plain still hero
   with the pin and its panel intact. */
@media (prefers-reduced-motion: reduce) {
    /* Matches the pinned height, so the still sits the same way on the page
       and does not leave a strip of surface under itself. */
    .hero-zoom {
        height: var(--hero-view, 90vh);
    }

    /* Nothing is pinned here, so the offsets that keep the pinned hero clear of
       the menu bar would only push the still down the page and leave a gap
       above it. */
    .hero-zoom-sticky {
        position: relative;
        top: 0;
        height: var(--hero-view, 90vh);
    }

    .hero-zoom-cue,
    .hero-zoom-reset {
        display: none;
    }

    .hero-marker--pin .hero-marker-btn::before {
        animation: none;
    }
}
.home-content {
    padding-top: 40px;
    padding-bottom: 60px;
}

/*------------------------------------*\
    PAGE BANNER
\*------------------------------------*/

.page-banner {
    position: relative;
    display: flex;
    align-items: center;
    min-height: 356px;
    overflow: hidden;
}

.page-banner-image {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center;
}

/* Figma: rgba(0, 0, 0, 0.10) over the photo */
.page-banner-overlay {
    position: absolute;
    inset: 0;
    background: rgba(0, 0, 0, 0.20);
}

.page-banner-inner {
    position: relative;
    z-index: 1;
    display: flex;
    justify-content: center;
    width: 100%;
}

/* Figma: 509 x 112, 2px solid #FFF, radius 10px */
.page-banner-box {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: min(509px, 100%);
    min-height: 112px;
    padding: 20px 40px;
    border: 2px solid #ffffff;
    border-radius: 10px;
}

/* The design's 48px / 700 / 46px / -0.96px is exactly the h1 token, stated here
   rather than inherited because single entries render this as a <p> — their h1
   is the headline in the body. */
.page-banner-title {
    margin: 0;
    color: #ffffff;
    font-family: var(--font-family-nav);
    font-size: var(--font-size-h1);
    font-weight: 700;
    line-height: var(--line-height-h1);
    letter-spacing: var(--letter-spacing-heading);
    text-align: center;
}

@media only screen and (max-width: 991.98px) {
    .page-banner {
        min-height: 260px;
    }
    .page-banner-box {
        min-height: 92px;
        padding: 18px 28px;
    }
    .site-nav .menu-item-has-children > a::after{
        width: 11px;
        height: 7px;
    }
}

@media only screen and (max-width: 575.98px) {
    .page-banner {
        min-height: 200px;
    }
    .page-banner-box {
        min-width: 100%;
        min-height: 76px;
        padding: 14px 18px;
    }
}

.page-title {
    margin-bottom: 24px;
}

/*------------------------------------*\
    SINGLE ENTRY
\*------------------------------------*/

/* Shared by posts and every carousel post type — news, media, publications,
   projects, other links, the data portal. One measured column inside the
   container, so a short syndicated item still reads as a proper page. */

.single-entry-body {
    padding-top: 48px;
}

.single-entry-inner {
    max-width: 760px;
    margin: 0 auto;
}

.single-entry-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px;
    margin-bottom: 16px;
    color: var(--color-muted);
    font-size: var(--font-size-small);
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

/* h2 scale, not h1: the banner above already carries the page's h1 size, and
   at 48px a long syndicated headline swamps the column. */
.single-entry-title {
    margin-bottom: 26px;
    font-size: var(--font-size-h2);
    line-height: var(--line-height-heading);
}

.single-entry-figure {
    margin-bottom: 30px;
    border-radius: 12px;
    overflow: hidden;
    box-shadow: 0 4px 18px rgba(0, 0, 0, 0.10);
}

.single-entry-figure img {
    width: 100%;
    height: auto;
}

/* Logo card types supply artwork, not a photo — so it sits on a tint at its
   own proportions rather than being stretched across the column. */
.single-entry-figure--logo {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 30px;
    border: 1px solid var(--color-border);
    background: var(--color-surface-alt);
    box-shadow: none;
}

.single-entry-figure--logo img {
    width: auto;
    max-height: 130px;
}

/* Citation details on a publication — a two-column definition list that stacks
   on small screens. */
.single-entry-citation {
    display: grid;
    grid-template-columns: max-content 1fr;
    gap: 6px 20px;
    margin: 0 0 30px;
    padding: 18px 20px;
    border-left: 4px solid var(--color-primary);
    background: var(--color-surface-alt);
    font-size: var(--font-size-small);
}

.single-entry-citation dt {
    color: var(--color-muted);
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

.single-entry-citation dd {
    margin: 0;
}

.single-entry-content {
    margin-bottom: 32px;
}

.single-entry-cta-wrap {
    margin-bottom: 28px;
}

/* The page's primary action: same green pill as the cards, sized up so it reads
   as the thing to click. */
.single-entry-cta {
    display: inline-flex;
    align-items: center;
    gap: 9px;
    padding: 15px 32px;
    background: var(--color-primary);
    color: #ffffff;
    font-size: var(--font-size-body);
    font-weight: 700;
    line-height: 1;
    letter-spacing: 0.04em;
}

.single-entry-cta:hover,
.single-entry-cta:focus {
    color: #ffffff;
    opacity: 0.92;
}

.single-entry-cta svg {
    flex-shrink: 0;
    transition: transform 180ms ease;
}

.single-entry-cta:hover svg,
.single-entry-cta:focus-visible svg {
    transform: translate(2px, -2px);
}

/* A download arrow points down, so the lift on hover would fight it */
.single-entry-cta[download]:hover svg,
.single-entry-cta[download]:focus-visible svg {
    transform: translateY(2px);
}

.single-entry-back a,
.single-entry-edit a {
    color: var(--color-primary);
    font-size: var(--font-size-small);
    font-weight: 600;
}

.single-entry-edit {
    margin-top: 8px;
    font-size: var(--font-size-small);
}

/* --- Other entries grid --- */

/* Tinted band so the tail of the page separates from the article above it
   without needing a rule. */
.section-related {
    margin-top: 8px;
    border-top: 1px solid var(--color-border);
    background: var(--color-surface-alt);
}

.related-grid {
    row-gap: 30px;
}

/* Cards are flex columns that pin their link to the base — they need the full
   height of the row to do it. */
.related-grid-item-inner {
    display: flex;
    height: 100%;
}

@media only screen and (max-width: 767.98px) {
    .single-entry-body {
        padding-top: 36px;
    }
    .single-entry-cta {
        width: 100%;
        justify-content: center;
    }
}

/* --- Archive listing --- */

/* Shares the card grid with the "Other entries" block above */
.archive-description {
    max-width: 760px;
    margin: 0 auto 36px;
}

/* --- Publication filters --- */

/* Plain GET form, so each filtered view is a linkable URL. Laid out as a single
   wrapping row of labelled controls above the grid. */
.pub-filters {
    margin-bottom: 34px;
    padding: 20px 22px;
    border: 1px solid var(--color-border);
    border-radius: 10px;
    background: var(--color-surface-alt);
}

.pub-filters-row {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 16px;
}

/* min-width: 0 is what stops the controls overlapping. A search input carries an
   intrinsic minimum width from its default `size`, and a flex item will not
   shrink below that — so the field grew past its own column and sat on top of
   the one beside it. Widths come from the flex basis instead. */
.pub-filter {
    display: flex;
    flex-direction: column;
    flex: 1 1 150px;
    gap: 6px;
    min-width: 0;
}

/* Twice the share of the leftover space: they hold free text, not a short label.
   The keyword box leads the row and is given the widest basis of the set — it is
   the control most people reach for first. */
.pub-filter--keyword {
    flex: 2 1 240px;
}

.pub-filter--author {
    flex: 2 1 200px;
}

/* Wide enough for its longest option — a <select> truncates its own text rather
   than ellipsising it, so the room has to come from the layout. */
.pub-filter--sort {
    flex: 1.4 1 175px;
}

.pub-filter label {
    color: var(--color-muted);
    font-size: var(--font-size-small);
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

.pub-filter select,
.pub-filter input[type="search"] {
    width: 100%;
    min-width: 0;
    /* normalize.css forces content-box on search inputs, and `input[type=...]`
       outranks the global `*` border-box rule — so width: 100% came out 30px
       (the padding plus borders) wider than the column and sat over the next
       control. Restated here with matching specificity. */
    box-sizing: border-box;
    height: 44px;
    padding: 0 14px;
    border: 1px solid var(--color-border);
    border-radius: 6px;
    background: var(--color-surface);
    color: var(--color-text);
    font-size: var(--font-size-small);
}

.pub-filter select:focus,
.pub-filter input[type="search"]:focus {
    outline: 2px solid var(--color-primary);
    outline-offset: 1px;
}

/* Sized by its contents — the button should not stretch with the fields */
.pub-filter--actions {
    flex: 0 0 auto;
    flex-direction: row;
    align-items: center;
    gap: 14px;
}

.pub-filters-submit {
    height: 44px;
    padding: 0 26px;
    background: var(--color-primary);
    color: #ffffff;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

.pub-filters-reset {
    color: var(--color-primary);
    font-size: var(--font-size-small);
    font-weight: 600;
    text-decoration: underline;
}

.pub-filters-count {
    margin-top: 14px;
    color: var(--color-muted);
    font-size: var(--font-size-small);
}

@media only screen and (max-width: 575.98px) {
    .pub-filter,
    .pub-filter--actions {
        width: 100%;
    }
    .pub-filters-submit {
        flex: 1 1 auto;
    }
}

/* Bootstrap's .pagination expects a list; this is paginate_links() output, so
   the layout is set here rather than inherited. */
.pagination {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 8px;
    margin-top: 40px;
}

.pagination .page-numbers {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 40px;
    height: 40px;
    padding: 0 12px;
    border: 1px solid var(--color-border);
    border-radius: 999px;
    color: var(--color-text);
    font-size: var(--font-size-small);
    font-weight: 600;
}

.pagination .page-numbers:hover,
.pagination .page-numbers:focus {
    border-color: var(--color-primary);
    color: var(--color-primary);
    opacity: 1;
}

.pagination .page-numbers.current {
    border-color: var(--color-primary);
    background: var(--color-primary);
    color: #ffffff;
}

.pagination .page-numbers.dots {
    border-color: transparent;
}

/*------------------------------------*\
    FLEXIBLE CONTENT SECTIONS
\*------------------------------------*/

.section {
    position: relative;
    padding-top: 56px;
    padding-bottom: 56px;
}

.section-heading {
    margin-bottom: 20px;
}

/* Shared prose styling for WYSIWYG output */
.section-text > * + *,
.entry-content > * + * {
    margin-top: 16px;
}

.section-text ul,
.section-text ol,
.entry-content ul,
.entry-content ol {
    padding-left: 0;
    list-style: none;
}

.section-text ul li,
.section-text ol li,
.entry-content ul li,
.entry-content ol li {
    position: relative;
    padding-left: 26px;
}

.section-text ul li + li,
.section-text ol li + li,
.entry-content ul li + li,
.entry-content ol li + li {
    margin-top: 16px;
}

/* Green arrow markers from the design.
   The box is exactly one line tall so `center` keeps the icon aligned with the
   first line of text regardless of font size. */
.section-text ul li::before,
.entry-content ul li::before {
    content: '';
    position: absolute;
    left: 0;
    top: 0;
    width: 12px;
    height: calc(var(--line-height-body, 1.4) * 1em);
    background: url('../img/icon-play-bullet.svg') no-repeat left center;
    background-size: 12px auto;
}

.section-text ol,
.entry-content ol {
    counter-reset: section-list;
}

.section-text ol li,
.entry-content ol li {
    counter-increment: section-list;
}

.section-text ol li::before,
.entry-content ol li::before {
    content: counter(section-list) '.';
    position: absolute;
    left: 0;
    top: 0;
    color: var(--color-primary);
    font-weight: 700;
}

.section-text a,
.entry-content a {
    color: var(--color-primary);
    font-weight: 600;
    text-decoration: underline;
}

/* --- Media column --- */

.section-media {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    margin: 0;
}

.section-media-image {
    position: relative;
    z-index: 2;
    width: 100%;
    height: auto;
    border-radius: 12px;
    box-shadow: 0 22px 48px rgba(0, 0, 0, 0.18);
}

.section-media figcaption {
    position: relative;
    z-index: 2;
    margin-top: 12px;
    color: var(--color-muted);
    font-size: var(--font-size-small);
}

/* Dashed ring and glow sit behind the image, scaled off the column width so
   they stay proportional at every breakpoint. */
.section-media-ring {
    position: absolute;
    left: 50%;
    top: 50%;
    width: 90%;
    max-width: none;
    transform: translate(-50%, -50%);
    pointer-events: none;
    user-select: none;
    z-index: 0;
}

.section-media-glow {
    position: absolute;
    left: 50%;
    top: 50%;
    width: 108%;
    aspect-ratio: 1 / 1;
    transform: translate(-50%, -50%);
    border-radius: 400px;
    background: radial-gradient(50% 50% at 50% 50%, rgba(0, 212, 107, 0.50) 0%, rgba(0, 212, 107, 0.00) 100%);
    pointer-events: none;
    z-index: 1;
}

/* --- Section: Content Card --- */

/* Bold centred lead-in above the card */
.content-card-intro {
    max-width: 880px;
    margin: 0 auto 40px;
    color: var(--color-text);
    font-size: var(--font-size-h5);
    font-weight: 700;
    line-height: var(--line-height-body);
    text-align: center;
}

/* Figma: radius 16px, #FFF, shadow 0 8px 30px rgba(17, 0, 21, 0.13).
   No padding — the image runs flush to the card edges and `overflow: hidden`
   clips it to the rounded corners. The copy column carries its own inset. */
.content-card {
    max-width: 1034px;
    margin: 0 auto;
    border-radius: 16px;
    overflow: hidden;
    background: #ffffff;
    box-shadow: 0 8px 30px 0 rgba(17, 0, 21, 0.13);
}

/* Zero the column gutter too, or each column keeps 12px of side padding */
.content-card .row {
    --bs-gutter-x: 0;
}

.content-card-image {
    width: 100%;
    height: 100%;
    min-height: 750px;
    object-fit: cover;
    border-radius: 0;
}

.content-card-body {
    padding: 36px 36px 40px;
}

/* Global h3 size and tracking, green, with heading leading — the design's
   stacked two-line heading is far tighter than h3's 46px default. */
.content-card-heading {
    margin-bottom: 20px;
    color: var(--color-primary);
    line-height: var(--line-height-heading);
}

/* Card copy runs at the small token, as in the design */
.content-card-text p,
.content-card-text li {
    font-size: var(--font-size-small);
}

/* Now a list of individual logos rather than one combined image */
.content-card-logos {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
    margin: 28px 0 0;
    padding: 0;
    list-style: none;
}

.content-card-logo {
    font-size: 0; /* kills the inline-gap under the image */
    line-height: 0;
}

.content-card-logo img {
    width: 74px;
    height: 74px;
    border-radius: 10px;
    object-fit: contain;
}

.content-card-logo a {
    display: block;
    transition: opacity 180ms ease;
}

.content-card-logo a:hover,
.content-card-logo a:focus-visible {
    opacity: 0.75;
}

@media only screen and (max-width: 575.98px) {
    .content-card-logo img {
        width: 46px;
        height: 46px;
    }
}

@media only screen and (max-width: 991.98px) {
    .content-card-image {
        min-height: 260px;
    }
    .content-card-body {
        padding: 28px 24px 32px;
    }
}

/* --- Section: Gallery --- */

/* Figma: #FAFAFA band */
.section-gallery {
    background: #fafafa;
}

.gallery-heading {
    margin-bottom: 32px;
    text-align: center;
}

/* Full-bleed track. The slides are wider than a third of the viewport, so the
   centre one reads as the subject and its neighbours are cropped by the edges —
   overflow: hidden on the track is what keeps that off the page's scrollbar. */
.gallery-slider {
    position: relative;
}

.gallery-slider-track {
    overflow: hidden;
}

/* Swiper measures each slide from its CSS width under slidesPerView: 'auto'.
   The custom property comes from the layout's "Images at once" control. */
.gallery-slide {
    width: var(--gallery-slide-w, 40vw);
    /* Hard ceiling on a wide monitor. The source photographs top out around
       1000px across, so letting a slide grow past this only upscales them. */
    max-width: 760px;
    height: auto;
}

.gallery-item {
    display: block;
    overflow: hidden;
    background: rgba(35, 35, 35, 0.04);
}

.gallery-item img {
    width: 100%;
    height: auto;
    aspect-ratio: 72 / 51;
    object-fit: cover;
    transition: transform 400ms ease;
}

/* Wider crop than the old thumbnail grid: at this size the slide is a banner,
   and 16:9 matches the proportions of the design. */
.gallery-slide .gallery-item img {
    aspect-ratio: 16 / 9;
}

/* The arrows sit over the cropped neighbours, so they need their own ground to
   stay legible against a photograph. */
.gallery-slider .carousel-nav {
    width: 46px;
    height: 46px;
    margin-top: -23px;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.88);
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.18);
}

.gallery-slider .carousel-nav--prev {
    left: 20px;
}

.gallery-slider .carousel-nav--next {
    right: 20px;
}

.gallery-slider .carousel-nav:hover,
.gallery-slider .carousel-nav:focus-visible {
    background: #ffffff;
    opacity: 1;
}

/* Below the desktop breakpoint the slide has to grow again — a 40vw image on a
   tablet is too small to read as the subject. */
@media only screen and (max-width: 991.98px) {
    .gallery-slide {
        width: 62vw;
    }
}

@media only screen and (max-width: 767.98px) {
    /* One image at a time on a phone, with just a sliver of the next to show
       there is more, and a taller crop so portrait shots are not gutted. */
    .gallery-slide {
        width: 86vw;
    }
    .gallery-slide .gallery-item img {
        aspect-ratio: 3 / 2;
    }
    .gallery-slider .carousel-nav {
        width: 38px;
        height: 38px;
        margin-top: -19px;
    }
    .gallery-slider .carousel-nav--prev {
        left: 8px;
    }
    .gallery-slider .carousel-nav--next {
        right: 8px;
    }
}

.gallery-item:hover,
.gallery-item:focus {
    opacity: 1;
}

.gallery-item:hover img,
.gallery-item:focus-visible img {
    transform: scale(1.04);
}

@media (prefers-reduced-motion: reduce) {
    .gallery-item img {
        transition: none;
    }
    .gallery-item:hover img,
    .gallery-item:focus-visible img {
        transform: none;
    }
}

/* --- Section: Posts Carousel --- */

/* Heading with the green rule to its left */
.carousel-heading {
    position: relative;
    margin-bottom: 28px;
    padding-left: 16px;
}

.carousel-heading::before {
    content: '';
    position: absolute;
    left: 0;
    top: 0.12em;
    bottom: 0.12em;
    width: 4px;
    border-radius: 2px;
    background: var(--color-primary);
}

/* The arrows are absolutely positioned rather than flex items, so the track
   spans the full container width and the first card's left edge lines up with
   the heading above it. As flex siblings they pushed the track inward by the
   button width plus the gap. */
.posts-carousel {
    position: relative;
}

.posts-carousel-track {
    /* Room for the card shadows, which overflow: hidden would otherwise clip.
       The matching padding puts the slides back on the container edge, so the
       alignment with the heading is preserved. */
    margin: -14px;
    padding: 14px;
    overflow: hidden;
}

.posts-carousel .swiper-wrapper {
    align-items: stretch;
}

.posts-carousel .swiper-slide {
    height: auto;
    display: flex;
}

/* Holds the AOS reveal so Swiper's own transforms never clash with it. Must
   pass the slide's full height and width through to the card. */
.posts-carousel-slide-inner {
    display: flex;
    flex: 1 1 auto;
    min-width: 0;
}

/* --- Arrows --- */

/* Centred with a negative margin rather than translateY, because the global
   button:hover lift overwrites `transform` and would knock it off centre. */
.carousel-nav {
    position: absolute;
    top: 50%;
    z-index: 2;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 44px;
    margin-top: -22px;
    padding: 0;
    border: none;
    border-radius: 0;
    background: transparent;
    cursor: pointer;
}

/* Clear of the container on wide screens */
.carousel-nav--prev {
    left: -38px;
}

.carousel-nav--next {
    right: -38px;
}

.carousel-nav span {
    display: block;
    width: 11px;
    height: 11px;
    border-top: 2px solid var(--color-text);
    border-right: 2px solid var(--color-text);
    transition: border-color 180ms ease;
}

.carousel-nav--prev span {
    transform: rotate(-135deg);
    margin-right: -5px;
}

.carousel-nav--next span {
    margin-left: -5px;
    transform: rotate(45deg);
}


.carousel-nav:hover span,
.carousel-nav:focus-visible span {
    border-color: var(--color-primary);
}

.carousel-nav:hover,
.carousel-nav:focus {
    transform: none;
    opacity: 1;
}

/* Swiper adds this when there is nothing to scroll to */
.carousel-nav.swiper-button-disabled {
    opacity: 0.3;
    cursor: default;
}

.carousel-nav.swiper-button-lock {
    display: none;
}

/* Sits under the track, clear of the arrows on either side */
.carousel-view-all {
    margin-top: 26px;
    text-align: center;
}

.carousel-view-all a {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    color: var(--color-primary);
    font-size: var(--font-size-small);
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

.carousel-view-all svg {
    transition: transform 180ms ease;
}

.carousel-view-all a:hover svg,
.carousel-view-all a:focus-visible svg {
    transform: translateX(3px);
}

/* --- Card --- */

.post-card {
    display: flex;
    flex-direction: column;
    width: 100%;
    padding: 24px;
    border-radius: 8px;
    background: #ffffff;
    box-shadow: 0 4px 18px rgba(0, 0, 0, 0.10);
}

.post-card-date {
    margin-bottom: 12px;
    color: var(--color-muted);
    font-size: var(--font-size-small);
    font-weight: 400;
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

/* Four lines then ellipsis. Carousel slides all take the height of the tallest
   card, so an academic title left to run its full length spilled out of the card
   instead of stretching it. The card links to the full title either way.
   The news and media cards clamp tighter — see .news-card-title below. */
.post-card-title {
    display: -webkit-box;
    -webkit-line-clamp: 4;
    line-clamp: 4;
    -webkit-box-orient: vertical;
    overflow: hidden;
    margin-bottom: 12px;
    font-size: var(--font-size-h5);
    line-height: 1.3;
    letter-spacing: normal;
}

.post-card-title a {
    color: var(--color-text);
}

.post-card-title a:hover,
.post-card-title a:focus {
    color: var(--color-primary);
    opacity: 1;
}

/* Authors on a publication card, under the title */
.post-card-authors {
    margin-bottom: 12px;
    color: var(--color-muted);
    font-size: var(--font-size-small);
    line-height: 1.4;
}

.post-card-excerpt {
    margin-bottom: 18px;
    font-size: var(--font-size-small);
    line-height: 1.5;
}

/* Pinned to the base so links align across cards of differing height */
.post-card-link {
    margin-top: auto;
    color: var(--color-text);
    font-size: var(--font-size-small);
    font-weight: 700;
}

.post-card-link:hover,
.post-card-link:focus {
    color: var(--color-primary);
    opacity: 1;
}

/* Below this there is no margin left of the container to sit in, so the arrows
   move onto the track's outer edges. They land in the card's own padding, and
   the chevron stays legible against the white card. Card alignment with the
   heading is unaffected either way. */
@media only screen and (max-width: 1239.98px) {
    .carousel-nav--prev {
        left: -2px;
    }
    .carousel-nav--next {
        right: -2px;
    }
}

/* --- Card style: news (image, date, clamped title, green base) --- */

/* The image is inset by the card's own padding, so its edges line up with the
   date and title rather than bleeding to the card edge. */
.post-card--news {
    padding: 20px 20px 22px;
    border-bottom: 5px solid var(--color-primary);
}

.news-card-media {
    display: block;
    margin-bottom: 18px;
}

/* aspect-ratio rather than a fixed height, so the crop holds at any card width */
.news-card-media img {
    width: 100%;
    height: auto;
    aspect-ratio: 3 / 2;
    object-fit: cover;
}

/* Two lines then ellipsis, so cards stay even regardless of title length */
.news-card-title {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

/* --- Card style: project (logo, caption, pill button) --- */

.post-card--project {
    align-items: center;
    justify-content: space-between;
    padding: 28px 24px;
    text-align: center;
}

.project-card-logo {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    min-height: 56px;
    margin-bottom: 14px;
}

.project-card-logo img {
    max-width: 100%;
    max-height: 56px;
    width: auto;
    object-fit: contain;
}

.project-card-caption {
    margin-bottom: 18px;
    font-size: var(--font-size-small);
    line-height: 1.4;
}

/* Pushed to the base so buttons align across cards with and without captions */
.project-card-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    margin-top: auto;
    padding: 12px 26px;
    border-radius: 999px;
    background: var(--color-primary);
    color: #ffffff;
    font-size: var(--font-size-small);
    font-weight: 700;
    line-height: 1;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

.project-card-btn:hover,
.project-card-btn:focus {
    color: #ffffff;
    opacity: 1;
}

/* Outbound variant — same pill, plus a diagonal arrow */
.external-card-btn {
    gap: 7px;
}

.external-card-btn svg {
    flex-shrink: 0;
    transition: transform 180ms ease;
}

.external-card-btn:hover svg,
.external-card-btn:focus-visible svg {
    transform: translate(2px, -2px);
}

/* --- Card style: publication (cover, title, download) --- */

.post-card--publication {
    padding: 14px 14px 18px;
}

.publication-card-media {
    display: block;
    margin-bottom: 16px;
}

.publication-card-media img {
    width: 100%;
    height: auto;
    aspect-ratio: 3 / 2;
    object-fit: cover;
}

/* auto top margin sits on the title, not the link, so the title + download
   pair is pushed to the base as a group. Cards without a cover then bottom-
   align with those that have one, instead of stranding the title up top. */
.publication-card-title {
    margin-top: auto;
    margin-bottom: 14px;
    font-size: var(--font-size-small);
    font-weight: 700;
    line-height: 1.4;
    letter-spacing: normal;
}

/* No cover means the title is the card's first child — then there is nothing to
   bottom-align against, and a listing of text-only entries reads better top
   aligned than with the copy pushed to the base. */
.publication-card-title:first-child {
    margin-top: 0;
}

.publication-card-title a {
    color: var(--color-text);
}

.publication-card-title a:hover,
.publication-card-title a:focus {
    color: var(--color-primary);
    opacity: 1;
}

.publication-card-authors {
    /* The title above owns the auto top margin, so these sit with it */
    margin-bottom: 6px;
    color: var(--color-muted);
    font-size: var(--font-size-small);
    line-height: 1.4;
}

.publication-card-meta {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-bottom: 14px;
    color: var(--color-muted);
    font-size: var(--font-size-small);
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

/* Separator only when a year actually precedes it */
.publication-card-meta span + .publication-card-language::before {
    content: '·';
    margin-right: 8px;
}

.publication-card-link {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    /* No auto margin here — the title above owns the spacing, keeping the two
       together at the base rather than splitting them apart. */
    margin-right: auto;
    color: var(--color-primary);
    font-size: var(--font-size-small);
    font-weight: 700;
}

.publication-card-link:hover,
.publication-card-link:focus {
    color: var(--color-primary);
    opacity: 0.75;
}

/* --- Card style: link (title with corner arrow) --- */

.post-card--link {
    flex-direction: row;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
    padding: 20px 20px 22px;
}

.link-card-title {
    color: var(--color-text);
    font-size: var(--font-size-small);
    font-weight: 700;
    line-height: 1.45;
}

.link-card-arrow {
    flex-shrink: 0;
    color: var(--color-text);
    line-height: 0;
    transition: color 180ms ease, transform 180ms ease;
}

.post-card--link:hover,
.post-card--link:focus {
    opacity: 1;
}

.post-card--link:hover .link-card-arrow,
.post-card--link:focus-visible .link-card-arrow {
    color: var(--color-primary);
    transform: translate(2px, -2px);
}

.post-card--link:hover .link-card-title {
    color: var(--color-primary);
}

@media only screen and (max-width: 575.98px) {
    .carousel-nav {
        width: 22px;
    }
    .post-card {
        padding: 20px;
    }
}

/* --- Section: Form --- */

/* Gravity Forms' own stylesheet is disabled (see gform_disable_css in
   functions.php), so everything below — including the field grid GF would
   normally provide — is defined here. No specificity fight, exact control. */

.section-form {
    --field-border: #eae9e9;
    --field-radius: 4px;
    --field-gap: 22px;
    --field-error: #e02b2b;
}

.form-section-heading {
    margin-bottom: 32px;
    text-align: center;
}

/* Figma: 860px card, radius 10px, shadow -4px 4px 25px rgba(0,0,0,0.15) */
.form-card {
    max-width: 860px;
    margin: 0 auto;
    padding: 48px;
    border-radius: 10px;
    background: #ffffff;
    box-shadow: -4px 4px 25px 0 rgba(0, 0, 0, 0.15);
}

.form-card-intro {
    margin-bottom: 28px;
}

/* --- Container resets --- */

.form-card .gform_heading {
    display: none;
}

/* Checkbox fields are <fieldset> elements — without this the browser draws its
   default border around each consent row. */
.form-card fieldset.gfield {
    min-width: 0;
    margin: 0;
    padding: 0;
    border: 0;
}

.form-card .gform_wrapper form {
    margin: 0;
}

/* --- Field grid --- */

.form-card .gform_fields {
    display: grid;
    grid-template-columns: repeat(12, 1fr);
    column-gap: 24px;
    row-gap: var(--field-gap);
    margin: 0;
    padding: 0;
    list-style: none;
}

.form-card .gfield {
    grid-column: span 12;
    min-width: 0;
}

.form-card .gfield--width-half {
    grid-column: span 6;
}

.form-card .gfield--width-third {
    grid-column: span 4;
}

.form-card .gfield--width-quarter {
    grid-column: span 3;
}

.form-card .gfield_visibility_hidden,
.form-card .gform_hidden,
.form-card .gfield--type-honeypot {
    display: none;
}

/* --- Labels --- */

.form-card .gfield_label {
    display: block;
    margin-bottom: 8px;
    padding: 0;
    color: var(--color-text);
    font-family: var(--font-family-base);
    font-size: var(--font-size-h6);
    font-weight: 400;
    line-height: 1.4;
}

.form-card .gfield_required {
    color: var(--field-error);
}

.form-card .gfield_required_text {
    display: none;
}

/* Consent groups use their choice text as the visible label */
.form-card .gfield--type-checkbox > .gfield_label,
.form-card .gfield--type-radio > .gfield_label {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
}

.form-card .ginput_container {
    margin: 0;
}

/* --- Inputs: Figma 1px #EAE9E9, radius 4px, 14px 20px 15px --- */

.form-card .gform_wrapper input[type="text"],
.form-card .gform_wrapper input[type="email"],
.form-card .gform_wrapper input[type="tel"],
.form-card .gform_wrapper input[type="url"],
.form-card .gform_wrapper input[type="number"],
.form-card .gform_wrapper input[type="password"],
.form-card .gform_wrapper select,
.form-card .gform_wrapper textarea {
    display: block;
    width: 100%;
    max-width: 100%;
    margin: 0;
    padding: 14px 20px 15px;
    border: 1px solid var(--field-border);
    border-radius: var(--field-radius);
    background-color: #ffffff;
    color: var(--color-text);
    font-family: var(--font-family-base);
    font-size: var(--font-size-h6);
    line-height: 1.4;
    transition: border-color 180ms ease, box-shadow 180ms ease;
}

.form-card .gform_wrapper input:focus,
.form-card .gform_wrapper select:focus,
.form-card .gform_wrapper textarea:focus {
    outline: none;
    border-color: var(--color-primary);
    box-shadow: 0 0 0 3px rgba(0, 127, 64, 0.12);
}

.form-card .gform_wrapper ::placeholder {
    color: rgba(35, 35, 35, 0.42);
    opacity: 1;
}

/* Bolder, with our own chevron replacing the native arrow */
.form-card .gform_wrapper select {
    padding-right: 48px;
    font-weight: 700;
    appearance: none;
    -webkit-appearance: none;
    background-image: url('../img/icon-dropdown.svg');
    background-repeat: no-repeat;
    background-position: right 20px center;
    background-size: 14px 10px;
    cursor: pointer;
}

/* GF renders rows="10"; the design's box is far shorter */
.form-card .gform_wrapper textarea {
    height: 115px;
    min-height: 115px;
    resize: vertical;
}

/* --- Checkboxes --- */

.form-card .gfield_checkbox {
    display: flex;
    flex-direction: column;
    gap: 16px;
    margin: 0;
    padding: 0;
    list-style: none;
}

.form-card .gfield_checkbox .gchoice {
    display: flex;
    align-items: flex-start;
    gap: 14px;
    margin: 0;
}

.form-card .gfield_checkbox input[type="checkbox"] {
  
    flex-shrink: 0;
    width: 18px;
    height: 18px;
    margin: 3px 0 0;
    padding: 0;
    border: 1px solid rgba(35, 35, 35, 0.45);
    border-radius: 2px;
    background-color: #ffffff;
    appearance: none;
    -webkit-appearance: none;
    cursor: pointer;
    transition: background-color 160ms ease, border-color 160ms ease;
}

.form-card .gfield_checkbox input[type="checkbox"]:checked {
    border-color: var(--color-primary);
    background-color: var(--color-primary);
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='none' stroke='%23ffffff' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round' d='M3.5 8.5l3 3 6-6'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: center;
    background-size: 13px 13px;
}

.form-card .gfield_checkbox input[type="checkbox"]:focus-visible {
    outline: 2px solid var(--color-primary);
    outline-offset: 2px;
}

.form-card .gfield_checkbox label {
    margin: 0;
    color: var(--color-text);
    font-family: var(--font-family-base);
    font-size: var(--font-size-h6);
    font-weight: 400;
    line-height: 1.45;
    cursor: pointer;
}

/* --- Submit --- */

.form-card .gform_footer {
    display: flex;
    align-items: center;
    justify-content: center;
    margin: 32px 0 0;
    padding: 0;
}

.form-card .gform_footer .gform_button {
    width: auto;
    padding: 15px 44px;
    border: none;
    border-radius: 999px;
    background: var(--color-primary);
    color: #ffffff;
    font-family: var(--font-family-nav);
    font-size: var(--font-size-small);
    font-weight: 700;
    line-height: 1;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    cursor: pointer;
    transition: transform 200ms ease, opacity 200ms ease;
}

.form-card .gform_footer .gform_button:hover {
    transform: translateY(-1px);
    opacity: 0.94;
}

.form-card .gform_ajax_spinner {
    width: 22px;
    height: 22px;
    margin-left: 12px;
}

/* --- Validation --- */

.form-card .gfield_error input,
.form-card .gfield_error select,
.form-card .gfield_error textarea {
    border-color: var(--field-error);
}

.form-card .gfield_validation_message,
.form-card .validation_message {
    margin-top: 6px;
    padding: 0;
    border: none;
    background: transparent;
    color: var(--field-error);
    font-size: var(--font-size-small);
    line-height: 1.4;
}

.form-card .gform_validation_errors {
    margin-bottom: 24px;
    padding: 14px 20px;
    border: 1px solid var(--field-error);
    border-radius: var(--field-radius);
    background: rgba(224, 43, 43, 0.06);
}

.form-card .gform_validation_errors .gform_submission_error {
    color: var(--field-error);
    font-size: var(--font-size-h6);
    font-weight: 600;
}

.form-card .gform_confirmation_message {
    color: var(--color-text);
    font-size: var(--font-size-h6);
    text-align: center;
}

@media only screen and (max-width: 575.98px) {
    .form-card {
        padding: 28px 20px;
    }
    /* Name fields stack rather than squeeze */
    .form-card .gfield--width-half,
    .form-card .gfield--width-third,
    .form-card .gfield--width-quarter {
        grid-column: span 12;
    }
}

/* --- Section: Timeline --- */

.section-timeline {
    --timeline-line: rgba(35, 35, 35, 0.32);
    --timeline-dot: 14px;
    /* Dash length and gap on a `dashed` border scale with its width, so this
       one value controls both stroke weight and dash spacing. */
    --timeline-stroke: 2px;
    --timeline-radius: 20px;
}

.timeline-heading {
    margin-bottom: 40px;
    text-align: center;
}

/* Dot centres land at (i + 0.5) / cols of the row width, which is exactly
   where a Bootstrap column of that count centres its card. */
.timeline-track {
    position: relative;
    height: 34px;
}

.timeline-dot {
    position: absolute;
    top: 50%;
    left: calc((var(--i) + 0.5) * 100% / var(--cols));
    width: var(--timeline-dot);
    height: var(--timeline-dot);
    transform: translate(-50%, -50%);
    border-radius: 50%;
    background: var(--color-primary);
    box-shadow: 0 0 24px rgba(0, 127, 64, 0.55);
}

/* Runs from the first dot to this row's own last dot — a short final row
   stops early instead of trailing off to full width. */
.timeline-track-line {
    position: absolute;
    top: 50%;
    left: calc(100% / var(--cols) / 2);
    right: calc(100% - (var(--count) - 0.5) * 100% / var(--cols));
    border-top: var(--timeline-stroke) dashed var(--timeline-line);
}

.timeline-cards {
    align-items: flex-start;
}

/* Figma: #F1F1F1, radius 10px, centred content */
.timeline-card {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    height: 100%;
    padding: 27px 24px;
    border-radius: 10px;
    background: #f1f1f1;
    text-align: center;
}

.timeline-card-title {
    color: #0a0a0a;
    font-family: var(--font-family-nav);
    font-size: var(--font-size-h5);
    font-weight: 700;
    line-height: 1.3;
}

.timeline-card-text {
    margin-top: 12px;
    color: #0a0a0a;
    font-size: var(--font-size-h6);
    font-weight: 400;
    line-height: 1.45;
}

/* S-connector: down the right at this row's last dot, across, then down the
   left at the next row's first dot.
   Built from three parts so each turn is a rounded corner on a single element
   — a curve drawn across two elements would break mid-radius. Each corner box
   is exactly --timeline-radius wide and the straight run bridges the gap
   between them, so the whole path is continuous. */
.timeline-link {
    position: relative;
    display: block;
    height: 72px;
}

/* Incoming: drops at this row's last dot, curves into the horizontal */
.timeline-link::before {
    content: '';
    position: absolute;
    top: 0;
    height: 50%;
    width: var(--timeline-radius);
    right: calc(100% - (var(--count) - 0.5) * 100% / var(--cols));
    border-right: var(--timeline-stroke) dashed var(--timeline-line);
    border-bottom: var(--timeline-stroke) dashed var(--timeline-line);
    border-bottom-right-radius: var(--timeline-radius);
}

/* Outgoing: curves out of the horizontal, drops at the next row's first dot */
.timeline-link::after {
    content: '';
    position: absolute;
    top: calc(50% - var(--timeline-stroke));
    bottom: 0;
    width: var(--timeline-radius);
    left: calc(100% / var(--cols) / 2);
    border-left: var(--timeline-stroke) dashed var(--timeline-line);
    border-top: var(--timeline-stroke) dashed var(--timeline-line);
    border-top-left-radius: var(--timeline-radius);
}

/* The straight run between the two curves */
.timeline-link-line {
    position: absolute;
    top: calc(50% - var(--timeline-stroke));
    left: calc(100% / var(--cols) / 2 + var(--timeline-radius));
    right: calc(100% - (var(--count) - 0.5) * 100% / var(--cols) + var(--timeline-radius));
    border-top: var(--timeline-stroke) dashed var(--timeline-line);
}
/* Below lg the serpentine has no meaning — switch to a vertical spine with a
   dot beside each stacked card. */
@media only screen and (max-width: 991.98px) {
    .timeline-track,
    .timeline-link {
        display: none;
    }
    /* Zeroing the x-gutter removes Bootstrap's negative row margin, so a
       column's left edge sits exactly at the timeline's padding edge. That
       makes the dot offset below exact rather than guesswork. */
    .timeline-cards {
        --bs-gutter-x: 0;
        --bs-gutter-y: 1.5rem;
    }
    .timeline {
        position: relative;
        padding-left: 40px;
    }
    /* One continuous spine for the whole stack — no gaps at row boundaries */
    .timeline::before {
        content: '';
        position: absolute;
        left: 13px;
        top: 16px;
        bottom: 16px;
        border-left: var(--timeline-stroke) dashed var(--timeline-line);
    }
    .timeline-card-col {
        position: relative;
    }
    .timeline-card-col::before {
        content: '';
        position: absolute;
        left: -27px; /* column edge (40px) back to the spine (13px) */
        top: 28px;
        width: var(--timeline-dot);
        height: var(--timeline-dot);
        transform: translateX(-50%);
        border-radius: 50%;
        background: var(--color-primary);
        box-shadow: 0 0 16px rgba(0, 127, 64, 0.5);
    }
    .timeline-row + .timeline-row {
        margin-top: 1.5rem;
    }
}

/* --- Section: Team --- */

/* Figma: #FAFAFA band */
.section-team {
    background: #fafafa;
}

.section-team-heading {
    margin-bottom: 40px;
    text-align: center;
}

/* Column flex so the members row can absorb the group's full height —
   that is what makes cards match across groups on the same row, not just
   within one group. */
.team-group {
    display: flex;
    flex-direction: column;
    margin-bottom: 40px;
}

.team-group-heading {
    margin-bottom: 20px;
}

.team-members {
    flex: 1 1 auto;
    --bs-gutter-x: 1.5rem;
    --bs-gutter-y: 1.5rem;
}

/* Cards stretch to fill their row line */
.team-member {
    display: flex;
}

.team-card {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: start;
    width: 100%;
    padding: 24px 16px 20px;
    border-radius: 6px;
    border-bottom: 5px solid var(--color-primary);
    background: #ffffff;
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.06);
    text-align: center;
}
/* The lone-card treatment is for the single-person Project Manager group;
   a full-width group that happens to hold one person keeps the normal card. */
.team-group--half .team-member.head .team-card{
    border-radius: 9px;
}
.team-card .profile{
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
}

.team-card-image {
    width: 120px;
    height: 120px;
    margin-bottom: 20px;
}

/* A real portrait is cropped to a circle; the fallback mark is shown whole */
.team-card-image.is-photo {
    border-radius: 50%;
    object-fit: cover;
}

.team-card-image.is-logo {
    object-fit: contain;
}

.team-card-name {
    color: #263d4f;
    font-size: var(--font-size-h5);
    font-weight: 600;
    line-height: 1.35;
}

.team-card-affiliation {
    margin-top: 8px;
    color: #263d4f;
    font-size: var(--font-size-small);
    font-weight: 400;
    line-height: 1.5;
}

/* Full-width groups hold more, smaller cards */
.team-group--full .team-card-image {
    width: 72px;
    height: 72px;
    margin-bottom: 14px;
}
.team-group--full .team-card-affiliation{
	font-size: 12px;
}
.team-group--full .team-card-name {
    font-size: var(--font-size-small);
}

.team-group--full .team-card {
    padding: 30px 12px;
}

@media only screen and (min-width: 992px) {
    /* A pair of half groups reads as one line of cards running the width of
       the row: each group takes a share of the row proportional to how many
       cards it puts on a line (`--team-group-columns`, set by the template and
       capped at three), and its cards then divide that share equally. Because
       every group on the line uses the same per-card share, a one-person group
       sits in a card the same size as its neighbours' rather than a
       half-row-wide slab, and the gap that used to sit between the two groups
       closes up. */
    .team-group--half.team-group--paired {
        flex: var(--team-group-columns, 1) 1 0;
        max-width: none;
    }

    /* A fixed share rather than a grown one, so the members left over on a
       short last line keep the width of the cards above them. */
    .team-group--half.team-group--paired .team-member {
        flex: 0 0 auto;
        width: calc(100% / var(--team-group-columns, 1));
        max-width: 100%;
    }

    /* Past its three columns a group runs to a second line and becomes the
       tall one on the row. Its lines then hug their own cards, so the shorter
       group beside it sits at its natural height instead of stretching one
       card down the full height of the row. */
    .team-group--half.team-group--wrapped .team-members {
        align-content: flex-start;
    }

    /* An unpaired half group keeps the plain half-row treatment: `col-lg` is
       `flex: 1 0 0`, so a card left over on a short final line would otherwise
       grow to fill the line on its own. */
    .team-group--half:not(.team-group--paired) .team-member {
        flex: 0 0 auto;
        width: 50%;
    }

    /* 5 across, which is where the cards already wrapped on their own */
    .team-group--full .team-member {
        flex: 0 0 auto;
        width: 20%;
    }
}

@media only screen and (max-width: 991.98px) {
    .team-card-image {
        width: 96px;
        height: 96px;
    }
}

/* --- Section: Text + Figure --- */

.text-figure-heading {
    margin-bottom: 24px;
}

/* Plain figure — no rounding, shadow or crop, so diagrams stay legible */
.text-figure {
    margin: 0;
}


.text-figure-image {
    width: 100%;
    max-width: 330px;
    height: auto;
}

.text-figure-caption {
    margin-top: 12px;
    color: var(--color-muted);
    font-size: var(--font-size-small);
    line-height: var(--line-height-body);
}

/* Second figure stacks under the first */
.text-figure--secondary {
    margin-top: 28px;
}

/* A source credit, not a caption — quieter than the line above it */
.text-figure-credit {
    font-size: 12px;
    font-style: italic;
}

@media only screen and (max-width: 991.98px) {
    /* Figure below the copy on small screens, whichever side it sits on */
    .section-text-figure .text-figure {
        margin-top: 32px;
    }
}

/* --- Section: Callout + Text --- */

.callout-panel {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 14px;
    min-height: 117px;
    padding: 24px 28px;
    border-radius: 8px;
    background: var(--color-primary);
    text-align: left;
    transition: transform 200ms ease, box-shadow 200ms ease;
}

/* Circular 52px icon, per the design's exported flag asset */
.callout-icon {
    flex-shrink: 0;
    width: 52px;
    height: 52px;
    border-radius: 50%;
    object-fit: cover;
}

.callout-label {
    color: #ffffff;
    font-size: var(--font-size-h6);
    font-weight: 700;
    line-height: 1.25;
}

a.callout-panel:hover,
a.callout-panel:focus-visible {
    transform: translateY(-2px);
    box-shadow: 0 12px 28px rgba(0, 60, 30, 0.22);
    opacity: 1;
}

@media only screen and (max-width: 991.98px) {
    .callout-panel {
        min-height: 96px;
        margin-bottom: 24px;
    }
}

/* --- Section: CTA Banner --- */

.cta-banner {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 24px;
    min-height: 257px;
    padding: 40px 25px;
    border-radius: 24px;
    background: var(--color-primary);
    text-align: center;
}

/* Heading and sub line invert on the green panel */
.cta-banner-heading {
    color: #ffffff;
    line-height: var(--line-height-heading);
}

.cta-banner-text {
    color: #ffffff;
}

.cta-banner-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 12px 60px;
    border-radius: 85px;
    background: #ffffff;
    color: var(--color-primary);
    font-size: var(--font-size-small);
    font-weight: 700;
    line-height: 1;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

.cta-banner-btn:hover,
.cta-banner-btn:focus {
    color: var(--color-primary);
    opacity: 1;
}

@media only screen and (max-width: 575.98px) {
    .cta-banner {
        min-height: 0;
        gap: 20px;
        padding: 32px 20px;
        border-radius: 16px;
    }
    .cta-banner-btn {
        padding: 12px 36px;
    }
}

/* --- Section: Icon Grid --- */

.section-icon-grid-heading {
    margin-bottom: 48px;
    
    text-align: center;
}

.icon-grid {
    --bs-gutter-y: 56px;
}

.icon-grid-item {
    display: block;
    text-align: center;
}

/* Figma: 101px circle, #FFF, shadow 0 0 110px rgba(0,0,0,0.10) */
.icon-grid-badge {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 101px;
    height: 101px;
    margin: 0 auto 46px;
    border-radius: 50%;
    background: #ffffff;
    box-shadow: 0 0 110px 0 rgba(0, 0, 0, 0.10);
    color: var(--color-primary);
    transition: transform 240ms ease, box-shadow 240ms ease;
}

/* Icons vary in aspect ratio, so bound the box and let them fit inside it */
.icon-grid-badge img,
.icon-grid-badge iconify-icon {
    display: block;
    width: auto;
    height: auto;
    max-width: 48px;
    max-height: 40px;
    object-fit: contain;
}

.icon-grid-badge iconify-icon {
    width: 40px;
    height: 40px;
}

a.icon-grid-item:hover .icon-grid-badge,
a.icon-grid-item:focus-visible .icon-grid-badge {
    transform: translateY(-4px);
    box-shadow: 0 14px 40px rgba(0, 0, 0, 0.12);
}

a.icon-grid-item:hover,
a.icon-grid-item:focus {
    opacity: 1;
}

/* Figma: 187px wide, 14px / 600, #0A0A0A, centred */
.icon-grid-text {
    display: block;
    max-width: 187px;
    margin: 0 auto;
    color: #0a0a0a;
    font-size: var(--font-size-small);
    font-weight: 600;
    line-height: 1.35;
}

@media only screen and (max-width: 575.98px) {
    .icon-grid {
        --bs-gutter-y: 36px;
    }
    .icon-grid-badge {
        width: 84px;
        height: 84px;
        margin-bottom: 24px;
        box-shadow: 0 0 60px 0 rgba(0, 0, 0, 0.12);
    }
    .icon-grid-badge img,
    .icon-grid-badge iconify-icon {
        max-width: 36px;
        max-height: 34px;
    }
    .icon-grid-badge iconify-icon {
        width: 34px;
        height: 34px;
    }
}

/* Breathing room between the copy and the decorated image */
@media only screen and (min-width: 992px) {
    
    .section {
        padding-top: 72px;
        padding-bottom: 72px;
    }
    .section-content-media--left .section-copy {
        padding-left: 32px;
    }
    .section-content-media--right .section-copy {
        padding-right: 32px;
    }
}

@media only screen and (max-width: 991.98px) {
    /* Image below the copy on small screens, whichever side it sits on */
    .section-content-media .col-lg-6:first-child {
        order: 2;
    }
    .section-content-media .col-lg-6:last-child {
        order: 1;
    }
    .section-media {
        margin-top: 32px;
    }
    .section-media-ring,
    .section-media-glow {
        width: 100%;
    }
}

@media only screen and (min-width: 992px) {
    .section-content-media--left .section-copy{
        padding-right: 54px;
    }
    .section-content-media--right .section-copy{
        padding-right: 60px;
    }
}

@media only screen and (max-width: 991.98px) {
    /* Stacked layout: copy across the top, the globe centred in the space
       below it. The anchor moves with it — every layer and every marker is
       positioned from these two values, so this is the only thing to change. */
    .hero-zoom {
        --anchor-x: 50%;
        --anchor-y: 60%;
        --layer-base: max(100vw, 100vh);
        /* What keeps the planet a planet is the gap between its diameter and
           the frame width — once it overruns the frame there is no limb, and
           the shot becomes flat wallpaper. --layer-base is the taller side on a
           portrait phone, so the desktop 0.33 opened the globe at about 70% of
           the width and it had barely half an octave of growth left. 0.24 opens
           it at roughly half the width, which is the same headroom desktop
           gets, and is the only reason the approach reads as three-dimensional
           down here. */
        --fill-start: 0.24;
        --fill-end: 3.7;
        /* More octaves to cross than desktop (the run ends closer in, on a
           narrower frame), so a steeper curve is needed to give the approach
           the same share of the scroll rather than blowing through it. */
        --zoom-gamma: 2.0;
        /* No drift here either — see the note on the desktop values. A narrow
           frame has even less room for it than a wide one. */
        --pan-x-start: 0;
        --pan-y-start: 0;
        /* A phone flick covers far less ground than a wheel, so the run is
           shortened — but not as far as it was: there is more zoom to get
           through here than on desktop, and 0.72 made the descent frantic. */
        height: calc(var(--hero-runway, 420) * 0.85vh);
    }
    .hero-zoom-copy {
        top: 0;
        transform: none;
        padding-top: 48px;
    }
    .hero-zoom-reset {
        left: 14px;
        bottom: 14px;
    }
    /* Anchor panels to the viewport on small screens so they cannot be clipped */
    .hero-marker-panel {
        position: fixed;
        left: 50%;
        top: auto;
        bottom: 16px;
        width: min(320px, calc(100vw - 32px));
        transform: translateX(-50%);
        z-index: 25;
    }
}

@media only screen and (max-width: 575.98px) {
    .hero-marker {
        --marker-size: 30px;
    }
    .hero-marker--city {
        --marker-size: 20px;
    }
    .hero-marker-label {
        font-size: var(--font-size-small);
    }
}

@media (prefers-reduced-motion: reduce) {
    .hero-marker--pin .hero-marker-btn::before {
        animation: none;
    }
}

#siteCookie {
    background-color: rgba(0, 0, 0, 0.78);
    position: fixed;
    z-index: 30;
    bottom: 0;
    padding: 12px 0;
    width: 100%;
}

#siteCookie,
#siteCookie p,
#siteCookie a {
    color: #fff;
    font-weight: 600;
}

#siteCookie .inner {
    gap: 12px;
}

#siteCookie p {
    margin: 0;
    flex: 1 1 auto;
    min-width: 0;
    font-size: var(--font-size-small);
}

#siteCookie a {
    text-decoration: underline;
}

.cookie-dismiss {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    padding: 0;
    flex-shrink: 0;
    color: #fff;
    background: transparent;
}

.cookie-dismiss:hover,
.cookie-dismiss:focus {
    transform: none;
    opacity: 1;
    background: rgba(255, 255, 255, 0.14);
}

/* Nav switches to the burger drawer below Bootstrap's xl breakpoint. Keeping
   this on a Bootstrap breakpoint means .d-xl-* utilities line up exactly. */
@media only screen and (max-width: 1199.98px) {
    :root {
        --font-size-h1: 2.5rem;   /* 40px */
        --font-size-h2: 1.75rem;  /* 28px */
        --font-size-h3: 1.375rem; /* 22px */
        --line-height-h1: 1.1;
        --line-height-h2: 1.25;
        --line-height-h3: 1.35;
    }

    /* Single compact bar: brand left, burger right */
    .site-header {
        position: sticky;
        top: 0;
    }
    .header-bar {
        padding-top: 12px;
        padding-bottom: 12px;
    }
    .header-inner {
        flex-wrap: nowrap;
        gap: 12px;
    }
    /* The bar is the panel's positioning context. Its z-index also keeps the bar
       and panel above the dismiss overlay (18). */
    .header-bar {
        position: relative;
        z-index: 20;
    }

    /* Starts below the header rather than at the viewport top, so it can never
       sit over the logo row whatever the stacking order ends up being. */
    .nav-overlay {
        position: absolute;
        top: 100%;
        left: 0;
        right: 0;
        bottom: auto;
        height: 100vh;
    }

    /* --- Drop-down panel ---
       Full-width sheet that fades and slides down from under the header bar.
       `top: 100%` on the bar lands it flush beneath, and because the bar is
       full width so is the panel. It travels with the sticky header. */
    .site-nav {
        position: absolute;
        top: 100%;
        left: 0;
        right: 0;
        bottom: auto;
        display: block;
        width: 100%;
        max-height: calc(100vh - 100%);
        margin: 0;
        padding: 10px 0 26px;
        background: var(--color-surface);
        /* The panel starts flush against the header's own bottom border and
           covers it, so it carries its own hairline to keep the two separate. */
        border-top: 1px solid rgba(35, 35, 35, 0.10);
        box-shadow: 0 22px 40px rgba(0, 0, 0, 0.10);
        opacity: 0;
        visibility: hidden;
        transition: opacity 200ms ease, visibility 320ms;
        z-index: 19;
        /* Also does the clipping the animation below depends on */
        overflow-y: auto;
        overscroll-behavior: contain;
        -webkit-overflow-scrolling: touch;
    }
    .site-nav.navActive {
        opacity: 1;
        visibility: visible;
    }
    /* The travel is on the list, not the panel. The panel is a descendant of
       .header-bar and so always paints above the bar's background — moving the
       panel itself made its top edge slide across the header. Translating the
       list instead keeps the panel fixed under the header while its overflow
       clips the list, so the items read as emerging from behind the bar. */
    .site-nav > ul {
        flex-direction: column;
        align-items: stretch;
        gap: 0;
        width: 100%;
        max-width: none;
        transform: translateY(-22px);
        transition: transform 320ms cubic-bezier(0.4, 0, 0.2, 1);
    }
    .site-nav.navActive > ul {
        transform: translateY(0);
    }
    .site-nav li {
        width: 100%;
    }
    /* Centred, mixed case — no per-item rules. Add the `nav-divider` class to a
       menu item in Appearance > Menus to start a new group above it. */
    .site-nav a {
        display: block;
        padding: 13px 24px;
        font-size: var(--font-size-small);
        letter-spacing: normal;
        text-transform: none;
        text-align: center;
    }
    .site-nav > ul > li.nav-divider {
        margin-top: 10px;
        padding-top: 10px;
        border-top: 1px solid rgba(35, 35, 35, 0.10);
    }
    .site-nav .current-menu-item > a,
    .site-nav .current_page_item > a {
        color: var(--color-primary);
    }
    .site-nav .menu-item-has-children > a {
        display: flex;
        align-items: center;
        justify-content: center;
        gap: 10px;
    }
    .site-nav .menu-item-has-children > a::after {
        margin-left: 0;
        flex-shrink: 0;
    }
    .site-nav .menu-item-has-children.sub-menu-active > a {
        color: var(--color-primary);
    }
    .site-nav .menu-item-has-children.sub-menu-active > a::after {
        transform: rotate(180deg);
    }
    .site-nav .sub-menu {
        position: static;
        display: block;
        width: auto;
        min-width: 0;
        max-width: none;
        margin: 0;
        padding: 0;
        background: var(--color-surface-alt);
        border-radius: 0;
        box-shadow: none;
        transform: none;
        opacity: 1;
        visibility: visible;
        max-height: 0;
        overflow: hidden;
        transition: max-height 320ms ease;
    }
    .site-nav .menu-item-has-children.sub-menu-active > .sub-menu {
        max-height: 1000px;
    }
    .site-nav .sub-menu li {
        width: 100%;
    }
    .site-nav .sub-menu a {
        padding: 11px 24px;
        font-size: var(--font-size-small);
        font-weight: 400;
        text-align: center;
        text-transform: none;
        border-bottom: none;
    }
    html.fix,
    body.fix {
        overflow: hidden;
    }

    /* Locking the root scroll takes the scrollport away from `position: sticky`,
       so the header would drop back to its static position at the top of the
       document — off-screen, taking the open drawer with it. While the drawer is
       open the header is pinned with `fixed` instead, and the body reserves the
       height it no longer occupies in flow so nothing behind it shifts.
       --header-h is published by scripts.js on open. */
    html.fix .site-header {
        position: fixed;
        top: 0;
        left: 0;
        right: 0;
    }

    body.fix {
        padding-top: var(--header-h, 0px);
    }

    /* --- Footer --- */
    .footer-top {
        padding: 40px 0 32px;
    }
    /* The container narrows to 960px here while the strip is still on one line
       (lg and up), so the gutters between logos tighten to keep it fitting. */
    .footer-logos {
        gap: 24px 16px;
    }
}

@media only screen and (max-width: 767.98px) {
    :root {
        --font-size-h1: 2rem;      /* 32px */
        --font-size-h2: 1.5rem;    /* 24px */
        --font-size-h3: 1.25rem;   /* 20px */
        --font-size-h4: 1.125rem;  /* 18px */
        --font-size-body: 1rem;    /* 16px */
        --line-height-h3: 1.3;
    }
    
    .footer-logos {
        gap: 24px;
        --footer-logo-h: 36px;
    }
    .footer-logo {
        flex: 0 1 auto;
    }
    .footer-logo-center img {
        max-height: 34px;
    }
    .footer-bottom-inner {
        flex-direction: column;
        align-items: center;
        text-align: center;
        gap: 12px;
    }
    .footer-sep {
        display: none;
    }
    .footer-address {
        display: block;
    }
}

@media only screen and (max-width: 575.98px) {
    :root {
        --font-size-h1: 1.75rem;   /* 28px */
        --font-size-h2: 1.375rem;  /* 22px */
    }
    .header-brand img {
        max-height: 30px;
    }
}

/* Respect reduced-motion preferences */
@media (prefers-reduced-motion: reduce) {
    html {
        scroll-behavior: auto;
    }
    .site-nav,
    .site-nav > ul,
    .nav-overlay,
    .site-nav .sub-menu,
    .navbar-toggle span {
        transition-duration: 0.01ms;
    }
}
