/* ============================================================
   AnthroWeb — Exploded Bento live diagrams (SPEC M8)
   Markup: .claude/redesign/viz_snippets.py
     .viz[data-viz=slug] > .viz__stage > svg.viz__layer--plate
                                        svg.viz__layer--live
                                        svg.viz__layer--glyph
   Every layer draws in one 160 x 100 "plate unit" space; --u is the
   size of one unit in px, derived from the .viz box (container query)
   so the diagram scales as one object and never leaves its panel.
   States: [data-reveal]:not(.is-in) → exploded (layers far apart),
   revealed → assembled, card :hover/:focus-within → re-explodes.
   Loops run only on .viz.is-live (set by main.js while visible);
   otherwise — without JS and under reduced motion — they rest on
   frame 0, which every choreography below designs as its finished
   state (rank #1, ring at 100, code typed …).
   Animated properties: transform, opacity, stroke-dashoffset only.
   ============================================================ */

.viz {
  --viz-blue: #38a8f0;
  --viz-deep: #1a6fd0;
  --viz-cyan: #6fd6ff;
  --viz-ice: #d6f3ff;
  --viz-mint: #46e0a3;
  --viz-ink: #02060d;
  --viz-hair: rgba(111, 214, 255, .34);
  --viz-soft: rgba(111, 214, 255, .36);
  --viz-tick: rgba(111, 214, 255, .55);
  --viz-io: cubic-bezier(.65, 0, .25, 1);
  --viz-out: cubic-bezier(.2, .8, .2, 1);
  --viz-fall: cubic-bezier(.55, 0, 1, .45);
  --viz-snap: cubic-bezier(.3, 1.55, .5, 1);
  --viz-spring: cubic-bezier(.3, 1.45, .55, 1);
  --viz-settle: cubic-bezier(.25, 1.2, .5, 1);
  --gr: 5.4;   /* resting layer gap, in plate units */
  --gh: 0;     /* extra gap while the card is hovered / focused */
  position: relative;
  display: block;
  width: 100%;
  aspect-ratio: 16 / 10;
  overflow: hidden;
  overflow: clip;
  contain: layout paint style;
  container-type: size;
  pointer-events: none;
  -webkit-user-select: none;
  user-select: none;
}
@supports (transition-timing-function: linear(0, 1)) {
  .viz {
    /* damped springs (zeta .6 / .7) sampled for linear() */
    --viz-spring: linear(0, .005 .8%, .04 2.5%, .068 3.3%, .14 5%, .274 7.5%, .52 11.7%, .66 14.2%, .783 16.7%, .853 18.3%, .914 20%, .987 22.5%, 1.038 25%, 1.071 27.5%, 1.092 30.8%, 1.092 35%, 1.015 50.8%, .993 60%, 1);
    --viz-settle: linear(0, .004 .8%, .033 2.5%, .056 3.3%, .116 5%, .228 7.5%, .477 12.5%, .594 15%, .7 17.5%, .79 20%, .865 22.5%, .924 25%, .969 27.5%, 1.01 30.8%, 1.037 35%, 1.046 40%, 1.002 66.7%, 1);
  }
}

/* ---------- the isometric stage (orthographic, like a drawing) ---------- */
/* the markup ships the stage [hidden] so it takes no space before this
   stylesheet arrives; un-hide it (beats any global [hidden] reset) */
.viz .viz__stage[hidden] { display: block !important; }
.viz__stage {
  --u: 1.2px;
  position: absolute;
  display: block;
  left: 50%;
  top: 50%;
  width: calc(160 * var(--u));
  height: calc(100 * var(--u));
  margin: calc(-50 * var(--u)) 0 0 calc(-80 * var(--u));
  transform-style: preserve-3d;
  transform: rotateX(56deg) rotateZ(-38deg);
}
@supports (width: 1cqmin) {
  /* sized so the projected stack — incl. the exploded entrance — fits */
  .viz__stage { --u: min(.48cqw, .7cqh); }
}
@container (max-aspect-ratio: 1.25) {
  /* tall tiles (SEO lead): the art is width-bound, so let it fill the width */
  .viz__stage { --u: min(.535cqw, .7cqh); }
}

/* construction lines: stand along the explode axis at the sheet's outer
   corners (drawn full length, scaled down → crisp), seen only while the
   stack is exploded */
.viz__stage::before,
.viz__stage::after {
  content: "";
  position: absolute;
  left: calc(8 * var(--u));
  top: calc(8 * var(--u));
  width: 1px;
  height: calc(40 * var(--u));
  background: linear-gradient(rgba(111, 214, 255, .75), rgba(111, 214, 255, .75) 70%, rgba(111, 214, 255, 0));
  transform-origin: 0 0;
  transform: rotateX(-90deg) scaleY(calc((var(--gr) + var(--gh)) / 40));
  opacity: 0;
  transition: transform .7s var(--viz-spring), opacity .25s linear;
}
.viz__stage::after {
  left: calc(152 * var(--u));
  top: calc(92 * var(--u));
}

.viz .viz__layer {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  display: block;
  max-width: none;
  overflow: visible;
  fill: none;
  stroke: none;
  stroke-linecap: round;
  stroke-linejoin: round;
  transform: translateZ(calc(var(--z) * var(--gr) * var(--u)));
  translate: 0 0 calc(var(--z) * var(--gh) * var(--u));
  /* longhands: a malformed --d (reveal stagger from main.js) can only
     void the delay (→ initial 0s), never the transition itself */
  transition-property: transform, translate;
  transition-duration: 1.25s, .7s;
  transition-timing-function: var(--viz-settle), var(--viz-spring);
  transition-delay: calc(var(--d, 0s) + .12s), 0s;
}

/* plate: engineering grid on a dark glass slab, registration ticks, lit edge */
.viz .viz__layer--plate {
  --z: -1;
  border-radius: calc(7 * var(--u));
  background:
    linear-gradient(var(--viz-tick), var(--viz-tick)) left calc(3 * var(--u)) top calc(3 * var(--u)) / calc(4.5 * var(--u)) 1px no-repeat,
    linear-gradient(var(--viz-tick), var(--viz-tick)) left calc(3 * var(--u)) top calc(3 * var(--u)) / 1px calc(4.5 * var(--u)) no-repeat,
    linear-gradient(var(--viz-tick), var(--viz-tick)) right calc(3 * var(--u)) top calc(3 * var(--u)) / calc(4.5 * var(--u)) 1px no-repeat,
    linear-gradient(var(--viz-tick), var(--viz-tick)) right calc(3 * var(--u)) top calc(3 * var(--u)) / 1px calc(4.5 * var(--u)) no-repeat,
    linear-gradient(var(--viz-tick), var(--viz-tick)) left calc(3 * var(--u)) bottom calc(3 * var(--u)) / calc(4.5 * var(--u)) 1px no-repeat,
    linear-gradient(var(--viz-tick), var(--viz-tick)) left calc(3 * var(--u)) bottom calc(3 * var(--u)) / 1px calc(4.5 * var(--u)) no-repeat,
    linear-gradient(var(--viz-tick), var(--viz-tick)) right calc(3 * var(--u)) bottom calc(3 * var(--u)) / calc(4.5 * var(--u)) 1px no-repeat,
    linear-gradient(var(--viz-tick), var(--viz-tick)) right calc(3 * var(--u)) bottom calc(3 * var(--u)) / 1px calc(4.5 * var(--u)) no-repeat,
    linear-gradient(rgba(111, 214, 255, .085) 1px, transparent 1px) 0 0 / calc(10 * var(--u)) calc(10 * var(--u)),
    linear-gradient(90deg, rgba(111, 214, 255, .085) 1px, transparent 1px) 0 0 / calc(10 * var(--u)) calc(10 * var(--u)),
    radial-gradient(130% 110% at 30% 20%, rgba(26, 111, 208, .34), rgba(5, 14, 27, .94) 62%);
  box-shadow:
    inset 0 0 0 1px rgba(111, 214, 255, .2),
    calc(-1.3 * var(--u)) calc(1.5 * var(--u)) 0 rgba(56, 168, 240, .26),
    calc(-2.6 * var(--u)) calc(3 * var(--u)) 0 rgba(26, 111, 208, .14),
    0 0 calc(34 * var(--u)) rgba(26, 111, 208, .34);
}

/* live: the inset glass sheet the demo runs on (with the badge's shadow) */
.viz .viz__layer--live {
  --z: 0;
  left: 5%;
  top: 8%;
  width: 90%;
  height: 84%;
  border-radius: calc(5 * var(--u));
  background:
    radial-gradient(calc(17 * var(--u)) calc(17 * var(--u)) at 88% 17%, rgba(0, 4, 10, .5), rgba(0, 4, 10, 0)),
    linear-gradient(155deg, rgba(111, 214, 255, .075), rgba(26, 111, 208, .035) 60%, rgba(111, 214, 255, .05));
  box-shadow: inset 0 0 0 1px rgba(111, 214, 255, .15);
  filter: drop-shadow(0 0 calc(2.4 * var(--u)) rgba(56, 168, 240, .55));
}

/* glyph: the service mark on a glass badge floating over the top-right */
.viz .viz__layer--glyph {
  --z: 1;
  left: 75%;
  top: 7%;
  width: 18.75%;
  height: 30%;
  border-radius: calc(8 * var(--u));
  background: linear-gradient(140deg, rgba(56, 168, 240, .66), rgba(26, 111, 208, .38) 52%, rgba(4, 12, 24, .85));
  box-shadow:
    inset 0 0 0 1px rgba(214, 243, 255, .55),
    calc(-1 * var(--u)) calc(1.2 * var(--u)) 0 rgba(56, 168, 240, .4),
    0 0 calc(14 * var(--u)) rgba(56, 168, 240, .45);
  stroke: var(--viz-ice);
  stroke-width: 1.9;
  /* floats a little higher than one gap so it reads as its own layer */
  transform: translateZ(calc((var(--gr) + 7) * var(--u)));
}

/* ---------- states ---------- */
html.js [data-reveal]:not(.is-in) .viz { --gr: 24; }
@media (hover: hover) {
  .card:hover .viz { --gh: 14; }
  .card:hover .viz__stage::before,
  .card:hover .viz__stage::after { opacity: 1; transition: transform .7s var(--viz-spring), opacity .4s linear .12s; }
}
.card:focus-within .viz { --gh: 14; }
.card:focus-within .viz__stage::before,
.card:focus-within .viz__stage::after { opacity: 1; transition: transform .7s var(--viz-spring), opacity .4s linear .12s; }

/* loops only while on screen; frame 0 is the finished state */
.viz:not(.is-live) * { animation-play-state: paused !important; }

html.t-low .viz .viz__layer--live,
html.t-static .viz .viz__layer--live { filter: none; }

/* reduced motion: no loops, no transitions — every element's base style is
   its designed frame 0 (beats any global "animation-duration: .01ms" reset) */
html.reduce-motion .viz { --gr: 9 !important; --gh: 0 !important; }
html.reduce-motion .viz *,
html.reduce-motion .viz__layer { animation: none !important; transition: none !important; }
html.reduce-motion .viz__stage::before,
html.reduce-motion .viz__stage::after { display: none; }
@media (prefers-reduced-motion: reduce) {
  .viz { --gr: 9 !important; --gh: 0 !important; }
  .viz *, .viz__layer { animation: none !important; transition: none !important; }
  .viz__stage::before, .viz__stage::after { display: none; }
}
@media (forced-colors: active) { .viz { display: none; } }
@media print { .viz { display: none; } }

/* ---------- shared shape vocabulary ---------- */
/* inner shapes take paint only from this file (card-level svg rules such as
   ".card svg path { stroke: … }" can't leak in) */
.viz .viz__layer * { fill: inherit; stroke: inherit; stroke-width: inherit; }
.viz .vh { stroke: var(--viz-hair); stroke-width: .8; }
.viz .vd { stroke: rgba(111, 214, 255, .3); stroke-width: .8; stroke-dasharray: 2 2.2; }
.viz .vs { stroke: var(--viz-soft); stroke-width: 1.8; }
.viz .vi { stroke: var(--viz-ice); stroke-width: 2.4; }
.viz .vn { stroke: rgba(56, 168, 240, .75); stroke-width: 5; }
.viz .vk { fill: rgba(56, 168, 240, .12); }
.viz__layer [class] { transform-box: fill-box; transform-origin: center; }
.viz__layer [pathLength] { stroke-dasharray: 1 1; }

/* ============================================================
   1. website-design — wireframe → colour → code   (7.2 s)
   ============================================================ */
[data-viz="website-design"] .v1 { stroke: var(--viz-cyan); stroke-width: .9; animation: viz-wds-wire 7.2s linear infinite both; }
[data-viz="website-design"] .v2 { fill: rgba(26, 111, 208, .72); animation: viz-wds-pop 7.2s var(--viz-out) infinite both; }
[data-viz="website-design"] .v3 { fill: rgba(111, 214, 255, .13); animation: viz-wds-pop 7.2s var(--viz-out) .3s infinite both; }
[data-viz="website-design"] .v4 { stroke: var(--viz-ice); stroke-width: 3.2; animation: viz-wds-pop 7.2s var(--viz-out) .55s infinite both; }
[data-viz="website-design"] .v5 { stroke: var(--viz-cyan); stroke-width: 4.4; animation: viz-wds-pop 7.2s var(--viz-out) .55s infinite both; }
[data-viz="website-design"] .v6 { stroke: var(--viz-ice); stroke-width: 1.6; opacity: .8; animation: viz-wds-code 7.2s linear infinite both; }
[data-viz="website-design"] .v7 { stroke: var(--viz-ice); stroke-width: 1.2; opacity: 0; animation: viz-wds-scan 7.2s var(--viz-io) infinite both; }
@keyframes viz-wds-wire {
  0%, 8% { stroke-dashoffset: 0; opacity: 1; }
  11% { stroke-dashoffset: 0; opacity: 0; }
  11.5% { stroke-dashoffset: 1; opacity: 0; }
  12.5% { stroke-dashoffset: 1; opacity: 1; }
  30%, 100% { stroke-dashoffset: 0; opacity: 1; }
}
@keyframes viz-wds-pop {
  0%, 8% { transform: none; opacity: 1; }
  11% { transform: none; opacity: 0; }
  30% { transform: scale(.9); opacity: 0; }
  38%, 100% { transform: none; opacity: 1; }
}
@keyframes viz-wds-code {
  0%, 8% { stroke-dashoffset: 0; opacity: .8; }
  11% { stroke-dashoffset: 0; opacity: 0; }
  11.5% { stroke-dashoffset: 1; opacity: 0; }
  54% { stroke-dashoffset: 1; opacity: .8; animation-timing-function: steps(9, end); }
  68%, 100% { stroke-dashoffset: 0; opacity: .8; }
}
@keyframes viz-wds-scan {
  0%, 48% { transform: none; opacity: 0; }
  50% { opacity: .95; }
  62% { opacity: .95; }
  64%, 100% { transform: translateX(136px); opacity: 0; }
}

/* ============================================================
   2. website-development — Lighthouse ring closes at 100   (6.4 s)
   ============================================================ */
[data-viz="website-development"] .v8 { stroke: rgba(111, 214, 255, .14); stroke-width: 1.6; }
[data-viz="website-development"] .v1 { stroke: var(--viz-blue); stroke-width: 5; animation: viz-wdv-arc 6.4s linear infinite both; }
[data-viz="website-development"] .v2 { stroke: var(--viz-mint); stroke-width: 5; animation: viz-wdv-mint 6.4s linear infinite both; }
[data-viz="website-development"] .v3 { stroke: var(--viz-mint); stroke-width: 3.6; animation: viz-wdv-check 6.4s var(--viz-io) infinite both; }
[data-viz="website-development"] .v4 { stroke: var(--viz-mint); stroke-width: 2.8; animation: viz-wdv-mini 6.4s linear infinite both; }
[data-viz="website-development"] .v4:nth-of-type(7) { animation-delay: .22s; }
[data-viz="website-development"] .v4:nth-of-type(8) { animation-delay: .44s; }
[data-viz="website-development"] .v5 { stroke: var(--viz-mint); stroke-width: .9; opacity: 0; animation: viz-wdv-shock 6.4s var(--viz-out) infinite both; }
@keyframes viz-wdv-arc {
  0%, 9% { stroke-dashoffset: 0; animation-timing-function: cubic-bezier(.55, 0, .9, .4); }
  14%, 18% { stroke-dashoffset: 1; animation-timing-function: cubic-bezier(.15, .6, .25, 1); }
  58%, 100% { stroke-dashoffset: 0; }
}
@keyframes viz-wdv-mint {
  0%, 9% { opacity: 1; }
  12%, 57% { opacity: 0; }
  61%, 100% { opacity: 1; }
}
@keyframes viz-wdv-check {
  0%, 9% { stroke-dashoffset: 0; opacity: 1; }
  12% { stroke-dashoffset: 0; opacity: 0; }
  12.5% { stroke-dashoffset: 1; opacity: 0; }
  59% { stroke-dashoffset: 1; opacity: 1; }
  67%, 100% { stroke-dashoffset: 0; opacity: 1; }
}
@keyframes viz-wdv-mini {
  0%, 9% { stroke-dashoffset: 0; animation-timing-function: cubic-bezier(.55, 0, .9, .4); }
  14%, 22% { stroke-dashoffset: 1; animation-timing-function: cubic-bezier(.2, .6, .3, 1); }
  50%, 100% { stroke-dashoffset: 0; }
}
@keyframes viz-wdv-shock {
  0%, 58% { transform: scale(.8); opacity: 0; }
  60% { opacity: .9; }
  80%, 100% { transform: scale(1.14); opacity: 0; }
}

/* ============================================================
   3. web-development — code types, the preview renders   (7.2 s)
   ============================================================ */
[data-viz="web-development"] .vn { stroke-width: 3; }
[data-viz="web-development"] .vs { stroke-width: 1.4; stroke: rgba(111, 214, 255, .26); }
[data-viz="web-development"] .viz__layer--live > path:not([class]) { stroke-width: 3; stroke-linecap: butt; }
[data-viz="web-development"] .viz__layer--live > path:nth-of-type(4) { stroke: var(--viz-blue); animation: viz-wdc-1 7.2s linear infinite both; }
[data-viz="web-development"] .viz__layer--live > path:nth-of-type(5) { stroke: var(--viz-ice); animation: viz-wdc-2 7.2s linear infinite both; }
[data-viz="web-development"] .viz__layer--live > path:nth-of-type(6) { stroke: var(--viz-cyan); animation: viz-wdc-3 7.2s linear infinite both; }
[data-viz="web-development"] .viz__layer--live > path:nth-of-type(7) { stroke: var(--viz-ice); animation: viz-wdc-4 7.2s linear infinite both; }
[data-viz="web-development"] .viz__layer--live > path:nth-of-type(8) { stroke: var(--viz-blue); animation: viz-wdc-5 7.2s linear infinite both; }
[data-viz="web-development"] .viz__layer--live > path:nth-of-type(9) { stroke: var(--viz-cyan); animation: viz-wdc-6 7.2s linear infinite both; }
[data-viz="web-development"] .viz__layer--live > path:nth-of-type(10) { stroke: rgba(214, 243, 255, .55); animation: viz-wdc-7 7.2s linear infinite both; }
[data-viz="web-development"] .v5 { stroke: var(--viz-ice); stroke-width: 2.6; transform-origin: 0 50%; animation: viz-wdc-b1 7.2s var(--viz-out) infinite both; }
[data-viz="web-development"] .v6 { fill: rgba(26, 111, 208, .85); stroke: rgba(111, 214, 255, .5); stroke-width: .6; animation: viz-wdc-b2 7.2s var(--viz-out) infinite both; }
[data-viz="web-development"] .v7 { stroke: rgba(111, 214, 255, .55); stroke-width: 5; stroke-linecap: butt; animation: viz-wdc-b3 7.2s var(--viz-out) infinite both; }
[data-viz="web-development"] .v8 { stroke: var(--viz-ice); stroke-width: 1.4; animation: viz-wdc-caret 7.2s linear infinite both, viz-blink 1.05s linear infinite both; }
[data-viz="web-development"] .v9 { stroke: var(--viz-mint); stroke-width: 5; animation: viz-wdc-ok 7.2s var(--viz-out) infinite both; }
@keyframes viz-wdc-1 { 0%, 8% { stroke-dashoffset: 0; opacity: 1; } 11% { stroke-dashoffset: 0; opacity: 0; } 11.5% { stroke-dashoffset: 1; opacity: 0; } 12%, 14% { stroke-dashoffset: 1; opacity: 1; animation-timing-function: steps(7, end); } 20%, 100% { stroke-dashoffset: 0; opacity: 1; } }
@keyframes viz-wdc-2 { 0%, 8% { stroke-dashoffset: 0; opacity: 1; } 11% { stroke-dashoffset: 0; opacity: 0; } 11.5% { stroke-dashoffset: 1; opacity: 0; } 12%, 22% { stroke-dashoffset: 1; opacity: 1; animation-timing-function: steps(7, end); } 28%, 100% { stroke-dashoffset: 0; opacity: 1; } }
@keyframes viz-wdc-3 { 0%, 8% { stroke-dashoffset: 0; opacity: 1; } 11% { stroke-dashoffset: 0; opacity: 0; } 11.5% { stroke-dashoffset: 1; opacity: 0; } 12%, 30% { stroke-dashoffset: 1; opacity: 1; animation-timing-function: steps(7, end); } 36%, 100% { stroke-dashoffset: 0; opacity: 1; } }
@keyframes viz-wdc-4 { 0%, 8% { stroke-dashoffset: 0; opacity: 1; } 11% { stroke-dashoffset: 0; opacity: 0; } 11.5% { stroke-dashoffset: 1; opacity: 0; } 12%, 38% { stroke-dashoffset: 1; opacity: 1; animation-timing-function: steps(7, end); } 44%, 100% { stroke-dashoffset: 0; opacity: 1; } }
@keyframes viz-wdc-5 { 0%, 8% { stroke-dashoffset: 0; opacity: 1; } 11% { stroke-dashoffset: 0; opacity: 0; } 11.5% { stroke-dashoffset: 1; opacity: 0; } 12%, 46% { stroke-dashoffset: 1; opacity: 1; animation-timing-function: steps(7, end); } 52%, 100% { stroke-dashoffset: 0; opacity: 1; } }
@keyframes viz-wdc-6 { 0%, 8% { stroke-dashoffset: 0; opacity: 1; } 11% { stroke-dashoffset: 0; opacity: 0; } 11.5% { stroke-dashoffset: 1; opacity: 0; } 12%, 54% { stroke-dashoffset: 1; opacity: 1; animation-timing-function: steps(7, end); } 60%, 100% { stroke-dashoffset: 0; opacity: 1; } }
@keyframes viz-wdc-7 { 0%, 8% { stroke-dashoffset: 0; opacity: 1; } 11% { stroke-dashoffset: 0; opacity: 0; } 11.5% { stroke-dashoffset: 1; opacity: 0; } 12%, 62% { stroke-dashoffset: 1; opacity: 1; animation-timing-function: steps(7, end); } 68%, 100% { stroke-dashoffset: 0; opacity: 1; } }
@keyframes viz-wdc-b1 { 0%, 8% { transform: none; opacity: 1; } 11%, 28% { transform: scaleX(0); opacity: 0; } 30%, 100% { transform: none; opacity: 1; } }
@keyframes viz-wdc-b2 { 0%, 8% { transform: none; opacity: 1; } 11%, 44% { transform: scale(.7); opacity: 0; } 47%, 100% { transform: none; opacity: 1; } }
@keyframes viz-wdc-b3 { 0%, 8% { transform: none; opacity: 1; } 11%, 60% { transform: translateY(4px); opacity: 0; } 63%, 100% { transform: none; opacity: 1; } }
@keyframes viz-wdc-caret {
  0%, 8% { transform: none; animation-timing-function: steps(1, end); }
  11.5% { transform: translate(-40px, -48px); }
  14% { transform: translate(-40px, -48px); animation-timing-function: steps(7, end); }
  20% { transform: translate(-10px, -48px); animation-timing-function: steps(1, end); }
  22% { transform: translate(-34px, -40px); animation-timing-function: steps(7, end); }
  28% { transform: translate(12px, -40px); animation-timing-function: steps(1, end); }
  30% { transform: translate(-28px, -32px); animation-timing-function: steps(7, end); }
  36% { transform: translate(28px, -32px); animation-timing-function: steps(1, end); }
  38% { transform: translate(-28px, -24px); animation-timing-function: steps(7, end); }
  44% { transform: translate(6px, -24px); animation-timing-function: steps(1, end); }
  46% { transform: translate(-34px, -16px); animation-timing-function: steps(7, end); }
  52% { transform: translate(16px, -16px); animation-timing-function: steps(1, end); }
  54% { transform: translate(-40px, -8px); animation-timing-function: steps(7, end); }
  60% { transform: translate(-18px, -8px); animation-timing-function: steps(1, end); }
  62% { transform: translate(-40px, 0); animation-timing-function: steps(7, end); }
  68%, 100% { transform: none; }
}
@keyframes viz-blink { 0%, 55% { opacity: 1; } 56%, 100% { opacity: 0; } }
@keyframes viz-wdc-ok {
  0%, 8% { transform: none; opacity: 1; }
  11%, 68% { transform: scale(.2); opacity: 0; }
  72% { transform: scale(1.35); opacity: 1; }
  76%, 100% { transform: none; opacity: 1; }
}

/* ============================================================
   4. custom-web-applications — modules snap into a dashboard (6.4 s)
   ============================================================ */
[data-viz="custom-web-applications"] .v1 { --sx: 0px; --sy: -12px; animation: viz-cwa-snap 6.4s var(--viz-io) infinite both; }
[data-viz="custom-web-applications"] .v1 > :first-child { fill: rgba(111, 214, 255, .1); stroke: rgba(111, 214, 255, .55); stroke-width: .7; }
[data-viz="custom-web-applications"] .v1 > :last-child { stroke: var(--viz-ice); stroke-width: 3; }
[data-viz="custom-web-applications"] .v1:nth-of-type(1) { --sx: -14px; --sy: 0px; }
[data-viz="custom-web-applications"] .v1:nth-of-type(1) > :first-child { fill: rgba(26, 111, 208, .42); }
[data-viz="custom-web-applications"] .v1:nth-of-type(1) > :last-child { stroke: var(--viz-cyan); stroke-width: 3.4; }
[data-viz="custom-web-applications"] .v1:nth-of-type(2) { animation-delay: .1s; }
[data-viz="custom-web-applications"] .v1:nth-of-type(2) > :last-child { stroke: var(--viz-mint); stroke-width: 3.6; }
[data-viz="custom-web-applications"] .v1:nth-of-type(3) { --sx: -8px; --sy: -14px; animation-delay: .2s; }
[data-viz="custom-web-applications"] .v1:nth-of-type(4) { --sy: -16px; animation-delay: .28s; }
[data-viz="custom-web-applications"] .v1:nth-of-type(5) { --sx: 8px; --sy: -14px; animation-delay: .36s; }
[data-viz="custom-web-applications"] .v1:nth-of-type(6) { --sx: -12px; --sy: 14px; animation-delay: .46s; }
[data-viz="custom-web-applications"] .v1:nth-of-type(6) > :last-child { stroke: var(--viz-cyan); stroke-width: 1.6; }
[data-viz="custom-web-applications"] .v1:nth-of-type(7) { --sx: 16px; --sy: 10px; animation-delay: .56s; }
[data-viz="custom-web-applications"] .v1:nth-of-type(7) > :last-child { stroke: var(--viz-soft); stroke-width: 1.4; }
@keyframes viz-cwa-snap {
  0%, 9% { transform: none; opacity: 1; }
  16%, 30% { transform: translate(var(--sx), var(--sy)) scale(.9); opacity: 0; animation-timing-function: var(--viz-snap); }
  40%, 100% { transform: none; opacity: 1; }
}

/* ============================================================
   5. mobile-apps — a list scrolls inside a phone   (6 s)
   ============================================================ */
[data-viz="mobile-apps"] .vk { fill: rgba(56, 168, 240, .16); }
[data-viz="mobile-apps"] .v8 { fill: rgba(3, 10, 20, .9); stroke: rgba(214, 243, 255, .7); stroke-width: 1.3; }
[data-viz="mobile-apps"] .vi { stroke-width: 3; }
[data-viz="mobile-apps"] .vn { stroke: var(--viz-cyan); stroke-width: 4; }
[data-viz="mobile-apps"] .v1 { animation: viz-ma-list 6s var(--viz-io) infinite both; }
[data-viz="mobile-apps"] .v1 > :first-child { fill: rgba(111, 214, 255, .1); stroke: rgba(111, 214, 255, .4); stroke-width: .6; }
[data-viz="mobile-apps"] .v1 > :last-child { stroke: rgba(214, 243, 255, .7); stroke-width: 2; }
[data-viz="mobile-apps"] .v1:nth-of-type(1) { opacity: 0; }
[data-viz="mobile-apps"] .v1:nth-of-type(2) { transform: translateY(-12px); animation-delay: -1.2s; }
[data-viz="mobile-apps"] .v1:nth-of-type(3) { transform: translateY(-24px); animation-delay: -2.4s; }
[data-viz="mobile-apps"] .v1:nth-of-type(4) { transform: translateY(-36px); animation-delay: -3.6s; }
[data-viz="mobile-apps"] .v1:nth-of-type(5) { transform: translateY(-48px); animation-delay: -4.8s; }
[data-viz="mobile-apps"] .v2 { fill: rgba(214, 243, 255, .16); stroke: var(--viz-ice); stroke-width: .8; opacity: 0; animation: viz-ma-tap 6s var(--viz-out) infinite both; }
@keyframes viz-ma-list {
  0% { transform: none; opacity: 0; }
  9%, 20% { transform: translateY(-12px); opacity: 1; }
  29%, 40% { transform: translateY(-24px); }
  49%, 60% { transform: translateY(-36px); }
  69% { transform: translateY(-48px); }
  80% { transform: translateY(-48px); opacity: 1; }
  89%, 100% { transform: translateY(-60px); opacity: 0; }
}
@keyframes viz-ma-tap {
  0%, 50% { transform: scale(.3); opacity: 0; }
  52% { opacity: .95; }
  66%, 100% { transform: scale(1.7); opacity: 0; }
}

/* ============================================================
   6. seo — the highlighted result climbs #5 → #1   (6.4 s)
   ============================================================ */
[data-viz="seo"] .v11 { stroke: rgba(111, 214, 255, .13); stroke-width: 12; }
[data-viz="seo"] .v6 { stroke: var(--viz-cyan); stroke-width: 2.2; animation: viz-seo-q 6.4s linear infinite both; }
[data-viz="seo"] .v9 { stroke: rgba(111, 214, 255, .3); stroke-width: 3; }
[data-viz="seo"] :is(.v2, .v3, .v4, .v5) circle { fill: rgba(111, 214, 255, .45); }
[data-viz="seo"] :is(.v2, .v3, .v4, .v5) path { stroke: rgba(111, 214, 255, .38); stroke-width: 2.2; }
[data-viz="seo"] .v1 rect { fill: rgba(56, 168, 240, .26); stroke: rgba(214, 243, 255, .6); stroke-width: .7; }
[data-viz="seo"] .v1 circle { fill: var(--viz-cyan); }
[data-viz="seo"] .v1 > path:nth-of-type(1) { stroke: var(--viz-ice); stroke-width: 3; }
[data-viz="seo"] .v1 > path:nth-of-type(2) { stroke: rgba(111, 214, 255, .75); stroke-width: 1.5; }
[data-viz="seo"] .v10 { stroke: var(--viz-mint); stroke-width: 1.6; opacity: 0; animation: viz-seo-up 6.4s linear infinite both; }
[data-viz="seo"] .v1 { animation: viz-seo-1 6.4s var(--viz-io) infinite both; }
[data-viz="seo"] .v2 { animation: viz-seo-2 6.4s var(--viz-io) infinite both; }
[data-viz="seo"] .v3 { animation: viz-seo-3 6.4s var(--viz-io) infinite both; }
[data-viz="seo"] .v4 { animation: viz-seo-4 6.4s var(--viz-io) infinite both; }
[data-viz="seo"] .v5 { animation: viz-seo-5 6.4s var(--viz-io) infinite both; }
[data-viz="seo"] .v7 { stroke: var(--viz-mint); stroke-width: 3; transform-origin: 0 50%; animation: viz-seo-win 6.4s var(--viz-out) infinite both; }
[data-viz="seo"] .v8 { stroke: var(--viz-mint); stroke-width: 1; opacity: 0; animation: viz-seo-ring 6.4s var(--viz-out) infinite both; }
@keyframes viz-seo-q {
  0%, 9% { stroke-dashoffset: 0; opacity: 1; }
  12% { stroke-dashoffset: 0; opacity: 0; }
  12.5% { stroke-dashoffset: 1; opacity: 0; }
  13% { stroke-dashoffset: 1; opacity: 1; animation-timing-function: steps(8, end); }
  19%, 100% { stroke-dashoffset: 0; opacity: 1; }
}
@keyframes viz-seo-1 {
  0%, 9% { transform: none; opacity: 1; }
  12% { transform: none; opacity: 0; }
  12.5%, 19% { transform: translateY(40px); opacity: 0; }
  24%, 28% { transform: translateY(40px); opacity: 1; }
  33%, 40% { transform: translateY(30px); }
  45%, 52% { transform: translateY(20px); }
  57%, 64% { transform: translateY(10px); }
  69%, 100% { transform: none; opacity: 1; }
}
@keyframes viz-seo-2 {
  0%, 9% { transform: none; opacity: 1; }
  12% { transform: none; opacity: 0; }
  12.5%, 19% { transform: translateY(-10px); opacity: 0; }
  24% { opacity: 1; }
  64% { transform: translateY(-10px); }
  69%, 100% { transform: none; opacity: 1; }
}
@keyframes viz-seo-3 {
  0%, 9% { transform: none; opacity: 1; }
  12% { transform: none; opacity: 0; }
  12.5%, 19% { transform: translateY(-10px); opacity: 0; }
  24% { opacity: 1; }
  52% { transform: translateY(-10px); }
  57%, 100% { transform: none; opacity: 1; }
}
@keyframes viz-seo-4 {
  0%, 9% { transform: none; opacity: 1; }
  12% { transform: none; opacity: 0; }
  12.5%, 19% { transform: translateY(-10px); opacity: 0; }
  24% { opacity: 1; }
  40% { transform: translateY(-10px); }
  45%, 100% { transform: none; opacity: 1; }
}
@keyframes viz-seo-5 {
  0%, 9% { transform: none; opacity: 1; }
  12% { transform: none; opacity: 0; }
  12.5%, 19% { transform: translateY(-10px); opacity: 0; }
  24% { opacity: 1; }
  28% { transform: translateY(-10px); }
  33%, 100% { transform: none; opacity: 1; }
}
@keyframes viz-seo-up {
  0%, 26%, 35%, 38%, 47%, 50%, 59%, 62%, 71%, 100% { opacity: 0; }
  28%, 33%, 40%, 45%, 52%, 57%, 64%, 69% { opacity: 1; }
}
@keyframes viz-seo-win {
  0%, 9% { transform: none; opacity: 1; }
  12% { transform: none; opacity: 0; }
  12.5%, 69% { transform: scaleX(0); opacity: 0; }
  70% { opacity: 1; }
  76%, 100% { transform: none; opacity: 1; }
}
@keyframes viz-seo-ring {
  0%, 68% { transform: scale(.4); opacity: 0; }
  69.5% { opacity: .95; }
  84%, 100% { transform: scale(2); opacity: 0; }
}

/* ============================================================
   7. local-seo — a pin drops, radar rings roll out   (6 s pin / 3 s rings)
   ============================================================ */
[data-viz="local-seo"] .v8 { stroke: rgba(111, 214, 255, .1); stroke-width: 5; stroke-linecap: butt; }
[data-viz="local-seo"] .viz__layer--plate .vh { stroke: rgba(111, 214, 255, .2); }
[data-viz="local-seo"] .viz__layer--plate .vn { stroke: rgba(111, 214, 255, .4); stroke-width: 3; }
[data-viz="local-seo"] .v2 { stroke: var(--viz-cyan); stroke-width: 1.1; transform: scale(1.86); opacity: .242; animation: viz-lseo-ring 3s linear infinite both; }
[data-viz="local-seo"] .v2:nth-of-type(3) { transform: scale(1.41); opacity: .443; animation-delay: -2.55s; }
[data-viz="local-seo"] .v2:nth-of-type(4) { transform: scale(.96); opacity: .645; animation-delay: -2.1s; }
[data-viz="local-seo"] .v3 { fill: rgba(2, 6, 13, .55); stroke: rgba(111, 214, 255, .55); stroke-width: .6; animation: viz-lseo-shadow 6s linear infinite both; }
[data-viz="local-seo"] .v1 { animation: viz-lseo-pin 6s linear infinite both; }
[data-viz="local-seo"] .v1 path { fill: var(--viz-cyan); stroke: var(--viz-ice); stroke-width: .8; }
[data-viz="local-seo"] .v1 circle { fill: var(--viz-ink); }
@keyframes viz-lseo-pin {
  0%, 56% { transform: none; opacity: 1; }
  61% { transform: translateY(-12px); opacity: 0; }
  62% { transform: translateY(-40px); opacity: 0; animation-timing-function: var(--viz-fall); }
  66% { opacity: 1; }
  74% { transform: none; animation-timing-function: cubic-bezier(0, .55, .45, 1); }
  78% { transform: translateY(-6px); animation-timing-function: var(--viz-fall); }
  82%, 100% { transform: none; opacity: 1; }
}
@keyframes viz-lseo-shadow {
  0%, 56% { transform: none; opacity: 1; }
  61%, 62% { transform: scale(.3); opacity: 0; animation-timing-function: var(--viz-fall); }
  74% { transform: none; opacity: 1; animation-timing-function: cubic-bezier(0, .55, .45, 1); }
  78% { transform: scale(.75); animation-timing-function: var(--viz-fall); }
  82%, 100% { transform: none; opacity: 1; }
}
/* one ring burst every 3 s: lands with the pin (4.44 s) and mid-idle */
@keyframes viz-lseo-ring {
  0% { transform: scale(1.86); opacity: .242; }
  18% { transform: scale(2.4); opacity: 0; }
  48% { transform: scale(.3); opacity: 0; }
  51% { opacity: .9; }
  100% { transform: scale(1.86); opacity: .242; }
}

/* ============================================================
   8. technical-seo — a crawler ticks through the site tree (6.8 s)
   ============================================================ */
[data-viz="technical-seo"] .v2 { stroke: var(--viz-cyan); stroke-width: 1.1; animation: viz-tseo-links 6.8s linear infinite both; }
[data-viz="technical-seo"] .v1 { stroke: var(--viz-cyan); stroke-width: 10; stroke-linecap: butt; }
[data-viz="technical-seo"] .v1:nth-of-type(3) { stroke: var(--viz-ice); stroke-width: 12; animation: viz-tseo-1 6.8s linear infinite both; }
[data-viz="technical-seo"] .v1:nth-of-type(4) { animation: viz-tseo-2 6.8s linear infinite both; }
[data-viz="technical-seo"] .v1:nth-of-type(5) { animation: viz-tseo-3 6.8s linear infinite both; }
[data-viz="technical-seo"] .v1:nth-of-type(6) { animation: viz-tseo-4 6.8s linear infinite both; }
[data-viz="technical-seo"] .v1:nth-of-type(7) { animation: viz-tseo-5 6.8s linear infinite both; }
[data-viz="technical-seo"] .v1:nth-of-type(8) { animation: viz-tseo-6 6.8s linear infinite both; }
[data-viz="technical-seo"] .v1:nth-of-type(9) { animation: viz-tseo-7 6.8s linear infinite both; }
[data-viz="technical-seo"] .v1:nth-of-type(10) { animation: viz-tseo-8 6.8s linear infinite both; }
[data-viz="technical-seo"] .v9 { animation: viz-tseo-bot 6.8s var(--viz-io) infinite both; }
[data-viz="technical-seo"] .v9 circle:first-child { fill: rgba(70, 224, 163, .14); stroke: var(--viz-mint); stroke-width: .9; }
[data-viz="technical-seo"] .v9 circle:last-child { fill: var(--viz-ice); }
@keyframes viz-tseo-links {
  0%, 9% { stroke-dashoffset: 0; opacity: 1; }
  12% { stroke-dashoffset: 0; opacity: 0; }
  12.5% { stroke-dashoffset: 1; opacity: 0; }
  13% { stroke-dashoffset: 1; opacity: 1; }
  16% { stroke-dashoffset: 1; }
  68%, 100% { stroke-dashoffset: 0; opacity: 1; }
}
@keyframes viz-tseo-1 { 0%, 9% { opacity: 1; } 13%, 15% { opacity: .22; } 17%, 100% { opacity: 1; } }
@keyframes viz-tseo-2 { 0%, 9% { opacity: 1; } 13%, 21.5% { opacity: .22; } 23%, 100% { opacity: 1; } }
@keyframes viz-tseo-3 { 0%, 9% { opacity: 1; } 13%, 28.5% { opacity: .22; } 30%, 100% { opacity: 1; } }
@keyframes viz-tseo-4 { 0%, 9% { opacity: 1; } 13%, 35.5% { opacity: .22; } 37%, 100% { opacity: 1; } }
@keyframes viz-tseo-5 { 0%, 9% { opacity: 1; } 13%, 42.5% { opacity: .22; } 44%, 100% { opacity: 1; } }
@keyframes viz-tseo-6 { 0%, 9% { opacity: 1; } 13%, 49.5% { opacity: .22; } 51%, 100% { opacity: 1; } }
@keyframes viz-tseo-7 { 0%, 9% { opacity: 1; } 13%, 56.5% { opacity: .22; } 58%, 100% { opacity: 1; } }
@keyframes viz-tseo-8 { 0%, 9% { opacity: 1; } 13%, 63.5% { opacity: .22; } 65%, 100% { opacity: 1; } }
@keyframes viz-tseo-bot {
  0%, 19% { transform: none; }
  21.5%, 26% { transform: translate(44px, -30px); }
  28.5%, 33% { transform: translate(86px, -30px); }
  35.5%, 40% { transform: translate(44px, 0); }
  42.5%, 47% { transform: translate(86px, -8px); }
  49.5%, 54% { transform: translate(86px, 8px); }
  56.5%, 61% { transform: translate(44px, 28px); }
  63.5%, 68% { transform: translate(86px, 28px); }
  74%, 100% { transform: none; }
}

/* ============================================================
   9. ai — signal pulses travel a neural graph   (4.8 s)
   ============================================================ */
[data-viz="ai"] .vh { stroke: rgba(111, 214, 255, .3); stroke-width: .7; }
[data-viz="ai"] .vn { stroke: rgba(56, 168, 240, .9); stroke-width: 6; }
/* three pulses 1.6 s apart; each reaches the answer node at 55 % of its
   cycle, so the node flashes every 1.6 s — and frame 0 is a flash peak */
[data-viz="ai"] .v1 { stroke: var(--viz-ice); stroke-width: 2.4; stroke-dasharray: .1 1.2; stroke-dashoffset: -1.05; animation: viz-ai-pulse 4.8s cubic-bezier(.45, .05, .55, .95) -2.64s infinite both; }
[data-viz="ai"] .v1:nth-of-type(4) { animation-delay: -4.24s; }
[data-viz="ai"] .v1:nth-of-type(5) { stroke-dashoffset: -.33; animation-delay: -1.04s; }
[data-viz="ai"] .v2 { stroke: var(--viz-mint); stroke-width: 7.5; transform: scale(1.35); animation: viz-ai-core 1.6s var(--viz-out) infinite both; }
[data-viz="ai"] .v3 { stroke: rgba(70, 224, 163, .45); stroke-width: 15; transform: scale(.6); animation: viz-ai-halo 1.6s var(--viz-out) infinite both; }
@keyframes viz-ai-pulse {
  0% { stroke-dashoffset: .1; }
  55%, 100% { stroke-dashoffset: -1.05; }
}
@keyframes viz-ai-core {
  0% { transform: scale(1.35); }
  45%, 100% { transform: none; }
}
@keyframes viz-ai-halo {
  0% { transform: scale(.6); opacity: 1; }
  70%, 100% { transform: scale(1.5); opacity: 0; }
}

/* ============================================================
   10. ai-chatbots — bubbles type, typing dots bounce   (7.2 s)
   ============================================================ */
[data-viz="ai-chatbots"] :is(.v1, .v3, .v4) rect { fill: rgba(111, 214, 255, .11); stroke: rgba(111, 214, 255, .5); stroke-width: .7; }
[data-viz="ai-chatbots"] :is(.v1, .v4) path { stroke: rgba(214, 243, 255, .78); stroke-width: 2; }
[data-viz="ai-chatbots"] .v2 rect { fill: var(--viz-deep); }
[data-viz="ai-chatbots"] .v2 path { stroke: var(--viz-ice); stroke-width: 2; }
[data-viz="ai-chatbots"] .v3 path { stroke: var(--viz-cyan); stroke-width: 2.8; animation: viz-cb-dot .9s ease-in-out infinite both; }
[data-viz="ai-chatbots"] .v3 path:nth-of-type(2) { animation-delay: .15s; }
[data-viz="ai-chatbots"] .v3 path:nth-of-type(3) { animation-delay: .3s; }
[data-viz="ai-chatbots"] .vn { stroke: var(--viz-cyan); stroke-width: 5; }
[data-viz="ai-chatbots"] :is(.v1, .v4) circle { fill: var(--viz-cyan); }
[data-viz="ai-chatbots"] :is(.v1, .v3, .v4) { transform-origin: 0 100%; }
[data-viz="ai-chatbots"] .v2 { transform-origin: 100% 100%; }
[data-viz="ai-chatbots"] .v1 { animation: viz-cb-1 7.2s var(--viz-out) infinite both; }
[data-viz="ai-chatbots"] .v1 path { animation: viz-cb-t1 7.2s linear infinite both; }
[data-viz="ai-chatbots"] .v2 { animation: viz-cb-2 7.2s var(--viz-out) infinite both; }
[data-viz="ai-chatbots"] .v2 path { animation: viz-cb-t2 7.2s linear infinite both; }
[data-viz="ai-chatbots"] .v3 { opacity: 0; animation: viz-cb-3 7.2s var(--viz-out) infinite both; }
[data-viz="ai-chatbots"] .v4 { animation: viz-cb-4 7.2s var(--viz-out) infinite both; }
[data-viz="ai-chatbots"] .v4 path { animation: viz-cb-t4 7.2s linear infinite both; }
@keyframes viz-cb-1 {
  0%, 8% { transform: none; opacity: 1; }
  12% { transform: translateY(-8px); opacity: 0; }
  12.5%, 14% { transform: scale(.55); opacity: 0; animation-timing-function: var(--viz-snap); }
  19%, 100% { transform: none; opacity: 1; }
}
@keyframes viz-cb-2 {
  0%, 8% { transform: none; opacity: 1; }
  12% { transform: translateY(-8px); opacity: 0; }
  12.5%, 30% { transform: scale(.55); opacity: 0; animation-timing-function: var(--viz-snap); }
  35%, 100% { transform: none; opacity: 1; }
}
@keyframes viz-cb-3 {
  0%, 44% { transform: scale(.55); opacity: 0; animation-timing-function: var(--viz-snap); }
  48%, 61% { transform: none; opacity: 1; }
  64%, 100% { transform: scale(.8); opacity: 0; }
}
@keyframes viz-cb-4 {
  0%, 8% { transform: none; opacity: 1; }
  12% { transform: translateY(-8px); opacity: 0; }
  12.5%, 62% { transform: scale(.55); opacity: 0; animation-timing-function: var(--viz-snap); }
  67%, 100% { transform: none; opacity: 1; }
}
@keyframes viz-cb-t1 { 0%, 12% { stroke-dashoffset: 0; } 12.5%, 19% { stroke-dashoffset: 1; animation-timing-function: steps(10, end); } 28%, 100% { stroke-dashoffset: 0; } }
@keyframes viz-cb-t2 { 0%, 12% { stroke-dashoffset: 0; } 12.5%, 35% { stroke-dashoffset: 1; animation-timing-function: steps(8, end); } 41%, 100% { stroke-dashoffset: 0; } }
@keyframes viz-cb-t4 { 0%, 12% { stroke-dashoffset: 0; } 12.5%, 67% { stroke-dashoffset: 1; animation-timing-function: steps(12, end); } 78%, 100% { stroke-dashoffset: 0; } }
@keyframes viz-cb-dot {
  0%, 60%, 100% { transform: none; opacity: .45; }
  30% { transform: translateY(-2.6px); opacity: 1; }
}

/* ============================================================
   11. ai-automation — pulses run the workflow, the gear turns (6 s)
   ============================================================ */
[data-viz="ai-automation"] .vh { stroke: rgba(111, 214, 255, .36); stroke-width: 1; }
[data-viz="ai-automation"] .v8 { fill: #174c80; stroke: #174c80; stroke-width: 8; }
[data-viz="ai-automation"] .vi { stroke-width: 1.3; }
[data-viz="ai-automation"] .v1,
[data-viz="ai-automation"] .v2 { stroke: var(--viz-ice); stroke-width: 2.6; stroke-dasharray: .14 1.2; stroke-dashoffset: .14; }
[data-viz="ai-automation"] .v1 { animation: viz-aa-in 6s cubic-bezier(.45, .05, .55, .95) infinite both; }
[data-viz="ai-automation"] .v1:nth-of-type(3) { animation-delay: .18s; }
[data-viz="ai-automation"] .v2 { animation: viz-aa-out 6s cubic-bezier(.45, .05, .55, .95) infinite both; }
[data-viz="ai-automation"] .v3 { animation: viz-spin 9s linear infinite both; }
[data-viz="ai-automation"] .v3 circle:first-child { stroke: var(--viz-cyan); stroke-width: 3.8; stroke-dasharray: 2.6 3.306; stroke-linecap: butt; }
[data-viz="ai-automation"] .v3 circle:last-child { fill: #174c80; stroke: var(--viz-cyan); stroke-width: 2.4; }
[data-viz="ai-automation"] .v4 { stroke: rgba(111, 214, 255, .5); stroke-width: 16; opacity: 0; animation: viz-aa-fire 6s var(--viz-out) infinite both; }
[data-viz="ai-automation"] .v5 { fill: var(--viz-mint); stroke: var(--viz-mint); stroke-width: 8; animation: viz-aa-done 6s var(--viz-out) infinite both; }
[data-viz="ai-automation"] .v6 { stroke: var(--viz-ink); stroke-width: 1.7; animation: viz-aa-check 6s var(--viz-out) infinite both; }
@keyframes viz-aa-in {
  0%, 16% { stroke-dashoffset: .14; }
  42%, 100% { stroke-dashoffset: -1.05; }
}
@keyframes viz-aa-out {
  0%, 46% { stroke-dashoffset: .14; }
  60%, 100% { stroke-dashoffset: -1.05; }
}
@keyframes viz-spin { to { transform: rotate(360deg); } }
@keyframes viz-aa-fire {
  0%, 14% { transform: scale(.3); opacity: 0; }
  16% { opacity: 1; }
  32%, 100% { transform: scale(1.6); opacity: 0; }
}
@keyframes viz-aa-done {
  0%, 9% { transform: none; opacity: 1; }
  12%, 59% { transform: scale(.4); opacity: 0; }
  63% { transform: scale(1.2); opacity: 1; }
  67%, 100% { transform: none; opacity: 1; }
}
@keyframes viz-aa-check {
  0%, 9% { transform: none; opacity: 1; }
  12%, 62% { transform: scale(.3); opacity: 0; }
  66% { transform: scale(1.25); opacity: 1; }
  70%, 100% { transform: none; opacity: 1; }
}

/* ============================================================
   12. data-analytics — bars rise, a sparkline draws   (6.4 s)
   ============================================================ */
[data-viz="data-analytics"] .v1 path { stroke: rgba(56, 168, 240, .78); stroke-width: 8; stroke-linecap: butt; transform-box: fill-box; transform-origin: 50% 100%; animation: viz-da-bar 6.4s var(--viz-io) infinite both; }
[data-viz="data-analytics"] .v1 path:last-child { stroke: var(--viz-cyan); }
[data-viz="data-analytics"] .v1 path:nth-child(2) { animation-delay: .07s; }
[data-viz="data-analytics"] .v1 path:nth-child(3) { animation-delay: .14s; }
[data-viz="data-analytics"] .v1 path:nth-child(4) { animation-delay: .21s; }
[data-viz="data-analytics"] .v1 path:nth-child(5) { animation-delay: .28s; }
[data-viz="data-analytics"] .v1 path:nth-child(6) { animation-delay: .35s; }
[data-viz="data-analytics"] .v1 path:nth-child(7) { animation-delay: .42s; }
[data-viz="data-analytics"] .v2 { fill: rgba(111, 214, 255, .1); animation: viz-da-area 6.4s linear infinite both; }
[data-viz="data-analytics"] .v3 { stroke: var(--viz-ice); stroke-width: 1.8; animation: viz-da-line 6.4s var(--viz-io) infinite both; }
[data-viz="data-analytics"] .v4 { stroke: var(--viz-mint); stroke-width: 6; animation: viz-da-dot 6.4s var(--viz-out) infinite both; }
[data-viz="data-analytics"] .v5 { stroke: var(--viz-mint); stroke-width: .9; opacity: 0; animation: viz-da-halo 6.4s var(--viz-out) infinite both; }
[data-viz="data-analytics"] .v6 { fill: var(--viz-mint); animation: viz-da-kpi 6.4s var(--viz-out) infinite both; }
@keyframes viz-da-bar {
  0%, 9% { transform: none; }
  13%, 17% { transform: scaleY(0); animation-timing-function: cubic-bezier(.3, 1.3, .5, 1); }
  30%, 100% { transform: none; }
}
@keyframes viz-da-area { 0%, 9% { opacity: 1; } 12%, 50% { opacity: 0; } 60%, 100% { opacity: 1; } }
@keyframes viz-da-line {
  0%, 9% { stroke-dashoffset: 0; opacity: 1; }
  12% { stroke-dashoffset: 0; opacity: 0; }
  12.5% { stroke-dashoffset: 1; opacity: 0; }
  13%, 31% { stroke-dashoffset: 1; opacity: 1; }
  55%, 100% { stroke-dashoffset: 0; opacity: 1; }
}
@keyframes viz-da-dot {
  0%, 9% { transform: none; opacity: 1; }
  12%, 54% { transform: scale(.3); opacity: 0; }
  58% { transform: scale(1.5); opacity: 1; }
  62%, 100% { transform: none; opacity: 1; }
}
@keyframes viz-da-halo {
  0%, 55% { transform: scale(.5); opacity: 0; }
  57% { opacity: .9; }
  76%, 100% { transform: scale(1.9); opacity: 0; }
}
@keyframes viz-da-kpi {
  0%, 9% { transform: none; opacity: 1; }
  12%, 58% { transform: translateY(5px); opacity: 0; }
  64%, 100% { transform: none; opacity: 1; }
}
