/* Extraction figure ({{< extraction >}}): chips in, tokens out, tokens kept.
   The SVG is generated by make_extraction_figure.py, which owns the geometry
   and the step each layer appears at; this file owns colour and motion. Every
   layer is a Reveal fragment with class "custom", so Reveal hides nothing
   itself: each layer's hidden and .visible states are set here. Lengths in px
   are SVG user units. */

.reveal .extraction {
  /* Timing */
  --t-fade: 400ms;
  --t-draw: 700ms;
  --t-feed: 900ms;   /* a chip's trip into the model */
  --t-emit: 600ms;   /* a token's trip out of it */
  --ease: cubic-bezier(.2, .8, .2, 1);

  /* Palette: ink, paper, fonts and the accent (--accent: teal, or the CNG
     theme's yellow) come from the theme; the blue is copied from
     _extensions/dwgodwin/slides/slides.scss. The accent is patches and the
     tokens a strategy keeps, as on the grid-alignment figure; blue is the
     model. */
  --ex-ink: var(--r-main-color, #F2F4F6);
  --ex-paper: var(--r-background-color, #1D232B);
  --ex-pick: var(--accent, #2DD4BF);
  --ex-model: #418BD9;
}

/* Drawn at 1:1, across the slide's text area */
.reveal .extraction svg {
  display: block;
  width: 100%;
  height: auto;
  max-width: none;
  max-height: none;
  overflow: visible;
}

/* ---- Colour ------------------------------------------------------------ */

.reveal .extraction text { fill: var(--ex-ink); }

.reveal .extraction .mono {
  font-family: var(--r-code-font, ui-monospace, monospace);
}

.reveal .extraction :is(.name, .title, .kept text) { font-weight: 700; }

.reveal .extraction :is(.head, .note, .key) { fill-opacity: 0.6; }

.reveal .extraction .label {
  letter-spacing: 0.18em;
  fill-opacity: 0.7;
}

.reveal .extraction #model .wire {
  fill: none;
  stroke: var(--ex-ink);
  stroke-width: 2;
  stroke-opacity: 0.5;
}

.reveal .extraction #model .tip {
  fill: var(--ex-ink);
  fill-opacity: 0.5;
}

.reveal .extraction #model .block {
  fill: color-mix(in srgb, var(--ex-model) 22%, var(--ex-paper));
  stroke: var(--ex-model);
  stroke-width: 2.5;
  stroke-linejoin: round;
}

/* ---- Inputs: the chips this model doesn't take step back --------------- */

.reveal .extraction .unused {
  transition: opacity var(--t-fade) var(--ease);
}

.reveal .extraction svg:has(.patchify.visible) .unused {
  opacity: 0.25;
}

/* ---- Patch grids: drawn over the chips the model takes ----------------- */

.reveal .extraction :is(.patchify, .ghost) path {
  fill: none;
  stroke: var(--ex-pick);
  stroke-width: 0.8;
  stroke-opacity: 0.55;
}

.reveal .extraction .patchify path {
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  transition: stroke-dashoffset 250ms ease-in;
}

.reveal .extraction .patchify.visible path {
  stroke-dashoffset: 0;
  transition: stroke-dashoffset var(--t-draw) var(--ease) calc(var(--i) * 80ms);
}

.reveal .extraction .patchify text {
  fill: var(--ex-pick);
  opacity: 0;
  transition: opacity var(--t-fade) var(--ease);
}

.reveal .extraction .patchify.visible text { opacity: 1; }

/* ---- Encode: copies of the chips travel into the model... -------------- */

.reveal .extraction .ghost {
  opacity: 0;
  transform-box: fill-box;
  transform-origin: center;
}

.reveal .extraction .feed.visible .ghost {
  animation: ex-feed var(--t-feed) cubic-bezier(.5, 0, .6, 1) calc(var(--i) * 90ms) backwards;
}

@keyframes ex-feed {
  0% { opacity: 1; transform: none; }
  75% { opacity: 1; }
  100% { opacity: 0; transform: translate(var(--dx), var(--dy)) scale(0.2); }
}

/* ...which lights up as they arrive... */
.reveal .extraction :is(.glow, .glow.visible) {
  fill: var(--ex-model);
  opacity: 0;
}

.reveal .extraction .glow.visible {
  animation: ex-glow 1400ms ease calc(var(--t-feed) * 0.6);
}

@keyframes ex-glow {
  35% { opacity: 0.7; }
}

/* ...and the tokens fly out to their places, in sequence order */
.reveal .extraction .tok {
  opacity: 0;
  transform: translate(var(--dx), var(--dy)) scale(0.2);
  transform-box: fill-box;
  transform-origin: center;
  transition: opacity 200ms, transform 0s 200ms;
}

.reveal .extraction .tok.cls { fill: var(--ex-ink); }

.reveal .extraction .tokens.visible .tok {
  --wait: calc(var(--t-feed) + var(--i) * 4ms);
  opacity: 1;
  transform: none;
  transition: opacity 200ms linear var(--wait), transform var(--t-emit) var(--ease) var(--wait);
}

.reveal .extraction :is(.tokens text, .summary) {
  opacity: 0;
  transition: opacity var(--t-fade) var(--ease);
}

.reveal .extraction :is(.tokens.visible text, .summary.visible) {
  opacity: 1;
  transition-delay: var(--t-feed);
}

/* ---- Strategies: one at a time ----------------------------------------- */

/* While a strategy is shown, the tokens it doesn't keep step back */
.reveal .extraction .cells {
  transition: opacity var(--t-fade) var(--ease);
}

.reveal .extraction svg:has(.pick.visible) .cells {
  opacity: 0.28;
}

.reveal .extraction .pick {
  opacity: 0;
  transition: opacity 200ms;
}

.reveal .extraction .pick.visible { opacity: 1; }

/* A strategy gives way as soon as a later one is shown */
.reveal .extraction .pick:has(~ .pick.visible) { opacity: 0; }

/* The tokens it keeps pop in one by one, each labelled with its index */
.reveal .extraction .kept {
  opacity: 0;
  transform: scale(0.6);
  transform-box: fill-box;
  transform-origin: center;
}

.reveal .extraction .pick.visible .kept {
  opacity: 1;
  transform: none;
  transition: opacity 200ms linear calc(var(--i) * 90ms),
    transform var(--t-fade) var(--ease) calc(var(--i) * 90ms);
}

.reveal .extraction .kept rect {
  fill: var(--ex-pick);
  stroke: var(--ex-paper);
  stroke-width: 2;
}

.reveal .extraction .kept text { fill: var(--ex-paper); }

/* The patch each kept token came from, outlined on the input chips */
.reveal .extraction .source {
  fill: var(--ex-pick);
  fill-opacity: 0.35;
  stroke: var(--ex-pick);
  stroke-width: 2;
}

/* ---- Readout: the strategies as the config writes them ----------------- */

.reveal .extraction :is(.ro-head, .strategy) {
  opacity: 0;
  transition: opacity var(--t-fade) var(--ease);
}

.reveal .extraction .ro-head.visible { opacity: 0.6; }
.reveal .extraction .strategy.visible { opacity: 1; }

/* Strategies already shown stay listed, stepped back */
.reveal .extraction .strategy.visible:has(~ .strategy.visible) { opacity: 0.35; }

.reveal .extraction .strategy :is(.bar, .count) { fill: var(--ex-pick); }

.reveal .extraction .strategy:has(~ .strategy.visible) :is(.bar, .count) { fill: var(--ex-ink); }

/* ---- Reduced motion and print: every state applies at once -------------- */

@media (prefers-reduced-motion: reduce) {
  .reveal .extraction,
  .reveal .extraction * {
    transition: none !important;
    animation: none !important;
  }
}

@media print {
  .reveal .extraction,
  .reveal .extraction * {
    transition: none !important;
    animation: none !important;
  }
}
