/* ---------- "Each frame is decoded as soon as it is generated": #fig-cache (js/cache.js).
 * One looping animation of the frame timeline. Everything here is scoped to #fig-cache.
 * Colors are CSS custom properties only (css/theme.css). The play / pause button is the video players' round
 * button (css/videos.css, .controls .pp). ---------- */

/* Sizes: the view is up to 700 px wide and shows NVIS slots; L is the screen slot of frame t (counting from 0).
 * The window covers the screen slots L-2 to L; the slot at L-3 is the one that just left it. */
#fig-cache .cache-view {
  --nvis: 9; --L: 4; --gap: 30px;
  --pitch: calc(100cqw / var(--nvis));
  --sw: calc(var(--pitch) - 6px);
  --sh: calc(var(--sw) * 0.58);
  position: relative; width: min(100%, 700px); margin-inline: auto; container-type: inline-size;
}

/* Labels */
#fig-cache .lb { font: 400 11px/16px var(--mono); letter-spacing: 0.01em; color: var(--faint); white-space: nowrap; }
#fig-cache .cv-top { display: flex; justify-content: space-between; height: 16px; }
#fig-cache .cv-mid, #fig-cache .cv-bot { position: relative; height: 20px; }
#fig-cache .cv-mid .lb { position: absolute; top: 2px; text-align: center; }
#fig-cache .lb-drop { left: calc((var(--L) - 3) * var(--pitch)); width: var(--pitch); }
#fig-cache .lb-cache { left: calc((var(--L) - 2) * var(--pitch)); width: calc(2 * var(--pitch) - 6px); color: var(--purple); }
#fig-cache .lb-cache::after {
  content: ""; position: absolute; left: 4px; right: 4px; bottom: -4px; height: 4px; border: 1px solid var(--purple); border-bottom: 0;
}
#fig-cache .cv-bot .lb { position: absolute; top: 4px; left: calc((var(--L) - 1) * var(--pitch)); width: calc(3 * var(--pitch) - 6px); text-align: center; color: var(--accent); }

/* The strip: slots move with the track; the window, the arrow and the labels stay put. The two ends fade out. */
#fig-cache .cv-strip {
  position: relative; height: calc(2 * var(--sh) + var(--gap) + 12px); overflow: hidden;
  -webkit-mask-image: linear-gradient(to right, transparent, var(--ink) 11%, var(--ink) 89%, transparent);
  mask-image: linear-gradient(to right, transparent, var(--ink) 11%, var(--ink) 89%, transparent);
}
#fig-cache .cv-track {
  position: absolute; inset: 0;
  transform: translateX(calc((var(--L) - var(--t, 0)) * var(--pitch)));
  transition: transform 0.4s ease-in-out;
}
#fig-cache .fr { position: absolute; top: 6px; left: 0; width: var(--sw); transform: translateX(calc(var(--k, 0) * var(--pitch))); }
#fig-cache .f, #fig-cache .p {
  box-sizing: border-box; width: 100%; height: var(--sh); border: 1px dashed var(--ghost); border-radius: var(--radius);
  transition: background-color 0.25s ease, border-color 0.25s ease, color 0.25s ease, opacity 0.4s ease;
}
#fig-cache .f { display: flex; align-items: center; justify-content: center; font: 500 11px/1 var(--mono); color: var(--ink); }
#fig-cache .p { margin-top: var(--gap); }

/* Feature slots, by role */
#fig-cache .fr[data-role="past"] .f, #fig-cache .fr[data-role="past"] .p { opacity: 0.4; }
#fig-cache .fr[data-role="dropped"] .f { opacity: 0.55; }
#fig-cache .fr[data-role="cache"] .f { border-style: solid; border-color: var(--purple); background: color-mix(in srgb, var(--purple) 14%, var(--ground)); color: var(--purple); }
#fig-cache .fr[data-role="cur"] .f { border-style: solid; border-color: var(--accent); background: var(--accent); color: var(--on-act); }

/* Output slots: dashed until the pixels of that frame are produced */
#fig-cache .fr.done .p {
  border-style: solid; border-color: var(--accent);
  background-color: color-mix(in srgb, var(--accent) 16%, var(--ground));
  background-image: conic-gradient(color-mix(in srgb, var(--accent) 34%, var(--ground)) 25%, transparent 0 50%, color-mix(in srgb, var(--accent) 34%, var(--ground)) 0 75%, transparent 0);
  background-size: 10px 10px;
}

/* The window over t-2, t-1, t, and the arrow from frame t to its pixels */
#fig-cache .cv-win {
  position: absolute; top: 1px; height: calc(var(--sh) + 10px);
  left: calc((var(--L) - 2) * var(--pitch) - 4px); width: calc(3 * var(--pitch) - 6px + 8px);
  border: 2px solid var(--accent); border-radius: 3px; pointer-events: none;
}
#fig-cache .cv-arr {
  position: absolute; width: 16px; height: 24px; top: calc(6px + var(--sh) + 3px);
  left: calc(var(--L) * var(--pitch) + var(--sw) / 2 - 8px);
  color: var(--accent); opacity: 0; transform: translateY(-5px); transition: opacity 0.25s ease, transform 0.25s ease;
}
#fig-cache .cache-view[data-ph="2"] .cv-arr { opacity: 1; transform: none; }
#fig-cache .cv-arr-line { fill: none; stroke: currentColor; stroke-width: 2; }
#fig-cache .cv-arr-head { fill: currentColor; }

/* Play / pause: the button is the video players' (.controls .pp); only its placement is set here. */
#fig-cache .controls { justify-content: center; margin-top: var(--sp-3); }

@media (max-width: 560px) {
  #fig-cache .cache-view { --nvis: 6; --L: 3; }
  #fig-cache .lb-cache::after { left: 2px; right: 2px; }
}
/* Reduced motion: the figure is a still frame. If the reader presses play it moves, because they asked for it. */
@media (prefers-reduced-motion: reduce) {
  #fig-cache .cache-view:not([data-running="true"]) .cv-track,
  #fig-cache .cache-view:not([data-running="true"]) .f,
  #fig-cache .cache-view:not([data-running="true"]) .p,
  #fig-cache .cache-view:not([data-running="true"]) .cv-arr { transition: none; }
}
