/* ============================================================
   Kenzen Page System — molde de páginas
   ============================================================

   Construido sobre las MISMAS variables de marca que Kenzen Landing System y
   Kenzen Blog System (`--kls-ruby`, `--kls-bg-dark`, `--kls-text`…), para que
   los tres vayan a juego y sigan el mismo color de acento.

   Nunca escribir un color literal aquí: rompería la multi-marca en silencio
   —se vería bien en Kenzen y mal en las demás—. Es el fallo que hubo que
   sanear en julio de 2026 en los otros dos plugins.

   El `:root` define los valores por defecto, así que este fichero funciona
   solo aunque los otros plugins no estén.
   ============================================================ */

:root {
  --kls-ruby:            #c41230;
  --kls-ruby-rgb:        196,18,48;
  --kls-ruby-light:      #e8193a;
  --kls-ruby-dark:       #8b0010;
  --kls-dark-rgb:        11,18,32;
  --kls-bg-dark:         #0B1220;
  --kls-bg-page:         #ffffff;
  --kls-bg-alt:          #F7F7F7;
  --kls-text:            #0B1220;
  --kls-text-muted:      #3D4A60;
  --kls-text-subtle:     #8A8578;
  --kls-font-sans:       'Plus Jakarta Sans', -apple-system, BlinkMacSystemFont, sans-serif;
  --kls-font-display:    'Plus Jakarta Sans', -apple-system, BlinkMacSystemFont, sans-serif;

  /* Los usan los campos de formulario del hueco (más abajo, con `!important`).
     Faltaban aquí: los define `kenzen-landing.css`, que en una página KPS no
     se encola, así que `var(--kls-radius)` quedaba sin valor y el navegador
     **descartaba la declaración entera** — los campos salían con las esquinas
     rectas. Mismos valores que en KLS, que es de donde vienen. */
  --kls-radius:          8px;
  --kls-radius-lg:       12px;

  --kps-container:       1200px;
  --kps-radius:          12px;
  --kps-section-py:      clamp(3rem, 7vw, 5.5rem);
}

/* ── Shell ──────────────────────────────────────────────────── */
.kps-shell {
  font-family: var(--kls-font-sans);
  color: var(--kls-text);
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

.kps-shell *,
.kps-shell *::before,
.kps-shell *::after {
  box-sizing: border-box;
}

/* ── Enlaces dentro de los textos (v0.2.42) ───────────────────
   Desde la 0.2.42 todo texto que no sea un título admite HTML, así que el
   enlace dentro de una frase deja de ser un caso raro.

   Hasta entonces no había ninguna regla para ellos y **no se veían**: KPS no
   estilaba los enlaces en línea, el tema tampoco los subraya, y el enlace
   heredaba el color del párrafo. Se comprobó en la portada de
   estherperarnau.com el 4 sep 2026 — el enlace estaba en el HTML y en la
   captura era indistinguible del resto de la frase.

   Subrayado **siempre**, y color de acento solo donde se lee. Es la misma
   regla que `.kenzen-blog-content__body a` de KBS, para que un texto se vea
   igual en un artículo y en una página.

   ⚠️ **En el acento OSCURO, no en el pelado** (desde la 0.3.16). En
   medicina-integrativa.eu el acento es #0085bd y da 4,13 sobre blanco, por
   debajo del 4,5 que pide un texto de párrafo; `--kls-ruby-dark` llega a 8,91.
   Es la regla de `kps-acc-meta`: el problema es el color, no el tamaño.

   ⚠️ **`.kps-acc__body` faltaba en la lista.** Los enlaces del acordeón no
   tenían regla y cogían el azul de fábrica de Divi (#2ea3f2, 2,75:1): se vio
   en la comparativa del Máster, auditoría del 28 sep 2026. Si se añade otro
   contenedor de texto con HTML, va en las dos listas de aquí abajo. */
.kps-hero__lead a,
.kps-block__text a,
.kps-block__media-text a,
.kps-card__text a,
.kps-cta__text a,
.kps-banner__text a,
.kps-acc__body a {
  color: var(--kls-ruby-dark);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
  transition: opacity 0.2s;
}

/* Sobre fondo lleno —hero con foto o color, banda del CTA y la barra— el acento
   no llega al contraste mínimo: medido el 25 ago 2026 sobre el oscuro de
   esther-cursos daba 1,91:1. Así que ahí el enlace se distingue de otra forma:
   **blanco puro contra el 74-82 % del párrafo**, más el subrayado.

   Dos señales y no una a propósito. El subrayado solo no basta cuando debajo
   hay una foto: la línea cae sobre lo que haya —agua, cielo, un hombro— y se
   pierde. El salto de brillo se ve siempre, aunque el subrayado quede sobre una
   zona clara.

   El `#fff` literal es el mismo caso que el de la cuenta atrás, más abajo: no
   es un color de marca, es «texto sobre fondo lleno». Escribir aquí un color de
   marca sí rompería la multi-marca. */
.kps-hero--invertido .kps-hero__lead a,
.kps-cta__text a,
.kps-banner__text a {
  color: #fff;
  text-decoration-thickness: 2px;
  text-decoration-color: rgba(255, 255, 255, 0.85);
}

.kps-hero__lead a:hover,
.kps-block__text a:hover,
.kps-block__media-text a:hover,
.kps-card__text a:hover,
.kps-cta__text a:hover,
.kps-banner__text a:hover,
.kps-acc__body a:hover {
  opacity: 0.75;
}

.kps-container {
  max-width: var(--kps-container);
  margin-inline: auto;
  padding-inline: clamp(1.25rem, 5vw, 3rem);
}

.kps-highlight {
  color: var(--kls-ruby);
}

/* ── Hero ───────────────────────────────────────────────────── */
/* ── El relleno del hero, y lo que le descuenta la barra ──────
   Los dos rellenos viven en variables para que la resta de abajo se escriba
   **una sola vez**: la variante con foto solo cambia los valores.

   `--kps-banner-compensa` es la mitad de la altura de la barra superior, y la
   publica un script en línea justo después de pintarla (ver `banner.php`).
   Con la barra puesta, el hero se recorta esa mitad por arriba y otra tanto por
   abajo, así que el conjunto sigue ocupando lo mismo en pantalla que antes de
   añadirla. Sin barra vale `0px` y no cambia nada.

   El `max()` es el suelo: con una barra muy alta —dos líneas de texto en móvil—
   la resta se comería el relleno entero y el título quedaría pegado al borde. */
/* ── El hueco de la cabecera ─────────────────────────────────
   Solo cuando la barra de la oferta va ENCIMA del hero. Entonces lo primero
   de la página es una tira de unos 60px y, con un tema de cabecera
   transparente que no reserva sitio —Divi con `et_transparent_nav`—, se mete
   entera debajo del menú. El hero no lo necesita: su relleno superior ya es
   más alto que cualquier cabecera.

   El valor lo publica `KPS_Assets::print_chrome_offset_script()` midiendo el
   solape en el navegador. Si ese script no corre —respaldo estático, u
   optimizador que lo aplace— cae a `0px` y queda como si no existiera. */
.kps-shell--hueco {
  padding-top: var(--kps-chrome-offset, 0px);
}

.kps-hero {
  --kps-hero-pt: clamp(3.5rem, 9vw, 6.5rem);
  --kps-hero-pb: clamp(2rem, 5vw, 3.5rem);
  padding-block:
    max(1.5rem, calc(var(--kps-hero-pt) - var(--kps-banner-compensa, 0px)))
    max(1.5rem, calc(var(--kps-hero-pb) - var(--kps-banner-compensa, 0px)));
  background: linear-gradient(
    to bottom,
    rgba(var(--kls-ruby-rgb), 0.10) 0%,
    rgba(var(--kls-ruby-rgb), 0.04) 45%,
    var(--kls-bg-page) 100%
  );
}

/* ── Hero sobre color de marca ───────────────────────────────
   Variante 'marca': fondo sólido y todo el contenido en blanco. Hay que
   invertir también etiqueta y botones — si no, la etiqueta queda blanca sobre
   blanco y el botón primario, rubí sobre rubí: invisibles los dos.
   El resaltado del título se queda en blanco puro y el resto baja a 88 %, que
   es lo que mantiene el contraste entre ambos cuando ya no puede haber color. */
.kps-hero--marca {
  background: var(--kls-ruby);
}

/* ── Hero sobre un color cualquiera ──────────────────────────
   Igual que la de marca, con el color que se elija en el editor. El valor
   llega en `--kps-hero-bg` por atributo `style`, no como un `background`
   escrito en línea: así el fondo lo sigue decidiendo esta hoja y no el HTML.
   La reserva a `--kls-ruby` no debería llegar a usarse —la plantilla convierte
   en 'marca' un hero de color sin color—, pero deja la regla completa por sí
   sola. */
.kps-hero--color {
  background: var(--kps-hero-bg, var(--kls-ruby));
}

/* ── Hero con imagen a sangre completa ───────────────────────
   La foto va en un <img> y no en `background-image` a propósito: así se
   lleva el `srcset` de WordPress —un móvil no se descarga la de 2560 px— y
   admite `fetchpriority`, que es lo que la adelanta en la cola de descarga.
   Hereda todas las inversiones de la variante de marca (ver el selector
   agrupado de abajo): sobre foto oscura el problema de contraste es el
   mismo. */
.kps-hero--imagen {
  position: relative;
  isolation: isolate;
  background: var(--kls-bg-dark);
}

/* El reparto del hero claro es asimétrico a propósito —mucho arriba, poco
   abajo— porque su degradado se funde con la página y el corte no se ve. Con
   foto sí se ve: hay un canto duro arriba y otro abajo, y ese mismo reparto
   deja el contenido pegado al de arriba. Aquí va espacio generoso y casi
   simétrico, con algo más abajo, que es donde el ojo pide aire cuando el
   bloque de texto se lee alineado al centro.
   Solo toca la variante con foto: los heros claro y de marca no se mueven. */
.kps-hero--imagen {
  --kps-hero-pt: clamp(5rem, 11vw, 8.5rem);
  --kps-hero-pb: clamp(5.5rem, 12vw, 9rem);
}

.kps-hero--imagen .kps-hero__bg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center var(--kps-foco, 50%);
  z-index: -2;
}

/* El velo garantiza el contraste con cualquier foto, no solo con una oscura.
   Va más cargado abajo, que es donde caen los botones.

   Tres intensidades desde la v0.2.20, elegibles por página: el texto del hero
   va siempre en blanco, así que una foto clara necesita bastante más velo que
   una oscura para que se lea. Antes era fijo y obligaba a retocar la foto
   fuera de WordPress. 'medio' es el valor con el que nació la variante, así
   que las páginas que ya existen no cambian.

   Y desde la v0.2.22 también se puede elegir el TINTE, que es otra cosa: la
   intensidad decide cuánto tapa y el tinte de qué color tapa. Va en
   `--kps-velo-rgb` y en RGB sueltos porque los tres degradados son `rgba()`
   con distinta opacidad — un hex no encajaría ahí. Sin elegir nada manda el
   color oscuro de la marca, que es lo que se hacía siempre. */
.kps-hero--imagen .kps-hero__velo {
  position: absolute;
  inset: 0;
  z-index: -1;
}

.kps-hero__velo--suave {
  background: linear-gradient(
    to bottom,
    rgba(var(--kps-velo-rgb, var(--kls-dark-rgb)), 0.28) 0%,
    rgba(var(--kps-velo-rgb, var(--kls-dark-rgb)), 0.36) 55%,
    rgba(var(--kps-velo-rgb, var(--kls-dark-rgb)), 0.52) 100%
  );
}

.kps-hero__velo--medio {
  background: linear-gradient(
    to bottom,
    rgba(var(--kps-velo-rgb, var(--kls-dark-rgb)), 0.55) 0%,
    rgba(var(--kps-velo-rgb, var(--kls-dark-rgb)), 0.62) 55%,
    rgba(var(--kps-velo-rgb, var(--kls-dark-rgb)), 0.78) 100%
  );
}

.kps-hero__velo--fuerte {
  background: linear-gradient(
    to bottom,
    rgba(var(--kps-velo-rgb, var(--kls-dark-rgb)), 0.74) 0%,
    rgba(var(--kps-velo-rgb, var(--kls-dark-rgb)), 0.80) 55%,
    rgba(var(--kps-velo-rgb, var(--kls-dark-rgb)), 0.90) 100%
  );
}

.kps-hero--imagen .kps-hero__inner {
  position: relative;
  text-shadow: 0 1px 24px rgba(0, 0, 0, 0.35);
}

/* ── El texto en el tercio inferior (v0.2.39) ────────────────
   Para qué: con una persona en el centro del encuadre no se puede poner el
   texto centrado encima — le cae en la cara. Lo que se hacía era empujar el
   texto a un lado, que descuadra la página entera y además hay que calcularlo
   para esa foto concreta. Bajándolo, el texto se queda centrado en el eje de
   la página y la cara se ve entera encima.

   La altura mínima es lo que crea el hueco: sin ella el hero mide lo que mide
   su contenido y «abajo» no significaría nada. `min()` para que en una
   pantalla baja no se coma la página y en una alta no se estire sin fin.

   El `flex-end` convive con el `padding-block` del hero: el relleno de abajo
   sigue separando el texto del canto, y el de arriba sigue compensando la
   barra si la hay. */
.kps-hero--contenido-abajo {
  min-height: min(80vh, 46rem);
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
}

/* Refuerzo del velo por abajo, solo en esta variante.

   ⚠ Es obligatorio, y no es adorno: el texto va en blanco y el sitio donde
   ahora cae —el tercio inferior— es justo donde suele estar lo más claro de
   una foto. Se hace con una capa aparte y no retocando los tres degradados
   para que **la intensidad siga significando lo mismo**: quien eligió
   «suave» no ve de pronto un velo medio en toda la foto, solo algo más de
   peso donde hay letras. */
.kps-hero--contenido-abajo .kps-hero__velo::after {
  content: "";
  position: absolute;
  inset: auto 0 0 0;
  height: 55%;
  background: linear-gradient(
    to top,
    rgba(var(--kps-velo-rgb, var(--kls-dark-rgb)), 0.45) 0%,
    rgba(var(--kps-velo-rgb, var(--kls-dark-rgb)), 0) 100%
  );
}

/* ── Contenido sobre fondo lleno ─────────────────────────────
   Lo que comparten las variantes 'marca', 'color' e 'imagen': el texto va en
   blanco, y con él hay que invertir etiqueta y botones o desaparecen.

   La clase `--invertido` la pone la plantilla junto a la variante concreta.
   Antes cada una de estas reglas iba con los selectores repetidos uno por
   variante, y añadir la tercera habría significado tocar las doce.

   ⚠ El HTML de respaldo de las páginas guardadas antes de la v0.2.22 no lleva
   esta clase, pero tampoco esta hoja: `render_static()` incrusta una copia del
   CSS del momento junto al marcado, así que cada respaldo es coherente consigo
   mismo. */
.kps-hero--invertido .kps-hero__title { color: rgba(255, 255, 255, 0.88); }
.kps-hero--invertido .kps-highlight { color: #fff; }
/* ⚠️ **El párrafo va en blanco PLENO** (desde la 0.3.20). Estaba al 82 % y, con
   19 px, pide 4,5: sobre el azul de medicina se quedaba en 3,27. En pleno llega
   a 4,13 — el techo lo pone ahí el propio acento, no la opacidad. El título sí
   puede ir atenuado: a su tamaño basta 3:1. Auditoría del 28 sep 2026. */
.kps-hero--invertido .kps-hero__lead { color: #fff; }

.kps-hero--invertido .kps-badge {
  background: rgba(255, 255, 255, 0.14);
  border-color: rgba(255, 255, 255, 0.28);
  box-shadow: none;
  color: #fff;
}
.kps-hero--invertido .kps-badge__dot { background: #fff; }

/* El botón primario toma el color del fondo sobre el que se recorta: en la
   variante de color a medida, el rubí de la marca cantaría. */
.kps-hero--invertido .kps-btn--primario {
  background: #fff;
  color: var(--kps-hero-bg, var(--kls-ruby));
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.18);
}
.kps-hero--invertido .kps-btn--primario:hover {
  background: rgba(255, 255, 255, 0.9);
  color: var(--kps-hero-bg, var(--kls-ruby-dark));
}

.kps-hero--invertido .kps-btn--secundario {
  background: transparent;
  color: #fff;
  border-color: rgba(255, 255, 255, 0.55);
}
.kps-hero--invertido .kps-btn--secundario:hover {
  border-color: #fff;
  background: rgba(255, 255, 255, 0.1);
}

.kps-hero__inner {
  text-align: center;
  max-width: 900px;
}

.kps-hero__title {
  font-family: var(--kls-font-display);
  font-size: clamp(2rem, 5.5vw, 3.4rem);
  font-weight: 800;
  line-height: 1.08;
  letter-spacing: -0.035em;
  color: var(--kls-text);
  margin: 0 0 1rem;
}

.kps-hero__lead {
  font-size: clamp(1rem, 2.3vw, 1.2rem);
  color: var(--kls-text-muted);
  line-height: 1.7;
  margin: 0 auto 2rem;
  max-width: 68ch;
}

/* ── Etiqueta ───────────────────────────────────────────────── */
.kps-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.55em;
  padding: 0.45em 1em;
  margin-bottom: 1.5rem;
  border-radius: 999px;
  background: var(--kls-bg-page);
  border: 1px solid rgba(var(--kls-dark-rgb), 0.08);
  box-shadow: 0 2px 10px rgba(var(--kls-dark-rgb), 0.05);
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--kls-text-muted);
}

.kps-badge__dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--kls-ruby);
}

/* ── Botones ────────────────────────────────────────────────── */
.kps-btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  justify-content: center;
}

.kps-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0.8em 1.5em;
  border-radius: 8px;
  font-size: 0.95rem;
  font-weight: 700;
  text-decoration: none;
  transition: transform 0.18s, box-shadow 0.18s, background 0.18s;
}

.kps-btn--primario {
  background: var(--kls-ruby);
  color: #fff;
  box-shadow: 0 6px 20px rgba(var(--kls-ruby-rgb), 0.28);
}

.kps-btn--primario:hover {
  background: var(--kls-ruby-dark);
  transform: translateY(-1px);
  color: #fff;
}

.kps-btn--secundario {
  background: var(--kls-bg-page);
  color: var(--kls-text);
  border: 1px solid rgba(var(--kls-dark-rgb), 0.12);
}

.kps-btn--secundario:hover {
  border-color: rgba(var(--kls-dark-rgb), 0.24);
  transform: translateY(-1px);
}

/* ── Bloque ─────────────────────────────────────────────────── */
.kps-block {
  padding-block: var(--kps-section-py);
  background: transparent;
}

.kps-block--gris {
  background: var(--kls-bg-alt);
}

/* Primer bloque sin cabecera, justo debajo del hero.

   Los dos rellenos se suman —hasta 3,5rem del hero abajo más 5,5rem del bloque
   arriba— y, sin cabecera que los ocupe, eso es un vacío de 9rem entre el texto
   del hero y el contenido. Se ve en cualquier página cuyo primer bloque sea un
   listado: la de blog, sin ir más lejos.

   El selector es adyacente a propósito. Entre dos bloques ese relleno sí separa
   dos secciones y no se toca; y si el hero está apagado, tampoco: entonces el
   bloque es lo primero de la página y necesita su aire.

   Solo se recorta ARRIBA. El de abajo separa del bloque siguiente o del CTA. */
.kps-hero + .kps-block--sin-cabecera {
  padding-block-start: clamp(0.5rem, 2vw, 1.25rem);
}

.kps-block__head {
  text-align: center;
  max-width: 780px;
  margin: 0 auto clamp(2rem, 5vw, 3.5rem);
}

.kps-kicker {
  display: inline-block;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--kls-ruby);
  margin-bottom: 0.9rem;
}

.kps-kicker--inv {
  color: var(--kls-ruby-light);
}

.kps-block__title {
  font-family: var(--kls-font-display);
  font-size: clamp(1.6rem, 4vw, 2.4rem);
  font-weight: 800;
  line-height: 1.16;
  letter-spacing: -0.03em;
  color: var(--kls-text);
  margin: 0 0 0.9rem;
}

/* `div`, no `p`, desde la v0.2.19. El texto admite `<p>`, `<ul>` y `<li>` por
   `allowed_html()`, y ninguno de los tres puede ir dentro de un párrafo: el
   navegador cerraba el envoltorio por su cuenta y dejaba un párrafo vacío
   ocupando su margen. Los márgenes se gobiernan ahora desde los hijos. */
.kps-block__text {
  font-size: 1.02rem;
  color: var(--kls-text-muted);
  line-height: 1.75;
  margin: 0;
}

.kps-block__text > :first-child { margin-top: 0; }
.kps-block__text > :last-child  { margin-bottom: 0; }
.kps-block__text p              { margin: 0 0 1em; }
.kps-block__text ul,
.kps-block__text ol             { margin: 0 0 1em; padding-left: 1.25em; }
.kps-block__text li             { margin-bottom: 0.4em; }

.kps-block__slot {
  margin-top: 0.5rem;
}

/* ── Vídeo del bloque (v0.2.38) ──────────────────────────────
   Va entre la cabecera y el hueco, centrado y con un ancho máximo: a todo el
   ancho de un contenedor de 1.100 px un 16:9 mide casi 620 px de alto y se come
   la pantalla entera de un portátil.

   `aspect-ratio` en vez del truco del padding: la caja tiene que tener alto
   ANTES de que se sustituya la portada por el iframe, o al pulsar el play la
   página pega un salto. */
.kps-block__video {
  position: relative;
  max-width: 46rem;
  margin: 0 auto 2rem;
  aspect-ratio: 16 / 9;
  border-radius: 14px;
  overflow: hidden;
  background: #000;
  box-shadow: 0 12px 32px rgba(var(--kls-dark-rgb), 0.14);
}

.kps-block__video iframe {
  width: 100%;
  height: 100%;
  border: 0;
  display: block;
}

/* La portada: la miniatura de YouTube y el botón de play. El reproductor de
   verdad no se carga hasta que se pulsa — son varios cientos de KB y cookies
   de terceros que, si nadie le da al play, no hacen ninguna falta. */
.kps-video-facade {
  width: 100%;
  height: 100%;
  border: 0;
  margin: 0;
  padding: 0;
  cursor: pointer;
  background-color: #000;
  background-size: cover;
  background-position: center;
  display: flex;
  align-items: center;
  justify-content: center;
}

.kps-video-facade__play {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 68px;
  height: 48px;
  border-radius: 14px;
  background: rgba(0, 0, 0, 0.75);
  transition: background 0.15s, transform 0.15s;
}

.kps-video-facade:hover .kps-video-facade__play,
.kps-video-facade:focus-visible .kps-video-facade__play {
  background: #c41230;
  transform: scale(1.06);
}

.kps-block__action {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  justify-content: center;
  margin-top: clamp(1.5rem, 4vw, 2.5rem);
}

/* ── Disposición con imagen al lado (v0.2.8) ─────────────────────────────
   Un eje del MISMO bloque, no una sección nueva: cambia cómo se reparte el
   espacio, no qué contiene. La cabecera deja de ir centrada porque a dos
   columnas el texto centrado se lee mal. */
.kps-block--media .kps-block__split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(2rem, 5vw, 4rem);
  align-items: center;
}

.kps-block--media .kps-block__head {
  text-align: left;
  max-width: none;
  margin: 0;
}

/* El orden lo decide el CSS, no el marcado: así el HTML sale siempre en el
   mismo orden de lectura —texto y luego imagen— y en móvil, donde las
   columnas se apilan, el texto va primero en las dos variantes. */
.kps-block--media-izquierda .kps-block__media {
  order: -1;
}

.kps-block__media {
  margin: 0;
}

.kps-block__img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--kps-radius);
  box-shadow: 0 14px 40px rgba(var(--kls-dark-rgb), 0.12);
}

/* Los botones de la columna de texto se alinean con él, no al centro. */
.kps-btn-row--inline {
  justify-content: flex-start;
  margin-top: 1.75rem;
}

@media (max-width: 860px) {
  .kps-block--media .kps-block__split {
    grid-template-columns: 1fr;
    gap: 2rem;
  }

  /* Apilado, la imagen vuelve debajo del texto también en media_izquierda. */
  .kps-block--media-izquierda .kps-block__media {
    order: 0;
  }
}

/* ── Tarjetas ───────────────────────────────────────────────── */
.kps-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 1.5rem;
}

/* ── Columnas fijas por bloque (v0.3.14) ──────────────────────
   `auto-fit` con `minmax(260px)` y 1,5rem de hueco necesita 1.112 px para
   cuatro columnas, y `.kps-container` da 1.104: un bloque de cuatro tarjetas
   sale **3 + 1**, con la última sola. Ocho píxeles.

   ⚠️ **No se arregla bajando el mínimo.** Con 250px la banda de métricas de la
   comparativa del Máster queda bien, pero los cuatro testimonios de la portada
   de Esther Perarnau —párrafos, no cifras— pasan a cuatro columnas estrechas, y
   el bloque de seis de esa misma comparativa pasa de 3 + 3 a 4 + 2. El número
   bueno depende de lo que haya DENTRO de la tarjeta, así que lo elige el bloque.

   ⚠️ **Y no se declaran con `minmax(0, 1fr)` por capricho.** Con `1fr` a secas,
   una palabra larga sin espacios —una URL en el texto de una tarjeta— ensancha
   su columna por encima del reparto y descuadra la fila entera: el mínimo
   implícito de una pista de rejilla es `auto`, no cero. */
.kps-cards--cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.kps-cards--cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.kps-cards--cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }

/* Por debajo del contenedor completo, las columnas fijas no caben: 4 y 3 pasan
   a 2 antes de apilarse del todo en el móvil (la regla de 640px, más abajo).
   Sin este escalón, cuatro columnas a 700px de ancho dan tarjetas de 160px. */
@media (max-width: 1100px) {
  .kps-cards--cols-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 860px) {
  .kps-cards--cols-3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

.kps-card {
  display: block;
  padding: 1.75rem;
  border-radius: var(--kps-radius);
  background: var(--kls-bg-page);
  border: 1px solid rgba(var(--kls-dark-rgb), 0.07);
  box-shadow: 0 4px 16px rgba(var(--kls-dark-rgb), 0.05);
  text-decoration: none;
  color: inherit;
  transition: transform 0.2s, box-shadow 0.2s;
}

.kps-card--link:hover {
  transform: translateY(-3px);
  box-shadow: 0 12px 32px rgba(var(--kls-dark-rgb), 0.10);
}

.kps-card__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 46px;
  height: 46px;
  border-radius: 10px;
  background: rgba(var(--kls-ruby-rgb), 0.08);
  color: var(--kls-ruby);
  font-size: 1.15rem;
  margin-bottom: 1.1rem;
}

/* El icono es un SVG incrustado desde la v0.2.6, no un glifo: `font-size` no
   lo dimensiona. Sin ancho ni alto el navegador lo pinta a 300x150 y revienta
   la tarjeta. Con `1em` sigue al tamaño de letra de arriba, como hacía el glifo. */
.kps-card__icon svg {
  width: 1em;
  height: 1em;
  flex-shrink: 0;
}

/* La foto de la tarjeta (v0.2.38). Ocupa el sitio del icono y es bastante más
   grande que él: es una cara, y a 46 px no se reconoce a nadie.

   `aspect-ratio` + `object-fit: cover` para que un retrato que no venga
   cuadrado no salga deformado — llegan de donde llegan, y el recorte centrado
   acierta casi siempre con una cara. El borde claro la despega de la tarjeta
   cuando la foto tiene el fondo blanco, que si no parece flotar. */
.kps-card__foto {
  display: block;
  width: 88px;
  height: 88px;
  margin-bottom: 1.1rem;
  border-radius: 50%;
  overflow: hidden;
  background: rgba(var(--kls-dark-rgb), 0.06);
  box-shadow: 0 0 0 3px rgba(var(--kls-dark-rgb), 0.06);
}

.kps-card__foto img {
  width: 100%;
  height: 100%;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  display: block;
}

/* ── Tarjeta con cubierta (card_media: portada) ─────────────────
   La foto ocupa la cabecera de la tarjeta a sangre. La tarjeta pierde el
   relleno superior y lo recupera el contenido, para que la imagen llegue
   a los bordes sin que el texto se pegue a ellos. */
/* Con cubierta, las columnas tienen ancho máximo y la rejilla se centra.
   Sin esto una sola tarjeta se estira a los 1080 px del contenedor y la
   portada sale gigante — que es justo el caso de un catálogo que empieza
   con un curso. Con tres vuelve a llenar la fila. */
.kps-cards--portada {
  grid-template-columns: repeat(auto-fit, minmax(260px, 340px));
  justify-content: center;
}

.kps-cards--portada .kps-card {
  padding-top: 0;
  overflow: hidden;
}

.kps-card__portada {
  display: block;
  margin: 0 0 1.1rem;
  /* Compensa el relleno lateral de la tarjeta para llegar a los bordes. */
  margin-inline: calc(-1 * var(--kps-card-padding, 1.6rem));
  background: rgba(var(--kls-dark-rgb), 0.06);
  line-height: 0;
}

.kps-card__portada img {
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 10;
  object-fit: cover;
  display: block;
}

/* ── Botón de la tarjeta ────────────────────────────────────────
   Es un `span`, no un enlace: la tarjeta entera ya va envuelta en uno.
   `margin-top:auto` lo pega abajo, así que en una fila de tarjetas de
   texto desigual todos los botones quedan a la misma altura. */
.kps-card__btn {
  align-self: flex-start;
  margin-top: auto;
  padding: 0.55em 1.15em;
  border-radius: 8px;
  background: var(--kls-c-ruby, var(--kls-ruby));
  color: #fff;
  font-size: 0.86rem;
  font-weight: 700;
  line-height: 1.2;
  text-decoration: none;
  transition: transform 0.2s, box-shadow 0.2s;
}

.kps-card--link:hover .kps-card__btn {
  transform: translateY(-1px);
  box-shadow: 0 6px 18px rgba(var(--kls-dark-rgb), 0.22);
}

/* Para que `margin-top:auto` empuje, la tarjeta tiene que ser una columna
   flexible; hasta ahora le bastaba con `display:block`. */
.kps-card {
  display: flex;
  flex-direction: column;
}

.kps-card__title {
  font-family: var(--kls-font-display);
  font-size: 1.12rem;
  font-weight: 700;
  line-height: 1.3;
  color: var(--kls-text);
  margin: 0 0 0.6rem;
}

.kps-card__text {
  font-size: 0.95rem;
  color: var(--kls-text-muted);
  line-height: 1.7;
  margin: 0;
}


/* ── Acordeón (v0.3.6) ──────────────────────────────────────────
   Contenido largo plegado: un `<details>` por ítem. Lo abre el navegador, así
   que funciona sin JS, se abre solo al buscar con Ctrl+F y responde al teclado.
   Ver `templates/sections/accordion.php`. */
.kps-acc {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  text-align: left;
  /* El acordeón vive en el hueco del bloque, y la cabecera del bloque va
     centrada: sin esto heredaría el centrado y un temario centrado no se lee. */
  max-width: 900px;
  margin-inline: auto;
  width: 100%;
}

.kps-acc__item {
  border: 1px solid rgba(var(--kls-dark-rgb), 0.09);
  border-radius: var(--kps-radius);
  background: var(--kls-bg-page);
  box-shadow: 0 2px 10px rgba(var(--kls-dark-rgb), 0.04);
  overflow: hidden;
  transition: box-shadow 0.2s, border-color 0.2s;
}

.kps-acc__item[open] {
  border-color: rgba(var(--kls-ruby-rgb), 0.28);
  box-shadow: 0 10px 30px rgba(var(--kls-dark-rgb), 0.08);
}

.kps-acc__head {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 1.15rem 1.4rem;
  cursor: pointer;
  /* El triángulo de serie del navegador se quita para poner el signo propio:
     en Safari hace falta el pseudo-elemento, en el resto basta `list-style`. */
  list-style: none;
  transition: background 0.2s;
}

.kps-acc__head::-webkit-details-marker { display: none; }

.kps-acc__head:hover {
  background: rgba(var(--kls-ruby-rgb), 0.03);
}

/* El foco se ve, y se ve DENTRO: un `outline` normal se lo comería el
   `overflow:hidden` del ítem. */
.kps-acc__head:focus-visible {
  outline: 2px solid var(--kls-ruby);
  outline-offset: -2px;
}

.kps-acc__text {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  flex: 1 1 auto;
  min-width: 0;
}

.kps-acc__badge {
  font-size: 0.7rem;
  font-weight: 800;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--kls-ruby);
}

.kps-acc__title {
  font-family: var(--kls-font-display);
  font-size: 1.15rem;
  font-weight: 700;
  line-height: 1.3;
  color: var(--kls-text);
}

.kps-acc__sub {
  font-size: 0.9rem;
  line-height: 1.5;
  color: var(--kls-text-muted);
}

/* El signo: `+` cerrado, `−` abierto. Con caracteres y no con un SVG girado,
   que es una pieza menos que mantener y no se descuadra al cambiar de fuente. */
.kps-acc__head::after {
  content: '+';
  flex: none;
  width: 2rem;
  height: 2rem;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: rgba(var(--kls-ruby-rgb), 0.08);
  color: var(--kls-ruby);
  font-size: 1.25rem;
  font-weight: 700;
  line-height: 1;
}

.kps-acc__item[open] .kps-acc__head::after {
  content: '−';
  background: var(--kls-ruby);
  color: #fff;
}

.kps-acc__body {
  padding: 0.25rem 1.4rem 1.5rem;
  border-top: 1px solid rgba(var(--kls-dark-rgb), 0.06);
  margin-top: 0.25rem;
  font-size: 0.95rem;
  line-height: 1.7;
  color: var(--kls-text-muted);
}

.kps-acc__body > *:first-child { margin-top: 1rem; }

.kps-acc__body p { margin: 0 0 0.9rem; }
.kps-acc__body p:last-child { margin-bottom: 0; }

.kps-acc__body ul,
.kps-acc__body ol {
  margin: 0 0 1rem;
  padding-left: 1.1rem;
}

.kps-acc__body li { margin-bottom: 0.35rem; }

/* Los rótulos de dentro —«PRESENCIAL», «ONLINE PREGRABADO»— van como párrafo
   con una clase, porque la lista blanca de KPS no admite encabezados: un `<h4>`
   dentro de un campo de texto se escaparía a la vista.

   Son la única señal de que el formato cambia —se pasa de días presenciales a
   vídeo pregrabado— y en gris apagado se leían como un rótulo más. Van en
   destacado sobre fondo lleno para que la división se vea sin buscarla.

   ⚠️ `inline-block` para que el fondo abrace al texto: en un párrafo normal la
   banda cruzaría el ancho entero y parecería un separador de sección, no una
   etiqueta. Y el radio es el de la casa, no una píldora: el rótulo largo
   —«ONLINE PREGRABADO · A visualizar antes del Módulo N Presencial»— parte en
   dos líneas en móvil, y una píldora partida solo redondea los extremos. */
.kps-acc__body .kps-acc-group {
  display: inline-block;
  margin: 1.6rem 0 0.7rem;
  padding: 0.32rem 0.7rem;
  border-radius: var(--kls-radius);
  font-size: 0.72rem;
  font-weight: 800;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  background: var(--kls-destacado, var(--kls-ruby));
  color: #fff;
}

.kps-acc__body .kps-acc-group:first-child { margin-top: 0.2rem; }

/* El mismo rótulo, para lo que NO es presencial (v0.3.12).

   Un calendario del Máster alterna días en un aula con streaming y con vídeo
   pregrabado, y esa es la primera pregunta de quien lo consulta: ¿tengo que ir?
   Con un solo color, la respuesta estaba únicamente en la palabra. Los bloques
   del calendario viejo sí la distinguían —azul el streaming, naranja el
   presencial— y al pasarlo a KPS se perdía.

   ⚠️ **En `-dark`, no en el acento pelado.** El acento de
   medicina-integrativa.eu es #0085bd y da **4,13** con texto blanco: por debajo
   del 4,5 que pide un texto de 0,72rem, aunque vaya en negrita —el umbral de
   texto grande empieza en 18,66px—. `--kls-ruby-dark` es el mismo azul derivado
   y llega a 8,91. Mismo motivo que `kps-acc-meta`, y el mismo techo de siempre:
   subir la opacidad no arregla un color que no llega. */
.kps-acc__body .kps-acc-group--online {
  background: var(--kls-ruby-dark, var(--kls-ruby));
}

.kps-acc__body .kps-acc-session {
  margin: 0 0 0.4rem;
  font-weight: 700;
  color: var(--kls-text);
}

/* Rótulo de apartado DENTRO de una sesión larga: parte su contenido en bloques,
   cada uno con su propia lista debajo. P12.9 del temario del Máster tiene tres.
   Venían como párrafo normal, del mismo tamaño y peso que el texto, así que los
   bloques se leían como una parrafada seguida.

   ⚠️ **Más pequeño que el título de sesión, no más grande.** Es el nivel de
   debajo, y en el temario vienen escritos en MAYÚSCULAS: un `<strong>` a secas
   los dejaría pesando más que el título del que cuelgan. Negrita y espaciado
   para que se vean, 0,82rem para que no manden, y el color del texto fuerte
   —el cuerpo del desplegable es `--kls-text-muted`, más claro—. */
.kps-acc__body .kps-acc-apartado {
  margin: 1.2rem 0 0.5rem;
  font-size: 0.82rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--kls-text);
}

/* Ponente y duración. En `--kls-text-subtle` quedaban planos —2,85 sobre
   blanco en medicina-integrativa.eu— y son el dato que más se busca del
   temario. Van en el acento de la marca.

   ⚠️ En el acento pelado, no: `--kls-ruby` es #0085bd ahí y da 4,13 sobre
   blanco, por debajo del 4,5 que pide un texto de este tamaño. `-dark` es el
   mismo azul derivado y llega a 8,91. */
.kps-acc__body .kps-acc-meta {
  margin: 0 0 0.6rem;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--kls-ruby-dark, var(--kls-ruby));
}

@media (max-width: 560px) {
  .kps-acc__head { padding: 1rem 1.1rem; gap: 0.7rem; }
  .kps-acc__body { padding: 0.25rem 1.1rem 1.25rem; }
  .kps-acc__title { font-size: 1.05rem; }
}

/* ── CTA final ──────────────────────────────────────────────── */
.kps-cta {
  padding-block: var(--kps-section-py);
  background: var(--kls-bg-dark);
}

.kps-cta__inner {
  text-align: center;
  max-width: 760px;
}

.kps-cta__title {
  font-family: var(--kls-font-display);
  font-size: clamp(1.5rem, 3.6vw, 2.2rem);
  font-weight: 800;
  line-height: 1.2;
  letter-spacing: -0.02em;
  color: #fff;
  margin: 0 0 0.9rem;
}

/* Mismo cambio de `p` a `div` que en el bloque, y por el mismo motivo. Aquí
   el síntoma era más visible: un hueco muerto entre el titular y el botón. */
.kps-cta__text {
  font-size: 1.02rem;
  color: rgba(255, 255, 255, 0.74);
  line-height: 1.7;
  margin: 0 0 1.75rem;
}

.kps-cta__text > :first-child { margin-top: 0; }
.kps-cta__text > :last-child  { margin-bottom: 0; }
.kps-cta__text p              { margin: 0 0 0.75em; }

/* ── Responsive ─────────────────────────────────────────────── */
@media (max-width: 640px) {
  .kps-btn-row {
    flex-direction: column;
    align-items: stretch;
  }

  .kps-cards {
    grid-template-columns: 1fr;
  }
}

/* ══════════════════════════════════════════════════════════════════════
   Ninja Forms dentro de un hueco de bloque (v0.2.7)

   Portado desde la seccion de contacto de Kenzen Landing System, donde el
   aspecto de Ninja Forms ya estaba resuelto. Se reapunta el ambito de
   .kenzen-contact__form-wrap a .kps-block__slot, asi que cualquier
   formulario metido en un bloque queda con el estilo de la casa sin
   necesidad de campos nuevos.

   Se COPIA en vez de compartirse porque los tres plugins son independientes
   a proposito, igual que los deltas de color. Si se toca el de KLS, tocar
   este tambien.

   Los dos fondos que en KLS eran literales (#f2f4f7 y #fff) pasan aqui a
   var(--kls-bg-alt) y var(--kls-bg-page). El color #fff del texto del boton
   se mantiene: es texto sobre el color de acento, no un color de marca, y es
   lo que ya usa .kps-btn--primario.
   ══════════════════════════════════════════════════════════════════════ */
.kps-block__slot .nf-form-cont,
.kps-block__slot .nf-form-layout {
  font-family: var(--kls-font-sans) !important;
}

/* Eliminar padding y margin propios de NF */
.kps-block__slot .nf-form-fields-required,
.kps-block__slot .nf-field-container {
  margin-bottom: 1.25rem !important;
}

.kps-block__slot .nf-form-fields-required {
  font-size: 0.8rem;
  color: var(--kls-text-subtle);
  margin-bottom: 1.5rem !important;
}

/* Labels */
.kps-block__slot .nf-field-label label,
.kps-block__slot label {
  font-family: var(--kls-font-sans) !important;
  font-size: 0.9rem !important;
  font-weight: 700 !important;
  color: var(--kls-text) !important;
  letter-spacing: -0.01em;
  margin-bottom: 0.5rem !important;
  display: block;
}

/* Asterisco required */
.kps-block__slot .ninja-forms-req-symbol {
  color: var(--kls-ruby) !important;
}

/* Inputs y textarea */
.kps-block__slot input[type="text"],
.kps-block__slot input[type="email"],
.kps-block__slot input[type="tel"],
.kps-block__slot input[type="number"],
.kps-block__slot input[type="url"],
.kps-block__slot textarea {
  width: 100% !important;
  background: var(--kls-bg-alt) !important;
  border: 1.5px solid transparent !important;
  border-radius: var(--kls-radius-lg) !important;
  padding: 0.9rem 1.1rem !important;
  font-family: var(--kls-font-sans) !important;
  font-size: 1rem !important;
  color: var(--kls-text) !important;
  outline: none !important;
  box-shadow: none !important;
  transition: border-color 0.2s, background 0.2s !important;
  -webkit-appearance: none;
  appearance: none;
}

.kps-block__slot input[type="text"]:focus,
.kps-block__slot input[type="email"]:focus,
.kps-block__slot input[type="tel"]:focus,
.kps-block__slot input[type="number"]:focus,
.kps-block__slot input[type="url"]:focus,
.kps-block__slot textarea:focus {
  background: var(--kls-bg-page) !important;
  border-color: var(--kls-ruby) !important;
  box-shadow: 0 0 0 3px rgba(var(--kls-ruby-rgb),0.08) !important;
}

.kps-block__slot textarea {
  min-height: 130px !important;
  resize: vertical !important;
}

/* Botón enviar */
.kps-block__slot input[type="button"],
.kps-block__slot button[type="submit"],
.kps-block__slot .nf-element[type="button"],
.kps-block__slot .submit-wrap input {
  width: 100% !important;
  background: var(--kls-ruby) !important;
  color: #fff !important;
  border: none !important;
  border-radius: var(--kls-radius) !important;
  padding: 1rem 2rem !important;
  font-family: var(--kls-font-sans) !important;
  font-size: 0.9rem !important;
  font-weight: 800 !important;
  letter-spacing: 0.12em !important;
  text-transform: uppercase !important;
  cursor: pointer !important;
  transition: background 0.2s, transform 0.15s !important;
  margin-top: 0.5rem !important;
  box-shadow: 0 4px 18px rgba(var(--kls-ruby-rgb),0.25) !important;
}

.kps-block__slot input[type="button"]:hover,
.kps-block__slot button[type="submit"]:hover,
.kps-block__slot .submit-wrap input:hover {
  background: var(--kls-ruby-dark) !important;
  transform: translateY(-2px) !important;
  box-shadow: 0 6px 24px rgba(var(--kls-ruby-rgb),0.35) !important;
}

/* Mensajes de error y éxito */
.kps-block__slot .nf-error .nf-field-element input,
.kps-block__slot .nf-error .nf-field-element textarea {
  border-color: var(--kls-ruby) !important;
}

.kps-block__slot .nf-error-msg {
  font-size: 0.8rem !important;
  color: var(--kls-ruby) !important;
  margin-top: 0.3rem !important;
}

.kps-block__slot .nf-response-msg {
  padding: 1rem 1.25rem;
  background: rgba(var(--kls-ruby-rgb),0.06);
  border-left: 3px solid var(--kls-ruby);
  border-radius: 0 var(--kls-radius) var(--kls-radius) 0;
  font-weight: 600;
  color: var(--kls-text);
  margin-top: 1rem;
}

/* ─────────────────────────────────────────────────────────────────────────
   Disposiciones con cabecera ancha (v0.2.10)

   media_izquierda_hueco · media_derecha_hueco

   La cabecera ocupa todo el ancho y hace de separador entre secciones; debajo,
   la imagen y el hueco comparten fila. Se apoyan en la retícula que ya monta
   `.kps-block--media .kps-block__split`, así que aquí solo van las diferencias.
   ───────────────────────────────────────────────────────────────────────── */

/* La cabecera recupera el centrado del layout `centrado`: con media hereda
   text-align:left y max-width:none, que es justo lo contrario de un separador. */
.kps-block--hueco-lateral .kps-block__head {
  text-align: center;
  max-width: 780px;
  margin: 0 auto clamp(2rem, 5vw, 3.5rem);
}

/* Alineadas arriba, no centradas: la lista y la foto rara vez miden lo mismo,
   y centrarlas deja la primera fila de la lista flotando a media altura. */
.kps-block--hueco-lateral .kps-block__split {
  align-items: start;
}

/* El marcado sale siempre contenido → imagen. Solo esta variante lo invierte,
   y lo hace por CSS para que en móvil el contenido siga yendo primero. */
.kps-block--media-izquierda-hueco .kps-block__media {
  order: -1;
}

/* El hueco ya está separado por la cabecera; el margen de arriba sobra. */
.kps-block__slot--columna {
  margin-top: 0;
}

/* La imagen se recorta a la altura de la columna en vez de estirar la fila:
   una foto vertical al lado de una lista corta descuadraba la sección. */
.kps-block--hueco-lateral .kps-block__img {
  height: 100%;
  max-height: 32rem;
  object-fit: cover;
}

.kps-btn-row--hueco {
  justify-content: flex-start;
  margin-top: 1.5rem;
}

@media (max-width: 860px) {
  /* Apilado, la foto vuelve a mandar su propia altura: recortada a 32rem sobre
     el ancho completo del móvil se veía como una franja. */
  .kps-block--hueco-lateral .kps-block__img {
    height: auto;
    max-height: none;
  }
  .kps-btn-row--hueco {
    justify-content: center;
  }
}

/* Texto bajo la imagen (v0.2.12). Llena el hueco que queda cuando la columna
   de al lado —una lista larga de cursos— es más alta que la foto. */
.kps-block__media-text {
  margin: 1rem 0 0;
  font-size: 0.92rem;
  line-height: 1.6;
  color: var(--kls-text-muted, #3D4A60);
}

/* ── Barra superior ──────────────────────────────────────────
   Franja de borde a borde por encima del hero. Va fuera del contenedor a
   propósito: el color llega hasta los bordes de la ventana y `.kps-container`
   solo centra el contenido.

   El `#fff` es texto y fondo de botón **sobre el color de acento**, no un color
   de marca — el mismo criterio que ya sigue `.kps-btn--primario`. Cualquier otro
   literal aquí rompería la multi-marca en silencio. */
/* La barra anuncia algo que caduca: es el sitio del color destacado. Cae al
   acento si esta web no ha elegido ninguno, que es como se pintaba antes.
   El color guardado es el tono OSCURO por convención (ver KPS_Identidad::
   DESTACADO), justo para que este blanco de encima se lea. */
.kps-banner {
  background: var(--kls-destacado, var(--kls-ruby));
  color: #fff;
}

.kps-banner__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 0.6rem 1.25rem;
  padding-block: 0.7rem;
}

.kps-banner__text {
  margin: 0;
  font-size: 0.95rem;
  font-weight: 600;
  line-height: 1.4;
  text-align: center;
}

.kps-banner__cta {
  /* Sin esto, el botón se estira o se parte cuando el texto ocupa dos líneas. */
  flex: none;
  display: inline-block;
  padding: 0.4em 1.1em;
  border-radius: 8px;
  background: #fff;
  color: var(--kls-destacado-dark, var(--kls-ruby));
  font-size: 0.85rem;
  font-weight: 700;
  text-decoration: none;
  white-space: nowrap;
  transition: transform 0.2s, box-shadow 0.2s;
}

.kps-banner__cta:hover {
  transform: translateY(-1px);
  box-shadow: 0 6px 18px rgba(var(--kls-dark-rgb), 0.22);
}

/* En el móvil, 44 px de alto como mínimo: con el relleno de escritorio medía 33
   y es el único botón de la barra, el que hay que acertar con el dedo. Solo por
   debajo de 640 px, que en escritorio estiraría la franja entera. */
@media (max-width: 640px) {
  .kps-banner__cta {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 44px;
  }
}

/* ── Cuenta atrás de la barra ─────────────────────────────────
   Las cifras las escribe `kenzen-page.js` contra el epoch de
   `data-kps-countdown`; el reloj nace `hidden` y solo se destapa si queda
   tiempo. Sin JS —el respaldo estático de `post_content`— no aparece, en vez de
   quedarse congelado en el día en que se guardó la página.

   Sobre el fondo de marca, cajas con un velo OSCURO y cifras en blanco: un
   `#fff` aquí es texto sobre el color de acento, no un color de marca.

   ⚠️ **El velo era blanco (al 16 %) y aclaraba justo detrás de las cifras.**
   En medicina dejaba la caja en un naranja más claro que la franja y el blanco
   encima a 3,69:1 — peor que la franja sola (4,57). (Sin el código del color
   aquí: `test-kps-banner.php` busca literales en este bloque, comentarios
   incluidos, y con razón.) Oscuro, el contraste solo puede subir, sea cual sea
   el color de la barra: 5,98 en medicina. Y los rótulos (días, horas…) iban a
   9,6 px con opacidad: ahora 11 px y opacos. Auditoría del 28 sep 2026. */
.kps-banner__reloj {
  display: flex;
  gap: 0.4rem;
}

/* ⚠️ El `display:flex` de arriba gana al `[hidden]{display:none}` del
   navegador. Sin esta regla el reloj se vería siempre, con ceros incluidos. */
.kps-banner__reloj[hidden] {
  display: none;
}

.kps-banner__unit {
  display: flex;
  flex-direction: column;
  align-items: center;
  min-width: 2.6rem;
  padding: 0.25rem 0.4rem;
  border-radius: 6px;
  background: rgba(0, 0, 0, 0.15);
  line-height: 1.1;
}

.kps-banner__unit b {
  font-size: 1.05rem;
  font-weight: 800;
  /* Sin esto el ancho baila en cada tic al cambiar de dígito. */
  font-variant-numeric: tabular-nums;
}

.kps-banner__unit i {
  font-size: 0.6875rem;
  font-style: normal;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}

/* ======================================================
   FOCO DEL TECLADO — común a KPS y KLS
   ======================================================
   ⚠️ **Los botones y tarjetas no marcaban el foco.** Al tabular no se sabía
   dónde se estaba: `.kps-btn`, `.kps-card--link`, `.kps-banner__cta` y los
   botones de KLS no tenían ninguna regla, y Divi los deja con `outline: 0`.
   Auditoría de interfaz de medicina, 28 sep 2026.

   `:focus-visible` y no `:focus`: con el ratón no cambia nada.

   ⚠️ **La misma regla está en los DOS plugins**, `kenzen-page.css` y
   `kenzen-landing.css`, idéntica. Hay webs con uno solo de los dos, y así
   ninguna se queda sin ella. Si se cambia, cambiarla en los dos.

   `:where()` en los contenedores para que pese lo mínimo y cualquier foco más
   concreto de un componente (el acordeón, el selector de moneda…) siga
   mandando. Aun así gana al `outline: 0` de Divi, que es de elemento.

   ── Dónde va en blanco ──
   Sobre los fondos oscuros de los dos plugins y sobre la banda de KPS, que va
   en el destacado. Medido con una sonda en medicina, Kenzen y Esther el 28 sep:
   el destacado oscuro daba 1,95 sobre la banda y 2,27 sobre el vídeo.
   ⚠️ **`.kenzen-hero` y `.kenzen-countdown` NO van en la lista**, aunque lo
   parezca: el hero de KLS es transparente sobre el fondo claro, y la cuenta
   atrás va sobre un tinte del 6 %. Con ellos, el contorno salía blanco sobre
   blanco (1,00).

   ── El vídeo, por dentro ──
   `.kps-block__video` lleva `overflow: hidden` y mide lo mismo que la
   portada: un contorno por fuera queda recortado entero. Por eso va hacia
   dentro, en blanco sobre la miniatura. */
:where([class*="kps-"], [class*="kenzen-"], [class*="kls-"]):focus-visible,
:where([class*="kps-"], [class*="kenzen-"], [class*="kls-"]) :where(a, button, summary, [tabindex]):focus-visible {
  outline: 2px solid var(--kls-ruby-dark);
  outline-offset: 3px;
}

:where(.kps-cta, .kps-banner, .kps-hero--imagen, .kps-hero--invertido,
       .kenzen-footer, .kenzen-authority-section, .kenzen-bio-item--slate,
       .kls-sticky-bar) :where(a, button, summary, [tabindex]):focus-visible,
:where(.kps-cta, .kps-banner, .kps-hero--imagen, .kps-hero--invertido,
       .kenzen-footer, .kenzen-authority-section, .kenzen-bio-item--slate,
       .kls-sticky-bar) :where([class*="kps-"], [class*="kenzen-"], [class*="kls-"]):focus-visible {
  outline-color: #fff;
}

.kps-video-facade:focus-visible {
  outline: 3px solid #fff;
  outline-offset: -6px;
}

/* ======================================================
   MOVIMIENTO REDUCIDO
   ======================================================
   Quien pide al sistema que reduzca el movimiento no debería ver botones que
   suben al pasar el ratón, desplegables que se deslizan ni cuentas atrás que
   se animan. KLS ya lo respetaba; KPS no tenía ni una regla. Auditoría del
   28 sep 2026.

   `0.01ms` y no `none`: con `none` no se dispara `transitionend`, y un JS que
   lo espere se quedaría colgado. Acotado a `.kps-shell` para no tocar nada del
   tema. */
@media (prefers-reduced-motion: reduce) {
  .kps-shell *,
  .kps-shell *::before,
  .kps-shell *::after {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    scroll-behavior: auto !important;
  }
}
