/* ===========================================================================
   OFITODO — Capa de movimiento
   Carga DESPUÉS de ofitodo.css y paginas.css: solo añade, nunca redefine
   color, tipografía ni retícula. Se desactiva quitando su <link>.

   POR QUÉ EXISTE
   El sitio ya animaba la entrada de secciones con `animation-timeline: view()`,
   que es CSS puro y no cuesta un byte de JavaScript. El problema es que hoy
   solo lo entienden los navegadores Chromium: en Safari (todo iPhone y iPad) y
   en Firefox no se mueve nada. Esta capa reproduce la misma idea con
   IntersectionObserver para que la animación sea la misma en todos, y de paso
   diferencia el gesto según lo que entra: el texto sube, la fotografía se
   destapa, el hilo del proceso se dibuja.

   REGLA DE SEGURIDAD (la misma que ya seguía el sitio)
   El contenido nace VISIBLE. Solo se oculta cuando el JavaScript ha confirmado
   que puede volver a mostrarlo, y para eso pone `js-mov` en <html>. Sin
   JavaScript, sin IntersectionObserver o con el script roto, la página se ve
   completa. Además el script revela todo a los 3,5 s pase lo que pase.
   Ninguna sección puede quedarse en blanco.
   =========================================================================== */

:root {
  /* Salida exponencial: arranca rápido y se posa. Es lo que separa una
     animación cara de una barata, y no cuesta nada. */
  --mov-ease: cubic-bezier(.16, 1, .3, 1);
  --mov-dur: .82s;
  --mov-y: 24px;
}

/* Estado por defecto: todo a la vista. No depende de nada. */
.revelar { opacity: 1; transform: none; }

@media (prefers-reduced-motion: no-preference) {

  /* Con JS activo mandamos nosotros: se apagan las animaciones ligadas al
     scroll de ofitodo.css para que un elemento no reciba dos gestos a la vez. */
  html.js-mov .revelar,
  html.js-mov .paso,
  html.js-mov .paso::before { animation: none; }

  /* La entrada va por ANIMACIÓN SIN RETARDO NI RELLENO, y el escalonado lo
     reparte el JavaScript decidiendo CUÁNDO pone la clase. Las tres decisiones
     tienen la misma razón, y cada una salió de un fallo real:

     1. Con transición, el retardo del escalonado tiene que vivir en el estado
        ya revelado (una transición se define por los valores de DESPUÉS del
        cambio), así que se aplicaba también al `:hover`: una tarjeta con medio
        segundo de escalonado tardaba medio segundo en elevarse bajo el cursor.
     2. Declarar `transform` en el estado revelado —aunque sea `none`— pesa
        (0,3,1) y anula cualquier `.tarjeta:hover` o `.taller:nth-child(even)`,
        que pesan (0,2,0). Aquí no se declara.
     3. Con relleno (`backwards`/`both`) el elemento se queda congelado en el
        fotograma inicial mientras la animación no arranca. Si por lo que sea
        no arranca, la pieza se queda INVISIBLE — justo lo que este archivo
        promete que no puede pasar. Sin relleno, el valor de reposo es el de
        la cascada: visible. El peor caso deja de ser una sección en blanco y
        pasa a ser una sección que aparece sin animarse. */
  html.js-mov .revelar:not(.visto) {
    opacity: 0;
    transform: translateY(var(--mov-y));
    will-change: opacity, transform;
  }
  html.js-mov .revelar.visto {
    animation: mov-entra var(--mov-dur) var(--mov-ease);
  }
  @keyframes mov-entra {
    from { opacity: 0; transform: translateY(var(--mov-y)); }
    to   { opacity: 1; transform: none; }
  }

  /* --- Fotografía: se destapa, no se desvanece ---------------------------
     Un producto de catálogo aparece mejor descubriéndose de abajo hacia
     arriba que apareciendo de la nada: el gesto imita levantar una funda y
     deja ver el mueble entero desde el primer fotograma.
     Sin translateY: el recorte ya da el movimiento, y sumar los dos hace que
     la foto "resbale" dentro de su marco. */
  html.js-mov .tarjeta.revelar:not(.visto) .tarjeta__img,
  html.js-mov .sector.revelar:not(.visto) img,
  html.js-mov .taller.revelar:not(.visto) .taller__foto,
  html.js-mov .dos__media.revelar:not(.visto) > *,
  html.js-mov .obra__foto.revelar:not(.visto) img {
    clip-path: inset(0 0 100% 0);
  }
  html.js-mov .tarjeta.revelar.visto .tarjeta__img,
  html.js-mov .sector.revelar.visto img,
  html.js-mov .taller.revelar.visto .taller__foto,
  html.js-mov .dos__media.revelar.visto > *,
  html.js-mov .obra__foto.revelar.visto img {
    animation: mov-destapa .95s var(--mov-ease);
  }
  @keyframes mov-destapa {
    from { clip-path: inset(0 0 100% 0); }
    to   { clip-path: inset(0 0 0 0); }
  }
  /* La pieza que lleva foto sube menos: el recorte ya da el movimiento y sumar
     los dos hace que la imagen resbale dentro de su marco. Se cambia la
     variable, no la declaración, para que el fotograma inicial de mov-entra
     arranque del mismo sitio donde el estado oculto la dejó. */
  html.js-mov .tarjeta.revelar,
  html.js-mov .sector.revelar,
  html.js-mov .taller.revelar,
  html.js-mov .dos__media.revelar { --mov-y: 12px; }

  /* --- Proceso de compra: el hilo se dibuja --------------------------------
     El hilo codifica secuencia, así que se dibuja DESPUÉS de que aparece el
     paso del que sale (de ahí el retardo propio sumado al del escalonado). */
  /* Aquí el retardo sí puede ir en la transición: es un pseudoelemento, no
     tiene :hover propio que se quede esperando, y una transición sin ejecutar
     aterriza igualmente en su valor final (el hilo dibujado). */
  html.js-mov .paso::before {
    transform: scaleX(0);
    transform-origin: left center;
    transition: transform .6s var(--mov-ease) .26s;
  }
  html.js-mov .paso.visto::before { transform: scaleX(1); }

  /* La línea de tiempo vertical de la portada se dibuja hacia abajo, tramo a
     tramo, según va apareciendo cada paso. Mismo contrato: nace dibujada y
     solo se recoge cuando el JS ha confirmado que puede volver a soltarla. */
  html.js-mov .flujo__paso::before {
    transform: scaleY(0);
    transform-origin: top center;
    transition: transform .55s var(--mov-ease) .18s;
  }
  html.js-mov .flujo__paso.visto::before { transform: scaleY(1); }

  /* --- Portada: el único momento coreografiado de la página ----------------
     El resto del sitio usa un solo gesto repetido. Aquí las piezas entran en
     el orden en que se leen, y el fondo se asienta con un zoom largo que nadie
     percibe como animación pero que quita la sensación de foto pegada. */
  html.js-mov .hero__inner > * {
    opacity: 0;
    transform: translateY(18px);
    transition: opacity .9s var(--mov-ease) var(--hero-d, 0s),
                transform .9s var(--mov-ease) var(--hero-d, 0s);
  }
  html.js-mov .hero--entra .hero__inner > * { opacity: 1; transform: none; }

  html.js-mov .hero__inner > .etiqueta { --hero-d: .05s; }
  html.js-mov .hero__inner > h1 { --hero-d: .14s; }
  html.js-mov .hero__inner > p { --hero-d: .24s; }
  html.js-mov .hero__inner > .hero__acciones { --hero-d: .34s; }
  html.js-mov .hero__inner > .hero__datos { --hero-d: .44s; }

  /* La regla que separa el titular de las cifras se traza sola. */
  html.js-mov .hero__datos { border-top-color: transparent; position: relative; }
  html.js-mov .hero__datos::before {
    content: ""; position: absolute; left: 0; right: 0; top: -1px; height: 1px;
    background: rgb(255 255 255 / .18);
    transform: scaleX(0); transform-origin: left center;
    transition: transform 1.1s var(--mov-ease) .6s;
  }
  html.js-mov .hero--entra .hero__datos::before { transform: scaleX(1); }

  .hero__media img { animation: hero-asienta 24s var(--mov-ease) both; }
  @keyframes hero-asienta {
    from { transform: scale(1.07); }
    to   { transform: scale(1); }
  }

  /* --- Logotipos de cliente ------------------------------------------------
     La franja entra como una sola pieza y los logotipos van dentro. Se probó
     escalonarlos uno a uno y se descartó: para conseguir el retardo por
     logotipo hace falta relleno en la animación, y el relleno es justo lo que
     puede dejar un elemento congelado en invisible. Siete logotipos no valen
     reintroducir ese riesgo. Lo que sí conservan es recuperar su color al
     pasar el cursor, que ya existía. */
}

/* ===========================================================================
   VÍDEO DE RENDER EN SECCIÓN
   Mismo patrón que ya usa el vídeo del hero y por las mismas razones: la
   imagen se queda como base (es la que ve Google, la que ve quien tiene el
   dato caro y la que queda si el códec falla), y el vídeo se monta encima
   solo cuando ya puede reproducirse. Nunca hay un hueco negro.
   =========================================================================== */
.media-video { display: block; position: relative; overflow: hidden; border-radius: var(--r-lg); }
.media-video > img { display: block; width: 100%; height: auto; }
.media-video video {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; opacity: 0; transition: opacity .7s var(--mov-ease);
  pointer-events: none;
}
.media-video video.listo { opacity: 1; }
@media (prefers-reduced-motion: reduce) { .media-video video { display: none; } }

/* El bloque «A tu medida» ya daba forma y sombra al <img>; ahora las lleva el
   marco, porque el vídeo va dentro de él. */
.dos__media .media-video { box-shadow: var(--s-2); }
.dos__media .media-video > img { border-radius: 0; box-shadow: none; aspect-ratio: 4/3; object-fit: cover; }

/* Cierre con render de fondo. El degradado azul de marca se conserva EXACTO y
   pasa a ir encima del vídeo, así que el contraste del texto blanco no cambia:
   lo que hay detrás del degradado no altera lo que se lee delante. */
.cierre { position: relative; isolation: isolate; overflow: hidden; }
.cierre .media-video {
  position: absolute; inset: 0; z-index: -2; border-radius: 0;
}
.cierre .media-video > img { width: 100%; height: 100%; object-fit: cover; }
.cierre::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(135deg, var(--azul-900) 0%, var(--azul) 48%, #24558f 100%);
  opacity: .93;
}
.cierre > .contenedor { position: relative; z-index: 1; }

/* ===========================================================================
   SUPERFICIES DEL NAVEGADOR
   Lo que no dibujamos también viste la página. Selección, cursor de texto,
   barra de desplazamiento y cifras venían con el ajuste por defecto del
   navegador, que no pertenece a ningún sistema de diseño. Todo sale de la
   paleta que ya existe: ni un color nuevo.
   =========================================================================== */
::selection { background: color-mix(in srgb, var(--acento) 26%, transparent); color: var(--tinta); }
.hero ::selection, .cierre ::selection, .banda-proy ::selection {
  background: rgb(255 255 255 / .28); color: #fff;
}
:root { accent-color: var(--acento); caret-color: var(--acento); }

@supports (scrollbar-color: auto) {
  html { scrollbar-color: var(--tenue) transparent; scrollbar-width: thin; }
}
::-webkit-scrollbar { width: 11px; height: 11px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: var(--tenue); border-radius: 999px;
  border: 3px solid var(--blanco); background-clip: padding-box;
}
::-webkit-scrollbar-thumb:hover { background: var(--suave); background-clip: padding-box; }

/* Cifras que se comparan entre sí van en versales tabulares: sin esto las
   columnas del hero bailan mientras el contador sube. */
.hero__dato strong, .tarjeta__meta, .paso__n b { font-variant-numeric: tabular-nums; }

/* El subrayado de un enlace dentro de un párrafo cae sobre las letras con
   descendente. Se separa una pizca y se afina. */
.prosa a, .cierre a:not(.btn), .hero a:not(.btn) {
  text-underline-offset: .18em; text-decoration-thickness: from-font;
}
