/* ============================================================
   v2 layer — loaded AFTER ../css/custom.css, never instead of it.
   The base sheet owns the identity (dark slate, --ricci amber =
   Ricci/focusing, --weyl cyan = Weyl/shearing, --good green =
   agreement). This layer adds only what a media-first, demo-heavy
   deck needs and the base sheet has no vocabulary for:

     · a third semantic channel for the TOOL (sft-wick)
     · code / config blocks that read from the back row
     · a left-to-right "machine" flow (input -> engine -> output)
     · full-bleed media slides with a floating caption
     · one-number result callouts
     · a Feynman-diagram strip
     · fragment-stepped build-ups that don't reflow the slide

   Nothing here overrides a base rule except where noted.
   ============================================================ */

:root {
  --tool:      #b98cf5;   /* sft-wick: the machinery itself (violet) */
  --tool-soft: #d3b6fb;
  --tool-ink:  #1a0f2b;   /* text on a solid --tool chip            */
  --code-bg:   #0e1420;
  --code-rule: #22304a;
  --warn:      #f2775e;   /* "this is what breaks" / stale / caveat */
}

.tool { color: var(--tool); font-weight: 600; }
.warn { color: var(--warn); font-weight: 600; }
.chip.tool { color: var(--tool-ink); background: var(--tool); }
.chip.warn { color: #2a0f08; background: var(--warn); }

/* the accent rule under h2.lead is amber->cyan in the base sheet;
   on tool-section slides it becomes violet->cyan so the section
   reads as "the engine" at a glance. */
.reveal section.tool-section h2.lead::after {
  background: linear-gradient(90deg, var(--tool), var(--weyl));
}
.reveal section.tool-section .kicker { color: var(--tool); }

/* ============================================================
   1 · CODE / CONFIG BLOCKS
   Sized for a projector: a 20-line block at 0.46em is unreadable
   from row 8. Cap real content at ~12 lines and let it breathe.
   ============================================================ */

.codecard {
  background: var(--code-bg);
  border: 1px solid var(--code-rule);
  border-radius: 12px;
  box-shadow: 0 12px 34px rgba(0, 0, 0, 0.5);
  text-align: left;
  overflow: hidden;
  display: block;
  margin: 0.3em auto;
}
.codecard .codehead {
  display: flex;
  align-items: center;
  gap: 0.6em;
  padding: 0.4em 0.9em;
  background: #131b2b;
  border-bottom: 1px solid var(--code-rule);
  font-size: 0.46em;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-faint);
  font-weight: 600;
}
.codecard .codehead .dot {
  width: 0.5em; height: 0.5em; border-radius: 50%;
  background: var(--tool); flex: 0 0 auto;
}
.codecard pre,
.reveal .codecard pre {
  margin: 0;
  padding: 0.7em 0.9em;
  background: transparent;
  box-shadow: none;
  font-size: 0.46em;
  line-height: 1.55;
  width: auto;
  max-width: 100%;
  overflow-x: auto;   /* a long line scrolls inside the card, never past it */
}
.codecard code,
.reveal .codecard code {
  font-family: "JetBrains Mono", "SF Mono", ui-monospace, Menlo, Consolas, monospace;
  color: #cfe0f5;
  white-space: pre;
  tab-size: 2;
}

/* hand-rolled tokens — no highlight.js, so the deck stays offline
   and the emphasis is ours, not a generic theme's. */
.codecard .k   { color: var(--tool); }              /* keyword / dict key   */
.codecard .s   { color: var(--good); }              /* string               */
.codecard .n   { color: var(--ricci-soft); }        /* number               */
.codecard .c   { color: var(--ink-faint); font-style: italic; }  /* comment */
.codecard .op  { color: var(--ink-dim); }           /* punctuation          */
.codecard .hl  { color: var(--weyl); font-weight: 600; }         /* the line that matters */
.codecard .out { color: var(--ink-dim); }           /* printed output       */

/* a line the audience should look at: a soft left bar, no background
   flash (background flashes read as an error on a projector). */
.codecard .line-mark {
  display: block;
  border-left: 3px solid var(--weyl);
  margin-left: -1.0em;
  padding-left: calc(1.0em - 3px);
}

/* ============================================================
   2 · THE MACHINE FLOW  (input -> engine -> output)
   ============================================================ */

.flow {
  display: flex;
  align-items: stretch;
  justify-content: center;
  gap: 0.55em;
  margin: 0.5em auto;
  max-width: 46em;
}
.flow > .step {
  flex: 1 1 0;
  min-width: 0;
  background: var(--bg1);
  border: 1px solid var(--rule);
  border-radius: 12px;
  padding: 0.7em 0.75em;
  text-align: center;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 0.3em;
}
.flow > .step .steplabel {
  font-size: 0.5em;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-faint);
  font-weight: 600;
}
.flow > .step .stepbody { font-size: 0.72em; color: var(--ink); line-height: 1.3; }
.flow > .step .stepnote { font-size: 0.54em; color: var(--ink-dim); line-height: 1.25; }
.flow > .step.engine {
  border-color: var(--tool);
  background: linear-gradient(180deg, #1a1330 0%, var(--bg1) 100%);
  box-shadow: 0 0 0 1px rgba(185, 140, 245, 0.22), 0 10px 30px rgba(0, 0, 0, 0.45);
}
.flow > .step.engine .steplabel { color: var(--tool); }
.flow > .arrow {
  flex: 0 0 auto;
  align-self: center;
  color: var(--ink-faint);
  font-size: 1.1em;
  line-height: 1;
}

/* vertical variant for tall slides */
.flow.vertical { flex-direction: column; max-width: 24em; }
.flow.vertical > .arrow { transform: rotate(90deg); }

/* ============================================================
   3 · FULL-BLEED MEDIA
   For the slides that are a single animation and one line of text.
   Use on <section class="bleed"> with data-background-* on the
   section, or wrap an <img>/<video> in .bleedwrap.
   ============================================================ */

.reveal section.bleed { height: 100%; padding: 0; }
.bleedwrap {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
.bleedwrap img,
.bleedwrap video {
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  object-fit: contain;
}
/* Media that is wider than 16:9 leaves a band top and bottom. Pushing it up
   turns that into ONE band at the bottom, which is where the caption sits —
   otherwise the caption lands on the media's own footer text. */
.bleedwrap.top-align { align-items: flex-start; padding-top: 6px; }
/* caption floats over the media, bottom-left, on its own scrim so it
   stays readable whatever frame the animation is on */
.bleedcap {
  position: absolute;
  left: 40px;
  bottom: 34px;
  max-width: 22em;
  text-align: left;
  background: rgba(11, 15, 23, 0.78);
  border: 1px solid var(--rule);
  border-radius: 12px;
  padding: 0.6em 0.85em;
  backdrop-filter: blur(6px);
  z-index: 3;
}
.bleedcap .capkicker {
  font-size: 0.46em; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--ink-faint); font-weight: 600;
}
.bleedcap .captext { font-size: 0.62em; color: var(--ink); line-height: 1.35; margin-top: 0.15em; }
.bleedcap.right { left: auto; right: 40px; }
.bleedcap.top   { bottom: auto; top: 34px; }

/* ============================================================
   4 · ONE-NUMBER RESULT CALLOUTS
   A result the room should remember gets a size, not a sentence.
   ============================================================ */

.stats { display: flex; gap: 1.1em; justify-content: center; align-items: stretch; margin: 0.6em auto; }
.stat {
  flex: 1 1 0;
  min-width: 0;
  background: var(--bg1);
  border: 1px solid var(--rule);
  border-radius: 12px;
  padding: 0.75em 0.7em;
  text-align: center;
}
.stat .statval {
  font-size: 1.55em;
  font-weight: 700;
  line-height: 1.05;
  letter-spacing: -0.02em;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.stat .statval .unit { font-size: 0.46em; font-weight: 600; color: var(--ink-dim); letter-spacing: 0; }
/* reveal's reset flattens sup/sub to the baseline; a stat like 1.4×10⁻¹⁶ needs
   the exponent raised or it reads as a subtraction. */
.reveal sup { font-size: 0.62em; vertical-align: super; line-height: 0; }
.reveal sub { font-size: 0.62em; vertical-align: sub;   line-height: 0; }
.stat .statlab { font-size: 0.52em; color: var(--ink-dim); line-height: 1.3; margin-top: 0.35em; }
.stat.good  .statval { color: var(--good); }
.stat.tool  .statval { color: var(--tool); }
.stat.ricci .statval { color: var(--ricci); }
.stat.weyl  .statval { color: var(--weyl); }
.stat.warn  .statval { color: var(--warn); }

/* ============================================================
   5 · FEYNMAN-DIAGRAM STRIP
   Diagrams read only if they are big; a strip of 3-4 at even
   width beats a grid of 8 at postage-stamp size.
   ============================================================ */

.diagstrip { display: flex; align-items: flex-end; justify-content: center; gap: 1.0em; margin: 0.5em auto; }
.diagstrip .diag { flex: 0 1 auto; text-align: center; }
.diagstrip .diag img { max-height: 30vh; width: auto; display: block; margin: 0 auto; filter: drop-shadow(0 8px 20px rgba(0,0,0,0.45)); }
.diagstrip .diag .diaglab {
  font-size: 0.52em; color: var(--ink-dim); margin-top: 0.4em; line-height: 1.25;
}
.diagstrip .diag .diagorder {
  font-size: 0.46em; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--ink-faint); font-weight: 600;
}
.diagstrip .plus { align-self: center; color: var(--ink-faint); font-size: 0.9em; padding-bottom: 1.6em; }

/* ============================================================
   6 · BUILD-UPS THAT DON'T REFLOW
   reveal's default fragment removes the element from flow while
   hidden, so every step jumps the layout. .steady reserves the
   space up front: only opacity changes.
   ============================================================ */

.reveal .fragment.steady { opacity: 0; visibility: hidden; transition: opacity 0.35s ease; }
.reveal .fragment.steady.visible { opacity: 1; visibility: visible; }

/* dim-then-highlight: prior items recede instead of vanishing */
.reveal .fragment.recede { opacity: 1; }
.reveal .fragment.recede.visible { opacity: 0.32; transition: opacity 0.35s ease; }

/* ============================================================
   7 · SIDE-BY-SIDE COMPARISON (Gaussian vs non-Gaussian, O0 vs full)
   ============================================================ */

.vs { display: flex; gap: 1.0em; align-items: stretch; justify-content: center; margin: 0.4em auto; }
.vs > .side { flex: 1 1 0; min-width: 0; text-align: center; }
.vs > .side .sidehead {
  font-size: 0.55em; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase;
  margin-bottom: 0.4em;
}
.vs > .side.a .sidehead { color: var(--ink-dim); }
.vs > .side.b .sidehead { color: var(--tool); }
.vs > .side img { max-height: 52vh; width: auto; max-width: 100%; display: block; margin: 0 auto; }
.vs > .divider { flex: 0 0 1px; background: var(--rule); }

/* ============================================================
   8 · SMALL PRINT / PROVENANCE
   Every result slide says where the number came from. A talk that
   can point at the script that made the figure is a talk people
   trust; this keeps that line present but quiet.
   ============================================================ */

.prov {
  position: absolute; bottom: 12px; left: 22px; right: 22px;
  font-size: 0.38em; line-height: 1.35;
  color: var(--ink-faint); letter-spacing: 0.03em;
  font-family: "JetBrains Mono", "SF Mono", ui-monospace, Menlo, monospace;
  text-align: left;
}
.prov .warnflag { color: var(--warn); font-weight: 600; }

/* .prov is absolutely positioned, so a slide carrying one must reserve the
   space or the last line of content lands on top of it. :has() does this
   without touching the markup; .provpad is the manual fallback. */
.reveal section:has(> .prov),
.reveal section.provpad { padding-bottom: 2.6em; }

/* ============================================================
   9 · PRINT / PDF EXPORT GUARDS
   ============================================================ */

@media print {
  .reveal .fragment.steady { opacity: 1 !important; visibility: visible !important; }
  .reveal .fragment.recede { opacity: 1 !important; }
  .bleedcap { backdrop-filter: none; background: rgba(11, 15, 23, 0.92); }
}

/* ============================================================
   10 · CLOSING SLIDE
   The take-aways slide carries three long items, two funder
   logos and a provenance line, which together ran 21px past the
   720px canvas. Tighten the logos and the list rhythm rather
   than cutting a take-away.
   ============================================================ */
.reveal ol.takeaways li { margin: 0.5em 0; line-height: 1.34; }
.acklogos { gap: 1.6em; margin-top: 0.9em; }
.acklogos img { height: 68px; padding: 9px 15px; border-radius: 10px; }


/* ============================================================
   9 · BACKUP-SLIDE HEADINGS
   custom.css:49 gives h3 --ink-dim, the same value the body's
   secondary text carries, so a backup slide's title read as less
   important than the prose beneath it.  Backups are a tier down,
   which the size already says; the colour should not say it twice.
   The accent rule comes back at two thirds width, so the slides
   stay in the deck's language without competing with the main
   headlines.
   ============================================================ */
.reveal h3 { color: var(--ink); }
.reveal section .kicker + h3::after {
  content: ""; display: block; width: 1.6em; height: 2px;
  margin: 0.3em auto 0;
  background: linear-gradient(90deg, var(--ricci), var(--weyl));
  border-radius: 2px; opacity: 0.75;
}


/* ============================================================
   10 · IMAGE CAPS IN CANVAS PIXELS, NOT vh
   custom.css sizes every figure in vh, with the comment "never
   taller than the canvas".  That is the intent, but vh resolves
   against the real viewport, while the figure lives inside a
   1280x720 canvas that reveal scales to fit.  The two only agree
   when the window happens to be 720 css px tall.

   Measured on this deck with all fragments shown:

     browser pane, 633x375   overflow NONE
     presentation, 1920x1080 overflow on 4 slides, worst +142px

   The small window is the one an overflow audit is usually run
   in, so the deck measured clean and broke on the projector.
   Same numbers, expressed as NN/100 x 720, which is what the vh
   values were reaching for.  Scoped to v2; custom.css is shared
   with the v1 deck and is left alone.
   ============================================================ */
.reveal img.fig, .reveal video.fig { max-height: 475px; }
.reveal img.media, .reveal video.media { max-height: 475px; }
.reveal .cols .col img.fig, .reveal .cols .col video.fig { max-height: 432px; }
.reveal .cols .col img.fig.tall, .reveal .cols .col video.fig.tall { max-height: 533px; }
.reveal .figcard img, .reveal .figcard svg { max-height: 461px; }
.reveal .diagstrip .diag img { max-height: 216px; }
.reveal .vs > .side img { max-height: 374px; }
