/* ==========================================================================
   RHIC 2026 — Design System · "The Thread"
   Layers: fonts → tokens → base → utilities → buttons → header → hero →
           sections → embeds → coming-soon → footer → motion/reduced-motion
   ========================================================================== */

/* 1. FONTS ---------------------------------------------------------------- */
@font-face {
  font-family: "Archivo";
  src: url("../fonts/archivo-var.woff2") format("woff2-variations");
  font-weight: 100 900;
  font-stretch: 62% 125%;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Inter";
  src: url("../fonts/inter-var.woff2") format("woff2-variations");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

/* 2. TOKENS --------------------------------------------------------------- */
:root {
  --navy-900: #081a2b;
  --navy-800: #0d2c49;
  --navy-700: #124166;
  --blue-500: #227ec2;
  --teal-600: #1e9789;
  --teal-500: #23ad9e;
  --teal-300: #7ed9cd;
  --surface-0: #ffffff;
  --surface-1: #f4f8fa;
  --sand-50: #faf7f2;
  --ink-900: #0e2233;
  --ink-600: #3e5468;
  --ink-400: #6b7e8f;
  --border: #dce6ee;
  --border-dark: rgba(255, 255, 255, 0.14);
  --gradient-brand: linear-gradient(135deg, #124166, #1b6e96, #23ad9e);
  --overlay: rgba(8, 26, 43, 0.72);
  --focus-ring: 0 0 0 3px rgba(35, 173, 158, 0.4);

  /* Shape of the RHIC mark, traced from the supplied logo artwork: the angled
     top-right corner, the teal tab on the left, and the notch the thread runs
     through. Defined once here because it is used in several places and they
     must never drift apart.

     The previous decagon facet is kept in backup/hero-facet-decagon/ — see the
     README there to revert. */
  --logo-clip: polygon(
    69.4% 0.0%, 85.3% 21.7%, 85.9% 25.8%, 99.4% 43.3%, 99.4% 96.7%,
    98.2% 99.2%, 61.2% 99.2%, 34.1% 97.5%, 20.6% 78.3%, 9.4% 77.5%,
    0.6% 65.0%, 0.6% 52.5%, 22.4% 51.7%, 18.8% 46.7%, 0.6% 45.8%,
    1.2% 27.5%, 17.1% 26.7%, 17.1% 2.5%, 18.8% 0.0%
  );
  /* The artwork's own proportions. The hero media follows this so the mark is
     never stretched. */
  --logo-aspect: 170 / 120;

  /* Form validation. A muted brick rather than a pure red: it has to sit
     beside the teal accent without shouting over it. */
  --af-bad: #b5452f;
  --af-bad-bg: rgba(181, 69, 47, 0.07);
  --af-bad-ink: #8c3423;

  --shadow-1: 0 1px 2px rgba(8, 26, 43, 0.06);
  --shadow-2: 0 8px 24px rgba(8, 26, 43, 0.08);
  --shadow-3: 0 20px 48px rgba(8, 26, 43, 0.12);

  --r-sm: 8px;
  --r-md: 16px;
  --r-lg: 24px;
  --r-pill: 999px;

  --font-display: "Archivo", system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
  --font-body: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif;

  --ease: cubic-bezier(0.4, 0, 0.2, 1);
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --t-fast: 0.2s;
  --t-med: 0.3s;

  --container: 1240px;
  --gutter: 32px;
  --section-y: clamp(64px, 9vw, 120px);
  --header-h: 76px;
  --announce-h: 40px;
  /* What the sticky header occupies once the announce bar has scrolled away:
     the brand row plus the nav row on desktop, the brand row alone below
     1024px where the nav collapses into a drawer. Anything sized to "one
     screenful" must subtract this, not --header-h. */
  --header-pinned: 128px;
}
/* Below the drawer breakpoint the nav row is display:contents, so only the
   brand row stays pinned. */
@media (max-width: 1023px) { :root { --gutter: 24px; --header-pinned: 64px; } }
@media (max-width: 767px)  { :root { --gutter: 20px; --header-h: 64px; } }

/* 3. BASE ------------------------------------------------------------------ */
*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }
/* Decorative layers are deliberately oversized and offset (hero facets, page-hero
   deco, the pillars branch), and GSAP's pin-spacer wraps pinned sections at their
   own measured width. Any of those can round a fraction of a pixel past the
   viewport and raise a horizontal scrollbar across the whole page.
   `clip` rather than `hidden`: hidden makes the element a scroll container, which
   breaks the sticky site header. clip contains the overflow without that side
   effect, and the fallback keeps older browsers on the current behaviour rather
   than silently breaking the header. */
@supports (overflow-x: clip) {
  html { overflow-x: clip; }
}
body {
  margin: 0;
  font-family: var(--font-body);
  font-size: 1.0625rem;
  line-height: 1.65;
  color: var(--ink-900);
  background: var(--surface-0);
  -webkit-font-smoothing: antialiased;
}
h1, h2, h3, h4, h5, h6 {
  font-family: var(--font-display);
  color: inherit;
  line-height: 1.12;
  margin: 0 0 0.5em;
  font-weight: 700;
  text-wrap: balance;
}
p { margin: 0 0 1em; }
img, video, svg { max-width: 100%; height: auto; }
a { color: var(--blue-500); text-decoration: none; transition: color var(--t-fast) var(--ease); }
a:hover { color: var(--teal-600); }
ul, ol { list-style: none; margin: 0; padding: 0; }
button { font: inherit; cursor: pointer; background: none; border: 0; color: inherit; }
:focus-visible { outline: none; box-shadow: var(--focus-ring); border-radius: 4px; }
::selection { background: var(--teal-500); color: var(--navy-900); }

.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 200;
  background: var(--teal-500); color: var(--navy-900);
  padding: 12px 20px; border-radius: 0 0 var(--r-sm) 0; font-weight: 600;
}
.skip-link:focus { left: 0; }

/* 4. UTILITIES ------------------------------------------------------------- */
.container { max-width: var(--container); margin-inline: auto; padding-inline: var(--gutter); }
.section { padding-block: var(--section-y); }
/* Adjacent sections stack a full pad each (~240px at desktop), which reads as
   dead air. Trim the seam so the boundary keeps a clear but not cavernous
   break; a background change still separates the two visually. */
.section + .section,
.section + .submission-categories,
.section + .submission-guidelines,
.submission-categories + .section,
.submission-guidelines + .section,
.submission-categories + .submission-guidelines,
.submission-guidelines + .submission-categories { padding-top: calc(var(--section-y) * 0.62); }
.section--dark { background: var(--navy-900); color: #fff; }
.section--dark .section-lede { color: rgba(255, 255, 255, 0.78); }
.section--tint { background: var(--surface-1); }
.section--sand { background: var(--sand-50); }

.section-tag {
  display: inline-flex; align-items: center; gap: 10px;
  font-family: var(--font-display); font-size: 0.8125rem; font-weight: 600;
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--teal-600);
  margin-bottom: 14px;
}
.section-tag::before { content: ""; width: 28px; height: 2px; background: var(--teal-500); border-radius: 2px; }
.section--dark .section-tag { color: var(--teal-300); }
.section-title { font-size: clamp(1.9rem, 3.5vw, 2.75rem); font-stretch: 110%; letter-spacing: -0.01em; }
.section-lede { font-size: 1.125rem; color: var(--ink-600); max-width: 46em; }
.section-head { margin-bottom: clamp(32px, 5vw, 56px); }
.section-head--center { text-align: center; }
.section-head--center .section-lede { margin-inline: auto; }

/* Reveal system (IO adds .is-in; stagger via --d set by JS) */
.js .reveal { opacity: 0; transform: translateY(24px);
  transition: opacity 0.6s var(--ease-out), transform 0.6s var(--ease-out);
  transition-delay: var(--d, 0s); }
.js .reveal.is-in { opacity: 1; transform: none; }

/* 5. BUTTONS --------------------------------------------------------------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  font-family: var(--font-display); font-weight: 600; font-size: 0.9375rem;
  letter-spacing: 0.02em; line-height: 1;
  padding: 16px 30px; border-radius: var(--r-pill);
  border: 1.5px solid transparent; text-decoration: none;
  transition: background-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease),
    border-color var(--t-fast) var(--ease), transform var(--t-fast) var(--ease),
    box-shadow var(--t-fast) var(--ease);
  white-space: nowrap;
}
.btn:focus-visible { box-shadow: var(--focus-ring); }
.btn--accent { background: var(--teal-500); color: var(--navy-900); }
.btn--accent:hover { background: var(--teal-600); color: var(--navy-900); transform: translateY(-1px); }
.btn--accent:active { transform: none; background: #17847a; }
.btn--primary { background: var(--navy-700); color: #fff; }
.btn--primary:hover { background: #0d3350; color: #fff; transform: translateY(-1px); }
.btn--primary:active { transform: none; background: #0a2a42; }
.btn--ghost { border-color: rgba(255, 255, 255, 0.4); color: #fff; }
.btn--ghost:hover { background: rgba(255, 255, 255, 0.1); border-color: var(--teal-300); color: #fff; }
.btn--outline { border-color: var(--navy-700); color: var(--navy-700); }
.btn--outline:hover { background: var(--navy-700); color: #fff; }
.btn--sm { padding: 11px 22px; font-size: 0.875rem; }
/* Touch devices: keep small buttons at the 44px minimum tap target. */
@media (pointer: coarse) {
  .btn--sm { min-height: 44px; }
}
.btn[disabled], .btn.is-disabled { opacity: 0.45; pointer-events: none; }
@media (max-width: 560px) {
  .btn { white-space: normal; }
  .hero__cta .btn, .band__cta .btn, .cd-band .btn { width: 100%; }
}
.btn .btn__arrow { transition: transform var(--t-fast) var(--ease); }
.btn:hover .btn__arrow { transform: translateX(3px); }

/* 6. ANNOUNCEMENT BAR ------------------------------------------------------ */
.announce {
  background: var(--navy-700); color: rgba(255, 255, 255, 0.88);
  font-size: 0.8125rem; letter-spacing: 0.04em;
  text-align: center; padding: 10px var(--gutter);
  /* The item is nowrap, so at any width where the marquee is off but the line
     still does not fit it would push the whole page sideways. Two halves to
     the fix: clip here so no viewport is ever left without containment, and
     run the marquee below the width where the line fits (see the media query
     further down). Re-measure that boundary whenever this text changes — it
     dropped from 859px to 519px when the patronage clause was removed. */
  overflow: hidden;
}
.announce b { color: #fff; font-weight: 600; }
.announce__item { white-space: nowrap; }
/* Desktop: one centred line, the duplicate is not needed. */
.announce__item--dup { display: none; }

@media (max-width: 519px) {
  .announce {
    font-size: 0.75rem; padding-inline: 0;
    -webkit-mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
            mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
  }
  .announce__track {
    display: flex; width: max-content; max-width: none; padding: 0;
    animation: announce-scroll 26s linear infinite;
  }
  .announce__item { padding-inline: 1.6em; }
  .announce__item--dup { display: inline; }
  /* Half the distance, because the content is two identical copies — the loop
     restarts exactly where the first copy began, so there is no jump. */
  @keyframes announce-scroll {
    from { transform: translateX(0); }
    to   { transform: translateX(-50%); }
  }
  /* Pause on touch, so anyone reading it can stop it. */
  .announce:active .announce__track { animation-play-state: paused; }
}

@media (prefers-reduced-motion: reduce) {
  .announce__track { animation: none; }
  /* Static and readable rather than a clipped, frozen marquee. */
  .announce__item--dup { display: none; }
  @media (max-width: 519px) {
    .announce { overflow-x: auto; -webkit-mask-image: none; mask-image: none; }
    .announce__track { width: auto; }
  }
}

/* 7. HEADER / NAV ----------------------------------------------------------

   The header is light so the original colour logo reads on it — the artwork is
   navy and teal, and was invisible on the old dark bar. Everything inside is
   driven by these three tokens; the mobile drawer overrides them back to the
   dark set, because it covers the page rather than sitting on it. */
.site-header {
  --hdr-fg: var(--ink-900);
  --hdr-fg-dim: var(--ink-600);
  --hdr-line: var(--border);
  position: sticky; top: 0; z-index: 100;
  background: rgba(255, 255, 255, 0.94);
  -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--hdr-line);
  transition: box-shadow var(--t-med) var(--ease);
}
.site-header.is-scrolled { box-shadow: 0 8px 24px rgba(8, 26, 43, 0.12); }
.site-header__row {
  display: flex; align-items: center; justify-content: space-between; gap: 20px;
  height: var(--header-h);
  transition: height var(--t-med) var(--ease);
}
.site-header.is-scrolled .site-header__row { height: calc(var(--header-h) - 8px); }
.brand { display: inline-flex; align-items: center; flex-shrink: 0; }
.brand img { height: 44px; width: auto; }
/* Only one mark shows at a time — see body.nav-open in the drawer block. */
.brand__mark--white { display: none; }
@media (max-width: 767px) { .brand img { height: 36px; } }

/* Second header row — the full nav gets its own band, so 10 items never
   compete with the brand and actions for width. */
.site-header__navrow {
  border-top: 1px solid var(--hdr-line);
  background: rgba(8, 26, 43, 0.025);
  /* Deliberately NOT overflow:hidden. That was added as a guard against a nav
     wider than the viewport, but the dropdown panels are positioned below this
     row — clipping the row hid every one of them. The compact link tier
     (1024-1279px) is what actually keeps the list inside the viewport now. */
}
/* Centre the row so the links sit balanced under the brand/actions row. */
@media (min-width: 1024px) {
  /* .nav is a block, so the list was only as wide as its items and
     justify-content had no free space to distribute — it read as
     left-aligned. Giving the list the full row width lets it centre. */
  .site-header__navrow .nav { display: block; width: 100%; }
  .site-header__navrow .nav__list { width: 100%; justify-content: center; }
}
.nav { position: relative; }
.nav__list { display: flex; align-items: center; gap: 0; flex-wrap: nowrap; }
.nav__item { position: relative; }
.nav__link {
  display: inline-flex; align-items: center; gap: 6px; white-space: nowrap;
  font-family: var(--font-display); font-size: 0.85rem; font-weight: 500;
  color: var(--hdr-fg-dim); padding: 13px 11px;
  position: relative; text-decoration: none; background: none; border: 0;
  transition: color var(--t-fast) var(--ease);
}
/* Three tiers, because nine items with six carets need ~1000px at the default
   size. Without the compact tier the whole nav has to collapse to a burger at
   1199px, which wastes a desktop-width screen. */
@media (min-width: 1024px) and (max-width: 1279px) {
  .nav__link { font-size: 0.78rem; padding: 13px 7px; letter-spacing: -0.005em; }
}
@media (min-width: 1280px) {
  .nav__link { font-size: 0.9rem; padding: 13px 15px; }
}
.nav__link:hover, .nav__item.is-open > .nav__link { color: var(--hdr-fg); }

/* Glide pill: one shared highlight that travels between items rather than
   each link fading its own background. Positioned from JS. */
.nav__glide {
  position: absolute; top: 50%; left: 0; height: 34px; width: 0;
  transform: translateY(-50%); border-radius: var(--r-pill);
  background: rgba(18, 65, 102, 0.06);
  box-shadow: inset 0 0 0 1px rgba(30, 151, 137, 0.35);
  opacity: 0; pointer-events: none; z-index: 0;
  transition: transform var(--t-med) var(--ease-out-expo),
              width var(--t-med) var(--ease-out-expo),
              opacity var(--t-fast) var(--ease);
}
.nav.has-glide .nav__glide { opacity: 1; }
.nav__link > * , .nav__link { position: relative; z-index: 1; }

/* Thread underline — grows from the left, echoing the site's thread motif. */
.nav__link::after {
  content: ""; position: absolute; left: 11px; right: 100%; bottom: 6px; height: 2px;
  background: linear-gradient(90deg, var(--teal-500), var(--teal-300));
  border-radius: 2px; transition: right var(--t-med) var(--ease-out-expo);
}
.nav__link:hover::after, .nav__item.is-open > .nav__link::after { right: 11px; }
@media (min-width: 1280px) {
  .nav__link::after { left: 15px; }
  .nav__link:hover::after, .nav__item.is-open > .nav__link::after { right: 15px; }
}
.nav__caret { transition: transform var(--t-med) var(--ease-out-expo); }
.nav__item.is-open > .nav__link .nav__caret,
.nav__item:hover > .nav__link .nav__caret { transform: rotate(180deg); }

.nav__sub {
  position: absolute; top: calc(100% + 8px); left: 0; min-width: 262px;
  background: linear-gradient(180deg, var(--navy-800), var(--navy-900));
  border: 1px solid rgba(126, 217, 205, 0.18);
  border-radius: 14px; box-shadow: var(--shadow-3);
  padding: 14px 14px 14px 40px; /* left inset holds the ladder rails */
  opacity: 0; visibility: hidden;
  /* Folding ladder: the panel unfolds downward from its top hinge. */
  transform: perspective(900px) rotateX(-82deg); transform-origin: top center;
  transition: opacity 0.2s var(--ease),
              transform 0.42s var(--ease-out-expo),
              visibility 0.42s;
  z-index: 110;
}
/* Two threads running the height of the panel — the ladder's rails. */
.nav__sub::after {
  content: ""; position: absolute; left: 19px; top: 16px; bottom: 16px; width: 9px;
  background:
    linear-gradient(var(--teal-500), var(--teal-500)) left / 1.5px 100% no-repeat,
    linear-gradient(var(--teal-500), var(--teal-500)) right / 1.5px 100% no-repeat;
  opacity: 0.45; transform: scaleY(0); transform-origin: top;
  transition: transform 0.4s var(--ease-out-expo) 0.1s;
  pointer-events: none;
}
/* Panels near the right edge open leftwards, otherwise they push the page
   wider (a hidden panel still counts toward scroll width). */
.nav__item:nth-last-child(2) > .nav__sub,
.nav__item:nth-last-child(3) > .nav__sub { left: auto; right: 0; }
/* Twin filaments dropping from the parent link into the ladder rails. */
.nav__sub::before {
  content: ""; position: absolute; left: 19px; top: -9px; width: 9px; height: 9px;
  background:
    linear-gradient(180deg, transparent, var(--teal-500)) left / 1.5px 100% no-repeat,
    linear-gradient(180deg, transparent, var(--teal-500)) right / 1.5px 100% no-repeat;
  transform: scaleY(0); transform-origin: top;
  transition: transform 0.3s var(--ease-out-expo) 0.06s;
}
.nav__item.is-open > .nav__sub,
.nav__item:focus-within > .nav__sub {
  opacity: 1; visibility: visible; transform: perspective(900px) rotateX(0deg);
}
.nav__item.is-open > .nav__sub::before,
.nav__item:focus-within > .nav__sub::before { transform: scaleY(1); }
.nav__item.is-open > .nav__sub::after,
.nav__item:focus-within > .nav__sub::after { transform: scaleY(1); }
@media (hover: hover) and (min-width: 1024px) {
  .nav__item:hover > .nav__sub {
    opacity: 1; visibility: visible; transform: perspective(900px) rotateX(0deg);
  }
  .nav__item:hover > .nav__sub::before,
  .nav__item:hover > .nav__sub::after { transform: scaleY(1); }
}
/* Rungs: each row is spaced so the ladder reads as separate steps. */
.nav__sub li + li { margin-top: 6px; }
.nav__sub a {
  display: block; padding: 11px 14px; border-radius: var(--r-sm);
  color: rgba(255, 255, 255, 0.82); font-size: 0.9rem; position: relative;
  transition: color var(--t-fast) var(--ease), background-color var(--t-fast) var(--ease),
              transform var(--t-fast) var(--ease-out);
}
/* Nut: a hex bolt seated across the two rails at each rung. */
.nav__sub a::before {
  content: ""; position: absolute; left: -25px; top: 50%; width: 11px; height: 11px;
  margin-top: -5.5px;
  background: var(--navy-700);
  box-shadow: inset 0 0 0 1.5px var(--teal-500);
  clip-path: polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0% 50%);
  transition: background-color var(--t-fast) var(--ease), transform var(--t-med) var(--ease-out);
}
.nav__sub a:hover, .nav__sub a:focus-visible {
  color: #fff; background: rgba(255, 255, 255, 0.07); transform: translateX(3px);
}
/* the nut turns as you pick the rung */
.nav__sub a:hover::before, .nav__sub a:focus-visible::before {
  background: var(--teal-300); transform: rotate(90deg);
}
/* Sub-items cascade in, so the panel unfolds rather than just appearing. */
@media (prefers-reduced-motion: no-preference) {
  /* Rows cascade in so the panel unfolds instead of appearing all at once.
     The transition (incl. per-row delay) lives on the base rule — the open
     state only flips the values, so the delays are not overridden. */
  /* Each rung swings down on its own hinge, one after the next. */
  .nav__sub li {
    opacity: 0; transform: perspective(600px) rotateX(-70deg);
    transform-origin: top center;
    transition: opacity 0.24s var(--ease), transform 0.34s var(--ease-out-expo);
  }
  .nav__item.is-open > .nav__sub li,
  .nav__item:focus-within > .nav__sub li {
    opacity: 1; transform: perspective(600px) rotateX(0deg);
  }
  @media (hover: hover) and (min-width: 1024px) {
    .nav__item:hover > .nav__sub li {
      opacity: 1; transform: perspective(600px) rotateX(0deg);
    }
  }
  /* Closing collapses the whole ladder together (no reverse cascade), so the
     panel folds shut cleanly instead of unzipping rung by rung. */
  .nav__sub li { transition-delay: 0s; }
  .nav__item.is-open > .nav__sub li:nth-child(1),
  .nav__item:focus-within > .nav__sub li:nth-child(1) { transition-delay: 0.10s; }
  .nav__item.is-open > .nav__sub li:nth-child(2),
  .nav__item:focus-within > .nav__sub li:nth-child(2) { transition-delay: 0.16s; }
  .nav__item.is-open > .nav__sub li:nth-child(3),
  .nav__item:focus-within > .nav__sub li:nth-child(3) { transition-delay: 0.22s; }
  .nav__item.is-open > .nav__sub li:nth-child(4),
  .nav__item:focus-within > .nav__sub li:nth-child(4) { transition-delay: 0.28s; }
  .nav__item.is-open > .nav__sub li:nth-child(5),
  .nav__item:focus-within > .nav__sub li:nth-child(5) { transition-delay: 0.34s; }
  @media (hover: hover) and (min-width: 1024px) {
    .nav__item:hover > .nav__sub li:nth-child(1) { transition-delay: 0.10s; }
    .nav__item:hover > .nav__sub li:nth-child(2) { transition-delay: 0.16s; }
    .nav__item:hover > .nav__sub li:nth-child(3) { transition-delay: 0.22s; }
    .nav__item:hover > .nav__sub li:nth-child(4) { transition-delay: 0.28s; }
    .nav__item:hover > .nav__sub li:nth-child(5) { transition-delay: 0.34s; }
  }
}

.site-header__actions { display: flex; align-items: center; gap: 14px; margin-left: 6px; flex-shrink: 0; }
.brand { flex-shrink: 0; }
.patronage-chip {
  /* The white plate existed to lift the ministry mark off the old dark bar.
     On the light header it vanishes, so the chip is now outlined instead. */
  display: none; background: #fff; border: 1px solid var(--border);
  border-radius: var(--r-sm); padding: 5px 10px;
  line-height: 0; flex-shrink: 0;
}
.patronage-chip img { height: 30px; width: auto; }
/* The 1240px container is too narrow for 10 nav items plus the brand and
   actions, so the header alone widens on large screens. */
/* Even widened, the chip only fits on very large screens; below that it would
   sit under the last links. It still appears in the footer. */
/* Ministry mark: logo left, ministry right, burger far right. Kept on phones
   too (scaled down); hidden only on the very narrowest, where the logo and
   burger need the whole row. */
@media (min-width: 380px) { .patronage-chip { display: inline-flex; } }
@media (max-width: 1023px) {
  .patronage-chip { padding: 4px 8px; margin-left: auto; }
  .patronage-chip img { height: 20px; }
}
@media (max-width: 480px) { .patronage-chip img { height: 17px; } }
/* The ministry mark carries no width attribute, and the brand, actions and
   chip are all flex-shrink:0 — below this the row has no slack left, so the
   chip goes rather than letting the toggle be pushed off-screen. */
@media (max-width: 420px) { .patronage-chip { display: none; } }

.nav-toggle {
  display: none; width: 44px; height: 44px; border-radius: var(--r-sm);
  position: relative; z-index: 130; flex-shrink: 0;
}
.nav-toggle span, .nav-toggle::before, .nav-toggle::after {
  content: ""; display: block; width: 22px; height: 2px; background: var(--hdr-fg);
  border-radius: 2px; margin: 5px auto; transition: transform var(--t-med) var(--ease),
    opacity var(--t-fast) var(--ease);
}
/* Open: the three bars become an X. This IS the close control — a second
   dedicated close button next to it only produced two X's doing one job. */
body.nav-open .nav-toggle::before { transform: translateY(7px) rotate(45deg); }
body.nav-open .nav-toggle span { opacity: 0; transform: scaleX(0); }
body.nav-open .nav-toggle::after { transform: translateY(-7px) rotate(-45deg); }
/* A ring appears around it while open, so it reads as a dismiss affordance
   rather than a menu button that happens to have changed shape. */
body.nav-open .nav-toggle {
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.2);
  background: rgba(255, 255, 255, 0.06);
}
body.nav-open .nav-toggle:hover {
  border-color: var(--teal-500); background: rgba(35, 173, 158, 0.18);
}
body.nav-open .nav-toggle:hover::before { transform: translateY(7px) rotate(135deg); }
body.nav-open .nav-toggle:hover::after  { transform: translateY(-7px) rotate(-225deg); }

@media (max-width: 1023px) {
  .nav-toggle { display: block; }
  .site-header .btn--register { display: none; }
  /* The nav becomes a fixed drawer; its row band must not reserve height or
     act as a containing block for it. */
  .site-header__navrow { border-top: 0; background: none; }
  .site-header__navrow, .site-header__navrow > .container {
    display: contents; /* drawer escapes the wrapper entirely */
  }
  .nav__glide { display: none; }
  /* the nav is position:fixed on mobile (out of flow) — push actions to the right edge */
  .site-header__actions { margin-left: auto; }
  /* drawer open: header sits ABOVE the overlay, fully opaque — nothing bleeds
     through. The drawer covers the page rather than sitting on it, so it keeps
     the dark palette; the tokens flip back so the logo, bars and links invert
     with it. */
  body.nav-open .site-header {
    --hdr-fg: #fff;
    --hdr-fg-dim: rgba(255, 255, 255, 0.82);
    --hdr-line: var(--border-dark);
    z-index: 130; background: var(--navy-900);
    -webkit-backdrop-filter: none; backdrop-filter: none;
  }
  /* The colour logo disappears on the dark drawer, so swap in the white cut. */
  body.nav-open .brand__mark--colour { display: none; }
  body.nav-open .brand__mark--white { display: block; }
  #site-nav.nav {
    position: fixed; inset: 0; z-index: 120; background: var(--navy-900);
    padding: calc(var(--header-h) + 32px) var(--gutter) 40px;
    overflow-y: auto; margin: 0;
    opacity: 0; visibility: hidden; transition: opacity var(--t-med) var(--ease), visibility var(--t-med);
  }
  body.nav-open #site-nav.nav { opacity: 1; visibility: visible; }
  body.nav-open { overflow: hidden; }
  .nav__list { flex-direction: column; align-items: stretch; gap: 0; }
  .nav__item { border-bottom: 1px solid var(--border-dark); }
  .nav__link {
    width: 100%; justify-content: space-between; padding: 19px 4px;
    font-size: 1.32rem; font-weight: 700; font-stretch: 108%;
    text-transform: uppercase; letter-spacing: 0.03em; color: #fff;
    opacity: 0; transform: translateY(12px);
    transition: opacity 0.4s var(--ease-out), transform 0.4s var(--ease-out);
    transition-delay: var(--d, 0s);
  }
  body.nav-open .nav__link { opacity: 1; transform: none; }
  .nav__link::after { display: none; }
  .nav__sub {
    position: static; min-width: 0; background: none; border: 0; box-shadow: none;
    padding: 0 0 0 12px; transform: none; display: block;
    max-height: 0; overflow: hidden; opacity: 0; visibility: hidden;
    transition: max-height 0.5s var(--ease-out-expo), opacity 0.35s var(--ease),
      visibility 0.5s, padding 0.5s var(--ease-out-expo);
  }
  .nav__item.is-open > .nav__sub {
    max-height: 440px; opacity: 1; visibility: visible; padding-bottom: 10px;
  }
  /* The desktop ladder fold is 3D and rail-based; the mobile accordion
     expands in flow instead, so reset the rungs, rails and nuts here. */
  .nav__sub li { opacity: 1; transform: none; transition: none; }
  .nav__sub::before, .nav__sub::after { display: none; }
  .nav__sub a::before { display: none; }
  .nav__sub li + li { margin-top: 0; }
  /* beat the desktop open-state fold, which also targets .is-open > .nav__sub */
  .nav__item.is-open > .nav__sub,
  .nav__item:focus-within > .nav__sub { transform: none; }
  .nav__sub a { opacity: 0; transform: translateY(8px);
    transition: opacity 0.35s var(--ease-out-quint), transform 0.35s var(--ease-out-quint); }
  .nav__item.is-open > .nav__sub a { opacity: 1; transform: none; }
  .nav__item.is-open > .nav__sub a:nth-child(1) { transition-delay: 0.08s; }
  .nav__item.is-open > .nav__sub li:nth-child(2) a { transition-delay: 0.12s; }
  .nav__item.is-open > .nav__sub li:nth-child(3) a { transition-delay: 0.16s; }
  .nav__item.is-open > .nav__sub li:nth-child(4) a { transition-delay: 0.2s; }
  .nav__item.is-open > .nav__sub li:nth-child(5) a { transition-delay: 0.24s; }
  .nav__item.is-open > .nav__sub li:nth-child(6) a { transition-delay: 0.28s; }
  /* drawer backdrop: subtle RHIC facet field, no glassmorphism */
  #site-nav.nav::after {
    content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
    background:
      radial-gradient(420px 420px at 88% 12%, rgba(35, 173, 158, 0.1), transparent 65%),
      radial-gradient(360px 360px at 8% 92%, rgba(34, 126, 194, 0.08), transparent 65%);
  }
  .nav__sub a { font-size: 1rem; padding: 12px 10px; }
  .nav__mobile-cta { display: block; margin-top: 28px; }
  .nav__mobile-cta .btn { width: 100%; }
}
@media (min-width: 1024px) { .nav__mobile-cta { display: none; } }

/* 8. HERO ------------------------------------------------------------------ */
.hero {
  position: relative; background: var(--navy-900); color: #fff; overflow: hidden;
  /* Budget against the header that actually stays pinned, not the token.
     --header-h is 76px (the brand row), but on desktop the nav row sits below
     it and the whole 128px block is sticky — so reserving only 76px left the
     hero ~50px taller than the screen and pushed the CTAs under the fold. */
  min-height: min(calc(100svh - var(--header-pinned)), 1040px);
  display: flex; align-items: center;
}
.hero__bg { position: absolute; inset: 0; pointer-events: none; }
.hero__bg::before {
  content: ""; position: absolute; inset: 0;
  background:
    radial-gradient(900px 600px at 82% 18%, rgba(34, 126, 194, 0.14), transparent 60%),
    radial-gradient(700px 700px at 8% 85%, rgba(35, 173, 158, 0.1), transparent 60%);
}
.hero__facets { position: absolute; right: -4%; top: -6%; width: 56%; opacity: 0.5; }
/* The thread is a fixed-width strip pinned to the left of the hero copy.

   It used to be a full-bleed SVG with preserveAspectRatio="slice", which tied
   the line's x-position to the viewport while the copy is centred in a 1240px
   container — between roughly 1200 and 1370px the two collided and the line
   ran through the headline. A fixed strip whose right edge tracks the
   container removes the coupling: the vertical run always lands the same
   distance to the left of the text. */
.hero__thread {
  position: absolute; top: 0; bottom: 0; height: 100%;
  /* The run is at x=64 of the 148-wide strip, so offsetting by -64 puts it on
     the strip's left origin; the extra 26px is the gap to the copy. Once the
     container stops growing the value goes negative and the strip simply
     slides off the left edge, which is the graceful end of the gesture —
     better than the line creeping into the headline. */
  left: calc(50% - var(--container) / 2 - 90px);
  width: 148px;
}
/* Narrow desktops have no room for it beside the copy at all. */
@media (max-width: 1365px) { .hero__thread { display: none; } }
.hero__thread path { stroke: var(--teal-500); stroke-width: 2; fill: none; }
.hero__thread circle { fill: var(--teal-300); }

/* Text left, logo-shaped media right — the original two-column hero. The mark
   is landscape, so the media column is the wider of the two; stacking it under
   the headline pushed the hero past two screens. */
.hero__grid {
  position: relative; z-index: 1; display: grid;
  /* The headline leads, so it gets the wider column — an even split forced
     "INTERNATIONAL" to break mid-word. */
  grid-template-columns: minmax(0, 1.2fr) minmax(0, 0.9fr);
  gap: clamp(28px, 3.5vw, 52px); align-items: center;
  padding-block: clamp(40px, 6vh, 72px);
  width: 100%;
}
.hero__eyebrow {
  font-family: var(--font-display); font-size: 0.8125rem; font-weight: 600;
  letter-spacing: 0.18em; text-transform: uppercase; color: var(--teal-300);
  margin-bottom: 22px; display: flex; align-items: center; gap: 12px;
}
.hero__eyebrow::before { content: ""; width: 34px; height: 2px; background: var(--teal-500); }
.hero__title {
  font-size: clamp(1.8rem, 4.5vw, 3.9rem); font-weight: 800; font-stretch: 110%;
  text-transform: uppercase; letter-spacing: 0.005em; line-height: 1.06; margin-bottom: 24px;
}
.hero__title .line { display: block; overflow: hidden; }
.hero__title .line > span { display: inline-block; }
.hero__title em { font-style: normal; color: var(--teal-300); }
.js:not(.has-gsap) .hero:not(.is-ready) .hero__title .line > span { transform: translateY(110%); }
.js:not(.has-gsap) .hero.is-ready .hero__title .line > span {
  animation: hero-line 0.75s var(--ease-out) both;
  animation-delay: calc(0.12s + var(--l, 0) * 0.09s);
}
.has-gsap .hero__title .line > span { transform: translateY(112%); }
@keyframes hero-line { from { transform: translateY(110%); } to { transform: translateY(0); } }

.hero__tagline {
  font-size: clamp(1.05rem, 1.6vw, 1.3rem); color: rgba(255, 255, 255, 0.85);
  font-weight: 400; letter-spacing: 0.01em; margin-bottom: 30px;
}
.hero__tagline b { color: var(--teal-300); font-weight: 600; }

.hero__meta {
  display: flex; flex-wrap: wrap; gap: 20px 36px;
  border-block: 1px solid var(--border-dark); padding-block: 18px; margin-bottom: 32px;
}
.hero__meta .meta__label {
  display: block; font-family: var(--font-display); font-size: 0.72rem; font-weight: 600;
  letter-spacing: 0.16em; text-transform: uppercase; color: rgba(255, 255, 255, 0.55);
  margin-bottom: 4px;
}
.hero__meta .meta__value { font-family: var(--font-display); font-weight: 600; font-size: 1.02rem; color: #fff; }

.hero__cta { display: flex; flex-wrap: wrap; gap: 14px; margin-bottom: 30px; }
.hero__patronage { font-size: 0.8125rem; color: rgba(255, 255, 255, 0.55); letter-spacing: 0.03em; margin: 0; }

/* Short-viewport hero.
   The hero's job is to get the reader to "Register Now" / "Submit Your
   Abstract" without scrolling. Its content needs ~640px, which a 14" laptop at
   100% zoom (~460px under the pinned header) cannot give — the CTAs landed
   below the fold while the same page was fine on a 17".

   Rather than shrink everything everywhere, the spacing tightens only when the
   viewport is genuinely short. Height is the right query here, not width: a
   1920x800 window has the same problem as a 1366x768 one, and a tall portrait
   monitor has none. Type sizes are trimmed a little; the gaps between blocks
   carry most of the reduction, because whitespace is what the reader can spare
   and legibility is not. */
@media (min-width: 1024px) and (max-height: 860px) {
  .hero__grid { padding-block: clamp(24px, 3.2vh, 40px); }
  .hero__eyebrow { margin-bottom: 14px; }
  .hero__title { font-size: clamp(1.8rem, 3.6vw, 3.1rem); margin-bottom: 16px; }
  .hero__tagline { font-size: clamp(1rem, 1.35vw, 1.15rem); margin-bottom: 20px; }
  .hero__meta { padding-block: 13px; margin-bottom: 22px; gap: 12px 32px; }
  .hero__cta { margin-bottom: 20px; }
}

/* Shorter still (a 14" at 100%, or any window with the dev tools docked). */
@media (min-width: 1024px) and (max-height: 720px) {
  .hero__grid { padding-block: 20px; }
  .hero__eyebrow { margin-bottom: 10px; font-size: 0.75rem; }
  .hero__title { font-size: clamp(1.7rem, 3.1vw, 2.6rem); margin-bottom: 12px; }
  .hero__tagline { font-size: 1rem; margin-bottom: 14px; }
  .hero__meta { padding-block: 11px; margin-bottom: 16px; gap: 10px 28px; }
  .hero__meta .meta__value { font-size: 0.95rem; }
  .hero__cta { margin-bottom: 14px; }
  /* The patronage line is the least load-bearing thing in the hero, and the
     same credit already appears in the announce bar and the footer. */
  .hero__patronage { display: none; }
}

.js .hero__stagger { opacity: 0; transform: translateY(18px); }
.js:not(.has-gsap) .hero.is-ready .hero__stagger {
  animation: hero-fade 0.7s var(--ease-out) both;
  animation-delay: calc(0.45s + var(--s, 0) * 0.12s);
}
@keyframes hero-fade { to { opacity: 1; transform: none; } }

/* Logo-masked media.
   The mark is landscape (192:60) where the old facet was portrait, so the
   media column is given the full width of the hero grid rather than a narrow
   430px sliver — otherwise the video would be reduced to a letterbox strip. */
.hero__media {
  position: relative; justify-self: stretch;
  width: 100%; max-width: 100%;
}
.hero__facet {
  position: relative; aspect-ratio: var(--logo-aspect); overflow: hidden;
  clip-path: var(--logo-clip);
  background: var(--navy-800);
}
.hero__facet video, .hero__facet img {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
}
.hero__facet::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(200deg, rgba(8, 26, 43, 0) 55%, rgba(8, 26, 43, 0.55));
}
.hero__facet-outline {
  position: absolute; inset: 0; transform: translate(14px, 14px); z-index: -1;
  clip-path: var(--logo-clip);
  background: linear-gradient(160deg, rgba(35, 173, 158, 0.35), rgba(34, 126, 194, 0.12));
  opacity: 0.55;
}
.js:not(.has-gsap) .hero.is-ready .hero__media { animation: hero-media 1s var(--ease-out) 0.3s both; }
@keyframes hero-media { from { opacity: 0; transform: translateY(26px); } to { opacity: 1; transform: none; } }

/* The hero thread turns the corner at the bottom-left and runs horizontally
   at the same height as this label, so the line used to strike through the
   word. Sit the cue clear of that run: above the corner, and indented past
   the thread's vertical leg. */
/* Sits in the hero's bottom-left corner, below the content rather than beside
   it: at its old inset it shared a band with the CTA row and the word "SCROLL"
   ran into the Register button. Vertical, so it occupies the narrow strip left
   of the container and cannot collide with anything again. */
.hero__scrollcue {
  /* Right of the social rail's column (it is 55px wide and vertically centred),
     so the two never share space at any viewport height. */
  position: absolute; left: calc(var(--gutter) + 30px); bottom: 26px; z-index: 2;
  display: flex; flex-direction: column; align-items: center; gap: 10px;
  font-family: var(--font-display); font-size: 0.66rem; font-weight: 600;
  letter-spacing: 0.24em; text-transform: uppercase; color: rgba(255, 255, 255, 0.42);
  writing-mode: vertical-rl;                 /* reads bottom-to-top up the line */
  pointer-events: none;
}
.hero__scrollcue::after {
  content: ""; width: 1px; height: 40px; background: linear-gradient(var(--teal-500), transparent);
  animation: cue 2.4s var(--ease) infinite;
  transform-origin: top;
}
/* Only where there is room beside the container for it to live. */
@media (max-width: 1279px) { .hero__scrollcue { display: none; } }
@keyframes cue { 0%, 100% { transform: scaleY(0.4); opacity: 0.5; } 50% { transform: scaleY(1); opacity: 1; } }

@media (max-width: 1023px) {
  .hero__grid { grid-template-columns: 1fr; }
  /* One video, not two. The logo-shaped cut IS the mobile background now: the
     separate full-bleed .hero__bg-mobile film used to play behind it, so the
     same footage ran twice, out of sync, and read as a mistake. */
  .hero__bg-mobile { display: none; }

  .hero__media {
    display: block;
    position: absolute; inset: 0; z-index: 0;
    width: 100%; margin: 0;
    pointer-events: none;                 /* text above stays selectable */
  }
  .hero__facet {
    position: absolute; left: 50%; top: 50%;
    transform: translate(-50%, -50%);
    width: 132%;                          /* bleed past the edges so the mark
                                             reads as a backdrop, not a card */
    aspect-ratio: var(--logo-aspect);
  }
  /* Brand wash over the film, so the headline stays readable — this is the
     gradient that used to live on .hero__bg-mobile::after. */
  .hero__facet::after {
    background: linear-gradient(180deg,
      rgba(8, 26, 43, 0.84) 0%,
      rgba(8, 26, 43, 0.62) 34%,
      rgba(8, 26, 43, 0.64) 62%,
      rgba(8, 26, 43, 0.95) 100%);
  }
  .hero__content { position: relative; z-index: 1; }
  .hero__facet-outline { display: none; }   /* too fussy at this size */
  .hero { min-height: 0; }
  .hero__thread { display: none; }
  .hero__scrollcue { display: none; }
}

/* 9. PAGE HERO (subpages) -------------------------------------------------- */
.page-hero {
  position: relative; background: var(--navy-900); color: #fff; overflow: hidden;
  padding-block: clamp(56px, 9vw, 104px);
}
.page-hero__bg { position: absolute; inset: 0; opacity: 0.5; pointer-events: none; }
.page-hero__bg img { width: 100%; height: 100%; object-fit: cover; }
.page-hero__bg::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(90deg, rgba(8, 26, 43, 0.95) 30%, rgba(8, 26, 43, 0.55));
}
.page-hero .container { position: relative; z-index: 1; }
.page-hero__title {
  font-size: clamp(2rem, 4.2vw, 3.2rem); font-weight: 800; font-stretch: 112%;
  text-transform: uppercase; margin-bottom: 10px;
}
.page-hero__lede { color: rgba(255, 255, 255, 0.8); font-size: 1.1rem; max-width: 44em; margin: 0; }

.breadcrumb-nav { margin-top: 22px; }
.breadcrumbs { display: flex; flex-wrap: wrap; gap: 8px; font-size: 0.85rem; }
.breadcrumbs a { color: rgba(255, 255, 255, 0.65); }
.breadcrumbs a:hover { color: var(--teal-300); }
.breadcrumbs li + li::before { content: "/"; margin-right: 8px; color: rgba(255, 255, 255, 0.35); }
.breadcrumbs [aria-current] { color: var(--teal-300); }

/* 10. EMBED SHELL (Eventegration) ------------------------------------------ */
/* A little breathing room inside the frame. The embedded form draws its own
   content flush to its edges, so without this its first step marker sat hard
   against our border and read as clipped. */
.embed-shell {
  position: relative; background: var(--surface-0); border: 1px solid var(--border);
  border-radius: var(--r-lg); box-shadow: var(--shadow-2); overflow: hidden;
  padding: clamp(10px, 1.6vw, 22px);
}
@media (max-width: 640px) { .embed-shell { padding: 8px; } }
.embed-shell iframe { display: block; width: 100%; border: 0; }
.embed-skeleton {
  position: absolute; inset: 0; z-index: 2; background: var(--surface-1);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 18px; text-align: center; padding: 32px;
  transition: opacity 0.5s var(--ease), visibility 0.5s;
}
.embed-shell.is-loaded .embed-skeleton { opacity: 0; visibility: hidden; }
.embed-skeleton__mark {
  width: 96px; height: 30px;
  clip-path: var(--logo-clip);
  background: linear-gradient(160deg, var(--navy-700), var(--teal-500));
  animation: pulse-mark 1.6s var(--ease) infinite;
}
@keyframes pulse-mark { 0%, 100% { opacity: 0.45; transform: scale(0.96); } 50% { opacity: 1; transform: scale(1); } }
.embed-skeleton__text { font-family: var(--font-display); font-weight: 600; color: var(--ink-600); margin: 0; }
.embed-fallback { display: none; }
.embed-shell.is-failed .embed-skeleton { opacity: 0; visibility: hidden; }
.embed-shell.is-failed .embed-fallback {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 14px; position: absolute; inset: 0; z-index: 3; background: var(--surface-1);
  text-align: center; padding: 32px;
}
.embed-help { margin-top: 18px; text-align: center; font-size: 0.9rem; color: var(--ink-600); }
.embed-help a { font-weight: 600; }

/* 11. COMING SOON ----------------------------------------------------------- */
.coming-soon {
  position: relative; background: var(--navy-900); color: #fff; overflow: hidden;
  /* Same reservation as the hero: the pinned header, not the token. */
  min-height: min(calc(100svh - var(--header-pinned)), 860px);
  display: flex; align-items: center; text-align: center;
}
.coming-soon .container { position: relative; z-index: 1; max-width: 760px; }
.coming-soon__tag { color: var(--teal-300); }
.coming-soon__title { font-size: clamp(2.1rem, 4.5vw, 3.4rem); font-stretch: 112%; text-transform: uppercase; }
.coming-soon__lede { color: rgba(255, 255, 255, 0.75); font-size: 1.1rem; }
.coming-soon__meta {
  display: inline-flex; flex-wrap: wrap; justify-content: center; gap: 12px 28px;
  border-block: 1px solid var(--border-dark); padding: 14px 8px; margin: 26px 0 30px;
  font-family: var(--font-display); font-weight: 600; font-size: 0.95rem;
}
.coming-soon__cta { display: flex; flex-wrap: wrap; gap: 14px; justify-content: center; }

/* 12. FOOTER ---------------------------------------------------------------- */
.site-footer { background: var(--navy-900); color: rgba(255, 255, 255, 0.78); position: relative; }
.site-footer__horizon { display: block; width: 100%; height: 70px; }
.site-footer__horizon path { stroke: var(--teal-500); stroke-width: 1.5; fill: none; opacity: 0.65; }
.site-footer__horizon circle { fill: var(--teal-300); }
.site-footer__grid {
  display: grid; grid-template-columns: 1.4fr 1fr 1fr 1.1fr;
  gap: clamp(32px, 4vw, 56px); padding-block: 24px 56px;
}
.site-footer h2 {
  font-size: 0.8125rem; font-weight: 600; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--teal-300); margin-bottom: 18px;
}
.site-footer__brand img { height: 52px; width: auto; margin-bottom: 18px; }
.site-footer__brand p { font-size: 0.95rem; margin-bottom: 6px; }
.site-footer a { color: rgba(255, 255, 255, 0.78); }
.site-footer a:hover { color: var(--teal-300); }
.site-footer__links li { margin-bottom: 10px; font-size: 0.95rem; }
.footer-patronage { background: #fff; border-radius: var(--r-sm); padding: 10px 14px; display: inline-block; line-height: 0; margin-top: 6px; }
.footer-patronage img { height: 40px; width: auto; }
.social-row { display: flex; gap: 10px; margin-top: 16px; }
.social-row a {
  display: inline-flex; align-items: center; justify-content: center;
  width: 42px; height: 42px; border-radius: 50%;
  border: 1px solid var(--border-dark); color: #fff;
  transition: background-color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease),
    transform var(--t-fast) var(--ease);
}
.social-row a:hover { background: var(--teal-500); border-color: var(--teal-500); color: var(--navy-900); transform: translateY(-2px); }
.site-footer__bottom {
  border-top: 1px solid var(--border-dark); padding-block: 20px;
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px 24px;
  justify-content: space-between;
  font-size: 0.85rem; color: rgba(255, 255, 255, 0.55);
}
/* Design credit sits last on desktop, centred when the row wraps on mobile. */
.site-footer__credit { margin-inline-start: auto; }
.site-footer__credit a { color: rgba(255, 255, 255, 0.72); }
.site-footer__credit a:hover,
.site-footer__credit a:focus-visible { color: var(--teal-300); }
@media (max-width: 767px) {
  .site-footer__bottom { justify-content: center; text-align: center; }
  .site-footer__credit { margin-inline-start: 0; }
}
@media (max-width: 1023px) { .site-footer__grid { grid-template-columns: 1fr 1fr; } }
@media (max-width: 640px)  { .site-footer__grid { grid-template-columns: 1fr; } }

/* 13. HOME — SCALE STRIP ---------------------------------------------------- */
.stat-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 24px; }
.stat-tile {
  background: var(--surface-0); border: 1px solid var(--border); border-radius: var(--r-md);
  padding: 30px 28px 26px; position: relative; overflow: hidden;
}
.stat-tile::after {
  content: ""; position: absolute; top: 0; right: 0; width: 26px; height: 26px;
  background: linear-gradient(225deg, var(--surface-1) 50%, transparent 50%);
}
.stat-tile__num {
  font-family: var(--font-display); font-weight: 800; font-stretch: 110%;
  font-size: clamp(2.3rem, 3.6vw, 3rem); line-height: 1; color: var(--navy-700);
  font-variant-numeric: tabular-nums; display: flex; align-items: baseline; gap: 2px;
}
.stat-tile__num i { font-style: normal; color: var(--teal-500); font-size: 0.72em; }
.stat-tile__label { font-family: var(--font-display); font-weight: 600; font-size: 1.02rem; margin: 10px 0 6px; color: var(--ink-900); }
.stat-tile__desc { font-size: 0.9rem; color: var(--ink-400); margin: 0; }
.stat-tile--seal .stat-tile__num { color: var(--teal-600); font-size: clamp(1.7rem, 2.6vw, 2.1rem); }
@media (max-width: 1023px) { .stat-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px)  { .stat-grid { grid-template-columns: 1fr; gap: 16px; } }

/* 14. SPLIT (About) --------------------------------------------------------- */
.split { display: grid; grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr); gap: clamp(40px, 6vw, 88px); align-items: center; }
.split__media { position: relative; }
.split__media img {
  width: 100%; aspect-ratio: 4 / 5; object-fit: cover; border-radius: var(--r-lg); display: block;
  clip-path: polygon(0 0, calc(100% - 48px) 0, 100% 48px, 100% 100%, 0 100%);
}
.split__media::before {
  content: ""; position: absolute; inset: auto -16px -16px auto; width: 60%; height: 60%;
  border: 1.5px solid var(--teal-500); border-radius: var(--r-lg); opacity: 0.35; z-index: -1;
  clip-path: polygon(0 0, calc(100% - 48px) 0, 100% 48px, 100% 100%, 0 100%);
}
.split__body .btn { margin-top: 10px; }
@media (max-width: 1023px) {
  .split { grid-template-columns: 1fr; }
  .split__media img { aspect-ratio: 16 / 10; }
}

/* 15. COUNTDOWN BAND -------------------------------------------------------- */
.cd-band { background: var(--navy-900); color: #fff; padding-block: clamp(44px, 6vw, 64px); position: relative; overflow: hidden; }
.cd-band::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(700px 320px at 85% 50%, rgba(35, 173, 158, 0.12), transparent 65%);
}
.cd-band .container { position: relative; display: flex; flex-wrap: wrap; align-items: center; gap: 28px 48px; justify-content: space-between; }
.cd-band__title { font-size: 1.35rem; font-stretch: 110%; margin: 0 0 6px; }
.cd-band__deadline { font-size: 0.9rem; color: rgba(255, 255, 255, 0.7); margin: 0; }
.cd-band__deadline b { color: var(--teal-300); font-weight: 600; }
.cd-row { display: flex; flex-wrap: wrap; gap: 12px; align-items: center; }
.cd-box {
  min-width: 82px; text-align: center; padding: 14px 10px 11px;
  border: 1px solid var(--border-dark); border-radius: var(--r-md); background: rgba(255, 255, 255, 0.04);
}
.cd-box b { display: block; font-family: var(--font-display); font-weight: 700; font-size: 1.9rem; line-height: 1; font-variant-numeric: tabular-nums; }
.cd-box span { font-size: 0.68rem; font-weight: 600; letter-spacing: 0.14em; text-transform: uppercase; color: rgba(255, 255, 255, 0.55); }
@media (max-width: 560px) { .cd-box { min-width: 66px; padding: 11px 6px 9px; } .cd-box b { font-size: 1.5rem; } }
/* Narrow phones: 4-across overflows, so drop the countdown to an even 2x2 grid. */
@media (max-width: 400px) {
  .cd-row { display: grid; grid-template-columns: repeat(2, 1fr); width: 100%; }
  .cd-box { min-width: 0; }
}

/* 16. FEATURE CARDS (Why attend) ------------------------------------------- */
.feature-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 24px; }
.feature-card {
  background: var(--surface-0); border: 1px solid var(--border); border-radius: var(--r-md);
  padding: 30px 28px;
  transition: transform 0.25s var(--ease), box-shadow 0.25s var(--ease), border-color 0.25s var(--ease);
}
.feature-card:hover { transform: translateY(-6px); box-shadow: var(--shadow-2); border-color: var(--teal-500); }
.feature-card__icon {
  width: 52px; height: 52px; border-radius: 14px; display: flex; align-items: center; justify-content: center;
  background: rgba(35, 173, 158, 0.12); color: var(--teal-600); margin-bottom: 20px;
}
.feature-card h3 { font-size: 1.14rem; margin-bottom: 8px; }
.feature-card p { font-size: 0.95rem; color: var(--ink-600); margin: 0; }
@media (max-width: 1023px) { .feature-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 640px)  { .feature-grid { grid-template-columns: 1fr; gap: 16px; } }

/* 17. TRACKS (dark) --------------------------------------------------------- */
.tracks-cta { display: flex; flex-wrap: wrap; gap: 12px; }
.track-chip {
  font-family: var(--font-display); font-weight: 600; font-size: clamp(0.95rem, 1.4vw, 1.12rem);
  padding: 14px 24px; border: 1px solid var(--border-dark); border-radius: var(--r-pill);
  color: rgba(255, 255, 255, 0.88); text-decoration: none;
  transition: border-color var(--t-fast) var(--ease), background-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
a.track-chip:hover { border-color: var(--teal-500); background: rgba(35, 173, 158, 0.14); color: #fff; }
.track-chip--more { border-style: dashed; color: var(--teal-300); }
.tracks-footer { margin-top: 36px; }

/* 18. JOURNEY TIMELINE ------------------------------------------------------ */
.journey ol { display: grid; grid-template-columns: repeat(5, 1fr); gap: 28px; position: relative; counter-reset: none; }
.journey ol.journey-cols-4 { grid-template-columns: repeat(4, 1fr); }
.journey ol::before {
  content: ""; position: absolute; top: 7px; left: 8px; right: 8px; height: 2px;
  background: linear-gradient(90deg, var(--teal-500), var(--border) 85%); border-radius: 2px;
}
.journey li { position: relative; padding-top: 30px; }
.journey li::before {
  content: ""; position: absolute; top: 0; left: 0; width: 16px; height: 16px; border-radius: 50%;
  background: var(--surface-0); border: 3px solid var(--teal-500);
}
.journey__day { font-family: var(--font-display); font-size: 0.72rem; font-weight: 600; letter-spacing: 0.14em; text-transform: uppercase; color: var(--teal-600); display: block; }
.journey__date { font-family: var(--font-display); font-weight: 700; font-size: 1.05rem; color: var(--ink-900); display: block; margin: 2px 0 10px; }
.journey h3 { font-size: 1.02rem; margin-bottom: 6px; }
.journey p { font-size: 0.88rem; color: var(--ink-600); margin: 0; }
@media (max-width: 1023px) {
  .journey ol, .journey ol.journey-cols-4 { grid-template-columns: 1fr; gap: 0; padding-left: 8px; }
  .journey ol::before { top: 8px; bottom: 8px; left: 7px; right: auto; width: 2px; height: auto;
    background: linear-gradient(180deg, var(--teal-500), var(--border) 90%); }
  .journey li { padding: 0 0 28px 34px; }
  .journey li::before { top: 2px; }
}

/* 19. OMAN INTERLUDE -------------------------------------------------------- */
.oman { background: var(--navy-900); color: #fff; padding-block: var(--section-y) 0; overflow: hidden; }
.oman .section-lede { color: rgba(255, 255, 255, 0.78); }
.oman .section-tag { color: var(--teal-300); }
/* Five 220x800 portrait slats, always in ONE row at every breakpoint, and
   always shown whole. Height comes from the source ratio rather than a fixed
   value, so nothing is cropped and nothing scrolls sideways: as the viewport
   narrows the columns narrow with it and the row simply gets shorter. */
.oman__slats {
  display: grid; grid-template-columns: repeat(5, 1fr); gap: 6px;
  margin-top: clamp(36px, 5vw, 64px);
}
/* min-width:0 lets a grid item shrink below its content's intrinsic width —
   without it the 220px-wide image floors the column and overflows the track. */
.oman__slats figure { margin: 0; overflow: hidden; min-width: 0; }
.oman__slats img {
  width: 100%; height: auto; aspect-ratio: 220 / 800; object-fit: cover;
  display: block; transition: transform 0.6s var(--ease-out);
}
@media (hover: hover) { .oman__slats figure:hover img { transform: scale(1.05); } }
@media (max-width: 767px) { .oman__slats { gap: 4px; } }

/* 20. GRADIENT BAND + CLOSING ----------------------------------------------- */
.band { background: var(--gradient-brand); color: #fff; text-align: center; padding-block: clamp(56px, 8vw, 88px); }
.band .section-title { color: #fff; }
.band p { color: rgba(255, 255, 255, 0.88); max-width: 52em; margin-inline: auto; }
.band__cta { display: flex; flex-wrap: wrap; gap: 14px; justify-content: center; margin-top: 28px; }

.closing { background: var(--navy-900); color: #fff; text-align: center; padding-block: clamp(72px, 10vw, 120px); position: relative; overflow: hidden; }
.closing::before {
  content: ""; position: absolute; inset: 0;
  background: radial-gradient(800px 400px at 50% 110%, rgba(35, 173, 158, 0.14), transparent 70%);
}
.closing .container { position: relative; }
.closing .section-title { font-size: clamp(2rem, 4.4vw, 3.2rem); }
.closing p { color: rgba(255, 255, 255, 0.78); max-width: 46em; margin-inline: auto; }

/* 20a. ABOUT PAGE ----------------------------------------------------------- */
.num-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 18px 40px; }
.num-item { display: flex; align-items: center; gap: 16px; padding: 14px 0; border-bottom: 1px solid var(--border); }
.num-item__chip {
  flex-shrink: 0; width: 44px; height: 44px; border-radius: 50%;
  border: 1.5px solid var(--teal-500); color: var(--navy-700);
  font-family: var(--font-display); font-weight: 700; font-size: 0.9rem;
  display: flex; align-items: center; justify-content: center;
}
.num-item__label { font-family: var(--font-display); font-weight: 600; font-size: 1.02rem; }
@media (max-width: 767px) { .num-grid { grid-template-columns: 1fr; gap: 0; } }

/* Audience photo cards — "Who Should Attend" ---------------------------------- */
.aud-grid { display: grid; grid-template-columns: repeat(5, 1fr); gap: 20px; }
.aud-card { margin: 0; }
.aud-card__media {
  position: relative; overflow: hidden; border-radius: var(--r-md);
  border: 1px solid var(--border); background: var(--surface-1);
  aspect-ratio: 307 / 280;
}
.aud-card__media img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  transition: transform var(--t-med) var(--ease-out);
}
/* Navy scrim anchors the number and keeps the photos reading as one set. */
.aud-card__media::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(to top, rgba(8, 26, 43, 0.55) 0%, rgba(8, 26, 43, 0) 46%);
}
.aud-card__num {
  position: absolute; left: 10px; bottom: 8px; z-index: 1;
  font-family: var(--font-display); font-weight: 700; font-size: 1.15rem;
  color: #fff; letter-spacing: 0.02em; text-shadow: 0 1px 6px rgba(8, 26, 43, 0.5);
}
.aud-card__label {
  font-family: var(--font-display); font-weight: 600; font-size: 0.94rem;
  color: var(--ink-900); margin-top: 10px; line-height: 1.35;
}
.aud-card:hover .aud-card__media img { transform: scale(1.06); }
.aud-card:hover .aud-card__media { border-color: var(--teal-500); }

@media (max-width: 1200px) { .aud-grid { grid-template-columns: repeat(4, 1fr); } }
@media (max-width: 900px)  { .aud-grid { grid-template-columns: repeat(3, 1fr); gap: 16px; } }
@media (max-width: 620px)  { .aud-grid { grid-template-columns: repeat(2, 1fr); gap: 14px; } }
@media (max-width: 360px)  { .aud-card__label { font-size: 0.86rem; } }
@media (prefers-reduced-motion: reduce) {
  .aud-card__media img { transition: none; }
  .aud-card:hover .aud-card__media img { transform: none; }
}

.exp-banner { position: relative; border-radius: var(--r-lg); overflow: hidden; min-height: 440px; display: flex; align-items: center; }
.exp-banner__bg { position: absolute; inset: 0; }
.exp-banner__bg img { width: 100%; height: 100%; object-fit: cover; }
.exp-banner__bg::after { content: ""; position: absolute; inset: 0; background: linear-gradient(90deg, rgba(8, 26, 43, 0.15), rgba(8, 26, 43, 0.82) 65%); }
.exp-banner__panel { position: relative; z-index: 1; color: #fff; max-width: 520px; margin-left: auto; padding: clamp(28px, 5vw, 56px); }
.exp-banner__panel .section-tag { color: var(--teal-300); }
.exp-banner__panel h2 { font-size: clamp(1.8rem, 3vw, 2.5rem); font-stretch: 110%; }
.exp-banner__panel p { color: rgba(255, 255, 255, 0.88); margin: 0; }

.leader-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; align-items: stretch; }
.leader-card {
  background: var(--surface-0); border: 1px solid var(--border); border-radius: var(--r-md);
  padding: 30px; display: flex; flex-direction: column; gap: 16px;
  position: relative; overflow: hidden; height: 100%;
  transition: border-color var(--t-med) var(--ease), box-shadow var(--t-med) var(--ease),
              transform var(--t-med) var(--ease-out);
}
/* Facet notch, echoing .stat-tile — ties the card into the wider system. */
.leader-card::after {
  content: ""; position: absolute; top: 0; right: 0; width: 26px; height: 26px;
  background: linear-gradient(225deg, var(--surface-1) 50%, transparent 50%);
}
.leader-card:hover { border-color: var(--teal-500); box-shadow: var(--shadow-2); transform: translateY(-3px); }
/* Fixed two-line eyebrow so both avatar rows start on the same baseline. */
.leader-card__tag {
  font-size: 0.78rem; font-weight: 600; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--teal-600); margin: 0 0 4px;
  line-height: 1.5; min-height: 3em; /* reserve 2 lines so avatar rows align */
}
.leader-card__head { display: flex; gap: 18px; align-items: center; }
.leader-card__head img {
  width: 84px; height: 84px; border-radius: 50%; object-fit: cover; object-position: top center;
  flex-shrink: 0; border: 2px solid var(--border); background: var(--surface-1);
}
.leader-card__role { font-size: 0.85rem; color: var(--ink-400); margin: 2px 0 0; }
.leader-card h3 { font-size: 1.15rem; margin: 0; }
.leader-card blockquote { margin: 0; font-size: 0.97rem; color: var(--ink-600); border-left: 3px solid var(--teal-500); padding-left: 16px; }
/* Push the CTA to the bottom so buttons align across cards of unequal text. */
.leader-card .btn { align-self: flex-start; margin-top: auto; }
@media (max-width: 1023px) {
  .leader-grid { grid-template-columns: 1fr; }
  .leader-card__tag { min-height: 0; }
}

/* Leadership message modal — branded shell over Bootstrap's dialog ------------- */
/* Navy brand scrim instead of Bootstrap's flat black. */
.modal-backdrop.show { background-color: var(--overlay); opacity: 1; }
@supports (backdrop-filter: blur(2px)) {
  .leader-modal { backdrop-filter: blur(3px); }
}
.leader-modal .modal-content {
  border: 0; border-radius: var(--r-lg); overflow: hidden;
  box-shadow: var(--shadow-3); background: var(--surface-0);
}
.leader-modal .modal-dialog { max-width: 860px; }

.leader-modal__head {
  position: relative; isolation: isolate; overflow: hidden;
  background: var(--gradient-brand); color: #fff;
  padding: clamp(28px, 4vw, 40px) clamp(24px, 4vw, 44px) clamp(26px, 3.4vw, 36px);
}
.leader-modal__facets { position: absolute; inset: 0; width: 100%; height: 100%; z-index: -2; }
.leader-modal__thread {
  position: absolute; left: 0; bottom: 0; width: 100%; height: 68px; z-index: -1;
  fill: none; stroke: var(--teal-300); stroke-opacity: 0.5; stroke-width: 1.5;
}
.leader-modal__thread circle { fill: var(--teal-300); stroke: none; }

.leader-modal__close {
  position: absolute; top: 16px; right: 16px; z-index: 2;
  width: 40px; height: 40px; display: grid; place-items: center;
  border-radius: 50%; border: 1px solid rgba(255, 255, 255, 0.28);
  background: rgba(255, 255, 255, 0.08); color: #fff; cursor: pointer;
  transition: background-color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease),
              transform var(--t-fast) var(--ease);
}
.leader-modal__close svg { width: 18px; height: 18px; }
.leader-modal__close:hover { background: rgba(255, 255, 255, 0.18); border-color: var(--teal-300); transform: rotate(90deg); }
.leader-modal__close:focus-visible { outline: none; box-shadow: var(--focus-ring); }

.leader-modal__id { display: flex; gap: clamp(16px, 2.4vw, 24px); align-items: center; padding-right: 48px; }
.leader-modal__id img {
  width: 96px; height: 96px; flex-shrink: 0; border-radius: 50%;
  object-fit: cover; object-position: top center;
  border: 3px solid rgba(255, 255, 255, 0.5); background: rgba(255, 255, 255, 0.12);
}
.leader-modal__eyebrow {
  font-family: var(--font-display); font-size: 0.72rem; font-weight: 600; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--teal-300); margin: 0 0 8px;
}
.leader-modal__name {
  font-family: var(--font-display); font-size: clamp(1.15rem, 2.2vw, 1.5rem); font-stretch: 110%;
  font-weight: 700; line-height: 1.2; color: #fff; margin: 0;
}
.leader-modal__role { font-size: 0.9rem; color: rgba(255, 255, 255, 0.75); margin: 6px 0 0; }

.leader-modal__body { padding: clamp(26px, 3.4vw, 40px) clamp(24px, 4vw, 44px); position: relative; }
/* Oversized quote mark, tying back to the cards' blockquote rule. */
.leader-modal__body::before {
  content: "\201C"; position: absolute; top: 4px; left: clamp(12px, 2vw, 22px);
  font-family: var(--font-display); font-size: 6rem; line-height: 1;
  color: var(--teal-500); opacity: 0.14; pointer-events: none;
}
.leader-modal__body p {
  position: relative; margin: 0; color: var(--ink-600);
  font-size: 1.02rem; line-height: 1.75;
  border-left: 3px solid var(--teal-500); padding-left: clamp(16px, 2vw, 22px);
}
/* Entrance: lift + settle, matching the site's ease-out-expo motion language. */
.leader-modal.fade .modal-dialog {
  transform: translateY(24px) scale(0.98);
  transition: transform var(--motion-med, 350ms) var(--ease-out-expo, cubic-bezier(0.16, 1, 0.3, 1)),
              opacity var(--motion-med, 350ms) var(--ease);
}
.leader-modal.show .modal-dialog { transform: translateY(0) scale(1); }

/* The header must never be squeezed by the scrollable body — it holds the
   name/role and would clip them. Let it keep its intrinsic height. */
.leader-modal .modal-dialog-scrollable .leader-modal__head { flex-shrink: 0; }
.leader-modal__name { overflow-wrap: anywhere; }

@media (max-width: 575px) {
  .leader-modal__id { flex-direction: column; align-items: flex-start; text-align: left; padding-right: 40px; }
  .leader-modal__id img { width: 76px; height: 76px; }
  /* Narrow screens: scroll the whole dialog so the header can't be clipped. */
  .leader-modal .modal-dialog-scrollable { max-height: calc(100% - 1rem); }
  .leader-modal .modal-dialog-scrollable .modal-content { overflow-y: auto; }
  .leader-modal .modal-dialog-scrollable .modal-body { overflow-y: visible; }
}
@media (prefers-reduced-motion: reduce) {
  .leader-modal.fade .modal-dialog { transform: none; transition: none; }
  .leader-card { transition: none; }
  .leader-card:hover { transform: none; }
  .leader-modal__close:hover { transform: none; }
}

.rh-chips { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 26px; }
.rh-chip {
  display: inline-flex; align-items: baseline; gap: 8px; padding: 12px 20px;
  border: 1px solid var(--border-dark); border-radius: var(--r-pill);
  font-family: var(--font-display); font-weight: 600; font-size: 0.92rem; color: rgba(255, 255, 255, 0.9);
}
.rh-chip b { font-size: 1.25rem; color: var(--teal-300); font-variant-numeric: tabular-nums; }
.rh-quote { border-left: 3px solid var(--teal-500); padding: 6px 0 6px 20px; margin: 24px 0; color: rgba(255, 255, 255, 0.85); font-size: 1.05rem; }

/* Pillars + The Thread */
.pillars { position: relative; display: grid; gap: 28px; }
.pillars__thread { position: absolute; left: 47px; top: -36px; height: calc(100% + 72px); width: 4px; z-index: 0; pointer-events: none; }
.pillars__thread path { stroke: var(--teal-500); stroke-width: 2.5; fill: none; }
.pillar {
  position: relative; z-index: 1; color: #fff; border-radius: var(--r-lg);
  padding: clamp(28px, 4vw, 44px) clamp(28px, 4vw, 48px) clamp(28px, 4vw, 44px) 96px;
  clip-path: polygon(0 0, calc(100% - 36px) 0, 100% 36px, 100% 100%, 0 100%);
}
.pillar--sustainability { background: linear-gradient(135deg, #14835d, #22b287); }
.pillar--leadership { background: linear-gradient(135deg, #183454, #22476b); }
.pillar--innovation { background: linear-gradient(135deg, #148eb8, #25abd1); }
.pillar__node {
  position: absolute; left: 36px; top: clamp(28px, 4vw, 44px); width: 24px; height: 24px; border-radius: 50%;
  background: var(--surface-0); border: 4px solid var(--teal-500); transform: translateX(-50%);
}
.pillar__kicker { font-size: 0.78rem; font-weight: 600; letter-spacing: 0.16em; text-transform: uppercase; color: rgba(255, 255, 255, 0.75); margin-bottom: 6px; }
.pillar h3 { font-size: 1.5rem; font-stretch: 110%; margin-bottom: 4px; }
.pillar__sub { font-family: var(--font-display); font-weight: 600; color: rgba(255, 255, 255, 0.85); margin-bottom: 14px; }
.pillar p { color: rgba(255, 255, 255, 0.92); margin-bottom: 10px; }
.pillar p:last-child { margin-bottom: 0; font-weight: 600; }
@media (max-width: 640px) {
  .pillar { padding-left: 64px; }
  .pillars__thread { left: 31px; }
  .pillar__node { left: 24px; }
}

.thread-story { position: relative; overflow: hidden; }
.thread-story__svg { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
.thread-story__svg path { stroke: var(--teal-500); stroke-width: 2; fill: none; opacity: 0.8; }
.thread-story .container { position: relative; z-index: 1; }

.luban-media { position: relative; text-align: center; }
.luban-media img { max-width: min(78%, 380px); filter: drop-shadow(0 24px 40px rgba(8, 26, 43, 0.28)); }
@media (prefers-reduced-motion: no-preference) {
  .luban-media img { animation: luban-float 5.5s ease-in-out infinite; }
}
@keyframes luban-float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-12px); } }

/* 20c. SCIENTIFIC PROGRAMME -------------------------------------------------- */
.journey ul { margin-top: 8px; }
/* Nested inside .journey li, which carries padding-top:30px for the timeline
   step dots. That padding must be cleared here, otherwise the absolutely
   positioned dash below pins to the top of a 30px-taller box and reads as an
   orphaned bullet floating above its own text. */
.journey ul li {
  font-size: 0.86rem; color: var(--ink-600); position: relative;
  padding: 0 0 0 16px; margin-bottom: 4px;
}
.journey ul li::before { content: ""; position: absolute; left: 0; top: 0.6em; width: 8px; height: 2px; background: var(--teal-500); }

.tracks-index { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px 32px; }
.tracks-index li {
  position: relative; display: flex; align-items: center; gap: 14px;
  padding: 10px 0; border-bottom: 1px solid var(--border);
  font-family: var(--font-display); font-weight: 600; font-size: 0.98rem; color: var(--ink-900);
  transition: border-color var(--t-med) var(--ease);
}
/* Thumbnail replaces the dot marker, so the dot must not also render. */
.tracks-index li::before { content: none; }
.track-ico {
  flex: 0 0 auto; width: 52px; height: 52px; object-fit: contain;
  border-radius: var(--r-sm); background: var(--surface-1); padding: 2px;
  transition: transform var(--t-med) var(--ease-out), background-color var(--t-med) var(--ease);
}
.tracks-index li:hover { border-bottom-color: var(--teal-500); }
.tracks-index li:hover .track-ico { transform: scale(1.08); background: rgba(35, 173, 158, 0.12); }
@media (max-width: 1023px) { .tracks-index { grid-template-columns: 1fr 1fr; } }
@media (max-width: 640px)  { .tracks-index { grid-template-columns: 1fr; } }
@media (max-width: 400px)  { .track-ico { width: 46px; height: 34px; } }
@media (prefers-reduced-motion: reduce) {
  .track-ico, .tracks-index li { transition: none; }
  .tracks-index li:hover .track-ico { transform: none; }
}

.overview-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; align-items: stretch; }
.overview-card { background: var(--surface-0); border: 1px solid var(--border); border-radius: var(--r-lg); padding: clamp(24px, 3vw, 40px); }
.overview-card h3 { font-size: 1.3rem; }
.check-list li { position: relative; padding: 8px 0 8px 30px; font-weight: 500; }
.check-list li::before {
  content: ""; position: absolute; left: 0; top: 12px; width: 18px; height: 18px; border-radius: 50%;
  background: var(--teal-500);
  clip-path: none;
}
.check-list li::after {
  content: ""; position: absolute; left: 4px; top: 17px; width: 10px; height: 6px;
  border-left: 2px solid #fff; border-bottom: 2px solid #fff; transform: rotate(-45deg);
}
@media (max-width: 1023px) { .overview-grid { grid-template-columns: 1fr; } }

.status-chip {
  display: inline-flex; align-items: center; gap: 10px; padding: 12px 22px;
  border: 1.5px dashed var(--teal-300); border-radius: var(--r-pill);
  font-family: var(--font-display); font-weight: 600; font-size: 0.92rem; color: var(--teal-300);
  max-width: 100%; /* never push past the container on narrow screens */
}
.status-chip::before {
  content: ""; width: 8px; height: 8px; border-radius: 50%; background: var(--teal-300);
  flex: 0 0 auto; /* dot must not shrink when the label wraps */
}

/* Numbered because the four dates are a sequence — the order is the
   information, not decoration. The counter lives on the grid so the markup
   stays plain; nothing has to hardcode "1". */
.dates-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; counter-reset: rhic-date; }
.date-card {
  position: relative; counter-increment: rhic-date;
  background: var(--surface-0); border: 1px solid var(--border); border-radius: var(--r-md);
  /* Top padding clears the badge: the card is centred, so without the reserved
     band a long date would run underneath the number. */
  padding: 40px 20px 22px; text-align: center;
}
.date-card::before {
  content: counter(rhic-date);
  position: absolute; top: 12px; left: 50%; transform: translateX(-50%);
  width: 26px; height: 26px; border-radius: 50%;
  font-family: var(--font-display); font-weight: 700; font-size: 0.82rem;
  line-height: 26px; text-align: center;
  color: var(--ink-400); background: var(--surface-1); border: 1px solid var(--border);
}
.date-card--hot::before {
  color: #fff; background: var(--teal-600); border-color: var(--teal-600);
}
.date-card .date { display: block; font-family: var(--font-display); font-weight: 700; font-size: 1.05rem; color: var(--navy-700); margin-bottom: 6px; }
.date-card h3, .date-card h4 { font-size: 0.88rem; color: var(--ink-600); font-weight: 500; font-family: var(--font-body); margin: 0; }
.date-card--hot { border-color: var(--teal-500); box-shadow: var(--shadow-1); }
.date-card--hot .date { color: var(--teal-600); }
/* Four cards divide evenly into 2x2, so the last one no longer needs to span
   the row (it did when there were five). */
@media (max-width: 1023px) { .dates-grid { grid-template-columns: repeat(2, 1fr); } }
/* Two columns leave ~150px per card, which is not enough for a label like
   "Final Presentation Submission" beside a date. */
@media (max-width: 520px)  { .dates-grid { grid-template-columns: 1fr; gap: 12px; } }

/* Abstract submission tabs (restyled legacy block) */
.submission-categories { padding-block: var(--section-y); background: var(--surface-1); }
.submission-categories .section-heading h2 { font-size: clamp(1.9rem, 3.5vw, 2.75rem); font-stretch: 110%; }
.submission-categories .section-heading p { color: var(--ink-600); max-width: 46em; margin-inline: auto; }
/* Bootstrap's .nav sets flex-wrap: wrap. Combined with the fixed max-height
   below, the column would wrap into a SECOND column once the tracks exceeded
   620px — doubling the width and giving the rail a horizontal scrollbar, with
   the left-hand cards clipped out of view. The list must only ever scroll
   down, so wrapping is turned off and overflow-x is pinned to hidden
   (setting overflow-y alone computes the other axis to auto). */
.track-tabs {
  gap: 8px;
  max-height: 620px;
  flex-wrap: nowrap;
  overflow-y: auto;
  overflow-x: hidden;
  padding-right: 6px;
  scrollbar-width: thin;
}
.track-tabs .nav-link {
  text-align: left; width: 100%; background: var(--surface-0); border: 1px solid var(--border);
  border-radius: 12px; color: var(--ink-900); font-family: var(--font-display); font-weight: 600;
  font-size: 0.93rem; padding: 14px 18px; transition: border-color var(--t-fast) var(--ease), background-color var(--t-fast) var(--ease);
}
.track-tabs .nav-link:hover { border-color: var(--teal-500); background: var(--surface-0); color: var(--ink-900); }
.track-tabs .nav-link.active { background: var(--navy-700); border-color: var(--navy-700); color: #fff; }
.submission-categories .tab-content {
  background: var(--surface-0); border: 1px solid var(--border); border-radius: var(--r-lg);
  padding: clamp(24px, 3vw, 40px); height: 100%;
}
.track-content h3 { font-size: 1.35rem; margin-bottom: 20px; }
.content-block { margin-bottom: 22px; }
.content-block:last-child { margin-bottom: 0; }
.content-block h4, .content-block h5 {
  font-family: var(--font-display); font-size: 0.78rem; font-weight: 600; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--teal-600); margin-bottom: 8px;
}
.content-block p { color: var(--ink-600); margin-bottom: 0; font-size: 0.97rem; }
.content-block ul li { position: relative; padding-left: 20px; margin-bottom: 5px; color: var(--ink-600); font-size: 0.97rem; }
.content-block ul li::before { content: ""; position: absolute; left: 0; top: 0.62em; width: 10px; height: 2px; background: var(--teal-500); }
.submission-note { text-align: center; margin-top: 28px; color: var(--ink-400); font-size: 0.92rem; }
@media (max-width: 991px) { .track-tabs { max-height: none; flex-direction: row !important; flex-wrap: wrap; overflow: visible; margin-bottom: 18px; } .track-tabs .nav-link { width: auto; } }

/* Submission guidelines (restyled legacy block) */
.submission-guidelines { padding-block: var(--section-y); }
@media (max-width: 767px) {
  .submission-guidelines .row, .submission-categories .row { --bs-gutter-x: 1.5rem; }
}
.guideline-card, .presentation-wrapper { background: var(--surface-0); border: 1px solid var(--border); border-radius: var(--r-lg); padding: clamp(24px, 3vw, 40px); height: 100%; }
.guideline-card h3, .presentation-wrapper h3 { font-size: 1.3rem; margin-bottom: 18px; }
.guideline-list li { display: flex; gap: 12px; align-items: baseline; padding: 8px 0; color: var(--ink-600); }
.guideline-list li i { color: var(--teal-500); }
.presentation-card { display: flex; gap: 16px; align-items: flex-start; padding: 16px 0; border-top: 1px solid var(--border); }
.presentation-card:first-of-type { border-top: 0; }
.presentation-card .icon {
  flex-shrink: 0; width: 46px; height: 46px; border-radius: 12px; display: flex; align-items: center; justify-content: center;
  background: rgba(35, 173, 158, 0.12); color: var(--teal-600); font-size: 1.1rem;
}
.presentation-card h4 { font-size: 1.05rem; margin-bottom: 4px; }
.presentation-card p { color: var(--ink-600); font-size: 0.95rem; margin: 0; }

/* 20d. WORKSHOPS + REGISTRATION SHELLS -------------------------------------- */
/* Fixed height with the form scrolling inside it — deliberately NOT auto-sized
   to the content.

   Auto-sizing did work: the frame grew to the form's full height and the page
   scrolled as one. But the workshops form opens its cart and checkout as
   `position: fixed` overlays, and a fixed element is positioned against the
   iframe's own viewport. Once that viewport was the entire 7000px document,
   those overlays were laid out far outside what the reader could see — the
   cart appeared not to open at all.

   So the frame keeps a viewport of its own. The embedded page's overlays land
   inside it, where they belong. The height message is still handled (it lifts
   the "failed" notice and proves the embed is alive); it just no longer sets
   the height. */
/* Height is budgeted against what the *pinned* header actually leaves.
   The header is sticky, so once the reader scrolls into the form it never
   gives its height back: 128px on desktop (76px brand row + 51px nav row) and
   64px below 1024px, where the nav collapses into a drawer. Subtracting only
   a flat 150px understated that by ~30px on desktop and, worse, the 760px
   minimum exceeded the usable space entirely on short laptops (800px tall →
   672px usable), which is what produced the frame-inside-page double scroll.

   --embed-chrome is that reservation: pinned header + the shell's own padding
   and breathing room below, so the frame ends just above the fold and the two
   scrollbars never compete. The floor is deliberately low (460px) — on a short
   screen a slightly shorter frame that fits beats a taller one that forces the
   page to scroll as well. The ceiling keeps the frame from becoming an
   unreadably tall column on a large monitor. */
:root { --embed-chrome: 172px; }
@media (max-width: 1023px) { :root { --embed-chrome: 104px; } }

.embed-shell iframe {
  height: clamp(460px, calc(100svh - var(--embed-chrome)), 1000px);
}
/* The workshops app carries its own internal toolbar, so it earns a little
   more room than the plain registration form. */
.embed-shell--app iframe {
  height: clamp(500px, calc(100svh - var(--embed-chrome) + 40px), 1100px);
}
.embed-wrap { max-width: 1240px; margin-inline: auto; }
.embed-wrap--form { max-width: 960px; }
@media (max-width: 767px) {
  .embed-wrap { padding-inline: 0; }
  .embed-wrap .embed-shell { border-radius: 0; border-left: 0; border-right: 0; }
}

.note-card {
  background: var(--surface-0); border: 1px solid var(--border); border-left: 4px solid var(--teal-500);
  border-radius: var(--r-md); padding: 26px 28px;
}
.note-card h3, .note-card h4 { font-size: 1.08rem; margin-bottom: 10px; }
.note-card ul li { display: flex; gap: 10px; align-items: baseline; padding: 5px 0; color: var(--ink-600); font-size: 0.95rem; }
.note-card ul li i { color: var(--teal-600); }
/* `.note-card ul li` is display:flex, built for the icon lists used elsewhere in the card;
   that removes the bullet marker. The registration-instructions lists (register.php) are
   plain prose bullets, so they opt out and keep normal list rendering. */
.note-card ul.note-card__bullets li { display: list-item; gap: 0; padding: 0 0 6px; }
.note-card ul.note-card__bullets { list-style: disc; }

.info-chips { display: flex; flex-wrap: wrap; gap: 12px 28px; border-block: 1px solid var(--border); padding-block: 16px; margin-bottom: 26px; }
.info-chips .meta__label { display: block; font-family: var(--font-display); font-size: 0.72rem; font-weight: 600; letter-spacing: 0.16em; text-transform: uppercase; color: var(--ink-400); margin-bottom: 3px; }
.info-chips .meta__value { font-family: var(--font-display); font-weight: 600; font-size: 1rem; color: var(--ink-900); }

/* 20e. REGISTRATION --------------------------------------------------------- */
.price-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 24px; }
.price-card {
  background: var(--surface-0); border: 1px solid var(--border); border-radius: var(--r-md);
  padding: 28px; display: flex; flex-direction: column; gap: 6px;
  transition: transform 0.25s var(--ease), box-shadow 0.25s var(--ease), border-color 0.25s var(--ease);
}
.price-card:hover { transform: translateY(-6px); box-shadow: var(--shadow-2); border-color: var(--teal-500); }
.price-card--featured { border-color: var(--teal-500); box-shadow: var(--shadow-1); }
.price-card__row { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 10px; }
.price-card__icon {
  width: 48px; height: 48px; border-radius: 12px; display: flex; align-items: center; justify-content: center;
  background: rgba(35, 173, 158, 0.12); color: var(--teal-600); font-size: 1.15rem;
}
.price-card__amount { display: flex; align-items: baseline; gap: 6px; font-family: var(--font-display); }
.price-card__amount small { font-size: 0.8rem; font-weight: 600; letter-spacing: 0.08em; color: var(--ink-400); }
.price-card__amount b { font-size: 2.2rem; font-weight: 800; color: var(--navy-700); font-variant-numeric: tabular-nums; }
.price-card h3 { font-size: 1.08rem; margin: 0; }
/* Eligibility note — only some categories carry one. */
.price-card__note {
  margin: 8px 0 0; font-size: 0.845rem; line-height: 1.55; color: var(--ink-400);
}
.price-card__note b { color: var(--ink-600); font-weight: 600; }
/* Only some categories carry a note, so the text blocks differ in height. A
   spacer with `margin-top: auto` absorbs the difference and drops the button to
   the bottom, keeping the buttons aligned across a grid row. Applied to the
   button itself, `auto` would collapse the 16px gap on the tallest card — hence
   the explicit floor via padding on the card instead. */
.price-card .btn { margin-top: auto; align-self: flex-start; }
.price-card h3, .price-card__note { padding-bottom: 16px; }
.price-card__note { padding-bottom: 16px; margin-bottom: 0; }
@media (max-width: 1023px) { .price-grid { grid-template-columns: 1fr 1fr; } }
@media (max-width: 640px)  { .price-grid { grid-template-columns: 1fr; } }

/* FEE TABLE ---------------------------------------------------------------
   Three categories read against three registration periods. A real <table>
   because the row/column relationship is the content, not decoration — the
   markup gives screen readers the header association for free.

   The wrapper scrolls, not the page: without `overflow-x: auto` here the
   table's min-width would widen <body> on a phone and reintroduce the
   sitewide horizontal scroll the announce bar already cost us once. */
.fee-table-wrap {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: var(--surface-0);
  box-shadow: var(--shadow-1);
}
.fee-table {
  width: 100%;
  min-width: 640px;              /* below this the prices collide; wrapper scrolls */
  border-collapse: collapse;
  font-variant-numeric: tabular-nums;
}
.fee-table th, .fee-table td {
  padding: 18px 20px;
  text-align: center;
  border-bottom: 1px solid var(--border);
}
.fee-table thead th {
  background: var(--surface-1);
  vertical-align: bottom;
  position: relative;
  font-family: var(--font-display);
}
.fee-table thead th:first-child { text-align: left; }
.fee-table__period {
  display: block; font-size: 1rem; font-weight: 700; color: var(--navy-700);
}
.fee-table__dates {
  display: block; margin-top: 4px;
  font-family: var(--font-body);
  font-size: 0.8rem; font-weight: 500; color: var(--ink-400);
}
.fee-table__badge {
  display: inline-block; margin-top: 8px;
  padding: 3px 10px; border-radius: 999px;
  background: var(--teal-500); color: #fff;
  font-family: var(--font-body);
  font-size: 0.68rem; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase;
}
/* Row headers are the category names — left-aligned, they read as labels. */
.fee-table tbody th {
  text-align: left; font-size: 0.98rem; font-weight: 600; color: var(--ink-900);
  display: flex; align-items: center; gap: 10px;
}
.fee-table__icon {
  flex: none; width: 34px; height: 34px; border-radius: 10px;
  display: grid; place-items: center;
  background: var(--surface-1); color: var(--teal-600); font-size: 1rem;
}
.fee-table__amount { display: inline-flex; align-items: baseline; gap: 5px; font-family: var(--font-display); }
.fee-table__amount small { font-size: 0.72rem; font-weight: 600; letter-spacing: 0.08em; color: var(--ink-400); }
.fee-table__amount b { font-size: 1.6rem; font-weight: 800; color: var(--navy-700); }
.fee-table tbody tr:last-child th, .fee-table tbody tr:last-child td { border-bottom: 0; }

/* The live period, tinted down the whole column. */
.fee-table th.is-current, .fee-table td.is-current { background: rgba(35, 173, 158, 0.07); }
.fee-table thead th.is-current { box-shadow: inset 0 3px 0 var(--teal-500); }
.fee-table td.is-current .fee-table__amount b { color: var(--teal-600); }

.fee-status {
  display: flex; align-items: center; justify-content: center; gap: 10px;
  flex-wrap: wrap; text-align: center;
  margin: 0 0 22px; padding: 12px 18px;
  border: 1px solid rgba(35, 173, 158, 0.3); border-radius: 999px;
  background: rgba(35, 173, 158, 0.08);
  color: var(--ink-600); font-size: 0.94rem;
}
.fee-status b { color: var(--navy-700); }
.fee-status__dot {
  width: 9px; height: 9px; border-radius: 50%; background: var(--teal-500);
  box-shadow: 0 0 0 4px rgba(35, 173, 158, 0.18);
}
.fee-status--closed {
  border-color: var(--border); background: var(--surface-1);
}
.fee-actions { display: flex; justify-content: center; margin-top: 26px; }
.fee-subhead {
  margin: 46px 0 20px; text-align: center;
  font-size: 1.25rem; color: var(--navy-700);
}
.fee-note {
  margin: 26px auto 0; max-width: 760px; text-align: center;
  color: var(--ink-400); font-size: 0.9rem; line-height: 1.6;
}
@media (max-width: 640px) {
  .fee-table th, .fee-table td { padding: 14px 14px; }
  .fee-table__amount b { font-size: 1.4rem; }
  .fee-status { border-radius: var(--r-md); }
}

.mini-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; }
.mini-card {
  background: var(--surface-0); border: 1px solid var(--border); border-radius: var(--r-md);
  padding: 20px; display: flex; align-items: center; gap: 14px;
}
.mini-card .icon {
  flex-shrink: 0; width: 42px; height: 42px; border-radius: 11px; display: flex; align-items: center; justify-content: center;
  background: rgba(35, 173, 158, 0.12); color: var(--teal-600); font-size: 1.05rem;
}
.mini-card h3 { font-family: var(--font-display); font-weight: 600; font-size: 0.94rem; margin: 0; }
@media (max-width: 1023px) { .mini-grid { grid-template-columns: 1fr 1fr; } }
@media (max-width: 560px)  { .mini-grid { grid-template-columns: 1fr; } }

.doc-list { display: grid; gap: 8px; margin-top: 10px; }
.journey .doc-list li,
.doc-list li {
  display: flex; gap: 10px; align-items: baseline; color: var(--ink-600); font-size: 0.93rem;
  padding: 0; margin: 0; position: static;
}
/* The bi-icon is this list's marker — suppress the inherited .journey ul li
   dash, which would otherwise render as a second, orphaned bullet. Needs to
   out-specify `.journey ul li::before`. */
.journey ul.doc-list li::before,
.doc-list li::before { content: none; display: none; }
.doc-list li i { color: var(--teal-600); flex: 0 0 auto; line-height: 1.5; }

/* 20b. QA MODE (dev screenshots: ?qa=1) ------------------------------------- */
body.qa-mode *, body.qa-mode *::before, body.qa-mode *::after { animation: none !important; transition: none !important; }
body.qa-mode .reveal, body.qa-mode .hero__stagger { opacity: 1 !important; transform: none !important; }
.js body.qa-mode .hero__title .line > span, body.qa-mode .hero__title .line > span { transform: none !important; }
body.qa-mode .hero__media { opacity: 1 !important; transform: none !important; }

/* ==========================================================================
   MOTION 2.0 — signature layer (GSAP-owned; CSS provides fallbacks + states)
   ========================================================================== */
:root {
  --motion-fast: 180ms;
  --motion-med: 350ms;
  --motion-slow: 700ms;
  --motion-cine: 1200ms;
  --ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-out-quint: cubic-bezier(0.22, 1, 0.36, 1);
}

/* When GSAP is active it owns the hero — disable the CSS keyframe fallbacks */
.has-gsap .hero.is-ready .hero__title .line > span,
.has-gsap .hero.is-ready .hero__stagger,
.has-gsap .hero.is-ready .hero__media { animation: none; }
.has-gsap .hero__facet video, .has-gsap .hero__facet img { will-change: transform; }

/* Journey: scrub-driven progress line + sequential node activation */
.journey ol::before {
  background: linear-gradient(90deg, var(--teal-500) calc(var(--jp, 0) * 100%), var(--border) calc(var(--jp, 0) * 100%));
}
.journey li::before {
  transition: transform var(--motion-med) var(--ease-out-quint), box-shadow var(--motion-med) var(--ease),
    background-color var(--motion-med) var(--ease), border-color var(--motion-med) var(--ease);
}
.journey li.is-active::before {
  background: var(--teal-500); transform: scale(1.2);
  box-shadow: 0 0 0 7px rgba(35, 173, 158, 0.16);
}
.journey li .journey__day { transition: color var(--motion-med) var(--ease); }
.journey li.is-active .journey__day { color: var(--teal-600); }
@media (max-width: 1023px) {
  .journey ol::before, .journey ol.journey-cols-4::before {
    background: linear-gradient(180deg, var(--teal-500) calc(var(--jp, 0) * 100%), var(--border) calc(var(--jp, 0) * 100%));
  }
}

/* Tracks: spotlight field + node-dot hover (no layout shift) */
.tracks-spot { position: relative; }
.tracks-spot::before {
  content: ""; position: absolute; inset: 0; pointer-events: none; opacity: 0;
  background: radial-gradient(340px circle at var(--mx, 50%) var(--my, 30%), rgba(35, 173, 158, 0.12), transparent 70%);
  transition: opacity 0.4s var(--ease);
}
.tracks-spot.is-lit::before { opacity: 1; }
.track-chip { position: relative; transition: border-color var(--motion-fast) var(--ease), background-color var(--motion-fast) var(--ease), color var(--motion-fast) var(--ease), transform var(--motion-fast) var(--ease); }
.track-chip::before {
  content: ""; position: absolute; left: 11px; top: 50%; width: 6px; height: 6px; margin-top: -3px;
  border-radius: 50%; background: var(--teal-300); opacity: 0; transform: scale(0.4);
  transition: opacity var(--motion-fast) var(--ease), transform var(--motion-fast) var(--ease-out-quint);
}
a.track-chip:hover, a.track-chip:focus-visible { transform: translateY(-2px); }
a.track-chip:hover::before, a.track-chip:focus-visible::before { opacity: 1; transform: scale(1); }

/* About pillars: scroll-story focus states (GSAP toggles .is-lit) */
.has-gsap .pillar { opacity: 0.45; transform: scale(0.985); transition: opacity 0.55s var(--ease-out-quint), transform 0.55s var(--ease-out-quint); }
.has-gsap .pillar.is-lit { opacity: 1; transform: scale(1); }
.has-gsap .pillar .pillar__node { transition: box-shadow 0.4s var(--ease), transform 0.4s var(--ease-out-quint); }
.has-gsap .pillar.is-lit .pillar__node { box-shadow: 0 0 0 8px rgba(35, 173, 158, 0.18); transform: translateX(-50%) scale(1.12); }

/* Closing CTA: thread arrival */
.closing__thread { position: absolute; left: 50%; top: 0; transform: translateX(-50%); height: 130px; width: 40px; overflow: visible; }
.closing__thread path { stroke: var(--teal-500); stroke-width: 2; fill: none; }
.closing__thread circle { fill: var(--teal-300); }

/* Buttons: press + focus polish */
.btn:active { transform: scale(0.985); }

/* Nav: current page indicator */
.nav__link[aria-current="page"] { color: #fff; }
.nav__link[aria-current="page"]::after { right: 13px; }

/* Mobile menu: wipe reveal instead of plain fade */
@media (max-width: 1023px) {
  #site-nav.nav {
    clip-path: inset(0 0 100% 0);
    transition: clip-path 0.55s var(--ease-out-expo), opacity 0.3s var(--ease), visibility 0.55s;
  }
  body.nav-open #site-nav.nav { clip-path: inset(0 0 0% 0); }
}

/* Page-hero entrance states (GSAP-owned) */
.has-gsap .page-hero__bg img { will-change: transform; }

/* ==========================================================================
   MOTION 3.0 — high-intensity layer (text-fill, intro, transitions)
   ========================================================================== */

/* Scroll-driven text fill — signature typographic system.
   --fill scrubbed 0%→100% by motion.js on [data-tfill] elements. */
.has-gsap [data-tfill] {
  --fill: 0%;
  background-image: linear-gradient(90deg, var(--tf-on) var(--fill), var(--tf-off) var(--fill));
  -webkit-background-clip: text; background-clip: text;
  color: transparent; -webkit-text-fill-color: transparent;
}
.has-gsap [data-tfill="up"] {
  background-image: linear-gradient(0deg, var(--tf-on) var(--fill), var(--tf-off) var(--fill));
}
/* palette per context */
[data-tfill] { --tf-on: var(--navy-700); --tf-off: #b9c9d6; }
.section--dark [data-tfill], .oman [data-tfill], .closing [data-tfill], .cd-band [data-tfill] {
  --tf-on: var(--teal-300); --tf-off: rgba(255, 255, 255, 0.28);
}
.pillar [data-tfill] { --tf-on: #ffffff; --tf-off: rgba(255, 255, 255, 0.38); }
/* outline variant for giant editorial moments */
.has-gsap [data-tfill].tfill-outline { -webkit-text-stroke: 1px rgba(255, 255, 255, 0.35); }
/* fallbacks: readable final state without GSAP / with reduced motion */
html:not(.has-gsap) [data-tfill] { background: none; color: inherit; -webkit-text-fill-color: currentColor; }
@media (prefers-reduced-motion: reduce) {
  [data-tfill] { background: none !important; color: inherit !important; -webkit-text-fill-color: currentColor !important; }
}

/* Journey dates fill sequentially with the progress line (set via --dfill) */
.has-gsap .journey__date {
  background-image: linear-gradient(90deg, var(--teal-600) var(--dfill, 0%), var(--ink-900) var(--dfill, 0%));
  -webkit-background-clip: text; background-clip: text;
  color: transparent; -webkit-text-fill-color: transparent;
}
@media (prefers-reduced-motion: reduce) {
  .has-gsap .journey__date { background: none; color: var(--ink-900); -webkit-text-fill-color: currentColor; }
}

/* Tracks: living-system hover — siblings recede, target lifts */
@media (hover: hover) {
  .tracks-cta:hover .track-chip:not(:hover) { opacity: 0.45; }
  .track-chip { transition: border-color var(--motion-fast) var(--ease), background-color var(--motion-fast) var(--ease),
    color var(--motion-fast) var(--ease), transform var(--motion-fast) var(--ease), opacity var(--motion-med) var(--ease); }
}

/* Branded intro overlay (≤1s, skipped on revisit + reduced motion + no JS) */
.intro {
  position: fixed; inset: 0; z-index: 400; background: var(--navy-900);
  display: flex; align-items: center; justify-content: center; pointer-events: none;
}
.intro { flex-direction: column; }
.intro svg { width: min(230px, 54vw); height: auto; overflow: visible; }
/* The finished artwork, stacked exactly over the outline the SVG draws.
   Hidden until motion.js fades it in; if JS never runs, the whole overlay is
   already display:none (html:not(.has-gsap) .intro below). */
.intro [data-intro-logo] {
  position: absolute; width: min(230px, 54vw); height: auto; opacity: 0;
}
.intro path { stroke: var(--teal-500); stroke-width: 2; fill: none; }
.intro [data-intro-mark] { filter: drop-shadow(0 0 5px rgba(35, 173, 158, 0.4)); }
.intro [data-intro-comet] {
  stroke: #ffffff; stroke-width: 3.5; stroke-linecap: round; opacity: 0;
  filter: drop-shadow(0 0 9px rgba(126, 217, 205, 1));
}
.intro circle { fill: var(--teal-300); }
.intro [data-intro-node] { filter: drop-shadow(0 0 8px rgba(126, 217, 205, 0.9)); }
.intro [data-intro-pulse] { opacity: 0; fill: #ffffff; filter: drop-shadow(0 0 8px rgba(126, 217, 205, 1)); }
.intro [data-intro-pulse] { r: 3; }
html:not(.js) .intro, html:not(.has-gsap) .intro { display: none; }
@media (prefers-reduced-motion: reduce) { .intro { display: none; } }
/* absolute failsafe: overlay can never trap the page */
.intro { animation: intro-failsafe 0.3s var(--ease) 2.4s forwards; }
@keyframes intro-failsafe { to { opacity: 0; visibility: hidden; } }

/* Mobile menu: thread line accompanies the wipe */
@media (max-width: 1023px) {
  #site-nav.nav::before {
    content: ""; position: absolute; left: var(--gutter); top: calc(var(--header-h) + 20px); bottom: 40px;
    width: 2px; background: linear-gradient(180deg, var(--teal-500), transparent);
    transform: scaleY(0); transform-origin: top;
    transition: transform 0.7s var(--ease-out-expo) 0.15s;
  }
  body.nav-open #site-nav.nav::before { transform: scaleY(1); }
  .nav__list { position: relative; padding-left: 18px; }
}

/* Scientific network (about thread-story) */
.net-node { fill: var(--teal-300); }
.thread-story__svg .net-line { stroke: var(--teal-500); stroke-opacity: 0.55; stroke-width: 1.5; fill: none; }

/* Footer social: inline SVG glyphs */
.social-row a svg { width: 17px; height: 17px; display: block; }

/* ==========================================================================
   MOTION 4.0 — cinematic scene layer (desktop pins, stages, ghost type)
   ========================================================================== */

/* Tracks → typography wall (desktop, GSAP present) */
@media (min-width: 1024px) {
  .has-gsap .tracks-cta { gap: 6px 34px; }
  .has-gsap .tracks-cta .track-chip {
    border: 0; background: transparent; border-radius: 0;
    font-size: clamp(1.5rem, 2.2vw, 2.1rem); font-stretch: 108%; font-weight: 700;
    padding: 10px 4px 10px 26px; letter-spacing: 0.005em;
  }
  .has-gsap .tracks-cta .track-chip::before { left: 4px; width: 8px; height: 8px; margin-top: -4px; }
  .has-gsap .tracks-cta a.track-chip:hover { background: transparent; transform: translateX(6px); }
  .has-gsap .tracks-cta .track-chip--more { font-size: 1.05rem; align-self: center; border: 1px dashed var(--border-dark); border-radius: var(--r-pill); padding: 12px 22px; }
}

/* Journey ghost date — giant watermark digits behind the timeline */
.journey .container { position: relative; }
.journey ol { position: relative; z-index: 1; }
.journey__ghost {
  position: absolute; right: 2vw; top: 46%; transform: translateY(-50%);
  font-family: var(--font-display); font-weight: 800; font-stretch: 110%;
  font-size: clamp(180px, 22vw, 300px); line-height: 1; pointer-events: none;
  color: transparent; -webkit-text-stroke: 1.5px rgba(18, 65, 102, 0.13);
  z-index: 0; opacity: 0;
}

/* Oman takeover scale (desktop)
   The cinematic scene used to pin a fixed slat height, which re-cropped the
   220x800 source. Client asked for the full photo in a single row, so the
   height is left to aspect-ratio and the scene keeps only its scroll effects. */
.oman__lead { display: block; width: 100%; height: 44px; margin-top: clamp(28px, 4vw, 48px); }
.oman__lead path { stroke: var(--teal-500); stroke-width: 2; fill: none; }

/* Pillars cinematic stage (desktop pinned scene; mobile keeps stacked flow) */
.pillars__branch { display: none; }
.pillars--stage { height: 100vh; min-height: 660px; display: block; }
.pillars--stage .pillar {
  position: absolute; left: 50%; top: 50%; width: min(860px, 90%);
  margin: 0; will-change: transform;
  /* GSAP owns transform/opacity on the stage. Stated here too so a pillar is
     never left invisible by the .reveal defaults if the timeline has not run
     yet (or the script failed) — an absolutely-positioned card stuck at
     opacity:0 leaves a blank slot and no way to recover it. */
  opacity: 1;
}
.pillars--stage .pillar__node { display: none; }
.pillars--stage .pillars__thread { display: none; }
.pillars--stage .pillars__branch {
  display: block; position: absolute; inset: -4% 0; width: 100%; height: 108%; z-index: 0;
}
.pillars__branch path { stroke: var(--teal-500); stroke-width: 2; fill: none; }
.pillars--stage .pillar { z-index: 1; }

/* Closing echo typography (layered depth + hover split) */
.closing .container { position: relative; }
.closing__echo {
  position: absolute; left: 0; width: 100%; text-align: center; pointer-events: none;
  font-family: var(--font-display); font-weight: 700; font-stretch: 112%;
  font-size: clamp(2rem, 4.4vw, 3.2rem); line-height: 1.12; margin: 0;
  z-index: 0; white-space: nowrap;
}
.closing__echo--a { color: rgba(126, 217, 205, 0.14); }
.closing__echo--b { color: rgba(255, 255, 255, 0.07); }
.closing .section-title { position: relative; z-index: 1; }

/* Internal page-hero decorative layer (injected by motion.js) */
.page-hero__deco { position: absolute; right: -3%; top: -18%; height: 140%; opacity: 0.55; pointer-events: none; }
.page-hero__deco path { fill: none; stroke-width: 1.5; }
.page-hero__deco .deco-facet { stroke: rgba(126, 217, 205, 0.16); }
.page-hero__deco .deco-thread { stroke: var(--teal-500); stroke-width: 2; }
.page-hero__deco circle { fill: var(--teal-300); }

/* ==========================================================================
   MOTION 6.0 — flip cards, body-text fill, why-stage, contact thread
   ========================================================================== */

/* Scroll-driven BODY text fill (applied by motion.js as [data-bfill]) */
.has-gsap [data-bfill] {
  --fill: 0%;
  background-image: linear-gradient(90deg, var(--bf-on) var(--fill), var(--bf-off) var(--fill));
  -webkit-background-clip: text; background-clip: text;
  color: transparent; -webkit-text-fill-color: transparent;
}
[data-bfill] { --bf-on: var(--ink-600); --bf-off: #c5d3df; }
.section--dark [data-bfill], .oman [data-bfill], .closing [data-bfill], .cd-band [data-bfill],
.band [data-bfill], .thread-story [data-bfill], .pillar [data-bfill], .coming-soon [data-bfill],
.exp-banner__panel [data-bfill], .page-hero [data-bfill] {
  --bf-on: rgba(255, 255, 255, 0.86); --bf-off: rgba(255, 255, 255, 0.3);
}
/* word-split variant: parent renders normally, each word fills in sequence
   while staying inline — natural wrapping is untouched */
.has-gsap [data-bfill].is-split { background: none; color: inherit; -webkit-text-fill-color: currentColor; }
.has-gsap [data-bfill].is-split .bfill-word {
  background-image: linear-gradient(90deg, var(--bf-on) var(--fill), var(--bf-off) var(--fill));
  -webkit-background-clip: text; background-clip: text;
  color: transparent; -webkit-text-fill-color: transparent;
}
/* Word spans must stay inline so they wrap normally. Inside a flex parent
   (e.g. .status-chip) each word would otherwise become a non-wrapping flex
   item and spill past the container on narrow screens. */
.has-gsap [data-bfill].is-split .bfill-word { display: inline; }
.status-chip.is-split { flex-wrap: wrap; row-gap: 2px; }

/* Submissions are open, so this is a live state rather than a "coming soon"
   placeholder: solid border, and the dot pulses instead of sitting inert. */
.status-chip--live {
  border-style: solid;
  border-color: rgba(126, 217, 205, 0.55);
  background: rgba(35, 173, 158, 0.1);
}
.status-chip--live::before { animation: chip-pulse 2.4s var(--ease) infinite; }
@keyframes chip-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(126, 217, 205, 0.55); }
  70%      { box-shadow: 0 0 0 7px rgba(126, 217, 205, 0); }
}
@media (prefers-reduced-motion: reduce) {
  .status-chip--live::before { animation: none; }
}
html:not(.has-gsap) [data-bfill] { background: none; color: inherit; -webkit-text-fill-color: currentColor; }
@media (prefers-reduced-motion: reduce) {
  [data-bfill], [data-bfill] .bfill-line, [data-bfill] .bfill-word { background: none !important; color: inherit !important; -webkit-text-fill-color: currentColor !important; }
}

/* Flip cards (built by motion.js from [data-flip] feature cards) */
.flip-card { perspective: 1100px; min-height: 252px; padding: 0 !important; cursor: pointer; }
.flip-card:focus-visible { box-shadow: var(--focus-ring); }
.flip-inner {
  position: relative; width: 100%; height: 100%; min-height: inherit;
  transform-style: preserve-3d;
  transition: transform 0.75s var(--ease-out-expo);
}
.flip-card.is-flipped .flip-inner { transform: rotateY(180deg); }
@media (hover: hover) {
  .flip-card:hover .flip-inner, .flip-card:focus-visible .flip-inner { transform: rotateY(180deg); }
}
.flip-face {
  position: absolute; inset: 0; border-radius: var(--r-md);
  -webkit-backface-visibility: hidden; backface-visibility: hidden;
  display: flex; flex-direction: column; justify-content: center;
  padding: 28px;
}
.flip-front .feature-card__icon { margin-bottom: 18px; }
.flip-front h3 { margin-bottom: 0; }
.flip-front::after {
  content: ""; position: absolute; right: 16px; bottom: 14px; width: 18px; height: 18px;
  border-right: 2px solid var(--teal-500); border-bottom: 2px solid var(--teal-500);
  border-bottom-right-radius: 6px; opacity: 0.6;
}
.flip-back {
  transform: rotateY(180deg);
  background: linear-gradient(150deg, var(--navy-700), #16645f);
  color: #fff;
}
.flip-back h4 {
  font-size: 0.78rem; font-weight: 600; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--teal-300); margin-bottom: 10px;
}
.flip-back p { color: rgba(255, 255, 255, 0.92); margin: 0; font-size: 0.95rem; }
@media (prefers-reduced-motion: reduce) {
  .flip-inner, .flip-card:hover .flip-inner { transition: none; }
}

/* Why-Attend pinned stage (desktop, built by motion.js) */
/* Height of the pinned stage. Frames are centred in it, so any height beyond
   the tallest frame reads as dead space under the heading — keep it just
   above the two-card frames rather than filling the viewport. */
.why-stage { position: relative; height: 60vh; min-height: 430px; overflow: hidden; }
.why-frame {
  position: absolute; left: 50%; top: 50%; width: min(960px, 94%);
  display: grid; grid-template-columns: 1fr 1fr; gap: 24px; z-index: 1;
}
.why-frame::before {
  content: attr(data-num); position: absolute; right: -13%; top: 50%; transform: translateY(-50%);
  font-family: var(--font-display); font-weight: 800; font-stretch: 110%;
  font-size: clamp(150px, 15vw, 230px); line-height: 1; pointer-events: none;
  color: transparent; -webkit-text-stroke: 1.5px rgba(18, 65, 102, 0.14); z-index: -1;
}

/* Contact: connecting thread behind the contact cards.
   Four cards (email, general phone, sponsorship phone, venue) sit as a 2x2
   rather than inheriting the shared three-column .feature-grid, which would
   strand the fourth card alone on a second row. The thread is centred on the
   gap between the two rows. */
.contact-grid-wrap { position: relative; }
.contact-grid-wrap .feature-grid { position: relative; z-index: 1; grid-template-columns: repeat(2, 1fr); }
@media (max-width: 640px) { .contact-grid-wrap .feature-grid { grid-template-columns: 1fr; } }
.contact-thread { position: absolute; left: 2%; width: 96%; top: 50%; height: 44px; z-index: 0; overflow: hidden; transform: translateY(-50%); }
.contact-thread path { stroke: var(--teal-500); stroke-width: 2; fill: none; }
.contact-thread circle { fill: var(--teal-300); }

/* Premium button label-roll (text rolls out upward, duplicate rolls in) */
.btn .btn__label { position: relative; display: inline-block; overflow: hidden; vertical-align: baseline; }
.btn .btn__label-inner { display: block; transition: transform 0.5s var(--ease-out-expo); will-change: transform; }
.btn .btn__label-inner--dup { position: absolute; inset: 0; transform: translateY(115%); }
@media (hover: hover) {
  .btn:hover .btn__label-inner:not(.btn__label-inner--dup) { transform: translateY(-115%); }
  .btn:hover .btn__label-inner--dup { transform: translateY(0); }
}
@media (prefers-reduced-motion: reduce) {
  .btn .btn__label-inner { transition: none; }
  .btn:hover .btn__label-inner:not(.btn__label-inner--dup) { transform: none; }
  .btn:hover .btn__label-inner--dup { transform: translateY(115%); }
}

/* ==========================================================================
   MOTION 7.0 — track rails, stage guards, stats sweep
   ========================================================================== */

/* Track chips as two opposing rails (theme unchanged: navy field, teal accents) */
/* rails break out of the container so they read as full-bleed marquees */
.tracks-rails { display: block; width: 100vw; margin-left: calc(50% - 50vw); }
.track-rail { overflow: hidden; margin-bottom: 14px; -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent); }
.track-lane { display: flex; gap: 12px; width: max-content; will-change: transform; }
.track-lane .track-chip { flex: 0 0 auto; }
.tracks-more { margin-top: 22px; padding-left: max(var(--gutter), calc(50vw - var(--container) / 2)); }
@media (max-width: 767px) {
  .track-rail { margin-bottom: 10px; }
  .track-lane { gap: 8px; }
  .track-lane .track-chip { font-size: 0.9rem; padding: 11px 18px; }
}
/* desktop typography-wall styling must not fight the rails */
@media (min-width: 1024px) {
  .has-gsap .tracks-rails .track-chip {
    border: 1px solid var(--border-dark); border-radius: var(--r-pill);
    background: rgba(255, 255, 255, 0.02);
    font-size: clamp(1rem, 1.15vw, 1.2rem); padding: 13px 24px;
  }
  .has-gsap .tracks-rails a.track-chip:hover { transform: translateY(-2px); background: rgba(35, 173, 158, 0.14); }
  .has-gsap .tracks-rails .track-chip::before { left: 11px; }
  .has-gsap .tracks-rails .track-chip--more { font-size: 0.95rem; }
}

/* Why-stage is a DESKTOP-ONLY scene — mobile always keeps the flat grid */
@media (max-width: 1023px) {
  .why-stage { height: auto !important; min-height: 0 !important; display: grid !important; }
  .why-frame { position: static !important; width: auto !important; transform: none !important;
    opacity: 1 !important; visibility: visible !important; display: contents !important; }
  .why-frame::before { display: none !important; }
  .journey__ghost { display: none !important; }
}


/* screen-reader-only utility (labels that must not render visually) */
.sr-only {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0;
}

/* Call-for-papers CTA: shown in a waiting state until the portal URL exists */
.cfp-cta { display: flex; flex-wrap: wrap; align-items: center; gap: 12px 16px; margin-top: 20px; }
.cfp-cta .btn[disabled] { opacity: 0.55; cursor: not-allowed; pointer-events: none; }
.cfp-cta__note { font-size: 0.86rem; color: rgba(255, 255, 255, 0.6); }

/* 21. TRACK EXPLORER -------------------------------------------------------
   Searchable track cards that expand into a full session agenda. The agenda is
   rendered server-side inside each card (no fetch), so search, deep links and
   no-JS all work off the same DOM. */

/* --- search bar --- */
/* The chips sit directly under the search, so the gap belongs to .tx-cats —
   keeping it here as well pushed them a long way down the page on mobile. */
.tx-search { max-width: 620px; margin: 0 auto; }
.tx-search__field { position: relative; display: flex; align-items: center; }
.tx-search__ico {
  position: absolute; left: 18px; width: 18px; height: 18px;
  color: var(--ink-400); pointer-events: none;
}
.tx-search input {
  width: 100%; font: inherit; font-size: 1rem; color: var(--ink-900);
  padding: 15px 46px 15px 48px;
  background: var(--surface-0); border: 1px solid var(--border);
  border-radius: var(--r-pill); box-shadow: var(--shadow-1);
  transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}
.tx-search input::placeholder { color: var(--ink-400); }
/* suppress the native search widget's own clear button — we render our own */
.tx-search input::-webkit-search-cancel-button,
.tx-search input::-webkit-search-decoration { -webkit-appearance: none; appearance: none; }
.tx-search input:focus { outline: none; border-color: var(--teal-500); box-shadow: var(--focus-ring); }
.tx-search__clear {
  position: absolute; right: 8px; display: grid; place-items: center;
  width: 32px; height: 32px; border: 0; border-radius: 50%;
  background: transparent; color: var(--ink-400); cursor: pointer;
  opacity: 0; visibility: hidden; transition: opacity var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.tx-search.has-value .tx-search__clear { opacity: 1; visibility: visible; }
.tx-search__clear:hover { color: var(--ink-900); background: var(--surface-1); }
.tx-search__clear:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.tx-search__count {
  margin: 12px 0 0; text-align: center; font-size: 0.9rem; color: var(--ink-400);
  min-height: 1.2em;
}

/* --- category chips (filter the grid; distinct from .tx-filter, which
       filters session types inside one open card) --- */
.tx-cats {
  display: flex; flex-wrap: wrap; justify-content: center; gap: 8px;
  margin: 16px auto clamp(22px, 3vw, 34px); max-width: 1060px;
}
.tx-cat {
  font: inherit; font-size: 0.85rem; font-weight: 600; color: var(--ink-600);
  padding: 9px 18px; border: 1px solid var(--border); border-radius: var(--r-pill);
  background: var(--surface-0); cursor: pointer;
  transition: color var(--t-fast) var(--ease), background var(--t-fast) var(--ease),
              border-color var(--t-fast) var(--ease);
}
.tx-cat:hover { border-color: var(--teal-500); color: var(--navy-800); }
.tx-cat.is-on {
  background: var(--navy-800); border-color: var(--navy-800); color: #fff;
}
.tx-cat:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.tx-cat__n { opacity: 0.6; font-weight: 500; margin-left: 2px; }
.tx-cat.is-on .tx-cat__n { opacity: 0.75; }
@media (max-width: 640px) {
  .tx-cats { gap: 6px; }
  .tx-cat { font-size: 0.8rem; padding: 8px 14px; }
}

/* --- card grid --- */
.tx-grid {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px;
  align-items: start;
}
.tx-grid > li::before { content: none; }
@media (max-width: 1023px) { .tx-grid { grid-template-columns: 1fr 1fr; gap: 16px; } }
@media (max-width: 640px)  { .tx-grid { grid-template-columns: 1fr; } }

/* A card that is open spans the full row so the agenda gets real width. */
.tx-card.is-open { grid-column: 1 / -1; }

.tx-card {
  background: var(--surface-0); border: 1px solid var(--border);
  border-radius: var(--r-md); box-shadow: var(--shadow-1);
  overflow: hidden;
  /* Clears the sticky header when tracks.js scrolls an opened card (or a
     #track-<slug> deep link) into view, so its title is never hidden behind
     the header. Two nav rows on desktop, one shorter bar on mobile. */
  scroll-margin-top: calc(var(--header-h) + 78px);
  transition: box-shadow var(--t-med) var(--ease), border-color var(--t-med) var(--ease),
              transform var(--t-med) var(--ease-out);
}
@media (max-width: 1023px) { .tx-card { scroll-margin-top: calc(var(--header-h) + 16px); } }
.tx-card:hover { box-shadow: var(--shadow-2); border-color: #c5d7e4; }
.tx-card:hover:not(.is-open) { transform: translateY(-3px); }
.tx-card.is-open { box-shadow: var(--shadow-3); border-color: var(--teal-500); }
.tx-card[hidden] { display: none; }

/* --- card header (the clickable summary) --- */
.tx-card__btn {
  width: 100%; display: flex; align-items: center; gap: 14px;
  padding: 16px 18px; text-align: left;
  background: none; border: 0; cursor: pointer; font: inherit; color: inherit;
}
.tx-card__btn:focus-visible { outline: none; box-shadow: var(--focus-ring); border-radius: var(--r-md); }
/* Square, because the track artwork is square. The old 54x40 box let the
   surface tint show as bars down each side, which read as a cropped image. */
.tx-card__ico {
  flex: none; width: 46px; height: 46px; object-fit: contain; padding: 5px;
  border-radius: var(--r-sm); background: var(--surface-1);
  transition: transform var(--t-med) var(--ease-out), background var(--t-med) var(--ease);
}
.tx-card__btn:hover .tx-card__ico { transform: scale(1.07); background: rgba(35, 173, 158, 0.12); }
.tx-card__txt { flex: 1 1 auto; min-width: 0; }
.tx-card__name {
  display: block; font-family: var(--font-display); font-weight: 600;
  font-size: 1.02rem; line-height: 1.3; color: var(--navy-800);
  /* long track names must wrap, never widen the grid column */
  overflow-wrap: anywhere;
}
.tx-card__meta {
  display: block; margin-top: 4px; font-size: 0.82rem; color: var(--ink-400);
}
/* chevron */
.tx-card__chev {
  flex: none; width: 26px; height: 26px; display: grid; place-items: center;
  border-radius: 50%; background: var(--surface-1); color: var(--navy-700);
  transition: transform var(--t-med) var(--ease-out), background var(--t-med) var(--ease);
}
.tx-card__chev svg { width: 13px; height: 13px; }
.tx-card.is-open .tx-card__chev { transform: rotate(180deg); background: var(--teal-500); color: #fff; }

/* "Coming soon" tracks stay visible but read as clearly pending. */
.tx-card--soon .tx-card__ico { filter: grayscale(1); opacity: 0.55; }
.tx-card--soon .tx-card__name { color: var(--ink-600); }
.tx-soon-tag {
  display: inline-block; margin-top: 5px; padding: 3px 10px;
  font-size: 0.72rem; font-weight: 600; letter-spacing: 0.03em; text-transform: uppercase;
  color: var(--ink-600); background: var(--surface-1);
  border: 1px solid var(--border); border-radius: var(--r-pill);
}

/* --- expanding panel ---------------------------------------------------
   Height is animated via a max-height set in JS from scrollHeight, so the
   transition has a real end value; JS clears it on transitionend so a card
   left open can still reflow (font load, resize, rotate). */
.tx-card__panel {
  overflow: hidden; max-height: 0;
  transition: max-height var(--motion-med) var(--ease-out-quint);
}
.tx-card:not(.is-open) .tx-card__panel { visibility: hidden; }
.tx-card__panel-in { padding: 4px 18px 20px; border-top: 1px solid var(--border); }

.tx-day + .tx-day { margin-top: 22px; }
/* .tx-day__head is defined once, with the sticky behaviour, further down —
   a second declaration here only made it unclear which one applied. */
.tx-day__date {
  font-family: var(--font-display); font-weight: 600; font-size: 0.98rem; color: var(--navy-700);
}
.tx-day__coord { font-size: 0.84rem; color: var(--ink-400); }

/* --- toolbar: day tabs + type filters ------------------------------------ */
.tx-toolbar {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: 12px 20px; padding: 14px 0 4px;
}
.tx-daytabs { display: flex; flex-wrap: wrap; gap: 6px; }
.tx-daytab {
  font: inherit; font-size: 0.86rem; font-weight: 600; color: var(--ink-600);
  padding: 8px 15px; border: 1px solid var(--border); border-radius: var(--r-pill);
  background: var(--surface-0); cursor: pointer;
  transition: color var(--t-fast) var(--ease), background var(--t-fast) var(--ease),
              border-color var(--t-fast) var(--ease);
}
.tx-daytab:hover { border-color: var(--teal-500); color: var(--navy-800); }
.tx-daytab.is-on { background: var(--navy-700); border-color: var(--navy-700); color: #fff; }
.tx-daytab:focus-visible { outline: none; box-shadow: var(--focus-ring); }

.tx-filters { display: flex; flex-wrap: wrap; gap: 6px; }
.tx-filter {
  font: inherit; font-size: 0.78rem; font-weight: 600; color: var(--ink-600);
  padding: 6px 12px; border: 1px solid var(--border); border-radius: var(--r-pill);
  background: var(--surface-0); cursor: pointer;
  transition: color var(--t-fast) var(--ease), background var(--t-fast) var(--ease),
              border-color var(--t-fast) var(--ease);
}
.tx-filter:hover { border-color: var(--teal-500); color: var(--navy-800); }
.tx-filter.is-on { background: rgba(35, 173, 158, 0.14); border-color: var(--teal-500); color: var(--teal-600); }
.tx-filter:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.tx-filter__n { opacity: 0.65; font-weight: 500; }

.tx-day.is-hidden { display: none; }
.tx-nomatch { padding: 26px 4px; text-align: center; color: var(--ink-400); font-size: 0.9rem; }

/* --- agenda rows -------------------------------------------------------
   A definition-style two-column layout rather than a <table>: it collapses to
   one column on mobile without the horizontal scroll a table would force.
   The left column doubles as a timeline rail, echoing the site's "Thread". */
.tx-sessions { list-style: none; margin: 0; padding: 0; position: relative; }
.tx-sessions > li::before { content: none; }

/* The day header scrolls with its sessions.

   It used to be sticky, which sounded useful on a long agenda but in practice
   detached it from its own day and parked it on top of the session rows —
   the first session ended up hidden behind the coordinator line. The date is
   only ever a few rows away, and the card header above already says which
   track you are in, so pinning it bought little and cost legibility. */
.tx-day__head {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 8px 14px;
  padding: 4px 0 12px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 6px;
}

.tx-row {
  /* the column must fit "11:00 AM – 11:15 AM" without touching the rail */
  display: grid; grid-template-columns: 158px 1fr; gap: 4px 26px;
  padding: 14px 0; position: relative;
}
/* the rail itself: a hairline behind the time column */
.tx-row::before {
  content: ""; position: absolute; left: 172px; top: 0; bottom: 0;
  width: 1px; background: var(--border);
}
.tx-row:first-child::before { top: 18px; }
.tx-row:last-child::before  { bottom: auto; height: 18px; }
/* the node on the rail */
.tx-row::after {
  content: ""; position: absolute; left: 169px; top: 19px;
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--surface-0); border: 2px solid var(--teal-500);
}
.tx-row--break::after { border-color: var(--border); }

.tx-row__time {
  font-size: 0.84rem; font-weight: 600; color: var(--navy-700);
  font-variant-numeric: tabular-nums; white-space: nowrap; padding-top: 1px;
}
.tx-row__time--tba { color: var(--ink-400); font-weight: 500; }
.tx-row__topic { font-size: 0.97rem; color: var(--ink-900); line-height: 1.45; overflow-wrap: anywhere; }
.tx-row__topic--tba { color: var(--ink-400); font-style: italic; }
.tx-row__people { margin-top: 8px; display: flex; flex-direction: column; gap: 7px; }

/* speaker line: avatar + name/country/role */
.tx-row__person { display: flex; align-items: flex-start; gap: 9px; }
.tx-av {
  flex: none; width: 26px; height: 26px; border-radius: 50%;
  display: grid; place-items: center;
  font-size: 0.66rem; font-weight: 700; letter-spacing: 0.02em;
  color: var(--navy-700); background: rgba(35, 173, 158, 0.13);
  font-family: var(--font-display);
}
.tx-row__who { min-width: 0; font-size: 0.87rem; line-height: 1.45; }
.tx-row__nm { font-weight: 600; color: var(--navy-800); }
.tx-flag {
  display: inline-block; margin-left: 7px; padding: 1px 7px;
  font-size: 0.66rem; font-weight: 700; letter-spacing: 0.03em;
  color: var(--blue-500); background: rgba(34, 126, 194, 0.11);
  border-radius: var(--r-pill); vertical-align: 1px; white-space: nowrap;
}
.tx-row__rl { display: block; color: var(--ink-400); }
.tx-row__mods { margin-top: 7px; font-size: 0.83rem; color: var(--ink-400); }

/* session-type chip */
.tx-tag {
  display: inline-block; margin-bottom: 5px; padding: 2px 9px;
  font-size: 0.7rem; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase;
  color: var(--teal-600); background: rgba(35, 173, 158, 0.1);
  border-radius: var(--r-pill);
}
.tx-tag--keynote  { color: #fff; background: var(--teal-600); }
.tx-tag--workshop { color: var(--blue-500); background: rgba(34, 126, 194, 0.12); }
.tx-tag--panel    { color: #8a5a00; background: rgba(214, 158, 46, 0.16); }
.tx-tag--research { color: #6b3fa0; background: rgba(124, 77, 178, 0.13); }
.tx-tag--ceremony { color: var(--navy-700); background: rgba(18, 65, 102, 0.1); }
.tx-tag--case     { color: #0f7b6c; background: rgba(35, 173, 158, 0.13); }
.tx-tag--lecture  { color: var(--ink-600); background: var(--surface-1); }

/* breaks read as quiet dividers, not sessions */
.tx-row--break { background: var(--surface-1); border-radius: var(--r-sm); padding: 9px 14px; margin: 4px 0; border-top: 0; }
.tx-row--break + .tx-row { border-top: 0; }
.tx-row--break .tx-row__topic { font-size: 0.88rem; color: var(--ink-400); font-weight: 500; }

/* day / section divider inside a sheet */
.tx-divider {
  margin: 18px 0 8px; padding: 10px 14px;
  font-family: var(--font-display); font-weight: 600; font-size: 0.9rem;
  line-height: 1.4; color: var(--navy-800); background: rgba(35, 173, 158, 0.08);
  border-left: 3px solid var(--teal-500); border-radius: 0 var(--r-sm) var(--r-sm) 0;
  /* section headers are full sentences — they must wrap, not widen the panel */
  overflow-wrap: anywhere; white-space: normal;
}
/* the rail must not run through a section header */
.tx-divider + .tx-row::before { top: 18px; }

/* Arabic tracks render right-to-left within their own panel only */
.tx-day[dir="rtl"] { text-align: right; }
.tx-day[dir="rtl"] .tx-row { grid-template-columns: 1fr 158px; }
.tx-day[dir="rtl"] .tx-row__time { grid-column: 2; grid-row: 1; }
.tx-day[dir="rtl"] .tx-row__body { grid-column: 1; grid-row: 1; }
/* mirror the rail to the right edge of the time column */
.tx-day[dir="rtl"] .tx-row::before { left: auto; right: 172px; }
.tx-day[dir="rtl"] .tx-row::after  { left: auto; right: 169px; }
.tx-day[dir="rtl"] .tx-row__person { flex-direction: row-reverse; }
.tx-day[dir="rtl"] .tx-flag { margin-left: 0; margin-right: 7px; }
.tx-day[dir="rtl"] .tx-divider { border-left: 0; border-right: 3px solid var(--teal-500); border-radius: var(--r-sm) 0 0 var(--r-sm); }

@media (max-width: 640px) {
  /* one column: the rail would waste ~40% of a phone's width, so drop it */
  .tx-row { grid-template-columns: 1fr; gap: 3px; padding-left: 0; }
  .tx-row::before, .tx-row::after { display: none; }
  .tx-row { border-top: 1px solid var(--border); }
  .tx-row:first-child { border-top: 0; }
  .tx-day[dir="rtl"] .tx-row { grid-template-columns: 1fr; }
  .tx-day[dir="rtl"] .tx-row__time,
  .tx-day[dir="rtl"] .tx-row__body { grid-column: 1; grid-row: auto; }
  .tx-card__panel-in { padding-inline: 14px; }
  .tx-toolbar { gap: 10px; }
  .tx-filters, .tx-daytabs { width: 100%; }
}

/* empty-state when a search matches nothing */
.tx-empty {
  display: none; text-align: center; padding: 40px 20px; color: var(--ink-400);
}
.tx-empty.is-on { display: block; }

/* no-JS: panels are open and the search box is pointless */
html:not(.js) .tx-search { display: none; }
html:not(.js) .tx-card__panel { max-height: none; visibility: visible; }
html:not(.js) .tx-card__chev { display: none; }

@media (prefers-reduced-motion: reduce) {
  .tx-card, .tx-card__ico, .tx-card__chev, .tx-card__panel,
  .tx-daytab, .tx-filter { transition: none; }
  .tx-card:hover:not(.is-open) { transform: none; }
  .tx-card__btn:hover .tx-card__ico { transform: none; }
}

/* 22. REDUCED MOTION -------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; }
  .js .reveal, .hero__stagger, .js .hero:not(.is-ready) .hero__title .line > span { opacity: 1 !important; transform: none !important; }
  .hero__scrollcue::after { animation: none; }
}

/* ==========================================================================
   17. ABSTRACT SUBMISSION FORM (abstracts-submit.php)
   Built on the same tokens as the rest of the site. Without JavaScript every
   fieldset is visible and the form is one long page; .af--stepped is added by
   assets/js/abstract-form.js and is what turns it into steps.
   ========================================================================== */

.af { margin-top: 8px; }

/* Progress rail. Non-interactive until a step is completed, so it is a
   status display first and a control second. */
.af-steps {
  list-style: none; margin: 0 0 30px; padding: 0;
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px;
}
.af-steps > li::before { content: none; }
.af-step {
  display: flex; align-items: center; gap: 9px;
  font-size: 0.82rem; font-weight: 600; color: var(--ink-400);
  padding: 12px 4px 0; border-top: 3px solid var(--border);
  transition: color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}
.af-step > span {
  display: grid; place-items: center; flex-shrink: 0;
  width: 24px; height: 24px; border-radius: 50%;
  background: var(--surface-1); color: var(--ink-400);
  font-size: 0.76rem; font-variant-numeric: tabular-nums;
}
.af-step.is-on { color: var(--navy-800); border-top-color: var(--teal-500); }
.af-step.is-on > span { background: var(--teal-500); color: #fff; }
.af-step.is-done { color: var(--ink-600); border-top-color: var(--teal-300); cursor: pointer; }
.af-step.is-done > span { background: var(--teal-300); color: var(--navy-800); }
@media (max-width: 640px) {
  .af-steps { grid-template-columns: repeat(4, 1fr); gap: 4px; }
  /* Labels stay: the rail is stacked (dot over text) rather than side by side,
     so they fit — and "Author / Abstract / Profile / Declarations" is what
     tells the reader how much is left, which a bare number does not. */
  .af-step { font-size: 0.66rem; line-height: 1.25; gap: 6px; }
  .af-step > span { font-size: 0.72rem; width: 22px; height: 22px; }
}

/* Panels. The border only appears in stepped mode, where a panel reads as a
   single card; unstepped they run together as sections of one document. */
.af-panel { border: 0; margin: 0 0 26px; padding: 0; }
.af--stepped .af-panel {
  background: var(--surface-0); border: 1px solid var(--border);
  border-radius: var(--r-md); padding: clamp(20px, 3vw, 30px); box-shadow: var(--shadow-1);
}
.af-legend {
  font-family: var(--font-display); font-weight: 700; font-size: 1.15rem;
  color: var(--navy-800); padding: 0; margin-bottom: 18px;
}
.af--stepped .af-legend { float: left; width: 100%; }

.af-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 18px 20px; }
@media (max-width: 700px) { .af-grid { grid-template-columns: 1fr; } }

.af-field { margin-bottom: 18px; min-width: 0; }
.af-grid .af-field { margin-bottom: 0; }

.af-label {
  display: block; margin-bottom: 7px;
  font-size: 0.9rem; font-weight: 600; color: var(--navy-800);
}
.af-req { color: var(--teal-600); }
.af-optional { font-weight: 500; color: var(--ink-400); font-size: 0.85em; }

.af-input {
  width: 100%; font: inherit; font-size: 0.95rem; color: var(--ink-900);
  background: var(--surface-0);
  padding: 12px 14px; border: 1px solid var(--border); border-radius: var(--r-sm);
  transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}
.af-input:hover { border-color: var(--teal-300); }
.af-input:focus-visible { outline: none; border-color: var(--teal-500); box-shadow: var(--focus-ring); }
.af-input[aria-invalid="true"] { border-color: var(--af-bad); background: var(--af-bad-bg); }
.af-textarea { resize: vertical; min-height: 110px; line-height: 1.6; }
select.af-input { appearance: none; background-image:
    url("data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%233e5468' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 12px center; background-size: 17px;
  padding-right: 38px; }

.af-file {
  width: 100%; font: inherit; font-size: 0.9rem; color: var(--ink-600);
  padding: 11px 14px; border: 1.5px dashed var(--border); border-radius: var(--r-sm);
  background: var(--surface-1);
}
.af-file::file-selector-button {
  font: inherit; font-size: 0.85rem; font-weight: 600; cursor: pointer;
  margin-right: 12px; padding: 8px 14px; border: 0; border-radius: var(--r-pill);
  background: var(--navy-800); color: #fff;
}

/* Radio pills and checkboxes: the whole label is the target, not just the dot. */
.af-radios { display: flex; flex-wrap: wrap; gap: 8px; }
.af-pill { position: relative; cursor: pointer; }
.af-pill input { position: absolute; opacity: 0; width: 0; height: 0; }
.af-pill > span {
  display: inline-block; font-size: 0.88rem; font-weight: 600; color: var(--ink-600);
  padding: 10px 17px; border: 1px solid var(--border); border-radius: var(--r-pill);
  background: var(--surface-0);
  transition: color var(--t-fast) var(--ease), background var(--t-fast) var(--ease),
              border-color var(--t-fast) var(--ease);
}
.af-pill:hover > span { border-color: var(--teal-500); color: var(--navy-800); }
.af-pill input:checked + span { background: var(--navy-800); border-color: var(--navy-800); color: #fff; }
.af-pill input:focus-visible + span { box-shadow: var(--focus-ring); }
[role="radiogroup"][aria-invalid="true"] { padding: 6px; margin: -6px; border-radius: var(--r-sm); background: var(--af-bad-bg); }

.af-check { display: flex; gap: 11px; align-items: flex-start; cursor: pointer; font-size: 0.93rem; line-height: 1.55; }
.af-check input { flex-shrink: 0; width: 19px; height: 19px; margin-top: 2px; accent-color: var(--teal-600); cursor: pointer; }
.af-check input:focus-visible { outline: none; box-shadow: var(--focus-ring); border-radius: 4px; }

.af-hint { margin: 7px 0 0; font-size: 0.83rem; color: var(--ink-400); line-height: 1.5; }
.af-count { font-variant-numeric: tabular-nums; font-weight: 600; color: var(--ink-600); }
.af-count.is-short { color: var(--ink-400); }
.af-count.is-over { color: var(--af-bad); }

.af-err { margin: 7px 0 0; font-size: 0.85rem; font-weight: 600; color: var(--af-bad); }

.af-alert {
  margin-bottom: 24px; padding: 15px 18px; border-radius: var(--r-sm);
  border: 1px solid var(--af-bad); background: var(--af-bad-bg);
  color: var(--af-bad-ink); font-size: 0.92rem; line-height: 1.55;
}

/* The honeypot must be reachable by a bot parsing the DOM but never seen or
   focused by a person — display:none would make it obvious to skip. */
.af-hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

.af-actions { display: flex; flex-wrap: wrap; gap: 12px; align-items: center; margin-top: 6px; }
.af-foot { margin: 16px 0 0; font-size: 0.85rem; color: var(--ink-400); }

/* ---- required note, moved above the stepper so it is read before the
   first field rather than after the last one ---- */
.af-required-note {
  margin: 0 0 18px; font-size: 0.85rem; color: var(--ink-400);
}

/* A native control the enhanced version has replaced. Kept in the DOM — it
   still holds the value and still posts — but taken out of the layout.
   Not display:none: some browsers skip validating and autofilling that. */
.af-hidden-native {
  position: absolute !important; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0;
}

/* Flags render from the system emoji font; the stack keeps them from falling
   back to letter boxes ("OM") on Windows, where colour flags are absent. */
.af-flag {
  font-family: "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", sans-serif;
  font-size: 1.15em; line-height: 1; flex: none;
}

/* ---- country combobox ---- */

.af-country { position: relative; }

.af-country__btn {
  display: flex; align-items: center; gap: 10px;
  width: 100%; text-align: left; cursor: pointer;
}
.af-country__name { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.af-country__caret { flex: none; color: var(--ink-400); transition: transform 0.18s ease; }
.af-country__btn[aria-expanded="true"] { border-color: var(--teal-500); box-shadow: var(--focus-ring); }
.af-country__btn[aria-expanded="true"] .af-country__caret { transform: rotate(180deg); }

.af-country__pop {
  position: absolute; z-index: 40; top: calc(100% + 6px); left: 0; right: 0;
  background: #fff; border: 1px solid var(--border); border-radius: var(--r-sm);
  box-shadow: 0 14px 34px rgba(8, 26, 43, 0.16);
  overflow: hidden;
  /* Opaque in its own right: the sheet sits over a dimmed page on mobile and
     must not let the form show through it. */
  background-color: #fff;
}

.af-country__search {
  display: flex; align-items: center; gap: 8px;
  padding: 10px 12px; border-bottom: 1px solid var(--border); color: var(--ink-400);
}
.af-country__search input {
  flex: 1; border: 0; outline: none; background: none;
  font: inherit; font-size: 0.94rem; color: var(--ink-900); min-width: 0;
}

.af-country__list {
  list-style: none; margin: 0; padding: 4px;
  max-height: 264px; overflow-y: auto; overscroll-behavior: contain;
}
.af-country__list > li::before { content: none; }

.af-country__opt {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 10px; border-radius: 7px; cursor: pointer;
  font-size: 0.94rem; line-height: 1.3;
}
.af-country__optname { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.af-country__dial { flex: none; font-size: 0.86rem; color: var(--ink-400); font-variant-numeric: tabular-nums; }
/* Hover and keyboard focus share one highlight, so arrowing and pointing look
   the same rather than fighting each other. */
.af-country__opt:hover,
.af-country__opt.is-active { background: var(--surface-1); }
.af-country__opt.is-selected { background: var(--teal-50, rgba(35, 173, 158, 0.1)); font-weight: 600; }
.af-country__opt.is-selected .af-country__dial { color: var(--teal-600); }

.af-country__none { margin: 0; padding: 14px 14px 16px; font-size: 0.88rem; color: var(--ink-400); }

/* ---- phone: fixed dial code + typed national number ---- */

.af-phone { display: flex; align-items: stretch; }
.af-phone__dial {
  display: inline-flex; align-items: center; gap: 7px; flex: none;
  padding: 0 12px;
  border: 1px solid var(--border); border-right: 0;
  border-radius: var(--r-sm) 0 0 var(--r-sm);
  background: var(--surface-1);
  font-size: 0.94rem; font-variant-numeric: tabular-nums; color: var(--ink-600);
  white-space: nowrap;
}
.af-phone__num { border-radius: 0 var(--r-sm) var(--r-sm) 0; min-width: 0; flex: 1; }
/* Focus the number and the pair reads as one control. */
.af-phone:focus-within .af-phone__dial { border-color: var(--teal-500); }
.af-phone__num[aria-invalid="true"] { border-color: var(--af-bad); background: var(--af-bad-bg); }
.af-phone__num[aria-invalid="true"] + .af-phone__dial,
.af-phone:has(.af-phone__num[aria-invalid="true"]) .af-phone__dial { border-color: var(--af-bad); }

/* ---- inline field notes (duplicate email) ---- */

.af-inputwrap { position: relative; display: flex; align-items: center; }
.af-inputwrap .af-input { width: 100%; padding-right: 40px; }

.af-note {
  margin: 7px 0 0; font-size: 0.85rem; line-height: 1.5;
  display: flex; gap: 7px; align-items: flex-start;
}
.af-note::before { content: "●"; font-size: 0.7em; line-height: 1.9; flex: none; }
.af-note--warn { color: #8a6414; }
.af-note--bad  { color: var(--af-bad); font-weight: 600; }
.af-note--ok   { color: var(--teal-600); }

/* Small spinner shown inside the email field while the check is in flight. */
.af-spin {
  position: absolute; right: 13px; width: 15px; height: 15px; flex: none;
  border: 2px solid var(--border); border-top-color: var(--teal-500);
  border-radius: 50%; animation: af-spin 0.7s linear infinite;
}
@keyframes af-spin { to { transform: rotate(360deg); } }

/* ---- word counter: green in range, red over ---- */
.af-count.is-ok { color: var(--teal-600); }

/* ---- submit button with its spinner ---- */

.af-submit { display: inline-flex; align-items: center; justify-content: center; gap: 10px; }
.af-submit__spin {
  display: none; width: 15px; height: 15px; flex: none;
  border: 2px solid rgba(13, 44, 73, 0.25); border-top-color: var(--navy-900);
  border-radius: 50%; animation: af-spin 0.7s linear infinite;
}
.af-submit.is-busy { pointer-events: none; }
.af-submit.is-busy .af-submit__spin { display: block; }

.btn:disabled, .btn[disabled] {
  opacity: 0.5; cursor: not-allowed; transform: none;
  filter: grayscale(0.3);
}

@media (prefers-reduced-motion: reduce) {
  .af-spin, .af-submit__spin { animation-duration: 2.4s; }
  .af-country__caret { transition: none; }
}

/* On a phone the list becomes a bottom sheet. Anchoring it under the button
   (as on desktop) puts a 300px panel below a field that is already near the
   fold, so it opens off-screen; pinning it to the bottom keeps the search box
   above the keyboard and the options within thumb reach.
   `top: auto` on a fixed element resolves to its static position — which is
   why `bottom` and `top: auto` must both be set explicitly here. */
@media (max-width: 640px) {
  .af-country__pop {
    position: fixed; z-index: 200;
    left: 0; right: 0; bottom: 0; top: auto;
    border-radius: 14px 14px 0 0;
    border-bottom: 0;
    box-shadow: 0 -10px 40px rgba(8, 26, 43, 0.24);
    animation: af-sheet 0.2s ease-out;
  }
  .af-country__search { padding: 14px 16px; }
  .af-country__search input { font-size: 16px; }  /* 16px stops iOS zooming in */
  .af-country__list { max-height: min(52vh, 340px); padding: 6px; }
  .af-country__opt { padding: 11px 12px; }

  /* Dim the page behind the sheet so the list reads as a layer, not as part
     of the form. Drawn by the combobox wrapper rather than the panel: a
     `z-index: -1` pseudo-element on the panel paints behind the panel's own
     background, which left the sheet see-through. */
  .af-country[data-open]::after {
    content: ""; position: fixed; inset: 0; z-index: 190;
    background: rgba(8, 26, 43, 0.45);
    animation: af-fade 0.2s ease-out;
  }
}
@keyframes af-fade { from { opacity: 0; } }
@keyframes af-sheet { from { transform: translateY(14px); opacity: 0; } }

/* ---- abstract confirmation page ---- */

.thanks { padding-top: clamp(80px, 10vw, 130px); }
.thanks__wrap { max-width: 660px; }

.thanks__card {
  text-align: center;
  padding: clamp(30px, 5vw, 46px) clamp(22px, 4vw, 40px);
  background: #fff;
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  box-shadow: 0 18px 46px rgba(8, 26, 43, 0.08);
}

.thanks__tick { color: var(--teal-500); line-height: 0; }
/* The ring draws, then the check strikes through it — the motion says
   "accepted" in a way a static tick does not. */
.thanks__tick-ring {
  stroke-dasharray: 208; stroke-dashoffset: 208;
  animation: thanks-ring 0.75s cubic-bezier(0.3, 0.9, 0.4, 1) forwards;
  opacity: 0.3;
}
.thanks__tick-mark {
  stroke-dasharray: 48; stroke-dashoffset: 48;
  animation: thanks-mark 0.42s cubic-bezier(0.4, 0.9, 0.4, 1) 0.5s forwards;
}
@keyframes thanks-ring { to { stroke-dashoffset: 0; } }
@keyframes thanks-mark { to { stroke-dashoffset: 0; } }

.thanks__title {
  margin: 16px 0 10px;
  font-size: clamp(1.85rem, 4.4vw, 2.6rem);
  line-height: 1.12; letter-spacing: -0.02em; color: var(--navy-800);
}
.thanks__lede { margin: 0; color: var(--ink-600); font-size: 1.03rem; line-height: 1.6; }

.thanks__ref {
  display: inline-flex; flex-direction: column; gap: 9px; align-items: center;
  margin: 26px 0 0; padding: 16px 22px;
  background: var(--surface-1); border: 1px solid var(--border); border-radius: var(--r-sm);
}
.thanks__ref-label {
  font-size: 0.7rem; font-weight: 700; letter-spacing: 0.11em;
  text-transform: uppercase; color: var(--ink-400);
}
.thanks__ref-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; justify-content: center; }
.thanks__ref-code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.98rem; letter-spacing: 0.02em; color: var(--navy-800);
  user-select: all;   /* one click selects the whole reference */
}

.thanks__copy {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 11px; cursor: pointer;
  border: 1px solid var(--border); border-radius: 999px; background: #fff;
  font: inherit; font-size: 0.8rem; font-weight: 600; color: var(--ink-600);
  transition: border-color 0.16s ease, color 0.16s ease, background 0.16s ease;
}
.thanks__copy:hover { border-color: var(--teal-500); color: var(--teal-600); }
.thanks__copy.is-copied { border-color: var(--teal-500); background: var(--teal-100, rgba(35,173,158,.12)); color: var(--teal-600); }

.thanks__note { margin: 14px 0 0; font-size: 0.86rem; color: var(--ink-400); line-height: 1.55; }

.thanks__next {
  margin-top: 26px; padding: clamp(22px, 3.5vw, 30px);
  background: #fff; border: 1px solid var(--border); border-radius: var(--r-md);
}
.thanks__next-title {
  margin: 0 0 18px; font-size: 0.74rem; font-weight: 700;
  letter-spacing: 0.11em; text-transform: uppercase; color: var(--ink-400);
}

.thanks__steps { list-style: none; margin: 0; padding: 0; }
.thanks__steps > li::before { content: none; }

.thanks__step { position: relative; display: flex; gap: 14px; padding: 0 0 20px; }
.thanks__step:last-child { padding-bottom: 0; }
/* The connector is drawn on the step, not between them, so the last one has
   no dangling tail. */
.thanks__step:not(:last-child)::before {
  content: ""; position: absolute; left: 6px; top: 18px; bottom: 2px;
  width: 2px; background: var(--border);
}
.thanks__step-dot {
  position: relative; z-index: 1; flex: none;
  width: 14px; height: 14px; margin-top: 4px; border-radius: 50%;
  background: #fff; border: 2px solid var(--border);
}
.thanks__step.is-done .thanks__step-dot { background: var(--teal-500); border-color: var(--teal-500); }
.thanks__step-body { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.thanks__step-body b { font-size: 0.95rem; color: var(--navy-800); }
.thanks__step-body span { font-size: 0.88rem; color: var(--ink-400); line-height: 1.55; }
.thanks__step.is-done .thanks__step-body b { color: var(--teal-600); }

.thanks__actions {
  display: flex; flex-wrap: wrap; gap: 12px;
  justify-content: center; margin-top: 28px;
}
.thanks__help { margin: 18px 0 0; text-align: center; font-size: 0.86rem; color: var(--ink-400); }

@media (prefers-reduced-motion: reduce) {
  .thanks__tick-ring, .thanks__tick-mark { animation: none; stroke-dashoffset: 0; }
}

@media (max-width: 560px) {
  .thanks__actions .btn { width: 100%; justify-content: center; }
}

.af-tick { color: var(--teal-500); }
.af-ref {
  display: inline-flex; flex-direction: column; gap: 5px; align-items: center;
  margin: 26px auto 6px; padding: 15px 26px;
  background: var(--surface-1); border: 1px solid var(--border); border-radius: var(--r-md);
}
.af-ref__label { font-size: 0.72rem; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-400); }
.af-ref__code { font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 0.95rem; color: var(--navy-800); }

/* ==========================================================================
   18. VENUE — OCEC block with the 360° tour (contact.php)
   ========================================================================== */

.venue__grid {
  display: grid; grid-template-columns: minmax(0, 0.92fr) minmax(0, 1.08fr);
  gap: clamp(32px, 5vw, 64px); align-items: center;
}
@media (max-width: 1023px) { .venue__grid { grid-template-columns: 1fr; } }

.venue__title-accent { color: var(--teal-600); display: block; }

/* Two-up facts. Each is an icon + a short line — no card, so the eye reads them
   as a list of attributes rather than four competing boxes. */
.venue__facts {
  list-style: none; margin: 26px 0 30px; padding: 0;
  display: grid; grid-template-columns: 1fr 1fr; gap: 20px 24px;
}
.venue__facts > li::before { content: none; }
.venue__fact {
  display: flex; align-items: flex-start; gap: 13px;
  font-size: 0.98rem; line-height: 1.45; color: var(--ink-600);
}
.venue__fact b { color: var(--navy-800); font-weight: 700; }
.venue__fact-ico {
  flex: 0 0 auto; display: grid; place-items: center;
  width: 42px; height: 42px; border-radius: 50%;
  background: rgba(35, 173, 158, 0.12); color: var(--teal-600);
}
.venue__fact-ico svg { width: 21px; height: 21px; }
@media (max-width: 520px) { .venue__facts { grid-template-columns: 1fr; gap: 16px; } }

/* Tour. Clipped to the congress mark so the embed reads as part of the brand
   rather than a bare rectangle from another site. */
.venue__tour { margin: 0; }
.venue__tour-frame {
  position: relative; aspect-ratio: 16 / 11; overflow: hidden;
  border-radius: var(--r-md); background: var(--navy-800);
  box-shadow: var(--shadow-3);
}
.venue__tour-frame iframe {
  position: absolute; inset: 0; width: 100%; height: 100%; border: 0;
  opacity: 0; transition: opacity 0.6s var(--ease);
}
.venue__tour.is-loaded .venue__tour-frame iframe { opacity: 1; }

.venue__tour-skeleton {
  position: absolute; inset: 0; z-index: 1;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 16px;
  color: rgba(255, 255, 255, 0.72); font-size: 0.9rem;
  transition: opacity 0.5s var(--ease), visibility 0.5s;
}
.venue__tour.is-loaded .venue__tour-skeleton { opacity: 0; visibility: hidden; }
.venue__tour-skeleton p { margin: 0; }
.venue__tour-mark {
  width: 74px; height: 52px;
  background: linear-gradient(150deg, var(--teal-500), var(--navy-700));
  clip-path: var(--logo-clip);
  animation: pulse-mark 1.7s var(--ease) infinite;
}

.venue__tour-cap {
  display: flex; align-items: center; gap: 9px; flex-wrap: wrap;
  margin-top: 14px; font-size: 0.87rem; color: var(--ink-400);
}
.venue__tour-cap a { color: var(--teal-600); }
.venue__tour-dot {
  width: 7px; height: 7px; border-radius: 50%; background: var(--teal-500);
  flex: 0 0 auto; animation: chip-pulse 2.4s var(--ease) infinite;
}
@media (prefers-reduced-motion: reduce) {
  .venue__tour-mark, .venue__tour-dot { animation: none; }
}

/* ==========================================================================
   19. MOBILE DRAWER CLOSE  +  SOCIAL RAIL
   ========================================================================== */

/* --- Social rail: fixed to the left edge, as on v1 ----------------------- */
.social-rail {
  /* Hidden until the reader is past the hero (main.js adds .is-visible at
     100vh). translateY(-50%) does the vertical centring, so both states must
     carry it — animating transform alone would drop the rail off-centre. */
  position: fixed; left: 0; top: 50%;
  transform: translate(-100%, -50%); opacity: 0; pointer-events: none;
  transition: transform var(--t-med) var(--ease-out-expo),
              opacity var(--t-med) var(--ease);
  z-index: 90; display: flex; flex-direction: column; gap: 2px;
  padding: 10px 8px; border-radius: 0 var(--r-md) var(--r-md) 0;
  background: rgba(8, 26, 43, 0.72);
  -webkit-backdrop-filter: blur(9px); backdrop-filter: blur(9px);
  border: 1px solid var(--border-dark); border-left: 0;
}
/* body-qualified so it outranks `body.nav-open .social-rail` below, which is
   (0,2,1) and would otherwise keep the rail hidden even when shown. The
   drawer rule still wins while the menu is open because it comes later at
   equal specificity. */
body .social-rail.is-visible {
  transform: translate(0, -50%); opacity: 1; pointer-events: auto;
}
.social-rail__link {
  display: grid; place-items: center; width: 38px; height: 38px;
  border-radius: 10px; color: rgba(255, 255, 255, 0.72);
  transition: color var(--t-fast) var(--ease), background var(--t-fast) var(--ease),
              transform var(--t-med) var(--ease-out-expo);
}
.social-rail__link svg { width: 17px; height: 17px; fill: currentColor; }
/* Each platform lights up in its own brand colour on hover — a single teal for
   all four made them read as one control rather than four destinations.
   --brand is set per item below; the teal is only the fallback. */
.social-rail__link:hover, .social-rail__link:focus-visible {
  color: #fff; background: var(--brand, var(--teal-600));
  transform: translateX(4px) scale(1.06);
}
.social-rail__item--linkedin  { --brand: #0a66c2; }
.social-rail__item--x         { --brand: #101418; }
.social-rail__item--facebook  { --brand: #1877f2; }
/* Instagram is a gradient, not a flat colour — a flat purple looks wrong and a
   flat pink looks like a different brand. */
.social-rail__item--instagram .social-rail__link:hover,
.social-rail__item--instagram .social-rail__link:focus-visible {
  background: radial-gradient(circle at 30% 107%,
    #fdf497 0%, #fd5949 45%, #d6249f 60%, #285aeb 90%);
}
.social-rail__link:focus-visible { outline: none; box-shadow: var(--focus-ring); }

/* Label slides out of the rail on hover. */
.social-rail__label {
  position: absolute; left: calc(100% + 10px); top: 50%; transform: translate(-8px, -50%);
  padding: 5px 11px; border-radius: var(--r-pill); white-space: nowrap;
  background: var(--navy-800); color: #fff; font-size: 0.76rem; font-weight: 600;
  opacity: 0; pointer-events: none;
  transition: opacity var(--t-fast) var(--ease), transform var(--t-med) var(--ease-out-expo);
}
.social-rail__item { position: relative; display: block; }
.social-rail__item:hover .social-rail__label,
.social-rail__link:focus-visible + .social-rail__label {
  opacity: 1; transform: translate(0, -50%);
}

/* Entrance: the rail draws itself in, one icon after the next.
   The icons are visible by default and the animation starts them off-screen
   instead — so if animations are suppressed (reduced motion, qa-mode, an
   older browser) the rail is simply there, rather than permanently invisible. */
.social-rail__item { opacity: 0; transform: translateX(-10px);
  transition: opacity 0.4s var(--ease-out), transform 0.4s var(--ease-out-expo); }
.social-rail.is-visible .social-rail__item {
  opacity: 1; transform: none;
  transition-delay: calc(var(--i, 0) * 0.06s);
}
@keyframes rail-in {
  from { opacity: 0; transform: translateX(-14px); }
  to   { opacity: 1; transform: none; }
}

/* Below the drawer, and out of the way of a thumb on small screens. */
@media (max-width: 767px) { .social-rail { display: none; } }
body.nav-open .social-rail, body.nav-open .social-rail.is-visible { opacity: 0; pointer-events: none; }

@media (prefers-reduced-motion: reduce) {
  .social-rail, .social-rail__item { transition: none; }
  .social-rail.is-visible .social-rail__item { transition-delay: 0s; }
  .social-rail__link:hover { transform: none; }
}

/* ==========================================================================
   20. CALL FOR ABSTRACTS  +  CLOSED STATE (abstracts-submit.php)
   ========================================================================== */

.cfp__intro { max-width: 880px; }
.cfp__lede {
  font-size: 1.06rem; line-height: 1.62; color: rgba(255, 255, 255, 0.84);
  max-width: 62ch; margin: 0 0 14px;
}
.cfp__lede--dim { color: rgba(255, 255, 255, 0.66); }

.status-chip--closed {
  border-style: solid; border-color: rgba(255, 255, 255, 0.28);
  background: rgba(255, 255, 255, 0.05); color: rgba(255, 255, 255, 0.82);
}
.status-chip--closed::before { background: rgba(255, 255, 255, 0.5); }

/* The call-for-abstracts dates now use the shared .date-card grid (see §
   "dates-grid"), so the numbered .cfp__date variant that used to live here is
   gone. Its corner badge sat absolutely over the date text, which collided
   once the month name wrapped; the shared card has no badge and abbreviates
   the month, so the two pages match and the collision cannot recur. */
.cfp .dates-grid { margin-top: 34px; }

/* Closed state */
.af-closed { text-align: center; padding: clamp(30px, 6vw, 60px) 0; }
.af-closed__ico { width: 56px; height: 56px; color: var(--ink-400); margin-bottom: 18px; }
.af-closed .section-lede { margin-inline: auto; }

/* --- Form polish ---------------------------------------------------------
   The first pass was structurally right but visually flat: inputs and page
   shared one white, the step rail read as a stray row of numbers, and every
   field carried the same weight. This gives the form a surface of its own and
   a clearer hierarchy. */

/* Card the whole form, so it reads as a document you are filling in. */
.af--stepped .af-panel {
  box-shadow: var(--shadow-2);
  border-color: var(--border);
  position: relative; overflow: hidden;
}
/* Accent edge on the active panel — small, and it anchors the eye. */
.af--stepped .af-panel::before {
  content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 3px;
  background: linear-gradient(180deg, var(--teal-500), rgba(35, 173, 158, 0));
}

.af-legend {
  display: flex; align-items: center; gap: 11px;
  font-size: 1.24rem; margin-bottom: 22px;
  padding-bottom: 16px; border-bottom: 1px solid var(--border);
}
.af--stepped .af-legend { width: 100%; }

/* Inputs sit on a tinted ground so the field is visible before it is focused;
   an outline-only box on white disappears at a glance. */
.af-input {
  background: var(--surface-1);
  border-color: transparent;
  box-shadow: inset 0 0 0 1px var(--border);
  padding: 13px 15px;
}
.af-input:hover { background: var(--surface-0); box-shadow: inset 0 0 0 1px var(--teal-300); }
.af-input:focus-visible {
  background: var(--surface-0);
  border-color: transparent;
  box-shadow: inset 0 0 0 1.5px var(--teal-500), var(--focus-ring);
}
.af-input[aria-invalid="true"] {
  background: var(--af-bad-bg);
  box-shadow: inset 0 0 0 1.5px var(--af-bad);
}

.af-label { font-size: 0.86rem; letter-spacing: 0.01em; }

/* Step rail: a connected progress line rather than four loose labels. */
.af-steps { position: relative; gap: 0; }
.af-step { border-top: 0; padding: 0 4px; }
.af-step::before {
  content: ""; position: absolute; top: 11px; left: 0; right: 0; height: 2px;
  background: var(--border); z-index: 0;
}
.af-step:first-child::before { left: 50%; }
.af-step:last-child::before  { right: 50%; }
.af-step > span { position: relative; z-index: 1; border: 2px solid var(--surface-0); }
.af-step {
  flex-direction: column; gap: 7px; text-align: center;
  align-items: center; justify-content: flex-start;
}
.af-step.is-on > span {
  box-shadow: 0 0 0 4px rgba(35, 173, 158, 0.18);
}

/* Declarations read as commitments, so they get a surface of their own. */
.af-check {
  padding: 14px 16px; border-radius: var(--r-sm);
  background: var(--surface-1); border: 1px solid var(--border);
  transition: border-color var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
}
.af-check:hover { border-color: var(--teal-300); background: var(--surface-0); }
.af-check:has(input:checked) {
  border-color: var(--teal-500); background: rgba(35, 173, 158, 0.07);
}

.af-actions {
  margin-top: 26px; padding-top: 22px; border-top: 1px solid var(--border);
  justify-content: flex-end;
}
.af-actions [data-af-back] { margin-right: auto; }

@media (max-width: 560px) {
  .af-actions { flex-direction: column-reverse; align-items: stretch; }
  .af-actions .btn { width: 100%; }
  .af-actions [data-af-back] { margin-right: 0; }
}

/* ==========================================================================
   21. NOT FOUND (404.php)
   ========================================================================== */

.nf { text-align: center; }
.nf__wrap { max-width: 660px; }

.nf__mark { width: 120px; height: auto; margin: 0 auto 6px; display: block; }
.nf__mark path, .nf__mark circle { stroke: var(--teal-500); stroke-width: 2; fill: none; }
.nf__mark .nf__node { fill: var(--teal-300); stroke: none; }
.nf__mark .nf__thread { opacity: .45; }

.nf__code {
  font-family: var(--font-display); font-weight: 800; font-stretch: 110%;
  font-size: clamp(64px, 13vw, 118px); line-height: .9; margin: 0 0 4px;
  color: transparent; -webkit-text-stroke: 1.5px rgba(18, 65, 102, 0.18);
  letter-spacing: 0.02em;
}
.nf__title { margin-bottom: 12px; }
.nf__lede { margin-inline: auto; }
.nf__asked {
  display: block; margin-top: 10px; font-size: 0.9rem; color: var(--ink-400);
}
.nf__asked code {
  font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 0.88em;
  padding: 2px 7px; border-radius: 5px; background: var(--surface-1);
  overflow-wrap: anywhere;
}

.nf__actions {
  display: flex; flex-wrap: wrap; gap: 12px; justify-content: center;
  margin: 28px 0 40px;
}

.nf__links { text-align: left; }
.nf__links-head {
  margin: 0 0 12px; text-align: center;
  font-size: 0.74rem; font-weight: 700; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--ink-400);
}
.nf__links ul {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: 1fr 1fr; gap: 10px;
}
.nf__links li::before { content: none; }
.nf__links a {
  display: flex; flex-direction: column; gap: 3px;
  padding: 15px 17px; border-radius: var(--r-md); text-decoration: none;
  background: var(--surface-0); border: 1px solid var(--border);
  transition: border-color var(--t-fast) var(--ease), transform var(--t-med) var(--ease-out),
              box-shadow var(--t-med) var(--ease);
}
.nf__links a:hover {
  border-color: var(--teal-500); transform: translateY(-2px); box-shadow: var(--shadow-2);
}
.nf__links span { font-weight: 600; color: var(--navy-800); }
.nf__links small { font-size: 0.82rem; color: var(--ink-400); }
@media (max-width: 560px) { .nf__links ul { grid-template-columns: 1fr; } }

/* --- Registration / workshop chooser -------------------------------------
   Neither embed has a src until a choice is made, so this panel is what the
   visitor meets first. It has to read as a decision, not as a loading state. */
.embed-choice__ask { text-align: center; padding: 8px 0 4px; }
.embed-choice__q {
  font-family: var(--font-display); font-weight: 700; font-size: 1.15rem;
  color: var(--ink-900); margin: 0 0 18px;
}
.embed-choice__opts {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 16px; max-width: 720px; margin-inline: auto;
}
.embed-choice__opt {
  display: grid; gap: 6px; justify-items: center; text-align: center;
  padding: 26px 22px; cursor: pointer;
  background: var(--surface-0); border: 1px solid var(--border);
  border-radius: var(--r-md);
  transition: border-color var(--t-med) var(--ease), box-shadow var(--t-med) var(--ease),
              transform var(--t-med) var(--ease-out);
}
.embed-choice__opt:hover, .embed-choice__opt:focus-visible {
  border-color: var(--teal-500); box-shadow: var(--shadow-1);
  transform: translateY(-3px); outline: none;
}
.embed-choice__opt:focus-visible { box-shadow: var(--focus-ring); }
.embed-choice__opt .bi { font-size: 1.7rem; color: var(--teal-600); line-height: 1; }
.embed-choice__opt-label {
  font-family: var(--font-display); font-weight: 700; font-size: 1.02rem; color: var(--navy-700);
}
.embed-choice__opt-note { font-size: 0.86rem; color: var(--ink-600); line-height: 1.45; }

/* Once chosen: a quiet header naming the choice, with the way back. */
.embed-choice__chosen {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  margin: 0 0 14px; font-family: var(--font-display); font-weight: 700;
  font-size: 1rem; color: var(--navy-700);
}
.embed-choice__change {
  background: none; border: 0; cursor: pointer; padding: 6px 2px;
  font-family: var(--font-body); font-size: 0.86rem; font-weight: 600;
  color: var(--teal-600); text-decoration: underline; text-underline-offset: 3px;
}
.embed-choice__change:hover { color: var(--navy-700); }
.embed-choice__change:focus-visible { outline: none; box-shadow: var(--focus-ring); border-radius: var(--r-sm); }

@media (max-width: 640px) {
  .embed-choice__opts { grid-template-columns: 1fr; gap: 12px; }
  .embed-choice__opt { padding: 20px 18px; }
}

/* ==========================================================================
   MEDIA — social carousel, video gallery
   ==========================================================================
   The rail is a real scrolling element with scroll-snap, not a transformed
   track. Touch swipe, trackpad, keyboard and focus scrolling then all work
   without any JavaScript from us; media.js only adds the buttons, dots and
   autoplay on top. With JS off it stays a usable scrollable strip.
   ---------------------------------------------------------------------- */
.media-carousel { position: relative; }

.media-carousel__rail {
  display: grid;
  grid-auto-flow: column;
  gap: 20px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  /* Room for the card shadow, which a clipping overflow would shear off. */
  padding: 6px 2px 14px;
  /* The scrollbar is replaced by the dots and buttons below. */
  scrollbar-width: none;
  -ms-overflow-style: none;
  overscroll-behavior-x: contain;
}
.media-carousel__rail::-webkit-scrollbar { display: none; }
.media-carousel__rail:focus-visible { outline: 2px solid var(--teal-500); outline-offset: 4px; border-radius: var(--r-md); }

.media-carousel__rail > * { scroll-snap-align: start; }

/* grid-auto-columns is what sets "how many fit" at each width, and media.js
   measures the rendered slide to derive its page size — so these two never
   need to agree in code, only visually. */
.media-carousel__rail--square { grid-auto-columns: calc((100% - 3 * 20px) / 4); }
.media-carousel__rail--wide   { grid-auto-columns: calc((100% - 2 * 20px) / 3); }

@media (max-width: 1023px) {
  .media-carousel__rail--square { grid-auto-columns: calc((100% - 2 * 20px) / 3); }
  .media-carousel__rail--wide   { grid-auto-columns: calc((100% - 20px) / 2); }
}
@media (max-width: 767px) {
  .media-carousel__rail--square { grid-auto-columns: calc((100% - 20px) / 2); }
  .media-carousel__rail--wide   { grid-auto-columns: 100%; }
}
@media (max-width: 480px) {
  .media-carousel__rail--square { grid-auto-columns: 100%; }
}

.media-carousel__controls {
  display: flex; align-items: center; justify-content: center; gap: 16px; margin-top: 18px;
}
/* One page of content needs no controls; media.js sets .is-static. */
.media-carousel.is-static .media-carousel__controls { display: none; }

.media-carousel__btn {
  width: 42px; height: 42px; flex: none; border-radius: 50%;
  display: grid; place-items: center; cursor: pointer;
  background: var(--surface-0); color: var(--navy-700);
  border: 1px solid var(--border); box-shadow: var(--shadow-1);
  font-size: 1.1rem; transition: background .2s, color .2s, border-color .2s;
}
.media-carousel__btn:hover { background: var(--teal-500); color: #fff; border-color: var(--teal-500); }
.media-carousel__btn:focus-visible { outline: none; box-shadow: var(--focus-ring); }

.media-carousel__dots { display: flex; align-items: center; gap: 8px; }
.media-carousel__dot {
  width: 8px; height: 8px; padding: 0; border: 0; border-radius: 50%; cursor: pointer;
  background: var(--border); transition: width .25s, background .25s;
}
.media-carousel__dot.is-on { width: 24px; border-radius: 999px; background: var(--teal-500); }
.media-carousel__dot:focus-visible { outline: none; box-shadow: var(--focus-ring); }

/* ---- social slide ---- */
.social-slide { margin: 0; display: flex; flex-direction: column; gap: 10px; min-width: 0; }
.social-slide__frame {
  position: relative; border-radius: var(--r-md); overflow: hidden;
  background: var(--surface-1); border: 1px solid var(--border); box-shadow: var(--shadow-1);
}
.social-slide__img {
  display: block; width: 100%; height: auto;
  /* Square crop: designs arrive as a mix of 1:1 and 4:5, and a ragged rail
     reads as broken rather than varied. */
  aspect-ratio: 1 / 1; object-fit: cover;
  transition: transform .4s ease;
}
.social-slide__frame:hover .social-slide__img { transform: scale(1.04); }

/* The link covers the tile but shows only as a corner badge. */
.social-slide__link {
  position: absolute; inset: 0;
  display: flex; align-items: flex-end; justify-content: flex-end; padding: 12px;
  color: #fff; font-size: 1.05rem; text-decoration: none;
  background: linear-gradient(to top, rgba(8, 26, 43, 0.55), rgba(8, 26, 43, 0) 45%);
  opacity: 0; transition: opacity .25s;
}
.social-slide__frame:hover .social-slide__link,
.social-slide__link:focus-visible { opacity: 1; }
.social-slide__link:focus-visible { outline: 2px solid #fff; outline-offset: -4px; }

.social-slide__badge {
  position: absolute; right: 10px; bottom: 10px;
  width: 30px; height: 30px; border-radius: 50%; display: grid; place-items: center;
  background: rgba(8, 26, 43, 0.55); color: #fff; font-size: 0.9rem;
}
.social-slide__cap {
  font-size: 0.9rem; color: var(--ink-600); line-height: 1.5;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}

/* ---- social grid (full gallery) ---- */
.social-grid {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 22px;
}
@media (max-width: 1023px) { .social-grid { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 767px)  { .social-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 420px)  { .social-grid { grid-template-columns: 1fr; } }

.social-tile { margin: 0; display: flex; flex-direction: column; gap: 10px; min-width: 0; }
.social-tile__frame {
  position: relative; border-radius: var(--r-md); overflow: hidden;
  background: var(--surface-1); border: 1px solid var(--border); box-shadow: var(--shadow-1);
}
.social-tile__img {
  display: block; width: 100%; height: auto; aspect-ratio: 1 / 1; object-fit: cover;
  transition: transform .4s ease;
}
.social-tile__frame:hover .social-tile__img { transform: scale(1.04); }
.social-tile__frame:hover .social-slide__link { opacity: 1; }
.social-tile__cap { display: flex; flex-direction: column; gap: 3px; }
.social-tile__text {
  font-size: 0.9rem; color: var(--ink-600); line-height: 1.5;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.social-tile__date { font-size: 0.78rem; color: var(--ink-400); }

/* ---- video cards ----
   16:9 everywhere, because the client's videos are landscape. */
.video-card {
  display: flex; flex-direction: column; min-width: 0;
  background: var(--surface-0); border: 1px solid var(--border);
  border-radius: var(--r-md); overflow: hidden; box-shadow: var(--shadow-1);
  transition: transform .25s, box-shadow .25s;
}
.video-card:hover { transform: translateY(-4px); box-shadow: var(--shadow-2); }

.video-card__player { position: relative; aspect-ratio: 16 / 9; background: var(--navy-900); }
.video-card__poster { display: block; width: 100%; height: 100%; object-fit: cover; }
.video-card__poster--none {
  width: 100%; height: 100%;
  background: linear-gradient(135deg, var(--navy-800), var(--teal-600));
}

/* The play control fills the frame: the whole poster is the target. */
.video-card__play,
.video-hero__play {
  position: absolute; inset: 0; width: 100%; border: 0; cursor: pointer;
  display: grid; place-items: center;
  background: rgba(8, 26, 43, 0.28); transition: background .25s;
}
.video-card__play:hover, .video-hero__play:hover { background: rgba(8, 26, 43, 0.45); }
.video-card__play:focus-visible, .video-hero__play:focus-visible { outline: 3px solid var(--teal-300); outline-offset: -5px; }

.video-card__play-ico, .video-hero__play-ico {
  width: 54px; height: 54px; border-radius: 50%; display: grid; place-items: center;
  background: rgba(255, 255, 255, 0.94); color: var(--navy-700);
  font-size: 1.7rem; padding-left: 4px;   /* optical centring of the triangle */
  box-shadow: 0 6px 20px rgba(8, 26, 43, 0.3);
  transition: transform .25s, background .25s;
}
.video-card__play:hover .video-card__play-ico,
.video-hero__play:hover .video-hero__play-ico { transform: scale(1.08); background: #fff; }

.video-card__time {
  position: absolute; right: 10px; bottom: 10px;
  padding: 3px 8px; border-radius: 6px;
  background: rgba(8, 26, 43, 0.78); color: #fff;
  font-size: 0.75rem; font-weight: 600; font-variant-numeric: tabular-nums;
  pointer-events: none;   /* never blocks the play button beneath it */
}
.video-card__time--lg { right: 16px; bottom: 16px; font-size: 0.85rem; padding: 5px 11px; }

.media-video__frame { display: block; width: 100%; height: 100%; border: 0; }
/* An uploaded file plays in a <video>, which unlike an iframe has intrinsic
   proportions. Letterbox it against black rather than stretching the picture. */
video.media-video__frame { object-fit: contain; background: #000; }

.video-card__body { padding: 15px 17px 18px; display: flex; flex-direction: column; gap: 7px; }
.video-card__title { margin: 0; font-size: 1.02rem; line-height: 1.4; color: var(--navy-700); }
.video-card__desc {
  margin: 0; font-size: 0.88rem; color: var(--ink-600); line-height: 1.55;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}

/* ---- featured video ---- */
.video-hero {
  position: relative; aspect-ratio: 16 / 9; overflow: hidden;
  border-radius: var(--r-lg); background: var(--navy-900);
  box-shadow: var(--shadow-2); border: 1px solid var(--border);
  max-width: 980px; margin-inline: auto;
}
.video-hero__poster { display: block; width: 100%; height: 100%; object-fit: cover; }
.video-hero__play-ico { width: 74px; height: 74px; font-size: 2.3rem; }
@media (max-width: 640px) {
  .video-hero__play-ico { width: 56px; height: 56px; font-size: 1.7rem; }
}

/* Once playing, the iframe is the only child and fills the frame. */
.video-hero.is-playing, .video-card__player.is-playing { background: #000; }

/* LEAD FORM — submit state + confirmation -------------------------------- */

/* Spinner lives in the button and only becomes visible in the busy state, so
   there is no layout shift when it appears. */
.lead-submit { position: relative; display: inline-flex; align-items: center; gap: 0; }
.lead-submit__spin {
  width: 0; height: 16px; flex: none; border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, 0.35); border-top-color: #fff;
  opacity: 0; transition: width .18s var(--ease), margin-right .18s var(--ease), opacity .18s;
}
.lead-submit.is-busy { pointer-events: none; }
.lead-submit.is-busy .lead-submit__spin {
  width: 16px; margin-right: 10px; opacity: 1;
  animation: lead-spin .7s linear infinite;
}
@keyframes lead-spin { to { transform: rotate(360deg); } }
/* Reduced motion still needs a visible busy state — just not a spinning one. */
@media (prefers-reduced-motion: reduce) {
  .lead-submit.is-busy .lead-submit__spin { animation: none; }
}
.lead-submit:disabled, .lead-submit.is-busy { opacity: 0.85; cursor: progress; }

/* ---- confirmation card ---- */
.lead-done {
  max-width: 620px; margin-inline: auto; text-align: center;
  background: var(--surface-0); border: 1px solid var(--border);
  border-radius: var(--r-lg); box-shadow: var(--shadow-2);
  padding: clamp(30px, 5vw, 48px) clamp(22px, 4vw, 44px);
}
.lead-done__ico {
  width: 62px; height: 62px; margin: 0 auto 20px;
  display: grid; place-items: center; border-radius: 50%;
  background: var(--gradient-brand); color: #fff;
  box-shadow: 0 8px 22px rgba(35, 173, 158, 0.28);
}
.lead-done__ico svg { width: 32px; height: 32px; }
.lead-done__title {
  margin: 0 0 10px; font-family: var(--font-display);
  font-size: clamp(1.35rem, 2.6vw, 1.7rem); color: var(--navy-700); line-height: 1.3;
}
.lead-done__lede { margin: 0 0 26px; color: var(--ink-600); line-height: 1.65; }

/* Numbered steps, left-aligned inside a centred card: a centred list with
   ragged edges on both sides is hard to scan. */
.lead-done__steps {
  list-style: none; margin: 0 0 24px; padding: 0;
  text-align: left; display: flex; flex-direction: column; gap: 2px;
  counter-reset: lead-step;
}
.lead-done__steps li {
  counter-increment: lead-step;
  position: relative; padding: 12px 0 12px 46px;
  border-top: 1px solid var(--border);
}
.lead-done__steps li:first-child { border-top: 0; }
.lead-done__steps li::before {
  content: counter(lead-step);
  position: absolute; left: 0; top: 11px;
  width: 28px; height: 28px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--surface-1); color: var(--teal-600);
  font-family: var(--font-display); font-size: 0.82rem; font-weight: 700;
}
.lead-done__steps b { display: block; color: var(--ink-900); font-size: 0.96rem; font-weight: 600; }
.lead-done__steps span { display: block; color: var(--ink-400); font-size: 0.86rem; margin-top: 2px; }

.lead-done__urgent {
  margin: 0 0 22px; padding-top: 20px; border-top: 1px solid var(--border);
  color: var(--ink-400); font-size: 0.9rem;
}
.lead-done__urgent a { color: var(--teal-600); font-weight: 600; }
.lead-done__cta { display: flex; flex-wrap: wrap; gap: 10px; justify-content: center; }

/* SOCIAL RAIL — collapsed by default ------------------------------------
   The rail used to sit open over page content at narrower widths. It now
   shows only a small tab; the icons slide out on hover (pointer devices) or
   on tap (touch, where hover does not exist). */
.social-rail { padding: 0; overflow: hidden; }

.social-rail__tab {
  display: grid; place-items: center;
  width: 34px; height: 44px; padding: 0;
  background: none; border: 0; cursor: pointer;
  color: rgba(255, 255, 255, 0.8);
  transition: color var(--t-fast) var(--ease);
}
.social-rail__tab:hover { color: #fff; }
.social-rail__tab:focus-visible { outline: none; box-shadow: var(--focus-ring); border-radius: 8px; }
.social-rail__tab-ico { display: grid; place-items: center; }
.social-rail__tab-ico svg {
  width: 17px; height: 17px;
  transition: transform var(--t-med) var(--ease-out-expo);
}

/* The icons are laid out as always but clipped to zero height while closed.
   grid-template-rows animates cleanly where height:auto cannot. */
/* Hidden outright while collapsed rather than animated to zero: the rail is a
   flex column, and a shrinkable grid child kept squeezing four 38px icons into
   20px of total height. display toggling sidesteps that entirely. */
.social-rail__items { display: none; }
.social-rail.is-open .social-rail__items { display: block; }
@media (hover: hover) and (pointer: fine) {
  .social-rail:hover .social-rail__items { display: block; }
}
.social-rail:focus-within .social-rail__items { display: block; }
/* Top padding matters once open: the tab that used to occupy that space is
   collapsed away, so without it the first icon sits flush against the edge. */
.social-rail__inner { display: flex; flex-direction: column; gap: 2px; padding: 10px 8px; }

/* Open on hover only where hovering is real — a touch device reports
   `hover: none` and would otherwise latch the rail open after a tap. */
@media (hover: hover) and (pointer: fine) {
  
  .social-rail:hover .social-rail__tab-ico svg { transform: rotate(90deg); }
}
/* Keyboard focus anywhere inside opens it too. */


/* Explicit open state, set by main.js on tap and kept in sync with
   aria-expanded. Wins over the hover rules because it comes later. */


/* Once open, the tab has done its job and the icons speak for themselves —
   leaving it on top of them reads as a fifth, broken network. It collapses to
   zero height rather than display:none so the rail does not jump, and stays
   in the DOM so a keyboard user can still tab to it to close the rail. */
.social-rail__tab {
  overflow: hidden;
  transition: height var(--t-med) var(--ease-out-expo),
              min-height var(--t-med) var(--ease-out-expo),
              opacity var(--t-fast) var(--ease),
              color var(--t-fast) var(--ease);
}
/* Collapsed via grid-template-rows on a wrapper, exactly as the icon list is:
   animating the button's own height fought its intrinsic grid sizing and left
   it stuck at 44px. The wrapper has no intrinsic size of its own, so 1fr → 0fr
   collapses cleanly and animates. */
/* The tab is simply removed from flow once the rail is open: the icons are
   the content at that point, and an animated collapse of a 34px button is not
   worth the flex/grid contortions it took to make it size correctly. */
.social-rail__tabwrap { display: block; }
.social-rail.is-open .social-rail__tabwrap { display: none; }
@media (hover: hover) and (pointer: fine) {
  .social-rail:hover .social-rail__tabwrap { display: none; }
}

/* While collapsed the per-item entrance animation must not re-run; it is the
   container that moves now, not each icon. */
.social-rail.is-visible .social-rail__item { opacity: 1; transform: none; animation: none; }

/* The hover label sat to the right of each icon; inside a clipped container it
   would be cut off, so it is dropped — the aria-label still names each link. */
.social-rail__label { display: none; }

/* Phones: the rail is already display:none above 767px-down, but if that ever
   changes the tab must stay tappable rather than hover-only. */
@media (max-width: 767px) { .social-rail { display: none; } }

/* CALL FOR PAPERS — deadline counter ------------------------------------
   Sits next to the submit button on the dark call-for-papers band. Reads as a
   badge rather than a second button, so it adds urgency without competing
   with the actual call to action. */
.cfp-count {
  /* Height-matched to .btn beside it rather than padded by eye: the badge and
     the button share a row, and a few pixels of difference reads as a
     misalignment on a dark band. */
  display: inline-flex; align-items: center; justify-content: center; gap: 9px;
  align-self: center; min-height: 52px;
  padding: 0 18px; border-radius: 999px;
  background: rgba(255, 255, 255, 0.07);
  border: 1px solid rgba(126, 217, 205, 0.32);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
  line-height: 1.05; white-space: nowrap;
}
.cfp-count__n {
  font-family: var(--font-display); font-size: 1.55rem; font-weight: 800;
  color: var(--teal-300); font-variant-numeric: tabular-nums;
}
.cfp-count__u {
  font-size: 0.7rem; font-weight: 600; letter-spacing: 0.08em;
  text-transform: uppercase; color: rgba(255, 255, 255, 0.62);
}

/* Inside two weeks the badge warms up. Colour alone is not the message — the
   number itself is already the signal — so no extra meaning is lost by it. */
.cfp-count--urgent {
  background: rgba(255, 176, 102, 0.12);
  border-color: rgba(255, 176, 102, 0.45);
}
.cfp-count--urgent .cfp-count__n { color: #ffc182; }

@media (max-width: 480px) {
  .cfp-count { min-height: 46px; padding: 0 15px; }
  .cfp-count__n { font-size: 1.3rem; }
}
