/* Point route loop: a coverage / service-area map that draws itself on a 5 s clock.
   Square points pop in one after another (.06 s apart), then hairline dashed routes between them fade in
   (.03 s apart) while their dashes keep travelling; near the end the routes fade, the points shrink away,
   and it goes again. CSS does all the motion; part.js only draws the route lines between the points.

   Markup:
   <div class="prl" data-prl-routes="1-2 2-3 3-1">          (any positioned box: a map, a picture)
     <span class="prl__pt" style="--x:20%; --y:30%"></span>  (points in DOM order = 1, 2, 3 ...)
     ...
   </div>
   part.js adds <svg class="prl__routes"> with one <line class="prl__route"> per pair and numbers points and
   routes (--i) for the stagger. Without JS, hand-write the svg (class prl__route, style="--i:n") and it animates.

   Measured from the source (% of the 5 s cycle):
   point   0-8% hidden at scale .4; 8-12% pops to 1.15 + fades in (linear); 12-16% settles to 1
           on cubic-bezier(.22,1,.36,1); holds to 84%; 84-90% shrinks to .4 + fades on cubic-bezier(.64,0,.78,0)
   route   0-30% hidden; 30-40% fades in on cubic-bezier(.22,1,.36,1); holds to 82%; 82-87% fades out on
           cubic-bezier(.64,0,.78,0)
   dashes  4 4, travelling 8px every .8 s (linear, forever)
   stagger points i x .06 s, routes i x .03 s
   The eases live inside the keyframes as literals: browsers ignore var() for a keyframe's
   animation-timing-function (it silently falls back to linear), so they are not knobs. */

.prl {
  --prl-cycle: 5s;
  --prl-delay: 0s;               /* the whole map's offset in the loop */
  --prl-ink: #fa3600;            /* points + routes */
  --prl-core: #fff;              /* the small square inside each point */
  --prl-pt: 2.15%;               /* point size, % of the map width (or px) */
  --prl-pt-min: 8px;             /* never smaller than this */
  --prl-pt-gap: 0.06s;           /* point stagger */
  --prl-route-gap: 0.03s;        /* route stagger */
  --prl-line: 1px;               /* route width */
  --prl-dash: 4px;               /* dash and gap length */
  --prl-dash-time: 0.8s;         /* time for the dashes to move one dash + gap */
  position: relative;
}

.prl__pt {
  position: absolute;
  z-index: 4;
  left: var(--x, 50%);
  top: var(--y, 50%);
  width: max(var(--prl-pt-min), var(--prl-pt));
  aspect-ratio: 1;
  /* centre on --x/--y without using transform (the animation owns it); % margins follow the width */
  margin: calc(max(var(--prl-pt-min), var(--prl-pt)) / -2) 0 0 calc(max(var(--prl-pt-min), var(--prl-pt)) / -2);
  box-sizing: border-box;
  background: var(--prl-ink);
  border: 1px solid var(--prl-ink);
  opacity: 0;
  transform: scale(0.4);
  transform-origin: center;
  will-change: transform, opacity;
  animation: prl-point var(--prl-cycle) linear calc(var(--prl-delay) + var(--i, 0) * var(--prl-pt-gap)) infinite both;
}
.prl__pt::after {
  content: "";
  position: absolute;
  inset: 31.25%;                 /* 4.5 of 12: the white core */
  background: var(--prl-core);
}

.prl__routes {
  position: absolute;
  inset: 0;
  z-index: 2;
  width: 100%;
  height: 100%;
  overflow: visible;
  pointer-events: none;
}
.prl__route {
  fill: none;
  stroke: var(--prl-ink);
  stroke-width: var(--prl-line);
  stroke-dasharray: var(--prl-dash) var(--prl-dash);
  stroke-dashoffset: 0;
  opacity: 0;
  will-change: opacity, stroke-dashoffset;
  animation:
    prl-route var(--prl-cycle) linear calc(var(--prl-delay) + var(--i, 0) * var(--prl-route-gap)) infinite both,
    prl-dash var(--prl-dash-time) linear infinite;
}

@keyframes prl-point {
  0%, 8% { opacity: 0; transform: scale(0.4); }
  12% { opacity: 1; transform: scale(1.15); animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1); }
  16% { opacity: 1; transform: scale(1); }
  84% { opacity: 1; transform: scale(1); animation-timing-function: cubic-bezier(0.64, 0, 0.78, 0); }
  90%, 100% { opacity: 0; transform: scale(0.4); }
}
@keyframes prl-route {
  0% { opacity: 0; }
  30% { opacity: 0; animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1); }
  40% { opacity: 1; }
  82% { opacity: 1; animation-timing-function: cubic-bezier(0.64, 0, 0.78, 0); }
  87%, 100% { opacity: 0; }
}
@keyframes prl-dash {
  from { stroke-dashoffset: 0; }
  to { stroke-dashoffset: calc(var(--prl-dash) * -2); }
}

/* Reduced motion: the whole map sits drawn, dashes still. */
@media (prefers-reduced-motion: reduce) {
  .prl__pt, .prl__route { animation: none; opacity: 1; transform: none; stroke-dashoffset: 0; }
}
