/*
Theme Name: Osty (Child Theme)
Theme URI: http://madsparrow.us/
Author: Mad Sparrow
Author URI: https://themeforest.net/user/madsparrow
Description: Osty Creative Agency and Portfolio Theme – The theme is built to take advantage of the Full Site Editing features introduced in WordPress and Elementor plugin, which means that colors, typography, and the layout of every single page on your site can be customized to suit your vision. Whether you want to build a complex or incredibly simple website, you can do it quickly and intuitively through the bundled styles or dive into creation and full customization yourself.
Tags: one-column, two-columns, right-sidebar, custom-menu, post-formats, sticky-post, translation-ready, page transition
Version: 1.0
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Text Domain: osty
Tags: one-column, two-columns, right-sidebar, flexible-header, accessibility-ready, custom-colors, custom-header, custom-menu, custom-logo, editor-style, featured-images, footer-widgets, post-formats, rtl-language-support, sticky-post, theme-options, threaded-comments, translation-ready
Template: osty
*/

/* Add your own modification from here
-------------------------------------------------------------- */

/* =========================================================================
 * CNAAY — tipografía de títulos: Vansie
 *
 * Origen: C:\Users\dinme\Documents\Sitios Web\cnaay\fuentes
 * Se sirven woff2 (34 KB) y woff (46 KB); el .otf y el .ttf NO se suben,
 * pesan el triple y ningún navegador vigente los necesita.
 *
 * `font-display: swap` es obligatorio en el estándar CWV del proyecto: el
 * texto se pinta de inmediato con la fuente de respaldo y cambia al cargar,
 * en vez de quedarse invisible.
 * ========================================================================= */
@font-face {
    font-family: 'Vansie';
    src: url('assets/fonts/Vansie-Regular.woff2') format('woff2'),
         url('assets/fonts/Vansie-Regular.woff')  format('woff');
    font-weight: 400;
    font-style: normal;
    font-display: swap;
}

/* ⚠️ `--font-heading` NO se sobrescribe aquí: Kirki imprime su propio
   `:root{--font-heading:Poppins}` en un <style> del <head> que va DESPUÉS de
   esta hoja, así que con la misma especificidad gana él. La variable se
   redeclara en functions.php (`cnaay_tipografia_titulos`) en `wp_head` con
   prioridad tardía — es cascada, no un truco de especificidad. */

/* =========================================================================
 * CNAAY 2027 — paleta de marca
 * Ver el documento completo en cliente-123/paleta.md
 *
 * Tres materiales: ORO (la marca), VIOLETA (el movimiento) y NEGRO CÁLIDO
 * (el fondo). El violeta nunca ocupa más superficie que el oro.
 * ========================================================================= */

/* --- Colores base, independientes del modo --- */
:root {
    --cnaay-oro-luz:        #F2D384;
    --cnaay-oro:            #E8B84B;   /* marca principal en modo oscuro */
    --cnaay-oro-sombra:     #A87C1A;
    --cnaay-oro-tinta:      #8A6410;   /* texto dorado sobre fondo claro */

    --cnaay-violeta-luz:    #C88CFF;
    --cnaay-violeta:        #A855F7;   /* acento principal */
    --cnaay-violeta-sombra: #6D28D9;

    --cnaay-negro:          #0E0A12;
    --cnaay-hueso:          #FAF8F4;
}

/* --- Pie de página: MISMOS valores en los dos modos ---------------------
 *
 * El footer va oscuro siempre (decisión de paleta.md: cierra el sitio con la
 * identidad y evita el oro sobre blanco justo en la zona del logo).
 *
 * ⚠️ Por eso estas variables se declaran UNA sola vez, fuera de los bloques
 * `[data-theme]`. Si el footer usara `--cnaay-surface` o `--cnaay-text`, en
 * modo claro saldría un panel BLANCO con texto negro dentro de un footer
 * negro. Elementor guarda un solo valor por control, así que la única forma
 * de tener un footer estable es que la variable no dependa del modo. */
:root {
    --cnaay-footer-bg:         #0E0A12;   /* el fondo del <footer> */
    --cnaay-footer-panel:      #1A1320;   /* el panel de dentro, un punto más claro */
    --cnaay-footer-text:       #F5F1E8;
    --cnaay-footer-soft:       #A79FB0;   /* copyright y iconos en reposo */
    --cnaay-footer-line:       #2E2438;   /* las dos divisorias del demo */
    --cnaay-footer-icon-bg:    #241C2C;   /* pastilla redonda de las redes */
}

/* --- Botón «estilo Osty»: MISMOS colores en los dos modos -----------------
 *
 * Decisión del cliente (2026-08-19): el `btn-osty` conserva SIEMPRE los
 * colores del modo oscuro — pastilla dorada, texto y puntos oscuros—, también
 * en modo claro.
 *
 * Son los valores que el tema le da EN MODO OSCURO, congelados aquí. Misma
 * razón que el footer para declararlos fuera de los bloques `[data-theme]`:
 * si dependieran del modo, no habría forma de fijarlos.
 */
:root {
    --cnaay-btn-osty-fill: #E8B84B;   /* --color-primary          (relleno) */
    --cnaay-btn-osty-pill: #F5F1E8;   /* --color-contrast-higher  (pastilla izq. y hover) */
    --cnaay-btn-osty-ink:  #2E2438;   /* --color-contrast-lower   (texto y puntos) */
}

/* --- Texto SOBRE FOTOGRAFÍA: MISMO valor en los dos modos -----------------
 *
 * Para los bloques que son foto + velo oscuro (las tarjetas apiladas de
 * Categorías en la portada). paleta.md lo dicta para ese bloque: «se comporta
 * igual que en modo Black: texto claro sobre overlay oscuro». El valor es el
 * token *White* de la paleta («texto sobre imágenes»). El extremo opaco del
 * velo es `--cnaay-negro`, que ya está declarado arriba.
 *
 * ⚠️ Misma razón que el footer para declararlo UNA vez fuera de los bloques
 * de modo: con `--cnaay-text` el modo claro pondría texto NEGRO sobre un velo
 * negro. */
:root {
    --cnaay-foto-texto:        #F5F1E8;
}

/* --- Modo BLACK --- */
:root[data-theme="dark"], body[data-theme="dark"] {
    --cnaay-bg:        #0E0A12;
    --cnaay-surface:   #1A1320;
    --cnaay-primary:   #E8B84B;
    --cnaay-accent:    #A855F7;
    --cnaay-text:      #F5F1E8;
    --cnaay-text-soft: #A79FB0;
    --cnaay-border:    #2E2438;

    /* Enlaces violeta en texto corrido: el violeta puro da 4.96:1 y solo
       pasa en tamaño grande. En cuerpo de texto va el claro (8.08:1). */
    --cnaay-link:      #C88CFF;
    --cnaay-success:   #3FB984;

    --cnaay-gold:   linear-gradient(135deg, #A87C1A 0%, #F2D384 45%, #E8B84B 70%, #8A6410 100%);
    --cnaay-violet: linear-gradient(90deg, #6D28D9 0%, #A855F7 50%, #C88CFF 100%);
    --cnaay-depth:  radial-gradient(ellipse at 50% 0%, #1A1320 0%, #0E0A12 70%);

    /* Derivados: el relleno dorado del botón es el MISMO en los dos modos
       (#E8B84B con texto oscuro); lo que cambia es el hover. */
    --cnaay-btn-fill:       #E8B84B;
    --cnaay-btn-fill-text:  #14101A;
    --cnaay-btn-fill-hover: #F2D384;
    --cnaay-btn-hover-text: #14101A;
    --cnaay-badge-text:     #FAF8F4;
    --cnaay-overlay:        rgba(14, 10, 18, .55);
    --cnaay-violet-soft:    rgba(168, 85, 247, .25);
    --cnaay-violet-glow:    rgba(168, 85, 247, .30);
}

/* --- Modo WHITE --- */
:root[data-theme="light"], body[data-theme="light"] {
    --cnaay-bg:        #FAF8F4;   /* hueso, NO blanco puro */
    --cnaay-surface:   #FFFFFF;   /* el blanco puro solo en tarjetas */
    --cnaay-primary:   #8A6410;   /* oro a tinta: el brillante no pasa (3.56:1) */
    --cnaay-accent:    #6D28D9;
    --cnaay-text:      #14101A;
    --cnaay-text-soft: #5C5566;
    --cnaay-border:    #E6E0D6;

    --cnaay-link:      #6D28D9;
    --cnaay-success:   #1F7A55;

    --cnaay-gold:   linear-gradient(135deg, #8A6410 0%, #C79A2E 50%, #A87C1A 100%);
    --cnaay-violet: linear-gradient(90deg, #5B21B6 0%, #6D28D9 50%, #A855F7 100%);
    --cnaay-depth:  radial-gradient(ellipse at 50% 0%, #FFFFFF 0%, #FAF8F4 70%);

    /* Mismo relleno dorado, pero aquí el hover se va al oro profundo con
       texto claro (el doc: fondo #A87C1A, texto #FAF8F4). */
    --cnaay-btn-fill:       #E8B84B;
    --cnaay-btn-fill-text:  #14101A;
    --cnaay-btn-fill-hover: #A87C1A;
    --cnaay-btn-hover-text: #FAF8F4;
    --cnaay-badge-text:     #FAF8F4;
    --cnaay-overlay:        rgba(20, 16, 26, .45);
    --cnaay-violet-soft:    rgba(109, 40, 217, .85);
    --cnaay-violet-glow:    rgba(109, 40, 217, .20);
}

/* =========================================================================
 * Aplicación de la paleta — lo que NO expone control en el widget
 * ========================================================================= */

/* Hero: un solo degradado por pantalla — el titular principal en oro metálico */
.elementor .e-con.e-parent h1.elementor-heading-title {
    background: var(--cnaay-gold);
    -webkit-background-clip: text;
            background-clip: text;
    -webkit-text-fill-color: transparent;
}

/* Botones: el hover sí cambia por modo */
.btn.btn-default.btn--primary:hover {
    background-color: var(--cnaay-btn-fill-hover);
    color: var(--cnaay-btn-hover-text);
}

/* Services: el borde se enciende en oro al pasar el mouse */
.elementor-widget-services .ms-sb {
    border: 1px solid var(--cnaay-border);
    transition: border-color .3s ease;
}
.elementor-widget-services .ms-sb:hover { border-color: var(--cnaay-primary); }

/* Magnetic: halo violeta difuso alrededor de cada foto */
.magnetic_hero .hero__image img { box-shadow: 0 0 40px var(--cnaay-violet-glow); }

/* El ancho de cada foto lo fija el script de build (control `width` del
   widget) a partir de $MAGNETIC_IMGS. Esto es la red de seguridad para cuando
   alguien agregue fotos desde el panel sin tocar ese ancho: el mínimo
   automático de los flex items les impide encoger y la fila desbordaría. */
.magnetic_hero .hero__images .hero__image { min-width: 0; }

/* Acordeón: la línea se enciende en el acento al abrir o al hover */
.ms_accordion.l-ef .ms_ac--label::after { border-color: var(--cnaay-primary); }

/* Footer: oscuro en LOS DOS modos, con franja violeta arriba.
   La estructura (tres franjas, columnas, divisorias) la arma la plantilla
   `cnaay-footer`, replicando la del demo. Aquí solo va lo que la plantilla
   no puede resolver por control. */
.ms-footer { background: var(--cnaay-footer-bg); border-top: 2px solid transparent; border-image: var(--cnaay-violet) 1; }
.ms-footer, .ms-footer .elementor-heading-title, .ms-footer p { color: var(--cnaay-footer-text); }
.ms-footer .ms-sl { color: var(--cnaay-oro); }

/* El h2 de sección va a 64px por la regla de más abajo; en el footer los
   títulos son <p> chicos, así que no le afecta. Lo que sí hay que sujetar es
   el enlace del correo y el del aviso: heredan el color del modo. */
.ms-footer .ms-sl, .ms-footer .ms-sl span { color: var(--cnaay-footer-text); }
.ms-footer .ms-sl:hover, .ms-footer .ms-sl:hover span { color: var(--cnaay-oro); }

/* =========================================================================
 * Títulos de sección
 *
 * Valores del demo «Personal Page» (post-1517.css, elementos 2d44008 /
 * f7d2115 / 328051a / 3c33477): 64px en escritorio y 42px por debajo de
 * 768px. Antes heredaban el `h2` del tema —`calc(var(--text-xl) + 1px)`, unos
 * 36px— y quedaban muy por debajo de la escala del demo.
 *
 * Solo alcanza a los widgets `heading` de Elementor con etiqueta h2, que en
 * la portada son exactamente los títulos de sección. Los h2 del cuerpo (los
 * que produce el filtro sobre `ms_animated_headline`) no llevan la clase
 * `.elementor-heading-title` y siguen con la escala del tema.
 * ========================================================================= */
.elementor-widget-heading h2.elementor-heading-title {
    font-size: 64px;
    line-height: 1.1;
}

@media (max-width: 767px) {
    .elementor-widget-heading h2.elementor-heading-title { font-size: 42px; }
}

/* =========================================================================
 * Espacio bajo los títulos de sección — neutralizar el relleno de los widgets
 *
 * El margen uniforme lo pone el script (`cabecera()`, constante
 * CNAAY_GAP_TITULO). Pero algunos widgets traen relleno propio ARRIBA, y eso
 * se suma al margen y rompe la uniformidad aunque el margen sí sea el mismo.
 *
 * El caso grave es `ms_projects`: el tema le mete **80px de padding-top** a
 * `.portfolio_wrap`, así que bajo «Ediciones anteriores» el hueco medía 128px
 * contra los 20px de «Bases rápidas». Se anula aquí, que es donde está el
 * problema, en vez de compensarlo con un margen negativo a ojo.
 *
 * ⚠️ TRAMPA DE ESPECIFICIDAD: la regla del tema es
 * `.portfolio_wrap[data-type="list"]:not([data-filter="s_2"])`, que puntúa
 * (0,3,0) porque el argumento del `:not()` también cuenta. Un selector de
 * (0,2,0) —por muy después que vaya en la cascada— NO le gana. Hay que
 * igualar la puntuación y ganar por orden.
 * ========================================================================= */
.elementor-widget-ms_projects .portfolio_wrap[data-type="list"] { padding-top: 0; }

/* =========================================================================
 * Modalidades — tarjeta con el patrón del card de posts del tema
 *
 * Valores tomados 1:1 de `.ms-posts--card` (themes/osty/assets/css/main.css)
 * y de post-1517.css del demo. NADA aproximado a ojo.
 *
 * La forma del card del tema es: el bloque de texto arriba con las esquinas
 * superiores redondeadas, y la imagen abajo con las inferiores redondeadas.
 * El widget `services` imprime la imagen PRIMERO en el DOM, así que el
 * bloque de texto se sube visualmente con `order`, sin tocar el marcado.
 *
 * ⚠️ Depende de que el widget vaya con `image_style => 'default'`. Con
 * 'boxed' el tema mete `padding:1rem` a la imagen y Elementor hornea un
 * `background-color` por instancia que pelea con estas reglas.
 *
 * ⚠️ TRAMPA: `_css_classes` de Elementor NO pone la clase en el marcado del
 * widget, sino en su DIV envoltorio (`.elementor-element … .cnaay-card …
 * .elementor-widget-services`). Por eso se enrutan como `.cnaay-card .ms-sb`
 * y no como `.ms-sb.cnaay-card`, que nunca casa.
 * ========================================================================= */
/*
 * ⚠️ El `height:100%` de abajo necesita que el ENVOLTORIO tenga altura, y no
 * la tenía: la columna sí se estiraba a la más alta de la fila (flexbox la
 * iguala en el eje transversal), pero el widget de dentro se quedaba en su
 * altura de contenido. Medido en Convocatoria a dos columnas: columnas de
 * 476px con tarjetas de 454 y 476 ⇒ una acababa 22px más arriba que su
 * vecina, y las bases de las tarjetas se veían desparejas.
 *
 * La columna es un contenedor flex en DIRECCIÓN COLUMNA, así que el eje
 * principal es el vertical: lo que estira al hijo es `flex-grow`, no
 * `align-self: stretch` (ese actúa en el horizontal, que ya estaba bien).
 * Con la tarjeta a la altura completa, el `flex:1 1 auto` del bloque de texto
 * absorbe la diferencia y la foto se queda abajo con su 16/9 intacto.
 *
 * ℹ️ Vale mientras la columna lleve SOLO la tarjeta, que es el caso en los
 * dos usos (Modalidades de la portada y Categorías de Convocatoria).
 */
.cnaay-card { flex-grow: 1; }

.cnaay-card .ms-sb {
    display: flex;
    flex-direction: column;
    height: 100%;
    overflow: hidden;
    background-color: var(--cnaay-surface);
    border-radius: 24pt;               /* .ms-posts--card, main.css */
}

/* El texto sube al lugar del card del tema (.post-content) */
.cnaay-card .ms-sb .ms-sb--inner {
    order: -1;
    flex: 1 1 auto;                    /* iguala alturas entre las 3 tarjetas */
    padding: 1.5rem 1.7rem;            /* .has-post-thumbnail .post-meta-cont */
    border-top-left-radius: 24pt;
    border-top-right-radius: 24pt;
}

.cnaay-card .ms-sb .ms-sb--title {
    margin-top: 8pt;
    font-size: 20px;
    font-weight: 600;
}
.cnaay-card .ms-sb .ms-sb--title a { transition: opacity 150ms var(--ease-in-out); }
.cnaay-card .ms-sb .ms-sb--title a:hover { opacity: .5; }

/*
 * ⭐ En tarjeta ANCHA el título crece (2026-08-20)
 *
 * Los 20px salen del card de posts del tema, pensado para una tarjeta angosta.
 * Al pasar Categorías de Convocatoria a dos columnas la tarjeta se fue a 528px
 * y el título quedó a **4px del cuerpo** (20 contra 16): se leía como texto en
 * negrita, no como título. Lo reportó el cliente.
 *
 * ⭐ Se ata al ANCHO DE LA PROPIA TARJETA con una container query, no al del
 * viewport. La clase `.cnaay-card` la comparten dos bloques con retículas
 * distintas y el tamaño tiene que seguir a la caja, no a la pantalla:
 *
 *   Categorías (Convocatoria)  528px escritorio → 28px · 320 tablet · 305 móvil → 20px
 *   Modalidades (portada)      332px en las tres → 20px, sin tocar
 *
 * Con un `@media` habría que enumerar breakpoints por bloque y volver a tocarlo
 * cada vez que una retícula cambie de número de columnas.
 *
 * ⚠️ `container-type: inline-size` aplica `contain: layout inline-size style`.
 * El ancho ya lo fija la columna, así que no cambia nada del reparto — pero sí
 * convierte la tarjeta en contenedor de sus absolutos, y **hay que comprobar
 * que el `flex-grow:1` de arriba siga igualando alturas** (verificado).
 */
.cnaay-card { container-type: inline-size; }

@container (min-width: 420px) {
    .cnaay-card .ms-sb .ms-sb--title {
        font-size: 28px;
        line-height: 1.15;
    }
}

.cnaay-card .ms-sb .ms-sb--text { font-size: 16px; line-height: 1.4; }

/* La imagen: abajo, 16/9 y esquinas inferiores redondeadas */
.cnaay-card .ms-sb .ms-sb--img {
    display: block;
    position: relative;
    margin: 0;                         /* el tema le pone 1.5rem abajo */
    aspect-ratio: 16/9;
    overflow: hidden;
    border-bottom-left-radius: 24pt;
    border-bottom-right-radius: 24pt;
}
.cnaay-card .ms-sb .ms-sb--img a { display: block; width: 100%; height: 100%; }

.cnaay-card .ms-sb .ms-sb--img img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center;
    /* Curva y duración exactas del tema (.ms-posts--card … figure img) */
    transition: all .45s cubic-bezier(.15, .75, .5, 1);
    will-change: transform;
}

/* Hover: el mismo zoom del card de posts */
.cnaay-card .ms-sb:hover .ms-sb--img img { transform: scale(1.1, 1.1); }

/* Variante alta: para los bloques cuya foto es VERTICAL (los aparatos de
   Convocatoria, especificados a 800 × 1000). Con el 16/9 de la tarjeta normal
   una foto de figura completa se recorta por la cabeza y los pies.
   ⚠️ Lleva `.ms-sb` en medio a propósito: la regla base es
   `.cnaay-card .ms-sb .ms-sb--img`, que puntúa (0,3,0). Con dos clases esta
   perdería aunque vaya después. */
.cnaay-card--alto .ms-sb .ms-sb--img { aspect-ratio: 4/5; }

/* =========================================================================
 * TARJETA DE PATROCINADOR (`.cnaay-sponsor`) — 2026-08-20
 *
 * Rediseño pedido por el cliente sobre una referencia: tarjeta con un PANEL
 * arriba donde vive el logo, y debajo el nombre y la descripción. Antes el
 * logo iba suelto sobre el fondo de la página dentro de una caja con borde.
 *
 * ⚠️⚠️ **EL PANEL DEL LOGO VA CLARO EN LOS DOS MODOS, y no es capricho: sin
 * él dos logos DESAPARECEN.** Powerade y Yucatecos Viajeros son PNG negros con
 * transparencia; sobre el fondo oscuro del sitio quedaban invisibles (se ve en
 * la captura del cliente). El panel claro es lo que los hace legibles y es,
 * además, lo que hace la referencia. Mismo criterio —y mismo valor— que
 * `--cnaay-foto-texto`: se declara UNA vez, fuera de los bloques `[data-theme]`,
 * porque si siguiera al modo volvería a tragarse los logos en oscuro.
 *
 * ⚠️ `object-fit: CONTAIN`, nunca `cover`: un logo no se recorta. Es la
 * diferencia con `.cnaay-card`, donde la foto sí llena la caja.
 *
 * ℹ️ Los ocho logos vienen con proporciones distintas (Snack Up es 3000×2239 y
 * el resto 3000×1289). El panel de proporción fija + `contain` los iguala
 * ópticamente mientras no lleguen normalizados a 400×200.
 * ========================================================================= */
:root {
    --cnaay-logo-panel: #F5F1E8;   /* mismo hueso que `--cnaay-foto-texto` */
}

/*
 * El MARCO lo comparten la ficha de patrocinador y la de jurado: las dos salen
 * del widget `services`, así que basta con listarlas juntas. Lo único que
 * cambia entre ellas es el PANEL — logo con `contain` sobre hueso, retrato con
 * `cover` a 1:1 — y eso va más abajo, por separado.
 */
.cnaay-sponsor .ms-sb,
.cnaay-persona .ms-sb {
    display: flex;
    flex-direction: column;
    height: 100%;
    padding: 12px;
    background-color: var(--cnaay-surface);
    border: 1px solid var(--cnaay-border);
    border-radius: 20px;
}

/* El panel: el logo centrado, con aire alrededor y sin recorte. */
.cnaay-sponsor .ms-sb .ms-sb--img {
    margin: 0;
    display: grid;
    place-items: center;
    aspect-ratio: 4 / 3;
    padding: 1.6rem;
    background-color: var(--cnaay-logo-panel);
    border-radius: 12px;
    overflow: hidden;
}
.cnaay-sponsor .ms-sb .ms-sb--img img {
    width: 100%;
    height: 100%;
    object-fit: contain;
    object-position: center;
}

.cnaay-sponsor .ms-sb .ms-sb--inner,
.cnaay-persona .ms-sb .ms-sb--inner {
    flex: 1 1 auto;                 /* iguala alturas entre tarjetas del renglón */
    padding: 1.1rem .5rem .3rem;
}
.cnaay-sponsor .ms-sb .ms-sb--title,
.cnaay-persona .ms-sb .ms-sb--title {
    margin-top: 0;
    margin-bottom: .4rem;
    font-size: 20px;
    font-weight: 600;
}
.cnaay-sponsor .ms-sb .ms-sb--text,
.cnaay-persona .ms-sb .ms-sb--text {
    font-size: 15px;
    line-height: 1.45;
    color: var(--cnaay-text-soft);
}

/* Igual que `.cnaay-card`: sin esto la tarjeta no llena su columna y las bases
   del renglón quedan desparejas. */
.cnaay-sponsor,
.cnaay-persona { flex-grow: 1; }

/* =========================================================================
 * FICHA DE JURADO (`.cnaay-persona`) — PREPARADA, hoy sin publicar
 *
 * El cliente pidió para el jurado «un estilo similar» al de patrocinadores y
 * **dejarlo preparado**: no hay jueces confirmados para 2027, así que la página
 * publica «Jurado próximamente» y estas reglas no llegan a usarse todavía. El
 * interruptor es el array `$jurado` de `cnaay_build_convocatoria.php`: en
 * cuanto tenga líneas, salen las tarjetas.
 *
 * Comparte el marco con `.cnaay-sponsor` (arriba). Aquí va solo lo que cambia.
 * ========================================================================= */

/*
 * El panel es un RETRATO, no un logo: llena la caja y se recorta.
 *
 * ⚠️ Es justo lo contrario que en patrocinadores —`cover` en vez de `contain`,
 * y sin panel claro detrás—. Un logo no se recorta y necesita fondo propio; una
 * foto sí se recorta y aporta su propio fondo. Proporción 1:1, que es la
 * especificación de imagen del bloque (800 × 800).
 */
.cnaay-persona .ms-sb .ms-sb--img {
    margin: 0;
    aspect-ratio: 1 / 1;
    border-radius: 12px;
    overflow: hidden;
    background-color: var(--cnaay-border);   /* mientras carga o si falta la foto */
}
.cnaay-persona .ms-sb .ms-sb--img img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center top;   /* en un retrato, la cara está arriba */
}

/*
 * El cargo, en su propia línea sobre la trayectoria.
 *
 * ⭐ Va dentro del `<p class="ms-sb--text">` porque el widget imprime ese campo
 * SIN escapar (`block_services.php:312`), así que `ficha_jurado()` le mete un
 * `<span>`. Al vivir dentro de un `<p>` tiene que ser un elemento en línea: se
 * vuelve bloque desde aquí.
 */
.cnaay-persona .cnaay-persona__cargo {
    display: block;
    margin-bottom: .35rem;
    color: var(--cnaay-primary);
    font-weight: 600;
}

/*
 * Estado «próximamente» — lo que se ve HOY.
 * El párrafo grande en el oro de la paleta; el de apoyo, en el texto suave.
 */
#cnaay-jurado-proximamente .cnaay-proximamente {
    margin-bottom: .6rem;
    color: var(--cnaay-primary);
    font-family: var(--font-heading);
    font-size: 32px;
    line-height: 1.2;
}
#cnaay-jurado-proximamente p:not(.cnaay-proximamente) {
    color: var(--cnaay-text-soft);
    max-width: 46ch;
    margin-inline: auto;
}

/* En móvil van DOS por renglón (petición del cliente) y la caja se queda en
   ~160px: se aprieta el aire para que el nombre no se parta en tres. */
@media (max-width: 767px) {
    /*
     * ⭐ Fuera las canaletas laterales. Medido a 375px: de los 345 de la
     * sección, la fila se comía 20 y las columnas otros 40 — 60px de aire
     * lateral que no se ve, y la tarjeta se quedaba en **131px**. Sin ellos
     * son **160px**, un 22 % más de caja para el logo y el nombre. El gap de
     * 24 entre las dos columnas se conserva: ese sí separa.
     *
     * ⚠️ Va por `#cnaay-marcas` (1,0,0) porque Elementor hornea el padding en
     * `.elementor-{id} .elementor-element-{uid}`, que puntúa (0,3,0).
     */
    #cnaay-marcas,
    #cnaay-marcas > .e-con { padding-left: 0; padding-right: 0; }

    .cnaay-sponsor .ms-sb { padding: 8px; }
    .cnaay-sponsor .ms-sb .ms-sb--img { padding: 1rem; }
    .cnaay-sponsor .ms-sb .ms-sb--inner { padding: .8rem .35rem .2rem; }
    .cnaay-sponsor .ms-sb .ms-sb--title { font-size: 17px; }
    .cnaay-sponsor .ms-sb .ms-sb--text  { font-size: 14px; }
}

/* =========================================================================
 * MENÚ DEL HEADER — el horizontal SIEMPRE visible en escritorio (2026-08-20)
 *
 * Petición del cliente: «el header con el logo siempre está visible, así que
 * quiero el menú siempre visible; oculta el desplegable y muéstralo solo en
 * tablet y móvil».
 *
 * ⚠️⚠️ **NO era un `display:none` y ya: el tema INTERCAMBIA los dos menús al
 * hacer scroll.** `app.js` tiene `showMenu()`/`hideMenu()` colgados de
 * `$(window).on('scroll')`, y con `body[data-menu="fixed"]` la regla es:
 *
 *     scroll === 0  →  hideMenu()  →  se ve el menú horizontal
 *     scroll  >  0  →  showMenu()  →  el horizontal se va y entra la hamburguesa
 *
 * `showMenu()` anima con GSAP `#primary-menu-default > li.menu-item` a
 * `{ autoAlpha: 0, x: -35 }`. Medido: tras scrollear, cada ítem queda con
 * `transform: translate(-35px); opacity: 0; visibility: hidden` **inline**.
 * Por eso ocultar solo la hamburguesa habría dejado la página SIN NINGÚN MENÚ
 * en cuanto el usuario bajara un pixel.
 *
 * ⭐ GSAP escribe inline pero **sin `!important`**, así que una declaración
 * `!important` del hijo le gana y congela el estado «arriba» para siempre. Es
 * la forma de desactivar la animación sin desengancharla: el handler de scroll
 * del tema es una arrow anónima dentro de un closure, no hay referencia con la
 * que hacerle `.off()`, y un `$(window).off('scroll')` a ciegas se llevaría por
 * delante los demás — incluido el que pinta el fondo del header.
 *
 * ⛔ **Solo de 1024px para arriba.** Por debajo el tema YA hace lo correcto sin
 * ayuda: `@media (max-width:1023px){ .main-header__nav{display:none} }` esconde
 * el horizontal, y `handleMenuAnimation()` fuerza `showMenu()` sin mirar el
 * scroll. Ahí la hamburguesa es el menú. El breakpoint es el del propio tema
 * (usa `max-width:1023px` y `min-width:64rem`), no uno inventado.
 *
 * ⚠️ Se oculta `.main-header__btn`, el CONTENEDOR, no solo `.container-menu`:
 * dentro van también el overlay del menú (`.ms-menu-wrapper`), su fondo
 * (`.ms-ma-bg`) y la capa de cierre — todo eso sobra en escritorio. Y así
 * desaparecen también los ~125px que la pastilla reservaba en la fila.
 *
 * ⚠️⚠️ **NO tocar `.ms-h_w` a secas.** Esa clase la comparten la hamburguesa
 * (`.container-menu.ms-h_w`) **y el interruptor de modo claro/oscuro**
 * (`.ms_theme_mode.ms-h_w`). Ocultarla por clase se llevaría el toggle, que es
 * una decisión cerrada del proyecto. Verificado: el toggle cuelga de
 * `.ms-hw-inner`, hermano de `.main-header__btn`, así que esta regla no lo roza.
 * ========================================================================= */
@media (min-width: 1024px) {

    /*
     * El desplegable entero fuera: botón, overlay y capas de fondo.
     *
     * ⚠️⚠️ **`visibility: hidden` + `position: absolute`, NUNCA `display: none`.**
     *
     * Con `display:none` el elemento deja de tener caja y **todo lo que el JS
     * del tema mida sobre él devuelve 0**, que es de donde salieron DOS bugs
     * seguidos, los dos reportados por el cliente:
     *
     *   · `showMenu()` hace `menuWidth = $('.container-menu').outerWidth()` y
     *     luego anima `.main-header__btn` a ese ancho → horneaba `width:0px`
     *     inline, y al reducir la ventana la pastilla desbordaba y el
     *     interruptor de modo se le encimaba.
     *   · `ms_menu_button()` mide UNA sola vez en `window.load` y escribe el
     *     resultado en píxeles inline sobre `.ms-ma-bg` y `#primary-menu-button`
     *     (`el_wrap_bg.css({width: close_width+'px', …})`). Cargando en
     *     escritorio quedaban en **`width: 0px`** y `0×0`, y al bajar de
     *     breakpoint el desplegable salía descuadrado. **Nunca se recalcula.**
     *
     * `visibility: hidden` conserva la caja —así `outerWidth()` mide bien—,
     * pero el elemento no se ve, no recibe clics y sale del orden de tabulación
     * y del árbol de accesibilidad. `position: absolute` lo saca del flujo para
     * que no reserve los ~125px en la fila del header, que es lo que buscaba el
     * `display:none` original.
     *
     * ⭐ Esto arregla la CAUSA: con la caja medible, los dos cálculos del tema
     * dan el valor correcto desde el principio y no hay nada que contrarrestar.
     */
    .main-header__btn {
        position: absolute !important;
        visibility: hidden !important;
        pointer-events: none !important;
    }

    /*
     * ⚠️⚠️ Y TAMBIÉN LOS HIJOS, uno por uno (2026-08-25, reporte con captura).
     *
     * `visibility` se hereda, pero un hijo con visibility PROPIA le gana a la
     * heredada — y el tema tiene exactamente eso: al scrollear añade `move` y
     * su regla `.move .container-menu { visibility: visible }` volvía a
     * encender la pastilla DENTRO del contenedor oculto. Por eso el botón
     * aparecía «desde el primer scroll hacia abajo» en escritorio, encimado
     * al menú horizontal. Medido: con scroll 800 el padre daba `hidden` y
     * `.container-menu`, `.action-menu` y el «Menu» daban `visible`.
     *
     * Con el `!important` EN CADA descendiente ya no hay regla del tema que
     * lo re-encienda. Las cajas se conservan: las medidas del JS siguen bien.
     */
    .main-header__btn * {
        visibility: hidden !important;
    }

    /* Y el menú horizontal, inmune al `showMenu()` del tema. */
    #primary-menu-default > li.menu-item {
        opacity: 1 !important;
        visibility: visible !important;
        transform: none !important;
    }
}

/*
 * ⚠️⚠️ EFECTO DE SEGUNDO ORDEN del `display:none` de arriba — el toggle se
 * montaba encima del «Menu» al reducir la ventana (reportado 2026-08-20).
 *
 * `showMenu()` empieza midiendo: `const menuWidth = $('.container-menu').outerWidth();`
 * y luego hace `.fromTo('.main-header__btn', {width:'0%'}, {width: menuWidth})`.
 * En escritorio el botón está en `display:none`, así que **esa medida devuelve
 * 0** y GSAP hornea `width: 0px` inline. Al reducir la ventana, `showMenu()`
 * vuelve a llamarse pero su guard `if (!$menuInner.hasClass('move'))` lo salta
 * —ya venía en `move` de haber scrolleado—, así que **el `width: 0` rancio se
 * queda**. El botón colapsa, su pastilla de ~119px desborda (el contenedor es
 * `overflow: visible`) y el interruptor de modo se le encima.
 *
 * Medido a 375: con el inline `width:0` el toggle salta de x=207 a x=326 y pisa
 * la pastilla **36px**. Sin él, van pegados sin tocarse.
 *
 * El arreglo es el mismo recurso que con los ítems del menú: GSAP escribe
 * inline sin `!important`, así que aquí se le devuelve el ancho natural. En
 * móvil la hamburguesa tiene que estar SIEMPRE, así que no se pierde ninguna
 * animación que importe — solo el barrido de ancho con el que el tema la
 * revelaba.
 */
@media (max-width: 1023px) {
    .main-header__btn { width: auto !important; }
}

/* =========================================================================
 * Menú del header — tres entradas
 *
 * Con solo Inicio · Convocatoria · Acerca de, el menú centrado se veía
 * disperso: el tema reparte los ítems a lo ancho y quedaban tres palabras
 * sueltas separadas por medio header. Se agrupa al centro y se acerca el
 * espaciado, sin estirar el bloque de borde a borde.
 * ========================================================================= */
.main-header__layout .menu-center .main-navigation > ul,
.main-header__layout .menu-center .navbar-nav {
    gap: 8px;
    justify-content: center;
}

.main-header__layout .menu-center .navbar-nav > li > a {
    padding-left: 14px;
    padding-right: 14px;
}

/* =========================================================================
 * Barra de anclas de Convocatoria
 *
 * La página es larga (trece bloques) y sin esto hay que scrollear a ciegas.
 * Se queda pegada JUSTO DEBAJO del header al hacer scroll.
 *
 * ⚠️ `top` tiene que ser el **borde inferior real** del header, no su alto.
 * Medido: el header arranca 5px abajo y mide 90, o sea termina en 95. Con
 * `top:90` la barra se le metía 5px por debajo y se veía encimada.
 *
 * ⚠️⚠️ Y el z-index tiene que ir POR DEBAJO del header. El header del tema
 * está en `z-index: 3` (medido); con 20 la barra se pintaba ENCIMA del logo y
 * del menú. Con 2 el header siempre gana, y la barra sigue tapando el
 * contenido normal de la página, que es lo que tiene que hacer — las secciones
 * son `position: relative; z-index: auto` y no crean contexto por encima.
 *
 * ⚠️ El padre de un elemento `sticky` no puede tener `overflow` distinto de
 * `visible` o deja de pegarse; por eso la barra va en su propio contenedor de
 * sección, hija directa del documento.
 * ========================================================================= */
:root { --cnaay-header-borde: 95px; }   /* borde inferior del header fijo */
:root { --cnaay-anclas-alto: 0px; }     /* alto de la barra de anclas; 0 si no hay */

/* =========================================================================
 * SALTO A UN ANCLA — que no aterrice debajo del header
 *
 * El header es FIJO y en Convocatoria la barra de anclas va pegada justo
 * debajo, también fija. Entre las dos tapan una franja del alto de la ventana,
 * y el navegador —que no sabe nada de eso— dejaba el borde de la sección en
 * y=0: los primeros 162px de la sección quedaban ocultos. Como cada sección
 * abre con 100px de padding y luego su título, **lo que se tapaba era
 * justamente el título** y la página parecía cortada a media frase.
 *
 * `scroll-padding-top` en el contenedor de scroll le dice al navegador cuánto
 * descontar. Se aplica a TODO salto de ancla: clic en la barra, enlace desde
 * otra página (`/convocatoria/#bases`) y carga directa con hash.
 *
 * Medido: header 95 + barra 67 = 162, más **32px de aire**.
 *
 * ⚠️ Esos 32px son el hueco REAL entre la barra y el título, no un margen de
 * seguridad: el `_element_id` de cada ancla está en la **cabecera** —el propio
 * h2, sin padding arriba (ver `cnaay_build_convocatoria.php`)—, no en la
 * sección con sus 100px. O sea que el título aterriza exactamente sobre esta
 * línea. Con 8px quedaba lamiendo la barra. **Este es el número que se toca
 * para dar más o menos aire.**
 *
 * ⚠️ Los dos valores se miden en JS y cambian por breakpoint (el header usa
 * otro alto de logo en móvil). `--cnaay-anclas-alto` vale **0 fuera de
 * Convocatoria**, así que ahí solo se descuenta el header — que es lo correcto
 * para `/acerca-de/#contacto` y compañía.
 *
 * ℹ️ `scroll-padding-top` lo respetan el salto nativo y `scrollIntoView()`.
 * Un scroll hecho a mano con `window.scrollTo()` lo ignoraría — el tema tiene
 * su smooth-scroll APAGADO (`data-smooth-scroll="off"`), así que aquí manda el
 * nativo.
 * ========================================================================= */
html {
    scroll-padding-top: calc(var(--cnaay-header-borde) + var(--cnaay-anclas-alto, 0px) + 32px);
}

/* =========================================================================
 * Fondo del header una vez pasado el hero
 *
 * El header va transparente sobre el hero, pero al scrollear se quedaba
 * transparente también sobre el contenido y el logo y el menú se leían encima
 * de las tarjetas.
 *
 * ⚠️ La clase `show-bg` del tema NO sirve: en esta versión solo cambia la
 * opacidad de un `::before` que no existe (`content: none`), y nadie llega a
 * ponerla. Comprobado. La clase la pone `cnaay-fixes.js` midiendo el borde
 * inferior del hero.
 *
 * El borde inferior es el mismo tratamiento que usa el tema en su `show-bg`:
 * el color de fondo del sitio al 20 %.
 * ========================================================================= */
/*
 * ⚠️⚠️ NO se pinta el fondo sobre `.main-header__layout` directamente: deja
 * FRANJAS. La geometría real, medida:
 *
 *   .main-header          absolute, se va con el scroll  (no sirve de nada)
 *   .main-header__layout  FIXED, ocupa y = 10 … 90       ← el que se queda
 *   .main-header__inner   relative, ocupa y =  5 … 95    ← ¡sobresale!
 *
 * O sea que el contenido (logo y menú) se sale 5px por arriba y 5px por abajo
 * de la caja que se pintaría, y encima queda sin cubrir la franja de 0 a 10.
 * Se veían tres bandas.
 *
 * La solución es una franja FIJA de 0 hasta el borde inferior real del header
 * —el mismo valor con el que se ancla la barra de anclas—, pintada por detrás
 * del contenido con `z-index: -1`.
 *
 * ⚠️ Va en `::after` y no en `::before`: el tema ya tiene
 * `.main-header.ms-nb--transparent .main-header__layout::before{opacity:0}` y
 * anularía el nuestro.
 */
.main-header .main-header__layout::after {
    transition: opacity 250ms ease;
    opacity: 0;
}

.main-header.cnaay-header-solido .main-header__layout::after {
    content: "";
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    height: var(--cnaay-header-borde);
    background-color: var(--cnaay-bg);
    border-bottom: solid 1px var(--cnaay-border);
    z-index: -1;
    opacity: 1;
}

#cnaay-anclas {
    position: sticky;
    top: var(--cnaay-header-borde);
    z-index: 2;
    background: var(--cnaay-surface);
    border-bottom: 1px solid var(--cnaay-border);
}

/* En móvil no caben nueve enlaces: la fila scrollea en horizontal en vez de
   partirse en renglones.

   ⚠️ El scroll va en el CONTENEDOR DIRECTO, no en un `.e-con-inner`: la barra
   está en modo `full`, y en ese modo Elementor NO genera el wrapper interno.
   Medido a 413px: la fila necesita 413 y el hueco es de 375. */
#cnaay-anclas,
#cnaay-anclas > .e-con {
    overflow-x: auto;
    overflow-y: hidden;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
}
#cnaay-anclas::-webkit-scrollbar,
#cnaay-anclas > .e-con::-webkit-scrollbar { display: none; }

/* Los enlaces no se parten a media palabra ni se encogen. */
#cnaay-anclas .ms-sl { white-space: nowrap; }
#cnaay-anclas > .e-con > .elementor-element { flex: 0 0 auto; }

@media (max-width: 767px) {
    #cnaay-anclas { top: var(--cnaay-header-borde); }
}

/* --- SIN subrayado (decisión del cliente, 2026-08-20) --------------------
 *
 * La barra se queda SOLO con el giro, igual que el menú principal. El
 * subrayado no es nuestro: son los dos pseudo-elementos que `.ms-sl` trae del
 * tema — `::before` la línea gris fija y `::after` la dorada que entra en
 * hover, las dos a `bottom:4pt` y 1px de alto.
 *
 * ⭐ Se apagan con `content: none`, que impide que el navegador los GENERE. No
 * basta con `transform: scaleX(0)`: el tema los vuelve a estirar desde
 * `.ms-sl:hover::after{transform:scaleX(1)}`, que puntúa (0,2,1) — lo mismo
 * que un selector `.cnaay-ancla .ms-sl::after`, así que sería un empate
 * decidido solo por el orden de las hojas. Anulando `content` no hay pelea:
 * el tema solo lo declara en la regla sin `:hover`, de (0,1,1), y sin
 * pseudo-elemento las reglas de hover no tienen sobre qué aplicar.
 *
 * ℹ️ Esto libera los dos pseudos de `.ms-sl`, pero el giro se queda con sus
 * `<span>` reales: el widget no pasa `custom_attributes` al `<a>`, así que
 * nunca habría un `title` del que tirar para copiar el `content: attr(title)`
 * del menú.
 */
.cnaay-ancla .ms-sl::before,
.cnaay-ancla .ms-sl::after { content: none; }

/* --- La palabra GIRA al pasar el cursor, como en el menú principal --------
 *
 * Valores 1:1 de `themes/osty/assets/css/main.css`, regla
 * `#primary-menu-default > .menu-item > a span` y su `::after`: la palabra
 * gira 91° sobre el eje X y se desvanece mientras otra copia entra desde
 * −90°, con el centro de giro empujado −.55em en Z.
 *
 * ⚠️⚠️ **El menú usa `a::after { content: attr(title) }` y aquí NO se puede.**
 * Dos motivos, y el segundo sigue vigente aunque el primero ya no:
 *   1. `.ms-sl` gastaba SUS DOS pseudo-elementos en el subrayado animado.
 *      Desde el 2026-08-20 están libres (ver el bloque de arriba).
 *   2. El widget **no pasa `custom_attributes` al `<a>`**, así que no hay
 *      ningún `title` del que sacar el `content`.
 * Por eso la segunda copia es un `<span>` real, que inyecta el filtro de
 * `functions.php` a partir de la clase `cnaay-ancla`.
 *
 * ⚠️ `_css_classes` cae en el ENVOLTORIO del widget, no en el `<a>`: el
 * selector tiene que ser `.cnaay-ancla .ms-sl`, nunca `.ms-sl.cnaay-ancla`.
 *
 * ⚠️ Solo de 1024px para arriba — igual que el tema, que anula el efecto con
 * `content:none` dentro de `@media (max-width:1023px)`. En táctil no hay hover
 * y el texto se quedaría girado a medias.
 */
@media (min-width: 1024px) {

    .cnaay-ancla .cnaay-flip {
        display: inline-block;
        backface-visibility: hidden;
        transform-style: preserve-3d;
        transform-origin: center center -.55em;
    }

    .cnaay-ancla .cnaay-flip--out {
        transform: rotateX(0);
        transition: opacity   .7s cubic-bezier(.785, .135, .15, .86),
                    transform .5s cubic-bezier(.785, .135, .15, .86);
    }

    /* La copia que entra va encima, sin ocupar sitio. */
    .cnaay-ancla .cnaay-flip--in {
        position: absolute;
        top: 0;
        left: 0;
        opacity: 0;
        transform: rotateX(-90deg);
        transition: transform .5s cubic-bezier(.785, .135, .15, .86),
                    opacity   .5s cubic-bezier(.785, .135, .15, .86);
    }

    .cnaay-ancla .ms-sl:hover .cnaay-flip--out { transform: rotateX(91deg); opacity: 0; }
    .cnaay-ancla .ms-sl:hover .cnaay-flip--in  { transform: rotateX(0);     opacity: 1; }
}

/* =========================================================================
 * Botón «estilo Osty» (`btn-osty`) — los tres círculos, INVISIBLES en claro
 *
 * El plugin imprime el SVG con `fill="#121212"` HORNEADO en el PHP
 * (`block_button.php`, las dos copias del icono). Ese negro va bien sobre las
 * pastillas del modo oscuro, pero en modo claro la pastilla izquierda es
 * `--color-contrast-higher` = #14101A —o sea, casi el mismo negro— y el icono
 * **desaparece**. Medido:
 *
 *                      pastilla izq.   pastilla der.
 *   oscuro  #121212      16.62 ✓          10.16 ✓
 *   CLARO   #121212       1.00 ✗ !!        3.49  (al filo del mínimo de 3:1)
 *
 * Se rutea el relleno a `--color-contrast-lower`, que es **la respuesta del
 * propio tema**: es lo que usa en su regla de hover
 * (`.btn:hover .f-btn-l svg path{fill:var(--color-contrast-lower)}`). Queda:
 *
 *   oscuro  13.07 ✓ / 7.99 ✓      claro  14.30 ✓ / 4.09 ✓
 *
 * ⚠️ `fill` es un ATRIBUTO DE PRESENTACIÓN, así que basta CSS para ganarle —
 * no hace falta tocar `osty_plugin`, que además se pierde al actualizar.
 *
 * Afecta a todo `btn-osty` del sitio; hoy son los cuatro botones «Ver
 * categorías» de las tarjetas apiladas de la portada.
 * ========================================================================= */
.btn-osty svg path { fill: var(--color-contrast-lower); }

/* -------------------------------------------------------------------------
 * …y el botón entero NO cambia de color en modo claro (2026-08-19)
 *
 * Petición del cliente: el `btn-osty` conserva siempre el aspecto del modo
 * oscuro. El tema lo pinta **solo** con cuatro variables suyas —las contadas
 * en `main.css`: `--color-primary`, `--color-contrast-higher`,
 * `--color-contrast-lower` y `--color-contrast-medium`—, así que en vez de
 * reescribir sus ocho reglas (base, hover, y las de cada tamaño) se
 * **redefinen esas variables DENTRO del botón**.
 *
 * Las custom properties heredan, así que todo lo de dentro —las dos
 * pastillas, el texto y los dos SVG, en reposo y en hover— resuelve contra
 * estos valores y no contra los del modo. Una sola regla en vez de ocho, y no
 * se rompe si el tema añade otra que use las mismas variables.
 *
 * ⚠️ Solo afecta a `btn-osty`. El `btn-default` —«Inscríbete», «Ver
 * convocatoria»…— **sigue conmutando con el modo**, que es lo que pide
 * `paleta.md`.
 *
 * ℹ️ El oro como RELLENO en modo claro es correcto según `paleta.md`: lo que
 * prohíbe es el oro brillante como color de TEXTO sobre el hueso. Aquí el
 * texto va en `--cnaay-btn-osty-ink` sobre el oro: 8.05:1.
 * ------------------------------------------------------------------------- */
.btn-osty {
    --color-primary:         var(--cnaay-btn-osty-fill);
    --color-contrast-higher: var(--cnaay-btn-osty-pill);
    --color-contrast-lower:  var(--cnaay-btn-osty-ink);
}

/*
 * ⚠️⚠️ …PERO CONGELAR LAS VARIABLES NO BASTA (2026-08-20).
 *
 * Lo reportó el cliente: el botón seguía cambiando entre Black y White. El
 * relleno y los puntos sí estaban fijos; **el TEXTO no**.
 *
 * La causa no es que el tema cambie el VALOR de una variable —eso es lo que
 * arregla el bloque de arriba— sino que **cambia de VARIABLE según el modo**:
 *
 *     .btn                          { color: var(--color-contrast-higher) }  (0,1,0)
 *     body[data-theme="dark"] .btn  { color: var(--color-contrast-lower)  }  (0,2,0)
 *
 * En oscuro gana la segunda y el texto sale con la tinta oscura; en claro esa
 * regla no casa, cae a la primera y el texto sale con `--color-contrast-higher`,
 * que en este botón está congelado en **#F5F1E8** — o sea crema sobre oro.
 * Medido en carga real: `#2E2438` en oscuro contra `#F5F1E8` en claro.
 *
 * ⭐ Ninguna redefinición de variables puede arreglar esto: hay que fijar la
 * propiedad. La regla puntúa **(0,2,1)** —un elemento y dos clases— para ganarle
 * a la (0,2,0) del tema sin empatar y sin `!important`.
 *
 * ℹ️ Los tres puntos NO necesitan lo mismo: su regla del tema
 * (`body[data-theme="dark"] .btn svg path`) y la nuestra
 * (`.btn-osty svg path`) apuntan las dos a `--color-contrast-lower`, que aquí
 * está congelado ⇒ resuelven al mismo valor gane quien gane. Verificado en los
 * dos modos.
 */
body .btn.btn-osty { color: var(--cnaay-btn-osty-ink); }

/*
 * ⚠️ Dentro de la TABLA DE CUOTAS hay que soltarle el fondo que el tema le
 * pinta al `<a>` en hover:
 *
 *     .ms-pt-block .ms-pt--footer .btn:hover { background-color: … }   (0,3,0)
 *
 * En el botón plano eso ES el efecto; en el estilo Osty el color lo llevan las
 * dos pastillas y el `<a>` tiene que quedarse transparente, o aparece un bloque
 * de fondo detrás de ellas. El selector puntúa (0,4,0) para ganarle.
 */
.ms-pt-block .ms-pt--footer .btn-osty:hover { background-color: transparent; }

/*
 * ⚠️⚠️ **Y la pastilla derecha tiene que LLENAR el botón, o el hueco del hover
 * sale al triple.**
 *
 * `btn--full-width` estira el `<a>` pero NO a `.f-btn-r`, que se queda del
 * ancho de su contenido. Como el botón centra (`justify-content:center`),
 * quedan ~28px de holgura a cada lado — y esa holgura se SUMA al
 * `translateX(54.67px)` del hover. Medido:
 *
 *                        ancho <a>   .f-btn-r   hueco al hover
 *   Categorías (ok)         215        215           7px
 *   Cuotas (antes)          247        190          35px   ← se veían separadas
 *
 * `.f-btn-l` es absoluto, así que `.f-btn-r` es el único hijo en flujo: con
 * `flex-grow:1` llena el botón, arranca en x=0 como en Categorías y el hueco
 * vuelve a 7px.
 *
 * ⭐ Generalizado el 2026-08-25 (antes iba acotado a `.ms-pt--footer`): la
 * misma física aplica a CUALQUIER btn-osty a ancho completo — hoy los tres de
 * Cuotas y el «Inscríbete ahora» del CTA de la portada (plantilla 7571), que
 * pasó a osty conservando su `full_width`.
 */
.btn-osty.btn--full-width .f-btn-r { flex-grow: 1; }

/* =========================================================================
 * FORMULARIO (Luna Forms) — que siga la paleta del sitio en los DOS modos
 *
 * ⚠️⚠️ **El plugin NO contempla modo oscuro.** Su CSS no tiene ni una regla
 * `prefers-color-scheme` ni `[data-theme]` (comprobado en `assets/css/form.css`),
 * y sus ajustes de apariencia solo cubren layout, ancho, color de acento,
 * estilo de campo y formas — nada de fondo ni texto de los campos.
 *
 * Eso provoca una colisión seria en modo oscuro:
 *
 *   fondo del input   #FFFFFF   ← fijo, del plugin
 *   color del texto   #F5F1E8   ← del TEMA, que sí conmuta con el modo
 *   → contraste ~1.05:1: **lo que escribes es prácticamente invisible.**
 *
 * Y el placeholder venía en `rgb(117,117,117)` con `opacity:.5`, que sobre
 * blanco da ~1.9:1 — ilegible en los dos modos, no solo en oscuro.
 *
 * Se enganchan los campos a los tokens del sitio, que ya conmutan solos:
 *
 *   fondo        --cnaay-surface     #1A1320 oscuro / #FFFFFF claro
 *   texto        --cnaay-text        #F5F1E8 / #14101A
 *   borde        --cnaay-border      #2E2438 / #E6E0D6
 *   placeholder  --cnaay-text-soft   #A79FB0 / #5C5566   (opacidad a 1)
 *
 * ⚠️ La `opacity:.5` del plugin hay que anularla: con ella el color del
 * placeholder se mezcla con el fondo y el contraste deja de ser predecible.
 *
 * ⚠️ El `select` NO es un `<select>` nativo: el plugin lo sustituye por un
 * `button.lnf-selx-trigger` + un panel `.lnf-selx-drop`. Hay que vestir los
 * dos, o el desplegable se abre blanco sobre la página oscura.
 * ========================================================================= */
.lnf-form input[type="text"],
.lnf-form input[type="email"],
.lnf-form input[type="tel"],
.lnf-form input[type="url"],
.lnf-form input[type="number"],
.lnf-form input[type="password"],
.lnf-form input[type="date"],
.lnf-form input[type="datetime-local"],
.lnf-form textarea,
.lnf-form select,
.lnf-form .lnf-selx-trigger {
    background-color: var(--cnaay-surface);
    color: var(--cnaay-text);
    border-color: var(--cnaay-border);
}

/*
 * Opacidad a 1: es lo que hace el contraste predecible (ver arriba).
 *
 * ⚠️⚠️ **El `!important` aquí NO es un parche perezoso: es obligatorio.** Quien
 * fuerza la opacidad es el TEMA, no el plugin, y lo hace con `!important` sobre
 * un selector de un solo elemento (`main.css`):
 *
 *     input::placeholder, textarea::placeholder { opacity: .5 !important; }
 *
 * Una declaración `!important` gana a cualquier otra normal **por muy
 * específica que sea**, así que subir la especificidad no sirve de nada: la
 * única forma de recuperar el control es otro `!important`. Solo se aplica a
 * la opacidad, y solo dentro de `.lnf-form` — el resto del sitio (buscador,
 * etc.) se queda con el comportamiento del tema.
 */
.lnf-form input::placeholder,
.lnf-form textarea::placeholder {
    color: var(--cnaay-text-soft);
    opacity: 1 !important;
}

/* El desplegable propio del plugin, que se abre por encima de la página. */
.lnf-form .lnf-selx-drop {
    background-color: var(--cnaay-surface);
    color: var(--cnaay-text);
    border-color: var(--cnaay-border);
}
.lnf-form .lnf-selx-opt { color: var(--cnaay-text); }
.lnf-form .lnf-selx-opt:hover,
.lnf-form .lnf-selx-opt[aria-selected="true"] {
    background-color: var(--cnaay-border);
    color: var(--cnaay-text);
}
.lnf-form .lnf-selx-grouplbl { color: var(--cnaay-text-soft); }

/* Etiquetas y textos de apoyo. */
.lnf-form label       { color: var(--cnaay-text); }
.lnf-form .lnf-desc   { color: var(--cnaay-text-soft); }
.lnf-form .lnf-req    { color: var(--cnaay-primary); }

/*
 * El ACENTO del plugin es `#2372D9`, el azul de marca de Luna: en un sitio de
 * oro y violeta desentona. Su ajuste `accent_color` solo admite un HEX, y un
 * hex no puede conmutar entre modos — el mismo problema que los controles de
 * Elementor. Por eso se rutea aquí a la variable.
 *
 * ⚠️ El botón NO puede quedarse con el texto blanco que trae el plugin: sobre
 * el oro daría ~1.9:1. Van los tokens de botón del sitio, que `paleta.md` ya
 * dejó calculados en 10.18:1 (#14101A sobre #E8B84B).
 */
.lnf-form { --lnf-accent: var(--cnaay-primary); }

.lnf-form .lnf-button {
    background-color: var(--cnaay-btn-fill);
    color: var(--cnaay-btn-fill-text);
}
.lnf-form .lnf-button:hover,
.lnf-form .lnf-button:focus-visible {
    background-color: var(--cnaay-btn-fill-hover);
    color: var(--cnaay-btn-hover-text);
}

/* =========================================================================
 * PORTADA · Categorías — tarjetas APILADAS («Section Sticky» del tema)
 *
 * Copiadas 1:1 de la página «Services» del demo. El tema imprime en cada
 * tarjeta la clase `ms-sticky-w` + `style="top:0px"` inline
 * (`inc/theme-elementor.php`) y `main.css` trae `position:sticky!important`.
 *
 * ⚠️ A `top:0` la tarjeta pegada se METE debajo del header, que aquí es fijo
 * y se vuelve sólido al pasar el hero (el demo va a 0 porque su header no es
 * fijo). Se pega justo bajo el borde real del header, que `cnaay-fixes.js`
 * publica en `--cnaay-header-borde` por breakpoint (95 escritorio / 90 móvil;
 * con admin bar ya va corrido). Hace falta `!important` para ganarle al
 * inline del tema; y el selector puntúa (1,1,0), por encima del
 * `body.admin-bar .ms-sticky-w:not(.thumbnail){top:32px!important}` de
 * main.css (0,2,1).
 *
 * ⚠️ Va por `#cnaay-categorias` (el `_element_id` de la sección, puesto en
 * `cnaay_build_index.php`) porque `_css_classes` NO llega al marcado de los
 * contenedores.
 * ========================================================================= */
#cnaay-categorias .ms-sticky-w { top: var(--cnaay-header-borde) !important; }

/* El «01.» de cada tarjeta es un <p> (el demo lo hace <h2>, pero dos h2 por
   tarjeta sin jerarquía no van). Solo hay que devolverle la fuente de títulos
   (Vansie vía --font-heading): la interlínea ya es la misma que en el demo,
   porque Elementor da `line-height:1` a todo `.elementor-heading-title` sea
   cual sea la etiqueta. ⚠️ NO poner aquí `var(--heading-line-height)` (1.2):
   engorda la fila 7px respecto al demo.

   Misma razón para el «01» de los pilares de Acerca de (helper `pilar()`). */
.cnaay-stack__num .elementor-heading-title,
.cnaay-pilar__num .elementor-heading-title { font-family: var(--font-heading); }

/* =========================================================================
 * ACERCA DE · A2 «Quiénes somos» — la foto se sale de la retícula
 *
 * La sección es `boxed` (contenido 1140px, medido), así que la foto se saca
 * hacia el margen derecho con un margen NEGATIVO para que el bloque deje de
 * ser dos rectángulos iguales pegados.
 *
 * ⚠️⚠️ **Un margen negativo fijo provoca scroll horizontal.** El hueco que
 * queda a la derecha depende del ancho de la ventana, así que el valor se
 * calcula y se limita con `min()`:
 *
 *     max(-80px, min(0px, calc((1140px - 100vw) / 2 + 17px)))
 *
 *   · `(1140px - 100vw)/2` es exactamente el hueco disponible, en negativo.
 *   · `+ 17px` descuenta la barra de scroll: `100vw` la INCLUYE, pero el
 *     contenido se centra en `clientWidth`, que no. Sin esta holgura la foto
 *     se pasa ~8px del borde visible y aparece la barra horizontal — es la
 *     misma trampa del `innerWidth` vs `clientWidth` de siempre.
 *   · `min(0px, …)` lo apaga solo por debajo de ~1174px de ventana, donde ya
 *     no hay hueco que aprovechar.
 *   · `max(-80px, …)` **TOPA el desborde**. Sin tope, a 1920 el hueco es de
 *     373px y la foto se iba a 836×680: dejaba de ser vertical, que es lo
 *     primero que se pidió. Con el tope va como mucho a 543×680 (0.80, casi
 *     el 3:4 del original) y el gesto se sigue leyendo igual. **Este es el
 *     número que se toca si se quiere más o menos desborde.**
 *
 * Verificado sin desborde a 1920 / 1440 / 1280 / 1200 / 1024 / 768 / 375.
 *
 * `overflow-x: clip` en la sección es la red de seguridad. ⚠️ `clip`, NO
 * `hidden`: `hidden` crea un contenedor de scroll y rompería cualquier
 * `position:sticky` que caiga dentro.
 *
 * ⚠️⚠️ **El margen negativo SOLO no basta: hay que ensanchar la foto.** El
 * widget es un *flex item* de su columna, y en flexbox un `margin-right`
 * negativo NO ensancha al elemento (eso solo pasa con un bloque de `width:
 * auto`): únicamente acerca al hermano siguiente, y aquí no hay ninguno.
 * Medido en el primer intento: la foto seguía en 463px, terminando en x=1202,
 * o sea exactamente en el borde del contenido — margen aplicado y cero efecto
 * visible. Por eso van las tres declaraciones: `width` la ensancha, el margen
 * evita que el contenedor cuente ese ancho de más, y…
 *
 * ⚠️⚠️ …**`max-width: none` es obligatorio.** El widget lleva `max-width: 100%`
 * y sin quitarlo el ancho se TOPA en el de su columna: se queda exactamente
 * igual. Verificado en vivo — ni siquiera un `width: 516px !important` inline
 * movía nada (seguía en 463px) hasta soltar el `max-width`. Si algún día «el
 * desborde dejó de funcionar», mirar esto antes que la aritmética.
 * ========================================================================= */
#cnaay-quienes { overflow-x: clip; }

@media (min-width: 1025px) {
    #cnaay-quienes .cnaay-foto-desborde {
        --cnaay-desborde: max(-80px, min(0px, calc((1140px - 100vw) / 2 + 17px)));
        width: calc(100% - var(--cnaay-desborde));
        max-width: none;
        margin-right: var(--cnaay-desborde);
    }
}

/* Token que consumen los widgets Luna (luna-custom-widgets). Sin él caía al
   fallback #2372D9, que es el azul de marca de cliente-abc.
   ⚠️ Va DENTRO de cada bloque de modo, no en `:root`: el tema pone
   `data-theme` en el <body>, así que `:root[data-theme]` NUNCA casa y la
   variable se quedaba fija en el valor del modo oscuro. */
:root[data-theme="dark"], body[data-theme="dark"]   { --luna-accent: var(--cnaay-accent); }
:root[data-theme="light"], body[data-theme="light"] { --luna-accent: var(--cnaay-accent); }

/* =========================================================================
 * DOCUMENTO LEGAL en contenido clásico (`.cnaay-legal`)
 *
 * Lo usa el aviso de privacidad (7650), que NO va en Elementor: es prosa larga
 * que va a cambiar cuando la revise el abogado, y se edita mucho mejor como
 * `post_content`. La escribe `_build/cnaay_build_aviso.php`.
 *
 * ⚠️⚠️ **El tema aplana TODOS los márgenes.** Su reset de `main.css` deja `h2`,
 * `h3`, `p`, `ul` y `figure` en `margin: 0`, porque la plantilla por defecto
 * está pensada para que dentro vaya Elementor —que pone su propio espaciado— y
 * no prosa. Medido antes de esta regla: las trece secciones salían pegadas en
 * un solo muro de texto, sin un pixel entre párrafo y párrafo. Cualquier
 * contenido clásico que se meta al sitio va a necesitar esto.
 *
 * ⚠️ **Y la caja del tema es demasiado ancha para leer.** `.ms-default-page.
 * container` da 1241px a 1280 de viewport: medido, **117 caracteres por
 * línea**, cuando lo legible son 45–75. El tope de `--cnaay-legal-ancho` deja
 * ~73.
 *
 * ⚠️⚠️ **Y la columna VA CENTRADA.** El primer intento la dejó pegada a la
 * izquierda —para que arrancara alineada con el `<h1>`, que vive en un
 * `.container` hermano— y el resultado fue peor que el problema: 473px de
 * hueco muerto acumulados a la derecha, que se leen como **un sidebar que
 * falta**, no como una columna de lectura. Lo reportó el cliente.
 *
 * ⭐ Para que el título no se descuelgue, lo que se centra es el **`h1`**, no
 * su contenedor: `.ms-sp--header` es un `.container` con `padding: 0 15px`, así
 * que toparlo a la misma anchura dejaría el título 15px a la derecha del texto.
 * Centrando el `h1` dentro de su caja, los dos caen en la misma `x` (medido:
 * 242 y 243, la diferencia es el padding de 12px del otro contenedor).
 *
 * ℹ️ Los colores, el borde de las tablas y las viñetas NO se tocan: eso el tema
 * sí lo trae y ya conmuta con el modo (medido: texto `#F5F1E8` en oscuro,
 * `td` con borde de 1px y padding 8/20). Aquí solo va el ritmo vertical, el
 * ancho de línea y el centrado.
 *
 * ⚠️ La clase `cnaay-legal-page` del `<body>` la pone `functions.php` cuando el
 * contenido de la página trae el envoltorio `.cnaay-legal` — así cualquier
 * documento nuevo hecho con `guardar_legal()` lo hereda sin tocar nada.
 * ========================================================================= */
:root { --cnaay-legal-ancho: 780px; }

.cnaay-legal {
    max-width: var(--cnaay-legal-ancho);
    margin-inline: auto;
}

/*
 * ⚠️⚠️ TRAMPA DE ESPECIFICIDAD (la tercera de este proyecto). El título NO se
 * centraba con `body.cnaay-legal-page .ms-sp--title`, que puntúa **(0,2,0)**:
 * el tema trae `.page .ms-sp--header .ms-sp--title` con su propio `max-width`,
 * y eso puntúa **(0,3,0)**. La regla estaba en la hoja, casaba con el elemento
 * y no hacía absolutamente nada — el computado seguía en 1320px.
 *
 * Se sube a **(0,3,1)** añadiendo el contenedor y calificando con la etiqueta.
 * Igualar a (0,3,0) habría bastado por orden de hojas, pero un empate que solo
 * gana el orden se rompe a la primera que alguien mueva un enqueue.
 */
body.cnaay-legal-page .ms-sp--header h1.ms-sp--title {
    max-width: var(--cnaay-legal-ancho);
    margin-inline: auto;
}

.cnaay-legal h2 { margin-top: 3rem;   margin-bottom: 1rem; }
.cnaay-legal h3 { margin-top: 2rem;   margin-bottom: .5rem; }

.cnaay-legal p,
.cnaay-legal ul,
.cnaay-legal ol { margin-bottom: 1rem; }

.cnaay-legal li + li { margin-top: .35rem; }

/* La primera línea, la de «Última actualización», va apagada: es metadato del
   documento, no su contenido. */
.cnaay-legal__fecha { color: var(--cnaay-text-soft); margin-bottom: 2rem; }

/* Las tablas scrollean dentro de su propia caja en lugar de desbordar la
   página: la de transferencias lleva tres columnas y en móvil no cabe.
   ⚠️ `auto` y no `clip`: aquí SÍ se quiere que la tabla se pueda arrastrar. */
.cnaay-legal .cnaay-tabla {
    margin: 1.5rem 0;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
}
.cnaay-legal .cnaay-tabla table { min-width: 34rem; }

/* Aire antes del pie de página: el contenedor del tema no trae ninguno. */
.cnaay-legal { margin-bottom: 5rem; }

/* =========================================================================
 * LEGADO — paleta del SISTEMA DE REGISTRO (proyectos/clientes/cnaay)
 *
 * Morado #5b4bd7 y dorado #f4b400: es lo que usan hoy el registro en
 * producción y TODOS sus correos (correos.php). El sitio ya NO la usa, pero
 * se conserva declarada porque son dos identidades conviviendo.
 * ⚠️ Pendiente decidir si el registro se alinea a la identidad 2027.
 * ========================================================================= */
:root {
    --cnaay-legacy-morado: #5b4bd7;
    --cnaay-legacy-dorado: #f4b400;
}

/* =========================================================================
 * Modalidades (portada) — la foto se ve COMPLETA (2026-08-24)
 * -------------------------------------------------------------------------
 * Petición del cliente: tarjetas más amplias y las imágenes «casi
 * completas». La sección crece a 1300px desde el build (`boxed_width`) y
 * aquí se cambia el recorte: las fotos de Modalidades son 800×600 (4:3),
 * así que con `aspect-ratio: 4/3` se muestran enteras, sin recorte.
 *
 * ⭐ Acotado por `_element_id` (#cnaay-modalidades) A PROPÓSITO: la clase
 * `.cnaay-card` la comparten las tarjetas de aparato de Convocatoria, cuyas
 * fotos son 1600×900 — esas siguen en el 16/9 de la regla base. El id
 * (1,3,0) le gana a la base (0,3,0) sin !important.
 * ========================================================================= */
#cnaay-modalidades .cnaay-card .ms-sb .ms-sb--img { aspect-ratio: 4 / 3; }

/* =========================================================================
 * Convocatoria · aparatos — encuadre a la DERECHA (2026-08-25)
 * -------------------------------------------------------------------------
 * Las tarjetas de aparato reusan las cuatro fotos de Categorías de la
 * portada (1920×600): en la caja 16/9 el `cover` recorta los costados, y
 * el sujeto de las cuatro fotos está en el tercio DERECHO (verificado
 * viéndolas una por una). Con el `object-position` por defecto (centro)
 * quedaría medio cuerpo fuera.
 * ========================================================================= */
#cnaay-aparatos .cnaay-card .ms-sb .ms-sb--img img { object-position: 100% 50%; }

/* =========================================================================
 * Heros SIEMPRE en paleta OSCURA (cliente, 2026-08-25)
 * -------------------------------------------------------------------------
 * Los heros van sobre fotografía con velo oscuro en LOS DOS modos (los velos
 * usan --cnaay-negro, congelada desde el principio). Pero el hero de la
 * PORTADA hornea tokens de texto en sus widgets (--cnaay-text ×4,
 * --cnaay-text-soft ×5, --cnaay-primary ×3, --cnaay-border ×2, medido en su
 * _elementor_data): al cambiar a claro, el texto se volvía tinta sobre la
 * foto oscura. Aquí se redefinen esos tokens DENTRO del hero a sus valores
 * del modo oscuro — mismo patrón que el btn-osty congelado.
 *
 * Las variables CSS heredan del ancestro MÁS CERCANO: esta redefinición en
 * el subárbol le gana a body[data-theme="light"] sin pelear especificidad.
 *
 * `.elementor-widget-ms-hero` cubre los 6 heros de interiores. HOY no usan
 * ningún token (su texto es blanco horneado del demo, medido), pero el
 * freeze los blinda si algún día se les mete un widget con tokens.
 * ========================================================================= */
#cnaay-hero,
.elementor-widget-ms-hero {
    --cnaay-text:      #F5F1E8;
    --cnaay-text-soft: #A79FB0;
    --cnaay-primary:   #E8B84B;
    --cnaay-border:    #2E2438;

    /*
     * ⚠️ Y LA RAMPA DEL TEMA TAMBIÉN (2026-08-25, 2.ª pasada — reporte con
     * captura). Los textos del hero SIN color explícito no usan --cnaay-*:
     * heredan de los `--color-contrast-*` que Kirki redefine por modo. Con
     * solo los --cnaay-* congelados, esos seguían volviéndose tinta en claro.
     * Valores = los del bloque [data-theme="dark"] del tema.
     */
    --color-contrast-higher: hsl(0, 0%, 96%);
    --color-contrast-high:   hsl(240, 5%, 82%);
    --color-contrast-medium: hsl(213, 3%, 57%);
    --color-contrast-low:    hsl(240, 3%, 41%);
    --color-contrast-lower:  hsl(0, 0%, 19%);
    --color-contrast-white:  hsl(0, 0%, 19%);
    --color-primary:         #E8B84B;   /* el fondo de .btn--primary es var(--color-primary) */

    /*
     * ⚠️ Y EL DEGRADADO DE MARCA (2026-08-25, reporte con captura: «CNAAY»
     * seguía cambiando). Los h1 se pintan con `background: var(--cnaay-gold)`
     * recortado al texto, y --cnaay-gold se define POR MODO (brillante en
     * oscuro, oro profundo plano en claro). Aquí SÍ basta congelar la
     * variable: la regla se re-resuelve en el propio h1, no es herencia.
     * El hover del botón igual: sus dos variables también cambian por modo.
     */
    --cnaay-gold: linear-gradient(135deg, #A87C1A 0%, #F2D384 45%, #E8B84B 70%, #8A6410 100%);
    --cnaay-btn-fill-hover: #F2D384;
    --cnaay-btn-hover-text: #14101A;
}

/* =========================================================================
 * El «Menu» del botón cerrado, oculto (2026-08-25)
 * -------------------------------------------------------------------------
 * El tema inyecta un <li class="menu-title"> con el texto «Menu» (en inglés,
 * hardcodeado en app.js). En nuestro build su caja mide 129px (70 en el
 * demo: el ancho depende del panel ABIERTO horneado) y en el estado cerrado
 * cuelga FUERA de la pastilla: 54px a la izquierda y 26px por debajo —
 * es el «Menú encimado» que reportó el cliente junto al bug de la pastilla.
 *
 * ⭐ `visibility:hidden`, NUNCA `display:none`: el JS del tema mide estas
 * cajas (`ms_menu_button()` toma outerWidth/Height del ul completo) y sin
 * caja las medidas dan 0 — la trampa que ya costó tres bugs. Con el panel
 * ABIERTO el ul lleva la clase `show` y el selector deja de casar: el
 * título vuelve solo.
 * ========================================================================= */
@media (max-width: 1023px) {
    #primary-menu-button:not(.show) .menu-title { visibility: hidden; }
}

/* =========================================================================
 * Menú horizontal legible sobre el header SÓLIDO (2026-08-25)
 * -------------------------------------------------------------------------
 * Las páginas van con `ms-nb--white` (menú blanco sobre el hero, que ahora
 * es oscuro en los dos modos: correcto ahí). Pero pasado el hero, el fondo
 * sólido del header sigue al modo — y en CLARO el blanco no contrasta.
 *
 * El tema YA trae la regla para oscurecerlo en ese estado
 * (`.ms-nb--white .main-header__inner.move … { color: var(--color-contrast-higher) }`),
 * pero su propia regla del blanco lleva el ID `#primary-menu-default` y le
 * gana SIEMPRE por especificidad: nunca aplica. Aquí se re-emite con el
 * mismo ID + la clase del estado sólido (que pone `cnaay-fixes.js` al pasar
 * el hero, no al primer pixel de scroll): especificidad mayor, y el var del
 * tema resuelve por modo — tinta en claro, blanco en oscuro. El subrayado
 * de hover (::after) va igual.
 * ========================================================================= */
.main-header.cnaay-header-solido .main-header__layout .main-header__default > #primary-menu-default > .menu-item > a {
    color: var(--color-contrast-higher);
}
/*
 * ⚠️ CORREGIDO (2026-08-25, reporte del cliente): aquí decía
 * `background-color` suponiendo que el ::after era un subrayado — pero en
 * este tema es la COPIA del texto para el GIRO del hover, y el fondo lo
 * convertía en una caja sólida encima del enlace. La regla del tema colorea
 * `a` y `a::after` juntos con `color`; se replica eso.
 */
.main-header.cnaay-header-solido .main-header__layout .main-header__default > #primary-menu-default > .menu-item > a::after {
    color: var(--color-contrast-higher);
    background-color: transparent;
}

/*
 * ⚠️⚠️ LA PIEZA QUE FALTABA (2026-08-25, 3.ª pasada): congelar VARIABLES no
 * basta para el texto sin regla propia. Esos párrafos HEREDAN del <body> el
 * color YA RESUELTO (la herencia copia el valor calculado, no la variable),
 * así que redefinir --cnaay-text en el subárbol no los toca. Medido: con las
 * variables congeladas en el widget, el <p> seguía pintando el #14101A que
 * Kirki resuelve en el body para modo claro.
 *
 * La salida es darles una REGLA dentro del hero: cualquier regla le gana a
 * la herencia, y como var() aquí se re-resuelve EN el subárbol, toma los
 * valores congelados de arriba. La especificidad está elegida a propósito:
 * (0,1,1)/(0,2,1) — le gana a la herencia (siempre) y PIERDE contra los
 * colores explícitos de los widgets de Elementor (0,3,0+): el oro de los
 * títulos y los tonos suaves configurados no se tocan.
 */
[id="cnaay-hero"] :is(h1, h2, h3, h4, h5, h6, p, li),
.elementor-widget-ms-hero .ms-hc :is(h1, h2, h3, h4, h5, h6, p, li) {
    color: var(--cnaay-text);
}

/*
 * El botón «Inscríbete» del hero, congelado en su par OSCURO (oro brillante
 * + tinta). Su fondo ya queda por --color-primary congelada arriba; el color
 * del texto llega por otra ruta de Kirki, así que va DIRECTO. Sobre la foto
 * oscura, el par claro (oro profundo + blanco) era el que se veía mal.
 */
[id="cnaay-hero"] .btn.btn--primary,
.elementor-widget-ms-hero .btn.btn--primary {
    background-color: #E8B84B;
    color: #303030;
}

/* =========================================================================
 * Marquesina del PIE: siempre en claro (cliente, 2026-08-25)
 * -------------------------------------------------------------------------
 * El pie va oscuro CONGELADO en los dos modos (sus `--cnaay-footer-*` se
 * declaran fuera de los bloques [data-theme]), pero el texto del ticker se
 * pintaba con la regla del tema `.ms-tt-wrap .ms-tt__text { color:
 * var(--color-contrast-higher) }`, que Kirki SÍ cambia por modo: en claro
 * se iba a #14101A y desaparecía sobre el fondo oscuro del pie.
 *
 * ℹ️ El `title_color` que pone el build en el widget no llega a este
 * elemento — por eso hace falta la regla. Especificidad (0,3,0) para ganarle
 * a la del tema (0,2,0) sin !important. El `-webkit-text-stroke-color` va
 * también: el tema lo declara aparte y con la misma variable.
 * ========================================================================= */
.ms-footer .ms-tt-wrap .ms-tt__text,
.ms-footer .ms-tt-wrap .ms-tt__text span {
    color: var(--cnaay-footer-text);
    -webkit-text-stroke-color: var(--cnaay-footer-text);
}
