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

html, body {
  background: var(--bg-0);
  color: var(--fg-0);
  font-family: 'Inter', sans-serif;
  -webkit-font-smoothing: antialiased;
  overflow: hidden;
  width: 100vw;
  height: 100vh;
}

a { color: var(--accent-1-text); text-decoration: none; }

/* Stage: scales the 1920x1080 deck to viewport.
   JS computes an explicit translate(px) + scale() so we don't rely on flex
   centering of a child that may be larger than its parent. */
.stage {
  position: fixed;
  inset: 0;
  overflow: hidden;
  background: var(--bg-0);
}

.deck {
  position: absolute;
  top: 0; left: 0;
  width: 1920px;
  height: 1080px;
  transform-origin: top left;
  background: var(--bg-1);
  overflow: hidden;
}

/* Slides — bottom padding reserves room for .slide__footnotes + .slide__number */
.slide {
  position: absolute;
  inset: 0;
  padding: 72px 96px 140px;
  display: none;
  flex-direction: column;
  background: var(--bg-1);
}

.slide.is-active { display: flex; }

/* Eyebrows/kickers (the mini-headers above each title) are retired deck-wide:
   cut for signal-to-noise. Hidden here rather than deleted from 50+ slide
   files so the copy survives in the markup if they ever come back. The
   .kicker rule also covers the 11b-* slides' scoped kickers — their ID-scoped
   styles never set display, so this wins. */
.slide__eyebrow,
.slide .kicker {
  display: none;
}
.slide__eyebrow {
  font-family: 'JetBrains Mono', monospace;
  font-size: 24px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent-1-text);
  margin-bottom: var(--s-4);
}

.slide__title {
  color: var(--fg-0);
  font-size: var(--t-h2);
  font-weight: 800;
  line-height: 1.1;
  letter-spacing: -0.015em;
  margin-bottom: var(--s-5);
}

/* ── section tracker band (injected by js/tracker.js) ──────────────────────
   The talk as a route, floating over the slide — no box, no border. The
   road ahead is a dotted line ending in the pipeline arrowhead; the stretch
   already traveled is solid in the title gradient; section stops are beads
   in the India-map pin recipe; the current slide is a breathing accent
   marker. Section names ride above the line in mono caps. */
.slide .sec-track {
  position: absolute;
  top: 0; left: 0;
  width: 100%; height: 60px;
  overflow: visible;
  pointer-events: none;
}
.slide .sec-track .tr-base {
  stroke: var(--fg-2);
  stroke-width: 3.5;
  stroke-linecap: round;
  stroke-dasharray: 0.5 11;               /* the 23a route texture */
  opacity: .45;
}
.slide .sec-track .tr-arrow { fill: var(--fg-2); opacity: .45; }
.slide .sec-track .tr-fill { stroke-width: 5; stroke-linecap: round; }
.slide .sec-track .tr-tick { fill: var(--fg-2); opacity: .5; }
.slide .sec-track .tr-stop {
  fill: var(--accent-2);
  stroke: var(--bg-1);
  stroke-width: 2.5;
}
.slide .sec-track .tr-stop.is-future {
  fill: var(--bg-2);
  stroke: var(--fg-2);
  stroke-width: 1.5;
  opacity: .8;
}
.slide .sec-track .tr-name {
  font-family: 'JetBrains Mono', monospace;
  font-size: 17px;
  font-weight: 700;
  letter-spacing: 0.1em;
  fill: var(--fg-2);
}
.slide .sec-track .tr-name.is-past { fill: var(--fg-1); opacity: .75; }
.slide .sec-track .tr-name.is-future { opacity: .6; }
.slide .sec-track .tr-name.is-here { font-size: 19px; fill: var(--fg-0); }
.slide .sec-track .tr-now-core {
  fill: var(--accent-2);
  stroke: var(--bg-1);
  stroke-width: 2;
}
.slide .sec-track .tr-now-halo {
  fill: var(--accent-2);
  transform-box: fill-box;
  transform-origin: center;
  animation: tr-breathe 2.4s ease-in-out infinite;
}
@keyframes tr-breathe {
  0%, 100% { transform: scale(1);   opacity: .32; }
  50%      { transform: scale(1.4); opacity: .12; }
}
@media (prefers-reduced-motion: reduce) {
  .slide .sec-track .tr-now-halo { animation: none; opacity: .25; }
}

/* The very last slide (built by tracker.js): the trail takes off — a banner
   of gradient strands from the Close stop, through the arrow, off the
   canvas, plus sparkles. Strand geometry (three sway phases) arrives per
   element as --r0/--r1/--r2 inline custom properties; --fd staggers launch
   and sway phase so the band ripples instead of moving as one. */
.slide .sec-track .tr-strand {
  fill: none;
  stroke-linecap: round;
  stroke-dasharray: 1;      /* with pathLength=1: draw-on units */
  stroke-dashoffset: 1;
}
.slide.is-active .sec-track .tr-strand {
  animation:
    tr-strand-grow 1.1s var(--ease) calc(0.15s + var(--fd, 0) * 0.14s) forwards,
    tr-strand-sway 3.2s ease-in-out calc(var(--fd, 0) * -0.8s) infinite;
}
@keyframes tr-strand-grow { to { stroke-dashoffset: 0; } }
@keyframes tr-strand-sway {
  0%, 100% { d: var(--r0); }
  33%      { d: var(--r1); }
  66%      { d: var(--r2); }
}

.slide .sec-track .tr-spark {
  opacity: 0;
  transform-box: fill-box; transform-origin: center;
}
.slide.is-active .sec-track .tr-spark {
  animation: tr-spark 2.1s ease-in-out calc(0.9s + var(--si, 0) * 0.37s) infinite;
}
@keyframes tr-spark {
  0%, 100% { opacity: 0;  transform: scale(0.2) rotate(0deg); }
  45%      { opacity: 1;  transform: scale(1)   rotate(90deg); }
  70%      { opacity: .6; transform: scale(.7)  rotate(140deg); }
}

@media (prefers-reduced-motion: reduce) {
  .slide .sec-track .tr-strand { stroke-dashoffset: 0; }
  .slide.is-active .sec-track .tr-strand { animation: none; }
  .slide .sec-track .tr-spark { display: none; }
}

/* Window blurred (deck.js toggles this): freeze the band so a covered
   window doesn't burn CPU on animations nobody can see. !important because
   every `animation:` shorthand above implicitly resets play-state to
   `running` at higher specificity. */
body.deck-idle .sec-track * { animation-play-state: paused !important; }

/* slides carrying the band start their content clear of it */
.slide:has(.sec-track) { padding-top: 112px; }

.slide__title--big {
  font-size: var(--t-h1);
  font-weight: 900;
  line-height: 1;
  letter-spacing: -0.025em;
}

.slide__body { flex: 1; min-height: 0; }

.slide__footnotes {
  position: absolute;
  bottom: 32px;
  left: 96px;
  right: 96px;
  border-top: 1px solid var(--border-1);
  padding-top: 16px;
  font-size: 20px;
  color: var(--fg-2);
  /* 1.55 was tuned for the old narrow column, where a single citation wrapped to
     three or four lines and needed the air. Full-bleed, most citations are one
     line and the leading is between entries, not inside them. */
  line-height: 1.45;
  list-style: none;
  /* Stacked, full-bleed. Previously a wrapping flex ROW with each item capped at
     480px, which was the worst of both: citations were squeezed into a narrow
     column and wrapped to three or four lines each, while the other two thirds of
     the slide width sat empty. One citation per line across the full measure is
     both shorter vertically and easier to scan. Slides carrying an inline
     max-width on their <li> were overriding the old cap and have been cleared. */
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.slide__footnotes li { padding-left: 28px; text-indent: -28px; max-width: none; }
.slide__footnotes .num {
  color: var(--accent-1-text); font-weight: 700;
  font-family: 'JetBrains Mono', monospace; margin-right: 8px;
}

.slide__number {
  position: absolute;
  bottom: 32px;
  right: 32px;
  font-family: 'JetBrains Mono', monospace;
  font-size: 20px;
  color: var(--fg-2);
}

/* Speaker notes live inside the slide markup but never render. Borrowed slides
   carry <aside class="notes"> with time budgets; without this they paint. */
aside.notes { display: none; }

/* Gradient text utility — uses lighter -text variants so headings clear AAA
   large at the dimmest point of the gradient. */
.gradient-text {
  background: var(--grad-text);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
}

/* Fragment states — the heart of the step-through system */
.frag {
  transition:
    opacity var(--t-med) var(--ease),
    transform var(--t-med) var(--ease),
    border-color var(--t-med) var(--ease),
    box-shadow var(--t-med) var(--ease),
    background var(--t-med) var(--ease),
    color var(--t-med) var(--ease);
}
.frag.is-pending { opacity: 0.22; }
.frag.is-current { /* component-specific styles applied here */ }
.frag.is-past { opacity: 1; }

/* Multilingual font helpers */
.g-bn { font-family: 'Noto Sans Bengali', sans-serif; }
.g-hi { font-family: 'Noto Sans Devanagari', sans-serif; }
.g-ko { font-family: 'Noto Sans KR', sans-serif; }

/* Letterbox background */
body::before {
  content: ""; position: fixed; inset: 0; background: var(--bg-0); z-index: -1;
}

/* Print: each slide is one page at fragment-final state */
@media print {
  @page { size: 1920px 1080px; margin: 0; }
  html, body, .stage { overflow: visible; height: auto; width: auto; }
  .stage { display: block; position: static; }
  .deck { transform: none !important; width: 1920px; height: auto; }
  .slide { display: flex !important; page-break-after: always; position: relative; height: 1080px; }
  .frag { opacity: 1 !important; }
  .frag.is-pending { opacity: 1 !important; }
}
