/*
 * White Hat Core — hoja principal.
 *
 * Se carga sin bloquear el pintado; lo imprescindible ya viaja en critical.css.
 * Ningun color literal: todo sale de las variables de inc/tokens.php.
 *
 * Orden: fondo · utilidades · navegacion · secciones · componentes · blog ·
 * formularios · pie · movimiento.
 */

/* ============================================================
   1. Capa de fondo
   ============================================================ */

.wh-bgfx {
	position: fixed;
	inset: 0;
	z-index: -1;
	pointer-events: none;
}

.wh-bgfx--grid {
	background-image:
		linear-gradient(rgba(var(--wh-sky-rgb) / .055) 1px, transparent 1px),
		linear-gradient(90deg, rgba(var(--wh-sky-rgb) / .055) 1px, transparent 1px);
	background-size: 64px 64px;
	/* La rejilla se desvanece hacia abajo para que no compita con el texto. */
	mask-image: linear-gradient(180deg, #000 0%, transparent 78%);
}

.wh-bgfx--aurora::before,
.wh-bgfx--aurora::after {
	content: "";
	position: absolute;
	width: 46vw;
	aspect-ratio: 1;
	border-radius: 50%;
	filter: blur(90px);
	opacity: calc(var(--wh-glow) * .3);
}
.wh-bgfx--aurora::before {
	top: -14vw;
	inset-inline-start: -10vw;
	background: radial-gradient(circle, var(--wh-primary), transparent 68%);
}
.wh-bgfx--aurora::after {
	top: 34vh;
	inset-inline-end: -16vw;
	background: radial-gradient(circle, var(--wh-lime), transparent 68%);
	opacity: calc(var(--wh-glow) * .18);
}

.wh-bgfx--circuit {
	background-image:
		linear-gradient(rgba(var(--wh-sky-rgb) / .05) 1px, transparent 1px),
		linear-gradient(90deg, rgba(var(--wh-sky-rgb) / .05) 1px, transparent 1px),
		radial-gradient(circle at 20% 30%, rgba(var(--wh-primary-rgb) / .1), transparent 40%),
		radial-gradient(circle at 80% 70%, rgba(var(--wh-lime-rgb) / .07), transparent 40%);
	background-size: 44px 44px, 44px 44px, 100% 100%, 100% 100%;
	mask-image: linear-gradient(180deg, #000, transparent 85%);
}

/* Grano fino sobre todo el fondo: rompe las bandas que produce un degradado
   grande en pantallas de 8 bits. El SVG va en linea para no pedir un archivo. */
.wh-grain::after {
	content: "";
	position: fixed;
	inset: 0;
	z-index: -1;
	pointer-events: none;
	opacity: .035;
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ============================================================
   2. Utilidades y piezas sueltas
   ============================================================ */

.wh-rot90  { transform: rotate(90deg); }
.wh-rot-90 { transform: rotate(-90deg); }

.wh-i { flex: none; }

/* Rejilla comun. El numero de columnas llega como variable desde el widget o
   la plantilla, y se reduce sola en pantallas estrechas. */
.wh-grid {
	display: grid;
	gap: clamp(1rem, 2.2vw, 1.75rem);
	grid-template-columns: repeat(var(--wh-cols, 3), minmax(0, 1fr));
}

@media (max-width: 61.99rem) {
	.wh-grid { grid-template-columns: repeat(min(var(--wh-cols, 3), 2), minmax(0, 1fr)); }
}
@media (max-width: 40rem) {
	.wh-grid { grid-template-columns: 1fr; }
}

.wh-kicker {
	display: inline-flex;
	align-items: center;
	gap: .55rem;
	margin: 0 0 .5rem;
	font-family: var(--wh-font-mono);
	font-size: var(--wh-fs-xs);
	font-weight: 500;
	letter-spacing: .14em;
	text-transform: uppercase;
	color: var(--wh-sky);
}

.wh-kicker__dot {
	width: 7px;
	height: 7px;
	border-radius: 50%;
	background: var(--wh-lime);
	box-shadow: 0 0 0 4px rgba(var(--wh-lime-rgb) / .16);
}

.wh-badge {
	display: inline-flex;
	align-items: center;
	gap: .55rem;
	margin: 0;
	padding: .45rem .95rem .45rem .7rem;
	border: 1px solid rgba(var(--wh-sky-rgb) / .26);
	border-radius: var(--wh-radius-pill);
	background: rgba(var(--wh-surface-rgb) / .5);
	backdrop-filter: blur(8px);
	font-family: var(--wh-font-mono);
	font-size: var(--wh-fs-xs);
	letter-spacing: .06em;
	color: var(--wh-sky);
}

.wh-badge__pulse {
	position: relative;
	width: 8px;
	height: 8px;
	border-radius: 50%;
	background: var(--wh-lime);
}
.wh-badge__pulse::after {
	content: "";
	position: absolute;
	inset: -4px;
	border-radius: 50%;
	border: 1px solid var(--wh-lime);
	animation: wh-ping 2.4s var(--wh-ease-out) infinite;
}

@keyframes wh-ping {
	0%   { transform: scale(.6); opacity: .9; }
	80%, 100% { transform: scale(1.9); opacity: 0; }
}

.wh-rule {
	display: block;
	width: 8rem;
	height: 2px;
	margin-top: 1.75rem;
	border-radius: 2px;
	background: var(--wh-grad-brand);
	box-shadow: var(--wh-glow-primary);
}

.wh-pills { display: flex; flex-wrap: wrap; gap: .4rem; margin: 0; padding: 0; list-style: none; }

.wh-pill {
	padding: .28rem .7rem;
	border: 1px solid rgba(var(--wh-sky-rgb) / .2);
	border-radius: var(--wh-radius-pill);
	background: rgba(var(--wh-sky-rgb) / .07);
	font-family: var(--wh-font-mono);
	font-size: var(--wh-fs-xs);
	color: var(--wh-muted);
}

/* Las etiquetas del articulo son un <li class="wh-pill"> con el enlace dentro.
   El enlace ocupaba SOLO el texto, asi que pulsar el borde de la pastilla —que
   es lo que se ve y donde la gente apunta— no hacia nada. Se estira el enlace
   hasta llenarla: los margenes negativos cancelan el relleno del <li> y el
   relleno propio del enlace lo devuelve, de modo que se ve exactamente igual
   pero ya responde entero. */
.wh-pill > a {
	display: block;
	margin: -.28rem -.7rem;
	padding: .28rem .7rem;
	color: inherit;
	text-decoration: none;
}
.wh-pills--sm .wh-pill { font-size: var(--wh-fs-xs); padding: .22rem .6rem; }

.wh-chip {
	display: inline-flex;
	align-items: center;
	gap: .55rem;
	padding: .6rem 1.1rem;
	border: 1px solid rgba(var(--wh-sky-rgb) / .18);
	border-radius: var(--wh-radius-pill);
	background: rgba(var(--wh-surface-rgb) / .55);
	white-space: nowrap;
	transition: border-color var(--wh-dur-fast) var(--wh-ease), color var(--wh-dur-fast) var(--wh-ease);
}
.wh-chip:hover { border-color: var(--wh-primary); color: var(--wh-sky); }
.wh-chip__icon { color: var(--wh-sky); }
.wh-chip__label { font-size: var(--wh-fs-sm); }

/* Conmutador claro / oscuro.
   El boton contiene los dos iconos a la vez y se oculta el que no toca. Hacerlo
   con CSS y no con JavaScript evita que el icono equivocado parpadee mientras
   carga la pagina. */
.wh-scheme-toggle { position: relative; overflow: hidden; }
.wh-scheme-toggle__sun,
.wh-scheme-toggle__moon {
	display: grid;
	place-items: center;
	transition: transform var(--wh-dur) var(--wh-ease-out), opacity var(--wh-dur-fast) var(--wh-ease);
}
.wh-scheme-toggle__sun { position: absolute; inset: 0; }

/* De origen el sitio es oscuro: se ofrece pasar a claro, asi que se ve el sol. */
.wh-scheme-toggle__moon { opacity: 0; transform: rotate(-90deg) scale(.6); }
.wh-scheme-toggle__sun  { opacity: 1; transform: none; }

/* Con el tema claro activo se ofrece volver a oscuro: se ve la luna. */
:root[data-wh-scheme="light"] .wh-scheme-toggle__sun  { opacity: 0; transform: rotate(90deg) scale(.6); }
:root[data-wh-scheme="light"] .wh-scheme-toggle__moon { opacity: 1; transform: none; }

.wh-social { display: flex; gap: .45rem; margin: 0; padding: 0; list-style: none; }
.wh-social a {
	display: grid;
	place-items: center;
	width: 2.35rem;
	height: 2.35rem;
	border: 1px solid rgba(var(--wh-sky-rgb) / .18);
	border-radius: var(--wh-radius-sm);
	color: var(--wh-muted);
	transition: color var(--wh-dur-fast) var(--wh-ease), border-color var(--wh-dur-fast) var(--wh-ease), transform var(--wh-dur-fast) var(--wh-ease);
}
.wh-social a:hover { color: var(--wh-primary); border-color: var(--wh-primary); transform: translateY(-2px); }
.wh-social--sm a { width: 1.9rem; height: 1.9rem; }

.wh-checks { display: grid; gap: .7rem; margin: 1.5rem 0 0; padding: 0; list-style: none; }
.wh-checks__item { display: flex; align-items: flex-start; gap: .7rem; }
.wh-checks__icon {
	display: grid;
	place-items: center;
	flex: none;
	width: 1.4rem;
	height: 1.4rem;
	margin-top: .18rem;
	border-radius: 50%;
	background: rgba(var(--wh-lime-rgb) / .16);
	color: var(--wh-lime);
}

/* ============================================================
   3. Barra superior y navegacion
   ============================================================ */

/* ---- Cromo de marca ----------------------------------------------
   Cabecera y pie en crema, contenido en oscuro. El logotipo es navy sobre
   blanco, asi que solo se lee bien sobre claro; y el contraste entre el cromo
   claro y el cuerpo oscuro le da al sitio su sello. Todo el texto del cromo
   hereda --wh-on-chrome, que es la tinta exacta del logotipo. */

.wh-topbar {
	position: relative;
	z-index: 61;
	border-bottom: 1px solid rgba(var(--wh-on-chrome-rgb) / .1);
	background: var(--wh-topbar);
	font-size: var(--wh-fs-xs);
	color: rgba(var(--wh-on-chrome-rgb) / .82);
}
.wh-topbar a { color: inherit; font-weight: 500; }
.wh-topbar a:hover { color: var(--wh-primary-deep); }
.wh-topbar svg { color: var(--wh-primary-deep); }

/* Navegacion sobre crema */
.wh-header .wh-menu a { color: rgba(var(--wh-on-chrome-rgb) / .78); }
.wh-header .wh-menu a:hover,
.wh-header .wh-menu .current-menu-item > a,
.wh-header .wh-menu .current-menu-ancestor > a {
	color: var(--wh-on-chrome);
	background: rgba(var(--wh-on-chrome-rgb) / .06);
}
.wh-header .wh-brand__text { color: var(--wh-on-chrome); }

/* Colocación fina del logotipo, en píxeles, desde
   Personalizador → Cabecera → «Mover el logo».

   Se usa `translate` y no márgenes a propósito: `translate` mueve lo que se
   PINTA sin cambiar el hueco que el elemento ocupa, así que empujar el logo
   tres píxeles no desplaza el menú ni el botón de al lado. Con márgenes, sí.

   Sirve para el ajuste óptico: un logotipo con más aire por un lado que por
   otro queda descentrado aunque su caja esté perfectamente centrada. */
.wh-header .wh-brand__link {
	transform: translate(var(--wh-logo-x, 0px), var(--wh-logo-y, 0px));
}
.wh-header .wh-iconbtn {
	border-color: rgba(var(--wh-on-chrome-rgb) / .18);
	color: var(--wh-on-chrome);
}
.wh-header .wh-iconbtn:hover {
	border-color: var(--wh-primary-deep);
	background: rgba(var(--wh-primary-rgb) / .1);
}
.wh-header .wh-burger { color: var(--wh-on-chrome); }

/* El boton principal usa el cobalto profundo del logotipo, que es el que
   contrasta sobre crema; el cobalto aclarado esta pensado para fondo oscuro. */
.wh-header .wh-btn--primary {
	background: var(--wh-primary-deep);
	color: #FFF;
	box-shadow: 0 6px 18px rgba(var(--wh-primary-rgb) / .3);
}
.wh-header .wh-btn--primary:hover { background: var(--wh-ink); }

/* Los submenus caen sobre el contenido oscuro, no sobre el cromo. */
.wh-header .wh-menu .sub-menu {
	background: var(--wh-surface);
	border-color: rgba(var(--wh-sky-rgb) / .16);
}
.wh-header .wh-menu .sub-menu a { color: var(--wh-muted); }
.wh-header .wh-menu .sub-menu a:hover { color: var(--wh-text); background: rgba(var(--wh-sky-rgb) / .1); }
.wh-topbar__in { display: flex; align-items: center; justify-content: space-between; gap: 1rem; min-height: 2.4rem; flex-wrap: wrap; }
.wh-topbar__note { margin: 0; }
.wh-topbar__meta { display: flex; align-items: center; gap: 1.1rem; margin-inline-start: auto; }
.wh-topbar__item { display: inline-flex; align-items: center; gap: .4rem; transition: color var(--wh-dur-fast) var(--wh-ease); }
.wh-topbar__item:hover { color: var(--wh-sky); }

@media (max-width: 48rem) {
	.wh-topbar__note { display: none; }
	.wh-topbar__meta { margin-inline: auto; }
}

/* La tipografia, el tamano, el grosor, la caja, el espaciado entre letras y la
   separacion entre enlaces del menu se eligen en
   Personalizador → Cabecera. Aqui solo se usan las variables; los valores de
   fabrica reproducen exactamente lo que habia antes de existir esos ajustes. */
.wh-menu {
	display: flex;
	align-items: center;
	gap: var(--wh-menu-gap, .25rem);
	margin: 0;
	padding: 0;
	list-style: none;
	/* SALVAGUARDA contra el desbordamiento.
	   ------------------------------------
	   Con estos ajustes se puede elegir una letra de 22 px en negrita, en
	   mayusculas y con mucha separacion; en pantallas medianas el menu deja de
	   caber y empuja al resto de la cabecera, y la PAGINA ENTERA se desplaza en
	   horizontal (medido: 276 px a 1024 px de ancho).

	   Se protege dejando que el menu pase a otra linea. Y NO de las otras dos
	   formas que parecen razonables, porque las dos rompen algo:

	     * `overflow-x: auto` recorta los DESPLEGABLES. Un submenu esta
	       posicionado en absoluto y `overflow` crea un contexto de recorte:
	       el submenu se corta contra el borde del menu y no se ve.
	     * `min-width: 0` deja que el menu se encoja hasta CERO dentro de la
	       cabecera flexible. Pasó: el menu desaparecio entero del sitio en
	       produccion. Un ancho minimo de 0 no es un limite, es un permiso.

	   Envolver no recorta nada y no puede colapsar: la cabecera crece un poco
	   de alto y no se pierde ningun enlace. */
	flex-wrap: wrap;
}

.wh-menu > li { position: relative; }

.wh-menu a {
	display: inline-flex;
	align-items: center;
	gap: .3rem;
	padding: .55rem .8rem;
	border-radius: var(--wh-radius-sm);
	font-family: var(--wh-menu-font, var(--wh-font-body));
	font-size: var(--wh-menu-size, var(--wh-fs-sm));
	font-weight: var(--wh-menu-weight, 500);
	text-transform: var(--wh-menu-case, none);
	letter-spacing: var(--wh-menu-spacing, 0);
	color: var(--wh-muted);
	transition: color var(--wh-dur-fast) var(--wh-ease), background var(--wh-dur-fast) var(--wh-ease);
}
.wh-menu a:hover,
.wh-menu .current-menu-item > a,
.wh-menu .current-menu-ancestor > a { color: var(--wh-text); background: rgba(var(--wh-sky-rgb) / .08); }

/* Subrayado luminoso que crece desde el centro. */
.wh-menu > li > a::after {
	content: "";
	position: absolute;
	inset-inline: .8rem;
	bottom: .25rem;
	height: 2px;
	border-radius: 2px;
	background: var(--wh-grad-brand);
	transform: scaleX(0);
	transition: transform var(--wh-dur) var(--wh-ease-out);
}
.wh-menu > li:hover > a::after,
.wh-menu > .current-menu-item > a::after { transform: scaleX(1); }

.wh-menu__arrow { transition: transform var(--wh-dur-fast) var(--wh-ease); }
.wh-menu > li:hover .wh-menu__arrow { transform: rotate(180deg); }

/* Submenus */
.wh-menu .sub-menu {
	position: absolute;
	top: calc(100% + .5rem);
	inset-inline-start: 0;
	z-index: 20;
	display: grid;
	gap: .1rem;
	min-width: 15rem;
	margin: 0;
	padding: .5rem;
	list-style: none;
	border: var(--wh-hairline);
	border-radius: var(--wh-radius);
	background: var(--wh-surface);
	box-shadow: var(--wh-shadow-lg);
	opacity: 0;
	visibility: hidden;
	transform: translateY(-6px);
	transition: opacity var(--wh-dur-fast) var(--wh-ease), transform var(--wh-dur) var(--wh-ease-out), visibility var(--wh-dur-fast);
}
.wh-menu li:hover > .sub-menu,
.wh-menu li:focus-within > .sub-menu { opacity: 1; visibility: visible; transform: translateY(0); }
.wh-menu .sub-menu a { display: flex; width: 100%; }
.wh-menu .sub-menu .sub-menu { top: -.5rem; inset-inline-start: 100%; }

/* Panel movil */
.wh-drawer {
	position: fixed;
	inset: 0;
	z-index: 200;
	background: rgba(0 0 0 / .55);
	backdrop-filter: blur(3px);
	opacity: 0;
	transition: opacity var(--wh-dur) var(--wh-ease);
}
.wh-drawer[hidden] { display: none; }
.wh-drawer.is-open { opacity: 1; }

.wh-drawer__panel {
	position: absolute;
	inset-block: 0;
	inset-inline-end: 0;
	width: min(24rem, 92vw);
	display: flex;
	flex-direction: column;
	gap: 1.5rem;
	padding: 1.25rem;
	overflow-y: auto;
	background: var(--wh-surface);
	border-inline-start: var(--wh-hairline);
	transform: translateX(100%);
	transition: transform var(--wh-dur) var(--wh-ease-out);
}
.wh-drawer.is-open .wh-drawer__panel { transform: translateX(0); }

.wh-drawer__top { display: flex; align-items: center; justify-content: space-between; gap: 1rem; }

/* El logotipo del cajón, sobre su propio fondo claro.
   ---------------------------------------------------
   El logotipo es navy sobre transparente. El panel del cajón usa el color de
   superficie, que es azul muy oscuro: la palabra «HaT» quedaba navy sobre navy
   y **no se veía**. Se detectó mirando el menú en un teléfono real; en el
   escritorio no se abre este cajón, así que ninguna prueba de ancho lo pilla.
   Es la misma razón por la que la cabecera y el pie van en crema.

   El logotipo no se toca ni se recolora: se le pone debajo el fondo sobre el
   que está pensado. */
.wh-drawer__top .wh-brand__link {
	padding: .5rem .7rem;
	border-radius: var(--wh-radius);
	background: var(--wh-header, #F2ECE3);
}
.wh-drawer__menu { display: grid; gap: .2rem; margin: 0; padding: 0; list-style: none; }
.wh-drawer__menu a {
	display: block;
	padding: .8rem .6rem;
	border-radius: var(--wh-radius-sm);
	border-bottom: 1px solid rgba(var(--wh-line-rgb) / .35);
	font-family: var(--wh-font-display);
	font-size: var(--wh-fs-lg);
	font-weight: 600;
}
.wh-drawer__menu a:hover { background: rgba(var(--wh-sky-rgb) / .08); }
.wh-drawer__menu .sub-menu { padding-inline-start: .9rem; list-style: none; }
.wh-drawer__menu .sub-menu a { font-size: var(--wh-fs-md); font-weight: 500; color: var(--wh-muted); }
.wh-drawer__foot { margin-top: auto; display: grid; gap: 1rem; justify-items: start; }

/* Capa de busqueda */
.wh-searchlayer {
	position: fixed;
	inset: 0;
	z-index: 210;
	display: grid;
	place-items: center;
	padding: var(--wh-gutter);
	background: rgba(var(--wh-base-rgb) / .92);
	backdrop-filter: blur(10px);
	opacity: 0;
	transition: opacity var(--wh-dur) var(--wh-ease);
}
.wh-searchlayer[hidden] { display: none; }
.wh-searchlayer.is-open { opacity: 1; }
.wh-searchlayer__panel { position: relative; width: min(42rem, 100%); }
.wh-searchlayer__close { position: absolute; top: -3.5rem; inset-inline-end: 0; }

/* ============================================================
   4. Buscador
   ============================================================ */

.wh-search { position: relative; display: flex; align-items: center; }
.wh-search__icon {
	position: absolute;
	inset-inline-start: 1rem;
	display: grid;
	place-items: center;
	color: var(--wh-muted);
	pointer-events: none;
}
.wh-search__input {
	width: 100%;
	padding: .95rem 6.5rem .95rem 3rem;
	border: 1px solid rgba(var(--wh-sky-rgb) / .2);
	border-radius: var(--wh-radius-pill);
	background: rgba(var(--wh-surface-rgb) / .7);
	transition: border-color var(--wh-dur-fast) var(--wh-ease), box-shadow var(--wh-dur) var(--wh-ease);
}
.wh-search__input:focus { outline: none; border-color: var(--wh-primary); box-shadow: var(--wh-glow-primary); }
.wh-search__go {
	position: absolute;
	inset-inline-end: .4rem;
	padding: .55rem 1.1rem;
	border: 0;
	border-radius: var(--wh-radius-pill);
	background: var(--wh-primary);
	color: var(--wh-on-primary);
	font-size: var(--wh-fs-xs);
	font-weight: 600;
	cursor: pointer;
}

/* ============================================================
   5. Hero: efectos y panel lateral
   ============================================================ */

.wh-hero__fx { position: absolute; inset: 0; z-index: 1; overflow: hidden; }
.wh-hero__fx span { position: absolute; display: block; }

.wh-hero--fx-beams .wh-hero__fx-a,
.wh-hero--fx-beams .wh-hero__fx-b {
	width: 60vw;
	height: 140%;
	top: -20%;
	background: linear-gradient(180deg, transparent, rgba(var(--wh-primary-rgb) / .16), transparent);
	filter: blur(60px);
	transform: rotate(18deg);
}
.wh-hero--fx-beams .wh-hero__fx-a { inset-inline-start: -12vw; }
.wh-hero--fx-beams .wh-hero__fx-b {
	inset-inline-end: -18vw;
	background: linear-gradient(180deg, transparent, rgba(var(--wh-lime-rgb) / .1), transparent);
	transform: rotate(-14deg);
}

.wh-hero--fx-grid .wh-hero__fx-a {
	inset: auto 0 0;
	height: 62%;
	background-image:
		linear-gradient(rgba(var(--wh-sky-rgb) / .12) 1px, transparent 1px),
		linear-gradient(90deg, rgba(var(--wh-sky-rgb) / .12) 1px, transparent 1px);
	background-size: 56px 56px;
	/* La rejilla se tumba en perspectiva y se pierde en el horizonte. */
	transform: perspective(340px) rotateX(58deg);
	transform-origin: bottom;
	mask-image: linear-gradient(180deg, transparent, #000 60%);
}

.wh-hero--fx-orbs .wh-hero__fx-a,
.wh-hero--fx-orbs .wh-hero__fx-b,
.wh-hero--fx-orbs .wh-hero__fx-c {
	border-radius: 50%;
	filter: blur(80px);
	animation: wh-drift 22s var(--wh-ease) infinite alternate;
}
.wh-hero--fx-orbs .wh-hero__fx-a { width: 34vw; aspect-ratio: 1; top: -8%; inset-inline-start: 4%; background: radial-gradient(circle, rgba(var(--wh-primary-rgb) / .5), transparent 70%); }
.wh-hero--fx-orbs .wh-hero__fx-b { width: 28vw; aspect-ratio: 1; bottom: -6%; inset-inline-end: 8%; background: radial-gradient(circle, rgba(var(--wh-lime-rgb) / .3), transparent 70%); animation-delay: -7s; }
.wh-hero--fx-orbs .wh-hero__fx-c { width: 22vw; aspect-ratio: 1; top: 32%; inset-inline-end: 30%; background: radial-gradient(circle, rgba(var(--wh-gold-rgb) / .24), transparent 70%); animation-delay: -14s; }

@keyframes wh-drift {
	from { transform: translate3d(0, 0, 0) scale(1); }
	to   { transform: translate3d(4%, -6%, 0) scale(1.14); }
}

.wh-hero--fx-scan .wh-hero__fx-a {
	inset-inline: 0;
	height: 2px;
	background: linear-gradient(90deg, transparent, var(--wh-lime), transparent);
	opacity: .5;
	animation: wh-scan 6s linear infinite;
}

@keyframes wh-scan {
	from { top: -2%; }
	to   { top: 102%; }
}

.wh-hero__acts { display: flex; flex-wrap: wrap; gap: .75rem; margin-top: 2rem; }

.wh-hero__proof {
	display: flex;
	flex-wrap: wrap;
	gap: .5rem 1.4rem;
	margin: 1.75rem 0 0;
	padding: 0;
	list-style: none;
	font-size: var(--wh-fs-sm);
	color: var(--wh-muted);
}
.wh-hero__proof li { display: inline-flex; align-items: center; gap: .45rem; }
.wh-hero__proof svg { color: var(--wh-lime); }

.wh-hero__hint {
	position: absolute;
	bottom: 2rem;
	inset-inline: 0;
	z-index: 3;
	display: grid;
	place-items: center;
}
.wh-hero__hint-rail {
	display: grid;
	justify-items: center;
	width: 1.5rem;
	height: 2.4rem;
	padding-top: .45rem;
	border: 1px solid rgba(var(--wh-sky-rgb) / .35);
	border-radius: var(--wh-radius-pill);
}
.wh-hero__hint-dot {
	width: 4px;
	height: 7px;
	border-radius: 2px;
	background: var(--wh-lime);
	animation: wh-hint 1.9s var(--wh-ease) infinite;
}

@keyframes wh-hint {
	0%, 100% { transform: translateY(0); opacity: 1; }
	60%      { transform: translateY(9px); opacity: .2; }
}

.wh-hero__figure { position: relative; margin: 0; }
.wh-hero__figure img { width: 100%; border-radius: var(--wh-radius-lg); border: var(--wh-hairline); }
.wh-hero__figure-glow,
.wh-figure__glow {
	position: absolute;
	inset: -12%;
	z-index: -1;
	border-radius: 50%;
	background: radial-gradient(circle, rgba(var(--wh-primary-rgb) / .3), transparent 66%);
	filter: blur(56px);
}

/* Panel de metricas */
.wh-statpanel {
	position: relative;
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: 1px;
	padding: 1px;
	border-radius: var(--wh-radius-lg);
	background: rgba(var(--wh-line-rgb) / .5);
	overflow: hidden;
	box-shadow: var(--wh-shadow-lg);
}
.wh-statpanel__cell {
	display: grid;
	gap: .35rem;
	padding: clamp(1.2rem, 3vw, 2rem);
	background: var(--wh-surface);
}
.wh-statpanel__value {
	font-family: var(--wh-font-display);
	font-size: var(--wh-fs-3xl);
	font-weight: 700;
	line-height: 1;
	letter-spacing: -0.03em;
	background: var(--wh-grad-brand);
	-webkit-background-clip: text;
	background-clip: text;
	-webkit-text-fill-color: transparent;
}
.wh-statpanel__label { font-size: var(--wh-fs-sm); color: var(--wh-muted); }
.wh-statpanel__glow {
	position: absolute;
	inset: -30% -10% auto;
	height: 60%;
	background: radial-gradient(ellipse at top, rgba(var(--wh-primary-rgb) / .22), transparent 70%);
	pointer-events: none;
}

/* Orbita de tecnologias.
   El conjunto gira y cada nodo se contrarrota a la misma velocidad, de modo que
   las etiquetas siempre se leen en horizontal. Girar el contenedor y no cada
   nodo por separado mantiene la animacion en una sola capa compuesta. */
.wh-orbit {
	position: relative;
	display: grid;
	place-items: center;
	aspect-ratio: 1;
	max-width: 32rem;
	margin-inline: auto;
}

.wh-orbit__core {
	display: grid;
	place-items: center;
	width: 6rem;
	height: 6rem;
	border: 1px solid rgba(var(--wh-lime-rgb) / .35);
	border-radius: 50%;
	background: var(--wh-surface);
	color: var(--wh-lime);
	box-shadow: var(--wh-glow-primary);
	animation: wh-core-pulse 3.4s var(--wh-ease) infinite;
}

@keyframes wh-core-pulse {
	0%, 100% { box-shadow: 0 0 0 0 rgba(var(--wh-lime-rgb) / .28), var(--wh-glow-primary); }
	60%      { box-shadow: 0 0 0 22px rgba(var(--wh-lime-rgb) / 0), var(--wh-glow-primary); }
}

.wh-orbit__ring {
	position: absolute;
	border: 1px dashed rgba(var(--wh-sky-rgb) / .18);
	border-radius: 50%;
}
.wh-orbit__ring--1 { inset: 20%; }
.wh-orbit__ring--2 { inset: 2%; }

/* Barrido de radar: da sensacion de sistema vivo sin animar cada nodo. */
.wh-orbit__sweep {
	position: absolute;
	inset: 2%;
	border-radius: 50%;
	background: conic-gradient(from 0deg, transparent 0deg, rgba(var(--wh-primary-rgb) / .18) 26deg, transparent 60deg);
	animation: wh-spin 6s linear infinite;
	pointer-events: none;
}

.wh-orbit__belt {
	position: absolute;
	inset: 0;
	display: grid;
	place-items: center;
}
.wh-orbit--spin .wh-orbit__belt { animation: wh-spin var(--wh-orbit-dur, 48s) linear infinite; }

@keyframes wh-spin {
	from { transform: rotate(0deg); }
	to   { transform: rotate(360deg); }
}

/* El contragiro tiene que arrancar desde el angulo propio del nodo, no desde
   cero: una animacion sustituye por completo al transform estatico, asi que si
   empezara en 0 se perderia la compensacion y las etiquetas saldrian giradas. */
@keyframes wh-spin-back {
	from { transform: rotate(calc(-360deg / var(--wh-orbit-n) * var(--wh-i))); }
	to   { transform: rotate(calc(-360deg / var(--wh-orbit-n) * var(--wh-i) - 360deg)); }
}

.wh-orbit__node {
	position: absolute;
	/* Angulo del nodo + radio. El giro del cinturon lo aporta el contenedor. */
	transform:
		rotate(calc(360deg / var(--wh-orbit-n) * var(--wh-i)))
		translateX(clamp(7.5rem, 21vw, 12.5rem));
	animation: wh-orbit-in .6s var(--wh-ease-out) backwards;
	animation-delay: calc(var(--wh-i) * 90ms);
}

.wh-orbit__inner {
	display: inline-flex;
	align-items: center;
	gap: .45rem;
	padding: .45rem .85rem;
	border: 1px solid rgba(var(--wh-sky-rgb) / .22);
	border-radius: var(--wh-radius-pill);
	background: rgba(var(--wh-surface-rgb) / .92);
	backdrop-filter: blur(6px);
	font-size: var(--wh-fs-xs);
	white-space: nowrap;
	color: var(--wh-muted);
	/* Contrarrotacion: anula el angulo propio y el del cinturon. */
	transform: rotate(calc(-360deg / var(--wh-orbit-n) * var(--wh-i)));
	transition: border-color var(--wh-dur-fast) var(--wh-ease),
	            color var(--wh-dur-fast) var(--wh-ease),
	            box-shadow var(--wh-dur) var(--wh-ease);
}
.wh-orbit--spin .wh-orbit__inner {
	animation: wh-spin-back var(--wh-orbit-dur, 48s) linear infinite;
}

.wh-orbit__inner svg { color: var(--wh-sky); flex: none; }

/* Los nodos con enlace se anuncian como pulsables. */
.wh-orbit__node--link { cursor: pointer; }
.wh-orbit__node--link .wh-orbit__inner { border-color: rgba(var(--wh-primary-rgb) / .4); }
.wh-orbit__node--link:hover .wh-orbit__inner,
.wh-orbit__node--link:focus-visible .wh-orbit__inner {
	border-color: var(--wh-lime);
	color: var(--wh-text);
	box-shadow: var(--wh-glow-lime);
}
.wh-orbit__node--link:hover .wh-orbit__inner svg { color: var(--wh-lime); }

/* Al posarse sobre la orbita, todo se detiene para poder pulsar sin perseguir
   un objetivo en movimiento. */
.wh-orbit:hover .wh-orbit__belt,
.wh-orbit:hover .wh-orbit__inner,
.wh-orbit:focus-within .wh-orbit__belt,
.wh-orbit:focus-within .wh-orbit__inner,
.wh-orbit:hover .wh-orbit__sweep { animation-play-state: paused; }

@keyframes wh-orbit-in {
	from { opacity: 0; }
	to   { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
	.wh-orbit__belt,
	.wh-orbit__inner,
	.wh-orbit__sweep,
	.wh-orbit__core { animation: none !important; }
}

@media (max-width: 46rem) {
	/* Sin espacio para una orbita, los nodos pasan a ser una lista de accesos
	   directos: el mismo contenido, utilizable con el pulgar.

	   Los selectores repiten la clase del contenedor a proposito. Una consulta
	   de medios no anade especificidad, y las reglas del giro estan escritas
	   como `.wh-orbit--spin .wh-orbit__belt`, que pesa mas que `.wh-orbit__belt`
	   a secas: sin igualar ese peso, en el telefono seguian girando los nodos y
	   se amontonaban unos sobre otros. */
	.wh-orbit,
	.wh-orbit--spin {
		display: flex;
		flex-wrap: wrap;
		justify-content: center;
		gap: .5rem;
		aspect-ratio: auto;
		max-width: 100%;
	}

	.wh-orbit .wh-orbit__core,
	.wh-orbit .wh-orbit__ring,
	.wh-orbit .wh-orbit__sweep { display: none; }

	.wh-orbit .wh-orbit__belt,
	.wh-orbit--spin .wh-orbit__belt {
		position: static;
		display: contents;
		animation: none;
	}

	.wh-orbit .wh-orbit__node,
	.wh-orbit--spin .wh-orbit__node {
		position: static;
		transform: none;
		animation: none;
	}

	.wh-orbit .wh-orbit__inner,
	.wh-orbit--spin .wh-orbit__inner {
		transform: none;
		animation: none;
	}
}

/* Con movimiento reducido, la cinta deja de desplazarse. La segunda copia solo
   existe para que el bucle no muestre un hueco al reiniciarse, asi que sin
   movimiento sobra: mostrarla duplicaria toda la lista en pantalla. */
@media (prefers-reduced-motion: reduce) {
	.wh-marquee__set[aria-hidden="true"] { display: none; }
}

/* ============================================================
   6. Encabezados de seccion
   ============================================================ */

.wh-sechead { max-width: var(--wh-head-max, 62ch); margin-bottom: clamp(2rem, 4vw, 3.25rem); }
.wh-sechead--center { margin-inline: auto; text-align: center; }
.wh-sechead__title { font-size: var(--wh-fs-3xl); }
.wh-sechead__sub { margin-top: 1rem; font-size: var(--wh-fs-lg); color: var(--wh-muted); }

/* ============================================================
   7. Tarjetas de servicio
   ============================================================ */

.wh-scard {
	position: relative;
	display: grid;
	align-content: start;
	gap: .8rem;
	padding: clamp(1.4rem, 3vw, 2.1rem);
	border: var(--wh-hairline);
	border-radius: var(--wh-radius-lg);
	background: var(--wh-surface);
	overflow: hidden;
	transition: transform var(--wh-dur) var(--wh-ease-out),
	            border-color var(--wh-dur) var(--wh-ease),
	            box-shadow var(--wh-dur) var(--wh-ease);
}

.wh-grid--glass .wh-scard { background: rgba(var(--wh-surface-rgb) / .58); backdrop-filter: blur(10px); }
.wh-grid--bare  .wh-scard { background: none; border-color: transparent; padding-inline: 0; }
.wh-grid--stroke .wh-scard { background: none; }

.wh-scard--wide { grid-column: span 2; }
@media (max-width: 61.99rem) { .wh-scard--wide { grid-column: span 1; } }

.wh-scard__hit { position: absolute; inset: 0; z-index: 3; }

.wh-scard__num {
	position: absolute;
	top: 1rem;
	inset-inline-end: 1.2rem;
	font-family: var(--wh-font-mono);
	font-size: var(--wh-fs-2xl);
	font-weight: 500;
	color: rgba(var(--wh-sky-rgb) / .16);
	line-height: 1;
}

.wh-scard__icon {
	display: grid;
	place-items: center;
	width: 3.1rem;
	height: 3.1rem;
	border: 1px solid rgba(var(--wh-sky-rgb) / .2);
	border-radius: var(--wh-radius);
	background: rgba(var(--wh-sky-rgb) / .08);
	transition: transform var(--wh-dur) var(--wh-ease-out), background var(--wh-dur) var(--wh-ease);
}

/* Variante con el logotipo real de la aplicación en vez del icono dibujado.
   Se quitan el borde y el fondo: el icono de una app ya trae los suyos, y
   dejarlos pone un recuadro dentro de otro. `object-fit: contain` garantiza que
   el logo entre entero, sin recortarse ni deformarse, sea cual sea su
   proporción. */
.wh-scard__icon--img {
	width: 3.4rem;
	height: 3.4rem;
	border: 0;
	background: none;
	overflow: hidden;
	border-radius: var(--wh-radius);
}
.wh-scard__icon--img img {
	width: 100%;
	height: 100%;
	object-fit: contain;
	border-radius: inherit;
}

.wh-scard--primary .wh-scard__icon { color: var(--wh-primary); }
.wh-scard--sky     .wh-scard__icon { color: var(--wh-sky); }
.wh-scard--lime    .wh-scard__icon { color: var(--wh-lime); }
.wh-scard--gold    .wh-scard__icon { color: var(--wh-gold); }

.wh-scard__title { font-size: var(--wh-fs-lg); }
.wh-scard__text  { color: var(--wh-muted); font-size: var(--wh-fs-sm); }

.wh-scard__more {
	display: inline-flex;
	align-items: center;
	gap: .4rem;
	margin-top: .3rem;
	font-size: var(--wh-fs-sm);
	font-weight: 600;
	color: var(--wh-primary);
	transition: gap var(--wh-dur-fast) var(--wh-ease);
}

/* Foco que sigue al cursor. La posicion la escribe el JavaScript en las
   variables --wh-mx y --wh-my. */
.wh-scard__spot {
	position: absolute;
	inset: 0;
	z-index: 1;
	opacity: 0;
	background: radial-gradient(24rem circle at var(--wh-mx, 50%) var(--wh-my, 50%), rgba(var(--wh-primary-rgb) / .16), transparent 42%);
	transition: opacity var(--wh-dur) var(--wh-ease);
	pointer-events: none;
}
.wh-hover-spot .wh-scard:hover .wh-scard__spot { opacity: 1; }

.wh-hover-spot .wh-scard:hover,
.wh-hover-lift .wh-scard:hover {
	transform: translateY(-5px);
	border-color: rgba(var(--wh-primary-rgb) / .5);
	box-shadow: var(--wh-shadow-lg);
}
.wh-scard:hover .wh-scard__icon { transform: translateY(-2px) scale(1.05); }
.wh-scard:hover .wh-scard__more { gap: .7rem; }

.wh-hover-tilt .wh-scard { transform-style: preserve-3d; }
.wh-hover-tilt .wh-scard:hover {
	transform: perspective(900px) rotateX(var(--wh-rx, 0deg)) rotateY(var(--wh-ry, 0deg)) translateZ(6px);
	border-color: rgba(var(--wh-primary-rgb) / .5);
	box-shadow: var(--wh-shadow-lg);
}

/* ============================================================
   8. Beneficios
   ============================================================ */

.wh-feat { display: grid; gap: .7rem; align-content: start; }
.wh-feats--side .wh-feat { grid-template-columns: auto 1fr; align-items: start; }
.wh-feats--divided .wh-feat { padding-inline: clamp(0rem, 2vw, 1.5rem); }
.wh-feats--divided .wh-feat + .wh-feat { border-inline-start: 1px solid rgba(var(--wh-line-rgb) / .5); }

@media (max-width: 61.99rem) {
	.wh-feats--divided .wh-feat + .wh-feat { border-inline-start: 0; }
}

.wh-feat__icon {
	display: grid;
	place-items: center;
	width: 2.7rem;
	height: 2.7rem;
	border-radius: var(--wh-radius);
	background: rgba(var(--wh-primary-rgb) / .12);
	color: var(--wh-primary);
}
.wh-feat__title { font-size: var(--wh-fs-lg); }
.wh-feat__text  { color: var(--wh-muted); font-size: var(--wh-fs-sm); }

.wh-feats--plain .wh-feat__icon { width: 1.5rem; height: 1.5rem; background: none; color: var(--wh-lime); }

/* ============================================================
   9. Contadores
   ============================================================ */

.wh-counters--band {
	gap: 1px;
	padding: 1px;
	border-radius: var(--wh-radius-lg);
	background: rgba(var(--wh-line-rgb) / .5);
	overflow: hidden;
}
.wh-counters--band .wh-counter { padding: clamp(1.4rem, 3vw, 2.4rem); background: var(--wh-surface); }

.wh-counters--cards .wh-counter {
	padding: clamp(1.4rem, 3vw, 2.2rem);
	border: var(--wh-hairline);
	border-radius: var(--wh-radius-lg);
	background: var(--wh-surface);
}

.wh-counter { display: grid; gap: .4rem; justify-items: center; text-align: center; }
.wh-counter__icon { color: var(--wh-sky); }
.wh-counter__value {
	display: inline-flex;
	align-items: baseline;
	gap: .1rem;
	font-family: var(--wh-font-display);
	font-size: var(--wh-fs-4xl);
	font-weight: 700;
	line-height: 1;
	letter-spacing: -0.035em;
	font-variant-numeric: tabular-nums;
}
.wh-counters--grad .wh-counter__value {
	background: var(--wh-grad-brand);
	-webkit-background-clip: text;
	background-clip: text;
	-webkit-text-fill-color: transparent;
}
.wh-counter__label { font-size: var(--wh-fs-sm); color: var(--wh-muted); }

/* ============================================================
   10. Terminal
   ============================================================ */

.wh-term {
	position: relative;
	border: 1px solid rgba(var(--wh-sky-rgb) / .22);
	border-radius: var(--wh-radius);
	background: rgba(var(--wh-base-rgb) / .92);
	overflow: hidden;
}
.wh-term--glow { box-shadow: var(--wh-glow-primary), var(--wh-shadow-lg); }

.wh-term__bar {
	display: flex;
	align-items: center;
	gap: .8rem;
	padding: .6rem 1rem;
	border-bottom: 1px solid rgba(var(--wh-line-rgb) / .6);
	background: rgba(var(--wh-surface-rgb) / .8);
}
.wh-term__dots { display: flex; gap: .38rem; }
.wh-term__dots i { width: 11px; height: 11px; border-radius: 50%; background: rgba(var(--wh-sky-rgb) / .3); }
.wh-term__dots i:first-child { background: rgba(232 136 120 / .8); }
.wh-term__dots i:nth-child(2) { background: rgba(var(--wh-gold-rgb) / .8); }
.wh-term__dots i:last-child   { background: rgba(var(--wh-lime-rgb) / .7); }
.wh-term__title { font-family: var(--wh-font-mono); font-size: var(--wh-fs-xs); color: var(--wh-muted); }

.wh-term__body {
	margin: 0;
	padding: 1.2rem 1.3rem 1.6rem;
	font-family: var(--wh-font-mono);
	font-size: var(--wh-fs-sm);
	line-height: 1.85;
	overflow-x: auto;
	white-space: pre-wrap;
	word-break: break-word;
}
.wh-term__line { display: block; }
.wh-term__prompt { color: var(--wh-lime); font-weight: 600; }
.wh-term__line--cmd     { color: var(--wh-text); }
.wh-term__line--out     { color: var(--wh-muted); }
.wh-term__line--ok      { color: var(--wh-lime); }
.wh-term__line--warn    { color: var(--wh-gold); }
.wh-term__line--err     { color: #F08878; }
.wh-term__line--comment { color: rgba(var(--wh-sky-rgb) / .55); font-style: italic; }

.wh-term__caret {
	display: inline-block;
	width: .55em;
	height: 1.05em;
	vertical-align: text-bottom;
	background: var(--wh-lime);
	animation: wh-blink 1.1s steps(2, start) infinite;
}

@keyframes wh-blink { 50% { opacity: 0; } }

/* Mientras la consola se escribe sola, las lineas pendientes se ocultan. */
.wh-term[data-wh-term] .wh-term__line.is-pending { visibility: hidden; }

/* ============================================================
   11. Cinta deslizante
   ============================================================ */

.wh-marquee {
	position: relative;
	overflow: hidden;
	/* Los extremos se difuminan para que las pastillas no se corten en seco. */
	mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}
.wh-marquee__track { display: flex; width: max-content; animation: wh-marquee var(--wh-marquee-dur, 34s) linear infinite; }
.wh-marquee--rev .wh-marquee__track { animation-direction: reverse; }
.wh-marquee:hover .wh-marquee__track { animation-play-state: paused; }
.wh-marquee__set { display: flex; gap: .75rem; padding-inline-end: .75rem; }

@keyframes wh-marquee {
	from { transform: translateX(0); }
	to   { transform: translateX(-50%); }
}

@media (prefers-reduced-motion: reduce) {
	.wh-marquee__track { animation: none; flex-wrap: wrap; width: 100%; }
	.wh-marquee { mask-image: none; }
}

.wh-stack--inline { display: flex; flex-wrap: wrap; gap: .6rem; }

/* ============================================================
   12. Proceso por pasos
   ============================================================ */

.wh-steps { position: relative; margin: 0; padding: 0; list-style: none; }

.wh-steps--vertical,
.wh-steps--zigzag { display: grid; gap: clamp(1.5rem, 3vw, 2.5rem); }

.wh-step { position: relative; display: grid; grid-template-columns: auto 1fr; gap: 1.2rem; align-items: start; }

.wh-step__marker {
	display: grid;
	place-items: center;
	width: 3rem;
	height: 3rem;
	border: 1px solid rgba(var(--wh-sky-rgb) / .28);
	border-radius: 50%;
	background: var(--wh-surface);
	color: var(--wh-sky);
	z-index: 2;
}
.wh-step__n { font-family: var(--wh-font-mono); font-size: var(--wh-fs-sm); font-weight: 600; }

.wh-step__top { display: flex; flex-wrap: wrap; align-items: baseline; gap: .5rem .9rem; }
.wh-step__title { font-size: var(--wh-fs-lg); }
.wh-step__meta {
	padding: .12rem .55rem;
	border-radius: var(--wh-radius-pill);
	background: rgba(var(--wh-lime-rgb) / .14);
	font-family: var(--wh-font-mono);
	font-size: var(--wh-fs-xs);
	color: var(--wh-lime);
}
.wh-step__text { margin-top: .5rem; color: var(--wh-muted); font-size: var(--wh-fs-sm); }

/* Carril que une los pasos y se rellena segun avanza el desplazamiento. */
.wh-steps__rail {
	position: absolute;
	inset-block: 1.5rem;
	inset-inline-start: 1.5rem;
	width: 2px;
	background: rgba(var(--wh-line-rgb) / .6);
	z-index: 1;
}
.wh-steps__fill {
	display: block;
	width: 100%;
	height: var(--wh-steps-progress, 0%);
	background: var(--wh-grad-brand);
	box-shadow: var(--wh-glow-primary);
	transition: height .18s linear;
}

.wh-steps--zigzag .wh-step:nth-child(even) { direction: rtl; }
.wh-steps--zigzag .wh-step:nth-child(even) > * { direction: ltr; }

.wh-steps--horizontal {
	display: grid;
	grid-auto-flow: column;
	grid-auto-columns: minmax(15rem, 1fr);
	gap: 1.5rem;
	overflow-x: auto;
	padding-bottom: 1rem;
	scroll-snap-type: x mandatory;
}
.wh-steps--horizontal .wh-step { grid-template-columns: 1fr; scroll-snap-align: start; }
.wh-steps--horizontal .wh-steps__rail {
	inset: 1.5rem 0 auto;
	width: auto;
	height: 2px;
}
.wh-steps--horizontal .wh-steps__fill { width: var(--wh-steps-progress, 0%); height: 100%; }

/* ============================================================
   13. Testimonios
   ============================================================ */

.wh-quotes-wrap { display: grid; gap: 1.5rem; }

.wh-quote {
	position: relative;
	display: grid;
	align-content: start;
	gap: .9rem;
	margin: 0;
	padding: clamp(1.4rem, 3vw, 2.1rem);
	border: var(--wh-hairline);
	border-radius: var(--wh-radius-lg);
	background: var(--wh-surface);
}
.wh-quote__mark { color: rgba(var(--wh-primary-rgb) / .35); }
.wh-quote__text { margin: 0; font-size: var(--wh-fs-md); line-height: 1.7; }
.wh-stars { display: flex; gap: .1rem; margin: 0; color: var(--wh-gold); }

.wh-quote__by { display: flex; align-items: center; gap: .75rem; margin-top: auto; padding-top: .5rem; }
.wh-quote__photo { width: 3rem; height: 3rem; border-radius: 50%; object-fit: cover; }
.wh-quote__initial {
	display: grid;
	place-items: center;
	width: 3rem;
	height: 3rem;
	border-radius: 50%;
	background: var(--wh-grad-brand);
	color: var(--wh-on-primary);
	font-family: var(--wh-font-display);
	font-weight: 700;
}
.wh-quote__who { display: grid; font-size: var(--wh-fs-sm); }
.wh-quote__who span { color: var(--wh-muted); font-size: var(--wh-fs-xs); }

/* El carrusel usa desplazamiento nativo con ajuste: funciona con rueda, dedo,
   teclado y barra de desplazamiento, sin ninguna libreria. */
.wh-quotes--carousel {
	display: grid;
	grid-auto-flow: column;
	grid-auto-columns: minmax(min(22rem, 84vw), 1fr);
	gap: 1.25rem;
	overflow-x: auto;
	scroll-snap-type: x mandatory;
	scrollbar-width: none;
	padding-bottom: .5rem;
}
.wh-quotes--carousel::-webkit-scrollbar { display: none; }
.wh-quotes--carousel > * { scroll-snap-align: start; }

@media (min-width: 62rem) {
	/* Ancho fijo, NO `minmax(0, ...)`. Con minimo 0 las columnas se encogen
	   hasta que caben todas, la tira deja de desbordar y el carrusel se queda
	   quieto aunque las flechas y los puntos respondan. Se detecto en el
	   carrusel de novedades, que copiaba esta misma regla. */
	.wh-quotes--carousel { grid-auto-columns: calc((100% - 2.5rem) / 3); }
}

.wh-quotes--masonry { display: block; columns: var(--wh-cols, 3); column-gap: 1.25rem; }
.wh-quotes--masonry .wh-quote { break-inside: avoid; margin-bottom: 1.25rem; }

.wh-carousel__nav { display: flex; align-items: center; justify-content: center; gap: 1rem; }
.wh-carousel__dots { display: flex; gap: .4rem; }
.wh-carousel__dots button {
	width: .55rem;
	height: .55rem;
	padding: 0;
	border: 0;
	border-radius: 50%;
	background: rgba(var(--wh-sky-rgb) / .3);
	cursor: pointer;
	transition: width var(--wh-dur) var(--wh-ease), background var(--wh-dur-fast) var(--wh-ease);
}
.wh-carousel__dots button[aria-current="true"] { width: 1.6rem; border-radius: var(--wh-radius-pill); background: var(--wh-primary); }

/* ------------------------------------------------------------
   Novedades de las aplicaciones (carrusel)
   ------------------------------------------------------------
   Misma mecanica que el de testimonios: desplazamiento nativo con puntos de
   ajuste. Funciona con el dedo, la rueda y el teclado aunque el JavaScript no
   llegue a ejecutarse; lo que aporta el JS son las flechas y los puntos. */

.wh-appnews { display: grid; gap: 1.5rem; }

.wh-appnews__track {
	display: grid;
	grid-auto-flow: column;
	/* Una tarjeta y un poco de la siguiente: es lo que le dice al visitante,
	   sin explicarselo, que la tira se puede mover. */
	grid-auto-columns: minmax(min(20rem, 78vw), 1fr);
	gap: 1.25rem;
	overflow-x: auto;
	scroll-snap-type: x mandatory;
	scrollbar-width: none;
	padding-bottom: .5rem;
}
.wh-appnews__track::-webkit-scrollbar { display: none; }
.wh-appnews__track > * { scroll-snap-align: start; }

@media (min-width: 62rem) {
	/* Tres tarjetas por pantalla, y las demas a la derecha esperando.
	   OJO: aqui NO puede ir `minmax(0, ...)`. Con minimo 0 las columnas se
	   encogen hasta que caben todas, la tira deja de ser mas ancha que su
	   contenedor y el carrusel se queda quieto: las flechas y los puntos
	   responden, pero no hay nada que desplazar. Con un ancho fijo, las que no
	   caben se salen y el desplazamiento funciona. */
	.wh-appnews__track { grid-auto-columns: calc((100% - 2.5rem) / 3); }
}

.wh-appnews__card {
	display: grid;
	align-content: start;
	gap: .65rem;
	padding: clamp(1.4rem, 3vw, 1.9rem);
	border: var(--wh-hairline);
	border-radius: var(--wh-radius-lg);
	background: var(--wh-surface);
	transition: border-color var(--wh-dur-fast) var(--wh-ease),
		transform var(--wh-dur-fast) var(--wh-ease);
}
.wh-appnews__card:hover {
	border-color: rgba(var(--wh-primary-rgb) / .45);
	transform: translateY(-2px);
}

.wh-appnews__icon {
	display: grid;
	place-items: center;
	width: 2.6rem;
	height: 2.6rem;
	border-radius: var(--wh-radius-sm);
	border: var(--wh-hairline);
	background: rgba(var(--wh-primary-rgb) / .12);
	color: var(--wh-primary);
}
.wh-appnews__app {
	margin: 0;
	font-family: var(--wh-font-mono);
	font-size: var(--wh-fs-xs);
	letter-spacing: .1em;
	text-transform: uppercase;
	color: var(--wh-sky);
}
.wh-appnews__title { margin: 0; font-size: var(--wh-fs-lg); line-height: 1.25; }
.wh-appnews__text { margin: 0; color: var(--wh-muted); font-size: var(--wh-fs-sm); line-height: 1.6; }

.wh-appnews__cta {
	display: inline-flex;
	align-items: center;
	gap: .4rem;
	margin-top: .35rem;
	color: var(--wh-sky);
	font-size: var(--wh-fs-sm);
	font-weight: 600;
	text-decoration: none;
	/* Alto suficiente para pulsarlo con el dedo sin apuntar. */
	min-height: 2.4rem;
}
.wh-appnews__cta:hover { color: var(--wh-primary); }

.wh-appnews__nav { display: flex; align-items: center; justify-content: center; gap: 1rem; }
.wh-appnews__dots { display: flex; }
/* El punto se ve pequeño pero se pulsa grande.
   El truco es `background-clip: content-box`: el botón mide 1,5 rem con su
   relleno —suficiente para el dedo— pero el color solo se pinta en la caja de
   contenido, así que a la vista sigue siendo un punto de 0,55 rem. Sin esto el
   destino táctil mide 9 px, que es la mitad de lo que se puede pulsar sin
   apuntar. */
.wh-appnews__dots button {
	box-sizing: content-box;
	width: .55rem;
	height: .55rem;
	/* .8rem arriba y abajo dejan el botón en unos 34 px de alto; con .5rem se
	   quedaba en 25 y no llegaba al mínimo. */
	padding: .8rem .3rem;
	border: 0;
	background: rgba(var(--wh-sky-rgb) / .3);
	background-clip: content-box;
	border-radius: 50%;
	cursor: pointer;
	transition: width var(--wh-dur) var(--wh-ease), background var(--wh-dur-fast) var(--wh-ease);
}
.wh-appnews__dots button[aria-current="true"] {
	width: 1.6rem;
	border-radius: var(--wh-radius-pill);
	background: var(--wh-primary);
	background-clip: content-box;
}
.wh-appnews__arrow {
	display: grid;
	place-items: center;
	width: 2.6rem;
	height: 2.6rem;
	border: var(--wh-hairline);
	border-radius: 50%;
	background: transparent;
	color: var(--wh-text);
	cursor: pointer;
	transition: border-color var(--wh-dur-fast) var(--wh-ease), color var(--wh-dur-fast) var(--wh-ease);
}
.wh-appnews__arrow:hover { border-color: var(--wh-primary); color: var(--wh-primary); }
/* El chevron del tema apunta hacia ABAJO. `wh-rot-90` lo gira -90 grados y
   queda apuntando a la derecha (es lo que usan las migas de pan). Para la
   izquierda hace falta el giro contrario. */
.wh-rot-270 { transform: rotate(90deg); }

/* ============================================================
   14. Planes
   ============================================================ */

.wh-plan {
	position: relative;
	display: grid;
	align-content: start;
	gap: 1rem;
	padding: clamp(1.5rem, 3vw, 2.2rem);
	border: var(--wh-hairline);
	border-radius: var(--wh-radius-lg);
	background: var(--wh-surface);
	overflow: hidden;
}
.wh-plan--hot { border-color: rgba(var(--wh-primary-rgb) / .55); box-shadow: var(--wh-glow-primary); }

.wh-plan__ribbon {
	position: absolute;
	top: 1.1rem;
	inset-inline-end: -2.6rem;
	margin: 0;
	padding: .3rem 3rem;
	background: var(--wh-grad-brand);
	color: var(--wh-on-primary);
	font-size: var(--wh-fs-xs);
	font-weight: 700;
	letter-spacing: .04em;
	transform: rotate(38deg);
}

.wh-plan__name { font-size: var(--wh-fs-xl); }
.wh-plan__tag  { color: var(--wh-muted); font-size: var(--wh-fs-sm); }

.wh-plan__price { display: flex; align-items: baseline; gap: .2rem; font-family: var(--wh-font-display); }
.wh-plan__cur    { font-size: var(--wh-fs-lg); color: var(--wh-muted); }
.wh-plan__amount { font-size: var(--wh-fs-4xl); font-weight: 700; letter-spacing: -0.035em; line-height: 1; }
.wh-plan__period { font-size: var(--wh-fs-sm); color: var(--wh-muted); }
.wh-plan__note   { margin-top: -.5rem; font-size: var(--wh-fs-xs); color: var(--wh-muted); }

.wh-plan__list { display: grid; gap: .6rem; margin: .5rem 0; padding: 0; list-style: none; }
.wh-plan__item { display: flex; align-items: flex-start; gap: .6rem; font-size: var(--wh-fs-sm); }
.wh-plan__item svg { margin-top: .28rem; color: var(--wh-lime); }
.wh-plan__item--off { color: var(--wh-muted); opacity: .62; }
.wh-plan__item--off svg { color: var(--wh-muted); }

.wh-plan .wh-btn { margin-top: auto; }
.wh-plan__glow {
	position: absolute;
	inset: auto -20% -40%;
	height: 55%;
	background: radial-gradient(ellipse at bottom, rgba(var(--wh-primary-rgb) / .2), transparent 70%);
	pointer-events: none;
}

/* ============================================================
   15. Preguntas frecuentes
   ============================================================ */

.wh-faq { display: grid; gap: .7rem; }
.wh-faq--two { grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (max-width: 48rem) { .wh-faq--two { grid-template-columns: 1fr; } }

.wh-faq__item {
	border: var(--wh-hairline);
	border-radius: var(--wh-radius);
	background: var(--wh-surface);
	overflow: hidden;
	transition: border-color var(--wh-dur-fast) var(--wh-ease);
}
.wh-faq__item[open] { border-color: rgba(var(--wh-primary-rgb) / .45); }

.wh-faq__q {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 1rem;
	padding: 1.1rem 1.3rem;
	font-family: var(--wh-font-display);
	font-size: var(--wh-fs-md);
	font-weight: 600;
	cursor: pointer;
	list-style: none;
}
.wh-faq__q::-webkit-details-marker { display: none; }

.wh-faq__sign {
	display: grid;
	place-items: center;
	flex: none;
	width: 1.85rem;
	height: 1.85rem;
	border-radius: 50%;
	background: rgba(var(--wh-sky-rgb) / .1);
	color: var(--wh-sky);
	transition: transform var(--wh-dur) var(--wh-ease-out), background var(--wh-dur-fast) var(--wh-ease);
}
.wh-faq__item[open] .wh-faq__sign { transform: rotate(45deg); background: rgba(var(--wh-primary-rgb) / .2); }

.wh-faq__a { padding: 0 1.3rem 1.3rem; color: var(--wh-muted); font-size: var(--wh-fs-sm); }

/* ============================================================
   16. Barras y anillos
   ============================================================ */

.wh-gauges--bar { display: grid; gap: 1.4rem; }
.wh-gauges--ring { display: grid; grid-template-columns: repeat(var(--wh-cols, 4), minmax(0, 1fr)); gap: 1.5rem; }

.wh-gauge__top { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; margin-bottom: .55rem; }
.wh-gauge__label { font-weight: 600; font-size: var(--wh-fs-sm); }
.wh-gauge__pct { font-family: var(--wh-font-mono); font-size: var(--wh-fs-sm); color: var(--wh-sky); font-variant-numeric: tabular-nums; }
.wh-gauge__note { margin-top: .35rem; font-size: var(--wh-fs-xs); color: var(--wh-muted); }

.wh-gauge__track {
	height: .5rem;
	border-radius: var(--wh-radius-pill);
	background: rgba(var(--wh-line-rgb) / .6);
	overflow: hidden;
}
.wh-gauge__fill {
	display: block;
	width: 0;
	height: 100%;
	border-radius: inherit;
	background: var(--wh-grad-brand);
	box-shadow: var(--wh-glow-primary);
	transition: width 1.1s var(--wh-ease-out);
	transition-delay: calc(var(--wh-i) * 90ms);
}
.wh-gauges.is-live .wh-gauge__fill { width: calc(var(--wh-val) * 1%); }

.wh-gauge--lime .wh-gauge__fill { background: linear-gradient(90deg, var(--wh-sky), var(--wh-lime)); }
.wh-gauge--gold .wh-gauge__fill { background: var(--wh-grad-gold); }
.wh-gauge--sky  .wh-gauge__fill { background: linear-gradient(90deg, var(--wh-primary), var(--wh-sky)); }

/* El anillo se dibuja con un degradado conico enmascarado: sin SVG y sin JS. */
.wh-gauge--ring { display: grid; justify-items: center; text-align: center; gap: .6rem; }
.wh-gauge__ring {
	display: grid;
	place-items: center;
	width: 7.5rem;
	aspect-ratio: 1;
	border-radius: 50%;
	background: conic-gradient(var(--wh-primary) calc(var(--wh-ring, 0) * 1%), rgba(var(--wh-line-rgb) / .55) 0);
	transition: background 1.1s var(--wh-ease-out);
	transition-delay: calc(var(--wh-i) * 90ms);
}
.wh-gauge__ring::before {
	content: "";
	position: absolute;
	width: 5.8rem;
	aspect-ratio: 1;
	border-radius: 50%;
	background: var(--wh-base);
}
.wh-gauge--ring .wh-gauge__pct { position: relative; font-size: var(--wh-fs-lg); color: var(--wh-text); }
.wh-gauges--ring.is-live .wh-gauge__ring { --wh-ring: var(--wh-val); }
.wh-gauge--lime .wh-gauge__ring { background: conic-gradient(var(--wh-lime) calc(var(--wh-ring, 0) * 1%), rgba(var(--wh-line-rgb) / .55) 0); }
.wh-gauge--gold .wh-gauge__ring { background: conic-gradient(var(--wh-gold) calc(var(--wh-ring, 0) * 1%), rgba(var(--wh-line-rgb) / .55) 0); }
.wh-gauge--sky  .wh-gauge__ring { background: conic-gradient(var(--wh-sky) calc(var(--wh-ring, 0) * 1%), rgba(var(--wh-line-rgb) / .55) 0); }

/* ============================================================
   17. Equipo y logotipos
   ============================================================ */

.wh-person {
	display: grid;
	align-content: start;
	gap: .6rem;
	padding: clamp(1.3rem, 3vw, 1.9rem);
	border: var(--wh-hairline);
	border-radius: var(--wh-radius-lg);
	background: var(--wh-surface);
	transition: transform var(--wh-dur) var(--wh-ease-out), border-color var(--wh-dur) var(--wh-ease);
}
.wh-person:hover { transform: translateY(-4px); border-color: rgba(var(--wh-primary-rgb) / .45); }

.wh-person__avatar { width: 4.5rem; height: 4.5rem; margin-bottom: .4rem; }
.wh-person__avatar img { width: 100%; height: 100%; border-radius: 50%; object-fit: cover; }
.wh-person__glyph {
	display: grid;
	place-items: center;
	width: 100%;
	height: 100%;
	border: 1px solid rgba(var(--wh-sky-rgb) / .22);
	border-radius: 50%;
	background: rgba(var(--wh-primary-rgb) / .12);
	color: var(--wh-primary);
}
.wh-person__name { font-size: var(--wh-fs-lg); }
.wh-person__role { font-family: var(--wh-font-mono); font-size: var(--wh-fs-xs); color: var(--wh-lime); letter-spacing: .04em; }
.wh-person__bio  { color: var(--wh-muted); font-size: var(--wh-fs-sm); }

.wh-logos { display: grid; gap: 1.5rem; }
.wh-logos__intro { text-align: center; font-family: var(--wh-font-mono); font-size: var(--wh-fs-xs); letter-spacing: .14em; text-transform: uppercase; color: var(--wh-muted); }
.wh-logos__cell { display: grid; place-items: center; padding: 1rem 1.6rem; }
.wh-logos__img { max-height: 2.6rem; width: auto; object-fit: contain; }
.wh-logos--gray .wh-logos__img {
	filter: grayscale(1) brightness(1.6);
	opacity: .6;
	transition: filter var(--wh-dur) var(--wh-ease), opacity var(--wh-dur) var(--wh-ease);
}
.wh-logos--gray .wh-logos__cell:hover .wh-logos__img { filter: none; opacity: 1; }

/* ============================================================
   18. Texto e imagen enfrentados
   ============================================================ */

.wh-split { display: grid; grid-template-columns: var(--wh-split, 1fr 1fr); gap: clamp(2rem, 5vw, 4rem); align-items: center; }
.wh-split--solo { grid-template-columns: 1fr; }
.wh-split--flip .wh-split__copy { order: 2; }

@media (max-width: 61.99rem) {
	.wh-split { grid-template-columns: 1fr; }
	.wh-split--flip .wh-split__copy { order: 0; }
}

.wh-split__acts { margin-top: 1.8rem; }

.wh-figure { position: relative; margin: 0; }
.wh-figure img { width: 100%; border-radius: var(--wh-radius-lg); }
.wh-figure--glow img { border: var(--wh-hairline); }
.wh-figure--browser {
	border: var(--wh-hairline);
	border-radius: var(--wh-radius);
	background: var(--wh-surface);
	overflow: hidden;
}
.wh-figure--browser img { border-radius: 0; }
.wh-figure__bar { display: flex; gap: .38rem; padding: .7rem 1rem; border-bottom: 1px solid rgba(var(--wh-line-rgb) / .6); }
.wh-figure__bar i { width: 10px; height: 10px; border-radius: 50%; background: rgba(var(--wh-sky-rgb) / .3); }

/* ============================================================
   19. Llamada a la accion
   ============================================================ */

.wh-cta { position: relative; overflow: hidden; border-radius: var(--wh-radius-lg); }
.wh-cta__in {
	position: relative;
	z-index: 2;
	display: grid;
	gap: 1.75rem;
	padding: clamp(2rem, 5vw, 3.5rem);
}
.wh-cta--center .wh-cta__in { justify-items: center; text-align: center; }
.wh-cta--split .wh-cta__in { grid-template-columns: 1fr auto; align-items: center; }
@media (max-width: 61.99rem) { .wh-cta--split .wh-cta__in { grid-template-columns: 1fr; } }

.wh-cta--panel { border: var(--wh-hairline); background: var(--wh-surface); }
.wh-cta--gradient { background: var(--wh-grad-brand); color: var(--wh-on-primary); }
.wh-cta--gradient .wh-cta__text,
.wh-cta--gradient .wh-cta__note { color: rgba(255 255 255 / .82); }
.wh-cta--gradient .wh-em { -webkit-text-fill-color: currentColor; }
.wh-cta--bare { border-radius: 0; }
.wh-cta--edge {
	border-radius: 0;
	/* Igual que el hero: se descuenta la barra de desplazamiento. */
	margin-inline: calc(50% - 50vw + var(--wh-sbw) / 2);
	width: calc(100vw - var(--wh-sbw));
	padding-inline: var(--wh-gutter);
	background: var(--wh-surface-2);
}

.wh-cta__title { font-size: var(--wh-fs-3xl); }
.wh-cta__text  { margin-top: .9rem; max-width: 58ch; color: var(--wh-muted); font-size: var(--wh-fs-lg); }
.wh-cta__btns  { display: flex; flex-wrap: wrap; gap: .75rem; }
.wh-cta__note  { margin-top: .8rem; font-size: var(--wh-fs-xs); color: var(--wh-muted); }

.wh-cta--glow .wh-cta__fx {
	position: absolute;
	inset: -50% -10% auto;
	height: 110%;
	background: radial-gradient(ellipse at top, rgba(var(--wh-primary-rgb) / .25), transparent 62%);
	pointer-events: none;
}

/* ============================================================
   20. Blog
   ============================================================ */

.wh-phero { position: relative; padding-block: clamp(4.5rem, 10vw, 8rem) clamp(2rem, 4vw, 3.5rem); overflow: hidden; }
.wh-phero__in { position: relative; z-index: 2; }
.wh-phero__title { margin-top: .4rem; font-size: var(--wh-fs-4xl); }
.wh-phero__sub { margin-top: 1rem; max-width: 62ch; color: var(--wh-muted); font-size: var(--wh-fs-lg); }
.wh-phero__grid {
	position: absolute;
	inset: 0;
	z-index: 1;
	background-image:
		linear-gradient(rgba(var(--wh-sky-rgb) / .06) 1px, transparent 1px),
		linear-gradient(90deg, rgba(var(--wh-sky-rgb) / .06) 1px, transparent 1px);
	background-size: 52px 52px;
	mask-image: radial-gradient(ellipse at 20% 0%, #000, transparent 72%);
}

.wh-crumbs { margin-bottom: 1.1rem; font-size: var(--wh-fs-xs); color: var(--wh-muted); }
.wh-crumbs__list { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem; margin: 0; padding: 0; list-style: none; }
.wh-crumbs a:hover { color: var(--wh-sky); }
.wh-crumbs__sep { display: inline-grid; opacity: .5; }

.wh-pmeta { display: flex; flex-wrap: wrap; gap: .5rem 1.3rem; margin: 1.5rem 0 0; padding: 0; list-style: none; font-size: var(--wh-fs-sm); color: var(--wh-muted); }
.wh-pmeta__item { display: inline-flex; align-items: center; gap: .4rem; }

.wh-layout { display: grid; gap: clamp(2rem, 4vw, 3.5rem); padding-block: var(--wh-section); align-items: start; }
@media (min-width: 62rem) {
	.wh-sidebar-right .wh-layout { grid-template-columns: minmax(0, 1fr) 20rem; }
	.wh-sidebar-left  .wh-layout { grid-template-columns: 20rem minmax(0, 1fr); }
	.wh-sidebar-left  .wh-layout__side { order: -1; }
}
.wh-no-sidebar .wh-layout { grid-template-columns: minmax(0, 1fr); }

.wh-sticky { position: sticky; top: 6.5rem; display: grid; gap: 1.5rem; }

.wh-card {
	position: relative;
	display: grid;
	align-content: start;
	border: var(--wh-hairline);
	border-radius: var(--wh-radius-lg);
	background: var(--wh-surface);
	overflow: hidden;
	transition: transform var(--wh-dur) var(--wh-ease-out), border-color var(--wh-dur) var(--wh-ease), box-shadow var(--wh-dur) var(--wh-ease);
}
.wh-card:hover { transform: translateY(-4px); border-color: rgba(var(--wh-primary-rgb) / .45); box-shadow: var(--wh-shadow-lg); }
.wh-card__link { position: absolute; inset: 0; z-index: 3; }

/* 16:9, la misma proporcion que el recorte `whcore-card` de inc/setup.php.
   Si las dos no coinciden, el navegador vuelve a recortar por encima de lo que
   ya recorto WordPress y se pierde texto de la portada por segunda vez. */
.wh-card__media { position: relative; aspect-ratio: 16 / 9; overflow: hidden; background: var(--wh-surface-2); }
.wh-card__img { width: 100%; height: 100%; object-fit: cover; transition: transform .7s var(--wh-ease-out); }
.wh-card:hover .wh-card__img { transform: scale(1.05); }
.wh-card__ph { display: grid; place-items: center; height: 100%; color: rgba(var(--wh-sky-rgb) / .3); }

.wh-card__body { display: grid; gap: .55rem; padding: 1.3rem; }
.wh-card__cat { font-family: var(--wh-font-mono); font-size: var(--wh-fs-xs); letter-spacing: .1em; text-transform: uppercase; color: var(--wh-lime); }
.wh-card__title { font-size: var(--wh-fs-lg); }
.wh-card__excerpt { color: var(--wh-muted); font-size: var(--wh-fs-sm); }
.wh-card__foot { display: flex; align-items: center; gap: .6rem; margin-top: .3rem; font-size: var(--wh-fs-xs); color: var(--wh-muted); }
.wh-card__dot { width: 3px; height: 3px; border-radius: 50%; background: currentColor; opacity: .6; }

.wh-card--list { grid-template-columns: 14rem 1fr; align-items: center; }
.wh-card--list .wh-card__media { aspect-ratio: 4 / 3; height: 100%; }
@media (max-width: 40rem) { .wh-card--list { grid-template-columns: 1fr; } }

.wh-card--feature { grid-column: 1 / -1; grid-template-columns: 1.1fr 1fr; align-items: center; }
.wh-card--feature .wh-card__media {
	aspect-ratio: 16 / 10;
	height: 100%;
	padding: 1rem;
	background: var(--wh-base);
}
.wh-card--feature .wh-card__img { object-fit: contain; }
.wh-card--feature .wh-card__body { padding: clamp(1.4rem, 3vw, 2.4rem); }
.wh-card--feature .wh-card__title { font-size: var(--wh-fs-2xl); }
@media (max-width: 61.99rem) { .wh-card--feature { grid-template-columns: 1fr; } }

.wh-archive--list { grid-template-columns: 1fr; }

/* ---- Indice del blog ---------------------------------------------- */

.wh-blog { padding-block: 0 var(--wh-section); }
.wh-blog__lead { margin-bottom: clamp(1.5rem, 3vw, 2.5rem); }
.wh-blog__cta { padding-bottom: var(--wh-section); }

/* Filtros por tema. Se desplazan en horizontal cuando no caben, en vez de
   apilarse y empujar los articulos fuera de la primera pantalla. */
.wh-catbar {
	display: flex;
	gap: .5rem;
	margin-bottom: clamp(1.5rem, 3vw, 2.5rem);
	padding-bottom: .4rem;
	overflow-x: auto;
	scrollbar-width: none;
}
.wh-catbar::-webkit-scrollbar { display: none; }

.wh-catbar__item {
	display: inline-flex;
	align-items: center;
	gap: .5rem;
	flex: none;
	padding: .5rem 1rem;
	border: 1px solid rgba(var(--wh-sky-rgb) / .2);
	border-radius: var(--wh-radius-pill);
	background: rgba(var(--wh-surface-rgb) / .5);
	font-size: var(--wh-fs-sm);
	color: var(--wh-muted);
	white-space: nowrap;
	transition: border-color var(--wh-dur-fast) var(--wh-ease),
	            color var(--wh-dur-fast) var(--wh-ease),
	            background var(--wh-dur-fast) var(--wh-ease);
}
.wh-catbar__item:hover { border-color: var(--wh-primary); color: var(--wh-text); }
.wh-catbar__item.is-active {
	border-color: var(--wh-primary);
	background: rgba(var(--wh-primary-rgb) / .16);
	color: var(--wh-text);
}
.wh-catbar__n {
	padding: .05rem .45rem;
	border-radius: var(--wh-radius-pill);
	background: rgba(var(--wh-sky-rgb) / .14);
	font-family: var(--wh-font-mono);
	font-size: var(--wh-fs-xs);
}

.wh-pager { margin-top: clamp(2rem, 4vw, 3rem); }
.wh-pager__list { display: flex; flex-wrap: wrap; justify-content: center; gap: .4rem; margin: 0; padding: 0; list-style: none; }
.wh-pager a,
.wh-pager span {
	display: inline-flex;
	align-items: center;
	gap: .3rem;
	min-width: 2.6rem;
	justify-content: center;
	padding: .55rem .85rem;
	border: 1px solid rgba(var(--wh-sky-rgb) / .18);
	border-radius: var(--wh-radius-sm);
	font-size: var(--wh-fs-sm);
	transition: border-color var(--wh-dur-fast) var(--wh-ease), background var(--wh-dur-fast) var(--wh-ease);
}
.wh-pager a:hover { border-color: var(--wh-primary); background: rgba(var(--wh-primary-rgb) / .1); }
.wh-pager .current { background: var(--wh-primary); border-color: var(--wh-primary); color: var(--wh-on-primary); font-weight: 600; }
.wh-pager .dots { border-color: transparent; }

.wh-article__cover { margin: 0 auto; }
.wh-article__cover img { width: 100%; border-radius: var(--wh-radius-lg); }

.wh-progress { position: fixed; inset-inline: 0; top: 0; z-index: 300; height: 3px; pointer-events: none; }
.wh-progress span { display: block; width: var(--wh-read, 0%); height: 100%; background: var(--wh-grad-brand); box-shadow: var(--wh-glow-primary); }

.wh-toc {
	margin-bottom: 2rem;
	padding: 1.2rem 1.4rem;
	border: var(--wh-hairline);
	border-inline-start: 3px solid var(--wh-primary);
	border-radius: var(--wh-radius);
	background: rgba(var(--wh-surface-rgb) / .6);
}
.wh-toc__title { margin: 0 0 .6rem; font-family: var(--wh-font-mono); font-size: var(--wh-fs-xs); letter-spacing: .12em; text-transform: uppercase; color: var(--wh-muted); }
.wh-toc__list { display: grid; gap: .35rem; margin: 0; padding: 0; list-style: none; counter-reset: wh-toc; }
.wh-toc__item--h3 { padding-inline-start: 1.1rem; font-size: var(--wh-fs-sm); }
.wh-toc a {
	color: var(--wh-muted);
	font-size: var(--wh-fs-sm);
	text-decoration: none;
	transition: color var(--wh-dur-fast) var(--wh-ease);
}
.wh-prose .wh-toc a { text-decoration: none; }
.wh-toc a:hover,
.wh-toc a.is-active { color: var(--wh-sky); }

/* El tamano tactil de los enlaces del indice NO se ajusta aqui: se hace mas
   abajo, en el bloque de moviles (@media max-width: 47.99rem), junto al resto
   de componentes que se agrandan para el dedo. Tener dos reglas para lo mismo
   en sitios distintos es como se llega a que una anule a la otra y nadie
   entienda por que el ajuste "no hace nada". */

.wh-share { display: flex; align-items: center; gap: .9rem; margin-top: 2.5rem; padding-top: 1.5rem; border-top: 1px solid rgba(var(--wh-line-rgb) / .5); }
.wh-share__label { margin: 0; font-family: var(--wh-font-mono); font-size: var(--wh-fs-xs); letter-spacing: .1em; text-transform: uppercase; color: var(--wh-muted); }
.wh-share__list { display: flex; gap: .4rem; margin: 0; padding: 0; list-style: none; }
.wh-share__list a,
.wh-share__list button {
	display: grid;
	place-items: center;
	width: 2.3rem;
	height: 2.3rem;
	border: 1px solid rgba(var(--wh-sky-rgb) / .18);
	border-radius: var(--wh-radius-sm);
	background: none;
	color: var(--wh-muted);
	cursor: pointer;
	transition: color var(--wh-dur-fast) var(--wh-ease), border-color var(--wh-dur-fast) var(--wh-ease);
}
.wh-share__list a:hover,
.wh-share__list button:hover { color: var(--wh-primary); border-color: var(--wh-primary); }

.wh-postnav { display: grid; gap: 1rem; margin-top: 2.5rem; }
@media (min-width: 48rem) { .wh-postnav { grid-template-columns: 1fr 1fr; } }
.wh-postnav .nav-links { display: contents; }
.wh-postnav a {
	display: grid;
	gap: .3rem;
	padding: 1.1rem 1.3rem;
	border: var(--wh-hairline);
	border-radius: var(--wh-radius);
	background: var(--wh-surface);
	transition: border-color var(--wh-dur-fast) var(--wh-ease);
}
.wh-postnav a:hover { border-color: var(--wh-primary); }
.wh-postnav .nav-next { text-align: end; }
.wh-postnav__dir { font-family: var(--wh-font-mono); font-size: var(--wh-fs-xs); letter-spacing: .1em; text-transform: uppercase; color: var(--wh-muted); }
.wh-postnav__title { font-family: var(--wh-font-display); font-weight: 600; }

.wh-related { padding-block: var(--wh-section); border-top: 1px solid rgba(var(--wh-line-rgb) / .5); }
.wh-related__title { margin-bottom: 2rem; font-size: var(--wh-fs-2xl); }
.wh-related .wh-grid { --wh-cols: 3; }

.wh-none { display: grid; justify-items: center; gap: 1.2rem; padding-block: 4rem; text-align: center; }
.wh-none__icon { color: rgba(var(--wh-sky-rgb) / .35); }
.wh-none__text { color: var(--wh-muted); }
.wh-none .wh-search { width: min(30rem, 100%); }

.wh-404 { padding-block: var(--wh-section); }
.wh-404__panel {
	display: grid;
	justify-items: center;
	gap: 1.6rem;
	padding: clamp(2rem, 5vw, 3.5rem);
	border: var(--wh-hairline);
	border-radius: var(--wh-radius-lg);
	background: var(--wh-surface);
	text-align: center;
}
.wh-404__code {
	margin: 0;
	font-family: var(--wh-font-display);
	font-size: clamp(4rem, 16vw, 9rem);
	font-weight: 700;
	line-height: 1;
	letter-spacing: -0.05em;
	background: var(--wh-grad-brand);
	-webkit-background-clip: text;
	background-clip: text;
	-webkit-text-fill-color: transparent;
}
.wh-404 .wh-search { width: min(30rem, 100%); }
.wh-404__links { display: flex; flex-wrap: wrap; justify-content: center; gap: .75rem; }

/* Widgets de la barra lateral y del pie */
.wh-widget,
.wh-fwidget { font-size: var(--wh-fs-sm); }
.wh-widget {
	padding: 1.3rem;
	border: var(--wh-hairline);
	border-radius: var(--wh-radius);
	background: var(--wh-surface);
}
.wh-widget__title,
.wh-fwidget__title { margin: 0 0 .9rem; font-size: var(--wh-fs-md); }
.wh-widget ul,
.wh-fwidget ul { display: grid; gap: .5rem; margin: 0; padding: 0; list-style: none; }
.wh-widget a:hover,
.wh-fwidget a:hover { color: var(--wh-sky); }

/* ============================================================
   21. Contenido escrito
   ============================================================ */

.wh-single { padding-block: var(--wh-section); }

.wh-prose { max-width: 74ch; }
.wh-prose > * + * { margin-top: 1.35em; }
.wh-prose h2 { margin-top: 2.4em; font-size: var(--wh-fs-2xl); }
.wh-prose h3 { margin-top: 2em; font-size: var(--wh-fs-xl); }
.wh-prose h4 { margin-top: 1.8em; font-size: var(--wh-fs-lg); }
.wh-prose p,
.wh-prose li { color: var(--wh-muted); }
.wh-prose strong { color: var(--wh-text); font-weight: 600; }

.wh-prose a {
	color: var(--wh-sky);
	text-decoration: underline;
	text-decoration-color: rgba(var(--wh-sky-rgb) / .4);
	text-underline-offset: .18em;
	transition: text-decoration-color var(--wh-dur-fast) var(--wh-ease);
}
.wh-prose a:hover { text-decoration-color: currentColor; }

.wh-prose ul,
.wh-prose ol { padding-inline-start: 1.3rem; }
.wh-prose li + li { margin-top: .5em; }
.wh-prose ul li::marker { color: var(--wh-lime); }
.wh-prose ol li::marker { color: var(--wh-sky); font-family: var(--wh-font-mono); }

.wh-prose img,
.wh-prose figure img { border-radius: var(--wh-radius); }
.wh-prose figcaption {
	margin-top: .6rem;
	font-size: var(--wh-fs-xs);
	color: var(--wh-muted);
	text-align: var(--wh-caption-align, center);
}

/* ==========================================================================
   ALINEACION DEL CONTENIDO — se elige en Personalizador → Textos e imágenes
   ==========================================================================
   Todo lo de este bloque se controla con tres variables que rellena PHP:
   --wh-text-align, --wh-heading-align y --wh-caption-align. La hoja de estilos
   no sabe que valores existen; solo los usa. Asi, anadir una opcion nueva no
   obliga a tocar el CSS.

   ALCANCE (cambiado el 21-ago-2026)
   ---------------------------------
   Antes esto solo llegaba a `.wh-prose--tuned`, el cuerpo de las paginas y las
   entradas. El problema es que en este sitio casi todo lo demas son secciones
   montadas con nuestros widgets, asi que poner «justificado» en el panel
   parecia no hacer nada: se justificaban dos paginas y el resto seguia igual.

   Ahora alcanza tambien al TEXTO CORRIDO de las secciones (mas abajo, en el
   bloque «TEXTO DE LAS SECCIONES»). Lo que sigue SIN tocarse, a proposito:

     - Los titulos, que tienen su propia opcion (--wh-heading-align).
     - Los bloques que su propia seccion centra a proposito (`--center`): ahi
       el centrado es parte del diseno de esa seccion, no una preferencia de
       lectura, y pisarlo descolocaria el conjunto.
     - Etiquetas, botones, cifras y pies pequenos: justificar tres palabras
       abre huecos enormes y no arregla nada. */

.wh-prose--tuned p,
.wh-prose--tuned li,
.wh-prose--tuned blockquote {
	text-align: var(--wh-text-align, start);
}

/* ...pero NO a lo que dentro del articulo es NAVEGACION, no lectura: el indice
   y los botones de compartir. Son listas de enlaces cortos; justificarlos deja
   huecos absurdos entre dos palabras.

   Los avisos y las preguntas frecuentes SI se alinean con el resto (cambiado el
   21-ago-2026). Antes estaban en esta lista, y el resultado era incoherente: la
   misma pregunta frecuente salia justificada cuando venia de un widget de
   seccion y a la izquierda cuando venia dentro de un articulo.

   Se listan uno a uno a proposito: un selector generico como
   `[class*="wh-"] > p` tambien acertaria a `.wh-prose` y anularia el ajuste
   entero. */
.wh-prose--tuned .wh-toc p,
.wh-prose--tuned .wh-toc li,
.wh-prose--tuned .wh-share p,
.wh-prose--tuned .wh-share li {
	text-align: start;
}

/* El guionado es lo que hace usable el texto justificado.
   Sin el, el navegador reparte todo el espacio sobrante ENTRE las palabras y
   aparecen los famosos "rios" de espacio en blanco bajando por el parrafo.
   Con guionado, parte las palabras largas al final de linea y el espaciado se
   mantiene normal. Necesita que la pagina declare su idioma (lo hace WordPress
   en <html lang>), porque las reglas de partir palabras son distintas en cada
   uno. */
.wh-prose--tuned p,
.wh-prose--tuned li {
	hyphens: auto;
	-webkit-hyphens: auto;
}

/* Un titulo no se justifica nunca: con pocas palabras por linea quedarian
   huecos enormes. PHP ya se encarga de darle 'start' cuando el texto va
   justificado; aqui solo se aplica lo que decida. */
.wh-prose--tuned h1,
.wh-prose--tuned h2,
.wh-prose--tuned h3,
.wh-prose--tuned h4,
.wh-prose--tuned h5,
.wh-prose--tuned h6 {
	text-align: var(--wh-heading-align, start);
}

/* --- TEXTO DE LAS SECCIONES ----------------------------------------------
   Lo mismo, pero para el texto corrido de los widgets propios: la descripcion
   de una tarjeta, el cuerpo de un bloque partido, el texto de un paso, la
   respuesta de una pregunta frecuente, la biografia de una persona...

   La lista es explicita, clase por clase, y eso es a proposito. Un selector
   generico del tipo `.wh-scard p` tambien acertaria al pie de la tarjeta, a la
   etiqueta y al boton, que no son texto de lectura. Cuando se anada un widget
   nuevo con texto largo, se anade aqui su clase; es una linea. */
.wh-scard__text,
.wh-feat__text,
.wh-feat__body,
.wh-step__text,
.wh-step__body,
.wh-appnews__text,
.wh-person__bio,
.wh-card__excerpt,
.wh-form__text,
.wh-hero__sub,
.wh-phero__sub,
.wh-split__body p,
.wh-split__body li,
.wh-term__body p,
.wh-term__body li,
.wh-card__body p,
.wh-faq__a p {
	text-align: var(--wh-text-align, start);
	/* El guionado va SIEMPRE con el justificado, y aqui todavia mas que en el
	   articulo: estas columnas son estrechas (una tarjeta ronda los 300 px), y
	   sin partir palabras el navegador abre huecos enormes entre ellas. */
	hyphens: auto;
	-webkit-hyphens: auto;
}

/* Y lo que la seccion centra a proposito, se queda centrado.
   Estas son secciones cuyo diseno es simetrico —titulo, subtitulo y botones en
   el eje—. Un ajuste global de lectura no debe romper eso: quedaria un parrafo
   pegado a la izquierda debajo de un titulo centrado. */
.wh-sechead--center .wh-sechead__sub,
.wh-cta--center .wh-cta__text,
.wh-feat--center .wh-feat__text,
.wh-feat--center .wh-feat__body {
	text-align: center;
}

/* --- Imagenes ------------------------------------------------------------
   El valor por defecto lo pone la clase que anade PHP al contenedor
   (`wh-img--center`, `wh-img--start`, `wh-img--end`), y solo afecta a las
   imagenes que NO llevan alineacion propia del editor. */
.wh-img--center > figure:not([class*="align"]),
.wh-img--center > p > img:not([class*="align"]),
.wh-img--center > img:not([class*="align"]) {
	display: block;
	margin-inline: auto;
}

.wh-img--start > figure:not([class*="align"]),
.wh-img--start > img:not([class*="align"]) {
	float: inline-start;
	margin: .4em 1.6rem 1.2rem 0;
	max-width: min(50%, 22rem);
}

.wh-img--end > figure:not([class*="align"]),
.wh-img--end > img:not([class*="align"]) {
	float: inline-end;
	margin: .4em 0 1.2rem 1.6rem;
	max-width: min(50%, 22rem);
}

/* --- Las clases que pone el editor de WordPress --------------------------
   El tema declaraba `align-wide` pero no traia ni una regla para estas clases,
   asi que alinear una imagen desde el editor no hacia absolutamente nada y no
   habia forma de saber por que. Estas son las cinco que usa WordPress. */
.wh-prose--tuned .aligncenter,
.wh-prose--tuned .wp-block-image.aligncenter {
	display: block;
	margin-inline: auto;
	text-align: center;
}
.wh-prose--tuned .alignleft {
	float: left;
	margin: .4em 1.6rem 1.2rem 0;
	max-width: min(50%, 22rem);
}
.wh-prose--tuned .alignright {
	float: right;
	margin: .4em 0 1.2rem 1.6rem;
	max-width: min(50%, 22rem);
}
/* «Ancha» y «a ancho completo» se salen del ancho de lectura a proposito. */
.wh-prose--tuned .alignwide {
	width: min(var(--wh-width-wide, 1440px), 92vw);
	max-width: none;
	margin-inline: calc(50% - min(var(--wh-width-wide, 1440px), 92vw) / 2);
}
.wh-prose--tuned .alignfull {
	width: 100vw;
	max-width: none;
	margin-inline: calc(50% - 50vw);
	border-radius: 0;
}
.wh-prose--tuned .alignfull img { border-radius: 0; }

/* Detras de una imagen flotada hay que "limpiar", o el siguiente titulo se
   sube a su costado y el articulo queda descosido. */
.wh-prose--tuned h2,
.wh-prose--tuned h3 { clear: both; }

/* En un telefono no cabe texto al lado de una imagen: se pierden los dos.
   Por debajo de 34rem todo pasa a ancho completo y centrado, sin excepcion. */
@media (max-width: 34rem) {
	.wh-prose--tuned .alignleft,
	.wh-prose--tuned .alignright,
	.wh-img--start > figure,
	.wh-img--start > img,
	.wh-img--end > figure,
	.wh-img--end > img {
		float: none;
		display: block;
		margin-inline: auto;
		max-width: 100%;
	}
	/* Justificar en pantallas estrechas produce huecos enormes porque caben
	   muy pocas palabras por linea. Se vuelve al margen izquierdo. */
	.wh-prose--tuned p,
	.wh-prose--tuned li { text-align: start; }
}

.wh-prose blockquote {
	margin-inline: 0;
	padding: 1.2rem 1.5rem;
	border-inline-start: 3px solid var(--wh-primary);
	border-radius: 0 var(--wh-radius) var(--wh-radius) 0;
	background: rgba(var(--wh-surface-rgb) / .6);
	font-size: var(--wh-fs-lg);
}
.wh-prose blockquote p { color: var(--wh-text); }

.wh-prose code {
	padding: .16em .42em;
	border-radius: var(--wh-radius-sm);
	background: rgba(var(--wh-sky-rgb) / .12);
	font-family: var(--wh-font-mono);
	font-size: .88em;
	color: var(--wh-lime);
}
.wh-prose pre {
	padding: 1.2rem 1.3rem;
	border: var(--wh-hairline);
	border-radius: var(--wh-radius);
	background: rgba(var(--wh-base-rgb) / .8);
	overflow-x: auto;
	font-family: var(--wh-font-mono);
	font-size: var(--wh-fs-sm);
	line-height: 1.7;
}
.wh-prose pre code { padding: 0; background: none; color: inherit; }

/* Las tablas se desplazan dentro de su caja: nunca ensanchan la pagina. */
.wh-prose :is(table, .wh-table) {
	display: block;
	width: 100%;
	overflow-x: auto;
	border-collapse: collapse;
	font-size: var(--wh-fs-sm);
}
.wh-prose :is(th, td) { padding: .7rem .9rem; border: 1px solid rgba(var(--wh-line-rgb) / .6); text-align: start; }
.wh-prose th { background: rgba(var(--wh-sky-rgb) / .08); font-family: var(--wh-font-display); }

/* ---- Piezas de articulo ------------------------------------------- */

/* Entradilla: el primer parrafo, algo mayor, que resume de que va el texto. */
.wh-prose .wh-lead {
	font-size: var(--wh-fs-lg);
	line-height: 1.6;
	color: var(--wh-text);
}

/* Imagen explicativa a todo el ancho de la columna de lectura, con pie. */
.wh-figure-inline { margin-block: 2.2em; }
.wh-figure-inline img {
	width: 100%;
	border: var(--wh-hairline);
	border-radius: var(--wh-radius);
}

/* EN EL MOVIL, EL DIAGRAMA SE DESPLAZA EN VEZ DE ENCOGERSE.
   =========================================================
   Los diagramas de los articulos son imagenes de 1200 px con tres columnas de
   texto dentro. Con `width: 100%` a secas, en un telefono de 390 px se reducen
   a un tercio y su letra queda en unos cuatro pixeles: se ve que hay un dibujo,
   pero no se puede leer NADA. Y no da ningun error, claro — la imagen carga
   perfectamente, solo que ilegible, asi que ninguna prueba automatica lo nota.
   Se descubrio mirando una captura de movil de verdad.

   La solucion es la que manda para cualquier contenido ancho: que se desplace
   dentro de su propia caja, en vez de encogerse hasta desaparecer. Se conserva
   un ancho minimo legible y aparece una barra horizontal SOLO en la figura.

   Ojo con una confusion: en el menu, `overflow-x` esta PROHIBIDO porque
   recorta los desplegables, que van posicionados en absoluto. Aqui no hay nada
   posicionado dentro de la figura, asi que no recorta nada. */
@media (max-width: 700px) {
	.wh-figure-inline {
		overflow-x: auto;
		/* Inercia al arrastrar en iOS; sin esto el gesto se siente rigido. */
		-webkit-overflow-scrolling: touch;
		/* El redondeo va aqui ahora: si se queda solo en la imagen, la esquina
		   se ve cortada al desplazar. */
		border-radius: var(--wh-radius);
	}

	.wh-figure-inline img {
		/* 1000 px deja la letra del diagrama en unos once pixeles, que se lee.
		   `width: auto` es imprescindible: con `width: 100%` el navegador
		   volveria a encogerla hasta el ancho de la pantalla y el minimo no
		   serviria de nada. */
		width: auto;
		min-width: 1000px;
		max-width: none;
	}

	/* El pie NO se desplaza con la imagen: es texto normal y debe caber en la
	   pantalla. Por eso se saca del area desplazable fijandolo al ancho del
	   contenido. */
	.wh-figure-inline figcaption {
		position: sticky;
		left: 0;
		width: 100%;
		max-width: 100vw;
	}
}
.wh-figure-inline figcaption {
	margin-top: .7rem;
	font-size: var(--wh-fs-xs);
	color: var(--wh-muted);
	/* Lo elige Personalizador → Textos e imágenes; si no hay nada, centrado. */
	text-align: var(--wh-caption-align, center);
}

/* Avisos destacados. Tres tonos con significados distintos: consejo, peligro
   y llamada a la accion, para que se distingan de un vistazo sin leerlos. */
.wh-callout {
	display: grid;
	gap: .5rem;
	margin-block: 2em;
	padding: 1.3rem 1.5rem;
	border: 1px solid;
	border-radius: var(--wh-radius);
}
.wh-callout__title { font-family: var(--wh-font-display); font-weight: 700; font-size: var(--wh-fs-md); }
.wh-callout__body { font-size: var(--wh-fs-sm); }
.wh-callout__body p { margin: 0; }
.wh-callout__body p + p { margin-top: .7em; }

.wh-callout--tip {
	border-color: rgba(var(--wh-sky-rgb) / .35);
	background: linear-gradient(90deg, rgba(var(--wh-sky-rgb) / .1), rgba(var(--wh-sky-rgb) / .02));
}
.wh-callout--tip .wh-callout__title { color: var(--wh-sky); }

.wh-callout--warn {
	border-color: rgba(var(--wh-gold-rgb) / .4);
	background: linear-gradient(90deg, rgba(var(--wh-gold-rgb) / .1), rgba(var(--wh-gold-rgb) / .02));
}
.wh-callout--warn .wh-callout__title { color: var(--wh-gold); }

.wh-callout--cta {
	border-color: rgba(var(--wh-primary-rgb) / .45);
	background: linear-gradient(90deg, rgba(var(--wh-primary-rgb) / .12), rgba(var(--wh-primary-rgb) / .03));
}
.wh-callout--cta .wh-callout__title { color: var(--wh-primary); }

/* Preguntas y respuestas al final del articulo.
   Se dejan siempre abiertas, sin acordeon: es el formato que mejor aprovechan
   los buscadores con inteligencia artificial para citar una fuente, y esconder
   la respuesta tras un clic reduce las probabilidades de que la lean. */
.wh-qa {
	padding: 1.2rem 1.4rem;
	margin-block: .9em;
	border-inline-start: 3px solid var(--wh-primary);
	border-radius: 0 var(--wh-radius) var(--wh-radius) 0;
	background: rgba(var(--wh-surface-rgb) / .55);
}
.wh-prose .wh-qa__q {
	margin: 0 0 .5em;
	font-size: var(--wh-fs-md);
	color: var(--wh-text);
}
.wh-qa__a { font-size: var(--wh-fs-sm); }
.wh-qa__a p { margin: 0; }

.wh-prose hr { margin-block: 2.5em; border: 0; border-top: 1px solid rgba(var(--wh-line-rgb) / .6); }

.wh-pagelinks { display: flex; gap: .4rem; margin-top: 2rem; }

/* ============================================================
   22. Formularios
   ============================================================ */

.wh-form {
	display: grid;
	gap: 1.2rem;
	padding: clamp(1.5rem, 3.5vw, 2.4rem);
	border: var(--wh-hairline);
	border-radius: var(--wh-radius-lg);
	background: var(--wh-surface);
}
.wh-form__title { font-size: var(--wh-fs-xl); }
.wh-form__text  { color: var(--wh-muted); font-size: var(--wh-fs-sm); }

.wh-form__grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1rem; }
@media (max-width: 40rem) { .wh-form__grid { grid-template-columns: 1fr; } }

.wh-field { display: grid; gap: .4rem; margin: 0; }
.wh-field--full { grid-column: 1 / -1; }
.wh-field__label { font-size: var(--wh-fs-xs); font-weight: 600; letter-spacing: .02em; color: var(--wh-muted); }
.wh-field__req { color: var(--wh-lime); }
.wh-field__hint { font-size: var(--wh-fs-xs); color: rgba(var(--wh-text-rgb) / .45); line-height: 1.45; }

/* ---- Fichas de seleccion -----------------------------------------
   Sustituyen a los desplegables: se ve todo de un vistazo y se elige con un
   toque. Por debajo siguen siendo <input type="radio">, asi que funcionan con
   teclado, con lector de pantalla y sin JavaScript. */

.wh-chipset { border: 0; padding: 0; margin: 0; min-width: 0; }
.wh-chipset__list { display: flex; flex-wrap: wrap; gap: .5rem; margin-top: .6rem; }

/* El circulo del boton de opcion se saca de la vista, pero sigue existiendo y
   sigue recibiendo el foco: por eso no se usa display:none. */
.wh-chipset__input {
	position: absolute;
	width: 1px; height: 1px;
	opacity: 0;
	pointer-events: none;
}

.wh-chipset__chip {
	display: inline-flex;
	align-items: center;
	gap: .45rem;
	padding: .55rem 1rem;
	border: 1px solid rgba(var(--wh-sky-rgb) / .22);
	border-radius: var(--wh-radius-pill);
	background: rgba(var(--wh-base-rgb) / .5);
	font-size: var(--wh-fs-xs);
	color: var(--wh-muted);
	cursor: pointer;
	user-select: none;
	transition: border-color var(--wh-dur-fast) var(--wh-ease),
	            background var(--wh-dur-fast) var(--wh-ease),
	            color var(--wh-dur-fast) var(--wh-ease),
	            transform var(--wh-dur-fast) var(--wh-ease);
}
.wh-chipset__chip svg { color: var(--wh-sky); transition: color var(--wh-dur-fast) var(--wh-ease); }
.wh-chipset__chip:hover { border-color: rgba(var(--wh-primary-rgb) / .5); color: var(--wh-text); transform: translateY(-1px); }

.wh-chipset__input:checked + .wh-chipset__chip {
	border-color: var(--wh-primary);
	background: rgba(var(--wh-primary-rgb) / .16);
	color: var(--wh-text);
	box-shadow: var(--wh-glow-primary);
}
.wh-chipset__input:checked + .wh-chipset__chip svg { color: var(--wh-lime); }

/* El foco se pinta sobre la ficha, ya que el control real es invisible. */
.wh-chipset__input:focus-visible + .wh-chipset__chip {
	outline: 2px solid var(--wh-primary);
	outline-offset: 3px;
}

.wh-field__input {
	width: 100%;
	padding: .8rem 1rem;
	border: 1px solid rgba(var(--wh-sky-rgb) / .2);
	border-radius: var(--wh-radius-sm);
	background: rgba(var(--wh-base-rgb) / .55);
	font-size: var(--wh-fs-sm);
	transition: border-color var(--wh-dur-fast) var(--wh-ease), box-shadow var(--wh-dur) var(--wh-ease);
}
.wh-field__input:focus { outline: none; border-color: var(--wh-primary); box-shadow: 0 0 0 3px rgba(var(--wh-primary-rgb) / .18); }
.wh-field__input::placeholder { color: rgba(var(--wh-text-rgb) / .35); }
textarea.wh-field__input { resize: vertical; min-height: 7rem; }

/* Un campo marcado como no valido solo se pinta despues de que el usuario lo
   haya tocado: avisar mientras escribe es hostil. */
.wh-field__input:user-invalid { border-color: #F08878; }

.wh-field--consent label { display: flex; align-items: flex-start; gap: .6rem; font-size: var(--wh-fs-xs); color: var(--wh-muted); }
.wh-field--consent input { margin-top: .22rem; accent-color: var(--wh-primary); }
.wh-field--consent a { color: var(--wh-sky); text-decoration: underline; }

/* La trampa para robots no puede usar display:none: algunos rellenadores la
   detectan. Se saca de la pantalla en su lugar. */
.wh-hp {
	position: absolute !important;
	left: -9999px;
	width: 1px;
	height: 1px;
	overflow: hidden;
}

.wh-form__actions { display: flex; flex-wrap: wrap; align-items: center; gap: 1rem; }
.wh-form__note { font-size: var(--wh-fs-xs); color: var(--wh-muted); }

.wh-form__msg { font-size: var(--wh-fs-sm); }
.wh-form__msg:empty { display: none; }
.wh-form__msg {
	padding: .9rem 1.1rem;
	border-radius: var(--wh-radius-sm);
	border-inline-start: 3px solid var(--wh-lime);
	background: rgba(var(--wh-lime-rgb) / .1);
}
.wh-form__msg.is-error { border-inline-start-color: #F08878; background: rgba(240 136 120 / .1); }

.wh-form.is-sending { opacity: .65; pointer-events: none; }

.wh-contact { display: grid; gap: clamp(2rem, 4vw, 3.5rem); align-items: start; }
@media (min-width: 62rem) {
	.wh-contact--split { grid-template-columns: .85fr 1fr; }
}
.wh-contact__list { display: grid; gap: 1.1rem; margin: 1.8rem 0; padding: 0; list-style: none; }
.wh-contact__row { display: flex; align-items: flex-start; gap: .85rem; }
.wh-contact__icon {
	display: grid;
	place-items: center;
	flex: none;
	width: 2.5rem;
	height: 2.5rem;
	border: 1px solid rgba(var(--wh-sky-rgb) / .2);
	border-radius: var(--wh-radius-sm);
	color: var(--wh-primary);
}
.wh-contact__pair { display: grid; gap: .1rem; }
.wh-contact__label { font-family: var(--wh-font-mono); font-size: var(--wh-fs-xs); letter-spacing: .08em; text-transform: uppercase; color: var(--wh-muted); }
.wh-contact__value { font-size: var(--wh-fs-sm); }
a.wh-contact__value:hover { color: var(--wh-sky); }

.wh-comments { max-width: 74ch; margin-top: 3rem; padding-top: 2rem; border-top: 1px solid rgba(var(--wh-line-rgb) / .5); }
.wh-comments__title { margin-bottom: 1.5rem; font-size: var(--wh-fs-xl); }
.wh-comments__list { display: grid; gap: 1.5rem; margin: 0 0 2.5rem; padding: 0; list-style: none; }
.wh-comments__list ol { list-style: none; padding-inline-start: 1.5rem; }
.wh-comments .comment-body { padding: 1.2rem; border: var(--wh-hairline); border-radius: var(--wh-radius); background: var(--wh-surface); }
.wh-comments .comment-author { display: flex; align-items: center; gap: .6rem; font-weight: 600; }
.wh-comments .comment-author img { border-radius: 50%; }
.wh-comments .comment-metadata { font-size: var(--wh-fs-xs); color: var(--wh-muted); }
.wh-comments input:not([type="submit"]),
.wh-comments textarea {
	width: 100%;
	padding: .8rem 1rem;
	border: 1px solid rgba(var(--wh-sky-rgb) / .2);
	border-radius: var(--wh-radius-sm);
	background: rgba(var(--wh-base-rgb) / .55);
}

/* ============================================================
   23. Pie de pagina
   ============================================================ */

.wh-fcta { position: relative; overflow: hidden; padding-block: clamp(2.5rem, 6vw, 4.5rem); border-top: 1px solid rgba(var(--wh-line-rgb) / .5); }
.wh-fcta__in { position: relative; z-index: 2; display: grid; gap: 1.75rem; align-items: center; }
@media (min-width: 62rem) { .wh-fcta__in { grid-template-columns: 1fr auto; } }
.wh-fcta__title { font-size: var(--wh-fs-2xl); }
.wh-fcta__text { margin-top: .7rem; max-width: 58ch; color: var(--wh-muted); }
.wh-fcta__glow {
	position: absolute;
	inset: -60% -10% auto;
	height: 130%;
	background: radial-gradient(ellipse at top, rgba(var(--wh-primary-rgb) / .18), transparent 62%);
	pointer-events: none;
}

/* El pie cierra en crema, igual que la cabecera: el logotipo vuelve a leerse y
   la pagina queda enmarcada entre dos bandas claras. */
.wh-footer {
	position: relative;
	padding-block: clamp(2.5rem, 5vw, 4rem) 1.5rem;
	background:
		radial-gradient(80rem 26rem at 50% 0%, rgba(var(--wh-primary-rgb) / .07), transparent 70%),
		linear-gradient(180deg, var(--wh-footer) 0%, var(--wh-topbar) 100%);
	color: var(--wh-on-chrome);
}
.wh-footer .wh-footer__about,
.wh-footer .wh-footer__contact li,
.wh-footer .wh-fwidget { color: rgba(var(--wh-on-chrome-rgb) / .72); }
.wh-footer .wh-fwidget__title,
.wh-footer .wh-brand__text { color: var(--wh-on-chrome); }
.wh-footer a { color: inherit; }
.wh-footer a:hover { color: var(--wh-primary-deep); }
.wh-footer .wh-footer__contact svg { color: var(--wh-primary-deep); }
.wh-footer .wh-social a {
	border-color: rgba(var(--wh-on-chrome-rgb) / .18);
	color: rgba(var(--wh-on-chrome-rgb) / .7);
}
.wh-footer .wh-social a:hover { border-color: var(--wh-primary-deep); color: var(--wh-primary-deep); }
.wh-footer .wh-btn--ghost {
	border-color: rgba(var(--wh-on-chrome-rgb) / .28);
	color: var(--wh-on-chrome);
}
.wh-footer .wh-btn--ghost:hover {
	border-color: var(--wh-primary-deep);
	background: rgba(var(--wh-primary-rgb) / .1);
	color: var(--wh-primary-deep);
}
.wh-footer__grid { display: grid; gap: clamp(2rem, 4vw, 3rem); }
@media (min-width: 62rem) {
	.wh-footer__grid { grid-template-columns: 1.4fr repeat(var(--wh-fcols, 4), minmax(0, 1fr)); }
}
.wh-footer__brand { display: grid; gap: 1.1rem; align-content: start; justify-items: start; }
.wh-footer__about { max-width: 38ch; color: var(--wh-muted); font-size: var(--wh-fs-sm); }
.wh-footer__contact { display: grid; gap: .5rem; margin: 0; padding: 0; list-style: none; font-size: var(--wh-fs-sm); }
.wh-footer__contact li { display: flex; align-items: center; gap: .5rem; color: var(--wh-muted); }
.wh-footer__contact a:hover { color: var(--wh-sky); }
.wh-footer__col { display: grid; gap: 1.5rem; align-content: start; }

/* Destinos tactiles del pie en pantallas que se tocan con el dedo.
   ---------------------------------------------------------------
   Los enlaces del pie salen de widgets de menu, asi que son texto suelto: en
   movil quedaban de 18 px de alto y hay que apuntar para acertarles. Tanto
   Apple como Google recomiendan 44 px como minimo para cualquier cosa que se
   pulse con el dedo.

   Se aplica solo donde importa: en pantallas con puntero "grueso" (dedo) y en
   anchos por debajo del punto en el que el pie se reparte en columnas. En
   escritorio con raton no cambia nada.

   `inline-flex` es lo que permite que el enlace, que por naturaleza ocupa solo
   lo que mide su texto, acepte una altura minima. */
@media (pointer: coarse), (max-width: 61.99rem) {
	.wh-footer__col a,
	.wh-footer__legal a {
		display: inline-flex;
		align-items: center;
		min-height: 2.75rem;
	}
}

.wh-footer__bar {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: 1rem;
	margin-top: clamp(2rem, 4vw, 3rem);
	padding-top: 1.5rem;
	border-top: 1px solid rgba(var(--wh-line-rgb) / .5);
	font-size: var(--wh-fs-xs);
	color: var(--wh-muted);
}
.wh-footer__legal { display: flex; flex-wrap: wrap; gap: 1.1rem; margin: 0; padding: 0; list-style: none; }
.wh-footer__legal a:hover { color: var(--wh-sky); }

/* Filo de marca: recorre los tres colores del logotipo. */
.wh-footer__rule {
	position: absolute;
	inset-inline: 0;
	top: -1px;
	height: 2px;
	background: linear-gradient(90deg,
		transparent 0%,
		rgba(var(--wh-primary-rgb) / .7) 22%,
		rgba(var(--wh-lime-rgb) / .8) 50%,
		rgba(var(--wh-gold-rgb) / .7) 78%,
		transparent 100%);
}

.wh-footer__bar {
	border-top-color: rgba(var(--wh-on-chrome-rgb) / .14);
	color: rgba(var(--wh-on-chrome-rgb) / .58);
}
.wh-footer__legal a:hover { color: var(--wh-primary-deep); }

.wh-totop,
.wh-wa {
	position: fixed;
	bottom: 1.5rem;
	z-index: 90;
	display: grid;
	place-items: center;
	width: 3rem;
	height: 3rem;
	border-radius: 50%;
	cursor: pointer;
	transition: opacity var(--wh-dur) var(--wh-ease), transform var(--wh-dur) var(--wh-ease-out), visibility var(--wh-dur);
}
.wh-totop {
	inset-inline-end: 1.5rem;
	border: 1px solid rgba(var(--wh-sky-rgb) / .22);
	background: var(--wh-surface);
	color: var(--wh-text);
	opacity: 0;
	visibility: hidden;
	transform: translateY(12px);
}
.wh-totop.is-on { opacity: 1; visibility: visible; transform: translateY(0); }
.wh-totop:hover { border-color: var(--wh-primary); }

.wh-wa {
	inset-inline-start: 1.5rem;
	border: 0;
	background: #25D366;
	color: #FFF;
	box-shadow: 0 6px 24px rgba(37 211 102 / .35);
}
.wh-wa:hover { transform: translateY(-3px); }

/* ============================================================
   24. Aparicion al desplazar
   ============================================================ */

/* El estado inicial solo se aplica cuando el observador ha tomado el control,
   para que sin JavaScript el contenido se vea siempre. */
[data-wh-reveal].wh-armed > *,
[data-wh-reveal].wh-armed.wh-reveal-self {
	opacity: 0;
	transform: translateY(18px);
	transition: opacity .6s var(--wh-ease-out), transform .6s var(--wh-ease-out);
	transition-delay: calc(var(--wh-i, 0) * var(--wh-stagger, 70ms));
}

[data-wh-reveal].is-in > *,
[data-wh-reveal].is-in.wh-reveal-self { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
	[data-wh-reveal].wh-armed > * { opacity: 1; transform: none; }
}


/* ---- Zonas tactiles en pantallas pequenas -------------------------
   En un telefono, un enlace de 20 px de alto se falla al pulsar. Se les da
   altura suficiente sin cambiar como se ven: el area crece con relleno, no con
   tamano de letra. Se aplica solo por debajo de 48rem, donde se toca con el
   dedo; con raton no hace falta y ocuparia espacio de mas. */

@media (max-width: 47.99rem) {

	.wh-topbar__in { min-height: 2.9rem; }
	.wh-topbar__item {
		min-height: 2.4rem;
		padding-block: .35rem;
	}
	.wh-topbar__meta { gap: .5rem 1.1rem; flex-wrap: wrap; justify-content: center; }

	.wh-contact__value,
	.wh-footer__contact a,
	.wh-footer__legal a,
	.wh-crumbs a {
		display: inline-flex;
		align-items: center;
		min-height: 2.4rem;
	}

	/* Las migas se ponen en una sola linea desplazable en vez de partirse en
	   varias, que es lo que empuja el titulo fuera de la primera pantalla. */
	.wh-crumbs__list {
		flex-wrap: nowrap;
		overflow-x: auto;
		scrollbar-width: none;
		padding-bottom: .2rem;
	}
	.wh-crumbs__list::-webkit-scrollbar { display: none; }
	.wh-crumbs__item { white-space: nowrap; }

	.wh-social a { width: 2.6rem; height: 2.6rem; }
	.wh-share__list a,
	.wh-share__list button { width: 2.6rem; height: 2.6rem; }
	.wh-pager a, .wh-pager span { min-height: 2.6rem; }
	/* Con .3rem el enlace se quedaba en 31,9 px, justo por debajo del minimo
	   que se pide para pulsar con el dedo. Medido en el sitio: la linea ocupa
	   unos 22 px, asi que hacen falta cerca de 9 px arriba y abajo. */
	.wh-toc a { display: inline-block; padding-block: .55rem; }

	/* Las etiquetas, con altura suficiente para el pulgar.
	   El relleno va en el ENLACE, no en la pastilla: es el enlace lo que
	   responde al toque, y darle altura a la pastilla no se la da a el. Los
	   margenes negativos cancelan ese relleno de mas, asi que la pastilla se
	   sigue viendo del mismo tamano. */
	.wh-pill > a { padding-block: .62rem; margin-block: -.62rem; }

	/* Las casillas de los formularios venian con el tamano de fabrica del
	   navegador: 13 px. Es la mitad de lo que se puede pulsar con fiabilidad, y
	   la de «guardar mis datos» del formulario de comentarios es la que mas se
	   falla.

	   El `:not(.wh-chipset__input)` NO es un adorno: esas casillas estan
	   escondidas a proposito (1 px, opacidad 0) porque quien recibe el toque es
	   la ficha de al lado. Sin la exclusion, esta regla las agranda a 32 px y
	   deshace ese apano. */
	.wh-form input[type="checkbox"]:not(.wh-chipset__input),
	.wh-form input[type="radio"]:not(.wh-chipset__input),
	.comment-form input[type="checkbox"] {
		width: 2rem;
		height: 2rem;
	}

	/* Las fichas del formulario son el control principal en movil: se agrandan
	   para poder elegir con el pulgar sin apuntar. */
	.wh-chipset__chip { min-height: 2.6rem; padding: .6rem 1rem; }
	.wh-field--consent label { min-height: 2.4rem; }
}


/* El indicador de "sigue bajando" solo tiene sentido en un hero alto de
   escritorio. En un telefono queda flotando entre el contenido y no aporta
   nada: ahi ya se entiende que la pagina sigue. */
@media (max-width: 46rem) {
	.wh-hero__hint { display: none; }
	/* Sin el indicador, el hero puede respirar menos por abajo. */
	.wh-hero--tall,
	.wh-hero--full { min-height: 0; }
	.wh-hero { padding-block: clamp(3.5rem, 12vw, 6rem) clamp(2.5rem, 8vw, 4rem); }
}

/* Entre tableta y escritorio pequeno la orbita se queda justa: ocho nodos
   sobre una circunferencia de ese radio se tocan entre si. Se achican las
   fichas en ese tramo en lugar de agrandar la orbita, que ahi no cabe. */
@media (min-width: 46.01rem) and (max-width: 68rem) {
	.wh-orbit { max-width: 34rem; }
	.wh-orbit__inner {
		font-size: .78rem;
		padding: .35rem .7rem;
		gap: .35rem;
	}
	.wh-orbit__inner svg { width: 14px; height: 14px; }
}
