/* =====================================================================
   Immigration Latam Group — "La Ruta" (v2)
   Tokens, base, componentes, layout, responsive, reduced-motion.
   ===================================================================== */

/* ---------- 0. Fuentes (autoalojadas, solo subset latin) --------------
   Public Sans — tipografía oficial del U.S. Web Design System (USWDS),
   usada acá por su asociación directa con procesos/documentos oficiales
   de EEUU, que encaja con "proceso legal verificable". Variable font,
   pesos 300-800 en un solo archivo (+ itálica aparte). Autoalojada por
   la misma razón que antes: dos orígenes externos menos en el camino
   crítico, sin el re-cálculo tardío de LCP que causa el swap vía CDN.
   Solo el subset "latin" (cubre español completo) — no se cargan
   cirílico, griego, vietnamita, etc. que Google sirve por separado. */
@font-face {
    font-family: 'Public Sans';
    font-style: normal;
    font-weight: 300 800;
    font-display: swap;
    src: url('../fonts/public-sans-variable-latin.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
    font-family: 'Public Sans';
    font-style: italic;
    font-weight: 300 800;
    font-display: swap;
    src: url('../fonts/public-sans-italic-variable-latin.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
    font-family: 'JetBrains Mono';
    font-style: normal;
    font-weight: 400 500;
    font-display: swap;
    src: url('../fonts/jetbrains-mono-latin.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ---------- 1. Tokens ------------------------------------------------ */
:root {
    --navy: #0B1830;
    --navy-deep: #060B14;
    --navy-soft: #14264A;
    --frost: #F3F4F1;
    --frost-hi: #FFFFFF;
    --bordeaux: #6E2A34;
    --red: #C23B32;
    --red-dim: #9E2F27;
    --mist: #586372;
    --mist-on-dark: #A2A7AD;
    --line: rgba(11, 24, 48, .12);
    --line-strong: rgba(11, 24, 48, .22);
    --line-on-dark: rgba(243, 244, 241, .16);
    /* Lavado translúcido de --navy, no --frost sólido — se nota como
       superficie apenas distinta del blanco en vez de leerse como una
       tarjeta gris plena (ver .faq-question, v23). Reusado en
       .card-area (v24) y .card--tint (v26) para que "el mismo color
       que el FAQ" sea siempre exactamente el mismo valor, no una
       aproximación repetida a mano en cada lugar. */
    --tint-navy: rgba(11, 24, 48, .035);

    --font-display: 'Public Sans', -apple-system, Segoe UI, sans-serif;
    --font-body: 'Public Sans', -apple-system, Segoe UI, sans-serif;
    --font-mono: 'JetBrains Mono', 'Courier New', monospace;

    --sp-1: 4px; --sp-2: 8px; --sp-3: 12px; --sp-4: 16px; --sp-5: 24px;
    --sp-6: 32px; --sp-7: 48px; --sp-8: 64px; --sp-9: 96px; --sp-10: 140px;

    --container-w: 1240px;
    --doc-column-w: 720px;
    /* 2px → 16px: "se siente muy cuadrada" — pedido explícito de
       redondear TODAS las tarjetas del sitio (.card, .card-area,
       .destino-pill, .form-card, filas de tabla-visa en móvil). Es un
       único token compartido a propósito: badges/inputs que también lo
       usan quedan visualmente consistentes con las cards en vez de
       desentonar con esquinas angulares sueltas.  Los botones (.btn)
       tienen su propio radio pill (999px, ver sección 6) — no viven de
       este token porque el pedido de "más circulares" para botones fue
       más extremo que para el resto de las cajas del sitio. */
    --radius: 16px;
    --shadow-rest: 0 1px 2px rgba(6, 11, 20, .06);
    --shadow-lift: 0 20px 44px rgba(6, 11, 20, .16);
    --ease: cubic-bezier(.22, .8, .32, 1);
    --dur-fast: 220ms;
    --dur-med: 480ms;
}

/* ---------- 2. Reset --------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
html.reduced-motion, html.reduced-motion * { scroll-behavior: auto !important; }
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.001ms !important;
    }
}
body {
    margin: 0;
    background: var(--frost-hi);
    color: var(--navy);
    font-family: var(--font-body);
    font-size: 16px;
    line-height: 1.6;
    -webkit-font-smoothing: antialiased;
}
img, svg { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
ul, ol { margin: 0; padding: 0; list-style: none; }
button { font: inherit; cursor: pointer; background: none; border: none; }
input, textarea, select { font: inherit; color: inherit; }
h1, h2, h3, h4, p, figure { margin: 0; }
table { border-collapse: collapse; width: 100%; }
:focus-visible { outline: 2px solid var(--red); outline-offset: 3px; }

/* ---------- 3. Tipografía ----------------------------------------------- */
h1, h2, h3, h4 {
    font-family: var(--font-display);
    font-weight: 800;
    line-height: 1.06;
    color: var(--navy);
    letter-spacing: -.02em;
}
h1 { font-size: clamp(2.4rem, 5vw, 4.4rem); }
h2 { font-size: clamp(1.8rem, 3.2vw, 2.75rem); }
h3 { font-size: clamp(1.3rem, 2vw, 1.75rem); }
h4 { font-size: 1.15rem; }
em, i.accent { font-style: italic; font-weight: 400; color: var(--bordeaux); }

.lead { font-size: 1.125rem; color: var(--mist); line-height: 1.65; }
.mono { font-family: var(--font-mono); }
.eyebrow {
    font-family: var(--font-mono);
    font-size: .75rem;
    font-weight: 500;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--mist);
    display: inline-flex;
    align-items: center;
    gap: var(--sp-3);
}
.eyebrow::before { content: ""; width: 26px; height: 1px; background: var(--red); flex-shrink: 0; }
.eyebrow--on-dark { color: rgba(243, 244, 241, .6); }
.eyebrow--on-dark::before { background: var(--red); }

.cifra { background: var(--navy); text-align: center; }
/* Numeral grande en Public Sans 800 (la misma display font del sitio) —
   no un tercer font-face nuevo, que hubiera ido contra la curaduría
   deliberada de fuentes autoalojadas del proyecto (ver CLAUDE.md).
   Sólido, sin contorno hueco: acá el número es un dato real (4590), tiene
   que leerse a simple vista. */
.cifra__valor {
    font-family: var(--font-display); font-weight: 800;
    font-size: clamp(3rem, 6vw, 4.5rem); line-height: 1;
    letter-spacing: -.02em;
    color: var(--frost);
}
.cifra__label {
    background: var(--navy);
    color: #969CA4;
    font-family: var(--font-mono);
    font-size: .75rem;
    font-weight: 500;
    letter-spacing: .12em;
    text-transform: uppercase;
    margin-top: var(--sp-3);
}

.section-head { display: flex; flex-direction: column; gap: var(--sp-3); margin-bottom: var(--sp-7); }
.section-head h2 { margin-top: var(--sp-2); }
.section-head .lead { max-width: 58ch; }

/* Link "Volver" de una página "despegada" del flujo normal de
   navegación (ver header.php $minimalChrome y validar-perfil.php) — el
   wizard es la conversión principal del sitio, así que su header
   reemplaza la nav completa por wordmark + este link, sin invitar a
   irse a navegar a mitad del formulario. */
.back-link {
    display: inline-flex; align-items: center; gap: var(--sp-2);
    font-family: var(--font-mono); font-size: .8125rem; letter-spacing: .04em;
    color: var(--mist);
    transition: color var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
}
.back-link:hover { color: var(--red); transform: translateX(-3px); }

/* ---------- 4. Layout --------------------------------------------------- */
.container { max-width: var(--container-w); margin-inline: auto; padding-inline: var(--sp-5); }
.doc-column { max-width: var(--doc-column-w); margin-inline: auto; }
/* Contenido HTML crudo desde la BD (articulos.contenido / paginas_legales.contenido,
   ver tr(), impreso sin escapar en views/articulo.php y views/legal.php)
   — el reset global deja h1-h4/p en margin:0 y ul/ol sin viñeta (line
   157) para no arrastrar esos huecos al resto del sitio, así que acá se
   restauran solo dentro de .prose, la única zona que renderiza prosa
   larga con subtítulos/listas de verdad. */
.prose h2 { font-size: clamp(1.35rem, 2.2vw, 1.75rem); margin-top: var(--sp-8); }
.prose h2:first-child { margin-top: 0; }
.prose p { margin-top: var(--sp-4); }
.prose ul, .prose ol { margin-top: var(--sp-4); padding-left: 1.25em; }
.prose ul { list-style: disc; }
.prose ol { list-style: decimal; }
.prose li + li { margin-top: var(--sp-2); }
.prose li::marker { color: var(--red); }
.section { padding-block: var(--sp-10); }
.section--tight { padding-block: var(--sp-8); }
.section--dark { background: var(--navy); color: var(--frost); }
.section--dark h1, .section--dark h2, .section--dark h3 { color: var(--frost); }
/* Header de programa (v19, ajustado en v20) con la foto del destino de
   fondo — clase propia en vez de meterlo en .section--dark: esa clase
   también la usa la sección de "Cifras" del home, que no tiene ni
   necesita imagen. El degradé usa --navy (no un negro genérico) para
   que el velo se sienta "del sitio" en vez de una superposición
   cualquiera, y va más oscuro donde cae el texto (izquierda, todo el
   contenido de este hero está alineado ahí) — se aclara hacia la
   derecha para que la foto respire, en vez de un velo parejo sobre toda
   la sección. Sin imagen cargada para el destino, la sección se ve
   exactamente como antes (fondo --navy sólido).
   .programa-hero__bg img vive sobredimensionada (height:130%, corrida
   -15% arriba) para que assets/js/motion.js pueda trasladarla con el
   scroll (paralaje) sin que se vea nunca un borde vacío — overflow:hidden
   acá (y en .programa-hero) recorta ese excedente. */
.programa-hero { position: relative; overflow: hidden; }
.programa-hero__bg { position: absolute; inset: 0; z-index: 0; overflow: hidden; }
.programa-hero__bg img {
    position: absolute; top: -15%; left: 0;
    width: 100%; height: 130%; object-fit: cover; display: block;
    will-change: transform;
}
.programa-hero__bg::after {
    content: ""; position: absolute; inset: 0;
    background: linear-gradient(100deg, rgba(11, 24, 48, .96) 0%, rgba(11, 24, 48, .9) 45%, rgba(11, 24, 48, .72) 100%);
}
.programa-hero .container { position: relative; z-index: 1; }
@media (max-width: 768px) {
    /* En mobile el texto suele ocupar todo el ancho, no solo la mitad
       izquierda — un degradé angosto dejaría letras sobre foto clara. */
    .programa-hero__bg::after { background: rgba(11, 24, 48, .92); }
}
.section--divider { border-top: 1px solid var(--line); }
.section--tint { background: var(--frost); }
@media (max-width: 720px) {
    .section { padding-block: var(--sp-8); }
    .container { padding-inline: var(--sp-4); }
}
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-7); }
.grid-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(270px, 1fr)); gap: var(--sp-5); }
@media (max-width: 720px) { .grid-2 { grid-template-columns: 1fr; } }
/* Cifras del proceso (home): tenía grid-template-columns:repeat(3,1fr)
   inline en el HTML, que le ganaba al auto-fit responsivo de
   .grid-cards sin importar el ancho — 3 columnas fijas desbordaban en
   móvil ("Pendiente de definir" x3 no entra en ~360px). Clase propia
   con su propio breakpoint en vez de inline. */
.cifras-grid { grid-template-columns: repeat(3, 1fr); }
@media (max-width: 640px) { .cifras-grid { grid-template-columns: 1fr; } }
/* Fundador (home, id="fundador") — reemplaza la sección de "equipo"
   (grilla de N personas, ver historial en CLAUDE.md v14): ahora es una
   sola foto + presentación de Gustavo Soto, dos columnas en desktop/
   tablet, apiladas en móvil. */
.fundador__grid {
    display: grid; grid-template-columns: 1fr 1fr;
    gap: var(--sp-8); align-items: center;
}
.fundador__photo img {
    width: 100%; aspect-ratio: 1 / 1; object-fit: cover;
    border-radius: var(--radius); box-shadow: var(--shadow-rest);
}
.fundador__cargo { color: var(--red-dim); font-size: .8125rem; letter-spacing: .04em; text-transform: uppercase; margin-top: var(--sp-2); }
.fundador__bio { color: var(--mist); line-height: 1.7; margin-top: var(--sp-4); max-width: 56ch; }
.fundador__content .btn { margin-top: var(--sp-6); }
@media (max-width: 720px) {
    .fundador__grid { grid-template-columns: 1fr; gap: var(--sp-6); }
    .fundador__photo img { max-width: 240px; margin-inline: auto; }
}

/* ---------- 5. Header / nav ---------------------------------------------- */
.site-header {
    position: sticky; top: 0; z-index: 40;
    background: rgba(243, 244, 241, .92);
    backdrop-filter: blur(10px);
    border-bottom: 1px solid var(--line);
    transition: transform var(--dur-med) var(--ease), background var(--dur-med) var(--ease), border-color var(--dur-med) var(--ease);
}
/* Ocultar al bajar / mostrar al subir (main.js) — en todas las páginas. */
.site-header.is-hidden { transform: translateY(-100%); }
/* Mientras el hero está en pantalla, el header adopta su mismo tono
   oscuro (en vez de la barra clara con blur) — mismo color de familia,
   pero como bloque propio separado del hero por .hero-divider (ver más
   abajo), no fundido/superpuesto con él como en un intento anterior.
   Server-rendered de entrada (header.php, $activeNav==='home') para que
   no haya parpadeo de barra clara antes de que corra el JS; main.js la
   apaga con un IntersectionObserver sobre [data-hero] apenas el hero
   deja de estar en pantalla, así nunca queda una franja oscura flotando
   sobre las secciones claras de más abajo. */
.site-header.is-on-hero {
    /* Transparente (antes var(--navy) sólido) para que .hero-atmos —
       el fondo+glow que sigue el cursor, ver sección 7 — se vea A
       TRAVÉS del header en vez de quedar tapado por una barra plana.
       Es justo lo que hacía que el efecto se sintiera "cortado" al
       mover el mouse hacia la nav. */
    background: transparent;
    backdrop-filter: none;
    border-bottom-color: transparent;
}
.site-header.is-on-hero .wordmark span,
.site-header.is-on-hero .site-nav__links a { color: var(--frost); }
.site-header.is-on-hero .wordmark small { color: var(--mist-on-dark); }
.site-header.is-on-hero .lang-switch { background: rgba(243, 244, 241, .08); border-color: var(--line-on-dark); }
.site-header.is-on-hero .lang-switch__opt:not(.is-active) { color: rgba(243, 244, 241, .6); }
/* .nav-toggle no necesita override acá: es un círculo rojo sólido con
   barras blancas siempre (ver sección de toggle más abajo), se lee
   igual de bien sobre header transparente o claro. */
html.reduced-motion .site-header { transition: none; }
.site-header__row {
    max-width: var(--container-w); margin-inline: auto;
    padding: var(--sp-4) var(--sp-5);
    display: flex; align-items: center; justify-content: space-between; gap: var(--sp-5);
    min-height: 76px;
}
.wordmark { display: flex; flex-direction: column; line-height: 1.15; }
.wordmark span { font-family: var(--font-display); font-weight: 800; font-size: 1.15rem; letter-spacing: -.02em; }
.wordmark small { font-family: var(--font-mono); font-size: .625rem; letter-spacing: .1em; text-transform: uppercase; color: var(--mist); }

.site-nav { display: flex; align-items: center; gap: var(--sp-7); }
.site-nav__links { display: flex; align-items: center; gap: var(--sp-6); }
.site-nav__links a { font-size: .9375rem; position: relative; padding-block: var(--sp-1); }
.site-nav__links a::after {
    content: ""; position: absolute; left: 0; right: 100%; bottom: -3px; height: 1px;
    background: var(--red); transition: right var(--dur-fast) var(--ease);
}
.site-nav__links a:hover::after, .site-nav__links a[aria-current="page"]::after { right: 0; }
/* Etiqueta "New" junto a un ítem del nav (hoy: Ofertas) — mismo
   lenguaje visual que .badge-activa (píldora roja, mono, uppercase)
   pero compacta para caber en línea junto al texto del link, en vez de
   flotar absoluta como esa. Reutilizada tal cual en el menú móvil.
   Pulso de escala + anillo de sombra para que se note sin abrir el
   menú primero — un lenguaje de "llamado de atención" propio, distinto
   del anillo concéntrico de .whatsapp-float__ring/.tiktok-card__play
   (esos son círculos grandes; acá es una píldora chica, un doble anillo
   se vería apretado). */
.nav-badge {
    display: inline-flex; align-items: center;
    background: var(--red); color: #fff;
    font-family: var(--font-mono); font-size: .5625rem; font-weight: 700;
    letter-spacing: .04em; text-transform: uppercase;
    padding: 2px 6px; border-radius: 999px;
    vertical-align: 2px;
    animation: nav-badge-pulse 1.8s ease-in-out infinite;
}
.mobile-menu__links .nav-badge { font-size: .625rem; padding: 2px 7px; }
@keyframes nav-badge-pulse {
    0%, 100% { transform: scale(1); box-shadow: 0 0 0 0 rgba(194, 59, 50, .55); }
    50% { transform: scale(1.12); box-shadow: 0 0 0 5px rgba(194, 59, 50, 0); }
}
html.reduced-motion .nav-badge { animation: none; }

.lang-switch {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    background: var(--frost);
    border: 1px solid var(--line-strong);
    border-radius: 999px;
    padding: 3px;
}
.lang-switch__opt {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-family: var(--font-mono);
    font-size: .6875rem;
    font-weight: 600;
    letter-spacing: .03em;
    line-height: 1;
    color: var(--mist);
    /* Solo bandera (sin texto visible, ver .sr-only en el <span>): más
       padding que antes para no perder área táctil ahora que el
       contenido visible es apenas la banderita. */
    padding: 9px;
    border-radius: 999px;
    transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.lang-switch__opt .flag-icon { width: 20px; vertical-align: 0; }
.lang-switch__opt.is-active .flag-icon { box-shadow: 0 0 0 1px rgba(255, 255, 255, .5); }
.site-nav__links .lang-switch .lang-switch__opt::after { content: none; }
.lang-switch__opt:hover:not(.is-active) { color: var(--red); }
.lang-switch__opt.is-active { background: var(--red); color: #fff; }
.lang-switch--lg { background: rgba(243, 244, 241, .08); border-color: var(--line-on-dark); padding: 4px; }
.lang-switch--lg .lang-switch__opt { color: rgba(243, 244, 241, .6); font-size: .8125rem; padding: 11px; }
.lang-switch--lg .lang-switch__opt .flag-icon { width: 24px; }
.lang-switch--lg .lang-switch__opt:hover:not(.is-active) { color: var(--red); }

/* ---- Toggle (hamburger → X, ligado a aria-expanded, sin JS de estilos) ----
   Antes eran 3 líneas sueltas sin fondo, casi invisibles en el header —
   pedido explícito de un botón "más llamativo y referencial": círculo
   sólido en rojo de marca, barras blancas más gruesas, con el mismo
   hover/lift que ya usan los botones del sitio, para que se lea de
   entrada como un control, no como un detalle decorativo. */
.nav-toggle {
    display: none;
    width: 48px; height: 48px;
    align-items: center; justify-content: center;
    border-radius: 999px;
    background: var(--red);
    flex-shrink: 0;
    transition: background var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease);
}
@media (hover: hover) {
    .nav-toggle:hover { transform: translateY(-2px); box-shadow: 0 8px 20px rgba(194, 59, 50, .4); }
}
/* 4 barras escalonadas (ancho variable, ancladas a la derecha) en vez
   de 3 líneas iguales — ícono pedido puntualmente por referencia. En
   reposo se leen como un patrón asimétrico más "de producto"; en hover
   las dos barras cortas crecen hasta el ancho completo (siguen anclada
   a la derecha, así que crecer = extenderse hacia la IZQUIERDA, el
   "desplazable hacia la izquierda" pedido), con un pequeño delay
   escalonado entre ellas para que se sienta como una ola, no un salto
   — el detalle "futurista". Expandido (X) usa las barras 2 y 3
   centradas y rotadas ±45°, las 1 y 4 se desvanecen. */
.nav-toggle__bars { position: relative; width: 20px; height: 20px; }
.nav-toggle__bars i {
    content: ""; display: block; position: absolute; right: 0;
    height: 2.5px; background: #fff; border-radius: 2px;
    transition: width .45s var(--ease), transform var(--dur-fast) var(--ease), opacity var(--dur-fast) var(--ease), top var(--dur-fast) var(--ease);
}
.nav-toggle__bars i:nth-child(1) { top: 0; width: 100%; }
.nav-toggle__bars i:nth-child(2) { top: 6px; width: 60%; }
.nav-toggle__bars i:nth-child(3) { top: 12px; width: 78%; }
.nav-toggle__bars i:nth-child(4) { top: 18px; width: 100%; }
@media (hover: hover) {
    .nav-toggle:hover .nav-toggle__bars i:nth-child(2) { width: 100%; transition-delay: .04s; }
    .nav-toggle:hover .nav-toggle__bars i:nth-child(3) { width: 100%; transition-delay: .09s; }
}
.nav-toggle[aria-expanded="true"] .nav-toggle__bars i:nth-child(1),
.nav-toggle[aria-expanded="true"] .nav-toggle__bars i:nth-child(4) { opacity: 0; width: 40%; }
.nav-toggle[aria-expanded="true"] .nav-toggle__bars i:nth-child(2) { top: 9px; width: 100%; transform: rotate(45deg); }
.nav-toggle[aria-expanded="true"] .nav-toggle__bars i:nth-child(3) { top: 9px; width: 100%; transform: rotate(-45deg); }

/* ---- Menú de pantalla completa (móvil + tablet) --------------------------- */
.mobile-menu {
    position: fixed; inset: 0; z-index: 100;
    /* height explícito (no solo inset:0): en navegadores móviles con
       barra de herramientas dinámica, un position:fixed dimensionado
       solo por inset puede terminar más alto que el viewport realmente
       visible — el contenido de más abajo (footer/CTA) queda oculto
       detrás de la barra del navegador y "no se puede scrollear" hasta
       ahí porque, dentro de su propia caja, no hay nada más que mostrar.
       100dvh (dynamic viewport height) sí usa el viewport visible real. */
    height: 100vh; height: 100dvh;
    visibility: hidden;
    display: none;
}
.mobile-menu.is-open { visibility: visible; }
.mobile-menu__panel {
    position: absolute; inset: 0;
    background: var(--navy);
    display: flex; flex-direction: column;
    padding: var(--sp-4) var(--sp-5);
    transform: translateX(100%);
    transition: transform .45s var(--ease);
    overflow-y: auto;
    overflow-x: hidden;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
}
.mobile-menu.is-open .mobile-menu__panel { transform: translateX(0); }
.mobile-menu__top { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4); min-height: 44px; min-width: 0; }
.mobile-menu__top .wordmark { min-width: 0; }
.mobile-menu__top .wordmark span, .mobile-menu__top .wordmark small { display: block; overflow-wrap: break-word; }
.mobile-menu__close { flex-shrink: 0; }
.mobile-menu__top .wordmark span { color: var(--frost); }
.mobile-menu__top .wordmark small { color: var(--mist-on-dark); }
.mobile-menu__close {
    width: 44px; height: 44px; display: flex; align-items: center; justify-content: center;
    color: var(--frost); border-radius: var(--radius);
}
.mobile-menu__close .icon { width: 22px; height: 22px; }
/* Antes: links a la izquierda arriba del todo y el footer (idioma + CTA)
   empujado al fondo con margin-top:auto — en pantallas altas (tablet)
   quedaba un hueco enorme sin nada en el medio. Ahora .mobile-menu__body
   envuelve links+separador+footer y se centra como un solo bloque en el
   espacio que sobra debajo de .mobile-menu__top, con .mobile-menu__top
   fijo arriba — diseño más armado, no "arriba y abajo con aire muerto
   en el medio". */
.mobile-menu__body {
    flex: 1; min-height: 0;
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    width: 100%;
}
.mobile-menu__links {
    display: flex; flex-direction: column; align-items: center; gap: var(--sp-2);
    width: 100%; max-width: 340px;
}
.mobile-menu__links li {
    width: 100%;
    opacity: 0; transform: translateY(10px);
}
.mobile-menu.is-open .mobile-menu__links li {
    animation: menu-item-in .5s var(--ease) both;
    animation-delay: calc(.05s + var(--i, 0) * .05s);
}
@keyframes menu-item-in { to { opacity: 1; transform: translateY(0); } }
/* Links como botones (texto) — pill, fondo propio y estado activo
   resuelto, no una lista con líneas divisorias entre ítems. */
.mobile-menu__links a {
    display: block; text-align: center;
    padding: var(--sp-3) var(--sp-5);
    border-radius: 999px;
    font-family: var(--font-display); font-weight: 700; font-size: 1.125rem;
    color: var(--frost);
    background: rgba(243, 244, 241, .05);
    transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
@media (hover: hover) {
    .mobile-menu__links a:hover { background: rgba(194, 59, 50, .18); }
}
.mobile-menu__links a[aria-current="page"] { color: #fff; background: var(--red); }
/* Redes sociales debajo de los links de texto — reutiliza .social-row/
   .social-badge del footer tal cual (ya están pensados para fondo
   oscuro, con su propio hover, ver sección 16), acá solo se centran
   para calzar con el resto del menú. */
.mobile-menu__social { justify-content: center; margin-top: var(--sp-5); }
/* Separador entre los links y el pie (idioma + CTA) — 20px de aire
   arriba y abajo, pedido explícito, en vez del hueco sin forma de antes. */
.mobile-menu__divider {
    width: 100%; max-width: 340px; height: 1px;
    background: var(--line-on-dark);
    margin: 20px 0;
}
.mobile-menu__footer {
    width: 100%; max-width: 340px;
    display: flex; flex-direction: column; align-items: center; gap: var(--sp-3);
}
.mobile-menu__footer .lang-switch { align-self: center; }
html.reduced-motion .mobile-menu__panel { transition: none; }
html.reduced-motion .mobile-menu__links li { animation: none !important; opacity: 1; transform: none; }

@media (max-width: 1024px) {
    .site-nav { display: none; }
    .nav-toggle { display: flex; }
    /* .btn.btn-nav-cta (2 clases): .btn se define más abajo en el archivo
       con la misma especificidad que un ".btn-nav-cta" solo tendría, y al
       venir después en la cascada le ganaría a este "display:none" pese
       al media query — ya pasó una vez, por eso la nota. */
    .btn.btn-nav-cta { display: none; }
    .mobile-menu { display: block; }
}

/* ---------- 6. Botones (con micro-interacción magnética) -----------------
   Radio "pill" (999px) — deliberadamente distinto del --radius: 2px del
   resto del sitio (cards, badges, inputs siguen angulares, look
   editorial). El pedido fue específico a botones: "más circulares", no
   "todo el sitio más redondeado" — así que el radio vive acá, no en el
   token global. */
.btn {
    display: inline-flex; align-items: center; gap: var(--sp-2);
    font-family: var(--font-body); font-weight: 600; font-size: .9375rem;
    padding: var(--sp-4) var(--sp-6);
    border-radius: 999px;
    border: 1px solid transparent;
    transition: transform var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease), background-position var(--dur-med) var(--ease), color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
    white-space: nowrap;
    will-change: transform;
}
.btn-primary {
    background: linear-gradient(135deg, var(--red) 0%, var(--red-dim) 100%);
    background-size: 180% 180%; background-position: 0% 50%;
    color: #fff;
}
@media (hover: hover) {
    .btn-primary:hover { background-position: 100% 50%; box-shadow: 0 10px 28px rgba(194, 59, 50, .38); transform: translateY(-2px); }
}
/* .btn-on-dark.btn-primary ya no tiene override propio — pedido
   explícito de que el CTA primario sea rojo también sobre fondo oscuro
   (antes salía blanco/frost acá para "resaltar" sobre el navy). Cae al
   degradado rojo normal de .btn-primary sin necesidad de duplicarlo. */
.btn-secondary { background: transparent; border-color: var(--line-strong); color: var(--navy); }
@media (hover: hover) {
    .btn-secondary:hover { background: rgba(194, 59, 50, .08); border-color: var(--red); color: var(--red); box-shadow: 0 0 0 4px rgba(194, 59, 50, .12); transform: translateY(-2px); }
}
.btn-on-dark.btn-secondary { border-color: var(--line-on-dark); color: var(--frost); }
@media (hover: hover) {
    .btn-on-dark.btn-secondary:hover { background: rgba(194, 59, 50, .18); border-color: var(--red); color: var(--red); box-shadow: 0 0 0 4px rgba(194, 59, 50, .18); transform: translateY(-2px); }
}
.btn:active { transform: translateY(0) scale(.97); }
.btn:focus-visible { outline: none; box-shadow: 0 0 0 4px rgba(194, 59, 50, .3); }
.btn-link { padding: 0; border-bottom: 1px solid var(--red); border-radius: 0; font-family: var(--font-mono); font-size: .8125rem; letter-spacing: .04em; }
.btn-block { width: 100%; justify-content: center; }
.btn[disabled] { opacity: .5; cursor: not-allowed; }

/* ---------- 7. Hero atmosférico -------------------------------------------- */
/* Separador entre el header y el hero (solo home, ver header.php) — 20px
   de aire arriba y abajo de una línea fina, mismo criterio que el
   separador del menú móvil. Fondo navy sólido (no transparente): vive
   en flujo normal entre el header sticky y el hero, así que necesita su
   propio color de fondo para no dejar ver el blanco de <body> — el
   mismo navy del hero, para que header + separador + hero se sigan
   leyendo como una sola familia de color aunque ya no se superpongan.
   El degradado sutil en la línea (transparente → rojo → transparente)
   es el único toque de color, en vez de una línea gris plana. */
/* position:relative (sin mover nada, solo para participar del stacking
   por z-index:auto) — necesario para que este bloque pinte POR ENCIMA
   de .hero-atmos (ver sección 7), que es position:absolute y si no
   tapa el fondo transparente de acá con el suyo (Apéndice E de CSS2.1:
   un descendiente posicionado con z-index:auto siempre pinta por
   delante de hermanos no posicionados, sin importar el orden en el
   documento). */
.hero-divider { position: relative; background: transparent; padding: 20px 0; }
.hero-divider span {
    display: block; height: 2px;
    margin-inline: clamp(var(--sp-5), 6vw, var(--sp-10));
    background: linear-gradient(90deg, transparent, var(--line-on-dark) 15%, var(--red) 50%, var(--line-on-dark) 85%, transparent);
}
.hero {
    position: relative;
    /* Header y hero son secuenciales en el LAYOUT, sin superponerse (se
       probó fundidos/solapados y no convenció) — separados por
       .hero-divider. El fondo visual sí los une (ver .hero-atmos más
       abajo, agregado para que el glow del cursor no se corte en esa
       costura), pero eso es una capa aparte por detrás, no un cambio de
       posicionamiento de estos tres bloques. --header-h sigue
       midiéndose por JS (main.js) en vez de asumir un número fijo — acá
       solo se resta del 100vh, ya no hace falta compensar ningún margen
       negativo. */
    min-height: calc(100vh - var(--header-h, 76px));
    display: flex; flex-direction: column; justify-content: center;
    overflow: hidden;
    /* Sin fondo propio: lo pinta .hero-atmos por detrás (ver más abajo),
       para que el degradado sea uno solo y continuo desde arriba del
       header hasta el final del hero, sin una costura de color donde
       antes empezaba la caja de .hero. */
    background: transparent;
    /* Horizontal en clamp (no --sp-5 fijo): con --sp-5 (24px) el texto
       quedaba pegado al borde en monitores anchos, "estirado" de punta a
       punta — acá crece con el viewport hasta --sp-10 (140px) en vez de
       quedarse en el piso de 24px para siempre. El fondo (mapa) no se ve
       afectado: .hero__bg usa inset:0 propio, ignora el padding del hero. */
    padding: var(--sp-8) clamp(var(--sp-5), 6vw, var(--sp-10)) var(--sp-9);
    color: var(--frost);
}
/* Fondo "Mapa": la ruta Bogotá → Polonia/Croacia/Montenegro sobre un
   mapa mundi de puntos — tercera dirección de este fondo, después de
   "Corriente" (aurora+blobs) y "Red" (nodos genéricos); ver historial de
   diseño. Continentes como polígonos lat/long simplificados rellenos de
   puntos (estilización deliberada, no un mapa político preciso);
   Colombia y los 3 destinos resaltados en rojo dentro de su continente.
   Todo generado en runtime por JS (assets/js/motion.js) sobre el
   <svg data-hero-map>; acá solo va el contenedor. Antes tenía un wash
   bordeaux propio (radial-gradient fijo) detrás del mapa — se quitó
   (pedido explícito) porque, al vivir dentro de .hero y no de
   .hero-atmos (ver sección "Fondo compartido header+separador+hero"
   más abajo), tenía un borde recto justo donde .hero empieza, debajo
   del header — se notaba como un corte, distinto al spotlight que sí
   cubre esa franja sin costuras. Las animaciones (pulso de nodos, trazo
   de ruta) son WAAPI sobre opacity/transform/stroke, no CSS. */
.hero__bg { position: absolute; inset: 0; pointer-events: none; }
.hero__map { position: absolute; inset: 0; width: 100%; height: 100%; }
.hero__map .map-dot { fill: rgba(162, 167, 173, .45); }
.hero__map .map-dot.is-context { fill: rgba(162, 167, 173, .16); }
.hero__map .map-dot.is-marked { fill: var(--red); }
.hero__map .map-arc { fill: none; stroke: rgba(194, 59, 50, .22); stroke-width: 1; stroke-dasharray: 1 5; }
.hero__map .map-glow { fill: none; stroke: var(--red); stroke-linecap: round; filter: drop-shadow(0 0 5px rgba(194, 59, 50, .9)) drop-shadow(0 0 14px rgba(194, 59, 50, .45)); }
.hero__map .map-node { fill: var(--navy-deep); stroke: var(--red); stroke-width: 1.5; transform-box: fill-box; transform-origin: center; }
.hero__map .map-label { font-family: var(--font-mono); font-size: 10px; letter-spacing: .04em; fill: rgba(243, 244, 241, .68); }
/* Tablet/móvil: el mapa vive detrás de TODO el hero (como en desktop) en
   vez de un bloque propio abajo del texto — eso se probó y quedaba mal,
   como dos bloques pegados. La legibilidad del texto encima la da la
   opacidad, no el espacio propio. */
@media (max-width: 1024px) {
    .hero__bg { opacity: .38; }
}
/* Fondo compartido header+separador+hero (pedido explícito: el glow que
   sigue el cursor se sentía "cortado" al pasar del hero al header). NO
   envuelve al header en el DOM — .site-header necesita seguir siendo
   position:sticky para TODA la página, y si este bloque lo contuviera,
   el sticky quedaría acotado a la altura de este bloque en vez de la
   página completa. En cambio es un hermano absoluto, primer hijo de
   <body> (ver header.php), sizeado a la altura real "top de la página →
   borde inferior de .hero" por JS (assets/js/motion.js, sizeAtmos()) —
   el calc() de acá es solo el piso antes de que ese JS corra (o si
   nunca corre). .hero-divider y .hero ya son position:relative, así que
   pintan por delante de este z-index:auto sin necesidad de tocar
   z-index a mano (ver comentario en .hero-divider).
   El spotlight vive ACÁ (no dentro de .hero) para poder cubrir también
   el header/separador; assets/js/motion.js escribe --mx/--my sobre este
   mismo elemento en mousemove. */
.hero-atmos {
    position: absolute; inset: 0 0 auto 0;
    height: calc(100vh + 42px); /* 42px = alto real de .hero-divider (20+20 padding + 2 línea) */
    background: linear-gradient(180deg, var(--navy) 0%, var(--navy-deep) 100%);
    pointer-events: none;
}
/* Spotlight que sigue el cursor (assets/js/motion.js escribe --mx/--my
   en mousemove sobre .hero-atmos) — el "efecto al pasar el mouse"
   pedido. Gateado a (hover:hover): en táctil no hay cursor que seguir,
   así que el fondo se queda con la deriva ambiental de arriba, que sí
   corre en cualquier dispositivo ("el dedo" también ve un fondo vivo,
   solo que no reactivo al toque puntual). */
.hero__spotlight {
    position: absolute; inset: 0;
    /* 280px (antes 480px) — el círculo grande se sentía "muy amplio" ya
       lleno de mapa/puntos, no leía como un foco puntual siguiendo el
       cursor. Con "transparent 60%" el borde también cae más cerca del
       centro, más definido. */
    background: radial-gradient(280px circle at var(--mx, 50%) var(--my, 35%), rgba(194, 59, 50, .3), transparent 60%);
    opacity: 0;
    transition: opacity .5s var(--ease);
    pointer-events: none;
}
/* .hero-atmos.is-active (no :hover — header/separador/hero ya no son un
   solo elemento hoverable, es JS el que decide si el cursor cae dentro
   del rango combinado, ver motion.js) */
@media (hover: hover) {
    .hero-atmos.is-active .hero__spotlight { opacity: 1; }
}
.hero__grain {
    position: absolute; inset: 0; opacity: .05; mix-blend-mode: overlay; pointer-events: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}
.hero__inner { position: relative; z-index: 2; max-width: 920px; }
.hero__inner h1 { color: var(--frost); margin-top: var(--sp-5); }
/* --bordeaux (el énfasis en <em> por defecto en todo el sitio) se pierde
   contra el fondo oscuro del hero — acá puntualmente pasa a --red, más
   vivo, sin tocar la regla global "em, i.accent" que usan otras
   secciones sobre fondo claro. */
.hero__inner h1 em { color: var(--red); }
.hero .lead { color: rgba(243, 244, 241, .72); max-width: 48ch; margin-top: var(--sp-5); }
.hero__actions { display: flex; gap: var(--sp-5); align-items: center; flex-wrap: wrap; margin-top: var(--sp-7); }
.hero__trust { margin-top: var(--sp-8); display: flex; align-items: center; gap: var(--sp-4); font-size: 1.125rem; }
.hero__trust span { font-family: var(--font-mono); font-size: .75rem; letter-spacing: .05em; color: var(--mist-on-dark); }
.scroll-cue {
    position: absolute; bottom: var(--sp-6); left: var(--sp-5);
    display: flex; align-items: center; gap: var(--sp-3);
    font-family: var(--font-mono); font-size: .7rem; letter-spacing: .1em; text-transform: uppercase; color: var(--mist-on-dark);
}
.scroll-cue__line { width: 1px; height: 34px; background: linear-gradient(var(--red), transparent); animation: pulse 2.2s ease-in-out infinite; }
@keyframes pulse { 0%, 100% { opacity: .3; } 50% { opacity: 1; } }
html.reduced-motion .scroll-cue__line { animation: none; opacity: .6; }
@media (max-width: 720px) { .scroll-cue { display: none; } }

/* Entrada del hero: CSS puro (no espera a que carguen GSAP/ScrollTrigger
   por red) para no penalizar el LCP del texto principal. Solo anima
   posición, nunca opacity — un crawler de accesibilidad que capture el
   DOM a mitad de animación no debe encontrar texto con contraste reducido
   (el texto está a opacidad 1 desde el primer frame). */
@keyframes reveal-in {
    from { transform: translateY(14px); }
    to { transform: translateY(0); }
}
[data-reveal] { animation: reveal-in .9s var(--ease) both; }
html.reduced-motion [data-reveal] { animation: none; }

/* ---------- 8. Ruta del proceso (riel horizontal, pin nativo) -------------- */
/* v12 — reemplaza el pin de ScrollTrigger + giro 3D (una etapa a la vez):
   se sentía trabado y escondía el resto del recorrido. El pin ahora lo
   resuelve el navegador (position:sticky, sin ScrollTrigger ni Lenis — ver
   motion.js) y las 5 etapas se deslizan juntas en un riel horizontal, así
   que las etapas vecinas siguen siendo visibles/legibles mientras una está
   activa. */
.route { position: relative; background: var(--frost-hi); }
.route__head {
    display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap;
    gap: var(--sp-3);
    max-width: var(--container-w); margin-inline: auto;
    padding: var(--sp-8) var(--sp-5) var(--sp-6);
}
.route__tag { font-family: var(--font-mono); font-size: .75rem; letter-spacing: .05em; color: var(--mist); }
.route__tag b { color: var(--red); font-weight: 700; }

.route__pinspace { position: relative; height: 240vh; }
.route__sticky {
    position: sticky; top: var(--header-h, 76px); height: calc(100vh - var(--header-h, 76px));
    display: flex; flex-direction: column; justify-content: center;
    overflow: hidden;
}
.route__row { display: flex; align-items: center; gap: var(--sp-6); padding-inline: var(--sp-5); }
.route__end {
    flex-shrink: 0; writing-mode: vertical-rl;
    font-family: var(--font-mono); font-size: .75rem; letter-spacing: .1em; color: var(--mist);
}
.route__end--right { transform: rotate(180deg); }
.route__viewport { flex: 1 1 auto; min-width: 0; overflow: hidden; }
.route__track { position: relative; display: flex; width: max-content; gap: var(--sp-6); padding-block: var(--sp-2); will-change: transform; }
.route__track::before { content: ""; position: absolute; left: 0; right: 0; top: 44px; height: 1px; background: var(--line-strong); }
.route__card {
    width: clamp(240px, 20vw, 300px); flex: 0 0 auto; position: relative;
    padding: var(--sp-5); border: 1px solid var(--line); border-radius: var(--radius);
    background: var(--frost-hi);
    transition: border-color var(--dur-med) var(--ease), box-shadow var(--dur-med) var(--ease), transform var(--dur-med) var(--ease);
}
.route__card.is-active { border-color: var(--red); box-shadow: 0 20px 40px -28px rgba(194, 59, 50, .4); transform: translateY(-4px); }
.route__badge {
    width: 40px; height: 40px; margin-bottom: var(--sp-4); position: relative; z-index: 1;
    display: flex; align-items: center; justify-content: center; border-radius: 50%;
    background: var(--navy); color: var(--frost);
    font-family: var(--font-mono); font-weight: 700; font-size: .8125rem;
    transition: background var(--dur-med) var(--ease);
}
.route__card.is-active .route__badge { background: var(--red); }
.route__card h3 { margin-bottom: var(--sp-2); }
.route__card p { color: var(--mist); line-height: 1.6; font-size: .9375rem; }

.route__dots { display: flex; justify-content: center; gap: var(--sp-2); padding-top: var(--sp-5); }
.route__dot { width: 6px; height: 6px; border-radius: 50%; background: var(--line-strong); transition: background var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease); }
.route__dot.is-active { background: var(--red); transform: scale(1.7); }

html.reduced-motion .route__pinspace { height: auto; }
html.reduced-motion .route__sticky { position: static; height: auto; overflow: visible; }
html.reduced-motion .route__row { flex-direction: column; align-items: stretch; gap: 0; padding-inline: var(--sp-5); }
html.reduced-motion .route__end, html.reduced-motion .route__dots { display: none; }
html.reduced-motion .route__viewport { overflow: visible; }
html.reduced-motion .route__track { width: auto; flex-direction: column; gap: var(--sp-6); }
html.reduced-motion .route__track::before { display: none; }
html.reduced-motion .route__card { width: auto; opacity: 1; transform: none; transition: none; }

/* Tablet y móvil: el riel horizontal pinneado no tiene sentido con scroll
   táctil (el navegador no puede "hijackear" bien el scroll de un dedo, y
   en iOS/Android suele sentirse trabado). En vez de dejar la sección
   completamente estática, cada tarjeta se revela con un fade + slide
   simple vía IntersectionObserver (ver motion.js) a medida que entra en
   pantalla — animado, pero respetuoso del scroll nativo del dispositivo. */
@media (max-width: 1024px) {
    .route__pinspace { height: auto; }
    .route__sticky { position: static; height: auto; overflow: visible; }
    .route__row { flex-direction: column; align-items: stretch; gap: 0; padding: var(--sp-8) var(--sp-4) var(--sp-6); }
    .route__end, .route__dots { display: none; }
    .route__viewport { overflow: visible; }
    .route__track { width: auto; flex-direction: column; gap: var(--sp-6); }
    .route__track::before { display: none; }
    .route__card {
        width: auto; opacity: 0; transform: translateY(24px);
        transition: opacity .6s var(--ease), transform .6s var(--ease);
        /* Delay por índice (--i, inyectado inline por PHP): en viewports
           altos (tablet) varias tarjetas pueden cruzar el umbral del
           IntersectionObserver casi al mismo tiempo, y sin este delay
           todas aparecían juntas de golpe — se leía como "no hay
           animación" en vez de como una revelación en cascada. */
        transition-delay: calc(var(--i, 0) * .12s);
    }
    .route__card.is-visible { opacity: 1; transform: none; }
}
/* Tablet: 2 columnas en vez de 1 sola apilada — el ancho sobra para una
   grilla y así se ve más "estructurado" que una lista larga. Recién
   colapsa a 1 columna real bajo 640px (mismo umbral que el bento). */
@media (max-width: 1024px) and (min-width: 641px) {
    .route__track { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-7) var(--sp-6); }
}

/* ---------- 9. Selector de destinos (mapa) --------------------------------- */
.destinos-map { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-8); align-items: center; }
.destinos-map__svg svg { width: 100%; height: auto; }
.destinos-map__arc { fill: none; stroke: var(--line-strong); stroke-width: 1.5; stroke-dasharray: 3 6; }
.destinos-map__point { fill: var(--mist); transition: fill var(--dur-fast) var(--ease), r var(--dur-fast) var(--ease); }
.destinos-map__point.is-hover { fill: var(--red); }
.destinos-map__label { font-family: var(--font-mono); font-size: 11px; fill: var(--mist); letter-spacing: .05em; }
.destinos-list { display: flex; flex-direction: column; gap: var(--sp-4); }
.destino-pill {
    display: flex; flex-direction: column; gap: var(--sp-2);
    padding: var(--sp-5) var(--sp-6);
    border: 1px solid var(--line); border-radius: var(--radius);
    /* --frost (mismo tono que el header por defecto, ver .site-header),
       no --frost-hi (blanco puro, igual al fondo de <body>) — pedido
       explícito de que las tarjetas del sitio compartan el color de
       superficie del header en vez de mezclarse con el blanco de la
       página, distinguibles antes solo por el borde de 1px. */
    background: var(--frost);
    transition: border-color var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease);
}
@media (hover: hover) {
    .destino-pill:hover, .destino-pill.is-hover { border-color: var(--red); transform: translateX(4px); box-shadow: var(--shadow-rest); }
}
.destino-pill__top { display: flex; justify-content: space-between; align-items: baseline; }
.destino-pill h3 { font-size: 1.4rem; }
.destino-pill__meta { color: var(--mist); font-size: .875rem; }
@media (max-width: 768px) { .destinos-map { grid-template-columns: 1fr; } .destinos-map__svg { order: 2; } }

/* ---------- 10. Bento -------------------------------------------------------- */
.bento {
    display: grid; grid-template-columns: repeat(4, 1fr); grid-auto-rows: minmax(170px, auto);
    gap: 1px; background: var(--line); border: 1px solid var(--line);
    /* Redondeado "solo las esquinas": es una sola grilla con líneas
       divisorias internas (el gap de 1px pintado con --line), no
       tarjetas sueltas — así que el radio va en el CONTENEDOR, no en
       cada celda (si cada `.bento-card` tuviera su propio radio, las
       celdas del medio quedarían con esquinas redondeadas sueltas
       contra las líneas divisorias rectas, muy inconsistente).
       overflow:hidden recorta las celdas de las puntas para que sigan
       la curva del contenedor en vez de sobresalir cuadradas. */
    border-radius: var(--radius);
    overflow: hidden;
}
.bento-card {
    /* --frost, ver comentario en .destino-pill — el hover a --frost-hi
       (blanco puro) de abajo ahora sí se nota (antes ambos eran blanco,
       el "hover" de background no cambiaba nada realmente). */
    background: var(--frost); padding: var(--sp-6);
    display: flex; flex-direction: column; justify-content: space-between;
    transform-style: preserve-3d; will-change: transform;
    transition: background var(--dur-fast) var(--ease);
}
.bento-card:hover { background: var(--frost-hi); }
.bento-card.is-dark { background: var(--navy); color: var(--frost); }
.bento-card.is-dark:hover { background: var(--navy-soft); }
.bento-card.is-dark h3 { color: var(--frost); }
.bento-card.is-dark p { color: rgba(243, 244, 241, .65); }
.bento-card .k { font-family: var(--font-mono); font-size: .6875rem; letter-spacing: .1em; text-transform: uppercase; color: var(--red-dim); }
.bento-card.is-dark .k { color: var(--red); }
.bento-card h3 { font-size: 1.4rem; margin-top: var(--sp-3); }
.bento-card p { color: var(--mist); font-size: .9rem; line-height: 1.55; margin-top: var(--sp-2); }
.bento-c1 { grid-column: span 2; grid-row: span 2; }
.bento-c2 { grid-column: span 2; }
.bento-c3 { grid-column: span 1; }
/* Tablet: 2 columnas estructuradas, no un salto directo a 1 sola columna
   (la tarjeta grande sigue ocupando el ancho completo como banner). */
@media (max-width: 1024px) and (min-width: 641px) {
    .bento { grid-template-columns: repeat(2, 1fr); }
    .bento-c1 { grid-column: span 2; grid-row: span 1; }
    .bento-c2 { grid-column: span 2; }
    .bento-c3 { grid-column: span 1; }
}
@media (max-width: 640px) { .bento { grid-template-columns: 1fr; } .bento-c1, .bento-c2, .bento-c3 { grid-column: span 1; } }
/* Variante de 3 celdas iguales (Quiénes somos, v29) — a diferencia del
   bento de "Por qué ILG" (una celda grande + dos chicas, porque esas 4
   piezas eran de naturaleza distinta: un principio, un proceso, dos
   cifras), acá los 3 pilares son estructuralmente idénticos
   (ícono+título+párrafo), así que no hay jerarquía que justificar un
   tamaño desigual — 3 columnas parejas, cada .bento-card ya cae 1x1 por
   default sin necesitar clases .bento-c1/c2/c3. */
.bento--trio { grid-template-columns: repeat(3, 1fr); }
@media (max-width: 640px) { .bento--trio { grid-template-columns: 1fr; } }

/* ---------- 11. Marquee (ofertas) -------------------------------------------- */
.marquee { overflow: hidden; border-block: 1px solid var(--line); position: relative; }
.marquee::before, .marquee::after {
    content: ""; position: absolute; top: 0; bottom: 0; width: 80px; z-index: 2; pointer-events: none;
}
/* --frost acá también (franja + máscaras de fundido en los bordes) —
   ver comentario en .destino-pill. Las máscaras tienen que arrancar del
   mismo --frost de la franja, no de --frost-hi: si no, quedaba una
   costura visible (un parche más blanco) justo donde empieza/termina
   el degradado. */
.marquee { background: var(--frost); }
.marquee::before { left: 0; background: linear-gradient(90deg, var(--frost), transparent); }
.marquee::after { right: 0; background: linear-gradient(270deg, var(--frost), transparent); }
.marquee__track {
    display: flex; width: max-content;
    animation: marquee 32s linear infinite;
}
.marquee:hover .marquee__track { animation-play-state: paused; }
html.reduced-motion .marquee__track { animation: none; }
html.reduced-motion .marquee__item[aria-hidden] { display: none; }
@keyframes marquee { from { transform: translateX(0); } to { transform: translateX(-50%); } }
.marquee__item {
    display: inline-flex; align-items: center; gap: var(--sp-3);
    padding: var(--sp-5) var(--sp-6);
    font-family: var(--font-mono); font-size: .875rem; white-space: nowrap;
    border-right: 1px solid var(--line);
}
.marquee__item .ref { color: var(--red-dim); }

/* ---------- 12. Cards -------------------------------------------------------- */
.card {
    /* --frost, ver comentario en .destino-pill. */
    background: var(--frost); border: 1px solid var(--line); border-radius: var(--radius);
    box-shadow: var(--shadow-rest); padding: var(--sp-6);
    transition: transform var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}
@media (hover: hover) {
    .card:hover { transform: translateY(-3px); box-shadow: var(--shadow-lift); border-color: var(--red); }
}
/* Variante con el mismo fondo translúcido que .faq-question/.card-area
   (v26, pedido del cliente de igualar el color en Contacto) — modificador
   aparte en vez de cambiar .card global: .card se usa en todo el sitio
   (destinos, ofertas, tiktok, etc.), tocar su fondo de base hubiera
   afectado secciones que no se pidió cambiar. */
.card--tint { background: var(--tint-navy); }
/* Barra de filtro por destino (/ofertas) — antes reusaba .hero__actions
   (pensada para 1-2 CTA de hero, no para N pills de filtro) y con
   flex-wrap normal se veía irregular en móvil: la fila 2 no arrancaba
   alineada con la 1 y los anchos de pill distintos ("Todas" vs
   "Montenegro") lo hacían ver desprolijo. En vez de forzar un wrap
   parejo (se rompe otra vez apenas se agregue un destino más), pasa a
   scroll horizontal de una sola fila en móvil — mismo patrón de "tira
   de chips" que cualquier filtro de e-commerce, escala sola si se suman
   destinos en vez de generar más filas irregulares. */
.filtro-pills { display: flex; gap: var(--sp-3); flex-wrap: wrap; align-items: center; }
@media (max-width: 640px) {
    .filtro-pills {
        flex-wrap: nowrap; overflow-x: auto; -webkit-overflow-scrolling: touch;
        scrollbar-width: none; padding-bottom: 2px;
    }
    .filtro-pills::-webkit-scrollbar { display: none; }
    .filtro-pills .btn { flex-shrink: 0; }
}
.card-oferta { position: relative; display: flex; flex-direction: column; gap: var(--sp-3); }
.badge-activa {
    position: absolute; top: -12px; right: var(--sp-6);
    background: var(--red); color: #fff;
    display: inline-flex; align-items: center; gap: 6px;
    font-family: var(--font-mono); font-size: .625rem; letter-spacing: .1em; text-transform: uppercase;
    padding: 6px 14px; border-radius: var(--radius);
    box-shadow: 0 6px 16px rgba(194, 59, 50, .35);
}
.badge-activa .icon { width: 12px; height: 12px; }
.card-oferta__ref { color: var(--mist); }
.card-oferta__ubicacion { color: var(--mist); font-size: .875rem; }
.card-oferta__salario { font-family: var(--font-mono); font-weight: 600; }
/* Sangra hasta el borde de la tarjeta (márgenes negativos que cancelan
   el padding de .card) — el resto del contenido sigue con su padding
   normal porque .card-oferta ya es flex con gap, no necesita margin
   propio para separarse de la imagen. */
.card-oferta__imagen {
    display: block; margin: calc(var(--sp-6) * -1) calc(var(--sp-6) * -1) 0;
    aspect-ratio: 16 / 9; overflow: hidden; border-radius: var(--radius) var(--radius) 0 0;
}
.card-oferta__imagen img { width: 100%; height: 100%; object-fit: cover; display: block; }
.oferta-detalle__imagen { margin-top: var(--sp-7); border-radius: var(--radius); overflow: hidden; aspect-ratio: 16 / 7; }
.oferta-detalle__imagen img { width: 100%; height: 100%; object-fit: cover; display: block; }
@media (max-width: 640px) { .oferta-detalle__imagen { aspect-ratio: 16 / 10; } }
/* Mismo criterio de sangrado que .card-oferta__imagen (v18) — .card acá
   no es flex (los hijos van con margin-top inline entre sí), por eso
   necesita su propio margin-bottom en vez de apoyarse en gap. */
.destino-card__imagen {
    display: block; margin: calc(var(--sp-6) * -1) calc(var(--sp-6) * -1) var(--sp-5);
    aspect-ratio: 16 / 9; overflow: hidden; border-radius: var(--radius) var(--radius) 0 0;
}
.destino-card__imagen img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform var(--dur-med) var(--ease); }
@media (hover: hover) {
    .card:hover .destino-card__imagen img { transform: scale(1.05); }
}
/* Mismo fondo translúcido que .faq-question (ver sección 14, FAQ) —
   pedido explícito del cliente de igualar el color, --frost sólido
   quedó reemplazado en las dos secciones a la vez. */
.card-area { border: 1px solid var(--line); border-radius: var(--radius); padding: var(--sp-5) var(--sp-6); background: var(--tint-navy); transition: border-color var(--dur-fast) var(--ease); }
.card-area:hover { border-color: var(--red); }
/* Mapa de la oficina (Contacto, v26) — mismo sangrado a los bordes que
   .destino-card__imagen. El iframe de Google Maps queda con
   pointer-events:none: un mapa interactivo real dentro de una página
   con scroll normal atrapa la rueda del mouse en cuanto el cursor pasa
   por encima (zoom del mapa en vez de scroll de la página) — acá el
   mapa es una vista previa clickeable, no un mapa para navegar in situ.
   El link real que lo hace "clickeable" es un <a> hermano superpuesto,
   no un <a> envolviendo el <iframe> — un iframe es "contenido
   interactivo" y el spec de HTML no permite anidarlo dentro de un <a>. */
.oficina-card__mapa {
    position: relative; margin: calc(var(--sp-6) * -1) calc(var(--sp-6) * -1) var(--sp-5);
    aspect-ratio: 16 / 9; overflow: hidden; border-radius: var(--radius) var(--radius) 0 0;
    background: var(--line);
}
.oficina-card__mapa iframe { width: 100%; height: 100%; border: 0; display: block; pointer-events: none; }
.oficina-card__mapa-link {
    position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
    background: rgba(11, 24, 48, 0); color: #fff; opacity: 0;
    transition: background var(--dur-fast) var(--ease), opacity var(--dur-fast) var(--ease);
}
.oficina-card__mapa-link .icon { width: 28px; height: 28px; }
@media (hover: hover) {
    .oficina-card__mapa-link:hover { background: rgba(11, 24, 48, .45); opacity: 1; }
}
.oficina-card__mapa-link:focus-visible { background: rgba(11, 24, 48, .45); opacity: 1; outline: 2px solid var(--red); outline-offset: -2px; }
/* País (bandera + nombre) y WhatsApp de la oficina (v27) — reordenado
   a pedido del cliente: mapa, país, dirección, WhatsApp, en ese orden
   dentro de la misma tarjeta. */
.oficina-card__pais { display: flex; align-items: center; gap: var(--sp-2); margin-top: var(--sp-2); font-size: .9375rem; }
.oficina-card__pais .flag-icon { border-radius: 2px; flex-shrink: 0; }
.oficina-card__whatsapp { margin-top: var(--sp-4); }
.oficina-card__whatsapp .icon--brand { width: 16px; height: 16px; }

/* ---------- 13. Tabla "Sobre la visa" ---------------------------------------- */
.table-visa th, .table-visa td { text-align: left; padding: var(--sp-3) var(--sp-4); border-bottom: 1px solid var(--line); }
.table-visa th { font-family: var(--font-mono); font-size: .6875rem; letter-spacing: .08em; text-transform: uppercase; color: var(--mist); font-weight: 500; }
.table-visa tbody tr:hover { background: rgba(11, 24, 48, .03); }
.visa-flag { display: inline-flex; align-items: center; gap: var(--sp-2); font-family: var(--font-mono); font-size: .8125rem; }
.visa-flag__dot { width: 8px; height: 8px; border-radius: 50%; }
.visa-flag--si .visa-flag__dot { background: var(--red); }
.visa-flag--no .visa-flag__dot { background: var(--red); }
@media (max-width: 640px) {
    .table-visa, .table-visa thead { display: none; }
    .table-visa tbody, .table-visa tr, .table-visa td { display: block; width: 100%; }
    .table-visa tr { border: 1px solid var(--line); border-radius: var(--radius); margin-bottom: var(--sp-3); padding: var(--sp-3) var(--sp-4); background: var(--frost); }
    .table-visa td { border-bottom: none; padding: var(--sp-1) 0; display: flex; justify-content: space-between; align-items: center; }
    .table-visa td::before { content: attr(data-label); font-family: var(--font-mono); font-size: .6875rem; text-transform: uppercase; letter-spacing: .06em; color: var(--mist); }
}

/* ---------- 14. FAQ ----------------------------------------------------------- */
/* Cada pregunta es su propia "caja" en vez de una fila a ras de un
   divisor — así el fondo de la pregunta se diferencia del blanco de la
   sección sin competir con él. El fondo es un lavado translúcido de
   --navy (rgba, no --frost sólido) a propósito: --frost opaco se leía
   como una tarjeta gris plena, más fuerte de lo pedido; con alpha bajo
   se nota como una superficie apenas distinta, no como una caja rellena
   — mismo criterio de color que --line (rgba(11,24,48,...)), solo que
   más tenue. El borde pasa a --red en hover/abierta, igual que
   .route__card.is-active y el resto de estados "activos" del sitio. La
   respuesta se queda sin fondo propio para que la diferenciación sea
   sutil: un solo bloque con jerarquía, no dos fondos compitiendo. */
.faq-list { display: flex; flex-direction: column; gap: var(--sp-3); }
.faq-question {
    width: 100%; display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4);
    padding: var(--sp-4) var(--sp-5); text-align: left;
    background: var(--tint-navy); border: 1px solid var(--line); border-radius: var(--radius);
    font-family: var(--font-display); font-weight: 700; font-size: 1.0625rem; color: var(--navy);
    transition: border-color var(--dur-fast) var(--ease);
}
@media (hover: hover) {
    .faq-question:hover { border-color: var(--red); }
}
.faq-item.is-open .faq-question { border-color: var(--red); }
.faq-question .icon { color: var(--red); flex-shrink: 0; transition: transform var(--dur-fast) var(--ease); }
.faq-item.is-open .faq-question .icon { transform: rotate(180deg); }
/* Deslizamiento al abrir/cerrar vía CSS grid (grid-template-rows
   0fr→1fr) en vez de max-height con un valor fijo adivinado o
   display:none/block sin transición — anima a la altura real del
   contenido sin JS y sin depender de GSAP (esta sección vive también en
   /ayuda, que no carga motion.js). El padding NO puede ir en
   .faq-answer (el contenedor de grid): si quedara ahí, seguiría
   ocupando esa altura incluso en 0fr y el cierre nunca llegaría a 0 —
   por eso vive en .faq-answer__inner.
   Gotcha real (reproducido con un HTML aislado antes de tocar esto):
   `grid-template-rows: 0fr` a secas NO colapsa a 0 — el tamaño mínimo
   automático del grid-item sigue basándose en el contenido incluso con
   overflow:hidden en el hijo, y queda una fila de ~24px (justo la
   altura de una línea de texto, se veía como una respuesta "cortada"
   asomando bajo la pregunta cerrada). El fix es envolver el valor en
   `minmax(0, 0fr)`/`minmax(0, 1fr)` — eso sí fuerza el mínimo del track
   a 0 en vez de heredar el mínimo automático del contenido. */
.faq-answer {
    display: grid; grid-template-rows: minmax(0, 0fr); overflow: hidden;
    transition: grid-template-rows var(--dur-med) var(--ease);
}
.faq-item.is-open .faq-answer { grid-template-rows: minmax(0, 1fr); }
.faq-answer__inner {
    overflow: hidden; min-height: 0;
    padding: var(--sp-4) var(--sp-5) var(--sp-2); color: var(--mist); max-width: 68ch;
}
html.reduced-motion .faq-answer { transition: none; }

/* ---------- 15. Formularios / wizard -------------------------------------------- */
.field { display: flex; flex-direction: column; gap: var(--sp-2); margin-bottom: var(--sp-5); }
.field label { font-family: var(--font-mono); font-size: .75rem; letter-spacing: .05em; text-transform: uppercase; color: var(--mist); }
.field label .req { color: var(--bordeaux); margin-left: 2px; }
.field input, .field select, .field textarea {
    background: var(--frost-hi); border: 1px solid var(--line-strong); border-radius: var(--radius);
    padding: var(--sp-4); font-size: .9375rem; font-family: var(--font-body);
}
.field input:focus, .field select:focus, .field textarea:focus { border-color: var(--red); outline: none; box-shadow: 0 0 0 3px rgba(194, 59, 50, .18); }
.field textarea { resize: vertical; min-height: 100px; }
/* Campos con ícono referencial: el ícono vive dentro de un
   .field__wrap para poder posicionarlo absoluto sobre el input/select.
   .field es flex column con align-items:stretch por defecto — así es
   como un input SIN width:100% igual ocupaba el ancho completo antes
   de este cambio (stretch de flexbox, siendo hijo directo de .field).
   Meter el input dentro de .field__wrap lo saca de ser hijo directo
   del flex container, así que pierde ese stretch automático y hay que
   fijar width:100% a mano — si no, el campo vuelve a su ancho
   intrínseco de navegador (angosto, no ocupa la tarjeta completa). */
.field--icon .field__wrap { position: relative; }
.field--icon .field__wrap .icon {
    position: absolute; left: 15px; top: 50%; transform: translateY(-50%);
    color: var(--mist); pointer-events: none;
}
.field--icon input, .field--icon select { padding-left: 44px; width: 100%; }
.field-row { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-4); }
@media (max-width: 640px) { .field-row { grid-template-columns: 1fr; } }
/* Form de captación rápida del home en tablet: .field-row es compartida
   con el wizard de validar-perfil (que sí debe seguir en 2 columnas
   ahí), así que este ajuste va scopeado a .form-card (solo existe en el
   form del home). En tablet el form-card comparte fila con el bloque de
   texto de al lado (.grid-2 recién colapsa a 1 columna en 720px) y
   queda angosto — correo/whatsapp en 2 columnas ahí se ve apretado. */
@media (max-width: 1024px) and (min-width: 641px) {
    .form-card .field-row { grid-template-columns: 1fr; }
}
.field-check { flex-direction: row; align-items: flex-start; gap: var(--sp-3); }
.field-check label { text-transform: none; letter-spacing: normal; font-family: var(--font-body); font-size: .875rem; color: var(--navy); }
/* Checkbox propio (no el nativo del SO) — mismo lenguaje visual que
   .toggle-pill (relleno rojo + check blanco al marcar, anillo de foco,
   "pop" de escala) para que las declaraciones del paso 7 y el aviso de
   inversión del paso 5 no desentonen con el resto de "celdas de
   selección" del formulario. */
.field-check input {
    appearance: none; -webkit-appearance: none;
    margin-top: 2px; width: 20px; height: 20px; flex-shrink: 0; cursor: pointer;
    border: 1.5px solid var(--line-strong); border-radius: 6px;
    background-color: var(--frost-hi); background-repeat: no-repeat; background-position: center; background-size: 13px;
    transition: background-color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease);
}
@media (hover: hover) {
    .field-check input:hover { border-color: var(--red); }
}
.field-check input:checked {
    background-color: var(--red); border-color: var(--red);
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 13l4 4L19 7'/%3E%3C/svg%3E");
    animation: check-pop .3s var(--ease);
}
.field-check input:focus-visible { outline: none; box-shadow: 0 0 0 4px rgba(194, 59, 50, .3); }
.field-check input:active { transform: scale(.9); }
@keyframes check-pop { 0% { transform: scale(.7); } 60% { transform: scale(1.15); } 100% { transform: scale(1); } }
.field-error { color: var(--bordeaux); font-size: .8125rem; }
.field-hint { color: var(--mist); font-size: .8125rem; }
/* Botones de selección Sí/No (campo_sino() en validar-perfil.php) —
   antes radios + label en texto plano, ahora pills clicables. Sigue
   siendo un <input type="radio"> real (accesibilidad/semántica de
   formulario intactas) envuelto en <label>, solo visualmente oculto
   (no display:none — así se mantiene tabbable) y estilado vía el
   <span> hermano con :checked. Mismo lenguaje de interacción que
   .btn (hover con translateY, active con scale, focus-visible con
   anillo rojo) para no inventar un estilo nuevo. */
.toggle-row { display: flex; gap: var(--sp-3); margin-top: var(--sp-1); flex-wrap: wrap; }
.toggle-pill { position: relative; display: inline-flex; cursor: pointer; }
.toggle-pill input {
    position: absolute; opacity: 0; width: 1px; height: 1px; margin: 0; padding: 0;
}
.toggle-pill span {
    display: inline-flex; align-items: center; gap: var(--sp-2);
    padding: var(--sp-3) var(--sp-6); border-radius: 999px;
    border: 1px solid var(--line-strong); background: var(--frost-hi);
    font-family: var(--font-body); font-weight: 600; font-size: .9375rem; color: var(--navy);
    transition: transform var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.toggle-pill span .icon { opacity: 0; width: 0; transition: opacity var(--dur-fast) var(--ease), width var(--dur-fast) var(--ease); }
@media (hover: hover) {
    .toggle-pill:hover span { border-color: var(--red); transform: translateY(-2px); box-shadow: var(--shadow-rest); }
}
.toggle-pill input:checked + span {
    background: linear-gradient(135deg, var(--red) 0%, var(--red-dim) 100%);
    border-color: transparent; color: #fff;
    box-shadow: 0 10px 24px rgba(194, 59, 50, .3);
}
.toggle-pill input:checked + span .icon { opacity: 1; width: 1em; }
.toggle-pill input:focus-visible + span { outline: none; box-shadow: 0 0 0 4px rgba(194, 59, 50, .3); }
.toggle-pill input:active + span { transform: scale(.97); }

.form-card { background: var(--frost); border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow-rest); padding: var(--sp-7); }

.wizard-progress { display: flex; flex-direction: column; gap: var(--sp-2); margin-bottom: var(--sp-7); }
.wizard-progress__label { font-family: var(--font-mono); font-size: .75rem; letter-spacing: .05em; text-transform: uppercase; color: var(--mist); display: flex; justify-content: space-between; }
.wizard-progress__bar { height: 2px; background: var(--line); position: relative; }
.wizard-progress__bar span { position: absolute; left: 0; top: 0; bottom: 0; background: var(--red); transition: width var(--dur-med) var(--ease); }
.wizard-step { display: none; }
.wizard-step.is-active { display: block; }
.wizard-actions { display: flex; justify-content: space-between; gap: var(--sp-4); margin-top: var(--sp-7); }
.form-success { text-align: center; display: flex; flex-direction: column; align-items: center; gap: var(--sp-4); padding: var(--sp-9) var(--sp-5); }
.form-success__mark {
    width: 64px; height: 64px; border-radius: 50%; border: 1.5px solid var(--red);
    display: flex; align-items: center; justify-content: center;
}

/* ---------- 16. Footer -------------------------------------------------------- */
.site-footer { background: var(--navy); color: rgba(243, 244, 241, .75); padding-block: var(--sp-9) var(--sp-6); }
.site-footer--minimal { padding-block: var(--sp-6); }
.site-footer--minimal .footer-bottom { margin-top: 0; padding-top: 0; border-top: none; }
.site-footer a:hover { color: var(--red); }
.footer-grid { display: grid; grid-template-columns: 1.4fr 1fr 1fr 1fr; gap: var(--sp-6); }
@media (max-width: 900px) { .footer-grid { grid-template-columns: 1fr 1fr; } }
@media (max-width: 560px) { .footer-grid { grid-template-columns: 1fr; } }
.footer-col__title { font-family: var(--font-mono); font-size: .75rem; letter-spacing: .08em; text-transform: uppercase; color: rgba(243, 244, 241, .5); font-weight: 500; margin-bottom: var(--sp-3); }
.footer-col ul { display: flex; flex-direction: column; gap: var(--sp-2); font-size: .9375rem; }
/* Ícono + texto como una sola unidad flex (no depender de que floten
   inline uno junto al otro): con inline simple, una columna angosta
   podía envolver el texto completo a una segunda línea dejando el
   ícono solo arriba — align-items:center + gap los mantiene pegados y
   alineados pase lo que pase con el ancho disponible. */
.footer-col ul li a { display: inline-flex; align-items: center; gap: var(--sp-2); }
.footer-col ul li a .icon { flex-shrink: 0; }
.footer-bottom { display: flex; justify-content: space-between; flex-wrap: wrap; gap: var(--sp-3) var(--sp-6); margin-top: var(--sp-8); padding-top: var(--sp-5); border-top: 1px solid var(--line-on-dark); font-family: var(--font-mono); font-size: .75rem; color: rgba(243, 244, 241, .6); }
.footer-legal { display: flex; gap: var(--sp-5); flex-wrap: wrap; }
.social-row { display: flex; gap: var(--sp-3); flex-wrap: wrap; }
.social-badge {
    width: 40px; height: 40px; border-radius: 50%;
    border: 1px solid var(--line-on-dark);
    display: flex; align-items: center; justify-content: center;
    font-family: var(--font-mono); font-weight: 600; font-size: .8125rem;
    color: rgba(243, 244, 241, .7);
    transition: border-color var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease);
}
/* Antes el hover rellenaba el círculo de --red 100% sólido — el ícono
   (currentColor, blanco encima) quedaba perdido contra el rojo, se leía
   como "el botón entero se puso rojo" en vez de un hover con efecto.
   Mismo lenguaje que .btn-on-dark.btn-secondary:hover (fondo rojo
   traslúcido + glow + lift), no relleno sólido — así el ícono se queda
   en rojo, legible, sobre el fondo. (hover:hover) porque en táctil no
   hay mouseleave real y quedaba "pegado" en rojo tras un tap. */
@media (hover: hover) {
    .social-badge:hover {
        border-color: var(--red);
        color: var(--red);
        background: rgba(194, 59, 50, .18);
        box-shadow: 0 0 0 4px rgba(194, 59, 50, .18);
        transform: translateY(-2px);
    }
}
.social-badge:active { transform: translateY(0) scale(.95); }
.social-badge .icon--brand { width: 18px; height: 18px; vertical-align: 0; }

/* Contenedor fijo del widget completo (botón + burbuja de mensaje) —
   antes el <a> del botón era el que tenía position:fixed; ahora ese rol
   lo cumple .whatsapp-widget para poder ubicar la burbuja al lado sin
   que cada uno necesite su propio cálculo de posición en pantalla. */
.whatsapp-widget {
    position: fixed; bottom: calc(var(--sp-5) + var(--consent-h, 0px)); right: var(--sp-5); z-index: 50;
    display: flex; align-items: center; gap: var(--sp-3);
    transition: bottom var(--dur-med) var(--ease);
}
.whatsapp-float {
    position: relative; flex-shrink: 0;
    width: 56px; height: 56px; border-radius: 50%; background: var(--red);
    display: flex; align-items: center; justify-content: center;
    box-shadow: var(--shadow-lift);
    transition: transform var(--dur-fast) var(--ease);
}
@media (hover: hover) {
    .whatsapp-float:hover { transform: scale(1.06); }
}
.whatsapp-float svg { width: 28px; height: 28px; position: relative; z-index: 1; }
/* Pulso "de nueva generación": dos anillos concéntricos que se expanden
   y se desvanecen en cascada (delay escalonado uno del otro), en vez de
   un solo scale del botón entero (ese ya está tomado por el hover) —
   se lee como una señal viva, tipo "acá hay alguien esperando". */
.whatsapp-float__ring {
    position: absolute; inset: 0; border-radius: 50%;
    border: 2px solid var(--red);
    animation: whatsapp-pulse 2.4s cubic-bezier(.22, .8, .32, 1) infinite;
    pointer-events: none;
}
.whatsapp-float__ring--2 { animation-delay: 1.2s; }
@keyframes whatsapp-pulse {
    0% { transform: scale(1); opacity: .55; }
    100% { transform: scale(1.9); opacity: 0; }
}
html.reduced-motion .whatsapp-float__ring { animation: none; display: none; }

/* Burbuja "¿Necesitas ayuda?" — oculta por defecto, assets/js/main.js le
   suma .is-visible a los pocos segundos de cargar la página (una vez
   por sesión vía sessionStorage, para no repetirla en cada navegación
   dentro del sitio). Blanco sólido (no --frost, tiene que funcionar
   flotando sobre CUALQUIER fondo del sitio, claro u oscuro) con la
   misma sombra elevada que .whatsapp-float. */
.whatsapp-tooltip {
    position: relative;
    background: var(--frost-hi); color: var(--navy);
    padding: var(--sp-3) var(--sp-5);
    border-radius: var(--radius);
    box-shadow: var(--shadow-lift);
    font-size: .9375rem; font-weight: 600;
    white-space: nowrap;
    opacity: 0; transform: translateX(12px) scale(.92);
    pointer-events: none;
    transition: opacity var(--dur-med) var(--ease), transform var(--dur-med) var(--ease);
}
.whatsapp-tooltip.is-visible { opacity: 1; transform: translateX(0) scale(1); pointer-events: auto; }
.whatsapp-tooltip::after {
    content: ""; position: absolute; top: 50%; right: -7px; margin-top: -7px;
    border: 7px solid transparent; border-left-color: var(--frost-hi);
}
.whatsapp-tooltip__link { display: block; }
.whatsapp-tooltip__close {
    position: absolute; top: -8px; right: -8px; width: 20px; height: 20px; border-radius: 50%;
    background: var(--navy); color: #fff;
    display: flex; align-items: center; justify-content: center;
    box-shadow: 0 2px 6px rgba(6, 11, 20, .3);
}
.whatsapp-tooltip__close .icon { width: 11px; height: 11px; }
@media (max-width: 400px) {
    .whatsapp-tooltip { font-size: .875rem; padding: var(--sp-2) var(--sp-4); }
}

/* ---------- 17. Íconos --------------------------------------------------------
   Tamaño en "em" por defecto: el ícono escala con el font-size del texto
   que lo rodea (así "se adapta" en vez de quedar fijo en 20px sin importar
   dónde se use). inline-block + vertical-align lo alinea con el texto en
   CUALQUIER contenedor, incluso los que no son flex (un <a> de footer, un
   <h3> con ícono + texto) — antes heredaba "display:block" del reset
   general de svg y rompía el flujo de línea ahí. Solo los usos realmente
   decorativos/independientes (ícono grande arriba de una tarjeta) piden
   un tamaño fijo explícito con --lg/--xl. */
.icon {
    width: 1em; height: 1em;
    display: inline-block;
    vertical-align: -0.15em;
    flex-shrink: 0;
}
.icon--lg { width: 28px; height: 28px; vertical-align: middle; }
.icon--xl { width: 36px; height: 36px; vertical-align: middle; }
.icon--red { color: var(--red); }
.icon--flip { transform: scaleX(-1); }
.flag-icon {
    display: inline-block;
    width: 1.3em; height: auto;
    aspect-ratio: 4 / 3;
    vertical-align: -0.2em;
    border-radius: 2px;
    box-shadow: 0 0 0 1px var(--line-strong);
    object-fit: cover;
}

/* ---------- 18. Utilidades ----------------------------------------------------- */
.text-center { text-align: center; }
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0; }
.skip-link { position: absolute; left: -999px; top: 0; background: var(--navy); color: var(--frost); padding: var(--sp-3) var(--sp-4); z-index: 100; font-family: var(--font-mono); font-size: .8125rem; }
.skip-link:focus { left: var(--sp-4); top: var(--sp-4); }

/* ---------- 19. Banner de aceptación de términos --------------------------
   Tarjeta fija abajo-izquierda (no cubre el CTA de WhatsApp que vive
   abajo-derecha) — oculta por defecto y visible solo si
   assets/js/main.js decide mostrarla (ver [data-consent-banner] ahí).
   --consent-h la fija ese mismo JS con la altura real del banner
   mientras está visible; .whatsapp-widget la usa para subirse y no
   quedar tapado en pantallas angostas donde el banner pasa a barra de
   ancho completo (ver media query abajo). */
:root { --consent-h: 0px; }
.consent-banner {
    position: fixed; left: var(--sp-5); right: auto; bottom: var(--sp-5); z-index: 60;
    max-width: 460px;
    background: var(--frost-hi); border: 1px solid var(--line); border-radius: var(--radius);
    box-shadow: var(--shadow-lift);
    opacity: 0; visibility: hidden; transform: translateY(12px);
    transition: opacity var(--dur-med) var(--ease), transform var(--dur-med) var(--ease), visibility 0s linear var(--dur-med);
}
.consent-banner.is-visible {
    opacity: 1; visibility: visible; transform: translateY(0);
    transition: opacity var(--dur-med) var(--ease), transform var(--dur-med) var(--ease);
}
.consent-banner__inner { display: flex; align-items: center; gap: var(--sp-4); padding: var(--sp-5); }
.consent-banner__icon { color: var(--red); flex-shrink: 0; width: 22px; height: 22px; }
.consent-banner p { font-size: .875rem; line-height: 1.55; color: var(--mist); flex: 1; }
.consent-banner a { color: var(--navy); text-decoration: underline; text-underline-offset: 2px; }
.consent-banner a:hover { color: var(--red); }
.consent-banner .btn { padding: var(--sp-3) var(--sp-5); font-size: .875rem; flex-shrink: 0; }
/* En móvil pasa de "tarjeta" a barra angosta pegada abajo — pedido
   explícito de que se vea "más discreta": texto y botón quedan en la
   MISMA fila (nunca el botón se cae a una fila propia, a diferencia del
   intento anterior con flex-wrap + flex-basis:100%), con tipografía y
   padding más chicos y una sombra solo hacia arriba (no la elevada de
   la tarjeta de escritorio, que se ve rara sin bordes izq/der). */
@media (max-width: 640px) {
    .consent-banner {
        left: 0; right: 0; bottom: 0; max-width: none;
        border-radius: 0; border-inline: none; border-bottom: none;
        box-shadow: 0 -6px 20px rgba(6, 11, 20, .14);
    }
    .consent-banner:not(.is-visible) { transform: translateY(100%); }
    .consent-banner__inner { padding: var(--sp-3) var(--sp-4); gap: var(--sp-3); }
    .consent-banner__icon { display: none; }
    .consent-banner p { font-size: .75rem; line-height: 1.45; }
    .consent-banner .btn { padding: var(--sp-2) var(--sp-4); font-size: .8125rem; }
}

/* ---------- 20. Selector de bandera (país / indicativo WhatsApp) ------------
   Reemplaza un <select> nativo por un botón + listbox propios — un select
   nativo no puede mostrar una <img> de bandera dentro de cada <option> de
   forma confiable entre navegadores. El <select> real SIGUE en el DOM y
   sigue siendo el valor que se envía con el form; assets/js/main.js solo
   construye la UI encima y la mantiene sincronizada (ver
   enhanceFlagSelect). Progresivo a propósito: [data-flag-select-ui] parte
   con el atributo `hidden` puesto en el HTML, y solo el JS lo retira al
   terminar de montar la lista — si el JS no corre, el <select> nativo
   (ya estilado por ".field select" en la sección 15) se ve y funciona
   exactamente igual que un formulario sin esta mejora, nunca queda un
   botón decorativo sin función tapando un control real. */
.flag-select { position: relative; }
.flag-select__ui[hidden] { display: none; }
.flag-select__trigger {
    display: flex; align-items: center; gap: var(--sp-2);
    background: none; border: none; border-radius: var(--radius);
    font-family: var(--font-body); color: var(--navy);
    cursor: pointer;
}
.flag-select__trigger--full {
    width: 100%; padding: var(--sp-4); font-size: .9375rem; text-align: left;
    background: var(--frost-hi); border: 1px solid var(--line-strong);
}
.flag-select__trigger--full:focus-visible,
.flag-select.is-open .flag-select__trigger--full { border-color: var(--red); outline: none; box-shadow: 0 0 0 3px rgba(194, 59, 50, .18); }
.flag-select.is-invalid .flag-select__trigger--full { border-color: var(--red); box-shadow: 0 0 0 3px rgba(194, 59, 50, .18); }
.flag-select__current { display: flex; align-items: center; gap: var(--sp-2); flex: 1; min-width: 0; }
.flag-select__current span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--navy); }
.flag-select__current .flag-select__placeholder { color: var(--mist); }
.flag-select__caret { color: var(--mist); flex-shrink: 0; transition: transform var(--dur-fast) var(--ease); }
.flag-select.is-open .flag-select__caret { transform: rotate(180deg); }

/* overscroll-behavior:contain evita que el scroll de la lista "se pase"
   a la página al llegar al final. */
.flag-select__list {
    position: absolute; z-index: 20; top: calc(100% + 6px); left: 0; min-width: 100%;
    max-height: 264px; overflow-y: auto; overscroll-behavior: contain;
    background: var(--frost-hi); border: 1px solid var(--line-strong); border-radius: var(--radius);
    box-shadow: var(--shadow-lift);
    padding: var(--sp-2);
    list-style: none;
}
.flag-select__list[hidden] { display: none; }
.flag-select__list [role="option"] {
    display: flex; align-items: center; gap: var(--sp-3);
    padding: var(--sp-3); border-radius: calc(var(--radius) - 6px);
    cursor: pointer; font-size: .9375rem; white-space: nowrap;
}
.flag-select__list [role="option"]:hover,
.flag-select__list [role="option"].is-active { background: var(--frost); }
.flag-select__list [role="option"][aria-selected="true"] { color: var(--red); font-weight: 600; }

/* Campo de WhatsApp: la bandera (indicativo) y el número quedan dentro de
   UNA sola caja bordeada (mismo look que el resto de los campos), no dos
   cajas pegadas — el trigger/select del indicativo queda sin borde propio
   y una línea fina lo separa del input. Variante "compacta" a propósito:
   pedido explícito de que el selector de indicativo se vea "sin texto,
   solo banderas" — tanto cerrado como en la lista (el nombre del país +
   indicativo sigue disponible para lectores de pantalla vía .sr-only en
   cada <li>, ver views/home.php; el código numérico visible queda solo
   dentro del input una vez elegido, ej. "+57" seguido del número). */
.field__wrap--tel {
    display: flex; align-items: stretch;
    background: var(--frost-hi); border: 1px solid var(--line-strong); border-radius: var(--radius);
}
.field__wrap--tel:focus-within { border-color: var(--red); box-shadow: 0 0 0 3px rgba(194, 59, 50, .18); }
.field .field__wrap--tel input {
    flex: 1; min-width: 0; border: none; background: none; border-radius: 0;
}
.field .field__wrap--tel input:focus { outline: none; box-shadow: none; }
.field .field__wrap--tel select {
    border: none; background: none; border-radius: 0; height: 100%;
}
.flag-select--compact { display: flex; border-right: 1px solid var(--line); }
.flag-select--compact .flag-select__ui { display: flex; }
.flag-select--compact .flag-select__trigger { padding: 0 var(--sp-3); min-width: 52px; justify-content: center; }
.flag-select--compact .flag-select__list {
    min-width: 0; width: max-content; padding: var(--sp-2);
}
.flag-select--compact .flag-select__list [role="option"] { justify-content: center; padding: var(--sp-2) var(--sp-4); }

/* ---------- 21. TikTok (últimos videos) -------------------------------------- */
/* v13 — 3 tarjetas fijas (tiktok_videos, ver database.sql), thumbnail
   auto-alojado (no la URL firmada de TikTok, que vence — ver
   admin/includes/tiktok.php). El tilt reusa el mismo [data-tilt] del
   bento (assets/js/motion.js) — por eso .tiktok-card NUNCA anima
   `transform` por CSS (ni en :hover): GSAP escribe `transform` inline
   apenas hay un mousemove, y una regla CSS sobre la misma propiedad
   quedaría pisada para siempre después del primer hover (mismo motivo
   por el que .bento-card:hover tampoco toca transform). El "lift" en
   hover se hace con box-shadow/border en vez de translateY. Click abre
   el modal de reproducción (ver .lightbox__video más abajo y main.js) —
   se probó mostrar el embed nativo siempre visible en la página (v25,
   segunda corrección) pero el cliente lo revirtió ("quedó peor": más
   pesado, más lento de cargar, y el marco propio de TikTok no combinaba
   con el resto del sitio) — volvió a esta miniatura + modal. */
.tiktok-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--sp-5); }
.tiktok-card {
    position: relative; display: flex; flex-direction: column;
    background: var(--frost-hi); border: 1px solid var(--line); border-radius: var(--radius);
    box-shadow: var(--shadow-rest); overflow: hidden;
    transform-style: preserve-3d; will-change: transform;
    transition: box-shadow var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}
@media (hover: hover) {
    .tiktok-card:hover { border-color: var(--red); box-shadow: var(--shadow-lift); }
    .tiktok-card:hover .tiktok-card__thumb img { transform: scale(1.06); }
    .tiktok-card:hover .tiktok-card__play { background: var(--red); transform: translate(-50%, -50%) scale(1.08); }
}
.tiktok-card__thumb { position: relative; aspect-ratio: 9 / 16; overflow: hidden; background: var(--navy); }
.tiktok-card__thumb img {
    width: 100%; height: 100%; object-fit: cover; display: block;
    transition: transform var(--dur-med) var(--ease);
}
.tiktok-card__play {
    position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
    width: 54px; height: 54px; border-radius: 50%;
    background: rgba(11, 24, 48, .55); backdrop-filter: blur(2px); color: #fff;
    display: flex; align-items: center; justify-content: center;
    transition: background var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
}
.tiktok-card__play .icon { width: 20px; height: 20px; margin-left: 3px; }
/* Anillo de pulso ambiente — un solo aro, sutil, no varios (eso ya se
   sintió "genérico" en otras rondas de motion de este proyecto). */
.tiktok-card__play::before {
    content: ""; position: absolute; inset: -8px; border-radius: 50%;
    border: 1.5px solid rgba(255, 255, 255, .55);
    animation: tiktok-pulse 2.4s var(--ease) infinite;
}
@keyframes tiktok-pulse {
    0% { transform: scale(.85); opacity: .9; }
    100% { transform: scale(1.35); opacity: 0; }
}
html.reduced-motion .tiktok-card__play::before { animation: none; display: none; }
.tiktok-card__meta { display: flex; align-items: flex-start; gap: var(--sp-2); padding: var(--sp-4); }
.tiktok-card__meta .icon--brand { flex-shrink: 0; width: 18px; height: 18px; margin-top: 2px; color: var(--mist); }
.tiktok-card__titulo {
    font-size: .875rem; line-height: 1.5; color: var(--navy);
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; line-clamp: 2; overflow: hidden;
}
.tiktok-cta { display: flex; justify-content: center; margin-top: var(--sp-7); }

@media (max-width: 1024px) and (min-width: 641px) {
    .tiktok-grid { grid-template-columns: repeat(3, 1fr); gap: var(--sp-4); }
}
@media (max-width: 640px) {
    .tiktok-grid { grid-template-columns: 1fr; max-width: 320px; margin-inline: auto; gap: var(--sp-6); }
}

/* ---------- 22. Galería de destino (carrusel 3D) + lightbox ------------------ */
/* v17 — reemplaza la grilla simple (v16) por un carrusel tipo "coverflow"
   elegido entre 3 previews reales (ver CLAUDE.md): la foto activa queda
   grande y de frente, las demás se acomodan en arco detrás, cada vez más
   chicas y giradas. assets/js/motion.js es DUEÑO EXCLUSIVO de `transform`
   en .galeria-card (posición 3D calculada en cada render) — por eso,
   a diferencia de .tiktok-card, esta galería NO usa [data-tilt]: el mismo
   hook de GSAP pisaría el transform que ya escribe el carrusel. Clic en
   la foto activa abre el lightbox; clic en una del costado la trae al
   centro (ver motion.js). */
.galeria-wrap { margin-top: var(--sp-6); }
/* overflow-x recorta las tarjetas del costado para que no desborden la
   página en horizontal, overflow-y queda visible para que la sombra de
   la tarjeta activa no se corte por abajo — pero tiene que ser
   `overflow-x: clip`, NO `hidden`: `hidden`/`auto` acoplan los dos ejes
   entre sí (la spec dice que si un eje no es "visible" el otro pasa de
   "visible" a "auto" para poder scrollear parejo), así que con `hidden`
   en X, Chrome recortaba igual en Y aunque overflow-y dijera "visible"
   — probado con un HTML aislado antes de este fix, se veía clarísimo:
   la sombra se cortaba en seco en el borde inferior del stage. `clip`
   (a diferencia de `hidden`/`auto`/`scroll`) no arma un contenedor de
   scroll, así que cada eje se recorta de verdad por separado. */
.galeria-stage { position: relative; height: clamp(280px, 34vw, 380px); perspective: 1500px; overflow-x: clip; overflow-y: visible; }
.galeria-track { position: relative; width: 100%; height: 100%; transform-style: preserve-3d; touch-action: pan-y; cursor: grab; user-select: none; }
.galeria-track:active { cursor: grabbing; }
.galeria-card {
    position: absolute; top: 50%; left: 50%; padding: 0; margin: 0; border: none;
    width: clamp(170px, 22vw, 260px); aspect-ratio: 3 / 4;
    border-radius: var(--radius); overflow: hidden; background: var(--navy); cursor: pointer;
    box-shadow: 0 30px 60px -22px rgba(11, 24, 48, .45);
    transition: transform .55s var(--ease), opacity .55s var(--ease), box-shadow .3s var(--ease);
    will-change: transform;
}
.galeria-card img { width: 100%; height: 100%; object-fit: cover; display: block; }
.galeria-card.is-active { box-shadow: 0 40px 90px -20px rgba(11, 24, 48, .6); cursor: zoom-in; }
.galeria-card:focus-visible { outline: 2px solid var(--red); outline-offset: 3px; }
html.reduced-motion .galeria-card { transition: none; }

.galeria-nav {
    position: absolute; top: 50%; transform: translateY(-50%); z-index: 20;
    width: 46px; height: 46px; border-radius: 50%; border: 1px solid var(--line-strong);
    background: var(--frost-hi); display: flex; align-items: center; justify-content: center;
    cursor: pointer; color: var(--navy); box-shadow: var(--shadow-rest);
    transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}
@media (hover: hover) { .galeria-nav:hover { background: var(--red); color: #fff; border-color: var(--red); } }
.galeria-nav--prev { left: 0; }
.galeria-nav--next { right: 0; }
.galeria-nav--prev .icon { transform: rotate(180deg); }
.galeria-dots { display: flex; justify-content: center; gap: 8px; margin-top: var(--sp-5); }
.galeria-dots button { width: 6px; height: 6px; padding: 0; border: none; border-radius: 50%; background: var(--line-strong); cursor: pointer; transition: background var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease); }
.galeria-dots button.is-active { background: var(--red); transform: scale(1.7); }
@media (max-width: 640px) {
    .galeria-nav { width: 38px; height: 38px; }
}

/* Overlay fijo, siempre en el DOM (nunca display:none) para poder
   animar la opacidad al abrir/cerrar — pointer-events:none lo saca del
   camino mientras está cerrado en vez de tapar la página. */
.lightbox {
    position: fixed; inset: 0; z-index: 100;
    display: flex; align-items: center; justify-content: center;
    background: rgba(6, 11, 20, .92);
    padding: var(--sp-8) var(--sp-6);
    opacity: 0; visibility: hidden; pointer-events: none;
    transition: opacity var(--dur-med) var(--ease), visibility 0s var(--dur-med);
}
.lightbox.is-open { opacity: 1; visibility: visible; pointer-events: auto; transition: opacity var(--dur-med) var(--ease); }
html.reduced-motion .lightbox { transition: none; }
.lightbox__img { max-width: min(88vw, 1100px); max-height: 80vh; object-fit: contain; border-radius: var(--radius); box-shadow: 0 30px 80px rgba(0, 0, 0, .5); }
/* Variante para el modal de TikTok (home) — mismo overlay/.lightbox__close
   que la galería de fotos, pero el contenido es el embed oficial de
   TikTok (blockquote + embed.js, ver main.js), no una imagen ni un
   iframe propio. Sin aspect-ratio fijo a propósito: el reproductor real
   de TikTok trae su panel de caption/like/compartir debajo del video,
   así que termina más alto que un simple 9:16 — forzar esa proporción
   lo recortaría. max-height + overflow-y:auto es la salvedad para
   pantallas bajas (móvil en horizontal) donde el embed completo no
   entra verticalmente. */
.lightbox__video {
    width: min(340px, 90vw); max-height: 90vh; overflow-y: auto;
    border-radius: var(--radius); background: var(--navy);
    box-shadow: 0 30px 80px rgba(0, 0, 0, .5);
}
.lightbox__video:empty { display: none; }
.lightbox__close, .lightbox__nav {
    position: absolute; display: flex; align-items: center; justify-content: center;
    width: 44px; height: 44px; border-radius: 50%;
    background: rgba(243, 244, 241, .08); border: 1px solid var(--line-on-dark); color: var(--frost);
    cursor: pointer; transition: background var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}
.lightbox__close:hover, .lightbox__nav:hover { background: var(--red); border-color: var(--red); }
.lightbox__close { top: var(--sp-5); right: var(--sp-5); }
.lightbox__nav { top: 50%; transform: translateY(-50%); }
.lightbox__nav--prev { left: var(--sp-5); }
.lightbox__nav--next { right: var(--sp-5); }
.lightbox__nav--prev .icon { transform: rotate(180deg); }
@media (max-width: 640px) {
    .lightbox { padding: var(--sp-6) var(--sp-4); }
    .lightbox__close, .lightbox__nav { width: 38px; height: 38px; }
    .lightbox__close { top: var(--sp-3); right: var(--sp-3); }
    .lightbox__nav--prev { left: var(--sp-3); }
    .lightbox__nav--next { right: var(--sp-3); }
}
