/* =========================================================================
   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;
    color: var(--marca-acento);
    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-acento);
    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);
}

.riel__pie {
    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-acento);
    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 BiciTeq. 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);
}

@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);
}

.bloque-web--oscuro .etiqueta-seccion {
    color: var(--marca-acento);
}

.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);
}

/* --- 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);
}
