
/* ==========================================================================
   RURALTECH V5-G / G2-B
   Local Hub Response

   Runtime-only interactive projection.
   Does NOT redefine V5-E/V5-F geometry.
   ========================================================================== */


/* --------------------------------------------------------------------------
   Overlay plane

   Same bleed, parallax variables and scale as the V5-F infrastructure plane.
   -------------------------------------------------------------------------- */

.rt-local-hub-layer {
  position: absolute;
  inset: -1.4%;

  z-index: 0;

  pointer-events: none;

  transform:
    translate3d(
      var(--rt-infra-x, 0px),
      var(--rt-infra-y, 0px),
      0
    )
    scale(1.014);

  transform-origin: center center;

  will-change: transform;

  overflow: hidden;
}


.rt-local-hub-layer > svg {
  display: block;

  width: 100%;
  height: 100%;

  overflow: visible;

  pointer-events: none;
}


/* --------------------------------------------------------------------------
   Route response

   Invisible at rest.
   Only the selected child -> parent relation is revealed.
   -------------------------------------------------------------------------- */

.rt-v5g-route__trace {
  fill: none;

  stroke: rgba(201, 239, 233, .78);
  stroke-width: 1.15;

  stroke-linecap: round;
  stroke-linejoin: round;

  vector-effect: non-scaling-stroke;

  opacity: 0;

  filter:
    drop-shadow(
      0 0 3px
      rgba(172, 231, 226, .18)
    );

  transition:
    opacity 320ms ease,
    stroke-width 320ms ease;
}


.rt-v5g-route.is-active
.rt-v5g-route__trace {
  opacity: .18;
  stroke-width: 1.20;
}


/* --------------------------------------------------------------------------
   Hub response
   -------------------------------------------------------------------------- */

.rt-v5g-hub {
  --rt-hub-strength: 0;
  --rt-hub-color: 207, 239, 233;
}


.rt-v5g-hub[data-role="regional-occitan-root"] {
  --rt-hub-color: 234, 215, 164;
}


.rt-v5g-hub[data-role="littoral-aggregation"] {
  --rt-hub-color: 194, 232, 231;
}


.rt-v5g-hub__halo {
  fill:
    rgba(
      var(--rt-hub-color),
      calc(
        var(--rt-hub-strength)
        * .10
      )
    );

  stroke: none;

  opacity: 1;

  transition:
    fill 220ms ease;
}


.rt-v5g-hub__ring {
  fill: none;

  stroke:
    rgba(
      var(--rt-hub-color),
      calc(
        var(--rt-hub-strength)
        * .44
      )
    );

  stroke-width: 1;

  vector-effect: non-scaling-stroke;

  opacity: 1;

  filter:
    drop-shadow(
      0 0 4px
      rgba(
        var(--rt-hub-color),
        .16
      )
    );

  transition:
    stroke 220ms ease;
}


.rt-v5g-hub__core {
  fill:
    rgba(
      var(--rt-hub-color),
      calc(
        var(--rt-hub-strength)
        * .68
      )
    );

  opacity: 1;

  transition:
    fill 180ms ease;
}


/*
 * The nearest hub breathes.
 */

.rt-v5g-hub.is-active
.rt-v5g-hub__ring {
  animation:
    rt-v5g-active-hub-pulse
    2.8s
    ease-in-out
    infinite;
}


/*
 * Parent receives a weaker response.
 */

.rt-v5g-hub.is-receiving
.rt-v5g-hub__ring {
  animation:
    rt-v5g-parent-breathe
    3.5s
    ease-in-out
    infinite;
}


/*
 * Very short arrival accent.
 */

.rt-v5g-hub.is-arrival
.rt-v5g-hub__ring {
  stroke-width: 1.6;
}


@keyframes rt-v5g-active-hub-pulse {

  0%,
  100% {
    stroke-width: .9;
  }

  50% {
    stroke-width: 1.4;
  }
}


@keyframes rt-v5g-parent-breathe {

  0%,
  100% {
    opacity: .62;
  }

  50% {
    opacity: 1;
  }
}


/* --------------------------------------------------------------------------
   Data packet

   Position is controlled by JS using SVG path geometry.
   This avoids guessing flow direction from dash offsets.
   -------------------------------------------------------------------------- */

.rt-v5g-packet,
.rt-v5g-packet-tail {
  pointer-events: none;

  opacity: 0;

  vector-effect: non-scaling-stroke;
}


.rt-v5g-packet {
  fill: rgba(239, 229, 191, .78);

  filter:
    drop-shadow(
      0 0 5px
      rgba(232, 214, 161, .46)
    );
}


.rt-v5g-packet-tail {
  fill: rgba(200, 238, 232, .30);

  filter:
    drop-shadow(
      0 0 3px
      rgba(187, 232, 228, .25)
    );
}


.rt-local-hub-layer.has-active-route
.rt-v5g-packet,
.rt-local-hub-layer.has-active-route
.rt-v5g-packet-tail {
  opacity: 1;
}


/* --------------------------------------------------------------------------
   Accessibility
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {

  .rt-v5g-hub__ring,
  .rt-v5g-hub.is-active .rt-v5g-hub__ring,
  .rt-v5g-hub.is-receiving .rt-v5g-hub__ring {
    animation: none !important;
  }

  .rt-v5g-packet,
  .rt-v5g-packet-tail {
    display: none !important;
  }

  .rt-v5g-route__trace {
    transition: none;
  }
}


/* --------------------------------------------------------------------------
   No hover semantics on coarse pointers.
   -------------------------------------------------------------------------- */

@media (pointer: coarse) {

  .rt-local-hub-layer {
    display: none;
  }
}

