/* ============================================================
   Khronos Group 305 · maqueta de rediseño
   Tipografía: Perpetua para los titulares (`assets/perpetua.css`,
   autoalojada) e Inter para el texto corrido, autoalojada aquí
   abajo. Las parejas A, B y C se dejan definidas por si se quiere
   volver sobre ellas, pero sus serifas ya no se descargan.
   ============================================================ */

/* ------------------------------------------------------------
   INTER, AUTOALOJADA (25-ago)
   Hasta hoy las 28 páginas pedían la tipografía a Google Fonts, y
   ahí se pagaban tres cosas en el camino crítico: abrir dos
   conexiones a dominios ajenos (DNS, TCP y TLS antes de recibir un
   solo byte), una hoja de estilo externa que BLOQUEA el pintado, y
   la descarga de **Fraunces entera**, que desde que se encendió
   Perpetua (`data-type="p"`, el 25-ago) no la usa ninguna página.

   Ahora los dos archivos viven en `assets/fonts/`. Son la versión
   variable, así que un archivo por alfabeto cubre los tres gruesos
   que usa la web (400, 500 y 600). El `latin` son 47 KB y trae todo
   lo que necesitan el inglés y el español; el `latin-ext` son 83 KB
   y solo se descarga si aparece un carácter de su rango, que en
   esta web no pasa.

   `font-display:swap`, igual que servía Google: el texto se ve
   desde el primer instante con la de sistema y cambia al llegar la
   buena, en vez de dejar el hueco en blanco.

   LICENCIA: Inter es SIL Open Font License, libre para uso web.
   Es la diferencia con Perpetua, que sigue pendiente de que Robert
   confirme la suya.
   ------------------------------------------------------------ */
@font-face{
  font-family:"Inter";
  src:url("fonts/Inter-latin.woff2") format("woff2");
  font-weight:100 900;font-style:normal;font-display:swap;
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,
    U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face{
  font-family:"Inter";
  src:url("fonts/Inter-latin-ext.woff2") format("woff2");
  font-weight:100 900;font-style:normal;font-display:swap;
  unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,
    U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,
    U+2113,U+2C60-2C7F,U+A720-A7FF;
}

/* ------------------------------------------------------------
   COLOR
   La web va en oscuro. El claro se conserva entero como segunda
   piel (html[data-theme="light"]) para poder comparar las dos en
   la misma llamada, así que ningún color se escribe suelto en las
   reglas de abajo: todo sale de estos tokens.

   Los nombres dicen para qué sirve cada uno, no de qué color es:
     --bg / --bg-alt   fondo de página y fondo de sección alterna
     --sup             superficie de tarjeta (lo que se levanta del fondo)
     --ink / --ink-soft  texto principal y texto secundario
     --line            filete de separación
     --line-fuerte     filete de dibujo (líneas de tiempo, aros de icono)
     --borde-vivo      el filete cuando algo se señala con el ratón
     --sombra          sombra proyectada, ya con su opacidad
     --tinta-inv / --sobre-inv  bloque a contratinta (contacto y pie),
                       que en las dos pieles es oscuro con texto claro
   ------------------------------------------------------------ */
/* Los cuatro tonos de fondo (página, sección alterna, tarjeta, filete) están
   separados por unos tres o cuatro puntos de luminancia percibida cada uno.
   En oscuro no vale con "un poco más claro": por debajo de ese salto las
   tarjetas se funden con la página y la web parece una mancha. Y todos tiran
   a cálido, como el crema del que vienen, para que la piel clara y la oscura
   se reconozcan como la misma marca. */
:root{
  --bg:#0F0E0C;
  --bg-alt:#17150F;
  --sup:#201C17;
  --ink:#F2EEE8;
  --ink-soft:#A79E92;
  --line:#332E27;
  --line-fuerte:#413A31;
  --borde-vivo:#5A5145;
  --sombra:rgba(0,0,0,.55);
  --sombra-suave:rgba(0,0,0,.38);
  --tinta-inv:#070605;
  --sobre-inv:#F4F1EC;
  /* EL BRONCE QUE SE LEE SOBRE TINTA, y es el único token de color que NO
     tiene pareja en la piel clara, a propósito: `--tinta-inv` es negro en las
     dos pieles (es el bloque a contratinta, el del contacto y el pie), así que
     lo que va encima no cambia de una a otra. El `--acento` normal sí cambia,
     y en la piel clara es un bronce oscuro que sobre negro no se ve. */
  --acento-inv:#C89454;
  --acento-inv-tenue:rgba(200,148,84,.38);
  --foto-vacia:#252119;   /* el hueco de una foto mientras carga */
  /* Único color de la web. La marca no trae ninguno (el logo es negro), así
     que el acento se saca del mismo crema del que vienen los grises: un
     bronce cálido, del sector. Se usa con cuentagotas y siempre en piezas
     pequeñas (números de paso, filetes, aros), nunca en texto corrido.
     Los dos tonos son distintos por piel a propósito: el mismo bronce que
     se lee sobre el fondo oscuro se pierde sobre el papel claro. */
  --acento:#C89454;
  --acento-tenue:rgba(200,148,84,.38);
  /* Lo que se escribe ENCIMA del bronce macizo, que hoy es solo el botón de
     enviar del formulario. Va por piel y no fijo porque los dos bronces son
     distintos: el de la web oscura es luminoso y pide tinta encima, el de la
     clara es tostado y pide papel. */
  --sobre-acento:#14120F;
  /* Respuesta del formulario. Tenían un solo valor porque el bloque de
     contacto iba a contratinta en las dos pieles; desde el 23-ago el cierre se
     aclara con la página, así que necesitan pareja: estos dorados sobre papel
     no se leen. */
  --aviso-ok:#D9B27A;
  --aviso-mal:#E8A87C;
  --nav-bg:rgba(15,14,12,.92);
  /* La barra flotante. Es una isla de cristal: fondo muy tenue con el
     desenfoque detrás, filete claro y sombra baja para despegarla del vídeo. */
  --isla-bg:rgba(18,16,13,.46);
  --isla-borde:rgba(255,255,255,.11);
  --isla-sombra:rgba(0,0,0,.42);
  --maxw:1240px;
  --barra:76px;   /* alto de la barra fija; el móvil la baja a 68 */
  --pad:28px;     /* margen lateral del sitio; el móvil estrecho lo baja a 22 */
  /* LA ESCALA DE ESQUINAS (24-ago). Antes de esto la hoja tenía QUINCE valores
     distintos de `border-radius`, cada uno decidido un día distinto: la baraja
     de la portada en 28, la isla del navbar en 20, las fotos en 6, las fichas
     de dato en 4, el menú en 5, 4 y 3, y el formulario en 2. El resultado era
     que dentro de una tarjeta de esquina generosa había pegotes cuadrados.

     Tres medidas y ninguna más, por lo que ES la pieza y no por dónde está:

       · ISLA    lo que se levanta del fondo y contiene otras cosas: la tarjeta
                 de servicio, la baraja de la portada, la isla del navbar, el
                 panel del asistente, la obra de la pila, el visor.
       · PIEZA   lo que va apoyado DENTRO de una isla, y las fotos: las fichas
                 de dato, las tarjetas del equipo, las láminas del portafolio.
       · MENUDO  lo pequeño y de servicio: las filas y miniaturas del menú, los
                 mandos del mapa, los campos del formulario, los globos del
                 asistente. El panel del menú en sí es isla, porque contiene.

     Lo que era píldora sigue siendo píldora (chips y conmutador de idioma) y
     los círculos siguen en 50%: no son esquinas, son formas. */
  --radio-isla:22px;
  --radio-pieza:12px;
  --radio-menudo:8px;
  --f-body:"Inter",-apple-system,BlinkMacSystemFont,"Helvetica Neue",Arial,sans-serif;
  color-scheme:dark;
}

/* Piel clara · la maqueta original, intacta. Se sirve en /claro */
html[data-theme="light"]{
  --bg:#FAF8F5;
  --bg-alt:#F1EDE7;
  --sup:#FFFFFF;
  --ink:#14120F;
  --ink-soft:#5E584E;
  --line:#E1DBD1;
  --line-fuerte:#D8D1C6;
  --borde-vivo:#CFC7BA;
  --sombra:rgba(20,18,15,.12);
  --sombra-suave:rgba(20,18,15,.07);
  --tinta-inv:#14120F;
  --sobre-inv:#F4F1EC;
  --foto-vacia:#DED7CC;
  --acento:#8A5A22;
  --acento-tenue:rgba(138,90,34,.34);
  --sobre-acento:#FCFAF7;
  --aviso-ok:#7A5A1E;
  --aviso-mal:#9C4A21;
  --nav-bg:rgba(250,248,245,.97);
  --isla-bg:rgba(252,250,247,.62);
  --isla-borde:rgba(20,18,15,.10);
  --isla-sombra:rgba(20,18,15,.13);
  color-scheme:light;
}

/* Pareja A · Instrument Serif + Inter (estudio, elegante y seco) */
html[data-type="a"]{--f-title:"Instrument Serif",Georgia,"Times New Roman",serif;--t-ls:-.01em;--t-w:400;--t-scale:1.12}
/* Pareja B · Fraunces + Inter (mismo aire, con más carácter y calidez) */
html[data-type="b"]{--f-title:"Fraunces",Georgia,serif;--t-ls:-.02em;--t-w:600;--t-scale:1}
/* Pareja C · Archivo + Inter (técnico, moderno, sin serif) */
html[data-type="c"]{--f-title:"Archivo",-apple-system,"Helvetica Neue",sans-serif;--t-ls:-.035em;--t-w:700;--t-scale:1}

*{box-sizing:border-box}
/* EL FONDO DEL DOCUMENTO VA NEGRO, y no es el fondo de la web: es lo que se ve
   POR DETRÁS de ella cuando el rebote elástico del sistema despega la página,
   arriba al tirar hacia arriba estando ya arriba del todo, y abajo al revés.

   Sin esto, el rebote de arriba enseñaba una franja blanca por encima del hero,
   que es un vídeo a pantalla completa: justo el sitio donde peor se ve. El
   truco es que en cuanto `html` tiene fondo propio, deja de heredar el del
   `body` para pintar el lienzo del navegador, y el `body` sigue pintando el
   suyo dentro de su caja. Así el rebote enseña este negro y la web se ve igual.

   Negro y no otro color porque los dos extremos de la web ya lo son: arriba el
   hero con su velo y abajo el pie, en las dos pieles. Es el mismo `--arranca`
   del lienzo, y por el mismo motivo. */
html{-webkit-text-size-adjust:100%;background:#0F0E0C}
body{margin:0;background:var(--bg);color:var(--ink);font-family:var(--f-body);
  font-size:17px;line-height:1.65;-webkit-font-smoothing:antialiased;overflow-x:hidden}

/* ------------------------------------------------------------
   SECCIONES QUE CAMBIAN DE PIEL
   El cliente pidió en el briefing del 15-ago que la web fuera alternando
   claras y oscuras. En vez de cortar de una a otra, la piel se TRANSFORMA
   mientras se baja: cambian a la vez el fondo, el texto, el texto secundario
   y los filetes, mezclando las dos pieles según cuánto ha subido la sección
   por la pantalla. Es lo que da la sensación de página viva al desplazarse.

   `--p` lo pone el guion y va de 0 (la piel de la página) a 1 (la contraria).
   Cada sección declara con `data-piel` a cuál va, y el guion la mezcla desde
   la que traía la anterior. Sin guion (o pidiendo menos movimiento) el valor
   se queda en su destino y el cambio es un corte limpio, que también vale.

   Aquí SÍ se escriben los colores a pelo, que es lo único de todo el archivo
   donde pasa, y es a propósito: esto no es una regla que use color, es una
   definición de piel, igual que el `:root` de arriba. Los dos juegos están
   repetidos en los dos sentidos porque la mezcla tiene que saber de dónde
   sale y adónde va, y eso se invierte al entrar por /claro.
   ------------------------------------------------------------ */
.piel{
  --p:0;
  /* CUÁN OSCURO ES EL FONDO DE ESTE TRAMO, de 0 (blanco) a 1 (negro). Hace
     falta aparte de `--p` porque `--p` no dice claro ni oscuro: dice "la piel
     de la página" (0) o "la contraria" (1), y eso cambia de significado entre
     las dos pieles. Lo usa lo que tiene que reaccionar al color real del fondo
     y no al lado del viaje, como el velo de los retratos del equipo. */
  --oscuro: calc(1 - var(--p));
  /* ---------- EL TEXTO NO VIAJA CON EL FONDO ----------
     Hasta el 20-ago el fondo y el texto se mezclaban con el MISMO valor, y eso
     hacía que a medio camino los dos fueran exactamente el mismo color:
     contraste 1 a 1, texto invisible. No se notaba porque el destino era
     siempre 0 o 1 y por el centro solo se pasaba de largo, arrastrando.

     Para que una sección pueda PARARSE en un tono intermedio, el texto tiene
     que cruzar antes y de golpe: `--pt` va de 0 a 1 en la franja estrecha del
     centro, así que cuando el fondo aún es oscuro medio el texto ya está claro
     del todo, y al revés. El fondo se queda con `--p`, que es el que dibuja el
     recorrido; el texto, los filetes y el acento van con `--pt`.

     ZONA PROHIBIDA: ningún `data-piel` entre 0.40 y 0.55. Ahí el fondo es gris
     medio y NO existe ningún color de texto que llegue a contraste suficiente:
     es un límite físico, no un ajuste que falte. Rango bueno: 0 a 0.35 y 0.60
     a 1, medido. Por el centro se puede pasar, pero no parar. */
  --pt: var(--p);   /* reserva: si un navegador no entendiera la línea de abajo,
                       el texto vuelve a viajar con el fondo, que es como estaba
                       antes del 20-ago. Se ve peor a mitad de camino, pero no
                       se rompe nada. */
  --pt: clamp(0, calc((var(--p) - 0.42) / 0.16), 1);
  /* Cuánto está el fondo "a medio camino": 0 en los dos extremos y 1 en el
     centro. Es una parábola, y va al cuadrado para que en los extremos no
     empuje nada y solo actúe donde de verdad hace falta. Sirve para una cosa:
     el texto secundario es gris en las dos pieles, así que sobre un fondo
     intermedio se queda corto; ahí se le acerca al texto principal. */
  --medio: calc(4 * var(--p) * (1 - var(--p)));
  --empuje: calc(var(--medio) * var(--medio) * 70%);
  /* El recorrido partido en dos mitades, para lo que tiene que pasar por la
     piedra cálida en vez de por el gris (lo mismo que hace el lienzo con
     `--cm`, ver más abajo). `--p1` recorre la primera mitad y se queda en tope,
     `--p2` no arranca hasta pasado el medio: encadenando las dos mezclas sale
     un camino de tres colores sin una sola línea de guion. */
  --p1: clamp(0, calc(var(--p) * 2), 1);
  --p2: clamp(0, calc((var(--p) - 0.5) * 2), 1);
  --bg:        color-mix(in oklab,#0F0E0C,#FAF8F5 calc(var(--p) * 100%));
  --bg-alt:    color-mix(in oklab,#17150F,#F1EDE7 calc(var(--p) * 100%));
  /* LA SUPERFICIE VA POR LA PIEDRA, como el lienzo y las islas (24-ago). Iba
     en línea recta, y ese camino CRUZA POR GRIS: `#201C17` no tiene apenas
     color (croma 0,011) y el blanco no tiene ninguno, así que el punto medio de
     ese camino tampoco puede tenerlo. En la sección de "What we do", que va a
     0,72, la tarjeta salía `#57534F` sobre un fondo `#474543`: gris sobre gris.
     No se notó antes porque hasta el 24-ago esas tarjetas eran cristal
     translúcido y el fondo cálido se veía a través. Con la parada, el mismo
     punto sale `#625747`. Los dos extremos no se mueven. */
  --sup:       color-mix(in oklab,
                 color-mix(in oklab,#201C17,#9C8B72 calc(var(--p1) * 100%)),
                 #FFFFFF calc(var(--p2) * 100%));
  --ink:       color-mix(in oklab,#F2EEE8,#14120F calc(var(--pt) * 100%));
  --ink-soft:  color-mix(in oklab,
                 color-mix(in oklab,#A79E92,#5E584E calc(var(--pt) * 100%)),
                 var(--ink) var(--empuje));
  --line:      color-mix(in oklab,#332E27,#E1DBD1 calc(var(--pt) * 100%));
  --line-fuerte:color-mix(in oklab,#413A31,#D8D1C6 calc(var(--pt) * 100%));
  --borde-vivo:color-mix(in oklab,#5A5145,#CFC7BA calc(var(--pt) * 100%));
  --sombra:    color-mix(in oklab,rgba(0,0,0,.55),rgba(20,18,15,.12) calc(var(--p) * 100%));
  --sombra-suave:color-mix(in oklab,rgba(0,0,0,.38),rgba(20,18,15,.07) calc(var(--p) * 100%));
  --foto-vacia:color-mix(in oklab,#252119,#DED7CC calc(var(--p) * 100%));
  --acento:    color-mix(in oklab,#C89454,#8A5A22 calc(var(--pt) * 100%));
  --sobre-acento:color-mix(in oklab,#14120F,#FCFAF7 calc(var(--pt) * 100%));
  --acento-tenue:color-mix(in oklab,rgba(200,148,84,.38),rgba(138,90,34,.34) calc(var(--pt) * 100%));
  /* La barra cruza el tramo entero, así que es lo que más veces pasaba por el
     medio del camino: con la mezcla directa quedaba gris justo donde el fondo
     ya no lo está. Va por la piedra igual que el lienzo. */
  --nav-bg:    color-mix(in oklab,
                 color-mix(in oklab,rgba(15,14,12,.92),rgba(156,139,114,.945) calc(var(--p1) * 100%)),
                 rgba(250,248,245,.97) calc(var(--p2) * 100%));
  --isla-bg:   color-mix(in oklab,
                 color-mix(in oklab,rgba(18,16,13,.46),rgba(156,139,114,.54) calc(var(--p1) * 100%)),
                 rgba(252,250,247,.62) calc(var(--p2) * 100%));
  --isla-borde:color-mix(in oklab,rgba(255,255,255,.11),rgba(20,18,15,.10) calc(var(--p) * 100%));
  --isla-sombra:color-mix(in oklab,rgba(0,0,0,.42),rgba(20,18,15,.13) calc(var(--p) * 100%));
  /* La sección YA NO PINTA FONDO. Lo pone el lienzo, de una pieza para todo el
     tramo (ver `.lienzo` más abajo). Aquí se queda solo el color del texto, que
     sí es cosa de cada sección: cada una sabe sobre qué tono cae y ajusta lo que
     se lee encima. Si esto vuelve a pintar `background`, vuelven los bloques. */
  color:var(--ink);
}

/* ---------- EL LIENZO ----------
   Una sola capa detrás de todo el tramo de después del hero. El degradado lo
   escribe el guion midiendo dónde cae cada sección; el de aquí es la reserva
   para cuando el guion no llega a correr, y va de oscuro a claro y vuelta, que
   es el viaje en corto. */
.lienzo{position:relative;isolation:isolate}
/* RED DE SEGURIDAD, y hace falta: al pasar el fondo al lienzo se apagaron los
   de `.piel`, pero dos reglas seguían pintando el suyo por su cuenta (la banda
   de foto y texto, y la franja de licencias) y bastaba con eso para que la
   página volviera a leerse como bloques apilados. En vez de ir cazando cada
   una, aquí se apaga TODO lo que cuelgue directamente del lienzo: dentro de
   este tramo el fondo lo pone el lienzo y nadie más. Las tarjetas de dentro
   (servicios, equipo, licencias) sí conservan el suyo, que para eso son piezas
   apoyadas encima y no secciones. */
.lienzo > :not(.lienzo-fondo){background:none}
/* Los dos extremos del viaje. El guion no calcula colores: escribe el degradado
   como `color-mix` entre estos dos, así que el espejo de /claro sale solo con
   darles la vuelta aquí abajo, sin una línea de más en el guion. */
.lienzo-fondo{--c0:#0F0E0C;--c1:#FAF8F5;
  /* LA PARADA DE EN MEDIO, y hace falta. Mezclar el negro cálido con el crema
     de una tirada cruza por un gris casi neutro (#797875, con las tres
     componentes casi iguales): un topo frío que no tiene nada que ver con el
     resto de la paleta. Y como el recorrido de la portada sube y baja seis
     veces entre oscuro y claro, esa banda gris aparecía seis veces, que es lo
     que se leía como fondo sucio.

     Con esta piedra cálida en medio, el camino pasa por #5E5446 al bajar y por
     #B2A490 al subir: tonos con la misma temperatura que el bronce del acento.
     Es el mismo tono en las dos pieles, porque el medio del camino no depende
     de por qué lado se entre. Si algún día se quiere el tránsito más o menos
     tostado, se toca aquí y en ningún sitio más. */
  --cm:#9C8B72;
  /* Las dos juntas del lienzo con lo que no es el lienzo, las dos con color
     exacto y no con un tono parecido: ahí es donde se veía la raya.

     Las dos son ahora `--c0`, o sea el fondo de la página en la piel que
     toque, y eso es la decisión de tono del 23-ago dicha en dos líneas.

     ARRIBA la junta iba clavada en negro para coser con el borde de abajo del
     hero, que es vídeo con velo. Al aflojar el velo para que la portada entre
     con luz, ese negro se quedaba solo y se derramaba por detrás de las
     tarjetas de licencias como una sombra suelta. Se compararon cuatro colores
     de arranque en `muestras-cierre.html` (seguir al velo, papel, piedra
     cálida y el negro de siempre) y Sebas eligió PAPEL: el hero acaba en corte
     limpio contra la página y no hay sombra que disolver. Conviene saber que
     el aire era poco de todos modos: la franja de licencias cae a 86px del
     hero, así que cualquier transición tenía que resolverse ahí.

     ABAJO ya no está el negro del pie: está el bloque de contacto, que desde
     el 23-ago va a la piel de la página en vez de a contratinta. El pie sigue
     en negro, pero fuera del lienzo y separado por su filete de bronce, que es
     lo que lo convierte en remate. */
  --arranca:var(--c0);
  --acaba:var(--c0)}
html[data-theme="light"] .lienzo-fondo{--c0:#FAF8F5;--c1:#0F0E0C}
.lienzo-fondo{position:absolute;inset:0;z-index:-1;
  /* Reserva para cuando el guion no llega a correr, y va LISA a propósito.
     Antes era una copia a mano de las paradas del degradado, y sin guion eso
     es una trampa: las secciones se quedan con `--p:0` (el color de texto de
     la piel de la página) mientras el fondo sigue subiendo y bajando por su
     cuenta, así que había tramos con texto oscuro sobre fondo oscuro. Del
     color de la página se lee todo, que es lo único que importa aquí. */
  background:var(--c0)}
/* El pie de la página va en negro fijo, así que el lienzo termina oscuro para
   empalmar con él sin que se vea dónde acaba uno y empieza el otro. */
/* Entrando por /claro la página ya es clara, así que el viaje es el contrario:
   misma clase, mismos `data-piel`, resultado espejo. */
/* El espejo de /claro. Mismas dos velocidades que arriba: el fondo con `--p`
   y todo lo que se lee encima con `--pt`, que ya viene calculado del bloque
   anterior y no hace falta repetir. */
html[data-theme="light"] .piel{
  --oscuro: var(--p);   /* en claro el viaje va al revés, y con él esta medida */
  --bg:        color-mix(in oklab,#FAF8F5,#0F0E0C calc(var(--p) * 100%));
  --bg-alt:    color-mix(in oklab,#F1EDE7,#17150F calc(var(--p) * 100%));
  /* La misma piedra en la piel clara, recorrida al revés. Ver el porqué arriba,
     en la declaración de la piel oscura. */
  --sup:       color-mix(in oklab,
                 color-mix(in oklab,#FFFFFF,#9C8B72 calc(var(--p1) * 100%)),
                 #201C17 calc(var(--p2) * 100%));
  --ink:       color-mix(in oklab,#14120F,#F2EEE8 calc(var(--pt) * 100%));
  --ink-soft:  color-mix(in oklab,
                 color-mix(in oklab,#5E584E,#A79E92 calc(var(--pt) * 100%)),
                 var(--ink) var(--empuje));
  --line:      color-mix(in oklab,#E1DBD1,#332E27 calc(var(--pt) * 100%));
  --line-fuerte:color-mix(in oklab,#D8D1C6,#413A31 calc(var(--pt) * 100%));
  --borde-vivo:color-mix(in oklab,#CFC7BA,#5A5145 calc(var(--pt) * 100%));
  --sombra:    color-mix(in oklab,rgba(20,18,15,.12),rgba(0,0,0,.55) calc(var(--p) * 100%));
  --sombra-suave:color-mix(in oklab,rgba(20,18,15,.07),rgba(0,0,0,.38) calc(var(--p) * 100%));
  --foto-vacia:color-mix(in oklab,#DED7CC,#252119 calc(var(--p) * 100%));
  --acento:    color-mix(in oklab,#8A5A22,#C89454 calc(var(--pt) * 100%));
  --sobre-acento:color-mix(in oklab,#FCFAF7,#14120F calc(var(--pt) * 100%));
  --acento-tenue:color-mix(in oklab,rgba(138,90,34,.34),rgba(200,148,84,.38) calc(var(--pt) * 100%));
  --nav-bg:    color-mix(in oklab,
                 color-mix(in oklab,rgba(250,248,245,.97),rgba(156,139,114,.945) calc(var(--p1) * 100%)),
                 rgba(15,14,12,.92) calc(var(--p2) * 100%));
  --isla-bg:   color-mix(in oklab,
                 color-mix(in oklab,rgba(252,250,247,.62),rgba(156,139,114,.54) calc(var(--p1) * 100%)),
                 rgba(18,16,13,.46) calc(var(--p2) * 100%));
  --isla-borde:color-mix(in oklab,rgba(20,18,15,.10),rgba(255,255,255,.11) calc(var(--p) * 100%));
  --isla-sombra:color-mix(in oklab,rgba(20,18,15,.13),rgba(0,0,0,.42) calc(var(--p) * 100%));
}

/* La página no se arrastra de lado. Tres capas, porque en el teléfono el
   `overflow-x:hidden` del body por sí solo no basta: el que manda el scroll de
   la ventana es el elemento raíz, y en iOS se sigue pudiendo empujar.
   `clip` es el que hay que usar (no `hidden`): recorta sin crear un contenedor
   de scroll, así que no rompe anclas ni posicionamiento pegajoso. El `hidden`
   del body queda de respaldo para los navegadores que no conocen `clip`. */
html,body{max-width:100%}
@supports (overflow:clip){html,body{overflow-x:clip}}

/* La barra de scroll no se dibuja. Además de quitar el riel gris del costado,
   devuelve al hero los ~15px que la barra le robaba a la derecha en los Mac que
   la llevan siempre visible (ratón conectado), que era la franja clara que se
   veía sobre la foto de portada. Se sigue pudiendo desplazar con rueda, dedo,
   teclado y barra espaciadora. */
html{scrollbar-width:none}
*::-webkit-scrollbar{width:0;height:0}
*::-webkit-scrollbar-thumb,*::-webkit-scrollbar-track{background:transparent}

/* La barra va fija, así que un salto a #services dejaba el arranque de la
   sección debajo de ella. El desplazamiento por ancla se frena antes, con la
   altura de la barra más un respiro. Suave, salvo si el teléfono pide menos
   movimiento. */
html{scroll-padding-top:calc(var(--barra) + env(safe-area-inset-top,0px) + 20px);
  scroll-behavior:smooth}
[id]{scroll-margin-top:calc(var(--barra) + env(safe-area-inset-top,0px) + 20px)}
@media (max-width:640px){:root{--barra:68px}}
@media (prefers-reduced-motion:reduce){html{scroll-behavior:auto}}
/* EN EL TELÉFONO EL SALTO ES SECO, A PROPÓSITO (26-ago, lo pidió Robert: "da
   un brinco, debería ser suave o rápido"). El desplazamiento suave del
   navegador tiene que pintar la página entera cuadro a cuadro mientras corre,
   y la portada es la página más larga de la web, con el vídeo del recorrido y
   los bloques pegajosos por el camino: en un teléfono no le da tiempo y lo
   que se ve son tirones. Un salto limpio no puede entrecortarse. En ordenador
   el suave se queda, que ahí sí llega. */
@media (max-width:980px){html{scroll-behavior:auto}}
/* `height:auto` NO es adorno desde el 23-ago, que es cuando las imágenes
   estrenaron `width` y `height` en el marcado (las dos medidas son lo que deja
   al navegador reservar el hueco antes de que llegue la imagen, en vez de
   recolocar la página con cada una que carga). Con las dos puestas, una imagen
   que el `max-width` de aquí encoja se quedaría con la altura del atributo y
   saldría estirada: `height:auto` es lo que la deja seguir su proporción. */
img{max-width:100%;height:auto;display:block}
a{color:inherit}

/* El margen lateral del sitio va en variable porque hay piezas que tienen que
   compensarlo exactamente (una tira que se arrastra de lado a lado sangrando
   hasta el borde). Con el número escrito a mano en dos sitios, al cambiarlo en
   uno la pieza se salía por el costado. */
.wrap{max-width:var(--maxw);margin:0 auto;padding:0 var(--pad)}
/* La etiqueta y el titular son UNA pieza: la etiqueta dice de qué sección es el
   titular que viene debajo. Por eso va más cerca de él (16px) que él de su
   entradilla (24px, en la regla `h2 + .lead`). Iba al revés: 22px arriba y cero
   abajo, así que la etiqueta parecía el pie de la sección anterior y el titular
   se leía en el mismo bloque que la entradilla. */
.eyebrow{font-size:12px;font-weight:600;letter-spacing:.16em;text-transform:uppercase;
  color:var(--ink-soft);margin:0 0 16px;font-family:var(--f-body)}
h1,h2,h3{margin:0;font-family:var(--f-title);font-weight:var(--t-w);
  letter-spacing:var(--t-ls);line-height:1.1}
h2{font-size:calc(clamp(30px,4vw,50px) * var(--t-scale))}
h3{font-size:calc(20px * var(--t-scale));line-height:1.25}
p{margin:0 0 18px}
.lead{font-size:19px;color:var(--ink-soft);max-width:62ch}
/* La cabecera de sección es la misma en toda la web (etiqueta, titular y a
   veces entradilla), así que su aire tiene que ser el mismo también, y estaba
   justo al revés de la jerarquía: la etiqueta se separaba 22px del titular,
   que es su pareja, y el titular se quedaba PEGADO a su entradilla, porque
   `h2` no lleva margen abajo y `.lead` no lleva margen arriba. En la banda de
   foto y texto se había parcheado a mano con un margen en el h2; en el
   contacto no, y ahí se leía titular y entradilla como un solo bloque. */
h2 + .lead{margin-top:24px}

/* Lista seca. Sustituye a las enumeraciones metidas dentro de un párrafo, que
   en el teléfono se leen como un muro. Sin viñeta: cada línea separada por un
   filete, el mismo lenguaje de ficha que las tarjetas de dato. */
.bul{list-style:none;margin:18px 0 0;padding:0;display:grid;max-width:52ch}
.bul li{font-size:15px;line-height:1.4;color:var(--ink-soft);padding:9px 0;
  border-top:1px solid var(--line)}
.bul li:first-child{border-top:0;padding-top:0}
.bul + .lead{margin-top:24px}

/* EL AIRE DE SECCIÓN BAJA DE 104 A 88 (24-ago), y sale de una medida y no de
   un gusto: con el tope de sección puesto, la portada se lee sección a sección,
   y una sección que mide más que la pantalla no se puede enseñar entera por
   bien que pare el scroll. En la pantalla de trabajo (863px de alto, 765
   útiles descontando la barra) esos 32 píxeles por sección son la diferencia
   entre cortarse y caber en tres de ellas. */
section{padding:88px 0}
@media (max-width:760px){section{padding:72px 0}}

/* ---------- NAV · ISLA FLOTANTE ----------
   Una sola isla con todo dentro (marca, enlaces, idioma y botón), separada del
   borde de la pantalla y con el fondo de cristal: el vídeo de la portada se ve
   difuminado por detrás en vez de quedar tapado por una franja.

   Va en dos capas a propósito. `.nav` es el marco: fijo, transparente, con el
   aire de arriba y la zona segura del aparato. `.nav .wrap` es la isla: es la
   que lleva el fondo, el filete, la sombra y el redondeo. Separarlas es lo que
   permite esconder la isla ENTERA hacia arriba sin arrastrar nada más, y lo
   que deja el hueco de los lados libre para que se vea la página por debajo.

   Está SIEMPRE a la vista (lo pidió Robert el 26-ago). Antes se apartaba al
   bajar, y de aquello queda la clase `compact`, que ahora hace más trabajo:
   además de apretar el alto, cierra el cristal. */
.nav{position:fixed;inset:0 0 auto 0;z-index:50;
  background:transparent;border:0;pointer-events:none;
  padding:calc(env(safe-area-inset-top,0px) + 14px) var(--pad) 0}

.nav .wrap{display:flex;align-items:center;gap:24px;height:62px;
  pointer-events:auto;
  padding:0 12px 0 20px;
  border-radius:999px;
  background:var(--isla-bg);
  border:1px solid var(--isla-borde);
  box-shadow:0 12px 34px var(--isla-sombra);
  /* EL DESENFOQUE DE FONDO ES LO MÁS CARO QUE HAY EN PANTALLA MIENTRAS SE
     BAJA, porque obliga al navegador a copiar lo que pasa por detrás de la
     isla y volver a desenfocarlo en cada cuadro, y por detrás de la isla pasa
     la web entera. Bajado el 23-ago de 18px a 12px y fuera el `saturate`, que
     era un segundo pase sobre la misma copia para un realce que no se
     distingue sobre el vídeo ni sobre el papel. La isla sigue siendo de
     cristal; lo que se va es el precio de mantenerla. */
  backdrop-filter:blur(12px);
  -webkit-backdrop-filter:blur(12px);
  transition:height .4s var(--ease),background .4s ease,box-shadow .4s ease}
/* Ya bajando, la isla se aprieta un punto: es el mismo gesto de la barra
   compacta de antes, ahora sobre el alto de la isla. */
/* AL BAJAR, LA ISLA SE CIERRA. Es de cristal porque nació sobre el vídeo de
   la portada, y desde que se queda puesta por debajo le pasa el texto de la
   página: con el fondo tenue se leían las dos capas a la vez. El tono no se
   escribe a mano ni se duplica por piel: se mezcla el propio cristal con el
   fondo de la página (`--bg`, que es opaco y va con el revelado), así que
   sale solo en oscuro, en claro y en cada punto del viaje. El desenfoque se
   queda: lo que asoma del fondo sigue siendo fondo, no letra. */
.nav.compact .wrap{height:56px;box-shadow:0 10px 26px var(--isla-sombra);
  background:color-mix(in oklab,var(--isla-bg),var(--bg) 58%)}
.brand{display:flex;align-items:center;gap:13px;text-decoration:none;flex:0 0 auto}
/* La K del logo nuevo de Robert, recortada del original y sin marco ni letras:
   el dorado se lee igual sobre el vídeo oscuro y sobre las secciones claras,
   así que no hay que retocar la marca del cliente. */
.brand img{width:30px;height:34px;object-fit:contain}
.brand .t{font-weight:600;letter-spacing:-.01em;line-height:1.15;font-size:17px}
.brand small{display:block;font-size:10.5px;font-weight:500;letter-spacing:.14em;
  text-transform:uppercase;color:var(--ink-soft)}
.nav nav{margin-left:auto;display:flex;gap:28px;font-size:15px}
.nav nav a{text-decoration:none;color:var(--ink-soft)}
.nav nav a:hover{color:var(--ink)}
/* El botón va en cápsula en toda la web, y no solo dentro de la isla como
   hasta el 20-ago. Tenía dos formas según dónde cayera (cápsula arriba, recto
   en el resto), así que el mismo "Start a project" se dibujaba de dos maneras
   a la vez en la portada: uno en la barra y otro debajo, a media pantalla de
   distancia. La cápsula era además la forma que ya usaban las otras dos cosas
   pulsables del sitio, el globo del asistente y sus respuestas rápidas, así
   que redondear el botón alinea las tres en vez de crear una cuarta.

   El radio en cápsula es SOLO de lo pulsable. Las tarjetas, las fotos y los
   campos siguen con su esquina recta, que es lo que sostiene el aire de plano
   de arquitecto: si se redondea todo, el sitio pierde el registro. */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;padding:13px 22px;
  border-radius:999px;font-size:15px;font-weight:500;text-decoration:none;font-family:var(--f-body);
  border:1px solid var(--ink);background:var(--ink);color:var(--bg);min-height:46px;white-space:nowrap;cursor:pointer}
.btn.ghost{background:transparent;color:var(--ink)}
/* Dentro de la isla el botón va un punto más pequeño para que quepa en la
   cápsula sin engordarla. La forma ya la trae de arriba. */
.nav .wrap > .btn{min-height:42px;padding:11px 20px;font-size:14.5px}
/* En móvil la barra se queda con lo justo: marca, idioma y menú.
   El botón de contacto vive dentro del desplegable, que es donde hay sitio. */
@media (max-width:760px){.nav .wrap > .btn{display:none}}
@media (max-width:640px){.nav .wrap{height:56px;gap:12px;padding:0 10px 0 16px}
  .nav{padding:calc(env(safe-area-inset-top,0px) + 10px) 14px 0}
  .brand{gap:10px}.brand img{width:26px;height:29px}
  .brand .t{font-size:14px}
  .brand small{font-size:9px;letter-spacing:.12em}}
@media (max-width:380px){.brand .t{font-size:13px}.brand small{display:none}}

/* ---------- MENÚ DESPLEGABLE (móvil y tablet) ---------- */
.navtoggle{display:none;place-items:center;width:44px;height:44px;margin-right:-8px;
  border:0;background:transparent;padding:0;cursor:pointer;flex:0 0 auto}
.navtoggle i{display:block;position:relative;width:22px;height:1.5px;background:var(--ink);
  transition:background .2s ease}
.navtoggle i::before,.navtoggle i::after{content:"";position:absolute;left:0;width:22px;height:1.5px;
  background:var(--ink);transition:transform .34s var(--ease)}
.navtoggle i::before{top:-7px}
.navtoggle i::after{top:7px}
body.menu-on .navtoggle i{background:transparent}
body.menu-on .navtoggle i::before{transform:translateY(7px) rotate(45deg)}
body.menu-on .navtoggle i::after{transform:translateY(-7px) rotate(-45deg)}

/* El panel cuelga del body, no de la barra, y en fijo: dentro de la barra
   quedaba atrapado en su capa de backdrop-filter y el fondo se pintaba solo
   los primeros píxeles, con el resto del menú suelto sobre la foto. El JS le
   pone el top con la altura real de la barra al abrirlo. Fondo sólido porque
   cae sobre el hero. */
/* El panel cuelga por debajo de la isla y con su mismo lenguaje: separado de
   los bordes y redondeado. Una franja a sangre debajo de una barra flotante se
   lee como dos elementos de webs distintas. */
.navmenu{position:fixed;top:68px;left:14px;right:14px;z-index:49;background:var(--bg);
  border:1px solid var(--isla-borde);border-radius:var(--radio-isla);
  box-shadow:0 22px 44px var(--sombra);
  /* Con los grupos abiertos el menú puede pasar del alto de la pantalla, así
     que se desplaza por dentro. El tope real lo pone el JS al abrirlo, con la
     altura que tenga la barra en ese momento; esto es el respaldo.
     `contain` evita que al llegar al final arrastre la página de debajo. */
  max-height:calc(100dvh - 68px);overflow-y:auto;overscroll-behavior:contain;
  padding:6px 0 24px;opacity:0;visibility:hidden;transform:translateY(-12px);
  transition:opacity .26s var(--ease),transform .34s var(--ease),visibility 0s linear .34s}
body.menu-on .navmenu{opacity:1;visibility:visible;transform:none;
  transition:opacity .24s var(--ease),transform .38s var(--ease),visibility 0s}
.navmenu .wrap{display:grid;padding:0 20px}
.navmenu .link{display:flex;align-items:center;min-height:52px;padding:6px 0;
  text-decoration:none;color:var(--ink);font-size:18px;font-weight:500;letter-spacing:-.01em;
  border-bottom:1px solid var(--line)}
.navmenu .acts{display:grid;gap:10px;margin-top:20px}
.navmenu .acts .btn{width:100%}
/* Estos dos encendidos van DESPUÉS de las reglas base a propósito: misma
   especificidad, así que manda la última que se lee. */
@media (max-width:980px){.nav nav{display:none}.navtoggle{display:grid}}
@media (min-width:981px){.navmenu{display:none}}
@media (prefers-reduced-motion:reduce){
  .navmenu{transition:opacity .01s,visibility 0s}
  .navtoggle i,.navtoggle i::before,.navtoggle i::after{transition:none}}

/* ---------- DESPLEGABLE DE LA BARRA (pantalla grande) ----------
   Servicios y Proyectos llevan dentro un atajo a dos o tres de los suyos y
   una salida a la lista completa. Se abre al pasar por encima y también al
   llegar con el tabulador (`:focus-within`), así que no depende del ratón.

   El grupo ocupa TODO el alto de la barra, no solo el de su palabra: si no,
   al bajar el ratón hacia la tarjeta se sale del elemento y el menú se
   cierra a medio camino. Por eso `nav` se estira y el grupo con él. */
.nav nav{align-self:stretch;align-items:center}
.nd{position:relative;display:flex;align-items:center;height:100%}
.nd > a{display:inline-flex;align-items:center;gap:7px}
.nd > a::after{content:"";width:5px;height:5px;flex:0 0 auto;
  border-right:1.4px solid currentColor;border-bottom:1.4px solid currentColor;
  transform:translateY(-2px) rotate(45deg);transition:transform .3s var(--ease)}
.nd:hover > a::after,.nd:focus-within > a::after{transform:translateY(1px) rotate(225deg)}

/* La tarjeta cuelga del borde de abajo de la barra. El `padding-top` es
   colchón transparente: el ratón cruza el filete sin pasar por un hueco
   muerto que cerraría el menú. */
/* OJO al selector: todas estas reglas van acotadas a `.nav`. Sin acotar, un
   `.sub` a secas alcanzaba también al párrafo del hero, que se llama igual, y
   se lo llevaba a `position:absolute` con `visibility:hidden`: la frase de la
   portada llevaba oculta y fuera de flujo desde que se montó este menú, y por
   eso los botones salían pegados al titular. */
.nav .sub{position:absolute;top:100%;left:-20px;z-index:5;padding-top:20px;
  opacity:0;visibility:hidden;pointer-events:none;transform:translateY(-8px);
  transition:opacity .24s var(--ease),transform .3s var(--ease),visibility 0s linear .3s}
.nd:hover .sub,.nd:focus-within .sub{opacity:1;visibility:visible;pointer-events:auto;
  transform:none;transition:opacity .22s var(--ease),transform .28s var(--ease),visibility 0s}
.nav .sub .in{background:var(--sup);border:1px solid var(--line);border-radius:var(--radio-isla);
  box-shadow:0 24px 50px var(--sombra);padding:8px;min-width:292px}
.nav .sub a{display:flex;align-items:center;gap:13px;padding:10px 12px;border-radius:var(--radio-menudo);
  font-size:14.5px;line-height:1.3;color:var(--ink);text-decoration:none;
  transition:background .22s ease}
.nav .sub a:hover{background:var(--bg-alt);color:var(--ink)}
.nav .sub .n{font-size:11px;font-weight:600;letter-spacing:.14em;color:var(--ink-soft);flex:0 0 auto}
.nav .sub small{display:block;font-size:12px;color:var(--ink-soft);margin-top:2px;letter-spacing:0}
.nav .sub figure{margin:0;width:46px;height:46px;flex:0 0 auto;border-radius:var(--radio-menudo);
  overflow:hidden;background:var(--foto-vacia)}
.nav .sub figure img{width:100%;height:100%;object-fit:cover}
/* La salida a la lista completa se separa con un filete: es de otra especie
   que los atajos de arriba. */
.nav .sub a.all{margin-top:7px;padding-top:14px;border-top:1px solid var(--line);
  border-radius:0;font-weight:500}
.nav .sub a.all:hover{background:transparent;opacity:.62}
.nav .sub a.all::after{content:" →"}
@media (prefers-reduced-motion:reduce){
  .nav .sub{transition:opacity .01s,visibility 0s}
  .nd > a::after{transition:none}}

/* ---------- GRUPOS DENTRO DEL MENÚ DE MÓVIL ----------
   Lo mismo que el desplegable, plegado en acordeón: doce enlaces sueltos no
   caben en una pantalla de 667px de alto. La fila que abre es un botón, no un
   enlace, para que no haya duda de si lleva a algún sitio; el primer hijo del
   grupo es siempre la lista completa.
   El plegado va con `grid-template-rows` de 0fr a 1fr, que anima sin tener
   que medir alturas a mano. */
.navmenu .grp{display:flex;align-items:center;justify-content:space-between;gap:14px;
  width:100%;min-height:52px;padding:6px 0;margin:0;text-align:left;cursor:pointer;
  background:transparent;border:0;border-bottom:1px solid var(--line);color:var(--ink);
  font-family:var(--f-body);font-size:18px;font-weight:500;letter-spacing:-.01em}
.navmenu .grp .chev{width:8px;height:8px;flex:0 0 auto;margin-right:4px;
  border-right:1.6px solid var(--ink-soft);border-bottom:1.6px solid var(--ink-soft);
  transform:translateY(-2px) rotate(45deg);transition:transform .32s var(--ease)}
.navmenu .grp[aria-expanded="true"] .chev{transform:translateY(1px) rotate(225deg)}
.navmenu .subs{display:grid;grid-template-rows:0fr;
  transition:grid-template-rows .34s var(--ease)}
.navmenu .grp[aria-expanded="true"] + .subs{grid-template-rows:1fr}
.navmenu .subs > div{overflow:hidden;min-height:0}
.navmenu .subs a{display:flex;align-items:center;gap:11px;min-height:46px;
  padding:6px 0 6px 18px;text-decoration:none;color:var(--ink-soft);font-size:15.5px;
  border-bottom:1px solid var(--line)}
.navmenu .subs a .n{font-size:11px;font-weight:600;letter-spacing:.14em;flex:0 0 auto}
.navmenu .subs a small{display:block;font-size:12.5px;margin-top:1px}
.navmenu .subs a.all{color:var(--ink);font-weight:500}
.navmenu .subs a.all::after{content:" →"}
.navmenu .subs figure{display:none}
@media (prefers-reduced-motion:reduce){
  .navmenu .subs{transition:none}
  .navmenu .grp .chev{transition:none}}

/* ---------- HERO ---------- */
/* La altura va en svh (el alto de pantalla con la barra del navegador desplegada):
   con vh, el móvil calcula sobre la pantalla entera y la barra se come el pie del
   hero; con dvh, el hero cambia de alto al bajar y el texto salta. Se deja vh
   delante como respaldo para navegadores antiguos. */
/* Alto del hero: con el texto apoyado en el pie, cada punto de alto que se le
   da es hueco vacío entre la barra y el titular. A 88 sobraba media pantalla;
   a 74 el bloque sube y la franja de licencias ya asoma, que es lo que invita
   a seguir bajando. Es el número que se toca si se quiere más o menos aire. */
/* Sin hueco reservado arriba: la barra flota por encima y el vídeo pasa por
   detrás, que es lo que la hace de pantalla completa. */
.hero{position:relative;height:78vh;height:78svh;min-height:540px;
  overflow:hidden;background:#1A1815}
.hero img,.hero video{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}

/* ---------- EL RECORRIDO DE LA PORTADA ----------
   Con el motor puesto la portada deja de ser una pantalla y pasa a ser un
   recorrido: el vídeo avanza al bajar y encima se relevan tres mensajes.

   Todo esto cuelga de `html.scrolly`, que pone el guion solo si el motor llega
   a arrancar. Sin JavaScript, con menos movimiento pedido o con la red tacaña,
   nada de aquí aplica y queda la portada de una pantalla de siempre.

   El carril mide una pantalla por mensaje más una de cortesía, para que el
   último respire antes de que el hero se despegue. El hero se pega arriba del
   todo, sin el hueco de la barra: en esta portada el vídeo pasa por detrás de
   la barra a propósito, que es lo que la hace de pantalla completa. */
.scrolly .carril{position:relative;
  height:calc(var(--mensajes,3) * 110svh + 100svh)}
.scrolly .carril > .hero{position:sticky;top:0;
  height:100svh;min-height:0;margin-top:0}

/* El vídeo del recorrido ya viene nivelado plano a plano, así que el filtro no
   está para arreglarle la luz sino para que el texto se lea encima: el montaje
   pasa de un lápiz sobre negro a un papel blanco a plena luz.

   Los dos números que deciden cuánto pesa el negro del primer impacto están
   fuera, en variables, porque son lo que se calibró contra la revisión de
   Robert del 21-ago, que veía la web demasiado oscura de entrada:

     --hero-luz   cuánta luz conserva el vídeo (1 = sin filtro)
     --hero-velo  cuánto pesa el velo que va encima (1 = el de siempre, 0 = nada)

   Venían de .66 y 1, y quedan en .95 y .5: el vídeo entra casi con su luz y el
   velo se queda en la mitad, lo justo para que el titular se lea encima. Se
   eligieron comparándolos en vivo sobre la portada de verdad, y con ellos cae
   la sombra que había debajo del hero (ver `--arranca` arriba). */
.scrolly{--hero-luz:.95;--hero-velo:.5}
.scrolly .hero-video{filter:saturate(.82) contrast(1.02) brightness(var(--hero-luz,.95))}
.scrolly .hero .scrim{
  background:
    radial-gradient(78% 58% at 50% 46%,
      rgba(12,11,9,calc(.72 * var(--hero-velo,.5))) 0%,
      rgba(12,11,9,calc(.44 * var(--hero-velo,.5))) 54%,
      rgba(12,11,9,calc(.16 * var(--hero-velo,.5))) 84%),
    linear-gradient(to top,
      rgba(12,11,9,calc(.86 * var(--hero-velo,.5))) 0%,
      rgba(12,11,9,calc(.42 * var(--hero-velo,.5))) 26%,transparent 74%)}

/* ---------- LOS MENSAJES QUE SE RELEVAN ----------
   Todos ocupan el mismo sitio, uno encima de otro, y el guion los va
   encendiendo por turno. Nacen apagados menos el primero, que es el que se ve
   sin motor. La visibilidad se apaga con retardo para no cortar el desvanecido
   a media transición, y se enciende sin retardo para que el que entra esté ahí
   desde el primer cuadro. */
.mensajes{display:grid}
.mensaje{grid-area:1/1;opacity:0;visibility:hidden;
  transition:visibility 0s linear .45s}
.mensaje[data-viva]{opacity:1;visibility:visible;transition:visibility 0s}
/* El titular del recorrido usa la tipografía del sitio, como todos los demás.
   Iba en Archivo, aparte del resto, con el argumento de que una sans compacta
   aguanta mejor encima de un vídeo en movimiento. El argumento era bueno y el
   resultado no: la portada abría con una letra que no vuelve a salir en
   ninguna otra pantalla, así que lo primero que se veía del sitio no era del
   sitio. La legibilidad sobre el vídeo la resuelve el velo, que para eso está,
   y no una segunda familia.

   El interlineado sí se queda por debajo del global (1.06 contra 1.1): son dos
   líneas que tienen que leerse como un bloque, y ahí no hay párrafo debajo con
   el que cuadrar. */
.mensaje .t{margin:0 auto;max-width:42ch;text-wrap:balance;
  font-family:var(--f-title);
  font-weight:var(--t-w);letter-spacing:var(--t-ls);line-height:1.06;
  font-size:calc(clamp(30px,4.2vw,52px) * var(--t-scale))}
/* El rótulo dice de qué sección es lo que se anuncia: es lo que convierte el
   relevo en un índice y no en un carrusel de frases sueltas. */
.mensaje .eyebrow{color:var(--acento);margin:0 0 14px}
/* Solo el primero lleva botones: los demás son mensajes de paso, no
   invitaciones, y repetir el botón tres veces lo gasta. */

/* El vídeo entra por encima del póster cuando ya tiene fotogramas que enseñar:
   sin esto se ve un parpadeo entre la imagen fija y el primer cuadro. */
.hero-video{opacity:0;transition:opacity .7s var(--ease)}
.hero-video.listo{opacity:1}
/* El velo tenía todo el peso abajo, que es donde estaba el texto. Con el texto
   en el centro hace falta oscurecer también ahí, o el titular se pelea con lo
   que pase por el vídeo. Dos capas: una mancha suave en el centro y la base de
   siempre, más floja, para que la franja de licencias siga cosiendo. */
.hero .scrim{position:absolute;inset:0;
  background:
    radial-gradient(115% 85% at 50% 48%,rgba(12,11,9,.60) 0%,rgba(12,11,9,.34) 55%,rgba(12,11,9,.26) 100%),
    linear-gradient(to top,rgba(12,11,9,.72) 0%,rgba(12,11,9,.20) 46%,rgba(12,11,9,.16) 100%)}
/* El bloque va centrado dentro del hero, en los dos ejes: el vídeo queda de
   marco por igual arriba y abajo, y ya no hay medio hero vacío por encima del
   texto como cuando iba apoyado en el pie. */
.hero .inner{position:absolute;inset:0;display:grid;align-content:center;
  color:#fff;text-align:center}
/* `balance` reparte las palabras entre las líneas en vez de dejar la última
   coja. Con este ancho la frase cae en DOS líneas parejas, y sigue haciéndolo
   en español, que es tres caracteres más largo: por eso el corte no va a mano
   con un salto de línea, que solo valdría para un idioma. */
/* Misma letra que el resto del sitio, y no una propia: ver el porqué en
   `.mensaje .t`, unas líneas arriba. Del ajuste anterior solo sobrevive el
   interlineado, que baja de 1.1 a 1.06 para que las dos líneas se lean como un
   bloque y no como dos frases. */
.hero h1{margin:0 auto;max-width:42ch;text-wrap:balance;
  font-family:var(--f-title);
  font-weight:var(--t-w);letter-spacing:var(--t-ls);line-height:1.06;
  font-size:calc(clamp(30px,4.2vw,52px) * var(--t-scale))}
/* El aire de debajo es mayor que el de arriba a propósito: el titular y su
   frase son una misma cosa, y los botones son otra. */
.hero .sub{margin:30px auto 40px;font-size:18px;color:rgba(255,255,255,.88);max-width:58ch}
.hero .cta{display:flex;gap:12px;flex-wrap:wrap;justify-content:center}
/* En tableta la frase sigue cayendo en DOS líneas: hay ancho de sobra, solo
   había que bajarle el cuerpo. */
@media (max-width:900px){
  .hero h1,.mensaje .t{max-width:42ch;font-size:calc(clamp(28px,4.4vw,38px) * var(--t-scale))}
  .hero .sub{max-width:46ch;margin-bottom:32px}
}
/* En el teléfono son TRES, y no es una decisión de gusto: en 390px de pantalla
   quedan 346 útiles, y meter los 76 caracteres de la frase en dos líneas pide
   letra de 18px, que ya no se lee como titular sino como párrafo. Tres líneas
   a 26px es lo más cerca que se puede estar de dos sin perder el titular. Se
   quita el tope de caracteres para que use todo el ancho y `balance` las deja
   parejas en vez de dejar la última coja. */
@media (max-width:640px){
  .hero h1,.mensaje .t{max-width:none;font-size:calc(clamp(24px,6.4vw,30px) * var(--t-scale))}
  .hero .sub{font-size:16.5px;max-width:38ch}
}
.hero .btn{border-color:#fff;background:#fff;color:#14120F}
.hero .btn.ghost{background:transparent;color:#fff;border-color:rgba(255,255,255,.55)}
@media (max-width:640px){.hero{height:76vh;height:76svh;min-height:460px}}

/* ---------- CREDENCIALES Y FICHAS DE DATO ---------- */
/* Mismo componente para la franja de licencias del hero y para la ficha
   técnica de la página de proyecto: tarjetas sueltas, sin líneas divisorias. */
.creds,.facts{background:var(--bg)}
.creds .wrap,.facts .wrap{display:grid;grid-template-columns:repeat(4,1fr);gap:18px;
  padding-top:38px;padding-bottom:38px}
.creds .item,.facts .item,.outcome .item,.sx-datos .item{background:var(--sup);border:1px solid var(--line);border-radius:var(--radio-pieza);
  padding:22px 22px 20px;transition:border-color .35s ease,box-shadow .35s ease}
.creds .item:hover,.facts .item:hover,.outcome .item:hover,.sx-datos .item:hover{border-color:var(--borde-vivo);box-shadow:0 12px 30px var(--sombra-suave)}
.creds .k,.facts .k,.outcome .k,.sx-datos .k{font-size:11px;letter-spacing:.16em;text-transform:uppercase;color:var(--ink-soft)}
/* EL DATO VA EN UNA SOLA LÍNEA, SIEMPRE (25-ago). Partido en dos se lee como
   una frase y deja de ser un dato, y encima descuadra las cuatro tarjetas
   entre sí porque no todas parten igual. Tres cosas lo sostienen:

     · `nowrap`, que es la regla dura.
     · el tamaño baja con la ventana (15 a 18px) en vez de ser fijo: en la
       tarjeta estrecha del móvil un 18px fijo no cabe ni con textos cortos.
     · el ancho. El cuño de la esquina obliga a un hueco a la derecha, pero ese
       hueco solo lo necesita el RÓTULO, que va a su altura; el dato pasa por
       debajo y usa la tarjeta entera. Son 40px más de sitio.

   Con esto entra todo lo que hay hoy. Lo que NO entra no se arregla aquí: se
   acorta el texto, que para eso es un dato y no una frase. */
.creds .v,.facts .v,.outcome .v,.sx-datos .v{font-size:clamp(15px,1.35vw,18px);
  font-weight:600;letter-spacing:-.015em;margin-top:9px;line-height:1.3;
  white-space:nowrap}

/* ---------- EL SELLO DE PERMISO (solo en las credenciales de la portada) ----
   Las cuatro tarjetas de después del vídeo eran papel sobre papel: sobre el
   tramo claro no pesaban nada, y son la primera prueba que da la web (la
   licencia, la seguridad, los años y la jurisdicción). Elegido el 23-ago
   comparando seis maneras de hacerlas suyas, y dentro de esa, cuatro grados
   de subida del texto.

   Es un CUÑO: aro de trazo discontinuo con la K dentro, arriba a la derecha,
   que es el gesto del oficio (lo que sale de la oficina de permisos viene
   sellado).

   VA EN LAS DOS TIRAS QUE SIGUEN AL HERO (25-ago), y no solo en la portada: la
   de credenciales (`.creds`) y la ficha técnica de la página de obra
   (`.facts`). Son la misma pieza en el mismo sitio, y con dos acabados
   distintos la ficha de obra se leía como una página de otra web. La ficha de
   obra también tiene qué sellar: el rol, el tamaño, el municipio y la
   jurisdicción son exactamente lo que va sellado en un expediente.

   Sigue SIN ir en `.outcome` (el cierre de la página de obra) ni en
   `.sx-datos` (servicios), que comparten estilo de tarjeta: son tiras
   SEGUNDAS dentro de la misma página, y dos juegos de cuños seguidos se
   leerían como papel pintado. Una tira sellada por página, la de arriba.

   LA K NO ES UNA IMAGEN, ES UN RECORTE: el PNG del logo hace de plantilla y el
   color lo pone el token de debajo. Es lo que permite que salga en bronce
   sobre papel y en bronce claro sobre negro sin dos archivos ni filtros de
   inversión, igual que el resto de los logos de la web. Y va en pseudos, así
   que el marcado no se toca: la web en español no se entera.

   El texto sube con ella: el rótulo deja de ser texto secundario y pasa al
   color de la marca (el mismo que pinta el cuño) y el dato gana cuerpo. La
   tarjeta pasa de tener dos renglones parecidos a tener uno que titula y otro
   que responde. */
/* LA TARJETA VA A CONTRATINTA. Es el mismo recurso con el que la web remata
   abajo (el contacto se aclaró el 23-ago pero el pie sigue en negro), así que
   la portada abre y cierra con el mismo gesto, y sobre el tramo claro es lo
   que de verdad las despega del fondo.

   Va en tinta EN LAS DOS PIELES, y no es un descuido: `--tinta-inv` es negro en
   las dos, igual que en el pie. Lo que cambia con la piel es lo de alrededor,
   no la tarjeta. */
.creds .item,.facts .item{position:relative;
  background:var(--tinta-inv);border-color:transparent}
/* Solo el rótulo esquiva el cuño: está a su misma altura. El dato va debajo y
   no lo necesita. */
.creds .k,.facts .k{padding-right:52px}
/* Sobre tinta la sombra no dice nada y el filete vivo es un gris que ensucia:
   al pasar por encima responde el bronce, que es lo único que se ve ahí. */
.creds .item:hover,.facts .item:hover{border-color:var(--acento-inv-tenue);box-shadow:none}
/* El aro. Discontinuo y tenue: un aro macizo se lee como un botón. */
.creds .item::after,.facts .item::after{content:"";position:absolute;right:12px;top:12px;
  width:44px;height:44px;border-radius:50%;
  border:1.5px dashed var(--acento-inv-tenue);pointer-events:none}
/* La K dentro del aro */
.creds .item::before,.facts .item::before{content:"";position:absolute;right:24px;top:24px;
  width:20px;height:22px;opacity:.85;pointer-events:none;
  -webkit-mask:url("LOGO-k.png") no-repeat center/contain;
  mask:url("LOGO-k.png") no-repeat center/contain;
  background:var(--acento-inv)}
.creds .k,.facts .k{color:var(--acento-inv)}
/* El color es el mismo en las dos. El CUERPO no: los datos de la portada son
   cortos ("CBC 1262672") y caben a 20px fijos, pero los de la ficha de obra
   llegan a treinta caracteres ("Representación del propietario") y van a una
   línea, así que se quedan con el tamaño elástico de la regla de arriba, que
   es justo lo que se puso para que quepan. */
.creds .v,.facts .v{color:var(--sobre-inv)}
.creds .v{font-size:20px}
/* En el teléfono la tarjeta va a una columna y el dato ocupa todo el ancho: el
   cuño se queda donde está, pero el texto necesita el hueco reservado igual. */
@media (max-width:480px){
  .creds .item,.facts .item{padding-right:60px}
}

/* RED PARA UNA FICHA QUE SE QUEDE EN DOS DATOS. Las seis obras van hoy a
   cuatro tarjetas, que es como tiene que ser; si alguna se quedara en dos, en
   la rejilla de cuatro se pegaría a la izquierda con media tira vacía, y con
   la tarjeta en tinta ese hueco canta el doble. Así las dos se colocan en las
   columnas de enmedio: mantienen el ancho de columna del resto de la web y la
   tira queda centrada.

   Va con `:has()` para no tocar el marcado (y con él, las páginas en español,
   que las escribe el generador). Un navegador que no lo entienda las deja
   donde estaban: no se rompe nada, solo no se centran. Y solo por encima de
   900px, que es donde la rejilla tiene las cuatro columnas. */
@media (min-width:901px){
  .facts .wrap:has(.item:nth-child(2):last-child) .item:first-child{grid-column:2}
}
@media (max-width:900px){.creds .wrap,.facts .wrap{grid-template-columns:repeat(2,1fr);gap:14px}}
/* La columna única entra antes que en el resto de la web (620 y no 480): con
   dos tarjetas por fila, por debajo de esos 620 la tarjeta se queda en 200px y
   el dato de una línea ya no cabe ni en su tamaño más pequeño. */
@media (max-width:620px){.creds .wrap,.facts .wrap{grid-template-columns:1fr;
  padding-top:28px;padding-bottom:28px}}

/* ---------- CIFRAS ---------- */
/* Cuatro números grandes y sin caja. La banda de credenciales de arriba ya va
   en tarjetas, y dos rejillas de recuadros seguidas se leen como la misma cosa
   repetida: aquí manda el número, con una línea encima que hace de percha.
   Los dígitos van tabulares para que no baile el ancho mientras el contador
   sube, que es lo que hace que se vea barato. */
/* Las cifras dejan de ser cuatro columnas iguales sobre una foto: eso pesaba
   lo mismo en las cuatro, así que ninguna decía nada, y la foto con velo y
   parallax era la mitad de la sensación de plantilla de la portada.

   Ahora es una lista: un renglón por cifra, número enorme a la izquierda,
   rótulo y frase a la derecha, y un filete fino entre renglones. De menor a
   mayor, para que la que más pesa cierre el bloque. Sin foto detrás el color
   sale de los tokens y las dos pieles funcionan solas. */
/* El aire de esta sección lo pone su `.wrap`, no la sección, y por eso hay que
   quitarle el que `site.css` le da a TODO `<section>` (la trampa de siempre en
   este repo). Se estaban sumando los dos: 214px de hueco arriba en escritorio
   contra los 104px de las demás secciones, y 130px en el teléfono, donde eso
   es un tercio de pantalla en blanco antes de la primera cifra. */
.numeros{position:relative;isolation:isolate;padding:0}
.numeros .wrap{padding-top:clamp(58px,8vw,110px);padding-bottom:clamp(58px,8vw,110px)}

/* El rótulo y el pie comparten renglón: el pie ya no cuelga debajo de la lista
   rompiendo el cierre del último filete. */
.numeros-head{display:flex;align-items:baseline;justify-content:space-between;
  gap:24px;flex-wrap:wrap}
.numeros-pie{color:var(--ink-soft);margin:0;font-size:.95rem}

.numeros-lista{list-style:none;margin:clamp(26px,3.4vw,44px) 0 0;padding:0}
/* `align-items:end` asienta el rótulo sobre la línea de base del número, que es
   lo que hace que el renglón se lea como una sola pieza y no como dos columnas
   sueltas. */
.numeros-lista li{display:grid;grid-template-columns:minmax(0,.9fr) minmax(0,1.1fr);
  gap:clamp(18px,4vw,64px);align-items:end;border-top:1px solid var(--line);
  padding:clamp(16px,2.2vw,28px) 0 clamp(18px,2.4vw,32px)}
.numeros-lista li:last-child{border-bottom:1px solid var(--line)}

/* El número no baja de `line-height:1`: las ventanas del contador miden un
   renglón exacto y con menos altura cortarían los dígitos por arriba. */
.numeros .n{font-family:var(--f-title);font-size:clamp(54px,10.5vw,146px);line-height:1;
  letter-spacing:-.04em;margin:0;color:var(--ink);font-variant-numeric:tabular-nums;
  font-weight:var(--t-w);display:flex;align-items:baseline;gap:.03em}

/* Cada dígito es una ventana de un renglón con su tira de números detrás: lo
   que se mueve es la tira, no el texto, así que el número no parpadea al
   contar. El tamaño de letra no se toca aquí: lo hereda del número. */
.rueda{display:inline-block;overflow:hidden;height:1em;vertical-align:bottom}
.rueda > i{display:block;font-style:inherit;transform:translateY(0);
  transition:transform 1.25s cubic-bezier(.2,.75,.2,1);transition-delay:var(--d,0s)}
.rueda > i > b{display:block;height:1em;line-height:1;font-weight:inherit}
@media (prefers-reduced-motion:reduce){.rueda > i{transition:none}}

.numeros .mas{font-size:.34em;color:var(--ink-soft);letter-spacing:0;
  align-self:flex-start;margin-top:.12em}
.numeros .tx{padding-bottom:clamp(4px,.9vw,12px)}
.numeros .et{font-size:12px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--ink);margin:0}
.numeros .de{color:var(--ink-soft);margin:10px 0 0;max-width:32ch;
  font-size:clamp(15px,1.5vw,17.5px);line-height:1.5}

/* En estrecho el renglón se apila: número arriba, rótulo y frase debajo. Se
   mantiene el filete, que es lo que sigue dando la lista. */
@media (max-width:760px){
  .numeros-lista li{grid-template-columns:1fr;gap:12px;align-items:start}
  .numeros .n{font-size:clamp(58px,17vw,96px)}
  .numeros .tx{padding-bottom:0}
}

/* ---------- INTRO ---------- */
.intro-grid{display:grid;grid-template-columns:1fr 1.15fr;gap:64px;align-items:start}
@media (max-width:900px){.intro-grid{grid-template-columns:1fr;gap:26px}}
.quote{font-family:var(--f-title);font-size:calc(23px * var(--t-scale));line-height:1.4;
  letter-spacing:var(--t-ls);border-left:2px solid var(--ink);padding-left:24px;margin:34px 0 0;color:var(--ink)}

/* Foto dentro del bloque de quiénes somos: el titular deja de estar solo en
   media pantalla vacía y la columna de la izquierda pesa lo mismo que la derecha. */
.intro-grid:has(.intro-media){align-items:stretch}
.intro-grid:has(.intro-media) > div:first-child{display:flex;flex-direction:column}
.intro-media{margin:30px 0 0;overflow:hidden;border-radius:var(--radio-pieza);flex:1;min-height:330px}
.intro-media img{width:100%;height:100%;object-fit:cover;display:block}
@media (max-width:900px){.intro-grid:has(.intro-media){align-items:start}
  .intro-media{margin-top:22px;flex:none;min-height:0;aspect-ratio:16/10}}

/* ---------- BANDA DE TEXTO E IMAGEN ---------- */
/* Corta el ritmo de secciones a página completa: media parte de obra y media de
   texto, cambiando de lado cada vez. En móvil la foto siempre va debajo.
   La banda ENTERA vive dentro de la rejilla del sitio (no va a sangre): la foto
   arranca a plomo con "Selected work" y con el resto de secciones, en vez de
   salirse por el costado izquierdo y parecer torcida. Por eso aquí basta el
   `.wrap` de siempre, sin cálculos de riel. */
/* Sin fondo propio: la banda va transparente sobre el lienzo. Era el fondo que
   se colaba y partía la página justo debajo de las cifras. */
.split{max-width:var(--maxw);margin:0 auto;padding:clamp(56px,6vw,88px) var(--pad);
  display:grid;grid-template-columns:1fr 1fr;gap:clamp(32px,4.5vw,72px);
  align-items:center}
.split .ph{margin:0;position:relative;overflow:hidden;aspect-ratio:4/5;
  border-radius:var(--radio-pieza);background:var(--bg-alt)}
.split .ph img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block}
/* Una foto DE PIE dentro de un marco apaisado se recorta por arriba y por
   abajo, y centrada se queda con la franja de en medio. En la banda del método
   eso dejaba fuera el casco y el chaleco de la marca, que es lo que hace que la
   foto sea de ellos y no de un banco de imágenes: el encuadre sube. */
.split .ph img.enc-alto{object-position:50% 26%}

/* LA FOTO DEL MÉTODO ES MENOS ALTA QUE LAS DEMÁS, y es lo que hace que esa
   banda quepa en una pantalla: el marco de 4/5 la dejaba en 730px de alto y con
   ellos la sección se pasaba de largo. Va solo aquí y no en `.split`, que es el
   marco de todas las bandas de la web. */
.split.flip.contramano .ph{aspect-ratio:4/4.2}
.split .tx{display:flex;flex-direction:column;justify-content:center}
.split .tx h2{margin:0;max-width:19ch}
.split .tx .lead{max-width:44ch;margin-bottom:0}
/* Lo destacado de cualquier párrafo va a tinta plena, no a más tamaño: el
   cuerpo es gris suave y la negrita sube a negro, que es lo que hace que la
   frase salte al ojear sin que el bloque parezca un anuncio. */
.lead strong,.bul strong{font-weight:600;color:var(--ink)}
/* EL ENLACE DE PASO DE LAS DOS BANDAS DE FOTO (24-ago)
   Misma cápsula que la de los servicios, pero rellena de TINTA en vez de
   bronce: el bronce marca "aquí se cuenta un servicio", y estas dos llevan a la
   ficha de permisos y al contacto. Era un subrayado de 1px a 14px, que al lado
   de una foto a pantalla completa no se leía como algo pulsable.

   El relleno es `--ink` sobre `--bg`, así que SIGUE LA PIEL SOLA: negro sobre
   el papel y blanco cuando el bloque cruza al oscuro, sin escribir el color a
   mano en ningún sitio. Es lo mismo que hace `.btn` desde el 20-ago.

   El hover se aclara con `color-mix`, no con `opacity`: la opacidad es del
   revelado de entrada y, escrita aquí, gana por especificidad y deja el enlace
   a medio aparecer. */
.split .more{align-self:flex-start;margin-top:28px;
  display:inline-flex;align-items:center;justify-content:center;gap:9px;
  font-size:14px;font-weight:500;text-decoration:none;font-family:var(--f-body);
  background:var(--ink);border:1px solid var(--ink);color:var(--bg);
  border-radius:999px;padding:13px 22px;min-height:46px;box-sizing:border-box;
  transition:background .3s ease,border-color .3s ease}
.split .more::after{content:"\2192";display:inline-block;
  transition:transform .35s var(--ease)}
.split .more:hover{background:color-mix(in srgb,var(--ink) 84%,var(--bg));
  border-color:color-mix(in srgb,var(--ink) 84%,var(--bg))}
.split .more:hover::after{transform:translateX(4px)}
.split.flip .ph{order:2}
@media (max-width:900px){.split{grid-template-columns:1fr;gap:30px;
    padding:clamp(52px,9vw,72px) var(--pad)}
  /* En una columna la foto va SIEMPRE debajo del texto: primero se lee, luego
     se ve. Da igual de qué lado caiga la imagen en pantalla grande. */
  .split .tx{order:1}
  .split .ph,.split.flip .ph{order:2}
  .split .ph{aspect-ratio:16/10}
  .split .tx h2{max-width:none}.split .tx .lead{max-width:none}}
@media (max-width:520px){.split .ph{aspect-ratio:4/3}}

/* ============================================================
   LA SECUENCIA · el titular se abre hasta convertirse en la foto

   La única sección de la web que se RECORRE en vez de mirarse. Cinco pantallas
   de gesto, en este orden: el titular aparece pequeño con la foto por dentro de
   las letras, crece hasta llenar la pantalla, la imagen releva a las letras
   ocupando el hueco entero, se sostiene mientras el texto de apoyo pasa por
   encima, y al final la foto vuelve a encogerse a su recuadro.

   Elegida el 21-ago comparando siete recorridos en `muestras-recorrido.html`,
   que ya no está: las muestras se borran al cerrar su tema y viven en el
   historial de git, en el commit del 21-ago.
   El diagnóstico de partida no era falta de animación: era que todo viajaba en
   la misma dirección y a la misma velocidad, así que el ojo veía seis veces el
   mismo rectángulo por bien que cambiara el color al bajar. Esto rompe eso una
   vez, en un solo sitio. Una segunda sección así, y sería una feria.

   SIN GUION DE POR MEDIO: lo mueve el navegador con `animation-timeline`. Quien
   no lo tenga, o pida menos movimiento, ve la banda de foto y texto de siempre,
   que es el respaldo previsto y no una versión rota. Por eso todo cuelga del
   `@supports`, y por eso el alto extra vive dentro y no en la regla normal.

   TRES COSAS QUE COSTARON UNA SESIÓN Y CONVIENE NO VOLVER A PAGAR:

   1 · Una pieza pegada con `sticky` nunca sale de la pantalla, así que su
       propio recorrido de scroll no avanza: la animación se queda clavada en el
       primer cuadro y parece que el navegador no la soporta. Hay que engancharla
       al recorrido del CONTENEDOR, con `view-timeline-name` en la sección y
       `timeline-scope` en el `body` para que los hijos lo vean.

   2 · El titular crece con `font-size` y NUNCA con `scale`. Un `transform` le
       crea su propio marco de referencia y el fondo deja de estar anclado a la
       pantalla; y el anclaje es justo lo que hace invisible el relevo, porque el
       trozo de foto que se ve por dentro de cada letra es exactamente el que
       estará ahí cuando se abra la foto entera.

   3 · El titular va corto ESCRITO EN EL MARCADO. Ver el porqué entero en el
       comentario de la sección en `index.html`.
   ============================================================ */
body{timeline-scope:--permisos}

@supports (animation-timeline: view()){
  @media (prefers-reduced-motion:no-preference){

    /* El alto es lo que DURA el gesto. Cinco pantallas: menos y el relevo de las
       letras a la foto se atropella, más y se hace larga la espera. */
    .secuencia{display:block;max-width:none;padding:0;min-height:500svh;
      view-timeline-name:--permisos}

    /* La foto se pega a la pantalla y se abre desde un recuadro central. La
       vuelta al recuadro del final es lo que la devuelve a la página. */
    .secuencia .ph{position:sticky;top:0;height:100svh;aspect-ratio:auto;
      border-radius:0;margin:0;
      animation:sec-foto linear both;animation-timeline:--permisos;
      animation-range:cover 0% cover 100%}
    /* El encuadre va centrado: en la foto del equipo lo que cuenta (la mesa con
       los planos y la gente alrededor) está en el medio, y bajarlo al 66%
       cortaba cabezas por arriba. El valor tiene que ser EL MISMO que el del
       fondo del titular, más abajo, o el relevo de las letras a la foto pega un
       salto. */
    .secuencia .ph img{height:100%;top:0;object-position:50% 50%}
    /* El velo entra con la foto, no antes: mientras la foto solo se ve por
       dentro de las letras, oscurecerla sería apagar el propio titular. */
    /* EL VELO ES MÁS DENSO EN EL CENTRO, que es exactamente donde cae el texto
       de apoyo. El de partida se aclaraba justo ahí (bajaba a .18 en mitad de la
       pantalla) porque venía de una banda donde el texto iba al pie; con el
       texto centrado eso deja la entradilla sobre la parte más iluminada de la
       foto. La mancha central es la que hace el trabajo y la vertical solo cose
       los bordes. */
    .secuencia .ph::after{content:"";position:absolute;inset:0;
      background:
        radial-gradient(125% 92% at 50% 50%,rgba(7,6,5,.62) 0%,rgba(7,6,5,.46) 52%,rgba(7,6,5,.30) 100%),
        linear-gradient(180deg,rgba(7,6,5,.46),rgba(7,6,5,.22) 45%,rgba(7,6,5,.56));
      animation:sec-velo linear both;animation-timeline:--permisos;
      animation-range:cover 0% cover 100%}

    /* El texto se monta ENCIMA de la foto ocupando su mismo hueco: el margen
       negativo de una pantalla es lo que los superpone sin sacar a ninguno de
       los dos del flujo. */
    .secuencia .tx{position:sticky;top:0;height:100svh;
      margin:-100svh auto 0;max-width:var(--maxw);width:100%;padding:0 var(--pad);
      justify-content:center;align-items:center;text-align:center;z-index:2;
      color:#F4F1EC}

    /* El titular ocupa la pantalla entera por su cuenta, fuera del flujo, para
       poder crecer sin empujar al texto de apoyo que viene después.

       EL SELECTOR VA LARGO A PROPÓSITO. Con `.secuencia h2` a secas, el
       `max-width:19ch` de `.split .tx h2` gana por especificidad y le deja al
       titular una caja estrecha pegada al lado izquierdo: al estar `absolute`
       con `inset:0`, el ancho recortado no se reparte, se descuelga del borde
       izquierdo y la frase se ve corrida hacia allí. Con la frase de dieciséis
       letras que había antes casi no se notaba; con una larga, se va media
       pantalla. En el teléfono no pasaba porque ahí `.split .tx h2` ya lleva
       `max-width:none`. */
    .split.secuencia .tx h2{position:absolute;inset:0;margin:0;max-width:none;
      display:flex;align-items:center;justify-content:center;
      padding:0;line-height:1;pointer-events:none;white-space:nowrap;
      /* MISMO ENCUADRE QUE LA FOTO DE ABAJO, y tiene que serlo: el relevo de las
         letras a la imagen solo es invisible si el trozo que se ve por dentro de
         cada letra es exactamente el que estará ahí al abrirse la foto entera.
         Si aquí se centra y abajo se baja al 66%, en el relevo la imagen pega un
         salto. Los dos van anclados a la PANTALLA, por eso `fixed`. */
      background:url("obras/todo-integrado.webp") 50% 50% / cover fixed no-repeat;
      -webkit-background-clip:text;background-clip:text;color:transparent;
      animation:sec-letra linear both;animation-timeline:--permisos;
      animation-range:cover 0% cover 100%}

    .secuencia .eyebrow,.secuencia .lead,.secuencia .more{
      animation:sec-apoyo linear both;animation-timeline:--permisos;
      animation-range:cover 0% cover 100%}
    /* Encima de una foto no vale el cuerpo de una entradilla normal: sube de
       tamaño, la tinta va plena y lleva un filete de sombra ancha y floja, que
       no se ve como sombra pero despega la letra de lo que pase por detrás. */
    .secuencia .lead{max-width:44ch;color:#F7F4EF;
      font-size:clamp(17px,1.45vw,21px);line-height:1.55;
      text-shadow:0 1px 26px rgba(7,6,5,.72),0 1px 3px rgba(7,6,5,.5)}
    .secuencia .lead strong{color:#FFF}
    /* Encima de la foto la tinta de la piel no vale: el bloque va a 0.18, que
       es papel, y una cápsula negra sobre una foto oscura desaparece. Aquí el
       relleno se escribe a mano en blanco, que es lo mismo que ya hace el hero
       con sus dos botones. La sombra ancha y floja no se ve como sombra: la
       despega de lo que pase por detrás. */
    .secuencia .more{align-self:center;
      background:#F4F1EC;border-color:#F4F1EC;color:#14120F;
      text-shadow:none;box-shadow:0 2px 26px rgba(7,6,5,.42)}
    .secuencia .more:hover{background:#FFF;border-color:#FFF}
    .secuencia .eyebrow{color:#E7C79A;text-shadow:0 1px 18px rgba(7,6,5,.7)}

    /* EL TOPE LO MIDE EL GUION, y hace falta: el titular va en una línea sin
       partir, así que cuánto puede crecer depende de LO LARGO QUE SEA, y eso
       cambia con el idioma. "We close it." son doce caracteres y "Lo cerramos
       nosotros." son veintiuno: con un tope escrito a ojo en `vw`, el español se
       salía de la pantalla por los dos lados. El guion mide el texto y escribe
       en `--sec-tope` el tamaño exacto al que deja de caber; si no llega a
       correr, manda el valor de reserva, que es el conservador. */
    @keyframes sec-letra{
      0%  {font-size:clamp(30px,5.5vw,64px);opacity:0}
      7%  {opacity:1}
      54% {font-size:min(15vw,300px,var(--sec-tope,300px) * .82);opacity:1}
      66% {font-size:min(23vw,460px,var(--sec-tope,300px));opacity:0}
      100%{font-size:min(23vw,460px,var(--sec-tope,300px));opacity:0}
    }
    /* LA FOTO ESPERA A QUE LA LETRA HAYA CRECIDO. Antes empezaba a abrirse en el
       44%, cuando el titular iba por dos tercios de su tamaño, y el crecimiento
       de la frase se perdía debajo de la imagen abriéndose. Ahora la letra tiene
       hasta el 54% para crecer sola y la foto arranca detrás, en el 56%. */
    @keyframes sec-foto{
      0%,56%  {clip-path:inset(50% 50% 50% 50% round 6px)}
      72%,86% {clip-path:inset(0% 0% 0% 0% round 0px)}
      100%    {clip-path:inset(30% 27% 30% 27% round 6px)}
    }
    /* EL VELO VA CON EL TEXTO, NO CON LA FOTO. Estaba puesto al máximo desde
       que la imagen terminaba de abrirse, así que el único momento en que la
       foto se ve entera y sin nada delante era también el momento en que estaba
       más apagada: se abría a pantalla completa para no apreciarse.

       Ahora hay un tramo de foto LIMPIA (del 72 al 80), que es donde se mira, y
       el velo sube justo por delante del texto de apoyo, que entra en el 76. Y
       vuelve a bajar cuando el texto se va. */
    @keyframes sec-velo{0%,72%{opacity:0}80%{opacity:.35}86%,92%{opacity:1}100%{opacity:.55}}
    @keyframes sec-apoyo{
      0%,76%  {opacity:0;transform:translateY(22px)}
      86%,92% {opacity:1;transform:none}
      100%    {opacity:0;transform:translateY(-22px)}
    }

    /* En el teléfono el gesto mejora en vez de empeorar: una foto a pantalla
       completa en 390px es más rotunda que en el escritorio. Solo cambian dos
       cosas. El tamaño de letra, porque el titular va en una línea sin partir y
       tiene que caber. Y el anclaje del fondo, que en iOS no funciona con
       `fixed`: se paga un salto pequeño en el relevo de las letras a la foto, y
       es mejor eso que un titular con la foto quieta mientras todo se mueve. */
    @media (max-width:900px){
      .split.secuencia .tx h2{background-attachment:scroll}
      @keyframes sec-letra{
        0%  {font-size:clamp(26px,9vw,48px);opacity:0}
        7%  {opacity:1}
        54% {font-size:min(26vw,300px,var(--sec-tope,180px) * .82);opacity:1}
        66% {font-size:min(38vw,460px,var(--sec-tope,180px));opacity:0}
        100%{font-size:min(38vw,460px,var(--sec-tope,180px));opacity:0}
      }
    }
  }
}




/* ============================================================
   EL PLANO DE FONDO · el dibujo que se traza entre el hero y la secuencia

   Lo pidio Robert el 23-ago: que al terminar el video de la portada se vaya
   viendo de fondo, a la derecha, el dibujo de la torre, y que se haya ido para
   cuando arranca la expansion de "All integrated". Elegido en
   `muestras-fondo-plano.html` comparando cinco intensidades, cuatro tamanos,
   cuatro formas de aparecer y tres maneras de resolver el cruce con el texto.

   POR QUE ES UN SVG Y NO LA FOTO. El 3.png del Drive es una imagen: no tiene
   lineas, tiene puntos, asi que no hay nada que se pueda recorrer con la punta.
   El dibujo se paso por un separador de lineas y un trazador (mkbitmap y
   potrace) y salieron 2.156 trazos de verdad. Eso es lo que permite que se
   dibuje trazo a trazo en vez de destaparse.

   EL TRUCO QUE LO HACE VIABLE. Animar dos mil trazos por separado tumba
   cualquier navegador. Lo que se anima son 120 TURNOS de dieciocho trazos cada
   uno, repartidos de abajo arriba, y cada turno mueve una sola variable
   heredada (`--dash`) que sus trazos usan como avance. 120 animaciones en vez
   de 2.000, y a efectos de lo que se ve es trazo a trazo.

   El reparto es toda la suavidad: los turnos arrancan repartidos por casi todo
   el recorrido (del 2 al 79) y cada uno dura once, asi que lo que sube por el
   dibujo es un frente estrecho de trazos saliendo. Con los turnos pisandose
   casi enteros, que fue el primer montaje, a mitad de camino ya se veia el
   dibujo entero.

   Y LA SALIDA SE BORRA, no se apaga: el avance de borrado va en NEGATIVO, y eso
   retira cada linea por el extremo contrario al que entro, como una goma
   siguiendo el trazo. Encima, cada turno se apaga con curva de frenada y el
   dibujo entero se desenfoca en el ultimo tramo, para que no termine en seco.

   El texto de este tramo se corre un poco a la izquierda (mas abajo) para que
   la letra no caiga encima del dibujo. Se probo estrechar la columna a la mitad
   y quedaba apretado: obligaba a recomponer las licencias en dos por dos y a
   bajar el tamano de las cifras.
   ============================================================ */

/* Los avances y las opacidades son variables registradas porque el navegador
   solo sabe interpolar lo que tiene tipo declarado. Y son DOS de cada cosa a
   proposito: si el que pinta y el que borra movieran la misma, el segundo (que
   se rellena hacia atras) dejaria el dibujo puesto desde el primer momento. */
@property --dash{syntax:'<number>';inherits:true;initial-value:1}
@property --dash-borra{syntax:'<number>';inherits:true;initial-value:0}
@property --op-entra{syntax:'<number>';inherits:false;initial-value:0}
@property --op-sale{syntax:'<number>';inherits:false;initial-value:1}

.pista-plano{position:relative}
/* Las secciones de dentro pierden su fondo igual que las que cuelgan del
   lienzo: en este tramo el fondo lo pone el lienzo y nadie mas. Y van por
   ENCIMA del dibujo, que si no el dibujo les pasaria por delante del texto. */
.pista-plano > :not(.plano){background:none;position:relative;z-index:1}

/* Pegado a la pantalla y sin ocupar sitio: el margen negativo de una pantalla
   es lo que deja pasar por delante las licencias y las cifras. Los bordes se
   desvanecen porque el dibujo mide mas que la pantalla y el recorte lo cortaba
   en seco, y un filo recto delata que hay una imagen puesta encima. */
.plano{position:sticky;top:0;height:100svh;margin-bottom:-100svh;z-index:0;
  display:flex;align-items:center;pointer-events:none;overflow:clip;
  -webkit-mask-image:linear-gradient(to bottom,rgba(0,0,0,0) 0,#000 13%,#000 87%,rgba(0,0,0,0) 100%);
  mask-image:linear-gradient(to bottom,rgba(0,0,0,0) 0,#000 13%,#000 87%,rgba(0,0,0,0) 100%)}
.plano-caja{position:relative;width:100%;display:flex;justify-content:flex-end}
.plano img.reserva,.plano .vec{height:126svh;width:auto;display:block;
  transform:translateX(12%)}
.plano img.reserva{opacity:.34}
/* SIN `filter`, y no es por el desenfoque en sí (23-ago). El dibujo se
   despedía difuminándose, con un `blur` de tres píxeles animado en el último
   tramo. El problema es que un filtro puesto en la regla base OBLIGA A
   RASTERIZAR el elemento aparte durante todo el recorrido, valga cero o valga
   tres, y aquí el elemento son 2.156 trazos que además están cambiando en cada
   cuadro: se pagaba el tramo entero para un remate de los últimos dos
   segundos. Y encima era casi invisible, porque a esa altura los trazos ya se
   están borrando con su propio gesto, que es lo que de verdad despide el
   dibujo. */
.plano .vec{display:none;color:var(--ink);opacity:.52}
.plano .vec svg{height:100%;width:auto;display:block;overflow:visible}
.plano .vec path{fill:none;stroke:currentColor;stroke-width:1.1;
  vector-effect:non-scaling-stroke;stroke-linecap:round;stroke-linejoin:round;
  stroke-dasharray:1;stroke-dashoffset:calc(var(--dash) + var(--dash-borra))}
/* Con el vector montado, la reserva se retira */
html.plano-vivo .plano img.reserva{display:none}
html.plano-vivo .plano .vec{display:block}

/* El texto se corre a la izquierda lo justo para no pisar el dibujo. Solo por
   encima de 1100px, que es donde el dibujo existe. */
@media (min-width:1101px){
  .pista-plano .creds .wrap,.pista-plano .numeros .wrap{padding-right:14%}
}

/* En pantalla estrecha las cifras ocupan el ancho entero y el dibujo quedaria
   debajo del texto, ensuciandolo. Fuera, y el guion ni lo pide. */
@media (max-width:1100px){
  .plano{display:none}
}

@supports (animation-timeline: view()){
  @media (prefers-reduced-motion:no-preference){
    /* EL RELOJ ES LA PISTA, no el lienzo: el lienzo llega hasta el pie. */
    .pista-plano{view-timeline-name:--plano;view-timeline-axis:block}

    /* El turno: traza y borra. El `animation-range` de cada uno lo escribe el
       guion, que es quien sabe cuantos turnos han salido. */
    .plano .vec g[data-turno]{--dash:1;--dash-borra:0;
      opacity:calc(var(--op-entra) * var(--op-sale));
      animation:plano-traza cubic-bezier(.33,0,.15,1) both,
                plano-borra cubic-bezier(.6,0,.35,1) both;
      animation-timeline:--plano,--plano}
    @keyframes plano-traza{
      from{--dash:1;--op-entra:0}
      55% {--op-entra:1}
      to  {--dash:0;--op-entra:1}
    }
    @keyframes plano-borra{
      from{--dash-borra:0;--op-sale:1}
      60% {--op-sale:.7}
      to  {--dash-borra:-1;--op-sale:0}
    }
  }
}

/* ============================================================
   LA APERTURA DE UNA FICHA DE SERVICIO · del trazo al render

   Es la pieza con la que abren las cuatro fichas, y cuenta el oficio en un
   solo gesto: el plano de la obra se dibuja solo, y cuando está entero da el
   relevo a la obra acabada, que se sostiene a pantalla completa mientras el
   titular pasa por encima. Elegida el 24-ago en `muestras-plano.html` contra
   la mesa que se levanta y las capas que se separan en axonometría.

   Reutiliza el motor de trazado del fondo de la portada, con una sola
   diferencia y es la que manda: aquí el dibujo NO SE BORRA. En la portada es
   un fondo por el que pasan las credenciales y las cifras, y tiene que
   despedirse; aquí es la apertura, y lo que hace es entregar el relevo.

   El reparto de los turnos lo escribe `site.js`, que es quien sabe cuántos
   hay. Aquí solo vive lo que no depende de eso.

   TRES DECISIONES QUE NO SON ADORNO:

   · El velo de la foto va en DIAGONAL y no plano. El texto se lee sobre la
     mitad izquierda, así que el papel tiene que estar donde está el texto y
     retirarse donde está el edificio. Un velo uniforme obliga a subirlo tanto
     que apaga la foto entera.
   · El reloj es la PISTA, no la escena. La escena está pegada y no se mueve,
     así que colgada de ella no habría recorrido que medir.
   · La foto entra CON ALGO DE ZOOM y lo pierde al llegar. Entrando plana se
     lee como un cambio de diapositiva; con el zoom que se calma se lee como
     que la cámara termina de posarse.
   ============================================================ */
.apertura{position:relative}
/* EL SUELO ES UN HERO NORMAL, y no es un detalle de compatibilidad: es lo que
   se ve en el teléfono, en un navegador sin recorridos de scroll y con el
   movimiento reducido. La foto de la obra a pantalla y el titular encima. La
   pista de cuatro pantallas y el dibujo trazándose SOLO existen donde hay con
   qué moverlos, y por eso viven los dos dentro del `@supports` de abajo: sin
   esto, un navegador sin soporte se comía cuatro pantallas de nada y con la
   foto apagada. */
.ap-escena{position:relative;min-height:74svh;overflow:clip;
  display:grid;place-items:center;
  padding:calc(var(--barra) + 40px) 0 56px}

/* La obra acabada. */
.ap-foto{position:absolute;inset:0;z-index:1}
.ap-foto img{width:100%;height:100%;object-fit:cover;display:block;
  background:var(--foto-vacia)}
/* EL VELO DE LA APERTURA (rehecho el 25-ago, con el del hero de ficha).
   Iba de lado: casi opaco a la izquierda y despejado a partir del 38%. El
   texto de este hero es tinta oscura, asi que necesita fondo claro debajo, y
   ahi habia dos agujeros:

   · En pantalla ancha el bloque de texto llega hasta cerca de la mitad, y en
     esa mitad el velo ya estaba al 62%: el final de las lineas caia sobre foto
     casi limpia. Ahora la parada fuerte se estira hasta el 42% y el desvanecido
     empieza despues, que es donde ya no hay letra.
   · Por debajo de 1100px el texto SE CENTRA (regla de abajo), o sea que caia
     justo donde el velo se habia ido del todo: 5,4 a 1 medido, tinta oscura
     sobre foto con detalle. Era el peor sitio de la web para leer, y es el
     tamaño con el que se ve desde un telefono.

   Escrito en tokens y no en blancos literales, como el resto: en `/oscuro` el
   fondo es negro y la tinta clara, y el velo se da la vuelta solo. */
.ap-foto::after{content:"";position:absolute;inset:0;
  background:linear-gradient(100deg,
    color-mix(in srgb,var(--bg) 96%,transparent) 0,
    color-mix(in srgb,var(--bg) 88%,transparent) 42%,
    color-mix(in srgb,var(--bg) 30%,transparent) 72%,
    transparent 100%)}

/* El dibujo. Nace apagado del todo: lo enciende el `@supports`. */
.ap-caja{display:none;position:absolute;inset:0;place-items:center end;
  padding-right:4vw;pointer-events:none;
  -webkit-mask-image:linear-gradient(to bottom,rgba(0,0,0,0) 0,#000 11%,#000 89%,rgba(0,0,0,0) 100%);
  mask-image:linear-gradient(to bottom,rgba(0,0,0,0) 0,#000 11%,#000 89%,rgba(0,0,0,0) 100%)}
.ap-caja img.reserva,.apertura .vec{height:112svh;width:auto;display:block}
.ap-caja img.reserva{opacity:.34}
.apertura .vec{display:none;color:var(--ink);opacity:.6}
.apertura .vec svg{height:100%;width:auto;display:block;overflow:visible}
.apertura .vec path{fill:none;stroke:currentColor;stroke-width:1.1;
  vector-effect:non-scaling-stroke;stroke-linecap:round;stroke-linejoin:round;
  stroke-dasharray:1;stroke-dashoffset:var(--dash)}
/* Con el vector montado, la reserva se retira */
html.plano-vivo .ap-caja img.reserva{display:none}
html.plano-vivo .apertura .vec{display:block}

.ap-tx{position:relative;z-index:2;justify-self:start;
  margin-left:6vw;max-width:560px;padding:0 var(--pad)}
.ap-tx h1{margin:0 0 16px}
/* A TINTA PLENA, no en el gris de los textos de apoyo del resto de la web:
   aqui cae sobre foto, y el gris era el primero en perderse. */
.ap-tx .lead{margin:0;max-width:46ch;color:var(--ink)}
/* EL ROTULO, CON FILETE DE ACENTO. Solo el del hero: `.eyebrow` es de toda la
   web y en el resto de secciones va suelto sobre fondo liso, donde no hace
   falta. Aqui cae sobre foto, asi que ademas sube a tinta como el resto de las
   letras de este hero. El filete es el bronce de la marca, que es lo unico de
   color que hay en el bloque. */
.ap-tx .eyebrow{display:flex;align-items:center;gap:11px;color:var(--ink)}
/* El filete va EN LINEA y no como borde izquierdo: de borde habria que sacarlo
   con un margen negativo para que el rotulo siguiera alineado con el titulo, y
   ese margen se sale de la pantalla en el telefono. Asi ocupa su sitio dentro
   del bloque y no descuadra nada. */
.ap-tx .eyebrow::before{content:"";flex:none;width:24px;height:2px;background:var(--acento)}
/* SIN SITIO PARA LA COLUMNA, EL TEXTO SE VA AL PIE (25-ago).
   Antes se quedaba centrado en mitad de la foto, que es donde peor se lee y
   donde el velo lateral ya no llegaba. Ahora hace lo mismo que el hero de la
   ficha de obra: se apoya abajo, con un velo vertical que sube desde el pie y
   deja la parte alta de la foto limpia. Misma curva que `.p-hero .scrim`, para
   que las dos familias de hero se lean como una sola cosa. */
@media (max-width:1100px){
  .ap-escena{place-items:end center;padding-bottom:44px}
  .ap-tx{margin-left:0;justify-self:stretch;max-width:none}
  .ap-foto::after{background:linear-gradient(to top,
    color-mix(in srgb,var(--bg) 94%,transparent) 0%,
    color-mix(in srgb,var(--bg) 80%,transparent) 38%,
    color-mix(in srgb,var(--bg) 28%,transparent) 68%,
    transparent 100%)}
}

/* LA APERTURA SIN DIBUJO. Las fichas de inspecciones y de representación del
   propietario todavía no tienen su pieza propia (van a muestra aparte), así que
   abren con la foto de obra sola. Es la misma apertura y el mismo aire, sin la
   pista de cuatro pantallas: sin dibujo que trazar, esas cuatro pantallas serían
   cuatro pantallas mirando una foto quieta. */
.apertura.sola .ap-caja{display:none}

@supports (animation-timeline: view()){
  @media (prefers-reduced-motion:no-preference){
    @media (min-width:1101px){
      /* Aquí SÍ: la pista de cuatro pantallas, y la escena pegada dentro. */
      .apertura:not(.sola){height:400svh;view-timeline-name:--apertura;view-timeline-axis:block}
      .apertura:not(.sola) .ap-escena{position:sticky;top:0;height:100svh;min-height:0;padding:0}
      .apertura:not(.sola) .ap-caja{display:grid}
      .apertura:not(.sola) .ap-foto{opacity:0}

      /* El turno: aquí solo traza, no borra. El `animation-range` de cada uno
         lo escribe el guion, que es quien sabe cuántos hay. */
      .apertura:not(.sola) .vec g[data-turno]{--dash:1;opacity:var(--op-entra);
        animation:plano-traza cubic-bezier(.33,0,.15,1) both;
        animation-timeline:--apertura}

      /* El relevo. La foto entra cuando al dibujo le queda poco, no cuando ha
         terminado: solapados, el ojo lee un relevo; en fila lee dos cosas. */
      .apertura:not(.sola) .ap-foto{animation:ap-foto-entra cubic-bezier(.22,.61,.36,1) both;
        animation-timeline:--apertura;animation-range:cover 58% cover 90%}
      @keyframes ap-foto-entra{
        from{opacity:0;transform:scale(1.1)}
        to  {opacity:1;transform:scale(1)}
      }
      .apertura:not(.sola) .vec{animation:ap-vec-sale linear both;
        animation-timeline:--apertura;animation-range:cover 60% cover 82%}
      @keyframes ap-vec-sale{ from{opacity:.6} to{opacity:0} }
    }
  }
}

/* ============================================================
   DOS VELOCIDADES · los gestos que no cuestan sitio

   La secuencia de los permisos es cara: pide cinco pantallas y solo puede
   haber una en toda la web. Estos dos no piden ni un píxel de más, porque no
   sostienen nada quieto: lo único que hacen es que dos piezas de la misma
   sección viajen a VELOCIDADES distintas mientras la página pasa por delante.

   Y esa es justamente la queja que arreglan. La web entraba bien pero se leía
   monótona, y no era por falta de animación: era que todo viajaba en la misma
   dirección y a la misma velocidad, así que el ojo veía el mismo rectángulo
   una y otra vez por bien que cambiara el color al bajar.

   Los dos van sin guion, con el recorrido de la propia sección
   (`animation-timeline: view()`), y por eso NO llevan opacidad: las piezas
   están puestas desde el principio y lo que cambia es a qué velocidad va cada
   una. No se leen como "entrar", se leen como que el bloque tiene vida propia.
   Quien no lo soporte, o pida menos movimiento, ve la sección quieta y entera.

   Van con `will-change` porque son de las pocas cosas de la web que se mueven
   durante todo el recorrido de una sección, no en un tramo corto.
   ============================================================ */
@supports (animation-timeline: view()){
  @media (prefers-reduced-motion:no-preference){

    /* ---- A CONTRAMANO · la banda del método ----
       La columna de texto adelanta a la página (sube más rápido) y la foto se
       retrasa (baja), así que se cruzan a media pantalla. Es el gesto que más
       lejos queda de "todo hacia abajo", y va aquí a propósito: es la otra
       banda de foto y texto de la portada, y con la de permisos convertida en
       secuencia, las dos dejan de hacer lo mismo.

       La foto además se abre desde una franja estrecha, que es lo que hace que
       el cruce tenga algo con lo que compararse. */
    .contramano .tx{animation:cruce-texto linear both;
      animation-timeline:view();animation-range:cover 0% cover 100%;
      will-change:transform}
    .contramano .ph{animation:cruce-franja linear both;
      animation-timeline:view();animation-range:entry 16% cover 46%}
    /* La imagen necesita sobrante por arriba y por abajo para poder viajar sin
       dejar ver el fondo por ningún lado. */
    .contramano .ph img{height:116%;top:-8%;
      animation:cruce-foto linear both;
      animation-timeline:view();animation-range:cover 0% cover 100%;
      will-change:transform}

    @keyframes cruce-texto{from{transform:translateY(64px)}to{transform:translateY(-64px)}}
    @keyframes cruce-foto{from{transform:translateY(-6%)}to{transform:translateY(6%)}}
    @keyframes cruce-franja{
      from{clip-path:inset(34% 0 34% 0)}
      to{clip-path:inset(0 0 0 0)}
    }

    /* ---- LA FOTO SE ABRE · quiénes somos ----
       Protagonista la foto: nace como una franja y se abre hasta su formato
       entero, con la imagen viajando despacio por dentro. El texto de al lado
       sigue entrando con el motor de siempre, y a otra velocidad: es lo que
       hace que la sección tenga dos ritmos en vez de uno.

       Aquí el recorrido se mide contra la propia foto y no contra la sección,
       porque la sección es alta y la foto solo ocupa una parte: enganchado a la
       sección, la foto habría terminado de abrirse antes de asomar. */
    .intro-media{overflow:hidden;
      animation:cruce-franja linear both;
      animation-timeline:view();animation-range:entry 12% cover 52%}
    .intro-media img{
      animation:cruce-foto linear both;
      animation-timeline:view();animation-range:cover 0% cover 100%;
      will-change:transform}
    /* Sobrante para el viaje, igual que en la banda de arriba. Va con
       `object-fit` porque esta foto sí llena su marco por altura. */
    .intro-media img{height:116%;object-fit:cover}
  }
}

/* ---------- TICKER DE CLIENTES ---------- */
/* ------------------------------------------------------------
   LA BANDA DA LA VUELTA ENTERA (21-ago)
   La banda de clientes no tenia entrada ni salida: estaba fuera del motor de
   revelado, asi que aparecia puesta y desaparecia puesta. Ahora da DOS vueltas
   completas sobre su eje horizontal al entrar, como una persiana que gira, con
   los logos girando con ella y sin dejar de correr. Al salir gira al reves.

   Lo que hace que el gesto se sienta grande NO son los grados: es EL VIAJE.
   La banda mide unos 150px de alto, y enganchado a ella el giro entero se
   desplegaba en 150px de scroll, o sea en un parpadeo. Ahora la banda tiene su
   propio recorrido de casi dos pantallas y se queda PEGADA mientras dura, que
   es la misma leccion de la persiana del equipo: el aire de antes va en el
   envoltorio, no en la pieza. Elegida en muestra contra la cinta que se
   levanta del fondo, el arco de carrusel y el tren con estela.

   Dos vueltas y no una: con el viaje largo, una sola vuelta se reparte tan
   despacio que deja de leerse como un giro y parece un cabeceo.

   Las capas son obligatorias y cada una hace UNA cosa:
     · `ticker-viaje`  reserva el recorrido y lleva el reloj de la seccion.
     · `ticker-escena` se queda pegada y pone la perspectiva. La perspectiva va
       AQUI y no en el viaje: el viaje mide dos pantallas y el punto de fuga se
       iria a esa distancia.
     · `ticker-mask`   recorta, pinta el desvanecido de los lados y es la que
       GIRA. Girando el marco, el desvanecido gira con la banda y se lee como
       una pieza solida, no como logos sueltos dando vueltas.
     · `ticker-track`  gira sola por tiempo, como siempre. Su animacion y la del
       giro estan en elementos distintos a proposito: metidas en el mismo, la
       segunda mata a la primera y la cinta se para.
   ------------------------------------------------------------ */
/* El aire en blanco de los dos lados de la banda de clientes. Solo es alto: el
   color lo pone el lienzo leyendo su `data-piel`, como en cualquier otro tramo.
   En el teléfono va más bajo, que ahí 140px de nada seguido es media pantalla. */
.aire-blanco{height:140px}
@media (max-width:760px){.aire-blanco{height:88px}}

.ticker{padding:0;overflow:clip}
/* LA BANDA LLANA (24-ago) · la de la página de About

   Allí la banda de clientes es un apoyo al final de la página, no un número:
   se queda con lo único que hace falta, los logos pasando.

   Se le quita el giro Y el recorrido de 185svh que lo sostenía, y las dos cosas
   van juntas: sin gesto que repartir, esas casi dos pantallas de scroll serían
   dos pantallas mirando una cinta correr, que es peor que no tener gesto. Con
   la escena sin `sticky` la banda vuelve a ocupar su alto y nada más.

   La pista sigue corriendo sola por tiempo (`ticker-scroll`), que es lo que se
   pidió, y sigue parándose al pasar el ratón por encima. */
.ticker.llana .ticker-viaje{height:auto}
.ticker.llana .ticker-escena{position:static;transform:none}
.ticker.llana .ticker-mask{animation:none}
.ticker-viaje{position:relative;height:185svh;view-timeline-name:--banda;
  view-timeline-axis:block}
/* UN SOLO `timeline-scope` para toda la web, y con TODOS los nombres dentro.
   Es una propiedad, no una lista que se acumule: una segunda declaracion sobre
   `html` mas abajo en el archivo no anade, SUSTITUYE, y el reloj declarado
   antes se queda sin ambito y su animacion congelada en el primer cuadro, sin
   dar ningun error. Al montar un reloj nuevo se anade aqui, no se declara otra
   vez. */
html{timeline-scope:--baraja,--banda}
.ticker-escena{position:sticky;top:50%;transform:translateY(-50%);
  padding:30px 0;perspective:760px;perspective-origin:50% 50%}
/* El rotulo iba a 11px con .22em de espaciado, y con cuarenta y cinco
   caracteres en mayusculas eso se descifra mas que se lee: sube a 13.5 y el
   espaciado se aprieta a .14em, que es de donde sale la lectura.

   Y el color pasa de `--ink-soft` a `--ink`, que sobre el fondo oscuro de la
   banda es practicamente blanco. Va con el token y no con un blanco literal a
   proposito: si manana la banda cambia de tono, el rotulo lo sigue en vez de
   quedarse en blanco sobre papel. */
.ticker .label{font-size:13.5px;letter-spacing:.14em;text-transform:uppercase;color:var(--ink);
  text-align:center;margin:0 0 34px;font-family:var(--f-body)}
.ticker-mask{overflow:hidden;padding:22px 0;transform-origin:50% 50%;
  -webkit-mask-image:linear-gradient(to right,transparent,#000 12%,#000 88%,transparent);
  mask-image:linear-gradient(to right,transparent,#000 12%,#000 88%,transparent)}
.ticker-track{display:flex;width:max-content;align-items:center;
  animation:ticker-scroll 42s linear infinite;will-change:transform}
.ticker-mask:hover .ticker-track{animation-play-state:paused}
/* Lo que se mueve sin parar, PARADO MIENTRAS NO SE VE. La marca la pone el
   guion con un observador: la banda de clientes, el paseo del muro de obras y
   el viaje del vídeo de portada seguían girando con la sección fuera de la
   pantalla, y cada una de esas animaciones es un cuadro que el compositor
   pinta sesenta veces por segundo para nadie. Al volver a entrar sigue por
   donde iba, porque `animation-play-state` no reinicia nada: no hay salto.
   No lleva `!important` a propósito: fuera de la pantalla no puede haber
   ratón encima, así que nunca compite con las reglas de `:hover`. */
.en-reposo{animation-play-state:paused}
@keyframes ticker-scroll{to{transform:translateX(-50%)}}
/* Sin `grayscale`: cada logo en su color, tambien en reposo. Lo que separa el
   logo que cruza el centro de los demas es la opacidad y el tamano, que se los
   da el guion.

   Y SIN `will-change`, que es lo que estaba pesando el scroll (21-ago). El
   guion clona la pista hasta llenar el ancho y luego la duplica entera para
   que el bucle cierre, asi que aqui no hay cuatro logos: hay SESENTA Y CUATRO.
   Con `will-change:transform,opacity` eso eran sesenta y cuatro capas de
   compositor permanentes, y el navegador tiene que componerlas todas en cada
   cuadro aunque no se muevan. La pista si la lleva, porque es UNA capa y se
   mueve siempre; los logos de dentro viajan con ella gratis. */
.ticker-track .item{display:inline-flex;align-items:center;justify-content:center;
  margin:0 38px;flex:0 0 auto;
  opacity:.62;transition:opacity .4s ease}
/* MÁS GRANDES Y UN PUNTO MÁS VIVOS (26-ago). Iban a 76px y en su color exacto;
   sobre la banda blanca pedían presencia, así que suben a 96 y se les da un 15%
   de color. El `saturate` solo se nota en los siete que tienen color: los nueve
   medallones negros no se mueven, porque el negro no tiene color que subir.
   Elegido entre tres tamaños en `muestras-logos.html`, que se borró al cerrar
   el tema y vive en el historial. */
.ticker-track .item img{height:96px;width:auto;object-fit:contain;filter:saturate(1.15)}
/* EL LOGO QUE LLEVA A SU WEB (26-ago). Seis de los trece clientes tienen web y
   son enlaces; los otros siete siguen siendo `span`, y esa es justo la señal de
   cuál se puede pinchar y cuál no, sin poner ningún icono encima. La cinta ya
   se para al pasar el ratón, así que el aviso es el cursor y un punto de
   tamaño. El foco se ve, que si no el enlace existe solo para el ratón. */
.ticker-track .item img{transition:transform .3s ease}
.ticker-track a.item:hover img{transform:scale(1.06)}
.ticker-track a.item:focus-visible{outline:2px solid var(--acento);outline-offset:6px;border-radius:6px}

@supports (animation-timeline: view()){
  @media (prefers-reduced-motion:no-preference){
    .ticker-mask{animation:banda-vuelta linear both;animation-timeline:--banda;
      animation-range:cover 0% cover 100%}
  }
}
/* CUANTAS VUELTAS DA, en una sola variable. Estaba escrito como 720 grados en
   dos sitios, y cambiarlo pedía tocar los dos y no equivocarse de signo.

   Eran dos vueltas enteras y quedan en MEDIA (23-ago), elegido en muestra
   contra vuelta y media, una y una con el recorrido acortado. El argumento de
   las dos vueltas era que con 185svh de recorrido una sola se reparte tan
   despacio que parece un cabeceo; con media el gesto es otro y ya no compite
   con la lectura de los logos, que es a lo que se viene. */
.ticker-mask{--vueltas:.5}
@keyframes banda-vuelta{
  0%{opacity:0;transform:rotateX(calc(var(--vueltas,2) * -360deg)) scale(.42)}
  42%{opacity:1;transform:rotateX(0deg) scale(1)}
  62%{opacity:1;transform:rotateX(0deg) scale(1)}
  100%{opacity:0;transform:rotateX(calc(var(--vueltas,2) * 360deg)) scale(.44)}}

@media (max-width:640px){
  .ticker-viaje{height:165svh}
  .ticker-escena{perspective:560px}
  .ticker-mask{padding:16px 0}
  .ticker-track .item{margin:0 22px}
  .ticker-track .item img{height:70px}}

@media (prefers-reduced-motion:reduce){
  .ticker-viaje{height:auto}
  .ticker-escena{position:static;transform:none}
  .ticker-mask{animation:none;opacity:1;transform:none}
  .ticker-track{animation:none}
  .ticker-track .item{opacity:.7;filter:grayscale(1)}}

/* ---------- SERVICIOS ---------- */
.svc-grid{display:grid;grid-template-columns:1fr 1fr;gap:22px;margin-top:52px}
/* ------------------------------------------------------------
   LA TARJETA DE SERVICIO ES UNA ISLA (21-ago)
   Antes era una caja de esquina de 4px con filete de marca arriba y el numero
   de marca de agua en la esquina. Ahora habla el idioma de la barra de
   navegacion: cristal, borde tenue, sombra larga y esquina de 28px. El numero
   sale de la esquina y se pone en un renglon con el icono, que es lo que deja
   sitio al titular sin reservarle margen a la derecha.

   El reposo es el FOCO BRONCE que sigue al puntero: `--fx`/`--fy` los escribe
   `site.js` con la posicion del raton dentro de la tarjeta. En el telefono no
   hay puntero, asi que se quedan en su valor de partida y la tarjeta se ve
   limpia.
   ------------------------------------------------------------ */
/* SIN `backdrop-filter`, y no es una renuncia: al elegir la isla ya se decidio
   que el fondo de la seccion se queda LISO asumiendo que el desenfoque no se
   veria. Sobre un fondo liso no hay nada que desenfocar, asi que lo unico que
   hacia era costar. Y costaba el doble aqui: estas cuatro giran en 3D con el
   reparto de la baraja, y desenfocar el fondo mientras la pieza rota obliga al
   compositor a recapturar y volver a desenfocar en cada cuadro. Es lo mas caro
   que se le puede pedir a un navegador. El cristal se sostiene igual con el
   fondo translucido y el borde tenue, que es de donde venia de verdad. */
/* PAPEL BLANCO, Y FUERA DEL RECORRIDO DE PIEL (24-ago)

   Dos cambios encadenados el mismo dia. Eran islas translucidas (`--isla-bg`,
   46% de opacidad) con borde tenue, la unica pieza del sitio dibujada asi: las
   fichas de la general de servicios y las obras del portafolio van sobre
   superficie solida. Se pasaron a solido, y ahi salio el segundo problema.

   La seccion va a `data-piel="0.72"`, o sea a tres cuartos de camino hacia la
   piel contraria, y una superficie que sigue ese recorrido llega ahi hecha un
   gris pardo. Asi que la tarjeta SE SALE del recorrido: no se tine con el
   tramo, se queda en la piel de la pagina. En la web clara eso es papel blanco
   sobre un fondo ya oscurecido, que es lo que las convierte en cuatro fichas
   puestas encima de la mesa; en la web oscura, el espejo.

   Por eso el juego de tokens se reescribe entero aqui dentro y no solo el
   fondo: sobre papel blanco, un texto que siga la piel del tramo va en claro y
   no se lee. Los valores son los de las dos pieles base, sin recorrido de por
   medio. Se declaran en la tarjeta, que esta mas cerca que la seccion, asi que
   ganan sin necesidad de `!important`. */
.svc{position:relative;padding:32px 30px 34px;border-radius:var(--radio-isla);
  background:var(--sup);
  border:1px solid var(--line);
  --fx:50%;--fy:0%;overflow:hidden;isolation:isolate;
  /* La tinta se declara AQUI y no solo en los tokens: `h3` no lleva color
     propio en toda la web, asi que hereda del padre. Sin esta linea el titular
     de cada servicio se quedaria con la tinta del tramo, que en la portada va
     en claro: blanco sobre papel blanco. */
  color:var(--ink);
  /* La piel oscura, que es la de base */
  --sup:#201C17;--ink:#F2EEE8;--ink-soft:#A79E92;
  --line:#332E27;--line-fuerte:#413A31;--borde-vivo:#5A5145;
  --acento:#C89454;--acento-tenue:rgba(200,148,84,.38);--sobre-acento:#14120F;
  --isla-sombra:rgba(0,0,0,.42);--sombra:rgba(0,0,0,.55);
  /* El disco del icono sigue usando los tokens de isla, asi que entran tambien:
     si se quedan fuera, se tinen con el tramo y salen sucios sobre el papel. */
  --isla-bg:rgba(18,16,13,.46);--isla-borde:rgba(255,255,255,.11)}
html[data-theme="light"] .svc{
  --sup:#FFFFFF;--ink:#14120F;--ink-soft:#5E584E;
  --line:#E1DBD1;--line-fuerte:#D8D1C6;--borde-vivo:#CFC7BA;
  --acento:#8A5A22;--acento-tenue:rgba(138,90,34,.34);--sobre-acento:#FCFAF7;
  --isla-sombra:rgba(20,18,15,.13);--sombra:rgba(20,18,15,.12);
  --isla-bg:rgba(252,250,247,.62);--isla-borde:rgba(20,18,15,.10)}
/* El foco sigue en `::before` y no en el fondo: ahora que el fondo es sólido ya
   podría teñirse directamente, pero el `::before` es lo que permite encenderlo
   y apagarlo con una transición sin tocar el color de la pieza. */
.svc::before{content:"";position:absolute;inset:0;pointer-events:none;z-index:0;
  background:radial-gradient(220px circle at var(--fx) var(--fy),
    color-mix(in srgb,var(--acento) 30%,transparent),transparent 70%);
  opacity:0;transition:opacity .45s ease}
.svc:hover::before,.svc.vivo::before{opacity:1}
/* La sombra ya no entra ni sale con el gesto: eso era de la baraja, donde una
   carta en el aire no proyecta. Una pieza que se levanta sobre su canto la tiene
   puesta todo el rato. */
.svc::after{content:"";position:absolute;inset:0;border-radius:inherit;
  box-shadow:0 12px 34px var(--isla-sombra);pointer-events:none;z-index:-1;opacity:.55}

.svc-alto{position:relative;z-index:1;display:flex;align-items:center;
  justify-content:space-between;width:100%;margin-bottom:16px}
/* El tenue va en el COLOR, no en `opacity`: la opacidad es del reparto, y
   `.svc .n{opacity}` le ganaria por especificidad y romperia el volteo. */
.svc .n{position:relative;top:auto;right:auto;margin:0;
  font-size:13px;line-height:1;font-weight:600;letter-spacing:.2em;
  color:var(--acento);transition:color .45s ease}
/* `svc-ic` lleva la posicion declarada aunque sea la de siempre: `.ic` existe
   suelta en este archivo con `position:absolute`, y una regla que no declara
   posicion se la come (trampas 45 y 47). */
.svc-ic{position:relative;top:auto;left:auto;
  width:38px;height:38px;border-radius:999px;display:grid;place-items:center;
  border:1px solid var(--isla-borde);background:var(--isla-bg);flex:0 0 auto;
  transition:border-color .35s ease}
.svc:hover .svc-ic{border-color:var(--acento)}
.svc-ic svg{width:18px;height:18px;fill:none;stroke:var(--acento);stroke-width:1.4;
  stroke-linecap:round;stroke-linejoin:round}
.svc h3{position:relative;margin:0 0 11px;padding-right:0;
  font-size:calc(23px * var(--t-scale));line-height:1.15}
.svc > p{position:relative;font-size:15.5px;color:var(--ink-soft);margin:0 0 18px;line-height:1.55}
/* Dentro de la isla las vinetas pierden el filete y el aire de la lista de
   siempre: en dos columnas dentro de una caja de cristal, cuatro rayas
   horizontales se leen como una tabla. */
.svc .bul{position:relative;display:grid;grid-template-columns:1fr 1fr;gap:6px 16px;
  margin:0 0 20px;max-width:none}
.svc .bul li{font-size:13.5px;color:var(--ink-soft);padding:0;border-top:0}
/* EL ENLACE QUE LLEVA A LA FICHA DE UN SERVICIO (24-ago)
   Un solo dibujo para los ocho: las cuatro tarjetas de la baraja de la portada
   y las cuatro fichas de la general de servicios. Antes eran dos dibujos para
   el mismo destino: aquí una cápsula de contorno, y allá un texto gris de 12px
   metido DENTRO del rótulo, arriba a la derecha, que era la pieza más pequeña
   de la tarjeta y encima estaba fuera del recorrido de lectura, así que se
   pasaba de largo.

   Va en bronce MACIZO, elegido en `muestras-enlace.html` contra la cápsula de
   contorno, contra un renglón que cruzaba la tarjeta entera y contra el disco
   al lado del rótulo. Con esto el bronce macizo deja de ser exclusivo del botón
   de enviar del contacto: pasa a ser el dibujo de "ir a ver esto", que son dos
   usos contados y no quince.

   La cápsula es la forma de todo lo pulsable del sitio, que es lo que sostiene
   el aire de plano de arquitecto: se redondea lo que se toca y nada más.

   Dos tallas, como ya hace `.btn` dentro de la isla de la barra: en la baraja
   de la portada va un punto más pequeño porque las cuatro tarjetas miden lo
   mismo por rejilla y engordar el botón las engorda a las cuatro. */
.svc .more,.sx .more{display:inline-flex;align-items:center;justify-content:center;gap:9px;
  font-size:14px;font-weight:500;text-decoration:none;font-family:var(--f-body);
  background:var(--acento);border:1px solid var(--acento);color:var(--sobre-acento);
  border-radius:999px;padding:13px 22px;min-height:46px;box-sizing:border-box;
  transition:background .3s ease,border-color .3s ease}
.svc .more::after,.sx .more::after{content:"\2192";display:inline-block;
  transition:transform .35s var(--ease)}
.svc .more:hover,.sx .more:hover{background:color-mix(in srgb,var(--acento) 86%,#FFF);
  border-color:color-mix(in srgb,var(--acento) 86%,#FFF)}
/* La flecha corre al señalar el enlace, y también al señalar la tarjeta entera
   de la portada: allí lo pulsable es la tarjeta, no solo el rótulo de dentro. */
.svc .more:hover::after,.sx .more:hover::after,
.svc:hover .more::after{transform:translateX(4px)}
/* La talla de la baraja */
.svc .more{margin-top:0;font-size:13.5px;padding:11px 18px;min-height:42px;gap:8px}

/* ------------------------------------------------------------
   LAS CUATRO SE LEVANTAN SOBRE SU CANTO (24-ago)

   Antes era una BARAJA: las cuatro nacían apiladas en el centro del hueco, boca
   abajo, y se repartían de una en una a su casilla girando media vuelta sobre
   su eje vertical, con un dorso que hacía de tapa hasta que la carta pasaba de
   canto. Se cambia porque el gesto era demasiado: media pantalla de viaje, un
   giro entero al entrar y otros 110 grados al salir, para cuatro tarjetas que
   hay que leer. Elegido en `muestras-baraja.html` contra dos recortes del
   volteo.

   Lo que entra en su lugar es el gesto que YA tienen las cuatro fichas de la
   general de servicios: la pieza se levanta apoyada en su canto de abajo
   (`transform-origin:50% 100%`), que es lo que se parece a un objeto de verdad
   y no a una imagen que cabecea. Con eso las tarjetas de la portada y las de
   `/services` se mueven igual, que era el punto.

   Lo que SE QUEDA de la baraja, porque no era del volteo sino del reparto:

   · El reloj es el de la SECCIÓN, no el de cada tarjeta. Con `view()` propio,
     las dos tarjetas de una misma fila comparten recorrido y entrarían siempre
     a la vez: no habría turnos. Por eso la rejilla declara `view-timeline-name`
     y su nombre vive en el `timeline-scope` único del `html`.

   · EL ESCALONADO Y LA VENTANA DE LECTURA VAN ATADOS. La ventana en la que una
     tarjeta está puesta tiene que ser más larga que lo que suman los retardos,
     o las cuatro no llegan a estar puestas a la vez en ningún momento y se lee
     como que se van antes de poder leerlas. Tres retardos de cinco son quince;
     la última termina de entrar en el 49% del recorrido de la sección y la
     primera no empieza a irse hasta el 72%, así que quedan veintitrés puntos
     con las cuatro quietas y de frente. La salida escalona de cuatro y no de
     cinco para que la cuarta acabe de irse justo en el 100% y no pasada de
     rosca, que la dejaría todavía puesta al salir la sección de pantalla.

   · La entrada rellena hacia los dos lados (`both`) y la salida SOLO hacia
     delante (`forwards`). Con la salida en `both` aplicaría su primer fotograma
     también antes de su tramo y, al ir declarada después, pisaría a la entrada:
     las tarjetas se quedarían puestas desde el principio y parecería que no se
     anima nada.

   · Los tramos van en `cover`, no en `entry`/`exit`. Esos dos se miden con el
     elemento entero dentro de la pantalla, y una sección más alta que la
     ventana no llega a estar dentro nunca: el tramo mide cero y el gesto ocurre
     de golpe.

   Y CAE EL DORSO, que era la tapa que escondía el texto mientras la carta pasaba
   de canto. Sin volteo no hay nada que tapar: el `<i class="dorso">` sale del
   marcado de las cuatro tarjetas.
   ------------------------------------------------------------ */
.svc-grid{view-timeline-name:--baraja;view-timeline-axis:block;position:relative}
/* La perspectiva ya no va en la rejilla: la trae la propia transformación con
   `perspective(1600px)`, igual que en las fichas de servicios. Declararla en
   las dos se acumula y exagera el ladeo. */
.svc{transform-origin:50% 100%}

@supports (animation-timeline: view()){
  @media (prefers-reduced-motion:no-preference){
    .svc{animation:svc-entra cubic-bezier(.22,.61,.36,1) both,
                   svc-sale  cubic-bezier(.55,0,.78,.4) forwards;
      animation-timeline:--baraja,--baraja;
      animation-range:cover calc(4% + var(--i) * 5%) cover calc(34% + var(--i) * 5%),
                      cover calc(72% + var(--i) * 4%) cover calc(88% + var(--i) * 4%)}
  }
}

@keyframes svc-entra{
  from{opacity:0;transform:perspective(1600px) rotateX(18deg) translateY(6%) scale(.94)}
  to  {opacity:1;transform:perspective(1600px) rotateX(0) translateY(0) scale(1)}
}
@keyframes svc-sale{
  from{opacity:1;transform:perspective(1600px) rotateX(0) translateY(0) scale(1)}
  to  {opacity:0;transform:perspective(1600px) rotateX(-14deg) translateY(-5%) scale(.97)}
}

@media (max-width:820px){
  .svc-grid{grid-template-columns:1fr;gap:16px}
  .svc{padding:26px 24px 28px}
  .svc .bul{grid-template-columns:1fr}
  .svc h3{font-size:calc(21px * var(--t-scale))}
  .svc-ic{width:36px;height:36px}.svc-ic svg{width:17px;height:17px}}

@media (prefers-reduced-motion:reduce){
  .svc{animation:none;opacity:1;transform:none}
  .svc::before{opacity:0}}

/* ---------- OBRA ---------- */
.work-head{display:flex;align-items:flex-end;justify-content:space-between;gap:24px;flex-wrap:wrap}
.work-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:26px;margin-top:52px}
@media (max-width:980px){.work-grid{grid-template-columns:repeat(2,1fr)}}
@media (max-width:600px){.work-grid{grid-template-columns:1fr}}
/* ------------------------------------------------------------
   OBRAS DE LA PORTADA · LA PILA

   Elegido en `muestras-entradas.html` (gesto 03). Las obras dejan de pasar de
   lado: cada una se queda pegada a la pantalla y la siguiente se monta encima,
   un poco más abajo, mientras la de debajo se hunde y se apaga. Bajando se ve
   la pila creciendo; subiendo se deshace sola. El scroll deja de mover la
   página y pasa a MONTAR algo, que es lo que un carrusel automático nunca hizo.

   Sustituye al carrusel de tarjetas anchas (flechas, trazos de posición, paseo
   solo y arrastre), que vive en el commit anterior a este. Y con él se van sus
   tres problemas: pasaba solo mientras alguien leía, escondía cinco obras de
   seis detrás de un gesto lateral, y en el teléfono competía con el scroll de
   la propia página.

   Cinco cosas la sostienen, y ninguna es de adorno:

   1 · EL ESCALONADO (`--i`) deja ver el canto de las que ya han pasado. Sin él
       cada foto tapa entera a la anterior y no se lee una pila, se lee una foto
       cambiando. El paso es pequeño a propósito: seis obras por un paso grande
       se comen la pantalla.
   2 · EL HUNDIDO VA SOBRE EL ENLACE, no sobre la foto. Las reglas de piel ya
       escriben `filter` sobre `.proj figure img` para bajarle el brillo según
       la sección aclara, y dos filtros sobre el mismo elemento se pisan: gana
       el último y el otro desaparece sin dar error.
   3 · EL ATAJO `animation:` BORRA `animation-timeline` (trampa 20), así que la
       línea de tiempo se vuelve a declarar justo detrás. Sin eso el gesto se
       queda en el primer cuadro y parece que el navegador no lo soporta.
   4 · LO ENCIENDE EL GUION con `.work-pila` (trampa 26). Sin JavaScript queda
       la rejilla de seis de siempre, que es una página perfectamente válida.
       Por eso el escalonado y el rótulo cuelgan de esa clase y no de `.proj`.
   5 · EN EL TELÉFONO NO HAY QUE INVENTAR NADA, y es la razón de fondo por la
       que este gesto vale para la portada: lo mueve el scroll, no el puntero,
       así que el dedo hace exactamente lo mismo que el ratón. Lo único que
       cambia es la medida (la foto pasa a proporción de retrato y el escalón
       se aprieta), porque 62svh de foto apaisada en 390px de ancho no es una
       obra, es una franja.
   ------------------------------------------------------------ */
.work-pila{display:block;margin-top:clamp(30px,4vw,44px)}
/* El `top` sube con el índice: 20, 36, 52... Se mide desde el borde de arriba y
   no desde la barra porque la barra se esconde al bajar, que es justo cuando
   esto se está mirando; los 20px son el aire que hace falta para que al SUBIR,
   con la barra ya de vuelta, no quede pegada al canto. */
.work-pila .proj{--pila-top:20px;--pila-paso:16px;
  position:sticky;top:calc(var(--pila-top) + var(--i,0) * var(--pila-paso));
  display:block;height:62svh;max-height:660px;margin:0 0 26px;
  border-radius:var(--radio-isla);overflow:hidden;background:var(--foto-vacia);
  box-shadow:0 -16px 44px var(--sombra-suave)}
.work-pila .proj:last-child{margin-bottom:0}
/* El `figure` trae de serie proporción 4/3 y su propio redondeo: aquí manda el
   alto del enlace, y el redondeo es uno solo, el de fuera, o se ve doble canto. */
.work-pila .proj figure{margin:0;height:100%;aspect-ratio:auto;border-radius:0}
/* El texto va encima de la foto, sobre un velo que solo cubre el pie. */
.work-pila .proj::after{content:"";position:absolute;inset:auto 0 0 0;height:58%;
  background:linear-gradient(to top,rgba(7,6,5,.9),rgba(7,6,5,.3) 55%,transparent);
  pointer-events:none;z-index:1}
.work-pila .proj .meta{position:absolute;left:0;right:0;bottom:0;z-index:2;
  padding:clamp(22px,3vw,32px) clamp(20px,2.6vw,30px);display:block;color:#fff}
.work-pila .proj .tag{color:#E7C79A;margin:0 0 6px}
.work-pila .proj .name{font-family:var(--f-title);
  font-size:clamp(24px,3vw,36px);letter-spacing:-.02em;display:block}
.work-pila .proj .loc{color:rgba(255,255,255,.78);font-size:15px}

/* El hundido de la que se queda debajo. Va con el recorrido de la propia obra
   (`view()`), en su tramo de SALIDA: mientras sube y se va, se encoge un punto
   y pierde luz, que es lo que da la sensación de que la nueva se le pone
   encima y no al lado. */
@supports (animation-timeline: view()){
  @media (prefers-reduced-motion:no-preference){
    .work-pila .proj{animation:se-hunde linear both;
      animation-timeline:view();animation-range:exit 0% exit 100%}
    @keyframes se-hunde{to{transform:scale(.93);filter:brightness(.62)}}
  }
}

/* ---------- LA PILA EN EL TELÉFONO ----------
   El gesto es el mismo (lo mueve el scroll, no el puntero); lo que cambia son
   las medidas. La foto pasa a proporción de retrato en vez de a alto de
   pantalla, el escalón se aprieta porque hay menos alto que repartir, y la
   sombra se afina, que una sombra de 44px de difuminado repintándose en cada
   cuadro es de lo poco que se nota de verdad en un teléfono. */
@media (max-width:720px){
  .work-pila .proj{--pila-top:14px;--pila-paso:10px;
    height:auto;aspect-ratio:4/5;max-height:none;margin-bottom:16px;
    box-shadow:0 -10px 26px var(--sombra-suave)}
  .work-pila .proj .meta{padding:20px}
  .work-pila .proj .name{font-size:22px}
  .work-pila .proj .loc{font-size:13.5px}
}

/* Con menos movimiento pedido no hay pila: la lista de seis, una debajo de
   otra, sin nada pegado ni hundiéndose. */
@media (prefers-reduced-motion:reduce){
  .work-pila .proj{position:static;transform:none;filter:none;box-shadow:none}
  .work-pila .proj figure img{transition:none}
}

.proj{display:block;text-decoration:none;color:inherit}
.proj figure{margin:0;position:relative;aspect-ratio:4/3;overflow:hidden;background:var(--foto-vacia);
  border-radius:var(--radio-pieza)}
.proj figure img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  transition:transform .6s cubic-bezier(.2,.6,.2,1)}
.proj:hover figure img{transform:scale(1.04)}
.proj .meta{display:flex;justify-content:space-between;gap:14px;margin-top:14px;align-items:baseline}
.proj .name{font-weight:600;letter-spacing:-.01em}
.proj .loc{font-size:14px;color:var(--ink-soft);white-space:nowrap}
.proj .tag{font-size:11.5px;letter-spacing:.14em;text-transform:uppercase;color:var(--ink-soft);margin-top:3px}

/* ---------- REELS ----------
   Carrusel de vídeo vertical (lo que publican en Instagram). Tres decisiones:

   · La pista se desplaza SOLA, con el scroll del propio navegador y anclaje
     por tarjeta (scroll-snap). Nada de arrastre escrito a mano: el nativo ya
     trae inercia, teclado y rueda, y en el teléfono es el gesto que la gente
     espera de algo que se parece a Instagram.
   · El alto se fija con una caja de proporción 9:16 y no con `aspect-ratio` a
     secas, porque la tarjeta lleva el vídeo en posición absoluta y así el
     hueco está reservado antes de que cargue nada: la sección no da el salto.
   · La pista se sale del `.wrap` a propósito y solo lleva su margen lateral,
     para que la última tarjeta asome por el borde derecho y se vea que hay
     más. El aire se toma del mismo `--pad` del sitio, nunca de `vw`, que
     cuenta la barra de scroll y descuadra la rejilla. */
/* `clip` y no `hidden`: `hidden` crearía contenedor de scroll y rompería las
   anclas de la página, que es una de las trampas ya pagadas en este sitio. */
.reels{overflow-x:clip}
.reels-head{display:flex;align-items:flex-end;justify-content:space-between;gap:24px;flex-wrap:wrap}
.reels-viewport{position:relative;margin-top:30px}
.reels-pista{display:flex;gap:18px;list-style:none;margin:0;
  padding:6px var(--pad) 10px;overflow-x:auto;overscroll-behavior-x:contain;
  scroll-snap-type:x mandatory;scroll-padding-left:var(--pad);
  scrollbar-width:none;-ms-overflow-style:none}
.reels-pista::-webkit-scrollbar{display:none}
/* Mientras la pista pasea sola, el enganche del snap pelea con el empujón de
   cada fotograma y sale a tirones: se apaga y vuelve solo si no hay paseo. */
.reels-pista.paseando{scroll-snap-type:none}

/* El desvanecido de los lados, que es lo que hace que la pista parezca seguir
   más allá del borde en vez de acabarse ahí.

   Va como MÁSCARA y no como un degradado de color puesto encima: lo que se
   apaga es la propia pista, así que vale igual en la piel oscura y en la clara
   sin repetir el color del fondo en dos sitios, que es de lo que se acaba
   olvidando uno al cambiar la paleta.

   Se pone sobre la pista y no sobre `.reels-viewport` a propósito: las flechas
   viven en el viewport, justo en la zona apagada, y quedarían medio borradas.

   El apagado es ancho a propósito, casi una tarjeta entera: la tarjeta tarda
   en irse, y ese tiempo es justo lo que separa un carrusel de una lista que se
   mueve. Va topado a un porcentaje del ancho para que en una ventana estrecha
   no se junten los dos lados y no quede nada nítido en medio, y el porcentaje
   se mide contra la pista, no contra `vw`, que cuenta la barra de scroll. Y no
   baja en línea recta, que se nota en bandas, sino con dos paradas intermedias
   que curvan la caída.
   La clase la pone el guion, y solo cuando la pista desborda de verdad: sin
   desbordar, el desvanecido se comería la última tarjeta sin motivo. */
.reels-pista.difuminada{
  --difuminado:min(calc(var(--pad) + 200px),21%);
  --apagado:linear-gradient(to right,
    transparent 0,
    rgba(0,0,0,.16) calc(var(--difuminado) * .34),
    rgba(0,0,0,.58) calc(var(--difuminado) * .66),
    #000 var(--difuminado),
    #000 calc(100% - var(--difuminado)),
    rgba(0,0,0,.58) calc(100% - var(--difuminado) * .66),
    rgba(0,0,0,.16) calc(100% - var(--difuminado) * .34),
    transparent 100%);
  -webkit-mask-image:var(--apagado);
  mask-image:var(--apagado)}
.reel{position:relative;flex:0 0 auto;width:264px;scroll-snap-align:start;cursor:zoom-in;
  border-radius:var(--radio-pieza);overflow:hidden;background:var(--foto-vacia);
  border:1px solid var(--line);box-shadow:0 14px 34px var(--sombra-suave);
  transition:transform .4s cubic-bezier(.2,.6,.2,1),border-color .35s ease}
.reel::before{content:"";display:block;padding-top:177.78%}   /* 9 : 16 */
.reel video{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  display:block;background:var(--foto-vacia)}
.reel:hover{transform:translateY(-4px);border-color:var(--borde-vivo)}
/* La tarjeta en la que se ha parado el paseo. Se levanta algo más que en el
   hover suelto para que se entienda que la pista se ha detenido por ella. */
.reel.destacada{transform:translateY(-6px) scale(1.035);border-color:var(--borde-vivo);
  box-shadow:0 20px 46px var(--sombra-suave)}

/* Botón de ampliar. Arriba, para no pelearse con el de sonido, y solo se
   enciende del todo al acercarse: la tarjeta ya dice con el cursor que se abre. */
/* Los dos botones del reel van con fondo SOLIDO y no con desenfoque de fondo.
   Hay quince reels, o sea treinta botones, y treinta desenfoques de fondo
   pesaban el scroll de la portada entera aunque estuvieran quietos y ocultos
   (medido el 21-ago). Se compensa subiendo el negro del fondo, y encima se ven
   mejor: lo que hay detras es video en movimiento, y un desenfoque de seis
   pixeles sobre video cambia en cada cuadro. */
.reel-lupa{position:absolute;right:10px;top:10px;width:38px;height:38px;
  display:inline-flex;align-items:center;justify-content:center;
  border:1px solid rgba(255,255,255,.28);border-radius:50%;
  background:rgba(7,6,5,.62);color:#fff;cursor:zoom-in;opacity:0;
  transition:opacity .3s ease,background .3s ease,border-color .3s ease}
.reel:hover .reel-lupa,.reel.destacada .reel-lupa,.reel-lupa:focus-visible{opacity:1}
.reel-lupa:hover{background:rgba(7,6,5,.8);border-color:rgba(255,255,255,.7)}
.reel-lupa svg{width:17px;height:17px;fill:none;stroke:currentColor;stroke-width:1.8;
  stroke-linecap:round;stroke-linejoin:round}

/* Botón de sonido. Empieza siempre en silencio (reproducir con voz sin que
   nadie lo haya pedido es de lo poco que hace cerrar una pestaña), así que el
   botón es la única forma de oírlo, y se apaga solo al pulsar otro. */
.reel-son{position:absolute;right:10px;bottom:10px;width:44px;height:44px;
  display:inline-flex;align-items:center;justify-content:center;
  border:1px solid rgba(255,255,255,.34);border-radius:50%;
  background:rgba(7,6,5,.7);color:#fff;cursor:pointer;
  transition:background .3s ease,border-color .3s ease}
.reel-son:hover{background:rgba(7,6,5,.8);border-color:rgba(255,255,255,.7)}
.reel-son svg{width:19px;height:19px;fill:none;stroke:currentColor;stroke-width:1.7;
  stroke-linecap:round;stroke-linejoin:round}
.reel-son .tachado{display:block}
.reel-son .onda{display:none}
.reel.suena .reel-son .tachado{display:none}
.reel.suena .reel-son .onda{display:block}

/* Las flechas solo salen en pantalla ancha: en el teléfono se arrastra, y un
   botón encima de la tarjeta solo taparía el vídeo. */
.reels-nav{position:absolute;top:50%;transform:translateY(-50%);z-index:2;
  width:46px;height:46px;display:none;align-items:center;justify-content:center;
  border-radius:50%;cursor:pointer;
  background:var(--sup);color:var(--ink);border:1px solid var(--line-fuerte);
  box-shadow:0 10px 26px var(--sombra-suave);
  transition:border-color .3s ease,transform .3s ease}
.reels-nav:hover{border-color:var(--borde-vivo);transform:translateY(-50%) scale(1.06)}
.reels-nav svg{width:20px;height:20px;fill:none;stroke:currentColor;stroke-width:1.8;
  stroke-linecap:round;stroke-linejoin:round}
.reels-nav.prev{left:calc(var(--pad) - 23px)}
.reels-nav.next{right:calc(var(--pad) - 23px)}
@media (min-width:1000px){.reels-nav:not([hidden]){display:inline-flex}}
@media (max-width:640px){
  .reels{padding:76px 0}
  .reels-viewport{margin-top:32px}
  .reel{width:230px}
  /* El apagado de escritorio se comería la pantalla entera del teléfono. */
  .reels-pista.difuminada{--difuminado:min(calc(var(--pad) + 74px),25%)}
}
@media (prefers-reduced-motion:reduce){
  .reels-pista{scroll-behavior:auto}
  .reel,.reels-nav{transition:none}
  .reel:hover,.reel.destacada{transform:none}
  .reelbox{transition:none}
}

/* Visor del reel. Un vídeo de teléfono en una tarjeta de 280px se ve pero no
   se lee, así que al pincharlo se abre a la altura de la pantalla, con sus
   mandos y con sonido. Se mide en `dvh` y no en `vh` porque en el móvil la
   barra del navegador se come lo segundo. */
.reelbox[hidden]{display:none}
.reelbox{position:fixed;inset:0;z-index:80;display:grid;place-items:center;
  background:rgba(7,6,5,.9);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);
  opacity:0;transition:opacity .26s ease}
.reelbox.on{opacity:1}
.reelbox-lienzo{display:grid;place-items:center;padding:clamp(46px,7vw,72px) 16px}
.reelbox-lienzo video{display:block;height:min(84dvh,900px);width:auto;max-width:92vw;
  aspect-ratio:9/16;border-radius:var(--radio-pieza);background:#000;
  box-shadow:0 30px 80px rgba(0,0,0,.6)}
.reelbox-x,.reelbox-nav{position:absolute;z-index:2;display:grid;place-items:center;
  width:44px;height:44px;border-radius:50%;cursor:pointer;color:#fff;
  background:rgba(20,18,15,.65);border:1px solid rgba(255,255,255,.28);
  transition:background .3s ease,border-color .3s ease}
.reelbox-x:hover,.reelbox-nav:hover{background:rgba(20,18,15,.9);border-color:rgba(255,255,255,.55)}
.reelbox-x svg,.reelbox-nav svg{width:22px;height:22px;fill:none;stroke:currentColor;
  stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}
.reelbox-x{top:clamp(14px,3vw,26px);right:clamp(14px,3vw,26px)}
.reelbox-nav{top:50%;transform:translateY(-50%)}
.reelbox-nav.ant{left:clamp(10px,2.4vw,26px)}
.reelbox-nav.sig{right:clamp(10px,2.4vw,26px)}
.reelbox-pie{position:absolute;left:0;right:0;bottom:clamp(10px,2vw,18px);margin:0;
  text-align:center;color:rgba(255,255,255,.6);font-size:.86rem;
  font-variant-numeric:tabular-nums}
/* En el móvil las flechas taparían el vídeo, que ya ocupa casi todo: se pasa
   de uno a otro cerrando y abriendo, o con el teclado en escritorio. */
@media (max-width:640px){
  .reelbox-nav{display:none}
  .reelbox-lienzo{padding:56px 10px}
}

/* ---------- PREGUNTAS FRECUENTES ---------- */
/* Pregunta a la izquierda y respuesta a la derecha, separadas por una línea.
   Abiertas, sin desplegable: esto es lo que lee Google para enseñarlo en el
   resultado y lo que citan los asistentes, y para eso tiene que estar a la
   vista. La respuesta se acota en `ch` y no en píxeles, que es el ancho de
   lectura de verdad y no depende del cuerpo de letra. */
.faq-lista{list-style:none;margin:30px 0 0;padding:0}

/* ---------- LAS PREGUNTAS, DE UNA EN UNA ----------
   Antes las tres estaban abiertas en dos columnas: la pregunta a la izquierda y
   su respuesta a la derecha, todo a la vez. Se leía como un muro de texto justo
   antes del contacto, que es donde menos aguanta.

   Ahora la pregunta ocupa el renglón entero y la respuesta se despliega debajo,
   SANGRADA a la columna donde estaba antes: así el bloque cambia de
   comportamiento sin perder el sitio que ya tenía en la página.

   EL DESPLIEGUE SE ANIMA CON LA REJILLA, y no con el alto, porque `height:auto`
   no se puede animar: el cuerpo es una rejilla de una fila que pasa de `0fr` a
   `1fr`, que sí interpola, y lo que hay dentro va con `overflow:hidden` para
   que no asome mientras la fila todavía está cerrada. */
.faq-item{border-top:1px solid var(--line)}
.faq-lista li:last-child .faq-item{border-bottom:1px solid var(--line)}

/* El triángulo que pinta el navegador sobra: el signo lo pone la web. */
.faq-item > summary{list-style:none;cursor:pointer;
  display:grid;grid-template-columns:1fr auto;gap:24px;align-items:start;
  padding:20px 0;transition:color .3s ease}
.faq-item > summary::-webkit-details-marker{display:none}
.faq-item > summary:hover h3{color:var(--acento)}
.faq-item > summary:focus-visible{outline:2px solid var(--acento);outline-offset:4px}
.faq-lista h3{font-family:var(--f-title);font-size:calc(21px * var(--t-scale));
  margin:0;line-height:1.25;max-width:34ch;transition:color .3s ease}

/* EL SIGNO ES UNA CRUZ QUE SE VUELVE UN MENOS: dos filetes cruzados y el
   vertical gira un cuarto de vuelta al abrir. Es el mismo bronce del resto de
   la web y no hay ningún icono que descargar. */
.faq-mas{position:relative;width:18px;height:18px;flex:0 0 auto;margin-top:6px}
.faq-mas::before,.faq-mas::after{content:"";position:absolute;left:0;top:50%;
  width:100%;height:1.5px;background:var(--acento);
  transition:transform .45s var(--ease)}
.faq-mas::after{transform:rotate(90deg)}
.faq-item[open] .faq-mas::after{transform:rotate(0deg)}

/* El cuerpo. La sangría lo deja donde estaba la respuesta cuando esto eran dos
   columnas, así que la sección conserva su dibujo. */
.faq-cuerpo{display:grid;grid-template-rows:0fr;
  transition:grid-template-rows .5s var(--ease)}
.faq-item[open] .faq-cuerpo{grid-template-rows:1fr}
/* LA SANGRÍA ES LA REJILLA DE ANTES, no un relleno. Primero se hizo con
   `padding-left` de un 44% y el resultado fue una columna de texto de dos
   palabras por línea: la caja mide con el relleno DENTRO, así que ese relleno
   se comía casi todo el `max-width` del párrafo y no quedaba sitio para el
   texto. Con las mismas dos columnas que tenía la sección abierta (1fr y
   1.25fr, con su hueco de 44px) la respuesta cae exactamente donde caía antes
   y conserva su ancho de lectura. */
.faq-dentro{overflow:hidden;min-height:0;
  display:grid;grid-template-columns:1fr 1.25fr;gap:44px}
.faq-lista p{grid-column:2;margin:0;color:var(--ink-soft);max-width:62ch;
  padding:0 0 28px;
  opacity:0;transform:translateY(8px);
  transition:opacity .4s var(--ease),transform .5s var(--ease)}
.faq-item[open] p{opacity:1;transform:none;transition-delay:.12s}

/* CON GUION, EL ESTADO LO LLEVA LA CLASE Y NO EL ATRIBUTO, y es lo único que
   permite animar el CIERRE: al quitar `open`, el navegador esconde el contenido
   de golpe y no queda nada que animar. Así que el guion abre el `details`
   primero, anima después, y al cerrar hace lo contrario: anima y quita `open`
   cuando la animación termina.

   Las reglas de `[open]` de arriba se quedan porque son el suelo: sin guion, la
   pregunta se abre y se cierra igual, solo que de un salto. Estas van detrás
   para ganarles cuando el guion sí está. */
.faq-item.js .faq-cuerpo{grid-template-rows:0fr}
.faq-item.js.abierta .faq-cuerpo{grid-template-rows:1fr}
.faq-item.js .faq-mas::after{transform:rotate(90deg)}
.faq-item.js.abierta .faq-mas::after{transform:rotate(0deg)}
.faq-item.js p{opacity:0;transform:translateY(8px)}
.faq-item.js.abierta p{opacity:1;transform:none;transition-delay:.12s}

@media (max-width:900px){
  .faq-item > summary{padding:22px 0;gap:16px}
  .faq-lista h3{max-width:none}
  /* Una sola columna: la respuesta va debajo de su pregunta, a ancho completo. */
  .faq-dentro{grid-template-columns:1fr;gap:0}
  .faq-lista p{grid-column:1;padding-bottom:24px}
}
.faq-pie{margin:26px 0 0;color:var(--ink-soft);font-size:.9rem}
@media (max-width:900px){
}

/* ---------- EQUIPO ---------- */
/* LA REJILLA DE FICHAS DE PERSONA. Estuvo sin usar desde que el equipo pasó al
   acordeón de tiras, y vuelve el 24-ago en la página de About para los OCHO del
   equipo, que es de quienes solo hay nombre y cargo: ocho fichas llenan dos
   filas de cuatro sin dejar hueco. Los tres que dirigen van arriba en tira, con
   su trayectoria puesta. */
/* TRES COLUMNAS Y NO CUATRO (1-sep): con la entrada de Juliana son nueve
   fichas, y en rejilla de cuatro la novena se quedaba sola en la última
   fila. Tres columnas dan tres filas llenas. */
.team-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:22px;margin-top:52px}
@media (max-width:980px){.team-grid{grid-template-columns:repeat(2,1fr);gap:16px}}
@media (max-width:560px){.team-grid{grid-template-columns:1fr}}
.person{background:var(--sup);border:1px solid var(--line);border-radius:var(--radio-pieza);padding:34px 26px 30px;
  text-align:center;transition:transform .35s cubic-bezier(.2,.6,.2,1),box-shadow .35s ease,border-color .35s ease}
.person:hover{transform:translateY(-4px);box-shadow:0 18px 44px var(--sombra-suave);border-color:var(--borde-vivo)}
.person .avatar{width:132px;height:132px;border-radius:50%;overflow:hidden;margin:0 auto 22px;
  background:var(--bg-alt);border:1px solid var(--line)}
.person .avatar img{width:100%;height:100%;object-fit:cover;object-position:50% 18%}
.person .role{font-size:11.5px;letter-spacing:.14em;text-transform:uppercase;color:var(--ink-soft);margin-top:8px}
.person p{font-size:15px;color:var(--ink-soft);margin:16px 0 0}
@media (max-width:980px){.person .avatar{width:116px;height:116px}}
.note{margin-top:44px;padding:24px 26px;border:1px solid var(--line);background:var(--bg);
  font-size:15px;color:var(--ink-soft);max-width:80ch}


/* ============================================================
   EL EQUIPO · ACORDEÓN DE RETRATOS

   Once tiras verticales de foto en dos filas. La que se señala se abre y las
   demás se estrechan para dejarle sitio, sin que la fila cambie de tamaño: lo
   que se mueve es el REPARTO. Cerradas van en blanco y negro con el nombre de
   pie en el canto; la abierta entra en color con su cargo.

   Sustituye a la rejilla de cuatro tarjetas con la foto redonda arriba, que es
   lo que se ve en cualquier web. Y hace algo que la rejilla no hacía: aguanta
   once personas sin ocupar once tarjetas de alto, y aguanta que las fotos no
   sean todas del mismo día ni con la misma luz, porque nunca se ven dos enteras
   a la vez.

   TRES MEDIDAS QUE VAN JUNTAS Y NO SE TOCAN POR SEPARADO, porque de ellas
   depende que a alguien se le corte la cabeza:

   1 · El ENCUADRE va arriba (`object-position` bajo). En estos retratos la
       cabeza empieza a un 5% del borde en el caso más justo, que es el de
       Robert, así que un encuadre alto se la lleva. Lo que se pierde por abajo
       son las manos, que es lo que sobra en un retrato de equipo.
   2 · La PROPORCIÓN de la tira abierta manda más que el encuadre. Estos
       retratos son 0,76 de ancho por alto; cuanto más apaisada quede la tira
       abierta, más alto de foto sobra y más grande es el recorte. Por eso la
       fila es alta y la tira abierta no se pasa de ancha.
   3 · En DOS FILAS no cabe tanta altura, así que ahí el recorte es mayor y el
       encuadre se sube un poco para devolver por abajo. Ocho por ciento del
       sobrante, medido: en la ventana más ancha son un 2,9% de la foto, y
       quedan dos puntos de margen antes de tocarle el pelo a Robert.

   Cada fila lleva su acordeón: abrir una de arriba no encoge las de abajo, que
   sería un movimiento enorme por señalar a una persona.
   ============================================================ */
.retratos{display:flex;gap:8px;height:50svh;margin-top:34px}
.retratos + .retratos{margin-top:10px}
/* SE ANIMA `flex-grow` Y NO EL ATAJO `flex`. El atajo son tres propiedades, y
   el navegador tiene que interpolar y recalcular las tres en cada cuadro para
   las seis tiras a la vez; con `flex-grow` sola hay un único número en juego y
   el deslizamiento sale limpio. La base va en `flex-basis:0` para que el reparto
   dependa solo de ese número y no del ancho de lo que haya dentro.

   La curva es de frenada larga: arranca decidida y se posa. Con una curva
   simétrica el reparto parece que se arrastra, y con una demasiado seca parece
   que salta. */
.retrato{position:relative;flex:1 1 0;min-width:0;overflow:hidden;
  border-radius:var(--radio-pieza);background:var(--bg-alt);cursor:default;
  will-change:flex-grow;
  transition:flex-grow 1.05s cubic-bezier(.22,1,.32,1)}
/* Con el ratón dentro de la fila, todas ceden un poco y la señalada se lleva el
   sitio. Sin esta primera regla, la que se abre empuja a las demás fuera del
   ancho en vez de repartir. */
.retratos:hover .retrato{flex-grow:.72}
/* CUÁNTO SE ABRE LA SEÑALADA, y por qué no es un número suelto. Los retratos
   son verticales y van con `cover`, así que la foto se escala hasta cubrir el
   ancho de la tira: cuanto más se abre, MENOS foto se ve y más cerca queda la
   cara. Con las seis tiras de la fila vieja se veía el 79% del retrato; al
   pasar el equipo a tres filas (22-ago), la de arriba tiene tres tiras, la
   abierta se llevaba 752px y se quedaba en el 50%, que es la cara pegada.

   Las dos filas de cuatro enseñan el 80% del retrato, que es lo que enseñaba
   la fila de seis de antes, y la de tres se queda un punto por debajo. Si
   algún día cambia el número de personas por fila, hay que rehacer la cuenta:
   lo que manda es el ANCHO de la tira abierta frente al ancho natural de la
   foto, no el factor en sí. Y de aquí no se puede bajar mucho más: por debajo
   de 1.4 la tira señalada deja de distinguirse de las otras y el acordeón
   pierde el gesto. */
.retratos .retrato:hover,.retrato.abierta{flex-grow:1.5}
/* La fila de tres (los tres que mandan) se abre menos que las de cuatro, o con
   el mismo factor se llevaría cien píxeles más de ancho. Sin `:has` se queda
   con el valor de arriba, que ya es más suave que el de antes. */
.retratos:not(:has(> :nth-child(4))) .retrato:hover,
.retratos:not(:has(> :nth-child(4))) .retrato.abierta{flex-grow:1.15}
/* La fila de CINCO (1-sep, al entrar Juliana el equipo pasa a doce y la fila
   de abajo crece). Con el factor de las de cuatro, la tira abierta se quedaba
   en el 34% del ancho de la fila en vez del 41%, o sea la cara más pegada que
   en las demás. El 2 lo devuelve al mismo 41%: es la cuenta que pide el
   comentario de arriba, rehecha para cinco tiras. */
.retratos:has(> :nth-child(5)) .retrato:hover,
.retratos:has(> :nth-child(5)) .retrato.abierta{flex-grow:2}
/* EL VELO Y LA LUZ DE LA FOTO VAN ATADOS AL FONDO, y no es un capricho: en
   reposo la foto va en gris y con un velo casi opaco encima, que es lo que
   hace legible el nombre de canto. Con la sección en negro eso funciona; con
   la sección en blanco, las once tiras se convierten en tres bandas negras
   pegadas al fondo claro, que es exactamente el corte en seco que se veía al
   aclarar el equipo (22-ago).

   `--oscuro` vale 1 sobre fondo negro y 0 sobre fondo blanco, así que sobre
   blanco el velo se afloja y la foto sube de luz. Abajo se conserva más velo
   que arriba porque ahí es donde cae el nombre. */
.retrato img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  object-position:50% 8%;
  filter:grayscale(1) contrast(1.05)
         brightness(calc(.86 + (1 - var(--oscuro,1)) * .12));
  transform:scale(1.04);
  transition:filter 1s var(--ease),transform 1.4s var(--ease)}
.retrato:hover img,.retrato.abierta img{filter:none;transform:none}
.retrato::after{content:"";position:absolute;inset:0;
  background:linear-gradient(to top,
    rgba(7,6,5,calc(.86 - (1 - var(--oscuro,1)) * .26)),
    rgba(7,6,5,calc(.12 - (1 - var(--oscuro,1)) * .08)) 52%,
    rgba(7,6,5,calc(.30 - (1 - var(--oscuro,1)) * .24)));
  transition:opacity .8s var(--ease)}
.retrato:hover::after,.retrato.abierta::after{opacity:.82}
/* Cerrada, el nombre va de pie en el canto: es lo que hace que la tira estrecha
   siga diciendo quién es sin necesidad de abrirse. */
.retrato .canto{position:absolute;left:50%;bottom:clamp(16px,1.8vw,24px);z-index:2;
  transform:translateX(-50%) rotate(180deg);writing-mode:vertical-rl;
  font-family:var(--f-title);font-size:clamp(12px,1.1vw,15px);color:#F4F1EC;
  white-space:nowrap;margin:0;transition:opacity .5s var(--ease)}
.retrato:hover .canto,.retrato.abierta .canto{opacity:0}
/* Se llama `rotulo` y no `ficha` POR ALGO: `.ficha` ya existe en este archivo,
   es la del mapa de obras de /work-a, y trae `inset:0` con fondo opaco y borde.
   Un nombre repetido no da error, así que el síntoma no apunta a la causa: la
   regla de aquí ganaba por especificidad en todo MENOS en lo que no declaraba,
   y como aquí no hace falta `top`, se colaba el `top:0` de la otra. Resultado:
   el rótulo estirado de arriba abajo y con el fondo de la página encima, o sea
   la foto del retrato tapada entera. */
.retrato .rotulo{position:absolute;left:0;right:0;bottom:0;top:auto;z-index:2;color:#F4F1EC;
  padding:clamp(16px,1.8vw,24px);opacity:0;transform:translateY(10px);
  transition:opacity .6s var(--ease) .18s,transform .6s var(--ease) .18s}
.retrato:hover .rotulo,.retrato.abierta .rotulo{opacity:1;transform:none}
.retrato .rotulo .nm{font-family:var(--f-title);
  font-size:clamp(16px,1.7vw,23px);margin:0 0 5px;line-height:1.15}
.retrato .rotulo .rl{font-size:10.5px;letter-spacing:.16em;text-transform:uppercase;
  color:#E7C79A;margin:0}
/* LA TRAYECTORIA, SOLO EN LOS TRES QUE MANDAN (24-ago)

   La lleva la primera fila de la página de About, que son Robert, Mey y Roman.
   Los otros ocho se quedan con nombre y cargo: las once frases no existen, y
   ponérselas a tres y a ocho no es lo mismo que inventárselas a ocho.

   Entra CON el rótulo, en el mismo gesto que ya abría la ficha al pasar, así
   que no añade movimiento nuevo: es una línea más de algo que ya se desplegaba.
   Y como el rótulo va sobre la foto oscurecida, el color se escribe a mano
   igual que el resto de la ficha, no con un token de piel.

   El tenue va en el COLOR y no en `opacity`, que es del revelado: escrito aquí
   le ganaría por especificidad al despliegue del rótulo y la frase se quedaría
   a medio aparecer. */
.retrato .rotulo .bio{margin:10px 0 0;font-size:13px;line-height:1.5;
  color:rgba(244,241,236,.88);max-width:44ch}
/* LA FICHA, SIEMPRE PUESTA (bloque de dirección de About)

   En el acordeón normal el rótulo nace apagado y se enciende al señalar la
   tira: es lo correcto cuando lo que hay dentro es un nombre, porque la foto se
   ve limpia y el dato llega cuando se pide. Aquí no: lo que hay que leer sin
   hacer nada es la trayectoria de los tres que dirigen, así que la ficha entra
   puesta y el gesto que queda es el de ensanchar.

   La foto también nace en color, sin el desvaído de espera, o la tira se leería
   como apagada teniendo su ficha encima. */
.retratos.abiertos .rotulo{opacity:1;transform:none}
.retratos.abiertos .canto{display:none}
.retratos.abiertos .retrato img{filter:none;transform:none}
.retratos.abiertos .retrato::after{opacity:.82}
/* En una fila de tres las tiras son anchas y la frase cabe entera. En una de
   cuatro no la hay, pero si algún día la hubiera, esto la deja legible. */
@media (max-width:1100px){.retrato .rotulo .bio{font-size:12.5px;max-width:none}}

/* En el teléfono no hay puntero al que responder, así que las tiras se apilan y
   se ven todas en color con su ficha puesta. No es una versión recortada del
   gesto: es la lista de siempre, que es lo que ahí funciona. */
@media (max-width:760px){
  .retratos{flex-direction:column;height:auto;gap:10px;margin-top:28px}
  .retratos + .retratos{margin-top:10px}
  .retrato{height:38svh;flex:none;will-change:auto}
  .retratos:hover .retrato,.retratos .retrato:hover{flex:none}
  .retrato .canto{display:none}
  .retrato .rotulo{opacity:1;transform:none}
  .retrato img{filter:none;transform:none;object-position:50% 6%}
  .retrato::after{opacity:.82}
  /* LOS TRES QUE DIRIGEN, APILADOS Y ABIERTOS (26-ago)

     El guion no los mete en la persiana, así que aquí caen en la columna de
     arriba. Se les da algo más de alto que a las tiras de solo nombre porque
     estos llevan la trayectoria dentro del rótulo: con 38svh la frase queda
     pegada a la cara. El velo sube un punto para que el texto no compita con
     la foto ahora que ocupa más. */
  .retratos.abiertos .retrato{height:46svh}
  .retratos.abiertos .retrato::after{opacity:.86}
}

/* ---------- EL EQUIPO EN EL TELÉFONO · APILADO ----------
   Hasta el 26-ago aquí vivía la persiana: la fila se quedaba pegada a media
   pantalla y la tira abierta iba pasando de la primera a la última según se
   bajaba, para enseñar once fotos sin gastar cuatro pantallas de scroll.

   La retiró Robert en la revisión del 26-ago: quiere las once como los tres de
   Leadership de la página About, fotos grandes apiladas una debajo de otra con
   su ficha puesta. Eso es exactamente lo que hace el bloque de `max-width:760px`
   de más arriba cuando nadie envuelve las filas, así que la versión de teléfono
   ya no necesita ni una regla propia ni JavaScript: es la lista de siempre.

   Si algún día se quiere recuperar, está entera en el historial, en el commit
   del 21-ago que la trajo. */
@media (max-width:760px){
  /* La cabecera de esta sección no lleva entradilla y lo que va debajo no es
     texto, es una pieza a pantalla: la etiqueta se pega un punto más a su
     titular y la sección arranca con menos aire que las de leer. */
  .team .eyebrow{margin-bottom:9px}
  .team{padding-top:56px}
}

/* ---------- ENCUADRES PROPIOS ----------
   El encuadre general de los retratos (`50% 8%`) da por hecho que la persona
   está centrada en su foto, y no todas lo están: son fotos de estudio con
   escenario, no recortes de ficha. Cuando la tira se abre, la ventana visible
   es bastante más estrecha que la foto (la imagen se escala por el alto y lo
   que se recorta es el ancho), así que a quien esté descolocado de lado se le
   corta justo por donde importa.

   Mey está sentada a la derecha del encuadre, con la mesa y la lámpara
   ocupando toda la mitad izquierda: su cara cae sobre el 65% del ancho, y
   centrando la ventana ahí queda ella en medio de la tira abierta.

   Va por `src` y no por una clase nueva para que valga igual en la web en
   español, donde la ruta es la misma con `../` delante y el marcado lo escribe
   `traducir.py`. Y con `.team` delante para ganarle al encuadre de la persiana,
   que sin él pesa lo mismo y va después en el archivo. */
.team .retrato img[src*="mey-ramos"]{object-position:78% 8%}

@media (prefers-reduced-motion:reduce){
  .retrato,.retrato img,.retrato .rotulo,.retrato .canto{transition:none}
}

/* ---------- CLIENTES ---------- */
.logos{display:flex;flex-wrap:wrap;margin-top:44px;border-top:1px solid var(--line);border-left:1px solid var(--line)}
.logos div{flex:1 1 190px;padding:24px 18px;border-right:1px solid var(--line);border-bottom:1px solid var(--line);
  font-size:15px;font-weight:500;color:var(--ink-soft);text-align:center;letter-spacing:-.01em}

/* ---------- CONTACTO ----------
   EL CIERRE YA NO VA A CONTRATINTA (23-ago). Hasta hoy el bloque iba en negro
   en las dos pieles con los textos en blanco escritos a mano encima, y eso lo
   dejaba fuera del sistema: era el único tramo de la portada que no era espejo
   y el único que no sabía en qué piel estaba.

   Ahora su `data-piel` es 0, o sea la piel de la página, así que en la web
   clara el contacto va en papel con el bronce haciendo el trabajo (rótulos,
   filetes, la flecha del desplegable y el botón de enviar) y en la oscura sale
   igual que estaba, sin una línea de más. Por eso aquí no queda ni un blanco
   literal: todo cuelga de los tokens, que es lo que hace que el espejo salga
   solo.

   Elegido en `muestras-cierre.html` entre cuatro versiones, con el pie
   quedándose en negro como remate (ver el bloque de abajo). */
/* El fondo NO se declara aquí: el contacto cuelga directo del lienzo, y
   `.lienzo > :not(.lienzo-fondo)` le apaga cualquier fondo propio para que lo
   pinte el degradado. Su tono es la última parada de ese degradado. */
.contact{color:var(--ink)}
.contact h2{color:var(--ink)}
/* ---------- LA PÁGINA LEGAL ----------
   Un documento, no una página de venta: una sola columna estrecha, sin foto de
   apertura y sin nada que se mueva. Lo único que importa aquí es que 45
   secciones de letra pequeña se puedan leer y encontrar.

   LA MEDIDA DE LA COLUMNA VA EN `ch` Y NO EN PÍXELES, que es lo que la hace
   legible: `74ch` son unos setenta y cinco caracteres por línea, que es el
   ancho donde el ojo vuelve al principio sin perder el renglón. En píxeles
   habría que recalcularla cada vez que cambie el cuerpo de letra.

   Los titulares de sección van en el cuerpo de la web y no en la letra de los
   títulos: en un documento numerado, un titular de display convierte el índice
   en decoración y encima estira la página a lo tonto. */
.doc{padding-top:calc(var(--barra) + 78px);color:var(--ink)}
.doc > .wrap{max-width:900px}
.doc h1{font-size:calc(clamp(30px,4vw,46px) * var(--t-scale));margin-top:6px}
.doc-cuerpo{max-width:74ch;margin-top:40px}
.doc-cuerpo p{margin:14px 0;color:var(--ink-soft);line-height:1.75;font-size:15.5px}
.doc-cuerpo em{font-style:normal;font-weight:600;color:var(--ink)}
/* La primera línea es la identificación de la empresa, no un párrafo más. */
.doc-intro{font-weight:600;color:var(--ink) !important;letter-spacing:-.01em}
.doc-cuerpo h2{font-family:var(--f-body);font-size:13px;font-weight:600;
  letter-spacing:.15em;text-transform:uppercase;color:var(--acento);
  margin:64px 0 4px;padding-top:26px;border-top:1px solid var(--line)}
.doc-cuerpo h2:first-child{margin-top:44px}
.doc-cuerpo h3{font-family:var(--f-body);font-size:16.5px;font-weight:600;
  color:var(--ink);margin:34px 0 0;letter-spacing:-.01em}
.doc-cuerpo ul{margin:14px 0;padding-left:20px;color:var(--ink-soft);
  line-height:1.75;font-size:15.5px}
.doc-cuerpo li{margin:8px 0}
.doc-cuerpo a{color:var(--ink)}
/* El aviso de la parte IV dice que lo de abajo es un resumen y que el que vale
   es el del contrato. Va marcado o se lee como una sección más. */
.doc-nota{border-left:2px solid var(--acento);padding-left:16px;font-style:italic}
.doc-pie{margin-top:56px;padding-top:24px;border-top:1px solid var(--line)}
.doc-pie p{margin:4px 0;font-size:14px}
@media (max-width:760px){.doc{padding-top:calc(var(--barra) + 48px)}
  .doc-cuerpo h2{margin-top:48px}}

/* LA PÁGINA DE CONTACTO (26-ago, la pidió Robert) usa esta misma pieza como
   página entera, y no como cierre de la portada. Dos diferencias y ninguna
   más: arranca sin foto, así que hay que dejarle el hueco de la barra fija,
   que va por encima; y su titular es `h1`, que sin esto saldría con la medida
   que le pone el navegador por defecto. La medida es la del `h2`: es la misma
   pieza, no un titular más grande. */
.contact.sola{padding-top:calc(var(--barra) + 78px)}
.contact.sola h1{font-size:calc(clamp(30px,4vw,50px) * var(--t-scale));color:var(--ink)}
@media (max-width:760px){.contact.sola{padding-top:calc(var(--barra) + 48px)}}
.contact .eyebrow{color:var(--acento)}
.contact .lead{color:var(--ink-soft)}
.contact .lead strong{color:var(--ink)}
.contact-grid{display:grid;grid-template-columns:1fr 1.1fr;gap:64px;margin-top:52px}
@media (max-width:900px){.contact-grid{grid-template-columns:1fr;gap:40px}}
.cinfo .row{padding:18px 0;border-bottom:1px solid var(--acento-tenue)}
.cinfo .k{font-size:11.5px;letter-spacing:.15em;text-transform:uppercase;color:var(--acento)}
.cinfo .v{font-size:18px;margin-top:6px;color:var(--ink)}
.cinfo .v a{text-decoration:none;color:var(--ink)}
form{display:grid;gap:16px}
.f2{display:grid;grid-template-columns:1fr 1fr;gap:16px}
@media (max-width:600px){.f2{grid-template-columns:1fr}}
form label{font-size:11.5px;letter-spacing:.14em;text-transform:uppercase;color:var(--ink-soft);
  display:block;margin-bottom:9px}
/* El campo va con fondo propio (`--sup`, la tarjeta) y no transparente. Sobre
   negro daba igual, pero sobre papel un campo transparente con filete tenue no
   se lee como campo: parece una línea suelta. */
form input,form select,form textarea{width:100%;background:var(--sup);border:1px solid var(--acento-tenue);
  color:var(--ink);padding:14px 15px;font-family:inherit;font-size:16px;border-radius:var(--radio-menudo);min-height:48px}
form textarea{min-height:118px;resize:vertical}
form input::placeholder,form textarea::placeholder{color:color-mix(in oklab,var(--ink-soft),var(--sup) 38%)}
form select{appearance:none;
  background-image:linear-gradient(45deg,transparent 50%,var(--acento) 50%),
    linear-gradient(135deg,var(--acento) 50%,transparent 50%);
  background-position:calc(100% - 19px) 21px,calc(100% - 13px) 21px;background-size:6px 6px;background-repeat:no-repeat}
form select option{color:var(--ink);background:var(--bg)}
/* El botón de enviar es la única pieza de la web que va en bronce macizo, y es
   a propósito: en el cierre claro es lo último que se hace en la página. En la
   piel oscura el bronce es el suyo, más luminoso, así que sale solo. */
form .btn{background:var(--acento);border-color:var(--acento);color:var(--sobre-acento);
  justify-self:start;padding:15px 30px}
.formnote{font-size:13px;color:var(--ink-soft);margin:0}
/* La respuesta al enviar. Antes esta linea no existia y el formulario se
   quedaba mudo, que es lo peor que puede hacer: el visitante se iba
   convencido de haber escrito. Va delante de la nota fija y pesa mas que
   ella. */
.formstatus{font-size:14.5px;line-height:1.5;margin:0;color:var(--aviso-ok);
  border-left:2px solid var(--aviso-ok);padding-left:13px}
.formstatus.malo{color:var(--aviso-mal);border-left-color:var(--aviso-mal)}
.formstatus[hidden]{display:none}
/* El campo cebo del formulario. Se saca de la pagina en vez de esconderse con
   display:none, que algunos robots ya saben leer, y queda fuera del tabulador
   por el tabindex del marcado, asi que con el teclado tampoco se llega. */
.cebo{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}

/* ---------- FOOTER ---------- */
/* EL PIE ES EL REMATE (23-ago). Al aclararse el contacto, el negro del pie
   dejó de ser "la continuación del cierre" y pasó a ser una franja baja que
   cierra la página: por eso el filete de arriba deja de ser un blanco tenue y
   pasa al bronce, que es lo que marca el corte en la web clara. En la oscura
   el pie sigue casi fundido con lo de arriba, como estaba, y el bronce se lee
   igual de bien. */
footer{background:var(--tinta-inv);color:rgba(244,241,236,.6);
  border-top:1px solid rgba(200,148,84,.30);padding:34px 0}
footer .wrap{display:flex;flex-wrap:wrap;gap:18px;justify-content:space-between;font-size:14px}
/* El aviso legal, al pie de TODAS las páginas y en letra menor, separado por un
   filete. Como caja dentro del cierre pesaba lo mismo que la llamada a
   contactar que tenía al lado, y una salvedad no puede competir con eso. Ocupa
   la línea entera del pie porque es lo último que se lee. */
footer .legal{flex:0 0 100%;margin:2px 0 0;padding-top:18px;
  border-top:1px solid rgba(244,241,236,.12);
  font-size:12px;line-height:1.55;color:rgba(244,241,236,.40);max-width:108ch}

/* VOLVER ARRIBA · BOTÓN FLOTANTE, SOLO EN LA PORTADA (26-ago, lo pidió Sebas).
   Nació como un renglón de texto al final del pie, en gris sobre negro, que es
   justo donde menos se ve y donde ya no queda nadie mirando. Ahora es un botón
   DORADO que aparece al llegar al final de la portada, al lado del globo del
   asistente y con su misma medida y su misma sombra: los dos se leen como la
   misma familia de mandos flotantes, uno para hablar y otro para volver.

   LLEVA EL TEXTO ESCRITO, no solo la flecha: una flecha suelta en una esquina
   hay que adivinarla, y este botón sale una vez, al final, para quien ya ha
   bajado toda la portada. Por eso es una píldora y no un círculo como el globo.

   La flecha va en el pseudo, como iba antes, para que el nodo de texto quede
   limpio: es lo que el traductor busca para dar con la frase.

   VA CENTRADO ABAJO, y no al lado del globo, por una razón de sitio: el panel
   del asistente mide 384 de ancho anclado a la esquina derecha, así que un
   botón puesto a su izquierda queda debajo del panel en cuanto alguien lo abre.
   En el centro no se pisan nunca, y encima cae donde el ojo ya está mirando al
   terminar de bajar. Solo en el teléfono sigue apagándose con el chat abierto,
   porque allí el panel ocupa la pantalla entera y no hay centro que valga. */
footer .arriba{position:fixed;left:50%;bottom:26px;z-index:61;
  display:inline-flex;align-items:center;gap:9px;
  height:52px;padding:0 22px;border-radius:999px;text-decoration:none;
  background:var(--acento);color:var(--sobre-acento);
  font-size:13.5px;font-weight:600;letter-spacing:.03em;white-space:nowrap;
  box-shadow:0 14px 32px var(--sombra);
  opacity:0;transform:translateX(-50%) translateY(14px) scale(.94);pointer-events:none;
  transition:opacity .45s var(--ease),transform .45s var(--ease)}
footer .arriba::after{content:"\2191";font-size:16px;line-height:1;font-weight:600}
/* La clase la pone el guion cuando el pie entra en pantalla. */
body.fin-on footer .arriba{opacity:1;transform:translateX(-50%);pointer-events:auto}
body.fin-on footer .arriba:hover,
body.fin-on footer .arriba:focus-visible{transform:translateX(-50%) translateY(-2px)}
@media (max-width:640px){footer .arriba{height:46px;padding:0 17px;font-size:12.5px;gap:7px}
  /* Aquí el panel del asistente sí ocupa la pantalla entera. */
  body.chat-on footer .arriba{opacity:0;transform:translateX(-50%) scale(.85);pointer-events:none}}

/* ============================================================
   PÁGINA DE PROYECTO
   ============================================================ */
/* Igual que el de portada: sin hueco reservado, la isla flota por encima. */
/* EL TEXTO DE ESTE HERO VA EN TINTA, NO EN BLANCO (25-ago).
   Hasta hoy era blanco sobre un velo negro, que es la herencia de cuando la
   web entera iba en oscuro. Con la web en claro, el titular de la ficha era lo
   unico que quedaba al reves que el resto de la pagina, y ademas era donde
   peor se leia: blanco fino sobre foto con detalle.

   Al pasar la letra a tinta, el velo tiene que cambiar con ella: negro debajo
   de texto negro no se lee. Ahora es el MISMO velo que usan las aperturas, del
   color de la piel, solo que vertical en vez de lateral. Y va escrito en
   tokens, no en negros literales, asi que la piel oscura de `/oscuro` sigue
   funcionando sola: alli `--bg` es negro y `--ink` es claro, y el hero vuelve
   a ser texto claro sobre velo oscuro sin una linea mas.

   El fondo de la caja mientras la foto carga tambien deja el negro literal por
   el token del hueco de foto, o durante ese instante habria tinta sobre negro. */
.p-hero{position:relative;height:78vh;height:78svh;min-height:520px;overflow:hidden;
  background:var(--foto-vacia)}
.p-hero img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.p-hero .scrim{position:absolute;inset:0;
  background:linear-gradient(to top,
    color-mix(in srgb,var(--bg) 94%,transparent) 0%,
    color-mix(in srgb,var(--bg) 80%,transparent) 34%,
    color-mix(in srgb,var(--bg) 28%,transparent) 64%,
    transparent 100%)}
.p-hero .inner{position:absolute;inset:auto 0 0 0;padding-bottom:52px;color:var(--ink)}
/* EL ENLACE DE VUELTA ES UN BOTON (25-ago).
   Era texto suelto en gris sobre la foto, o sea lo primero que se perdia, y
   ademas no se leia como algo que se pulsa. Ahora es una pastilla con la misma
   forma que el resto de botones de la web (la pildora de `.btn`), pero en
   version clara: fondo de la piel casi opaco y filete fino, para que se apoye
   en la foto sin pesar como el boton principal de la barra. Al señalarlo se da
   la vuelta y pasa a tinta llena, que es como se comporta `.btn.ghost`.

   Va del mismo modo en las dos familias de hero, y en las aperturas ademas
   estrena estilo: alli el `.back` no tenia ninguno.

   La flecha se queda DENTRO del texto del marcado y no en un `::before`: el
   traductor busca por texto exacto, asi que "← All work" y su pareja en
   español son la cadena entera. Sacarla romperia las dos. */
.p-hero .back,
.ap-tx .back,
.contact.sola .back{
  display:inline-flex;align-items:center;justify-content:center;
  min-height:38px;padding:8px 17px;margin-bottom:20px;
  border-radius:999px;
  font-family:var(--f-body);font-size:13.5px;font-weight:500;letter-spacing:.01em;
  color:var(--ink);text-decoration:none;
  background:color-mix(in srgb,var(--bg) 86%,transparent);
  border:1px solid color-mix(in srgb,var(--ink) 20%,transparent);
  transition:background .28s var(--ease),color .28s var(--ease),border-color .28s var(--ease)}
.p-hero .back:hover,.p-hero .back:focus-visible,
.ap-tx .back:hover,.ap-tx .back:focus-visible,
.contact.sola .back:hover,.contact.sola .back:focus-visible{
  background:var(--ink);border-color:var(--ink);color:var(--bg)}
/* EL NOMBRE DE LA OBRA VA EN UNA LÍNEA (25-ago). Antes lo ataba un
   `max-width:16ch` que lo partía en dos con media pantalla libre a la derecha:
   "Cat Cay Guest House" cortaba después de Guest, y un nombre propio partido
   se lee como dos cosas en vez de como el nombre de la obra.

   No hace falta límite ninguno: el más largo de todo lo que usa este hero
   ("Residential Duplex 6955" y "Legalizations & permits", los dos de 23
   caracteres) ocupa unos 710px de los 1184 del bloque, y por debajo de 1280px
   el cuerpo baja con la ventana al mismo ritmo que el ancho, así que la
   proporción no cambia y sigue cabiendo. */
.p-hero h1{font-size:calc(clamp(34px,5vw,64px) * var(--t-scale));white-space:nowrap}
.p-hero .where{margin-top:16px;font-size:18px;color:var(--ink)}
@media (max-width:640px){.p-hero{height:68vh;height:68svh;min-height:420px}
  .p-hero .inner{padding-bottom:38px}
  /* En el teléfono sí puede partir: en una línea habría que bajarlo a un
     cuerpo que ya no titula nada. Parte por donde toque, con las líneas
     igualadas para que no quede una larga y una de dos palabras. */
  .p-hero h1{white-space:normal;text-wrap:balance}}
/* Portada corta: la de una página que es sobre todo contenido, no una obra. */
.p-hero.corto{height:52vh;height:52svh;min-height:360px}
@media (max-width:640px){.p-hero.corto{height:46vh;height:46svh;min-height:300px}}


.p-body{display:grid;grid-template-columns:1fr 1.2fr;gap:64px;align-items:start}
@media (max-width:900px){.p-body{grid-template-columns:1fr;gap:28px}}
/* ---------- CÓMO FUE (línea de tiempo del caso) ----------
   Una columna con la línea a la izquierda y un punto por hito. Vertical
   también en pantalla grande: se lee de un tirón y no obliga a inventar
   una versión distinta para el móvil. */
.how{background:var(--bg-alt);border-top:1px solid var(--line);border-bottom:1px solid var(--line)}
.road{margin-top:48px;max-width:740px;padding-left:14px}
.mile{position:relative;padding:0 0 38px 52px;border-left:1px solid var(--line-fuerte);min-height:60px}
.mile:last-child{padding-bottom:0;border-left-color:transparent}
/* El hito es el icono: mismo círculo que en el camino del permiso */
.mile .ic{top:-3px;left:-22px;width:44px;height:44px}
.mile:hover .ic{border-color:var(--ink);transform:translateY(-2px)}
.mile .when{font-size:11.5px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--ink-soft);font-weight:600}
.mile h3{font-size:calc(19px * var(--t-scale));margin:9px 0 7px}
.mile p{margin:0;font-size:15.5px;line-height:1.55;color:var(--ink-soft);max-width:58ch}

/* ---------- EL CAMINO DEL PERMISO ----------
   Seis etapas cruzadas por una línea. En pantalla ancha la línea es
   horizontal y las etapas van en fila; al estrecharse pasa a dos filas de
   tres, y en el teléfono se pone de pie con la línea a la izquierda, igual
   que la línea de tiempo del proyecto. */
.path{display:grid;grid-template-columns:repeat(6,1fr);margin-top:64px}
.path .st{position:relative;border-top:1px solid var(--line-fuerte);padding:44px 20px 0 0}
/* El icono hace de hito sobre la línea, así que su fondo es opaco para
   cortarla limpio. Trazo fino y sin relleno, como el resto del dibujo. */
.ic{position:absolute;top:-24px;left:0;width:48px;height:48px;border-radius:50%;
  background:var(--sup);border:1px solid var(--line-fuerte);display:grid;place-items:center;
  transition:border-color .35s ease,transform .35s var(--ease)}
.ic svg{width:23px;height:23px;fill:none;stroke:var(--ink);stroke-width:1.4;
  stroke-linecap:round;stroke-linejoin:round}
.st:hover .ic{border-color:var(--ink);transform:translateY(-2px)}
.path .n{font-size:11.5px;letter-spacing:.16em;color:var(--ink-soft);font-weight:600}
.path h3{font-size:calc(17px * var(--t-scale));margin:9px 0 7px;line-height:1.2}
.path p{margin:0;font-size:14.5px;line-height:1.5;color:var(--ink-soft)}
/* Con las seis en fila, los títulos de una y de dos líneas descuadraban el
   arranque de los párrafos. Se les reserva el alto de dos líneas. */
@media (min-width:1081px){.path h3{min-height:2.4em}}
@media (max-width:1080px){.path{grid-template-columns:repeat(3,1fr);row-gap:36px}}
/* Dos secciones seguidas con el mismo fondo se leen como una sola */
.how + .next{background:var(--bg)}
/* En vertical la línea se separa del borde para que el círculo del icono no
   quede lamiendo el canto de la pantalla. */
@media (max-width:700px){.path{grid-template-columns:1fr;row-gap:0;margin-top:36px;padding-left:14px}
  .path .st{border-top:0;border-left:1px solid var(--line-fuerte);padding:0 0 34px 48px;min-height:62px}
  .path .st:last-child{padding-bottom:0;border-left-color:transparent}
  .ic{top:-3px;left:-21px;width:42px;height:42px}
  .ic svg{width:20px;height:20px}
  .path h3{font-size:calc(18px * var(--t-scale))}
  .path p{font-size:15px}}
.how .note{margin-top:52px}

/* ---------- EL CAMINO, EN FILAS QUE SE ABREN ----------
   La variante `.abre` del camino, elegida el 24-ago en `muestras-proceso.html`
   contra la cinta que avanza pegada y contra los pasos apilados.

   QUÉ ARREGLA, que son las dos quejas y no una. La primera es de reparto: seis
   pasos en seis columnas dejan cada uno en unos 190px, y ahí el título se
   parte en dos líneas, el texto entra justo y el icono queda de adorno. En
   filas, cada paso tiene el ancho entero de la página y cabe lo que haya que
   contar. La segunda es de movimiento: el bloque entraba deslizándose desde la
   izquierda y ahí se quedaba, así que detrás de una apertura que ocupa cuatro
   pantallas se leía como una tabla.

   LA APERTURA VA EN TRES TIEMPOS, y ese es todo el gesto: primero el filete se
   traza de izquierda a derecha, después el número crece desde pequeño, y por
   último entra el texto. Los tres se solapan. Hecho de una vez sería otra
   entrada más de las que ya tiene la web; escalonado se lee como que la fila
   SE ABRE, que es lo que cuenta un proceso: una cosa detrás de otra.

   EL RELOJ ES CADA FILA, con `view()` y sin nombre. Por eso este bloque queda
   FUERA del motor de revelado de `site.js` (con `:not(.abre)` en sus dos
   grupos): si el motor le escribiera su opacidad encima, se comería los tres
   tiempos y volveríamos a tener una entrada de una pieza. */
.path.abre{display:block;margin-top:52px}
/* El `border-top` y el `border-left` se quitan los dos: el de arriba porque
   aquí el filete lo pinta el `::before` (que es lo que se traza), y el de la
   izquierda porque el camino de siempre se pone de pie en el teléfono con una
   línea vertical, y esa línea aquí sobra. */
.path.abre .st{position:relative;border-top:0;border-left:0;padding:34px 0 30px;
  display:grid;grid-template-columns:96px 60px minmax(0,1fr);
  gap:0 30px;align-items:start}
/* El filete es del acento y no de la línea gris: es lo único que se traza, y
   en gris el gesto no se ve. */
.path.abre .st::before{content:"";position:absolute;left:0;right:0;top:0;height:1px;
  background:var(--acento-tenue);transform:scaleX(1);transform-origin:left}
.path.abre .n{grid-column:1;grid-row:1 / span 3;
  font-size:calc(34px * var(--t-scale));letter-spacing:0;line-height:1;
  color:var(--acento);font-weight:600}
/* El icono deja de ser el hito clavado sobre una línea y pasa a estar en el
   flujo, así que hay que quitarle el `position:absolute` de `.ic`. */
.path.abre .ic{position:static;grid-column:2;grid-row:1 / span 3;
  width:46px;height:46px;background:none;border-color:var(--acento-tenue)}
.path.abre .ic svg{width:21px;height:21px;stroke:var(--acento)}
.path.abre .st:hover .ic{border-color:var(--acento);transform:translateY(-2px)}
.path.abre h3{grid-column:3;grid-row:1;margin:0;
  font-size:calc(23px * var(--t-scale));min-height:0}
.path.abre p{grid-column:3;grid-row:2;margin-top:9px;
  font-size:15.5px;line-height:1.55;max-width:62ch}
/* La segunda línea, para los pasos que la tengan. */
.path.abre p.mas{grid-row:3;margin-top:10px;font-size:15px;color:var(--ink-soft)}

@media (max-width:820px){
  .path.abre{margin-top:36px;padding-left:0}
  .path.abre .st{grid-template-columns:64px minmax(0,1fr);gap:0 20px;
    padding:26px 0 24px}
  .path.abre .n{font-size:calc(26px * var(--t-scale))}
  /* El icono se cae en el teléfono: con el ancho justo, o está él o está el
     texto, y el texto es lo que se ha venido a leer. */
  .path.abre .ic{display:none}
  .path.abre h3,.path.abre p,.path.abre p.mas{grid-column:2}
  .path.abre h3{font-size:calc(19px * var(--t-scale))}
}

@supports (animation-timeline: view()){
  @media (prefers-reduced-motion:no-preference){
    /* Los tres tiempos. Sin soporte, o con el movimiento reducido, la fila
       sale puesta: el filete entero y todo a la vista. */
    .path.abre .st::before{transform:scaleX(0);
      animation:abre-filete cubic-bezier(.22,.61,.36,1) both;
      animation-timeline:view();animation-range:entry 4% entry 46%}
    @keyframes abre-filete{from{transform:scaleX(0)}to{transform:scaleX(1)}}

    .path.abre .n{animation:abre-numero cubic-bezier(.22,.61,.36,1) both;
      animation-timeline:view();animation-range:entry 12% entry 58%}
    @keyframes abre-numero{
      from{opacity:0;transform:translateY(14px) scale(.7)}
      to  {opacity:1;transform:none}
    }

    .path.abre .ic,.path.abre h3,.path.abre p{
      animation:abre-texto cubic-bezier(.22,.61,.36,1) both;
      animation-timeline:view();animation-range:entry 18% entry 70%}
    @keyframes abre-texto{
      from{opacity:0;transform:translateY(12px)}
      to  {opacity:1;transform:none}
    }
  }
}

/* Cierre del caso: el resultado en tres datos, con las mismas fichas que la
   franja de licencias, para no inventar un componente nuevo. */
.outcome{display:grid;grid-template-columns:repeat(3,1fr);gap:18px;margin-top:52px}
@media (max-width:760px){.road{margin-top:36px}.mile{padding:0 0 32px 48px}
  .mile .ic{left:-21px;width:42px;height:42px}
  .mile .ic svg{width:20px;height:20px}
  .mile p{font-size:15px}
  .outcome{grid-template-columns:1fr;gap:14px;margin-top:40px}}

.gallery{display:grid;grid-template-columns:repeat(2,1fr);gap:20px;margin-top:52px}
.gallery .tall{grid-column:span 2}
.gallery figure{margin:0;position:relative;aspect-ratio:4/3;overflow:hidden;background:var(--foto-vacia);
  border-radius:var(--radio-pieza)}
.gallery .tall figure{aspect-ratio:16/9}
.gallery img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
@media (max-width:600px){.gallery{grid-template-columns:1fr}.gallery .tall{grid-column:span 1}}

.next{background:var(--bg-alt);border-top:1px solid var(--line)}
.next .row{display:flex;justify-content:space-between;align-items:center;gap:24px;flex-wrap:wrap;margin-top:34px}

/* ============================================================
   ASISTENTE
   ============================================================ */
.chat-fab{position:fixed;right:26px;bottom:26px;z-index:61;width:52px;height:52px;border-radius:50%;
  background:var(--ink);border:0;padding:0;display:grid;place-items:center;cursor:pointer;
  box-shadow:0 14px 32px var(--sombra);transition:transform .25s ease}
.chat-fab:hover{transform:translateY(-2px)}
.chat-fab img{width:23px;height:23px;object-fit:contain}
.chat-fab .badge{position:absolute;top:2px;right:2px;width:11px;height:11px;border-radius:50%;
  background:#3FBF6E;border:2px solid var(--bg)}
body.chat-on .chat-fab{opacity:0;transform:scale(.75) translateY(6px);pointer-events:none}

/* El panel no se enciende y se apaga: crece desde la esquina del globo al
   abrir y vuelve a ella al cerrar. En móvil sube desde el borde inferior. */
.assistant{position:fixed;right:26px;bottom:26px;width:384px;max-width:calc(100vw - 32px);
  height:min(620px,calc(100dvh - 52px));z-index:62;background:var(--bg);border:1px solid var(--line);
  border-radius:var(--radio-isla);box-shadow:0 30px 70px var(--sombra);overflow:hidden;
  display:grid;grid-template-rows:auto 1fr auto;
  transform-origin:100% 100%;opacity:0;visibility:hidden;
  transform:scale(.82) translateY(26px);
  transition:opacity .3s var(--ease),transform .42s var(--ease),visibility 0s linear .42s}
body.chat-on .assistant{opacity:1;visibility:visible;transform:none;
  transition:opacity .28s var(--ease),transform .48s cubic-bezier(.2,.9,.3,1),visibility 0s}

/* Las burbujas y los botones de sugerencia entran uno detrás de otro */
.bubble,.chips,.wa-cta{animation:burbuja .42s var(--ease) both}
@keyframes burbuja{from{opacity:0;transform:translateY(10px) scale(.98)}to{opacity:1;transform:none}}

.assistant .head{display:flex;align-items:center;gap:12px;padding:15px 16px;
  border-bottom:1px solid var(--line);background:var(--sup)}
.assistant .head .av{width:38px;height:38px;border-radius:50%;background:var(--ink);
  display:grid;place-items:center;flex:0 0 auto}
.assistant .head .av img{width:19px;height:19px;object-fit:contain}
.assistant .head b{font-size:15px;font-weight:600;letter-spacing:-.01em;display:block}
.assistant .head span{font-size:12px;color:var(--ink-soft)}
.assistant .head .x{margin-left:auto;width:32px;height:32px;border:0;background:transparent;
  color:var(--ink-soft);font-size:20px;line-height:1;cursor:pointer;border-radius:50%}
.assistant .head .x:hover{background:var(--bg-alt)}

.assistant .body{padding:16px;overflow-y:auto;display:flex;flex-direction:column;gap:10px}
.bubble{padding:12px 14px;border-radius:var(--radio-menudo);font-size:14.5px;line-height:1.5;max-width:90%}
.bubble.them{background:var(--bg-alt);border:1px solid var(--line);align-self:flex-start}
.bubble.me{background:var(--ink);color:var(--bg);align-self:flex-end}
.chips{display:flex;flex-wrap:wrap;gap:8px;margin-top:2px}
.chip{border:1px solid var(--line);background:var(--sup);color:var(--ink);border-radius:40px;
  padding:9px 14px;font-size:13.5px;font-family:var(--f-body);cursor:pointer;line-height:1.3;text-align:left}
.chip:hover{border-color:var(--ink)}
/* ── La nube que invita a preguntar ─────────────────────────────────────────
   Asoma del globo del asistente a medida que se baja. Elegida el 26-ago en
   `muestras-avisos.html` contra la tira de aviso y contra el panel que ya ha
   empezado a hablar: gana porque el pico la ata al globo y se lee como que ha
   hablado quien vive ahí, no como un cartel del navegador.

   Va por debajo del globo (61) y del panel: si el asistente se abre, la nube
   ya se ha ido, pero el orden lo sostiene igual. */
.aviso{position:fixed;right:26px;bottom:90px;z-index:60;max-width:290px;cursor:pointer;
  background:var(--sup);color:var(--ink);border:1px solid var(--line);
  border-radius:var(--radio-menudo);box-shadow:0 14px 40px var(--sombra-suave);
  padding:13px 34px 13px 15px;font-family:var(--f-body);font-size:14px;line-height:1.45;
  transform-origin:100% 100%}
/* El pico, girado 45 grados y con solo dos lados de borde, que son los que se
   ven fuera de la nube. */
.aviso::after{content:"";position:absolute;right:18px;bottom:-7px;width:12px;height:12px;
  background:var(--sup);border-right:1px solid var(--line);border-bottom:1px solid var(--line);
  transform:rotate(45deg)}
.aviso .x{position:absolute;top:6px;right:6px;width:22px;height:22px;border:0;
  background:transparent;color:var(--ink-soft);font-size:15px;line-height:1;
  cursor:pointer;border-radius:50%}
.aviso .x:hover{background:var(--bg-alt)}
.aviso-entra{animation:aviso-asoma .34s var(--ease) both}
.aviso-sale{animation:aviso-retira .22s ease both}
@keyframes aviso-asoma{from{opacity:0;transform:translateY(10px) scale(.94)}to{opacity:1;transform:none}}
@keyframes aviso-retira{to{opacity:0;transform:translateY(8px) scale(.96)}}
@media (prefers-reduced-motion:reduce){.aviso-entra,.aviso-sale{animation:none}}

/* El botón del informe: dibujo de WhatsApp y texto, centrados juntos. Era
   `block` con `text-align`, y con el icono dentro hace falta que las dos
   piezas se alineen por su centro, que es lo que `flex` resuelve sin números
   mágicos de desplazamiento vertical. */
.wa-cta{display:flex;align-items:center;justify-content:center;gap:9px;
  text-decoration:none;padding:12px 14px;border:1px solid var(--ink);
  color:var(--ink);font-size:14px;font-weight:500;border-radius:var(--radio-menudo);margin-top:4px}
.wa-cta svg{flex:0 0 auto}
.wa-cta:hover{background:var(--ink);color:var(--bg)}

.assistant .composer{border-top:1px solid var(--line);background:var(--sup);padding:12px 14px;
  display:flex;gap:10px;align-items:flex-end}
.assistant .composer textarea{flex:1;border:1px solid var(--line);border-radius:var(--radio-isla);padding:11px 15px;
  font-family:var(--f-body);font-size:14.5px;resize:none;max-height:96px;min-height:44px;line-height:1.4;
  background:var(--bg);color:var(--ink)}
.assistant .composer textarea:focus{outline:none;border-color:var(--ink)}
.assistant .composer button{width:44px;height:44px;border-radius:50%;border:0;background:var(--ink);
  color:var(--bg);font-size:17px;cursor:pointer;flex:0 0 auto}
.assistant .foot{font-size:11.5px;color:var(--ink-soft);text-align:center;padding:0 14px 11px;background:var(--sup)}

@media (max-width:640px){
  .assistant{right:0;bottom:0;left:0;top:0;width:100%;max-width:none;height:100dvh;
    border:0;border-radius:0;box-shadow:none;
    transform-origin:50% 100%;transform:translateY(100%)}
  body.chat-on .assistant{transform:none}
  .assistant .head{padding:14px 16px;padding-top:max(14px,env(safe-area-inset-top))}
  .assistant .composer{padding-bottom:max(12px,env(safe-area-inset-bottom))}
  .chat-fab{right:18px;bottom:18px}
  footer .arriba{bottom:18px}
  .aviso{right:14px;left:14px;max-width:none;bottom:84px}
}

/* ============================================================
   MOVIMIENTO
   Above the fold en CSS puro (no espera al JS). Lo de abajo,
   revelado al entrar en pantalla. Todo con transform y opacity,
   y anulado entero con prefers-reduced-motion.
   ============================================================ */

:root{--ease:cubic-bezier(.22,.61,.36,1)}

/* Hero: la foto se asienta, y titular, entradilla y botones entran escalonados */
.hero img,.hero video,.p-hero img{animation:hero-settle 2.6s var(--ease) both}
@keyframes hero-settle{from{transform:scale(1.09)}to{transform:scale(1)}}

/* El vídeo de portada no se queda quieto: sigue acercándose muy despacio y
   vuelve, sin corte. Van dos animaciones sobre el mismo elemento y manda la
   segunda una vez que el asentamiento ha terminado. */
.hero-video{animation:hero-settle 2.6s var(--ease) both,
                     hero-viaje 40s linear 2.6s infinite alternate}
@keyframes hero-viaje{from{transform:scale(1)}to{transform:scale(1.1)}}

/* El titular entra palabra a palabra. Cada palabra es una ventana con su
   propia letra dentro, que sube desde abajo: por eso hacen falta las dos
   capas, la de fuera recorta y la de dentro viaja. El troceado lo hace el
   guion, y lo rehace al cambiar de idioma. */
.hero h1 .pal{display:inline-block;overflow:hidden;vertical-align:bottom;
  padding-bottom:.06em;margin-bottom:-.06em}
.hero h1 .pal > i{display:inline-block;font-style:inherit;
  transform:translateY(108%);opacity:0;
  animation:pal-entra 1.35s var(--ease) both;animation-delay:var(--d,0s)}
@keyframes pal-entra{to{transform:none;opacity:1}}

/* La portada se va al bajar: el bloque de texto sube más despacio que la
   página y se apaga mientras entra la franja de licencias. `--sal` lo escribe
   el guion, de 0 (arriba del todo) a 1 (hero fuera de pantalla). */
.hero .inner{will-change:transform,opacity;
  transform:translateY(calc(var(--sal,0) * -54px));
  opacity:calc(1 - var(--sal,0) * 1.25)}
/* Con el recorrido puesto el bloque no se mueve con `--sal`, así que la capa
   reservada no sirve de nada y se queda ocupando memoria de vídeo durante toda
   la página. */
.scrolly .hero .inner{will-change:auto}

/* Con el recorrido puesto, esas dos cosas las hace el relevo y sobran las de
   aquí: el bloque de texto ya no se va entero (se releva mensaje a mensaje) y
   el vídeo ya no se acerca solo (el scroll manda su tiempo, y un zoom encima
   de un fotograma buscado a mano se ve como un tirón). */
.scrolly .hero .inner{transform:none;opacity:1}
.scrolly .hero-video{animation:hero-settle 2.6s var(--ease) both}

/* EL VELO TAMBIÉN ENTRA (26-ago). Era lo único del hero de las páginas
   propias que no lo hacía: la foto se asienta durante 2,6s y el titular, la
   bajada de línea y el botón suben escalonados, pero el velo estaba puesto
   entero desde el primer cuadro. Puesto de golpe encima de una foto que sí se
   mueve, se lee como una sombra que ha caído ahí, no como parte de la entrada.

   SUBE DESDE ABAJO, que es de donde tiene que subir: se escala en vertical con
   el anclaje en el borde inferior, que es justo el lado donde el velo es
   opaco. Lo que se descubre arriba mientras dura ya era transparente, así que
   no se ve ningún corte.

   VA POR DELANTE DEL TITULAR a propósito, y esa es la parte que no se puede
   tocar sin mirar: el velo es lo que le da fondo a la letra para leerse. Con
   esta curva, a los 0,4s ya está casi entero y el titular todavía está
   subiendo, así que en ningún momento hay tinta sobre foto pelada.

   `opacity` y `scaleY` son las dos cosas que el navegador mueve sin volver a
   pintar, así que esto no le quita nada a la foto que se está asentando al
   mismo tiempo. */
.p-hero .scrim{transform-origin:50% 100%;animation:velo 1.4s var(--ease) both}
@keyframes velo{from{opacity:0;transform:scaleY(.86)}to{opacity:1;transform:none}}

.p-hero h1{animation:rise 1.5s var(--ease) .18s both}
.hero .sub,.p-hero .where{animation:rise 1.5s var(--ease) .44s both}
.hero .cta{animation:rise 1.5s var(--ease) .66s both}
/* Con el recorrido puesto, la entrada de la frase y de los botones la lleva el
   revelado de la web, que es el mismo que usa el resto de las secciones. Estas
   dos de aquí hay que APAGARLAS, no dejarlas convivir: una animación con
   `both` deja fijada la opacidad al terminar y le gana en la cascada a la
   transición del revelado, así que el mensaje aparecería ya puesto y el gesto
   no se vería nunca. Es la misma trampa que la de la isla, unas líneas arriba. */
.scrolly .mensaje .sub,.scrolly .mensaje .cta{animation:none}
.p-hero .back{animation:rise 1.3s var(--ease) .06s both}
@keyframes rise{from{opacity:0;transform:translateY(18px)}to{opacity:1;transform:none}}

/* La entrada va sobre la ISLA y no sobre `.nav`: una animación con `both` deja
   fijada la opacidad del elemento, y el marco tiene que quedar libre para que
   cualquier estado que lo apague no se encuentre con una opacidad clavada. */
.nav .wrap{animation:fade 1.2s var(--ease) both}
@keyframes fade{from{opacity:0}to{opacity:1}}

/* Con telón puesto, el hero espera a que la K termine de abrir */
html:not(.sin-intro) .hero img,html:not(.sin-intro) .hero video,
html:not(.sin-intro) .p-hero img,html:not(.sin-intro) .p-hero .scrim{animation-delay:2.3s}
html:not(.sin-intro) .nav .wrap{animation-delay:2.55s}
html:not(.sin-intro) .p-hero .back{animation-delay:2.6s}
html:not(.sin-intro) .hero h1,html:not(.sin-intro) .p-hero h1{animation-delay:2.7s}
html:not(.sin-intro) .hero .sub,html:not(.sin-intro) .p-hero .where{animation-delay:2.96s}
html:not(.sin-intro) .hero .cta{animation-delay:3.16s}

/* La barra NO se toca aquí. Todo lo suyo (fondo, sombra, alto, apretarse al
   bajar y apartarse) vive arriba, en el bloque NAV · ISLA FLOTANTE, y en un
   solo sitio a propósito.

   Aquí había el resto de la barra de antes: un `box-shadow` sobre `.nav`, que
   ocupa todo el ancho de la pantalla, así que dibujaba una sombra de lado a
   lado justo donde estaba el filete de la barra vieja. Y de paso, por venir
   más abajo en el archivo con la misma especificidad, su `transition` pisaba
   la de la isla y la dejaba sin transición ninguna: se apartaba de golpe por
   mucho que se le subiera la duración arriba.

   La sombra ahora va sobre la ISLA, que es lo que tiene que proyectarla. */

/* ---------- ENTRADA A LA WEB ----------
   La K en el centro, crece hasta comerse la pantalla y deja la home detrás.
   Solo la primera carga de la pestaña: al navegar entre páginas no reaparece
   (la marca la pone un script en el <head>, así no llega a verse el telón). */
.intro{position:fixed;inset:0;z-index:200;background:var(--bg);
  display:grid;place-items:center;animation:intro-telon 3s var(--ease) forwards}
/* ---------- EL LOGO ENTRA EN ESCENA ----------
   El telón no enseña el logo: lo monta delante. Primero se traza el marco (los
   montantes crecen desde su centro y los travesaños se abren hacia los lados,
   con un punto de retraso, que es lo que se lee como trazado y no como que
   aparece), después entra la K subiendo, y al final se aclaran las letras. Ya
   con el logo completo, el conjunto crece y se va.

   Para poder animarlo por piezas, el logo que mandó Robert va separado en
   cuatro PNG recortados del original y con el MISMO lienzo, así que se apilan
   uno sobre otro y encajan solos. Van en su versión para fondo oscuro (marco y
   KHRONOS en el crema de la web, K y filete en su dorado); en la piel clara
   entran las fieles, con esas partes en negro.

   Los tiempos de aquí y el `setTimeout` que retira el telón en el guion son el
   mismo número: si se toca uno, se toca el otro. */
/* Tres segundos de telón, repartidos: hasta 1,55 se monta el logo, un respiro
   corto para leerlo, y de 1,75 a 3 la crecida. Más de eso deja de ser una
   entrada y pasa a ser una espera. */
.intro-logo{position:relative;width:min(320px,64vw);aspect-ratio:999/820;
  animation:intro-salida 1.25s var(--ease) 1.75s forwards}
.intro-logo img{position:absolute;inset:0;width:100%;height:100%;object-fit:contain}

/* 1 · los montantes crecen desde su centro */
.intro-logo .c-marco-v{clip-path:inset(50% 0 50% 0);
  animation:traza-v .72s var(--ease) both}
/* 2 · los travesaños se abren hacia los lados, un punto después */
.intro-logo .c-marco-h{clip-path:inset(0 50% 0 50%);
  animation:traza-h .72s var(--ease) .2s both}
/* 3 · la K sube y entra */
.intro-logo .c-k{animation:entra-k .6s var(--ease) .68s both}
/* 4 · las letras se aclaran en su sitio */
.intro-logo .c-tx{animation:entra-tx .55s var(--ease) 1s both}

@keyframes traza-v{from{clip-path:inset(50% 0 50% 0)}to{clip-path:inset(0 0 0 0)}}
@keyframes traza-h{from{clip-path:inset(0 50% 0 50%)}to{clip-path:inset(0 0 0 0)}}
@keyframes entra-k{from{opacity:0;transform:translateY(13%)}to{opacity:1;transform:none}}
@keyframes entra-tx{from{opacity:0;transform:translateY(5%)}to{opacity:1;transform:none}}

/* La salida: el logo ya montado crece y se lleva el telón por delante. Menos
   crecida que con la marca sola, que un logo con texto dentro escalado
   veintiséis veces se lee como un borrón. */
@keyframes intro-salida{
  0%{transform:scale(1);opacity:1}
  100%{transform:scale(13);opacity:0}
}
/* El fondo aguanta hasta el final: lo que se va es la crecida, no el telón, o
   se ve la portada por detrás a media salida. */
@keyframes intro-telon{
  0%,80%{opacity:1}
  100%{opacity:0;visibility:hidden}
}

/* LAS CUATRO CAPAS DEL TELON, Y CUAL VA EN EL MARCADO (25-ago).
   Antes el marcado llevaba el juego de la piel oscura y esta regla lo cambiaba
   por el de la clara, que es la que se publica. El navegador se traia LOS DOS:
   el buscador de recursos pide el `src` del marcado mucho antes de que el CSS
   diga nada, y luego el `content` pide el otro. Eran 142 KB de telon en cada
   pagina para ver 71.

   Ahora el marcado lleva el juego de la piel CLARA, que es la que ve todo el
   mundo, y esta regla solo entra por `/oscuro`. Y los ocho archivos han pasado
   de PNG a WebP SIN PERDIDA: mismo dibujo pixel a pixel, comprobado, de 71 KB
   el juego a 29. */
html:not([data-theme="light"]) .intro-logo .c-marco-v{content:url("LOGO-cap-marco-v-claro.webp")}
html:not([data-theme="light"]) .intro-logo .c-marco-h{content:url("LOGO-cap-marco-h-claro.webp")}
html:not([data-theme="light"]) .intro-logo .c-k{content:url("LOGO-cap-k-claro.webp")}
html:not([data-theme="light"]) .intro-logo .c-tx{content:url("LOGO-cap-tx-claro.webp")}

/* Con el telón puesto, la página no se mueve por debajo */
body.intro-on{overflow:hidden}
html.sin-intro .intro{display:none}

/* Revelado al entrar en pantalla. La dirección la marca data-dir, para que no
   entre todo subiendo: hay bloques que llegan de los lados, de arriba o con
   un punto de zoom. */
/* El ritmo del revelado va aquí, y solo aquí: un revelado que dura poco más
   de medio segundo se lee como una web que reacciona; uno de segundo y pico
   con más recorrido se lee como una que respira. Es lo que se toca si hay que
   subir o bajar el pulso de toda la página de una vez (el escalonado entre
   piezas lo lleva el guion, en su propia constante). */
.reveal{opacity:0;
  transition:opacity 1.25s var(--ease),transform 1.4s var(--ease);
  transition-delay:var(--d,0s)}
/* EL VIAJE VERTICAL NO PUEDE PASAR DEL AIRE QUE HAY ENTRE DOS PIEZAS, y esto
   costó tres vueltas de "arregla el espaciado" para verlo: lo que se veía era
   el titular ESCRITO ENCIMA de su entradilla, y el aire estático estaba bien.
   Un elemento que entra desplazado no empuja a nadie (es un `transform`), así
   que mientras dura el gesto ocupa un sitio que no es el suyo. Con 42px de
   viaje y 16px de aire, la etiqueta se metía dentro del titular, el titular
   dentro de la entradilla y el de las obras encima de su botón, y encima solo
   en las pantallas por debajo de 1310px, que son todas las reales.

   El arreglo no es separar más las piezas (dejaría la web esponjosa y con el
   texto desparramado): es que el viaje quepa dentro del aire que ya hay, y el
   más estrecho de la web son los 12px que separan la etiqueta de su titular en
   el teléfono. Así que 12px de viaje, y por eso está escrito UNA vez aquí y no
   repartido por cada gesto: el día que se separe o se junte una pieza, esto se
   comprueba contra el hueco más pequeño que quede.

   Doce píxeles se leen igual de bien que cuarenta, porque lo que dice que el
   bloque acaba de llegar es la opacidad y la curva, no la distancia. */
.reveal[data-dir="up"]{transform:translateY(12px)}
.reveal[data-dir="down"]{transform:translateY(-12px)}
.reveal[data-dir="left"]{transform:translateX(-48px)}
.reveal[data-dir="right"]{transform:translateX(48px)}
.reveal[data-dir="zoom"]{transform:scale(.925)}
/* POR DEBAJO DE 1310px EL VIAJE ES SOLO VERTICAL, y esta es la segunda mitad
   del mismo problema que el solape: el cruce de lados descoloca el texto.

   El gesto está pensado para las bandas de foto y texto, donde el titular
   llega de un lado y el cuerpo del otro. Con las dos columnas de verdad, una
   al lado de la otra, eso se lee como un cruce. Apilado todo en una columna y
   alineado a la izquierda, lo que se ve es el titular sangrado unos píxeles
   respecto a su etiqueta y a su entradilla, que van hacia el otro lado: no
   parece un gesto, parece que el texto está mal alineado.

   Así que el cruce se queda donde tiene sentido (pantalla ancha, dos columnas)
   y por debajo entra todo por el mismo eje. Se acaba también el motivo original
   de este bloque, que era que un viaje de 34px se sale del margen de 22px del
   sitio y deja arrastrar la página de lado mientras dura la animación. */
@media (max-width:1310px){
  .reveal[data-dir="left"],.reveal[data-dir="right"]{transform:translateY(12px)}
}
.reveal[data-dir="rise"]{transform:translateY(16px) scale(.985)}
.reveal.in{opacity:1;transform:none}

/* --- El titular entra frase a frase --------------------------------------
   La pieza que se mueve es la FRASE ENTERA. Se probó antes con una ventana
   recortada por palabra, y aunque todas las palabras de una frase salgan
   sincronizadas, el ojo ve un recorte por palabra y lo lee como palabra a
   palabra: peor en un titular estrecho, donde las palabras de una misma frase
   caen en líneas distintas y el patrón no se parece a ninguna frase. Así que
   aquí no hay máscaras.

   El partido en frases lo hace el guion, que además lo rehace al cambiar de
   idioma (el traductor busca por texto exacto, así que un titular ya partido
   deja de ser alcanzable, igual que el de la portada).

   La frase va de bloque en línea porque un elemento en línea no acepta
   `transform`. Eso hace que una frase que no cabe en el resto de la línea
   salte entera a la siguiente, y en el único titular de la web con dos frases
   eso es justo lo que se quiere: una frase por renglón. */
.reveal.frases[data-dir]{opacity:1;transform:none}
/* Mismo motivo que arriba, y aquí es donde más se veía: el titular es la pieza
   con menos aire debajo de toda la web. */
.reveal.frases .fr{display:inline-block;vertical-align:top;
  opacity:0;transform:translateY(12px);
  transition:opacity 1.25s var(--ease),transform 1.4s var(--ease);
  transition-delay:var(--dw,0s)}
.reveal.frases[data-dir="down"] .fr{transform:translateY(-12px)}
.reveal.frases[data-dir="left"] .fr{transform:translateX(-40px)}
.reveal.frases[data-dir="right"] .fr{transform:translateX(40px)}
.reveal.frases.in .fr{opacity:1;transform:none}
/* El titular sigue al resto del bloque: sin cruce por debajo de 1310px, o queda
   sangrado respecto a la etiqueta que tiene encima y la entradilla de debajo,
   que viajan hacia el otro lado. El porqué, entero, en el bloque de arriba. */
@media (max-width:1310px){
  .reveal.frases[data-dir="left"] .fr,
  .reveal.frases[data-dir="right"] .fr{transform:translateY(12px)}
}

/* --- Lo que sale por arriba se aparta -------------------------------------
   Hasta ahora nada se iba: el observador sacaba de la lista cada bloque en
   cuanto entraba. Ahora la sección que sale por arriba se apaga subiendo, y
   vuelve a entrar si se sube a buscarla. Irse va más rápido que llegar (una
   salida que dura lo mismo que la entrada se lee como que la página va lenta)
   y sin escalonado: el bloque se retira entero, porque irse de uno en uno se
   ve como que la página se deshace por partes.

   Se declara con `[data-dir]` para ganar por especificidad a la dirección de
   entrada sin recurrir a !important. Lo que sale por ABAJO (subiendo) no lleva
   esta clase: vuelve a su estado de partida para poder entrar otra vez. */
.reveal.fuera[data-dir]{opacity:0;transform:translateY(-26px);
  transition-delay:0s;transition-duration:.7s,.78s}
/* Al irse, la caja se apaga entera y las frases de dentro se quedan quietas.
   Si cada frase deshiciera además su entrada, con su retardo puesto, la salida
   se vería descoordinada de su propio bloque. */
.reveal.frases.fuera[data-dir] .fr{opacity:1;transform:none;transition:none}

/* --- EL ARRANQUE ENTRA COMO LAMAS ----------------------------------------
   Las cuatro credenciales y las cifras no se desplazan: giran sobre su filete
   de abajo, como la lama de una persiana que pasa de estar tumbada de espaldas
   a quedarse de frente. Elegido el 23-ago entre cuatro gestos comparados sobre
   el contenido real, contra la entrada genérica de la web (desplazar y
   encender), que en este tramo se leía demasiado sencilla.

   LA PERSPECTIVA VA EN EL CONTENEDOR, y es lo que hace que el gesto se lea:
   así las cuatro tarjetas comparten punto de fuga y la fila parece apoyada en
   una mesa, con las de fuera girando de perfil y las de dentro casi de frente.
   Puesta en cada pieza, las cuatro girarían igual y se vería plano.

   Al salir no vuelve atrás: sigue girando en el mismo sentido, ahora sobre el
   borde de arriba, y se tumba hacia el lector. Por eso se cambia también el
   `transform-origin` en la salida, y no solo el ángulo.

   El dir es `lama` a propósito, que no lo usa ninguna regla de dirección: así
   este gesto no arrastra ni el viaje de 12px ni el cruce lateral de las demás
   entradas, y las reglas de abajo de 1310px no le tocan nada. */
.creds .wrap,.facts .wrap,.numeros-lista,.numeros-head{perspective:1100px;perspective-origin:50% 40%}
.reveal.lama{transform-origin:50% 100%;transform:rotateX(-82deg) translateY(10px);
  transition:transform 1.05s cubic-bezier(.16,.84,.3,1),opacity .5s var(--ease);
  transition-delay:var(--d,0s)}
.reveal.lama.in{transform:none;opacity:1}
.reveal.lama.fuera[data-dir]{transform-origin:50% 0;
  transform:rotateX(74deg) translateY(-14px);opacity:0;
  transition-duration:.6s,.42s;transition-delay:0s}

/* --- LA SECCIÓN SE SALE DEL MARCO ---------------------------------------
   Para el método, los reels y quiénes somos (23-ago). Se eligió comparando
   tres tandas: las dos primeras se descartaron enteras por flojas, aun con
   noventa píxeles de viaje, y la lección es la misma que dejó el ticker en
   agosto: el golpe no sale de subir grados ni píxeles, sale de que pase algo
   grande.

   REGLA DE LA QUE SALE TODO ESTO: la página no se alarga ni un píxel. Ninguna
   de las tres se queda pegada ni pide recorrido extra, así que el gesto ocurre
   dentro del hueco que la sección ya ocupa y se hace SOLO con `transform`, que
   no mueve a nadie de sitio: la foto llega mucho más grande de lo que le toca,
   pisando el sitio del texto, y se recoge hasta su marco.

   El texto se enciende TARDE, cuando la foto ya se ha recogido. Sin eso se
   leería por debajo de ella, que es el precio de dejar que una pieza invada la
   caja de otra.

   Con qué NO se puede pisar, que es lo que decide dónde se cuelga cada uno:
     · en el método, `.tx` ya lleva el cruce (una animación con `transform`) y
       una animación gana siempre a una transición, así que el gesto va a sus
       HIJOS. La foto sí puede: en `.ph` la animación es de `clip-path`, y la
       escala convive con el recorte,
     · en quiénes somos, `.intro-media` se abre desde una franja con el scroll y
       su imagen viaja por dentro: esa foto se queda fuera y solo entra el texto
       de las dos columnas. */
.reveal.marco{opacity:0;transform:translateY(26px);
  transition:transform 1.1s cubic-bezier(.16,.86,.24,1),opacity .5s var(--ease);
  transition-delay:var(--d,0s),calc(var(--d,0s) + .34s)}
.reveal.marco.in{transform:none;opacity:1}
.reveal.marco.fuera[data-dir]{transform:translateY(-40px);opacity:0;
  transition-duration:.55s,.3s;transition-delay:0s,0s}

/* El titular no viaja: entra a vez y media de cuerpo y se cierra hasta el suyo.
   El punto de giro va en el borde de lectura (izquierda) y no en el centro, o
   la primera palabra entraría fuera de la caja. */
.reveal.marco-titular{opacity:0;transform:scale(1.5);transform-origin:0% 50%;
  transition:transform 1.2s cubic-bezier(.14,.84,.2,1),opacity .5s var(--ease);
  transition-delay:var(--d,0s),calc(var(--d,0s) + .2s)}
.reveal.marco-titular.in{transform:none;opacity:1}
.reveal.marco-titular.fuera[data-dir]{transform:scale(1.12) translateY(-30px);opacity:0;
  transition-duration:.6s,.32s;transition-delay:0s,0s}

/* La foto NO nace apagada: se ve desde el principio, grande y fuera de su
   sitio. Es lo que hace el gesto: no aparece, se recoge. */
.reveal.marco-foto{opacity:1;transform:scale(1.42) translateY(18px);z-index:4;
  transition:transform 1.5s cubic-bezier(.14,.84,.2,1),opacity .5s var(--ease);
  transition-delay:var(--d,0s)}
.reveal.marco-foto.in{transform:none;opacity:1}
.reveal.marco-foto.fuera[data-dir]{transform:scale(1.24) translateY(-30px);opacity:0;
  transition-duration:.7s,.4s;transition-delay:0s}

/* LAS TARJETAS DE LOS REELS VAN POR LA PISTA, no una a una, y el motivo es de
   fondo: el turno lo da un observador de intersección con la pantalla, y estas
   tarjetas se desplazan solas de lado con el paseo del carrusel. Al salir una
   por el costado perdía el turno y volvía a su estado de partida, que aquí es
   el tamaño grande, así que quedaban tarjetas hinchadas y descuadradas en los
   extremos (visto el 24-ago).

   Colgando el gesto de la pista, el turno depende de si la sección está en
   pantalla y nada más. La pista en sí no se mueve: solo reparte. */
.reveal.marco-tarjetas{opacity:1;transform:none;transition:none}
.reveal.marco-tarjetas .reel{transform:scale(1.42) translateY(18px);
  transition:transform 1.5s cubic-bezier(.14,.84,.2,1),opacity .5s var(--ease);
  transition-delay:calc(var(--d,0s) + var(--i,0) * .1s)}
.reveal.marco-tarjetas.in .reel{transform:none}
.reveal.marco-tarjetas.fuera[data-dir] .reel{transform:scale(1.24) translateY(-30px);
  opacity:0;transition-duration:.7s,.4s;transition-delay:0s}

/* Lo que crece más allá de su caja tiene que quedarse dentro de su sección, o
   la página se deja arrastrar de lado. `clip` y nunca `hidden`, que crearía
   contenedor de scroll y rompería las anclas (regla 6 del repo). */
.split.contramano,#reels,.intro-grid,.faq{overflow-x:clip}

/* Las fotos de obra y galería entran además con un punto de escala */
.proj.reveal figure img,.gallery .reveal img{transform:scale(1.08);
  transition:transform 1.8s var(--ease);transition-delay:var(--d,0s)}
.proj.reveal.in figure img,.gallery .reveal.in img{transform:scale(1)}

/* Botón del asistente: aparece cuando ya se ha bajado un poco */
.chat-fab{opacity:0;transform:translateY(14px) scale(.9);
  transition:opacity .5s var(--ease),transform .5s var(--ease)}
body.fab-on .chat-fab{opacity:1;transform:none}

/* Transición entre páginas (Chrome y navegadores con View Transitions):
   la barra se queda quieta y la foto de la obra crece hasta el hero
   de su página de detalle. Los que no lo soporten navegan como siempre. */
@view-transition{navigation:auto}
::view-transition-group(root){animation-duration:.55s}
::view-transition-old(root){animation:vt-out .35s var(--ease) both}
::view-transition-new(root){animation:vt-in .5s var(--ease) both}
@keyframes vt-out{to{opacity:0}}
@keyframes vt-in{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:none}}
.nav{view-transition-name:nav}
::view-transition-group(nav){animation-duration:.4s}
.p-hero[data-vt] img{view-transition-name:obra}
/* La tarjeta de origen NO lleva el nombre escrito aquí: se lo pone el guion a
   la que se acaba de pulsar. Escrito en el CSS solo podía haber una obra con
   transición en toda la web, porque el nombre tiene que ser único. */
::view-transition-group(obra){animation-duration:.6s;
  animation-timing-function:cubic-bezier(.22,.61,.36,1)}

@media (prefers-reduced-motion:reduce){
  .hero img,.hero video,.p-hero img,.p-hero .scrim,.hero h1,.p-hero h1,
  .hero .sub,.p-hero .where,
  .hero .cta,.p-hero .back,.nav,.nav .wrap{animation:none}
  .nav{transition:none}
  .reveal,.reveal.fuera[data-dir],
  .reveal.lama,.reveal.lama.fuera[data-dir],
  .reveal.marco,.reveal.marco.fuera[data-dir],
  .reveal.marco-titular,.reveal.marco-titular.fuera[data-dir],
  .reveal.marco-foto,.reveal.marco-foto.fuera[data-dir],
  .reveal.marco-tarjetas .reel{opacity:1;transform:none;transition:none}
  .reveal.frases .fr{opacity:1;transform:none;transition:none}
  .proj.reveal figure img,.gallery .reveal img{transform:none;transition:none}
  .chat-fab{opacity:1;transform:none}
  @view-transition{navigation:none}
}

/* ============================================================
   LECTURA EN MÓVIL
   En la pantalla del teléfono el cuerpo de 17px y la entradilla
   de 19px piden demasiado desplazamiento. Se baja un escalón todo
   el texto corrido y se recorta el aire entre párrafos, dejando
   los titulares y los datos con peso para que sigan mandando.
   ============================================================ */
@media (max-width:760px){
  body{font-size:16px;line-height:1.6}
  p{margin:0 0 14px}
  .eyebrow{font-size:11.5px;margin-bottom:12px}
  h2 + .lead{margin-top:18px}
  h2{font-size:calc(clamp(26px,6.2vw,34px) * var(--t-scale))}
  h3{font-size:calc(18px * var(--t-scale))}
  .lead{font-size:16.5px;line-height:1.6}
  /* `auto` a los lados, que el bloque va centrado: con el margen a cero la
     caja se pegaba a la izquierda por debajo de 760px. */
  .hero .sub{font-size:16.5px;line-height:1.55;margin:24px auto 32px;max-width:38ch}
  .quote{font-size:calc(19px * var(--t-scale));padding-left:18px;margin-top:26px}
  /* Las credenciales van aparte desde el 23-ago: con el cuño puesto, el dato
     es lo que titula la tarjeta y se queda un punto por encima del resto. La
     ficha de obra lleva el mismo cuño pero no sube de cuerpo, porque sus datos
     son frases largas y tienen que caber en una línea. */
  .facts .v,.outcome .v{font-size:17px}
  .creds .v{font-size:18.5px}
  .svc{padding:24px 22px 26px}
  .svc h3{margin:16px 0 10px;padding-right:52px}
  .svc .n{font-size:38px;top:16px;right:20px}
  .svc-ic{width:40px;height:40px}.svc-ic svg{width:18px;height:18px}
  .svc p{font-size:15px;line-height:1.55}
  .bul{margin-top:14px}
  .bul li{font-size:14.5px;padding:8px 0}
  .person p{font-size:14.5px;line-height:1.55;margin-top:14px}
  .note{font-size:14px;line-height:1.55;padding:20px;margin-top:32px}
  .cinfo .v{font-size:17px}
  .cinfo .row{padding:15px 0}
  .formnote{font-size:12.5px}
  footer{padding:28px 0}
  footer .wrap{font-size:13px;gap:10px}
}
@media (max-width:520px){:root{--pad:22px}}

/* ---------- SELECTOR DE IDIOMA ---------- */
.langswitch{display:inline-flex;align-items:center;gap:2px;margin-left:auto;
  border:1px solid var(--line);border-radius:40px;padding:3px;background:var(--sup)}
/* Dentro de la isla el selector no lleva su propio fondo de tarjeta: sobre el
   cristal se veía como una pastilla pegada encima de otra. */
.nav .langswitch{background:transparent;border-color:var(--isla-borde)}
.nav .langswitch button,.nav .langswitch a{min-height:30px;padding:6px 11px;font-size:12px}
.nav nav ~ .langswitch{margin-left:22px}
.langswitch button,.langswitch a{border:0;background:transparent;border-radius:30px;cursor:pointer;
  display:inline-flex;align-items:center;justify-content:center;text-decoration:none;
  font-family:var(--f-body);font-size:12.5px;font-weight:500;letter-spacing:.06em;
  color:var(--ink-soft);padding:8px 13px;min-height:34px;transition:background .3s ease,color .3s ease}
.langswitch button[aria-pressed="true"],.langswitch a[aria-current="true"]{background:var(--ink);color:var(--bg)}
.langswitch button:hover[aria-pressed="false"],.langswitch a:not([aria-current]):hover{color:var(--ink)}
@media (max-width:980px){.nav nav ~ .langswitch{margin-left:auto}}

/* ---------- CAMBIO DE IDIOMA ----------
   El texto no salta de golpe: se funde con el nuevo. En Chrome lo hace el
   propio navegador con una transición de vista; donde no existe, se hace a
   mano bajando el texto un punto y devolviéndolo. */
html.lang-vt::view-transition-old(root){animation:lang-out .26s ease both}
html.lang-vt::view-transition-new(root){animation:lang-in .34s var(--ease) both}
html.lang-vt::view-transition-group(root){animation-duration:.34s}
@keyframes lang-out{to{opacity:0;filter:blur(2px)}}
@keyframes lang-in{from{opacity:0;filter:blur(2px)}to{opacity:1;filter:none}}

body.lang-swap{transition:opacity .22s ease,filter .22s ease;opacity:.35;filter:blur(1.5px)}

/* Los dos rótulos son ENLACES, no botones: cada idioma tiene su dirección
   (/services y /es/servicios), así que cambiar de idioma es navegar. Por eso
   el estado activo se marca con aria-current y no con aria-pressed, y por eso
   las reglas de aquí abajo valen para los dos: el marcado de las muestras
   internas todavía usa button. */
/* La píldora del selector se desliza al otro idioma en vez de encenderse */
.langswitch{position:relative;isolation:isolate}
.langswitch::before{content:"";position:absolute;z-index:-1;top:3px;bottom:3px;left:3px;
  width:calc(50% - 3px);border-radius:30px;background:var(--ink);
  transform:translateX(var(--x,0));transition:transform .42s cubic-bezier(.3,.8,.3,1)}
.langswitch[data-active="es"]::before{--x:100%}
.langswitch button,.langswitch a{min-width:46px;position:relative;z-index:1}
.langswitch button[aria-pressed="true"],.langswitch a[aria-current="true"]{background:transparent;color:var(--bg)}
/* En el móvil la píldora de idioma se compacta. Va aquí, detrás de las reglas
   base del selector, porque con la misma especificidad manda la última. */
@media (max-width:640px){.langswitch{padding:2px}
  .langswitch button,.langswitch a{padding:6px 8px;font-size:11.5px;min-height:30px;min-width:34px}
  .langswitch::before{top:2px;bottom:2px;left:2px;width:calc(50% - 2px)}}
@media (prefers-reduced-motion:reduce){
  .langswitch::before{transition:none}
  body.lang-swap{transition:none;opacity:1;filter:none}
  html.lang-vt::view-transition-old(root),html.lang-vt::view-transition-new(root){animation:none}
}

/* ---------- VISOR DE FOTOS ---------- */
/* Aviso de que la foto se puede abrir: el cursor y un punto de acercamiento al
   pasar por encima. En el teléfono no hay hover, así que allí solo cuenta que
   sea pulsable. */
.ampliable{cursor:zoom-in}
.ampliable:focus-visible{outline:2px solid var(--ink);outline-offset:3px}
.split .ph.ampliable img,.intro-media.ampliable img{transition:transform 1.1s var(--ease)}
.split .ph.ampliable:hover img,.intro-media.ampliable:hover img,
.gallery figure.ampliable:hover img{--pz:1.03}
.gallery figure.ampliable:hover img{transform:scale(1.03)}

/* `display:grid` gana al `hidden` del navegador, así que sin esta línea el
   visor se queda encima de todo aunque esté cerrado (invisible, pero se come
   los clics: el globo del asistente dejaba de responder). */
.visor[hidden]{display:none}
.visor{position:fixed;inset:0;z-index:80;display:grid;place-items:center;
  background:rgba(14,12,10,.94);opacity:0;transition:opacity .26s var(--ease);
  overscroll-behavior:contain;
  /* El hueco de la foto se declara aquí y se mide contra la ventana:
       --m       margen alrededor
       --lados   lo que se reserva a izquierda y derecha para los dos botones
                 de pasar, que si no se quedarían encima de la foto
       --pie     lo que se reserva abajo para el pie y la cuenta */
  --m:clamp(16px,4vw,54px);
  --lados:74px;
  --pie:52px;
  padding:var(--m)}
.visor.on{opacity:1}
html.visor-on,body.visor-on{overflow:hidden}

.visor-lienzo{display:grid;place-items:center;overflow:hidden;
  width:100%;height:100%;min-width:0;min-height:0}

/* La foto se ajusta a la pantalla y se ve entera, siempre. El tamaño se ata a
   la ventana (`dvw`/`dvh`) y no a la cadena de porcentajes de sus padres: con
   el contenedor centrado, su alto lo decide el contenido, así que un
   `max-height:100%` dentro no tenía contra qué resolverse y una foto vertical
   se salía por arriba y por abajo. El `dvh` es el alto real que queda visible
   en el teléfono, ya descontada la barra del navegador; se deja `vh` delante
   como respaldo para los navegadores que no lo conozcan. */
.visor-lienzo img{
  max-width:calc(100vw - var(--m) * 2 - var(--lados));
  max-width:calc(100dvw - var(--m) * 2 - var(--lados));
  max-height:calc(100vh - var(--m) * 2 - var(--pie));
  max-height:calc(100dvh - var(--m) * 2 - var(--pie));
  width:auto;height:auto;object-fit:contain;cursor:zoom-in;
  border-radius:var(--radio-isla);transform-origin:center;
  transition:transform .34s var(--ease),opacity .24s var(--ease)}
/* Mientras una foto releva a la otra no se puede pinchar: un clic a media
   transición dejaba la lupa puesta sobre la foto equivocada. */
.visor-lienzo.pasando img{pointer-events:none}
/* Con la foto ampliada el cursor deja de ser una lupa: ahí se agarra y se
   arrastra. `touch-action:none` es lo que impide que el teléfono se quede el
   gesto para desplazar la página o para su propio zoom, que era lo que hacía
   imposible recorrer la foto con el dedo. Y sin `user-select` el arrastre
   acababa seleccionando la imagen en vez de moverla. */
.visor-lienzo.lupa img{cursor:grab;border-radius:0;touch-action:none;
  -webkit-user-select:none;user-select:none;-webkit-user-drag:none}
.visor-lienzo.lupa img:active{cursor:grabbing}

.visor-x,.visor-nav{position:absolute;z-index:2;display:grid;place-items:center;
  width:46px;height:46px;border-radius:50%;border:1px solid rgba(255,255,255,.28);
  background:rgba(20,18,15,.55);color:#fff;cursor:pointer;padding:0;
  -webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);
  transition:background .25s ease,border-color .25s ease}
.visor-x:hover,.visor-nav:hover{background:rgba(20,18,15,.9);border-color:rgba(255,255,255,.55)}
.visor-x svg,.visor-nav svg{width:22px;height:22px}
.visor-x{top:clamp(14px,3vw,26px);right:clamp(14px,3vw,26px)}
.visor-nav{top:50%;transform:translateY(-50%)}
.visor-nav.ant{left:clamp(10px,2.4vw,26px)}
.visor-nav.sig{right:clamp(10px,2.4vw,26px)}

.visor-pie{position:absolute;left:0;right:0;bottom:clamp(12px,2.4vw,22px);margin:0;
  display:flex;gap:14px;justify-content:center;align-items:baseline;padding:0 60px;
  color:rgba(255,255,255,.82);font-size:13.5px;letter-spacing:.01em;text-align:center}
.visor-pie .cuenta{color:rgba(255,255,255,.5);font-variant-numeric:tabular-nums;white-space:nowrap}

/* En el teléfono los botones bajan a los pulgares y el pie se queda con la
   cuenta: el pie de foto entero robaba sitio a la imagen. */
/* Teléfono en horizontal: quedan poco más de 380 puntos de alto, y entre
   margen y pie se comían la mitad. Se aprieta todo y la foto recupera sitio. */
@media (max-height:520px){
  .visor{--m:10px;--pie:40px;padding:10px}
  .visor-pie{bottom:8px;font-size:12px}
  .visor-x{top:10px;right:10px}
}

@media (max-width:640px){
  /* Aquí los botones de pasar bajan a los pulgares, así que dejan de robar
     ancho y pasan a robar alto: los costados se liberan y el pie crece. */
  .visor{--m:12px;--lados:0px;--pie:84px;padding:12px 12px 84px}
  .visor-nav{top:auto;bottom:20px;transform:none}
  .visor-nav.ant{left:22px}
  .visor-nav.sig{right:22px}
  .visor-pie{bottom:34px;padding:0 84px;font-size:12.5px}
  .visor-pie .tx{display:none}
}
@media (prefers-reduced-motion:reduce){
  .visor{transition:none}
  .visor-lienzo img{transition:none}
  .split .ph.ampliable img,.intro-media.ampliable img{transition:none}
  .split .ph.ampliable:hover img,.intro-media.ampliable:hover img,
  .gallery figure.ampliable:hover img{transform:none}
}

/* ============================================================
   AJUSTES DE LA PIEL OSCURA
   Lo que no arregla un token: dibujos monocromos que se pintan
   con el color equivocado sobre fondo oscuro. Se resuelve con
   filtros y no cambiando el archivo, así una sola imagen sirve
   para las dos pieles. Sin anidar: el selector se repite entero
   en cada regla, que es lo que entiende cualquier navegador.
   ============================================================ */

/* La marca de Khronos es negra sobre transparente. Donde cae sobre fondo
   oscuro (telón de entrada y barra) se vuelve blanca. */
html:not([data-theme="light"]) .intro img,
html:not([data-theme="light"]) .brand img{filter:brightness(0) invert(1)}

/* Y al revés en el globo del asistente y en su cabecera, que van sobre un
   círculo claro: ahí la marca blanca se vuelve negra. */
html:not([data-theme="light"]) .chat-fab img,
html:not([data-theme="light"]) .assistant .head .av img{filter:brightness(0)}

/* LOS LOGOS DE CLIENTES VAN EN SU COLOR ORIGINAL, cada uno el suyo (21-ago).
   Antes la banda entera se pasaba a siluetas blancas con `brightness(0)
   invert(1)`, para que los que son oscuros no se tragaran sobre fondo oscuro.
   Se cambia por decision de Sebas: una marca se reconoce por su color, y una
   fila de siluetas iguales no dice de quien es cada una.

   Lo que esto cuesta, medido el 21-ago sobre los propios archivos (luminancia
   media de 0 a 255 de los pixeles opacos): NT Windows 65 y con color en todo
   el dibujo, Forever Properties 69, Paris Spa 15 y CRM Jewelers CERO, que es
   negro puro y no tiene color original ninguno. Los cuatro son oscuros. Sobre
   la piel oscura, CRM Jewelers y Paris Spa se ven poco o nada.
   Se arregla con material, no con filtros: pidiendole a Robert la version en
   claro de esos dos logos. Mientras no lleguen, es lo que hay. */
.ticker-track .item{opacity:.62;transition:opacity .4s ease}
.ticker-track .item.lit{opacity:1}

/* Las fotos bajan un punto de brillo en reposo: a pantalla completa y en
   oscuro, una fachada al sol deslumbra y rompe la lectura del texto que
   tiene al lado. Al señalarlas vuelven enteras. */
html:not([data-theme="light"]) .proj figure img,
html:not([data-theme="light"]) .split .ph img,
html:not([data-theme="light"]) .intro-media img{filter:brightness(.94);
  transition:transform .6s cubic-bezier(.2,.6,.2,1),filter .5s ease}
html:not([data-theme="light"]) .proj:hover figure img,
html:not([data-theme="light"]) .split .ph:hover img,
html:not([data-theme="light"]) .intro-media:hover img{filter:none}

/* El aro de los iconos de proceso queda flotando sin un fondo opaco que
   corte la línea por detrás. */
html:not([data-theme="light"]) .ic{background:var(--bg-alt)}

@media (prefers-reduced-motion:reduce){
  html:not([data-theme="light"]) .ticker-track .item{opacity:.5}
}

/* ============================================================
   LO QUE NO ARREGLA UN TOKEN, DENTRO DE UNA PIEL QUE SE MUEVE
   Los colores se recolocan solos, pero los dibujos monocromos van
   con filtros, y un logo no puede estar medio invertido de golpe:
   se vería el salto en mitad del fundido. Así que el filtro se
   interpola con el MISMO `--p` que el color, y el logo pasa de
   blanco a negro a la vez que el fondo pasa de oscuro a claro.

   Las reglas de arriba siguen valiendo para todo lo que está fuera
   de una sección que se transforma: el telón de entrada, el
   asistente y las demás páginas del sitio.
   ============================================================ */

/* Los logos van con `--pt` y no con `--p`, por lo mismo que el texto: se leen
   ENCIMA del fondo, no son fondo. Con `--p` una sección parada en un tono
   intermedio dejaba el logo a medio invertir, que es un gris plano encima de
   otro gris plano. Con `--pt` el logo ya ha terminado de cambiar antes de que
   el fondo llegue al centro, así que siempre está en blanco o en negro y nunca
   en la tierra de nadie. Cruzando se sigue viendo el fundido, que es lo que se
   buscó al montarlo. */

/* La marca de Khronos, negra sobre transparente: blanca sobre la piel oscura,
   en su negro original sobre la clara. */
html:not([data-theme="light"]) .nav.piel .brand img{
  filter:brightness(var(--pt)) invert(calc(1 - var(--pt)))}
html[data-theme="light"] .nav.piel .brand img{
  filter:brightness(calc(1 - var(--pt))) invert(var(--pt))}

/* Los logos de clientes NO llevan filtro de piel: van en su color original en
   las dos pieles (ver el bloque de arriba). Lo unico que cruza es la opacidad,
   que sobre fondo claro tiene que ser mas alta para que pesen igual.

   VA POR `--oscuro` Y NO POR `--pt` (26-ago). `--pt` dice a que lado del viaje
   se esta, no de que color es el fondo, y eso significa lo contrario en cada
   piel: con la web en claro la formula anterior dejaba los logos al 62% sobre
   el papel, justo donde hacen falta enteros. `--oscuro` dice lo que se
   necesita saber, 0 blanco y 1 negro, e igual en las dos pieles. */
.piel .ticker-track .item{opacity:calc(1 - .38 * var(--oscuro));transition:opacity .4s ease}
.piel .ticker-track .item.lit{opacity:1}

/* LA EXCEPCION DE FOREVER PROPERTIES (21-ago).
   De los cuatro es el que peor queda en su color: solo el 26% de su dibujo
   lleva color y el resto es casi negro, asi que en color se lee como una
   mancha. Se queda con el tratamiento de siempre, la silueta que se invierte
   con la piel, y los otros tres van en su color.

   La regla va por NOMBRE DE ARCHIVO y no por una clase en el marcado, igual que
   el encuadre de Mey Ramos en la persiana del equipo: asi vale tambien en la
   web en espanol, que se genera y no se toca a mano.

   Invertir y desgrisar no pueden ir a la vez (la regla de mas arriba), pero
   aqui no hay conflicto posible: este logo no vuelve al color nunca, ni siquiera
   al cruzar el centro, asi que solo se mueve la inversion. */
.piel .ticker-track{
  --inv-o:clamp(0, calc(var(--pt) / .42), 1);
  --inv-c:clamp(0, calc((var(--pt) - .58) / .42), 1)}
html:not([data-theme="light"]) .ticker-track .item img[src*="forever-properties"]{
  filter:brightness(0) invert(1)}
html:not([data-theme="light"]) .piel .ticker-track .item img[src*="forever-properties"]{
  filter:brightness(var(--inv-o)) invert(calc(1 - var(--inv-o)))}
/* En la piel clara la formula era `brightness(1 - inv-c)`, o sea que sobre
   fondo claro dejaba el logo EN SU COLOR: un gris clarisimo de linea fina que
   sobre el papel de la banda no se lee (26-ago). Ahora hace lo mismo que su
   gemela oscura: negro sobre claro, blanco sobre oscuro. */
html[data-theme="light"] .piel .ticker-track .item img[src*="forever-properties"]{
  filter:brightness(0) invert(var(--inv-c))}

/* URBAN DEVELOPERS, SOBRE PAPEL (26-ago).
   Es el unico medallon de disco CLARO Y OPACO: un gris de papel con el nombre
   en gris mas suave dentro. Sobre la banda blanca se quedaba flotando, sin
   borde que lo separase del fondo, mientras los nueve de disco oscuro pesaban
   como monedas.

   Se le baja el brillo SOLO cuando el fondo es claro, y por eso la cuenta va
   con `--oscuro`: sobre papel se queda en el 82% y el disco vuelve a ser una
   pieza; sobre fondo oscuro no se toca, que alli ya destaca solo. El nombre no
   gana contraste dentro de su disco (los dos bajan juntos), pero el logo
   completo si se separa de la banda, que es lo que faltaba.

   Se probaron cuatro niveles antes de elegir este: por debajo del 72% el
   medallon se lee ya como gris medio y desentona con los claros de al lado.

   Como el resto de excepciones de la banda, va por nombre de archivo para que
   valga igual en la web en espanol, que se genera y no se toca a mano. */
.piel .ticker-track .item img[src*="urban-developers"]{
  filter:brightness(calc(1 - .18 * (1 - var(--oscuro)))) saturate(1.15)}

/* Las fotos bajan un punto de brillo solo en la piel oscura, así que el punto
   se recupera a la vez que la sección aclara. */
html:not([data-theme="light"]) .piel .proj figure img,
html:not([data-theme="light"]) .piel .split .ph img,
html:not([data-theme="light"]) .piel .intro-media img{
  filter:brightness(calc(.94 + .06 * var(--p)));
  transition:transform .6s cubic-bezier(.2,.6,.2,1),filter .5s ease}
html[data-theme="light"] .piel .proj figure img,
html[data-theme="light"] .piel .split .ph img,
html[data-theme="light"] .piel .intro-media img{
  filter:brightness(calc(1 - .06 * var(--p)));
  transition:transform .6s cubic-bezier(.2,.6,.2,1),filter .5s ease}
.piel .proj:hover figure img,
.piel .split .ph:hover img,
.piel .intro-media:hover img{filter:none}

/* ============================================================
   PORTAFOLIO · EL MURO DE TRES TIRAS

   Tres tiras de fotos a sangre que se pasean SOLAS y sin final, las de fuera
   hacia un lado y la del medio hacia el otro. Elegido el 25-ago contra las
   otras dos formas de moverlo (atado al scroll, y las dos cosas a la vez) y
   contra el muro vertical de tres columnas del que salió.

   Tres cosas lo sostienen:

   · LA COPIA. Cada cinta lleva su contenido dos veces y recorre justo la mitad
     de su ancho (más medio hueco), así que al volver al punto de partida la
     imagen es la misma y no se ve el corte. Sin duplicar, el paseo se acaba.
   · LA MEDIDA ÚNICA. Las 28 fotos van a 315 x 236 recortadas por el centro,
     aunque vengan en proporciones distintas. Elegida la apaisada 4:3 porque es
     la que ya tienen 24 de las 28: es el recorte que menos foto tira.
   · EL DESVANECIDO DE LOS BORDES. Sin él la tira se corta a cuchillo contra el
     fondo y se ve el truco.

   Va con prefijo `pf-` a propósito: `tira`, `cinta`, `pieza` y `rot` ya
   existen en esta hoja (banda de clientes, visor, mapa) y un nombre repetido
   aquí no da error, solo se cuelan reglas de otra pieza.
   ============================================================ */
.pf{padding:clamp(46px,5.5vw,78px) 0}
/* LA COLUMNA VA ATADA A `minmax(0,1fr)`, y no es adorno (26-ago)

   La cinta de fotos mide varios miles de pixeles de ancho, y `overflow:clip`
   en la tira NO crea contenedor de scroll (por eso se eligio frente a
   `hidden`, que se lleva por delante las anclas de la pagina). Sin contenedor
   de scroll, ese ancho real SI cuenta para medir la rejilla: la columna
   implicita se estiraba a lo que mide la cinta.

   A las tiras no les afecta, porque van al 100% de la pista y se recortan
   solas. Al rotulo de servicio si: centrado dentro de una columna de miles de
   pixeles, acababa a 2.679px del borde, o sea fuera de la pantalla. Estaba
   pintado, en negro y a 55px, y no se veia ninguno de los dos.

   `minmax(0,1fr)` obliga a la columna a medir lo que mide la seccion y no lo
   que mide su hijo mas ancho. */
.pf-muro{--pf-alto:236px;--pf-hueco:16px;display:grid;
  grid-template-columns:minmax(0,1fr);gap:var(--pf-hueco)}
/* EL RÓTULO DE SERVICIO (26-ago)

   Parte el muro en "Design" y "Owner's representative". Va dentro de la propia
   rejilla, así que hereda su hueco y se esconde con ella cuando entra la
   versión de teléfono.

   Se escribe con la misma letra pequeña y espaciada que el resto de rótulos de
   la web (`eyebrow`), no como un titular: lo que manda en esta página son las
   fotos, y un H2 encima de cada grupo partiría la página en dos secciones que
   no lo son. Va alineado al margen del contenido y no al sangrado a sangre del
   muro, para que caiga a plomo con el titular de arriba.

   Del segundo en adelante lleva aire por encima, o el rótulo quedaría pegado a
   la última tira del grupo anterior y se leería como suyo. */
.pf-grupo{margin:0 auto;padding:0 var(--pad);width:100%;max-width:var(--maxw);
  text-align:center;font-family:var(--f-title);font-weight:var(--t-w);
  font-size:calc(clamp(30px,4vw,50px) * var(--t-scale));
  letter-spacing:var(--t-ls);line-height:1.1;color:var(--ink)}
/* El aire por arriba lo lleva TAMBIÉN el primero, no solo los siguientes: el
   rótulo abre su grupo y pegado a la franja de datos de encima se leía como
   parte de ella. Por abajo manda el hueco de la rejilla, que es el mismo que
   separa las tiras entre sí. */
.pf-grupo{margin-top:clamp(18px,2.4vw,30px)}
.pf-grupo ~ .pf-grupo{margin-top:clamp(30px,4vw,52px)}
/* `clip` y nunca `hidden`: `hidden` crea contenedor de scroll y se lleva por
   delante las anclas de la página. */
.pf-tira{overflow:clip;width:100%;
  mask-image:linear-gradient(to right,transparent,#000 5%,#000 95%,transparent);
  -webkit-mask-image:linear-gradient(to right,transparent,#000 5%,#000 95%,transparent)}
.pf-cinta{display:flex;gap:var(--pf-hueco);width:max-content;will-change:transform}
.pf-pieza{position:relative;display:block;flex:none;
  height:var(--pf-alto);width:calc(var(--pf-alto) * 1.3333);
  overflow:hidden;border-radius:var(--radio-pieza);background:var(--foto-vacia)}
/* Las fotos del muro van RECORTADAS EN EL ARCHIVO a 640 x 480 (2x de lo que se
   ve), no recortadas por el navegador desde el original: las 28 originales son
   5,1 MB y el recorte a medida son 1,1 MB, y la pagina se abre en el telefono.
   Los archivos son `<obra>-<n>-muro.webp`, al lado de su original. */
.pf-pieza img{width:100%;height:100%;display:block;object-fit:cover;object-position:center;
  transition:transform .6s cubic-bezier(.22,1,.36,1)}
.pf-pieza:hover img{transform:scale(1.05)}

/* EL NOMBRE, solo al señalar. En reposo se lee el oficio, no el listado: el
   titular de arriba ya dice de qué va la página. El degradado va en negro fijo
   y no en tokens porque cae SOBRE la foto, que es igual de oscura en las dos
   pieles. */
.pf-rot{position:absolute;inset:auto 0 0;padding:30px 12px 10px;
  display:flex;flex-direction:column;gap:2px;
  background:linear-gradient(to top,rgba(0,0,0,.74),rgba(0,0,0,0));
  opacity:0;transition:opacity .3s ease}
.pf-pieza:hover .pf-rot,.pf-pieza:focus-visible .pf-rot{opacity:1}
.pf-rot b{font-size:13px;font-weight:600;color:#F2EEE8;white-space:nowrap}
.pf-rot i{font-style:normal;font-size:11px;letter-spacing:.1em;text-transform:uppercase;
  color:rgba(242,238,232,.72);white-space:nowrap}

@media (prefers-reduced-motion:no-preference){
  .pf-cinta{animation:pf-paseo linear infinite}
  /* El paseo va por `data-paso` y no por la posición de la tira: desde que el
     muro lleva rótulos de servicio, los hijos de la rejilla ya no son solo
     tiras y `nth-child` contaba otra cosa. La del medio va al revés y más
     despacio, que es lo que hace que las tres no parezcan una sola. */
  .pf-tira[data-paso="a"] .pf-cinta{animation-duration:78s}
  .pf-tira[data-paso="b"] .pf-cinta{animation-duration:58s;animation-direction:reverse}
  .pf-tira[data-paso="c"] .pf-cinta{animation-duration:92s}
  /* Se para al señalar y también al llegar con el tabulador: si no, el foco
     salta a una foto que se está yendo de la pantalla. */
  .pf-tira:hover .pf-cinta,
  .pf-tira:focus-within .pf-cinta{animation-play-state:paused}
  @keyframes pf-paseo{from{transform:translateX(0)}
                      to{transform:translateX(calc(-50% - var(--pf-hueco) / 2))}}
}
/* Sin movimiento las tiras se quedan quietas y se arrastran a mano, que es la
   salida honesta: dejarlas cortadas y sin manera de ver el resto, no. */
@media (prefers-reduced-motion:reduce){
  .pf-tira{overflow-x:auto;-webkit-overflow-scrolling:touch}
  .pf-cinta{animation:none;transform:none}
}
/* El muro se queda quieto en el telefono aunque el aparato no pida menos
   movimiento: es el respaldo por si el guion no llega a montar la vista de
   movil (la de abajo). Cortado y sin manera de ver el resto, no. */
@media (max-width:760px){
  .pf-muro{--pf-alto:148px;--pf-hueco:11px}
  .pf-tira{overflow-x:auto;-webkit-overflow-scrolling:touch}
}

/* ------------------------------------------------------------
   EL PORTAFOLIO EN EL TELEFONO · una tira por obra
   El muro de tres tiras es de raton y en el telefono no funciona, y no por
   tamano: las tres cosas que lo hacen usable dependen del PUNTERO. Se para al
   senalar (en el telefono no se para nunca), el nombre de la obra sale al
   pasar por encima (no sale nunca) y la tira va con `overflow:clip` (tampoco
   se arrastra). Quedaban seis obras con pagina propia que ahi no se leian.

   Lo que entra en su sitio: UNA TIRA POR OBRA, con el rotulo fijo encima y el
   dedo llevandola con encaje foto a foto. Se conserva el gesto horizontal del
   escritorio, que es lo que Robert eligio, pero mandado por el dedo. Elegida
   en muestra contra las tarjetas apiladas, el mosaico de dos columnas y la
   obra a pantalla con encaje.

   La monta el guion desde `.pf-obras`, el mismo bloque escondido del que come
   el modal, asi que no hay una segunda lista de obras que mantener ni marcado
   duplicado en las dos lenguas. Mientras no la monte, la clase `tiene-movil`
   no esta y se ve el muro quieto de arriba.
   ------------------------------------------------------------ */
.pf-movil{display:none}
@media (max-width:760px){
  .pf.tiene-movil .pf-muro{display:none}
  .pf.tiene-movil .pf-movil{display:block}
}
/* EL RÓTULO DE SERVICIO EN EL TELÉFONO (26-ago)

   El mismo corte que parte el muro del escritorio en "Design" y "Owner's
   representative", aquí encima de su grupo de tiras. Y en cuanto está puesto,
   el servicio de cada obra SOBRA: se leería "Design" y justo debajo "Design ·
   Wyn 16" cuatro veces seguidas. El de la obra se apaga y manda el del grupo,
   que es el que dice lo mismo una sola vez.

   Se hereda todo de `.pf-grupo`, tamaño de titular y centrado incluidos; aquí
   solo el aire, porque en el muro lo pone la rejilla y en la lista del
   teléfono no hay rejilla. */
.pfm-grupo{margin:0 0 18px}
.pfm-grupo ~ .pfm-grupo{margin-top:14px}
.pf-movil .pfm-rot .serv{display:none}
.pfm-obra{padding:0 0 26px}
.pfm-obra:last-child{padding-bottom:0}
.pfm-rot{display:flex;align-items:baseline;justify-content:space-between;gap:12px;
  padding:0 var(--pad) 9px}
.pfm-rot .serv{display:block;font-size:10.5px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--acento);margin:0 0 3px}
.pfm-rot .nom{font-family:var(--f-title);font-size:20px;line-height:1.2;margin:0}
.pfm-rot .donde{margin:0;font-size:11px;letter-spacing:.12em;text-transform:uppercase;
  color:var(--ink-soft);white-space:nowrap}
/* El encaje va con `scroll-padding` para que la foto que entra se pare
   alineada con el rotulo, y no pegada al filo de la pantalla. */
.pfm-fila{display:flex;gap:10px;overflow-x:auto;padding:0 var(--pad) 11px;
  scroll-snap-type:x mandatory;scroll-padding-left:var(--pad);
  scrollbar-width:none;-webkit-overflow-scrolling:touch}
.pfm-fila::-webkit-scrollbar{display:none}
/* El ancho se saca del contenedor y NUNCA de `vw`: `vw` cuenta la barra de
   scroll y descuadra. Los 56px que se restan son lo que asoma de la siguiente
   foto, que es lo que dice que la tira sigue. */
.pfm-foto{flex:none;width:calc(100% - 56px);aspect-ratio:4/3;scroll-snap-align:start;
  display:block;overflow:hidden;border-radius:var(--radio-pieza);background:var(--foto-vacia)}
.pfm-foto img{width:100%;height:100%;display:block;object-fit:cover;object-position:center}
.pfm-mas{display:inline-block;margin:0 var(--pad);font-size:12px;letter-spacing:.06em;
  color:var(--ink-soft);text-decoration:none;padding-bottom:2px;
  border-bottom:1px solid var(--line)}
.pfm-mas:hover,.pfm-mas:focus-visible{color:var(--ink);border-bottom-color:var(--acento)}

/* ------------------------------------------------------------
   PROYECTOS · mosaico con el mapa al lado
   Cuatro obras a la izquierda y el mapa a la derecha, del mismo alto, para que
   no queden dos cajas descuadradas. Al pulsar una obra en el mapa, su ficha
   resumida ocupa el sitio del mosaico: el mapa no cambia de columna, así que
   no baila nada mientras se recorre.
   ------------------------------------------------------------ */
.proy{display:grid;grid-template-columns:1.1fr .9fr;gap:clamp(26px,3.6vw,52px);
  align-items:stretch}
.proy-lado{position:relative;min-height:0}
.mosaico{display:grid;grid-template-columns:repeat(2,1fr);gap:22px;align-content:start;
  transition:opacity .3s ease}
.mosaico.apagado{opacity:0;pointer-events:none}
.mosaico .obra{display:block;text-decoration:none;color:inherit}
.mosaico figure{margin:0;aspect-ratio:4/3;overflow:hidden;border-radius:var(--radio-pieza);
  background:var(--foto-vacia)}
.mosaico figure img{width:100%;height:100%;object-fit:cover;display:block;
  transition:transform .6s var(--ease)}
.mosaico .obra:hover img,.mosaico .obra.viva img{transform:scale(1.05)}
.mosaico .pie{margin-top:12px}
.mosaico .nom{font-family:var(--f-title);font-size:18px;letter-spacing:-.01em;display:block;
  transition:color .3s ease}
.mosaico .obra.viva .nom{color:var(--acento)}
.mosaico .donde{color:var(--ink-soft);font-size:14px}
.mosaico .linea{font-size:11px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--ink-soft);margin-top:2px}

/* La ficha resumida, que releva al mosaico */
.ficha{position:absolute;inset:0;display:flex;flex-direction:column;overflow:hidden;
  background:var(--bg);border:1px solid var(--line);border-radius:var(--radio-isla);
  opacity:0;transform:translateY(10px);pointer-events:none;
  transition:opacity .35s ease,transform .35s var(--ease)}
.ficha.puesta{opacity:1;transform:none;pointer-events:auto}
.ficha figure{margin:0;height:46%;min-height:150px;overflow:hidden;background:var(--foto-vacia)}
.ficha figure img{width:100%;height:100%;object-fit:cover;display:block}
.ficha-cuerpo{padding:24px;display:flex;flex-direction:column;gap:12px;flex:1;min-height:0}
.ficha .linea{font-size:11px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--acento);margin:0}
.ficha h3{font-family:var(--f-title);font-size:clamp(20px,2.2vw,27px);letter-spacing:-.02em;margin:0}
.ficha .donde{color:var(--ink-soft);font-size:15px;margin:0}
.ficha-pie{display:flex;gap:12px;align-items:center;margin-top:auto;flex-wrap:wrap}
.ficha-volver{font-family:var(--f-body);font-size:13.5px;background:transparent;
  border:1px solid var(--line-fuerte);color:var(--ink-soft);border-radius:var(--radio-menudo);
  padding:9px 14px;cursor:pointer;transition:color .25s ease,border-color .25s ease}
.ficha-volver:hover{color:var(--ink);border-color:var(--borde-vivo)}

/* El mapa, a sangre en su columna */
.mapa{position:relative;min-height:320px;overflow:hidden;border-radius:var(--radio-isla);
  cursor:grab;touch-action:none;background:#08121A}
.mapa.agarrando{cursor:grabbing}
.mapa svg{width:100%;height:100%;display:block;position:absolute;inset:0}
.mapa-malla path{fill:none;stroke:rgba(255,255,255,.055);stroke-width:1;
  vector-effect:non-scaling-stroke}
.mapa-tierra{fill:#1C1A16;stroke:rgba(200,148,84,.28);stroke-width:1;
  vector-effect:non-scaling-stroke}
.mapa-detalle{opacity:0;transition:opacity .4s ease}
.mapa-detalle.puesto{opacity:1}
.mapa-detalle .mapa-tierra.con-obra{fill:#2C2419;stroke:rgba(200,148,84,.55)}
.mapa-rotulo{fill:rgba(242,238,232,.62);font-family:var(--f-body);letter-spacing:.14em;
  text-transform:uppercase;text-anchor:middle;opacity:0;transition:opacity .35s ease;
  paint-order:stroke;stroke:rgba(8,18,26,.9);stroke-width:3;vector-effect:non-scaling-stroke}
.mapa-rotulo.puesto{opacity:1}

.mapa-punto{cursor:pointer;opacity:0;pointer-events:none;transition:opacity .35s ease}
.sueltos .mapa-punto{opacity:1;pointer-events:auto}
.mapa-punto .pin{fill:var(--acento);stroke:#08121A;stroke-width:2;vector-effect:non-scaling-stroke}
.mapa-punto .aro{fill:none;stroke:var(--acento);stroke-width:1.4;opacity:.55;
  vector-effect:non-scaling-stroke;transition:opacity .35s ease}
.mapa-punto .halo{fill:var(--acento);opacity:.14;transform-box:fill-box;transform-origin:center;
  transform:scale(.5);transition:transform .45s var(--ease),opacity .45s ease}
.mapa-punto .etiq{fill:#F2EEE8;font-family:var(--f-body);opacity:0;transition:opacity .3s ease;
  paint-order:stroke;stroke:rgba(8,18,26,.92);stroke-width:3.4;vector-effect:non-scaling-stroke}
.mapa-punto:hover .halo,.mapa-punto.viva .halo{transform:scale(1);opacity:.3}
.mapa-punto:hover .etiq,.mapa-punto.viva .etiq,.mapa-punto:focus-visible .etiq{opacity:1}
.mapa-punto:hover .aro,.mapa-punto.viva .aro{opacity:1}
.mapa-punto:focus{outline:none}

/* De lejos las obras caerían una encima de otra: se juntan en un marcador con
   su cuenta y se abren al acercarse. */
.mapa-grupo{cursor:pointer;transition:opacity .35s ease}
.sueltos .mapa-grupo{opacity:0;pointer-events:none}
.mapa-grupo .bola{fill:var(--acento);stroke:#08121A;stroke-width:2;vector-effect:non-scaling-stroke}
.mapa-grupo .halo{fill:var(--acento);opacity:.16}
.mapa-grupo .cuenta{fill:#14120F;font-family:var(--f-body);font-weight:600;text-anchor:middle}

.mapa-mandos{position:absolute;top:10px;right:10px;display:flex;flex-direction:column;gap:6px;z-index:2}
.mapa-mandos button{width:32px;height:32px;border-radius:var(--radio-menudo);cursor:pointer;
  background:rgba(8,18,26,.72);border:1px solid rgba(242,238,232,.22);color:#F2EEE8;
  font-family:var(--f-body);font-size:15px;line-height:1;display:grid;place-content:center;
  transition:border-color .25s ease,color .25s ease}
.mapa-mandos button:hover{border-color:var(--acento);color:var(--acento)}
.mapa-escala{position:absolute;right:12px;bottom:12px;z-index:2;color:rgba(242,238,232,.72);
  font-size:11px;letter-spacing:.08em;display:flex;align-items:center;gap:8px;pointer-events:none}
.mapa-escala i{display:block;height:6px;border:1px solid rgba(242,238,232,.55);border-top:0}

@media (max-width:980px){
  .proy{grid-template-columns:1fr}
  .mapa{min-height:340px;order:-1}}
@media (max-width:600px){.mosaico{grid-template-columns:1fr}}
@media (prefers-reduced-motion:reduce){
  .mosaico figure img,.mapa-punto .halo,.ficha{transition:none}}

/* ---------- LOS DATOS DE CADA OBRA, ESCONDIDOS ----------
   `.pf-obras` es un bloque de la página de proyectos con un artículo por obra:
   nombre, servicio, zona, enlace a la ficha y la lista de sus fotos. No se ve,
   y de él sale la versión de teléfono del muro.

   Va en el marcado y no en el guion porque el servicio y la zona SE TRADUCEN, y
   el traductor busca por texto exacto en el HTML.

   Hasta el 26-ago de aquí salía también la vista previa: un modal que abría la
   obra a pantalla con sus fotos pasando una a una. La retiró Robert en la
   revisión de ese día, porque entrar en la obra completa tiene más fuerza que
   verla de refilón. Todo su dibujo está en el historial, en el commit del
   25-ago que lo trajo. */
.pf-obras{display:none}

/* El mosaico y el mapa de arriba SIGUEN AQUI aunque hoy no los use ninguna
   pagina: la pagina de proyectos paso al muro de tres tiras el 25-ago y el
   mapa quedo aparcado a la espera de decidir donde va. Se acompana de
   `assets/mapa.js`, `assets/mapa-datos.js` y `assets/work.js`. Si se decide
   que no vuelve, se van los cuatro juntos. */

/* ============================================================
   PARALLAX DE LAS FOTOS DE BANDA
   La foto se mueve más despacio que la página, así que al bajar
   parece que está detrás y no pegada. Va con dos variables en vez
   de con un transform entero, porque encima de ese desplazamiento
   hay un zoom al pasar el ratón: si los dos escribieran `transform`,
   el último en aplicarse borraría al otro.
     --py  el desplazamiento, lo escribe el JS al hacer scroll
     --pz  la escala, la escribe el CSS al señalar con el ratón
   El recorte lo hace la figura, que ya tiene `overflow:hidden`; la
   foto crece un 14% de alto para tener de dónde moverse sin dejar
   ver el fondo por arriba ni por abajo.
   ============================================================ */
.split .ph img,.intro-media img{
  transform:translate3d(0,var(--py,0px),0) scale(var(--pz,1))}

/* El sobrealto y la subida se escriben con el selector entero, no con la clase
   suelta: las reglas de cada bloque fijan `inset:0` y `height:100%` con más
   peso, y una clase por su cuenta no las movería. La foto de "quiénes somos"
   no está posicionada, así que además se le da `relative` para que el `top`
   la mueva. */
.split .ph img.parallax,.intro-media img.parallax{
  height:114%;top:-7%;will-change:transform}
.intro-media img.parallax{position:relative}

@media (prefers-reduced-motion:reduce){
  .split .ph img.parallax,.intro-media img.parallax{
    height:100%;top:0;transform:none}
}

/* ============================================================
   EL CASO · texto quieto y fotos que pasan
   Dentro de la ficha de obra, el relato del proyecto se queda
   fijo a un lado mientras la obra desfila por el otro. Se lee el
   caso y se ve a la vez, que es justo lo que no permite un texto
   arriba y una galería debajo.

   Lo hace `position:sticky`, no un script: la columna se pega
   sola dentro de su rejilla y se suelta al terminar el bloque.
   Como la columna de fotos es más alta que la de texto, hay
   recorrido de sobra. En pantalla estrecha no hay dos columnas
   que valgan y todo vuelve a apilarse, foto detrás de párrafo.
   ============================================================ */
.caso-grid{display:grid;grid-template-columns:1fr 1.15fr;
  gap:clamp(30px,5vw,84px);align-items:start}
.caso-tx{position:sticky;
  top:calc(var(--barra) + env(safe-area-inset-top,0px) + clamp(40px,6vh,86px))}
.caso-tx h2{margin-bottom:24px;max-width:16ch}
.caso-tx .lead{font-size:17.5px;max-width:46ch}

/* El contador dice por dónde va y, sobre todo, avisa de que ahí abajo hay
   más obra: sin él, con la columna quieta, se pierde la cuenta. */
.caso-cuenta{display:flex;align-items:center;gap:14px;margin:34px 0 0;
  font-size:13px;letter-spacing:.14em;color:var(--ink-soft);
  font-variant-numeric:tabular-nums}
.caso-cuenta b{color:var(--ink);font-weight:600}
.caso-cuenta i{flex:0 0 64px;height:1px;background:var(--line);position:relative}
.caso-cuenta i::after{content:"";position:absolute;inset:0 auto 0 0;background:var(--ink);
  width:var(--parte,20%);transform:translateX(var(--desde,0));
  transition:transform .45s var(--ease)}

.caso-fotos{display:grid;gap:clamp(20px,3vw,44px)}
.caso-fotos figure{margin:0;position:relative;overflow:hidden;border-radius:var(--radio-pieza);
  background:var(--foto-vacia);aspect-ratio:4/3}
.caso-fotos figure:nth-child(even){aspect-ratio:3/4}
.caso-fotos figure img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  transform:translate3d(0,var(--py,0px),0) scale(var(--pz,1))}
.caso-fotos figure.ampliable:hover img{--pz:1.03}
.caso-fotos figure img.parallax{height:114%;top:-7%;will-change:transform}

/* El pie no está siempre puesto: aparece cuando esa foto es la que se está
   mirando, y se retira cuando pasa. Así no hay cuatro rótulos compitiendo. */
.caso-fotos figcaption{position:absolute;inset:auto 0 0 0;
  padding:clamp(30px,4vw,44px) clamp(16px,2vw,24px) clamp(14px,1.8vw,20px);
  font-size:13.5px;letter-spacing:.02em;color:rgba(255,255,255,.9);
  background:linear-gradient(to top,rgba(8,7,6,.78),rgba(8,7,6,0));
  opacity:0;transform:translateY(8px);
  transition:opacity .5s var(--ease),transform .5s var(--ease)}
.caso-fotos figure.mirando figcaption{opacity:1;transform:none}

/* La que se está mirando va a brillo pleno; las de alrededor, un punto atrás.
   Solo en oscuro, que es donde la foto en reposo se apagó a propósito. */
html:not([data-theme="light"]) .caso-fotos figure.mirando img{filter:none}

@media (max-width:900px){
  .caso-grid{grid-template-columns:1fr;gap:32px}
  .caso-tx{position:static}
  .caso-tx .lead{max-width:none}
  .caso-cuenta{display:none}
  .caso-fotos figure,.caso-fotos figure:nth-child(even){aspect-ratio:4/3}
  /* Sin columna quieta el pie no tiene que turnarse con nadie: se queda. */
  .caso-fotos figcaption{opacity:1;transform:none}
}
@media (prefers-reduced-motion:reduce){
  .caso-fotos figcaption{transition:none}
  .caso-cuenta i::after{transition:none}
  .caso-fotos figure img.parallax{height:100%;top:0;transform:none}
}

/* ============================================================
   PÁGINA DE SERVICIOS
   Cada servicio se lee de una pantalla, sin desplazarse por dentro: arriba,
   qué es y qué incluye a la izquierda con la foto del trabajo a la derecha;
   debajo, el camino en cuatro pasos cruzando de lado a lado.

   El camino va ANCHO y no en la columna del texto: en vertical alargaba la
   ficha hasta obligar a desplazarse para terminar de leer un solo servicio.
   Por eso también el texto de cada paso es de una línea; el detalle largo
   vive en la página del servicio, no aquí.
   ============================================================ */
/* Las cuatro tarjetas miden lo mismo, y para que eso no las estire hay que
   igualarles antes el contenido pieza por pieza: mismo número de puntos en la
   lista, dos fichas en todas, textos de la misma medida y el enlace de la de
   permisos fuera del flujo, en la línea del rótulo. Con eso la altura común
   es la de la más corta y lo que sobra se queda en un respiro sobre el camino.
   `1fr` reparte por igual, así que todas toman el alto de la mayor, y la
   cadena tiene que llegar hasta abajo: de ahí el `height:100%` del `.wrap`. */
.sx-lista{display:grid;grid-auto-rows:1fr}
.sx{border-top:1px solid var(--line);padding:clamp(44px,4.5vw,64px) 0}
.sx.alt{background:var(--bg-alt)}
/* El camino va en la MISMA columna que el texto, debajo de la lista: es lo
   que llena el hueco que la foto dejaba vacío a su izquierda. A todo el ancho
   quedaba desgajado del servicio y dejaba ese hueco muerto. */
/* Cada servicio es una tarjeta levantada del fondo, el mismo lenguaje que las
   cuatro de la portada. El ancho de la tarjeta se calcula quitando los dos
   márgenes del sitio, así que en el teléfono no llega a lamer el canto de la
   pantalla, y el aire de dentro es suyo, no el del `.wrap`. */
.sx .wrap{display:grid;grid-template-columns:1.04fr .96fr;
  /* La foto ya no se estira a todo el alto de la tarjeta: manda su proporción,
     y debajo de ella van las fichas, que es lo que llena esa columna. El texto
     ocupa las dos primeras filas a su izquierda, la del medio absorbe lo que
     sobre y el camino se apoya en el fondo: así los cuatro caen a la misma
     altura. */
  /* DOS FILAS Y LA DE ABAJO A TODO EL ANCHO (24-ago). La tercera fila era la
     del camino de pasos, que ahora vive en la ficha de cada servicio, y se
     quedaba vacía cobrando su `gap`: un pie muerto debajo de las fichas.

     Y las fichas de dato dejan de vivir en la columna de la foto: bajan a una
     barra que cruza la tarjeta entera, que es lo que las convierte en el remate
     del servicio en vez de en dos cajas apretadas debajo de la imagen. Elegido
     en `muestras-piezas.html` contra el dato grande en bronce sin caja y contra
     la lista en dos columnas con los datos como línea de remate. */
  grid-template-rows:auto auto;
  grid-template-areas:"head foto" "datos datos";
  gap:clamp(26px,2.6vw,34px) clamp(28px,3.6vw,58px);align-items:start;
  height:100%;
  width:calc(100% - var(--pad) * 2);max-width:calc(var(--maxw) - var(--pad) * 2);
  margin-inline:auto;
  background:var(--sup);border:1px solid var(--line);border-radius:var(--radio-isla);
  padding:clamp(26px,2.6vw,38px) clamp(26px,2.6vw,38px) clamp(32px,3.2vw,46px)}
.sx-head{grid-area:head}
/* Dentro de la tarjeta las fichas van sobre superficie, no sobre el fondo de
   página, así que el borde es lo único que las separa: se les baja el relleno
   para que no compitan en peso con la lista que tienen encima. */
/* LA BARRA DE REMATE. Los dos datos del servicio eran dos cajas con borde y
   fondo, con el mismo aspecto exacto que las credenciales del hero y con un
   alto forzado (`min-height:2.6em`) para que cuadraran entre ellas: se leían
   como un formulario, no como el dato que cierra el servicio.

   Ahora son una sola pieza que cruza la tarjeta de lado a lado, partida por un
   filete, con el rótulo y el valor en la misma línea. El alto forzado se cae
   solo: con los dos en línea ya no hay nada que cuadrar. */
.sx-datos{grid-area:datos;display:grid;grid-template-columns:1fr 1fr;gap:0;
  margin-top:8px;background:var(--bg-alt);border:1px solid var(--line);
  border-radius:var(--radio-pieza);overflow:hidden}
.sx-datos .item{padding:16px 22px;background:none;border:0;border-radius:0;
  display:flex;align-items:baseline;gap:12px;border-left:1px solid var(--line)}
.sx-datos .item:first-child{border-left:0}
.sx-datos .k{flex:0 0 auto}
.sx-datos .v{font-size:16px;margin:0;min-height:0;font-weight:500}
/* El titular reserva sus dos líneas para que el texto de debajo arranque a la
   misma altura tenga el nombre del servicio una línea o dos. */
.sx-head h2{margin:0 0 15px;max-width:none;
  font-size:calc(clamp(25px,2.9vw,36px) * var(--t-scale))}
/* Solo se le quita el margen de ABAJO, que es el de párrafo y aquí sobra. El de
   arriba tiene que seguir llegando de `h2 + .lead`, o el titular de cada
   servicio vuelve a quedarse pegado a su entradilla. */
.sx-head .lead{margin-bottom:0;max-width:52ch;font-size:17.5px}
/* LA LISTA, EN UN RENGLÓN. Eran cuatro viñetas apiladas con su filete: cuatro
   renglones para decir cuatro palabras, y encima lo primero que un cliente lee
   para saber si el servicio le sirve. Ahora van seguidas separadas por un punto
   en bronce, así que se leen de un golpe y las cuatro tarjetas quedan a la
   misma altura por este lado. */
.sx-head .bul{display:flex;flex-wrap:wrap;gap:0 10px;margin-top:18px;max-width:none}
.sx-head .bul li{border-top:0;padding:0;font-size:14.5px;display:flex;align-items:center}
.sx-head .bul li + li::before{content:"·";margin-right:10px;color:var(--acento);font-weight:700}
.sx-head .bul li{padding:6px 0}
/* El bronce, con cuentagotas: el rótulo del servicio y poco más. */
/* El rótulo vuelve a ser una línea normal. Era una barra con dos cosas a los
   lados porque el enlace a la ficha vivía dentro de él; ahora el enlace baja al
   final del texto, que es donde el ojo termina de leer. */
.sx .eyebrow{color:var(--acento);margin-bottom:16px}

/* La foto manda su propia proporción en vez de estirarse al alto de la tarjeta:
   estirada salía un rectángulo de medio metro que se comía la pantalla. Se
   cambia aquí el ratio si se la quiere más baja o más alta. */
.sx-foto{grid-area:foto;margin:0;position:relative;align-self:start;
  aspect-ratio:16/9;overflow:hidden;border-radius:var(--radio-pieza);background:var(--foto-vacia)}
.sx-foto img{width:100%;height:100%;object-fit:cover}
.sx-foto figcaption{position:absolute;left:0;right:0;bottom:0;padding:44px 20px 16px;
  font-size:12.5px;letter-spacing:.02em;color:#fff;
  background:linear-gradient(to top,rgba(12,11,9,.78),transparent)}

/* La forma la trae el bloque compartido con `.svc .more`, arriba en la baraja
   de la portada. Aquí solo el aire que lo separa de la lista que tiene encima. */
.sx .more{margin-top:26px}

/* Índice de arriba: cuatro atajos a los cuatro bloques. En el teléfono se
   desplaza de lado, que es donde de verdad hace falta. */

/* ---------- LA TARJETA DE SERVICIO GIRA SOBRE SU CANTO ----------
   Elegida el 24-ago en `muestras-cards.html` contra las dos hojas (texto y
   foto entrando por lados opuestos) y contra la escena a pantalla completa con
   el número gigante cruzando por detrás.

   El gesto: la tarjeta llega tumbada hacia atrás, gira sobre su canto de abajo
   hasta ponerse de frente, y al salir por arriba SIGUE el giro en el mismo
   sentido. Entrada y salida son el mismo movimiento continuado, no dos efectos
   distintos pegados: eso es lo que hace que se lea como una pieza que pasa por
   delante y no como una tarjeta que aparece y luego desaparece.

   Hasta hoy estas tarjetas subían, se encendían y ahí se quedaban. La queja no
   era solo la entrada: es que NO TENÍAN SALIDA, así que al recorrer la página
   se sentía que aparecían pero nunca se iban.

   La tarjeta gira COMO UNA PIEZA, y por eso sus cinco grupos salieron del motor
   de revelado de `site.js`. Ver allí el porqué entero.

   CUATRO COSAS QUE SOSTIENEN EL GESTO Y NO SON ADORNO:

   · La perspectiva va en el TRANSFORM de cada tarjeta, no en el contenedor.
     Puesta en el contenedor solo alcanza a sus hijos directos, y aquí lo que
     gira es el `.wrap`, que es nieto. Declarada en el propio transform, cada
     tarjeta tiene su punto de fuga y ninguna se deforma por estar lejos del
     centro de la lista.
   · El eje del giro es el CANTO DE ABAJO (`transform-origin:50% 100%`). Con el
     eje en el centro la tarjeta cabecea; apoyada en su canto se levanta, que es
     lo que se parece a un objeto de verdad.
   · Los tramos van en `cover` y no en `entry`/`exit`. Esos dos se miden con el
     elemento entero dentro de la pantalla, y una tarjeta más alta que la
     ventana no llega a estar dentro nunca: el tramo mide cero y el gesto ocurre
     de golpe. `cover` es el paso completo por delante y existe siempre.
   · La entrada rellena hacia los dos lados (`both`) y la salida SOLO hacia
     delante (`forwards`). Con la salida en `both` aplicaría su primer fotograma
     también antes de su tramo y, al ir declarada después, pisaría a la entrada:
     la tarjeta se quedaría recta desde el principio y parecería que no se anima
     nada. Costó una vuelta entera de muestra averiguarlo. */
.sx .wrap{transform-origin:50% 100%;box-shadow:0 26px 60px var(--sombra)}
/* La foto acompaña el redondeo de la tarjeta: con la esquina de 6px dentro de
   una caja de 22, el giro delata que son dos piezas pegadas. Solo el radio: el
   recorte ya lo tiene puesto arriba. */
.sx-foto{border-radius:var(--radio-pieza)}

@supports (animation-timeline: view()){
  @media (prefers-reduced-motion:no-preference){
    .sx .wrap{
      animation:sx-isla-entra cubic-bezier(.22,.61,.36,1) both,
                sx-isla-sale cubic-bezier(.55,0,.78,.4) forwards;
      animation-timeline:view(),view();
      animation-range:cover 2% cover 44%, cover 66% cover 99%}
    @keyframes sx-isla-entra{
      from{opacity:0;transform:perspective(1600px) rotateX(18deg) translateY(6%) scale(.94)}
      to  {opacity:1;transform:perspective(1600px) rotateX(0) translateY(0) scale(1)}
    }
    @keyframes sx-isla-sale{
      from{opacity:1;transform:perspective(1600px) rotateX(0) translateY(0) scale(1)}
      to  {opacity:0;transform:perspective(1600px) rotateX(-14deg) translateY(-5%) scale(.97)}
    }
  }
}

.sx-idx{display:flex;flex-wrap:wrap;gap:10px;margin-top:36px}
.sx-idx a{display:inline-flex;align-items:center;gap:9px;padding:11px 16px;
  border:1px solid var(--line);border-radius:var(--radio-menudo);background:var(--sup);
  font-size:14px;color:var(--ink);text-decoration:none;white-space:nowrap;
  transition:border-color .3s ease,transform .3s var(--ease)}
.sx-idx a:hover{border-color:var(--borde-vivo);transform:translateY(-2px)}
.sx-idx .n{font-size:11px;font-weight:600;letter-spacing:.14em;color:var(--acento)}

/* Con títulos de una palabra los cuatro pasos caben en fila hasta que la
   página se pone de una columna, así que no hace falta ningún paso intermedio
   a dos y dos: se va directo de la fila de cuatro al camino de pie. */
@media (max-width:900px){
  /* En una columna, igualar el alto solo dejaría en tres de las cuatro un
     hueco muerto del tamaño de la más larga. Cada una vuelve a medir lo suyo. */
  .sx-lista{display:block}
  .sx .wrap{grid-template-columns:1fr;grid-template-rows:none;
    grid-template-areas:"head" "foto" "datos";
    gap:clamp(26px,4.5vw,34px);height:auto}
  /* En el teléfono el enlace ocupa el ancho de la tarjeta: una cápsula corta
     perdida en una columna de 320px se lee como un adorno, y a ancho completo
     el pulgar la encuentra sin apuntar. */
  .sx .more{display:flex;width:100%}
  .sx-datos{grid-template-columns:1fr}
  .sx-datos .item{border-left:0;border-top:1px solid var(--line);
    padding:14px 18px;gap:10px}
  .sx-datos .item:first-child{border-top:0}
  .sx-foto{align-self:auto;min-height:0;aspect-ratio:2/1}
  .sx-head h2,.sx-head .lead{max-width:none}
  .sx-head .lead{font-size:16.5px}
}
@media (max-width:640px){
  .sx{padding:48px 0}
  .sx-datos{grid-template-columns:1fr;gap:10px}
  .sx-foto{aspect-ratio:16/10}
  /* Los cuatro atajos se ENVUELVEN, no se arrastran. Iban en una tira lateral
     para no comerse cuatro filas de la primera pantalla, pero un gesto de lado
     en mitad de una página que baja no se ve y no se busca: el cuarto atajo no
     existía para quien no lo descubriera por accidente. Envueltos ocupan dos
     filas y se ven los cuatro. */
  .sx-idx{flex-wrap:wrap;gap:8px}
}

/* ============================================================
   AIRE EN EL TELÉFONO
   Repaso de separaciones sección por sección. La regla que se aplica en todas
   es la misma: el hueco ENTRE dos piezas tiene que ser mayor que el hueco que
   hay DENTRO de cada una. Cuando no lo es, el ojo agrupa mal y dos cosas
   distintas se leen como una sola (el pie de una obra parece el título de la
   siguiente, dos tarjetas parecen una).

   En pantalla ancha esto se resolvía solo porque las piezas van en columnas,
   una al lado de otra. Al apilarlas en una sola columna, las separaciones que
   servían de canal entre columnas se quedan cortas como canal entre filas.
   ============================================================ */
@media (max-width:900px){
  /* Las dos mitades de la presentación pasan a ser dos bloques largos: 26px
     entre ellos era menos que el aire interno de cada uno. */
  .intro-grid{gap:36px}
  .p-body{gap:32px}
}
@media (max-width:820px){
  .svc-grid{gap:20px;margin-top:40px}
}
@media (max-width:900px){
  /* La banda de foto y texto: al apilarse, 30px separaban la foto del bloque de
     texto y 28px separaban el enlace de su propia entradilla DENTRO de ese
     bloque. Con las dos medidas iguales, foto y texto se leen como una pieza
     sola y el enlace parece colgar de la foto. */
  .split{gap:36px}
  .split .more{margin-top:22px}
}
@media (max-width:760px){
  /* Cabecera de sección y contenido: UNA sola medida para toda la web. Cada
     sección traía la suya (26px las cifras, 30px la pila de obras, 32px los
     reels, 40px las rejillas, 42px las preguntas), y en pantalla ancha eso no
     se ve porque cada bloque tiene su propio ancho y su propio ritmo. Apiladas
     todas en una columna, el ojo las lee seguidas y esos cinco huecos distintos
     se leen como descuido. */
  .svc-grid,.work-grid,.team-grid,.contact-grid,
  .work-pila,.faq-lista,.reels-viewport,.numeros-lista{margin-top:34px}
  .creds .wrap,.facts .wrap{padding-top:32px;padding-bottom:32px}
  .next .row{margin-top:30px;gap:22px}
  /* Las dos cabeceras que llevan un botón al otro lado del renglón: al apilarse
     el botón queda debajo del titular y necesita su propio aire. */
  .work-head,.reels-head{gap:26px}
  /* En las cifras el renglón lo comparten la etiqueta y el pie, que son dos
     líneas de la MISMA cabecera. Al apilarse sumaban el hueco de la rejilla
     (24px) y el margen de la etiqueta (12px): 36px de separación entre dos
     renglones que tienen que leerse juntos. */
  .numeros-head{gap:6px}
  .numeros-head .eyebrow{margin-bottom:0}
  .gallery{margin-top:40px;gap:22px}
}
@media (max-width:640px){
  /* Entre una obra y la siguiente tiene que caber más que entre la foto y su
     propio pie (14px), o el pie se lee como cabecera de la de abajo. */
  .work-grid{gap:38px}
  /* Tres líneas apiladas a 10px se leen como un párrafo, no como tres datos. */
  footer .wrap{gap:15px}
  /* Las fichas de equipo tienen 34px de aire DENTRO (el que separa el borde de
     la foto redonda) y llevaban 18px ENTRE una y la siguiente: apiladas en una
     columna, dos personas se leían como una sola ficha larga. */
  .team-grid{gap:26px}
  /* En una sola columna las fichas de licencia ya no tienen canal lateral que
     las separe, así que el de arriba tiene que dar la cara. */
  .creds .wrap,.facts .wrap{gap:16px}
  /* La página de servicios: título, foto y camino son tres piezas grandes. */
  .sx .wrap{gap:32px}
}
