/* ==========================================================================
   Jubilee World — homepage sections below the globe
   ========================================================================== */

/* --------------------------------------------------------------------------
   Shell — each section sits in a softly lit, rounded panel
   -------------------------------------------------------------------------- */
/* The vertical rhythm here is tuned so one section frames within one desktop
   screen: at 1440x900 a panel plus its margins comes to roughly 700-760px, which
   leaves the next section's title visible at the fold rather than starting it
   just off-screen. It was 56/48/52, and the 20px taken off each is why. The
   720px override further down keeps phones as they were. */
.panel {
  position: relative;
  max-width: 1460px;
  margin: 40px auto;
  padding: 36px clamp(20px, 3.4vw, 56px) 40px;
  border: 1px solid var(--border-soft);
  border-radius: 26px;
  background:
    radial-gradient(120% 120% at 85% 8%, rgba(75, 41, 123, 0.22), transparent 58%),
    var(--bg-alt);
  overflow: hidden;
}

/* Faint contour lines echoing the reference artwork. */
.panel::after {
  content: "";
  position: absolute;
  inset: 0 -10% 0 auto;
  width: 42%;
  pointer-events: none;
  background:
    radial-gradient(60% 90% at 100% 40%, rgba(169, 123, 255, 0.09), transparent 70%);
}

.panel__head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: 18px 28px;
  margin-bottom: 34px;
}

/* Two sizes, chosen by heading level rather than by a modifier class, because
   the level is the thing that decides: an <h1> names the page and an <h2> names
   a section of it, and .panel__title is used for both — <h1> on /movement and
   on every /[slug] stub, <h2> on the homepage's four sections and on Music &
   Media. A section heading was 54px against a 66px page title, which is not a
   hierarchy; at 34px it is clearly the second thing on the page. The same ratio
   is applied to .section-title and .cta-band__title in site.css. */
.panel__title {
  font-family: var(--f-display);
  font-size: clamp(30px, 4vw, 54px);
  font-weight: 800;
  letter-spacing: -1px;
  line-height: 1.02;
  color: var(--text);
}

h2.panel__title {
  font-size: clamp(22px, 2.55vw, 34px);
  letter-spacing: -0.4px;
  line-height: 1.12;
}

/* Sparkle + fading rule beneath the heading. */
.panel__flourish {
  display: flex;
  align-items: center;
  gap: 7px;
  margin-top: 12px;
}
.panel__flourish::before {
  content: "";
  width: 9px;
  height: 9px;
  background: var(--accent);
  clip-path: polygon(50% 0, 61% 39%, 100% 50%, 61% 61%, 50% 100%, 39% 61%, 0 50%, 39% 39%);
}
.panel__flourish::after {
  content: "";
  width: 74px;
  height: 1px;
  background: linear-gradient(90deg, var(--accent), transparent);
}

/* --------------------------------------------------------------------------
   New Releases
   -------------------------------------------------------------------------- */
.releases {
  display: grid;
  grid-template-columns: minmax(0, 1.32fr) minmax(0, 1fr);
  gap: clamp(24px, 3vw, 54px);
  /* Start, not stretch. The player used to be stretched to the metadata
     column's height so the bottom edges lined up, which meant the media box
     was whatever height the two track cards happened to add up to — 1.505 at
     1440px, against a 1.778 video. The video's own shape wins now, and the
     columns end where their content ends. The comp fills the difference under
     the player with a three-item feature strip (legacy/index.html); that copy
     has no home in the CMS, so the space is simply empty until it does. */
  align-items: start;
}

/* ---- player ---------------------------------------------------------- */

/* The player is as wide as its column and as tall as its own media, never
   taller. */
.player { display: flex; }

/* `--player-ratio` is the media's real shape. 16/9 covers every YouTube-backed
   release exactly — an embed is always 16/9 — and is the sensible default for a
   file too. A file-backed release then corrects it from the video's own
   videoWidth/videoHeight once metadata arrives (player.js), which is the only
   way to be right about an arbitrary upload: the one in the collection today is
   2044x1080, not 16/9, and nothing in the CMS records that. */
.player__shell {
  flex: 1 1 auto;
  min-width: 0;
  aspect-ratio: var(--player-ratio, 16 / 9);
  position: relative;
  border: 1px solid rgba(169, 123, 255, 0.4);
  border-radius: 14px;
  overflow: hidden;
  background: #000;
  box-shadow: 0 0 0 1px rgba(169, 123, 255, 0.1), 0 22px 60px rgba(0, 0, 0, 0.55);
}

/* The shell is what requestFullscreen() is called on (player.js). Every engine
   sizes a fullscreen element to the screen in both axes, which already beats a
   ratio, but say it rather than rely on it: a 16/9 box on a 16/10 display would
   otherwise letterbox itself twice. */
.player__shell:fullscreen { aspect-ratio: auto; }

/* The shell carries the ratio, so both of these just fill it. `cover` is a
   no-op on the video once the box matches it, and stays as the safe behaviour
   for the moment before metadata arrives and for a poster that is not the same
   shape as its film — assets/img/2025/12/1.jpg is 1200x857 against a 2044x1080
   file, and a still is the one thing here that can be cropped harmlessly. */
.player__video,
.player__poster {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  background: #000;
}

/* The poster is only a placeholder until the media paints. */
.player__poster {
  position: absolute;
  inset: 0;
  height: 100%;
  transition: opacity 0.4s var(--ease);
}
.player.is-playing .player__poster { opacity: 0; pointer-events: none; }

/* The muted preview a YouTube-backed big slot gets, built by releases.js. It
   fills the shell and nothing more: the shell is 16/9 for this branch and so is
   the embed, so there is no overhang to trim and no scale to hide it with. The
   scale that used to be here was sized for a 16/10 shell and the shell was
   really 1.505 once stretched, so it under-covered and YouTube's own letterbox
   bars showed through the top and bottom of the preview. The big play button
   stays on top of it — a preview is a moving poster, and the click that opens
   the dialog is still the way to hear it. */
.player__preview {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
  opacity: 0;
  transition: opacity 0.4s var(--ease);
  pointer-events: none;
}
.player.is-previewing .player__preview { opacity: 1; }

/* A play badge over footage that is already moving says the wrong thing, so the
   preview takes it away — the same thing `is-playing` does for the file-backed
   branch two rules below, now that hover-play and scroll autoplay put the
   YouTube branch in the same state.
 *
 * Only the icon goes. The button keeps its hit area and its z-index above the
 * iframe, because it is still the one thing on the poster that opens the dialog
 * — the click that turns a muted preview into the track with sound. The preview
 * only runs while the pointer is on the shell (or, on a phone, while the panel
 * is the thing on screen), so the badge is visible exactly when a visitor is
 * deciding whether to interact and gone once they are. */
.player.is-previewing .player__big-play { opacity: 0; z-index: 1; }

.player__big-play {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 94px;
  height: 94px;
  margin: -47px 0 0 -47px;
  display: grid;
  place-items: center;
  border: 2px solid rgba(169, 123, 255, 0.85);
  border-radius: 50%;
  background: rgba(75, 41, 123, 0.32);
  backdrop-filter: blur(3px);
  color: #fff;
  transition: transform 0.3s var(--ease), background 0.3s var(--ease),
              opacity 0.3s var(--ease);
}
.player__big-play svg { width: 30px; height: 30px; margin-left: 4px; }
.player__big-play:hover { transform: scale(1.07); background: rgba(75, 41, 123, 0.6); }
.player.is-playing .player__big-play { opacity: 0; pointer-events: none; }

/* ---- control bar ------------------------------------------------------ */

.player__controls {
  position: absolute;
  inset: auto 0 0 0;
  padding: 30px 16px 12px;
  background: linear-gradient(180deg, transparent, rgba(4, 2, 10, 0.9) 55%);
  opacity: 0;
  transform: translateY(6px);
  transition: opacity 0.3s var(--ease), transform 0.3s var(--ease);
}
.player:hover .player__controls,
.player.is-playing .player__controls,
.player:focus-within .player__controls { opacity: 1; transform: none; }

/* Scrubber — a real slider, keyboard included. */
.player__scrub {
  position: relative;
  height: 14px;
  display: flex;
  align-items: center;
  cursor: pointer;
  touch-action: none;
}
.player__scrub::before {
  content: "";
  position: absolute;
  inset-inline: 0;
  height: 3px;
  border-radius: 2px;
  background: rgba(255, 255, 255, 0.24);
}
.player__fill {
  position: relative;
  height: 3px;
  width: 0;
  border-radius: 2px;
  background: var(--accent);
}
.player__fill::after {
  content: "";
  position: absolute;
  right: -6px;
  top: 50%;
  width: 11px;
  height: 11px;
  margin-top: -5.5px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 0 8px rgba(169, 123, 255, 0.9);
  transform: scale(0);
  transition: transform 0.2s var(--ease);
}
.player:hover .player__fill::after,
.player__scrub:focus-visible .player__fill::after { transform: scale(1); }

.player__row {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-top: 6px;
}
.player__row .spacer { flex: 1 1 auto; }

.player__btn {
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  padding: 0;
  border-radius: 6px;
  color: rgba(255, 255, 255, 0.88);
  transition: color 0.2s var(--ease), background 0.2s var(--ease);
}
.player__btn:hover { color: #fff; background: rgba(255, 255, 255, 0.12); }
.player__btn svg { width: 17px; height: 17px; }

/* Each button carries both glyphs and shows the one matching its state. */
.player__btn [data-when] { display: none; }
.player__btn[data-state="play"]  [data-when="play"],
.player__btn[data-state="pause"] [data-when="pause"],
.player__btn[data-state="on"]    [data-when="on"],
.player__btn[data-state="muted"] [data-when="muted"] { display: block; }

.player__clock {
  font-family: var(--f-nav);
  font-size: 12.5px;
  font-variant-numeric: tabular-nums;
  color: rgba(255, 255, 255, 0.82);
  letter-spacing: 0.4px;
}

/* ---- metadata panel --------------------------------------------------- */

.release__badge {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 7px 13px;
  border-radius: 7px;
  background: var(--c-purple);
  font-family: var(--f-nav);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 1.8px;
  text-transform: uppercase;
  color: #fff;
}
.release__badge svg { width: 12px; height: 12px; }

/* Under the section heading above it, not over it. At 44px this was the largest
   thing in the section and "New Releases" was the second largest, which reads as
   the release being the subject and the section being a footnote to it. The
   order is h1 54 / section 34 / this 30 now, top to bottom on the page. */
.release__title {
  margin-top: 18px;
  font-family: var(--f-display);
  font-size: clamp(21px, 2.2vw, 30px);
  font-weight: 800;
  line-height: 1.08;
  letter-spacing: -0.8px;
  color: var(--text);
  text-wrap: balance;
}
/* The margin above is the gap under the badge. A release that has never held
   the big slot has no badge, and then the title is what starts the column and
   should line up with the top of the player beside it. */
.release__title:first-child { margin-top: 0; }

.release__rule {
  width: 62px;
  height: 2px;
  margin: 16px 0 18px;
  border: 0;
  background: linear-gradient(90deg, var(--accent), transparent);
}

.release__blurb {
  font-size: 16.5px;
  line-height: 1.7;
  color: var(--text-dim);
  max-width: 38ch;
}

/* Purple, by request, August 24, 2026: an artist's name is the same kind of
   thing wherever it appears in New Releases, and the rail cards' .track__artist
   was already --accent — so the big slot was the one that read as a heading
   instead. The avatar beside it sets its own colour and does not follow. */
.release__artist {
  display: flex;
  align-items: center;
  gap: 11px;
  margin-top: 24px;
  font-size: 16px;
  font-weight: 700;
  color: var(--accent);
}
.release__avatar {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: rgba(169, 123, 255, 0.18);
  border: 1px solid rgba(169, 123, 255, 0.4);
  color: var(--accent);
}
.release__avatar svg { width: 16px; height: 16px; }

.release__meta {
  margin-top: 9px;
  font-family: var(--f-nav);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--text-faint);
}

/* ---- up next ---------------------------------------------------------- */

.upnext {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 16px;
  margin-top: 30px;
}

.track {
  position: relative;
  display: block;
  border: 1px solid var(--border-soft);
  border-radius: 12px;
  background: var(--surface);
  overflow: hidden;
  text-align: left;
  transition: border-color 0.25s var(--ease), transform 0.25s var(--ease);
}
.track:hover { border-color: var(--accent); transform: translateY(-3px); }

/* The card is an <article> now and this is the button it used to be — an
   overlay covering the whole card, so a click anywhere still opens the dialog.
   See the note in ReleasesSection.tsx: the muted preview is an iframe, which a
   button is not allowed to contain. */
.track__open {
  position: absolute;
  inset: 0;
  z-index: 3;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}
.track__open:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -3px;
  border-radius: 12px;
}
.track:focus-within { border-color: var(--accent); }

/* 16/9, the shape of the film the card opens and of the still YouTube gives
   back for it: assets/img/releases/*.jpg are 640x360 and now show whole rather
   than cropped, where a 16/10 box took 11% off their sides. The two 1200x857
   thumbnails carried over from WordPress are still cropped — that is a
   source-asset shape, not a box.

   The box owns the ratio, the way .player__shell and .chapter__media do, so it
   holds its shape even for a release whose thumbnail is missing — those used to
   collapse to nothing. No `overflow: hidden` here: .track__play hangs half
   outside the frame on purpose (bottom: -17px), and the preview iframe no
   longer overhangs anything now that it is the same shape as the box. */
.track__media {
  position: relative;
  display: block;
  aspect-ratio: 16 / 9;
}

/* The muted preview releases.js builds over the thumbnail.
 *
 * pointer-events: none is load-bearing twice over: it keeps every click on the
 * button above, and it stops YouTube's own controls from ever taking one.
 *
 * No scale: the thumbnail box is 16/9 and so is the embed, so the frame lands
 * exactly on the poster it replaces. It used to be scaled 1.12 to cover a 16/10
 * box, which cropped the preview on all four sides. */
.track__preview {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
  opacity: 0;
  transition: opacity 0.4s var(--ease);
  pointer-events: none;
}
.track.is-previewing .track__preview { opacity: 1; }
/* Neither badge belongs on moving footage: the runtime is the poster's caption,
   and a play button over a playing video contradicts itself. Both go while the
   preview runs and come back with the poster. The whole card is the click
   target (.track__open), so nothing is lost by hiding this one — unlike the big
   slot's badge, which is the click target. */
.track.is-previewing .track__play,
.track.is-previewing .track__length { opacity: 0; }
.track__length { transition: opacity 0.3s var(--ease); }
.track__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.track__length {
  position: absolute;
  top: 8px;
  right: 8px;
  padding: 3px 7px;
  border-radius: 4px;
  background: rgba(4, 2, 10, 0.82);
  font-family: var(--f-nav);
  font-size: 11px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: #fff;
}

.track__play {
  position: absolute;
  left: 12px;
  bottom: -17px;
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border: 1px solid rgba(169, 123, 255, 0.75);
  border-radius: 50%;
  background: rgba(20, 12, 38, 0.9);
  color: #fff;
  transition: background 0.25s var(--ease), transform 0.25s var(--ease),
              opacity 0.25s var(--ease);
}
.track__play svg { width: 13px; height: 13px; margin-left: 2px; }
.track:hover .track__play { background: var(--c-purple); transform: scale(1.08); }

.track__body { display: block; padding: 26px 14px 14px; }
.track__title,
.track__artist,
.track__meta { display: block; }
.track__title {
  font-size: 15px;
  font-weight: 700;
  color: var(--text);
  margin-bottom: 3px;
}
.track__artist { font-size: 13px; color: var(--accent); }
.track__meta {
  margin-top: 5px;
  font-size: 12px;
  color: var(--text-faint);
  font-variant-numeric: tabular-nums;
}

/* ---- every release: the /new-releases grid ----------------------------- */

/* The same `.track` card as the rail, in a wider grid — which is why this sits
   in home.css beside it rather than in globe.css with the other page-scoped
   blocks. Splitting one component's rules across two files to keep a filename
   honest would cost more than it explains; all three stylesheets are on every
   page (layout.tsx) either way.

   auto-fill rather than a fixed column count: the card has a natural minimum
   and the row reflows to whatever the viewport allows, so nothing here has to
   know how many releases there are. */
.releases-all {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 20px;
  margin-top: 34px;
}

/* A release with a file but no YouTube id has nothing the dialog can play — it
   is a card that cannot be clicked, so it does not pretend to be one. */
.track--silent { opacity: 0.75; }
.track--silent:hover { border-color: var(--border-soft); transform: none; }
.track--silent .track__play { display: none; }

/* --------------------------------------------------------------------------
   Responsive
   -------------------------------------------------------------------------- */
@media (max-width: 1080px) {
  .releases { grid-template-columns: 1fr; }
  .release__blurb { max-width: none; }
}

@media (max-width: 720px) {
  .panel { margin: 32px auto; padding: 32px 18px 36px; border-radius: 18px; }
  .player__big-play { width: 68px; height: 68px; margin: -34px 0 0 -34px; }
  .player__big-play svg { width: 22px; height: 22px; }
}

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

/* --------------------------------------------------------------------------
   Upcoming Events — a schedule, not a card grid

   Deliberately the lightest section on the page: no photography, no hover
   states, shorter panel padding, and a decorative accent rule on every entry
   rather than separators between them, so nothing has to be reset as the grid
   folds from four columns to one.

   Lightest in colour as well now, by request: the band lifts to a mid purple
   while the panels above and below it stay on --bg-alt, which is what makes a
   schedule with no imagery in it read as a calendar rather than as a gap
   between two card sections. #2A1B4A is about four times the luminance of
   --bg-alt (#0F0A1A) — clearly a different surface — and still dark enough to
   carry --text at roughly 13:1. The border turns purple with it, since
   --border-soft's white edge disappears against a lit ground.
   -------------------------------------------------------------------------- */
.events-panel {
  padding-top: 40px;
  padding-bottom: 44px;
  border-color: rgba(169, 123, 255, 0.30);
  background:
    radial-gradient(120% 120% at 85% 8%, rgba(169, 123, 255, 0.20), transparent 60%),
    linear-gradient(180deg, #2A1B4A 0%, #1E1436 100%);
}

.events {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 20px 24px;
}

.event {
  display: flex;
  align-items: flex-start;
  gap: 13px;
  padding: 3px 0 3px 16px;
  /* Brighter than it was: the old 0.45 rule was tuned against --bg-alt and
     washes out on the lit band above. */
  border-left: 2px solid rgba(169, 123, 255, 0.7);
}

/* The month reads as a date tile rather than a coloured word — the one piece
   of "calendar" this section has, and the thing a visitor scans first. Plain
   --accent text lost its punch once the ground came up towards it; a filled
   chip keeps the contrast the accent used to carry on its own. */
.event__month {
  flex: none;
  align-self: flex-start;
  padding: 4px 9px;
  border-radius: 7px;
  border: 1px solid rgba(169, 123, 255, 0.35);
  background: rgba(169, 123, 255, 0.18);
  font-family: var(--f-nav);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 2px;
  text-transform: uppercase;
  color: #E6DAFF;
  white-space: nowrap;
}

.event__title {
  display: block;
  font-size: 16px;
  font-weight: 700;
  line-height: 1.3;
  color: var(--text);
  text-wrap: balance;
}

.event__location {
  display: block;
  margin-top: 4px;
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--text-dim);
}

@media (max-width: 980px) {
  .events { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

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

/* --------------------------------------------------------------------------
   Find Your Place — three whole-card links
   -------------------------------------------------------------------------- */
.panel--center { text-align: center; }

/* Extra headroom for the medallion and the centred title; 56 rather than the
   old 78 for the same reason .panel lost 20px.

   `scroll-margin-top` is for the closing band's "Find Your Place in Jubilee"
   button, which targets this section's `id`. Not clearance for a sticky header —
   there is none; the site header is absolute over the hero and static everywhere
   else — but so that a section arrived at by link starts a little below the
   viewport edge rather than flush against it. `html` already carries
   `scroll-behavior: smooth`, and site.css turns that off under
   `prefers-reduced-motion`, so the scroll animates or jumps to the visitor's
   own preference without anything here deciding for them. */
.pathways-panel {
  padding-top: 56px;
  scroll-margin-top: 28px;
  background:
    radial-gradient(80% 60% at 50% 0%, rgba(75, 41, 123, 0.3), transparent 62%),
    var(--bg);
}

/* Faint arcs sweeping in from the upper left, as in the reference. */
.pathways-panel::before {
  content: "";
  position: absolute;
  left: -18%;
  top: -46%;
  width: 62%;
  aspect-ratio: 1;
  border-radius: 50%;
  border: 1px solid rgba(169, 123, 255, 0.14);
  box-shadow:
    0 0 0 30px rgba(169, 123, 255, 0.04),
    0 0 0 62px rgba(169, 123, 255, 0.03);
  pointer-events: none;
}

/* Compass medallion above the heading, with rules running out to each side. */
.panel__medallion {
  position: relative;
  display: block;
  width: 46px;
  height: 46px;
  margin: 0 auto 18px;
  border: 1px solid rgba(169, 123, 255, 0.55);
  border-radius: 50%;
  background:
    radial-gradient(circle, rgba(169, 123, 255, 0.35), transparent 70%);
  box-shadow: 0 0 26px rgba(169, 123, 255, 0.45);
}
.panel__medallion::before {
  content: "";
  position: absolute;
  inset: 0;
  margin: auto;
  width: 17px;
  height: 17px;
  background: #fff;
  clip-path: polygon(50% 0, 60% 40%, 100% 50%, 60% 60%, 50% 100%, 40% 60%, 0 50%, 40% 40%);
}
/* The rules are drawn wide and clipped by the panel's own overflow. */
.panel__medallion::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 150vw;
  height: 1px;
  transform: translate(-50%, -50%);
  background: linear-gradient(90deg,
    transparent 0%, rgba(169, 123, 255, 0.3) 34%, transparent 46%,
    transparent 54%, rgba(169, 123, 255, 0.3) 66%, transparent 100%);
  z-index: -1;
}

.panel__title--center {
  max-width: 20ch;
  margin-inline: auto;
  text-wrap: balance;
}
.panel__title--center em {
  font-style: normal;
  background: linear-gradient(180deg, #E9DCFF, #A97BFF);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

/* Dot-and-rule seam under the heading. */
.panel__seam {
  position: relative;
  display: block;
  width: min(420px, 70%);
  height: 1px;
  margin: 20px auto 22px;
  background: linear-gradient(90deg, transparent, rgba(169, 123, 255, 0.5), transparent);
}
.panel__seam::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 5px;
  height: 5px;
  margin: -2.5px 0 0 -2.5px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 10px var(--accent);
}

.panel__lede {
  max-width: 68ch;
  margin: 0 auto 44px;
  font-size: clamp(15px, 1.25vw, 17.5px);
  line-height: 1.72;
  color: var(--text-dim);
  text-wrap: balance;
}

/* ---- the cards -------------------------------------------------------- */

.pathways {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(18px, 2vw, 30px);
  text-align: left;
}

.pathway {
  position: relative;
  display: flex;
  flex-direction: column;
  border: 1px solid rgba(169, 123, 255, 0.34);
  border-radius: 18px;
  background: linear-gradient(180deg, rgba(32, 20, 56, 0.5), rgba(12, 7, 24, 0.9));
  overflow: hidden;
  transition: border-color 0.3s var(--ease), transform 0.3s var(--ease),
              box-shadow 0.3s var(--ease);
}
.pathway:hover,
.pathway:focus-visible {
  border-color: var(--accent);
  transform: translateY(-5px);
  box-shadow: 0 0 0 1px rgba(169, 123, 255, 0.35), 0 22px 54px rgba(0, 0, 0, 0.55);
}

.pathway__media {
  position: relative;
  display: block;
  aspect-ratio: 16 / 11;
  overflow: hidden;
}
.pathway__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.7s var(--ease);
}
.pathway:hover .pathway__media img { transform: scale(1.05); }

/* Fade the photo into the card body rather than cutting it off hard. */
.pathway__media::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, transparent 38%, rgba(12, 7, 24, 0.75) 78%, #0C0718 100%);
}

/* Badge straddling the seam between photo and body. */
.pathway__icon {
  position: absolute;
  left: 26px;
  top: -25px;              /* half its height, so it straddles the seam */
  display: grid;
  place-items: center;
  width: 50px;
  height: 50px;
  border: 1px solid rgba(169, 123, 255, 0.6);
  border-radius: 50%;
  background: rgba(28, 16, 52, 0.82);
  backdrop-filter: blur(4px);
  color: var(--accent);
  z-index: 2;
  transition: background 0.3s var(--ease), box-shadow 0.3s var(--ease);
}
.pathway__icon svg { width: 21px; height: 21px; }
.pathway:hover .pathway__icon {
  background: rgba(75, 41, 123, 0.9);
  box-shadow: 0 0 22px rgba(169, 123, 255, 0.55);
}

.pathway__body {
  position: relative;      /* the badge hangs off this edge */
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  padding: 44px 26px 28px;
}

/* Eyebrow above the title — "For Artists", "For Creatives", "For Everyone". */
.pathway__label {
  display: block;
  margin-bottom: 10px;
  font-family: var(--f-nav);
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 2.6px;
  text-transform: uppercase;
  color: var(--accent);
}

.pathway__title {
  font-family: var(--f-display);
  font-size: clamp(21px, 1.9vw, 27px);
  font-weight: 800;
  line-height: 1.16;
  letter-spacing: -0.5px;
  color: var(--text);
  margin-bottom: 14px;
  text-wrap: balance;
}

.pathway__text {
  font-size: 15px;
  line-height: 1.68;
  color: var(--text-dim);
}

/* The arrow closing the description — all that is left of the pill button the
   8/10 review struck. It stays on the same line as the last word, so the copy
   reads "...for Christ today. →" exactly as written in the feedback. */
.pathway__arrow {
  display: inline-block;
  margin-left: 8px;
  font-size: 15px;
  color: var(--accent);
  transition: transform 0.3s var(--ease);
}
.pathway:hover .pathway__arrow,
.pathway:focus-visible .pathway__arrow { transform: translateX(5px); }

@media (max-width: 980px) {
  .pathways { grid-template-columns: 1fr; max-width: 520px; margin-inline: auto; }
  .pathways-panel { padding-top: 44px; }
}

/* --------------------------------------------------------------------------
   Around the Movement — scroll-snap carousel of whole-card links
   -------------------------------------------------------------------------- */
.around {
  background:
    radial-gradient(75% 55% at 50% 0%, rgba(75, 41, 123, 0.26), transparent 62%),
    var(--bg);
  padding-top: 56px;
}

/* "Around the Jubilee Movement" on one line, by request — it is 27 characters
   against .panel__title--center's 20ch, which is what broke it in two. Scoped
   to this section rather than raising that limit: the pathways panel's heading
   is also over 20ch and is meant to wrap, and the comp shows it wrapped. A
   narrow phone will still break this one, which is the right outcome — one line
   or overflow is not the choice being made here. */
.around .panel__title--center { max-width: none; }

/* Wide arcs sweeping across the top corners. */
.around::before {
  content: "";
  position: absolute;
  left: 50%;
  top: -132%;
  width: 150%;
  aspect-ratio: 1;
  transform: translateX(-50%);
  border-radius: 50%;
  border: 1px solid rgba(169, 123, 255, 0.16);
  box-shadow: 0 0 0 26px rgba(169, 123, 255, 0.035);
  pointer-events: none;
}

.carousel {
  position: relative;
  display: flex;
  align-items: center;
  gap: 14px;
}

.carousel__track {
  display: flex;
  gap: 18px;
  flex: 1 1 auto;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  padding: 4px;            /* room for the focus ring and hover lift */
  scroll-padding: 4px;
}
.carousel__track::-webkit-scrollbar { display: none; }

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

.carousel__nav {
  flex: none;
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border: 1px solid rgba(169, 123, 255, 0.45);
  border-radius: 50%;
  background: rgba(20, 12, 38, 0.7);
  color: var(--text);
  transition: background 0.25s var(--ease), border-color 0.25s var(--ease),
              opacity 0.25s var(--ease);
}
.carousel__nav svg { width: 19px; height: 19px; }
.carousel__nav:hover:not(:disabled) {
  background: rgba(75, 41, 123, 0.85);
  border-color: var(--accent);
}
.carousel__nav:disabled { opacity: 0.28; cursor: default; }

.carousel__dots {
  display: flex;
  justify-content: center;
  gap: 11px;
  margin-top: 30px;
}

.carousel__dot {
  width: 9px;
  height: 9px;
  padding: 0;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.24);
  transition: background 0.25s var(--ease), transform 0.25s var(--ease);
}
.carousel__dot:hover:not(:disabled) { background: rgba(255, 255, 255, 0.5); }
.carousel__dot.is-active { background: #fff; transform: scale(1.32); }
.carousel__dot:disabled { cursor: default; }

/* Nothing to page through — say so rather than leaving live-looking controls. */
.carousel--static .carousel__dots { opacity: 0.35; }

/* --------------------------------------------------------------------------
   Movement page — hero + the region directory

   The directory reuses .carousel wholesale (track, arrows, dots) and only
   brings its own card. A region card is text where a .movement card is a
   photograph, so it sizes itself instead of taking that card's 3/4.05 aspect
   ratio: a fixed width for the snap to work against, and a height set by the
   longest country list in view rather than by an image.
   -------------------------------------------------------------------------- */
/* The hero is set to docs/visuals/movepage.png rather than to the shared panel
   vocabulary, because the comp's whole idea is that the title, the lede, the
   hint and the map are one stack you take in at a glance. Measured off that
   file, scaled to a 1440 page: the title sits 18px under the header, the lede
   13px under the title's baseline, the hint 15px under the lede, and the map
   starts where the hint ends. Nothing between them. So the medallion and the
   seam are not rendered here — the comp has neither, and together they were
   80px of the gap this hero could not afford — and the hint gives up its pill,
   which is the other thing the comp does not have.

   The rules below come to the 305px the map's width calculation spends above
   itself. Changing one means changing that number too. */
.movement-hero {
  margin-top: 10px;
  padding-top: 16px;
  /* Less than .panel's 40 because nothing follows the map inside this section,
     and the horizon wants to run close to the section's own bottom edge the way
     it does in the comp. */
  padding-bottom: 26px;
}
.movement-hero .panel__medallion,
.movement-hero .panel__seam { display: none; }

/* Uppercase, which is the comp's title and is most of why it reads as the
   monumental thing on the page: at the same cap height it covers 43% of the
   page's width where the sentence-cased version covers 34%. Sized to land on
   that 43% in Be Vietnam Pro 800 rather than to a round number. The -1px
   tracking goes with the change: it suits lowercase display type, and caps at
   this weight need the air rather than less of it. `max-width` has to go with the change too: 20ch
   was measured on the shorter, lowercase line and would wrap this one. */
.movement-hero .panel__title {
  max-width: none;
  font-size: clamp(27px, 3.45vw, 49px);
  letter-spacing: 0.005em;
  text-transform: uppercase;
}

/* One line, by request — which means the measure has to come off entirely.
   .panel__lede caps itself at 68ch so a paragraph does not run the width of a
   1460px panel; this sentence is 117 characters and wants to. At 15px it sets
   in about 915px, so it holds one line down to roughly an 880px viewport and
   wraps below that, which is the right place to wrap. */
.movement-hero .panel__lede {
  max-width: none;
  margin-top: 14px;
  margin-bottom: 15px;
  font-size: clamp(13.5px, 1.05vw, 15px);
  line-height: 1.35;
}

/* No pill: in the comp this is a line of quiet text with a small globe on it,
   sitting close enough to the map to read as the map's caption. */
.movement-hero__hint {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  margin-top: 0;
  font-size: 13px;
  color: var(--text-dim);
}

.movement-hero__globe {
  display: grid;
  place-items: center;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: rgba(169, 123, 255, 0.18);
  color: var(--accent);
}
.movement-hero__globe svg { width: 12px; height: 12px; }

/* ---- "Global presence by region" ----------------------------------------
   In the comp this heading is a caption, not a title: a few sizes under the
   hero's, tracked wide, uppercase, with a rule running out to each side. That
   is the comp's whole ornament for the section, which is why RegionDirectory
   renders neither a medallion nor a seam. */

/* The seam between the map and the directory, and the only one left: they are
   one section now, so what separates them is a gap rather than two panel edges
   and the page's own ground showing between them. */
.regions { margin-top: 20px; }
.regions .panel__title {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: clamp(18px, 3vw, 50px);
  max-width: none;
  font-size: clamp(15px, 1.72vw, 25px);
  font-weight: 500;
  letter-spacing: 0.3em;
  line-height: 1.4;
  text-transform: uppercase;
  color: var(--text);
}
.regions .panel__title::before,
.regions .panel__title::after {
  content: "";
  flex: 0 1 clamp(38px, 5vw, 76px);
  height: 1px;
  background: linear-gradient(90deg, transparent, rgba(169, 123, 255, 0.55));
}
/* Tracking leaves a letter-space hanging off the last glyph. Left alone it
   pushes this rule out by that much and the words sit off-centre between the
   two; pulling it back by the same 0.3em is the fix. */
.regions .panel__title::after {
  margin-left: -0.3em;
  background: linear-gradient(90deg, rgba(169, 123, 255, 0.55), transparent);
}

.regions .panel__lede {
  max-width: none;
  margin-top: 10px;
  margin-bottom: 18px;
  font-size: clamp(13px, 1vw, 14.5px);
  line-height: 1.5;
}

/* The dots sat 30px off the cards when the section ended at a panel edge. It
   ends at the page now, so they come in with everything else. */
.regions .carousel__dots { margin-top: 16px; }

/* Textured like the closing CTA band rather than flat like --surface: the same
   layering, one step quieter. That band is a photograph under a weighted veil
   with light trails over it; a card 288px wide cannot carry a photograph, so
   the veil and the trails do the work on their own — a purple wash falling to
   near-black, and the ribbons as a raking set of thin light lines under a mask
   that fades them out before they reach the country list. */
.region {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  /* Half the width it was, by request: these are country lists, not cards with
     a picture on them, and at 144px a page of the carousel shows twice as many
     regions. The padding and the bullet indent come in with it, or a name like
     "Dominican Republic" would have 90px to live in. */
  flex: 0 0 clamp(116px, 11vw, 144px);
  scroll-snap-align: start;
  display: flex;
  flex-direction: column;
  gap: 11px;
  padding: 16px 13px;
  border: 1px solid rgba(169, 123, 255, 0.24);
  border-radius: 16px;
  background:
    radial-gradient(122% 88% at 16% 0%, rgba(169, 123, 255, 0.26), transparent 62%),
    linear-gradient(163deg, rgba(75, 41, 123, 0.62) 0%, rgba(8, 4, 16, 0.94) 60%),
    var(--surface);
  text-align: left;
}

.region::before {
  content: "";
  position: absolute;
  inset: -20% -30% auto -30%;
  height: 150%;
  z-index: -1;
  pointer-events: none;
  background: repeating-linear-gradient(
    74deg,
    rgba(199, 168, 255, 0.11) 0 1px,
    transparent 1px 26px
  );
  -webkit-mask-image: linear-gradient(180deg, #000 0%, transparent 74%);
          mask-image: linear-gradient(180deg, #000 0%, transparent 74%);
}

/* Stacked, not side by side: a 30px badge next to a two-line region name in
   118px of card leaves the name three characters a line. */
.region__head {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
}

.region__badge {
  flex: none;
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  border: 1px solid rgba(169, 123, 255, 0.4);
  background: rgba(169, 123, 255, 0.14);
  color: var(--accent);
}
.region__badge svg { width: 15px; height: 15px; }

.region__name {
  font-family: var(--f-nav);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 1px;
  text-transform: uppercase;
  line-height: 1.3;
  color: var(--text);
}

/* Scrolls inside the card rather than stretching it: Africa carries a dozen
   countries and Oceania two, and a carousel whose cards are different heights
   reads as broken. The cap is generous enough that most lists never reach it. */
.region__list {
  flex: 1 1 auto;
  max-height: 232px;
  overflow-y: auto;
  margin: 0;
  padding: 0;
  list-style: none;
  scrollbar-width: thin;
}

.region__country {
  position: relative;
  padding: 3px 0 3px 12px;
  font-size: 13px;
  line-height: 1.3;
  color: var(--text-dim);
}
.region__country::before {
  content: "";
  position: absolute;
  left: 0;
  top: 9px;
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: rgba(169, 123, 255, 0.75);
}

/* A country with its own website links to it. The resting state is the plain
   entry it was before — same colour, no underline — because a card of a dozen
   accented links reads as a menu, and the comp's list is a list. What marks it
   as clickable is the chevron, faint until the row is hovered.

   `display: inline`, not the inline-flex this wants to be: "Central African
   Republic" has to wrap inside a 118px card, and a flex box would push it out
   of the column instead. So the chevron is an inline svg that follows the last
   word, exactly as .pathway__arrow does. */
.region__link {
  color: inherit;
  text-decoration: none;
  transition: color 0.2s var(--ease);
}
/* The name's last word and the chevron travel together — see CountryName in
   RegionDirectory. Without it the chevron wrapped onto a line by itself on these
   narrow cards, which is what the client saw. */
.region__tail { white-space: nowrap; }

.region__link svg {
  /* `display: inline-block` because site.css's reset makes every svg a block,
     and a block chevron is a chevron on its own line — which is what it has been
     doing under every country name since this card shipped. The
     `vertical-align` below was written for an inline box and never applied
     until now. Client note, August 21, 2026. */
  display: inline-block;
  width: 10px;
  height: 10px;
  margin-left: 4px;
  vertical-align: -1px;
  color: var(--accent);
  opacity: 0.45;
  transition: opacity 0.2s var(--ease), transform 0.2s var(--ease);
}
.region__link:hover,
.region__link:focus-visible {
  color: var(--text);
}
.region__link:hover svg,
.region__link:focus-visible svg {
  opacity: 1;
  transform: translateX(2px);
}

/* ---- the presence map ---------------------------------------------------
   Lit silhouettes on the page's own ground, per docs/visuals/movepage.png: the
   land is the dark shape, the backdrop shows through around it, and what makes
   the continents legible is the rim along their coastlines and the wash across
   them rather than a fill lighter than the page. The sea plate this used to sit
   on is gone with it — see the note in WorldMap.tsx.
   ------------------------------------------------------------------------ */

/* Width is picked by the *height* the viewport has left, which is what "title
   and map in one screen" actually asks for. The viewBox is 1000x394, so a unit
   of height buys 2.326 units of width (the viewBox is 1000x430 now — 394 of
   projection plus 36 for the horizon under it), and 296px is the height this
   hero has already spent by the time the map starts: 250 measured for the
   header, title, one-line lede, hint and their margins, plus the 46 below the
   map — its own margin and the panel's bottom padding — so what clears the fold
   is the section, not just the map inside it. The nesting
   matters — the inner min/max picks a width from the viewport and holds it
   between 520 and 1140, the outer min then lets the container win on a narrow
   screen.

   1140 is the comp's own map width: 79% of the page, measured off
   docs/visuals/movepage.png scaled to 1440. That is wider than the 1180 this
   started at, not narrower — the map's problem was its height, and the 150px
   the spacing above gave back is what pays for the extra width. */
.worldmap {
  width: min(100%, max(520px, min(1140px, calc((100svh - 296px) * 2.326))));
  margin: 8px auto 4px;
}

.worldmap__svg {
  display: block;
  width: 100%;
  height: auto;
  overflow: visible;      /* the halo and the pin glow sit proud of the viewBox */
}

/* Faint enough to read as depth rather than as a grid; the mask in the markup
   is what keeps them from redrawing the plate's rectangle. */
.worldmap__grid line {
  stroke: rgba(169, 123, 255, 0.13);
  stroke-width: 1;
}

/* The halo: the land blurred and drawn under itself. It is the only thing
   holding the silhouette off the section now, so it is a hair brighter than it
   looks like it should need. */
.worldmap__halo {
  fill: rgba(146, 100, 252, 0.58);
}

/* The silhouette. Darker than the section at the top, a step above it at the
   bottom; the rim is a gradient too, so a coastline is brightest where the
   light is. Stroke over fill on one path — the stroke paints last, so the
   coastline stays crisp at 1140px and does not close up at 520. */
.worldmap__land {
  fill: url(#worldmap-land);
  stroke: url(#worldmap-rim);
  stroke-width: 1.05;
  stroke-linejoin: round;
}

.worldmap__specular {
  fill: url(#worldmap-specular);
  mix-blend-mode: screen;
}

/* The horizon. All three strokes take the same gradient, so they brighten and
   fade together along the curve; only weight and opacity separate them. The
   bloom is wide and blurred hard, which is the atmosphere; the line is thin and
   blurred barely, which is the edge of the planet. */
.worldmap__limbs { fill: none; stroke: url(#worldmap-limb); }

/* The lit surface: wide, soft and dim. It is what stops the horizon reading as
   a bright line ruled across empty space. */
.worldmap__planet {
  stroke-width: 30;
  opacity: 0.24;
}

.worldmap__limb-bloom {
  stroke-width: 13;
  opacity: 0.55;
}
.worldmap__limb {
  stroke-width: 2.1;
  stroke-linecap: round;
}
.worldmap__trail {
  stroke-width: 1.1;
  stroke-linecap: round;
}

/* Gold, against all that purple: --c-peach is the site's warm accent and the
   only hue on this page that is not a shade of it. */
/* Gold markers, the shape the globe's pins wear. No stroke: at 12 units tall an
   outline closes the hole in the pin's head and turns it into a blob. The dark
   shadow that used to separate them from pale land does nothing against a dark
   silhouette, so it is a warm bloom now — the pins are the lit thing on the
   map, the way they are in the comp. */
.worldmap__pin {
  fill: #F0A93F;
  filter: drop-shadow(0 0 2.5px rgba(255, 176, 92, 0.75));
}

/* Core chapters are the ones the homepage globe gives a rail card to, so the
   map keeps the same hierarchy rather than reading as 84 equal markers. */
.worldmap__pin--core {
  fill: var(--c-peach);
  filter: drop-shadow(0 0 5px rgba(255, 188, 125, 0.95))
          drop-shadow(0 0 1.5px rgba(255, 214, 168, 0.9));
}

@media (prefers-reduced-motion: no-preference) {
  .worldmap__pin { transition: r 0.25s var(--ease); }
}

@media (max-width: 620px) {
  .worldmap { width: 100%; margin-top: 20px; }
  /* Markers hold their presence as the map shrinks. Scaling about the tip
     keeps each one standing on its own coordinate.

     The origin is the pin's own tip in viewBox units, handed down per pin by
     WorldMap.tsx. `transform-box: fill-box` reads as the obvious way to say
     "about my own bottom-centre" and does not work here: on a <use> the scale
     lands about the svg's user-space origin instead, so a pin's position is
     multiplied by the scale factor along with its size. At 1.4 that walked
     every marker away from its country and pushed the eastmost 15 clean off a
     390px viewport. */
  .worldmap__pin {
    transform: scale(1.4);
    transform-box: view-box;
    transform-origin: var(--pin-tip-x) var(--pin-tip-y);
  }
  .worldmap__pin--core { transform: scale(1.2); }
}

/* ---- cards -------------------------------------------------------------- */

.movement {
  position: relative;
  flex: 0 0 clamp(214px, 20vw, 292px);
  aspect-ratio: 3 / 4.05;
  scroll-snap-align: start;
  border: 1px solid rgba(169, 123, 255, 0.4);
  border-radius: 18px;
  overflow: hidden;
  background: #0C0718;
  transition: border-color 0.3s var(--ease), transform 0.3s var(--ease),
              box-shadow 0.3s var(--ease);
}
.movement:hover,
.movement:focus-visible {
  border-color: var(--accent);
  transform: translateY(-5px);
  box-shadow: 0 0 0 1px rgba(169, 123, 255, 0.4), 0 20px 48px rgba(0, 0, 0, 0.6);
}

.movement__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.7s var(--ease);
}
.movement:hover .movement__img { transform: scale(1.06); }

.movement__foot {
  position: absolute;
  inset: auto 0 0 0;
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 12px;
  padding: 64px 18px 20px;
  background: linear-gradient(180deg, transparent, rgba(6, 3, 15, 0.86) 52%, #06030F 100%);
}

/* Play badge — only the YouTube card carries one (`play` in the data). */
.movement__play {
  position: absolute;
  left: 50%;
  top: 44%;
  display: grid;
  place-items: center;
  width: 54px;
  height: 54px;
  margin: -27px 0 0 -27px;
  border: 1px solid rgba(255, 255, 255, 0.7);
  border-radius: 50%;
  background: rgba(20, 12, 38, 0.62);
  backdrop-filter: blur(3px);
  color: #fff;
  transition: background 0.3s var(--ease), transform 0.3s var(--ease);
}
.movement__play svg { width: 20px; height: 20px; margin-left: 3px; }
.movement:hover .movement__play,
.movement:focus-visible .movement__play {
  background: rgba(75, 41, 123, 0.85);
  transform: scale(1.08);
}

.movement__text { min-width: 0; }

.movement__title {
  display: block;
  font-family: var(--f-display);
  font-size: clamp(17px, 1.4vw, 21px);
  font-weight: 800;
  line-height: 1.2;
  letter-spacing: -0.4px;
  color: #fff;
  text-wrap: balance;
}

/* Venue names inside the "Our Venues" card. */
.movement__list {
  display: block;
  margin-top: 9px;
}
/* No bullet glyph: the venue names read as a plain list under the card title.
   They used to carry a purple "•", which on a card that is already a link with
   an arrow button made the group look like navigation inside navigation. The
   names themselves stay — `items` in the CMS still feeds them. */
.movement__item {
  display: block;
  font-size: 12.5px;
  line-height: 1.5;
  color: rgba(255, 255, 255, 0.68);
}

/* Looks like a button; it is a span — the whole card is the link. */
.movement__go {
  flex: none;
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  border: 1px solid rgba(255, 255, 255, 0.55);
  border-radius: 50%;
  color: #fff;
  transition: background 0.3s var(--ease), border-color 0.3s var(--ease),
              transform 0.3s var(--ease);
}
.movement__go svg { width: 17px; height: 17px; }
.movement:hover .movement__go,
.movement:focus-visible .movement__go {
  background: var(--c-purple);
  border-color: var(--accent);
  transform: translateX(3px);
}

@media (max-width: 720px) {
  .carousel__nav { display: none; }   /* swipe is the gesture here */
  .movement { flex-basis: 66vw; }
}


/* --------------------------------------------------------------------------
   Placeholder pages
   -------------------------------------------------------------------------- */
.stub {
  padding-top: 92px;
  padding-bottom: 88px;
  background:
    radial-gradient(70% 55% at 50% 0%, rgba(75, 41, 123, 0.26), transparent 64%),
    var(--bg);
}

.stub__eyebrow {
  font-family: var(--f-nav);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 3.4px;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 14px;
}

.stub .panel__lede { margin-bottom: 34px; }
.stub__lede strong { color: var(--text); }

.stub__links {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 14px;
}

/* ==========================================================================
   THE LIGHT DESIGN — the sections a country page is made of
   ==========================================================================

   The other half of the block appended to site.css; read that one first — it
   carries the tokens, the scoping mechanism and the two guards that keep HQ's
   bytes untouched. The same two rules apply here: nothing above this comment
   moves, and every selector below carries the scope token.

     diff <(git show HEAD:public/assets/css/home.css) \
          <(head -n 1576 public/assets/css/home.css)
     sed -n '1577,1818p' public/assets/css/home.css \
       | grep -nE '^[^@ /}].*\{' | grep -v 'site-theme'

   That range stops at 1818 rather than at the end of the file because a second
   appended section follows this one, for `.country-hero` — a component that did
   not exist before this round. Unscoped selectors are allowed there and nowhere
   else; see its own header.

   What is here is only what the tokens could not reach. Most of this stylesheet
   came right the moment --bg/--surface/--text flipped: `.section`, `.prose`,
   `.section-title`, `.track`, `.region__*` type, the events list, every heading
   scale. What is left is the ornament — the purple washes, the arcs, the glows
   and the scrims — which was written as literal rgba() over a token, so it
   survives the flip and has to be re-authored at light alphas.

   Two families are deliberately left alone, and both are photographs rather
   than surfaces:

     - **Video-player chrome.** `.player__*`, `.track__length`, the letterbox
       grounds and the control scrims are dark because a video is dark. They read
       correctly on any page colour.
     - **Card scrims over imagery.** `.movement__foot` and `.pathway__media::after`
       fade a photograph into the card's own foot, and the type on them is white.
       Only the part of each that shows *through* to the card ground is adjusted
       below.
   -------------------------------------------------------------------------- */

/* ---- the panel shell ---------------------------------------------------- */

/* Every section on a country page sits in one of these, and so does every
   inherited page body. The wash is what made the flip look half-done: --bg-alt
   went white underneath a 0.22-alpha purple radial that stayed. */
body:has([data-site-theme="light"]) .panel {
  background:
    radial-gradient(120% 120% at 85% 8%, rgba(107, 52, 199, 0.07), transparent 58%),
    var(--bg-alt);
  border-color: var(--border);
}
body:has([data-site-theme="light"]) .panel::after {
  background:
    radial-gradient(60% 90% at 100% 40%, rgba(107, 52, 199, 0.05), transparent 70%);
}

/* ---- shared ornament: medallion, seam, gradient heading ----------------- */

/* The medallion is a lit ring with a white star punched out of it. On white the
   ring keeps its purple and the star has to become ink, or it disappears. */
body:has([data-site-theme="light"]) .panel__medallion {
  border-color: rgba(107, 52, 199, 0.45);
  background: radial-gradient(circle, rgba(107, 52, 199, 0.16), transparent 70%);
  box-shadow: 0 6px 18px rgba(26, 16, 38, 0.10);
}
body:has([data-site-theme="light"]) .panel__medallion::before { background: var(--accent); }
body:has([data-site-theme="light"]) .panel__medallion::after {
  background: linear-gradient(90deg,
    transparent 0%, rgba(107, 52, 199, 0.22) 34%, transparent 46%,
    transparent 54%, rgba(107, 52, 199, 0.22) 66%, transparent 100%);
}
body:has([data-site-theme="light"]) .panel__seam {
  background: linear-gradient(90deg, transparent, rgba(107, 52, 199, 0.38), transparent);
}
body:has([data-site-theme="light"]) .panel__seam::after {
  box-shadow: 0 0 8px rgba(107, 52, 199, 0.55);
}

/* The accent half of a heading — "You Belong in *Jubilee*" — is a gradient
   clipped to the text, and both of its stops are pale. It does not merely look
   wrong on white, it vanishes: #E9DCFF is 1.1:1 there. A slightly darker pair of
   the same hue keeps the two-tone effect and clears AA. */
body:has([data-site-theme="light"]) .panel__title--center em {
  background: linear-gradient(180deg, #7A45D8, #5A22B0);
  -webkit-background-clip: text;
  background-clip: text;
}

/* ---- You Belong in Jubilee --------------------------------------------- */

body:has([data-site-theme="light"]) .pathways-panel {
  background:
    radial-gradient(78% 60% at 50% 0%, rgba(107, 52, 199, 0.08), transparent 62%),
    var(--bg);
}
body:has([data-site-theme="light"]) .pathways-panel::before {
  border-color: rgba(107, 52, 199, 0.14);
  box-shadow: 0 0 0 26px rgba(107, 52, 199, 0.03);
}

/* The card was a dark gradient with a photograph on top; on white it is a white
   card with a shadow, so the elevation moves from the fill to the shadow. */
body:has([data-site-theme="light"]) .pathway {
  border-color: var(--border);
  background: #FFFFFF;
  box-shadow: 0 8px 22px rgba(26, 16, 38, 0.07);
}
body:has([data-site-theme="light"]) .pathway:hover,
body:has([data-site-theme="light"]) .pathway:focus-visible {
  border-color: var(--accent);
  box-shadow: 0 0 0 1px rgba(107, 52, 199, 0.22), 0 22px 44px rgba(26, 16, 38, 0.14);
}
/* The photo faded into near-black at the bottom of its own frame. Against a
   white card body that read as a broken image, which is the single most visible
   thing the token flip alone would have left behind. */
body:has([data-site-theme="light"]) .pathway__media::after {
  background: linear-gradient(180deg, transparent 38%, rgba(255, 255, 255, 0.72) 78%, #FFFFFF 100%);
}
body:has([data-site-theme="light"]) .pathway__icon {
  border-color: rgba(107, 52, 199, 0.45);
  background: rgba(255, 255, 255, 0.92);
}
body:has([data-site-theme="light"]) .pathway:hover .pathway__icon {
  background: var(--accent);
  color: #FFFFFF;
  box-shadow: 0 8px 20px rgba(107, 52, 199, 0.30);
}

/* ---- Around the Jubilee Movement --------------------------------------- */

body:has([data-site-theme="light"]) .around {
  background:
    radial-gradient(75% 55% at 50% 0%, rgba(107, 52, 199, 0.08), transparent 62%),
    var(--bg);
}
body:has([data-site-theme="light"]) .around::before {
  border-color: rgba(107, 52, 199, 0.14);
  box-shadow: 0 0 0 26px rgba(107, 52, 199, 0.03);
}
body:has([data-site-theme="light"]) .carousel__nav {
  border-color: rgba(107, 52, 199, 0.40);
  background: #FFFFFF;
  color: var(--accent);
  box-shadow: 0 6px 16px rgba(26, 16, 38, 0.10);
}
body:has([data-site-theme="light"]) .carousel__nav:hover:not(:disabled) {
  background: var(--accent);
  border-color: var(--accent);
  color: #FFFFFF;
}
body:has([data-site-theme="light"]) .carousel__dot { background: rgba(26, 16, 38, 0.20); }
body:has([data-site-theme="light"]) .carousel__dot:hover:not(:disabled) {
  background: rgba(26, 16, 38, 0.40);
}
body:has([data-site-theme="light"]) .carousel__dot.is-active { background: var(--accent); }

/* The card itself is a photograph with white type over its own scrim, so it is
   already right. Only what shows around the photograph changes: the letterbox
   ground behind an image that does not fill the 3/4.05 box, and the edge. */
body:has([data-site-theme="light"]) .movement {
  border-color: var(--border);
  background: #EFE9F8;
  box-shadow: 0 8px 22px rgba(26, 16, 38, 0.07);
}
body:has([data-site-theme="light"]) .movement:hover,
body:has([data-site-theme="light"]) .movement:focus-visible {
  border-color: var(--accent);
  box-shadow: 0 0 0 1px rgba(107, 52, 199, 0.22), 0 22px 44px rgba(26, 16, 38, 0.14);
}

/* ---- Upcoming Events --------------------------------------------------- */

/* Not inherited by a country — a country opts in by writing its own heading —
   but the moment one does, this band is the section that would look most wrong.
   Its whole purpose on dark is to be *lighter* than its neighbours so a
   schedule with no photography reads as a calendar; on white that inverts, and
   the band becomes the one tinted surface on the page. */
body:has([data-site-theme="light"]) .events-panel {
  border-color: rgba(107, 52, 199, 0.24);
  background:
    radial-gradient(120% 120% at 85% 8%, rgba(107, 52, 199, 0.10), transparent 60%),
    linear-gradient(180deg, #EDE4FB 0%, #E4D8F7 100%);
}
body:has([data-site-theme="light"]) .event { border-left-color: rgba(107, 52, 199, 0.55); }
body:has([data-site-theme="light"]) .event__month {
  background: rgba(107, 52, 199, 0.12);
  color: #4B297B;
}

/* ---- New Releases ------------------------------------------------------ */

/* `.track` is fully tokenised, so the tile itself came free. What did not is the
   empty-frame case: a release with no artwork showed a --surface box, which is
   now white on white. */
body:has([data-site-theme="light"]) .track { box-shadow: 0 6px 18px rgba(26, 16, 38, 0.06); }
body:has([data-site-theme="light"]) .track__media { background: #EFE9F8; }
body:has([data-site-theme="light"]) .track--silent:hover { border-color: var(--border); }

/* ---- the inherited /movement page -------------------------------------- */

body:has([data-site-theme="light"]) .movement-hero__globe {
  background: rgba(107, 52, 199, 0.12);
}

/* The map is the biggest single thing the token flip cannot reach: its land is a
   near-black gradient with a pale rim, drawn to glow out of a dark section. On
   white the silhouette has to become the dark shape and the halo has to stop
   being a light source. The gradients themselves are declared in WorldMap.tsx,
   so what is adjustable from here is the grid, the halo and the rim's opacity —
   which is enough, because the land reads as a solid mass either way. */
body:has([data-site-theme="light"]) .worldmap__grid line {
  stroke: rgba(75, 41, 123, 0.10);
}
body:has([data-site-theme="light"]) .worldmap__halo {
  fill: rgba(107, 52, 199, 0.16);
}
body:has([data-site-theme="light"]) .worldmap__land {
  stroke: rgba(75, 41, 123, 0.35);
}
/* The pins stay gold. They are the one warm colour in the design and the only
   thing on the map that is not purple — that reads as well on white as on
   near-black, and their drop-shadows are what carry them over the land. */

/* A region card is text, not a photograph, so it becomes a white card. The
   three-layer purple gradient and the hairline overlay both go. */
body:has([data-site-theme="light"]) .region {
  border-color: var(--border);
  background: #FFFFFF;
  box-shadow: 0 8px 22px rgba(26, 16, 38, 0.07);
}
body:has([data-site-theme="light"]) .region::before { opacity: 0.35; }
body:has([data-site-theme="light"]) .region__badge {
  border-color: rgba(107, 52, 199, 0.40);
  background: rgba(107, 52, 199, 0.10);
}

/* ---- placeholder pages ------------------------------------------------- */

body:has([data-site-theme="light"]) .stub {
  background:
    radial-gradient(70% 55% at 50% 0%, rgba(107, 52, 199, 0.09), transparent 64%),
    var(--bg);
}

/* ==========================================================================
   NEW IN THIS ROUND — the country hero banner
   ==========================================================================

   Selectors that did not exist before August 24, 2026, so they are appended
   rather than woven in: nothing above the light block moves, and this section is
   the one place below it where an unscoped selector is allowed. Every rule here
   names `.country-hero*`, which renders on nothing but a country's landing page
   (CountryHero.tsx).

   The base rules are the dark design, and the light overrides follow at the
   foot. That order is on purpose even though every country is light today: a
   country switched to `theme: dark` in /admin has to get a finished hero, not a
   half-styled one.
   -------------------------------------------------------------------------- */

.country-hero {
  position: relative;
  isolation: isolate;
  display: grid;
  align-items: center;
  overflow: hidden;
  min-height: clamp(420px, 54svh, 620px);
  /* The header is `--solid` and static on a country page, so the banner starts
     below it rather than under it — no top padding for a fixed bar to clear. */
  padding: clamp(48px, 6vw, 88px) clamp(20px, 5vw, 92px);
  color: var(--c-white);
  background: var(--bg-deep) center/cover no-repeat;
}

/* Weighted to the side the type is on, not spread evenly: the heading block sits
   left in all four of the client's mockups, and an even veil would dim the
   photograph everywhere to protect one corner of it. */
.country-hero::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    linear-gradient(90deg, rgba(6, 3, 15, 0.88) 0%, rgba(6, 3, 15, 0.62) 42%,
                    rgba(6, 3, 15, 0.24) 72%, rgba(6, 3, 15, 0.12) 100%);
}

.country-hero__inner {
  position: relative;
  max-width: 620px;
}

.country-hero__title {
  font-family: var(--f-display);
  font-size: clamp(38px, 5.6vw, 74px);
  font-weight: 800;
  line-height: 1.03;
  letter-spacing: -1.6px;
  text-transform: uppercase;
  text-wrap: balance;
}
/* The country's own name, picked out — `hero.headingAccent`. */
.country-hero__title em {
  font-style: normal;
  color: var(--accent);
}

/* The movement's line, set as a caption rather than a subheading: it is the same
   words HQ's globe carries, and on that hero they are also small and tracked. */
.country-hero__verse {
  margin-top: 20px;
  font-family: var(--f-nav);
  font-size: clamp(11px, 1.05vw, 13px);
  font-weight: 700;
  letter-spacing: 2.4px;
  text-transform: uppercase;
}
.country-hero__verse span { opacity: 0.66; }

.country-hero__lede {
  margin-top: 16px;
  font-size: 16.5px;
  line-height: 1.65;
  max-width: 46ch;
  color: rgba(255, 255, 255, 0.84);
}

/* ---- the chapter labels ------------------------------------------------- */

.country-hero__pins {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

/* Positioned from its own centre, so a percentage places the label rather than
   its top-left corner — the difference shows on the ones near an edge. */
.country-hero__pin {
  position: absolute;
  transform: translate(-50%, -50%);
  display: inline-flex;
  align-items: center;
  gap: 9px;
  padding: 7px 15px 7px 8px;
  border: 1px solid rgba(169, 123, 255, 0.42);
  border-radius: 999px;
  background: rgba(12, 7, 24, 0.8);
  backdrop-filter: blur(4px);
  font-size: 13px;
  font-weight: 600;
  white-space: nowrap;
}
.country-hero__pin-dot {
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: var(--accent);
  color: #FFFFFF;
}
.country-hero__pin-dot svg { width: 13px; height: 13px; }

@media (max-width: 860px) {
  /* Four labels placed for a 1440px frame collide at phone width, and they are
     decoration — the same chapters are a real list on Find Your Chapter. So they
     go rather than being re-placed for a viewport the positions were not chosen
     against. */
  .country-hero__pins { display: none; }
  .country-hero::before {
    background: linear-gradient(180deg, rgba(6, 3, 15, 0.62) 0%, rgba(6, 3, 15, 0.86) 100%);
  }
}

/* ---- the light design -------------------------------------------------- */

/* The mockups' banner is a bright photograph with near-black type on it, which is
   the opposite construction to `.page-hero` and to the dark hero above: the veil
   lifts the picture toward white on the type's side instead of darkening it. */
body:has([data-site-theme="light"]) .country-hero {
  color: var(--text);
  background-color: #EFE9F8;
}
body:has([data-site-theme="light"]) .country-hero::before {
  background:
    linear-gradient(90deg, rgba(255, 255, 255, 0.92) 0%, rgba(255, 255, 255, 0.72) 40%,
                    rgba(255, 255, 255, 0.28) 70%, rgba(255, 255, 255, 0.08) 100%);
}
body:has([data-site-theme="light"]) .country-hero__lede { color: var(--text-dim); }
body:has([data-site-theme="light"]) .country-hero__pin {
  border-color: rgba(75, 41, 123, 0.16);
  background: rgba(255, 255, 255, 0.94);
  color: var(--text);
  box-shadow: 0 8px 20px rgba(26, 16, 38, 0.16);
}

@media (max-width: 860px) {
  body:has([data-site-theme="light"]) .country-hero::before {
    background: linear-gradient(180deg, rgba(255, 255, 255, 0.72) 0%, rgba(255, 255, 255, 0.94) 100%);
  }
}

/* ---- Find Your Chapter: the chapter list -------------------------------- */

/* A country's own chapters, on the one page it has that headquarters does not
   (FindYourChapterBody). A list and not a card grid on purpose: 65 of the 67
   countries have a single chapter today, and one row of a list reads as a list
   where one card in a grid reads as a mistake. */
.chapter-list {
  display: grid;
  gap: 12px;
  max-width: 620px;
  margin-inline: auto;
  list-style: none;
  padding: 0;
}

.chapter-list__row {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 18px 22px;
  border: 1px solid var(--border-soft);
  border-radius: 14px;
  background: var(--surface);
}

.chapter-list__pin {
  flex: none;
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  border: 1px solid rgba(169, 123, 255, 0.4);
  background: rgba(169, 123, 255, 0.14);
  color: var(--accent);
}
.chapter-list__pin svg { width: 17px; height: 17px; }

.chapter-list__text { display: grid; gap: 3px; min-width: 0; }
.chapter-list__city {
  font-family: var(--f-display);
  font-size: 19px;
  font-weight: 700;
  color: var(--text);
}
.chapter-list__region {
  font-family: var(--f-nav);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--text-faint);
}

body:has([data-site-theme="light"]) .chapter-list__row {
  border-color: var(--border);
  box-shadow: 0 6px 18px rgba(26, 16, 38, 0.06);
}
body:has([data-site-theme="light"]) .chapter-list__pin {
  border-color: rgba(107, 52, 199, 0.35);
  background: rgba(107, 52, 199, 0.10);
}
