/* ==========================================================================
   ALCASA NUEVO HOGAR — HOJA DE ESTILOS (css/styles.css)
   ==========================================================================

   QUÉ ES ESTE ARCHIVO
   Es la hoja de estilos de toda la web: decide cómo se VE cada cosa
   (colores, letras, tamaños, huecos, posiciones y movimientos). El HTML de
   cada página dice QUÉ hay (un título, una foto, un botón); este archivo
   dice CÓMO se presenta. Lo cargan las cinco páginas: index.html (el home),
   proyectos.html, quienes-somos.html, contacto.html y aviso-legal.html.
   Los guiones de la carpeta js/ (main.js, paso.js, visor.js, contacto.js)
   casi siempre se limitan a poner y quitar clases o variables (alguna vez
   escriben directamente una posición, una medida o un desplazamiento que
   calculan en el momento); el aspecto de cada estado se decide aquí.

   NOTA PRÁCTICA
   Para cambiar un color de toda la web, cambia su variable en :root; no
   escribas colores nuevos fuera de la paleta.
   Lo mismo con medidas y tiempos: sus variables están también en :root
   (sección 1), y cambiándolas allí cambian en todas partes.

   CÓMO ESTÁ ORGANIZADO (en el orden en que aparece en el archivo)
      1  Variables (paleta, medidas, movimiento)
      2  Tipografías
      3  Base
      4  Cabecera y menú
      5  Portada (hero) y secuencia de entrada
      6  Section 2
      7  Section 3 (con el viaje de la fotografía y el paso del hero a Section 2)
      8  Pie
      9  Proyectos (cuadrícula)
     10  Página de contacto
     11  Visor de proyecto
     12  Adaptación a pantallas estrechas
     13  Paso de una página a otra
     14  Sección 4 (cierre del home con muestras de material)
     15  Formulario de contacto
     16  Aparición al bajar
     17  Quiénes somos (y, a continuación, la versión de móvil «app»)
     18  Pantalla completa (fotos sobre fondo negro y botón de ampliar)
   Cada sección empieza con un título que lleva su número y su nombre: para
   ir a una, busca ese título en el archivo.
   «Section 2», «Section 3» y «Sección 4» son los bloques del home que van
   después de la portada, en ese orden.

   --------------------------------------------------------------------------
   GLOSARIO: CÓMO LEER CSS SIN SABER NADA
   --------------------------------------------------------------------------

   Comentario
     Todo lo que va entre los signos barra-asterisco y asterisco-barra (como
     este texto) es una nota para personas. El navegador lo ignora.

   Regla
     Un bloque con esta forma:      .boton { color: red; }
     Lo de antes de la llave es el SELECTOR (a qué elementos afecta) y lo de
     dentro, las DECLARACIONES (qué se les hace). Cada declaración acaba en
     punto y coma.

   Propiedad y valor
     En «color: red;», color es la PROPIEDAD (qué se cambia) y red el VALOR
     (cómo queda). Las propiedades que empiezan por -webkit- son versiones
     para navegadores concretos (Safari, Chrome) de algo que aún no todos
     entienden igual.

   Selector
     Dice a qué elementos de la página se aplica una regla:
       body       la etiqueta <body>: todo lo que se ve de la página.
       a, img     todas las etiquetas <a> (enlaces) o <img> (imágenes).
       .logo      todo lo que lleve class="logo" en el HTML. El punto quiere
                  decir «clase». Una CLASE es un nombre que se le pone a un
                  elemento en el HTML para poder darle estilo desde aquí.
       #hero      el elemento con id="hero" (un id es único en cada página).
       *          cualquier elemento.
       .a .b      un .b que esté DENTRO de un .a, a cualquier profundidad.
       .a.b       (sin espacio) un elemento que lleve LAS DOS clases a la vez.
       .a > .b    un .b que sea hijo directo de .a.
       .a, .b     la coma junta selectores: la misma regla para los dos.
       [x="y"]    elementos que tengan el atributo x con el valor y, por
                  ejemplo [aria-expanded="true"].
       :not(.x)   que NO lleve la clase .x.
     Los nombres de clase siguen un patrón: .bloque__pieza--variante. Así,
     .hero__slide--1 es la pieza «slide» del bloque «hero», versión 1.
     Las clases que empiezan por is- (.is-transparente, .is-open…) o que
     nombran un estado (.en-vuelo, .se-ve…) las pone y las quita JavaScript
     mientras se usa la página. No están escritas en el HTML, salvo
     .is-transparente, que index.html ya trae puesta desde el principio.

   :root
     La raíz de la página (la etiqueta <html>). Aquí se guardan las
     variables para que valgan en toda la página.

   Pseudo-clases (con un solo signo de dos puntos)
     Estados de un elemento:
       :hover          el ratón está encima.
       :focus          está seleccionado (para escribir en él o pulsarlo).
       :focus-visible  está seleccionado con el teclado (tecla Tab). Sirve
                       para dibujar el recuadro de foco solo a quien navega
                       con teclado, y no a quien hace clic con el ratón.
       :first-child, :last-child, :nth-child(2)
                       es el primero, el último o el segundo de sus hermanos.

   Pseudo-elementos (con dos signos de dos puntos)
     ::before y ::after crean una pieza extra, que no está en el HTML, al
     principio o al final de un elemento. Se usan para dibujar adornos (un
     filete, un velo, una sombra). Solo existen si llevan content: "".

   Colores
     #3C1621  color en código hexadecimal (cantidad de rojo, verde y azul).
     rgba(60, 22, 33, .5)  el mismo color con transparencia: los tres
              primeros números son rojo, verde y azul (0 a 255) y el cuarto
              va de 0 (invisible) a 1 (opaco).
     transparent   sin color. currentColor   el color del texto del elemento.

   Variables  --x  y  var()
     «--principal: #3C1621;» guarda un valor con un nombre. En cualquier otro
     sitio, var(--principal) lo usa. Si se cambia la variable, cambia en
     todos los sitios a la vez. var(--x, 0) lleva un valor de reserva (0) que
     se usa si --x no existe. Algunas variables no se escriben en este
     archivo: las pone JavaScript mientras se usa la página (por ejemplo
     --avance, --avance3 o --alto-pie).

   Unidades
     px     píxel: medida fija de pantalla.
     rem    múltiplo del tamaño de letra base del navegador (normalmente
            16 px): 1rem = 16 px, 2rem = 32 px, .5rem = 8 px. Si la persona
            agranda la letra en su navegador, lo medido en rem crece con ella.
     em     múltiplo del tamaño de letra del propio elemento. En
            letter-spacing, .1em = una décima del tamaño de su letra.
     %      porcentaje de algo: del ancho de la caja que lo contiene, del
            propio elemento (dentro de transform) o del tiempo (en @keyframes).
     vw     1 % del ancho de la ventana (100vw = todo el ancho).
     vh     1 % del alto de la ventana (100vh = todo el alto).
     svh    como vh, pero tomando el alto más pequeño que puede tener la
            ventana en el móvil (con las barras del navegador a la vista),
            para que nada quede tapado por ellas.
     deg    grados de giro: 45deg = un octavo de vuelta; 180deg = media vuelta.
     ms, s  milisegundos y segundos: 1000ms = 1s; .45s = 0,45 segundos.
     Un número sin unidad es una proporción: line-height: 1.6 = 1,6 veces el
     tamaño de la letra; opacity: .5 = a medias. Un número que empieza por
     punto es decimal: .5 = 0,5.

   Funciones de cálculo
     calc(a + b)   hace una cuenta, aunque mezcle unidades:
                   calc(100% - 2rem) = todo el ancho menos 32 px.
     min(a, b)     usa el menor de los dos: min(72rem, 100%) = 72rem, salvo
                   que la caja sea más estrecha.
     max(a, b)     usa el mayor de los dos.
     clamp(mínimo, ideal, máximo)
                   usa el valor ideal sin bajar del mínimo ni pasar del
                   máximo. clamp(1rem, 4vw, 3rem) crece con la ventana (4 %
                   de su ancho) pero se queda entre 16 y 48 px.

   @media (condición) { … }
     Reglas que solo valen mientras se cumple la condición:
       (max-width: 900px)  ventana de 900 px de ancho o menos (móviles y
                           tabletas).
       (hover: hover)      aparato con ratón (no táctil).
       (prefers-reduced-motion: reduce)  la persona ha pedido en su sistema
                           menos animaciones.

   @supports (algo) { … }
     Reglas que solo valen si el navegador entiende ese «algo». Sirve para
     usar una novedad sin romper la web en los navegadores que no la tienen.

   @font-face
     Da de alta una tipografía: su nombre y el archivo donde está.

   @keyframes nombre  y  animation
     @keyframes describe un movimiento por fotogramas clave: cómo está al
     principio (from, o 0%), al final (to, o 100%) y, si hace falta, en medio.
     animation lo pone en marcha sobre un elemento. En su forma corta:
       animation: surgir .9s cubic-bezier(.22, .61, .36, 1) .3s both;
     = qué movimiento, cuánto dura, con qué curva de velocidad, cuánto
     espera antes de empezar y «both» (mientras espera ya se ve como en el
     primer fotograma y, al acabar, se queda como en el último).
     infinite = se repite sin parar.

   transition
     Suaviza un cambio de estado: en vez de saltar de golpe (por ejemplo, de
     un color a otro al pasar el ratón), el cambio se hace poco a poco en el
     tiempo indicado. «transition: opacity .45s ease» = la transparencia
     cambia en 0,45 s. Si hay varias, van separadas por comas.

   Curvas de velocidad
     Dicen cómo se reparte un movimiento en el tiempo: linear (siempre igual),
     ease (arranca y frena suave), ease-in (arranca despacio), ease-out
     (frena despacio), ease-in-out (las dos cosas). cubic-bezier(a, b, c, d)
     es una curva a medida, definida por cuatro números; linear(…) es una
     curva dibujada punto a punto.

   transform
     Mueve, gira o cambia de tamaño un elemento sin que los de alrededor se
     recoloquen:
       translateX(…) / translateY(…) / translate(x, y)  lo desplaza.
       rotate(45deg)   lo gira.
       scale(1.05)     lo agranda un 5 %;  scaleX(0) lo aplasta en
                       horizontal hasta que no se ve.
       none            sin ninguna transformación.
     transform-origin fija el punto desde el que gira o crece.

   position
     static    lo normal: el elemento va en el flujo de la página.
     relative  en su sitio, pero sirve de referencia para colocar dentro
               piezas en absolute.
     absolute  libre, encima de lo demás, medido desde los bordes de la caja
               madre que tenga position (relative, absolute, fixed, sticky).
     fixed     clavado a la ventana: no se mueve al bajar por la página.
     sticky    baja con la página hasta tocar un borde y allí se queda quieto.
     top, right, bottom, left dicen a qué distancia de cada borde se coloca;
     inset: 0 lo pega a los cuatro bordes a la vez.

   z-index
     Orden de apilado cuando dos elementos se solapan: el número más alto
     queda encima. Solo funciona en elementos con position (distinto de
     static).

   opacity
     Transparencia del elemento entero, con todo lo que tiene dentro:
     1 = se ve del todo; 0 = invisible (aunque sigue ocupando su sitio).

   display
     Cómo se coloca un elemento: block (ocupa su propio renglón), inline-block
     (va dentro de la línea de texto pero admite medidas), flex (coloca a sus
     hijos en fila o en columna; gap es el hueco entre ellos), grid (en
     rejilla), none (no se muestra ni ocupa sitio).

   Cajas
     Cada elemento es una caja: el contenido, el relleno por dentro
     (padding), el borde (border) y la separación por fuera (margin).
     padding-inline = relleno a izquierda y derecha; padding-block = arriba
     y abajo. Con varios valores: dos = «arriba y abajo» y «lados»; tres =
     arriba, lados, abajo; cuatro = arriba, derecha, abajo, izquierda (como
     las agujas del reloj).

   !important
     Añadido al final de una declaración, la hace ganar a cualquier otra.
     Esta hoja no lo usa: el orden y la precisión de los selectores bastan.

   CÓMO SE DECIDE QUÉ REGLA GANA
     Si varias reglas dan valores distintos a la misma propiedad del mismo
     elemento:
     1. Gana la que lleve !important.
     2. Si no, gana la más PRECISA: un id (#x) pesa más que una clase (.x),
        un atributo ([x]) o una pseudo-clase (:hover), y estos más que una
        etiqueta (a, img). Varias clases juntas pesan más que una sola, así
        que «.site-header.is-transparente .nav__link» gana a «.nav__link».
     3. A igualdad, gana la que aparece MÁS ABAJO en el archivo.
     Dentro de una misma regla pasa igual: si una propiedad se escribe dos
     veces, vale la segunda. Se usa para dar primero una versión de reserva
     y después la moderna: el navegador que no entiende la segunda la ignora
     y se queda con la primera.
     Estar dentro de un @media no da más peso: solo hace que la regla valga
     o no valga según la pantalla.
     Algunos valores pasan de padres a hijos (el color y el tipo de letra):
     inherit pide expresamente el del padre.
     Un estilo que JavaScript pone directamente en un elemento gana a lo que
     dice este archivo.
   ========================================================================== */

/* ==========================================================================
   1 · VARIABLES (paleta, medidas, movimiento)
   --------------------------------------------------------------------------
   Los valores que se repiten por la web se guardan aquí con nombre, dentro
   de :root (la raíz de la página), para que valgan en todas partes.
   Cambiando uno aquí, cambia en toda la web. Varias de estas variables las
   leen también los guiones de js/, que no llevan sus propios valores.
   ========================================================================== */

:root {                     /* abre la lista de variables de toda la web */
  /* Paleta de marca: los cinco colores de la web. */
  --principal:    #3C1621;  /* burdeos: color del texto y de los fondos de acento */
  --secundario:   #A59B92;  /* gris topo (piedra): texto secundario y filetes */
  --contraste-1:  #B98E5D;  /* caramelo: acentos y estados activos (ratón encima, seleccionado) */
  --contraste-2:  #D1B594;  /* arena: acentos suaves sobre fondo oscuro */
  --claro:        #E5E2DF;  /* crema: fondo general de la página */

  /* Tipografías (familias de letra)
     --display: SOLO para titulares (h1 y h2).
     --texto:   todo lo demás: párrafos, menú, botones, cifras, pies.
     Cada una es una lista de reserva: el navegador usa la primera que tenga
     y, si le falta, pasa a la siguiente. Las dos primeras (Playfair Display
     y Montserrat) van incluidas en la web, en la carpeta fuentes/, así que
     todo visitante las ve; las de detrás solo entran si fallara la descarga. */
  --display: "Playfair Display", Georgia, "Times New Roman", serif;  /* letra con remates, de titular */
  /* Letra sin remates; detrás, las del sistema de Apple y de Windows y, al final, cualquiera sin remates. */
  --texto:   "Montserrat", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;

  /* Medidas */
  --header-h: 88px;                         /* alto de la cabecera (76 px en pantallas estrechas) */
  --margen:   clamp(1.25rem, 4vw, 3.5rem);  /* margen lateral: 4 % del ancho, entre 20 y 56 px */

  /* Aire (espacio vacío) de las secciones del home: el de arriba y abajo de
     cada sección, y el que queda entre Section 2 y Section 3, que va más
     apretado. */
  --aire-seccion: clamp(4.5rem, 10vw, 9rem);  /* 10 % del ancho, entre 72 y 144 px */
  --aire-entre:   clamp(2rem, 4.5vw, 4rem);   /* 4,5 % del ancho, entre 32 y 64 px */

  /* Pase de imágenes de la portada (hero): duración total y retraso entre
     la salida de una imagen y la de la siguiente. Cada imagen se mueve
     durante --pase menos dos veces --desfase, es decir, 1,6 s.
     La segunda imagen sale un 25 % más tarde que el paso normal (a los
     0,25 s); la tercera mantiene sus 0,4 s (dos veces --desfase) para que
     el conjunto siga durando 2 s. */
  --pase:      2s;      /* lo que dura el pase entero */
  --desfase:   .2s;     /* retraso base entre una imagen y la siguiente */
  --desfase-2: .25s;    /* retraso propio de la segunda imagen */

  /* Paso de Section 2 a Section 3: la fotografía da media vuelta sobre su
     eje vertical mientras baja y cruza a la izquierda; gira como una página
     que se pasa, no como una persiana. Son 180deg justos porque es lo que
     tarda la cara de detrás en quedar de frente. */
  --giro: 180deg;       /* media vuelta */

  /* Ritmo del movimiento -------------------------------------------------
     De aquí sale todo lo que se mueve al pulsar algo: el paso a Proyectos,
     la formación de la cuadrícula, la apertura y el cierre del visor y la
     transición lateral entre páginas. Ningún elemento se desplaza durante
     más de --mov, y los escalonamientos (piezas que arrancan una detrás de
     otra) van por DENTRO de ese tiempo, no detrás.

     Es el único sitio donde se toca el ritmo: js/paso.js y js/visor.js leen
     estos valores de aquí en lugar de llevar los suyos, así que no hay dos
     relojes que puedan descuadrarse. Subiendo o bajando --mov, toda la web
     se vuelve más pausada o más ágil sin tocar ninguna otra línea.

     El pase del hero (--pase) y el giro de Section 2 quedan fuera: aquel es
     ambiente de fondo y este lo manda el scroll, no un clic. Si el visitante
     pide menos movimiento, la sección 12 deja estos tiempos casi en cero. */
  --mov:       600ms;   /* duración máxima de un movimiento tras un clic (0,6 s) */
  --mov-breve: 400ms;   /* versión corta, para piezas pequeñas del visor (0,4 s) */

  /* Apagado del home al pulsar «Ver Proyectos». Va aparte y es corto a
     propósito: mientras dura, la foto está quieta y no se mueve nada. Es
     tiempo de espera, no animación, así que no debe crecer con --mov: lo
     justo para que el cambio de página no se lea como un corte. */
  --mov-salida: 100ms;  /* 0,1 s */

  /* Salida lateral: la página que se va se retira de lado antes de que
     cargue la siguiente. Es movimiento de verdad, así que dura algo más que
     el apagado anterior, pero poco: la página se retira de un gesto y la que
     llega hace el recorrido largo (--mov). */
  --mov-salida-lado: 200ms;  /* 0,2 s */

  /* Curva de velocidad de esos movimientos. Va emparejada con la duración:
     esta arranca con calma y frena largo (hace el 50 % del camino en el 31 %
     del tiempo), que es lo que da el aire de la casa a 600 ms.
     OJO: si algún día se baja --mov por debajo de 400 ms, hay que volver a
     cubic-bezier(.32, .72, 0, 1), que sale disparada (78 % del camino en el
     primer 25 % del tiempo); con la de ahora, a esa velocidad, el movimiento
     parece arrancar tarde. Y al revés: aquella, a 600 ms, se lee como un
     tirón seco seguido de medio segundo de deriva. */
  --mov-curva: cubic-bezier(.4, 0, .1, 1);  /* arranque suave y frenada larga */

  /* Colores del pie de página. No son fijos: copian los de la página sobre
     la que se apoya, para que el pie nunca se lea como una banda pegada al
     final. Todas las páginas terminan en fondo claro (el home también), así
     que hoy no hay ninguna excepción. */
  --fondo-pie: var(--claro);       /* fondo del pie: crema */
  --tinta-pie: var(--principal);   /* texto del pie: burdeos */

  /* Aparición al bajar ---------------------------------------------------
     Cómo se mueve un bloque cuando asoma por abajo al bajar por la página
     (sección 16). Va aparte de --mov porque aquello lo dispara un clic y
     esto lo manda el scroll: aquí conviene ir más despacio y más largo, para
     que se lea como algo que se posa y no como algo que salta.
     js/main.js lee --revela y --revela-paso de aquí, igual que paso.js lee
     --mov, para que no haya dos relojes que puedan descuadrarse. */
  --revela:       900ms;                          /* lo que tarda cada pieza en llegar (0,9 s) */
  --revela-paso:  70ms;                           /* retraso entre una pieza y la siguiente */
  --revela-salto: 2rem;                           /* desde cuánto más abajo sube (32 px) */
  --revela-curva: cubic-bezier(.22, .61, .36, 1); /* sale rápida y se posa suave */

  /* Retraso entre un texto y el siguiente (título, párrafo, botón) dentro de
     un mismo bloque. Es mucho mayor que --revela-paso a propósito: aquí no
     se busca una onda casi simultánea sino que se vea entrar cada pieza por
     orden. Con 280 ms, cuando arranca el párrafo el título ya ha hecho unas
     dos terceras partes de su subida: se solapan, pero poco. */
  --entrada-paso: 280ms;  /* 0,28 s entre texto y texto */

  /* Tinta suave para etiquetas y pies de foto ---------------------------
     El gris topo sobre el crema solo llega a un contraste de 2,1:1 (la
     proporción de luz entre texto y fondo) y no se lee: está por debajo de
     lo que pide cualquier texto pequeño. Esto es el burdeos de la marca al
     68 %, que sube a 5,0:1 y mantiene el tono apagado que se buscaba. No es
     un color de fuera de la paleta: es uno de dentro con el fondo asomando
     por debajo, igual que los filetes y las sombras de toda la hoja.
     --secundario se queda para lo que va sobre fondo oscuro, donde sí se
     lee (por ejemplo, en el visor de fotografías). */
  --tinta-suave: rgba(60, 22, 33, .68);  /* burdeos de la marca con un 68 % de opacidad */
}                                        /* fin de :root (variables) */

/* ==========================================================================
   2 · TIPOGRAFÍAS
   --------------------------------------------------------------------------
   Los archivos de letra van dentro del proyecto (carpeta fuentes/): no los
   sirve nadie de fuera. Así la página no abre conexión con ningún tercero al
   cargar y ningún dato del visitante (su IP, su navegador) sale hacia otro
   servidor, que es lo que exige el RGPD (en varios países ya se ha
   sancionado usar Google Fonts desde sus servidores).
   Son las dos familias de la web en su versión «variable»: un solo archivo
   cubre todos los grosores que se usan. Llevan solo los caracteres
   latinos, que incluyen todas las tildes, la eñe y los signos de apertura.
   ========================================================================== */

/* Letra de titulares: Playfair Display. */
@font-face {                                                   /* da de alta una tipografía */
  font-family: "Playfair Display";                             /* nombre con el que se la llama */
  font-style: normal;                                          /* versión recta, no cursiva */
  font-weight: 400 500;                                        /* cubre los grosores 400 (normal) a 500 */
  font-display: swap;                                          /* mientras carga, el texto sale con otra letra */
  src: url("../fuentes/playfair-latin.woff2") format("woff2");  /* archivo (../ = subir desde css/) */
  /* Caracteres que trae el archivo, por su código Unicode (el número de cada
     letra o signo): letras latinas con tildes, comillas, guiones, euro… */
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}                                                              /* fin de Playfair Display */

/* Letra de texto: Montserrat. */
@font-face {                                                   /* da de alta una tipografía */
  font-family: "Montserrat";                                   /* nombre con el que se la llama */
  font-style: normal;                                          /* versión recta, no cursiva */
  font-weight: 300 500;                                        /* cubre los grosores 300 (fino) a 500 */
  font-display: swap;                                          /* mientras carga, el texto sale con otra letra */
  src: url("../fuentes/montserrat-latin.woff2") format("woff2");  /* archivo de la letra */
  /* Mismos caracteres que la anterior. */
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}                                                              /* fin de Montserrat */

/* ==========================================================================
   3 · BASE
   --------------------------------------------------------------------------
   Ajustes generales que valen para todas las páginas: cómo se miden las
   cajas, color y letra de la página, imágenes, enlaces, el hueco del pie,
   el recuadro de foco para quien navega con teclado y dos ayudas de
   accesibilidad (el enlace de salto y el texto solo para lectores de
   pantalla, los programas que leen la página en voz alta).
   ========================================================================== */

/* Todos los elementos, y sus piezas ::before y ::after: el ancho y el alto
   que se les da incluyen ya el relleno y el borde. Así una caja de 40 px
   mide 40 px de verdad, lleve el relleno que lleve. */
*,
*::before,
*::after { box-sizing: border-box; }

/* La página entera (etiqueta <html>). */
html {
  -webkit-text-size-adjust: 100%;  /* impide que el móvil agrande el texto por su cuenta al girarlo */
  /* El hueco de la barra de desplazamiento se reserva siempre. Sin esto,
     cada vez que algo bloquea el scroll (el visor, el menú móvil) la barra
     desaparece, la página se ensancha unos 15 px y todo pega un salto
     lateral al abrir y otro al cerrar. */
  scrollbar-gutter: stable;
}                                  /* fin de html */

/* El cuerpo de la página: todo lo que se ve. */
body {
  margin: 0;                            /* quita el margen que el navegador pone alrededor */
  background: var(--claro);             /* fondo crema */
  color: var(--principal);              /* texto burdeos (lo heredan todos los elementos) */
  font-family: var(--texto);            /* letra de texto para todo, salvo los titulares */
  font-weight: 400;                     /* grosor normal */
  line-height: 1.6;                     /* alto de renglón: 1,6 veces la letra, para leer con aire */
  -webkit-font-smoothing: antialiased;  /* en Mac, dibuja la letra más fina y suave */
}                                       /* fin de body */

/* Imágenes: cada una en su propio renglón (sin el hueco que deja debajo
   una imagen metida en una línea de texto), nunca más anchas que su caja y
   con el alto proporcional, para que no se deformen. */
img { display: block; max-width: 100%; height: auto; }

/* Hueco reservado al pie al final de cada página. El pie va fijo y solo
   sube al llegar al final, así que sin este hueco taparía el último trozo
   de página. Se pinta del mismo color que el pie para que no se vea una
   franja de otro color mientras el pie aún no ha subido. El alto lo mide
   js/main.js y lo guarda en --alto-pie. */
body::after {
  content: "";                    /* crea la pieza (vacía) */
  display: block;                 /* ocupa su propio renglón, a todo el ancho */
  height: var(--alto-pie, 0px);   /* tan alta como el pie; 0 mientras main.js no lo mida */
  background: var(--fondo-pie);   /* del color del fondo del pie */
}                                 /* fin de body::after */

a { color: inherit; text-decoration: none; }  /* enlaces: del color del texto que los rodea, sin subrayar */

/* Recuadro que marca lo que está seleccionado cuando se navega con el
   teclado (tecla Tab). Con el ratón no aparece. */
:focus-visible {
  outline: 2px solid var(--contraste-1);  /* línea caramelo de 2 px alrededor */
  outline-offset: 4px;                    /* separada 4 px del elemento */
}

/* Enlace «Saltar al contenido», el primero de cada página. Está escondido
   fuera de la pantalla y aparece arriba a la izquierda al llegar a él con
   el tabulador, para que quien navega con teclado o con lector de pantalla
   pueda saltarse la cabecera. */
.skip-link {
  position: absolute;            /* libre, fuera del flujo de la página */
  left: -9999px;                 /* muy lejos por la izquierda: fuera de la vista */
  top: 0;                        /* pegado arriba */
  z-index: 100;                  /* por encima de todo, también de la cabecera (50) */
  padding: .75rem 1.25rem;       /* relleno: 12 px arriba y abajo, 20 px a los lados */
  background: var(--principal);  /* fondo burdeos */
  color: var(--claro);           /* texto crema */
  font-size: .8rem;              /* letra pequeña (unos 13 px) */
  letter-spacing: .1em;          /* letras algo separadas */
  text-transform: uppercase;     /* en mayúsculas */
}                                /* fin de .skip-link */
.skip-link:focus { left: 0; }    /* al llegar con el teclado, entra en pantalla por la izquierda */

/* Texto para lectores de pantalla y buscadores, invisible en la página.
   Se reduce a un punto de 1 px recortado en vez de ocultarlo con
   display: none, porque lo oculto así tampoco lo leen los lectores. */
.solo-lectores {
  position: absolute;      /* fuera del flujo: no empuja nada */
  width: 1px;              /* 1 px de ancho */
  height: 1px;             /* 1 px de alto */
  margin: -1px;            /* retirado ese píxel, para que no ocupe sitio */
  padding: 0;              /* sin relleno */
  border: 0;               /* sin borde */
  overflow: hidden;        /* lo que no cabe en ese píxel no se ve */
  clip-path: inset(50%);   /* recorta la caja por los cuatro lados hasta dejarla en nada */
  white-space: nowrap;     /* el texto en un solo renglón, sin partirse */
}                          /* fin de .solo-lectores */

/* ==========================================================================
   4 · CABECERA Y MENÚ
   --------------------------------------------------------------------------
   La franja fija de arriba de todas las páginas: el logotipo a la izquierda
   y, a la derecha, el menú (Proyectos, Quiénes Somos, Contacto), el icono de
   Instagram y, en pantallas estrechas, el botón que abre el menú.
   En el home la cabecera flota sobre la foto de portada: arranca
   transparente, con el logotipo y la letra en claro (clase .is-transparente,
   que ya viene escrita en el HTML de index.html), y en cuanto se baja un
   poco (más de 24 px) main.js le quita esa clase y la cabecera toma fondo
   crema con letra burdeos. También se la quita mientras el menú del móvil
   está abierto. Las demás páginas no llevan esa clase: su cabecera tiene
   fondo claro siempre.
   Aquí están también los estados del menú (ratón encima, seleccionado con el
   teclado) con su subrayado caramelo, y la X en que se convierte el botón de
   menú al abrirlo. El menú desplegable del móvil está en la sección 12.
   Sin JavaScript la cabecera no puede reaccionar al scroll, así que
   index.html la deja sólida desde el principio (en su bloque <noscript>).
   ========================================================================== */

/* La cabecera entera: clavada arriba de la ventana, de lado a lado y por
   encima del resto de la página. */
.site-header {
  position: fixed;                         /* clavada a la ventana: no se va al bajar */
  top: 0;                                  /* pegada al borde de arriba */
  left: 0;                                 /* desde el borde izquierdo… */
  right: 0;                                /* …hasta el derecho: todo el ancho */
  z-index: 50;                             /* por encima del contenido de la página */
  background: var(--claro);                /* fondo crema */
  transition: background-color .45s ease;  /* el paso de transparente a crema (y al revés) dura 0,45 s */
}                                          /* fin de .site-header */

/* En el home, arriba del todo (con .is-transparente), la cabecera no tiene
   fondo: se ve la foto a través. */
.site-header.is-transparente { background: transparent; }

/* Velo tenue bajo la cabecera transparente: sin él, el logotipo claro y el
   menú se pierden sobre las zonas claras de la foto. Es una pieza extra
   (::before) que cubre la cabecera y que solo se ve mientras es
   transparente. */
.site-header::before {
  content: "";                    /* crea la pieza (vacía) */
  position: absolute;             /* libre, medida desde los bordes de la cabecera */
  inset: 0;                       /* la cubre entera */
  z-index: -1;                    /* detrás del logotipo y del menú, pero dentro de la cabecera */
  /* Degradado en línea recta («linear-gradient»): 180deg = de arriba abajo.
     Cada color lleva detrás el punto de la altura (en %) donde está puro;
     entre uno y otro, el navegador los funde poco a poco. */
  background: linear-gradient(180deg,
    rgba(42, 15, 23, .50) 0%,     /* arriba: burdeos más oscuro, al 50 % */
    rgba(42, 15, 23, .22) 60%,    /* al 60 % de la altura, al 22 % */
    rgba(42, 15, 23, 0) 100%);    /* abajo: del todo transparente */
  opacity: 0;                     /* de normal no se ve */
  transition: opacity .45s ease;  /* aparece y se va en 0,45 s, al ritmo del fondo */
  pointer-events: none;           /* no atrapa el ratón: los clics lo atraviesan */
}                                 /* fin del velo */

.site-header.is-transparente::before { opacity: 1; }  /* con la cabecera transparente, el velo se ve */

/* Fila interior de la cabecera: el logotipo a un extremo y el bloque de la
   derecha al otro. */
.site-header__inner {
  display: flex;                   /* pone a sus hijos en fila */
  align-items: center;             /* centrados en vertical, unos respecto a otros */
  justify-content: space-between;  /* uno en cada extremo, con el sobrante en medio */
  gap: 2rem;                       /* hueco mínimo de 32 px entre ellos */
  height: var(--header-h);         /* 88 px de alto (76 px en pantallas estrechas) */
  padding-inline: var(--margen);   /* margen lateral general a izquierda y derecha */
}                                  /* fin de la fila interior */

/* -------------------------------------------------------- el logotipo --- */

/* El enlace del logotipo lleva dentro dos versiones superpuestas: la
   oscura, para la cabecera con fondo, y la clara, para cuando es
   transparente sobre la foto. Se cambia de una a otra fundiéndolas. */
.logo {
  position: relative;  /* referencia para colocar la versión clara encima de la oscura */
  display: block;      /* caja propia (un enlace va de serie dentro de la línea de texto) */
  line-height: 0;      /* sin alto de renglón: la caja mide lo que la imagen, sin hueco de más */
}                      /* fin de .logo */

/* Las dos imágenes del logotipo. Cabecera y pie llevan la misma versión:
   solo la palabra, sin filete ni «NUEVO HOGAR», y al mismo tamaño para que
   los dos extremos de la página casen. */
.logo__img {
  height: 20px;                   /* 20 px de alto (16 px en pantallas estrechas) */
  width: auto;                    /* ancho automático, proporcional al alto */
  transition: opacity .45s ease;  /* el relevo entre las dos versiones se funde en 0,45 s */
}                                 /* fin de .logo__img */

/* La versión clara: colocada justo encima de la oscura y escondida. */
.logo__img--claro {
  position: absolute;  /* libre, medida desde los bordes del enlace .logo */
  top: 0;              /* arriba… */
  left: 0;             /* …a la izquierda: exactamente sobre la oscura */
  opacity: 0;          /* invisible de normal */
}                      /* fin de .logo__img--claro */

/* Cabecera transparente (sobre la foto): se esconde la oscura y se ve la
   clara. */
.site-header.is-transparente .logo__img--oscuro { opacity: 0; }
.site-header.is-transparente .logo__img--claro  { opacity: 1; }

/* -------------- bloque de la derecha: menú, Instagram y botón de menú --- */

/* Caja que pone en fila el menú, el icono de Instagram y el botón de menú. */
.site-header__derecha {
  display: flex;                        /* en fila */
  align-items: center;                  /* centrados en vertical */
  gap: clamp(1.25rem, 2.5vw, 2.25rem);  /* hueco entre ellos: 2,5 % del ancho, entre 20 y 36 px */
}

/* Enlace a Instagram: una caja de 40 × 40 px con el icono en el centro. La
   caja es mayor que el dibujo para que sea fácil acertar con el dedo. */
.social {
  display: flex;            /* coloca el icono dentro con flex… */
  align-items: center;      /* …centrado en vertical… */
  justify-content: center;  /* …y en horizontal */
  width: 40px;              /* 40 px de ancho */
  height: 40px;             /* 40 px de alto */
  margin-right: -8px;       /* se asoma 8 px: el dibujo queda alineado con el margen de la página */
  color: var(--principal);  /* burdeos; el icono toma este color (ver .social__icono) */
  /* Los cambios de color y de sombra (al bajar) tardan 0,45 s; el de
     transparencia (ratón encima), 0,35 s. */
  transition: color .45s ease, opacity .35s ease, filter .45s ease;
}                           /* fin de .social */

.social:hover { opacity: .6; }  /* con el ratón encima, se aclara (al 60 %) */

/* Instagram sobre la foto, con la cabecera transparente. */
.site-header.is-transparente .social {
  color: var(--claro);  /* icono crema */
  /* Sombra difusa que sigue la forma del dibujo (drop-shadow), para que se
     lea sobre zonas claras: 0 a los lados, 1 px hacia abajo, 8 px de
     difuminado, en burdeos más oscuro al 55 %. */
  filter: drop-shadow(0 1px 8px rgba(42, 15, 23, .55));
}

/* El dibujo del icono: un <svg>, un dibujo hecho de líneas y formas dentro
   del HTML. fill es el relleno de las formas y stroke, su contorno. */
.social__icono {
  width: 21px;           /* 21 px de ancho */
  height: 21px;          /* 21 px de alto */
  fill: none;            /* sin relleno: solo se dibuja el contorno */
  stroke: currentColor;  /* contorno del color del texto del enlace (burdeos o crema) */
  stroke-width: 1.4;     /* grosor de línea: 1,4 unidades del dibujo (algo más de 1 px) */
}                        /* fin de .social__icono */

/* El puntito de la esquina de la cámara: relleno del color del texto y sin
   contorno. */
.social__punto { fill: currentColor; stroke: none; }

/* ------------------------------------------------------------ el menú --- */

/* La lista de enlaces del menú (también la usa el menú del pie): en fila y
   sin las viñetas ni la sangría que trae de serie una lista. */
.nav__list {
  display: flex;                   /* en fila */
  align-items: center;             /* centrados en vertical */
  gap: clamp(1.75rem, 3vw, 3rem);  /* hueco entre enlaces: 3 % del ancho, entre 28 y 48 px */
  margin: 0;                       /* sin margen de serie */
  padding: 0;                      /* sin sangría de serie */
  list-style: none;                /* sin viñetas */
}                                  /* fin de .nav__list */

/* Cada enlace del menú (Proyectos, Quiénes Somos, Contacto). */
.nav__link {
  position: relative;       /* referencia para colocar debajo el subrayado */
  display: inline-block;    /* en línea, pero admite relleno arriba y abajo */
  padding-block: .35rem;    /* relleno de 5,6 px arriba y abajo */
  font-size: .95rem;        /* letra de unos 15 px */
  font-weight: 400;         /* grosor normal */
  letter-spacing: .02em;    /* letras apenas separadas */
  color: var(--principal);  /* burdeos */
  /* El color y la sombra cambian en 0,45 s al pasar de transparente a
     sólida. */
  transition: color .45s ease, text-shadow .45s ease;
}                           /* fin de .nav__link */

/* Enlaces del menú sobre la foto, con la cabecera transparente. */
.site-header.is-transparente .nav__link {
  color: var(--claro);  /* letra crema */
  /* Sombra difusa detrás de las letras, para que se lean sobre la foto:
     0 a los lados, 1 px hacia abajo, 12 px de difuminado, burdeos más oscuro
     al 60 %. */
  text-shadow: 0 1px 12px rgba(42, 15, 23, .6);
}

/* Subrayado que aparece al pasar por encima: un filete caramelo, el mismo
   gesto que separa «alcasa» de «NUEVO HOGAR» en el logotipo completo de la
   marca. Está siempre ahí, pero aplastado hasta no verse, y se estira de
   izquierda a derecha. */
.nav__link::after {
  content: "";                     /* crea la pieza (vacía) */
  position: absolute;              /* libre, medida desde los bordes del enlace */
  left: 0;                         /* pegada a la izquierda… */
  bottom: 0;                       /* …y abajo del todo */
  width: 100%;                     /* todo el ancho de la palabra */
  height: 1px;                     /* línea de 1 px de grueso */
  background: var(--contraste-1);  /* caramelo */
  transform: scaleX(0);            /* aplastada del todo: no se ve */
  transform-origin: left;          /* cuando crezca, lo hará desde la izquierda */
  transition: transform .4s cubic-bezier(.22, .61, .36, 1);  /* se estira en 0,4 s, suave al final */
}                                  /* fin del subrayado */
/* Con el ratón encima, o seleccionado con el teclado, el subrayado se
   estira hasta su ancho entero. */
.nav__link:hover::after,
.nav__link:focus-visible::after { transform: scaleX(1); }

/* ----------------------------------------- botón de menú (solo móvil) --- */

/* El botón de dos rayitas que abre y cierra el menú. En pantallas anchas
   no se ve; en las estrechas la sección 12 lo muestra (display: flex). */
.nav-toggle {
  display: none;            /* oculto */
  flex-direction: column;   /* cuando se vea, las rayitas irán una encima de otra */
  justify-content: center;  /* centradas en vertical (en columna, justify-content va de arriba abajo) */
  gap: 6px;                 /* 6 px entre rayita y rayita */
  width: 44px;              /* 44 px de ancho: zona cómoda para el dedo */
  height: 44px;             /* 44 px de alto */
  padding: 0;               /* sin relleno de serie */
  border: 0;                /* sin el borde que el navegador pone a los botones */
  background: none;         /* sin el fondo gris de serie */
  cursor: pointer;          /* con ratón, el puntero se vuelve una mano */
}                           /* fin de .nav-toggle */

/* Cada una de las dos rayitas. */
.nav-toggle__bar {
  display: block;                /* caja propia, para poder darle medidas */
  width: 26px;                   /* 26 px de largo */
  height: 1.5px;                 /* 1,5 px de grueso */
  background: var(--principal);  /* burdeos */
  transition: transform .3s ease, background-color .45s ease;  /* giro en 0,3 s; color en 0,45 s */
}                                /* fin de .nav-toggle__bar */

/* Rayitas crema sobre la foto, con la cabecera transparente. */
.site-header.is-transparente .nav-toggle__bar { background: var(--claro); }

/* Menú abierto: main.js pone aria-expanded="true" en el botón (atributo que
   también avisa a los lectores de pantalla). Las dos rayitas se juntan en el
   centro y se cruzan en una X. 3,75 px es la mitad de la distancia entre sus
   centros (6 px de hueco + 1,5 px de grueso), para que se encuentren en
   medio. */
.nav-toggle[aria-expanded="true"] .nav-toggle__bar:first-child {  /* la de arriba… */
  transform: translateY(3.75px) rotate(45deg);                    /* …baja 3,75 px y gira 45° */
}
.nav-toggle[aria-expanded="true"] .nav-toggle__bar:last-child {   /* la de abajo… */
  transform: translateY(-3.75px) rotate(-45deg);                  /* …sube 3,75 px y gira al otro lado */
}

/* ==========================================================================
   5 · PORTADA (HERO) Y SECUENCIA DE ENTRADA
   --------------------------------------------------------------------------
   La foto grande que ocupa toda la pantalla al abrir el home, con encima el
   antetítulo («Cocinas a medida · Toda España»), el título de dos líneas, un
   filete y el botón «Pedir cita».
   Al cargar, un pase de tres fotos se desplaza hacia la izquierda y se queda
   fija la tercera. Cada foto va en versión grande y en versión para móvil,
   y cada una en dos formatos: JPEG, que entiende cualquier navegador, y
   AVIF, mucho más ligero, que solo se usa si el navegador lo admite
   (@supports). Abajo, una flecha invita a bajar.
   A la vez, los textos entran escalonados, uno detrás de otro: antetítulo,
   primera y segunda línea del título, filete y botón. Sus movimientos se
   describen con @keyframes al final de esta sección.
   El hero se queda anclado mientras Section 2 sube por encima; ese paso,
   atado al scroll, está en la sección 7. Si la persona pide menos
   movimiento, la sección 12 quita el pase y la entrada escalonada.
   ========================================================================== */

/* El hero entero: toda la pantalla, con el texto centrado. */
.hero {
  position: sticky;         /* baja con la página, pero al tocar arriba se queda pegado… */
  top: 0;                   /* …arriba del todo: Section 2 pasa por encima en vez de empujarlo */
  display: flex;            /* coloca el texto con flex… */
  align-items: center;      /* …centrado en vertical… */
  justify-content: center;  /* …y en horizontal */
  height: 100vh;            /* todo el alto de la ventana (reserva para navegadores sin svh) */
  height: 100svh;           /* los que entienden svh usan esta: nada queda tapado en el móvil */
  overflow: hidden;         /* lo que se salga del hero (las fotos en movimiento) no se ve */
  /* Fondo de reserva mientras las fotos del pase aún no han llegado: un
     degradado en elipse («radial-gradient»). «120% 90%» es el tamaño de la
     elipse (ancho y alto, respecto al hero) y «at 50% 0%», su centro: arriba
     en medio. Va de un burdeos algo más claro (#56222F) en el centro al
     burdeos de la marca (al 55 % del camino) y a un burdeos más oscuro
     (#2A0F17) en los bordes. */
  background:
    radial-gradient(120% 90% at 50% 0%, #56222F 0%, var(--principal) 55%, #2A0F17 100%);
}                           /* fin de .hero */

/* --------------------------------------------------- pase de imágenes --- */
/* Las tres fotos van apiladas una encima de otra, cada una del tamaño del
   hero entero. En reposo (sin animación) las dos primeras quedan fuera por
   la izquierda y la tercera en su sitio, así que, si la animación no llegara
   a ejecutarse, se vería la foto final y no un hueco. */

/* La caja que contiene las tres fotos. */
.hero__pase {
  position: absolute;  /* libre, medida desde los bordes del hero */
  inset: 0;            /* lo cubre entero, detrás del texto */
  overflow: hidden;    /* lo que se salga de ella no se ve */
}                      /* fin de .hero__pase */

/* Cada una de las tres capas del pase. Aquí la animación se escribe por
   partes (duración, relleno, curva); el nombre del movimiento y el retraso
   de cada foto van más abajo, en .hero__slide--1, --2 y --3. */
.hero__slide {
  position: absolute;            /* libre, medida desde los bordes de la caja del pase */
  inset: 0;                      /* del tamaño del hero: las tres quedan superpuestas */
  overflow: hidden;              /* recorta la foto cuando se acerca con el ratón */
  transform: translateX(-100%);  /* en reposo, fuera por la izquierda (la 3.ª lo corrige abajo) */
  animation-duration: calc(var(--pase) - 2 * var(--desfase));  /* cada foto se mueve 1,6 s: 2 s − 2 × 0,2 s */
  animation-fill-mode: both;     /* antes de su turno ya está como al empezar; al acabar, se queda */
  /* Aviso al navegador de que esta capa se va a mover: la prepara aparte, en
     su propia capa de dibujo, para que el movimiento vaya fluido. */
  will-change: transform;

  /* Curva de velocidad. La segunda declaración manda en los navegadores que
     entienden linear(); la primera queda de reserva para los que no. Un
     cubic-bezier no puede aplanarse tanto en los extremos como pide esta
     curva, por eso se usa linear() con puntos calculados. */
  animation-timing-function: cubic-bezier(.9, 0, .05, 1);  /* reserva: arranca y frena muy despacio */
  /* La curva de verdad, dibujada punto a punto. Cada pareja es «cuánto
     camino lleva» y «en qué momento»: .5044 50% = a la mitad del tiempo ha
     hecho la mitad del camino. */
  animation-timing-function:
    linear(0 0%, .0009 5%, .0035 10%, .008 15%, .0248 20%, .0641 25%,         /* 0–25 %: casi quieta */
           .1242 30%, .2023 35%, .2947 40%, .397 45%, .5044 50%, .6117 55%,   /* 30–55 %: el tramo rápido */
           .7136 60%, .8054 65%, .8826 70%, .9416 75%, .9795 80%, .9947 85%,  /* 60–85 %: frena */
           .9976 90%, .9994 95%, 1 100%);                                     /* 90–100 %: se posa */
}                                /* fin de .hero__slide */

/* La foto dentro de cada capa (va puesta como imagen de fondo). */
.hero__foto {
  position: absolute;           /* libre, medida desde los bordes de su capa */
  inset: 0;                     /* la llena entera */
  background-size: cover;       /* la foto cubre la caja sin deformarse, recortando lo que sobre */
  background-position: center;  /* centrada: el recorte se reparte por igual */
  transition: transform .7s cubic-bezier(.22, .61, .36, 1);  /* acercamiento en 0,7 s, suave al final */
}                               /* fin de .hero__foto */

/* Qué foto va en cada capa. background-image pone una imagen de fondo; en
   la ruta, «../» sube desde la carpeta css/ a la principal de la web.
   El orden del pase no coincide con el número de archivo: la primera que se
   ve es hero-2 y la segunda, hero-1.
   Cada foto va en dos tamaños (-grande y -movil) y dos formatos. El JPEG es
   el que entiende cualquier navegador; el AVIF pesa un tercio y lo cogen
   los que pueden, gracias al @supports de más abajo. Los originales siguen
   en la carpeta sin tocar: estos son los recortes para web. */
.hero__slide--1 .hero__foto { background-image: url("../IMG/hero/hero-2-grande.jpg"); }  /* primera foto */
.hero__slide--2 .hero__foto { background-image: url("../IMG/hero/hero-1-grande.jpg"); }  /* segunda foto */
.hero__slide--3 .hero__foto { background-image: url("../IMG/hero/hero-3-grande.jpg"); }  /* tercera (fija) */

/* Solo en los navegadores que entienden image-set() con type("image/avif")
   (una forma de ofrecer una imagen diciendo su formato), las fotos pasan a
   la versión AVIF. «x.avif» es un nombre de prueba: no se descarga nada. */
@supports (background-image: image-set(url("x.avif") type("image/avif"))) {
  .hero__slide--1 .hero__foto {  /* primera foto… */
    background-image: image-set(url("../IMG/hero/hero-2-grande.avif") type("image/avif"));  /* …en AVIF */
  }
  .hero__slide--2 .hero__foto {  /* segunda foto… */
    background-image: image-set(url("../IMG/hero/hero-1-grande.avif") type("image/avif"));  /* …en AVIF */
  }
  .hero__slide--3 .hero__foto {  /* tercera foto… */
    background-image: image-set(url("../IMG/hero/hero-3-grande.avif") type("image/avif"));  /* …en AVIF */
  }
}                                /* fin de @supports (AVIF grande) */

/* En pantallas de 900 px de ancho o menos no hace falta tanta imagen: se
   cargan los recortes para móvil (-movil), que pesan menos.
   OJO: index.html pide estas fotos por adelantado (sus líneas «preload») con
   el mismo corte de 900 px; si se cambia aquí, hay que cambiarlo también
   allí. */
@media (max-width: 900px) {
  .hero__slide--1 .hero__foto { background-image: url("../IMG/hero/hero-2-movil.jpg"); }  /* primera foto */
  .hero__slide--2 .hero__foto { background-image: url("../IMG/hero/hero-1-movil.jpg"); }  /* segunda foto */
  .hero__slide--3 .hero__foto { background-image: url("../IMG/hero/hero-3-movil.jpg"); }  /* tercera (fija) */

  /* Y, si el navegador lo admite, en AVIF (como arriba). */
  @supports (background-image: image-set(url("x.avif") type("image/avif"))) {
    .hero__slide--1 .hero__foto {  /* primera foto… */
      background-image: image-set(url("../IMG/hero/hero-2-movil.avif") type("image/avif"));  /* …en AVIF */
    }
    .hero__slide--2 .hero__foto {  /* segunda foto… */
      background-image: image-set(url("../IMG/hero/hero-1-movil.avif") type("image/avif"));  /* …en AVIF */
    }
    .hero__slide--3 .hero__foto {  /* tercera foto… */
      background-image: image-set(url("../IMG/hero/hero-3-movil.avif") type("image/avif"));  /* …en AVIF */
    }
  }                                /* fin de @supports (AVIF para móvil) */
}                                  /* fin de @media (fotos para móvil) */

/* Las tres arrancan casi a la vez, con un pequeño retraso entre una y otra
   (0 s, 0,25 s y 0,4 s): la primera se retira hacia la izquierda, la segunda
   la sigue y deja a la vista la tercera, que llega con un ligero arrastre y
   se queda. Van apiladas y no en fila porque, si entraran todas desde
   fuera, durante el barrido quedaría media pantalla vacía por la izquierda:
   así siempre hay una foto debajo cubriendo. */

/* Primera foto: la de más arriba (capa 3); hace «salir» y arranca en seguida. */
.hero__slide--1 { z-index: 3; animation-name: salir;   animation-delay: 0s; }
/* Segunda foto: debajo (capa 2); también «salir», a los 0,25 s (--desfase-2). */
.hero__slide--2 { z-index: 2; animation-name: salir;   animation-delay: var(--desfase-2); }
/* Tercera foto: la de más abajo (capa 1); hace «asentar» y arranca a los
   0,4 s (dos veces --desfase). */
.hero__slide--3 { z-index: 1; animation-name: asentar; animation-delay: calc(2 * var(--desfase));
                  transform: translateX(0); }  /* en reposo, en su sitio: sin animación se ve esta */

/* Movimiento «salir» (primera y segunda foto): de tapar la pantalla a
   quedar fuera por la izquierda. */
@keyframes salir {
  from { transform: translateX(0); }      /* empieza en su sitio */
  to   { transform: translateX(-100%); }  /* acaba desplazada su ancho entero a la izquierda */
}

/* Movimiento «asentar» (tercera foto): entra con un ligero arrastre desde
   la derecha y se queda. */
@keyframes asentar {
  from { transform: translateX(12%); }  /* empieza un 12 % desplazada a la derecha */
  to   { transform: translateX(0); }    /* acaba en su sitio */
}

/* Solo con ratón: al pasar por encima del hero, la foto final se acerca un
   poco. */
@media (hover: hover) {
  .hero:hover .hero__slide--3 .hero__foto { transform: scale(1.05); }  /* la foto final crece un 5 % */
}

/* ------------------------------------------------------ velo y textos --- */

/* Velo que oscurece la foto para que el texto claro se lea. */
.hero__veil {
  position: absolute;                    /* libre, medida desde los bordes del hero */
  inset: 0;                              /* lo cubre entero */
  z-index: 4;                            /* encima de las tres fotos (capas 1 a 3) y debajo del texto (5) */
  /* Tres capas de fondo, separadas por comas; la primera queda encima:
     1. un halo que oscurece detrás del texto,
     2. un degradado neutro (negro) que da contraste arriba y abajo,
     3. un tinte burdeos muy leve.
     Neutro en vez de burdeos puro para no ensuciar las maderas y los beige
     de las fotos. */
  background:
    radial-gradient(75% 55% at 50% 44%,  /* 1. halo en elipse, centrado algo por encima de la mitad */
      rgba(42, 15, 23, .42) 0%,          /* en el centro, burdeos más oscuro al 42 % */
      rgba(42, 15, 23, .12) 60%,         /* al 60 % del radio, al 12 % */
      transparent 100%),                 /* en el borde de la elipse, nada */
    linear-gradient(180deg,              /* 2. degradado de arriba abajo */
      rgba(0, 0, 0, .40) 0%,             /* arriba, negro al 40 % (detrás de la cabecera) */
      rgba(0, 0, 0, .24) 42%,            /* hacia el centro, más suave: al 24 % */
      rgba(0, 0, 0, .60) 100%),          /* abajo, negro al 60 % (detrás de la flecha) */
    /* 3. De un color al mismo color: da un tinte liso, el burdeos de la
       marca al 16 %, igual en toda la foto. */
    linear-gradient(0deg, rgba(60, 22, 33, .16), rgba(60, 22, 33, .16));
}                                        /* fin de .hero__veil */

/* Caja del texto del hero: antetítulo, título, filete y botón. */
.hero__content {
  position: relative;             /* en su sitio, pero admite z-index */
  z-index: 5;                     /* por encima del velo */
  width: min(72rem, 100%);        /* como mucho 72 rem (1152 px); en ventanas estrechas, todo el ancho */
  padding-inline: var(--margen);  /* margen lateral general a izquierda y derecha */
  /* Relleno arriba: el alto de la cabecera más 16 px, porque la cabecera
     flota encima y taparía el texto. Abajo, 80 px: el sitio de la flecha. */
  padding-block: calc(var(--header-h) + 1rem) 5rem;
  text-align: center;             /* texto centrado */
}                                 /* fin de .hero__content */

/* Antetítulo: la línea pequeña de encima del título. */
.hero__eyebrow {
  margin: 0;                                /* sin el margen de serie de un párrafo */
  color: var(--contraste-2);                /* arena */
  font-size: clamp(.68rem, 1.1vw, .78rem);  /* pequeña: 1,1 % del ancho, entre unos 11 y 12,5 px */
  font-weight: 500;                         /* algo más gruesa que el texto normal */
  letter-spacing: .3em;                     /* letras muy separadas */
  text-transform: uppercase;                /* en mayúsculas */
}                                           /* fin de .hero__eyebrow */

/* Título principal del hero (el <h1> de la página). */
.hero__title {
  margin: clamp(1.5rem, 3vw, 2.25rem) 0 0;  /* 24 a 36 px por arriba; nada a los lados ni abajo */
  color: var(--claro);                      /* crema */
  font-family: var(--display);              /* letra de titulares (Playfair Display) */
  font-weight: 400;                         /* sin negrita (un título la trae de serie) */
  font-size: clamp(2.2rem, 5.6vw, 5rem);    /* grande: 5,6 % del ancho, entre 35 y 80 px */
  line-height: 1.1;                         /* renglones muy juntos */
  letter-spacing: -.005em;                  /* letras una pizca más juntas (valor negativo) */
}                                           /* fin de .hero__title */

/* Cada línea del título (cada <span>) en su propio renglón, para que puedan
   entrar por separado. */
.hero__line { display: block; }

/* Filete caramelo bajo el título, la firma de la casa. Al cargar la página
   se dibuja desde el centro hacia los lados (ver «trazar», más abajo). */
.hero__rule {
  display: block;                                 /* caja propia, para darle medidas */
  width: clamp(3.5rem, 7vw, 6rem);                /* largo: 7 % del ancho, entre 56 y 96 px */
  height: 2px;                                    /* 2 px de grueso */
  margin: clamp(1.75rem, 3.5vw, 2.75rem) auto 0;  /* 28 a 44 px por arriba; «auto» a los lados lo centra */
  background: var(--contraste-1);                 /* caramelo */
  /* Sombra tenue: sin ella el filete desaparece sobre las zonas claras de la
     foto. 0 a los lados, 1 px hacia abajo, 4 px de difuminado, burdeos más
     oscuro al 55 %. */
  box-shadow: 0 1px 4px rgba(42, 15, 23, .55);
}                                                 /* fin de .hero__rule */

/* ----------------------------------------------------------- el botón --- */

/* Botón de contorno fino, sin relleno: el «Pedir cita» del hero. Lo usan
   también otros botones del home, que añaden la variante .btn-outline--tinta
   (más abajo en el archivo) para ir sobre fondo claro. */
.btn-outline {
  display: inline-block;                       /* en línea, pero admite relleno y márgenes */
  margin-top: clamp(1.75rem, 3.5vw, 2.75rem);  /* separación con lo de encima: 28 a 44 px */
  padding: 1.1rem 3.25rem;                     /* relleno: 17,6 px arriba y abajo, 52 px a los lados */
  border: 1px solid rgba(229, 226, 223, .55);  /* contorno: línea continua de 1 px, crema al 55 % */
  /* Sirve tanto para enlaces <a> como para botones <button>: sin las cuatro
     líneas siguientes, el navegador le pinta al botón su fondo gris y sus
     esquinas redondeadas. */
  border-radius: 0;                            /* esquinas en ángulo recto */
  background: transparent;                     /* sin fondo */
  -webkit-appearance: none;                    /* lo mismo que la línea siguiente, para Safari */
          appearance: none;                    /* quita el aspecto de botón que pone el sistema */
  color: var(--claro);                         /* texto crema */
  font-size: .8rem;                            /* letra pequeña (unos 13 px) */
  font-weight: 500;                            /* algo más gruesa que la normal */
  letter-spacing: .22em;                       /* letras bien separadas */
  text-transform: uppercase;                   /* en mayúsculas */
  /* Fondo, contorno y texto cambian en 0,4 s. */
  transition: background-color .4s ease, border-color .4s ease, color .4s ease;
}                                              /* fin de .btn-outline */

/* Con el ratón encima, o seleccionado con el teclado, el botón se rellena
   de caramelo. */
.btn-outline:hover,
.btn-outline:focus-visible {
  background: var(--contraste-1);    /* fondo caramelo */
  border-color: var(--contraste-1);  /* contorno caramelo */
  color: var(--principal);           /* texto burdeos */
}                                    /* fin del botón activo */

/* --------------------------------------------------- flecha de bajada --- */

/* Enlace con la flecha, abajo en el centro del hero: lleva a Section 2. */
.hero__scroll {
  position: absolute;       /* libre, medida desde los bordes del hero */
  left: 50%;                /* su borde izquierdo, en la mitad del ancho */
  bottom: 2rem;             /* a 32 px del borde de abajo */
  z-index: 5;               /* encima del velo */
  display: flex;            /* coloca la flecha con flex… */
  align-items: center;      /* …centrada en vertical… */
  justify-content: center;  /* …y en horizontal */
  width: 44px;              /* zona de pulsación de 44 px de ancho… */
  height: 44px;             /* …y 44 px de alto */
  margin-left: -22px;       /* retrocede la mitad de su ancho: así queda centrada de verdad */
}                           /* fin de .hero__scroll */

/* La flecha: un cuadradito de 11 px del que solo se pintan los bordes
   derecho e inferior. Girado 45°, esa esquina apunta hacia abajo y se lee
   como una uve. */
.hero__arrow {
  display: block;                              /* caja propia, para darle medidas */
  width: 11px;                                 /* 11 px de ancho */
  height: 11px;                                /* 11 px de alto */
  border-right: 1px solid var(--claro);        /* lado derecho: línea crema de 1 px */
  border-bottom: 1px solid var(--claro);       /* lado de abajo: igual */
  transform: rotate(45deg);                    /* girado un octavo de vuelta */
  animation: bajar 2.4s ease-in-out infinite;  /* movimiento «bajar»: 2,4 s, suave, sin parar */
}                                              /* fin de .hero__arrow */

/* Movimiento «bajar»: la flecha baja un poco y vuelve, como un latido.
   Repite el giro de 45° en cada fotograma porque transform se sustituye
   entero. Como translate va después de rotate, se mide en los ejes ya
   girados: 4 px y 4 px en diagonal equivalen a bajar en vertical. */
@keyframes bajar {
  0%, 100% { transform: rotate(45deg) translate(0, 0); opacity: .75; }    /* inicio y fin: quieta, al 75 % */
  50%      { transform: rotate(45deg) translate(4px, 4px); opacity: 1; }  /* a mitad: baja y se ve entera */
}

/* ----------------------------------------------- secuencia de entrada --- */
/* Los textos del hero entran uno detrás de otro al cargar la página. Todo
   con CSS, sin JavaScript: si algo falla, el contenido se ve igual. */

/* Movimiento «surgir»: el texto aparece mientras sube hasta su sitio. */
@keyframes surgir {
  from { opacity: 0; transform: translateY(1.25rem); }  /* empieza invisible y 20 px más abajo */
  to   { opacity: 1; transform: none; }                 /* acaba visible y en su sitio */
}

/* Movimiento «trazar»: el filete se estira desde el centro (el punto desde
   el que crece si no se dice otro). */
@keyframes trazar {
  from { transform: scaleX(0); }  /* empieza aplastado: no se ve */
  to   { transform: scaleX(1); }  /* acaba a su ancho entero */
}

/* Orden de entrada. Todos usan la misma curva (rápida al principio y suave
   al llegar) y «both», así que cada pieza espera escondida hasta su turno.
   Cambia el retraso, el penúltimo valor: antetítulo a 0,15 s, primera línea
   del título a 0,30 s, segunda a 0,43 s, filete a 0,70 s y botón a 0,90 s.
   Cada texto tarda 0,9 s en llegar; el filete se traza en 1 s. Solo entra
   así el botón del hero (.hero .btn-outline), no los demás botones. */
.hero__eyebrow           { animation: surgir .9s cubic-bezier(.22, .61, .36, 1) .15s both; }  /* antetítulo */
.hero__line:nth-child(1) { animation: surgir .9s cubic-bezier(.22, .61, .36, 1) .30s both; }  /* 1.ª línea */
.hero__line:nth-child(2) { animation: surgir .9s cubic-bezier(.22, .61, .36, 1) .43s both; }  /* 2.ª línea */
.hero__rule              { animation: trazar 1s  cubic-bezier(.22, .61, .36, 1) .70s both; }  /* filete */
.hero .btn-outline       { animation: surgir .9s cubic-bezier(.22, .61, .36, 1) .90s both; }  /* botón */

/* ==========================================================================
   6 · SECTION 2
   --------------------------------------------------------------------------
   Primer bloque del home después de la foto grande de portada (el «hero»).
   Tiene dos columnas: a la izquierda el texto (título, párrafo y una rayita)
   y a la derecha una foto. Section 3 (sección 7) es igual pero con
   las columnas cambiadas, así que muchas reglas sirven para las dos a la vez
   (sus selectores van separados por comas: «.section2, .section3» = «a los
   dos»).
   En pantallas anchas, al bajar, la foto de Section 2 «viaja» hasta Section 3
   dando media vuelta como una carta: eso está en la sección 7, en «el viaje
   de la fotografía».
   ========================================================================== */

/* Las dos secciones enteras: fondo y color de letra. */
.section2,
.section3 {
  position: relative;        /* Se queda en su sitio normal, pero así admite z-index (orden de capas). */
  background: var(--claro);  /* Fondo crema de la marca. */
  color: var(--principal);   /* Letra en burdeos. */
}                            /* fin de las dos secciones */

/* Caja interior de cada sección: reparte texto y foto en dos columnas.
   Usa una rejilla («grid»): el contenido se coloca en filas y columnas, como
   en una tabla invisible. «fr» es una parte del espacio libre: «1fr 1fr»
   son dos columnas de igual ancho. */
.section2__inner,
.section3__inner {
  display: grid;                   /* Activa la rejilla. */
  grid-template-columns: 1fr 1fr;  /* Dos columnas iguales. */
  align-items: center;             /* Texto y foto centrados en vertical, uno respecto al otro. */
  gap: clamp(2.5rem, 6vw, 6rem);   /* Hueco entre columnas: 6 % del ancho de la ventana, entre 2,5 y 6 rem. */
  max-width: 90rem;                /* No se ensancha más de 90 rem (1440 px) en pantallas grandes. */
  margin-inline: auto;             /* Margen automático a izquierda y derecha: la caja queda centrada. */
  /* Relleno: arriba y abajo, el aire de sección; a los lados, el margen general. */
  padding: var(--aire-seccion) var(--margen);
}                                  /* fin de la caja interior */

/* Las dos secciones son un mismo bloque: por fuera (arriba de la 2, abajo de
   la 3) llevan el aire normal y entre una y otra van más juntas. */
.section2__inner { padding-bottom: var(--aire-entre); } /* Section 2: relleno de abajo más corto. */
.section3__inner { padding-top:    var(--aire-entre); } /* Section 3: relleno de arriba más corto. */

/* Títulos grandes de Section 2 y Section 3. */
.section2__titulo,
.section3__titulo {
  /* Compensación óptica: entre el borde de arriba de la caja del texto y
     donde empieza de verdad la letra hay un hueco. Con las medidas internas
     de la fuente Playfair Display (ascendente 1082, descendente 256, altura
     de mayúscula 700 sobre 1000) y una interlínea de 1,16, ese hueco mide
     0,29 em («em» = el tamaño de la letra del propio elemento). Al
     descontarlo con un margen negativo, la caja del texto coincide con la
     tinta, que es lo que se quiere centrar. */
  margin: -.29em 0 0;                   /* Sube el título 0,29 em; sin margen a los lados ni abajo. */
  font-family: var(--display);          /* Letra de titulares (Playfair Display). */
  font-weight: 400;                     /* Grosor normal, sin negrita. */
  font-size: clamp(2rem, 4vw, 3.5rem);  /* Tamaño: 4 % del ancho de la ventana, entre 2 y 3,5 rem. */
  line-height: 1.16;                    /* Interlínea apretada: 1,16 veces el tamaño de la letra. */
}                                       /* fin de los títulos */

/* Cada trozo del título (cada <span>) ocupa su propio renglón. */
.section2__titulo span,
.section3__titulo span { display: block; }

/* Párrafos de Section 2 y Section 3. */
.section2__parrafo,
.section3__parrafo {
  max-width: 34rem;                         /* Renglones de 34 rem como mucho, para leer cómodo. */
  margin: clamp(1.75rem, 3vw, 2.5rem) 0 0;  /* Separación con el título; nada a los lados ni abajo. */
  font-size: 1rem;                          /* Tamaño de letra normal (16 px). */
  font-weight: 300;                         /* Letra fina. */
  line-height: 1.75;                        /* Interlínea amplia. */
}                                           /* fin de los párrafos */

/* Rayita decorativa color caramelo bajo el párrafo de Section 2 (un «filete»). */
.section2__filete {
  display: block;                      /* Como bloque: ocupa su propio renglón y admite ancho y alto. */
  width: 4.5rem;                       /* 72 px de largo. */
  height: 2px;                         /* 2 px de grueso. */
  margin: clamp(2rem, 4vw, 3rem) 0 0;  /* Separación con el párrafo de encima. */
  background: var(--contraste-1);      /* Color caramelo. */
}                                      /* fin del filete */

/* ---------------------------------------- fotografía de Section 2 ------- */

.section2__figura { margin: 0; } /* Quita el margen que el navegador pone de serie a una <figure>. */

/* La fotografía es una carta de dos caras. La de delante es la foto de
   Section 2 y la de detrás, ya colocada del revés, la de Section 3. La carta
   da media vuelta sobre su eje vertical, como una página que se pasa: el
   cambio de cara ocurre al pasar por los 90º, cuando las dos caras están de
   canto y no se ven, así que no se nota ningún salto.
   Es un efecto en 3D: el navegador puede girar elementos en el espacio
   (rotateY = girar alrededor de un eje vertical, como una puerta) y dibujarlos
   en perspectiva. backface-visibility es quien esconde cada cara cuando queda
   de espaldas. */

/* La carta: la caja que contiene las dos caras y la que gira. */
.volteo {
  position: relative;            /* Sirve de referencia para colocar encima las dos caras. */
  /* Proporción fija de 3 de ancho por 2 de alto: el alto se calcula solo a
     partir del ancho, mida lo que mida la columna. */
  aspect-ratio: 3 / 2;
  transform-style: preserve-3d;  /* Las caras conservan su giro en 3D en vez de aplastarse en un plano. */
  transform-origin: 50% 50%;     /* Gira sobre su centro. */
}                                /* fin de la carta */

/* Cada una de las dos caras (cada foto). */
.volteo__cara {
  position: absolute;                   /* Se coloca libre, encima, medida desde los bordes de la carta. */
  inset: 0;                             /* Pegada a los cuatro bordes: las dos caras quedan superpuestas. */
  display: block;                       /* Como bloque (una <picture> va de serie en línea con el texto). */
  -webkit-backface-visibility: hidden;  /* Lo mismo que la línea siguiente, para Safari antiguos. */
          backface-visibility: hidden;  /* Cuando la cara queda de espaldas, no se ve. */
}                                       /* fin de las caras */

/* La foto dentro de cada cara. */
.volteo__cara img {
  display: block;     /* Como bloque: evita un huequito debajo de la imagen. */
  width: 100%;        /* Todo el ancho de la cara. */
  height: 100%;       /* Todo el alto de la cara. */
  /* Rellena la caja sin deformarse: si la proporción de la foto no coincide,
     recorta lo que sobra por los lados o por arriba y abajo. */
  object-fit: cover;
}                     /* fin de la foto de cada cara */

/* La cara de detrás (la foto de Section 3) empieza girada media vuelta: está
   de espaldas y, por tanto, oculta. */
.volteo__cara--dorso { transform: rotateY(180deg); }

/* ==========================================================================
   7 · SECTION 3
   --------------------------------------------------------------------------
   Es Section 2 dada la vuelta: la foto a la izquierda y el texto a la
   derecha. La foto es literalmente la misma: viaja desde Section 2 girando
   sobre sí misma, y aquí solo se le reserva el hueco donde aterriza.
   Contiene también, al final, el paso del hero a Section 2.
   ========================================================================== */

/* Section 3 entera. */
.section3 {
  z-index: 1;               /* Capa por debajo de Section 2 (que tiene 2): la foto
                               llega volando desde allí y tiene que pasar por encima. */
}

/* Hueco reservado donde aterriza la foto que viene de Section 2. */
.section3__hueco {
  aspect-ratio: 3 / 2;      /* Misma proporción que la foto (3 × 2), para que encaje justa. */
  /* No lleva fondo: durante el viaje se ve la página, y al final lo tapa
     la propia foto. */
}

/* ---------------------------------------- el viaje de la fotografía ----- */
/* Todo el efecto depende de la clase .en-vuelo, que main.js (el programa de
   la web) pone en la etiqueta <html> solo cuando hay sitio para hacerlo: dos
   columnas, sin que el sistema pida menos movimiento y con las medidas ya
   tomadas. Si no la pone (móvil, sin JavaScript, lo que sea), cada sección
   enseña su propia foto y no pasa nada.

   Variables que escribe main.js. No aparecen definidas en esta hoja: el
   programa las escribe directamente en la página y aquí solo se leen con
   var(). En «var(--avance3, 0)» el segundo valor es el de reserva, el que
   vale mientras main.js no haya escrito nada.
   · --avance3: cuánto lleva el viaje, de 0 (foto todavía en Section 2) a 1
     (foto ya puesta en su hueco). Se reescribe mientras se baja y va
     suavizado: arranca y termina despacio.
   · --dx3 y --dy3: el recorrido en horizontal y en vertical, medido sobre la
     rejilla real al cargar la página y al cambiar el tamaño de la ventana,
     así que el aterrizaje cuadra a cualquier ancho.
   Además, main.js pone la clase .viaje-llegado en <html> cuando el viaje
   pasa del 80 % (ver la última regla de este apartado). */

/* SIN vuelo (cuando <html> NO tiene .en-vuelo; eso significa «:not(...)»):
   la carta no gira nunca y su cara de detrás no llega a verse, así que
   Section 3 enseña su propia copia de la foto (.section3__eco, dentro del
   hueco). */
html:not(.en-vuelo) .section3__eco {
  display: block;                           /* Se ve, como bloque. */
  width: 100%;                              /* Todo el ancho del hueco. */
  height: auto;                             /* Alto automático, lo marca la proporción. */
  aspect-ratio: 3 / 2;                      /* Proporción 3 × 2, la misma de la foto viajera. */
  object-fit: cover;                        /* Rellena sin deformarse, recortando lo que sobre. */
  /* Le da media vuelta sobre su eje vertical (--giro, 180º, definido al
     principio del archivo). Como aquí no se esconde la espalda, se ve de
     espaldas, es decir, en espejo (izquierda y derecha cambiadas). */
  transform: rotateY(var(--giro, 180deg));
}                                           /* fin de la copia sin vuelo */

/* CON vuelo, la copia sobra: la foto de Section 3 llega en la cara de detrás
   de la carta. */
.en-vuelo .section3__eco { display: none; }

/* Mientras la foto cruza hacia Section 3, el texto de Section 2 se
   desvanece EN SU SITIO, sin moverse de lado: la foto es lo único que viaja,
   y así el ojo la sigue a ella sin que el texto le dispute el movimiento.
   Se apaga más rápido de lo que dura el viaje (factor 1,6): a mitad de
   recorrido apenas queda un 10 % y, al 62,5 %, ya no queda nada suyo en
   pantalla. */
.en-vuelo .section2__texto {
  /* --s2 es cuánto texto queda, de 1 a 0, en línea recta: 1 − avance × 1,6,
     sujeto entre 0 y 1 con clamp(). */
  --s2: clamp(0, calc(1 - var(--avance3, 0) * 1.6), 1);
  /* Opacidad (1 = se ve entero, 0 = invisible). No usa --s2 tal cual sino
     suavizada con la fórmula s²·(3 − 2s), la misma curva que main.js le
     aplica al avance: empieza a irse despacio, se va deprisa por el medio y
     termina de apagarse despacio, sin un corte seco al llegar a cero. */
  opacity: calc(var(--s2) * var(--s2) * (3 - 2 * var(--s2)));
  /* Aviso al navegador de que la opacidad va a cambiar sin parar: la prepara
     aparte, en su propia capa, para que el cambio vaya fluido. */
  will-change: opacity;
}                                           /* fin del texto de Section 2 en vuelo */

/* CON vuelo, la figura de Section 2 (foto + pie) se desplaza hacia el hueco
   de Section 3: nada con el avance a 0 y el recorrido entero con el avance
   a 1. translate(horizontal, vertical) = desplazar sin cambiar el tamaño. */
.en-vuelo .section2__figura {
  /* En horizontal, --dx3 × avance; en vertical, --dy3 × avance. */
  transform: translate(calc(var(--dx3, 0px) * var(--avance3, 0)),
                       calc(var(--dy3, 0px) * var(--avance3, 0)));
  will-change: transform;                   /* Prepara el movimiento aparte para que vaya fluido. */
}

/* CON vuelo gira solo la carta, no el pie: el texto tiene que quedar
   legible. La perspectiva va aquí, en la propia transformación, para que el
   punto de fuga caiga en el centro de la foto y no en el del conjunto con el
   pie. */
.en-vuelo .volteo {
  /* Vista en 3D, como mirada desde 1400 px de distancia (más número, giro
     menos exagerado), y giro sobre el eje vertical: de 0º con el avance a 0
     hasta 180º (--giro) con el avance a 1. */
  transform: perspective(1400px)
             rotateY(calc(var(--giro, 180deg) * var(--avance3, 0)));
  will-change: transform;                   /* Prepara el giro aparte para que vaya fluido. */
}

/* El texto de Section 3 espera a que la foto despeje su columna. Entra
   escalonado (título, párrafo, botón, uno tras otro) como los demás textos
   de la web, y arranca cuando la foto ha hecho el 80 % del viaje. Ese
   momento lo marca main.js poniendo .viaje-llegado en <html>.

   Hasta entonces el texto se queda escondido aunque el observador de
   apariciones (lo que va mostrando los bloques al bajar) ya lo haya dado
   por visto con .se-ve: la sección está en pantalla desde mucho antes de que
   la foto llegue. Y si se vuelve a subir, se retira de una vez y deprisa,
   sin escalonar, para dejar paso a la foto que regresa.

   A qué afecta: a las piezas .revela ya vistas (.se-ve) del texto de
   Section 3, cuando <html> tiene .con-js (JavaScript en marcha) y .en-vuelo
   pero todavía NO .viaje-llegado. */
html.con-js.en-vuelo:not(.viaje-llegado) .section3__texto .revela.se-ve {
  opacity: 0;                                              /* Invisible. */
  transform: translate3d(0, var(--revela-salto, 2rem), 0); /* Bajada 2 rem, desde donde luego subirá. */
  transition: opacity .3s ease, transform .3s ease;        /* Se retira en 0,3 s, todo a la vez. */
}                                                          /* fin de la espera del texto de Section 3 */

/* --------------------------------------- paso del hero a Section 2 ------ */
/* El hero queda anclado arriba (tiene position: sticky en su regla, en la
   parte del hero: va en su sitio normal, pero al llegar arriba se queda
   pegado mientras su contenedor siga en pantalla) y Section 2 sube por
   encima tapándolo con su fondo claro. A la vez, la foto se aleja un poco.
   Todo va atado a la posición del scroll: avanza mientras se mueve la rueda
   y se detiene con ella, sin secuestrar el scroll ni animaciones de
   duración fija.
   --avance lo escribe main.js en el hero: 0 arriba del todo, 1 con el hero
   ya tapado. */

.section2 {
  position: relative;     /* Posición normal; hace falta para que funcione z-index. */
  z-index: 2;             /* Capa por encima del hero anclado. */
}

/* Las fotos del hero: se alejan un poco según se baja. */
.hero__pase {
  transform: scale(calc(1.06 - .06 * var(--avance, 0))); /* Tamaño: 106 % arriba del todo, 100 % al final. */
  transform-origin: 50% 45%;       /* Se aleja hacia el centro, un poco por encima de la mitad. */
  will-change: transform;          /* Prepara el cambio aparte para que vaya fluido. */
}

/* El texto se aleja algo más deprisa que la foto (un 8 % frente a un 5,7 %)
   y esa diferencia de ritmo es lo que da profundidad. No se desplaza en
   vertical: se queda donde está y solo retrocede. */
.hero__content {
  transform: scale(calc(1 - .08 * var(--avance, 0))); /* Tamaño: del 100 % al 92 % según se baja. */
  will-change: transform;          /* Prepara el cambio aparte para que vaya fluido. */
}

/* Velo que oscurece el hero según se va tapando: del 0 % al 25 %. «::after»
   crea una capa extra dentro del hero sin tener que escribirla en el HTML. */
.hero::after {
  content: "";                            /* Obligatorio para que la capa exista; va vacía, sin texto. */
  position: absolute;                     /* Se coloca libre, encima de lo demás del hero. */
  inset: 0;                               /* Pegada a los cuatro bordes: cubre el hero entero. */
  z-index: 6;                             /* Por encima de la foto y del texto. */
  background: var(--principal);           /* Burdeos. */
  opacity: calc(var(--avance, 0) * .25);  /* Transparente arriba del todo; al 25 % con el hero tapado. */
  pointer-events: none;                   /* No atrapa clics: se puede pulsar lo que hay debajo. */
}                                         /* fin del velo del hero */

/* La flecha se retira en cuanto se empieza a bajar. */
.hero__scroll {
  opacity: clamp(0, calc(1 - var(--avance, 0) * 4), 1); /* Se apaga del todo en el primer 25 % del recorrido. */
  transition: opacity .2s linear;         /* Cada cambio se suaviza en 0,2 s, a ritmo constante. */
}

/* ==========================================================================
   8 · PIE
   --------------------------------------------------------------------------
   El pie de página (logotipo, menú e Instagram), con el mismo reparto que la
   cabecera. Va fijo abajo, escondido, y solo sube cuando se llega al final
   del documento: main.js le pone entonces la clase .is-visible. El hueco que
   necesita al final de la página se lo reserva main.js midiéndolo
   (--alto-pie), así sigue cuadrando cuando el pie ocupa dos renglones.
   ========================================================================== */

.site-footer {
  position: fixed;               /* Fijo respecto a la ventana: no se mueve al hacer scroll. */
  left: 0;                       /* Pegado al borde izquierdo… */
  right: 0;                      /* …y al derecho: todo el ancho. */
  bottom: 0;                     /* Pegado abajo. */
  z-index: 40;                   /* Capa alta: por encima del contenido de la página. */
  background: var(--fondo-pie);  /* Fondo del pie (hoy, crema). */
  color: var(--tinta-pie);       /* Letra del pie (hoy, burdeos). */
  /* Raya fina arriba: 1 px de gris topo al 35 %. Sobre fondo crema separa el
     pie de la página; sobre un fondo burdeos sobraría, porque ahí lo que se
     busca es que no se note la junta. */
  border-top: 1px solid rgba(165, 155, 146, .35);
  transform: translateY(100%);   /* Escondido: bajado todo su alto, fuera de la pantalla. */
  visibility: hidden;            /* Oculto también para el teclado y los lectores de pantalla. */
  transition: transform .5s cubic-bezier(.22, .61, .36, 1), /* al esconderse, baja en 0,5 s y frena suave */
              visibility 0s linear .5s;                    /* y se oculta del todo al acabar (espera 0,5 s) */
}                                /* fin del pie */

/* Pie visible: main.js le pone .is-visible al llegar al final de la página. */
.site-footer.is-visible {
  transform: translateY(0);      /* Vuelve a su sitio: sube a la vista. */
  visibility: visible;           /* Visible. */
  transition: transform .5s cubic-bezier(.22, .61, .36, 1), /* sube en 0,5 s con la misma curva */
              visibility 0s;                               /* y se hace visible al instante, sin esperar */
}                                /* fin del pie visible */

/* Interior del pie: logotipo a un lado y bloque de menú + Instagram al otro.
   «flex» coloca los hijos en fila. */
.site-footer__inner {
  display: flex;                   /* Hijos en fila. */
  align-items: center;             /* Centrados en vertical. */
  justify-content: space-between;  /* Uno en cada extremo, con el espacio libre en medio. */
  flex-wrap: wrap;                 /* Si no caben en una fila, pasan a la siguiente. */
  gap: 1rem 2rem;                  /* Separación: 1 rem entre filas y 2 rem entre columnas. */
  min-height: var(--header-h);     /* Al menos tan alto como la cabecera. */
  padding-block: .75rem;           /* Relleno arriba y abajo. */
  padding-inline: var(--margen);   /* Relleno a los lados: el margen general. */
}                                  /* fin del interior del pie */

/* Mismo bloque de la derecha que en la cabecera: pestañas e Instagram. */
.site-footer__derecha {
  display: flex;                        /* En fila. */
  align-items: center;                  /* Centrados en vertical. */
  gap: clamp(1.25rem, 2.5vw, 2.25rem);  /* Separación que crece con la ventana, entre 1,25 y 2,25 rem. */
}

/* Enlaces del menú e icono de Instagram del pie, con la tinta que toque en
   cada página. */
.site-footer .nav__link,
.site-footer .social { color: var(--tinta-pie); }

/* Del logotipo del pie solo se ve la versión oscura: la clara (pensada para
   fondos oscuros) queda invisible. */
.site-footer .logo__img--claro  { opacity: 0; }

/* Lista del menú del pie: si no cabe, pasa a dos renglones; 1 rem entre
   renglones y entre 1,5 y 2,5 rem entre enlaces. */
.nav-pie .nav__list { flex-wrap: wrap; gap: 1rem clamp(1.5rem, 2.5vw, 2.5rem); }

/* ==========================================================================
   9 · PROYECTOS (CUADRÍCULA)
   --------------------------------------------------------------------------
   Primero, piezas comunes a las páginas interiores (las que no tienen hero):
   el hueco para la cabecera, el encabezado con antetítulo y titular (lo usa
   Aviso legal) y el bloque de texto legal.
   Después, la cuadrícula de la página Proyectos: tarjetas con foto, un velo
   oscuro encima y el nombre del proyecto centrado. Al pulsar una tarjeta se
   abre el visor (sección 11), que maneja js/visor.js.
   ========================================================================== */

/* Páginas sin hero (<main> con la clase .interior): la cabecera flota por
   encima, así que hay que dejarle su hueco con un relleno de su mismo alto. */
main.interior { padding-top: var(--header-h); }

/* Encabezado de las páginas interiores: antetítulo y titular. */
.encabezado {
  max-width: 90rem;              /* Mismo ancho máximo que los demás bloques. */
  margin-inline: auto;           /* Centrado. */
  /* Relleno: arriba entre 3,5 y 6 rem; a los lados, el margen general;
     abajo entre 2 y 3 rem. */
  padding: clamp(3.5rem, 8vw, 6rem) var(--margen) clamp(2rem, 4vw, 3rem);
}

/* Antetítulo: la línea pequeña en mayúsculas encima del titular. */
.encabezado__antetitulo {
  margin: 0;                     /* Sin márgenes. */
  color: var(--tinta-suave);     /* Burdeos suave. */
  font-size: .72rem;             /* Letra pequeña. */
  font-weight: 500;              /* Algo gruesa. */
  letter-spacing: .28em;         /* Letras muy separadas entre sí. */
  text-transform: uppercase;     /* Todo en mayúsculas. */
}                                /* fin del antetítulo */

/* Titular de las páginas interiores. */
.encabezado__titulo {
  margin: clamp(1rem, 2vw, 1.5rem) 0 0;  /* Separación con el antetítulo; nada a los lados ni abajo. */
  font-family: var(--display);           /* Letra de titulares. */
  font-weight: 400;                      /* Grosor normal. */
  font-size: clamp(2rem, 4vw, 3.5rem);   /* Mismo tamaño que los títulos del home. */
  line-height: 1.16;                     /* Interlínea apretada. */
}                                        /* fin del titular */

/* Texto de Aviso legal. Mismo contenedor que el encabezado, para que el
   texto arranque en la misma vertical; el largo de los renglones lo limita
   cada párrafo. */
.texto-legal {
  max-width: 90rem;              /* Mismo ancho máximo que el encabezado. */
  margin-inline: auto;           /* Centrado. */
  padding: 0 var(--margen) clamp(4rem, 8vw, 7rem); /* Nada arriba; a los lados, el margen; abajo, 4 a 7 rem. */
  font-weight: 300;              /* Letra fina. */
  line-height: 1.8;              /* Interlínea amplia, para texto largo. */
}                                /* fin del texto legal */

/* Cada párrafo del texto legal. */
.texto-legal p {
  max-width: 44rem;              /* Renglones de 44 rem como mucho. */
  margin: 0 0 1.25rem;           /* Solo separación por debajo, entre párrafo y párrafo. */
}

/* Subtítulos del texto legal (líneas que empiezan por «## » en el panel). */
.texto-legal h2 {
  max-width: 44rem;              /* Mismo ancho que los párrafos. */
  margin: 2.25rem 0 .75rem;      /* Más aire por encima (empieza apartado) que por debajo. */
  font-family: var(--display);   /* Playfair Display, la letra de los títulos. */
  font-weight: 400;              /* Grosor normal. */
  font-size: 1.35rem;            /* Algo mayor que el texto. */
  line-height: 1.3;              /* Interlínea más apretada que la del texto. */
  color: var(--principal);       /* Burdeos. */
}

.texto-legal strong { font-weight: 600; }   /* Negrita (lo escrito entre **asteriscos** en el panel). */

/* Política de cookies: una «ficha» por cada cookie, separadas por una línea
   fina. Dentro, una lista de definiciones (<dl>): a la izquierda el dato
   (<dt>: Titular, Finalidad…) en letra pequeña espaciada; a la derecha su
   valor (<dd>). En el móvil, uno debajo del otro. */
.cookies-lista {
  max-width: 44rem;                          /* el mismo ancho que los párrafos */
  margin: 1.75rem 0 2.25rem;                 /* aire encima y debajo */
  border-bottom: 1px solid rgba(60, 22, 33, .15);   /* línea fina de cierre */
}
.cookie-ficha {
  padding: 1.25rem 0;                        /* aire dentro de cada ficha */
  border-top: 1px solid rgba(60, 22, 33, .15);      /* línea fina que separa cada ficha */
}
.cookie-ficha__nombre {
  margin: 0 0 .75rem;                        /* aire debajo del nombre */
  font-family: var(--display);               /* Playfair, como los subtítulos */
  font-weight: 400;                          /* grosor normal */
  font-size: 1.1rem;                         /* algo mayor que el texto */
  line-height: 1.3;
  color: var(--principal);                   /* burdeos */
}
.cookie-ficha dl {
  display: grid;                             /* dos columnas: dato y valor */
  grid-template-columns: 7.5rem 1fr;         /* el dato, 7,5rem; el valor, el resto */
  gap: .35rem 1rem;                          /* hueco entre filas y entre columnas */
  margin: 0;
}
.cookie-ficha dt {
  font-size: .7rem;                          /* pequeña */
  font-weight: 500;                          /* seminegrita */
  letter-spacing: .16em;                     /* separada */
  text-transform: uppercase;                 /* en mayúsculas */
  color: var(--tinta-suave);                 /* burdeos suave */
  line-height: 2.2;                          /* alineada con el primer renglón del valor */
}
.cookie-ficha dd { margin: 0; line-height: 1.7; }   /* el valor, sin sangría */
@media (max-width: 560px) {                  /* en el móvil… */
  .cookie-ficha dl { grid-template-columns: 1fr; gap: 0; }   /* …dato encima, valor debajo */
  .cookie-ficha dd { margin-bottom: .6rem; }                 /* aire entre parejas */
}

/* AVISO DE COOKIES — tarjeta pequeña y discreta en la esquina inferior
   izquierda (la enseña y la cierra js/cookies.js). Solo informa: no tapa
   la página ni la bloquea. Crema con letra burdeos, sombra suave como las
   píldoras del botón flotante, y el filete caramelo de la casa arriba. */
.aviso-cookies {
  position: fixed;                           /* fija a la ventana */
  left: clamp(1rem, 2.5vw, 2rem);            /* separada del borde izquierdo */
  bottom: clamp(1rem, 2.5vw, 2rem);          /* y del de abajo */
  z-index: 44;                               /* por debajo del botón flotante (45), la cabecera (50) y el visor (60) */
  width: min(22rem, calc(100vw - 2rem));     /* 22rem como mucho; en pantallas estrechas, lo que quepa */
  padding: 1.15rem 1.25rem 1rem;             /* relleno interior */
  background: var(--claro);                  /* crema */
  color: var(--principal);                   /* burdeos */
  border-top: 2px solid var(--contraste-1);  /* filete caramelo arriba */
  box-shadow:
    .05rem .15rem .35rem -.1rem rgba(60, 22, 33, .18),
    .3rem  .6rem  1.6rem -.4rem rgba(60, 22, 33, .28);   /* sombra suave burdeos */
  opacity: 0;                                /* empieza transparente… */
  transform: translateY(.6rem);              /* …y un poco más abajo */
  transition: opacity .35s ease, transform .35s var(--mov-curva, ease);   /* entra subiendo y fundiéndose */
}
.aviso-cookies[hidden] { display: none; }    /* escondida: no se ve ni ocupa */
.aviso-cookies.is-visible { opacity: 1; transform: none; }   /* visible, en su sitio */
.aviso-cookies__texto {
  margin: 0;                                 /* sin márgenes propios */
  font-size: .8rem;                          /* letra pequeña */
  font-weight: 400;                          /* grosor normal (más fina se leería mal tan pequeña) */
  line-height: 1.6;                          /* interlineado cómodo */
}
.aviso-cookies__texto a {
  color: var(--principal);                   /* burdeos */
  text-decoration: underline;                /* subrayado… */
  text-decoration-color: var(--contraste-1); /* …caramelo */
  text-underline-offset: .2em;               /* un poco separado de las letras */
  white-space: nowrap;                       /* «Política de cookies» no se parte */
}
.aviso-cookies__boton {
  display: block;                            /* en su propio renglón… */
  margin: .75rem 0 0 auto;                   /* …pegado a la derecha */
  padding: .5rem 1.1rem;                     /* relleno */
  border: 0;                                 /* sin borde */
  background: var(--principal);              /* burdeos, como el botón «Enviar» */
  color: var(--claro);                       /* letra crema */
  font-family: inherit;                      /* Montserrat */
  font-size: .68rem;                         /* pequeña */
  font-weight: 500;                          /* seminegrita */
  letter-spacing: .22em;                     /* muy separada */
  text-transform: uppercase;                 /* en mayúsculas */
  cursor: pointer;                           /* mano al pasar */
  transition: background-color .3s ease, color .3s ease;
}
.aviso-cookies__boton:hover,
.aviso-cookies__boton:focus-visible {
  background: var(--contraste-1);            /* caramelo al pasar o con el teclado */
  color: var(--principal);                   /* letra burdeos */
  outline: none;
}
@media (max-width: 720px) {                  /* en el móvil… */
  /* …a lo ancho, pero dejando a la derecha el sitio del botón flotante (unos 56 px + márgenes). */
  .aviso-cookies { width: auto; right: calc(clamp(1rem, 4vw, 1.5rem) + 3.5rem + .75rem); padding: 1rem 1.1rem .9rem; }   /* y algo más compacta */
}
@media (prefers-reduced-motion: reduce) {    /* si la persona pide menos movimiento: sin animación */
  .aviso-cookies { transition: none; }
}

/* Cuadrícula ------------------------------------------------------------- */

/* La cuadrícula entera de la página Proyectos. */
.galeria {
  display: grid;                           /* Rejilla. */
  grid-template-columns: repeat(3, 1fr);   /* Tres columnas iguales (en pantallas estrechas, 2 o 1). */
  gap: clamp(.75rem, 1.4vw, 1.25rem);      /* Separación entre tarjetas. */
  max-width: 90rem;                        /* Ancho máximo, como los demás bloques. */
  margin-inline: auto;                     /* Centrada. */
  /* Relleno: arriba entre 1,5 y 2,75 rem; a los lados, el margen general;
     abajo entre 4 y 7 rem. */
  padding: clamp(1.5rem, 3vw, 2.75rem) var(--margen) clamp(4rem, 8vw, 7rem);
  /* Los cambios se animan con el ritmo del visor (--visor-dur y --visor-curva,
     definidas en la sección del visor): los desplazamientos con su curva y
     el desvanecido empezando despacio (ease-in). */
  transition: transform var(--visor-dur) var(--visor-curva),
              opacity var(--visor-dur) ease-in;
}                                          /* fin de la cuadrícula */

/* Tarjetas que esperan tras el botón «Ver más proyectos» (llevan el atributo
   hidden). Hace falta decirlo aquí porque .proyecto pone display: block, que
   ganaría al «oculto» de serie del navegador. Al estar ocultas, sus fotos
   (de carga diferida) no se descargan hasta que se destapan. */
.proyecto[hidden] { display: none; }

/* Las que acaba de destapar el botón entran fundiéndose y subiendo un poco.
   La animación no se queda «puesta» al acabar (sin forwards), para no
   estorbar a los movimientos del visor, que también usan transform. */
.proyecto.es-nueva { animation: tarjeta-nueva .55s ease; }
@keyframes tarjeta-nueva {
  from { opacity: 0; transform: translateY(14px); } /* empieza transparente y 14 px más abajo */
}                                                   /* y termina como está de normal */

/* Caja del botón «Ver más proyectos», centrada bajo la cuadrícula. */
.ver-mas {
  display: flex;                 /* Para centrar el botón… */
  justify-content: center;       /* …en horizontal. */
  padding: 0 var(--margen) clamp(4rem, 8vw, 7rem); /* Abajo, el mismo aire que dejaba la cuadrícula. */
}
.ver-mas[hidden] { display: none; }   /* Sin tarjetas ocultas, ni se ve ni ocupa sitio. */
/* Sin el margen de arriba del botón (ya lo da la cuadrícula), con la letra de la web (un <button> no la
   hereda por su cuenta) y con manita al pasar el ratón. */
.ver-mas__boton { margin-top: 0; font-family: var(--texto); cursor: pointer; }

/* Con el botón a la vista, la cuadrícula deja menos aire debajo: el resto lo pone la caja del botón. */
.galeria:has(+ .ver-mas:not([hidden])) { padding-bottom: clamp(2rem, 4vw, 3rem); }

/* Al abrir un proyecto, visor.js pone .se-dispersa en la cuadrícula. Cada
   tarjeta se aparta en la dirección en la que está respecto a la pulsada
   (la de al lado hacia el lado, la de debajo hacia abajo, la diagonal en
   diagonal) y tanto más cuanto más lejos esté. Solo se desplazan: no
   cambian de tamaño. visor.js calcula el recorrido de cada una y lo escribe
   en sus variables --dx y --dy. A la vez, la cuadrícula entera se desvanece. */
.galeria.se-dispersa {
  opacity: 0;                    /* Se desvanece (con la transición de .galeria). */
  pointer-events: none;          /* No responde a clics mientras está apartada. */
}

/* Cada tarjeta, mientras la cuadrícula se dispersa. */
.galeria.se-dispersa .proyecto {
  transform: translate(var(--dx, 0px), var(--dy, 0px)); /* Se desplaza lo que le ha calculado visor.js. */
}

/* Cada tarjeta de proyecto. Es un botón (<button>): al pulsarlo se abre el
   visor. */
.proyecto {
  position: relative;            /* Referencia para colocar encima el velo y el rótulo. */
  display: block;                /* Como bloque. */
  overflow: hidden;              /* Lo que se salga (la foto al ampliarse) se recorta en el borde. */
  aspect-ratio: 5 / 4;           /* Proporción fija de 5 de ancho por 4 de alto. */
  /* Es un <button>: hay que quitarle lo que trae de serie. */
  margin: 0;                     /* Sin margen. */
  padding: 0;                    /* Sin relleno. */
  border: 0;                     /* Sin borde. */
  font: inherit;                 /* La misma letra que el resto de la página. */
  color: inherit;                /* El mismo color de letra. */
  text-align: inherit;           /* La misma alineación del texto. */
  cursor: pointer;               /* Cursor de manita al pasar el ratón. */
  /* Color de espera (gris topo): evita el destello blanco antes de que
     llegue la foto. */
  background: var(--secundario);
  transition: transform var(--visor-dur) var(--visor-curva); /* Al dispersarse, se mueve al ritmo del visor. */
}                                /* fin de la tarjeta */

/* La foto de la tarjeta, y la <picture> que la envuelve, llenan la tarjeta. */
.proyecto picture,
.proyecto img {
  display: block;                /* Como bloque. */
  width: 100%;                   /* Todo el ancho. */
  height: 100%;                  /* Todo el alto. */
}

/* La foto de la tarjeta. */
.proyecto img {
  object-fit: cover;             /* Rellena sin deformarse, recortando lo que sobre. */
  transition: transform .9s cubic-bezier(.22, .61, .36, 1); /* El zoom dura 0,9 s y frena suave. */
}

/* Con el ratón encima (:hover) o al llegar con el teclado (:focus-visible),
   la foto se amplía un 4,5 %. */
.proyecto:hover img,
.proyecto:focus-visible img { transform: scale(1.045); }

/* Velo para que el rótulo se lea sobre cualquier foto: un halo centrado
   donde va el texto más un degradado de arriba abajo. Medido sobre las
   fotos más claras, el contraste en el peor punto queda en 4,9:1, por encima
   del 4,5:1 que pide el tamaño de letra del rótulo.
   Está en una variable porque el visor lo reutiliza: la foto que viaja
   lleva el mismo velo, y así el empalme con la tarjeta es exacto.
   (:root es la raíz de la página, <html>: lo que se define ahí vale en
   todas partes.) */
:root {
  --velo-tarjeta: .9;            /* Opacidad del velo en reposo: 90 %. */
  /* Las dos capas del velo, una encima de otra (la primera queda arriba):
     1) Halo: mancha ovalada en el centro (del centro a su borde mide el
        58 % del ancho y el 38 % del alto) que va del burdeos más oscuro al
        48 % en el centro a transparente en el borde.
     2) Degradado vertical (180deg = de arriba abajo): arriba, burdeos de la
        marca al 22 %; abajo, burdeos más oscuro al 55 %. */
  --velo-proyecto:
    radial-gradient(58% 38% at 50% 50%,
      rgba(42, 15, 23, .48) 0%,
      rgba(42, 15, 23, 0) 100%),
    linear-gradient(180deg,
      rgba(60, 22, 33, .22) 0%,
      rgba(42, 15, 23, .55) 100%);
}                                /* fin del velo */

/* El velo de cada tarjeta: una capa extra (::after) encima de la foto. */
.proyecto::after {
  content: "";                        /* Obligatorio para que la capa exista; sin texto. */
  position: absolute;                 /* Libre, encima de la foto… */
  inset: 0;                           /* …y ocupando la tarjeta entera. */
  background: var(--velo-proyecto);   /* Las dos capas del velo definidas arriba. */
  /* Opacidad al 90 % (--velo-tarjeta). Va en una variable porque visor.js
     necesita el valor en reposo: si lo leyera del elemento con el ratón
     encima obtendría 1, y al cerrar la foto volvería con un velo más denso
     que el de la tarjeta. */
  opacity: var(--velo-tarjeta);
  transition: opacity .6s ease;       /* Los cambios de opacidad duran 0,6 s. */
}                                     /* fin del velo de la tarjeta */

/* Con el ratón encima o el foco del teclado, el velo se ve entero (100 %). */
.proyecto:hover::after,
.proyecto:focus-visible::after { opacity: 1; }

/* Rótulo con el nombre del proyecto, centrado sobre la foto. */
.proyecto__titulo {
  position: absolute;            /* Libre, encima de la foto… */
  inset: 0;                      /* …ocupando la tarjeta entera. */
  z-index: 1;                    /* Por encima del velo. */
  display: grid;                 /* Rejilla de una sola celda, solo para centrar el texto. */
  place-items: center;           /* Texto centrado en horizontal y en vertical. */
  padding: 1rem;                 /* Relleno para que un nombre largo no toque los bordes. */
  color: var(--claro);           /* Letra crema. */
  font-size: .78rem;             /* Letra pequeña. */
  font-weight: 500;              /* Algo gruesa. */
  letter-spacing: .24em;         /* Letras separadas. */
  text-transform: uppercase;     /* En mayúsculas. */
  text-align: center;            /* Renglones centrados si el nombre ocupa dos. */
}                                /* fin del rótulo */

/* ==========================================================================
   10 · PÁGINA DE CONTACTO
   --------------------------------------------------------------------------
   Dos mitades a pantalla completa: el formulario a la izquierda y la foto a
   la derecha, sin nada más en medio. En móvil se apilan y la foto pasa a ser
   una banda por debajo, para que el formulario quede a mano nada más entrar
   y no haya que pasar una foto a pantalla completa para llegar a él.
   (Los campos del formulario tienen su propio apartado más adelante.)
   ========================================================================== */

/* El resto de la web reserva siempre el hueco de la barra de scroll, para
   que no haya salto cuando aparece o desaparece. Aquí no hay scroll, así que
   ese hueco se quedaría como una franja crema al lado de la foto: en esta
   página se libera y la foto llega hasta el borde.
   «:has(...)» significa «que contiene…»: la regla vale para <html> solo si
   dentro hay un <main> con la clase .contacto-pagina, o sea, solo aquí. */
html:has(main.contacto-pagina) { scrollbar-gutter: auto; }

/* Relleno arriba del alto de la cabecera, que flota encima. */
main.contacto-pagina { padding-top: var(--header-h); }

/* El cuerpo de la página de contacto, repartido en dos columnas. */
.contacto-pagina {
  display: grid;                   /* Rejilla. */
  grid-template-columns: 1fr 1fr;  /* Dos columnas iguales: formulario y foto. */
  /* Alto mínimo: la ventana entera (100vh), para que la foto llegue siempre
     hasta el borde inferior. Esta página no lleva pie, así que no hay nada
     que descontar.
     OJO: aquí NO se descuenta la cabecera. Su hueco ya está dentro de este
     mismo elemento, en el padding-top de la regla de arriba, y con
     box-sizing: border-box el relleno cuenta dentro del min-height.
     Descontarla otra vez dejaría una franja vacía del alto de la cabecera
     por debajo de la foto. */
  min-height: 100vh;
}                                  /* fin del cuerpo de contacto */

/* Si el navegador entiende la unidad svh (@supports = «si el navegador
   admite…»), se usa en lugar de vh: svh descuenta la barra del navegador
   del móvil, que vh no descuenta. */
@supports (height: 100svh) {
  .contacto-pagina {
    min-height: 100svh;           /* El mismo alto mínimo, con svh. */
  }
}

/* Columna izquierda, la del formulario. */
.contacto-pagina__panel {
  display: flex;                   /* Flex, aquí solo para centrar en vertical su contenido. */
  align-items: center;             /* La caja del formulario queda centrada en vertical. */
  padding: clamp(1rem, 2.2vh, 3rem) var(--margen); /* Relleno arriba y abajo según el alto de la ventana. */
}

/* Caja con el antetítulo, el titular, el formulario y la otra vía de contacto. */
.contacto-pagina__caja {
  width: 100%;                     /* Ocupa todo el ancho disponible… */
  max-width: 31rem;                /* …hasta 31 rem como mucho. */
  margin-inline: auto;             /* Centrada en su columna. */
  /* Convierte esta caja en un «contenedor»: lo que tiene dentro puede
     medirse en proporción a SU ancho (con la unidad cqw, ver el titular más
     abajo) en vez de al ancho de la ventana. Así el titular nunca se sale de
     ella, mida lo que mida la caja. */
  container-type: inline-size;
}

/* Antetítulo «Contacto»: pequeño y en mayúsculas, encima del titular. */
.contacto-pagina__antetitulo {
  margin: 0;                       /* Sin márgenes. */
  color: var(--tinta-suave);       /* Burdeos suave. */
  font-size: .72rem;               /* Letra pequeña. */
  font-weight: 500;                /* Algo gruesa. */
  letter-spacing: .28em;           /* Letras muy separadas. */
  text-transform: uppercase;       /* En mayúsculas. */
}                                  /* fin del antetítulo */

/* Titular. Debajo va directamente el formulario, sin renglón de
   introducción (eso ya lo dice la Sección 4 del home, desde donde se llega
   a esta página); el aire de separación lo pone el propio titular.
   Va siempre en una sola línea: «Cuéntanos tu proyecto.» mide 10,44 em de
   ancho en Playfair (medido, no estimado; em = el tamaño de la letra), así
   que para ocupar el 98 % del ancho de la caja necesita 9,39 cqw (cqw = 1 %
   del ancho de .contacto-pagina__caja, el contenedor de arriba); se deja en
   9,3 para no llegar justo al borde.
   OJO: si se cambia el texto del titular, hay que rehacer esta cuenta. */
.contacto-pagina__titulo {
  /* Márgenes: arriba, poco (separación con el antetítulo); nada a los lados;
     abajo, más (separación con el formulario). Los dos crecen con el alto de
     la ventana. */
  margin: clamp(.35rem, 1.1vh, 1.25rem) 0 clamp(1rem, 2.6vh, 2.4rem);
  font-family: var(--display);     /* Letra de titulares. */
  font-weight: 400;                /* Grosor normal. */
  /* Dos font-size seguidos a propósito: el primero es el respaldo para
     navegadores que no entienden cqw (se mide contra el ancho o el alto de
     la ventana, lo que apriete más); el segundo lo sustituye donde sí se
     entiende, cambiando el ancho de la ventana por el de la propia caja para
     no depender de dónde caiga el resto de la columna.
     El mínimo es 1,25rem (20 px) para que quepa entero incluso en móviles
     de 320 px de ancho (con 1,75rem se cortaba por la derecha). */
  font-size: clamp(1.25rem, min(4.2vw, 4.65vh), 3.5rem);
  font-size: clamp(1.25rem, min(9.3cqw, 4.65vh), 3.5rem);
  line-height: 1.12;               /* Interlínea apretada. */
  white-space: nowrap;             /* Prohíbe partir el titular en dos líneas. */
}                                  /* fin del titular */

/* Renglón final: «¿Prefieres llamarnos?», teléfono y correo. */
.contacto-pagina__otra-via {
  margin: clamp(.5rem, 1.3vh, 1.5rem) 0 0;  /* Separación con el formulario. */
  color: var(--principal);                  /* Burdeos. */
  /* Un punto más pequeño para que el teléfono y el correo quepan en un
     renglón: partido en dos se comía los últimos píxeles útiles. */
  font-size: .8rem;
  font-weight: 300;                         /* Letra fina. */
  line-height: 1.55;                        /* Interlínea. */
}                                           /* fin de la otra vía */

/* Enlaces del teléfono y del correo: subrayados con una raya fina. */
.contacto-pagina__otra-via a {
  border-bottom: 1px solid rgba(60, 22, 33, .3); /* Raya de 1 px, burdeos de la marca al 30 %. */
  transition: border-color .35s ease;            /* El cambio de color de la raya dura 0,35 s. */
}

/* Con el ratón encima o el foco del teclado, la raya se vuelve caramelo. */
.contacto-pagina__otra-via a:hover,
.contacto-pagina__otra-via a:focus-visible { border-color: var(--contraste-1); }

/* El punto (·) entre teléfono y correo: un poco de aire a cada lado y color suave. */
.contacto-pagina__punto { margin-inline: .4rem; color: var(--tinta-suave); }

/* Columna derecha, la de la foto. La foto llena su mitad entera, mida lo
   que mida la columna de al lado: va colocada en absoluto dentro de ella y
   recortada con object-fit, no como imagen normal en el flujo de la página,
   que haría crecer la columna a su medida. */
.contacto-pagina__foto {
  position: relative;              /* Referencia para colocar la foto dentro. */
  overflow: hidden;                /* Recorta lo que se salga. */
  background: var(--secundario);   /* Color de espera (gris topo) mientras carga la foto. */
}

/* La <picture> se coloca libre y pegada a los cuatro bordes: ocupa la columna entera. */
.contacto-pagina__foto picture { position: absolute; inset: 0; }

/* La foto de contacto. */
.contacto-pagina__foto img {
  display: block;                  /* Como bloque. */
  width: 100%;                     /* Todo el ancho. */
  height: 100%;                    /* Todo el alto. */
  object-fit: cover;               /* Rellena sin deformarse, recortando lo que sobre. */
}

/* Pantallas de 860 px de ancho o menos (móviles y tabletas en vertical).
   Una media query (@media) aplica sus reglas solo si se cumple la condición. */
@media (max-width: 860px) {
  .contacto-pagina {
    grid-template-columns: 1fr;    /* Una sola columna: formulario arriba y foto debajo. */
    min-height: 0;                 /* Sin alto mínimo: mide lo que mida su contenido. */
  }

  .contacto-pagina__panel { padding-block: clamp(2.5rem, 9vw, 4rem); } /* Más relleno arriba y abajo. */
  .contacto-pagina__caja { max-width: 34rem; }                          /* La caja puede ser algo más ancha. */

  /* Banda, no columna: lo justo para que la foto se vea sin comerse la
     pantalla. Alto: el menor entre el 46 % del alto de la ventana y el 72 %
     del ancho. */
  .contacto-pagina__foto { height: min(46vh, 72vw); }
}                                  /* fin de pantallas estrechas */

/* ==========================================================================
   11 · VISOR DE PROYECTO
   ========================================================================== */

/* La ventana a pantalla completa que se abre en la página Proyectos al
   pulsar una tarjeta. Enseña todas las fotos de ese proyecto.

   Cómo funciona en conjunto:
   · Al abrir, la foto de la tarjeta «vuela» desde su casilla de la
     cuadrícula hasta el centro de la pantalla y crece. A la vez aparecen a
     los lados las demás fotos del proyecto, en un carrusel sin fin (se pasa
     de una a otra con las flechas, con el teclado o arrastrando).
   · Al cerrar, la foto vuelve a su casilla y se funde con la tarjeta.
   · El viaje lo calcula js/visor.js con la técnica FLIP (del inglés First,
     Last, Invert, Play: primero, último, invertir, reproducir): mide dónde
     está la tarjeta, coloca la foto ya en su sitio final, le aplica la
     transformación que la devuelve encima de la tarjeta y luego la quita
     con una transición. Así el viaje cuadra esté donde esté el scroll y sea
     cual sea el tamaño de la pantalla.
   · Al terminar una transición, el navegador lanza el aviso «transitionend»
     (un evento: un aviso que el JavaScript escucha para reaccionar).
     visor.js lo espera para rematar: enfocar el botón de cerrar al abrir, o
     esconder el visor al cerrar.
   · visor.js marca cada momento con clases en .visor: .sin-transicion
     (se monta sin animar), .is-abierto (fondo visible) e .is-desplegado
     (fotos de los lados, textos y controles visibles).

   Piezas (en proyectos.html): .visor (todo) contiene .visor__fondo (fondo
   que cierra al pulsarlo), .visor__cabecera (título y descripción),
   .visor__escena > .visor__pista > .visor__diapo (cada foto), las flechas
   .visor__nav, el contador .visor__contador y el aspa .visor__cerrar. */

/* Medidas y ritmos del visor, guardados como variables en :root (la raíz
   de la página) para que los usen todas las reglas de esta sección. */
:root {
  /* Curva de velocidad del visor: la general de la web (--mov-curva). El
     valor que va tras la coma dentro de var() es el de reserva, por si la
     variable no existiera. */
  --visor-curva: var(--mov-curva, cubic-bezier(.4, 0, .1, 1));
  --visor-dur:   var(--mov, 600ms);            /* duración del vuelo: la general de la web (--mov) */
  --diapo-gap:   clamp(1rem, 2.2vw, 2.25rem);  /* hueco entre las fotos del carrusel */

  /* Reparto del alto de la pantalla: un aire arriba (para la cabecera del
     visor), otro abajo (para el contador) y la foto en lo que queda. Su
     ancho sale de ese alto con la proporción 5:4 (ancho = alto × 1,25). Así
     la foto nunca pisa el texto ni se sale de la pantalla. */
  /* Aire de arriba: el alto de la cabecera de la web más 5rem. Es solo el
     valor de partida: al abrir, visor.js mide la cabecera del visor ya
     escrita (una o dos líneas de descripción) y lo sustituye. */
  --visor-arriba: calc(var(--header-h) + 5rem);
  --visor-abajo:  5rem;                                            /* aire de abajo, para el contador */
  /* Alto libre para la foto: el alto de la ventana (100vh) menos los dos aires. */
  --visor-hueco:  calc(100vh - var(--visor-arriba) - var(--visor-abajo));
  /* Ancho de cada foto: el menor (min) entre el 64 % del ancho de la
     ventana y el que permite el alto libre con la proporción 5:4. */
  --diapo-w:      min(64vw, calc(var(--visor-hueco) * 1.25));
}  /* fin de las variables del visor */

/* @supports aplica lo de dentro solo si el navegador entiende lo que se
   pregunta: aquí, la unidad svh. 1svh es el 1 % del alto de la ventana con
   las barras del navegador del móvil desplegadas; así la foto cabe también
   cuando esas barras están a la vista. */
@supports (height: 100svh) {
  /* El mismo alto libre de arriba, calculado con svh en lugar de vh. */
  :root { --visor-hueco: calc(100svh - var(--visor-arriba) - var(--visor-abajo)); }
}

/* La caja que contiene todo el visor. */
.visor {
  position: fixed;   /* fija a la ventana: no se mueve al hacer scroll */
  inset: 0;          /* pegada a los cuatro bordes: ocupa toda la pantalla */
  /* Capa 45 por defecto: POR DEBAJO de la cabecera (50) y por encima del
     pie (40). Así, mientras la foto vuela desde la tarjeta al centro (al
     abrir) o vuelve del centro a la tarjeta (al cerrar), en su trayecto por
     la franja de arriba pasa siempre POR DETRÁS del header y no lo tapa.
     Cuando el visor termina de aterrizar y se queda quieto en el centro,
     visor.js pone la clase .esta-lleno y el visor sube a capa 60: el aspa
     de cerrar (que está en la franja del header) queda a la vista, y todo
     el visor abierto se sitúa por encima de la cabecera de la web. Al
     empezar el cierre se retira .esta-lleno y la capa vuelve a 45 antes de
     que la foto empiece el vuelo de vuelta. */
  z-index: 45;
  overflow: hidden;  /* lo que se salga (las fotos del carrusel) queda recortado */
}

/* Visor completamente abierto: se sube por encima del header para que se vean
   el aspa y los rótulos del visor sin que el header los tape. Lo pone y lo
   quita visor.js en los extremos de la animación (fin del vuelo de ida,
   principio del vuelo de vuelta). */
.visor.esta-lleno { z-index: 60; }

/* [hidden] selecciona el visor cuando lleva el atributo hidden del HTML
   (así está mientras no se usa). Se asegura de que entonces no se vea. */
.visor[hidden] { display: none; }

/* Fondo crema del visor. Es un botón que cubre toda la pantalla: pulsar
   fuera de las fotos es pulsarlo a él, y visor.js cierra el visor. */
.visor__fondo {
  position: absolute;  /* colocado libre, medido desde los bordes del visor */
  inset: 0;            /* ocupa el visor entero */
  padding: 0;          /* quita el relleno que traen de serie los botones */
  border: 0;           /* quita el borde que traen de serie los botones */
  background: var(--claro);                    /* color crema de la marca */
  opacity: 0;          /* arranca invisible (0 = transparente, 1 = opaco) */
  transition: opacity var(--visor-dur) ease;   /* aparece y desaparece suave, al ritmo del vuelo */
  cursor: default;     /* flecha normal del ratón, no la mano de «pulsable» */
}  /* fin de .visor__fondo */

.visor.is-abierto .visor__fondo { opacity: 1; }   /* con el visor abierto, el fondo se ve entero */

/* Dos capas que se mueven por separado:
   · La escena lleva el viaje de ida y vuelta desde la tarjeta. visor.js le
     escribe un transform con translate (desplazar) y scale (escalar), y un
     transform-origin: el punto alrededor del cual se escala, que es el
     centro de la foto activa.
   · La pista, dentro de la escena, lleva el carrusel: visor.js la desliza
     a izquierda o derecha (translateX) para centrar cada foto. */

.visor__escena {
  position: absolute;      /* colocada libre dentro del visor */
  inset: 0;                /* ocupa el visor entero */
  display: grid;           /* rejilla… */
  place-items: center;     /* …que centra la pista en horizontal y en vertical */
  /* Centrada en el hueco que queda entre la cabecera del visor y el
     contador, no en toda la pantalla: relleno arriba y abajo con los dos
     aires (arriba, nada a los lados, abajo). */
  padding: var(--visor-arriba) 0 var(--visor-abajo);
  will-change: transform;  /* avisa de que se moverá: el navegador la prepara y el vuelo va fluido */
  /* Transparente al ratón (pointer-events: none): el clic fuera de las
     fotos la atraviesa, llega al fondo y cierra el visor. Las fotos sí
     reciben el clic (ver .visor__pista). */
  pointer-events: none;
}  /* fin de .visor__escena */

/* La pista: la fila de fotos del carrusel (es una lista <ul>). */
.visor__pista {
  display: flex;             /* pone las fotos una al lado de otra, en fila */
  gap: var(--diapo-gap);     /* separación entre fotos */
  margin: 0;                 /* quita el margen que traen de serie las listas */
  padding: 0;                /* quita el relleno que traen de serie las listas */
  list-style: none;          /* sin viñetas (los puntos de las listas) */
  will-change: transform;    /* se va a deslizar: el navegador la prepara */
  pointer-events: auto;      /* vuelve a recibir el ratón (la escena lo tenía anulado) */
  cursor: grab;              /* cursor de mano abierta: indica que se puede arrastrar */
}  /* fin de .visor__pista */

.visor__pista:active { cursor: grabbing; }   /* mientras se mantiene pulsada (:active), mano cerrada */

/* Cada foto del carrusel (un <li> que crea visor.js). En reposo está
   invisible y un poco encogida; las reglas de más abajo la hacen aparecer. */
.visor__diapo {
  position: relative;        /* referencia para colocar encima el velo, la portada y el rótulo */
  flex: 0 0 auto;            /* en la fila, ni se estira ni se encoge: mantiene su ancho */
  width: var(--diapo-w);     /* ancho calculado en las variables del visor */
  aspect-ratio: 5 / 4;       /* alto que corresponde a ese ancho en proporción 5:4, como las tarjetas */
  overflow: hidden;          /* recorta lo que sobresalga de la caja */
  background: var(--secundario);  /* gris topo de espera, mientras llega la foto */
  opacity: 0;                /* arranca invisible */
  transform: scale(.94);     /* y al 94 % de su tamaño; al aparecer crece al 100 % */
  transition: opacity var(--mov-breve, 200ms) ease,            /* aparece en el tiempo corto */
              transform var(--mov, 300ms) var(--visor-curva);  /* crece en el tiempo general */
}  /* fin de .visor__diapo */

/* Velo de la foto: la misma capa oscura (degradado burdeos) que llevan las
   tarjetas para que se lea el nombre del proyecto. La foto que viaja lo
   lleva: al salir se va difuminando y al volver reaparece, los dos al ritmo
   del viaje. Así, en el momento del relevo, la tarjeta y la foto tienen el
   mismo velo y el cambio no se nota. visor.js mueve la variable --velo
   (0 = sin velo; 0,9 = el de la tarjeta). */
.visor__diapo::after {
  content: "";               /* capa vacía, sin texto: solo el velo */
  position: absolute;        /* colocada libre encima de la foto */
  inset: 0;                  /* cubre la foto entera */
  z-index: 1;                /* por encima de la foto y de la portada, por debajo del rótulo */
  background: var(--velo-proyecto);  /* el degradado del velo (definido en la sección de Proyectos) */
  opacity: var(--velo, 0);   /* intensidad: la que escriba visor.js en --velo; si no hay, 0 */
  transition: opacity var(--visor-dur) var(--visor-curva);  /* cambia al ritmo del vuelo */
  pointer-events: none;      /* no intercepta clics: pasan a la foto */
}  /* fin del velo de la foto */

/* Mientras se monta el visor (.sin-transicion), el velo cambia de golpe. */
.visor.sin-transicion .visor__diapo::after { transition: none; }

/* El regreso a la cuadrícula ---------------------------------------------
   La foto que vuelve tiene que aterrizar IDÉNTICA a la tarjeta que la
   sustituye: en el relevo, cualquier diferencia se ve como un salto. Tres
   piezas se encargan de ello:

   · La imagen. Se puede cerrar desde cualquier foto del proyecto, pero la
     tarjeta enseña siempre la primera. .visor__portada es esa primera,
     puesta encima y fundiéndose mientras vuela: cuando aterriza no queda
     nada de la otra.
   · El rótulo. La tarjeta lleva el nombre del proyecto y la foto del visor
     no. .visor__rotulo viaja con la foto y entra con el velo, igual que en
     el vuelo del home a Proyectos, para que el nombre no salga de golpe al
     final.
   · El hover. Si el ratón estaba encima, la tarjeta aparecería ya ampliada
     y con el velo entero. .proyecto.es-regreso la deja en reposo hasta que
     la foto ha aterrizado.

   El velo vuelve con la foto (--velo): de 0 a 0,9 durante el vuelo, lo
   mismo que tiene la tarjeta. */

/* Portada: copia de la foto de la tarjeta (la primera del proyecto) que
   visor.js pone encima de la foto que se está viendo. Al abrir arranca
   visible y tapa la foto grande hasta que esta ha cargado; al cerrar
   arranca invisible y se funde encima, para aterrizar siendo la tarjeta.
   El fundido va del 15 % al 85 % del vuelo. Empieza tarde para no mezclar
   las dos fotos mientras la grande aún ocupa media pantalla, y termina
   antes de aterrizar para que los últimos fotogramas sean ya solo la
   portada. Con la curva de la casa, al 85 % del tiempo la foto ha hecho el
   99 % del camino. */
.visor__portada {
  position: absolute;         /* colocada libre encima de la foto */
  inset: 0;                   /* la cubre entera */
  z-index: 0;                 /* encima de la foto actual, debajo del velo */
  opacity: 0;                 /* arranca invisible; .se-ve la muestra */
  /* Fundido de opacidad que dura el 70 % del vuelo (× .7), suave al empezar
     y al acabar (ease-in-out). El segundo tiempo es la espera antes de
     empezar: el 15 % del vuelo (× .15). */
  transition: opacity calc(var(--visor-dur, 600ms) * .7) ease-in-out
              calc(var(--visor-dur, 600ms) * .15);
}  /* fin de .visor__portada */

.visor__portada.se-ve { opacity: 1; }   /* con la clase .se-ve (la pone visor.js), la portada se ve entera */

/* Rótulo: el nombre del proyecto que viaja con la foto (visor.js lo crea
   dentro de la foto activa). Se escribe al tamaño de la foto grande (--k
   veces el de la tarjeta; --k lo calcula visor.js) porque viaja dentro de la
   escena, que se encoge con un scale(). Al aterrizar la escala es justo
   1/--k y queda en los .78rem de la tarjeta, al píxel. El interletrado va
   en em (medida relativa al tamaño de la letra), así que escala solo.

   La opacidad va atada al velo: con el velo de la tarjeta, rótulo entero;
   sin velo, sin rótulo. Entran y salen juntos sin que nadie los sincronice. */
.visor__rotulo {
  position: absolute;         /* colocado libre encima de la foto */
  inset: 0;                   /* ocupa la foto entera */
  z-index: 2;                 /* por encima del velo (capa 1) */
  display: grid;              /* rejilla… */
  place-items: center;        /* …que centra el texto en la foto */
  padding: calc(1rem * var(--k, 1));        /* margen interior de la tarjeta (1rem) multiplicado por --k */
  color: var(--claro);        /* letra crema */
  font-size: calc(.78rem * var(--k, 1));    /* letra de la tarjeta (.78rem) multiplicada por --k */
  font-weight: 500;           /* grosor medio de letra */
  letter-spacing: .24em;      /* letras separadas (0,24 veces el tamaño de la letra) */
  text-transform: uppercase;  /* en mayúsculas */
  text-align: center;         /* texto centrado */
  pointer-events: none;       /* no intercepta clics */
  /* Visibilidad = velo actual / velo de la tarjeta: con --velo en 0,9 da 1
     (entero) y con --velo en 0 da 0 (invisible). */
  opacity: calc(var(--velo, 0) / var(--velo-tarjeta, .9));
  /* Al volver: entra en el último tramo, para no verse enorme mientras la
     foto está aún lejos. Mismo reparto que el vuelo del home: espera el
     40 % del vuelo (× .4) y aparece durante el 60 % restante (× .6). */
  transition: opacity calc(var(--visor-dur, 600ms) * .6) ease
              calc(var(--visor-dur, 600ms) * .4);
}  /* fin de .visor__rotulo */

/* Al abrir: se va enseguida (en el 30 % del vuelo, sin espera), antes de
   que la foto crezca y lo agrande. */
.visor.is-abierto .visor__rotulo {
  transition: opacity calc(var(--visor-dur, 600ms) * .3) ease;
}

/* Mientras se monta el visor (.sin-transicion), nada de esto se anima: la
   foto activa tiene que estar ya entera y a su tamaño en el primer
   fotograma, que es cuando sustituye a la tarjeta. */
.visor.sin-transicion .visor__diapo,
.visor.sin-transicion .visor__rotulo,
.visor.sin-transicion .visor__portada { transition: none; }   /* cambios de golpe */

/* La imagen dentro de cada foto del carrusel (también la portada). */
.visor__diapo img {
  display: block;      /* como bloque: evita el hueco que dejan las imágenes por debajo */
  width: 100%;         /* todo el ancho de la foto */
  height: 100%;        /* todo el alto */
  object-fit: cover;   /* llena la caja recortando lo que sobre, sin deformarse */
}

/* La activa (.es-activa, la foto centrada; la marca visor.js) se ve desde
   el primer momento: es la que viaja. */
.visor__diapo.es-activa { opacity: 1; transform: none; }   /* entera y a su tamaño real */

/* Las demás entran mientras la principal vuela, no después: así abrir es el
   cierre del revés y no una secuencia de dos tiempos. Entran escalonadas
   según lo lejos que estén de la activa (--lejania: 1 la de al lado, 2 la
   siguiente…; la escribe visor.js), pero el escalón se corta en la segunda:
   de la tercera en adelante ya no se ven, y esperarlas alargaría el gesto
   sin que nadie lo notara. */
.visor.is-desplegado .visor__diapo {
  opacity: .32;           /* las de los lados se ven apagadas, al 32 % */
  transform: none;        /* a su tamaño real */
  /* Espera antes de empezar: 25 ms por puesto de distancia, como mucho 2
     puestos (min() se queda con el menor: la lejanía o 2). */
  transition-delay: calc(min(var(--lejania, 0), 2) * 25ms);
}

.visor.is-desplegado .visor__diapo.es-activa { opacity: 1; }   /* la activa, entera */

/* Cabecera, controles y contador --------------------------------------- */
/* Título y descripción arriba, contador abajo, flechas a los lados y aspa
   de cerrar arriba a la derecha. Arrancan ocultos y aparecen con
   .is-desplegado. */

/* Lo común a las cuatro piezas. */
.visor__cabecera,
.visor__contador,
.visor__nav,
.visor__cerrar {
  position: absolute;   /* colocadas libres dentro del visor */
  z-index: 2;           /* por encima de la escena */
  opacity: 0;           /* arrancan invisibles */
  transition: opacity var(--mov, 300ms) ease,                  /* aparecen suave… */
              transform var(--mov, 300ms) var(--visor-curva);  /* …y se deslizan a su sitio */
}  /* fin de lo común a cabecera, contador, flechas y aspa */

/* Con el visor desplegado, aparecen la cabecera del visor, el contador y las
   flechas. La aspa se trata aparte más abajo, porque está en la franja del
   header y solo debe aparecer cuando el visor sube a capa 60. */
.visor.is-desplegado .visor__cabecera,
.visor.is-desplegado .visor__contador,
.visor.is-desplegado .visor__nav { opacity: 1; transform: none; }

/* El aspa vive dentro de la franja del header. Mientras la foto está
   volando (visor en capa 45), el header la tapa; enseñarla ahí sería
   engañoso, porque se vería a medias. Por eso solo aparece con .esta-lleno,
   la clase que visor.js añade cuando la foto ya está descansando en el
   centro y el visor sube a capa 60: el aspa entra a la vez que sube el
   visor, sin pop. Al cerrar, .esta-lleno se retira antes de que la foto
   empiece el vuelo de vuelta, y el aspa se difumina de manera limpia. */
.visor.esta-lleno .visor__cerrar { opacity: 1; transform: none; }

/* Título y descripción del proyecto, centrados arriba. */
.visor__cabecera {
  top: calc(var(--header-h) - .5rem);   /* justo bajo la franja de la cabecera de la web, medio rem más arriba */
  left: 0;                              /* de borde a borde (con right)… */
  right: 0;                             /* …hasta el borde derecho: ese es el espacio en el que se centra */
  /* Ancho: 40rem como mucho, y nunca más que la pantalla menos los dos
     márgenes laterales de la web. */
  width: min(40rem, calc(100% - 2 * var(--margen)));
  margin-inline: auto;                  /* …y márgenes laterales automáticos: queda centrada */
  text-align: center;                   /* texto centrado */
  transform: translateY(-.75rem);       /* arranca .75rem más arriba; al aparecer baja a su sitio */
}  /* fin de .visor__cabecera */

/* Título del proyecto. */
.visor__titulo {
  margin: 0;                                 /* sin los márgenes de serie de los titulares */
  font-family: var(--display);               /* tipografía de titulares (Playfair Display) */
  font-weight: 400;                          /* grosor normal */
  font-size: clamp(1.5rem, 2.6vw, 2.25rem);  /* crece con la pantalla, entre 1,5rem y 2,25rem */
  line-height: 1.2;                          /* altura de línea: 1,2 veces el tamaño de la letra */
}

/* Descripción del proyecto, bajo el título. */
.visor__desc {
  margin: .75rem 0 0;          /* separación de .75rem con el título, solo por arriba */
  color: var(--secundario);    /* gris topo */
  font-size: .9rem;            /* letra algo menor que la normal */
  font-weight: 300;            /* letra fina */
  line-height: 1.7;            /* líneas holgadas */
}

/* Contador «03 / 12», centrado abajo. */
.visor__contador {
  bottom: clamp(1.5rem, 4vh, 3rem);  /* separado del borde de abajo: 4 % del alto, entre 1,5 y 3rem */
  left: 0;                           /* de borde a borde… */
  right: 0;
  margin: 0 auto;                    /* …y centrado */
  text-align: center;                /* texto centrado */
  color: var(--secundario);          /* gris topo */
  font-size: .72rem;                 /* letra pequeña */
  font-weight: 500;                  /* grosor medio */
  letter-spacing: .24em;             /* letras separadas */
  transform: translateY(.75rem);     /* arranca .75rem más abajo; al aparecer sube a su sitio */
}  /* fin de .visor__contador */

/* Botones de flecha (anterior y siguiente), a media altura. */
.visor__nav {
  top: 50%;              /* borde de arriba a media altura de la pantalla… */
  width: 56px;           /* zona pulsable de 56 × 56 píxeles */
  height: 56px;          /* alto del botón (el ancho va en la línea de arriba) */
  margin-top: -28px;     /* …y subido la mitad de su alto: queda centrado en vertical */
  padding: 0;            /* sin el relleno de serie de los botones */
  border: 0;             /* sin borde */
  background: none;      /* sin fondo */
  cursor: pointer;       /* mano de «pulsable» */
}  /* fin de .visor__nav */

.visor__nav--prev { left: clamp(.5rem, 2vw, 1.75rem); }    /* «anterior», pegada a la izquierda */
.visor__nav--sig  { right: clamp(.5rem, 2vw, 1.75rem); }   /* «siguiente», pegada a la derecha */

/* El dibujo de la flecha: un cuadradito con solo dos bordes (arriba e
   izquierda) que, girado, forma una punta «<» o «>». */
.visor__flecha {
  display: block;                            /* como bloque, para poder darle medidas */
  width: 14px;                               /* 14 × 14 píxeles */
  height: 14px;                              /* alto del cuadradito (el ancho va arriba) */
  margin-inline: auto;                       /* centrado en el botón */
  border-top: 1px solid var(--principal);    /* trazo de arriba, burdeos */
  border-left: 1px solid var(--principal);   /* trazo de la izquierda, burdeos */
  transition: transform var(--mov-breve, 200ms) var(--visor-curva);  /* se mueve suave al pasar el ratón */
}  /* fin de .visor__flecha */

.visor__nav--prev .visor__flecha { transform: rotate(-45deg); }   /* girada -45°: apunta a la izquierda */
.visor__nav--sig  .visor__flecha { transform: rotate(135deg); }   /* girada 135°: apunta a la derecha */

/* Al pasar el ratón por el botón (:hover), la flecha se desplaza unos 4
   píxeles en horizontal. Como el desplazamiento va después del giro, sale
   hacia el centro de la pantalla: en sentido contrario al que apunta. */
.visor__nav--prev:hover .visor__flecha { transform: rotate(-45deg) translate(3px, 3px); }
.visor__nav--sig:hover  .visor__flecha { transform: rotate(135deg) translate(3px, 3px); }

/* Botón de cerrar (el aspa), arriba a la derecha, centrado en la franja que
   ocupa la cabecera de la web. */
.visor__cerrar {
  top: calc(var(--header-h) / 2 - 22px);   /* media cabecera menos medio botón: centrado en esa franja */
  right: var(--margen);                     /* separado del borde derecho el margen de la web */
  width: 44px;                              /* zona pulsable de 44 × 44 píxeles */
  height: 44px;                             /* alto del botón (el ancho va arriba) */
  padding: 0;                               /* sin el relleno de serie de los botones */
  border: 0;                                /* sin borde */
  background: none;                         /* sin fondo */
  cursor: pointer;                          /* mano de «pulsable» */
}  /* fin de .visor__cerrar */

/* El dibujo del aspa: una caja de 20 × 20 píxeles con dos rayas cruzadas. */
.visor__aspa {
  position: relative;    /* referencia para colocar las dos rayas */
  display: block;        /* como bloque, para poder darle medidas */
  width: 20px;           /* ancho de la caja del aspa */
  height: 20px;          /* alto de la caja del aspa */
  margin-inline: auto;   /* centrada en el botón */
}

/* Las dos rayas del aspa (dos capas añadidas con ::before y ::after). */
.visor__aspa::before,
.visor__aspa::after {
  content: "";                   /* capa vacía: solo la raya */
  position: absolute;            /* colocada libre dentro de la caja del aspa */
  top: 50%;                      /* a media altura */
  left: 0;                       /* desde el borde izquierdo… */
  width: 100%;                   /* …de lado a lado */
  height: 1px;                   /* 1 píxel de grosor */
  background: var(--principal);  /* burdeos */
}  /* fin de las rayas del aspa */

.visor__aspa::before { transform: rotate(45deg); }    /* una raya girada 45° */
.visor__aspa::after  { transform: rotate(-45deg); }   /* la otra, girada al revés: juntas forman la X */

/* Mientras el visor está abierto (visor.js pone .visor-abierto en <html>),
   la página de detrás no se desplaza. El salto lateral al quitar la barra
   de scroll lo evita el scrollbar-gutter de <html> (en la base de la hoja):
   el hueco de la barra sigue reservado y el contenido no se ensancha. */
html.visor-abierto,
html.visor-abierto body { overflow: hidden; }   /* sin scroll */

/* La tarjeta de origen (.es-origen) se esconde: su foto está viajando.
   visibility: hidden la oculta pero conserva su hueco en la cuadrícula. */
.proyecto.es-origen { visibility: hidden; }

/* Mientras la foto vuelve (.es-regreso), la tarjeta de origen se queda en
   reposo aunque tenga el ratón o el foco encima: sin zoom y con el velo de
   siempre, que es como llega la foto. Sin esto aparecería ya ampliada un
   4,5 % y con el velo entero, y en el relevo se vería el salto. Al aterrizar
   visor.js le quita la clase y el hover entra con su propia transición. */
/* Foto de la tarjeta: sin zoom y sin animación. */
.proyecto.es-regreso img     { transform: none; transition: none; }
/* Velo de la tarjeta: en su intensidad de reposo (0,9) y sin animación. */
.proyecto.es-regreso::after  { opacity: var(--velo-tarjeta); transition: none; }

/* ==========================================================================
   12 · ADAPTACIÓN A PANTALLAS ESTRECHAS (toda la web)
   --------------------------------------------------------------------------
   Retoques que solo se aplican cuando la ventana es estrecha (móviles y
   tabletas). Cada bloque va dentro de una media query (@media) con su ancho
   máximo: sus reglas se suman a las de escritorio y, cuando dicen otra cosa,
   ganan porque van más abajo en el archivo (a igualdad de precisión, gana
   la última).
   · Hasta 860 px: cabecera más baja, logotipo y botón de Instagram más
     pequeños, el menú se convierte en un panel desplegable que se abre con
     el botón de dos rayas, botones algo más compactos y Section 2 y
     Section 3 en una sola columna.
   · Hasta 860 px: el visor de proyecto, con la foto casi a todo el ancho.
   · Hasta 900 px y hasta 600 px: la cuadrícula de proyectos pasa de tres
     columnas a dos, y después a una.
   · Al final, el bloque de movimiento reducido: si la persona ha pedido
     menos animaciones, se quitan los movimientos de la portada, del visor,
     de la cuadrícula y del menú.
   ========================================================================== */

/* Pantallas de 860 px de ancho o menos: cabecera, menú, botones y
   Section 2 y Section 3. */
@media (max-width: 860px) {                   /* solo en ventanas de 860 px de ancho o menos */
  :root { --header-h: 76px; }                 /* cabecera más baja: 76 px de alto en vez de 88 */

  .logo__img { height: 16px; }                /* logotipo más pequeño: 16 px de alto en vez de 20 */

  /* Bloques de la derecha de la cabecera y del pie (menú, Instagram y botón
     de menú): menos hueco entre sus piezas, 1rem. */
  .site-header__derecha,
  .site-footer__derecha { gap: 1rem; }
  /* Botón de Instagram más pequeño (36 × 36 px en vez de 40 × 40); el margen
     negativo de la derecha alinea el icono con el margen de la página. */
  .social { width: 36px; height: 36px; margin-right: -6px; }

  .nav-toggle { display: flex; }              /* aparece el botón de menú (dos rayas), oculto en escritorio */

  /* El menú de la cabecera se convierte en un panel desplegable: fijo justo
     debajo de la cabecera, a todo el ancho y con fondo crema. Cerrado,
     espera escondido por encima; al pulsar el botón de menú, main.js le pone
     la clase .is-open y el panel baja deslizándose. */
  .nav {
    position: fixed;                     /* clavado a la ventana: no se mueve al hacer scroll */
    /* Pegado a la ventana: arriba, donde acaba la cabecera; a derecha e
       izquierda, en el borde (0); abajo, auto (mide lo que su contenido).
       Los cuatro valores van como las agujas del reloj. */
    inset: var(--header-h) 0 auto 0;
    z-index: 40;                         /* capa 40: al deslizarse pasa por encima del logotipo y botones */
    background: var(--claro);            /* fondo crema */
    border-top: 1px solid rgba(165, 155, 146, .35);   /* raya fina arriba: gris topo al 35 % */
    transform: translateY(-120%);        /* escondido: subido un 120 % de su propio alto, fuera de la vista */
    /* visibility: hidden lo oculta del todo: no se ve y, además, sus enlaces
       quedan fuera del orden de tabulación (no se llega a ellos con Tab). */
    visibility: hidden;
    /* visibility no se puede fundir: con 0s y una espera de .45s cambia de
       golpe justo al final, cuando el panel ya ha salido de la vista. */
    transition: transform .45s cubic-bezier(.22, .61, .36, 1),  /* al cerrarse, sube en 0,45 s frenando suave */
                visibility 0s linear .45s;                      /* y se oculta del todo al acabar */
  }  /* fin de .nav */

  /* Menú abierto: main.js pone .is-open al pulsar el botón de menú y la
     quita al volver a pulsarlo, al elegir un enlace, con la tecla Escape o
     si la ventana se ensancha por encima de 860 px. */
  .nav.is-open {
    transform: translateY(0);            /* baja a su sitio, bajo la cabecera */
    visibility: visible;                 /* visible y alcanzable con el tabulador */
    transition: transform .45s cubic-bezier(.22, .61, .36, 1),  /* baja en 0,45 s con la misma curva */
                visibility 0s;                                  /* y se hace visible al instante, sin esperar */
  }  /* fin de .nav.is-open */

  /* Las reglas que siguen empiezan por «.nav » para afectar solo al menú de
     la cabecera: el menú del pie usa las mismas clases y no debe
     convertirse en un desplegable. */
  /* La lista de enlaces del panel, en columna. */
  .nav .nav__list {
    flex-direction: column;              /* los enlaces uno debajo de otro, en vez de en fila */
    align-items: flex-start;             /* pegados a la izquierda */
    gap: 0;                              /* sin hueco entre ellos: los separan su relleno y su raya */
    padding: .5rem var(--margen) 1.75rem;   /* .5rem arriba, el margen de la web a los lados, 1,75rem abajo */
  }  /* fin de la lista del panel */

  .nav .nav__list li { width: 100%; }    /* cada elemento de la lista ocupa todo el ancho */

  /* Cada enlace del panel: una fila entera, alta y fácil de pulsar con el
     dedo, con una raya fina debajo. */
  .nav .nav__link {
    display: block;                      /* como bloque, para ocupar la fila */
    width: 100%;                         /* todo el ancho: se pulsa en cualquier punto de la fila */
    padding-block: 1rem;                 /* relleno de 1rem arriba y abajo */
    font-size: 1.05rem;                  /* letra algo mayor que la normal (0,95rem en escritorio) */
    border-bottom: 1px solid rgba(165, 155, 146, .25);   /* raya debajo: gris topo al 25 % */
  }  /* fin de los enlaces del panel */

  .nav .nav__link::after { display: none; }   /* sin el filete caramelo que sale debajo al pasar el ratón */

  .btn-outline { padding: 1rem 2.5rem; }      /* botones de contorno más compactos: menos relleno */

  /* Section 2 y Section 3 en una sola columna, con la foto delante del
     texto. */
  .section2__inner,
  .section3__inner {
    grid-template-columns: 1fr;          /* una sola columna, en vez de dos */
    gap: clamp(2rem, 6vw, 3rem);         /* hueco entre foto y texto: 6 % del ancho, entre 2 y 3rem */
  }

  /* order cambia el orden en que se colocan las piezas de una rejilla sin
     tocar el HTML: de serie todas tienen 0, y con -1 una pasa delante. En
     Section 2 la foto va detrás del texto en el HTML; así sube arriba. En
     Section 3 ya va primero. */
  .section2__figura { order: -1; }

  /* En una columna no hay nada con lo que alinear: fuera el margen negativo
     de los títulos (ver sección 6). */
  .section2__titulo,
  .section3__titulo { margin-top: 0; }        /* títulos sin el margen negativo de arriba */

  /* Aquí no hay cruce de columnas, así que main.js no pone .en-vuelo y cada
     sección enseña su propia foto (sin el viaje de Section 2 a Section 3). */
}  /* fin de pantallas de 860 px o menos (cabecera, menú, botones y secciones) */

/* Pantallas de 860 px o menos: el visor de proyecto. La foto casi llena el
   ancho y los controles se hacen algo más pequeños. */
@media (max-width: 860px) {
  /* Nuevas medidas del visor (sus variables están en la sección 11). */
  :root {
    /* Aire de arriba: el alto de la cabecera más 6,5rem, porque en pantalla
       estrecha la descripción ocupa más renglones. Es el valor de partida:
       al abrir, visor.js mide la cabecera del visor y lo sustituye. */
    --visor-arriba: calc(var(--header-h) + 6.5rem);
    --visor-abajo:  4rem;                /* aire de abajo, para el contador: 4rem en vez de 5 */
    /* Ancho de cada foto: el menor entre el 86 % del ancho de la ventana y
       el que permite el alto libre con la proporción 5:4. */
    --diapo-w:      min(86vw, calc(var(--visor-hueco) * 1.25));
  }  /* fin de las medidas del visor */

  .visor__cabecera { top: calc(var(--header-h) - 1rem); }   /* título y descripción, algo más arriba */
  .visor__desc     { font-size: .85rem; }                   /* letra de la descripción algo menor */
  /* Flechas: zona pulsable de 44 × 44 px (56 en escritorio), subidas la
     mitad de su alto (22 px) para seguir centradas en vertical. */
  .visor__nav      { width: 44px; height: 44px; margin-top: -22px; }
}  /* fin del visor en pantallas estrechas */

/* Pantallas de 900 px o menos: la cuadrícula de proyectos pasa a dos
   columnas. Tres dejarían las fotos demasiado pequeñas.
   OJO: los cortes de 900 y 600 px coinciden con los del atributo sizes de
   las fotos de proyectos.html (con él el navegador elige qué tamaño de foto
   descargar). Si se cambian aquí, hay que cambiarlos también allí. */
@media (max-width: 900px) {
  .galeria { grid-template-columns: repeat(2, 1fr); }   /* dos columnas iguales: repeat(2, 1fr) = «1fr 1fr» */
}

/* Pantallas de 600 px o menos (móviles): una sola columna de proyectos. */
@media (max-width: 600px) {
  .galeria { grid-template-columns: 1fr; }              /* una tarjeta por fila, a todo el ancho */
}

/* Movimiento reducido ------------------------------------------------------
   prefers-reduced-motion: reduce = la persona ha pedido en los ajustes de
   su sistema (móvil u ordenador) que se reduzcan las animaciones, por
   ejemplo porque le marean. Entonces se quitan los movimientos de la
   portada, del visor, de la cuadrícula y del menú: todo se ve y funciona
   igual, pero sin desplazamientos. */
@media (prefers-reduced-motion: reduce) {
  /* Portada (hero): animation: none apaga la animación por fotogramas de
     cada pieza (la flecha que sube y baja, la entrada de los textos, del
     filete y del botón, y el pase de imágenes). Cada una se queda quieta en
     su sitio y del pase se ve directamente la foto final. */
  .hero__arrow,
  .hero__eyebrow,
  .hero__line,
  .hero__rule,
  .hero .btn-outline,
  .hero__slide {
    animation: none;                     /* sin animación */
  }  /* fin de las piezas de la portada */

  /* Sin pase: directamente la imagen final, y sin zoom al pasar el ratón. */
  .hero__foto { transition: none; }                            /* la foto no se anima al cambiar */
  .hero:hover .hero__slide--3 .hero__foto { transform: none; } /* sin acercamiento con el ratón encima */

  /* Sin alejamiento de la foto ni del texto al bajar. Section 2 sigue
     tapando la portada: eso es un cambio de sitio, no un movimiento añadido. */
  .hero__pase,
  .hero__content { transform: none; }    /* foto y texto de la portada, siempre a su tamaño */

  .hero__scroll { opacity: 1; transition: none; }   /* la flecha de bajada, siempre visible y sin fundido */

  /* Sin vuelo entre secciones: main.js no pone .en-vuelo, la foto se queda
     donde está y Section 3 enseña su propia copia, ya volteada. */

  /* Todo lo que se mueve al pulsar algo deja de moverse: el cambio se
     produce igual, pero sin recorrido. Los tiempos bajan a 0,01 s, casi
     nada. No a 0 del todo: sin transición el navegador no lanzaría el aviso
     de fin (transitionend) que visor.js espera para rematar. */
  :root {
    --mov:       .01s;                   /* tiempo general de movimiento */
    --mov-breve: .01s;                   /* tiempo corto de las piezas del visor */
    --visor-dur: .01s;                   /* vuelo del visor */
  }  /* fin de los tiempos reducidos */
  .visor__diapo,
  .visor__portada,
  .visor__rotulo { transition: none; }   /* fotos, portada y rótulo del visor: cambian de golpe */
  .galeria,
  .proyecto { transition: none; }        /* cuadrícula y tarjetas: se ocultan y vuelven sin transición */
  .proyecto.es-nueva { animation: none; } /* las que destapa «Ver más proyectos» aparecen sin animación */
  .galeria.se-dispersa .proyecto { transform: none; }   /* al abrir el visor, las tarjetas no se apartan */

  .nav { transition: none; }             /* el menú desplegable aparece y desaparece de golpe */

  .nav__link::after { transition: none; }   /* el filete de los enlaces aparece sin trazarse */
}  /* fin del movimiento reducido */

/* ==========================================================================
   13 · PASO DE UNA PÁGINA A OTRA
   --------------------------------------------------------------------------
   Las transiciones al cambiar de página. Las pone en marcha js/paso.js,
   con ayuda del pequeño guion que va en el <head> de cada página. Los
   tiempos salen de las variables de la sección 1 (--mov, --mov-salida y
   --mov-salida-lado): paso.js los lee de allí.

   Hay tres momentos:
   · Salida de lado. Al pulsar un enlace a otra página de la web (el menú,
     por ejemplo), la página que se va se desliza hacia un lado y se
     desvanece, y la que llega entra desde el lado contrario. Al avanzar (en
     el orden home, Proyectos, Quiénes somos, Contacto, Aviso legal) se va
     hacia la izquierda; al volver atrás, hacia la derecha.
   · Despegue desde el home. Al pulsar «Ver Proyectos» (en Section 3), la
     foto de esa sección se queda clavada en su sitio y el resto del home se
     apaga.
   · Llegada a Proyectos. La foto reaparece en el mismo sitio y retrocede
     hasta la primera casilla de la cuadrícula, mientras las demás tarjetas
     avanzan desde el fondo y se posan por capas.

   Cómo se enteran las páginas: la que se va deja una nota en
   sessionStorage (una pequeña memoria del navegador que dura mientras la
   pestaña está abierta). Al cargar la siguiente, el guion de su <head> lee
   la nota y, antes de que se pinte nada, escribe en <html> el atributo
   data-paso con el tipo de llegada: "lateral", "lateral-atras" o "vuelo".
   Así la página que llega no se ve ni un fotograma ya colocada.
   Los atributos data-… son datos propios que JavaScript apunta en una
   etiqueta. Aquí se leen con selectores como html[data-paso="vuelo"]
   («la etiqueta <html> cuando su data-paso vale vuelo»). Al terminar,
   paso.js quita el atributo; y si algo fallara, el guion del <head> lo
   quita solo a los 3 segundos.

   Clases que pone paso.js por el camino: en <html>, .saliendo y
   .hacia-atras (página que se va), .entrando (página que llega de lado) y
   .despegando (home); en Proyectos, .midiendo y .florece (cuadrícula),
   .se-posa (foto que llega) y .es-destino (primera tarjeta).

   Si la persona ha pedido menos animaciones, no hay transición: se navega
   sin más. Sin JavaScript, los enlaces funcionan como siempre.
   ========================================================================== */

/* Variables del paso entre páginas. */
:root {
  --curva-paso: var(--mov-curva, cubic-bezier(.4, 0, .1, 1));  /* curva de velocidad de la entrada de lado */
  --desliz:     9vw;                                           /* cuánto se desplaza de lado: 9 % del ancho */

  /* Curva del vuelo de llegada de la foto a Proyectos: la general de la web.
     OJO: dentro de un transition, un var() de una variable que no está
     declarada y sin valor de reserva anula la declaración entera: la foto
     no viajaría, aparecería de golpe en su casilla. Por eso esta variable
     tiene que estar declarada aquí, y los var() del vuelo llevan además su
     valor de reserva. */
  --esc-curva: var(--mov-curva, cubic-bezier(.4, 0, .1, 1));
}  /* fin de las variables del paso */

/* Salida de lado ----------------------------------------------------------
   Al pulsar un enlace, paso.js pone .saliendo en <html> (y .hacia-atras si
   se vuelve atrás), deja la nota "lateral" o "lateral-atras" y a los 0,2 s
   (--mov-salida-lado) abre la página nueva. Antes clava la cabecera y el
   pie en su sitio: con el cuerpo de la página desplazado, lo que va fijo a
   la ventana daría un salto. */

/* La que se va se congela del todo. La que llega solo recorta lo que asoma
   por los lados (entra desplazada y crearía scroll horizontal).
   overflow-x: clip recorta en horizontal sin convertir la página en una
   caja con scroll propio. OJO: con overflow: hidden el navegador no podría
   saltar al ancla de un enlace como index.html#contacto; con clip, sí. */
html.saliendo { overflow: hidden; }                     /* la que se va: sin scroll, congelada */

html[data-paso="lateral"],
html[data-paso="lateral-atras"] { overflow-x: clip; }   /* la que llega: recorta lo que asoma a los lados */

/* Al avanzar, la que se va sale por la izquierda. Al volver atrás, por la
   derecha: el mismo gesto del revés, que es lo que espera quien está
   deshaciendo el camino. */
html.saliendo body {
  transform: translateX(calc(-1 * var(--desliz)));   /* hacia la izquierda: --desliz en negativo (× -1) */
  opacity: 0;                                        /* y se desvanece */
  /* Los dos cambios duran --mov-salida-lado (0,2 s) y van acelerando: la
     curva del desplazamiento arranca suave y no frena, y ease-in hace lo
     mismo con el fundido. */
  transition: transform var(--mov-salida-lado, 200ms) cubic-bezier(.4, 0, 1, 1),
              opacity var(--mov-salida-lado, 200ms) ease-in;
}  /* fin de la página que se va */

/* Al volver atrás (paso.js añade .hacia-atras), sale hacia la derecha. */
html.saliendo.hacia-atras body {
  transform: translateX(var(--desliz));              /* desplazada a la derecha un 9 % del ancho */
}

/* Y la que llega entra siempre desde el lado contrario al que salió la
   otra: arranca desplazada e invisible.
   Llega tras avanzar: esperando a la derecha. */
html[data-paso="lateral"] body       { transform: translateX(var(--desliz)); opacity: 0; }
/* Llega tras volver atrás: esperando a la izquierda. */
html[data-paso="lateral-atras"] body { transform: translateX(calc(-1 * var(--desliz))); opacity: 0; }

/* Tras dos fotogramas (para que antes se pinte la posición de salida),
   paso.js pone .entrando en <html>: el cuerpo de la página va a su sitio y
   aparece. Al terminar, paso.js quita .entrando y data-paso. */
html[data-paso="lateral"].entrando body,
html[data-paso="lateral-atras"].entrando body {
  transform: none;                                   /* a su sitio */
  opacity: 1;                                        /* visible */
  transition: transform var(--mov, 300ms) var(--curva-paso),   /* recorrido: dura --mov (0,6 s) */
              opacity var(--mov, 300ms) ease-out;               /* fundido: lo mismo, frenando al final */
}  /* fin de la entrada de lado */

/* Despegue desde el home --------------------------------------------------
   Al pulsar «Ver Proyectos», paso.js pone encima una copia de la foto de
   Section 3 (.despegue) justo donde está la real, marca .despegando en
   <html> y a los 0,1 s (--mov-salida) abre Proyectos. La foto no se mueve
   aquí: se queda clavada en su sitio mientras el resto del home se
   disuelve. Todo el recorrido ocurre ya en Proyectos. */

/* La copia de la foto que se queda clavada. paso.js le escribe top, left,
   ancho y alto: los de la foto real en ese momento. */
.despegue {
  position: fixed;             /* clavada a la ventana */
  z-index: 90;                 /* capa 90: por encima de todo, también de la cabecera (50) */
  overflow: hidden;            /* recorta la imagen a su caja */
  background: var(--claro);    /* fondo crema mientras se pinta la imagen */
}  /* fin de .despegue */

/* La imagen de la copia y su envoltorio <picture> (la etiqueta que ofrece
   la misma foto en varios formatos y tamaños para que el navegador elija). */
.despegue img, .despegue picture {
  display: block;       /* como bloque: sin hueco debajo */
  width: 100%;          /* todo el ancho de la copia */
  height: 100%;         /* todo el alto */
  object-fit: cover;    /* llena la caja recortando lo que sobre, sin deformarse */
}  /* fin de la imagen de la copia */

html.despegando { overflow: hidden; }   /* mientras despega, el home no se puede desplazar */

/* Se apagan el contenido del home (main: la etiqueta <main>, todo lo que va
   entre la cabecera y el pie) y el pie. La cabecera NO se apaga: es
   idéntica en las dos páginas, así que dejándola puesta el cambio no se
   nota. Si se apagara aquí y reapareciera allí, daría un parpadeo justo en
   mitad del movimiento. */
html.despegando main,
html.despegando .site-footer {
  opacity: 0;                                          /* se desvanecen */
  transition: opacity var(--mov-salida, 100ms) ease;  /* en 0,1 s: acaba justo al cambiar de página */
  pointer-events: none;                                /* ya no se pueden pulsar */
}  /* fin del apagado del home */

html.despegando .site-header { pointer-events: none; }   /* la cabecera sigue visible, pero no se pulsa */

/* Llegada a Proyectos -----------------------------------------------------
   La foto reaparece en el sitio exacto que ocupaba en el home y retrocede
   hasta la primera casilla mientras la cuadrícula se forma detrás de ella.
   Son dos movimientos que empiezan y acaban a la vez, no uno detrás de
   otro, y duran lo que --mov (hoy 0,6 s).

   El recorrido de la foto va en transform, que no obliga a recolocar la
   página. Solo el ancho y el alto se animan de verdad, porque la foto del
   home es 3:2 y la casilla 5:4: al cambiar de tamaño con object-fit: cover,
   el navegador reencuadra la imagen en lugar de deformarla, y eso un
   escalado (scale) no lo sabe hacer. */

/* La foto que llega desde el home: un <div class="escalador"> de
   proyectos.html con la misma foto de Section 3 y el rótulo «Proyecto1».
   paso.js la coloca en el sitio exacto que ocupaba en el home y desde ahí
   la hace retroceder hasta su casilla. Sin medidas no ocupa nada, así que
   si algo fallara no se vería un destello. */
.escalador {
  display: none;          /* normalmente no se muestra */
  position: fixed;        /* clavada a la ventana */
  top: 0;                 /* en la esquina de arriba… */
  left: 0;                /* …a la izquierda: desde ahí la desplaza el transform */
  z-index: 70;            /* capa 70: por encima de la cabecera (50) y de las tarjetas */
  width: 0;               /* sin ancho… */
  height: 0;              /* …ni alto, hasta que paso.js se los escriba */
  overflow: hidden;       /* recorta la imagen a su caja: así se reencuadra al cambiar de tamaño */
  /* Se coloca con transform desde la esquina de la ventana, no con top y
     left: así el movimiento lo hace el compositor (la parte del navegador
     que desplaza capas ya pintadas, sin recalcular la página) y al diseño
     solo le llega el cambio de tamaño.
     translate3d(x, y, z) desplaza en horizontal, en vertical y en
     profundidad. Aquí vale 0, 0, 0: es el punto de partida, y paso.js lo
     sustituye por la posición de la foto. */
  transform: translate3d(0, 0, 0);
  /* contain avisa de que lo de dentro no afecta a lo de fuera: al cambiar
     de tamaño, el navegador recalcula (layout) y repinta (paint) solo esta
     caja, no el resto de la página. */
  contain: layout paint;
}  /* fin de .escalador */

html[data-paso="vuelo"] .escalador { display: block; }   /* solo se muestra durante la llegada */

/* La imagen de la foto que llega (y su <picture>). */
.escalador img, .escalador picture {
  display: block;       /* como bloque: sin hueco debajo */
  width: 100%;          /* todo el ancho de la caja */
  height: 100%;         /* todo el alto */
  object-fit: cover;    /* llena la caja recortando lo que sobre: al pasar de 3:2 a 5:4, reencuadra */
}  /* fin de la imagen de la foto que llega */

/* El mismo velo que llevan las tarjetas, para que el último fotograma del
   vuelo y la tarjeta que lo sustituye sean idénticos. */
.escalador::after {
  content: "";                        /* capa vacía: solo el velo */
  position: absolute;                 /* colocada libre encima de la foto */
  inset: 0;                           /* la cubre entera */
  background: var(--velo-proyecto);   /* el degradado del velo de las tarjetas (sección 9) */
  opacity: 0;                         /* arranca sin velo, como la foto del home */
}  /* fin del velo de la foto que llega */

/* En marcha: paso.js le pone .se-posa y a la vez le escribe el tamaño y la
   posición de la primera casilla; estas transiciones hacen el viaje.
   --esc-dur la escribe paso.js (vale lo mismo que --mov). Las tres con la
   misma curva y la misma duración: si una fuera distinta, las esquinas no
   irían juntas y se vería un temblor en lugar de un reencuadre. */
.escalador.se-posa {
  transition: transform var(--esc-dur, 300ms) var(--esc-curva, cubic-bezier(.4, 0, .1, 1)),   /* posición */
              width     var(--esc-dur, 300ms) var(--esc-curva, cubic-bezier(.4, 0, .1, 1)),   /* ancho */
              height    var(--esc-dur, 300ms) var(--esc-curva, cubic-bezier(.4, 0, .1, 1));   /* alto */
}

/* Durante el viaje, el velo sube hasta el de la tarjeta. */
.escalador.se-posa::after {
  opacity: .9;         /* 0,9, como la tarjeta */
  transition: opacity var(--esc-dur, 300ms) var(--esc-curva, cubic-bezier(.4, 0, .1, 1));  /* ritmo del viaje */
}

/* El rótulo llega con la foto, en el último tramo: así el fotograma final
   del vuelo y la tarjeta que lo sustituye son idénticos y el relevo no se
   nota. */
.escalador .proyecto__titulo { opacity: 0; }   /* el rótulo arranca invisible */

.escalador.se-posa .proyecto__titulo {
  opacity: 1;                          /* aparece entero */
  /* Espera el 40 % del viaje (× .4) y aparece durante el 60 % restante (× .6). */
  transition: opacity calc(var(--esc-dur, 300ms) * .6) ease
              calc(var(--esc-dur, 300ms) * .4);
}  /* fin del rótulo en marcha */

/* Las tarjetas esperan DETRÁS del plano de la pantalla y avanzan hasta él.

   No es un encogido. perspective da profundidad a lo que hay dentro de la
   cuadrícula: un elemento empujado hacia el fondo (en el eje Z, el que va
   de la pantalla hacia dentro) se ve más pequeño y más cerca del punto de
   fuga, como en un dibujo en perspectiva. Cada tarjeta espera a una
   profundidad distinta, así que lo que se ve es un avance hacia quien
   mira, con la tarjeta creciendo sola por efecto de la perspectiva.

   Por capas: paso.js mira lo lejos que está cada tarjeta de la primera
   casilla (sumando filas y columnas) y la pone en una de cuatro capas.
   Cuanto más lejos, más al fondo espera y más tarde arranca. A cada
   tarjeta le escribe:
   · --z: su profundidad de espera, de -520 a -1060 px (con la perspectiva
     de 1150 px se ven entre el 69 % y el 52 % de su tamaño).
   · --tar-ret: cuánto espera antes de arrancar (un escalón por capa; un
     escalón es --mov entre 15).
   · --tar-dur: lo que dura su avance (--mov menos tres escalones, para que
     la última capa acabe a la vez que la foto).
   · --tar-op-dur y --tar-op-ret: lo mismo para su aparición, que dura el
     70 % del avance (se ve entera antes de terminar de llegar).
   Una tarjeta cuyo centro queda por debajo del borde inferior de la
   pantalla no viaja: solo aparece (profundidad 0 y avance de 0 ms).

   El punto de fuga no es el centro de la cuadrícula sino el centro de la
   primera casilla (paso.js escribe --px y --py), y esa es la pieza que ata
   las dos animaciones: al avanzar, cada tarjeta se separa de ese punto, de
   modo que la cuadrícula se abre justo desde donde se está posando la foto.

   Solo se mueven transform y opacity: las dos las resuelve el compositor
   sin recalcular el diseño, y así quince tarjetas se mueven a la vez sin
   esfuerzo. */
html[data-paso="vuelo"] { overflow: hidden; }   /* mientras dura la llegada, la página no se desplaza */

/* La cuadrícula mientras se forma. */
html[data-paso="vuelo"] .galeria {
  /* Profundidad: el ojo de quien mira, a 1150 px de la pantalla (cuanto
     menor, más fuerte el efecto). --hondura no está declarada en esta hoja,
     así que vale el de reserva; para cambiarlo, declararla en :root. */
  perspective: var(--hondura, 1150px);
  /* Punto de fuga (perspective-origin): el centro de la primera casilla, que
     paso.js escribe en --px y --py; sin ellos, el centro de la cuadrícula. */
  perspective-origin: var(--px, 50%) var(--py, 50%);
  /* Mientras se están colocando no se puede pulsar nada: una tarjeta a medio
     llegar está en un sitio que no es el suyo. */
  pointer-events: none;
}  /* fin de la cuadrícula durante la llegada */

/* Cada tarjeta, esperando al fondo. */
html[data-paso="vuelo"] .proyecto {
  opacity: 0;                                        /* invisible */
  transform: translate3d(0, 0, var(--z, -700px));    /* empujada al fondo la distancia --z (si falta, 700 px) */
  /* Sin transición mientras esperan: la tarjeta ya trae una sobre transform
     (la que usa el visor al apartarlas) y, con ella puesta, sacarlas al
     plano un instante para medir (.midiendo) las movería con animación en
     vez de hacerlo al momento. */
  transition: none;
  will-change: transform, opacity;                   /* cambiarán las dos: el navegador las prepara */
}  /* fin de la tarjeta en espera */

/* .midiendo: paso.js la pone un instante (no llega a pintarse) para medir
   dónde cae cada tarjeta. Desde el fondo el navegador las mediría ya
   encogidas por la perspectiva; así se miden en el plano de la pantalla. */
html[data-paso="vuelo"] .galeria.midiendo .proyecto { transform: none; }

/* .florece: paso.js la pone en la cuadrícula a la vez que la foto empieza a
   posarse. Cada tarjeta avanza hasta el plano de la pantalla y aparece, con
   los tiempos que le ha escrito paso.js. --tar-curva no está declarada en
   esta hoja: vale la curva de reserva, la de la casa. */
html[data-paso="vuelo"] .galeria.florece .proyecto {
  opacity: 1;                          /* visible */
  transform: translate3d(0, 0, 0);     /* en el plano de la pantalla: a su tamaño y en su casilla */
  transition: transform var(--tar-dur, 240ms)                            /* el avance dura --tar-dur… */
                        var(--tar-curva, cubic-bezier(.4, 0, .1, 1))     /* …con la curva de la casa… */
                        var(--tar-ret, 0ms),                             /* …tras esperar --tar-ret */
              opacity   var(--tar-op-dur, 170ms) linear var(--tar-op-ret, 0ms);  /* aparición, ritmo constante */
}  /* fin de la tarjeta que avanza */

/* La casilla de destino (la primera tarjeta, marcada .es-destino por
   paso.js) no se enseña hasta que la foto termina de posarse encima de
   ella. Al acabar, paso.js le quita la clase y aparece en el mismo
   fotograma en que desaparece la foto que viajaba; como son el mismo
   encuadre, el relevo no se nota. */
html[data-paso="vuelo"] .galeria.florece .proyecto.es-destino {
  opacity: 0;          /* invisible */
  transform: none;     /* en su sitio, sin profundidad */
  transition: none;    /* sin transición: cambia de golpe */
}

/* Movimiento reducido: sin transiciones entre páginas, se navega y punto.
   Es una red de seguridad: con esta preferencia el guion del <head> ya no
   escribe data-paso y paso.js no anima nada, pero si algo quedara marcado,
   todo se ve quieto y en su sitio. */
@media (prefers-reduced-motion: reduce) {
  /* Página que se va y página que llega de lado: en su sitio, visibles y
     sin transición. */
  html.saliendo body,
  html[data-paso="lateral"] body,
  html[data-paso="lateral-atras"] body { transform: none; opacity: 1; transition: none; }

  /* La cuadrícula aparece puesta, sin perspectiva y sin avance, y la foto
     que viajaba no llega a existir. */
  html[data-paso="vuelo"] .galeria {
    perspective: none;           /* sin profundidad */
    pointer-events: auto;        /* se puede pulsar desde el principio */
  }
  html[data-paso="vuelo"] .proyecto {
    opacity: 1;                  /* visibles */
    transform: none;             /* en su casilla */
    will-change: auto;           /* sin preparación especial (auto = lo normal) */
  }  /* fin de las tarjetas */
  html[data-paso="vuelo"] .galeria.florece .proyecto,
  html[data-paso="vuelo"] .galeria.florece .proyecto.es-destino {
    opacity: 1;                  /* visibles, también la primera */
    transform: none;             /* en su casilla */
    transition: none;            /* sin transición */
  }  /* fin de las tarjetas en marcha */
  html[data-paso="vuelo"] .escalador { display: none; }   /* la foto que viajaba no se muestra */
}  /* fin del movimiento reducido del paso entre páginas */

/* Botón de contorno para fondo claro ---------------------------------------
   No forma parte del paso entre páginas, pero va aquí. El botón normal
   (.btn-outline, sección 5) es crema, pensado para ir sobre la foto de la
   portada; sobre el fondo crema no se vería. Esta variante, la que llevan
   «Ver Proyectos» (Section 3) y «Escríbenos» (Sección 4), lo pasa a
   burdeos. Al pasar el ratón se sigue rellenando de caramelo: la regla del
   :hover del botón normal pesa más que esta. */
.btn-outline--tinta {
  border-color: var(--principal);        /* borde: burdeos pleno de la marca (#3C1621) */
  color: var(--principal);               /* letra: burdeos pleno de la marca */
}

/* ==========================================================================
   14 · SECCIÓN 4
   ========================================================================== */

/* El final del home (index.html, la sección con id="contacto"). En el
   centro: el titular «Cuéntanos tu proyecto.», un párrafo, el botón
   «Escríbenos» y los tres datos de contacto (teléfono, correo y estudio).
   A cada lado: un montaje de tres muestras de material (fotos de madera, de
   un acabado de color y de piedra) que enmarcan el texto. En pantallas
   estrechas los dos montajes pasan a ir encima y debajo del texto.

   Norma de diseño: nada de rayas decorativas, giros ni degradados. Solo se
   permite la sombra, porque sin ella las muestras parecerían recortes
   pegados y no piezas de material apoyadas en una pared. La luz viene de
   arriba a la izquierda, igual para las seis, y la sombra va en dos capas:
   una corta y marcada, que hace el contacto con la pared, y otra larga y
   difusa. Así es como cae una sombra de verdad.

   Las muestras se colocan en porcentaje dentro de una caja de proporción
   fija, así que el montaje entero crece o encoge con la pantalla sin
   descuadrarse. */

/* La sección entera: la franja crema con la que termina el home. */
.cierre {
  position: relative;         /* permite usar z-index y sirve de referencia a lo de dentro */
  z-index: 3;                 /* capa 3: por encima de Section 3 y del hero, que se queda anclado */
  overflow: hidden;           /* recorta lo que sobresalga: ninguna muestra saca barra de scroll lateral */
  background: var(--claro);   /* fondo crema */
  color: var(--principal);    /* texto en burdeos */
  /* scroll-margin-top: al saltar aquí desde un enlace a #contacto, la página
     se detiene dejando arriba el alto de la cabecera, para que no tape el
     principio de la sección. */
  scroll-margin-top: var(--header-h);
}                             /* fin de .cierre */

/* La caja interior: una rejilla (grid) de tres columnas —muestras, texto,
   muestras— en proporción fija 1 : 2 : 1. Se reparte en fracciones y no con
   un ancho fijo para la del medio: con un ancho fijo, al estrechar la
   ventana la central se quedaría todo el sitio y las muestras encogerían
   hasta verse ridículas. En fracciones, las tres menguan a la vez y el
   montaje mantiene su peso hasta que el diseño pasa a una sola columna. */
.cierre__inner {
  display: grid;              /* coloca sus hijos en una rejilla de columnas */
  /* Las tres columnas. fr = una parte del espacio libre: la central recibe
     2 partes y las laterales 1 cada una. minmax(0, …) permite que una
     columna encoja hasta 0 aunque su contenido sea más ancho; sin ese 0,
     un contenido largo ensancharía su columna y descuadraría el reparto. */
  grid-template-columns: minmax(0, 1fr) minmax(0, 2fr) minmax(0, 1fr);
  align-items: center;                 /* centra en vertical el contenido de cada columna */
  gap: clamp(1rem, 3vw, 3.25rem);      /* hueco entre columnas: 3 % del ancho de la ventana, entre 1 y 3,25rem */
  max-width: 96rem;                    /* no pasa de 96rem de ancho en pantallas muy grandes */
  margin-inline: auto;                 /* y se centra en la página */
  /* Relleno a los lados: el margen general de la web.
     Relleno arriba: 10 % del ancho de la ventana (entre 5 y 9rem).
     Relleno abajo: el MISMO cálculo más 150 px extra, para dejar más aire
     entre la sección y el pie de la página (que se sube al llegar al final,
     ver .site-footer). */
  padding-top:    clamp(5rem, 10vw, 9rem);
  padding-inline: var(--margen);
  padding-bottom: calc(clamp(5rem, 10vw, 9rem) + 150px);
}                                      /* fin de .cierre__inner */

/* --------------------------------------------------------- el texto ---- */

/* La columna central: titular, párrafo, botón y datos. */
.cierre__texto {
  text-align: center;         /* todo el texto, centrado */
  /* Convierte esta columna en un «contenedor»: lo que tiene dentro puede
     medirse en proporción a SU ancho (con la unidad cqw, ver abajo) en vez
     de al ancho de la ventana. Así el titular nunca se sale de ella, caiga
     donde caiga el ancho. */
  container-type: inline-size;
}                             /* fin de .cierre__texto */

/* El titular «Cuéntanos tu proyecto.»: siempre en una sola línea y lo más
   grande que quepa. Esa frase mide 10,44 em de ancho en Playfair (medido, no
   estimado; em = el tamaño de la letra), así que para ocupar el 98 % de su
   columna necesita 9,39 cqw. Se deja en 9,3 y con un techo de 3,25rem para
   que en pantallas anchas no crezca sin fin.
   cqw = 1 % del ancho del contenedor más cercano (aquí, .cierre__texto).

   Hay dos font-size seguidos a propósito: el primero es el respaldo para
   navegadores que no entienden cqw; el segundo lo sustituye donde sí se
   entiende. Con el respaldo el titular también cabe en una línea, porque
   3,4vw se queda corto a propósito.
   OJO: si se cambia el texto del titular, hay que rehacer la cuenta. */
.cierre__titulo {
  margin: 0;                                  /* sin márgenes propios */
  font-family: var(--display);                /* letra de titulares (Playfair Display) */
  font-weight: 400;                           /* grosor normal, sin negrita */
  font-size: clamp(1.35rem, 3.4vw, 3.25rem);  /* respaldo: 3,4 % del ancho de ventana, entre 1,35 y 3,25rem */
  font-size: min(3.25rem, 9.3cqw);            /* min() usa el menor: 9,3 % de la columna o 3,25rem */
  line-height: 1.16;                          /* alto de cada línea: 1,16 veces el tamaño de la letra */
  white-space: nowrap;                        /* prohíbe partir el titular en dos líneas */
}                                             /* fin de .cierre__titulo */

/* El párrafo bajo el titular. */
.cierre__parrafo {
  max-width: 34rem;                               /* renglones de 34rem como mucho, cómodos de leer */
  margin: clamp(1.1rem, 2.4vw, 1.75rem) auto 0;   /* arriba, hueco con el titular; auto a los lados lo centra */
  font-size: 1rem;                                /* tamaño de letra normal */
  font-weight: 300;                               /* letra fina */
  line-height: 1.75;                              /* renglones holgados */
  /* Reparte las palabras para que los renglones queden de largo parecido,
     en lugar de dejar el último casi vacío. El navegador que no lo entienda
     lo ignora y parte los renglones como siempre. */
  text-wrap: balance;
}                                                 /* fin de .cierre__parrafo */

/* El botón «Escríbenos», que lleva a la página de Contacto: hueco encima. */
.cierre__boton { margin-top: clamp(1.75rem, 3.4vw, 2.5rem); }

/* Los tres datos de contacto en tres columnas iguales, alineadas por
   arriba: la etiqueta encima y el dato debajo. Al repartirse el ancho a
   partes iguales quedan a la misma distancia entre sí sin tener que medir
   nada. En el HTML son una lista (<ul>), así que se le quitan las viñetas. */
.cierre__datos {
  display: grid;                                      /* rejilla */
  grid-template-columns: repeat(3, minmax(0, 1fr));   /* tres columnas iguales (repeat repite lo de dentro 3 veces) */
  align-items: start;                                 /* alineadas por arriba */
  gap: clamp(.75rem, 1.6vw, 1.25rem);                 /* hueco entre columnas */
  margin: clamp(2rem, 4vw, 3rem) 0 0;                 /* hueco encima, bajo el botón; nada a los lados ni abajo */
  padding: 0;                                         /* quita la sangría que el navegador pone a las listas */
  list-style: none;                                   /* quita las viñetas (los puntos) de la lista */
}                                                     /* fin de .cierre__datos */

/* Cada uno de los tres datos. */
.cierre__datos li {
  font-size: .85rem;          /* letra algo más pequeña que la normal */
  font-weight: 300;           /* fina */
  line-height: 1.55;          /* alto de línea */
  /* El correo no cabe de una línea en ninguna pantalla (necesita 210 px y la
     columna nunca pasa de 207), así que se parte por la arroba: el <wbr> del
     HTML marca ahí el único sitio por donde puede cortarse. break-word queda
     de red: si algún día entra un dato más largo, lo parte donde haga falta
     antes que dejar que se salga de su columna. */
  overflow-wrap: break-word;
}                             /* fin de .cierre__datos li */

/* Las etiquetas «Teléfono», «Correo» y «Estudio». */
.cierre__etiqueta {
  display: block;             /* ocupa su propio renglón, encima del dato */
  margin-bottom: .5rem;       /* hueco entre la etiqueta y el dato */
  font-size: .7rem;           /* letra pequeña */
  font-weight: 500;           /* seminegrita */
  letter-spacing: .18em;      /* letras separadas entre sí */
  text-transform: uppercase;  /* en mayúsculas, aunque en el HTML no lo estén */
}                             /* fin de .cierre__etiqueta */

/* Los enlaces del teléfono y del correo: llevan debajo una raya invisible
   que se tiñe de caramelo al pasar el ratón o al llegar con el teclado. */
.cierre__datos a {
  border-bottom: 1px solid transparent;   /* raya de 1 px debajo, de momento transparente */
  transition: border-color .35s ease;     /* el cambio de color de la raya dura 0,35 s y es suave */
}

/* :hover = con el ratón encima; :focus-visible = seleccionado con el teclado (tecla Tab). */
.cierre__datos a:hover,
.cierre__datos a:focus-visible { border-color: var(--contraste-1); }   /* la raya se vuelve caramelo */

/* ---------------------------------------------------- las muestras ----- */
/* Cada juego de muestras (.cierre__muestras) es una caja de proporción fija
   —100 de ancho por 124 de alto— y dentro van las tres fotos, con su
   posición y su tamaño en porcentaje de esa caja. Las medidas salen de la
   captura de referencia, pasadas a estas unidades: el mismo tamaño relativo
   entre las tres, el mismo hueco de pared entre la madera y el cuadrado
   (unas 13 unidades) y el mismo solape corto de la encimera sobre las otras
   dos. En cada juego: «madera» = nogal o roble, «cuadrado» = lacado claro o
   verde salvia, «encimera» = travertino o mármol.

   OJO con las unidades, que es donde está la trampa: width y left van en
   porcentaje del ANCHO de la caja, pero top va en porcentaje del ALTO. El
   montaje está pensado en unidades de ancho (100 a lo ancho, 124 a lo alto),
   así que cada top es su unidad dividida entre 1,24 (por ejemplo,
   80 / 1,24 = 64,52 %). El alto de cada muestra sale de su aspect-ratio, que
   también parte del ancho, y por eso no hay que convertirlo.

      muestra      unidad Y   top         alto (u)   abajo (u)
      madera           0        0 %          67,2       67,2
      cuadrado        80       64,52 %       44        124
      encimera         6        4,84 %      113,4      119,4

   («unidad Y» = distancia desde arriba; «abajo» = dónde termina la muestra,
   unidad Y + alto.) El juego de la derecha es la misma cuenta con las X
   invertidas (x' = 100 - x - ancho). Nada pasa de 124, que es el alto de la
   caja: por eso no se corta ninguna muestra.

   El tamaño del montaje lo da el ancho de su columna. --muestras-escala está
   para agrandarlo o achicarlo sin tocar nada más; hoy no está definida en
   ningún sitio, así que vale 1 (tamaño normal). */

/* Cada uno de los dos juegos (el de la izquierda y el de la derecha). */
.cierre__muestras {
  position: relative;                              /* referencia para colocar las muestras dentro, en % */
  justify-self: center;                            /* centrado a lo ancho dentro de su columna de la rejilla */
  width: calc(100% * var(--muestras-escala, 1));   /* ancho de su columna por la escala (1 si no se define) */
  /* aspect-ratio fija la proporción ancho / alto de la caja: por cada 100
     de ancho, 124 de alto. El alto se calcula solo a partir del ancho, así
     que la caja nunca se deforma, mida lo que mida la columna. */
  aspect-ratio: 100 / 124;
}                                                  /* fin de .cierre__muestras */

/* Los dos juegos se desplazan hacia el EXTERIOR de la pantalla: el de la
   izquierda 100 px a la izquierda, el de la derecha 100 px a la derecha. Así
   dejan más aire alrededor del texto central. .cierre lleva overflow:hidden,
   así que aunque sobresalgan un poco no aparece scroll horizontal. En
   pantallas estrechas (ver la media query de abajo) los juegos pasan a ir en
   banda encima y debajo del texto: allí el desplazamiento lateral no tiene
   sentido y se anula. */
.cierre__muestras--izq { transform: translateX(-100px); }
.cierre__muestras--der { transform: translateX( 100px); }

/* Cada muestra: una foto de material dentro de un <span>. */
.muestra {
  position: absolute;         /* se coloca libre dentro de su juego, medida desde sus bordes (left, top) */
  overflow: hidden;           /* recorta la foto a la forma de la muestra */
  /* Sombra en dos capas, con la luz arriba a la izquierda (por eso cae
     hacia abajo y a la derecha): la corta hace el contacto con la pared y la
     larga lo abre. Es lo que hace que se lean como piezas apoyadas y no como
     recortes pegados, lo que separa las que se solapan y lo que despega el
     lacado claro del fondo, que es casi de su mismo tono.
     Cada capa: desplazamiento a la derecha, hacia abajo, difuminado,
     extensión (negativa = sombra más pequeña que la pieza) y color. */
  box-shadow:
    .15rem .3rem  .55rem -.2rem rgba(60, 22, 33, .22),   /* corta y cerrada: burdeos de la marca al 22 % */
    .7rem  1.1rem 2.4rem -.8rem rgba(60, 22, 33, .28);   /* larga y abierta: burdeos de la marca al 28 % */
}                             /* fin de .muestra */

/* La foto dentro de cada muestra. */
.muestra img {
  display: block;             /* como bloque (ya lo es por la regla general de imágenes; se repite por seguridad) */
  width: 100%;                /* llena todo el ancho de la muestra */
  height: 100%;               /* y todo su alto */
  object-fit: cover;          /* cubre la caja sin deformarse; lo que sobra de la foto se recorta */
}                             /* fin de .muestra img */

/* Juego de la izquierda: nogal arriba, lacado claro debajo y el travertino
   cruzándolos. En cada línea: left = distancia al borde izquierdo de la
   caja, top = distancia al borde de arriba, width = ancho y aspect-ratio =
   proporción ancho / alto de la foto. */
/* Nogal (madera): tira vertical de 5 de ancho por 8 de alto, arriba del todo. */
.muestra--nogal      { left:  4%; top:  0%;     width: 42%; aspect-ratio: 5 / 8; }
/* Lacado claro (cuadrado): pegado al borde izquierdo, 80 unidades abajo (80 / 1,24). */
.muestra--lacado     { left:  0%; top: 64.52%;  width: 44%; aspect-ratio: 1 / 1; }
/* Travertino (encimera): tira alta de 10 por 21, 6 unidades abajo (6 / 1,24), hacia el texto. */
.muestra--travertino { left: 40%; top:  4.84%;  width: 54%; aspect-ratio: 10 / 21; }

/* Juego de la derecha: el mismo montaje con las X invertidas. Es otra
   combinación —roble, verde salvia y mármol blanco—, así que aquí no hay
   nada que voltear: son materiales distintos, no el mismo juego repetido. */
/* Roble (madera): arriba del todo, hacia el borde derecho. */
.muestra--roble      { left: 54%; top:  0%;     width: 42%; aspect-ratio: 5 / 8; }
/* Verde salvia (cuadrado): abajo, pegado al borde derecho (56 + 44 = 100). */
.muestra--verde      { left: 56%; top: 64.52%;  width: 44%; aspect-ratio: 1 / 1; }
/* Mármol blanco (encimera): cruzando por la izquierda, hacia el texto. */
.muestra--marmol     { left:  6%; top:  4.84%;  width: 54%; aspect-ratio: 10 / 21; }

/* Orden de apilado (z-index: el número más alto queda encima). En los dos
   juegos la encimera va por encima de las otras dos, y el cuadrado sobre la
   madera. Cada línea afecta a las dos muestras que nombra. */
.muestra--nogal,      .muestra--roble  { z-index: 1; }   /* madera: capa de abajo */
.muestra--lacado,     .muestra--verde  { z-index: 2; }   /* cuadrado: capa intermedia */
.muestra--travertino, .muestra--marmol { z-index: 3; }   /* encimera: capa de arriba */

/* ----------------------------------------------- pantallas estrechas --- */
/* En pantalla estrecha los dos juegos no caben a los lados del texto, así
   que se tumban: todo pasa a una sola columna, con un juego en banda encima
   del texto y el otro debajo (el orden en que van en el HTML). El montaje
   no se pierde, solo cambia de eje. Es la misma cuenta de antes, sobre una
   caja de 100 de ancho por 51 de alto: cada top es su unidad dividida entre
   0,51 (1 unidad = 1,96 %; 21 unidades = 41,18 %). La proporción de cada
   foto (su aspect-ratio) no cambia, y la más alta (la encimera, 50,4
   unidades) cabe justa en los 51. */
@media (max-width: 960px) {                      /* solo en ventanas de 960 px de ancho o menos */
  .cierre__inner {
    grid-template-columns: minmax(0, 34rem);     /* una sola columna, de 34rem como mucho */
    justify-content: center;                     /* esa columna, centrada en la página */
    gap: clamp(2rem, 6vw, 3rem);                 /* hueco entre las bandas de muestras y el texto */
    /* Relleno arriba: algo menor que en escritorio (4-6rem, según el ancho).
       Relleno abajo: lo mismo más los 150 px extra de separación con el pie. */
    padding-top:    clamp(4rem, 12vw, 6rem);
    padding-bottom: calc(clamp(4rem, 12vw, 6rem) + 150px);
  }                                              /* fin de .cierre__inner */

  /* Cada juego pasa a ser una banda apaisada. */
  .cierre__muestras {
    width: 100%;                                 /* todo el ancho de la columna (aquí no se aplica la escala) */
    aspect-ratio: 100 / 51;                      /* caja de 100 de ancho por 51 de alto */
  }

  /* En una sola columna las bandas están centradas: el desplazamiento a los
     lados que llevan en escritorio no tiene sentido aquí (las sacaría del
     texto y se cortarían con overflow:hidden). */
  .cierre__muestras--izq,
  .cierre__muestras--der { transform: none; }

  /* Nueva posición y nuevo ancho de cada muestra dentro de su banda. */
  .muestra--nogal      { left:  3%; top:  1.96%; width: 26%; }   /* nogal: a la izquierda, casi arriba */
  .muestra--lacado     { left: 26%; top: 41.18%; width: 27%; }   /* lacado: solapa con el nogal, más abajo */
  .muestra--travertino { left: 50%; top:  0%;    width: 24%; }   /* travertino: de arriba abajo, sobre el lacado */

  .muestra--roble      { left: 71%; top:  1.96%; width: 26%; }   /* roble: a la derecha, casi arriba */
  .muestra--verde      { left: 47%; top: 41.18%; width: 27%; }   /* verde: solapa con el roble, más abajo */
  .muestra--marmol     { left: 26%; top:  0%;    width: 24%; }   /* mármol: de arriba abajo, sobre el verde */

  /* La sombra, más pequeña, a juego con las muestras más pequeñas. */
  .muestra {
    box-shadow:
      .1rem  .2rem .4rem  -.15rem rgba(60, 22, 33, .22),   /* capa corta */
      .45rem .7rem 1.5rem -.5rem  rgba(60, 22, 33, .28);   /* capa larga */
  }                                              /* fin de .muestra */
}                                                /* fin de la media query de 960 px */

/* Hasta 420 px de ancho los tres datos no caben en fila sin partirse
   en trozos ilegibles, así que se apilan uno debajo de otro. */
@media (max-width: 420px) {
  .cierre__datos {
    grid-template-columns: 1fr;                  /* una sola columna */
    gap: clamp(1.1rem, 4vw, 1.5rem);             /* hueco entre un dato y el siguiente */
  }
}

/* ==========================================================================
   15 · FORMULARIO DE CONTACTO
   ========================================================================== */

/* El formulario de la página de Contacto (contacto.html). Lo que ocurre al
   rellenarlo y enviarlo (comprobar los campos, marcar los errores, escribir
   los mensajes) lo hace js/contacto.js; aquí solo está su aspecto.

   Cada campo es solo una línea fina (un «filete») sobre la que se escribe,
   con su etiqueta encima: ni cajas, ni fondos, ni recuadros. Parece el
   renglón de un cuaderno, y eso hace que la columna se lea de un vistazo.
   El sitio que ocuparían las cajas se lo queda el aire entre campos: el
   formulario no se acorta, se despeja.

   Las etiquetas flotan: con el campo vacío, la etiqueta descansa sobre la
   línea, como un rótulo; al pulsar en el campo o escribir en él, sube por
   encima y se queda ahí. Los avisos de error no se ven en pantalla (los
   lee el lector de pantalla); para quien ve, el error lo marcan la línea
   del campo y el renglón de estado bajo el botón. */

.formulario { margin: 0; }   /* el formulario en sí: sin ningún margen que le ponga el navegador */

/* Cada campo (.campo) es una caja con tres cosas dentro: el sitio donde se
   escribe (.campo__control), su etiqueta y su aviso de error. La etiqueta va
   DENTRO, flotando sobre la línea, y no en un renglón aparte: así cada línea
   tiene su etiqueta justo encima y no hay duda de a cuál pertenece. (En un
   renglón aparte, cada línea quedaría más cerca de la etiqueta del campo
   siguiente que de la suya, y parecería de ese otro.) De paso el formulario
   ahorra cuatro renglones, unos 40 px de alto.

   El relleno de arriba y el de abajo del campo van en variables porque la
   etiqueta los necesita para saber dónde posarse y cuánto subir. */
.campo {
  /* Relleno de arriba: el sitio al que sube la etiqueta. Es lo bastante alto
     para que, con la etiqueta subida, quede aire entre ella y lo escrito
     (antes, en pantallas bajas, se tocaban casi). */
  --campo-arriba: clamp(1.3rem, 3vh, 1.65rem);
  --campo-abajo:  clamp(.25rem, .7vh, .45rem);    /* relleno de abajo: entre el texto escrito y la línea */
  position: relative;                             /* la etiqueta y el aviso se colocan respecto a esta caja */
  /* Aire entre campos, atado al alto de la ventana (vh = 1 % del alto): en
     una pantalla baja se encoge lo justo para que la página siga entrando
     sin scroll, y en una alta se estira hasta 2,4rem. */
  margin-bottom: clamp(1rem, 2.6vh, 2.2rem);      /* (algo menos que antes: compensa el relleno de arriba, que ha crecido) */
}                                                 /* fin de .campo */

/* La etiqueta de cada campo («Nombre y apellidos», «Correo electrónico»…).
   En reposo se posa sobre la línea de escritura, haciendo de rótulo del
   campo vacío; en cuanto el campo recibe el foco o tiene algo escrito, sube
   por encima (regla siguiente). Nunca desaparece. Por eso no se usa un
   placeholder (el texto de ejemplo gris dentro del campo) como etiqueta: el
   placeholder se borra al escribir y el campo se queda sin nombre. */
.campo__etiqueta {
  position: absolute;                        /* flota encima del campo, sin ocupar sitio propio */
  left: 0;                                   /* pegada al borde izquierdo, donde empieza la línea */
  top: calc(var(--campo-arriba) + .47rem);   /* a la altura del texto: bajo el relleno de arriba y un poco más */
  line-height: 1.2;                          /* renglón justo: la etiqueta ocupa solo lo que mide su letra */
  color: var(--tinta-suave);                 /* burdeos suavizado mientras está en reposo */
  font-size: .75rem;                         /* letra pequeña */
  font-weight: 500;                          /* seminegrita */
  letter-spacing: .18em;                     /* letras separadas */
  text-transform: uppercase;                 /* en mayúsculas */
  pointer-events: none;                      /* el clic la atraviesa y va al campo de debajo */
  /* Transición: la subida (transform) dura 0,3 s con la curva de movimiento
     de la casa (--mov-curva); el cambio de color, 0,3 s suave. */
  transition: transform .3s var(--mov-curva, cubic-bezier(.4, 0, .1, 1)),
              color .3s ease;
}                                            /* fin de .campo__etiqueta */

/* La etiqueta sube cuando el campo tiene el foco (:focus, el cursor está
   dentro) o cuando ya tiene algo escrito. Piezas del selector:
   - :placeholder-shown = «el campo está mostrando su placeholder», es
     decir, está vacío. Por eso en el HTML cada campo lleva placeholder=" "
     (un espacio invisible): sin placeholder, esto no funcionaría.
   - :not(…) le da la vuelta: «NO está vacío», o sea, tiene algo escrito.
   - El signo + (selector «hermano siguiente») señala el elemento que va
     justo DESPUÉS, al mismo nivel: la etiqueta que sigue al campo. Por eso
     en el HTML el campo va antes que su etiqueta: CSS solo puede mirar
     hacia delante, no hacia atrás. */
.campo__control:focus + .campo__etiqueta,
.campo__control:not(:placeholder-shown) + .campo__etiqueta {
  /* translateY desplaza en vertical; negativo = hacia arriba. Sube lo que
     mide el relleno de arriba del campo más el .47rem de su posición: así
     queda arriba del todo del campo, bien separada de lo escrito debajo. */
  transform: translateY(calc(-1 * var(--campo-arriba) - .47rem));
  color: var(--principal);                   /* y pasa a burdeos pleno */
}                                            /* fin de la etiqueta subida */

/* La palabra «(opcional)» de la etiqueta del teléfono. Se distingue del resto
   de la etiqueta por el grosor y por ir en minúsculas, no por ser más clara:
   con transparencia bajaría a un contraste (diferencia de luz entre texto y
   fondo) de 3,9:1, menos de lo que pide un texto tan pequeño. */
.campo__opcional {
  font-weight: 400;           /* grosor normal, más fina que el resto de la etiqueta */
  letter-spacing: .12em;      /* algo menos separada */
  text-transform: none;       /* anula las mayúsculas: se ve tal como está escrita */
}

/* El sitio donde se escribe (los <input> y el <textarea>). Sin relleno a los
   lados: el texto arranca justo donde arranca la línea, en la misma vertical
   que la etiqueta. Es lo que alinea la columna entera. */
.campo__control {
  display: block;                                      /* ocupa su propio renglón */
  width: 100%;                                         /* todo el ancho de la columna */
  padding: var(--campo-arriba) 0 var(--campo-abajo);   /* relleno: arriba el sitio de la etiqueta; 0 a los lados */
  border: 0;                                           /* quita el recuadro que el navegador pone a los campos */
  /* Solo queda la línea de abajo: 1 px de burdeos de la marca al 55 %, que
     da un contraste de 3,46:1 sobre el crema. OJO: no bajar de 3:1, que es
     el mínimo que se pide al borde de un campo para que se vea dónde está
     (al 25 % se quedaría en 1,65:1). */
  border-bottom: 1px solid rgba(60, 22, 33, .55);
  border-radius: 0;                                    /* esquinas rectas: iOS las redondea por su cuenta */
  background: transparent;                             /* sin fondo: se ve el crema de la página */
  color: var(--principal);                             /* lo que se escribe, en burdeos */
  font-family: inherit;                                /* la letra de la página (los campos no la heredan solos) */
  font-size: 1rem;                                     /* tamaño normal (con menos, el iPhone amplía al escribir) */
  font-weight: 400;                                    /* grosor normal */
  line-height: 1.6;                                    /* alto de línea */
  transition: border-color .35s ease, box-shadow .35s ease;   /* los cambios de la línea duran 0,35 s */
  -webkit-appearance: none;                            /* quita el aspecto propio del navegador (Safari, Chrome antiguos) */
          appearance: none;                            /* lo mismo, versión estándar */
}                                                      /* fin de .campo__control */

/* El texto de ejemplo (::placeholder) dentro del campo: burdeos al 40 %.
   Hoy los placeholder son un espacio en blanco, así que no se ve nada. */
.campo__control::placeholder { color: var(--principal); opacity: .4; }

/* Con el ratón encima, la línea se oscurece: burdeos de la marca al 75 %. */
.campo__control:hover { border-bottom-color: rgba(60, 22, 33, .75); }

/* Con el foco (el cursor dentro del campo), la línea pasa a burdeos pleno y a
   dos píxeles de grosor. El segundo píxel es una sombra, no un borde más
   gordo: así no se mueve ni un milímetro el resto de la columna. */
.campo__control:focus {
  outline: none;                             /* quita el recuadro de foco del navegador */
  border-bottom-color: var(--principal);     /* línea en burdeos pleno */
  box-shadow: 0 1px 0 0 var(--principal);    /* sombra dura de 1 px justo debajo: la línea parece de 2 px */
}

/* Como el foco ya se ve en la línea, el recuadro del navegador también sobra
   al llegar al campo con el teclado. */
.campo__control:focus-visible { outline: none; }

/* El campo grande «Cuéntanos» (<textarea>). */
.campo__control--area {
  /* rows="4" del HTML ya le da un alto propio, y min-height solo pondría un
     suelo por debajo: hace falta height para que obedezca al alto de la
     ventana. */
  height: clamp(3.5rem, 8.6vh, 7rem);        /* alto: 8,6 % del alto de la ventana, entre 3,5 y 7rem */
  min-height: 0;                             /* sin alto mínimo que se lo impida */
  resize: vertical;                          /* se puede estirar hacia abajo arrastrando su esquina */
}                                            /* fin de .campo__control--area */

/* :-webkit-autofill = el navegador ha rellenado el campo con datos guardados.
   Chrome lo pinta entonces de azul, que se llevaría por delante la línea y
   volvería a dibujar una caja. Se le devuelve el color de la página con una
   sombra interior enorme de color crema. */
.campo__control:-webkit-autofill {
  -webkit-text-fill-color: var(--principal);             /* el texto rellenado, en burdeos */
  -webkit-box-shadow: 0 0 0 1000px var(--claro) inset;   /* sombra interior crema de 1000 px: tapa el azul */
  caret-color: var(--principal);                         /* el cursor que parpadea, en burdeos */
}

/* Relleno automático y foco a la vez. La sombra crema de arriba sustituye a
   la línea de foco en lugar de sumarse (gana la última sombra declarada),
   así que aquí van las dos juntas. */
.campo__control:-webkit-autofill:focus {
  -webkit-box-shadow: 0 0 0 1000px var(--claro) inset,   /* la sombra crema */
                      0 1px 0 0 var(--principal);         /* más la línea de foco */
}

/* Campo con error (js/contacto.js le pone la clase .es-erroneo a su caja).
   El error no se fía solo del color: la línea, además de ponerse caramelo,
   se engorda, y el renglón de estado de abajo lo dice por escrito, que es
   lo que lee quien no distingue el matiz. */
.campo.es-erroneo .campo__control {
  border-bottom-color: var(--contraste-1);   /* línea caramelo */
  box-shadow: 0 1px 0 0 var(--contraste-1);  /* y de 2 px, con el mismo truco de la sombra */
}

/* El aviso de error de cada campo. No se ve en pantalla ni ocupa sitio, así
   que no aprieta el formulario; pero el lector de pantalla (el programa que
   lee la web en voz alta a personas ciegas) lo lee al entrar en el campo,
   porque va enlazado con aria-describedby. Para quien ve, el error lo
   marcan la línea, que se engorda además de cambiar de color, y el renglón
   de estado de abajo, que nombra los campos que faltan. No se usa
   display: none porque eso lo ocultaría también al lector. Mientras no hay
   error, el aviso lleva el atributo hidden y no existe para nadie.
   Es la misma técnica que .solo-lectores. */
.campo__aviso {
  position: absolute;         /* sale del flujo: no empuja nada */
  width: 1px;                 /* se reduce a un punto de 1 px de ancho… */
  height: 1px;                /* …por 1 px de alto */
  margin: -1px;               /* retirado hacia fuera ese mismo píxel */
  padding: 0;                 /* sin relleno */
  border: 0;                  /* sin borde */
  overflow: hidden;           /* lo que no cabe en ese punto, oculto */
  /* clip-path recorta la parte visible de un elemento; inset(50%) recorta
     desde cada lado hasta la mitad, así que no queda nada a la vista. */
  clip-path: inset(50%);
  white-space: nowrap;        /* en una sola línea, para que el lector no junte las palabras al encogerlo */
}                             /* fin de .campo__aviso */

/* Correo y teléfono: dos campos cortos que pueden ir en la misma fila.
   Rejilla con hueco 0 entre filas y, entre columnas, del 3 % del ancho de la
   ventana (entre 1,25 y 2,25rem). Es un hueco mayor que el que haría falta
   con cajas: dos líneas seguidas con poco aire se leen como una sola línea
   partida. */
.campos-par { display: grid; gap: 0 clamp(1.25rem, 3vw, 2.25rem); }

/* Desde 1200 px de ancho, correo y teléfono van lado a lado. */
@media (min-width: 1200px) {
  .campos-par { grid-template-columns: 1fr 1fr; }   /* dos columnas de igual ancho */
}

/* Por debajo de 1200 px (1199,98 para no dejar ningún ancho con decimales sin
   regla) correo y teléfono van uno debajo del otro: hay un campo más en la
   columna, y el aire normal, multiplicado por seis huecos, haría que la
   página pidiera scroll a 1024 × 768. Aquí se aprieta un poco, lo justo para
   que siga entrando. */
@media (max-width: 1199.98px) {
  .campo { margin-bottom: clamp(.9rem, 2.2vh, 2rem); }   /* algo menos de aire entre campos */
}

/* -------------------------------------------- casilla de consentimiento --- */
/* La casilla «He leído y acepto el aviso legal y la política de privacidad».
   Rejilla de dos columnas: la casilla a la izquierda, con el ancho que
   necesite (auto), y el texto a la derecha, con todo el resto (1fr). */
.campo--casilla {
  display: grid;                             /* rejilla */
  grid-template-columns: auto 1fr;           /* casilla | texto */
  gap: .25rem .75rem;                        /* hueco: .25rem entre filas y .75rem entre casilla y texto */
  align-items: start;                        /* alineadas por arriba (el texto puede ocupar dos renglones) */
  margin-top: clamp(1.2rem, 3vh, 2.2rem);    /* aire encima, respecto al campo «Cuéntanos» */
}                                            /* fin de .campo--casilla */

/* El texto que acompaña a la casilla. */
.campo--casilla label {
  font-size: .88rem;          /* algo más pequeño que el normal */
  font-weight: 400;           /* grosor normal */
  line-height: 1.6;           /* alto de línea */
  color: var(--principal);    /* burdeos */
}

/* El enlace al aviso legal, dentro de ese texto. */
.campo--casilla label a {
  border-bottom: 1px solid rgba(60, 22, 33, .35);        /* subrayado fino: burdeos de la marca al 35 % */
  transition: border-color .35s ease, color .35s ease;   /* los cambios de color duran 0,35 s */
}

/* Con el ratón encima o seleccionado con el teclado: texto y subrayado en caramelo. */
.campo--casilla label a:hover,
.campo--casilla label a:focus-visible {
  color: var(--contraste-1);                 /* texto caramelo */
  border-bottom-color: var(--contraste-1);   /* subrayado caramelo */
}

/* La casilla en sí (<input type="checkbox">). */
.casilla {
  width: 20px;                /* más fácil de acertar con el dedo */
  height: 20px;               /* cuadrada, 20 × 20 px */
  margin: .1rem 0 0;          /* bajada un poco para alinearla con el primer renglón del texto */
  /* accent-color: color con el que el navegador pinta sus propios controles;
     aquí, el relleno de la casilla cuando está marcada. Burdeos. */
  accent-color: var(--principal);
  cursor: pointer;            /* el puntero del ratón pasa a ser una mano: se puede pulsar */
}                             /* fin de .casilla */

/* La trampa para robots: un campo que las personas no ven ni alcanzan con el
   teclado. Si llega relleno, lo ha rellenado un programa, y js/contacto.js
   hace como que lo envía pero no manda nada. Se saca de la vista sin usar
   display: none, porque algunos robots lo detectan y no caen. */
.trampa {
  position: absolute;         /* sale del flujo */
  left: -9999px;              /* y se lleva muy lejos, fuera de la pantalla por la izquierda */
  width: 1px;                 /* diminuto: 1 px de ancho… */
  height: 1px;                /* …por 1 px de alto */
  overflow: hidden;           /* lo que no cabe, oculto */
}                             /* fin de .trampa */

/* El botón «Enviar». Es el único bloque relleno de la columna, a propósito:
   entre tanta línea fina, es lo que deja claro dónde termina el formulario y
   qué hay que pulsar. */
.formulario__enviar {
  display: block;                                  /* ocupa su propio renglón */
  width: 100%;                                     /* todo el ancho de la columna */
  margin-top: clamp(1.3rem, 3.2vh, 2.4rem);        /* aire encima, atado al alto de la ventana */
  padding: clamp(.7rem, 1.7vh, 1.05rem) 1.5rem;    /* relleno: arriba y abajo según el alto; 1,5rem a los lados */
  border: 0;                                       /* sin borde */
  border-radius: 0;                                /* esquinas rectas */
  background: var(--principal);                    /* fondo burdeos */
  color: var(--claro);                             /* texto crema */
  font-family: inherit;                            /* la letra de la página (los botones no la heredan solos) */
  font-size: .78rem;                               /* letra pequeña */
  font-weight: 500;                                /* seminegrita */
  letter-spacing: .24em;                           /* letras muy separadas */
  text-transform: uppercase;                       /* en mayúsculas */
  cursor: pointer;                                 /* puntero de mano */
  /* El cambio de fondo y de color al pasar el ratón dura --mov, el ritmo
     general de la web (600 ms si faltara la variable). */
  transition: background-color var(--mov, 600ms) ease, color var(--mov, 600ms) ease;
  -webkit-appearance: none;                        /* quita el aspecto propio del navegador (Safari, Chrome antiguos) */
          appearance: none;                        /* lo mismo, versión estándar */
}                                                  /* fin de .formulario__enviar */

/* Con el ratón encima o seleccionado con el teclado: fondo caramelo y texto burdeos. */
.formulario__enviar:hover,
.formulario__enviar:focus-visible {
  background: var(--contraste-1);            /* fondo caramelo */
  color: var(--principal);                   /* texto burdeos */
}

/* Mientras se envía, js/contacto.js desactiva el botón. [disabled] = «que
   tenga el atributo disabled» (desactivado). */
.formulario__enviar[disabled] {
  opacity: .5;                /* al 50 %: se ve apagado */
  cursor: progress;           /* puntero de «trabajando» (flecha con reloj o rueda) */
}

/* El renglón de estado bajo el botón: ahí js/contacto.js escribe «Enviando…»,
   el agradecimiento o qué campos faltan. Empieza invisible y aparece
   fundiéndose cuando recibe la clase .is-visible (más abajo). */
.formulario__estado {
  margin: .9rem 0 0;              /* hueco encima, respecto al botón */
  color: var(--principal);        /* burdeos */
  font-size: .9rem;               /* algo más pequeño que el normal */
  font-weight: 300;               /* fina */
  line-height: 1.6;               /* alto de línea */
  opacity: 0;                     /* invisible de entrada */
  transition: opacity .35s ease;  /* aparece fundiéndose en 0,35 s */
}                                 /* fin de .formulario__estado */

/* :empty = sin nada dentro. Vacío no ocupa: si no, su margen dejaría un hueco
   muerto encima del último renglón. */
.formulario__estado:empty { margin: 0; }

/* Visible, y en modo error. El renglón de estado no se tiñe de caramelo:
   sobre el crema se queda en 2,3:1 de contraste, y justo el aviso de que
   algo falla es lo último que puede costar leer. Lo que marca el error aquí
   es el grosor de la letra; el color ya lo ponen las líneas de los campos. */
.formulario__estado.is-visible { opacity: 1; }         /* con texto: se ve */
.formulario__estado.es-error   { font-weight: 500; }   /* error: letra más gruesa */

/* La ventana emergente «Correo enviado, muchas gracias.» que sale al enviar
   bien el formulario (la enseña y la esconde js/contacto.js). Ocupa toda la
   pantalla con un velo burdeos semitransparente y, en el centro, una tarjeta
   crema con el mensaje y el botón «Cerrar». */
.enviado {
  position: fixed;                     /* fija a la ventana, encima de todo */
  inset: 0;                            /* de borde a borde (arriba, derecha, abajo, izquierda = 0) */
  z-index: 3000;                       /* por encima de la cabecera y del botón flotante */
  display: flex;                       /* para centrar la tarjeta… */
  align-items: center;                 /* …en vertical… */
  justify-content: center;             /* …y en horizontal */
  padding: 16px;                       /* margen con los bordes en el móvil */
  background: rgba(60, 22, 33, .55);   /* velo burdeos de la marca al 55 % */
  opacity: 0;                          /* transparente de entrada… */
  transition: opacity .3s ease;        /* …y aparece fundiéndose en 0,3 s */
}
.enviado[hidden] { display: none; }    /* escondida: no se ve ni ocupa (el display:flex de arriba lo anularía) */
.enviado.is-visible { opacity: 1; }    /* visible (la pone contacto.js) */
.enviado__caja {
  width: 100%;                         /* en el móvil, todo el ancho disponible… */
  max-width: 26rem;                    /* …y como mucho 26rem (unos 416 px) */
  padding: clamp(1.75rem, 5vw, 2.5rem);   /* relleno interior */
  background: var(--claro);            /* fondo crema */
  text-align: center;                  /* todo centrado */
  transform: translateY(12px);         /* empieza un poco más abajo… */
  transition: transform .3s var(--mov-curva, ease);   /* …y sube a su sitio al aparecer */
}
.enviado.is-visible .enviado__caja { transform: none; }   /* en su sitio */
.enviado__texto {
  margin: 0;                           /* sin márgenes propios */
  font-family: var(--texto, "Montserrat", sans-serif);   /* Montserrat, la letra de los textos */
  font-size: clamp(1.05rem, 2.6vw, 1.25rem);   /* algo mayor que el texto normal, según el ancho de la pantalla */
  font-weight: 400;                    /* grosor normal */
  line-height: 1.5;                    /* alto de línea */
  color: var(--principal);             /* burdeos */
}
.enviado__cerrar { margin-top: 1.5rem; }   /* aire entre el mensaje y el botón (el resto del aspecto es el de «Enviar») */
@media (prefers-reduced-motion: reduce) {  /* si la persona pide menos movimiento en su sistema: sin animación */
  .enviado, .enviado__caja { transition: none; }
}

/* La página de Contacto no lleva pie: eso libera ~90 px de alto respecto a
   las demás, así que aquí no hace falta el ajuste extra que antes se ponía
   para columna estrecha Y pantalla baja (1024 × 768 y parecidas). El
   estrechamiento a una columna a partir de 1200 px (@media más arriba) ya
   deja el formulario cómodo hasta 1024 × 720 sin scroll. */

/* ==========================================================================
   16 · APARICIÓN AL BAJAR
   ========================================================================== */

/* Hace que los bloques entren suavemente desde abajo (subiendo y dejando de
   ser transparentes) cuando asoman en pantalla al bajar por la página.

   Cómo se reparten el trabajo el HTML, el JavaScript y este CSS:
   - En el HTML, cada elemento que tiene que aparecer lleva la clase
     .revela, y el bloque que los agrupa lleva .revela-grupo.
   - js/main.js usa un IntersectionObserver: una herramienta del navegador
     que avisa cuando un elemento entra en la parte visible de la ventana
     (aquí, cuando ya ha subido por encima del 12 % de abajo de la ventana,
     no al asomar el primer píxel). En ese momento el guion pone a cada
     .revela del grupo la clase .se-ve y una variable --retardo con su
     espera: 0 ms el primero, un paso (--revela-paso) el segundo, dos pasos
     el tercero… Así entran escalonados sin numerarlos en el HTML: añadir o
     quitar uno no obliga a renumerar nada.
   - Cuando la animación ha terminado, el guion le añade .ya.
   - El estado escondido solo se aplica si <html> lleva la clase .con-js,
     que la pone el guion del <head> antes de pintar nada. Si el JavaScript
     no llega a ejecutarse o falla, la clase no está (o se quita) y el
     contenido se ve tal cual: la animación nunca deja una página en blanco. */

/* Punto de partida de todo .revela: transparente y un poco más abajo de su sitio. */
html.con-js .revela {
  opacity: 0;                 /* transparente del todo */
  /* translate3d(x, y, z) desplaza el elemento: nada a los lados, hacia abajo
     lo que diga --revela-salto (2rem) y nada en profundidad. */
  transform: translate3d(0, var(--revela-salto, 2rem), 0);
  /* will-change avisa al navegador de que esto va a cambiar, para que lo
     prepare aparte (en su propia «capa») y el movimiento sea fluido. */
  will-change: opacity, transform;
}                             /* fin del estado de partida */

/* Cuando js/main.js le pone .se-ve: vuelve a su sitio y se hace visible. */
html.con-js .revela.se-ve {
  opacity: 1;                 /* visible */
  transform: none;            /* en su sitio, sin desplazamiento */
  /* La transición. Cada var() lleva su valor de reserva detrás de la coma:
     sin él, el día que faltara una variable el navegador tiraría la
     declaración entera y el elemento aparecería de golpe, que es justo lo
     contrario de lo que se busca. */
  transition:
    opacity   var(--revela, 900ms) ease var(--retardo, 0ms),   /* opacidad: dura --revela, suave, tras --retardo */
    transform var(--revela, 900ms)                             /* desplazamiento: la misma duración, */
              var(--revela-curva, cubic-bezier(.22, .61, .36, 1))   /* curva que frena al final, */
              var(--retardo, 0ms);                             /* y la misma espera */
}                             /* fin del estado visible */

/* Ya colocado (.ya), deja de reservar capa: tener will-change puesto para
   siempre gasta memoria sin necesidad. */
html.con-js .revela.ya { will-change: auto; }

/* Los bloques de texto del home (Section 2, Section 3 y Sección 4) entran
   pieza a pieza —título, párrafo, botón— con el paso largo (--entrada-paso,
   280 ms) en vez del corto general (--revela-paso, 70 ms). main.js lee
   --revela-paso del propio bloque, así que basta con redefinirlo aquí. Las
   muestras de la Sección 4 siguen con el corto: entran casi a la vez, en
   onda rápida. */
.section2__texto,
.section3__texto,
.cierre__texto { --revela-paso: var(--entrada-paso, 280ms); }

/* El envoltorio de un botón que tiene que aparecer (p. ej. «Escríbenos» en la
   Sección 4). La aparición se hace con transition, y una transition puesta
   en el propio botón sustituiría a la suya: al pasar el ratón, el color
   cambiaría de golpe en vez de fundirse. Con la aparición en una caja de
   alrededor, cada uno conserva la suya. */
.revela-caja { display: block; }   /* la caja ocupa su propio renglón, como un bloque */

/* prefers-reduced-motion: reduce = la persona ha pedido en los ajustes de su
   sistema que se reduzcan las animaciones. Entonces todo se ve directamente,
   sin moverse. (js/main.js, además, quita .con-js en ese caso.) */
@media (prefers-reduced-motion: reduce) {
  html.con-js .revela,
  html.con-js .revela.se-ve {
    opacity: 1;               /* visible */
    transform: none;          /* en su sitio */
    transition: none;         /* sin transición */
  }
}                             /* fin de la media query de movimiento reducido */

/* ==========================================================================
   17 · QUIÉNES SOMOS
   ========================================================================== */

/* La página Quiénes Somos (quienes-somos.html). Mismo armazón que la web de
   referencia: una fotografía de entrada con el titular encima, una sola
   columna de texto centrada debajo y el logotipo como firma al final. Nada
   más. Lo que cambia es lo propio de la casa: Playfair para el titular,
   Montserrat para el texto y la paleta de siempre. */

/* La portada: la fotografía va a sangre, de lado a lado de la pantalla,
   justo debajo de la cabecera, con el titular centrado encima. */
.nosotros__portada {
  position: relative;                      /* referencia para la foto y el velo, que van encima */
  display: grid;                           /* rejilla… */
  place-items: center;                     /* …para centrar el titular en horizontal y en vertical */
  min-height: clamp(20rem, 60vh, 40rem);   /* alto: 60 % del alto de la ventana, entre 20 y 40rem */
  overflow: hidden;                        /* recorta lo que sobresalga */
  background: var(--secundario);           /* gris topo de espera mientras llega la foto */
}                                          /* fin de .nosotros__portada */

.nosotros__portada picture { position: absolute; inset: 0; }   /* la foto ocupa toda la portada, de borde a borde */

/* La imagen dentro de la portada. */
.nosotros__portada img {
  display: block;             /* como bloque */
  width: 100%;                /* todo el ancho de la portada */
  height: 100%;               /* y todo su alto */
  object-fit: cover;          /* cubre la portada sin deformarse; lo que sobra se recorta */
}                             /* fin de .nosotros__portada img */

/* Velo para que el titular (en crema) se lea sobre cualquier zona de la
   foto: un halo oscuro centrado donde va el texto, más un oscurecido suave
   de arriba abajo. Es el mismo recurso que llevan las tarjetas de Proyectos.

   El halo es ancho a propósito. Con uno más estrecho el titular se saldría
   de él por los extremos y el peor punto medido se quedaría en un contraste
   de 2,5:1 con la letra clara del titular, por debajo del 3:1 que pide un texto de este
   tamaño. Con el halo ancho el peor punto medido sube a 3,8:1 a 1440 px y
   pasa de 4,7:1 en el resto de anchuras, con el velo lo bastante flojo para
   que la fotografía se siga viendo por debajo.

   ::after crea una caja extra dentro de la portada, que aquí hace de velo. */
.nosotros__portada::after {
  content: "";                /* obligatorio para que la caja exista, aunque vaya vacía */
  position: absolute;         /* colocada encima de la foto… */
  inset: 0;                   /* …cubriendo toda la portada */
  /* Dos fondos superpuestos, separados por la coma; el primero queda encima. */
  background:
    radial-gradient(86% 70% at 50% 50%,      /* halo: óvalo centrado; del centro a su borde, 86 % del ancho y 70 % del alto */
      rgba(42, 15, 23, .57) 0%,              /* en el centro, burdeos más oscuro al 57 % */
      rgba(42, 15, 23, 0) 100%),             /* hacia el borde del óvalo, transparente */
    linear-gradient(180deg,                  /* degradado de arriba abajo (180deg = hacia abajo) */
      rgba(60, 22, 33, .17) 0%,              /* arriba, burdeos de la marca al 17 % */
      rgba(42, 15, 23, .30) 100%);           /* abajo, burdeos más oscuro al 30 % */
}                             /* fin del velo */

/* El titular sobre la foto (<h1>). */
.nosotros__titulo {
  position: relative;                        /* hace que z-index funcione */
  z-index: 1;                                /* por encima del velo */
  margin: 0;                                 /* sin márgenes propios */
  padding: var(--margen);                    /* aire alrededor: el margen general de la web */
  color: var(--claro);                       /* crema */
  font-family: var(--display);               /* letra de titulares (Playfair Display) */
  font-weight: 400;                          /* sin negrita */
  font-size: clamp(1.9rem, 5.4vw, 4rem);     /* 5,4 % del ancho de la ventana, entre 1,9 y 4rem */
  line-height: 1.12;                         /* renglones juntos, propio de un titular */
  text-align: center;                        /* centrado */
}                                            /* fin de .nosotros__titulo */

/* La columna de texto, centrada. Los párrafos son cortos a propósito: así
   cada uno ocupa uno o dos renglones y el bloque se lee como una sucesión de
   frases, que es el ritmo de la referencia. */
.nosotros__texto {
  /* Renglón de unos 70 caracteres: con el texto centrado, pasar de ahí
     obliga al ojo a buscar el principio de cada línea.
     El ancho de LECTURA son 50rem; el margen lateral (--margen) va sumado
     por fuera, dos veces (izquierda y derecha). Si no, en pantalla ancha
     --margen crece hasta 3,5rem y se come el ancho por dentro: la columna se
     quedaría en 688 px y la cadena etimológica se partiría en dos justo
     donde más sitio hay. */
  max-width: calc(50rem + 2 * var(--margen));
  margin: clamp(2.5rem, 5vw, 4.5rem) auto 0;   /* aire bajo la foto; auto a los lados la centra */
  padding-inline: var(--margen);               /* margen a izquierda y derecha para que no toque el borde */
  text-align: center;                          /* texto centrado */
}                                              /* fin de .nosotros__texto */

/* La línea pequeña de arriba, «Desde 2004». Lleva .nosotros__texto delante
   para ganar a la regla general de los párrafos de más abajo. */
.nosotros__texto .nosotros__antetitulo {
  margin: 0 0 clamp(1.5rem, 3vw, 2.25rem);   /* solo aire por debajo */
  color: var(--tinta-suave);                 /* burdeos suavizado */
  font-size: .72rem;                         /* letra pequeña */
  font-weight: 500;                          /* seminegrita */
  letter-spacing: .28em;                     /* letras muy separadas */
  text-transform: uppercase;                 /* en mayúsculas */
}                                            /* fin del antetítulo */

/* Cada párrafo de la columna. */
.nosotros__texto p {
  margin: 0 0 clamp(1.1rem, 2.2vw, 1.6rem);  /* aire solo por debajo */
  font-size: clamp(1rem, 1.15vw, 1.1rem);    /* entre 1 y 1,1rem según el ancho de la ventana */
  font-weight: 300;                          /* fina */
  line-height: 1.95;                         /* renglones muy holgados */
}

.nosotros__texto p:last-child { margin-bottom: 0; }   /* el último párrafo (:last-child), sin aire debajo */

/* La cadena etimológica: «Hogar · Latín focus (fuego) · Fogata para cocinar ·
   Hogar = Cocina», con rayas finas entre eslabón y eslabón. Va como una
   anotación al margen, en mayúsculas pequeñas: se lee de un vistazo y no
   compite con los párrafos. El texto va en burdeos, porque el caramelo sobre
   el crema se queda en 2,3:1 y no vale para una letra tan pequeña; las
   rayas, que son adorno y no texto, sí van en caramelo.
   Es una fila flexible (flex): los eslabones van uno detrás de otro y, si
   no caben, pasan al renglón siguiente. */
.nosotros__texto .nosotros__cadena {
  display: flex;                                  /* fila flexible */
  flex-wrap: wrap;                                /* si no cabe, sigue en otro renglón */
  justify-content: center;                        /* centrada a lo ancho */
  align-items: baseline;                          /* eslabones alineados por la base de las letras */
  gap: .6em clamp(.7rem, 1.6vw, 1.15rem);         /* hueco entre renglones; entre eslabones, según el ancho */
  margin: clamp(2.25rem, 5vw, 3.5rem) auto;       /* aire arriba y abajo; centrada a los lados */
  /* Tamaño fijo y no escalado: a .72rem la cadena entera mide justo el ancho
     de la columna de texto. Un punto más, y se parte en dos renglones en
     cuanto la ventana pasa de 1300 px. */
  font-size: .72rem;
  font-weight: 500;                               /* seminegrita */
  letter-spacing: .14em;                          /* letras separadas */
  text-transform: uppercase;                      /* en mayúsculas */
}                                                 /* fin de la cadena */

.nosotros__texto .nosotros__cadena i { font-style: italic; }   /* «focus», la palabra latina, en cursiva */

/* La raya entre eslabones. Va DETRÁS de cada eslabón, no delante del
   siguiente: si fuera delante, al partirse la cadena en dos renglones el
   segundo empezaría por una raya suelta. Detrás, el renglón termina en raya,
   que es justo lo que se quiere decir (que la cadena sigue).
   span:not(:last-child)::after = «detrás de cada eslabón, menos del último». */
.nosotros__texto .nosotros__cadena span:not(:last-child)::after {
  content: "";                                    /* caja vacía… */
  display: inline-block;                          /* …que va en la línea, como una palabra, pero admite ancho */
  width: clamp(1.1rem, 2.2vw, 1.9rem);            /* largo de la raya */
  margin-left: clamp(.7rem, 1.6vw, 1.15rem);      /* separación entre el texto y la raya */
  border-top: 1px solid var(--contraste-1);       /* la raya: un borde de 1 px por arriba, en caramelo */
  transform: translateY(-.3em);                   /* subida un poco, a media altura de las letras */
}                                                 /* fin de la raya */

/* Cierre de la página: el logotipo hace de firma, como la rúbrica de la
   referencia, con la línea «Cocinas a medida · Madrid» debajo. */
.nosotros__firma {
  margin: clamp(3rem, 7vw, 5.5rem) auto 0;               /* aire encima; centrada */
  padding: 0 var(--margen) clamp(4.5rem, 10vw, 8rem);    /* 0 arriba, margen a los lados, mucho aire abajo */
  text-align: center;                                    /* texto centrado */
}

/* El logotipo. Las imágenes de la web son de bloque (regla general de
   imágenes), así que centrarlas es cosa de los márgenes, no de text-align. */
.nosotros__firma img {
  width: clamp(7rem, 10vw, 9rem);    /* ancho: 10 % de la ventana, entre 7 y 9rem */
  height: auto;                      /* alto proporcional al ancho, sin deformarse */
  margin-inline: auto;               /* márgenes automáticos a los lados: centrado */
  opacity: .5;                       /* medio transparente: una firma discreta */
}

/* La línea «Cocinas a medida · Madrid». */
.nosotros__firma p {
  margin: clamp(1rem, 2vw, 1.5rem) 0 0;      /* aire solo encima, respecto al logotipo */
  color: var(--tinta-suave);                 /* burdeos suavizado */
  font-size: .72rem;                         /* letra pequeña */
  font-weight: 500;                          /* seminegrita */
  letter-spacing: .28em;                     /* letras muy separadas */
  text-transform: uppercase;                 /* en mayúsculas */
}                                            /* fin de .nosotros__firma p */


/* ==========================================================================
   17 · VERSIÓN DE MÓVIL — MODO «APP»
   --------------------------------------------------------------------------
   En pantallas de 720 px de ancho o menos la web toma otro carácter: la
   cabecera se queda solo con el logotipo (nada de menú ni Instagram), el
   pie normal se apaga y en su lugar aparece un botón flotante en la esquina
   inferior derecha (el FAB) que agrupa las acciones de contacto (formulario
   de Contacto e Instagram). Además, la home (index.html)
   cambia entera: el hero y las tres secciones desaparecen y se enseña un
   feed vertical de posts, uno por proyecto, con una tira de fotos que se
   pasan con el dedo y puntitos debajo. Pulsar la foto de un post abre el
   visor a pantalla completa, el mismo que hay en proyectos.html.

   Todo lo que sigue se activa solo dentro de la media query de abajo, así
   que la versión de escritorio no se ve afectada.
   ========================================================================== */

@media (max-width: 720px) {

  /* ------------------------------------- 17a. cabecera y pie en móvil --- */

  /* Sin la parte de la derecha de la cabecera (menú, Instagram y el botón
     de menú del móvil): en la versión de móvil-app toda esa navegación se
     agrupa en el FAB. El logotipo queda como la única marca arriba. */
  .site-header__derecha { display: none; }

  /* Con el bloque de la derecha oculto, el logotipo es lo único de la fila:
     se centra en la pantalla en vez de quedar arrimado a la izquierda. */
  .site-header__inner { justify-content: center; }                          /* el logotipo, centrado de lado a lado */
  .logo__img { height: 23px; }                                              /* logotipo del móvil: 27 px reducido un 15 % ≈ 23 px (lo pidió Javier) */
  /* Centrado «a la vista»: el logotipo es una palabra en minúsculas con una
     sola letra alta (la «l»), así que su caja centrada en la cabecera deja el
     cuerpo de las letras 4-5 px por debajo del centro y se ve caído. Se sube
     3 px: medido en pantalla, queda equilibrado. (.logo ya es position:relative.) */
  .site-header .logo { top: -3px; }

  /* El pie normal (logotipo + menú + Instagram, que en escritorio aparece
     al llegar al final) se apaga en móvil: su papel lo hacen el FAB (para
     contactar) y los enlaces pequeños del pie del feed (para navegar). */
  .site-footer { display: none; }

  /* Cuando el pie está apagado, el hueco que main.js reservaba abajo para
     que no lo tapara sobra: se pone a cero para que el contenido llegue
     hasta el borde. */
  body::after { display: none; }

  /* Cabecera siempre sólida en móvil, también arriba del todo en el home.
     main.js le pone .is-transparente mientras la página está arriba (pensado
     para el hero de escritorio); en móvil el hero no se ve y la cabecera
     quedaba medio transparente sobre la primera foto del feed. Estas reglas
     anulan ese efecto: fondo crema y logotipo oscuro, sin velo. */
  .site-header.is-transparente { background: var(--claro); }               /* fondo crema de la marca, nunca transparente */
  .site-header.is-transparente::before { opacity: 0; }                     /* sin el velo oscuro de encima de la foto */
  .site-header.is-transparente .logo__img--oscuro { opacity: 1; }          /* se ve el logotipo oscuro (burdeos)… */
  .site-header.is-transparente .logo__img--claro  { opacity: 0; }          /* …y se esconde el claro */

  /* Los enlaces #contacto que en escritorio bajan a la Sección 4 del home
     no encuentran esa sección en móvil (se oculta más abajo); se
     redirigen: los CTA principales del FAB van a contacto.html. Aquí nada
     que hacer en CSS: son enlaces normales. */

  /* --------------------- 17b. home móvil: se oculta el escritorio ------ */

  /* En index.html se apagan el hero y las tres secciones. El HTML se
     queda igual (por SEO y para escritorio); en móvil solo se ve el feed. */
  body.home .hero,
  body.home .section2,
  body.home .section3,
  body.home .cierre {
    display: none;
  }

  /* Al ocultar el hero se pierde su offset del padding-top de <main>: el
     feed empieza justo bajo la cabecera fija, sin más. */
  body.home main { padding-top: var(--header-h); }

  /* Contacto en el móvil: sin la foto de debajo del formulario (la página
     se queda en el formulario y los datos de contacto). Además, contacto.html
     le da al móvil una imagen vacía en vez de la foto, para no descargarla. */
  .contacto-pagina__foto { display: none; }

  /* Portada del móvil (.portada-movil, en index.html justo antes del feed):
     una entrada breve bajo la cabecera, sobre el crema de la página. El
     titular de la casa en Playfair, el filete caramelo y, en pequeño,
     «Nuestros proyectos», que da paso al feed. */
  .portada-movil {
    display: block;                                    /* aquí sí se ve (fuera del móvil está oculta) */
    padding: 2.25rem var(--margen) 3.895rem;           /* aire arriba y abajo: medido para que la portada quede justo en el centro entre el logo y la primera foto; el margen general a los lados */
    text-align: center;                                /* todo centrado */
  }
  .portada-movil__titulo {
    margin: 0;                                         /* sin el margen de serie de un párrafo */
    color: var(--principal);                           /* burdeos */
    font-family: var(--display);                       /* Playfair Display, la de los titulares */
    font-weight: 400;                                  /* sin negrita */
    font-size: clamp(1.6rem, 7.4vw, 2.15rem);          /* según el ancho del móvil: de unos 26 a 34 px */
    line-height: 1.15;                                 /* renglones juntos, como el titular del escritorio */
    letter-spacing: -.005em;                           /* una pizca más juntas */
  }
  .portada-movil__titulo span { display: block; }      /* cada línea del titular en su renglón */
  .portada-movil__filete {
    display: block;                                    /* caja propia, para darle medidas */
    width: 3rem;                                       /* 48 px de largo */
    height: 2px;                                       /* 2 px de grueso */
    margin: 1.15rem auto 0;                            /* aire encima; «auto» a los lados la centra */
    background: var(--contraste-1);                    /* caramelo */
  }
  .portada-movil__ante {
    margin: .95rem 0 0;                                /* aire encima, respecto a la rayita */
    color: var(--tinta-suave);                         /* burdeos suave */
    font-size: .72rem;                                 /* pequeña */
    font-weight: 500;                                  /* seminegrita */
    letter-spacing: .3em;                              /* letras muy separadas */
    text-transform: uppercase;                         /* en mayúsculas */
  }

  /* --------------------------- 17c. FEED móvil de proyectos ------------ */

  /* El feed se ve solo en móvil (fuera de la media query, .feed-movil está
     oculto en escritorio; ver más abajo). Es una lista vertical de posts,
     centrada, hasta 34rem de ancho para que en móviles muy anchos siga
     leyéndose bien. */
  .feed-movil {
    display: block;                                    /* aquí sí se ve */
    max-width: 34rem;                                  /* ancho máximo */
    margin-inline: auto;                               /* centrado */
    padding: 0;                                        /* sin relleno propio; cada post ocupa el ancho */
  }

  /* Cada post: la foto ocupa todo el ancho, y debajo, en una fila, el
     título del proyecto y los puntitos del carrusel. Los posts se
     separan solo por un hueco discreto: el feed se lee del tirón. */
  .feed-movil__post {
    margin: 0;
    padding: 0;
    padding-bottom: clamp(1.75rem, 5vw, 2.5rem);       /* aire entre un post y el siguiente */
  }

  /* La pista del carrusel horizontal. Es una lista <ul> hecha rejilla en
     línea: cada foto es una «columna» a todo lo ancho de la ventana.
     scroll-snap-type engancha el desplazamiento a la foto siguiente para
     que siempre quede una foto centrada, no a medias. */
  .feed-movil__pista {
    list-style: none;                                  /* sin viñetas */
    margin: 0;                                         /* sin márgenes de la lista */
    padding: 0;                                        /* sin sangría */
    display: grid;                                     /* rejilla */
    grid-auto-flow: column;                            /* nuevos elementos, a la derecha */
    grid-auto-columns: 100%;                           /* cada uno, el ancho entero de la pista */
    overflow-x: auto;                                  /* se puede desplazar horizontalmente */
    overflow-y: hidden;                                /* pero nunca verticalmente */
    scroll-snap-type: x mandatory;                     /* al soltar el dedo, se ajusta a la foto siguiente */
    scrollbar-width: none;                             /* sin barra en Firefox */
    -webkit-overflow-scrolling: touch;                 /* deslizamiento suave en iOS */
    background: var(--secundario);                     /* fondo gris topo mientras carga cualquier foto */
  }
  .feed-movil__pista::-webkit-scrollbar { display: none; }  /* sin barra en Chrome / Safari */

  /* Cada foto del carrusel se «engancha» al soltar el dedo. */
  .feed-movil__foto {
    scroll-snap-align: start;                          /* alinea su borde izquierdo con el de la pista */
    scroll-snap-stop: always;                          /* siempre se detiene en la siguiente, no se pasa dos */
    position: relative;                                /* referencia para su enlace */
    aspect-ratio: 5 / 4;                               /* misma proporción que las tarjetas del escritorio */
    background: var(--secundario);                     /* fondo mientras carga */
  }

  /* El enlace que envuelve la foto: ocupa la foto entera y es el que dispara
     el visor (visor.js). Se le da su data-proyecto y, al pulsarlo,
     visor.js hace el vuelo. */
  .feed-movil__link {
    display: block;                                    /* ocupa todo su hueco */
    width: 100%;
    height: 100%;
    border: 0;                                         /* sin borde: es un <button> */
    padding: 0;                                        /* sin relleno de serie de los botones */
    background: transparent;                           /* sin fondo */
    cursor: pointer;                                   /* puntero de mano */
    -webkit-tap-highlight-color: transparent;          /* sin el destello azul al tocar en iOS */
  }

  .feed-movil__link img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;                                 /* cubre el hueco sin deformarse */
  }

  /* Fila de abajo del post: título del proyecto a la izquierda, puntitos
     a la derecha (o solo el título si el proyecto tiene una única foto). */
  .feed-movil__meta {
    display: flex;                                     /* en fila */
    align-items: center;                               /* alineadas por el centro vertical */
    justify-content: space-between;                    /* título a un lado, puntitos al otro */
    padding: .8rem var(--margen) 0;                    /* separación con la foto y los lados */
    gap: 1rem;                                         /* hueco entre título y puntitos si se juntan */
  }

  .feed-movil__titulo {
    margin: 0;
    font-family: var(--display);                       /* Playfair Display */
    font-weight: 400;                                  /* grosor normal */
    font-size: 1.15rem;                                /* algo más pequeña que el titular grande */
    color: var(--principal);                           /* burdeos */
    flex-shrink: 0;                                    /* el título nunca se encoge ni parte: cede sitio la hilera de puntitos */
  }

  /* Hilera de puntitos. Cada uno mide 6 × 6 px; el activo, un pelín más
     grande y burdeos pleno; los otros, gris topo suave. */
  .feed-movil__puntos {
    display: flex;                                     /* en fila */
    align-items: center;
    gap: .35rem;                                       /* hueco entre puntitos */
    flex-wrap: wrap;                                   /* si no caben en una fila, bajan a otra… */
    justify-content: flex-end;                         /* …siempre arrimados a la derecha */
    min-width: 0;                                      /* puede estrecharse: OJO, sin esto un proyecto con muchas fotos ensanchaba la página */
  }
  .feed-movil__punto {
    width: 6px;
    height: 6px;
    border-radius: 50%;                                /* redonditos */
    background: rgba(60, 22, 33, .25);                 /* burdeos al 25 % (apagado) */
    transition: background .25s ease, transform .25s ease;
  }
  .feed-movil__punto.esta-activo {
    background: var(--principal);                      /* burdeos pleno (encendido) */
    transform: scale(1.25);                            /* un pelín mayor, para que se lea */
  }

  /* --------------- 17d. pie sencillo del feed móvil (mini-footer) ----- */

  /* Un pie muy pequeño al final del feed: enlace a Quiénes Somos y al
     Aviso Legal. Sirve para no dejar Quiénes Somos huérfano en móvil, sin
     robar protagonismo al feed. */
  .feed-movil__pie {
    display: flex;                                     /* en fila */
    justify-content: center;                           /* centrado */
    gap: 1.5rem;                                       /* hueco entre los enlaces */
    padding: 2rem var(--margen) 5.5rem;                /* aire arriba y abajo; los 5,5rem dejan sitio al FAB */
    font-size: .78rem;                                 /* letra pequeña */
    letter-spacing: .16em;                             /* separada */
    text-transform: uppercase;                         /* en mayúsculas */
  }
  .feed-movil__pie a {
    color: var(--tinta-suave);                         /* burdeos suave */
    border-bottom: 1px solid transparent;              /* subrayado invisible */
    transition: color .3s ease, border-color .3s ease;
  }
  .feed-movil__pie a:hover,
  .feed-movil__pie a:focus-visible {
    color: var(--principal);                           /* al tocar: burdeos pleno */
    border-bottom-color: var(--contraste-1);           /* raya caramelo */
  }

  /* --------------- 17e. FAB (botón flotante de contacto) --------------- */

  /* Caja del FAB: fija en la esquina inferior derecha. Solo ocupa el tamaño
     de la esfera; el panel de acciones flota por encima con position:
     absolute (ver más abajo) y no cuenta para la caja: así la esfera se
     queda pegada al borde inferior derecho, esté el panel abierto o
     cerrado. */
  .fab {
    position: fixed;                                   /* fijo respecto a la ventana */
    right: clamp(1rem, 4vw, 1.5rem);                   /* separado del borde derecho */
    bottom: clamp(1rem, 4vw, 1.5rem);                  /* separado del borde inferior */
    z-index: 45;                                       /* por debajo del header (50) y del visor (60) */
    /* La media query final del archivo pone display:flex aquí para que el
       FAB aparezca en móvil; en escritorio, la regla base .fab {display:none}
       lo mantiene oculto. */
  }

  /* La esfera pulsable. Círculo burdeos con un icono blanco dentro. */
  .fab__boton {
    display: flex;                                     /* centra el icono */
    align-items: center;
    justify-content: center;
    width: 56px;                                       /* 56 × 56 px: fácil de acertar con el pulgar */
    height: 56px;
    padding: 0;                                        /* sin relleno de serie de los botones */
    border: 0;                                         /* sin borde */
    border-radius: 50%;                                /* redondo */
    background: var(--principal);                      /* fondo burdeos */
    color: var(--claro);                               /* icono crema */
    cursor: pointer;
    /* Sombra en dos capas, misma pauta que las muestras de la Sección 4:
       una corta para el contacto y otra larga para separar. */
    box-shadow:
      .1rem .25rem  .5rem  -.15rem rgba(60, 22, 33, .3),
      .5rem .9rem   1.8rem -.6rem  rgba(60, 22, 33, .4);
    transition: background .3s ease, transform .3s ease;
    -webkit-tap-highlight-color: transparent;
  }
  .fab__boton:hover,
  .fab__boton:focus-visible {
    background: var(--contraste-1);                    /* al tocar: caramelo */
    outline: none;                                     /* sin recuadro de foco: la sombra ya se ve */
  }
  .fab.esta-abierto .fab__boton {
    background: var(--contraste-1);                    /* abierto: se queda caramelo */
    transform: rotate(45deg);                          /* gira 45°: el «+» se convierte en aspa */
  }

  /* Los dos iconos de la esfera: la burbuja (cuando está cerrada) y el más
     (que al girar la esfera se ve como aspa). Solo uno se muestra a la vez. */
  .fab__icono {
    display: block;
    width: 24px;
    height: 24px;
    transition: opacity .2s ease;
  }
  .fab.esta-abierto .fab__icono--cerrado { opacity: 0; position: absolute; pointer-events: none; }
  .fab:not(.esta-abierto) .fab__icono--abierto { opacity: 0; position: absolute; pointer-events: none; }

  /* Panel de acciones. Va colocado libre (absolute) DENTRO del FAB: se
     ancla a la esquina inferior derecha del FAB (right:0; bottom:100% + el
     hueco) y no ocupa hueco en el layout, así que la esfera no se mueve
     al abrir o cerrar el panel. Empieza escondido (opacity 0 + traslación
     abajo); con .esta-abierto se despliega deslizándose hacia arriba. */
  .fab__panel {
    position: absolute;                                /* colocado libre respecto al FAB */
    right: 0;                                          /* alineado a la derecha del FAB */
    bottom: calc(100% + .75rem);                       /* justo por encima de la esfera, con .75rem de aire */
    list-style: none;                                  /* sin viñetas */
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;                            /* apiladas en vertical */
    align-items: flex-end;                             /* pegadas al borde derecho */
    gap: .6rem;                                        /* hueco entre acciones */
    opacity: 0;                                        /* invisible al principio */
    visibility: hidden;                                /* fuera del orden de tabulación al estar cerrada */
    transform: translateY(.5rem) scale(.96);           /* un pelín bajada y encogida */
    pointer-events: none;                              /* mientras esté cerrada, no responde al ratón */
    /* visibility no se puede fundir: 0s con .25s de retraso la aplica de golpe al terminar el fundido. */
    transition: opacity .25s ease,
                transform .25s cubic-bezier(.22, .61, .36, 1),
                visibility 0s linear .25s;
  }
  .fab.esta-abierto .fab__panel {
    opacity: 1;                                        /* visible */
    visibility: visible;                               /* pulsable con teclado */
    transform: none;                                   /* a su sitio */
    pointer-events: auto;                              /* pulsable */
    transition: opacity .25s ease,
                transform .25s cubic-bezier(.22, .61, .36, 1),
                visibility 0s;                         /* visibility al instante al abrir */
  }

  /* Cada acción es un enlace. Fondo crema con letra burdeos: se separa del
     fondo (foto o cualquier página) y coincide con el resto de la marca. */
  .fab__accion {
    display: flex;                                     /* icono y etiqueta en fila */
    align-items: center;
    gap: .65rem;                                       /* hueco entre el icono y el texto */
    padding: .65rem 1rem .65rem .75rem;                /* relleno */
    background: var(--claro);                          /* fondo crema */
    color: var(--principal);                           /* letra burdeos */
    font-size: .78rem;                                 /* letra pequeña */
    font-weight: 500;                                  /* seminegrita */
    letter-spacing: .12em;                             /* separada */
    text-transform: uppercase;                         /* en mayúsculas */
    text-decoration: none;                             /* sin subrayado */
    white-space: nowrap;                               /* el texto en un solo renglón («Quiénes Somos» no se parte) */
    border-radius: 999px;                              /* píldora */
    /* Sombra suave, más corta que la de la esfera. */
    box-shadow:
      .05rem .15rem  .35rem -.1rem rgba(60, 22, 33, .22),
      .3rem  .5rem   1rem   -.4rem rgba(60, 22, 33, .28);
    transition: background .3s ease, color .3s ease, transform .2s ease;
    -webkit-tap-highlight-color: transparent;
  }
  .fab__accion:hover,
  .fab__accion:focus-visible {
    background: var(--principal);                      /* fondo burdeos al tocar */
    color: var(--claro);                               /* letra crema */
    outline: none;
  }
  .fab__accion svg {
    width: 18px;                                       /* icono de 18 × 18 dentro de la píldora */
    height: 18px;
    flex-shrink: 0;                                    /* nunca se encoge, aunque el texto sea largo */
  }
} /* fin de @media (max-width: 720px) — modo móvil-app */

/* En escritorio, el feed móvil y el FAB no existen. .feed-movil se oculta
   siempre; el FAB también, a menos que la media query de arriba lo destape
   (se muestra con display:flex dentro de la media query, ya visto). */
.feed-movil { display: none; }
.portada-movil { display: none; }   /* la portada del móvil tampoco existe en escritorio (la media query de arriba la destapa) */
.fab { display: none; }

/* Y con la media query aplicada, se destapan: el feed como bloque y el FAB
   como flex. Esto va aquí, fuera de la media anterior, para que un
   navegador que no entienda la @media (poco probable) no muestre por error
   el modo móvil en pantalla grande. */
@media (max-width: 720px) {
  .feed-movil    { display: block; }
  .portada-movil { display: block; }
  .fab           { display: flex; }
}


/* ==========================================================================
   18 · PANTALLA COMPLETA
   --------------------------------------------------------------------------
   Capa negra que tapa toda la pantalla y enseña las fotos de un proyecto en
   grande, una a una. La fabrica js/pantalla-completa.js (no está en el
   HTML). Se abre:
   · en el móvil, al pulsar una foto del feed de la home;
   · en el escritorio, con el botón de ampliar de cada foto del visor de
     proyecto (.visor__ampliar, al final de esta sección).
   Dentro: la tira de fotos (que se desliza en horizontal), dos flechas a
   los lados (solo con ratón), el contador abajo y el aspa arriba a la
   derecha.

   OJO: el fondo es negro puro (#000), fuera de la paleta de la marca. Es a
   propósito: lo pidió Javier para que las fotos destaquen. No usar este
   negro en ningún otro sitio.
   ========================================================================== */

/* Mientras está abierta (pantalla-completa.js pone .pc-abierta en <html>),
   la página de detrás no se desplaza. */
html.pc-abierta,
html.pc-abierta body { overflow: hidden; }   /* sin scroll detrás */
/* OJO: además se suelta el hueco reservado para la barra de desplazamiento
   (ver «scrollbar-gutter» en la sección 3); si no, a la derecha de la capa
   negra queda una franja clara de la página. */
html.pc-abierta { scrollbar-gutter: auto; }

/* La capa entera. */
.pc {
  position: fixed;                  /* clavada a la ventana */
  inset: 0;                         /* tapa la pantalla de borde a borde */
  z-index: 100;                     /* por encima de todo: cabecera (50), visor (60), esfera (45)… */
  background: #000;                 /* negro puro (ver el OJO de arriba) */
  opacity: 0;                       /* arranca transparente… */
  transition: opacity .25s ease;    /* …y se funde en 0,25 s (lo mismo que espera el guion al cerrar) */
}                                   /* fin de .pc */

.pc[hidden] { display: none; }      /* oculta del todo cuando lleva «hidden» */
.pc.esta-visible { opacity: 1; }    /* abierta: se ve entera */

/* La tira de fotos: una fila que se desliza en horizontal y se engancha
   en cada foto (scroll-snap), como un carrusel de Instagram. */
.pc__pista {
  display: flex;                    /* las fotos, en fila */
  height: 100%;                     /* todo el alto de la pantalla */
  margin: 0;                        /* sin el margen de serie de las listas */
  padding: 0;                       /* ni su sangría */
  list-style: none;                 /* sin viñetas */
  overflow-x: auto;                 /* se desliza a los lados… */
  overflow-y: hidden;               /* …pero no arriba y abajo */
  scroll-snap-type: x mandatory;    /* al soltar, siempre queda una foto centrada */
  overscroll-behavior: contain;     /* deslizar al final no arrastra la página de detrás */
  scrollbar-width: none;            /* sin barra de desplazamiento (Firefox) */
}                                   /* fin de .pc__pista */

.pc__pista::-webkit-scrollbar { display: none; }   /* sin barra de desplazamiento (Chrome, Safari, Edge) */

/* Cada foto ocupa la pantalla entera; la imagen va centrada dentro y el
   sobrante queda en negro. Pulsar ese negro cierra. */
.pc__foto {
  flex: 0 0 100%;                   /* cada una, exactamente el ancho de la pantalla */
  display: grid;                    /* rejilla… */
  grid-template: 100% / 100%;       /* …de una sola celda del tamaño exacto de la foto (alto / ancho)… */
  place-items: center;              /* …que centra la imagen */
  scroll-snap-align: center;        /* punto de enganche: el centro */
  scroll-snap-stop: always;         /* un deslizamiento rápido no se salta fotos */
  padding: clamp(0rem, 4vw - 1rem, 3rem);  /* en el móvil, la foto de borde a borde; en pantallas grandes, algo de aire */
  box-sizing: border-box;           /* ese aire cuenta dentro del ancho, no lo suma */
}                                   /* fin de .pc__foto */

.pc__foto picture { display: contents; }   /* <picture> no hace caja propia: manda la imagen */
.pc__foto source { display: none; }         /* OJO: sin esto, <source> ocupa una fila de la rejilla y empuja la foto abajo */

.pc__foto img {
  display: block;                   /* como bloque, sin hueco debajo */
  max-width: 100%;                  /* nunca más ancha que la pantalla… */
  max-height: 100%;                 /* …ni más alta */
  width: auto;                      /* tamaño según la foto… */
  height: auto;                     /* …sin deformarla */
  object-fit: contain;              /* entera, sin recortes */
}                                   /* fin de la imagen */

/* Botones de la capa (aspa y flechas): sin el aspecto de serie, con el
   icono en crema sobre un círculo crema muy transparente. */
.pc__cerrar,
.pc__nav {
  position: absolute;               /* colocados libres encima de las fotos */
  display: grid;                    /* rejilla… */
  place-items: center;              /* …que centra el icono */
  width: 48px;                      /* 48 × 48 px: fáciles de acertar con el dedo */
  height: 48px;
  padding: 0;                       /* sin relleno de serie */
  border: 0;                        /* sin borde */
  border-radius: 50%;               /* redondos */
  background: rgba(229, 226, 223, .12);   /* crema de la marca, casi transparente */
  color: var(--claro);              /* el icono, en crema */
  cursor: pointer;                  /* manita al pasar el ratón */
  transition: background-color .2s ease;  /* el cambio de fondo al pasar el ratón dura 0,2 s */
}                                   /* fin de los botones */

.pc__cerrar:hover,
.pc__nav:hover { background: rgba(229, 226, 223, .24); }   /* al pasar el ratón, el círculo se aclara */

/* Contorno visible al llegar con el teclado (Tab), en arena. */
.pc__cerrar:focus-visible,
.pc__nav:focus-visible { outline: 2px solid var(--contraste-2); outline-offset: 3px; }

/* Los iconos: dibujados con una línea fina del color del botón. */
.pc__cerrar svg,
.pc__nav svg {
  width: 22px;                      /* tamaño del dibujo */
  height: 22px;
  fill: none;                       /* sin relleno */
  stroke: currentColor;             /* la línea, del color del botón (crema) */
  stroke-width: 1.6;                /* grosor de la línea */
  stroke-linecap: round;            /* puntas redondeadas */
  stroke-linejoin: round;           /* esquinas redondeadas */
}                                   /* fin de los iconos */

.pc__cerrar { top: 1rem; right: 1rem; }   /* aspa: arriba a la derecha, a 16 px de los bordes */

/* Flechas: a media altura, una a cada lado. */
.pc__nav { top: 50%; transform: translateY(-50%); }   /* centradas en vertical */
.pc__nav--prev { left: 1rem; }      /* la de «anterior», a la izquierda */
.pc__nav--sig { right: 1rem; }      /* la de «siguiente», a la derecha */
.pc__nav[hidden] { display: none; } /* en la primera o la última foto, la que sobra se esconde */

/* Contador «3 / 11», abajo en el centro. */
.pc__contador {
  position: absolute;               /* colocado libre encima de las fotos */
  left: 50%;                        /* su borde izquierdo, en el centro… */
  bottom: 1.25rem;                  /* …a 20 px del borde de abajo */
  transform: translateX(-50%);      /* …y desplazado la mitad de su ancho: queda centrado */
  margin: 0;                        /* sin el margen de serie de los párrafos */
  color: var(--claro);              /* crema */
  font-size: .8rem;                 /* letra pequeña */
  letter-spacing: .18em;            /* letras algo separadas */
  pointer-events: none;             /* no intercepta clics */
}                                   /* fin del contador */

/* Con una sola foto, sobran las flechas y el contador. */
.pc--una .pc__nav,
.pc--una .pc__contador { display: none; }

/* En pantallas táctiles (sin ratón que «pase por encima»), sin flechas: las
   fotos se pasan deslizando el dedo. */
@media (hover: none) {
  .pc__nav { display: none; }       /* fuera flechas */
}

/* Si la persona ha pedido menos movimiento en su sistema, sin fundido. */
@media (prefers-reduced-motion: reduce) {
  .pc { transition: none; }         /* aparece y desaparece de golpe */
}

/* ---------------------------------- botón de ampliar del visor --------- */
/* Botón pequeño en la esquina de arriba a la derecha de cada foto del
   visor de proyecto (lo crea visor.js). Solo se ve en la foto activa y con
   el visor ya abierto del todo (.esta-lleno), para que no viaje con la foto
   durante la animación. Al pulsarlo, la foto se abre a pantalla completa. */
.visor__ampliar {
  position: absolute;               /* colocado libre encima de la foto */
  top: .75rem;                      /* a 12 px del borde de arriba… */
  right: .75rem;                    /* …y del de la derecha */
  z-index: 3;                       /* por encima del velo y del rótulo */
  display: grid;                    /* rejilla… */
  place-items: center;              /* …que centra el icono */
  width: 40px;                      /* 40 × 40 px */
  height: 40px;
  padding: 0;                       /* sin relleno de serie */
  border: 0;                        /* sin borde */
  border-radius: 50%;               /* redondo */
  background: rgba(229, 226, 223, .85);   /* crema de la marca, casi opaco: se lee sobre cualquier foto */
  color: var(--principal);          /* el icono, en burdeos */
  cursor: pointer;                  /* manita al pasar el ratón */
  opacity: 0;                       /* oculto de normal… */
  visibility: hidden;               /* …y fuera del recorrido del tabulador */
  transform: scale(.9);             /* un poco encogido; al aparecer crece */
  transition: opacity .25s ease, transform .25s ease,   /* aparición y desaparición suaves */
              visibility 0s linear .25s,                /* al ocultarse, deja de ser pulsable al acabar el fundido */
              background-color .2s ease;                /* cambio de fondo al pasar el ratón */
}                                   /* fin de .visor__ampliar */

/* En la foto activa, con el visor abierto del todo, se ve. */
.visor.esta-lleno .visor__diapo.es-activa .visor__ampliar {
  opacity: 1;                       /* visible */
  visibility: visible;              /* y alcanzable con el tabulador */
  transform: none;                  /* a su tamaño */
  transition-delay: 0s;             /* al aparecer, pulsable desde el primer momento (sin la espera de arriba) */
}

.visor__ampliar:hover { background: var(--claro); }   /* al pasar el ratón, crema pleno */

/* Contorno visible al llegar con el teclado, en burdeos. */
.visor__ampliar:focus-visible { outline: 2px solid var(--principal); outline-offset: 2px; }

.visor__ampliar svg {
  width: 20px;                      /* tamaño del dibujo */
  height: 20px;
  fill: none;                       /* sin relleno */
  stroke: currentColor;             /* la línea, del color del botón (burdeos) */
  stroke-width: 1.8;                /* grosor de la línea */
  stroke-linecap: round;            /* puntas redondeadas */
  stroke-linejoin: round;           /* esquinas redondeadas */
}                                   /* fin del icono */
