/* =========================================================================
   web.css — Web corporativa
   Sistema Integral de Gestión Comercial · Jabc SoftWorks

   FORMATO: Expandido absoluto (una declaración por línea)

   REGISTRO DISTINTO AL DEL PANEL Y AL DE LA TIENDA. Aquí el visitante no
   viene a trabajar ni a comprar todavía: viene a decidir si confía. Así que
   manda la escala —tipografía enorme, aire de sobra, una idea por pantalla—
   y todo lo demás se aparta.

   TRES REGLAS DE MOVIMIENTO, tomadas de la misma disciplina que el resto del
   sistema:

   1. TODO ES VISIBLE SIN JAVASCRIPT. Las animaciones de entrada se activan
      añadiendo .con-motion al <html> SOLO cuando GSAP cargó. Si el CDN falla
      o el visitante bloquea scripts, la página se lee entera; nunca queda un
      texto invisible esperando un scroll que ya no va a animarse.

   2. LA ANIMACIÓN ES DE ENTRADA, UNA VEZ. Nada se anima al volver a subir:
      el visitante ya lo vio, repetirlo es ruido.

   3. prefers-reduced-motion APAGA EL DESPLAZAMIENTO, no la página. Se
      conservan opacidad y color, que ayudan a entender; se retira el
      movimiento, que es lo que marea.
   ========================================================================= */

/* =========================================================================
   1. BASE
   ========================================================================= */
.web {
    font-size: 16px;
}

/* El techo es fijo: al saltar a un ancla (#servicio), sin esto el navegador
   deja el inicio de la sección ESCONDIDO debajo de la barra y la cabecera. */
html:has(body.web) {
    scroll-padding-top: 122px;
}

.web-envoltura {
    width: min(1180px, calc(100% - 48px));
    margin: 0 auto;
}

@media (max-width: 640px) {

    .web-envoltura {
        width: calc(100% - 32px);
    }
}

/* Secciones con tema propio: la portada puede alternar claro y oscuro sin
   que ningún componente sepa en cuál está. */
.bloque-web {
    position: relative;
    padding: clamp(72px, 11vw, 132px) 0;
}

.bloque-web--claro {
    background: var(--lienzo);
    color: var(--tinta);
}

.bloque-web--oscuro {
    background: #0B0A0C;
    color: #F5F4F2;
}

.bloque-web--oscuro .suave,
.bloque-web--oscuro .tenue {
    color: rgba(245, 244, 242, .62);
}

.bloque-web--marca {
    background: var(--marca-tinta);
    color: #fff;
}

.bloque-web--marca .suave {
    color: rgba(255, 255, 255, .74);
}

/* =========================================================================
   LOS TÍTULOS DE UN BLOQUE OSCURO VAN EN BLANCO. HAY QUE DECIRLO.

   Poner `color: #fff` en el bloque NO basta: app.css declara
   `h1, h2, h3, h4 { color: var(--tinta) }`, y un selector de elemento le
   gana siempre al color heredado del padre. El resultado era tinta casi
   negra sobre fondo casi negro.

   No se notaba porque el sistema tiene tema oscuro automático: si el
   navegador del visitante prefiere oscuro, --tinta se vuelve clara y todo
   se lee. En un navegador en modo CLARO —la mayoría— cada titular de las
   secciones oscuras de la portada era invisible.
   ========================================================================= */
.bloque-web--oscuro h1,
.bloque-web--oscuro h2,
.bloque-web--oscuro h3,
.bloque-web--oscuro h4,
.bloque-web--marca h1,
.bloque-web--marca h2,
.bloque-web--marca h3,
.bloque-web--marca h4,
.hero h1,
.hero h2 {
    color: #fff;
}

/* =========================================================================
   2. TIPOGRAFÍA GRANDE
   El clamp evita dos hojas de estilo: el mismo titular funciona en un
   teléfono de 360 px y en un monitor de 27 pulgadas.

   Caja baja, peso medio y interletraje apretado: la voz es de producto, no
   de rótulo. La fuerza la da el TAMAÑO y el aire alrededor, no el grosor.
   ========================================================================= */

.titular {
    font-family: var(--fuente-display);
    font-size: clamp(38px, 7.2vw, 88px);
    font-weight: 620;
    letter-spacing: -0.04em;
    line-height: 1.0;
    margin: 0;
    text-wrap: balance;
}

/* Se usa SUELTO, sin la clase .titular al lado (así está en las plantillas),
   así que repite las propiedades en vez de heredarlas. */
.titular--medio {
    font-family: var(--fuente-display);
    font-size: clamp(30px, 4.6vw, 56px);
    font-weight: 620;
    letter-spacing: -0.035em;
    line-height: 1.05;
    margin: 0;
    text-wrap: balance;
}

/* Una palabra del titular en el color de marca. Es el único adorno
   tipográfico que se permite, y por eso funciona. */
.titular em {
    font-style: normal;
    color: var(--marca-acento);
}

/* La misma familia display (Outfit) en el resto de encabezados grandes, para
   que ningún bloque se quede con la tipografía de cuerpo y se vea "mezclado":
   cifras destacadas, pasos del taller, nombres del escaparate y títulos de las
   páginas de contenido. */
.cifra-item__valor,
.riel__titulo,
.escaparate__nombre,
.pagina-texto h1,
.pagina-texto h2,
.franja-garantias__valor {
    font-family: var(--fuente-display);
    letter-spacing: -0.02em;
}

/* =========================================================================
   REVELADO POR LÍNEAS
   Cada renglón sube desde detrás de una máscara.

   ESTAS REGLAS SOLO EXISTEN BAJO .con-motion, y es deliberado: el JS trocea
   el titular en <span> aunque GSAP no haya cargado, y si la máscara
   recortara siempre, un fallo del CDN dejaría los titulares cortados a la
   mitad. Sin motion, los span no hacen nada y el texto se ve entero.

   overflow: clip en vez de hidden — no crea contexto de desplazamiento, así
   que no interfiere con el sticky del escaparate ni con los anclas de la
   página.
   ========================================================================= */
.palabra-medida {
    display: inline-block;
}

.con-motion .linea {
    display: block;
    overflow: clip;

    /* Un pelo de aire abajo: sin él, las descendentes (g, j, p, y) se
       recortan contra el borde de la máscara. */
    padding-bottom: 0.08em;
    margin-bottom: -0.08em;
}

.con-motion .linea__interior {
    display: block;
    will-change: transform;
}

.entradilla {
    font-size: clamp(17px, 1.9vw, 23px);
    line-height: 1.5;
    color: var(--tinta-suave);
    max-width: 56ch;
    margin: 20px 0 0;
    text-wrap: pretty;
}

.bloque-web--oscuro .entradilla {
    color: rgba(245, 244, 242, .68);
}

.bloque-web--marca .entradilla {
    color: rgba(255, 255, 255, .8);
}

/* Antetítulo: la única pieza en versalitas de toda la página. Funciona
   porque es la excepción; si todo fuera mayúsculas no diría nada. */
.etiqueta-seccion {
    display: inline-block;
    font-size: 12.5px;
    font-weight: 650;
    letter-spacing: .12em;
    text-transform: uppercase;
    /* --marca-texto y no --marca-acento: es letra de 12.5px, ver el token. */
    color: var(--marca-texto);
    margin-bottom: 16px;
}

/* Sobre fondo oscuro se aclara el acento: el color pleno de marca sobre
   negro vibra y compite con el titular que viene justo debajo. */
.bloque-web--oscuro .etiqueta-seccion,
.bloque-web--marca .etiqueta-seccion {
    color: color-mix(in srgb, var(--marca-acento) 55%, white);
}

/* =========================================================================
   3. HERO
   ========================================================================= */
.hero {
    position: relative;
    min-height: 92vh;
    min-height: 92dvh;
    display: grid;
    place-items: center;
    overflow: hidden;
    background: #0B0A0C;
    color: #fff;
    text-align: center;
}

.hero__fondo {
    position: absolute;
    inset: 0;
    overflow: hidden;
}

.hero__fondo video,
.hero__fondo img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    /* El fondo se oscurece aquí y no con una capa aparte: una sola pintada
       en lugar de dos, y el texto siempre legible sin importar el video. */
    filter: brightness(.52) saturate(1.05);
}

/* Sin video ni imagen, el degradado de marca. Nunca un hueco negro. */
.hero__fondo--degradado {
    background:
        radial-gradient(1100px 620px at 22% 8%, color-mix(in srgb, var(--marca-acento) 42%, transparent), transparent 62%),
        radial-gradient(900px 500px at 82% 88%, color-mix(in srgb, var(--marca-tinta) 65%, transparent), transparent 60%),
        #0B0A0C;
}

.hero__contenido {
    position: relative;
    z-index: 2;
    padding: 100px 0 80px;
}

.hero .titular {
    color: #fff;
    margin-inline: auto;
    max-width: 18ch;
}

.hero .entradilla {
    color: rgba(255, 255, 255, .82);
    margin-inline: auto;
}

.hero__acciones {
    margin-top: 34px;
    display: flex;
    gap: 12px;
    justify-content: center;
    flex-wrap: wrap;
}

/* El indicador de "desliza" se retiró a propósito: quien está viendo el hero
   sabe lo que es el scroll, y una animación infinita en el borde de la vista
   es ruido permanente. Si el hero invita, el visitante baja solo. */

/* =========================================================================
   4. BOTONES GRANDES
   ========================================================================= */
/* Rectangulares y en caja alta, no píldoras suaves: en un sitio plano de
   alto contraste, una píldora se lee como un botón de app y rompe el tono de
   rótulo de taller que sostiene toda la página. El radio pequeño se queda
   para que no parezca un botón de sistema operativo de los noventa. */
.btn-web {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 9px;
    height: 52px;
    padding: 0 26px;
    border: 1px solid transparent;
    border-radius: var(--radio-completo);
    font-family: inherit;
    font-size: 16px;
    font-weight: 560;
    letter-spacing: -0.01em;
    text-decoration: none;
    cursor: pointer;
    white-space: nowrap;
    transition: transform 180ms var(--salida), background-color 180ms ease, border-color 180ms ease, color 180ms ease;
}

.btn-web:active {
    transform: scale(.975);
}

.btn-web:hover {
    text-decoration: none;
}

/* El teclado también navega. focus-visible y no focus a secas: el anillo
   solo aparece al llegar con Tab, nunca tras un clic de ratón. */
.btn-web:focus-visible {
    outline: 2px solid var(--marca-acento);
    outline-offset: 3px;
}

/* Sobre el fondo oscuro del hero, un anillo del color del fondo no se ve:
   ahí el anillo va blanco. */
.hero .btn-web:focus-visible,
.bloque-web--oscuro .btn-web:focus-visible,
.bloque-web--marca .btn-web:focus-visible {
    outline-color: #fff;
}

.btn-web--principal {
    background: var(--marca-acento);
    color: var(--marca-acento-encima);
}

@media (hover: hover) and (pointer: fine) {

    .btn-web--principal:hover {
        background: color-mix(in srgb, var(--marca-acento) 86%, #fff);
    }
}

/* Sin cristal esmerilado: el desenfoque de fondo pertenece a una interfaz
   de sistema, no a un rótulo. Contorno blanco sólido y ya. */
.btn-web--contorno {
    border-color: rgba(255, 255, 255, .35);
    color: #fff;
    background: rgba(255, 255, 255, .06);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
}

@media (hover: hover) and (pointer: fine) {

    .btn-web--contorno:hover {
        background: rgba(255, 255, 255, .14);
        border-color: rgba(255, 255, 255, .55);
    }
}

/* Lift sutil al pasar el cursor (Emil: un botón debe sentirse vivo). El
   :active se vuelve a declarar AQUÍ, después del hover, para que la pulsación
   gane sobre el lift y el hundido se sienta al presionar. */
@media (hover: hover) and (pointer: fine) {

    .btn-web:hover {
        transform: translateY(-1px);
    }

    .btn-web:active {
        transform: scale(.975);
    }
}

.btn-web--tinta {
    border-color: var(--borde-fuerte);
    color: var(--tinta);
    background: var(--superficie);
}

@media (hover: hover) and (pointer: fine) {

    .btn-web--tinta:hover {
        background: var(--superficie-hundida);
    }
}

/* =========================================================================
   5. SPOTLIGHT — imagen a un lado, texto al otro
   ========================================================================= */
.spotlight {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: clamp(32px, 6vw, 84px);
    align-items: center;
}

.spotlight--derecha .spotlight__medio {
    order: 2;
}

@media (max-width: 860px) {

    .spotlight {
        grid-template-columns: 1fr;
        gap: 28px;
    }

    .spotlight--derecha .spotlight__medio {
        order: 0;
    }
}

.spotlight__medio {
    position: relative;
    aspect-ratio: 4 / 3;
    border-radius: clamp(16px, 2vw, 26px);
    overflow: hidden;
    background: var(--superficie-hundida);
    display: grid;
    place-items: center;
}

.spotlight__medio img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform 700ms var(--salida);
}

@media (hover: hover) and (pointer: fine) {

    .spotlight__medio:hover img {
        transform: scale(1.04);
    }
}

.spotlight__vacio {
    color: var(--tinta-tenue);
    text-align: center;
    padding: 30px;
}

.spotlight__texto .titular--medio {
    margin-bottom: 4px;
}

.spotlight__acciones {
    margin-top: 26px;
    display: flex;
    gap: 10px;
    flex-wrap: wrap;
}

/* =========================================================================
   6. CIFRAS
   ========================================================================= */
/* Franja de cifras / garantías.
   Separadas por una línea vertical en lugar de por aire: en un diseño plano,
   la regla dibujada es lo que agrupa. Con aire nada más, las tres cifras se
   leen como tres párrafos sueltos. */
.cifras {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 0;
    text-align: center;
}

.cifras > * {
    padding: 8px clamp(16px, 3vw, 40px);
    border-left: 1px solid var(--borde);
}

.cifras > *:first-child {
    border-left: 0;
}

.bloque-web--oscuro .cifras > *,
.bloque-web--marca .cifras > * {
    border-left-color: rgba(255, 255, 255, .18);
}

@media (max-width: 640px) {

    /* Apiladas, la raya vertical no separa nada: pasa a horizontal. */
    .cifras > * {
        border-left: 0;
        border-top: 1px solid var(--borde);
        padding: 20px 0;
    }

    .cifras > *:first-child {
        border-top: 0;
    }
}

.cifra-item__valor {
    font-size: clamp(40px, 6vw, 72px);
    font-weight: 690;
    letter-spacing: -0.05em;
    line-height: 1;
    font-variant-numeric: tabular-nums;
}

.cifra-item__etiqueta {
    margin-top: 10px;
    font-size: 14.5px;
    color: var(--tinta-suave);
    letter-spacing: -0.005em;
}

.bloque-web--oscuro .cifra-item__etiqueta {
    color: rgba(245, 244, 242, .6);
}

/* =========================================================================
   7. GALERÍA + LIGHTBOX
   ========================================================================= */
.galeria-web {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
    gap: 14px;
    margin-top: 40px;
}

.galeria-web__foto {
    position: relative;
    aspect-ratio: 1;
    border-radius: var(--radio-lg);
    overflow: hidden;
    border: 0;
    padding: 0;
    background: var(--superficie-hundida);
    cursor: zoom-in;
    transition: transform 300ms var(--salida);
}

.galeria-web__foto img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform 600ms var(--salida);
}

@media (hover: hover) and (pointer: fine) {

    .galeria-web__foto:hover {
        transform: translateY(-3px);
    }

    .galeria-web__foto:hover img {
        transform: scale(1.06);
    }
}

.lightbox {
    position: fixed;
    inset: 0;
    z-index: 90;
    display: grid;
    place-items: center;
    padding: 28px;
    background: rgba(6, 5, 7, .93);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    opacity: 1;
    transition: opacity 240ms var(--salida);
}

.lightbox[hidden] {
    display: grid;
    opacity: 0;
    pointer-events: none;
}

.lightbox img {
    max-width: 100%;
    max-height: 86vh;
    border-radius: var(--radio-lg);
    transform: scale(1);
    transition: transform 240ms var(--salida);
}

.lightbox[hidden] img {
    transform: scale(.97);
}

.lightbox__cerrar {
    position: absolute;
    top: 20px;
    right: 20px;
    width: 44px;
    height: 44px;
    display: grid;
    place-items: center;
    border: 0;
    border-radius: 50%;
    background: rgba(255, 255, 255, .12);
    color: #fff;
    cursor: pointer;
    transition: background-color 160ms ease, transform 160ms var(--salida);
}

.lightbox__cerrar:active {
    transform: scale(.92);
}

/* Tras la media query: en un táctil, el navegador dispara :hover al tocar y
   el botón se queda iluminado después de soltarlo, como si siguiera activo. */
@media (hover: hover) and (pointer: fine) {

    .lightbox__cerrar:hover {
        background: rgba(255, 255, 255, .22);
    }
}

.lightbox__pie {
    position: absolute;
    bottom: 24px;
    left: 0;
    right: 0;
    text-align: center;
    color: rgba(255, 255, 255, .7);
    font-size: 14px;
}

/* =========================================================================
   8. PRODUCTOS DESTACADOS EN LA PORTADA
   ========================================================================= */
.destacados-web {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(228px, 1fr));
    gap: 18px;
    margin-top: 44px;
}


/* =========================================================================
   8 ter. RIEL DEL TALLER
   Los pasos avanzan en horizontal mientras se desplaza en vertical.

   COMO EN EL ESCAPARATE, PRIMERO SE DEFINE LA FORMA SIN JAVASCRIPT: una
   lista vertical numerada, completa y legible. El riel se monta encima solo
   bajo .con-motion.
   ========================================================================= */
/* SIN overflow: hidden AQUÍ. Un ancestro con overflow oculto crea un
   contenedor de desplazamiento y ANULA el position: sticky de la escena de
   adentro: se queda quieta y todo el bloque pasa de largo. El recorte del
   carro se hace en la propia escena, que sí puede. */
.riel {
    position: relative;
    padding: clamp(72px, 11vw, 132px) 0;
}

.riel.bloque-web--claro {
    background: var(--lienzo);
    color: var(--tinta);
}

.riel.bloque-web--oscuro {
    background: #0B0A0C;
    color: #F5F4F2;
}

.riel.bloque-web--marca {
    background: var(--marca-tinta);
    color: #fff;
}

.riel__cabeza {
    text-align: center;
    margin-bottom: clamp(36px, 5vw, 60px);
}

.riel__cabeza .entradilla {
    margin-inline: auto;
}

.riel__carro {
    list-style: none;
    margin: 0;
    padding: 0;
    width: min(1180px, calc(100% - 48px));
    margin-inline: auto;
    display: grid;
    gap: 20px;
}

.riel__paso {
    position: relative;
    padding: 28px 26px 30px;
    border-radius: var(--radio-lg);
    background: var(--superficie);
    border: 1px solid var(--borde);
}

.riel.bloque-web--oscuro .riel__paso,
.riel.bloque-web--marca .riel__paso {
    background: rgba(255, 255, 255, .05);
    border-color: rgba(255, 255, 255, .12);
}

.riel__numero {
    display: block;
    font-size: 13px;
    font-weight: 700;
    letter-spacing: .14em;
    color: var(--marca-texto);   /* letra pequeña: ver el token */
    font-variant-numeric: tabular-nums;
    margin-bottom: 14px;
}

.riel__titulo {
    font-size: clamp(20px, 2.2vw, 26px);
    font-weight: 660;
    letter-spacing: -0.025em;
    line-height: 1.15;
    margin: 0;
}

.riel__texto {
    margin: 12px 0 0;
    font-size: 15.5px;
    line-height: 1.55;
    color: var(--tinta-suave);
}

.riel.bloque-web--oscuro .riel__texto,
.riel.bloque-web--marca .riel__texto {
    color: rgba(245, 244, 242, .68);
}

/* La foto del paso: debajo del texto, al ancho de la tarjeta y con una
   proporción FIJA.

   Lo importante es la proporción. Las fotos las sube quien administra, cada
   una con el recorte que traiga el teléfono, y sin fijarla los pasos quedarían
   de alturas distintas —una vertical de 3000 px junto a una apaisada— y el
   riel dejaría de leerse como una secuencia para parecer una lista rota.
   object-fit recorta lo que sobra en lugar de deformar a nadie. */
.riel__foto {
    display: block;
    width: 100%;
    aspect-ratio: 4 / 3;
    object-fit: cover;
    margin-top: 18px;
    border-radius: var(--radio);
    background: var(--superficie-hundida);
}

.riel.bloque-web--oscuro .riel__foto,
.riel.bloque-web--marca .riel__foto {
    background: rgba(255, 255, 255, .06);
}

/* Caben dos botones (agendar + ver servicios) y en pantalla estrecha se
   apilan sin quedar pegados. */
.riel__pie {
    display: flex;
    justify-content: center;
    align-items: center;
    flex-wrap: wrap;
    gap: 12px;
    text-align: center;
    margin-top: clamp(32px, 4.5vw, 52px);
}


/* --- El riel en movimiento -------------------------------------------
   La escena se pega y el carro se desliza en horizontal. El recorrido
   vertical de la pista se traduce a desplazamiento lateral del carro. */
.con-motion .riel {
    padding: 0;
}

.con-motion .riel__escena {
    position: sticky;
    top: 0;
    min-height: 100vh;
    min-height: 100dvh;
    display: flex;
    flex-direction: column;
    justify-content: center;
    padding: 92px 0 60px;
    overflow: hidden;
}

.con-motion .riel__carro {
    width: auto;
    margin-inline: 0;
    display: flex;
    gap: 22px;

    /* El primer paso arranca alineado con el texto de la cabecera, no
       pegado al borde de la ventana: si empezara en cero, se leería como
       un elemento cortado y no como el comienzo de una secuencia. */
    padding-inline: max(24px, calc((100vw - 1180px) / 2));
    will-change: transform;
}

.con-motion .riel__paso {
    flex: 0 0 clamp(260px, 27vw, 340px);
}

.con-motion .riel__pie {
    margin-top: clamp(24px, 3vw, 36px);
}

/* En pantalla angosta o baja, el riel horizontal no cabe: se comprimirían
   las tarjetas hasta dejar dos palabras por renglón. Vuelve a ser lista, y
   además se puede arrastrar con el dedo, que es el gesto natural ahí. */
@media (max-width: 860px), (max-height: 620px) {

    .con-motion .riel {
        padding: clamp(72px, 11vw, 132px) 0;
    }

    .con-motion .riel__escena {
        position: static;
        min-height: 0;
        padding: 0;
        overflow: visible;
    }

    .con-motion .riel__carro {
        display: grid;
        width: min(1180px, calc(100% - 48px));
        margin-inline: auto;
        padding-inline: 0;
        transform: none !important;
    }

    .con-motion .riel__paso {
        flex: initial;
    }
}


/* =========================================================================
   8 bis. ESCAPARATE DE PRODUCTO
   Cada destacado toma la pantalla completa mientras se desplaza.

   EL ORDEN DE ESTE BLOQUE IMPORTA: primero se define cómo se ve SIN
   JavaScript —una lista vertical de fichas, completa y legible— y solo
   después, bajo .con-motion, se convierte en escena fijada. Escrito al
   revés, un fallo del CDN dejaría cuatro productos superpuestos encima del
   mismo punto, ilegibles.
   ========================================================================= */
.escaparate {
    position: relative;
    padding: clamp(72px, 11vw, 132px) 0;
}

.escaparate.bloque-web--claro {
    background: var(--lienzo);
    color: var(--tinta);
}

.escaparate.bloque-web--oscuro {
    background: #0B0A0C;
    color: #F5F4F2;
}

.escaparate.bloque-web--marca {
    background: var(--marca-tinta);
    color: #fff;
}

.escaparate__cabeza {
    text-align: center;
    margin-bottom: clamp(36px, 5vw, 64px);
}

.escaparate__lienzo {
    display: grid;
    gap: clamp(48px, 7vw, 96px);
}

/* --- La ficha, en su forma de reposo (sin motion) --------------------- */
.escaparate__pieza {
    width: min(1180px, calc(100% - 48px));
    margin: 0 auto;
    display: grid;
    grid-template-columns: minmax(0, 1.08fr) minmax(0, 1fr);
    align-items: center;
    gap: clamp(28px, 5vw, 72px);
    /* La perspectiva vive en el contenedor para que el tilt 3D del medio se
       vea con profundidad real, no como una lámina que gira plana. */
    perspective: 1300px;
}

@media (max-width: 860px) {

    .escaparate__pieza {
        grid-template-columns: 1fr;
        gap: 24px;
    }
}

.escaparate__medio {
    position: relative;
    border-radius: var(--radio-lg);
    overflow: hidden;
    background: var(--superficie-hundida);
    aspect-ratio: 4 / 3;
    /* Reposo neutro. El JS actualiza --rx/--ry con el cursor; sin JS o con
       reduced-motion, quedan en 0 y la ficha está perfectamente plana. */
    --rx: 0deg;
    --ry: 0deg;
    transform: perspective(1300px) rotateX(var(--rx)) rotateY(var(--ry));
    transform-style: preserve-3d;
    transition: transform 140ms var(--salida), box-shadow 300ms var(--salida);
}

/* La luz de acento que sigue al cursor por encima de la imagen. Es un solo
   pseudo-elemento con mezcla suave; --mx/--my los mueve el JS. */
.escaparate__medio::after {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: inherit;
    background: radial-gradient(260px 260px at var(--mx, 50%) var(--my, 40%),
        color-mix(in srgb, var(--marca-acento) 30%, transparent), transparent 60%);
    opacity: 0;
    transition: opacity 300ms var(--salida);
    pointer-events: none;
    z-index: 2;
    mix-blend-mode: screen;
}

@media (hover: hover) and (pointer: fine) {

    .escaparate__medio.es-tilt {
        box-shadow: 0 40px 80px -40px rgba(0, 0, 0, .55);
    }

    .escaparate__medio.es-tilt::after {
        opacity: 1;
    }
}

@media (prefers-reduced-motion: reduce) {

    .escaparate__medio {
        transform: none;
        transition: none;
    }

    .escaparate__medio::after {
        display: none;
    }
}

.escaparate__medio img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.escaparate__sin-imagen {
    width: 100%;
    height: 100%;
    background:
        radial-gradient(420px 300px at 30% 20%, color-mix(in srgb, var(--marca-acento) 16%, transparent), transparent 70%),
        var(--superficie-hundida);
}

.escaparate__categoria {
    display: inline-block;
    font-size: 12.5px;
    font-weight: 650;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--marca-texto);   /* letra pequeña: ver el token */
    margin-bottom: 14px;
}

.escaparate__nombre {
    font-size: clamp(26px, 3.4vw, 42px);
    font-weight: 680;
    letter-spacing: -0.035em;
    line-height: 1.08;
    margin: 0;
    text-wrap: balance;
}

.escaparate__texto {
    margin: 16px 0 0;
    font-size: 16.5px;
    line-height: 1.55;
    color: var(--tinta-suave);
    max-width: 46ch;
}

.escaparate.bloque-web--oscuro .escaparate__texto,
.escaparate.bloque-web--marca .escaparate__texto {
    color: rgba(245, 244, 242, .7);
}

.escaparate__precio {
    display: flex;
    align-items: baseline;
    gap: 12px;
    margin-top: 24px;
}

.escaparate__precio-valor {
    font-size: clamp(26px, 3vw, 36px);
    font-weight: 660;
    letter-spacing: -0.035em;
    font-variant-numeric: tabular-nums;
}

/* El precio de mostrador tachado solo aparece si de verdad es mayor: un
   "antes" inventado es la práctica más barata que existe. */
.escaparate__precio-lista {
    font-size: 17px;
    color: var(--tinta-tenue);
    text-decoration: line-through;
    font-variant-numeric: tabular-nums;
}

.escaparate__existencia {
    display: flex;
    align-items: center;
    gap: 9px;
    margin: 12px 0 0;
    font-size: 14px;
    color: var(--tinta-suave);
}

.escaparate__punto {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--exito);
    flex-shrink: 0;
}

.escaparate__existencia--agotado .escaparate__punto {
    background: var(--tinta-tenue);
}

.escaparate__acciones {
    margin-top: 28px;
    display: flex;
    gap: 12px;
    flex-wrap: wrap;
}

.escaparate__pie {
    text-align: center;
    margin-top: clamp(40px, 6vw, 72px);
}

/* --- Puntos de navegación --------------------------------------------
   Sin motion no sirven de nada (la página ya está entera a la vista), así
   que se esconden. Aparecen solo cuando la escena se fija. */
.escaparate__puntos {
    display: none;
}

.escaparate__punto-nav {
    width: 9px;
    height: 9px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: currentColor;
    opacity: .26;
    cursor: pointer;
    transition: opacity 260ms var(--salida), transform 260ms var(--salida);
}

.escaparate__punto-nav[aria-current="true"] {
    opacity: 1;
    transform: scale(1.45);
}

.escaparate__punto-nav:focus-visible {
    outline: 2px solid var(--marca-acento);
    outline-offset: 4px;
}


/* =========================================================================
   ESCAPARATE EN MOVIMIENTO
   Solo con GSAP cargado. La pista se hace alta, la escena se pega arriba y
   las piezas se apilan en el mismo sitio para que el JS las cruce.
   ========================================================================= */
.con-motion .escaparate {
    padding: 0;
}

.con-motion .escaparate__escena {
    position: sticky;
    top: 0;
    min-height: 100vh;
    min-height: 100dvh;
    display: flex;
    flex-direction: column;
    justify-content: center;
    padding: 96px 0 64px;
    overflow: hidden;
}

.con-motion .escaparate__cabeza {
    margin-bottom: clamp(20px, 3vw, 40px);
}

.con-motion .escaparate__lienzo {
    position: relative;
    display: block;
}

/* Todas las piezas ocupan el MISMO hueco. La primera se queda en el flujo
   para que sea ella quien le dé altura al contenedor; las demás se
   superponen encima. */
.con-motion .escaparate__pieza {
    opacity: 0;
}

.con-motion .escaparate__pieza + .escaparate__pieza {
    position: absolute;
    inset: 0;
}

.con-motion .escaparate__pieza[data-activa="true"] {
    opacity: 1;
}

.con-motion .escaparate__puntos {
    display: flex;
    justify-content: center;
    gap: 12px;
    margin-top: clamp(24px, 3.5vw, 40px);
}

.con-motion .escaparate__pie {
    margin-top: clamp(20px, 3vw, 32px);
}

/* En pantallas angostas o bajas la escena fijada no cabe: obligaría a
   comprimir la ficha hasta hacerla ilegible. Ahí vuelve a ser lista. */
@media (max-width: 860px), (max-height: 620px) {

    .con-motion .escaparate {
        padding: clamp(72px, 11vw, 132px) 0;
    }

    .con-motion .escaparate__escena {
        position: static;
        min-height: 0;
        padding: 0;
        overflow: visible;
    }

    .con-motion .escaparate__lienzo {
        display: grid;
    }

    .con-motion .escaparate__pieza,
    .con-motion .escaparate__pieza + .escaparate__pieza {
        position: static;
        inset: auto;
        opacity: 1;
    }

    .con-motion .escaparate__puntos {
        display: none;
    }
}

/* =========================================================================
   9. BOLETÍN
   ========================================================================= */
.boletin {
    display: flex;
    gap: 10px;
    max-width: 470px;
    margin-top: 24px;
    flex-wrap: wrap;
}

.boletin input {
    flex: 1;
    min-width: 210px;
    height: 52px;
    padding: 0 18px;
    border: 1px solid var(--borde);
    border-radius: var(--radio-completo);
    background: var(--superficie);
    color: var(--tinta);
    font-family: inherit;
    font-size: 15.5px;
    transition: border-color 160ms ease, box-shadow 160ms ease;
}

.boletin input:focus {
    outline: none;
    border-color: var(--marca-acento);
    box-shadow: var(--anillo);
}

.bloque-web--marca .boletin input,
.bloque-web--oscuro .boletin input {
    background: rgba(255, 255, 255, .1);
    border-color: rgba(255, 255, 255, .28);
    color: #fff;
}

.bloque-web--marca .boletin input::placeholder,
.bloque-web--oscuro .boletin input::placeholder {
    color: rgba(255, 255, 255, .55);
}

/* =========================================================================
   10. CABECERA TRANSPARENTE SOBRE EL HERO
   Empieza invisible encima del video y se vuelve sólida al bajar. Sin ese
   cambio, el logotipo blanco desaparecería sobre el fondo claro.
   ========================================================================= */
.cabecera-web {
    position: relative;
    transition: background-color 320ms ease, border-color 320ms ease, backdrop-filter 320ms ease;
    border-bottom: 1px solid transparent;
}

.cabecera-web[data-solida="true"] {
    background: color-mix(in srgb, var(--superficie) 86%, transparent);
    backdrop-filter: saturate(180%) blur(14px);
    -webkit-backdrop-filter: saturate(180%) blur(14px);
    border-bottom-color: var(--borde);
}

.cabecera-web .cabecera__fila {
    height: 68px;
}

.cabecera-web .cabecera__logo,
.cabecera-web .cabecera__enlace {
    color: #fff;
    text-shadow: 0 1px 12px rgba(0, 0, 0, .3);
}

.cabecera-web[data-solida="true"] .cabecera__logo {
    color: var(--tinta);
    text-shadow: none;
}

.cabecera-web[data-solida="true"] .cabecera__enlace {
    color: var(--tinta-suave);
    text-shadow: none;
}



/* =========================================================================
   10 bis. BARRA DE ANUNCIO
   La franja de arriba del todo, del color de marca, con una sola frase.

   POR QUÉ ES UN SOLO MENSAJE Y NO UN CARRUSEL: un carrusel de promesas se
   convierte en ruido que nadie lee y, peor, obliga a esperar a que pase la
   que interesaba. Una frase fija se lee de un golpe.

   Es ESTÁTICA a propósito. La marquesina que se desliza sin parar es
   movimiento permanente en el borde del campo visual: molesta al leer y
   choca de frente con prefers-reduced-motion.
   ========================================================================= */
/* El contenedor fijo de TODO lo de arriba: anuncio + cabecera. Al ser una
   sola pieza no puede abrirse una ranura entre las dos, que era justo lo que
   pasaba cuando la cabecera iba fija por su cuenta con top: 37px. */
.techo-web {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 60;
}

.barra-anuncio {
    background: var(--marca-acento);
    color: var(--marca-acento-encima);
    font-size: 13.5px;
    font-weight: 560;
    letter-spacing: -0.005em;
    text-align: center;
    padding: 10px 16px;
    line-height: 1.35;
}

.barra-anuncio a {
    color: inherit;
    text-decoration: underline;
    text-underline-offset: 3px;
}

/* La barra NO se pliega al bajar. Se intentó (al estilo del listón de las
   tiendas grandes) y en la práctica el texto se deslizaba por debajo de la
   cabecera en cada cruce del umbral: se leía como un empalme. Una franja de
   37px fija no puede romperse, y la promoción se ve siempre. */


/* =========================================================================
   10 ter. FRANJA DE GARANTÍAS
   Tres o cuatro promesas cortas debajo del hero: envío, garantía, taller.
   Es lo primero que pregunta quien va a gastar veinte mil pesos en línea.
   ========================================================================= */
.franja-garantias {
    background: var(--superficie-hundida);
    color: var(--tinta);
    border-bottom: 1px solid var(--borde);
    padding: clamp(18px, 2.6vw, 30px) 0;
}

/* Bento asimétrico: la primera celda pesa más (1.6fr) y las otras dos van a
   1fr. No son tres columnas iguales — tienen ritmo, y la destacada rompe la
   monotonía con un degradado de marca. */
.franja-garantias__lista {
    display: grid;
    grid-template-columns: 1.6fr 1fr 1fr;
    gap: 12px;
}

.franja-garantias__item {
    display: flex;
    flex-direction: column;
    gap: 16px;
    padding: clamp(20px, 2.1vw, 28px);
    background: var(--superficie);
    border: 1px solid var(--borde);
    border-radius: var(--radio-lg);
    transition: transform 240ms var(--salida), box-shadow 240ms var(--salida);
}

/* Celda destacada: más presencia con un lavado del color de marca en la
   esquina, sin gritar. Es la única variación de fondo del bento, y por eso
   funciona. */
.franja-garantias__item--destacado {
    background:
        radial-gradient(130% 150% at 0% 0%, color-mix(in srgb, var(--marca-acento) 20%, transparent), transparent 58%),
        var(--superficie);
    border-color: color-mix(in srgb, var(--marca-acento) 32%, var(--borde));
}

.franja-garantias__item--destacado .franja-garantias__icono {
    width: 40px;
    height: 40px;
}

@media (hover: hover) and (pointer: fine) {

    .franja-garantias__item:hover {
        transform: translateY(-3px);
        box-shadow: 0 14px 34px -18px color-mix(in srgb, var(--marca-acento) 40%, rgba(0, 0, 0, .3));
    }
}

/* En pantallas angostas el bento se apila; la destacada queda arriba. */
@media (max-width: 760px) {

    .franja-garantias__lista {
        grid-template-columns: 1fr;
    }
}

.franja-garantias__icono {
    width: 34px;
    height: 34px;
    flex-shrink: 0;
    color: var(--marca-acento);
}

.franja-garantias__icono svg {
    width: 100%;
    height: 100%;
}

/* =========================================================================
   ICONOS QUE SE DIBUJAN

   El contorno se pinta como una línea discontinua tan larga como el propio
   trazo, con el hueco corrido al principio: no se ve nada. Al entrar en
   pantalla, el hueco se lleva a cero y el trazo aparece dibujándose.

   Los trazos vienen del servidor con pathLength="1", así que TODOS miden lo
   mismo a efectos de la animación. Sin eso habría que medir cada uno con
   getTotalLength() desde JavaScript, y el candado tardaría el triple que la
   caja en dibujarse.

   Vive bajo .con-motion: si GSAP no cargó, nadie va a poner el atributo que
   dispara el trazado y los iconos se quedarían invisibles para siempre.
   ========================================================================= */
.con-motion .franja-garantias__icono svg :is(path, circle, rect) {
    stroke-dasharray: 1;
    stroke-dashoffset: 1;
    transition: stroke-dashoffset 900ms var(--salida);
}

.con-motion .franja-garantias[data-trazando="true"] .franja-garantias__icono svg :is(path, circle, rect) {
    stroke-dashoffset: 0;
}

/* Escalonado entre los tres iconos: se leen de izquierda a derecha, como
   una frase, en lugar de dibujarse los tres encima. */
.con-motion .franja-garantias__item:nth-child(2) .franja-garantias__icono svg :is(path, circle, rect) {
    transition-delay: 90ms;
}

.con-motion .franja-garantias__item:nth-child(3) .franja-garantias__icono svg :is(path, circle, rect) {
    transition-delay: 180ms;
}

.con-motion .franja-garantias__item:nth-child(n+4) .franja-garantias__icono svg :is(path, circle, rect) {
    transition-delay: 270ms;
}

/* Movimiento reducido: el icono aparece, pero sin dibujarse. Se conserva
   la información, se retira el recorrido. */
@media (prefers-reduced-motion: reduce) {

    .con-motion .franja-garantias__icono svg :is(path, circle, rect) {
        stroke-dasharray: none;
        stroke-dashoffset: 0;
        transition: none;
    }
}

.franja-garantias__titulo {
    font-size: 15px;
    font-weight: 600;
    letter-spacing: -0.015em;
    line-height: 1.3;
}

.franja-garantias__nota {
    margin-top: 3px;
    font-size: 13.5px;
    color: var(--tinta-suave);
    line-height: 1.45;
}

/* =========================================================================
   11. PÁGINAS DE TEXTO (legales)
   ========================================================================= */
.pagina-texto {
    max-width: 72ch;
    margin: 0 auto;
    padding: clamp(48px, 8vw, 90px) 0;
}

.pagina-texto h1 {
    font-size: clamp(30px, 4.4vw, 46px);
    font-weight: 660;
    letter-spacing: -0.035em;
    line-height: 1.08;
    margin-bottom: 10px;
}

.pagina-texto__cuerpo {
    margin-top: 30px;
    font-size: 17px;
    line-height: 1.75;
    color: var(--tinta-suave);
    white-space: pre-line;
}

/* =========================================================================
   12. ANIMACIÓN DE ENTRADA
   Solo se aplica cuando GSAP cargó (.con-motion en el <html>). Sin él, todo
   se ve desde el primer momento: nunca hay contenido invisible atrapado.
   ========================================================================= */
.con-motion .revelar {
    opacity: 0;
    transform: translateY(26px);
    filter: blur(8px);
}

.con-motion .revelar-escala {
    opacity: 0;
    transform: scale(.97);
    filter: blur(8px);
}

@media (prefers-reduced-motion: reduce) {

    .con-motion .revelar,
    .con-motion .revelar-escala {
        opacity: 1;
        transform: none;
        filter: none;
    }

    .spotlight__medio:hover img,
    .galeria-web__foto:hover,
    .galeria-web__foto:hover img {
        transform: none;
    }
}

/* =========================================================================
   13. IMPRESIÓN
   ========================================================================= */
@media print {

    .techo-web,
    .boletin,
    .lightbox {
        display: none !important;
    }

    .bloque-web {
        padding: 20px 0;
        background: #fff !important;
        color: #000 !important;
    }
}


/* =========================================================================
   SECCIÓN DE VIDEO (constructor web)
   Contenedor 16:9 responsivo que acepta iframe (YouTube/Vimeo) o <video>.
   ========================================================================= */
.bloque-web--video .web-envoltura {
    max-width: 1000px;
}

.video-web {
    position: relative;
    aspect-ratio: 16 / 9;
    margin-top: 34px;
    border-radius: 18px;
    overflow: hidden;
    background: #000;
    box-shadow: 0 30px 60px -30px rgba(0, 0, 0, 0.5);
}

.video-web iframe,
.video-web video,
.video-web img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
}


/* =========================================================================
   ANIMACIONES DE ENTRADA POR SECCIÓN (data-animar)
   Solo se esconden si el observador está activo (html.web-anim-on): sin JS,
   todo se ve. El .es-visible lo pone el observador al entrar en pantalla.
   ========================================================================= */
.web-anim-on [data-animar] {
    opacity: 0;
    transition: opacity 0.7s cubic-bezier(0.23, 1, 0.32, 1),
                transform 0.7s cubic-bezier(0.23, 1, 0.32, 1),
                clip-path 0.85s cubic-bezier(0.23, 1, 0.32, 1);
    will-change: opacity, transform;
}

.web-anim-on [data-animar="subir"] {
    transform: translateY(42px);
}

.web-anim-on [data-animar="acercar"] {
    transform: scale(0.94);
}

.web-anim-on [data-animar="cortina"] {
    clip-path: inset(0 0 100% 0);
}

.web-anim-on [data-animar].es-visible {
    opacity: 1;
    transform: none;
    clip-path: inset(0 0 0 0);
}

@media (prefers-reduced-motion: reduce) {

    .web-anim-on [data-animar] {
        opacity: 1 !important;
        transform: none !important;
        clip-path: none !important;
        transition: none;
    }
}

/* =========================================================================
   14. MUNDO DJI LUMINOSO — capa de conversión de la landing
   Sistema Integral de Gestión Comercial · Jabc SoftWorks

   FORMATO: Expandido absoluto (una declaración por línea)

   La portada nació cinemática y oscura (héroe negro, secciones #0B0A0C). El
   cliente pidió el lenguaje de la tienda de DJI México: BLANCO luminoso, mucho
   aire, el producto flotando entero sobre luz. En vez de reescribir cada
   plantilla, esta capa final CONVIERTE la oscuridad en luz:

   · Los temas de sección que el editor marcó como "oscuro" se remapean a una
     BANDA HUMO clara. Así la alternancia claro/oscuro que ya existía se vuelve
     la alternancia blanco/humo de DJI, sin tocar el panel ni la base de datos.
   · El héroe se aclara y se ciñe: menos muro negro, más banner luminoso.
   · El producto del escaparate pasa a `contain` sobre azulejo de luz: la bici
     se ve ENTERA flotando, el gesto central de DJI.

   El acento sigue siendo el naranja de la tienda. Se toma la estructura de DJI,
   no su azul. La banda humo es consciente del tema: si el visitante fuerza el
   oscuro, se adapta en vez de quedar como una losa blanca sobre negro.
   ========================================================================= */

:root {
    --dji-banda: #f7f7f8;
    --dji-tinta-producto: #fbfbfc;
    --dji-sombra: 0 1px 2px rgba(24, 20, 16, .05), 0 8px 24px -12px rgba(24, 20, 16, .14);
    --dji-sombra-fuerte: 0 2px 6px rgba(24, 20, 16, .06), 0 24px 48px -20px rgba(24, 20, 16, .22);

    /* =====================================================================
       EL ACENTO DE MARCA, PERO PARA TEXTO PEQUEÑO

       El naranja de la marca funciona de maravilla en botones y fondos, donde
       lo que importa es que se vea. Como TEXTO chiquito no llega al mínimo
       de contraste: medido sobre los fondos reales del sitio da 3.90:1 en
       claro y 3.64:1 en oscuro, y el mínimo son 4.5:1. Se lee "más o menos",
       que en la práctica quiere decir que quien tiene la vista cansada no lo
       lee.

       No se toca --marca-acento: ahí sigue el color de la marca tal cual,
       para botones, iconos y bordes. Este token es SOLO para letra pequeña,
       y se ajusta al modo. Medido contra el fondo MÁS DESFAVORABLE de cada
       uno (la banda humo, que es el que menos contrasta):

         · en claro  se oscurece un poco  → 4.85:1  (antes 3.90)
         · en oscuro se aclara un poco    → 4.82:1  (antes 3.64)

       Se hace con color-mix sobre --marca-acento y no con un hexadecimal
       quemado a propósito: el color viene de la configuración de la empresa,
       así que si mañana la marca cambia de color, esto lo sigue solo.
       ===================================================================== */
}


@media (prefers-color-scheme: dark) {

    :root:not([data-tema="claro"]) {
        --dji-banda: color-mix(in srgb, var(--superficie) 78%, #fff 4%);
        --dji-tinta-producto: #f2f2f4;
        --dji-sombra: 0 1px 2px rgba(0, 0, 0, .4), 0 10px 28px -14px rgba(0, 0, 0, .7);
        --dji-sombra-fuerte: 0 2px 8px rgba(0, 0, 0, .45), 0 28px 52px -22px rgba(0, 0, 0, .8);
    }
}

:root[data-tema="oscuro"] {
    --dji-banda: color-mix(in srgb, var(--superficie) 78%, #fff 4%);
    --dji-tinta-producto: #f2f2f4;
    --dji-sombra: 0 1px 2px rgba(0, 0, 0, .4), 0 10px 28px -14px rgba(0, 0, 0, .7);
    --dji-sombra-fuerte: 0 2px 8px rgba(0, 0, 0, .45), 0 28px 52px -22px rgba(0, 0, 0, .8);
}


/* --- Héroe luminoso -----------------------------------------------------
   Se aclara el oscurecido del fondo (de .52 a .66) y se ciñe la altura, para
   que se lea como un banner de vida real y no como un muro cinematográfico.
   El texto conserva blanco con una sombra de apoyo: sobre la parte clara de
   una foto seguiría siendo legible sin volver a apagar la imagen.            */
.hero {
    min-height: 82vh;
    min-height: 82dvh;
}

.hero__fondo video,
.hero__fondo img {
    filter: brightness(.66) saturate(1.06);
}

.hero .titular,
.hero .entradilla {
    text-shadow: 0 1px 20px rgba(0, 0, 0, .35);
}

/* --- Botón principal con sombra suave DJI -------------------------------- */
.btn-web--principal {
    box-shadow: 0 1px 2px rgba(24, 20, 16, .12), 0 8px 20px -10px color-mix(in srgb, var(--marca-acento) 55%, transparent);
}

/* --- Temas de sección: la oscuridad se vuelve luz -----------------------
   El editor pudo marcar bloques como "oscuro"; en el mundo DJI eso pasa a ser
   la banda humo. El texto vuelve a tinta normal (blanco sobre humo sería
   invisible) y todos los ajustes que asumían fondo negro se neutralizan.     */
.bloque-web--claro {
    background: var(--superficie);
}

.bloque-web--oscuro,
.riel.bloque-web--oscuro,
.escaparate.bloque-web--oscuro {
    background: var(--dji-banda);
    color: var(--tinta);
}

/* Los títulos de un bloque antes-oscuro vuelven a tinta. El héroe NO entra
   aquí: sigue con su media y su texto blanco. */
.bloque-web--oscuro h1,
.bloque-web--oscuro h2,
.bloque-web--oscuro h3,
.bloque-web--oscuro h4 {
    color: var(--tinta);
}

.bloque-web--oscuro .entradilla,
.bloque-web--oscuro .cifra-item__etiqueta,
.bloque-web--oscuro .suave,
.bloque-web--oscuro .tenue,
.riel.bloque-web--oscuro .riel__texto,
.escaparate.bloque-web--oscuro .escaparate__texto {
    color: var(--tinta-suave);
}

/* EL ANTETÍTULO DE UN BLOQUE "OSCURO" QUE YA NO ES OSCURO.

   Ojo con el nombre de la clase: unas líneas más arriba, esta misma capa
   convierte .bloque-web--oscuro en un bloque CLARO (fondo --dji-banda). El
   nombre quedó de antes del rediseño.

   Por eso aquí no vale el acento aclarado que define la capa base para esas
   etiquetas (color-mix 55% con blanco): aquel está pensado para fondo negro
   de verdad, y sobre la banda humo se queda en 2.02:1, prácticamente
   invisible. Va el acento de texto, que es el que contrasta sobre claro.

   Medido: 2.02:1 con el aclarado, 4.85:1 con éste. */
.bloque-web--oscuro .etiqueta-seccion {
    color: var(--marca-texto);
}

.bloque-web--oscuro .cifras > * {
    border-left-color: var(--borde);
}

.riel.bloque-web--oscuro .riel__paso {
    background: var(--superficie);
    border-color: var(--borde);
}

.bloque-web--oscuro .boletin input {
    background: var(--superficie);
    border-color: var(--borde);
    color: var(--tinta);
}

.bloque-web--oscuro .boletin input::placeholder {
    color: var(--tinta-tenue);
}

/* --- Franja de garantías: banda humo ------------------------------------ */
.franja-garantias {
    background: var(--dji-banda);
    border-bottom-color: color-mix(in srgb, var(--tinta) 7%, transparent);
}

.franja-garantias__item {
    border-color: color-mix(in srgb, var(--tinta) 7%, transparent);
    box-shadow: var(--dji-sombra);
}

/* --- Pasos del taller: tarjeta DJI (sombra suave, sin borde duro) -------- */
.riel__paso {
    border-color: transparent;
    box-shadow: var(--dji-sombra);
}

/* --- Escaparate: azulejo de luz y sombra suave --------------------------
   La imagen del escaparate la pone el editor y suele ser de estilo de vida
   (la bici en el taller), no un recorte sobre blanco. Por eso se queda a
   `cover` —llena el marco sin barras—, pero sobre azulejo claro y con la
   sombra suave de DJI. El "producto entero flotando" (contain) vive donde de
   verdad son recortes: el catálogo y la ficha. El tilt 3D y la luz de acento
   que ya trae el escaparate siguen vivos.                                    */
.escaparate__medio {
    background: var(--dji-tinta-producto);
    box-shadow: var(--dji-sombra-fuerte);
}

/* CLIC AL PRODUCTO CORRECTO. En movimiento, las piezas se apilan una encima
   de otra (posición absoluta); las que no están activas quedan invisibles PERO
   encima, y se robaban el clic —por eso mandaba siempre al último destacado—.
   Con pointer-events desactivado, solo la pieza visible recibe el clic. */
.con-motion .escaparate__pieza {
    pointer-events: none;
}

.con-motion .escaparate__pieza[data-activa="true"] {
    pointer-events: auto;
}

/* En pantalla angosta/baja el escaparate NO se apila (es una lista estática):
   ahí todas las piezas deben poder pulsarse. Se restaura el clic. */
@media (max-width: 860px), (max-height: 620px) {

    .con-motion .escaparate__pieza {
        pointer-events: auto;
    }
}

/* Animación al pasar el cursor: la imagen del escaparate se acerca un poco,
   como en las tarjetas del catálogo. Se combina con el tilt 3D que ya tiene. */
.escaparate__medio img {
    transition: transform 600ms var(--salida);
}

@media (hover: hover) and (pointer: fine) {

    .escaparate__medio:hover img {
        transform: scale(1.05);
    }
}

@media (prefers-reduced-motion: reduce) {

    .escaparate__medio:hover img {
        transform: none;
    }
}

/* --- Spotlight: sombra suave bajo la imagen ----------------------------- */
.spotlight__medio {
    box-shadow: var(--dji-sombra);
}

/* --- Galería: sombra suave ---------------------------------------------- */
.galeria-web__foto {
    box-shadow: var(--dji-sombra);
}


/* =========================================================================
   16. ESCENA A SANGRE

   La foto ocupa el ancho completo y una frase se apoya encima. Es el bloque
   que le pone ganas de rodar a una portada que, sin él, solo tiene precios.

   ALTURA CONTENIDA A PROPÓSITO: 74vh y no 100. Una escena de pantalla
   completa a media página se lee como un segundo hero y frena el scroll; a
   tres cuartos se ve que hay algo debajo y el visitante sigue.
   ========================================================================= */
.escena {
    position: relative;
    display: flex;
    align-items: flex-end;
    min-height: clamp(420px, 74vh, 680px);
    padding: 0 0 clamp(40px, 7vw, 80px);
    overflow: hidden;
    isolation: isolate;
    color: #fff;
}

.escena__fondo {
    position: absolute;
    inset: 0;
    z-index: -2;
    background: var(--marca-tinta);
}

.escena__fondo img,
.escena__fondo video {
    width: 100%;
    height: 100%;
    object-fit: cover;
    /* La foto sale de un fotograma de video (1280 de ancho) y aquí se estira.
       Un punto de saturación y contraste le devuelve el cuerpo que pierde al
       escalar, sin llegar al filtro de postal. */
    filter: saturate(1.06) contrast(1.04);
}

/* --- CARRUSEL DE FONDO ------------------------------------------------
   Varias fotos apiladas en el mismo sitio; se ve la que lleva .es-visible y
   se cruzan con una disolvencia lenta.

   Se cruzan con OPACIDAD y no moviéndolas de lado a propósito: un fondo que
   se desliza compite con el texto que va encima y marea al leer. Aquí la
   frase manda y las fotos se relevan sin que el ojo tenga que perseguirlas.

   La transición es larga (1,6 s) porque esto no es una galería que se pasa:
   es un ambiente. */
.escena__fondo--carrusel .escena__foto {
    position: absolute;
    inset: 0;
    opacity: 0;
    transition: opacity 1.6s ease-in-out;
}

.escena__fondo--carrusel .escena__foto.es-visible {
    opacity: 1;
}

/* Sin JavaScript no hay relevo, así que se deja fija la primera: mejor una
   foto quieta que un fondo negro. */
.escena__fondo--carrusel:not([data-listo]) .escena__foto:first-child {
    opacity: 1;
}

@media (prefers-reduced-motion: reduce) {

    .escena__fondo--carrusel .escena__foto {
        transition: none;
    }
}

/* EL VELO ES LO QUE HACE LEGIBLE LA FRASE. Sube desde abajo, que es donde
   vive el texto, y deja limpia la mitad de arriba de la foto. */
.escena::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    background: linear-gradient(
        to top,
        rgba(6, 8, 12, .86) 0%,
        rgba(6, 8, 12, .52) 34%,
        rgba(6, 8, 12, .10) 66%,
        rgba(6, 8, 12, .28) 100%
    );
}

.escena__contenido {
    position: relative;
    max-width: 100%;
}

.escena__contenido--centro {
    text-align: center;
}

.escena__contenido--derecha {
    text-align: right;
}

/* La frase es GRANDE y CORTA. El ancho se topa en 16 caracteres por línea a
   propósito: obliga a que quepa en dos o tres renglones y a que nadie meta
   un párrafo aquí. */
.escena__frase {
    max-width: 16ch;
    margin: 0;
    color: #fff;
    font-size: clamp(34px, 6.4vw, 82px);
    font-weight: 680;
    line-height: 1.02;
    letter-spacing: -.035em;
    text-wrap: balance;
    text-shadow: 0 2px 30px rgba(0, 0, 0, .45);
}

.escena__contenido--centro .escena__frase,
.escena__contenido--derecha .escena__frase {
    max-width: 20ch;
    margin-inline: auto;
}

.escena__contenido--derecha .escena__frase {
    margin-right: 0;
}

.escena__pie {
    max-width: 46ch;
    margin: 18px 0 0;
    color: rgba(255, 255, 255, .86);
    font-size: clamp(15px, 1.6vw, 18px);
    line-height: 1.5;
}

.escena__contenido--centro .escena__pie {
    margin-inline: auto;
}

.escena__acciones {
    margin-top: 26px;
}

@media (max-width: 640px) {

    .escena {
        min-height: 62vh;
        align-items: flex-end;
    }

    .escena__frase {
        max-width: 12ch;
    }
}


/* =========================================================================
   15. EL CUERPO DE TIENDA: MOSAICO DE CATEGORÍAS Y ESTANTE

   La portada contaba la empresa durante cinco bloques antes de enseñar una
   sola producto. Estos dos ponen la mercancía en el primer scroll:

     · MOSAICO — "¿qué vas a rodar?". Reparte el tráfico al catálogo.
     · VITRINA — el estante: ocho productos con su precio, de un vistazo.

   Los dos usan los tokens DJI que definió la capa anterior, así que heredan
   el mismo blanco, la misma sombra y el mismo producto flotando. Nada de
   esto inventa un segundo lenguaje visual.

   CABECERAS A LA IZQUIERDA, no centradas como el resto de bloques. Es
   deliberado: después de varias secciones centradas, dos alineadas a la
   izquierda le dan a la página el respiro que necesita para no leerse como
   una plantilla.
   ========================================================================= */

.mosaico-cabeza,
.vitrina-cabeza {
    max-width: 42ch;
}

.mosaico-cabeza .entradilla,
.vitrina-cabeza .entradilla {
    margin-top: 12px;
}


/* ------------------------------------------------------------------------
   MOSAICO DE CATEGORÍAS

   DOS REJILLAS, CERO HUECOS. El PHP parte la lista en "las dos primeras" y
   "el resto"; aquí cada banda se reparte sola. Por eso no hace falta
   grid-auto-flow: dense, que es justo lo que deja celdas vacías en cuanto el
   número de categorías no es el que uno imaginó al diseñar.
   ------------------------------------------------------------------------ */
.mosaico {
    display: grid;
    gap: 16px;
    margin-top: 44px;
}

.mosaico--principal {
    grid-template-columns: repeat(2, 1fr);
}

/* Una sola categoría no forma pareja: ocupa el ancho entero. Sin esto queda
   un azulejo a media página y un hueco al lado, que es el error de rejilla
   más fácil de cometer y el más evidente de ver. */
.mosaico--solo {
    grid-template-columns: 1fr;
}

.mosaico--banda {
    grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
    margin-top: 16px;
}

/* ALTURA MÍNIMA Y NO PROPORCIÓN FIJA. Con aspect-ratio, un azulejo solo a lo
   ancho de la página se estiraría a más de 800 px de alto y se comería la
   pantalla. Con min-height, la altura la manda el diseño y el ancho lo manda
   la rejilla, sin importar cuántas categorías haya ese día. */
.azulejo {
    position: relative;
    display: block;
    overflow: hidden;
    min-height: clamp(260px, 32vw, 400px);
    border-radius: var(--radio-lg);
    background: var(--marca-tinta);
    box-shadow: var(--dji-sombra);
    text-decoration: none;
    /* Texto blanco SIEMPRE, sin importar el tema del bloque ni el modo del
       navegador: debajo hay una foto y un velo oscuro, no el fondo de la
       página. */
    color: #fff;
    isolation: isolate;
    transition:
        transform 260ms cubic-bezier(.23, 1, .32, 1),
        box-shadow 260ms ease;
}

.mosaico--banda .azulejo {
    min-height: 200px;
}

/* El azulejo solo se acuesta: a lo ancho de la página, alto de tarjeta. */
.mosaico--solo .azulejo {
    min-height: clamp(240px, 26vw, 340px);
}

.azulejo__foto {
    position: absolute;
    inset: 0;
}

.azulejo__foto img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform 620ms cubic-bezier(.23, 1, .32, 1);
}

/* Sin foto no se enseña un hueco: se enseña un panel de marca. Un mosaico a
   medio llenar tiene que verse decidido, no averiado. */
.azulejo__sin-foto {
    position: absolute;
    inset: 0;
    background:
        radial-gradient(120% 90% at 12% 0%, color-mix(in srgb, var(--marca-acento) 55%, transparent), transparent 62%),
        linear-gradient(160deg, var(--marca-tinta), color-mix(in srgb, var(--marca-tinta) 62%, #000));
}

/* EL VELO ES LO QUE GARANTIZA QUE SE LEA. Una foto clara de una bici bajo el
   sol dejaría el nombre en blanco sobre blanco. Con este degradado el texto
   se apoya siempre en algo oscuro, venga la foto que venga. */
.azulejo::after {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(
        to top,
        rgba(8, 10, 16, .84) 0%,
        rgba(8, 10, 16, .40) 40%,
        rgba(8, 10, 16, 0) 72%
    );
}

.azulejo__pie {
    position: relative;
    z-index: 1;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    gap: 3px;
    height: 100%;
    padding: 20px;
}

.azulejo__nombre {
    font-size: clamp(20px, 2.3vw, 29px);
    font-weight: 650;
    line-height: 1.08;
    letter-spacing: -.022em;
}

.mosaico--banda .azulejo__nombre {
    font-size: clamp(17px, 1.5vw, 21px);
}

.azulejo__conteo {
    font-size: 13px;
    color: rgba(255, 255, 255, .78);
}


/* ------------------------------------------------------------------------
   VITRINA (ESTANTE DE PRODUCTOS)

   auto-fit y no auto-fill. Con auto-fill, una tienda que arranca con tres
   productos deja la cuarta columna vacía y el estante se ve a medio surtir.
   auto-fit colapsa las columnas que sobran y reparte el ancho entre las que
   hay: tres productos ocupan la fila entera con tarjetas más generosas, y en
   cuanto haya ocho vuelven solas a cuatro por fila.
   ------------------------------------------------------------------------ */
.vitrina {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(232px, 1fr));
    gap: 18px;
    margin-top: 44px;
}

.vitrina__pieza {
    display: flex;
    flex-direction: column;
    overflow: hidden;
    border: 1px solid var(--borde);
    border-radius: var(--radio-lg);
    /* La tarjeta trae SU fondo y SU color de texto en pareja. Sin esto, dentro
       de un bloque oscuro heredaría el texto claro del bloque y quedaría
       blanco sobre la tarjeta blanca. */
    background: var(--superficie);
    color: var(--tinta);
    box-shadow: var(--dji-sombra);
    text-decoration: none;
    transition:
        transform 220ms cubic-bezier(.23, 1, .32, 1),
        box-shadow 220ms ease,
        border-color 220ms ease;
}

.vitrina__medio {
    position: relative;
    display: block;
    aspect-ratio: 4 / 3;
    overflow: hidden;
    background: var(--dji-tinta-producto);
}

/* contain y no cover: el producto FLOTA sobre el fondo claro en lugar de
   quedar recortado por los bordes. Es la mitad del lenguaje de esta marca. */
.vitrina__medio img {
    width: 100%;
    height: 100%;
    object-fit: contain;
    padding: 14px;
    transition: transform 520ms cubic-bezier(.23, 1, .32, 1);
}

.vitrina__sin-foto {
    position: absolute;
    inset: 0;
    background: linear-gradient(150deg, var(--dji-banda), color-mix(in srgb, var(--dji-banda) 70%, var(--borde)));
}

.vitrina__sello {
    position: absolute;
    top: 10px;
    left: 10px;
    padding: 4px 10px;
    border-radius: var(--radio-completo);
    background: var(--tinta);
    color: var(--superficie);
    font-size: 11px;
    font-weight: 650;
    letter-spacing: .015em;
}

.vitrina__sello--oferta {
    background: var(--marca-acento);
    color: var(--marca-acento-encima);
}

/* La ficha CRECE hasta el fondo de la tarjeta y el precio se va al final con
   margin-top: auto. Así, en una fila donde un producto tiene el nombre de una
   línea y el de al lado de dos, los precios siguen cayendo a la misma altura.
   Sin esto, el precio flota detrás de cada nombre y la fila se ve desalineada,
   que es lo primero que delata un estante mal armado. */
.vitrina__ficha {
    display: flex;
    flex: 1;
    flex-direction: column;
    gap: 4px;
    padding: 14px 16px 17px;
}

/* --tinta-suave y no --tinta-tenue: el tenue se queda en 3.1:1 sobre blanco y
   no pasa AA. Un dato que no se lee no es un dato. */
.vitrina__categoria {
    font-size: 12px;
    color: var(--tinta-suave);
}

.vitrina__nombre {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    font-size: 15px;
    font-weight: 620;
    line-height: 1.3;
    letter-spacing: -.01em;
}

.vitrina__precio {
    display: flex;
    align-items: baseline;
    gap: 8px;
    margin-top: auto;
    padding-top: 7px;
}

.vitrina__precio-valor {
    font-size: 17px;
    font-weight: 680;
    letter-spacing: -.02em;
}

.vitrina__precio-lista {
    font-size: 13px;
    color: var(--tinta-suave);
    text-decoration: line-through;
}

.vitrina__pie {
    display: flex;
    justify-content: center;
    margin-top: 34px;
}


/* ------------------------------------------------------------------------
   ESTADOS: foco, pulsación y hover

   El hover va detrás de (hover: hover): en una pantalla táctil, tocar activa
   el hover y la tarjeta se queda levantada después de soltar.
   ------------------------------------------------------------------------ */
.azulejo:focus-visible,
.vitrina__pieza:focus-visible {
    outline: 3px solid var(--marca-acento);
    outline-offset: 3px;
}

.azulejo:active,
.vitrina__pieza:active {
    transform: scale(.985);
}

@media (hover: hover) and (pointer: fine) {

    .azulejo:hover {
        transform: translateY(-3px);
        box-shadow: var(--dji-sombra-fuerte);
    }

    .azulejo:hover .azulejo__foto img {
        transform: scale(1.045);
    }

    .vitrina__pieza:hover {
        transform: translateY(-3px);
        border-color: var(--borde-fuerte);
        box-shadow: var(--dji-sombra-fuerte);
    }

    .vitrina__pieza:hover .vitrina__medio img {
        transform: scale(1.04);
    }
}


/* ------------------------------------------------------------------------
   MÓVIL

   El mosaico pasa a una columna (un azulejo por pantalla, que es donde luce)
   y la vitrina a DOS columnas, no a una: así se ve como una tienda y no como
   una lista, que es lo que hace cualquier tienda en el teléfono.
   ------------------------------------------------------------------------ */
@media (max-width: 720px) {

    .mosaico--principal {
        grid-template-columns: 1fr;
    }

    .mosaico--banda {
        grid-template-columns: repeat(2, 1fr);
    }
}

@media (max-width: 640px) {

    .mosaico-cabeza,
    .vitrina-cabeza {
        max-width: none;
    }

    .vitrina {
        grid-template-columns: repeat(2, 1fr);
        gap: 12px;
    }

    .vitrina__ficha {
        padding: 11px 12px 14px;
    }

    .vitrina__nombre {
        font-size: 14px;
    }

    .azulejo__pie {
        padding: 16px;
    }
}


/* ------------------------------------------------------------------------
   MOVIMIENTO REDUCIDO

   Se van los desplazamientos y las escalas; se quedan el foco y el borde,
   que informan en lugar de decorar.
   ------------------------------------------------------------------------ */
@media (prefers-reduced-motion: reduce) {

    .azulejo,
    .vitrina__pieza,
    .azulejo__foto img,
    .vitrina__medio img {
        transition: none;
    }

    .azulejo:hover,
    .vitrina__pieza:hover,
    .azulejo:active,
    .vitrina__pieza:active {
        transform: none;
    }

    .azulejo:hover .azulejo__foto img,
    .vitrina__pieza:hover .vitrina__medio img {
        transform: none;
    }
}


/* =========================================================================
   16. ALTERNADOR DE TEMA EN LA CABECERA

   El motor ya estaba entero y sin usar: web.css define :root[data-tema] y la
   cabecera lee 'sis_tema' de localStorage antes de pintar. Solo faltaba el
   botón, y el manejador de [data-alternar-tema] ya vive en ui.js.

   Discreto a propósito: convive con el botón "Comprar", que es el que tiene
   que ganarse la mirada. Sin fondo hasta que se pasa por encima.

   QUÉ ICONO SE VE: el del tema al que IRÍAS si lo tocas, no el que está
   puesto. En claro se ve la luna ("cámbiame a oscuro"); en oscuro, el sol.
   ========================================================================= */
.cabecera__tema {
    display: inline-grid;
    place-items: center;
    width: 40px;
    height: 40px;
    margin-left: 6px;
    padding: 0;
    border: 1px solid transparent;
    border-radius: var(--radio-completo);
    background: transparent;
    color: inherit;
    cursor: pointer;
    transition: background-color 160ms ease, border-color 160ms ease, transform 120ms ease;
}

@media (hover: hover) and (pointer: fine) {

    .cabecera__tema:hover {
        border-color: var(--borde);
        background: var(--superficie-hundida);
    }
}

.cabecera__tema:focus-visible {
    outline: 2px solid var(--marca-acento);
    outline-offset: 2px;
}

.cabecera__tema:active {
    transform: scale(.94);
}

/* Los dos iconos se apilan en la misma celda y solo se enseña uno. Van en el
   HTML desde el arranque para que no haya un parpadeo con el icono
   equivocado mientras carga el JavaScript. */
.cabecera__tema-sol,
.cabecera__tema-luna {
    grid-area: 1 / 1;
}

/* Por omisión (claro): se ofrece el oscuro, así que se ve la luna. */
.cabecera__tema-sol {
    display: none;
}

/* En oscuro se invierte. Primero por preferencia del sistema… */
@media (prefers-color-scheme: dark) {

    :root:not([data-tema="claro"]) .cabecera__tema-sol {
        display: block;
    }

    :root:not([data-tema="claro"]) .cabecera__tema-luna {
        display: none;
    }
}

/* …y después por elección explícita, que gana sobre la del sistema. */
:root[data-tema="oscuro"] .cabecera__tema-sol {
    display: block;
}

:root[data-tema="oscuro"] .cabecera__tema-luna {
    display: none;
}

:root[data-tema="claro"] .cabecera__tema-sol {
    display: none;
}

:root[data-tema="claro"] .cabecera__tema-luna {
    display: block;
}

/* En el teléfono la barra va apretada: el alternador cede su sitio al botón
   de comprar, que es lo que la gente viene a tocar. */
@media (max-width: 560px) {

    .cabecera__tema {
        display: none;
    }
}

@media (prefers-reduced-motion: reduce) {

    .cabecera__tema {
        transition: none;
    }

    .cabecera__tema:active {
        transform: none;
    }
}


/* =========================================================================
   17. COLOR DEL TEXTO ELEGIDO EN EL PANEL

   Lo pone quien edita la página, por sección: .texto--claro o .texto--oscuro.
   Sirve para las secciones que llevan foto de fondo, donde el color correcto
   depende de la imagen y no del tema del navegador.

   POR QUÉ TANTO SELECTOR: app.css declara `h1..h4 { color: var(--tinta) }` y
   varias piezas se pintan a sí mismas (.entradilla, .bloque__texto…). Un
   selector de elemento le gana al color heredado del contenedor, así que
   forzar el color en el padre NO alcanza: hay que nombrarlos.

   Lleva !important a propósito, y es de los pocos sitios donde se justifica:
   esto es una decisión EXPLÍCITA de quien edita, tomada delante de la foto
   concreta, y tiene que ganarle a cualquier regla de la hoja. Si no gana, la
   opción del panel no sirve para nada.
   ========================================================================= */
.texto--claro,
.texto--claro h1,
.texto--claro h2,
.texto--claro h3,
.texto--claro h4,
.texto--claro p,
.texto--claro li,
.texto--claro .titular,
.texto--claro .titular--medio,
.texto--claro .entradilla,
.texto--claro .suave,
.texto--claro .tenue,
.texto--claro .pequeno {
    color: #fff !important;
}

/* El antetítulo conserva el acento, pero aclarado para que se despegue de la
   foto en vez de fundirse con ella. */
.texto--claro .etiqueta-seccion,
.texto--claro .etiqueta-web {
    color: color-mix(in srgb, var(--marca-acento) 55%, white) !important;
}

/* Una sombra suave debajo del texto claro: sobre una foto con zonas claras,
   el blanco solo no basta y no se puede saber de antemano por dónde va a
   caer. La sombra no se ve sobre lo oscuro y salva lo claro. */
.texto--claro .titular,
.texto--claro .titular--medio,
.texto--claro h1,
.texto--claro h2 {
    text-shadow: 0 1px 16px rgba(0, 0, 0, .38);
}

.texto--oscuro,
.texto--oscuro h1,
.texto--oscuro h2,
.texto--oscuro h3,
.texto--oscuro h4,
.texto--oscuro p,
.texto--oscuro li,
.texto--oscuro .titular,
.texto--oscuro .titular--medio,
.texto--oscuro .entradilla {
    color: var(--tinta) !important;
    text-shadow: none;
}

.texto--oscuro .suave,
.texto--oscuro .tenue,
.texto--oscuro .pequeno {
    color: var(--tinta-suave) !important;
}

.texto--oscuro .etiqueta-seccion,
.texto--oscuro .etiqueta-web {
    color: var(--marca-texto) !important;
}




/* =========================================================================
   AGENDA DEL TALLER

   El formulario va dentro de una caja redondeada con borde sutil: separa el
   trámite del resto de la página sin gritar. Es el único sitio de la web
   donde se pide información, y tiene que verse como una unidad.
   ========================================================================= */
.agenda {
    margin-top: 28px;
    padding: clamp(20px, 3.5vw, 34px);
    border: 1px solid var(--borde);
    border-radius: clamp(16px, 2.2vw, 24px);
    background: var(--superficie);
    box-shadow: 0 1px 2px rgba(0, 0, 0, .04), 0 12px 32px -20px rgba(0, 0, 0, .35);
}

.agenda__paso {
    font-size: 13px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--tinta-tenue);
    margin: 26px 0 12px;
}

.agenda__paso:first-child {
    margin-top: 0;
}

.agenda__rejilla {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
    gap: 14px;
}

.agenda__pie {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 16px;
    flex-wrap: wrap;
    margin-top: 26px;
    padding-top: 20px;
    border-top: 1px solid var(--borde);
}


/* --- EL CALENDARIO ----------------------------------------------------
   Siete columnas fijas: es la forma que todo el mundo ya sabe leer. Los
   días que no se pueden elegir siguen ahí, en rojo y apagados — quitarlos
   descolocaría la cuadrícula y haría creer que ese día no existe. */
.calendario {
    margin-bottom: 18px;
}

.calendario__mes {
    font-size: 15px;
    font-weight: 660;
    text-transform: capitalize;
    margin-bottom: 10px;
}

.calendario__semana,
.calendario__rejilla {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 6px;
}

.calendario__semana {
    margin-bottom: 6px;
}

.calendario__semana span {
    text-align: center;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: .05em;
    color: var(--tinta-tenue);
}

.calendario__hueco {
    display: block;
}

/* El radio de verdad se esconde pero SIGUE AHÍ: es lo que hace que el
   calendario funcione con teclado y que un lector de pantalla lo anuncie.
   Sustituirlo por divs con JavaScript deja fuera a quien no usa ratón. */
.calendario__dia input {
    position: absolute;
    opacity: 0;
    pointer-events: none;
}

.calendario__caja {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 3px;
    min-height: 62px;
    padding: 8px 4px;
    border: 1.5px solid var(--borde);
    border-radius: 12px;
    background: var(--superficie);
    cursor: pointer;
    transition: border-color .15s ease, background .15s ease, transform .12s ease;
}

.calendario__dia:not(.calendario__dia--muerto):hover .calendario__caja {
    transform: translateY(-1px);
}

.calendario__numero {
    font-size: 16px;
    font-weight: 640;
    line-height: 1;
    font-variant-numeric: tabular-nums;
}

.calendario__punto {
    width: 7px;
    height: 7px;
    border-radius: 50%;
}

.calendario__cupo {
    font-size: 10.5px;
    font-weight: 600;
    color: var(--tinta-tenue);
    line-height: 1;
}

/* --- El semáforo ---
   El color NUNCA va solo: cada estado lleva además su número de lugares y
   su texto al pasar el ratón. Uno de cada doce hombres no distingue el
   verde del rojo, y un calendario que solo habla en color no le sirve. */
.calendario__dia--verde .calendario__punto { background: #16a34a; }
.calendario__dia--ambar .calendario__punto { background: #d97706; }
.calendario__dia--rojo  .calendario__punto { background: #dc2626; }

.calendario__dia--verde .calendario__caja { border-color: rgba(22, 163, 74, .45); }
.calendario__dia--ambar .calendario__caja { border-color: rgba(217, 119, 6, .5); }

.calendario__dia--muerto .calendario__caja {
    opacity: .42;
    cursor: not-allowed;
    background: var(--superficie-hundida);
}

.calendario__dia input:checked + .calendario__caja {
    border-color: var(--marca-acento);
    border-width: 2px;
    background: color-mix(in srgb, var(--marca-acento) 10%, transparent);
}

.calendario__dia input:focus-visible + .calendario__caja {
    outline: 2px solid var(--marca-acento);
    outline-offset: 2px;
}

.calendario__leyenda {
    display: flex;
    flex-wrap: wrap;
    gap: 16px;
    font-size: 12.5px;
    color: var(--tinta-tenue);
    margin-top: 4px;
}

.calendario__muestra {
    display: inline-block;
    width: 9px;
    height: 9px;
    border-radius: 50%;
    margin-right: 5px;
}

.calendario__muestra--verde { background: #16a34a; }
.calendario__muestra--ambar { background: #d97706; }
.calendario__muestra--rojo  { background: #dc2626; }

/* El día elegido, repetido en letra: un número suelto dentro de una
   cuadrícula es fácil de confundir, y esto se lee sin contar columnas. */
.agenda__elegido {
    margin-top: 14px;
    font-size: 15px;
    font-weight: 600;
}

.agenda__elegido:empty {
    display: none;
}

.agenda__listo {
    margin-top: 28px;
    padding: 26px 28px;
    border: 1.5px solid var(--exito-borde);
    border-radius: clamp(16px, 2.2vw, 24px);
    background: var(--exito-fondo);
}

.agenda__listo-titulo {
    font-size: 20px;
    font-weight: 700;
    letter-spacing: -.02em;
    margin-bottom: 8px;
}

@media (max-width: 480px) {

    .calendario__caja { min-height: 54px; padding: 6px 2px; }
    .calendario__numero { font-size: 14px; }
    .calendario__cupo { display: none; }
}
