/* ---------- explanatory animations ----------
 * Each figure.anim carries data-scene="N" (set by static/js/anim.js).
 * Elements with .sc are hidden unless the current scene lists them
 * (.sc-N) or a scene-specific keyframe animates them in.
 */

:root {
  --af1: #4F7CAC;
  --af2: #86A7CC;
  --af3: #BBD0E6;
  --ok: #3F8F5A;
  --amber: #E0A33A;
  --amber-deep: #B8801E;
}

.anim-row {
  display: grid;
  grid-template-columns: 3fr 2fr;
  gap: 16px;
  align-items: start;
}

@media (max-width: 760px) {
  .anim-row { grid-template-columns: 1fr; }
}

.anim { margin: 0; }

.anim-loss,
.anim-flow {
  max-width: 640px;
  margin: 0 auto 28px;
}

.anim svg {
  display: block;
  width: 100%;
  height: auto;
  background: transparent;
  font-family: inherit;
}

.anim text {
  fill: var(--ink);
  font-size: 14px;
}

.anim .mut { fill: var(--ink-soft); }
.anim .ttl { font-size: 17px; font-weight: 700; }
.anim .small { font-size: 12.5px; }
.anim .pp { transform-box: fill-box; transform-origin: center; }

/* scene gating: leave fast, enter after a short gap so scenes never cross-fade */
.anim .sc { opacity: 0; transition: opacity 0.12s ease; }
.anim[data-scene="0"] .sc-0,
.anim[data-scene="1"] .sc-1,
.anim[data-scene="2"] .sc-2,
.anim[data-scene="3"] .sc-3,
.anim:not([data-scene]) .fin { opacity: 1; transition: opacity 0.3s ease 0.15s; }

/* ---------- controls ---------- */

.anim-bar {
  display: flex;
  align-items: center;
  gap: 4px;
  margin-top: 6px;
}

.anim-dots { display: flex; }

.anim-dot {
  width: 28px;
  height: 28px;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  border-radius: 50%;
}

.anim-dot::before {
  content: "";
  display: block;
  width: 8px;
  height: 8px;
  margin: 0 auto;
  border-radius: 50%;
  background: var(--cream-deep);
  border: 1px solid var(--rule);
  transition: background 0.2s, border-color 0.2s, transform 0.2s;
}

.anim-dot:hover::before { border-color: var(--brown); }

.anim-dot.is-on::before {
  background: var(--terracotta);
  border-color: var(--terracotta);
  transform: scale(1.25);
}

.anim-dot:focus-visible { outline: 2px solid var(--terracotta); outline-offset: -3px; }

.anim-replay {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 28px;
  padding: 3px 11px 3px 9px;
  border: 1px solid var(--rule);
  border-radius: 999px;
  background: #fff;
  color: var(--ink-soft);
  font: inherit;
  font-size: 0.8rem;
  font-weight: 600;
  cursor: pointer;
  transition: color 0.15s, border-color 0.15s;
}

.anim-replay:hover { color: var(--brown); border-color: var(--brown); }
.anim-replay:focus-visible { outline: 2px solid var(--terracotta); outline-offset: 2px; }

.anim-replay svg {
  width: 11px;
  height: 11px;
  fill: currentColor;
}

@media (pointer: coarse) {
  .anim-dot { width: 44px; height: 44px; }
  .anim-replay { min-height: 44px; }
}

/* ---------- captions ---------- */

.anim-caps {
  display: grid;
  margin-top: 4px;
  font-size: 0.95rem;
  color: var(--ink-soft);
  line-height: 1.55;
}

.anim-caps .anim-cap {
  grid-area: 1 / 1;
  opacity: 0;
  transition: opacity 0.12s ease;
}

.anim-caps .anim-cap.is-on,
.anim:not([data-scene]) .anim-cap-static { opacity: 1; transition: opacity 0.3s ease 0.15s; }

.anim-caps b { color: var(--ink); }

/* ---------- keyframes ---------- */

@keyframes anim-pop {
  from { opacity: 0; transform: scale(0.6); }
  to   { opacity: 1; transform: scale(1); }
}

@keyframes anim-fade {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@keyframes anim-rise {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}

@keyframes anim-draw {
  to { stroke-dashoffset: 0; }
}

@keyframes anim-reveal {
  from { width: 0; }
  to   { width: 302px; }
}

@keyframes anim-pulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.35; }
}

@keyframes anim-fill-rect {
  to { fill: var(--terracotta); stroke: var(--terracotta); }
}

@keyframes anim-fill-text {
  to { fill: #fff; }
}

.anim .drawn {
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
}

/* ---------- animation 1: which step-wise target ---------- */

.anim-targets .o-node circle,
.anim-targets .a-node rect {
  fill: #fff;
  stroke: var(--ink-soft);
  stroke-width: 1.4;
}

.anim-targets .node text { font-size: 13px; font-weight: 600; }
.anim-targets .link { stroke: var(--rule); stroke-width: 1.5; }

.anim-targets[data-scene="0"] .node {
  animation: anim-pop 0.4s cubic-bezier(0.2, 0.8, 0.3, 1.2) both;
  animation-delay: calc(var(--i) * 50ms);
}

.anim-targets[data-scene="0"] .link {
  animation: anim-fade 0.25s both;
  animation-delay: calc(var(--i) * 50ms + 40ms);
}

.anim-targets[data-scene="0"] .hist { animation: anim-rise 0.4s both 1.0s; }
.anim-targets[data-scene="0"] .q    { animation: anim-pop 0.35s both 1.3s; }

.anim-targets[data-scene="1"] .bcast { animation: anim-draw 0.6s ease-out both 0.1s; }
.anim-targets[data-scene="1"] .vchip {
  animation: anim-pop 0.3s both;
  animation-delay: calc(0.4s + var(--j) * 90ms);
}
.anim-targets[data-scene="1"] .verdict-1 { animation: anim-rise 0.35s both 1.2s; }

.anim-targets[data-scene="2"] .obs-arrow { animation: anim-draw 0.5s ease-out both 0.1s; }
.anim-targets[data-scene="2"] .obs-head  { animation: anim-fade 0.15s both 0.55s; }
.anim-targets[data-scene="2"] .log       { animation: anim-pop 0.4s both 0.55s; }
.anim-targets[data-scene="2"] .log-line {
  animation: anim-fade 0.2s both;
  animation-delay: calc(0.8s + var(--i) * 50ms);
}
.anim-targets[data-scene="2"] .log-tag   { animation: anim-rise 0.35s both 1.2s; }
.anim-targets[data-scene="2"] .verdict-2 { animation: anim-rise 0.35s both 1.5s; }

.anim-targets[data-scene="3"] .arc {
  animation: anim-draw 0.4s ease-out both;
  animation-delay: calc(0.1s + var(--k) * 0.35s);
}
.anim-targets[data-scene="3"] .arc-head {
  animation: anim-fade 0.15s both;
  animation-delay: calc(0.45s + var(--k) * 0.35s);
}
.anim-targets[data-scene="3"] .a-hit rect {
  animation: anim-fill-rect 0.25s both;
  animation-delay: calc(0.4s + var(--k) * 0.35s);
}
.anim-targets[data-scene="3"] .a-hit text {
  animation: anim-fill-text 0.25s both;
  animation-delay: calc(0.4s + var(--k) * 0.35s);
}
.anim-targets[data-scene="3"] .verdict-3 { animation: anim-rise 0.35s both 1.7s; }

.anim-targets .verdict text { font-size: 14.5px; font-weight: 600; }
.anim-targets .verdict-1 text,
.anim-targets .verdict-2 text { fill: var(--red); }
.anim-targets .verdict-3 text { fill: var(--ok); }

/* ---------- animation 2: sample efficiency ---------- */

.anim-eff .axis { stroke: var(--ink-soft); stroke-width: 1.2; }
.anim-eff .grid { stroke: var(--rule); stroke-width: 1; }
.anim-eff .tick { font-size: 12px; fill: var(--ink-soft); }
.anim-eff .curve-g { fill: none; stroke: #8E7B70; stroke-width: 2; stroke-linejoin: round; }
.anim-eff .curve-c { fill: none; stroke: var(--terracotta); stroke-width: 2.5; stroke-linejoin: round; }
.anim-eff .target { stroke: var(--ink-soft); stroke-width: 1; stroke-dasharray: 4 3; }
.anim-eff .drop { stroke-width: 1.2; stroke-dasharray: 3 3; }
.anim-eff .mk-c .drop { stroke: var(--terracotta); }
.anim-eff .mk-g .drop { stroke: #8E7B70; }
.anim-eff .brk path { fill: none; stroke: var(--terracotta); stroke-width: 1.5; }
.anim-eff .brk text { fill: var(--brown-dark); }

.anim-eff .reveal { width: 0; }
.anim-eff[data-scene="0"] .reveal { animation: anim-reveal 2.6s linear both; }
.anim-eff[data-scene="1"] .reveal,
.anim-eff:not([data-scene]) .reveal { width: 302px; }

.anim-eff[data-scene="0"] .mk-c { animation: anim-fade 0.25s both 1.3s; }
.anim-eff[data-scene="0"] .mk-g { animation: anim-fade 0.25s both 2.08s; }
.anim-eff[data-scene="0"] .brk  { animation: anim-rise 0.35s both 2.4s; }

/* ---------- animation 3: the loss, diagonal to band ---------- */

.anim-loss .gl { stroke: var(--rule); stroke-width: 1; }
.anim-loss .lbl { font-size: 13px; fill: var(--ink-soft); }
.anim-loss .cell text { font-size: 13px; font-weight: 700; }
.anim-loss .cell rect { stroke: #fff; stroke-width: 1; }
.anim-loss .gl { stroke: var(--rule); }
.anim-loss .k0 rect { fill: var(--terracotta); }
.anim-loss .k1 rect { fill: var(--af1); }
.anim-loss .k2 rect { fill: var(--af2); }
.anim-loss .k3 rect { fill: var(--af3); }
.anim-loss .k0 text,
.anim-loss .k1 text { fill: #fff; }
.anim-loss .k2 text,
.anim-loss .k3 text { fill: var(--ink); }

.anim-loss .formula { font-size: 20px; font-weight: 600; }
.anim-loss .formula .sub { font-size: 12px; font-weight: 600; }
.anim-loss .fterm { fill-opacity: 0; transition: fill-opacity 0.35s ease; }
.anim-loss[data-scene="2"] .fterm,
.anim-loss[data-scene="3"] .fterm,
.anim-loss:not([data-scene]) .fterm { fill-opacity: 1; }

.anim-loss .col-hl { fill: none; stroke: var(--amber-deep); stroke-width: 2.5; }

.anim-loss[data-scene="0"] .board { animation: anim-fade 0.5s both; }
.anim-loss[data-scene="0"] .lbl  { animation: anim-fade 0.3s both; animation-delay: calc(0.2s + var(--i) * 30ms); }

.anim-loss[data-scene="1"] .k0 {
  animation: anim-pop 0.3s cubic-bezier(0.2, 0.8, 0.3, 1.2) both;
  animation-delay: calc(0.1s + var(--i) * 80ms);
}
.anim-loss[data-scene="1"] .tag-grpo { animation: anim-rise 0.35s both 0.8s; }

/* scene 2: the band fills row by row (one history, its whole chunk) */
.anim-loss[data-scene="2"] .af {
  animation: anim-pop 0.25s both;
  animation-delay: calc(0.25s + var(--i) * 0.28s + var(--k) * 0.07s);
}
.anim-loss .row-hl { fill: none; stroke: var(--amber-deep); stroke-width: 2.2; }
.anim-loss[data-scene="2"] .row-hl {
  animation: row-flash 0.6s ease-out both;
  animation-delay: calc(0.2s + var(--i) * 0.28s);
}
.anim-loss[data-scene="2"] .tag-af { animation: anim-rise 0.35s both 0.2s; }

@keyframes row-flash {
  0%   { opacity: 0; }
  25%  { opacity: 1; }
  100% { opacity: 0; }
}

.anim-loss[data-scene="3"] .col-hl { animation: anim-pulse 1.2s ease-in-out 0.2s 2 both; }
.anim-loss[data-scene="3"] .col-note { animation: anim-rise 0.35s both 0.3s; }

/* ---------- reduced motion ---------- */

@media (prefers-reduced-motion: reduce) {
  .anim *,
  .anim *::before {
    animation: none !important;
    transition: none !important;
  }
  .anim .drawn { stroke-dashoffset: 0; }
  .anim-eff .reveal { width: 302px; }
  .anim-targets[data-scene="3"] .a-hit rect { fill: var(--terracotta); stroke: var(--terracotta); }
  .anim-targets[data-scene="3"] .a-hit text { fill: #fff; }
}

/* ---------- animation 4: how the loss is computed ---------- */

.anim-flow .o-node circle,
.anim-flow .a-node rect { fill: #fff; stroke: var(--ink-soft); stroke-width: 1.3; }
.anim-flow .node text { font-size: 11.5px; font-weight: 600; }
.anim-flow .link { stroke: var(--rule); stroke-width: 1.5; }
/* the failed rollout is drawn in gray; only its a2 (k = 0) still feeds the GRPO loss */
.anim-flow .fl-fail circle,
.anim-flow .fl-fail rect { fill: #F1EBE6; stroke: #BDB1A8; }
.anim-flow .fl-fail text { fill: #8E7B70; }
.anim-flow .link.fl-fail { stroke: #E6DCD3; }
.anim-flow .box rect { fill: #fff; stroke-width: 1.4; }
.anim-flow .box text { font-size: 13px; font-weight: 700; }
.anim-flow .box-pi rect { stroke: var(--terracotta); }
.anim-flow .box-p rect { stroke: var(--af1); }
.anim-flow .lossbox rect { fill: #fff; stroke-width: 1.6; }
.anim-flow .box-lg rect { stroke: var(--terracotta); }
.anim-flow .box-la rect { stroke: var(--af1); }
.anim-flow .lossbox .l1 { font-size: 15px; font-weight: 700; }
.anim-flow .lossbox .l2 { font-size: 10.5px; fill: var(--ink-soft); }
.anim-flow .ar { fill: none; stroke-width: 1.6; }
.anim-flow .ar-grpo, .anim-flow .ar-pi { stroke: var(--terracotta); }
.anim-flow .ar-af, .anim-flow .ar-p { stroke: var(--af1); }
.anim-flow .ar-sum { stroke: var(--ink-soft); }
.anim-flow .llm-bg { fill: var(--cream-deep); }
.anim-flow .llm-hl { fill: none; stroke: var(--terracotta); stroke-width: 2; }
.anim-flow .llm text { font-size: 11.5px; font-weight: 600; }
.anim-flow .fl-dim { transition: opacity 0.4s; }

/* fills that stay once a scene has established them */
.anim-flow[data-scene="2"] .fl-a2 rect, .anim-flow[data-scene="3"] .fl-a2 rect, .anim-flow:not([data-scene]) .fl-a2 rect { fill: var(--terracotta); stroke: var(--terracotta); }
.anim-flow[data-scene="2"] .fl-a2 text, .anim-flow[data-scene="3"] .fl-a2 text, .anim-flow:not([data-scene]) .fl-a2 text { fill: #fff; }
.anim-flow[data-scene="3"] .fl-af rect, .anim-flow:not([data-scene]) .fl-af rect { fill: var(--af1); stroke: var(--af1); }
.anim-flow[data-scene="3"] .fl-af text, .anim-flow:not([data-scene]) .fl-af text { fill: #fff; }
.anim-flow[data-scene="2"] .fl-dim, .anim-flow[data-scene="3"] .fl-dim, .anim-flow:not([data-scene]) .fl-dim { opacity: 0.3; }

@keyframes anim-fill-af { to { fill: var(--af1); stroke: var(--af1); } }

/* arrows stay drawn in the scenes after the one that draws them */
.anim-flow[data-scene="2"] .ar-grpo, .anim-flow[data-scene="2"] .ar-pi,
.anim-flow[data-scene="3"] .ar-grpo, .anim-flow[data-scene="3"] .ar-pi,
.anim-flow[data-scene="3"] .ar-af, .anim-flow[data-scene="3"] .ar-p,
.anim-flow:not([data-scene]) .ar { stroke-dashoffset: 0; }

/* shared history highlight */
.anim-flow .hist-box { fill: var(--cream-deep); }

/* scene 0 */
.anim-flow[data-scene="0"] .hist-box { animation: anim-fade 0.5s both 0.6s; }
.anim-flow[data-scene="0"] .hist-lbl { animation: anim-rise 0.4s both 0.9s; }
.anim-flow[data-scene="0"] .node { animation: anim-pop 0.35s cubic-bezier(0.2, 0.8, 0.3, 1.2) both; animation-delay: calc(var(--i) * 40ms); }
.anim-flow[data-scene="0"] .link { animation: anim-fade 0.25s both; animation-delay: calc(var(--i) * 40ms + 30ms); }
.anim-flow[data-scene="0"] .badge { animation: anim-fade 0.5s both 0.3s; }
.anim-flow[data-scene="0"] .llm { animation: anim-rise 0.45s both 0.8s; }

/* scene 1 */
.anim-flow[data-scene="1"] .k0 { animation: anim-fade 0.25s both 0.1s; }
.anim-flow[data-scene="1"] .fl-a2 rect { animation: anim-fill-rect 0.3s both 0.15s; }
.anim-flow[data-scene="1"] .fl-a2 text { animation: anim-fill-text 0.3s both 0.15s; }
.anim-flow[data-scene="1"] .ar-grpo { animation: anim-draw 0.45s ease-out both 0.4s; }
.anim-flow[data-scene="1"] .hd-grpo { animation: anim-fade 0.15s both 0.8s; }
.anim-flow[data-scene="1"] .box-pi { animation: anim-pop 0.3s both 0.85s; }
.anim-flow[data-scene="1"] .ar-pi { animation: anim-draw 0.35s ease-out both 1.15s; }
.anim-flow[data-scene="1"] .hd-pi { animation: anim-fade 0.15s both 1.45s; }
.anim-flow[data-scene="1"] .box-lg { animation: anim-pop 0.3s both 1.5s; }

/* scene 2 */
.anim-flow[data-scene="2"] .k123 { animation: anim-fade 0.25s both; animation-delay: calc(0.1s + var(--k) * 0.2s); }
.anim-flow[data-scene="2"] .fl-af rect { animation: anim-fill-af 0.3s both; animation-delay: calc(0.15s + var(--k) * 0.2s); }
.anim-flow[data-scene="2"] .fl-af text { animation: anim-fill-text 0.3s both; animation-delay: calc(0.15s + var(--k) * 0.2s); }
.anim-flow[data-scene="2"] .fl-note { animation: anim-rise 0.35s both 0.5s; }
.anim-flow[data-scene="2"] .ar-af { animation: anim-draw 0.4s ease-out both; animation-delay: calc(0.6s + var(--k) * 0.2s); }
.anim-flow[data-scene="2"] .hd-af { animation: anim-fade 0.15s both; animation-delay: calc(0.95s + var(--k) * 0.2s); }
.anim-flow[data-scene="2"] .box-p { animation: anim-pop 0.3s both; animation-delay: calc(1.0s + var(--k) * 0.2s); }
.anim-flow[data-scene="2"] .ar-p { animation: anim-draw 0.35s ease-out both; animation-delay: calc(1.6s + var(--k) * 0.12s); }
.anim-flow[data-scene="2"] .hd-p { animation: anim-fade 0.15s both; animation-delay: calc(1.9s + var(--k) * 0.12s); }
.anim-flow[data-scene="2"] .box-la { animation: anim-pop 0.3s both 2.15s; }

/* scene 3: sum, then gradients flow back into the shared backbone */
.anim-flow .grad { fill: none; stroke: var(--amber-deep); stroke-width: 2.4; stroke-dasharray: 5 7; stroke-linecap: round; }
.anim-flow .grad-lbl { fill: var(--amber-deep); }
.anim-flow[data-scene="3"] .plus { animation: anim-pop 0.3s both 0.2s; }
.anim-flow[data-scene="3"] .ar-sum { animation: anim-draw 0.35s ease-out both 0.5s; }
.anim-flow[data-scene="3"] .grad-back { animation: grad-back 1.5s linear both 0.9s; }
.anim-flow[data-scene="3"] .grad-fwd { animation: grad-fwd 1.5s linear both 1.1s; }
.anim-flow[data-scene="3"] .grad-lbl { animation: anim-rise 0.35s both 2.0s; }
.anim-flow[data-scene="3"] .llm-bg { animation: llm-flash 1.0s ease-out both 2.1s; }
.anim-flow[data-scene="3"] .llm-hl { animation: anim-pulse 1.2s ease-in-out 2.1s 1 both; }

@keyframes grad-back {
  from { stroke-dashoffset: 0; opacity: 1; }
  85%  { opacity: 1; }
  to   { stroke-dashoffset: 72; opacity: 0; }
}

@keyframes grad-fwd {
  from { stroke-dashoffset: 72; opacity: 1; }
  85%  { opacity: 1; }
  to   { stroke-dashoffset: 0; opacity: 0; }
}

@keyframes llm-flash {
  0%   { fill: var(--cream-deep); }
  30%  { fill: #F3C7A9; }
  100% { fill: var(--cream-deep); }
}

@media (prefers-reduced-motion: reduce) {
  .anim-flow[data-scene="1"] .fl-a2 rect { fill: var(--terracotta); stroke: var(--terracotta); }
  .anim-flow[data-scene="1"] .fl-a2 text { fill: #fff; }
  .anim-flow[data-scene="2"] .fl-af rect { fill: var(--af1); stroke: var(--af1); }
  .anim-flow[data-scene="2"] .fl-af text { fill: #fff; }
}
