/* ===========================================================================
   HERO ANIMATION v2 (index.html only) - the "hero video" as a coded sequence.
   Story per the original plan: wire -> server -> homestead -> aerial twin.

   v2 adds a camera: the ha-cam group carries a 16s transform timeline that
   opens tight on the wire, tracks to the network core, then pulls back to
   reveal the homestead before the scene yields to the aerial twin (which
   lives OUTSIDE the camera so it composes full-frame). Rest state stays
   alive: breathing drift, sync chip blink, repeating event ping.

   Replay works by re-inserting the SVG node (restarts CSS + SMIL clocks).
   =========================================================================== */

.hero__anim { grid-area: 1 / 1; overflow: hidden; }
.hero__anim svg { width: 100%; height: 100%; display: block; }

/* Strokes never self-fill; :where() keeps specificity at zero so the
   explicit fill classes below still win. (SVG defaults fill to black.) */
:where(.hero__anim) path, :where(.hero__anim) polygon, :where(.hero__anim) polyline { fill: none; }

/* --- shared element classes ------------------------------------------------ */
.ha-ln      { fill: none; stroke: var(--primary); stroke-width: 2.5; stroke-linecap: round; stroke-linejoin: round; }
.ha-ln--soft{ fill: none; stroke: color-mix(in srgb, var(--primary) 55%, transparent); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.ha-ln--hair{ fill: none; stroke: color-mix(in srgb, var(--primary) 32%, transparent); stroke-width: 1.4; }
.ha-wire    { stroke-width: 3.5; }
.ha-strand  { stroke-width: 1.8; stroke: color-mix(in srgb, var(--accent) 70%, var(--primary)); }
.ha-fill    { fill: color-mix(in srgb, var(--primary) 10%, transparent); }
.ha-shadow  { fill: color-mix(in srgb, var(--primary) 22%, transparent); }
.ha-tag     { font-family: var(--font-mono); font-size: 21px; letter-spacing: 0.1em; fill: var(--text-muted); }
.ha-tag--on { fill: var(--primary); }
.ha-tag--sm { font-size: 16px; }
.ha-chipbg  { fill: color-mix(in srgb, var(--surface) 93%, transparent); stroke: color-mix(in srgb, var(--primary) 40%, var(--border)); }
.ha-led     { fill: var(--secondary); }
.ha-dot     { fill: var(--primary); }
.ha-pulse   { fill: var(--accent); }
.ha-fov     { fill: color-mix(in srgb, var(--primary) 18%, transparent); stroke: color-mix(in srgb, var(--primary) 28%, transparent); stroke-width: 1; }
.ha-ping    { fill: var(--accent); }
.ha-pingw   { fill: none; stroke: var(--accent); stroke-width: 2; }
.ha-sync    { fill: var(--secondary); }
.ha-scan    { fill: color-mix(in srgb, var(--primary) 9%, transparent); }
.ha-keystone{ fill: color-mix(in srgb, var(--primary) 18%, transparent); stroke: color-mix(in srgb, var(--primary) 45%, transparent); stroke-width: 1; }

/* v3 palette: alert red follows the MDS light/dark pattern (no token exists). */
.hero__anim { --ha-alert: #C0392B; }
[data-theme="dark"] .hero__anim { --ha-alert: #F2777A; }
.ha-lawn    { fill: color-mix(in srgb, var(--secondary) 8%, transparent); }
.ha-glow    { fill: color-mix(in srgb, var(--accent) 18%, transparent); }
.ha-roadfill{ fill: color-mix(in srgb, var(--text-muted) 10%, transparent); }
.ha-road    { fill: none; stroke: color-mix(in srgb, var(--text-muted) 55%, transparent); stroke-width: 2; }
.ha-lane    { fill: none; stroke: color-mix(in srgb, var(--text-muted) 50%, transparent); stroke-width: 2; stroke-dasharray: 18 14; }
.ha-veh     { fill: color-mix(in srgb, var(--text-muted) 70%, var(--primary)); }
.ha-veh2    { fill: color-mix(in srgb, var(--primary) 65%, var(--text-muted)); }
.ha-animal  { fill: color-mix(in srgb, var(--accent) 55%, var(--secondary)); }
.ha-person  { fill: var(--ha-alert); }
.ha-alertw  { fill: none; stroke: var(--ha-alert); stroke-width: 2.5; }
.ha-spot    { fill: color-mix(in srgb, var(--accent) 32%, transparent); }
.ha-spotpool{ fill: color-mix(in srgb, var(--accent) 22%, transparent); }
.ha-lbl     { font-family: var(--font-mono); font-size: 14px; letter-spacing: 0.09em; fill: var(--text-muted); opacity: 0.55; }

/* v4: shared ground layer, commercial scene, authorized-access green */
.ha-emp     { fill: var(--secondary); }
.ha-gate    { fill: none; stroke: var(--accent); stroke-width: 3.5; stroke-linecap: round; }
.ha-okw     { fill: none; stroke: var(--secondary); stroke-width: 2; }
.ha-tag--ok { fill: var(--secondary); }
.ha-lot     { fill: color-mix(in srgb, var(--text-muted) 7%, transparent); }

/* v5: coverage audit - uncovered ground reads as a red blind spot */
.ha-blind      { fill: color-mix(in srgb, var(--ha-alert) 16%, transparent); stroke: var(--ha-alert); stroke-width: 1.5; stroke-dasharray: 6 5; }
.ha-lbl--alert { fill: var(--ha-alert); opacity: 0.85; }

/* v6: true blind-spot mask, trees, riding ID tags, event tags, timeline */
.ha-blindwash  { fill: color-mix(in srgb, var(--ha-alert) 15%, transparent); }
.ha-tree--ok   { fill: color-mix(in srgb, var(--secondary) 30%, transparent); stroke: color-mix(in srgb, var(--secondary) 60%, transparent); stroke-width: 1.5; cursor: help; }
.ha-tree--warn { fill: color-mix(in srgb, var(--accent) 32%, transparent); stroke: color-mix(in srgb, var(--accent) 65%, transparent); stroke-width: 1.5; cursor: help; }
.ha-tree--bad  { fill: color-mix(in srgb, var(--ha-alert) 26%, transparent); stroke: var(--ha-alert); stroke-width: 1.5; cursor: help; }
.ha-hit        { cursor: help; }
.ha-ridetag rect { fill: color-mix(in srgb, var(--surface) 90%, transparent); stroke: color-mix(in srgb, var(--primary) 40%, var(--border)); }
.ha-ridetag text { font-family: var(--font-mono); font-size: 13px; letter-spacing: 0.06em; fill: var(--text); }
.ha-ridetag line { stroke: color-mix(in srgb, var(--primary) 55%, transparent); stroke-width: 1.5; }
.ha-evtag rect { fill: color-mix(in srgb, var(--surface) 92%, transparent); stroke: var(--ha-alert); }
.ha-evtag text { font-family: var(--font-mono); font-size: 14px; letter-spacing: 0.06em; fill: var(--ha-alert); }
.ha-evtag path { fill: var(--ha-alert); }
.ha-evtag--ok rect { stroke: var(--secondary); }
.ha-evtag--ok text { fill: var(--secondary); }
.ha-evtag--ok path { fill: var(--secondary); }
.ha-tlbase { fill: color-mix(in srgb, var(--text-muted) 20%, transparent); }
.ha-tlon   { fill: color-mix(in srgb, var(--primary) 45%, transparent); }
.ha-tlt    { font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.06em; fill: var(--text-muted); opacity: 0.6; }
.ha-tldot  { cursor: pointer; transition: r 0.15s ease; }
.ha-tldot:hover { r: 8px; }

/* v7/v8: rich tooltip inspection. Only deliberate targets are interactive;
   cones, washes, and other decoration must never intercept (they sit on top). */
:where(.hero__anim) svg * { pointer-events: none; }
.hero__anim .ha-click, .hero__anim .ha-click * { pointer-events: auto; }
.hero__anim .ha-click { cursor: pointer; }
.ha-click:hover { filter: brightness(1.35); }

/* The game-style tooltip card: fixed, cursor-adjacent, never eats the pointer */
.twin-tip {
  position: fixed; z-index: 60; max-width: 340px; pointer-events: none;
  background: color-mix(in srgb, var(--surface) 96%, transparent);
  border: 1px solid color-mix(in srgb, var(--primary) 35%, var(--border));
  border-top: 2px solid var(--accent);
  border-radius: var(--radius-md);
  box-shadow: 0 14px 36px rgba(0, 0, 0, 0.35);
  padding: var(--space-sm) var(--space-md);
}
.twin-tip .tt-kind {
  font-family: var(--font-mono); font-size: 0.66rem; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--text-muted);
}
.twin-tip h3 { font-size: var(--step-1); margin: 2px 0 2px; }
.twin-tip .tm-status { margin: 0 0 2px; }
.twin-tip ul {
  list-style: none; padding: 0; margin: 6px 0 0;
  display: flex; flex-direction: column; gap: 4px;
  font-size: var(--step--1); color: var(--text-muted);
}
.twin-tip li { padding-left: 14px; position: relative; }
.twin-tip li::before { content: "-"; position: absolute; left: 0; color: var(--primary); }
.tm-status { font-family: var(--font-mono); font-size: var(--step--1); letter-spacing: 0.08em; }
.tm-ok   { color: var(--secondary); }
.tm-warn { color: var(--accent-ink); }
.tm-info { color: var(--primary); }
.tm-bad  { color: #C0392B; }
[data-theme="dark"] .tm-bad { color: #F2777A; }
.ha-tldot--alert { fill: var(--ha-alert); }
.ha-tldot--ok    { fill: var(--secondary); }
.ha-tldot--gold  { fill: var(--accent); }
.ha-tldot--n     { fill: var(--primary); }

/* --- timeline primitives ---------------------------------------------------- */
.ha-draw {
  stroke-dasharray: 1; stroke-dashoffset: 1;
  animation: haDraw 1s cubic-bezier(0.4, 0, 0.2, 1) forwards;
  animation-delay: var(--d, 0s);
}
.ha-draw--slow { animation-duration: 1.6s; }
.ha-pop {
  opacity: 0;
  animation: haPop 0.5s ease-out forwards;
  animation-delay: var(--d, 0s);
}
.ha-pop--spring {
  opacity: 0;
  transform-box: fill-box; transform-origin: center;
  animation: haSpring 0.55s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
  animation-delay: var(--d, 0s);
}
.ha-ring {
  fill: none; stroke: var(--secondary); stroke-width: 2; opacity: 0;
  transform-box: fill-box; transform-origin: center;
  animation: haRing 0.9s ease-out forwards;
  animation-delay: var(--d, 0s);
}
.ha-flash {
  fill: none; stroke: var(--accent); stroke-width: 3; opacity: 0;
  transform-box: fill-box; transform-origin: center;
  animation: haRing 0.7s ease-out forwards;
  animation-delay: var(--d, 0s);
}

@keyframes haDraw   { to { stroke-dashoffset: 0; } }
@keyframes haPop    { from { opacity: 0; } to { opacity: 1; } }
@keyframes haSpring {
  0%   { opacity: 0; transform: scale(0.5); }
  70%  { opacity: 1; transform: scale(1.08); }
  100% { opacity: 1; transform: scale(1); }
}
@keyframes haRing {
  0%   { opacity: 0.9; transform: scale(0.4); }
  100% { opacity: 0;   transform: scale(2.6); }
}

/* --- the camera --------------------------------------------------------------
   transform-origin 0 0 in view-box units; each keyframe centers a focus
   point p at viewport center (600, 337.5) with zoom s:
   translate(600 - s*px, 337.5 - s*py) scale(s)
   0%  tight on the wire entry      p(230,330)  s1.60
   16% arrive at the network core   p(615,362)  s1.35   (t ~2.6s)
   36% hold on the core                                  (t ~5.8s)
   51% pulled back, homestead full  p(740,340)  s1.00   (t ~8.2s)
--------------------------------------------------------------------------------*/
.ha-cam {
  transform-box: view-box; transform-origin: 0 0;
  animation: haCam 16s forwards;
}
@keyframes haCam {
  0%   { transform: translate(232px, -190.5px) scale(1.6);   animation-timing-function: cubic-bezier(0.55, 0.08, 0.35, 1); }
  16%  { transform: translate(-230.25px, -151.2px) scale(1.35); animation-timing-function: linear; }
  36%  { transform: translate(-230.25px, -151.2px) scale(1.35); animation-timing-function: cubic-bezier(0.55, 0.08, 0.35, 1); }
  51%  { transform: translate(-140px, -2.5px) scale(1); }
  100% { transform: translate(-140px, -2.5px) scale(1); }
}

/* --- scene choreography (seconds) --------------------------------------------
   0.2 wire strands + main run draw, pulse travels
   2.3 RJ45 connector lands, connect flash
   2.6 enclosure + keystone rows + switch assemble, LEDs up 4.2-5.4
   5.8 camera pulls back; homestead draws 6.0-8.2; ground hatch
   8.0 branch runs; devices land 9.0-10.2; branch pulses from 9.8
  10.6 world yields; aerial in 11.0; reticle 11.2; parcel 11.6
  12.6 footprint + shadow; FOV cones sweep 13.6/14.0; scan pass 13.8
  15.2 event ping (repeats); chips + coords + title; rest drift
------------------------------------------------------------------------------ */
.ha-world {
  transform-box: fill-box; transform-origin: 55% 45%;
  animation: haWorldOut 1s ease-in forwards;
  animation-delay: 10.6s;
}
/* Two twins share the frame on a 40s alternation from t=16s:
   residential 16-34, crossfade, commercial 36-54, crossfade, repeat.
   The ground layer (street + traffic + title) persists across both. */
/* Both twins start fully hidden (visibility included) so their hover targets
   cannot be reached through the intro scenes; the reveal carries visibility in. */
.ha-aerial {
  opacity: 0; visibility: hidden;
  transform-box: fill-box; transform-origin: center;
  animation: haAerialIn 1.2s ease-out forwards,
             haDrift 18s ease-in-out 16s infinite alternate,
             haResCycle 40s ease-in-out 16s infinite;
  animation-delay: 11s, 16s, 16s;
}
.ha-comm {
  opacity: 0; visibility: hidden;
  transform-box: fill-box; transform-origin: center;
  animation: haCommCycle 40s ease-in-out 16s infinite,
             haDrift 18s ease-in-out 16s infinite alternate;
}
@keyframes haWorldOut  { to { opacity: 0; transform: scale(0.93); } }
@keyframes haAerialIn  { from { opacity: 0; transform: scale(1.12); visibility: visible; } to { opacity: 1; transform: scale(1); visibility: visible; } }
@keyframes haDrift     { from { transform: scale(1); } to { transform: scale(1.02); } }
/* visibility rides along so the hidden scene cannot swallow clicks */
@keyframes haResCycle  { 0%, 45% { opacity: 1; visibility: visible; } 50%, 95% { opacity: 0; visibility: hidden; } 100% { opacity: 1; visibility: visible; } }
@keyframes haCommCycle { 0%, 45% { opacity: 0; visibility: hidden; } 50%, 95% { opacity: 1; visibility: visible; } 100% { opacity: 0; visibility: hidden; } }

/* Reticle: quick in, lingers faint. Scan: one pass over the parcel. */
.ha-reticle { opacity: 0; animation: haReticle 2.6s ease-out forwards; animation-delay: 11.2s; }
@keyframes haReticle { 0% { opacity: 0; } 18% { opacity: 0.85; } 70% { opacity: 0.25; } 100% { opacity: 0.12; } }
.ha-scanbar { opacity: 0; animation: haScan 2.4s cubic-bezier(0.45, 0, 0.55, 1) forwards; animation-delay: 13.8s; }
@keyframes haScan {
  0%   { opacity: 0;   transform: translateX(0); }
  12%  { opacity: 1; }
  88%  { opacity: 1; }
  100% { opacity: 0;   transform: translateX(600px); }
}

/* FOV cones sweep open around their camera corner. */
.ha-sweep {
  opacity: 0;
  transform-origin: 0 0;
  animation: haSweep 0.9s cubic-bezier(0.4, 0, 0.2, 1) forwards;
  animation-delay: var(--d, 0s);
}
@keyframes haSweep {
  0%   { opacity: 0; transform: rotate(-28deg); }
  25%  { opacity: 1; }
  100% { opacity: 1; transform: rotate(0deg); }
}

/* Rest-state life: the sync dot breathes; the south cone leans in during
   each event cycle (12s, aligned with the SMIL person clock at 18s). */
.ha-sync { animation: haBlink 2.4s ease-in-out 16s infinite; }
@keyframes haBlink { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } }
.ha-conehot { animation: haPop 0.5s ease-out forwards var(--d, 0s), haConeHot 12s linear 18s infinite; }
@keyframes haConeHot { 0%, 20% { opacity: 0.8; } 24%, 58% { opacity: 1; } 70%, 100% { opacity: 0.8; } }

/* --- accessibility ------------------------------------------------------------
   Reduced motion: no sequence, no drift, no scan; the twin at rest. */
@media (prefers-reduced-motion: reduce) {
  .hero__anim .ha-world, .hero__anim .ha-reticle, .hero__anim .ha-scanbar { display: none; }
  .hero__anim .ha-aerial, .hero__anim .ha-draw, .hero__anim .ha-pop,
  .hero__anim .ha-pop--spring, .hero__anim .ha-sweep {
    animation: none; opacity: 1; stroke-dashoffset: 0; transform: none;
  }
  .hero__anim .ha-ring, .hero__anim .ha-flash, .hero__anim .ha-pingw { display: none; }
  .hero__anim .ha-sync { animation: none; }
  .hero__anim .ha-veh, .hero__anim .ha-veh2, .hero__anim .ha-animal,
  .hero__anim .ha-person, .hero__anim .ha-spot, .hero__anim .ha-spotpool,
  .hero__anim .ha-alertw { display: none; }
  .hero__anim .ha-conehot { animation: none; opacity: 1; }
  .hero__anim .ha-comm, .hero__anim .ha-emp, .hero__anim .ha-okw { display: none; }
  .hero__anim .ha-mover, .hero__anim .ha-evtag { display: none; }
  .hero__anim .ha-aerial { visibility: visible; }
}
