/* ============================================================================
   fx/firma-guangdong-brilliant.css · firma "cluster" (partitura: _motion-brief.md)
   Una industria enciende su cluster: las estaciones de la red se encienden por
   distancia real y los tramos suben de opacidad. Luz, no trazo.
   - Todo pre-estado cuelga de .fx-live, que pone fx/firma-guangdong-brilliant.js.
     Sin JS, con la firma caída o con reduced-motion no hay pre-estado: se ve
     todo encendido y quieto (estado base = estado final).
   - Solo pantalla y solo con prefers-reduced-motion: no-preference.
   - No toca el driver canónico (efectos.css/js).
   ========================================================================== */
.fx{
  --fx-dur-1:120ms;
  --fx-dur-2:300ms;
  --fx-dur-3:560ms;
  --fx-dur-ring:760ms;
  --fx-dur-exit:225ms;                           /* 75 % de --fx-dur-2 */
  --fx-ease-out:cubic-bezier(.23,1,.32,1);
  --fx-ease-out-expo:cubic-bezier(.16,1,.3,1);
  --fx-stagger:60ms;
  --fx-wave:70ms;
  --fx-halo-paper:rgba(107,74,126,.5);           /* --bloom */
  --fx-halo-ink:rgba(185,163,198,.62);           /* --lilac */
}

@media screen and (prefers-reduced-motion:no-preference){

/* ---------------------------------------------------------------------------
   1 · cluster-line: estaciones en línea (hero, cifras, capacidades, secuencia,
       regiones de cada industria). --fx-i lo pone el módulo por estación.
   ------------------------------------------------------------------------- */
.fx-live [data-fx="cluster-line"]{--fx-at:calc(var(--fx-i,0) * var(--fx-stagger) + var(--fx-delay,0ms))}
.fx-live [data-fx="cluster-line"] > li,
.fx-live [data-fx="cluster-line"] ol > li,
.fx-live [data-fx="cluster-line"] > a,
.fx-live [data-fx="cluster-line"] > span.stn{--fx-at:calc(var(--fx-i,0) * var(--fx-stagger) + var(--fx-delay,0ms))}

/* puntos apagados hasta que la línea entra */
.fx-live .figs[data-fx="cluster-line"]:not(.fx-in) li::before,
.fx-live .seq[data-fx="cluster-line"]:not(.fx-in) li::after,
.fx-live .capline[data-fx="cluster-line"]:not(.fx-in) li::after,
.fx-live .stations[data-fx="cluster-line"]:not(.fx-in) a::before,
.fx-live .stations[data-fx="cluster-line"]:not(.fx-in) span.stn::before,
.fx-live .route[data-fx="cluster-line"]:not(.fx-in) .st,
.fx-live .route[data-fx="cluster-line"]:not(.fx-in) .ix,
.fx-live .stationlist > li[data-fx="cluster-node"]:not(.fx-in)::after{opacity:.35;transform:scale(.6)}

/* encendido sobre tinta (lila) */
.fx-live .figs[data-fx="cluster-line"].fx-in li::before,
.fx-live .seq[data-fx="cluster-line"].fx-in li::after,
.fx-live .route[data-fx="cluster-line"].fx-in .st{
  animation:fx-dot-ink var(--fx-dur-3) var(--fx-ease-out) var(--fx-at) backwards,
            fx-halo-ink var(--fx-dur-ring) var(--fx-ease-out) var(--fx-at) backwards}
.fx-live .route[data-fx="cluster-line"].fx-in .ix{
  animation:fx-hub var(--fx-dur-3) var(--fx-ease-out) var(--fx-at) backwards,
            fx-halo-ink var(--fx-dur-ring) var(--fx-ease-out) var(--fx-at) backwards}

/* encendido sobre claro (bloom) */
.fx-live .capline[data-fx="cluster-line"].fx-in li::after,
.fx-live .stationlist > li[data-fx="cluster-node"].fx-in::after{
  animation:fx-dot-paper var(--fx-dur-3) var(--fx-ease-out) var(--fx-at,0ms) backwards,
            fx-halo-paper var(--fx-dur-ring) var(--fx-ease-out) var(--fx-at,0ms) backwards}
.fx-live .stations[data-fx="cluster-line"].fx-in a::before,
.fx-live .stations[data-fx="cluster-line"].fx-in span.stn::before{
  animation:fx-dot-paper var(--fx-dur-3) var(--fx-ease-out) var(--fx-at) backwards,
            fx-halo-chip var(--fx-dur-ring) var(--fx-ease-out) var(--fx-at) backwards}

/* tramos: bajan a .12 y suben a su opacidad de base cuando la estación llega */
.fx-live .figs[data-fx="cluster-line"]::before,
.fx-live .capline[data-fx="cluster-line"] li::before,
.fx-live .seq[data-fx="cluster-line"] li::before,
.fx-live .route[data-fx="cluster-line"] ol::before,
.fx-live .stationlist > li[data-fx="cluster-node"]::before{
  transition:opacity var(--fx-dur-3) var(--fx-ease-out) var(--fx-at,0ms)}
.fx-live .figs[data-fx="cluster-line"]:not(.fx-in)::before,
.fx-live .capline[data-fx="cluster-line"]:not(.fx-in) li::before,
.fx-live .seq[data-fx="cluster-line"]:not(.fx-in) li::before,
.fx-live .route[data-fx="cluster-line"]:not(.fx-in) ol::before,
.fx-live .stationlist > li[data-fx="cluster-node"]:not(.fx-in)::before{opacity:.12}

/* la línea de las cifras es una sola: se enciende detrás de la última estación */
.fx-live .figs[data-fx="cluster-line"]::before{transition-delay:calc(3 * var(--fx-stagger))}

@keyframes fx-dot-ink{0%{opacity:.35;transform:scale(.6)}45%{opacity:1;transform:scale(1.22);background-color:var(--lilac)}}
@keyframes fx-dot-paper{0%{opacity:.35;transform:scale(.6)}45%{opacity:1;transform:scale(1.22);background-color:var(--bloom)}}
@keyframes fx-hub{0%{opacity:.35;transform:scale(.6)}45%{opacity:1;transform:scale(1.12);background-color:var(--lilac)}}
@keyframes fx-halo-ink{0%{box-shadow:0 0 0 0 var(--fx-halo-ink)}100%{box-shadow:0 0 0 14px rgba(185,163,198,0)}}
@keyframes fx-halo-paper{0%{box-shadow:0 0 0 0 var(--fx-halo-paper)}100%{box-shadow:0 0 0 14px rgba(107,74,126,0)}}
@keyframes fx-halo-chip{0%{box-shadow:0 0 0 2px var(--amethyst),0 0 0 2px var(--fx-halo-paper)}100%{box-shadow:0 0 0 2px var(--amethyst),0 0 0 11px rgba(107,74,126,0)}}

/* ---------------------------------------------------------------------------
   2 · cluster-map: la red de 11 regiones. --fx-d por estación = distancia real
       desde Shenzhen (0–720 ms). data-fx-wave alterna 1/2 para relanzar la onda
       en cada clic del filtro sin forzar reflow.
   ------------------------------------------------------------------------- */
.fx-live svg[data-fx="cluster-map"] .stn{transition:opacity var(--fx-dur-2) var(--fx-ease-out) var(--fx-d,0ms)}
.fx-live svg[data-fx="cluster-map"] .stn.is-dim{transition-duration:var(--fx-dur-exit);transition-delay:0ms}
.fx-live svg[data-fx="cluster-map"]:not(.fx-in) .stn{opacity:.16}
.fx-live svg[data-fx="cluster-map"] .ln{transition:opacity var(--fx-dur-3) var(--fx-ease-out) var(--fx-d,0ms)}
.fx-live svg[data-fx="cluster-map"]:not(.fx-in) .ln{opacity:.1}

.fx-live svg[data-fx="cluster-map"] .stn > circle,
.fx-live svg[data-fx="cluster-map"] .stn > rect,
.fx-live svg[data-fx="cluster-world"] g > circle,
.fx-live svg[data-fx="cluster-world"] g > rect{transform-box:fill-box;transform-origin:center}

.fx-ring{fill:none !important;stroke-width:3;opacity:0;pointer-events:none}
svg[data-fx="cluster-map"] .fx-ring{stroke:var(--bloom) !important}
svg[data-fx="cluster-world"] .fx-ring{stroke:var(--lilac) !important}

/* onda de entrada ("in"): la estación parte apagada y chica, y así espera su turno */
.fx-live svg[data-fx="cluster-map"].fx-in[data-fx-wave="in"] .stn:not(.is-dim) > :not(.fx-ring):not(text){animation:fx-node-in var(--fx-dur-3) var(--fx-ease-out) var(--fx-d,0ms) backwards}
.fx-live svg[data-fx="cluster-map"].fx-in[data-fx-wave="in"] .stn:not(.is-dim) > .fx-ring{animation:fx-ring-in var(--fx-dur-ring) var(--fx-ease-out) var(--fx-d,0ms) backwards}
.fx-live svg[data-fx="cluster-map"].fx-in[data-fx-wave="in"] .stn--prov:not(.is-dim) > .fx-ring{animation-name:fx-ring-prov-in}
/* ondas del filtro ("a"/"b" alternan para relanzar): parten del tamaño real y sin
   fill backwards, así cada estación queda quieta hasta su turno (iteración 2 del 12) */
.fx-live svg[data-fx="cluster-map"].fx-in[data-fx-wave="a"] .stn:not(.is-dim) > :not(.fx-ring):not(text){animation:fx-node-a var(--fx-dur-3) var(--fx-ease-out) var(--fx-d,0ms)}
.fx-live svg[data-fx="cluster-map"].fx-in[data-fx-wave="b"] .stn:not(.is-dim) > :not(.fx-ring):not(text){animation:fx-node-b var(--fx-dur-3) var(--fx-ease-out) var(--fx-d,0ms)}
.fx-live svg[data-fx="cluster-map"].fx-in[data-fx-wave="a"] .stn:not(.is-dim) > .fx-ring{animation:fx-ring-a var(--fx-dur-ring) var(--fx-ease-out) var(--fx-d,0ms)}
.fx-live svg[data-fx="cluster-map"].fx-in[data-fx-wave="b"] .stn:not(.is-dim) > .fx-ring{animation:fx-ring-b var(--fx-dur-ring) var(--fx-ease-out) var(--fx-d,0ms)}
.fx-live svg[data-fx="cluster-map"].fx-in[data-fx-wave="a"] .stn--prov:not(.is-dim) > .fx-ring{animation-name:fx-ring-prov-a}
.fx-live svg[data-fx="cluster-map"].fx-in[data-fx-wave="b"] .stn--prov:not(.is-dim) > .fx-ring{animation-name:fx-ring-prov-b}

/* la lista de regiones (red) sigue el retardo de su estación */
.fx-live .regions li{transition:opacity var(--fx-dur-2) var(--fx-ease-out) var(--fx-d,0ms)}
.fx-live .regions li.is-dim{transition-duration:var(--fx-dur-exit);transition-delay:0ms}

@keyframes fx-node-in{0%{transform:scale(.7)}45%{transform:scale(1.22);fill:var(--bloom)}}
@keyframes fx-node-a{40%{transform:scale(1.2);fill:var(--bloom)}}
@keyframes fx-node-b{40%{transform:scale(1.2);fill:var(--bloom)}}
@keyframes fx-ring-in{0%{opacity:0;transform:scale(1)}10%{opacity:.85}100%{opacity:0;transform:scale(2.6)}}
@keyframes fx-ring-a{0%{opacity:0;transform:scale(1)}10%{opacity:.85}100%{opacity:0;transform:scale(2.6)}}
@keyframes fx-ring-b{0%{opacity:0;transform:scale(1)}10%{opacity:.85}100%{opacity:0;transform:scale(2.6)}}
@keyframes fx-ring-prov-in{0%{opacity:0;transform:scale(1)}10%{opacity:.85}100%{opacity:0;transform:scale(1.8)}}
@keyframes fx-ring-prov-a{0%{opacity:0;transform:scale(1)}10%{opacity:.85}100%{opacity:0;transform:scale(1.8)}}
@keyframes fx-ring-prov-b{0%{opacity:0;transform:scale(1)}10%{opacity:.85}100%{opacity:0;transform:scale(1.8)}}

/* ---------------------------------------------------------------------------
   3 · cluster-world: China enciende a Brilliant y Brilliant a los mercados.
       Los arcos suben de opacidad (no se trazan).
   ------------------------------------------------------------------------- */
.fx-live svg[data-fx="cluster-world"] g,
.fx-live svg[data-fx="cluster-world"] path{transition:opacity var(--fx-dur-3) var(--fx-ease-out) var(--fx-d,0ms)}
.fx-live svg[data-fx="cluster-world"]:not(.fx-in) g{opacity:.2}
.fx-live svg[data-fx="cluster-world"]:not(.fx-in) path{opacity:.08}
.fx-live svg[data-fx="cluster-world"].fx-in g > :not(.fx-ring):not(text){animation:fx-node-w var(--fx-dur-3) var(--fx-ease-out) var(--fx-d,0ms) backwards}
.fx-live svg[data-fx="cluster-world"].fx-in g > .fx-ring{animation:fx-ring-in var(--fx-dur-ring) var(--fx-ease-out) var(--fx-d,0ms) backwards}
.fx-live svg[data-fx="cluster-world"].fx-in .hub > .fx-ring{animation-name:fx-ring-prov-in}
@keyframes fx-node-w{0%{transform:scale(.7)}45%{transform:scale(1.2);fill:var(--lilac)}}

/* ---------------------------------------------------------------------------
   4 · reveal-cluster: el panel de industria prende la luz. El driver y el
       módulo ponen .in; .fx-done devuelve las transiciones de la base (hover).
   ------------------------------------------------------------------------- */
/* iteración 2 (12): pre-estado menos oscuro y opacidad más larga, para que nunca se vea
   un bloque gris; el título llega a +120 ms, casi con la foto */
.fx-live [data-fx="reveal-cluster"]{opacity:0;transition:opacity 420ms var(--fx-ease-out) var(--fx-d,0ms)}
.fx-live [data-fx="reveal-cluster"].in{opacity:1}
.fx-live [data-fx="reveal-cluster"]:not(.in) img{filter:brightness(.6) saturate(.85);transform:scale(1.04)}
.fx-live [data-fx="reveal-cluster"]:not(.in) .pane__in{opacity:0;transform:translateY(8px)}
.fx-live [data-fx="reveal-cluster"].in:not(.fx-done) img{
  transition:filter 900ms var(--fx-ease-out-expo) calc(var(--fx-d,0ms) + 40ms),
             transform 900ms var(--fx-ease-out-expo) calc(var(--fx-d,0ms) + 40ms)}
.fx-live [data-fx="reveal-cluster"].in:not(.fx-done) .pane__in{
  transition:opacity var(--fx-dur-2) var(--fx-ease-out) calc(var(--fx-d,0ms) + 120ms),
             transform 460ms var(--fx-ease-out) calc(var(--fx-d,0ms) + 120ms)}

/* cifras: el sufijo («+») llega con el valor final (iteración 2 del 12) */
/* iteración 3 (12): se oculta al instante cuando arranca la cuenta y solo la llegada transiciona */
.fx-live .figs__v.fx-counted .fx-suffix{transition:opacity var(--fx-dur-2) var(--fx-ease-out)}
.fx-live .figs__v:not(.fx-counted) .fx-suffix{opacity:0;transition:none}

/* la ruta del hero: tres nodos a 600 px entre sí piden un escalonado propio */
.fx-live .route[data-fx="cluster-line"]{--fx-stagger:200ms}

/* ---------------------------------------------------------------------------
   5 · parallax: holgura para que la foto nunca deje hueco (el módulo pone
       .fx-plx en el contenedor solo si el parallax queda activo)
   ------------------------------------------------------------------------- */
.fx-live .impact__media.fx-plx{top:-56px;bottom:-56px}
.fx-live .phead__media.fx-plx{top:-56px}
.fx-live .fx-plx img{will-change:transform}

/* ---------------------------------------------------------------------------
   6 · móvil: anillos más cortos, sin escala de la foto del panel
   ------------------------------------------------------------------------- */
@media (max-width:900px){
  .fx{--fx-stagger:50ms}
  .fx-live [data-fx="reveal-cluster"]:not(.in) img{transform:none}
  @keyframes fx-ring-in{0%{opacity:0;transform:scale(1)}10%{opacity:.85}100%{opacity:0;transform:scale(2)}}
  @keyframes fx-ring-a{0%{opacity:0;transform:scale(1)}10%{opacity:.85}100%{opacity:0;transform:scale(2)}}
  @keyframes fx-ring-b{0%{opacity:0;transform:scale(1)}10%{opacity:.85}100%{opacity:0;transform:scale(2)}}
  .fx-live .route[data-fx="cluster-line"]{--fx-stagger:160ms}
}

}/* fin no-preference */

/* failsafe: si el driver o la firma no arrancan, el head quita .fx-live y pone .fx-off */
.fx-off [data-fx^="reveal"]{opacity:1 !important;transform:none !important;filter:none !important}
