---
// The fleet constellation — 6 real nodes as IC chips on PCB traces.
// Pure SVG + scoped CSS keyframes (zero JS; reduced-motion turns every animation off).
// Anatomy per the design handoff: each route is TWO parallel traces (offset ±(2,-3)) —
// one carries a cyan packet outbound, the other a magenta packet inbound. Packets are
// stroke-dasharray 9/127 sliding via stroke-dashoffset. Hub = cave (56px chip, radar ring).
---

<svg
  class="constellation"
  viewBox="0 0 760 640"
  role="img"
  aria-label="Live topology of the six-node homelab fleet: hub cave reconciling alfred, robin, kate, wgirl and elfastc"
>
  <defs>
    <linearGradient id="lgA" x1="0" y1="0" x2="1" y2="1">
      <stop offset="0" stop-color="var(--accent)"></stop>
      <stop offset="1" stop-color="var(--accent-2)"></stop>
    </linearGradient>
  </defs>

  <!-- ── PCB traces: dual parallel lines per route (out = cyan, back = magenta) ── -->
  <!-- alfred -->
  <g transform="translate(2,-3)">
    <path class="t-glow t-cyan" d="M380 310 H460 L520 250 V180 L572 128 H595"></path>
    <path class="t-base t-cyan" d="M380 310 H460 L520 250 V180 L572 128 H595"></path>
    <path class="t-pkt pkt-fwd" d="M380 310 H460 L520 250 V180 L572 128 H595"></path>
  </g>
  <g transform="translate(-2,3)">
    <path class="t-glow t-mag" d="M380 310 H460 L520 250 V180 L572 128 H595"></path>
    <path class="t-base t-mag" d="M380 310 H460 L520 250 V180 L572 128 H595"></path>
    <path class="t-pkt t-pkt--mag pkt-rev-slow" d="M380 310 H460 L520 250 V180 L572 128 H595"></path>
  </g>
  <!-- robin -->
  <g transform="translate(2,-3)">
    <path class="t-glow t-cyan" d="M380 310 H470 L540 380 H602 L640 420"></path>
    <path class="t-base t-cyan" d="M380 310 H470 L540 380 H602 L640 420"></path>
    <path class="t-pkt pkt-fwd-slow" d="M380 310 H470 L540 380 H602 L640 420"></path>
  </g>
  <g transform="translate(-2,3)">
    <path class="t-glow t-mag" d="M380 310 H470 L540 380 H602 L640 420"></path>
    <path class="t-base t-mag" d="M380 310 H470 L540 380 H602 L640 420"></path>
    <path class="t-pkt t-pkt--mag pkt-rev" d="M380 310 H470 L540 380 H602 L640 420"></path>
  </g>
  <!-- kate (standby — dimmer) -->
  <g transform="translate(2,-3)" class="standby">
    <path class="t-glow t-cyan" d="M380 310 H300 L240 250 V202 L188 150 H176"></path>
    <path class="t-base t-cyan" d="M380 310 H300 L240 250 V202 L188 150 H176"></path>
    <path class="t-pkt t-pkt--solid pkt-fwd-slow" d="M380 310 H300 L240 250 V202 L188 150 H176"></path>
  </g>
  <g transform="translate(-2,3)" class="standby">
    <path class="t-glow t-mag" d="M380 310 H300 L240 250 V202 L188 150 H176"></path>
    <path class="t-base t-mag" d="M380 310 H300 L240 250 V202 L188 150 H176"></path>
    <path class="t-pkt t-pkt--mag t-pkt--solid pkt-rev" d="M380 310 H300 L240 250 V202 L188 150 H176"></path>
  </g>
  <!-- wgirl (standby) -->
  <g transform="translate(2,-3)" class="standby">
    <path class="t-glow t-cyan" d="M380 310 H310 L244 376 V446 L214 474"></path>
    <path class="t-base t-cyan" d="M380 310 H310 L244 376 V446 L214 474"></path>
    <path class="t-pkt t-pkt--solid pkt-fwd" d="M380 310 H310 L244 376 V446 L214 474"></path>
  </g>
  <g transform="translate(-2,3)" class="standby">
    <path class="t-glow t-mag" d="M380 310 H310 L244 376 V446 L214 474"></path>
    <path class="t-base t-mag" d="M380 310 H310 L244 376 V446 L214 474"></path>
    <path class="t-pkt t-pkt--mag t-pkt--solid pkt-rev-slow" d="M380 310 H310 L244 376 V446 L214 474"></path>
  </g>
  <!-- elfastc (standby) -->
  <g transform="translate(3,2)" class="standby">
    <path class="t-glow t-cyan" d="M380 310 V400 L452 472 V532"></path>
    <path class="t-base t-cyan" d="M380 310 V400 L452 472 V532"></path>
    <path class="t-pkt t-pkt--solid pkt-fwd-slow" d="M380 310 V400 L452 472 V532"></path>
  </g>
  <g transform="translate(-3,-2)" class="standby">
    <path class="t-glow t-mag" d="M380 310 V400 L452 472 V532"></path>
    <path class="t-base t-mag" d="M380 310 V400 L452 472 V532"></path>
    <path class="t-pkt t-pkt--mag t-pkt--solid pkt-rev" d="M380 310 V400 L452 472 V532"></path>
  </g>

  <!-- vias at trace bends -->
  <circle class="via via--cyan" cx="460" cy="310" r="3"></circle>
  <circle class="via via--cyan" cx="520" cy="250" r="3"></circle>
  <circle class="via via--cyan" cx="520" cy="180" r="3"></circle>
  <circle class="via via--mag" cx="470" cy="310" r="3"></circle>
  <circle class="via via--mag" cx="540" cy="380" r="3"></circle>
  <circle class="via via--dim" cx="300" cy="310" r="3"></circle>
  <circle class="via via--dim" cx="240" cy="250" r="3"></circle>
  <circle class="via via--dim" cx="310" cy="310" r="3"></circle>
  <circle class="via via--dim" cx="244" cy="376" r="3"></circle>
  <circle class="via via--dim" cx="380" cy="400" r="3"></circle>
  <circle class="via via--dim" cx="452" cy="472" r="3"></circle>

  <!-- ── hub: cave ── -->
  <circle class="ring" cx="380" cy="310" r="46" fill="none" stroke="url(#lgA)" stroke-width="1.5"></circle>
  <circle cx="380" cy="310" r="46" fill="rgba(63,186,245,0.05)" stroke="rgba(63,186,245,0.3)" stroke-width="1"></circle>
  <!-- pin stubs -->
  <g class="pins-cyan">
    <line x1="352" y1="296" x2="340" y2="296"></line><line x1="352" y1="310" x2="340" y2="310"></line>
    <line x1="352" y1="324" x2="340" y2="324"></line><line x1="366" y1="282" x2="366" y2="270"></line>
    <line x1="380" y1="282" x2="380" y2="270"></line><line x1="366" y1="338" x2="366" y2="350"></line>
    <line x1="380" y1="338" x2="380" y2="350"></line>
  </g>
  <g class="pins-mag">
    <line x1="408" y1="296" x2="420" y2="296"></line><line x1="408" y1="310" x2="420" y2="310"></line>
    <line x1="408" y1="324" x2="420" y2="324"></line><line x1="394" y1="282" x2="394" y2="270"></line>
    <line x1="394" y1="338" x2="394" y2="350"></line>
  </g>
  <rect class="chip chip--hub" x="352" y="282" width="56" height="56" rx="8" stroke="url(#lgA)"></rect>
  <rect x="364" y="294" width="32" height="32" rx="4" fill="none" stroke="rgba(63,186,245,0.4)" stroke-width="1"></rect>
  <circle class="core core--cyan pulse" cx="380" cy="310" r="5"></circle>
  <rect class="plate plate--hub" x="338" y="352" width="84" height="24" rx="4"></rect>
  <text class="lbl lbl--hub" x="380" y="368" text-anchor="middle">cave</text>
  <text class="cap cap--hub" x="380" y="392" text-anchor="middle">139 apps · reconciling</text>

  <!-- ── awake: alfred (Intel compute — NUC iGPU/QuickSync) ── -->
  <circle cx="612" cy="128" r="24" fill="rgba(0,199,253,0.07)"></circle>
  <rect class="chip chip--intel" x="595" y="111" width="34" height="34" rx="5"></rect>
  <circle class="core core--intel pulse" cx="612" cy="128" r="4"></circle>
  <rect class="plate plate--intel" x="576" y="152" width="72" height="20" rx="3"></rect>
  <text class="lbl" x="612" y="166" text-anchor="middle">alfred</text>

  <!-- ── awake: robin ── -->
  <circle cx="656" cy="420" r="24" fill="rgba(232,121,249,0.07)"></circle>
  <rect class="chip chip--mag" x="639" y="403" width="34" height="34" rx="5"></rect>
  <circle class="core core--mag pulse-slow" cx="656" cy="420" r="4"></circle>
  <rect class="plate plate--mag" x="620" y="444" width="72" height="20" rx="3"></rect>
  <text class="lbl" x="656" y="458" text-anchor="middle">robin</text>

  <!-- ── standby: kate ── -->
  <rect class="chip chip--cyan" x="145" y="135" width="30" height="30" rx="5"></rect>
  <circle class="core core--cyan pulse-slow" cx="160" cy="150" r="3.5"></circle>
  <rect class="plate plate--dim" x="126" y="172" width="68" height="20" rx="3"></rect>
  <text class="lbl lbl--dim" x="160" y="186" text-anchor="middle">kate</text>

  <!-- ── standby: wgirl ── -->
  <rect class="chip chip--mag" x="199" y="471" width="30" height="30" rx="5"></rect>
  <circle class="core core--mag pulse" cx="214" cy="486" r="3.5"></circle>
  <rect class="plate plate--dim" x="180" y="508" width="68" height="20" rx="3"></rect>
  <text class="lbl lbl--dim" x="214" y="522" text-anchor="middle">wgirl</text>

  <!-- ── standby: elfastc (Intel compute — 2× Arc B580) ── -->
  <rect class="chip chip--intel" x="437" y="533" width="30" height="30" rx="5"></rect>
  <circle class="core core--intel pulse-slow" cx="452" cy="548" r="3.5"></circle>
  <rect class="plate plate--dim" x="412" y="570" width="80" height="20" rx="3"></rect>
  <text class="lbl lbl--dim" x="452" y="584" text-anchor="middle">elfastc</text>

  <!-- ── key: compute colours (right side — left edge clips on narrow heroes) ── -->
  <g aria-label="compute colour key">
    <rect class="core--mag" x="620" y="572" width="8" height="8" rx="2"></rect>
    <text class="cap cap--key" x="634" y="580">nvidia compute</text>
    <rect class="core--intel" x="620" y="592" width="8" height="8" rx="2"></rect>
    <text class="cap cap--key" x="634" y="600">intel compute</text>
    <rect class="key--bat" x="620" y="612" width="8" height="8" rx="2"></rect>
    <text class="cap cap--key" x="634" y="620">core / services</text>
  </g>
</svg>

<style>
  .constellation {
    display: block;
    width: 100%;
    height: auto;
  }

  /* trace layers */
  .t-glow { fill: none; stroke-width: 7; }
  .t-glow.t-cyan { stroke: rgba(63, 186, 245, 0.12); }
  .t-glow.t-mag { stroke: rgba(232, 121, 249, 0.1); }
  .standby .t-glow.t-cyan { stroke: rgba(63, 186, 245, 0.1); }
  .standby .t-glow.t-mag { stroke: rgba(232, 121, 249, 0.08); }
  .t-base { fill: none; stroke-width: 2; }
  .t-base.t-cyan { stroke: rgba(63, 186, 245, 0.45); }
  .t-base.t-mag { stroke: rgba(232, 121, 249, 0.38); }
  .standby .t-base.t-cyan { stroke: rgba(63, 186, 245, 0.35); }
  .standby .t-base.t-mag { stroke: rgba(232, 121, 249, 0.3); }

  /* the moving packets */
  .t-pkt {
    fill: none;
    stroke: url(#lgA);
    stroke-width: 3;
    stroke-linecap: round;
    stroke-dasharray: 9 127;
    filter: drop-shadow(0 0 6px rgba(63, 186, 245, 0.9));
  }
  .t-pkt--mag { filter: drop-shadow(0 0 6px rgba(232, 121, 249, 0.9)); }
  .t-pkt--solid { stroke: rgba(63, 186, 245, 0.85); }
  .t-pkt--solid.t-pkt--mag { stroke: rgba(232, 121, 249, 0.85); }

  .pkt-fwd { animation: bzDash 8s linear infinite; }
  .pkt-fwd-slow { animation: bzDash 11s linear infinite; }
  .pkt-rev { animation: bzDashRev 9s linear infinite; }
  .pkt-rev-slow { animation: bzDashRev 13s linear infinite; }

  /* vias */
  .via { fill: var(--panel-solid); stroke-width: 1; }
  .via--cyan { stroke: rgba(63, 186, 245, 0.6); }
  .via--mag { stroke: rgba(232, 121, 249, 0.6); }
  .via--dim { stroke: rgba(126, 139, 161, 0.5); }

  /* chips + cores + plates + labels */
  .chip { fill: var(--panel-solid); }
  .chip--hub { stroke-width: 2; filter: drop-shadow(0 0 10px rgba(63, 186, 245, 0.45)); }
  .chip--cyan { stroke: var(--accent); stroke-width: 1.5; filter: drop-shadow(0 0 8px rgba(63, 186, 245, 0.55)); }
  .chip--mag { stroke: var(--accent-2); stroke-width: 1.5; filter: drop-shadow(0 0 8px rgba(232, 121, 249, 0.55)); }
  .chip--intel { stroke: var(--accent-intel); stroke-width: 1.5; filter: drop-shadow(0 0 8px rgba(0, 199, 253, 0.55)); }
  .core--cyan { fill: var(--accent); filter: drop-shadow(0 0 6px rgba(63, 186, 245, 1)); }
  .core--mag { fill: var(--accent-2); filter: drop-shadow(0 0 5px rgba(232, 121, 249, 1)); }
  .core--intel { fill: var(--accent-intel); filter: drop-shadow(0 0 6px rgba(0, 199, 253, 1)); }
  .pulse { animation: bzPulse 2.4s ease-in-out infinite; }
  .pulse-slow { animation: bzPulse 3.4s ease-in-out infinite; }
  .pins-cyan line { stroke: rgba(63, 186, 245, 0.6); stroke-width: 1.5; }
  .pins-mag line { stroke: rgba(232, 121, 249, 0.6); stroke-width: 1.5; }
  .plate { fill: rgba(13, 19, 34, 0.92); stroke-width: 1; }
  .plate--hub { stroke: rgba(63, 186, 245, 0.4); }
  .plate--cyan { stroke: rgba(63, 186, 245, 0.35); }
  .plate--mag { stroke: rgba(232, 121, 249, 0.35); }
  .plate--intel { stroke: rgba(0, 199, 253, 0.35); }
  .plate--dim { stroke: rgba(126, 139, 161, 0.3); }
  .lbl {
    fill: #e8f2fb;
    font-family: var(--font-mono);
    font-size: 11px;
  }
  .lbl--hub { font-size: 12px; font-weight: 700; }
  .lbl--dim { fill: #9fb0c8; }
  .cap { font-family: var(--font-mono); }
  .cap--hub {
    fill: var(--accent);
    font-size: 9.5px;
    filter: drop-shadow(0 0 4px rgba(63, 186, 245, 0.7));
  }
  .cap--dim { fill: #5c6a82; font-size: 9px; }
  .cap--key { fill: #7e8ba1; font-size: 9px; }
  /* gloss bat-black with a faint gold ring — the batcave swatch for core/services */
  .key--bat {
    fill: #10131c;
    stroke: rgba(245, 197, 24, 0.55);
    stroke-width: 1;
    filter: drop-shadow(0 0 4px rgba(245, 197, 24, 0.35));
  }

  /* radar ring off the hub */
  .ring {
    transform-box: fill-box;
    transform-origin: center;
    animation: bzRing 3.6s ease-out infinite;
  }

  /* dash pattern is 9+127 = a 136px period — the loop offset MUST be an exact multiple of it
     (2×136 = 272) or every packet dot visibly teleports at the loop seam. */
  @keyframes bzDash { to { stroke-dashoffset: -272; } }
  @keyframes bzDashRev { to { stroke-dashoffset: 272; } }
  @keyframes bzPulse { 0%, 100% { opacity: 0.35; } 50% { opacity: 1; } }
  @keyframes bzRing {
    /* start AND end at opacity 0 so the 3.6s restart never pops */
    0% { transform: scale(0.5); opacity: 0; }
    10% { opacity: 0.9; }
    100% { transform: scale(1.7); opacity: 0; }
  }

  @media (prefers-reduced-motion: reduce) {
    .pkt-fwd, .pkt-fwd-slow, .pkt-rev, .pkt-rev-slow, .pulse, .pulse-slow, .ring {
      animation: none;
    }
    .ring { opacity: 0.5; }
  }
</style>
