/* ============================================================
   IShowSpeed Foundation — main.css
   Mobile-first (390px reference). Tokens are layered:
     1. Primitives  — raw values
     2. Semantics   — purpose-named, alias primitives
     3. Component   — defined inline next to component rules
   Change a primitive to ripple a theme; reach for semantics in
   component code so intent reads cleanly.
   ============================================================ */


/* ---------- 1. TOKENS ---------- */

:root {
  /* --- Primitive: color --- */
  --color-black:        #000;
  --color-white:        #fff;
  --color-green-500:    #a9f42f;
  --color-green-300:    #d8e46e;
  --color-gray-900:     #202020;
  --color-gray-800:     #282828;

  /* --- Primitive: spacing (4px scale) --- */
  --space-1:  4px;
  --space-2:  8px;
  --space-3:  12px;
  --space-4:  16px;
  --space-5:  20px;
  --space-6:  24px;
  --space-7:  28px;
  --space-8:  32px;
  --space-9:  36px;

  /* --- Primitive: radius --- */
  --radius-sm:    8px;
  --radius-md:    10px;
  --radius-lg:    12px;
  --radius-pill:  999px;

  /* --- Primitive: type families --- */
  --font-display: "Asap Condensed", system-ui, -apple-system, sans-serif;
  --font-body:    "Manrope", system-ui, -apple-system, sans-serif;

  /* --- Primitive: font size — body scale (prose, UI, labels) --- */
  --fs-body-sm:  16px;  /* button, tag, tracker label, goal subtitle */
  --fs-body-md:  18px;  /* default body copy */
  --fs-body-lg:  20px;  /* attribution */
  --fs-body-xl:  26px;  /* pull quote */

  /* --- Primitive: font size — display scale (headlines, wordmarks) --- */
  --fs-display-xs:  25px;  /* header wordmark */
  --fs-display-sm:  48px;  /* tracker amount */
  --fs-display-md:  50px;  /* hero headline */
  --fs-display-lg:  56px;  /* "The Africa Fund" */

  /* --- Primitive: font weight --- */
  --fw-medium:     500;
  --fw-semibold:   600;
  --fw-bold:       700;
  --fw-extrabold:  800;

  /* --- Primitive: line height (unitless) --- */
  --lh-display:  1;   /* hero headline */
  --lh-flat:     1;      /* aligned wordmarks / tags */
  --lh-button:   1.25;   /* button, attribution, tracker label */
  --lh-quote:    1.4;    /* pull quote, tracker goal */
  --lh-body:     1.45;    /* default prose */

  /* --- Primitive: letter spacing --- */
  --tracking-default:   -0.01em;  /* body copy */
  --tracking-tight:     -0.03em;  /* large body, attribution */
  --tracking-tighter:   -0.04em;  /* display amounts, tags */
  --tracking-tightest:  -0.05em;  /* display headlines */
  --tracking-logo:      -0.06em;  /* header wordmark */

  /* --- Semantic: surface & text --- */
  --bg:              var(--color-black);
  --fg:              var(--color-white);
  --accent:          var(--color-green-500);
  --accent-soft:     var(--color-green-300);

  --text-strong:     rgba(255, 255, 255, 1);
  --text-muted:      rgba(255, 255, 255, 0.7);
  --text-subtle:     rgba(255, 255, 255, 0.6);
  --text-faint:      rgba(255, 255, 255, 0.5);
  --text-logo:       rgba(255, 255, 255, 0.85);
  --text-on-card:    rgba(255, 255, 255, 0.83);
  --text-on-track:   rgba(255, 255, 255, 0.4);
  --text-card-lede:  rgba(255, 255, 255, 0.64);

  --surface-card:    var(--color-gray-900);
  --surface-inner:   rgba(0, 0, 0, 0.6);
  --surface-track:   var(--color-gray-800);

  --border-subtle:   rgba(255, 255, 255, 0.07);
  --border-fainter:  rgba(255, 255, 255, 0.08);
  --border-track:    rgba(255, 255, 255, 0.29);

  --divider:         rgba(255, 255, 255, 0.07);

  /* --- Layout --- */
  --page-gutter:    var(--space-6);   /* 24px */
  --content-max:    342px;

  /* --- Motion: easing --- */
  --ease-out-soft:     cubic-bezier(0.16, 1, 0.3, 1);   /* entrance settle */
  --ease-in-out-snap:  cubic-bezier(0.65, 0, 0.35, 1);  /* write-on cubic */

  /* --- Motion: live pulse (campaign tag) ---
     Ring stagger is derived from the total cycle (½ cycle), so all
     animations stay locked in sync no matter what you tweak.
       • --pulse-duration  → one ring's pulse animation time
       • --pulse-rest      → silent gap added between consecutive pulses
     Total cycle = duration + rest. Set rest to 0 for a continuous
     heartbeat; raise it for a more deliberate pulse-pause-pulse beat. */
  --pulse-duration:            3.7s;
  --pulse-rest:                1.2s;
  --pulse-cycle:               calc(var(--pulse-duration) + var(--pulse-rest));
  --pulse-ring-ease:           var(--ease-out-soft);
  --pulse-ring-delay:          calc(var(--pulse-cycle) / 2);
  --pulse-ring-start-opacity:  0.35;
  --pulse-ring-max-scale:      4.2;
  --pulse-icon-scale-peak:     1.42;
  --pulse-icon-scale-dip:      0.96;
  --pulse-icon-opacity-dip:    0.65;
  --pulse-icon-glow-blur:      20px;
  --pulse-icon-glow-color:     rgba(169, 244, 47, 0.55);
}


/* ---------- 2. RESET ---------- */

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

html, body {
  margin: 0;
  padding: 0;
}

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

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

p { margin: 0; }

h1, h2, h3, h4 { margin: 0; font-weight: var(--fw-extrabold); }


/* ---------- 3. BASE ---------- */

body {
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font-body);
  font-size: var(--fs-body-md);
  font-weight: var(--fw-medium);
  line-height: var(--lh-body);
  letter-spacing: var(--tracking-default);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}


/* ---------- 4. LAYOUT ---------- */

.page {
  position: relative;
  max-width: 390px;
  margin: 0 auto;
}

.divider {
  width: 100%;
  height: 1px;
  background: var(--divider);
  border: 0;
  margin: 0;
}

/* Vertical side rails (Figma Vector 29 + 30): start at the second
   horizontal divider and run to the bottom of the page. */
.rails {
  position: relative;
}
.rails::before,
.rails::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  width: 1px;
  background: var(--divider);
  pointer-events: none;
}
.rails::before { left: var(--page-gutter); }
.rails::after  { right: var(--page-gutter); }


/* ---------- 5. HEADER ---------- */

.site-header {
  padding: var(--page-gutter) var(--space-5);
}
.site-header__logo {
  position: relative;
  width: 189px;
  height: 48px;
  font-family: var(--font-body);
  font-weight: var(--fw-extrabold);
  font-size: var(--fs-display-xs);
  line-height: 24px;
  letter-spacing: var(--tracking-logo);
  color: var(--text-logo);
}
.site-header__line {
  display: block;
}
.site-header__line--indent {
  padding-left: 56px;
}
.site-header__mark {
  position: absolute;
  top: 27.6px;
  left: 0;
  height: 37px;
}


/* ---------- 6. HERO ---------- */

.hero {
  padding: var(--space-5) var(--page-gutter) var(--space-9);
}
.hero__stack {
  display: flex;
  flex-direction: column;
  gap: var(--space-9); /* 36px between block + CTA */
}
.hero__media {
  display: flex;
  flex-direction: column;
  gap: var(--space-6); /* 24 */
}
.hero__image {
  width: 100%;
  height: 189px;
  border-radius: var(--radius-sm);
  object-fit: cover;
  object-position: center 30%;
}
.hero__copy {
  display: flex;
  flex-direction: column;
  gap: var(--space-5); /* 20 */
}

.hero__title {
  position: relative;
  font-family: var(--font-display);
  font-weight: var(--fw-extrabold);
  font-size: var(--fs-display-md);
  line-height: 0.91;
  letter-spacing: var(--tracking-tightest);
  color: var(--text-strong);
  width: 257px;
  height: 89px;
}
.hero__title-line {
  display: block;
}
.hero__title-play {
  position: absolute;
  top: 48px;
  left: 148px;
  width: 97px;
  height: 54px;
  pointer-events: none;
}

.hero__lede {
  font-size: var(--fs-body-md);
  line-height: var(--lh-body);
  letter-spacing: var(--tracking-default);
  color: var(--text-strong);
  width: 324px;
  max-width: 100%;
}
.hero__lede-muted {
  color: var(--text-subtle);
}


/* ---------- 7. QUOTE ---------- */

.quote {
  padding: var(--space-8) var(--page-gutter) var(--space-9);
  display: flex;
  flex-direction: column;
  gap: var(--space-5); /* default rhythm; specific gaps below */
}
.quote__mark {
  width: 32px;
  height: 30px;
}
.quote__mark--close {
  align-self: flex-end;
  transform: rotate(180deg);
  margin-top: var(--space-5);
}

.quote__text {
  font-family: var(--font-body);
  font-weight: var(--fw-medium);
  font-size: var(--fs-body-xl);
  line-height: var(--lh-quote);
  letter-spacing: var(--tracking-tight);
  color: var(--text-strong);
  width: 278px;
  max-width: 100%;
  margin-top: var(--space-5); /* 20px between quote-mark and text */
}

.quote__image {
  width: 100%;
  height: 144px;
  border-radius: var(--radius-sm);
  object-fit: cover;
  margin-top: var(--space-5); /* 20px gap above + below the image */
}

.quote__attribution {
  font-family: var(--font-body);
  font-weight: var(--fw-medium);
  font-size: var(--fs-body-lg);
  line-height: var(--lh-button);
  letter-spacing: var(--tracking-tight);
  color: var(--text-faint);
  text-align: right;
  margin-top: var(--space-8); /* 32px above attribution */
}


/* ---------- 8. AFRICA FUND ---------- */

.campaign {
  padding: var(--space-8) var(--page-gutter) var(--space-9);
}

.campaign__tag {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2); /* 6 → use 8 from scale; visual diff is 2px */
  margin-left: -6px; /* dot has glow halo, lift visually flush to gutter */
  margin-bottom: var(--space-5);
}
.campaign__tag-pulse {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
}
.campaign__tag-pulse::before,
.campaign__tag-pulse::after {
  content: "";
  position: absolute;
  inset: 25%; /* originate from the visual center of the 16px icon */
  border-radius: 50%;
  background: var(--accent);
  opacity: 0;
  transform: scale(1);
  animation: tag-pulse-ring var(--pulse-cycle) var(--pulse-ring-ease) infinite;
  pointer-events: none;
}
.campaign__tag-pulse::after {
  animation-delay: var(--pulse-ring-delay);
}
.campaign__tag-dot {
  width: 16px;
  height: 16px;
  position: relative; /* keep icon above the pulse rings */
  animation: tag-pulse-icon var(--pulse-cycle) ease-in-out infinite;
  will-change: transform, opacity, filter;
}

/* Ring active phase ends at 40% of the cycle, then holds invisible
   to 50% (where the staggered partner ring emits). That ~10% slice
   on either side of the cycle is the silent gap controlled by
   --pulse-rest — grow rest to grow the gap. */
@keyframes tag-pulse-ring {
  0% {
    opacity: var(--pulse-ring-start-opacity);
    transform: scale(1);
  }
  40%, 100% {
    opacity: 0;
    transform: scale(var(--pulse-ring-max-scale));
  }
}

@keyframes tag-pulse-icon {
  0%, 50%, 100% {
    transform: scale(var(--pulse-icon-scale-peak));
    opacity: 1;
    filter: drop-shadow(0 0 var(--pulse-icon-glow-blur) var(--pulse-icon-glow-color));
  }
  25%, 75% {
    transform: scale(var(--pulse-icon-scale-dip));
    opacity: var(--pulse-icon-opacity-dip);
    filter: drop-shadow(0 0 0 transparent);
  }
}

@media (prefers-reduced-motion: reduce) {
  .campaign__tag-pulse::before,
  .campaign__tag-pulse::after,
  .campaign__tag-dot {
    animation: none;
  }
}
.campaign__tag-text {
  font-family: var(--font-body);
  font-weight: var(--fw-bold);
  font-size: var(--fs-body-sm);
  letter-spacing: var(--tracking-tighter);
  color: var(--accent);
  line-height: var(--lh-flat);
}

.campaign__title {
  font-family: var(--font-body);
  font-weight: var(--fw-extrabold);
  font-size: var(--fs-display-lg);
  line-height: var(--lh-display);
  letter-spacing: var(--tracking-tightest);
  color: var(--text-strong);
  width: 253px;
  max-width: 100%;
  margin-bottom: var(--space-6);
}

/* image cluster — left photo sits low (137×119 starts at y=1555),
   right photo sits high (195×153 starts at y=1499). 56px Y offset. */
.campaign__images {
  position: relative;
  height: 155px;
  margin-bottom: var(--space-3);
}
.campaign__image {
  position: absolute;
  border-radius: var(--radius-sm);
  object-fit: cover;
  will-change: transform; /* parallax.js drives translate3d on scroll */
}
.campaign__image--left {
  left: 0;
  bottom: 0;
  width: 137px;
  height: 119px;
}
.campaign__image--right {
  right: 0;
  top: 0;
  width: 195px;
  height: 153px;
}

.campaign__lede {
  font-size: var(--fs-body-md);
  line-height: var(--lh-body);
  letter-spacing: var(--tracking-default);
  color: var(--text-strong);
  width: 339px;
  max-width: 100%;
  margin-bottom: var(--space-9); /* gap before tracker */
}
.campaign__lede-muted {
  color: var(--text-card-lede);
}


/* ---------- 9. TRACKER ---------- */

.tracker {
  position: relative;
  border: 0.5px solid var(--border-subtle);
  background: var(--surface-card);
  border-radius: var(--radius-md);
  padding: 3px;
  box-shadow: inset 0 2px 4px rgba(255, 255, 255, 0.03);
}

.tracker__head {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 10px 14px;
}
.tracker__head-icon {
  flex-shrink: 0;
}
.tracker__head-text {
  flex: 1;
  font-family: var(--font-body);
  font-weight: var(--fw-semibold);
  font-size: var(--fs-body-sm);
  line-height: var(--lh-button);
  letter-spacing: var(--tracking-default);
  color: var(--text-on-card);
}

.tracker__body {
  position: relative;
  background: var(--surface-inner);
  border: 0.5px solid var(--border-fainter);
  border-radius: var(--radius-sm);
  padding: var(--space-5) var(--space-5) var(--space-6);
  display: flex;
  flex-direction: column;
  gap: var(--space-8); /* 32 */
  box-shadow: inset 0 -1px 5px rgba(255, 255, 255, 0.11);
}
.tracker__amount-block {
  display: flex;
  flex-direction: column;
  gap: var(--space-1); /* 4 */
}
.tracker__amount {
  font-family: var(--font-display);
  font-weight: var(--fw-extrabold);
  line-height: var(--lh-display);
  letter-spacing: var(--tracking-tighter);
  color: var(--text-strong);
}
.tracker__amount-symbol {
  font-size: var(--fs-display-sm);
  color: var(--text-on-track);
  margin-right: 0.15em;
}
.tracker__amount-value {
  font-size: var(--fs-display-sm);
}
.tracker__goal {
  font-family: var(--font-body);
  font-weight: var(--fw-medium);
  font-size: var(--fs-body-sm);
  line-height: var(--lh-quote);
  letter-spacing: var(--tracking-tight);
  color: var(--text-muted);
}

/* progress bar — green segment sized by --fill (% of total raised),
   4px white spacer, dark fill rest. JS updates --fill live. */
.tracker__progress {
  display: flex;
  align-items: center;
  gap: var(--space-1); /* 4 */
  height: 42px;
}
.tracker__progress-fill {
  flex: 0 0 var(--fill, 0%);
  height: 100%;
  border: 0.4px solid var(--border-track);
  border-radius: var(--radius-lg);
  background: linear-gradient(to left, var(--accent), var(--accent-soft));
  box-shadow: inset 0 -0.4px 6px rgba(255, 255, 255, 0.6);
  transition: flex-basis 600ms var(--ease-out-soft);
}
.tracker__progress-marker {
  width: 4px;
  height: 100%;
  background: var(--color-white);
  border-radius: 16px;
  flex-shrink: 0;
}
.tracker__progress-track {
  flex: 1;
  height: 100%;
  background: var(--surface-track);
  border: 0.4px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  box-shadow: inset 0 -0.4px 6px rgba(255, 255, 255, 0.06);
}


/* ---------- 10. BUTTONS ---------- */

.btn {
  --btn-bg: var(--accent);
  --btn-fg: var(--color-black);

  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2); /* 8 */
  padding: 12px 20px;
  border-radius: var(--radius-pill);
  font-family: var(--font-body);
  font-weight: var(--fw-extrabold);
  font-size: var(--fs-body-sm);
  line-height: var(--lh-button);
  letter-spacing: var(--tracking-tight);
  white-space: nowrap;
  background: var(--btn-bg);
  color: var(--btn-fg);
  cursor: pointer;
  transition: transform 120ms ease, opacity 120ms ease;
}
.btn:hover { opacity: 0.9; }
.btn:active { transform: scale(0.98); }

.btn--primary {
  --btn-bg: var(--accent);
  --btn-fg: var(--color-black);
}
.btn--light {
  --btn-bg: var(--color-white);
  --btn-fg: var(--color-black);
}

.btn__arrow {
  display: inline-flex;
  width: 13px;
  height: 10px;
  color: var(--btn-fg);
}
.btn__arrow svg {
  width: 100%;
  height: 100%;
}

.tracker .btn {
  align-self: stretch;
}


/* ---------- 11. SVG SIZE HELPERS ---------- */

.icon-dot { width: 16px; height: 16px; }

/* Small bar-chart glyph in tracker header — built inline as SVG.
   Color comes from `currentColor` so future themes can repaint it. */
.icon-bars {
  width: 11px;
  height: 14px;
  color: var(--accent);
}


/* ---------- 12. GLOBE ---------- */

.globe {
  position: relative;
  width: 100%;
  aspect-ratio: 1 / 1;
  border-radius: var(--radius-sm);
  overflow: hidden;
  background: var(--bg);
}
.globe__canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
}

/* Popup overlay — DOM siblings of the canvas, positioned in canvas px.
   Each popup is a stack (pill on top, video card below) that scales
   from 0 → 1 with a bouncy genie pop on entrance, holds, then squeezes
   back into the anchor on exit. */
.globe__popups {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.globe__popup {
  position: absolute;
  width: 0;
  height: 0;
}

/* The animated element. translate(-50%, -50%) centers the stack on the
   location anchor so the genie scale-from-zero collapses to that exact
   point. Linear timing lets the keyframes do all the bounce shaping. */
.globe__popup-stack {
  position: absolute;
  left: 0;
  top: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  opacity: 0;
  transform: translate(-50%, -50%) scale(0);
  transform-origin: 50% 50%;
  animation: globe-genie var(--popup-life, 5s) linear forwards;
  will-change: transform, opacity;
}

.globe__popup-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 9px 4px 7px;
  background: rgba(40, 65, 10, 0.85);
  border: 0.5px solid rgba(169, 244, 47, 0.45);
  border-radius: var(--radius-pill);
  color: var(--text-strong);
  font-family: var(--font-body);
  font-weight: var(--fw-bold);
  font-size: 11px;
  letter-spacing: 0.04em;
  line-height: 1;
  text-transform: uppercase;
  white-space: nowrap;
  box-shadow: 0 4px 10px rgba(0, 0, 0, 0.35);
}
.globe__popup-pill-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 5px rgba(169, 244, 47, 0.85);
  animation: globe-pill-dot 1.4s ease-in-out infinite;
}
.globe__popup-pill-name {
  display: inline-block;
}

.globe__popup-card {
  width: 84px;
  height: 58px;
  border-radius: var(--radius-sm);
  overflow: hidden;
  background: #000;
  box-shadow:
    0 10px 22px rgba(0, 0, 0, 0.55),
    0 0 0 0.5px rgba(255, 255, 255, 0.12);
}
.globe__popup-video {
  width: 100%;
  height: 100%;
  display: block;
  object-fit: cover;
}

/* Genie pop: scale-from-zero with bouncy overshoot on enter, hold,
   then anticipation + squeeze back into the anchor on exit. */
@keyframes globe-genie {
  0%    { opacity: 0; transform: translate(-50%, -50%) scale(0);    }
  2.5%  { opacity: 1;                                                }
  6%    { transform: translate(-50%, -50%) scale(1.09);             }
  10%   { transform: translate(-50%, -50%) scale(0.97);             }
  14%   { transform: translate(-50%, -50%) scale(1.02);             }
  18%   { transform: translate(-50%, -50%) scale(1);                }
  92%   { opacity: 1; transform: translate(-50%, -50%) scale(1);    }
  94%   { transform: translate(-50%, -50%) scale(1.04);             }
  97%   { transform: translate(-50%, -50%) scale(0.55);             }
  99.5% { opacity: 1; transform: translate(-50%, -50%) scale(0.08); }
  100%  { opacity: 0; transform: translate(-50%, -50%) scale(0);    }
}

@keyframes globe-pill-dot {
  0%, 100% { opacity: 1;    transform: scale(1);    }
  50%      { opacity: 0.55; transform: scale(0.82); }
}

/* Reduced motion: skip the bounce — fade in/out at full size. */
@media (prefers-reduced-motion: reduce) {
  .globe__popup-stack {
    animation-name: globe-genie-reduced;
  }
  .globe__popup-pill-dot {
    animation: none;
  }
}
@keyframes globe-genie-reduced {
  0%   { opacity: 0; transform: translate(-50%, -50%) scale(1); }
  12%  { opacity: 1; transform: translate(-50%, -50%) scale(1); }
  88%  { opacity: 1; transform: translate(-50%, -50%) scale(1); }
  100% { opacity: 0; transform: translate(-50%, -50%) scale(1); }
}

/* Interactive hover label — shown above the hovered country dot in place
   of the auto-cycling video popups. Plain white text on the map; no
   capsule. Toggled by the .is-visible class. */
.globe__hover-pill {
  position: absolute;
  color: var(--text-strong);
  font-family: var(--font-body);
  font-weight: var(--fw-bold);
  font-size: 11px;
  letter-spacing: 0.04em;
  line-height: 1;
  text-transform: uppercase;
  white-space: nowrap;
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.85);
  pointer-events: none;
  opacity: 0;
  transform: translate(-50%, calc(-100% - 10px)) scale(0.92);
  transition:
    opacity 0.16s ease-out,
    transform 0.18s cubic-bezier(0.34, 1.5, 0.64, 1),
    left 0.16s cubic-bezier(0.16, 1, 0.3, 1),
    top 0.16s cubic-bezier(0.16, 1, 0.3, 1);
}
.globe__hover-pill.is-visible {
  opacity: 1;
  transform: translate(-50%, calc(-100% - 10px)) scale(1);
}
@media (prefers-reduced-motion: reduce) {
  .globe__hover-pill {
    transition: opacity 0.12s linear;
    transform: translate(-50%, calc(-100% - 10px));
  }
  .globe__hover-pill.is-visible {
    transform: translate(-50%, calc(-100% - 10px));
  }
}

/* Where We Go — section frame (matches the campaign pattern: gutters,
   title, lede, then the visual). */
.where-we-go {
  padding: var(--space-8) var(--page-gutter) var(--space-9);
}
.where-we-go__title {
  font-family: var(--font-body);
  font-weight: var(--fw-extrabold);
  font-size: var(--fs-display-lg);
  line-height: var(--lh-display);
  letter-spacing: var(--tracking-tightest);
  color: var(--text-strong);
  margin-bottom: var(--space-5);
  width: 70%;
}
.where-we-go__lede {
  font-size: var(--fs-body-md);
  line-height: var(--lh-body);
  letter-spacing: var(--tracking-default);
  color: var(--text-strong);
  margin-bottom: var(--space-8);
}
.where-we-go__lede-muted {
  color: var(--text-card-lede);
}
.where-we-go .globe {
  margin-bottom: var(--space-7);
}

/* Country list — two-column hairline grid with indexed rows. CSS
   counter generates the zero-padded number, removing the need for
   per-item template logic. Brutalist/Linear-esque: small uppercase
   type, tight tracking, faint dividers, no decorative glow. Each
   row reveals on scroll-in with a staggered delay driven by --i. */
.country-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: 1fr 1fr;
  column-gap: var(--space-5);
  row-gap: 0;
  border-top: 1px solid var(--border-fainter);
  counter-reset: country;
}
.country-list__item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 7px 0;
  border-bottom: 1px solid var(--border-fainter);
  counter-increment: country;
  font-family: var(--font-body);
  font-weight: var(--fw-semibold);
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-strong);
  line-height: 1;
  opacity: 0;
  transform: translateY(6px);
  transition:
    opacity 520ms var(--ease-out-soft) calc(var(--i, 0) * 32ms),
    transform 520ms var(--ease-out-soft) calc(var(--i, 0) * 32ms);
}
.country-list__item::before {
  content: counter(country, decimal-leading-zero);
  flex-shrink: 0;
  min-width: 1.4em;
  font-weight: var(--fw-medium);
  font-size: 10px;
  letter-spacing: 0.04em;
  color: var(--text-faint);
  font-variant-numeric: tabular-nums;
}
.country-list__dot {
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: var(--accent);
  flex-shrink: 0;
  /* Ambient breathing pulse — asymmetric keyframe (quick rise, slow
     decay) feels organic. Each row sets its own --pulse-delay in the
     template from a hand-shuffled array, so the 20 dots scatter
     across the 4s cycle without any detectable linear pattern. */
  animation: country-dot-breathe 2s ease-in-out infinite;
  animation-delay: var(--pulse-delay, 0s);
}

@keyframes country-dot-breathe {
  0%   { opacity: 0.60; transform: scale(0.89); }
  35%  { opacity: 1.00; transform: scale(1.00); }
  65%  { opacity: 0.85; transform: scale(0.95); }
  100% { opacity: 0.60; transform: scale(0.92); }
}

@media (prefers-reduced-motion: reduce) {
  .country-list__dot {
    animation: none;
    opacity: 1;
  }
}
.country-list__name {
  flex: 1;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.country-list.is-revealed .country-list__item {
  opacity: 1;
  transform: translateY(0);
}
@media (prefers-reduced-motion: reduce) {
  .country-list__item {
    transition: opacity 220ms linear;
    transform: none;
  }
}


/* ---------- 13. HERO ANIMATIONS ---------- */

/* Initial state for all entrance targets: hidden + reset transform.
   CSS is in <head> so this paints synchronously — no FOUC.
   Note: .hero__lede uses a mask sweep instead of opacity (see below). */
.hero__image,
.hero__title-line,
.hero__title-play,
.hero .btn {
  opacity: 0;
  animation-fill-mode: both;
  animation-timing-function: var(--ease-out-soft);
}

.hero__image                       { animation: hero-rise    560ms 80ms  both var(--ease-out-soft); }
.hero__title-line:nth-child(1)     { animation: hero-rise-sm 480ms 260ms both var(--ease-out-soft); }
.hero__title-line:nth-child(2)     { animation: hero-rise-sm 480ms 380ms both var(--ease-out-soft); }
.hero__title-play                  { animation: hero-fade    260ms 560ms both var(--ease-out-soft); }
.hero .btn                         { animation: hero-rise-sm 680ms 500ms both var(--ease-out-soft); }

@keyframes hero-rise    { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: translateY(0); } }
@keyframes hero-rise-sm { from { opacity: 0; transform: translateY(8px);  } to { opacity: 1; transform: translateY(0); } }
@keyframes hero-fade    { from { opacity: 0; } to { opacity: 1; } }

/* Lede top-down sweep — mask gradient (~0.5x element height fade zone)
   slides from below the text upward, so each visual line fades in as the
   edge passes through it. Reads as "loading line by line, top to bottom". */
.hero__lede {
  -webkit-mask-image: linear-gradient(180deg, #000 30%, transparent 70%);
          mask-image: linear-gradient(180deg, #000 30%, transparent 70%);
  -webkit-mask-size: 100% 250%;
          mask-size: 100% 250%;
  -webkit-mask-position: 0% 100%;
          mask-position: 0% 100%;
  -webkit-mask-repeat: no-repeat;
          mask-repeat: no-repeat;
  animation: lede-reveal 1800ms 320ms forwards var(--ease-out-soft);
}

@keyframes lede-reveal {
  to {
    -webkit-mask-position: 0% 0%;
            mask-position: 0% 0%;
  }
}

/* Play SVG write-on — centerline mask paths reveal the filled letters
   as their stroke draws. pathLength="100" normalizes timing per letter. */
.play-svg {
  display: block;
  width: 100%;
  height: 100%;
}

.play-mask__p,
.play-mask__l,
.play-mask__a,
.play-mask__y {
  stroke-dasharray: 100 100;
  stroke-dashoffset: 100;
}

/* Delays are relative to page load; write-on phase starts at 640ms,
   so the container fade (560-820ms) overlaps the P stroke beginning. */
.play-mask__p { animation: play-draw 380ms 640ms  forwards var(--ease-in-out-snap); }
.play-mask__l { animation: play-draw 180ms 920ms  forwards var(--ease-in-out-snap); }
.play-mask__a { animation: play-draw 320ms 1080ms forwards var(--ease-in-out-snap); }
.play-mask__y { animation: play-draw 330ms 1360ms forwards var(--ease-in-out-snap); }

@keyframes play-draw {
  to { stroke-dashoffset: 0; }
}

/* Reduced motion: full bypass. Everything visible immediately,
   Play SVG fully revealed, no animations run. */
@media (prefers-reduced-motion: reduce) {
  .hero__image,
  .hero__title-line,
  .hero__title-play,
  .hero .btn {
    opacity: 1;
    transform: none;
    animation: none;
  }
  .hero__lede {
    -webkit-mask-image: none;
            mask-image: none;
    animation: none;
  }
  .play-mask__p,
  .play-mask__l,
  .play-mask__a,
  .play-mask__y {
    stroke-dashoffset: 0;
    animation: none;
  }
}


/* ---------- 14. QUOTE ANIMATIONS ---------- */

/* Initial hidden state — paints synchronously, no FOUC.
   Follows the hero's main entrance (peaks 80–560ms) with a 700ms base delay
   so it reads as a continuation, not a competing beat. */
.quote__mark,
.quote__text,
.quote__image,
.quote__attribution {
  opacity: 0;
  animation-fill-mode: both;
  animation-timing-function: var(--ease-out-soft);
}

.quote__mark:not(.quote__mark--close) { animation: hero-rise-sm       480ms 700ms  both var(--ease-out-soft); }
.quote__text:nth-of-type(1)           { animation: hero-rise-sm       480ms 820ms  both var(--ease-out-soft); }
.quote__image                         { animation: hero-rise-sm       480ms 940ms  both var(--ease-out-soft); }
.quote__text:nth-of-type(2)           { animation: hero-rise-sm       480ms 1060ms both var(--ease-out-soft); }
.quote__attribution                   { animation: hero-rise-sm       480ms 1180ms both var(--ease-out-soft); }
.quote__mark--close                   { animation: quote-rise-flipped 480ms 1300ms both var(--ease-out-soft); }

/* Dedicated keyframe preserves the 180° rotation through the rise,
   so the closing mark doesn't un-flip mid-animation. */
@keyframes quote-rise-flipped {
  from { opacity: 0; transform: translateY(8px) rotate(180deg); }
  to   { opacity: 1; transform: translateY(0)   rotate(180deg); }
}

@media (prefers-reduced-motion: reduce) {
  .quote__mark,
  .quote__text,
  .quote__image,
  .quote__attribution {
    opacity: 1;
    animation: none;
  }
  .quote__mark--close {
    transform: rotate(180deg);
  }
}


/* ---------- 15. WEBGL REVEAL ---------- */

/* Full-viewport canvas that renders the reveal effect for every
   img[data-webgl] in sync with the DOM. `has-webgl` is set by JS only
   when WebGL2 is supported and motion isn't reduced — otherwise images
   render normally with their existing CSS animations.
   Canvas sits above the body background (z 0) and the page content sits
   above the canvas (z 1); tagged images are opacity 0, so the
   shader-rendered image shows through their footprint. */
#webgl {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
}

html.has-webgl .page { z-index: 1; }

html.has-webgl img[data-webgl] {
  opacity: 0;
  animation: none;
}
