/* ============================================================
   GRAPH HERO — LOOPING METHOD ANIMATION
   Self-contained: no external requests, no JS at all.
   Base (un-animated) styles = the STATIC COMPOSED FRAME
   (also serves reduced-motion and no-CSS-animation browsers).
   All motion lives inside @media (prefers-reduced-motion: no-preference).

   MASTER LOOP: 9s  (--loop)
   BEAT 1 · INTAKE      0.0–1.5s    0%–16.7%
   BEAT 2 · COMPREHEND  1.5–3.5s   16.7%–38.9%
   BEAT 3 · DISPATCH    3.5–5.5s   38.9%–61.1%
   BEAT 4 · RETRIEVE    5.5–7.5s   61.1%–83.3%   ← the argument
   BEAT 5 · RETURN      7.5–9.0s   83.3%–100%
   Loop reconciliation: last cycle's absorbed nodes + docked region
   consolidate into the standing graph during BEAT 1 (0–15%), while
   the eye is on the incoming mass — no snap-back.

   Ported into candyfactory-www: scoped under .graph-hero, source
   color names aliased to the site's brand tokens (identical hex),
   fonts mapped to the site's --mono / --display. Zero visual drift.
   ============================================================ */
.graph-hero{
  --teal:var(--mint); --blue:var(--sky); --yellow:var(--butter); --violet:var(--pop);
  --cream:var(--bg); --cream-soft:var(--bg-soft);
  --font-mono:var(--mono); --font-display:var(--display);
  /* --ink, --ink-soft, --pink, --hot, --paper inherit from site :root (identical values) */
  --loop:9s;
  --sh-sm:3px 3px 0 var(--ink); --sh-md:6px 6px 0 var(--ink); --sh-lg:8px 8px 0 var(--ink);
}
.graph-hero *{box-sizing:border-box}
/* source body background/color/font moved onto the scoped hero (no page-body leak) */
.graph-hero{
  background:
    radial-gradient(620px 420px at 10% 12%, color-mix(in oklab, var(--blue) 20%, transparent), transparent 70%),
    radial-gradient(720px 500px at 90% 88%, color-mix(in oklab, var(--pink) 18%, transparent), transparent 70%),
    var(--cream);
  color:var(--ink);
  font-family:var(--font-mono);
  overflow-x:hidden;
  max-width:1200px;margin:0 auto;padding:36px 20px 44px;
}
.graph-hero svg{display:block;width:100%;height:auto}

/* ---- shared svg styles ---- */
.graph-hero text{fill:var(--ink);font-family:var(--font-mono)}
.graph-hero .lb{font-size:11.5px;letter-spacing:.18em;font-weight:600;text-anchor:middle;fill:var(--ink)}
.graph-hero .edge{stroke:var(--ink-soft);stroke-width:1.6;opacity:.38;stroke-linecap:round}
.graph-hero .nd{stroke:var(--ink);stroke-width:2}
.graph-hero .hub{stroke-width:2.4}
.graph-hero .f-teal{fill:color-mix(in oklab, var(--teal) 45%, var(--paper))}
.graph-hero .f-blue{fill:color-mix(in oklab, var(--blue) 45%, var(--paper))}
.graph-hero .f-yellow{fill:color-mix(in oklab, var(--yellow) 50%, var(--paper))}
.graph-hero .f-violet{fill:color-mix(in oklab, var(--violet) 40%, var(--paper))}
.graph-hero .f-pink{fill:color-mix(in oklab, var(--pink) 48%, var(--paper))}
.graph-hero .f-hot{fill:color-mix(in oklab, var(--hot) 45%, var(--paper))}

.graph-hero .mass,.graph-hero .wk,.graph-hero .pk,.graph-hero .ret,.graph-hero .pulse,.graph-hero .pkt{transform-box:fill-box;transform-origin:center}

/* dock edges: drawable */
.graph-hero .dk{stroke:var(--ink-soft);stroke-width:1.6;stroke-linecap:round;stroke-dasharray:1;stroke-dashoffset:0;opacity:.55}
/* return edges */
.graph-hero .rte{stroke:var(--ink-soft);stroke-width:1.5;opacity:.45;stroke-linecap:round}
/* dispatch tracks */
.graph-hero .track{stroke:var(--ink-soft);stroke-width:1.5;stroke-dasharray:2 7;stroke-linecap:round;opacity:.5}
/* retrieve pull-lines: drawn worker → source node */
.graph-hero .pull{stroke-width:2.2;fill:none;stroke-linecap:round;stroke-dasharray:1;stroke-dashoffset:0;opacity:.9}
/* source pulse rings (static: quiet marker) */
.graph-hero .pulse{fill:none;stroke-width:2;opacity:.4;transform:scale(1.7)}
/* packets (static: shown mid-pull) */
.graph-hero .pkt{stroke:var(--ink);stroke-width:1.5;transform:translate(calc(var(--wx) * .55), calc(var(--wy) * .55))}
/* incoming mass (static: entering at left) */
.graph-hero .mass{transform:translate(-330px,4px)}
/* worker chips */
.graph-hero .wk .chip{fill:var(--paper);stroke:var(--ink);stroke-width:2}
.graph-hero .wk .chip-sh{fill:var(--ink)}
.graph-hero .wk .chip-t{font-size:10.5px;letter-spacing:.14em;font-weight:600}

/* ---- caption strip ---- */
.graph-hero .caps{max-width:1160px;margin:10px auto 0;min-height:20px;position:relative}
.graph-hero .caps b{color:var(--hot);font-weight:600}
.graph-hero .caps-static{font-size:11px;letter-spacing:.2em;color:var(--ink)}
.graph-hero .caps-live{display:none}
.graph-hero .caps-live .cap{position:absolute;left:0;top:0;font-size:11px;letter-spacing:.22em;white-space:nowrap;color:var(--ink)}
@media (max-width:560px){
  .graph-hero .caps-static,.graph-hero .caps-live .cap{font-size:10px;letter-spacing:.14em}
  .graph-hero .lb{display:none}                            /* in-svg annotations hide at phone scale */
  .graph-hero .wk .chip-t{display:none}
  .graph-hero .wk .chip{width:34px;x:-17px}                /* chips collapse to marked tiles */
  .graph-hero .wk .chip-sh{width:34px;x:-14px}
  .graph-hero .wk .sq{transform:scale(1.5)}
}

/* ============================================================
   MOTION — everything below only when motion is welcome
   ============================================================ */
@media (prefers-reduced-motion: no-preference){
  .graph-hero .static-only{display:none}
  .graph-hero .caps-static{display:none}
  .graph-hero .caps-live{display:block}

  .graph-hero .breathe{animation:breathe 7s ease-in-out infinite alternate}
  .graph-hero .tw{animation:twinkle 3.4s ease-in-out infinite alternate}

  .graph-hero .mass{animation:mass var(--loop) infinite;animation-timing-function:cubic-bezier(.3,.7,.25,1)}
  .graph-hero .pk.pk-a{animation:pink-a var(--loop) infinite}
  .graph-hero .pk.pk-b{animation:pink-b var(--loop) infinite}
  .graph-hero .pk.pk-c{animation:pink-c var(--loop) infinite}
  .graph-hero .plabel{animation:pink-label var(--loop) infinite}
  .graph-hero .dk.dk-a{animation:dock-a var(--loop) infinite}
  .graph-hero .dk.dk-b{animation:dock-b var(--loop) infinite}
  .graph-hero .track{animation:track var(--loop) infinite}
  .graph-hero .wk.w-1{animation:wk-1 var(--loop) infinite}
  .graph-hero .wk.w-2{animation:wk-2 var(--loop) infinite}
  .graph-hero .wk.w-3{animation:wk-3 var(--loop) infinite}
  .graph-hero .wk.w-4{animation:wk-4 var(--loop) infinite}
  .graph-hero .wk.w-5{animation:wk-5 var(--loop) infinite}
  .graph-hero .pull.p-a{animation:pull-a var(--loop) infinite}
  .graph-hero .pull.p-b{animation:pull-b var(--loop) infinite}
  .graph-hero .pull.p-c{animation:pull-c var(--loop) infinite}
  .graph-hero .pkt.k-a{animation:pkt-a var(--loop) infinite}
  .graph-hero .pkt.k-b{animation:pkt-b var(--loop) infinite}
  .graph-hero .pkt.k-c{animation:pkt-c var(--loop) infinite}
  .graph-hero .pulse{animation:pulse var(--loop) infinite}
  .graph-hero .ret{animation:ret var(--loop) infinite}
  .graph-hero .rte{animation:rte var(--loop) infinite}
  .graph-hero .cap.c1{animation:cap1 var(--loop) infinite}
  .graph-hero .cap.c2{animation:cap2 var(--loop) infinite}
  .graph-hero .cap.c3{animation:cap3 var(--loop) infinite}
  .graph-hero .cap.c4{animation:cap4 var(--loop) infinite}
  .graph-hero .cap.c5{animation:cap5 var(--loop) infinite}

  @keyframes breathe{from{transform:translateY(0)}to{transform:translateY(-5px)}}
  @keyframes twinkle{from{opacity:1}to{opacity:.55}}

  /* BEAT 1: mass slides in 0–16%; BEAT 2: opens 17–27%; re-arms offscreen while hidden */
  @keyframes mass{
    0%{opacity:1;transform:translate(-640px,26px) scale(1)}
    16%{transform:translate(0px,0px) scale(1)}
    18.5%{transform:translate(0px,0px) scale(1.07)}
    27%{opacity:0;transform:translate(0px,0px) scale(.1)}
    93%{opacity:0;transform:translate(-640px,26px) scale(1)}
    97%,100%{opacity:1;transform:translate(-640px,26px) scale(1)}
  }
  /* pink dock nodes: carryover visible at 0%, consolidate into main graph 3–14%,
     pop fresh from the opening mass 20–31% (staggered a/b/c) */
  @keyframes pink-a{
    0%,3%{opacity:1;transform:translate(0,0) scale(1)}
    14%{opacity:0;transform:translate(var(--ax),var(--ay)) scale(.45)}
    20%{opacity:0;transform:translate(0,0) scale(.2)}
    23.5%{opacity:1;transform:translate(0,0) scale(1.25)}
    25.5%,100%{opacity:1;transform:translate(0,0) scale(1)}
  }
  @keyframes pink-b{
    0%,3%{opacity:1;transform:translate(0,0) scale(1)}
    14%{opacity:0;transform:translate(var(--ax),var(--ay)) scale(.45)}
    23%{opacity:0;transform:translate(0,0) scale(.2)}
    26.5%{opacity:1;transform:translate(0,0) scale(1.25)}
    28.5%,100%{opacity:1;transform:translate(0,0) scale(1)}
  }
  @keyframes pink-c{
    0%,3%{opacity:1;transform:translate(0,0) scale(1)}
    14%{opacity:0;transform:translate(var(--ax),var(--ay)) scale(.45)}
    26%{opacity:0;transform:translate(0,0) scale(.2)}
    29.5%{opacity:1;transform:translate(0,0) scale(1.25)}
    31.5%,100%{opacity:1;transform:translate(0,0) scale(1)}
  }
  @keyframes pink-label{0%,3%{opacity:1}12%{opacity:0}30%{opacity:0}36%,100%{opacity:1}}
  /* dock edges strike 24–40% */
  @keyframes dock-a{
    0%,3%{stroke-dashoffset:0;opacity:.55}
    13%{opacity:0}
    23%{stroke-dashoffset:1;opacity:0}
    26%{opacity:.55}
    36%,100%{stroke-dashoffset:0;opacity:.55}
  }
  @keyframes dock-b{
    0%,3%{stroke-dashoffset:0;opacity:.55}
    13%{opacity:0}
    28%{stroke-dashoffset:1;opacity:0}
    31%{opacity:.55}
    40%,100%{stroke-dashoffset:0;opacity:.55}
  }
  /* BEAT 3: staggered dispatch — one departure at a time */
  @keyframes track{0%,39%{opacity:0}45%{opacity:.5}84%{opacity:.5}92%,100%{opacity:0}}
  @keyframes wk-1{
    0%,39.5%{opacity:0;transform:translate(var(--fx),var(--fy)) scale(.35)}
    40.5%{opacity:1;transform:translate(var(--fx),var(--fy)) scale(.55)}
    45.5%{transform:translate(0,0) scale(1)}
    84%{opacity:1;transform:translate(0,0) scale(1)}
    89%{opacity:1;transform:translate(var(--fx),var(--fy)) scale(.6)}
    90.5%,100%{opacity:0;transform:translate(var(--fx),var(--fy)) scale(.25)}
  }
  @keyframes wk-2{
    0%,42%{opacity:0;transform:translate(var(--fx),var(--fy)) scale(.35)}
    43%{opacity:1;transform:translate(var(--fx),var(--fy)) scale(.55)}
    48%{transform:translate(0,0) scale(1)}
    85.5%{opacity:1;transform:translate(0,0) scale(1)}
    90.5%{opacity:1;transform:translate(var(--fx),var(--fy)) scale(.6)}
    92%,100%{opacity:0;transform:translate(var(--fx),var(--fy)) scale(.25)}
  }
  @keyframes wk-3{
    0%,44.5%{opacity:0;transform:translate(var(--fx),var(--fy)) scale(.35)}
    45.5%{opacity:1;transform:translate(var(--fx),var(--fy)) scale(.55)}
    50.5%{transform:translate(0,0) scale(1)}
    87%{opacity:1;transform:translate(0,0) scale(1)}
    92%{opacity:1;transform:translate(var(--fx),var(--fy)) scale(.6)}
    93.5%,100%{opacity:0;transform:translate(var(--fx),var(--fy)) scale(.25)}
  }
  @keyframes wk-4{
    0%,47%{opacity:0;transform:translate(var(--fx),var(--fy)) scale(.35)}
    48%{opacity:1;transform:translate(var(--fx),var(--fy)) scale(.55)}
    53%{transform:translate(0,0) scale(1)}
    88.5%{opacity:1;transform:translate(0,0) scale(1)}
    93.5%{opacity:1;transform:translate(var(--fx),var(--fy)) scale(.6)}
    95%,100%{opacity:0;transform:translate(var(--fx),var(--fy)) scale(.25)}
  }
  @keyframes wk-5{
    0%,49.5%{opacity:0;transform:translate(var(--fx),var(--fy)) scale(.35)}
    50.5%{opacity:1;transform:translate(var(--fx),var(--fy)) scale(.55)}
    55.5%{transform:translate(0,0) scale(1)}
    90%{opacity:1;transform:translate(0,0) scale(1)}
    95%{opacity:1;transform:translate(var(--fx),var(--fy)) scale(.6)}
    96.5%,100%{opacity:0;transform:translate(var(--fx),var(--fy)) scale(.25)}
  }
  /* BEAT 4: pull-lines draw FROM worker INTO its region */
  @keyframes pull-a{
    0%,61%{stroke-dashoffset:1;opacity:0}
    62%{opacity:.9}
    66.5%{stroke-dashoffset:0}
    82%{stroke-dashoffset:0;opacity:.9}
    85%,100%{opacity:0;stroke-dashoffset:0}
  }
  @keyframes pull-b{
    0%,62.5%{stroke-dashoffset:1;opacity:0}
    63.5%{opacity:.9}
    68%{stroke-dashoffset:0}
    82.5%{stroke-dashoffset:0;opacity:.9}
    85.5%,100%{opacity:0;stroke-dashoffset:0}
  }
  @keyframes pull-c{
    0%,64%{stroke-dashoffset:1;opacity:0}
    65%{opacity:.9}
    69.5%{stroke-dashoffset:0}
    83%{stroke-dashoffset:0;opacity:.9}
    86%,100%{opacity:0;stroke-dashoffset:0}
  }
  /* packets: node → worker (retrieve), then worker → node (return) */
  @keyframes pkt-a{
    0%,65.5%{opacity:0;transform:translate(0,0)}
    66.5%{opacity:1;transform:translate(0,0)}
    74%{transform:translate(var(--wx),var(--wy))}
    84%{opacity:1;transform:translate(var(--wx),var(--wy))}
    91%{opacity:1;transform:translate(0,0)}
    92.5%,100%{opacity:0;transform:translate(0,0)}
  }
  @keyframes pkt-b{
    0%,67.5%{opacity:0;transform:translate(0,0)}
    68.5%{opacity:1;transform:translate(0,0)}
    76%{transform:translate(var(--wx),var(--wy))}
    85.5%{opacity:1;transform:translate(var(--wx),var(--wy))}
    92.5%{opacity:1;transform:translate(0,0)}
    94%,100%{opacity:0;transform:translate(0,0)}
  }
  @keyframes pkt-c{
    0%,69.5%{opacity:0;transform:translate(0,0)}
    70.5%{opacity:1;transform:translate(0,0)}
    78%{transform:translate(var(--wx),var(--wy))}
    87%{opacity:1;transform:translate(var(--wx),var(--wy))}
    94%{opacity:1;transform:translate(0,0)}
    95.5%,100%{opacity:0;transform:translate(0,0)}
  }
  /* source rings pulse twice while being read */
  @keyframes pulse{
    0%,62%{opacity:0;transform:scale(.5)}
    63%{opacity:.9;transform:scale(.6)}
    70%{opacity:0;transform:scale(2.1)}
    71%{opacity:.9;transform:scale(.6)}
    79%{opacity:0;transform:scale(2.1)}
    100%{opacity:0;transform:scale(.5)}
  }
  /* BEAT 5: new density appears; consolidates next cycle 3–13% */
  @keyframes ret{
    0%,3%{opacity:1;transform:scale(1)}
    13%{opacity:0;transform:scale(.2)}
    87%{opacity:0;transform:scale(.2)}
    92%{opacity:1;transform:scale(1.2)}
    94%,100%{opacity:1;transform:scale(1)}
  }
  @keyframes rte{0%,3%{opacity:.45}12%{opacity:0}90%{opacity:0}95%,100%{opacity:.45}}
  /* captions */
  @keyframes cap1{0%,15%{opacity:1}17.5%{opacity:0}97%{opacity:0}99.5%,100%{opacity:1}}
  @keyframes cap2{0%,15%{opacity:0}17.5%{opacity:1}37%{opacity:1}39.5%,100%{opacity:0}}
  @keyframes cap3{0%,37%{opacity:0}39.5%{opacity:1}59.5%{opacity:1}62%,100%{opacity:0}}
  @keyframes cap4{0%,59.5%{opacity:0}62%{opacity:1}81.5%{opacity:1}84%,100%{opacity:0}}
  @keyframes cap5{0%,81.5%{opacity:0}84%{opacity:1}97%{opacity:1}99.5%,100%{opacity:0}}
}
