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

:root {
  /* ============================================================
   * EL TRI DESIGN SYSTEM — canonical tokens
   * Consumed by:  src/style.css, src/main.js, src/chart.js,
   *               explorer/assets/overrides.css
   * Change tokens here; both surfaces (narrative + explorer) inherit.
   * ============================================================ */

  /* -- surface & ink ------------------------------------------- */
  --bg:            #080808;                    /* app background        */
  --surface:       #111111;                    /* cards · chrome         */
  --surface-sunk:  #0a0a0a;                    /* recessed fill · dark  */
  --surface-hi:    #1a0010;                    /* accent pill fill      */
  --border:        rgba(255,255,255,0.08);     /* 8% white — hairlines    */
  --border-strong: rgba(255,255,255,0.16);     /* 16% white — dividers   */
  --surface-tint:  rgba(255,255,255,0.08);     /* 8% white fill — subtle card tint,
                                                  distinct from --border by role
                                                  (fills vs hairlines).            */
  --text:          #f0f0f0;                    /* primary ink           */
  --text-inv:      #0a0a0a;                    /* ink on hue fills      */
  --dim:           rgba(240,240,240,0.65);     /* secondary ink · 65%   */

  /* white-alpha ramp — chart labels, faint fills, subtle text */
  --ink-hi:        rgba(255,255,255,0.5);      /* muted labels, decoration */
  --ink-mid:       rgba(255,255,255,0.28);     /* chart annotations, tags  */

  /* -- brand accents ------------------------------------------- */
  --accent:        #e8007d;   /* magenta — interaction / highlight */
  --accent-warm:   #ff6a00;   /* orange — "power" card             */
  --accent-wild:   #ffe600;   /* yellow — "wild" card + peak dots  */
  --accent-cool:   #00e5ff;   /* cyan   — "star" card              */

  /* -- country palette (Set A: flag identity, hue-spread) ------ */
  --mexico:        #00a550;   /* flag green                        */
  --korea:         #C60C30;   /* taegukgi red                      */
  --japan:         #E85D00;   /* red-orange                        */
  --usa:           #4a5fc1;   /* muted royal navy — reads USA without the arc-lamp intensity */
  --croatia:       #1E88E5;   /* sky blue                          */
  --spain:         #E8A700;   /* amber                             */

  /* -- typography ---------------------------------------------- *
   * Canonical 8-role scale. Every class in the app consumes one
   * of these. Do NOT invent new sizes/weights outside this scale.
   * Family / weight / size / letter-spacing / line-height are
   * co-defined per role so consumers only need to reference the role.
   * -------------------------------------------------------------- */
  --font-display:  'Syne', sans-serif;
  --font-mono:     'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, monospace;

  /* fluid sizes */
  --fs-display:    clamp(28px, 7vw, 72px);   /* intro-title, squad-headline    */
  --fs-h1:         clamp(22px, 3.5vw, 40px); /* narrative/context/verdict head */
  --fs-stat:       clamp(28px, 4vw, 44px);   /* big numbers (stat-value, etc.) */
  --fs-body:       clamp(13px, 1.2vw, 15px); /* prose everywhere               */
  --fs-caption:    12px;                     /* dense card copy                */
  --fs-eyebrow:    11px;                     /* SMALL CAPS labels              */
  --fs-tag:        12px;                     /* bold pills / buttons / roles   */
  --fs-meta:       11px;                     /* bold micro-labels              */

  /* -- spacing scale ------------------------------------------- */
  --sp-1:          4px;
  --sp-2:          8px;
  --sp-3:          12px;
  --sp-4:          16px;
  --sp-5:          24px;
  --sp-6:          32px;
  --sp-7:          48px;

  /* -- radii --------------------------------------------------- */
  /* Only 2 tokens: everything is either hard 0, chip 3px, card 6px,
     or semantic 50% (dots/circles). */
  --r-1:           3px;    /* chips, pills, small pressables (canvas + DOM) */
  --r-2:           6px;    /* card-scale corners */

  /* -- motion -------------------------------------------------- */
  /* easings — both are ease-out curves; quart is snappier for micro-
     interactions, quint has more overshoot-feel for hero entrances   */
  --ease-out-quart: cubic-bezier(0.25, 1, 0.5, 1);    /* micro       */
  --ease-out-quint: cubic-bezier(0.22, 1, 0.36, 1);   /* entrance    */

  /* durations — 3 stops covering hover, fade, entrance             */
  --dur-fast:       200ms;    /* hover / press / color micro-interactions */
  --dur-fade:       420ms;    /* slide fade in/out                        */
  --dur-entrance:   620ms;    /* hero + card cascade entrance             */

  /* stagger cascade knobs — consumed via var(--i) inline index      */
  --stagger-base:   80ms;
  --stagger-step:   70ms;

  /* legacy aliases (kept 1 release for safety) */
  --slide-fade-dur: var(--dur-fade);
  --entrance-dur:   var(--dur-entrance);
}

html, body {
  height: 100%;
  overflow: hidden;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-mono);
}

#app {
  width: 100%; height: 100%;
  position: relative;
  overflow: hidden;
  /* Sits above the persistent chart canvases so slide text/UI is never
     occluded by the chart layer. Nav (z:100) still dominates both. */
  z-index: 1;
}

/* ── SLIDE SYSTEM ── */
.slide {
  position: absolute;
  inset: 0;
  opacity: 1;
  pointer-events: all;
  transition: opacity var(--slide-fade-dur) var(--ease-out-quint);
  will-change: opacity;
}
/* Crossfade states used by goTo() */
.slide.slide-entering {
  opacity: 0;
}
.slide.slide-active {
  opacity: 1;
}
.slide.slide-leaving {
  opacity: 0;
  pointer-events: none;
}

/* ── CASCADE ENTRANCE ── */
/* Any child of .cascade animates in with a staggered delay based on --i.
   The keyframe now defines BOTH `from` and `to` so it works with any
   fill-mode; using `both` guarantees the pre-delay state stays hidden. */
.cascade > * {
  opacity: 0;
  transform: translateY(10px);
  animation: cascadeIn var(--entrance-dur) var(--ease-out-quint) both;
  animation-delay: calc(var(--stagger-base) + var(--i, 0) * var(--stagger-step));
  will-change: opacity, transform;
}
@keyframes cascadeIn {
  from {
    opacity: 0;
    transform: translateY(10px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* Respect user motion preference */
@media (prefers-reduced-motion: reduce) {
  .slide { transition: none; }
  .cascade > * {
    animation: none;
    opacity: 1;
    transform: none;
  }
  /* Intro choreography opts out too — top nav + lang buttons render
     at rest immediately; the crest3d code checks this at runtime. */
  .intro-top-nav,
  .slide-dots.as-lang-actions .intro-lang-btn {
    animation: none;
    opacity: 1;
    transform: none;
  }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

/* ── INTRO SLIDE ──
   Two-row layout: 3D crest owns the top, headline stack sits at the
   bottom. The crest no longer overlaps the type so we can run it at
   full opacity and full color.

   Choreography beats (all measured from slide mount):
     0ms–1200ms  crest rotates in from side-on to face (see crest3d.js)
     1200ms      text cascade begins (eyebrow → title lines → subtitle)
     ~2100ms     top nav + bottom lang buttons fade/rise in
*/
.slide-intro {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  justify-content: flex-start;
  overflow: hidden;
  padding: 0;
}

/* Push the text cascade past the crest's rotate-in. .cascade > * uses
   var(--stagger-base) + i * var(--stagger-step) for its delay; scoping
   an override to .slide-intro shifts the whole stack by 1200ms so the
   type doesn't jump the crest. */
.slide-intro {
  --stagger-base: 1200ms;
}

.intro-crest {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  width: 100%;
}
#flag-canvas {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  /* Crest owns its own zone now — no overlap with type, full glory. */
  opacity: 1;
}

.intro-chart-bg {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  opacity: 0.15;
  pointer-events: none;
}

.intro-content {
  position: relative;
  z-index: 2;
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--sp-4);
  padding: var(--sp-4) var(--sp-5) var(--sp-6);
  max-width: 680px;
  width: 100%;
  margin: 0 auto;
  box-sizing: border-box;
}

.intro-eyebrow {
  /* type: eyebrow */
  font-family: var(--font-mono);
  font-size: var(--fs-eyebrow);
  font-weight: 400;
  letter-spacing: 0.14em;
  line-height: 1.4;
  color: var(--dim);
  text-transform: uppercase;
  text-align: center;
  padding: 0 var(--sp-2);
}

.intro-title {
  /* type: display */
  font-family: var(--font-display);
  font-size: var(--fs-display);
  font-weight: 800;
  line-height: 1.02;
  letter-spacing: -0.02em;
  text-transform: uppercase;
  display: flex;
  flex-wrap: wrap;
  gap: 0.25em;
  justify-content: center;
  width: 100%;
  overflow-wrap: break-word;
  word-break: keep-all;
}

.intro-accent { color: var(--mexico); }

.intro-subtitle {
  /* type: body */
  font-family: var(--font-mono);
  font-size: var(--fs-body);
  font-weight: 400;
  line-height: 1.65;
  color: var(--dim);
  max-width: 420px;
  padding: 0 var(--sp-1);
}

.intro-actions {
  display: flex;
  gap: var(--sp-3);
  flex-wrap: wrap;
  justify-content: center;
}

.intro-meta-links {
  /* type: meta */
  margin-top: var(--sp-4);
  display: flex;
  gap: var(--sp-3);
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  font-family: var(--font-mono);
  font-size: var(--fs-meta);
  font-weight: 700;
  letter-spacing: 0.14em;
  line-height: 1;
  text-transform: uppercase;
}
.intro-meta-link {
  color: var(--dim);
  text-decoration: none;
  border-bottom: 1px dotted transparent;
  padding-bottom: 1px;
  transition: color        var(--dur-fast) var(--ease-out-quart),
              border-color var(--dur-fast) var(--ease-out-quart);
}
.intro-meta-link:hover {
  color: var(--accent);
  border-bottom-color: var(--accent);
}
.intro-meta-sep {
  color: var(--dim);
  pointer-events: none;
}

/* Intro-only top nav ─ Explorer + Design links. Pinned top-right so the
   crest + type stack own the vertical center. Uses the same meta-link
   type treatment as the (deprecated) .intro-meta-links row. */
.intro-top-nav {
  position: absolute;
  top: var(--sp-4);
  right: var(--sp-5);
  z-index: 3;
  display: flex;
  gap: var(--sp-3);
  align-items: center;
  font-family: var(--font-mono);
  font-size: var(--fs-meta);
  font-weight: 700;
  letter-spacing: 0.14em;
  line-height: 1;
  text-transform: uppercase;
  /* Choreography beat 3 (~2100ms): fade in after text has cascaded.
     `both` fill mode keeps the element hidden during the pre-delay
     window. Uses cascadeNavIn so we drop from above instead of below. */
  opacity: 0;
  animation: navFadeIn var(--dur-entrance) var(--ease-out-quint) both;
  animation-delay: 2100ms;
  will-change: opacity, transform;
}
@keyframes navFadeIn {
  from { opacity: 0; transform: translateY(-6px); }
  to   { opacity: 1; transform: translateY(0); }
}
.intro-top-link {
  color: var(--dim);
  text-decoration: none;
  border-bottom: 1px dotted transparent;
  padding-bottom: 2px;
  transition: color var(--dur-fast) var(--ease-out-quart),
              border-color var(--dur-fast) var(--ease-out-quart);
}
.intro-top-link:hover {
  color: var(--accent);
  border-bottom-color: var(--accent);
}
.intro-top-sep {
  color: var(--dim);
  pointer-events: none;
  opacity: 0.6;
}

/* Intro-only bottom-nav variant: on the cover slide the centered slot
   (normally the dots strip) holds the two language CTAs instead. Both
   prev and next are hidden on the intro (see updateGlobalNav) so the
   button pair claims the full width of the nav strip. We opt out of
   the absolute-center trick used for dots and let flex do the layout. */
.slide-dots.as-lang-actions {
  position: static;
  left: auto;
  transform: none;
  display: flex;
  gap: var(--sp-3);
  align-items: stretch;
  justify-content: center;
  flex: 1 1 auto;
  min-width: 0;
  width: 100%;
  max-width: 720px;
}
.slide-dots.as-lang-actions .intro-lang-btn {
  flex: 1 1 0;
  max-width: 340px;
  /* Choreography beat 3 (~2100ms): rise + fade in with the top nav.
     `both` fill mode holds the hidden start state through the delay. */
  opacity: 0;
  animation: cascadeIn var(--dur-entrance) var(--ease-out-quint) both;
  animation-delay: 2100ms;
  will-change: opacity, transform;
}
/* Stagger the second button by 80ms so the pair reads as choreographed,
   not a slab. */
.slide-dots.as-lang-actions .intro-lang-btn:nth-child(2) {
  animation-delay: 2180ms;
}
.intro-lang-btn {
  /* Sized on the --fs-tag token to match the two nav buttons on every
     other slide — the intro CTAs are the visual peers of prev/next. */
  font-family: var(--font-mono);
  font-size: var(--fs-tag);
  font-weight: 600;
  letter-spacing: 0.12em;
  line-height: 1.3;
  text-transform: uppercase;
  padding: var(--sp-3) var(--sp-4);
  min-height: 48px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--border);
  cursor: pointer;
  white-space: nowrap;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  transform-origin: center;
  transition: transform var(--dur-fast) var(--ease-out-quart),
              background var(--dur-fast) var(--ease-out-quart),
              border-color var(--dur-fast) var(--ease-out-quart),
              color var(--dur-fast) var(--ease-out-quart);
}
.intro-lang-btn.btn-primary {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}
.intro-lang-btn.btn-primary:hover {
  filter: brightness(1.08);
}
.intro-lang-btn.btn-ghost {
  background: transparent;
  color: var(--text);
}
.intro-lang-btn.btn-ghost:hover {
  border-color: var(--accent);
  color: var(--accent);
}
.intro-lang-btn:active,
.intro-lang-btn.is-pressed { transform: scale(0.97); }

/* ── NARRATIVE SLIDE ── */
.slide-narrative {
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

/* Desktop: side-by-side */
.narrative-layout {
  flex: 1;
  display: grid;
  grid-template-columns: 42% 58%;
  grid-template-rows: 1fr;
  gap: 0;
  overflow: hidden;
  min-height: 0;
}

.narrative-left {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: var(--sp-4);
  padding: var(--sp-6) var(--sp-5) var(--sp-5) var(--sp-6);
  border-right: 1px solid var(--border);
  overflow-y: auto;
  min-height: 0;
}

.narrative-right {
  overflow: hidden;
  position: relative;
  display: flex;
  align-items: stretch;
  padding: var(--sp-5) var(--sp-5) var(--sp-5) var(--sp-5);
  min-height: 0;
}

.narrative-chart {
  display: block;
  width: 100%;
  height: 100%;
  display: block;
  min-height: 0;
}

/* iPad / mid-size: keep side-by-side but adjust column ratio.
   Type sizes handled by --fs-h1 / --fs-body clamp() — no overrides needed. */
/* Mobile: chart on top, text scrolls below */
/* Smaller phones: padding tightens; type sizes handled by clamp() */
.country-eyebrow {
  /* type: eyebrow */
  font-family: var(--font-mono);
  font-size: var(--fs-eyebrow);
  font-weight: 400;
  letter-spacing: 0.14em;
  line-height: 1.4;
  color: var(--dim);
  text-transform: uppercase;
}

.archetype-tag {
  /* type: tag */
  font-family: var(--font-mono);
  font-size: var(--fs-tag);
  font-weight: 600;
  letter-spacing: 0.12em;
  line-height: 1.3;
  opacity: 0.85;
}

.narrative-headline {
  /* type: h1 */
  font-family: var(--font-display);
  font-size: var(--fs-h1);
  font-weight: 800;
  line-height: 1.1;
  letter-spacing: -0.02em;
  text-transform: uppercase;
  color: var(--text);
}

/* Attribution for pull-quote headlines. Sits directly under the headline,
   inherits the cascade slot the headline uses. */
.headline-attribution {
  font-family: var(--font-mono);
  font-size: var(--fs-eyebrow);
  font-weight: 500;
  letter-spacing: 0.02em;
  color: var(--text-muted, var(--text));
  opacity: 0.72;
  margin-top: 8px;
  margin-bottom: 4px;
}

.narrative-body {
  /* type: body */
  font-family: var(--font-mono);
  font-size: var(--fs-body);
  font-weight: 400;
  line-height: 1.65;
  color: var(--dim);
  max-width: 420px;
}

.stat-card {
  margin-top: var(--sp-2);
  padding: var(--sp-4) var(--sp-5);
  background: var(--surface-tint);
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
}

.stat-value {
  /* type: stat */
  font-family: var(--font-display);
  font-size: var(--fs-stat);
  font-weight: 800;
  line-height: 1;
  letter-spacing: -0.02em;
}

.stat-label {
  /* type: eyebrow (tighter LS) */
  font-family: var(--font-mono);
  font-size: var(--fs-eyebrow);
  font-weight: 400;
  letter-spacing: 0.14em;
  line-height: 1.4;
  color: var(--dim);
  text-transform: uppercase;
  margin-top: var(--sp-2);
}

/* ── CTA SLIDE ──
   Mirrors the intro slide: 3D crest on top, cascade content below,
   attribution pinned to the bottom above the fixed nav. Actions stack
   vertically — primary · secondary · tertiary (restart). Uses grid to
   keep flex-basis math from squeezing the content column on mobile. */
.slide-cta {
  display: grid;
  grid-template-rows: minmax(180px, 30vh) 1fr auto;
  grid-template-columns: 1fr;
  overflow: hidden;
  padding: 0;
  /* Same cascade rhythm as intro: text waits for the crest rotate-in. */
  --stagger-base: 1200ms;
}

.cta-crest {
  /* Cell 1: crest zone */
  position: relative;
  width: 100%;
  height: 100%;
  flex: none;
  min-height: 0;
}

.cta-crest > canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

.slide-cta .intro-content {
  /* Cell 2: text + actions. Grid row auto so it sizes to content —
     no flex squeeze, no overflow. */
  flex: none;
  padding: var(--sp-3) var(--sp-5) var(--sp-4);
  align-self: start;
}

.cta-explore-btn {
  text-decoration: none;
  display: inline-block;
}

/* Vertical stack of the three CTAs — full-width up to a comfortable
   reading measure so tap targets are large but the column stays tight. */
.cta-actions-stack {
  flex-direction: column;
  flex-wrap: nowrap;
  gap: var(--sp-2);
  width: 100%;
  max-width: 360px;
  margin-top: var(--sp-2);
}

.cta-actions-stack > .btn-primary,
.cta-actions-stack > .btn-ghost,
.cta-actions-stack > .btn-tertiary {
  width: 100%;
  text-align: center;
  justify-content: center;
  display: inline-flex;
  align-items: center;
  padding: var(--sp-3) var(--sp-4);
  min-height: 48px;
  white-space: nowrap;
}

/* Tertiary button: text-only, low-emphasis restart affordance. */
.btn-tertiary {
  font-family: var(--font-mono);
  font-size: var(--fs-tag);
  font-weight: 500;
  letter-spacing: 0.12em;
  line-height: 1.3;
  text-transform: uppercase;
  background: none;
  border: none;
  color: var(--dim);
  padding: var(--sp-3) var(--sp-4);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  transform-origin: center;
  transition: color var(--dur-fast) var(--ease-out-quart),
              transform var(--dur-fast) var(--ease-out-quart);
}
.btn-tertiary:hover { color: var(--text); }
.btn-tertiary:active,
.btn-tertiary.is-pressed { transform: scale(0.97); }

/* Attribution: last grid row. Fixed nav is hidden on CTA, so we only
   need standard bottom breathing room + safe-area for the home bar. */
.cta-attribution {
  font-family: var(--font-mono);
  font-size: var(--fs-eyebrow);
  letter-spacing: 0.14em;
  line-height: 1.4;
  color: var(--dim);
  text-transform: uppercase;
  text-align: center;
  padding: var(--sp-2) var(--sp-5) calc(var(--sp-5) + env(safe-area-inset-bottom, 0px));
}

/* ── NAV ── */
.slide-nav {
  display: flex;
  align-items: stretch;
  justify-content: center;
  padding: var(--sp-3) var(--sp-4);
  /* Honor iOS home-indicator + Android gesture-bar safe area so the
     buttons don't get cropped by the phone bezel.
     On wide viewports, use auto gutters so the nav row centers around
     ~720px of content (matches the reading column) instead of spanning
     the full viewport with buttons pinned to the edges. */
  padding-bottom: max(24px, calc(var(--sp-3) + env(safe-area-inset-bottom, 0px)));
  padding-left: max(calc(var(--sp-4) + env(safe-area-inset-left, 0px)), calc((100% - 720px) / 2));
  padding-right: max(calc(var(--sp-4) + env(safe-area-inset-right, 0px)), calc((100% - 720px) / 2));
  border-top: 1px solid var(--border);
  flex-shrink: 0;
  gap: var(--sp-3);
  min-height: 68px;
  /* Fixed to viewport bottom */
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  background: var(--bg);
  z-index: 100;
}

/* Center slot: on non-intro slides it collapses to zero width so the
   two flex buttons expand to fill the row (that's the dot-free design
   we're after). On intro it holds the two language CTAs and gets its
   own flex behavior via .as-lang-actions below. */
.slide-nav .nav-slots {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
}
.slide-nav .nav-slots.as-lang-actions {
  flex: 1 1 auto;
  gap: var(--sp-3);
  justify-content: center;
}
.slide-nav .nav-slots.as-lang-actions .intro-lang-btn { flex: 1 1 0; max-width: 240px; }

/* Nav-scoped overrides for the primary/ghost button tokens.
   Each button flexes to fill available width but never grows past
   ~240px, so on desktop we get two nicely sized CTAs floating over
   ample gutters and on mobile they stretch edge-to-edge. Padding
   + min-height gives us real 48px tap targets everywhere. */
.slide-nav > .btn-primary,
.slide-nav > .btn-ghost {
  flex: 1 1 0;
  max-width: 240px;
  min-height: 48px;
  padding: var(--sp-3) var(--sp-4);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  white-space: nowrap;
}

.slide-dots {
  display: flex;
  gap: var(--sp-2);
  align-items: center;
}

.dot {
  width: 5px; height: 5px;
  border-radius: 50%;
  background: var(--dim);
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease-out-quart),
              transform  var(--dur-fast) var(--ease-out-quart);
}

.dot.active {
  background: var(--accent);
  transform: scale(1.4);
}

/* Press-affordance: 0.97 scale on :active. Compound rule for the currently-
   active dot preserves its 1.4x scale and multiplies by 0.97 (≈ 1.358). */
.dot:active { transform: scale(0.97); }
.dot.active:active { transform: scale(1.358); }

/* ── BUTTONS ── */
.btn-primary {
  /* type: tag */
  font-family: var(--font-mono);
  font-size: var(--fs-tag);
  font-weight: 600;
  letter-spacing: 0.12em;
  line-height: 1.3;
  text-transform: uppercase;
  background: var(--accent);
  border: none;
  color: #fff;
  padding: var(--sp-4) var(--sp-5);
  cursor: pointer;
  /* Kill the iOS blue tap-flash so the scale-down is what the user sees. */
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  transform-origin: center;
  transition: opacity   var(--dur-fast) var(--ease-out-quart),
              transform var(--dur-fast) var(--ease-out-quart);
}

.btn-primary:hover { opacity: 0.85; }
.btn-primary:active,
.btn-primary.is-pressed { transform: scale(0.97); }

.btn-ghost {
  /* type: tag */
  font-family: var(--font-mono);
  font-size: var(--fs-tag);
  font-weight: 600;
  letter-spacing: 0.12em;
  line-height: 1.3;
  text-transform: uppercase;
  background: none;
  border: 1px solid var(--border);
  color: var(--dim);
  padding: var(--sp-4) var(--sp-5);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  transform-origin: center;
  transition: border-color var(--dur-fast) var(--ease-out-quart),
              color        var(--dur-fast) var(--ease-out-quart),
              transform    var(--dur-fast) var(--ease-out-quart);
}

.btn-ghost:hover {
  border-color: var(--ink-mid);
  color: var(--text);
}

.btn-ghost:active,
.btn-ghost.is-pressed { transform: scale(0.97); }

/* ── ¿Y SI SÍ? SQUAD SLIDE ── */
.slide-squad {
  display: flex;
  flex-direction: column;
  min-height: 100%;
  padding: 0;
  overflow-y: auto;
  overflow-x: hidden;
  -webkit-overflow-scrolling: touch;
  background: var(--bg);
}

.squad-header {
  padding: 2.2rem 2rem 1rem;
  flex-shrink: 0;
}

.squad-eyebrow {
  /* type: eyebrow */
  font-family: var(--font-mono);
  font-size: var(--fs-eyebrow);
  font-weight: 400;
  letter-spacing: 0.14em;
  line-height: 1.4;
  color: var(--accent);
  text-transform: uppercase;
  margin-bottom: 0.35rem;
}

.squad-headline {
  /* type: display */
  font-family: var(--font-display);
  font-size: var(--fs-display);
  font-weight: 800;
  line-height: 0.95;
  letter-spacing: -0.02em;
  text-transform: uppercase;
  color: #fff;
  margin: 0 0 0.7rem;
}

.squad-subhead {
  /* type: body */
  font-family: var(--font-mono);
  font-size: var(--fs-body);
  font-weight: 400;
  line-height: 1.65;
  color: var(--ink-hi);
  max-width: 520px;
  margin: 0;
}

/* ── compact born-outside bar chart in squad header ──
   Lives between the subhead and the card grid. Small, monochrome-
   plus-mexico canvas that grounds the Chavela quote in a hard data
   point without competing with the character cards below. */
.squad-bornchart {
  margin: 24px 0 0 0;
  padding: 12px 0 4px 0;
  border-top: 1px solid var(--border);
  max-width: 520px;
  display: block;
}
.squad-bornchart-label {
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.08em;
  color: var(--ink-mid);
  margin: 0 0 6px 0;
  text-transform: uppercase;
}
.squad-bornchart-canvas {
  display: block;
  width: 100%;
  height: 72px;
}

/* ── card grid ── */
.squad-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 1px;
  border-top: 1px solid var(--border);
  flex: 1;
}

.squad-card {
  padding: 1rem 1.1rem;
  border-right: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  position: relative;
  background: var(--bg);
  transition: background var(--dur-fast) var(--ease-out-quart);
}

.squad-card::before {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 2px;
  background: var(--card-accent, var(--border));
}

/* card archetypes */
.card-legend   { --card-accent: var(--accent);      }
.card-star     { --card-accent: var(--accent-cool); }
.card-wild     { --card-accent: var(--accent-wild); }
.card-power    { --card-accent: var(--accent-warm); }
.card-captain  { --card-accent: var(--accent);      }

.squad-card-top {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 0.5rem;
  margin-bottom: 0.6rem;
}

.squad-role {
  /* type: tag (colored) */
  font-family: var(--font-mono);
  font-size: var(--fs-tag);
  font-weight: 600;
  letter-spacing: 0.08em;    /* tightened from 0.12em to fit "EL INMIGRANTE" on one line */
  line-height: 1.3;
  text-transform: uppercase;
  color: var(--card-accent, var(--ink-hi));
  flex: 1;
  hyphens: none;
  overflow-wrap: normal;
}

.squad-stat-badge {
  display: flex;
  flex-direction: column;
  align-items: center;
  background: var(--surface-tint);
  border: 1px solid var(--card-accent, var(--border));
  padding: 0.2rem 0.45rem;
  min-width: 36px;
  flex-shrink: 0;
}

.squad-stat-val {
  /* type: stat (mono variant) */
  font-family: var(--font-mono);
  font-size: 15px;
  font-weight: 700;
  line-height: 1;
  color: var(--card-accent, #fff);
}

.squad-stat-lbl {
  /* type: eyebrow */
  font-family: var(--font-mono);
  font-size: var(--fs-eyebrow);
  font-weight: 400;
  letter-spacing: 0.14em;
  line-height: 1.4;
  color: var(--ink-mid);
  text-transform: uppercase;
  margin-top: 1px;
}

.squad-card-name {
  /* type: h1 (fixed, not fluid — grid cell) */
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 800;
  line-height: 1.05;
  letter-spacing: -0.02em;
  text-transform: uppercase;
  color: #fff;
  margin-bottom: 0.15rem;
}

.squad-card-age {
  /* type: eyebrow */
  font-family: var(--font-mono);
  font-size: var(--fs-eyebrow);
  font-weight: 400;
  letter-spacing: 0.14em;
  line-height: 1.4;
  color: var(--ink-mid);
  text-transform: uppercase;
  margin-bottom: 0.5rem;
}

.squad-card-detail {
  /* type: caption */
  font-family: var(--font-mono);
  font-size: var(--fs-caption);
  font-weight: 400;
  line-height: 1.5;
  color: var(--ink-hi);
  margin-bottom: 0.4rem;
}

.squad-card-origin {
  /* type: eyebrow (tighter LS — country names lower-cased) */
  font-family: var(--font-mono);
  font-size: var(--fs-eyebrow);
  font-weight: 400;
  letter-spacing: 0.10em;
  line-height: 1.4;
  color: var(--card-accent, var(--ink-mid));
  opacity: 0.7;
}

/* highlight the star card */
.card-star .squad-card-name {
  color: var(--card-accent);
}

.card-captain::before {
  height: 3px;
}

/* mobile layout */
/* bench / staff cards */
.card-bench { --card-accent: var(--ink-mid); }
.card-bench .squad-role { opacity: 0.7; }
.card-bench .squad-card-name { font-size: 16px; }

/* ghost card — Chicharito, not selected */
.card-ghost {
  --card-accent: var(--border-strong);
  opacity: 0.55;
  position: relative;
}
.card-ghost::after {
  /* type: meta */
  content: attr(data-stamp);
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%) rotate(-12deg);
  font-family: var(--font-mono);
  font-size: var(--fs-meta);
  font-weight: 700;
  letter-spacing: 0.14em;
  line-height: 1;
  color: var(--border-strong);
  border: 1px solid var(--border);
  padding: 0.2rem 0.5rem;
  white-space: nowrap;
  pointer-events: none;
}
.card-ghost .squad-card-name {
  text-decoration: line-through;
  text-decoration-color: var(--ink-mid);
}
.card-ghost .squad-stat-val { color: var(--ink-mid); }

/* section divider label between players and staff */
.squad-section-label {
  /* type: eyebrow (wider LS — section divider) */
  grid-column: 1 / -1;
  font-family: var(--font-mono);
  font-size: var(--fs-eyebrow);
  font-weight: 400;
  letter-spacing: 0.2em;
  line-height: 1.4;
  color: var(--border-strong);
  text-transform: uppercase;
  padding: 0.6rem 1.1rem 0.2rem;
  border-top: 1px solid var(--border);
}

/* ── VERDICT SLIDE ── */
.slide-verdict {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 2rem 1.5rem 1.5rem;
  overflow: hidden;
}
.verdict-layout {
  display: flex;
  flex-direction: column;
  gap: 1.2rem;
  flex: 1;
  justify-content: center;
}
.verdict-header {
  max-width: 560px;
}
.verdict-header .narrative-headline {
  /* Smaller variant of h1 for the tight verdict header (fixed, non-fluid) */
  font-size: 20px;
  margin-bottom: 0.5rem;
}
.verdict-header .narrative-body {
  /* type: caption — tighter than the standard body block */
  font-size: var(--fs-caption);
  line-height: 1.65;
  opacity: 0.75;
  max-width: 520px;
}
.verdict-chart-wrap {
  flex: 1;
  min-height: 220px;
  max-height: 340px;
  position: relative;
}
.verdict-chart-wrap canvas {
  width: 100%;
  height: 100%;
  display: block;
}




/* Global: all slides need bottom clearance for the fixed nav.
   Add env(safe-area-inset-bottom) so notched phones don't crop
   slide content behind the nav strip. Base nav is now ~100px tall
   (68 min-height + sp-3 top + sp-3 bottom) so reserve accordingly. */
.slide {
  padding-bottom: max(112px, calc(96px + env(safe-area-inset-bottom, 0px)));
}
#global-nav {
  box-shadow: 0 -1px 0 var(--border);
}

/* Persistent chart canvas — lives outside #app, positioned over the anchor.
   z-index: 0 keeps the chart at the BOTTOM of the interactive z-stack so
   slide text, cards, and nav always draw over it. #app is z:1, nav is
   z:100. Same rule applies to #chart-adj-persistent, set in main.js. */
#chart-mex-persistent,
#chart-adj-persistent {
  position: fixed;
  pointer-events: none;
  z-index: 0;
  display: block;
}

/* ── CONTEXT / TRANSITION SLIDE ── */
.slide-context {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--sp-7) 64px 80px;  /* 64/80 = large section breathing room */
  overflow-y: auto;
  overflow-x: hidden;
  -webkit-overflow-scrolling: touch;
}

.context-layout {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--sp-7);
  width: 100%;
  max-width: 1100px;
  align-items: center;
}

.context-text {
  display: flex;
  flex-direction: column;
  gap: var(--sp-5);
}

.context-headline {
  /* type: h1 */
  font-family: var(--font-display);
  font-size: var(--fs-h1);
  font-weight: 800;
  line-height: 1.1;
  letter-spacing: -0.02em;
  color: var(--text);
  margin: 0;
}

.context-deck {
  /* type: body */
  font-family: var(--font-mono);
  font-size: var(--fs-body);
  font-weight: 400;
  line-height: 1.65;
  color: var(--dim);
  margin: 0;
}

.context-pull {
  /* type: body (accent, quote-like) */
  font-family: var(--font-mono);
  font-size: var(--fs-body);
  font-weight: 400;
  line-height: 1.5;
  color: var(--accent);
  margin: 0;
  border-left: 2px solid var(--accent);
  padding-left: var(--sp-4);
}

.context-cards {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
}

.ctx-card {
  display: flex;
  align-items: center;
  gap: 0;
  background: var(--surface-tint);
  border: 1px solid var(--border);
  border-left: 3px solid var(--card-color);
  border-radius: var(--r-1);
  overflow: hidden;
  will-change: opacity, transform;
}

.ctx-card-color {
  width: 4px;
  align-self: stretch;
  flex-shrink: 0;
  display: none; /* handled by border-left */
}

.ctx-card-body {
  padding: var(--sp-4) var(--sp-4);
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
}

.ctx-card-label {
  /* type: caption (bumped from meta 10→11px for readability) */
  font-family: var(--font-mono);
  font-size: var(--fs-caption);
  font-weight: 700;
  letter-spacing: 0.14em;
  line-height: 1;
  color: var(--card-color);
  text-transform: uppercase;
}

.ctx-card-blurb {
  /* type: caption */
  font-family: var(--font-mono);
  font-size: var(--fs-caption);
  font-weight: 400;
  line-height: 1.5;
  color: var(--ink-hi);
}

/* Mobile */

/* ── SCORE EXPLAINER SLIDE (slide 1 — mobile-first, single column) ──
   Copy narrative on top, visual worked-example formula strip below.
   No two-column layout, no table — the whole slide flows top→bottom
   so phones render exactly the same shape as desktop. */

.slide-score-explainer {
  overflow-y: auto;
  overflow-x: hidden;
  -webkit-overflow-scrolling: touch;
}

.score-explainer-layout {
  max-width: 900px;
  width: 100%;
  margin: 0 auto;
  padding: var(--sp-8) var(--sp-6);
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  min-height: 100%;
  justify-content: center;
}

.score-headline {
  /* One line on desktop, wraps naturally on mobile.
     Keeps the same visual weight as other narrative slides. */
  max-width: 18ch;
}

.score-body {
  max-width: 65ch;
  color: rgba(240,240,240,0.85);
}

/* ── Worked example ── */
.score-worked {
  margin-top: var(--sp-4);
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
}

.score-worked-label {
  font-family: var(--font-mono);
  font-size: var(--fs-eyebrow);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--dim);
}

.score-formula {
  display: grid;
  grid-template-columns: 1fr auto 1fr auto 1fr auto 1fr;
  align-items: stretch;
  gap: var(--sp-2);
}

.score-pill {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-3);
  border: 1px solid var(--border-strong);
  border-radius: 4px;
  background: var(--surface);
  min-height: 108px;
}

.score-pill-key {
  font-family: var(--font-mono);
  font-size: var(--fs-eyebrow);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--dim);
}

.score-pill-detail {
  font-family: var(--font-mono);
  font-size: var(--fs-caption);
  color: rgba(240,240,240,0.85);
  line-height: 1.35;
}

.score-pill-value {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 28px;
  color: var(--accent);
  letter-spacing: -0.01em;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  margin-top: auto;
}

.score-plus,
.score-equals {
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 28px;
  color: var(--dim);
  padding: 0 var(--sp-1);
  user-select: none;
}

.score-total {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  padding: var(--sp-3);
  border: 1px solid var(--accent);
  border-radius: 4px;
  background: color-mix(in srgb, var(--accent) 8%, transparent);
  gap: var(--sp-1);
  min-height: 108px;
}

.score-total-value {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 48px;
  color: var(--accent);
  letter-spacing: -0.02em;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}

.score-total-label {
  font-family: var(--font-mono);
  font-size: var(--fs-eyebrow);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent);
  opacity: 0.85;
}

.score-footnote {
  font-family: var(--font-mono);
  font-size: var(--fs-caption);
  color: rgba(240,240,240,0.65);
  line-height: 1.5;
  max-width: 65ch;
}

.score-footnote strong {
  color: var(--accent);
  font-weight: 700;
}

/* ── Cover byline ─ tiny author credit under the subtitle ── */
.intro-byline {
  font-family: var(--font-mono);
  font-size: var(--fs-meta);
  font-weight: 700;
  letter-spacing: 0.14em;
  line-height: 1;
  text-transform: uppercase;
  color: var(--dim);
  opacity: 0.55;
  margin-top: var(--sp-3);
  padding: 0 var(--sp-1);
}

/* ── Motivation slide ─ essay-style opener before the score explainer ──
   Text-only slide. Layout mirrors verdict-header's centered stack so the
   driving question reads like a chapter opening. */
.slide-motivation .motivation-layout {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: var(--sp-4);
  padding: var(--sp-6) var(--sp-6);
  max-width: 780px;
  margin: 0 auto;
  overflow-y: auto;
  min-height: 0;
}
.slide-motivation .motivation-headline {
  max-width: 20ch;
}
.slide-motivation .motivation-body {
  max-width: 62ch;
}
.slide-motivation .motivation-pull {
  font-family: var(--font-mono);
  font-size: var(--fs-body);
  font-weight: 400;
  line-height: 1.55;
  color: var(--accent);
  margin: var(--sp-2) 0 0;
  padding-left: var(--sp-4);
  border-left: 2px solid var(--accent);
  max-width: 60ch;
}
.slide-motivation .motivation-meta {
  font-family: var(--font-mono);
  font-size: var(--fs-meta);
  font-weight: 400;
  line-height: 1.55;
  letter-spacing: 0.02em;
  color: var(--dim);
  opacity: 0.75;
  margin: var(--sp-2) 0 0;
  max-width: 60ch;
}

/* ─── Responsive ─────────────────────────────────────────────────
   Canonical breakpoints:
     sm ≤ 640px   phones (all orientations)
     md 641–1024  tablets, small laptops
     lg ≥ 1025    desktop (default rules)
   Reduced-motion query stays in place near :root.
─────────────────────────────────────────────────────────────────── */

/* ── ≤ 640px · Phones ─────────────────────────────────────────── */
@media (max-width: 640px) {
  /* Narrative slide — Option A: chart pinned to the top of the viewport,
     text in a scrollable card below it with a solid bg so it never floats
     over the (fixed-position) chart canvas. The slide itself does NOT
     scroll; only .narrative-left (the card) does.

     Text-only slides (score-explainer, motivation) share .slide-narrative
     for tokens but have NO chart — they scroll normally. :not() keeps
     them out of the pinned-chart pattern below. */
  .slide-narrative:not(.slide-score-explainer):not(.slide-motivation) {
    overflow: hidden;
  }
  .slide-narrative.slide-score-explainer,
  .slide-narrative.slide-motivation {
    overflow-y: auto;
    overflow-x: hidden;
    -webkit-overflow-scrolling: touch;
  }
  .narrative-layout {
    display: flex;
    flex-direction: column;
    height: 100%;
    overflow: hidden;
  }
  .narrative-right {
    order: -1;
    height: 42vh;
    min-height: 220px;
    max-height: 380px;
    padding: var(--sp-4) var(--sp-4) var(--sp-2) var(--sp-4);
    flex: 0 0 auto;
    border-bottom: 1px solid var(--border);
    border-right: none;
  }
  .narrative-left {
    order: 1;
    flex: 1 1 0;
    min-height: 0;
    /* Solid background — this is the key to Option A. Guarantees the
       card sits on top of the (fixed) chart canvas visually. */
    background: var(--bg);
    border-top: 1px solid var(--border);
    border-right: none;
    padding: var(--sp-5) var(--sp-5) var(--sp-5) var(--sp-5);
    gap: var(--sp-3);
    justify-content: flex-start;
    overflow-y: auto;
    overflow-x: hidden;
    -webkit-overflow-scrolling: touch;
    /* Subtle top glow to signal "card floats above chart". */
    box-shadow: 0 -8px 24px -8px rgba(0,0,0,0.5);
    position: relative;
    z-index: 1;
  }
  .stat-card { margin-top: var(--sp-1); margin-bottom: var(--sp-2); }

  /* Left-align long body copy on mobile to avoid Spanish justify gaps */
  .narrative-body,
  .intro-subtitle,
  .verdict-header .narrative-body,
  .context-body { text-align: left; }

  /* Verdict slide: stack chart above text with breathing room */
  .verdict-layout { gap: 1.5rem; }
  .verdict-chart-wrap { min-height: 240px; margin-bottom: var(--sp-1); }

  /* Intro CTAs side-by-side */
  .intro-actions {
    flex-wrap: nowrap;
    gap: var(--sp-2);
    width: 100%;
    max-width: 420px;
  }
  .intro-actions > .btn-primary,
  .intro-actions > .btn-ghost {
    flex: 1 1 0;
    padding: var(--sp-3) var(--sp-3);
    font-size: var(--fs-meta);
    white-space: nowrap;
    text-align: center;
  }

  /* Motivation slide: single column, top-anchored so it doesn't feel
     stranded in the middle on tall phones. */
  .slide-motivation .motivation-layout {
    padding: var(--sp-6) var(--sp-4) 80px;
    justify-content: flex-start;
    gap: var(--sp-3);
  }
  .slide-motivation .motivation-pull { padding-left: var(--sp-3); }

  /* Context slide: single column */
  .slide-context {
    padding: var(--sp-6) var(--sp-5) 80px;
    align-items: flex-start;
  }
  .context-layout {
    grid-template-columns: 1fr;
    gap: var(--sp-5);
  }

  /* Squad slide: 2-column grid on phone — stacked list felt monotonous
     when the copy above already runs long. Two tighter tiles per row keeps
     the grid identity from desktop and lets more roster surface at once. */
  .squad-header { padding: 1.4rem 1.2rem 0.8rem; }
  .squad-grid { grid-template-columns: repeat(2, 1fr); }
  .squad-card { padding: 0.75rem 0.7rem; }
  .squad-card-name { font-size: 14px; letter-spacing: -0.005em; }
  /* Star/bench/ghost overrides scale down proportionally in the 2-col grid */
  .card-star .squad-card-name { font-size: 15px; }
  .card-bench .squad-card-name { font-size: 14px; }
  .card-ghost .squad-card-name { font-size: 14px; }
  .squad-card-top { gap: 0.4rem; }
  .squad-stat-badge { padding: 0.25rem 0.45rem; }
  .squad-stat-val { font-size: 15px; }

  /* Score explainer: stack the formula vertically on phones.
     Pills become full-width, plus/equals become horizontal dividers.
     .slide is display:flex so the layout was being clamped to the
     slide's content-height (~732px), letting children overflow past
     the layout's padding-bottom and get hidden behind the fixed nav.
     flex-shrink:0 lets the layout grow to fit its content + padding. */
  .score-explainer-layout {
    padding: var(--sp-5) var(--sp-4);
    padding-bottom: calc(40px + env(safe-area-inset-bottom, 0px));
    gap: var(--sp-3);
    justify-content: flex-start;
    min-height: 0;
    flex: 0 0 auto;
  }
  .score-formula {
    grid-template-columns: 1fr;
    gap: var(--sp-1);
  }
  .score-pill,
  .score-total {
    min-height: 0;
    padding: var(--sp-3);
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: var(--sp-2);
  }
  .score-pill-key { flex: 0 0 auto; }
  .score-pill-detail { flex: 1 1 100%; order: 3; margin-top: 2px; }
  .score-pill-value { margin-top: 0; font-size: 22px; flex: 0 0 auto; }
  .score-plus,
  .score-equals {
    padding: var(--sp-1) 0;
    font-size: 22px;
  }
  .score-total {
    flex-direction: row;
    padding: var(--sp-4);
  }
  .score-total-value { font-size: 40px; }

  /* Slide nav: pinned + compact */
  /* Mobile nav overrides: fill the row edge-to-edge so both CTAs get
     the full-width, tap-friendly feel. Lift the desktop 240px cap. */
  .slide-nav {
    padding: var(--sp-3) var(--sp-3);
    gap: var(--sp-2);
    min-height: 64px;
    justify-content: stretch;
  }
  .slide-nav > .btn-primary,
  .slide-nav > .btn-ghost {
    min-height: 44px;
    max-width: none;
    padding: var(--sp-3) var(--sp-3);
  }
  .slide-nav .nav-slots.as-lang-actions .intro-lang-btn { max-width: none; }
  .intro-lang-btn {
    padding: var(--sp-3) var(--sp-3);
    min-height: 44px;
  }
  /* Top nav shifts left on phones so it doesn't crowd the edge. */
  .intro-top-nav {
    top: var(--sp-3);
    right: var(--sp-3);
    gap: var(--sp-2);
    font-size: 9px;
    letter-spacing: 0.08em;
  }
}

/* ── 641–1024px · Tablets, small laptops ──────────────────────── */
@media (min-width: 641px) and (max-width: 1024px) {
  .narrative-layout {
    grid-template-columns: 48% 52%;
  }
  .narrative-left  { padding: var(--sp-5) var(--sp-4) var(--sp-5) var(--sp-5); }
  .narrative-right { padding: var(--sp-5) var(--sp-4) var(--sp-4) var(--sp-3); }
}

/* ── ≥ 641px · Verdict horizontal layout ──────────────────────── */
@media (min-width: 641px) {
  .slide-verdict { padding: 2.5rem 3rem; }
  .verdict-layout {
    flex-direction: row;
    align-items: center;
    gap: 2.5rem;
  }
  .verdict-header    { flex: 0 0 300px; }
  .verdict-chart-wrap { flex: 1; min-height: 280px; }
}

/* ── Ceiling archetypes slide ───────────────────────────────── */
.slide-ceiling {
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  padding: 1.75rem 1.5rem 5rem;   /* bottom pad clears the global nav dots */
  overflow-y: auto;
  overflow-x: hidden;
  -webkit-overflow-scrolling: touch;
}
.ceiling-layout {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
  flex: 1;
  max-width: 960px;
  width: 100%;
  margin: 0 auto;
}
.ceiling-header {
  max-width: 640px;
}
.ceiling-header .country-eyebrow { margin-bottom: 0.4rem; }
.ceiling-header .ceiling-archetype {
  color: var(--accent, #e8007d);
  margin-bottom: 0.55rem;
}
.ceiling-header .narrative-headline {
  font-size: 20px;
  margin-bottom: 0.55rem;
}
.ceiling-header .narrative-body {
  font-size: var(--fs-caption);
  line-height: 1.6;
  opacity: 0.78;
  max-width: 620px;
}

.ceiling-panels {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  border-top: 1px solid var(--border);
  padding-top: 0.85rem;
}
.ceiling-panel {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.35rem;
  padding-bottom: 0.7rem;
  border-bottom: 1px dashed var(--border);
}
.ceiling-panel:last-child { border-bottom: none; padding-bottom: 0; }

.ceiling-panel-meta {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
}
.ceiling-panel-label {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  line-height: 1.3;
}
.ceiling-panel-blurb {
  font-family: var(--font-mono);
  font-size: 10.5px;
  color: var(--dim);
  opacity: 0.75;
  line-height: 1.5;
}

.ceiling-panel-chart {
  position: relative;
  width: 100%;
  height: 96px;
}
.ceiling-panel-chart canvas {
  width: 100%;
  height: 100%;
  display: block;
}

.ceiling-footnote {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--dim);
  opacity: 0.55;
  line-height: 1.55;
  max-width: 620px;
  margin-top: 0.25rem;
}

/* ── ≥ 641px · Ceiling: side-by-side label + chart per panel ── */
@media (min-width: 641px) {
  .slide-ceiling { padding: 2.5rem 3rem 5rem; }
  .ceiling-header .narrative-headline { font-size: 22px; }
  .ceiling-panels { gap: 0.6rem; padding-top: 1rem; }
  .ceiling-panel {
    grid-template-columns: 220px 1fr;
    align-items: center;
    gap: 1.5rem;
    padding-bottom: 0.75rem;
  }
  .ceiling-panel-chart { height: 108px; }
}

/* ── ≥ 900px · a bit more breathing room ────────────────────── */
@media (min-width: 900px) {
  .ceiling-panel { grid-template-columns: 260px 1fr; }
  .ceiling-panel-chart { height: 118px; }
}
