/* ============================================================
   Testing in the Age of AI — slide deck styles
   Design tokens mirror brand_guide.html. Components below are
   reused across slides; per-slide one-offs are grouped at the end.
   ============================================================ */

:root {
  /* ─── Backgrounds ─── */
  --bg-deepest:  #060B15;
  --bg-dark:     #0A0F1E;
  --bg-mid:      #0D1B3E;
  --bg-card:     #112240;
  --bg-card-alt: #0F1E38;
  --bg-surface:  #162550;
  /* Slide canvas — subtle diagonal gradient (deepest → card navy) */
  --grad-canvas: linear-gradient(135deg, #060B15 0%, #112240 100%);

  /* ─── Accent / brand ─── */
  --blue:        #2563EB;
  --blue-light:  #3B82F6;
  --sky:         #38BDF8;
  --violet:      #7C3AED;
  --violet-light:#A78BFA;
  --teal:        #0891B2;
  --teal-light:  #22D3EE;
  /* Emphasis accent for big statement titles — the "punch" color.
     Alpenglow coral (Rocky Mountain Ruby refresh): warm sunrise-on-peak
     against the cool navy. Reserved for highlighted words in hero/statement
     slides (+ the closing contact line); sky stays the workhorse for
     eyebrows, icons, small accents. Was cyan #22D3EE (Blastoff Rails). */
  --accent-bright: #FF8A7A;

  /* ─── Mountain motif: layered ridgeline (cover, statement, closing) ───
     Back → front: sky haze, blue haze, solid near-canvas navy. Snow caps
     are a faint warm white; the front edge is a hairline highlight. */
  --ridge-1:    rgba(56,189,248,.16);
  --ridge-2:    rgba(124,58,237,.32);
  --ridge-3:    #0A1530;
  --ridge-snow: rgba(255,214,200,.6);
  --ridge-edge: rgba(255,255,255,.14);
  /* Faint black silhouette behind content slides (same ridge shape,
     black at low opacity). Height in stage px; 0 disables it. */
  --ridge-bg-height: 400px;
  --ridge-bg-opacity: .55;

  /* ─── Test categories (slides 8–9) — mapped onto the brand accents.
         Light variants so the badge text clears AA on the card navy.
         Was the pink-spectrum trio (blush / fuchsia / crimson) pre-RMR. ─── */
  --cat-unit:    var(--teal-light);     /* Unit — fast, cheap, foundational */
  --cat-system:  var(--violet-light);   /* System — moderate */
  --cat-e2e:     var(--accent-bright);  /* End-to-end / integration — slow, expensive */

  /* ─── Precious metals (actor pills): shimmery gradients + a solid
         reference tone. AI = silver, Human = gold, Collab = rose-gold. ─── */
  --silver:    #C4CDDA;
  --gold:      #E7C66B;
  --rose-gold: #E5A99B;
  --grad-silver:    linear-gradient(135deg,#EAEFF6 0%,#B6C1D2 45%,#F2F6FB 55%,#9AA7BC 100%);
  --grad-gold:      linear-gradient(135deg,#F6E4A6 0%,#D6AE42 45%,#FBF1C7 55%,#C49A3C 100%);
  --grad-rose-gold: linear-gradient(135deg,#F6CFC4 0%,#D08C7E 45%,#F9DCD4 55%,#C2786C 100%);

  /* ─── Text ─── */
  --text-primary:   #FFFFFF;
  --text-secondary: #E2E8F0;
  --text-muted:     #94A3B8;
  --text-dim:       #64748B;

  /* ─── Borders ─── */
  --border-subtle: #1E3A5F;
  --border-hover:  #2D4A6F;
  /* Code-window frame — brighter slate so the window edge survives a
     projector (the old GitHub-gray #30363D washed out on dark). The
     inner bar divider stays a touch darker to avoid a loud double-line. */
  --code-border:       #5B7086;
  --code-border-inner: #3A4656;

  /* ─── Typography ─── */
  --font-display: 'Outfit', sans-serif;
  --font-body:    'Source Sans 3', sans-serif;
  --font-code:    'JetBrains Mono', monospace;

  /* Stage dimensions (the fixed design canvas) */
  --stage-w: 1920px;
  --stage-h: 1080px;
}

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

body {
  background: var(--bg-deepest);
  height: 100vh;
  overflow: hidden;
  font-family: var(--font-body);
}

/* ============================================================
   Deck chrome: progress bar, slide counter, help overlay.
   (Navigation behaviour lives in scripts.js — keyboard, touch,
   presenter mode. There are no on-screen prev/next buttons.)
   ============================================================ */

.viewport {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  background: var(--bg-deepest);
}

/* The stage is a fixed 1920x1080 canvas, scaled by JS to fit. */
.stage {
  width: var(--stage-w);
  height: var(--stage-h);
  position: relative;
  transform-origin: center center;
  flex-shrink: 0;
}

/* Progress bar pinned to the very top */
.progress-track {
  position: fixed;
  top: 0; left: 0; right: 0;
  height: 4px;
  background: color-mix(in srgb, var(--border-subtle) 80%, transparent);
  z-index: 20;
}
.progress-track .progress {
  height: 100%;
  width: 0;
  background: linear-gradient(90deg, var(--blue), var(--violet), var(--sky));
  transition: width 0.3s ease;
}

/* Slide counter, bottom-right */
.slide-num {
  position: fixed;
  bottom: 16px;
  right: 28px;
  font-family: var(--font-code);
  font-size: 18px;
  color: var(--text-muted);
  z-index: 20;
}
/* Hide the counter while presenting (F toggles fullscreen); the presenter
   window still shows slide numbers. */
:fullscreen .slide-num,
:-webkit-full-screen .slide-num { display: none; }

/* Keyboard-shortcut help overlay (toggled with H / ? ) */
.help-overlay {
  position: fixed;
  inset: 0;
  z-index: 30;
  display: none;
  align-items: center;
  justify-content: center;
  background: color-mix(in srgb, var(--bg-deepest) 88%, transparent);
  backdrop-filter: blur(4px);
}
.help-overlay.visible { display: flex; }
.help-card {
  background: var(--bg-card);
  border: 1px solid var(--border-subtle);
  border-radius: 12px;
  padding: 40px 48px;
  min-width: 420px;
}
.help-card h2 {
  font-family: var(--font-display);
  font-size: 27px;
  color: var(--text-primary);
  margin-bottom: 24px;
}
.help-row {
  display: flex;
  justify-content: space-between;
  gap: 40px;
  padding: 10px 0;
  border-bottom: 1px solid color-mix(in srgb, var(--border-subtle) 50%, transparent);
}
.help-row:last-child { border-bottom: none; }
.help-row .keys {
  font-family: var(--font-code);
  font-size: 17px;
  color: var(--sky);
}
.help-row .label {
  font-size: 18px;
  color: var(--text-secondary);
}
.help-hint {
  margin-top: 24px;
  font-size: 16px;
  color: var(--text-dim);
  text-align: center;
}

/* Go-to-slide overlay */
.goto-overlay {
  position: fixed;
  inset: 0;
  z-index: 30;
  display: none;
  align-items: center;
  justify-content: center;
  background: color-mix(in srgb, var(--bg-deepest) 80%, transparent);
  backdrop-filter: blur(4px);
}
.goto-overlay.visible { display: flex; }
.goto-card {
  background: var(--bg-card);
  border: 1px solid var(--border-subtle);
  border-radius: 12px;
  padding: 32px 40px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  min-width: 280px;
}
.goto-label {
  font-family: var(--font-display);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--sky);
}
.goto-input-row {
  display: flex;
  align-items: baseline;
  gap: 10px;
}
.goto-input {
  font-family: var(--font-code);
  font-size: 52px;
  font-weight: 600;
  width: 120px;
  background: transparent;
  border: none;
  border-bottom: 2px solid var(--sky);
  color: var(--text-primary);
  text-align: center;
  outline: none;
  -moz-appearance: textfield;
}
.goto-input::-webkit-outer-spin-button,
.goto-input::-webkit-inner-spin-button { -webkit-appearance: none; }
.goto-total {
  font-family: var(--font-code);
  font-size: 22px;
  color: var(--text-dim);
}
.goto-hint {
  font-size: 14px;
  color: var(--text-dim);
}

/* ============================================================
   Slide base
   ============================================================ */

.slide {
  position: absolute;
  inset: 0;
  background: var(--grad-canvas);
  padding: 40px 67px 64px;
  display: none;
  flex-direction: column;
  overflow: hidden;
}
.slide.active { display: flex; }
/* Mountain motif — faint black ridge silhouette on every content slide.
   Drawn as a ::before behind the slide's in-flow content (the slide is an
   isolated stacking context, so z-index:-1 stays above its own background).
   Excluded: slides that carry the colored .ridge (cover, statements, closing)
   and any slide tagged .slide--no-ridge (the test pyramid). */
.slide { isolation: isolate; }
.slide::before {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: var(--ridge-bg-height);
  background: url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 1920 480%22 preserveAspectRatio=%22none%22%3E%3Cpolygon fill=%22rgba(0,0,0,.22)%22 points=%220,260 180,170 320,230 470,120 600,190 760,90 900,180 1040,110 1180,200 1330,130 1470,210 1620,140 1780,220 1920,160 1920,480 0,480%22/%3E%3Cpolygon fill=%22rgba(0,0,0,.30)%22 points=%220,340 150,290 300,330 430,240 560,300 720,210 880,290 1010,220 1150,300 1300,250 1440,320 1590,260 1740,330 1920,280 1920,480 0,480%22/%3E%3Cpolygon fill=%22rgba(0,0,0,.42)%22 points=%220,420 200,380 380,410 520,350 680,400 840,330 1000,390 1160,340 1320,400 1500,360 1680,410 1820,370 1920,395 1920,480 0,480%22/%3E%3C/svg%3E") center bottom / 100% 100% no-repeat;
  opacity: var(--ridge-bg-opacity);
  pointer-events: none;
  z-index: -1;
}
.slide:has(> .ridge)::before,
.slide--no-ridge::before { content: none; }

/* Progressive-reveal fragments: hidden but still occupying their final
   layout slot (so earlier items never shift), revealed one step at a time. */
.fragment {
  opacity: 0;
  transform: translateY(10px);
  transition: opacity 0.35s ease, transform 0.35s ease;
}
.fragment.is-revealed {
  opacity: 1;
  transform: translateY(0);
}

/* Statically hidden step: occupies its final layout slot but never shows.
   Used by duplicated "progressive series" slides so the list never shifts. */
.ghost { visibility: hidden; }

/* Already-introduced item in a progressive series: still visible but dimmed,
   so focus stays on the newest item while prior ones recede. */
.muted { opacity: 0.34; transition: opacity 0.3s ease; }

/* The just-introduced item fades in a beat AFTER the slide appears, so the
   already-muted ones read first and the new one arrives on its own. The
   `both` fill keeps it invisible through the delay. */
.slide.active .principle-enter {
  animation: principleEnter 0.45s ease 0.2s both;
}
@keyframes principleEnter {
  from { opacity: 0; transform: translateY(16px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* AI flow: on arrival the newest step transitions in while prior steps stay
   put. The newest step is the live segment just before the first ghost (or the
   last live segment); on the first flow slide it's the Generate step itself. */
.slide.active .flow-step:first-child:has(+ .flow-seg.ghost),
.slide.active .flow-seg:not(.ghost):has(+ .flow-seg.ghost),
.slide.active .flow-seg:not(.ghost):last-child {
  animation: principleEnter 0.45s ease 0.2s both;
}

/* Thank-you slide: the green "# Finished" comment and the passing-result line
   stay hidden, then fade in a beat after the slide arrives (comment first,
   then the verification). opacity:0 via the `both` fill holds their lines so
   the code block never reflows. */
.slide.active .finish-reveal {
  animation: principleEnter 0.5s ease 0.6s both;
}
.slide.active .finish-reveal--result {
  animation-delay: 1s;
}

/* Variants */
.slide--dark { background: var(--grad-canvas); }
.slide--wide-pad { padding-left: 96px; padding-right: 96px; }
.slide--center {
  align-items: center;
  justify-content: center;
  text-align: center;
}

/* Centered one-line (or two-line reveal) statement headline */
.statement {
  font-family: var(--font-display);
  font-size: 92px;
  font-weight: 700;
  color: var(--text-primary);
  line-height: 1.15;
  position: relative;
  z-index: 1;
}
.statement .accent { color: var(--accent-bright); }
.statement > .fragment {
  display: block;
  margin-top: 0.35em;
}

/* ============================================================
   Slide header: eyebrow + title + accent rule
   ============================================================ */

.slide-head { margin-bottom: 40px; flex-shrink: 0; }

.eyebrow {
  font-family: var(--font-display);
  font-size: 20px;
  font-weight: 600;
  color: var(--sky);
  letter-spacing: 0.18em;
  margin-bottom: 14px;
}

.slide-title {
  font-family: var(--font-display);
  font-size: 54px;
  font-weight: 700;
  color: var(--text-primary);
  line-height: 1.15;
}
.slide-title::after {
  content: "";
  display: block;
  width: 100px;
  height: 4px;
  margin-top: 16px;
  background: var(--blue);
  border-radius: 2px;
}
.slide-title--sky::after { background: var(--sky); }

/* Optional one-line lead under the header */
.slide-lead {
  font-family: var(--font-body);
  font-size: 33px;
  color: var(--text-secondary);
  margin-top: 18px;
}

/* The body fills the remaining vertical space below the header. */
.slide-body { flex: 1; min-height: 0; }

/* ============================================================
   Layout helpers
   ============================================================ */

.grid-2 {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 50px;
  height: 100%;
}
.grid-3 {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 40px;
  height: 100%;
}
.grid-2x2 {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 36px 50px;
  height: 100%;
}
/* Compact 2x2: cards size to content (not full height) with bigger type */
.grid-2x2.compact-cards {
  align-content: center;
  gap: 28px 44px;
}
.compact-cards .numbered-card { padding: 22px 28px; }
.compact-cards .numbered-card__heading { font-size: 42px; }
.compact-cards .numbered-card__sub { font-size: 28px; }

/* Wide list on the left, narrower aside (e.g. a pull-quote) on the right */
.grid-aside {
  display: grid;
  grid-template-columns: 1.45fr 1fr;
  gap: 50px;
  height: 100%;
}
.stack {
  display: flex;
  flex-direction: column;
  gap: 24px;
  height: 100%;
}
.stack--tight { gap: 18px; }
/* Vertical column whose children can flex (e.g. a grid that fills,
   plus a tip rail pinned beneath it) */
.col {
  display: flex;
  flex-direction: column;
  gap: 32px;
  height: 100%;
}
.fill { flex: 1; min-height: 0; }

/* Principle layout: compact bullets on the left, an example region
   (code screenshot / gif / diagram) on the right. Used by the
   "principle" slides so three short points stop stretching to fill
   the slide. Vertically centered; the example carries the height. */
.principle-layout {
  display: grid;
  grid-template-columns: 42fr 58fr;
  gap: 56px;
  height: 100%;
  align-items: center;
}

/* Right column of a principle slide: the example/media region with a
   callout chip pinned to its bottom-right. The media flexes to fill,
   so adding the chip shrinks the box and reserves the corner. */
.principle-media {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 24px;
  height: 100%;
  min-height: 0;
  /* Keep this grid track at its proportional width: without it, a long
     white-space:pre code line forces the 58fr track wider (squeezing the
     bullets) and the windows render wider than the other principle slides. */
  min-width: 0;
}
.principle-media .media-placeholder,
.principle-media .image-frame { width: 100%; flex: 1; min-height: 0; }
/* Code examples on principle slides: every window the same (full) width,
   and small enough that two stack without clipping above the chip. */
.principle-media .code-window { width: 100%; }
.principle-media .code-window__body { font-size: 26px; line-height: 1.55; }
.principle-media .code-window__file { font-size: 18px; }

/* Slim chip callout — light surface, dark-navy text (inverted from the
   dark canvas so it reads as a quiet highlight). Icon + one line; sits
   bottom-right of a principle slide. Shrinks to fit its content. */
.callout-chip {
  display: inline-flex;
  align-items: center;
  gap: 14px;
  align-self: flex-end;
  max-width: 100%;
  padding: 15px 26px;
  border-radius: 8px;
  background: var(--text-secondary);
}
.callout-chip i { font-size: 28px; color: var(--bg-mid); flex-shrink: 0; }
.callout-chip span {
  font-family: var(--font-display);
  font-size: 28px;
  font-weight: 600;
  color: var(--bg-mid);
  line-height: 1.25;
}

/* ============================================================
   Bullets: a light, boxless list (icon + line + optional desc).
   Sizes to content and centers vertically — the opposite of a
   stretched rail. Accent via --c / icon via --ic (colour modifiers).
   ============================================================ */

.blist {
  display: flex;
  flex-direction: column;
  gap: 36px;
  justify-content: center;
  height: 100%;
}
.blist--tight { gap: 24px; }
.bullet {
  --c: var(--blue);
  --ic: var(--c);
  display: flex;
  gap: 20px;
  align-items: flex-start;
}
.bullet > i {
  font-size: 38px;
  color: var(--ic);
  margin-top: 4px;
  flex-shrink: 0;
}
.bullet__line {
  font-family: var(--font-display);
  font-size: 37px;
  font-weight: 600;
  color: var(--text-primary);
  line-height: 1.25;
}
.bullet__desc {
  font-family: var(--font-body);
  font-size: 27px;
  color: var(--text-muted);
  line-height: 1.4;
  margin-top: 6px;
}

/* ============================================================
   Card: surface with a colored top accent stripe.
   Accent is driven by --c (set via a colour modifier).
   --ic optionally overrides the icon colour (defaults to --c).
   ============================================================ */

.card {
  --c: var(--blue);
  --ic: var(--c);
  background: var(--bg-card);
  border: 1px solid var(--border-subtle);
  border-top: 4px solid var(--c);
  border-radius: 8px;
  padding: 28px 32px;
  overflow: hidden;
}

/* Colour modifiers — shared by .card, .rail, .badge, .num, etc. */
.is-blue   { --c: var(--blue); }
.is-sky    { --c: var(--sky); }
.is-violet { --c: var(--violet); }
.is-teal   { --c: var(--teal); }
.is-coral  { --c: var(--accent-bright); }   /* alpenglow punch as a panel accent — use sparingly */
.is-unit   { --c: var(--cat-unit); }
.is-system { --c: var(--cat-system); }
.is-e2e    { --c: var(--cat-e2e); }
.icon-sky  { --ic: var(--sky); }
/* `.bullet` resets --ic locally, so reach into it when icon-sky is set. */
.icon-sky .bullet { --ic: var(--sky); }

/* A big index number, e.g. "01", in the accent colour */
.num {
  font-family: var(--font-display);
  font-weight: 700;
  color: var(--c);
  line-height: 1;
}

/* ============================================================
   Rail: a row card with a left accent border (no top stripe).
   ============================================================ */

.rail {
  --c: var(--blue);
  --ic: var(--c);
  background: var(--bg-card);
  border: 1px solid var(--border-subtle);
  border-left: 4px solid var(--c);
  border-radius: 0 8px 8px 0;
  padding: 24px 28px;
}
.rail__row {
  display: flex;
  align-items: center;
  gap: 16px;
}
.rail__num {
  font-family: var(--font-display);
  font-size: 32px;
  font-weight: 700;
  color: var(--sky);
  min-width: 30px;
}
.rail__title {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-bottom: 10px;
}
.rail__desc {
  font-family: var(--font-body);
  font-size: 30px;
  color: var(--text-muted);
  margin-left: 38px;
  line-height: 1.4;
}

/* ============================================================
   Typographic / inline elements
   ============================================================ */

.icon { color: var(--ic); vertical-align: middle; }

/* Panel icons are always sky (light blue), regardless of the panel's
   accent — the panel's colour shows in its border/edge, the icon stays
   consistent. (Flow-step icons already sky below; chip icons opt out by
   not using .icon.) */
.rail .icon,
.card .icon,
.tip .icon,
.harness-card .icon,
.review-row .icon,
.decision .icon { color: var(--sky); }
/* Harness-focus cards (Rules / Skills / References): the head icon takes the
   card's accent so it matches the edge (exception to "panel icons are sky"). */
.harness-focus .card .icon { color: var(--c); }

/* ============================================================
   "Why We Test" spotlight (slide 5): pills on the left, a big
   accent icon on the right that swaps in — on a slight beat —
   as each pill is revealed.
   ============================================================ */
.why-grid {
  display: grid;
  grid-template-columns: 1fr 1fr; /* match slides 4 & 36 */
  gap: 50px;
  align-items: center;
}
.why-pills { height: auto; }
/* Slide 7 panels run a touch tighter than the default .rail. */
.why-pills .rail { padding-top: 18px; padding-bottom: 18px; }
.why-stage {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
  min-height: 0;
}
.why-icon {
  position: absolute;
  font-size: 280px;
  color: var(--sky);
  opacity: 0;
  transform: scale(0.78);
  transition: opacity 0.4s ease, transform 0.4s ease;
}
.why-icon.is-active {
  opacity: 1;
  transform: scale(1);
  /* Let the pill's 0.35s reveal fully finish, then a beat, then arrive. */
  transition-delay: 0.42s;
}
/* Image spotlights (e.g. panel 2) sized to fill the stage, with rounded
   corners. Unlike the glyph icons they arrive with their panel — no beat. */
.why-img {
  width: 100%;
  max-width: 100%;
  max-height: 100%;
  height: auto;
  border-radius: 14px;
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.35);
}
.why-img.is-active { transition-delay: 0s; }

.lead-strong {
  font-family: var(--font-display);
  font-weight: 600;
  color: var(--text-primary);
}

.body-text {
  font-family: var(--font-body);
  color: var(--text-secondary);
  line-height: 1.4;
}

/* Pill / badge */
.badge {
  display: inline-block;
  padding: 4px 14px;
  border-radius: 4px;
  font-family: var(--font-display);
  font-size: 16px;
  font-weight: 700;
  letter-spacing: 0.05em;
  color: var(--c);
  background: color-mix(in srgb, var(--c) 15%, transparent);
  border: 1px solid color-mix(in srgb, var(--c) 30%, transparent);
}

/* Metal actor pill — shimmery gradient fill, dark-navy text. Pick the
   metal with an actor modifier (.is-ai / .is-human / .is-collab).
   Reads clearly on dark cards where a tinted accent pill washes out. */
.badge--metal {
  color: var(--bg-mid);
  background: var(--metal, var(--grad-silver));
  border: none;
}
.is-ai     { --metal: var(--grad-silver); }     /* AI     → silver */
.is-human  { --metal: var(--grad-gold); }       /* Human  → gold   */
.is-collab { --metal: var(--grad-rose-gold); }  /* Collab → rose-gold */

/* Pull-quote card. Accent (--c) is inherited from the card modifier;
   falls back to sky when used standalone. */
.quote {
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.quote__mark {
  font-family: var(--font-display);
  font-size: 90px;
  font-weight: 800;
  color: var(--c, var(--sky));
  line-height: 1;
}
.quote__text {
  font-family: var(--font-body);
  font-size: 33px;
  font-style: italic;
  color: var(--text-secondary);
  line-height: 1.5;
}
.quote__note {
  font-family: var(--font-body);
  font-size: 28px;
  color: var(--text-muted);
  margin-top: 32px;
  line-height: 1.5;
}

/* Image cell — centers its media and clips any overflow as it scales. */
.image-frame {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 0;
  overflow: hidden;
}
.image-frame img {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  border-radius: 8px;
}
/* A growing image needs to spill past its cell as it scales beyond 1×. */
.image-frame:has(.grow-with-fragments) { overflow: visible; }

/* Continuously-playing gif: upscale to fill its half (overrides the default
   intrinsic-size cap). object-fit keeps aspect ratio; let it spill if needed. */
.image-frame:has(.gif-continuous) { overflow: visible; }
.gif-continuous {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

/* Source link pinned to the bottom-left of a slide */
.repo-link {
  position: absolute;
  right: 160px;
  bottom: 28px;
  font-family: var(--font-code);
  font-size: 21px;
  color: var(--accent-bright);
  text-decoration: none;
  opacity: 0.85;
}

/* Media that scales up as fragments are progressively revealed.
   JS sets the transform between data-min-scale and data-max-scale. */
.grow-with-fragments {
  transform: scale(0.9);
  /* Anchor growth to the right edge: it expands leftward over the pills while
     its right side stays on-slide (instead of ballooning past every edge). */
  transform-origin: right center;
  transition: transform 0.45s cubic-bezier(0.22, 0.61, 0.36, 1);
}

/* Right-aligned column of equal-width pills (slide 5). The group sizes to
   its widest child; each pill stretches to that width, so all match. */
.pills-col {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  height: 100%;
}
.pill-group {
  display: flex;
  flex-direction: column;
  gap: 18px;
  width: 768px; /* ≈40% of the 1920px slide */
}
.pill-group .rail { width: 100%; }

/* Framed placeholder for media to be added later (code screenshot,
   gif, diagram). Diagonal hatch reads as "intentionally empty".
   Replace with an <img> (optionally wrapped in .image-frame) when ready.
   Markup: <div class="media-placeholder"><i…></i><span>caption</span></div> */
.media-placeholder {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 16px;
  height: 100%;
  border: 2px dashed var(--border-subtle);
  border-radius: 8px;
  background: repeating-linear-gradient(135deg,
    var(--bg-card) 0 16px, var(--bg-card-alt) 16px 32px);
  color: var(--text-dim);
}
.media-placeholder i { font-size: 58px; color: var(--text-dim); }
.media-placeholder span {
  font-family: var(--font-code);
  font-size: 19px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

/* Slim banner pull-quote — full-width, one line, small inline glyph.
   Accent via --c (defaults to violet). */
.quote-banner {
  --c: var(--violet);
  display: flex;
  align-items: center;
  gap: 22px;
  background: color-mix(in srgb, var(--c) 10%, transparent);
  border: 1px solid color-mix(in srgb, var(--c) 35%, transparent);
  border-radius: 8px;
  padding: 22px 32px;
}
.quote-banner i {
  font-size: 34px;
  color: var(--violet-light);
  flex-shrink: 0;
}
.quote-banner__text {
  font-family: var(--font-body);
  font-size: 32px;
  font-style: italic;
  color: var(--text-secondary);
  line-height: 1.4;
}

/* Inline arrow connector */
.arrow {
  font-family: var(--font-display);
  color: var(--sky);
  align-self: center;
  justify-self: center;
}

/* Small inset tip rail (used at the bottom of a few slides) */
.tip {
  --c: var(--violet);
  background: var(--bg-card);
  border: 1px solid var(--border-subtle);
  border-left: 4px solid var(--c);
  border-radius: 0 8px 8px 0;
  padding: 16px 28px;
  display: flex;
  align-items: center;
  gap: 12px;
  font-family: var(--font-body);
  font-size: 25px;
  color: var(--sky);
}
.tip--italic { font-style: italic; }

/* ============================================================
   Slide 01 — cover
   ============================================================ */

.cover__title {
  position: absolute;
  top: 375px; left: 96px; right: 600px;
  font-family: var(--font-display);
  font-size: 81px;
  font-weight: 800;
  color: var(--text-primary);
  line-height: 1.1;
  letter-spacing: -0.02em;
}
.cover__rule {
  position: absolute;
  top: 500px; left: 96px;
  width: 240px; height: 5px;
  background: var(--sky);
  border-radius: 3px;
}
.cover__subtitle {
  position: absolute;
  top: 530px; left: 96px; right: 600px;
  font-family: var(--font-body);
  font-size: 44px;
  color: var(--text-secondary);
  line-height: 1.5;
}
.cover__meta {
  position: absolute;
  bottom: 60px; right: 96px;
  text-align: right;
}
.cover__meta-name {
  font-family: var(--font-display);
  font-size: 36px;
  font-weight: 600;
  color: var(--text-secondary);
  line-height: 1.2;
}
.cover__meta-event {
  font-family: var(--font-body);
  font-size: 30px;
  color: var(--text-muted);
  margin-top: 8px;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 10px;
}
.cover__meta-event i { line-height: 1; }
/* Mountain motif — layered ridgeline pinned to the slide's bottom edge.
   Markup: <svg class="ridge" aria-hidden="true"><use href="#ridge"/></svg>
   (the #ridge symbol is defined once at the top of the stage in index.html).
   Fills come from the --ridge-* tokens; they inherit into the <use> clone. */
.ridge {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  width: 100%;
  height: 480px;
  pointer-events: none;
  z-index: 0;
}
.ridge--divider { height: 300px; opacity: .9; }  /* statement slides */
.ridge--small   { height: 150px; opacity: .7; }  /* closing slide */
/* Cover text and meta sit above the ridge */
.cover__title, .cover__rule, .cover__subtitle, .cover__meta { z-index: 1; }

/* ============================================================
   Slide 02 — section divider
   ============================================================ */

.divider__wash {
  position: absolute;
  inset: 0;
  background: color-mix(in srgb, var(--blue) 4%, transparent);
}
.divider__kicker {
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 600;
  color: var(--sky);
  letter-spacing: 0.2em;
  margin-bottom: 20px;
}
.divider__title {
  font-family: var(--font-display);
  font-size: 72px;
  font-weight: 700;
  color: var(--text-primary);
}
.divider__sub {
  font-family: var(--font-body);
  font-size: 38px;
  color: var(--text-secondary);
  margin-top: 20px;
}
.divider__rule {
  width: 160px;
  height: 4px;
  background: var(--sky);
  margin-top: 32px;
  border-radius: 2px;
}

/* ============================================================
   Numbered "cover" cards (slide 04 / 07)
   ============================================================ */

.numbered-card {
  display: flex;
  gap: 20px;
  align-items: flex-start;
}
.numbered-card .num { font-size: 49px; }
.numbered-card__heading {
  font-family: var(--font-display);
  font-size: 38px;
  font-weight: 600;
  color: var(--text-primary);
}
.numbered-card__sub {
  font-family: var(--font-body);
  font-size: 25px;
  color: var(--text-muted);
  margin-top: 12px;
}
.numbered-card__title {
  font-family: var(--font-display);
  font-size: 38px;
  font-weight: 600;
  color: var(--text-primary);
  line-height: 1.3;
  margin-top: 4px;
}

/* Thinner principle boxes that size to content and sit centered/spread
   in the frame (used by the Testing Principles overview). */
.grid-2x2.lean-cards {
  align-content: center;
  gap: 32px 50px;
}
.lean-cards .numbered-card {
  padding: 24px 30px;
  align-items: center;
}
.lean-cards .numbered-card__title { margin-top: 0; }

/* Spotlight: a single principle card enlarged and centered, animating in
   from the top-left as if lifted out of the overview grid. */
.principle-spotlight {
  width: min(72%, 920px);
  padding: 52px 60px;
  gap: 32px;
  align-items: center;
}
.principle-spotlight .num { font-size: 84px; }
.principle-spotlight .numbered-card__title { font-size: 54px; margin-top: 0; }
.slide.active .principle-spotlight {
  animation: slide-to-center 0.6s cubic-bezier(0.22, 0.61, 0.36, 1) both;
}
/* Starts roughly where the top-left card sat in the slide-7 grid
   (stage coords ≈ 501,518 vs. centered 960,540), then grows to center. */
@keyframes slide-to-center {
  from { transform: translate(-459px, -22px) scale(0.55); opacity: 0.7; }
  to   { transform: translate(0, 0) scale(1); opacity: 1; }
}

/* ============================================================
   Definition cards (slide 05) — header + accented bullets
   ============================================================ */

.def-head {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-bottom: 36px;
}
.def-head span {
  font-family: var(--font-display);
  font-size: 31px;
  font-weight: 700;
  color: var(--text-primary);
  letter-spacing: 0.08em;
}
.def-bullet {
  display: flex;
  gap: 14px;
  align-items: flex-start;
  margin-bottom: 28px;
}
.def-bullet__mark {
  width: 4px;
  min-height: 50px;
  background: var(--c);
  border-radius: 2px;
  flex-shrink: 0;
  margin-top: 4px;
}
.def-bullet__text {
  font-family: var(--font-body);
  font-size: 29px;
  color: var(--text-secondary);
  line-height: 1.4;
}

/* ============================================================
   Category cards (slide 12 / 15)
   ============================================================ */

.cat-card__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 28px;
}
.cat-card__name {
  display: flex;
  align-items: center;
  gap: 12px;
}
.cat-card__name span {
  font-family: var(--font-display);
  font-size: 38px;
  font-weight: 700;
  color: var(--text-primary);
}
.cat-card__lead {
  font-family: var(--font-display);
  font-size: 29px;
  font-weight: 600;
  color: var(--text-secondary);
  line-height: 1.4;
  margin-bottom: 16px;
}
.cat-card__desc {
  font-family: var(--font-body);
  font-size: 25px;
  color: var(--text-muted);
  line-height: 1.5;
}

/* Horizontal category rows (slide 13): icon · name+detail · speed badge.
   Each row fills an equal share of the slide height. */
.cat-list {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 32px;
  height: 100%;
}
.cat-row {
  --c: var(--blue);
  flex: 1;
  max-height: 215px;
  display: flex;
  align-items: center;
  gap: 36px;
  background: var(--bg-card);
  border: 1px solid var(--border-subtle);
  border-left: 6px solid var(--c);
  border-radius: 0 12px 12px 0;
  padding: 0 48px;
}
.cat-row__icon {
  flex-shrink: 0;
  width: 96px;
  height: 96px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 16px;
  background: color-mix(in srgb, var(--c) 15%, transparent);
  border: 1px solid color-mix(in srgb, var(--c) 35%, transparent);
}
.cat-row__icon i { font-size: 50px; color: var(--sky); }
/* Test-category rows (slide 8): edge, icon-box tint AND the glyph take the
   category color (teal / violet / coral). The compound selector out-ranks the
   .cat-row default above; other cat-rows (e.g. cadence) keep blue + sky. */
.cat-row.is-unit   { --c: var(--cat-unit); }
.cat-row.is-system { --c: var(--cat-system); }
.cat-row.is-e2e    { --c: var(--cat-e2e); }
.cat-row.is-unit   .cat-row__icon i,
.cat-row.is-system .cat-row__icon i,
.cat-row.is-e2e    .cat-row__icon i { color: var(--c); }
.cat-row__body { flex: 1; min-width: 0; }
.cat-row__name {
  font-family: var(--font-display);
  font-size: 40px;
  font-weight: 700;
  color: var(--text-primary);
  line-height: 1.1;
}
.cat-row__lead {
  font-family: var(--font-body);
  font-size: 33px;
  color: var(--text-secondary);
  margin-top: 8px;
}
.cat-row__desc {
  font-family: var(--font-body);
  font-size: 28px;
  color: var(--text-muted);
  margin-top: 6px;
}
.cat-row .badge {
  flex-shrink: 0;
  font-size: 28px;
  padding: 14px 34px;
}

/* ============================================================
   Test pyramid (slide 13)
   ============================================================ */

.pyramid-layout {
  display: grid;
  grid-template-columns: 220px 1fr 240px;
  align-items: center;
  align-content: center;
  height: 100%;
  gap: 20px;
}
.pyramid-axis {
  grid-column: 1;
  grid-row: 1;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  height: 820px;
  position: relative;
  text-align: center;
}
.pyramid-axis::after {
  content: "";
  position: absolute;
  top: 0; bottom: 0; right: -20px;
  width: 2px;
  background: var(--text-dim);
}
.pyramid-axis span {
  font-family: var(--font-body);
  font-size: 26px;
  color: var(--text-muted);
  line-height: 1.4;
}
/* One continuous triangle: the container is clipped to a triangle and the
   three tiers are full-width horizontal bands sliced by that clip — so the
   sloped sides are real, not stepped. DOM order Unit→System→E2E with
   column-reverse renders the base at the bottom and reveals base→apex. */
.pyramid {
  grid-column: 2;
  grid-row: 1;
  width: 1340px;
  height: 780px;
  margin: 0 auto;
  display: flex;
  flex-direction: column-reverse;
  clip-path: polygon(50% 0, 100% 100%, 0 100%);
  filter: drop-shadow(0 18px 38px rgba(0, 0, 0, 0.45));
}
.tier {
  width: 100%;
  height: 260px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;            /* text centered within each slice */
  /* tier boundaries are drawn as elevation lines by .pyramid-topo */
  /* Each tier keeps its own branding color; diagonal top-left → bottom-right. */
  background: linear-gradient(135deg,
              color-mix(in srgb, var(--c) 52%, transparent) 0%,
              color-mix(in srgb, var(--c) 82%, transparent) 100%);
}
/* Elevation overlay (RMR refresh): straight elevation lines replace the tier
   borders and run across the pyramid to a tag on the right — the climb reads as
   a Colorado fourteener: base camp at Denver's 5,280 ft (always on screen),
   Leadville and treeline at the tier boundaries, a coral survey mark at the
   summit. Sits in the same grid cell as .pyramid, on top. Elevation tags are
   technical labels → JetBrains Mono; coral is reserved for the summit group
   (.is-summit) so the punch still means "the top". */
.pyramid-topo {
  grid-column: 2;
  grid-row: 1;
  width: 1340px;
  height: 780px;
  margin: 0 auto;
  overflow: visible;
  pointer-events: none;
}
.pyramid-topo .tick   { stroke: rgba(255,255,255,.45); stroke-width: 2; }   /* reads on the colored bands and on navy */
.pyramid-topo .elev   { font-family: var(--font-code); font-size: 20px; fill: var(--text-muted); letter-spacing: 0.02em; }
.pyramid-topo .elev--name { font-size: 17px; opacity: 0.8; }
/* summit group: coral tick, ring and tag */
.pyramid-topo .is-summit .tick { stroke: var(--accent-bright); }
.pyramid-topo .is-summit .elev { fill: var(--accent-bright); font-weight: 600; font-size: 22px; }
.pyramid-topo .summit-ring { fill: none; stroke: var(--accent-bright); stroke-width: 3; }
.pyramid-topo .summit-dot  { fill: var(--accent-bright); }

/* The apex is clipped to a triangle, so its visible color sits lower than the
   tier box's center — push the text down to center it within the visible slice. */
/* Band heights (sum = 780): a taller Unit base, a narrower System band. */
.tier--unit   { height: 300px; }
.tier--system { height: 220px; }
.tier--e2e { padding-top: 110px; }
.tier--e2e .tier__name { font-size: 23px; }   /* narrow apex slice */
.tier__name {
  font-family: var(--font-display);
  font-size: 28px;
  font-weight: 700;
  color: var(--text-primary);
  letter-spacing: 0.05em;
}
.tier__meta {
  font-family: var(--font-body);
  font-size: 22px;
  color: var(--text-secondary);
  margin-top: 8px;
}

/* ============================================================
   Decision rows (slide 14)
   ============================================================ */

.decision {
  display: flex;
  flex-direction: column;
  gap: 30px;
  height: 100%;
  justify-content: center;
}
.decision-row {
  display: grid;
  grid-template-columns: 1080px 60px 1fr;
  align-items: center;
}
.decision-q {
  background: var(--bg-card);
  border: 1px solid var(--border-subtle);
  border-radius: 8px;
  display: flex;
  align-items: center;
  padding: 0 32px;
  height: 140px;
  font-family: var(--font-body);
  font-size: 27px;
  color: var(--text-secondary);
}
.decision-a {
  background: var(--bg-card);
  border: 1px solid var(--border-subtle);
  border-top: 4px solid var(--c);
  border-radius: 8px;
  display: flex;
  align-items: center;
  padding: 0 32px;
  height: 140px;
  font-family: var(--font-display);
  font-size: 27px;
  font-weight: 600;
  color: var(--text-primary);
}

/* ============================================================
   Review rows (slide 16) — icon box + question
   ============================================================ */

.review-row {
  background: var(--bg-card);
  border: 1px solid var(--border-subtle);
  border-radius: 8px;
  display: flex;
  align-items: center;
  overflow: hidden;
  height: 110px;
}
.review-row__icon {
  width: 80px;
  height: 100%;
  background: var(--bg-card-alt);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.review-row__text {
  padding: 0 28px;
  font-family: var(--font-body);
  font-size: 32px;
  color: var(--text-secondary);
}

/* Detailed review checklist: 2x2 cards, each principle + its three questions */
.rev-check {
  display: flex;
  flex-direction: column;
  padding: 26px 30px;
}
.rev-check__head {
  display: flex;
  align-items: center;
  gap: 16px;
  margin-bottom: 34px;
}
.rev-check__head .num { font-size: 40px; }
/* Reviewing Tests: the red-flag glyphs take the card's accent so each flag
   matches its numeral (exception to "panel icons are sky"). .bullet resets
   --c locally, so the card's accent is carried through a dedicated variable. */
.rev-check { --rev-c: var(--c); }
.rev-check .bullet { --ic: var(--rev-c); }
.rev-check__title {
  font-family: var(--font-display);
  font-size: 36px;
  font-weight: 700;
  color: var(--text-primary);
  line-height: 1.1;
}
.rev-check__qs {
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.rev-check__qs .bullet { gap: 18px; }
.rev-check__qs .bullet > i { font-size: 33px; margin-top: 2px; }
.rev-check__qs .bullet__line { font-size: 33px; font-weight: 300; }
/* The gate above the grid: flag 00 spans both columns as a single strip,
   numeral + title on the left, the one-line rule on the right. */
.grid-2x2.has-gate { grid-template-rows: auto 1fr 1fr; gap: 24px 50px; }
/* With the gate taking a row, tighten the four cards so all three flags fit. */
.has-gate .rev-check:not(.rev-gate) { padding: 20px 30px; }
.has-gate .rev-check__head { margin-bottom: 18px; }
.has-gate .rev-check__qs { gap: 10px; }
.has-gate .rev-check__qs .bullet > i { font-size: 30px; }
.has-gate .rev-check__qs .bullet__line { font-size: 30px; }
.rev-gate {
  grid-column: 1 / -1;
  flex-direction: row;
  align-items: center;
  gap: 40px;
  padding: 18px 30px;
}
.rev-gate .rev-check__head { margin-bottom: 0; flex-shrink: 0; }
.rev-gate__copy {
  font-size: 33px;
  font-weight: 300;
  color: var(--text-primary);
  margin-left: auto;
}

/* ============================================================
   AI flow (slide 18)
   ============================================================ */

.flow {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  height: 100%;
}
.flow-step {
  --c: var(--blue);
  width: 290px;
  flex: 0 0 290px; /* never shrink — keeps every box exactly equal width */
  height: 340px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 24px;
  background: var(--bg-card);
  border: 1px solid var(--border-subtle);
  border-top: 4px solid var(--c);
  border-radius: 8px;
  padding: 24px;
  text-align: center;
}
/* Icons in sky blue so they read clearly against the card. */
.flow-step .icon { color: var(--sky); }
.flow-step__label {
  font-family: var(--font-display);
  font-size: 36px;
  font-weight: 700;
  color: var(--text-primary);
}
.flow-step__badge { margin: 0; }
.flow-step .badge {
  font-size: 24px;
  padding: 8px 24px;
}
/* A reveal segment wraps the connector arrow + the step that follows it,
   so each progressive step brings its arrow in together. */
.flow-seg {
  display: flex;
  align-items: center;
  gap: 12px;
}
.flow-arrow {
  font-family: var(--font-display);
  font-size: 52px;
  font-weight: 300;
  color: var(--sky);
  line-height: 1;
}

/* ============================================================
   Harness cards (slide 19)
   ============================================================ */

.harness-card__head {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-bottom: 24px;
}
.harness-card__head span {
  font-family: var(--font-display);
  font-size: 44px;
  font-weight: 700;
  color: var(--text-primary);
}
.harness-card__desc {
  font-family: var(--font-body);
  font-size: 30px;
  color: var(--text-muted);
  line-height: 1.5;
}
/* Box title relocated to the foot of the card — icon + label, centered,
   revealed after the last bullet and floated a little above the bottom edge. */
.harness-card__foot-title {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
  text-align: center;
}
.harness-card__foot-title span {
  font-family: var(--font-display);
  font-size: 40px;
  font-weight: 700;
  color: var(--text-primary);
}

/* Diagonal harness layout: three cards cascade top-left → centre →
   bottom-right, each revealed as a fragment that drifts in diagonally. */
.harness-diag { position: relative; }
.harness-slot { position: absolute; width: 560px; }
.harness-slot--tl  { top: 0; left: 0; }
.harness-slot--mid { top: 50%; left: 50%; transform: translate(-50%, -50%); }
.harness-slot--br  { bottom: 0; right: 0; }
/* Override the default fragment rise with a diagonal drift toward its slot. */
.harness-diag .fragment { transform: translate(-30px, -30px); }
.harness-diag .fragment.is-revealed { transform: translate(0, 0); }

/* ============================================================
   Focused harness card + its artifact, side by side.
   The card is pinned to the far left — tall and narrow — leaving the bulk of
   the real estate to its artifact (RULE.md / SKILL.md), which reveals on the
   right, runs nearly full height, and is clipped where it overflows.
   ============================================================ */
.harness-focus {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 124px;
  height: 100%;
  /* Pull the block up alongside the title so the artifact reclaims the empty
     right half of the header band and runs taller. */
  margin-top: -100px;
}
.harness-focus__card { flex: 0 0 540px; }
.harness-focus__card .card {
  padding: 48px 44px;
  min-height: 480px;
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.harness-focus__art {
  flex: 1 1 auto;
  align-self: stretch;
  display: flex;
  min-width: 0;
  padding: 4px 0;
}
.harness-focus__art .code-window { width: 100%; }
.harness-focus__art .code-window__body {
  white-space: pre-wrap;
  column-count: 1;
  overflow: hidden;
}

/* ============================================================
   Code window (slide 20)
   ============================================================ */

.code-window {
  background: #0D1117;
  border: 1px solid var(--code-border);
  border-radius: 8px;
  overflow: hidden;
  flex: 1;
}
.code-window__bar {
  height: 44px;
  background: #161B22;
  display: flex;
  align-items: center;
  padding: 0 20px;
  border-bottom: 1px solid var(--code-border-inner);
  position: relative;
}
/* macOS traffic-light buttons: red · yellow · green */
.code-window__dots {
  display: inline-flex;
  align-items: center;
  gap: 11px;
  font-size: 0; /* swallow any stray text node */
}
.code-window__dots span {
  width: 19px;
  height: 19px;
  border-radius: 50%;
  flex-shrink: 0;
}
.code-window__dots span:nth-child(1) { background: #FF5F57; } /* close  */
.code-window__dots span:nth-child(2) { background: #FEBC2E; } /* minimize */
.code-window__dots span:nth-child(3) { background: #28C840; } /* zoom   */
.code-window__file {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  font-family: var(--font-code);
  font-size: 18px;
  color: #5B7086;
}
.code-window__body {
  padding: 24px 32px;
  font-family: var(--font-code);
  font-size: 30px;
  line-height: 2;
  white-space: pre;
  color: #E2E8F0; /* base — any untyped token reads light, never dark */
}
/* Syntax tokens — "Hot pink (dark)" theme on #0D1117 GitHub-dark chrome. */
.tok-kw   { color: #FF49A0; } /* keywords (test/do/end/true) — hot pink */
.tok-str  { color: #5EEAD4; } /* strings — aqua                         */
.tok-fn   { color: #38BDF8; } /* method-def name — sky                  */
.tok-num  { color: #FDE68A; } /* numbers — yellow                       */
.tok-cls  { color: #FFD479; } /* class / constant — gold                */
.tok-call { color: #38BDF8; } /* method call — sky                      */
.tok-sym  { color: #C792EA; } /* symbol / label — violet                */
.tok-txt  { color: #E2E8F0; } /* identifiers / default — off-white      */
.tok-com  { color: #5B7086; } /* comments — muted slate                 */
/* Diff lines — GitHub-dark red/green, full-width tint so the mutation pops. */
.tok-del, .tok-add { display: inline-block; width: 100%; border-radius: 4px; }
.tok-del  { color: #FF7B72; background: rgba(248, 81, 73, 0.15); } /* removed line — red   */
.tok-add  { color: #7EE787; background: rgba(63, 185, 80, 0.15); } /* added line — green   */

/* ── Slide 21 "AI overgenerates" ──
   Step 1 reveals the `.code-tests` wrapper: all four tests cascade in on a
   short stagger. Each `.t-comment` is its own fragment, so the following
   steps fade the four code comments in one per click. Comments fade via
   opacity only (inline spans ignore the default fragment's translateY), and
   opacity:0 still holds each comment's line, so the layout never shifts. */
.gen-tests .code-tests { transform: none; transition: none; }
.gen-tests .test-block { opacity: 0; }
.gen-tests .code-tests.is-revealed .test-block { animation: testCascade 0.4s ease both; }
.gen-tests .code-tests.is-revealed .test-block:nth-of-type(1) { animation-delay: 0.05s; }
.gen-tests .code-tests.is-revealed .test-block:nth-of-type(2) { animation-delay: 0.20s; }
.gen-tests .code-tests.is-revealed .test-block:nth-of-type(3) { animation-delay: 0.35s; }
.gen-tests .code-tests.is-revealed .test-block:nth-of-type(4) { animation-delay: 0.50s; }
@keyframes testCascade { from { opacity: 0; } to { opacity: 1; } }

/* ── Prune duplicate ──
   The four judged tests arrive visible. One click reveals the "Pruned" chip
   (the only .fragment on the slide), and the `:has` hook strikes + dims the
   two delete-flagged blocks so the audience watches them get cut, leaving the
   two keepers bright. Line-through on the block spans descendant code too. */
.prune-cut .test-block.is-cut {
  transition: opacity 0.4s ease, text-decoration-color 0.4s ease;
}
.prune-cut:has(.fragment.is-revealed) .test-block.is-cut {
  opacity: 0.3;
  text-decoration: line-through;
  text-decoration-thickness: 2px;
  text-decoration-color: #FF7B72;
}

/* Light "document" code window — for the Rules / Skills / Tools artifact
   slides interleaved into the harness recap. White GitHub chrome, dark text. */
.code-window--light { background: #FFFFFF; border-color: #D0D7DE; }
.code-window--light .code-window__bar { background: #F6F8FA; border-bottom-color: #D0D7DE; }
.code-window--light .code-window__file { color: #57606A; }
.code-window--light .code-window__body { color: #1F2328; }
.code-window--light .md-h { color: #0550AE; font-weight: 700; }

/* Full markdown source flowed into balanced columns so an entire rules file
   fits a single frame. Lines wrap inside each column. */
.code-window__body--md {
  white-space: pre-wrap;
  column-count: 3;
  column-gap: 44px;
  column-fill: balance;
}

.ai-comment {
  background: #1A2332;
  border: 1px solid var(--border-subtle);
  border-radius: 8px;
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 0 28px;
  height: 70px;
  margin-top: 24px;
}
.ai-comment span {
  font-family: var(--font-body);
  font-size: 25px;
  color: var(--text-muted);
}

/* ============================================================
   Mutant in Action — progressive phase swap
   ============================================================ */

/* Two phases stacked in the same grid cell: the original code with its
   passing tests, then the mutated diff with the same tests. The mutated
   phase is itself a fragment — revealing it fades the original away. */
.mutant-stage { display: grid; flex: 1; min-height: 0; }
.mutant-phase {
  grid-area: 1 / 1;
  position: relative;
  min-height: 0;
  transition: opacity 0.35s ease;
}
.mutant-stage:has(.mutant-phase--mutated.is-revealed) .mutant-phase--original { opacity: 0; }

/* Inside the mutation code window: plain version + diff version stacked.
   Diff version is a fragment that fades in; plain fades out when it arrives. */
.mutant-diff-stage { display: grid; }
.mutant-diff-stage > * { grid-area: 1 / 1; }
.mutant-diff-stage:has(.fragment.is-revealed) .mutant-diff-plain {
  opacity: 0;
  transition: opacity 0.35s ease;
}

/* ============================================================
   Resources (slide 21)
   ============================================================ */

.res-label {
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 600;
  color: var(--sky);
  letter-spacing: 0.15em;
  margin-bottom: 32px;
}
.res-item {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-bottom: 40px;
}
.res-item span {
  font-family: var(--font-body);
  font-size: 31px;
  color: var(--text-secondary);
}
