/* Home hero, right column (#ai-flow in views/home/10-hero.php): the AI flow, stacked. Top: the scenario and
   the four steps (Read, Propose, Decide, Record) as a stepper, lit in turn. Then the stage: a network (the
   records read enter as labelled inputs on the left, one proposal leaves on the right to the Result tag)
   over one slot where each step's screen appears in turn. Under it: the note and Pause motion.
   Three illustrative scenarios, 18s each, 54s loop.
   Without JS or under reduced motion: one static frame (manufacturing line at 02 Propose).
   js/ai-flow.js adds .is-armed, and the loop runs from --af-t0 (5.4s in, 02 Propose complete), so it starts
   on the static frame. Pause motion (WCAG 2.2.2) and a hidden tab pause it via animation-play-state.
   Card look: the shared .decision-card, .dc-*, .meter and .tag from site.css. */
.af {
  --af-edge: color-mix(in srgb, var(--cyan) 20%, var(--navy-line));
  --af-node: color-mix(in srgb, var(--cyan) 55%, var(--navy-line));
  --af-tint: color-mix(in srgb, var(--cyan) 8%, var(--navy-800));
  --af-ride: color-mix(in srgb, var(--cyan) 35%, var(--white));
  --af-t0: -5.4s;
  --af-dot-rest: 1.5; /* seconds of stillness between dot waves, the one value to tune (see the network, under Motion) */
  display: grid;
  gap: var(--s-3);
  min-width: 0;
}
@media (max-width: 1099px) {
  .af { max-width: 560px; }
}

/* ---- Top: the scenario and the four steps ---- */
.af .af-now { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--s-1) var(--s-3); max-width: none; font-size: 15px; line-height: 1.4; }
.af-now-k {
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--on-dark-3);
}
.af-now-v { display: grid; min-width: 0; }
.af-now-v > span { grid-area: 1 / 1; font-weight: 600; color: var(--white); white-space: nowrap; }
.af-now-v > span > span { font-weight: 400; color: var(--on-dark-3); }
.af-steps { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 6px; margin: 0; padding: 0; list-style: none; }
.af-step {
  position: relative;
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 6px;
  min-width: 0;
  padding: 7px 6px 9px;
  background: var(--navy-800);
  border: 1px solid var(--navy-line);
  border-radius: var(--r-control);
  overflow: hidden;
  font-size: 14px;
  font-weight: 600;
  line-height: 1.3;
  color: var(--on-dark-3);
  white-space: nowrap;
}
.af-num { font-family: var(--font-mono); font-size: 12px; font-weight: 400; line-height: 1.3; color: var(--cyan); }
.af-step--2 { border-color: var(--cyan); background-color: var(--af-tint); color: var(--ink); }
.af-step::after {
  content: "";
  position: absolute;
  left: 8px;
  right: 8px;
  bottom: 3px;
  height: 2px;
  border-radius: 1px;
  background: var(--cyan);
  transform-origin: 0 50%;
  opacity: 0;
}
/* phone: the number sits over the name, so four steps fit in one row down to 320px */
@media (max-width: 479px) {
  .af-step { flex-direction: column; align-items: center; gap: 0; padding: 6px 4px 9px; font-size: 13px; }
  .af-num { font-size: 11px; }
}

/* ---- The stage: the network on top, the slot under it ---- */
.af-stage {
  position: relative;
  isolation: isolate;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--s-4);
  min-width: 0;
  padding: var(--s-4) var(--s-3) var(--s-3);
  overflow: hidden;
  background: color-mix(in srgb, var(--navy-800) 60%, transparent);
  border: 1px solid var(--navy-line);
  border-radius: var(--r-decision);
}
.af-net { position: relative; z-index: 0; display: grid; justify-items: center; gap: var(--s-3); min-width: 0; }
/* the graph row, centred: input labels, the network, the Result tag. The network is --af-gh tall (150px) wherever
   the row fits; on narrower phones it shrinks with the stage (cqi of .af-net), net of --af-lw, the two label
   columns at their widest (the longest input label, Paid sessions, 13 characters, and Result, 6: 19ch, with their
   padding, borders and --af-gap), so the row never overflows. A longer label needs more ch in --af-lw.
   On phones the labels shrink with the stage too, with no step at a breakpoint: --af-k runs from 0 (stage 280px
   or less) to 1px (350px or more) and sets their font (10.5-11.5px), padding (1px 4px to 2px 6px) and --af-gap
   (8-18px), and --af-lw is worked out from those, so the network and the gaps between labels only ever grow as
   the screen widens. */
.af-graph {
  --af-k: 1px;
  --af-gap: calc(8px + 10 * var(--af-k));
  --af-px: calc(4px + 2 * var(--af-k));
  /* + 4px: the two labels' borders, + 2px spare */
  --af-lw: calc(19ch + 4 * var(--af-px) + 2 * var(--af-gap) + 6px);
  --af-gh: 150px;
  display: flex;
  height: var(--af-gh);
  font-family: var(--font-mono);
  font-size: calc(10.5px + var(--af-k));
  line-height: 1.4;
}
@supports (width: 1cqi) {
  .af-net { container-type: inline-size; }
  .af-graph {
    --af-k: clamp(0px, (100cqi - 280px) / 70, 1px);
    --af-gh: clamp(84px, (100cqi - var(--af-lw)) / 1.1, 150px);
  }
}
/* input labels: in flow, so the column is as wide as the longest label of the three scenarios and the
   stage makes room for it; rows centred on the input nodes (25%, 50%, 75% of the graph's height) */
.af-ins { position: relative; z-index: 1; flex: none; display: grid; }
.af .af-ins > p {
  grid-area: 1 / 1;
  display: grid;
  grid-template-rows: repeat(3, minmax(0, 1fr));
  align-items: center;
  justify-items: end;
  max-width: none;
  padding: calc(var(--af-gh) / 8) var(--af-gap) calc(var(--af-gh) / 8) 0;
}
/* the Result tag, centred on the output node (50%); the output line runs under its edge, as the input lines
   run under the input labels. Lit (gold) in the static frame: the proposal has reached it. */
.af .af-res { position: relative; z-index: 1; flex: none; display: grid; align-items: center; max-width: none; padding-left: var(--af-gap); }
.af-ins span, .af-res span {
  padding: calc(1px + var(--af-k)) var(--af-px);
  background: var(--navy-800);
  border: 1px solid var(--af-node);
  border-radius: var(--r-control);
  color: var(--white);
  white-space: nowrap;
}
.af-res span { background-color: var(--tint); border-color: var(--cyan); }
/* sized from --af-gh, not from a percentage height, so the stage grid sees the graph's true width */
.af-svg { flex: none; width: calc(var(--af-gh) * 1.1); max-width: none; height: var(--af-gh); overflow: visible; }
.af .af-model { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--s-2); max-width: none; font-family: var(--font-mono); font-size: 12px; line-height: 1.4; color: var(--on-dark-3); }
.af-model .af-swap > span { color: var(--white); white-space: nowrap; }
/* the slot is as tall as the tallest screen, so the hero never changes height; each screen sits centred in it */
.af-slot { display: grid; min-width: 0; }
.af-slot > .af-sc { grid-area: 1 / 1; display: grid; align-items: center; min-width: 0; }
.af-slot .af-card { grid-area: 1 / 1; min-width: 0; }
/* static frame under 340px: the hidden scenarios' labels leave the label column, so the network shown centres */
@media (max-width: 339px) {
  .af:not(.is-armed) .af-ins > .af-sc:not(.af-sc--1) { display: none; }
}

/* the network: edges, one route per scenario, the output line to the Result tag, pulses, nodes */
.af-edges { fill: none; stroke: var(--af-edge); stroke-width: 1; vector-effect: non-scaling-stroke; }
.af-route, .af-res-lit { fill: none; stroke: var(--cyan); stroke-width: 1.5; stroke-linejoin: round; stroke-dasharray: 100; stroke-dashoffset: 0; }
/* the dots, hidden in the static frame: each edge carries its own, a round dot as wide as the stroke (a dash of
   length 0 with a round cap; the 200 gap, twice the edge at pathLength 100, keeps it to one), placed on its
   edge by stroke-dashoffset (Motion) */
.af-pl { opacity: 0; }
.af-pl path { fill: none; stroke: var(--white); stroke-width: 4; stroke-linecap: round; stroke-dasharray: 0 200; }
/* the rider: the dot on each hop of the scenario's gold route and on the line to the Result tag, larger and gold-white */
.af-pl .af-ride, .af-pl--out path { stroke: var(--af-ride); stroke-width: 5.5; }
/* the dot clock: the scenario's seconds (0-18), run on each layer's group (Motion) */
@property --af-s { syntax: '<number>'; inherits: false; initial-value: 0; }
/* worked out once a group from the clock, as numbers its dots inherit: --af-u the seconds into the wave (held at
   the group's --lo/--hi, so its dots restyle only while one of them moves), --af-n the wave's parity, --af-g 0
   or 1 (the gates); --af-p is each dot's own hop, 0 to 1 */
@property --af-u { syntax: '<number>'; inherits: true; initial-value: 0; }
@property --af-n { syntax: '<number>'; inherits: true; initial-value: 0; }
@property --af-g { syntax: '<number>'; inherits: true; initial-value: 0; }
@property --af-p { syntax: '<number>'; inherits: false; initial-value: 1; }
.af-nodes circle { fill: var(--navy-900); stroke: var(--af-node); stroke-width: 1.5; }
.af-nodes--o circle { fill: var(--cyan); stroke: var(--cyan); }

/* static frame: scenario 1 only, at 02 Propose */
.af .af-sc--2, .af .af-sc--3 { opacity: 0; }
.af-read, .af-decide, .af-record { opacity: 0; }

/* ---- Screens: the shared decision card, sized down ---- */
.af .af-card { --dc-pad: 14px; box-shadow: var(--shadow-1); font-size: 13px; line-height: 1.45; color: var(--ink); }
.af .af-card p { max-width: none; color: inherit; }
.af-card .dc-head { flex-wrap: wrap; gap: var(--s-1) var(--s-2); margin-bottom: var(--s-3); }
.af-card .dc-state { font-size: 12px; color: var(--ink-2); }
.af-card .dc-state b { font-weight: 600; color: var(--teal-ink); }
.af-meta, .af-card .dc-head .af-swap { font-family: var(--font-mono); font-size: 12px; line-height: 1.4; color: var(--ink-3); white-space: nowrap; }
.af-card .dc-title { margin-bottom: var(--s-2); font-size: 15px; line-height: 1.35; color: var(--ink); }
.af-card .meter-row { margin-bottom: var(--s-2); }
.af-card .meter { width: min(120px, 100%); height: 6px; gap: 2px; }
.af-card .meter-cell.is-on { animation: none; }
.af .af-card .meter-label { font-size: 12px; color: var(--ink-2); }
.af-card .meter-row:has(> .meter--t90) { padding-top: 18px; }
.af-card .meter--t90::after { font-size: 11px; }
.af-card .dc-reasons { font-size: 12.5px; line-height: 1.45; color: var(--ink-2); }
.af-card .dc-reasons li { grid-template-columns: 20px minmax(0, 1fr); gap: 6px; padding-block: 4px; }
.af-card .dc-reasons li > span:first-child { font-size: 11px; line-height: 1.75; }
.af .af-card .dc-audit {
  margin-top: var(--s-3);
  padding: 8px var(--dc-pad) 10px;
  font-family: var(--font-mono);
  font-size: 12px;
  line-height: 1.45;
  color: var(--ink-3);
}
.af-swap { display: grid; min-width: 0; }
.af-swap > * { grid-area: 1 / 1; min-width: 0; }
.af-card .dc-head .af-swap { justify-items: end; }
.af-done { opacity: 0; }

/* 01 Read: the records collected */
.af-rows { display: grid; margin: 0; padding: 0; list-style: none; }
.af-row {
  display: grid;
  grid-template-columns: 6px minmax(0, 1fr);
  column-gap: var(--s-2);
  padding: 6px 4px;
  border-top: 1px solid var(--hairline);
  border-radius: 2px;
}
.af-row::before { content: ""; grid-row: 1 / span 2; width: 6px; height: 6px; margin-top: 5px; border-radius: 50%; background: var(--teal); }
.af-src, .af-val { grid-column: 2; min-width: 0; }
.af-src { font-family: var(--font-mono); font-size: 11.5px; line-height: 1.45; color: var(--ink-3); }
.af-val { font-size: 13px; font-weight: 600; line-height: 1.4; color: var(--ink); }

/* 02 Propose: the suggested choice and its alternatives */
.af-choices {
  display: grid;
  gap: 2px;
  margin: var(--s-2) 0 0;
  padding: var(--s-2) 0 0;
  border-top: 1px solid var(--hairline);
  list-style: none;
  font-size: 12.5px;
  line-height: 1.4;
  color: var(--ink-2);
}
.af-choices li { display: grid; grid-template-columns: 56px minmax(0, 1fr); gap: 6px; padding: 3px 6px; border: 1px solid transparent; border-radius: var(--r-control); }
.af-choices li > span { font-family: var(--font-mono); font-size: 11.5px; line-height: 1.5; color: var(--ink-3); }
.af-choices .is-pick { background: var(--tint); border-color: var(--tint-border); color: var(--ink); }
.af-choices .is-pick > span { color: var(--teal-ink); }

/* 03 Decide: a person (or their rule) acts */
.af-ok { background: var(--tint); border-color: var(--tint-border); color: var(--teal-ink); }
.af-card .dc-head .tag { font-family: var(--font-sans); font-size: 12px; line-height: 1.4; }
.af-card .af-btns { flex-direction: row; flex-wrap: wrap; gap: 6px; margin-bottom: 22px; }
.af-card .af-btns .btn { position: relative; width: auto; min-height: 30px; padding: 0 10px; font-size: 12.5px; }
.af-btns .btn-primary { --b0: var(--action); --k0: var(--action); --c0: var(--white); }
.af-btns .btn-secondary { --b0: var(--surface); --k0: var(--ink); --c0: var(--ink); }
.af-pointer { position: absolute; left: 50%; top: 50%; z-index: 2; display: flex; align-items: flex-start; gap: 2px; pointer-events: none; opacity: 0; }
.af-cursor { flex: none; width: 16px; height: 16px; max-width: none; color: var(--white); }
.af-cursor path { fill: currentColor; stroke: var(--navy-900); stroke-width: 1.2; stroke-linejoin: round; }
/* the name sits in the 22px under the buttons, clear of the pressed button's ring and of its neighbours: the
   pointer is at the button's middle (15px down a 30px button), so 19px puts the 16px chip 4px under the button */
.af-chip {
  margin-top: 19px;
  padding: 1px 6px;
  background: var(--ink);
  color: var(--surface);
  border-radius: var(--r-control);
  font-family: var(--font-mono);
  font-size: 11.5px;
  font-weight: 400;
  line-height: 14px;
  white-space: nowrap;
}
.af .af-effect { font-size: 12.5px; line-height: 1.45; color: var(--ink-2); }

/* 04 Record: the audit row lands in the log */
/* the space sits on the older rows (li + li), so the new row folds to nothing before it lands */
.af-log { display: grid; grid-template-rows: 1fr auto auto; margin: 0; padding: 0; list-style: none; }
.af-log li { min-height: 0; overflow: hidden; }
.af-log li + li { padding-top: 6px; }
.af-entry {
  display: grid;
  grid-template-columns: 38px minmax(0, 1fr);
  gap: var(--s-2);
  padding: 8px;
  border: 1px solid var(--hairline);
  border-radius: var(--r-control);
  font-size: 12.5px;
  line-height: 1.45;
  color: var(--ink-2);
}
.af-t { font-family: var(--font-mono); font-size: 11.5px; line-height: 1.6; color: var(--ink-3); }
.af-log-new .af-entry { background: var(--tint); border-color: var(--tint-border); color: var(--teal-ink); }
.af-log-new .af-t { color: var(--teal-ink); }

/* ---- Under the stage: the note and Pause motion ---- */
.af-foot { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--s-2) var(--s-4); min-width: 0; }
.af .af-note { font-size: 14px; line-height: 1.5; color: var(--ink-3); }
.af-pause { display: none; cursor: pointer; color: var(--ink); }

/* ---- Motion: one 18s scenario, three scenarios in a 54s loop (1s = 5.556% of 18s, 1.852% of 54s) ----
   0-3.3s 01 Read (the read screen is up and its rows land as it fades in, 17.7-18.4s; the inputs light and
   data crosses the network from 0.9s, the route lighting with it 0.9-3.3s; a wave of data crosses again
   after every rest, through every step until the scenario fades) · 3.3-9.4s 02 Propose (the output node lights
   and the output line carries the proposal to the Result tag, which turns gold; meter, reasons and choices build as the card fades in and it
   is complete at about 4.45s) · 9.4-13.4s 03 Decide (the person clicks at 11.05s) · 13.4-17.3s 04 Record (the
   row lands at 14.2-14.7s). Everything fades 17.3-17.6s; the next scenario fades in over 17.7-18s already at
   01 Read, so two scenarios never show together. Every delay adds --af-t0, so the loop starts 5.4s in, on the
   static frame. Delayed parts (rows, pulses, nodes, meter cells, reasons) use keyframes timed from their own
   delay. Animations are set the same at every width; media queries change only layout, so a resize or a
   phone rotation never restarts one out of step. */
@media (prefers-reduced-motion: no-preference) {
  .af.is-armed .af-sc--1 { animation: af-sc-1 54s linear var(--af-t0) infinite; }
  .af.is-armed .af-sc--2 { animation: af-sc-2 54s linear var(--af-t0) infinite; }
  .af.is-armed .af-sc--3 { animation: af-sc-3 54s linear var(--af-t0) infinite; }
  .af.is-armed .af-step--1 { animation: af-lit-1 18s linear var(--af-t0) infinite; }
  .af.is-armed .af-step--2 { animation: af-lit-2 18s linear var(--af-t0) infinite; }
  .af.is-armed .af-step--3 { animation: af-lit-3 18s linear var(--af-t0) infinite; }
  .af.is-armed .af-step--4 { animation: af-lit-4 18s linear var(--af-t0) infinite; }
  .af.is-armed .af-step--1::after { animation: af-bar-1 18s linear var(--af-t0) infinite; }
  .af.is-armed .af-step--2::after { animation: af-bar-2 18s linear var(--af-t0) infinite; }
  .af.is-armed .af-step--3::after { animation: af-bar-3 18s linear var(--af-t0) infinite; }
  .af.is-armed .af-step--4::after { animation: af-bar-4 18s linear var(--af-t0) infinite; }
  .af.is-armed .af-read { animation: af-show-read 18s ease-out var(--af-t0) infinite; }
  .af.is-armed .af-row { animation: af-row 18s ease-out infinite both; animation-delay: calc(var(--af-t0) - 0.3s); }
  .af.is-armed .af-row:nth-child(2) { animation-delay: calc(var(--af-t0) - 0.15s); }
  .af.is-armed .af-row:nth-child(3) { animation-delay: var(--af-t0); }
  .af.is-armed .af-ins span:nth-child(1) { animation: af-ink-1 18s ease-out var(--af-t0) infinite; }
  .af.is-armed .af-ins span:nth-child(2) { animation: af-ink-2 18s ease-out var(--af-t0) infinite; }
  .af.is-armed .af-ins span:nth-child(3) { animation: af-ink-3 18s ease-out var(--af-t0) infinite; }
  .af.is-armed .af-propose { animation: af-show-p 18s ease-out var(--af-t0) infinite; }
  .af.is-armed .af-decide { animation: af-show-d 18s ease-out var(--af-t0) infinite; }
  .af.is-armed .af-record { animation: af-show-r 18s ease-out var(--af-t0) infinite; }

  /* network: a wave of data, again and again, through all four steps. A wave sets off at 0.9s (as the route
     starts to draw) and spreads from node to node: a round dot runs along each input stub (staggered), and
     each node, 0.04s after its first dot arrives, sends dots on along two of its four edges, the second 0.07s
     after the first (the other two carry the next wave: --m: 1 edges run on even waves with --k: 0, odd with
     --k: 1); each hidden-2 node sends one to the output node every wave, and the output dot (gold-white, like
     the riders) carries the result to the Result tag 2.4-3s into the wave, as the output line draws. Every dot
     crosses its edge at 205 units a second, eased p*p*(3-2p), so dots leaving a node spread apart and no two
     edges share a timing: at any moment the dots sit at different points on different lines, never one front.
     The rider (the gold-white dot on each hop of the scenario's gold route) runs every wave with the timing of
     the dot on that edge, and covers it. Per edge, --o is when its dot sets off (seconds into the wave) and
     --t its crossing time, worked out from that rule; a layer's --lo and --hi are its first --o and its last
     --o + --t (keep them in step when a timing changes).
     Then nothing moves for --af-dot-rest (1.5s), and the next wave sets off: one every 3s + rest (4.5s), four
     a scenario (0.9, 5.4, 9.9, 14.4s), the last reaching the Result tag at 17.4s as the scenario fades. Waves
     start over with each scenario, and a wave that could not reach the Result tag by 17.45s is skipped, so a
     scenario change never cuts one (a rest of 1.5 or 3s keeps the rest across the change the same as the
     others; any other value leaves a longer rest there, 3s at a rest of 1s). Nodes flash only in 01 Read, each
     as its first dot arrives (--d). Each layer's group runs a clock, --af-s (the scenario's seconds), and
     works out once, as numbers its dots inherit, the seconds into the wave (--af-u, held between --lo and --hi),
     the wave's parity (--af-n) and the gates (--af-g: 0 before the first wave, for a skipped wave and once the
     scenario fades, 17.3-17.6s); each dot then places itself (--af-p, its hop, 0 to 1). 48 dots (36 pulses, 12
     rider hops), about 22 a wave; a layer's dots restyle only while one of them moves, and nothing repaints
     while they rest. Without mod() the dots stay hidden. */
  .af-pl--in { --lo: 0; --hi: 0.43; }
  .af-pl--1 { --lo: 0.38; --hi: 1.19; }
  .af-pl--2 { --lo: 0.85; --hi: 1.99; }
  .af-pl--3 { --lo: 1.38; --hi: 2.32; }
  .af-pl--out { --lo: 2.4; --hi: 3; }
  .af-pl--1 path, .af-pl--2 path { --m: 1; }
  .af-pl .af-ride { --m: 0; }
  .af-pl--in > :nth-child(1), .af-pl--in > .af-sc--1 { --o: 0; --t: 0.34; }
  .af-pl--in > :nth-child(2), .af-pl--in > .af-sc--3 { --o: 0.09; --t: 0.34; }
  .af-pl--in > :nth-child(3), .af-pl--in > .af-sc--2 { --o: 0.05; --t: 0.34; }
  .af-pl--1 > :nth-child(1) { --o: 0.38; --t: 0.34; --k: 0; }
  .af-pl--1 > :nth-child(2), .af-pl--1 > .af-sc--1 { --o: 0.38; --t: 0.34; --k: 1; }
  .af-pl--1 > :nth-child(3) { --o: 0.45; --t: 0.48; --k: 0; }
  .af-pl--1 > :nth-child(4) { --o: 0.45; --t: 0.69; --k: 1; }
  .af-pl--1 > :nth-child(5), .af-pl--1 > .af-sc--3 { --o: 0.47; --t: 0.48; --k: 1; }
  .af-pl--1 > :nth-child(6) { --o: 0.47; --t: 0.34; --k: 0; }
  .af-pl--1 > :nth-child(7) { --o: 0.54; --t: 0.34; --k: 1; }
  .af-pl--1 > :nth-child(8) { --o: 0.54; --t: 0.48; --k: 0; }
  .af-pl--1 > :nth-child(9) { --o: 0.5; --t: 0.69; --k: 1; }
  .af-pl--1 > :nth-child(10) { --o: 0.43; --t: 0.48; --k: 1; }
  .af-pl--1 > :nth-child(11) { --o: 0.43; --t: 0.34; --k: 0; }
  .af-pl--1 > :nth-child(12), .af-pl--1 > .af-sc--2 { --o: 0.5; --t: 0.34; --k: 0; }
  .af-pl--2 > :nth-child(1) { --o: 1; --t: 0.34; --k: 1; }
  .af-pl--2 > :nth-child(2) { --o: 1.07; --t: 0.42; --k: 0; }
  .af-pl--2 > :nth-child(3) { --o: 1.07; --t: 0.6; --k: 1; }
  .af-pl--2 > :nth-child(4), .af-pl--2 > .af-sc--3 { --o: 1; --t: 0.81; --k: 0; }
  .af-pl--2 > :nth-child(5) { --o: 0.85; --t: 0.42; --k: 0; }
  .af-pl--2 > :nth-child(6) { --o: 0.85; --t: 0.34; --k: 1; }
  .af-pl--2 > :nth-child(7), .af-pl--2 > .af-sc--1 { --o: 0.92; --t: 0.42; --k: 0; }
  .af-pl--2 > :nth-child(8) { --o: 0.92; --t: 0.6; --k: 1; }
  .af-pl--2 > :nth-child(9) { --o: 0.99; --t: 0.6; --k: 1; }
  .af-pl--2 > :nth-child(10) { --o: 0.99; --t: 0.42; --k: 0; }
  .af-pl--2 > :nth-child(11) { --o: 0.92; --t: 0.34; --k: 0; }
  .af-pl--2 > :nth-child(12) { --o: 0.92; --t: 0.42; --k: 1; }
  .af-pl--2 > :nth-child(13) { --o: 1.18; --t: 0.81; --k: 0; }
  .af-pl--2 > :nth-child(14), .af-pl--2 > .af-sc--2 { --o: 1.18; --t: 0.6; --k: 1; }
  .af-pl--2 > :nth-child(15) { --o: 1.25; --t: 0.42; --k: 1; }
  .af-pl--2 > :nth-child(16) { --o: 1.25; --t: 0.34; --k: 0; }
  .af-pl--3 > :nth-child(1) { --o: 1.38; --t: 0.48; }
  .af-pl--3 > :nth-child(2), .af-pl--3 > .af-sc--2 { --o: 1.81; --t: 0.34; }
  .af-pl--3 > :nth-child(3), .af-pl--3 > .af-sc--1 { --o: 1.7; --t: 0.34; }
  .af-pl--3 > :nth-child(4), .af-pl--3 > .af-sc--3 { --o: 1.84; --t: 0.48; }
  .af-pl--out path { --o: 2.4; --t: 0.6; }
  .af-nodes--i > :nth-child(1) { --d: 1.14; } .af-nodes--i > :nth-child(2) { --d: 1.23; } .af-nodes--i > :nth-child(3) { --d: 1.19; }
  .af-nodes--1 > :nth-child(1) { --d: 1.52; } .af-nodes--1 > :nth-child(2) { --d: 1.61; } .af-nodes--1 > :nth-child(3) { --d: 1.57; } .af-nodes--1 > :nth-child(4) { --d: 1.64; }
  .af-nodes--2 > :nth-child(1) { --d: 2.07; } .af-nodes--2 > :nth-child(2) { --d: 2.21; } .af-nodes--2 > :nth-child(3) { --d: 2.06; } .af-nodes--2 > :nth-child(4) { --d: 2.39; }
  .af.is-armed .af-pl { animation: af-clock 18s linear var(--af-t0) infinite; }
  @supports (opacity: mod(1, 1)) {
    .af.is-armed .af-pl {
      --af-P: calc(3 + var(--af-dot-rest));
      --af-u: clamp(var(--lo), mod(var(--af-s) - 0.9, var(--af-P)), var(--hi));
      --af-n: mod(round(down, (var(--af-s) - 0.9) / var(--af-P), 1), 2);
      --af-g: calc(clamp(0, (var(--af-s) - 0.9) * 1000 + 1, 1) * clamp(0, (14.45 - var(--af-s) + mod(var(--af-s) - 0.9, var(--af-P))) * 100, 1) * clamp(0, (17.6 - var(--af-s)) / 0.3, 1));
      opacity: 1;
    }
    .af.is-armed .af-pl path {
      --af-p: clamp(0, (var(--af-u) - var(--o)) / var(--t), 1);
      stroke-dashoffset: calc(-100px * var(--af-p) * var(--af-p) * (3 - 2 * var(--af-p)));
      stroke-opacity: calc(min(var(--af-p), 1 - var(--af-p)) * 12 * var(--af-g) * (1 - var(--m, 0) * (var(--af-n) - var(--k, 0)) * (var(--af-n) - var(--k, 0))));
    }
  }
  .af.is-armed .af-nodes--i circle,
  .af.is-armed .af-nodes--1 circle,
  .af.is-armed .af-nodes--2 circle { animation: af-flash 18s ease-out infinite both; animation-delay: calc(var(--d) * 1s + var(--af-t0)); }
  .af.is-armed .af-nodes--o circle { animation: af-out 18s ease-out var(--af-t0) infinite; }
  .af.is-armed .af-route.af-sc--1 { animation: af-sc-1 54s linear var(--af-t0) infinite, af-route 18s linear var(--af-t0) infinite; }
  .af.is-armed .af-route.af-sc--2 { animation: af-sc-2 54s linear var(--af-t0) infinite, af-route 18s linear var(--af-t0) infinite; }
  .af.is-armed .af-route.af-sc--3 { animation: af-sc-3 54s linear var(--af-t0) infinite, af-route 18s linear var(--af-t0) infinite; }
  .af.is-armed .af-res-lit { animation: af-res-line 18s linear var(--af-t0) infinite; }
  .af.is-armed .af-res span { animation: af-res 18s ease-out var(--af-t0) infinite; }

  /* 02 Propose: the meter fills, then reasons and choices arrive, while the card fades in */
  .af-propose .meter-cell:nth-child(2) { --c: 0.04s; }
  .af-propose .meter-cell:nth-child(3) { --c: 0.08s; }
  .af-propose .meter-cell:nth-child(4) { --c: 0.12s; }
  .af-propose .meter-cell:nth-child(5) { --c: 0.16s; }
  .af-propose .meter-cell:nth-child(6) { --c: 0.2s; }
  .af-propose .meter-cell:nth-child(7) { --c: 0.24s; }
  .af-propose .meter-cell:nth-child(8) { --c: 0.28s; }
  .af-propose .meter-cell:nth-child(9) { --c: 0.32s; }
  .af.is-armed .af-propose .meter-cell.is-on { animation: af-cell 18s linear infinite both; animation-delay: calc(var(--af-t0) + 3.55s + var(--c, 0s)); }
  .af.is-armed .af-reasons li,
  .af.is-armed .af-choices li { animation: af-rise 18s ease-out infinite both; animation-delay: calc(var(--af-t0) + 3.6s); }
  .af.is-armed .af-reasons li:nth-child(2) { animation-delay: calc(var(--af-t0) + 3.7s); }
  .af.is-armed .af-reasons li:nth-child(3) { animation-delay: calc(var(--af-t0) + 3.8s); }
  .af.is-armed .af-choices li:nth-child(1) { animation-delay: calc(var(--af-t0) + 3.85s); }
  .af.is-armed .af-choices li:nth-child(2) { animation-delay: calc(var(--af-t0) + 3.95s); }
  .af.is-armed .af-choices li:nth-child(3) { animation-delay: calc(var(--af-t0) + 4.05s); }

  /* 03 Decide: pointer moves to the choice and clicks; the chosen button turns solid with a gold ring, the others dim;
     the state and the audit line change */
  .af.is-armed .af-pointer { animation: af-pointer 18s ease-in-out var(--af-t0) infinite; }
  .af.is-armed .af-press { animation: af-press 18s linear var(--af-t0) infinite; }
  .af.is-armed .af-btns .btn:not(.af-press) { animation: af-unpick 18s linear var(--af-t0) infinite; }
  .af.is-armed .af-decide .af-wait { animation: af-wait 18s linear var(--af-t0) infinite; }
  .af.is-armed .af-decide .af-done { animation: af-done 18s ease-out var(--af-t0) infinite; }

  /* 04 Record: the new row lands on top of the log */
  .af.is-armed .af-log { animation: af-log-rows 18s ease-out var(--af-t0) infinite; }
  .af.is-armed .af-log-new { animation: af-log 18s ease-out var(--af-t0) infinite; }
  .af.is-armed .af-log-new .af-entry { animation: af-log-edge 18s ease-out var(--af-t0) infinite; }

  /* Three holds, each on its own rule, so each sets and clears alone and the loop resumes where it stopped:
     paused while the tab is hidden, while the flow is scrolled out of view (js/ai-flow.js), and Pause
     motion. Pause motion sits in @supports so a browser without
     :has() drops only that rule (one invalid selector would drop a whole selector list). */
  #ai-flow.is-hidden *, #ai-flow.is-hidden *::after { animation-play-state: paused; }
  #ai-flow.is-off *, #ai-flow.is-off *::after { animation-play-state: paused; }
  @supports selector(:has(*)) {
    #ai-flow:has(#motion-pause:checked) *, #ai-flow:has(#motion-pause:checked) *::after { animation-play-state: paused; }
    .af.is-armed .af-pause { display: flex; }
  }

  @keyframes af-sc-1 { 0%, 32.037% { opacity: 1; } 32.593%, 99.444% { opacity: 0; } 100% { opacity: 1; } }
  @keyframes af-sc-2 { 0%, 32.778% { opacity: 0; } 33.333%, 65.37% { opacity: 1; } 65.926%, 100% { opacity: 0; } }
  @keyframes af-sc-3 { 0%, 66.111% { opacity: 0; } 66.667%, 98.704% { opacity: 1; } 99.259%, 100% { opacity: 0; } }
  /* steps: 01 is lit from 17.6s (while the next scenario fades in) through 3.3s */
  @keyframes af-lit-1 {
    0%, 18.333% { border-color: var(--cyan); background-color: var(--af-tint); color: var(--ink); }
    19.722%, 97.778% { border-color: var(--navy-line); background-color: var(--navy-800); color: var(--on-dark-3); }
    99.167%, 100% { border-color: var(--cyan); background-color: var(--af-tint); color: var(--ink); }
  }
  @keyframes af-lit-2 {
    0%, 18.333% { border-color: var(--navy-line); background-color: var(--navy-800); color: var(--on-dark-3); }
    19.722%, 52.222% { border-color: var(--cyan); background-color: var(--af-tint); color: var(--ink); }
    53.611%, 100% { border-color: var(--navy-line); background-color: var(--navy-800); color: var(--on-dark-3); }
  }
  @keyframes af-lit-3 {
    0%, 52.222% { border-color: var(--navy-line); background-color: var(--navy-800); color: var(--on-dark-3); }
    53.611%, 74.444% { border-color: var(--cyan); background-color: var(--af-tint); color: var(--ink); }
    75.833%, 100% { border-color: var(--navy-line); background-color: var(--navy-800); color: var(--on-dark-3); }
  }
  @keyframes af-lit-4 {
    0%, 74.444% { border-color: var(--navy-line); background-color: var(--navy-800); color: var(--on-dark-3); }
    75.833%, 96.111% { border-color: var(--cyan); background-color: var(--af-tint); color: var(--ink); }
    97.778%, 100% { border-color: var(--navy-line); background-color: var(--navy-800); color: var(--on-dark-3); }
  }
  @keyframes af-bar-1 { 0% { opacity: 1; transform: scaleX(0); } 18.333% { opacity: 1; transform: scaleX(1); } 19.722%, 100% { opacity: 0; transform: scaleX(1); } }
  @keyframes af-bar-2 { 0%, 18.333% { opacity: 0; transform: scaleX(0); } 18.389% { opacity: 1; transform: scaleX(0); } 52.222% { opacity: 1; transform: scaleX(1); } 53.611%, 100% { opacity: 0; transform: scaleX(1); } }
  @keyframes af-bar-3 { 0%, 52.222% { opacity: 0; transform: scaleX(0); } 52.278% { opacity: 1; transform: scaleX(0); } 74.444% { opacity: 1; transform: scaleX(1); } 75.833%, 100% { opacity: 0; transform: scaleX(1); } }
  @keyframes af-bar-4 { 0%, 74.444% { opacity: 0; transform: scaleX(0); } 74.5% { opacity: 1; transform: scaleX(0); } 96.111% { opacity: 1; transform: scaleX(1); } 97.778%, 100% { opacity: 0; transform: scaleX(1); } }
  /* the read screen is up from 17.7s (it fades in with its scenario) through 3.3s */
  @keyframes af-show-read { 0%, 18.333% { opacity: 1; } 19.722%, 97.778% { opacity: 0; } 98.333%, 100% { opacity: 1; } }
  /* a row lands, then stays until well after the read screen has gone (3.55s), and resets while it is hidden */
  @keyframes af-row {
    0% { opacity: 0; transform: translateX(-6px); background-color: transparent; }
    2.222% { opacity: 1; transform: none; background-color: var(--tint); }
    8% { background-color: transparent; }
    25% { opacity: 1; transform: none; }
    30%, 100% { opacity: 0; transform: none; background-color: transparent; }
  }
  @keyframes af-ink-1 {
    0%, 1.956% { border-color: var(--navy-line); color: var(--on-dark-3); background-color: var(--navy-800); }
    3.644% { border-color: var(--cyan); color: var(--white); background-color: var(--tint); }
    8.889%, 96.111% { border-color: var(--af-node); color: var(--white); background-color: var(--navy-800); }
    97.778%, 100% { border-color: var(--navy-line); color: var(--on-dark-3); background-color: var(--navy-800); }
  }
  @keyframes af-ink-2 {
    0%, 3.644% { border-color: var(--navy-line); color: var(--on-dark-3); background-color: var(--navy-800); }
    5.333% { border-color: var(--cyan); color: var(--white); background-color: var(--tint); }
    10.667%, 96.111% { border-color: var(--af-node); color: var(--white); background-color: var(--navy-800); }
    97.778%, 100% { border-color: var(--navy-line); color: var(--on-dark-3); background-color: var(--navy-800); }
  }
  @keyframes af-ink-3 {
    0%, 5.333% { border-color: var(--navy-line); color: var(--on-dark-3); background-color: var(--navy-800); }
    6.933% { border-color: var(--cyan); color: var(--white); background-color: var(--tint); }
    12.444%, 96.111% { border-color: var(--af-node); color: var(--white); background-color: var(--navy-800); }
    97.778%, 100% { border-color: var(--navy-line); color: var(--on-dark-3); background-color: var(--navy-800); }
  }
  @keyframes af-show-p { 0%, 19.722% { opacity: 0; transform: translateX(-10px); } 21.944%, 52.222% { opacity: 1; transform: none; } 53.611%, 100% { opacity: 0; transform: none; } }
  @keyframes af-show-d { 0%, 52.778% { opacity: 0; transform: translateX(-10px); } 55%, 74.444% { opacity: 1; transform: none; } 76.111%, 100% { opacity: 0; transform: none; } }
  @keyframes af-show-r { 0%, 75.556% { opacity: 0; transform: translateX(-10px); } 77.778%, 96.111% { opacity: 1; transform: none; } 97.778%, 100% { opacity: 0; transform: none; } }
  /* the dot clock: the scenario's seconds, 0 to 18 (each dot's wave and hop come from it) */
  @keyframes af-clock { from { --af-s: 0; } to { --af-s: 18; } }
  @keyframes af-flash { 0% { fill: var(--navy-900); } 0.889%, 3.556% { fill: var(--cyan); } 7.111%, 100% { fill: var(--navy-900); } }
  @keyframes af-out {
    0%, 18.333% { fill: var(--navy-900); stroke: var(--af-node); }
    19.444%, 96.111% { fill: var(--cyan); stroke: var(--cyan); }
    97.778%, 100% { fill: var(--navy-900); stroke: var(--af-node); }
  }
  /* the route draws with the pulses (0.9-3.3s), then the output line with the output pulse (3.3-3.9s); the
     Result tag turns gold as the line reaches it (3.7-3.9s) and stays lit until the scenario fades */
  @keyframes af-route { 0%, 5% { stroke-dashoffset: 100; stroke-opacity: 1; } 18.333%, 96.111% { stroke-dashoffset: 0; stroke-opacity: 1; } 97.778%, 100% { stroke-dashoffset: 0; stroke-opacity: 0; } }
  @keyframes af-res {
    0%, 20.556% { border-color: var(--navy-line); color: var(--on-dark-3); background-color: var(--navy-800); }
    21.667%, 96.111% { border-color: var(--cyan); color: var(--white); background-color: var(--tint); }
    97.778%, 100% { border-color: var(--navy-line); color: var(--on-dark-3); background-color: var(--navy-800); }
  }
  @keyframes af-res-line { 0%, 18.333% { stroke-dashoffset: 100; stroke-opacity: 1; } 21.667%, 96.111% { stroke-dashoffset: 0; stroke-opacity: 1; } 97.778%, 100% { stroke-dashoffset: 0; stroke-opacity: 0; } }
  /* meter cells and reasons stay until the propose screen has gone (9.65s) */
  @keyframes af-cell { 0% { background-color: var(--track); } 1.333%, 34% { background-color: var(--teal); } 35%, 100% { background-color: var(--track); } }
  @keyframes af-rise { 0% { opacity: 0; transform: translateY(4px); } 2.222%, 34% { opacity: 1; transform: none; } 35%, 100% { opacity: 0; transform: none; } }
  @keyframes af-pointer {
    0%, 56.111% { opacity: 0; translate: 48px 0; scale: 1; }
    57.222% { opacity: 1; translate: 48px 0; scale: 1; }
    60.556% { opacity: 1; translate: 0 0; scale: 1; }
    61.356% { scale: 0.86; }
    62.244% { scale: 1; }
    66.111% { opacity: 1; translate: 0 0; }
    68.111%, 100% { opacity: 0; translate: 0 0; scale: 1; }
  }
  @keyframes af-press {
    0%, 61.533% { background-color: var(--b0); border-color: var(--k0); color: var(--c0); box-shadow: 0 0 0 0 var(--cyan); }
    62.244%, 100% { background-color: var(--action); border-color: var(--cyan); color: var(--white); box-shadow: 0 0 0 2px var(--cyan); }
  }
  @keyframes af-unpick {
    0%, 61.533% { opacity: 1; background-color: var(--b0); border-color: var(--k0); color: var(--c0); }
    62.244%, 100% { opacity: 0.5; background-color: var(--surface); border-color: var(--navy-line); color: var(--ink-3); }
  }
  @keyframes af-wait { 0%, 61.667% { opacity: 1; } 62.444%, 100% { opacity: 0; } }
  @keyframes af-done { 0%, 62.556% { opacity: 0; transform: scale(1.06); } 63.889%, 100% { opacity: 1; transform: none; } }
  @keyframes af-log-rows { 0%, 78.889% { grid-template-rows: 0fr auto auto; } 81.667%, 100% { grid-template-rows: 1fr auto auto; } }
  @keyframes af-log { 0%, 78.889% { opacity: 0; translate: 0 -8px; } 81.667%, 100% { opacity: 1; translate: 0 0; } }
  @keyframes af-log-edge { 0%, 80.556% { border-color: var(--cyan); } 86.778%, 100% { border-color: var(--tint-border); } }
}

@media (forced-colors: active) {
  .af-step--2, .af-choices .is-pick, .af-log .af-log-new, .af-res span { outline: 2px solid Highlight; outline-offset: -2px; }
  .af-edges, .af-route, .af-res-lit, .af-nodes circle { stroke: CanvasText; }
}
