/* Heuristic — sistema de movimiento.
   Easing firma: cubic-bezier(.2,0,0,1). Duraciones 180 / 320 / 560 ms.
   Loops ambientales 6–9 s. Vocabulario: trazo de 1px que viaja. Sin glows. */

:root {
	--hx-ease: cubic-bezier(.2, 0, 0, 1);
	--hx-quick: 180ms;
	--hx-std: 320ms;
	--hx-slow: 560ms;
}

/* ------------------------------------------------ aparición por scroll */

/* El JS marca .hx-in cuando el bloque entra en pantalla. Sin JS no se oculta nada.

   Dos trampas aquí:
   · `.hx-card` declaraba su propia `transition` (transform + box-shadow) y, al
     compartir elemento con `.hx-reveal`, la ganaba: la opacidad entraba de golpe
     y parecía que el reveal «no funcionaba». La lista de transiciones es ahora
     única y compartida.
   · Elementor emite sus propias `transition` sobre `.elementor-element`, así que
     va con `!important` — solo en la propiedad `transition`, nunca en `transform`,
     o el alzado del hover dejaría de funcionar. */
.hx-reveal,
.hx-card {
	transition:
		opacity var(--hx-slow) var(--hx-ease),
		transform var(--hx-std) var(--hx-ease),
		box-shadow var(--hx-std) var(--hx-ease) !important;
}

.hx-reveal {
	opacity: 0;
	transform: translateY(16px);
	will-change: opacity, transform;
}

.hx-reveal.hx-in {
	opacity: 1;
	transform: none;
}

/* Cascada de 60 ms, tope 400 ms: el sexto hijo ya no espera más.

   El `!important` del retardo no es decorativo: el atajo `transition` de arriba
   lleva `!important` y un atajo **resetea `transition-delay` a 0**, así que sin
   esto la cascada no existía y las tarjetas entraban todas a la vez. */
.hx-reveal:nth-child(2) { transition-delay: 60ms !important; }
.hx-reveal:nth-child(3) { transition-delay: 120ms !important; }
.hx-reveal:nth-child(4) { transition-delay: 180ms !important; }
.hx-reveal:nth-child(5) { transition-delay: 240ms !important; }
.hx-reveal:nth-child(6) { transition-delay: 300ms !important; }

/* --- Grupo: el contenedor se marca una vez y cascadean sus hijos ---------

   `.hx-reveal` obliga a marcar cada elemento. Para cabeceras de sección, cifras,
   filas y muros basta una clase en el contenedor: sus hijos directos aparecen en
   cascada. Así el reveal llega a todo sin tocar widget por widget.

   El desplazamiento es más corto que en las tarjetas (10px frente a 16): son
   bloques de texto y un recorrido largo se lee como salto.

   Ojo: NO se anida un grupo dentro de otro. El hijo intermedio recibiría el
   retardo del padre y además el suyo, y la cascada se acumula. */
/* Un contenedor `boxed` mete un `.e-con-inner` entre medias, así que los hijos
   reales están un nivel más abajo: sin este segundo selector la cascada no
   llegaba a Partners ni al CTA. */
.hx-reveal-group > .elementor-element:not(.hx-reveal),
.hx-reveal-group > .e-con-inner > .elementor-element:not(.hx-reveal) {
	opacity: 0;
	transform: translateY(10px);
	transition:
		opacity var(--hx-slow) var(--hx-ease),
		transform var(--hx-std) var(--hx-ease),
		box-shadow var(--hx-std) var(--hx-ease) !important;
}

.hx-reveal-group.hx-in > .elementor-element:not(.hx-reveal),
.hx-reveal-group.hx-in > .e-con-inner > .elementor-element:not(.hx-reveal) {
	opacity: 1;
	transform: none;
}

.hx-reveal-group.hx-in > .elementor-element:not(.hx-reveal):nth-child(2),
.hx-reveal-group.hx-in > .e-con-inner > .elementor-element:not(.hx-reveal):nth-child(2) { transition-delay: 60ms !important; }
.hx-reveal-group.hx-in > .elementor-element:not(.hx-reveal):nth-child(3),
.hx-reveal-group.hx-in > .e-con-inner > .elementor-element:not(.hx-reveal):nth-child(3) { transition-delay: 120ms !important; }
.hx-reveal-group.hx-in > .elementor-element:not(.hx-reveal):nth-child(4),
.hx-reveal-group.hx-in > .e-con-inner > .elementor-element:not(.hx-reveal):nth-child(4) { transition-delay: 180ms !important; }
.hx-reveal-group.hx-in > .elementor-element:not(.hx-reveal):nth-child(5),
.hx-reveal-group.hx-in > .e-con-inner > .elementor-element:not(.hx-reveal):nth-child(5) { transition-delay: 240ms !important; }
.hx-reveal-group.hx-in > .elementor-element:not(.hx-reveal):nth-child(6),
.hx-reveal-group.hx-in > .e-con-inner > .elementor-element:not(.hx-reveal):nth-child(6) { transition-delay: 300ms !important; }
.hx-reveal-group.hx-in > .elementor-element:not(.hx-reveal):nth-child(n+7),
.hx-reveal-group.hx-in > .e-con-inner > .elementor-element:not(.hx-reveal):nth-child(n+7) { transition-delay: 360ms !important; }

/* Un hijo con su propio `.hx-reveal` queda fuera del grupo (`:not`): si no, la
   regla del grupo, más específica, le forzaría la opacidad antes de tiempo. */

/* ------------------------------------------- barrido de borde en tarjeta */

@property --hx-angle {
	syntax: '<angle>';
	inherits: false;
	initial-value: 0deg;
}

.hx-card {
	position: relative;
}

.hx-card:hover {
	transform: translateY(-3px);
	box-shadow: 0 12px 28px rgba(0, 26, 13, .07);
}

/* Un filete de 1px recorriendo el perímetro. `exclude` deja solo el borde. */
.hx-card::after,
.hx-card.e-con::after {
	content: '';
	position: absolute;
	inset: 0;
	z-index: 1;
	padding: 1px;
	border-radius: inherit;
	pointer-events: none;
	background: conic-gradient(from var(--hx-angle),
		transparent 0deg, transparent 296deg,
		rgba(19, 122, 58, .9) 334deg,
		#a8ce3a 352deg,
		transparent 360deg);
	-webkit-mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0);
	mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0);
	opacity: 0;
	transition: opacity var(--hx-quick) var(--hx-ease);
}

.hx-card:hover::after,
.hx-card.e-con:hover::after {
	opacity: 1;
	animation: hx-sweep 1.4s linear infinite;
}

@keyframes hx-sweep {
	to { --hx-angle: 360deg; }
}

/* --------------------------------------------------- retícula con haces */

/* El haz NO se mueve con transform: un elemento transformado amplía el área
   desplazable del documento, y con `translate(120vw/120vh)` la página se podía
   arrastrar a la derecha casi sin fin y le crecía un hueco blanco al final
   (Juano, 2026-07-29). Aquí el span ocupa la sección entera, quieto, y lo que
   viaja es la posición del degradado — que no genera desbordamiento alguno. */
.hx-grid > .hx-beam,
.hx-grid.e-con > .hx-beam {
	position: absolute;
	inset: 0;
	z-index: 0;
	pointer-events: none;
	background-repeat: no-repeat;
	/* Mientras corre el `animation-delay` el elemento mantiene su estilo base, así
	   que sin esto los tres haces se veían encendidos al cargar la página. Con
	   `both` adopta el fotograma 0 % —opacidad 0— desde el principio. */
	opacity: 0;
	animation-fill-mode: both;
}

.hx-beam.hx-beam--v {
	background-image: linear-gradient(to bottom, transparent, rgba(19, 122, 58, .55) 45%, rgba(168, 206, 58, .95) 62%, transparent);
	background-size: 1px 120px;
	/* Ciclo largo con ventana visible corta: cada haz pasa una vez y desaparece,
	   en vez de estar los tres encendidos permanentemente. */
	animation: hx-beam-down 13s var(--hx-ease) infinite;
}

.hx-beam.hx-beam--h {
	background-image: linear-gradient(to right, transparent, rgba(19, 122, 58, .5) 40%, rgba(168, 206, 58, .9) 64%, transparent);
	background-size: 160px 1px;
	animation: hx-beam-right 15s var(--hx-ease) infinite;
}

/* Sobre fondo oscuro el haz es lima puro: el verde bosque no despega del negro. */
.hx-grid--dark .hx-beam.hx-beam--v {
	background-image: linear-gradient(to bottom, transparent, rgba(168, 206, 58, .7) 50%, #ffffff 66%, transparent);
}

/* --x / --y los pone el JS con la columna o fila de la retícula de 80.

   El recorrido termina FUERA del bloque —`calc(100% + 160px)`—, porque acabar en
   `100%` dejaba el haz clavado en el borde inferior a media sección (Juano,
   2026-07-29). Y el apagado ocupa un 4% del ciclo, no un 34%. */
@keyframes hx-beam-down {
	0%        { background-position: var(--x, 240px) -160px; opacity: 0; }
	1%        { opacity: 1; }
	15%       { opacity: 1; }
	18%       { background-position: var(--x, 240px) calc(100% + 160px); opacity: 0; }
	100%      { background-position: var(--x, 240px) calc(100% + 160px); opacity: 0; }
}

@keyframes hx-beam-right {
	0%        { background-position: -200px var(--y, 160px); opacity: 0; }
	1%        { opacity: 1; }
	14%       { opacity: 1; }
	17%       { background-position: calc(100% + 200px) var(--y, 160px); opacity: 0; }
	100%      { background-position: calc(100% + 200px) var(--y, 160px); opacity: 0; }
}

/* -------------------------------------------- grafo del hero (wiz-style) */

.hx-graph {
	position: relative;
	width: 100%;
	max-width: 520px;
	aspect-ratio: 520 / 360;
	margin-inline: auto;
}

.hx-graph-wires {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
}

/* El paquete es un guion corto que recorre el camino: un solo trazo, cero halo. */
.hx-graph-flow path {
	stroke-dasharray: 26 400;
	stroke-dashoffset: 426;
	animation: hx-flow 3s var(--hx-ease) infinite;
	animation-delay: var(--d, 0s);
}

@keyframes hx-flow {
	0%        { stroke-dashoffset: 426; opacity: 0; }
	12%       { opacity: 1; }
	60%       { stroke-dashoffset: 0; opacity: 1; }
	72%, 100% { stroke-dashoffset: 0; opacity: 0; }
}

.hx-graph-node,
.hx-graph-core {
	position: absolute;
	display: inline-flex;
	align-items: center;
	gap: 8px;
	padding: 9px 12px;
	background: #ffffff;
	border: 1px solid var(--hx-line, #e4e8e4);
	border-radius: 6px;
	box-shadow: 0 8px 20px rgba(0, 26, 13, .08);
	font-family: 'Aeonik', sans-serif;
	font-size: 12px;
	font-weight: 500;
	color: #2b2b2b;
	white-space: nowrap;
}

/* Centrados sobre el mismo punto que ancla el trazo del SVG (viewBox 520×360),
   con translate(-50%,-50%): así el remate del cable queda debajo del nodo. */
.hx-graph-node {
	transform: translate(-50%, -50%);
}

.hx-graph-node.is-tl { left: 18.3%; top: 22.2%; }
.hx-graph-node.is-tr { left: 81.7%; top: 22.2%; }
.hx-graph-node.is-bl { left: 18.3%; top: 77.8%; }
.hx-graph-node.is-br { left: 81.7%; top: 77.8%; }

/* Punto de estado: late una vez por ciclo, escala mínima, sin difuminado */
.hx-graph-dot {
	width: 6px;
	height: 6px;
	border-radius: 50%;
	background: #a8ce3a;
	animation: hx-dot 3s var(--hx-ease) infinite;
}

.hx-graph-node.is-tr .hx-graph-dot { animation-delay: .5s; }
.hx-graph-node.is-bl .hx-graph-dot { animation-delay: 1s; }
.hx-graph-node.is-br .hx-graph-dot { animation-delay: 1.5s; }

@keyframes hx-dot {
	0%, 60%, 100% { transform: scale(1); opacity: .55; }
	68%           { transform: scale(1.5); opacity: 1; }
}

.hx-graph-core {
	top: 50%;
	left: 50%;
	transform: translate(-50%, -50%);
	background: #137a3a;
	border-color: #137a3a;
	color: #ffffff;
	padding: 12px 16px;
	box-shadow: 0 12px 28px rgba(0, 26, 13, .18);
}

/* Anillos: aro de 1px que se expande y se apaga. Nunca relleno, nunca borroso. */
.hx-graph-ring {
	position: absolute;
	inset: -1px;
	border: 1px solid rgba(19, 122, 58, .45);
	border-radius: 8px;
	animation: hx-ring 3s var(--hx-ease) infinite;
	pointer-events: none;
}

.hx-graph-ring.is-late { animation-delay: 1.5s; }

/* Corto y ceñido: a escala 1.5 el aro leía como un panel suelto detrás del núcleo. */
@keyframes hx-ring {
	0%        { transform: scale(1); opacity: .55; }
	70%, 100% { transform: scale(1.14); opacity: 0; }
}

/* ------------------------------------------ infografías: loops de vida */

/* Migración: flujo continuo, no pases discretos.
 *
 * Primera versión: un paquete que salía, se apagaba al llegar, reaparecía en el
 * origen, y un riel que subía a saltos de un tercio. Juano lo describió como «va
 * por partes y está rara, no parece pulida» (2026-07-29), con razón: eran nueve
 * eventos visibles en 12 s y cada uno cortaba el anterior.
 *
 * Esta versión tiene un solo gesto. Por el cable pasa un flujo permanente —dos
 * trazos desfasados con su propio bucle corto, así que nunca está vacío—, el riel
 * se llena de forma continua, y los checks entran con un fundido cuando el riel
 * cruza su tercio. Lo único que ocurre de golpe es el reinicio, y es un fundido
 * de los tres a la vez, no tres apagones seguidos.
 */
.hx-migration-mock .hx-mock-link {
	overflow: visible;
}

/* Dos trazos con el mismo bucle de 2,6 s y medio ciclo de desfase: mientras uno
   entra el otro está saliendo, y la línea nunca se queda muerta. El bucle es
   independiente del ciclo largo a propósito — sincronizarlos era lo que hacía que
   el cable pareciese ir «a tirones». */
.hx-migration-mock .hx-mock-link::before,
.hx-migration-mock .hx-mock-link::after {
	content: '';
	position: absolute;
	top: -1px;
	left: 0;
	width: 44px;
	height: 1px;
	background: linear-gradient(to right, transparent, rgba(19, 122, 58, .85) 60%, #a8ce3a);
	opacity: 0;
	animation: hx-mv-flow 2.6s linear infinite;
	animation-fill-mode: both;
}

.hx-migration-mock .hx-mock-link::after {
	animation-delay: 1.3s;
}

@keyframes hx-mv-flow {
	0%   { transform: translateX(0); opacity: 0 }
	12%  { opacity: 1 }
	88%  { opacity: 1 }
	100% { transform: translateX(calc(100% - 44px)); opacity: 0 }
}

/* El riel se llena de una sola pasada. La curva es la del sistema, así que arranca
   rápido y cierra despacio; a saltos de tercio se leía como tres barras distintas. */
.hx-migration-mock .hx-mv-track b {
	animation: hx-mv-fill 10s var(--hx-ease) infinite;
	animation-fill-mode: both;
}

@keyframes hx-mv-fill {
	0%        { width: 0; opacity: 1 }
	8%        { width: 0; opacity: 1 }
	72%       { width: 100%; opacity: 1 }
	92%       { width: 100%; opacity: 1 }
	98%, 100% { width: 100%; opacity: 0 }
}

/* Estado «copiado»: el verde del punto (una capa sobre el punto gris, ver mocks.css)
   y el check del destino. Los dos animan lo mismo —opacidad— así que comparten los
   tres keyframes; animar `background` en el keyframe compartido pintaba el check
   como un cuadrado verde. El fundido dura un 8 % del ciclo, 0,8 s: cambio, no
   parpadeo. Sin escala, que el `scale(.6)` era el «pop» que se notaba. */
.hx-migration-mock .is-src .hx-mv-dot::after,
.hx-migration-mock .is-dst .hx-mv-check {
	animation-duration: 10s;
	animation-timing-function: var(--hx-ease);
	animation-iteration-count: infinite;
	animation-fill-mode: both;
}

.hx-migration-mock .is-dst .hx-mv-check {
	opacity: 0;
}

/* Los tres instantes son los tercios del recorrido del riel: 28 %, 48 % y 68 %. */
.hx-migration-mock .is-src .hx-mv-row:nth-of-type(2) .hx-mv-dot::after,
.hx-migration-mock .is-dst .hx-mv-row:nth-of-type(2) .hx-mv-check { animation-name: hx-mv-on-1 }
.hx-migration-mock .is-src .hx-mv-row:nth-of-type(3) .hx-mv-dot::after,
.hx-migration-mock .is-dst .hx-mv-row:nth-of-type(3) .hx-mv-check { animation-name: hx-mv-on-2 }
.hx-migration-mock .is-src .hx-mv-row:nth-of-type(4) .hx-mv-dot::after,
.hx-migration-mock .is-dst .hx-mv-row:nth-of-type(4) .hx-mv-check { animation-name: hx-mv-on-3 }

@keyframes hx-mv-on-1 {
	0%, 24%   { opacity: 0 }
	32%, 92%  { opacity: 1 }
	98%, 100% { opacity: 0 }
}

@keyframes hx-mv-on-2 {
	0%, 44%   { opacity: 0 }
	52%, 92%  { opacity: 1 }
	98%, 100% { opacity: 0 }
}

@keyframes hx-mv-on-3 {
	0%, 64%   { opacity: 0 }
	72%, 92%  { opacity: 1 }
	98%, 100% { opacity: 0 }
}
}
}
	48%       { opacity: 1; transform: scale(1); }
	88%       { opacity: 1; transform: scale(1); }
	96%, 100% { opacity: 0; transform: scale(.6); }
}

/* Auditoría: las barras se rellenan al entrar en pantalla, una tras otra */
.hx-audit-mock .hx-audit-track > i {
	transform: scaleX(0);
	transform-origin: left center;
	transition: transform 900ms var(--hx-ease);
}

.hx-audit-mock.hx-in .hx-audit-track > i { transform: scaleX(1); }
.hx-audit-mock.hx-in .hx-audit-row:nth-of-type(2) .hx-audit-track > i { transition-delay: 120ms !important; }
.hx-audit-mock.hx-in .hx-audit-row:nth-of-type(3) .hx-audit-track > i { transition-delay: 240ms !important; }

/* Tickets: las barras crecen desde la base y luego respiran ±2px */
.hx-tickets-mock .hx-tickets-bars > i {
	transform-origin: bottom center;
	transform: scaleY(0);
	transition: transform 700ms var(--hx-ease);
}

.hx-tickets-mock.hx-in .hx-tickets-bars > i {
	transform: none;
	animation: hx-breathe 7s ease-in-out infinite;
}

/* Doce barras, desfase de 90 ms: la ola cruza el gráfico en poco más de 1 s */
.hx-tickets-mock .hx-tickets-bars > i:nth-child(1)  { transition-delay: 0ms !important;   animation-delay: .0s; }
.hx-tickets-mock .hx-tickets-bars > i:nth-child(2)  { transition-delay: 40ms !important;  animation-delay: .1s; }
.hx-tickets-mock .hx-tickets-bars > i:nth-child(3)  { transition-delay: 80ms !important;  animation-delay: .2s; }
.hx-tickets-mock .hx-tickets-bars > i:nth-child(4)  { transition-delay: 120ms !important; animation-delay: .3s; }
.hx-tickets-mock .hx-tickets-bars > i:nth-child(5)  { transition-delay: 160ms !important; animation-delay: .4s; }
.hx-tickets-mock .hx-tickets-bars > i:nth-child(6)  { transition-delay: 200ms !important; animation-delay: .5s; }
.hx-tickets-mock .hx-tickets-bars > i:nth-child(7)  { transition-delay: 240ms !important; animation-delay: .6s; }
.hx-tickets-mock .hx-tickets-bars > i:nth-child(8)  { transition-delay: 280ms !important; animation-delay: .7s; }
.hx-tickets-mock .hx-tickets-bars > i:nth-child(9)  { transition-delay: 320ms !important; animation-delay: .8s; }
.hx-tickets-mock .hx-tickets-bars > i:nth-child(10) { transition-delay: 360ms !important; animation-delay: .9s; }
.hx-tickets-mock .hx-tickets-bars > i:nth-child(11) { transition-delay: 400ms !important; animation-delay: 1s; }
.hx-tickets-mock .hx-tickets-bars > i:nth-child(12) { transition-delay: 440ms !important; animation-delay: 1.1s; }

@keyframes hx-breathe {
	0%, 100% { transform: translateY(0); }
	50%      { transform: translateY(-2px); }
}

/* Diagrama de red del paso 02: paquetes por las diagonales y pulso en el núcleo */
/* El retardo lo pone el marcado (--d) para que se lea entrada → firewall → salida. */
.hx-net-flow line {
	stroke-dasharray: 16 120;
	stroke-dashoffset: 136;
	animation: hx-netflow 4s var(--hx-ease) infinite;
	animation-delay: var(--d, 0s);
}

@keyframes hx-netflow {
	0%        { stroke-dashoffset: 136; opacity: 0; }
	14%       { opacity: 1; }
	62%       { stroke-dashoffset: 0; opacity: 1; }
	74%, 100% { stroke-dashoffset: 0; opacity: 0; }
}

/* El pulso del firewall cae entre la llegada y la salida del paquete. */
.hx-net-node.is-center {
	animation: hx-core 4s ease-in-out infinite;
	animation-delay: .5s;
}

@keyframes hx-core {
	0%, 100% { box-shadow: 0 8px 20px rgba(0, 26, 13, .1), 0 0 0 0 rgba(19, 122, 58, .35); }
	50%      { box-shadow: 0 8px 20px rgba(0, 26, 13, .1), 0 0 0 4px rgba(19, 122, 58, 0); }
}

/* Conector de los tres pasos: el trazo se dibuja y los nudos se encienden */
.hx-connector::after {
	content: '';
	position: absolute;
	top: 50%;
	left: 0;
    z-index: -1;
	width: 60px;
	height: 1px;
	background: linear-gradient(to right, transparent, #137a3a 60%, #a8ce3a);
	animation: hx-connector-run 7s var(--hx-ease) infinite;
}

@keyframes hx-connector-run {
	0%        { transform: translateX(0); opacity: 0; }
	6%        { opacity: 1; }
	50%       { transform: translateX(calc(100cqw - 60px)); opacity: 1; }
	58%, 100% { transform: translateX(calc(100cqw - 60px)); opacity: 0; }
}

/* `cqw` necesita contenedor de consulta declarado */
.hx-connector,
.hx-migration-mock .hx-mock-link {
	container-type: inline-size;
}

/* --------------------------------- grafo como capa de fondo del hero */

.hx-hero-visual.e-con {
	position: relative;
}

/* El grafo es el visual del hero: ocupa la columna entera. Antes iba detrás del
   panel de monitorización, pero ese panel se retiró (estático y redundante). */
.hx-hero-visual .hx-hero-graph-layer {
	width: 100%;
}

.hx-hero-visual .hx-hero-graph-layer .hx-graph {
	max-width: none;
	aspect-ratio: 520 / 330;
}

/* Los nodos NO se recolocan aquí: el SVG se estira con `preserveAspectRatio=none`,
   así que sus anclas siguen en el mismo porcentaje y todo encaja al comprimir. */

/* En tablet y móvil los nodos se aprietan: bajan de cuerpo y el marco crece. */
@media (max-width: 1024px) {
	.hx-hero-visual .hx-hero-graph-layer .hx-graph {
		aspect-ratio: 520 / 300;
	}
}

@media (max-width: 767px) {
	/* En móvil los dos paneles se apilan y el cable pasa a ser vertical
	   (`border-left`, ver mocks.css), así que el flujo y el riel también: con el
	   recorrido en X quedaban cruzados sobre un cable en Y. */
	.hx-migration-mock .hx-mock-link::before,
	.hx-migration-mock .hx-mock-link::after {
		top: 0;
		left: -1px;
		width: 1px;
		height: 44px;
		background: linear-gradient(to bottom, transparent, rgba(19, 122, 58, .85) 60%, #a8ce3a);
		animation-name: hx-mv-flow-v;
	}

	@keyframes hx-mv-flow-v {
		0%   { transform: translateY(0); opacity: 0 }
		12%  { opacity: 1 }
		88%  { opacity: 1 }
		100% { transform: translateY(calc(100% - 44px)); opacity: 0 }
	}

	.hx-migration-mock .hx-mv-track {
		top: 0;
		bottom: 0;
		left: -1px;
		right: auto;
		width: 1px;
		height: auto;
	}

	.hx-migration-mock .hx-mv-track b {
		width: 100%;
		height: 0;
		background: linear-gradient(to bottom, #137a3a, #a8ce3a);
		animation-name: hx-mv-fill-v;
	}

	@keyframes hx-mv-fill-v {
		0%, 8%    { height: 0; opacity: 1 }
		72%, 92%  { height: 100%; opacity: 1 }
		98%, 100% { height: 100%; opacity: 0 }
	}

	.hx-hero-visual .hx-hero-graph-layer .hx-graph {
		aspect-ratio: 390 / 320;
	}

	.hx-graph-node,
	.hx-graph-core {
		font-size: 11px;
		padding: 7px 9px;
		gap: 6px;
	}

	.hx-graph-core {
		padding: 9px 12px;
	}
}

/* Panel del hero: cada fila hace check en cascada y se queda */
.hx-hero-panel .hx-row-check {
	animation: hx-tick 9s var(--hx-ease) infinite;
	transform-origin: center;
}

/* ------------------------------------------------------- accesibilidad */

@media (prefers-reduced-motion: reduce) {
	/* Los selectores repiten el `:not(.hx-reveal)` del grupo a propósito: sin él
	   esta regla es menos específica y no llegaba a apagar nada. */
	.hx-reveal,
	.hx-reveal.hx-in,
	.hx-reveal-group > .elementor-element:not(.hx-reveal),
	.hx-reveal-group.hx-in > .elementor-element:not(.hx-reveal),
	.hx-reveal-group > .e-con-inner > .elementor-element:not(.hx-reveal),
	.hx-reveal-group.hx-in > .e-con-inner > .elementor-element:not(.hx-reveal) {
		opacity: 1 !important;
		transform: none;
		transition: none !important;
		transition-delay: 0s !important;
	}

	.hx-beam,
	.hx-graph-flow path,
	.hx-graph-dot,
	.hx-graph-ring,
	.hx-migration-mock .hx-mock-link::before,
	.hx-migration-mock .hx-mock-link::after,
	.hx-connector::after,
	.hx-net-lines g line,
	.hx-net-node.is-center,
	.hx-tickets-mock .hx-tickets-bars > i,
	.hx-migration-mock .is-dst .hx-mv-check,
	.hx-migration-mock .is-src .hx-mv-dot::after,
	.hx-migration-mock .hx-mv-track b,
	.hx-hero-panel .hx-row-check,
	.hx-card::after {
		animation: none !important;
	}

	/* Estado final visible, sin recorrido */
	.hx-graph-flow path { stroke-dashoffset: 0; opacity: .7; }
	.hx-audit-mock .hx-audit-track > i,
	.hx-tickets-mock .hx-tickets-bars > i { transform: none; transition: none; }
	.hx-beam,
	.hx-graph-ring,
	.hx-migration-mock .hx-mock-link::before,
	.hx-migration-mock .hx-mock-link::after,
	.hx-connector::after { display: none; }
	.hx-migration-mock .is-dst .hx-mv-check,
	.hx-migration-mock .is-src .hx-mv-dot::after { opacity: 1; transform: none; }
	/* Sin animación el riel se quedaría a 0 y parecería roto: se muestra completo. */
	.hx-migration-mock .hx-mv-track b { width: 100%; }
	.hx-card:hover { transform: none; }
}
