/* Generado por scripts/construir-assets.mjs. No editar a mano. */

@font-face{font-family:Archivo;font-style:normal;font-weight:100 900;font-stretch:62% 125%;font-display:swap;src:url(/assets/fuentes/af21ab248943f479-s.104iauyxhaf24.woff2)format("woff2");unicode-range:U+102-103,U+110-111,U+128-129,U+168-169,U+1A0-1A1,U+1AF-1B0,U+300-301,U+303-304,U+308-309,U+323,U+329,U+1EA0-1EF9,U+20AB}
@font-face{font-family:Archivo;font-style:normal;font-weight:100 900;font-stretch:62% 125%;font-display:swap;src:url(/assets/fuentes/4ae66b896b591e96-s.0b9excvam7id0.woff2)format("woff2");unicode-range:U+100-2BA,U+2BD-2C5,U+2C7-2CC,U+2CE-2D7,U+2DD-2FF,U+304,U+308,U+329,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}
@font-face{font-family:Archivo;font-style:normal;font-weight:100 900;font-stretch:62% 125%;font-display:swap;src:url(/assets/fuentes/21ca8f3f56c22ca2-s.p.0fmzj955937qe.woff2)format("woff2");unicode-range:U+??,U+131,U+152-153,U+2BB-2BC,U+2C6,U+2DA,U+2DC,U+304,U+308,U+329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:Archivo Fallback;src:local(Arial);ascent-override:88.96%;descent-override:21.28%;line-gap-override:0.0%;size-adjust:98.7%}

/* next/font ponía --f-sans en el html; aquí lo declaramos nosotros. */
:root { --f-sans: 'Archivo'; }
/* ============================================================================
@layer tokens, reset, base, layout, primitives, chrome, features, pages, utilities;

/* tokens.css */
@layer tokens {
/* ============================================================================
   Tokens. Lenguaje visual: catálogo de mayorista técnico.
   Base clara de alto contraste, tinta casi negra, un único color comprometido
   (el ámbar del logotipo) que carga las superficies clave. Sin degradados
   decorativos, sin glows.
   ========================================================================== */

:root {
  /* --------------------------------------------------------------- Color */
  /* Neutros: croma casi cero. No es crema, no es papel, no es beige. */
  --bg: oklch(0.972 0.002 250);
  --bg-2: oklch(0.945 0.003 250);
  --bg-3: oklch(0.905 0.004 250);
  --surface: oklch(1 0 0);
  --bg-blur: oklch(0.972 0.002 250 / 0.88); /* cabecera translúcida */

  --ink: oklch(0.19 0.008 250);
  --ink-2: oklch(0.42 0.006 250); /* 5.3:1 sobre --bg, apto para cuerpo */
  /* 5.1:1 sobre --bg y 4.7:1 sobre --bg-2. Era 0.56, que daba 4.28 y se quedaba
     a un pelo del 4.5 que pide la WCAG para texto normal: valía para etiquetas
     pero no para los 13px de las metas de noticia, y ahí es donde se usaba. */
  --ink-3: oklch(0.52 0.005 250);

  --line: oklch(0.875 0.004 250);
  --line-2: oklch(0.78 0.004 271); /* el gris claro de la hoja: #b6b7ba */

  /* Los tres planos de la hoja de colorimetría que entregó el cliente. Son
     valores literales, no derivados: el resto de la rampa sale de aquí. */
  --marca-naranja: #f29400;
  --marca-gris: #818285;
  --marca-gris-claro: #b6b7ba;

  /* Color comprometido: el naranja de la hoja, oklch(0.747 0.166 66). Sobre el
     fondo claro da 2.15:1, así que no sostiene texto: en tema claro se usa
     bajado de luminosidad a tono constante, y el naranja literal manda en el
     tema oscuro, en las placas oscuras y en el propio logotipo. */
  --brand: oklch(0.53 0.124 66); /* #9b5a00, 5.03:1 sobre --bg */
  --brand-deep: oklch(0.45 0.106 66); /* hover de superficie sólida, 7.04:1 */
  --brand-lift: oklch(0.747 0.166 66); /* el naranja literal, para placa oscura */
  --brand-ink: oklch(0.995 0 0); /* tinta sobre el relleno del acento */
  --brand-soft: oklch(0.955 0.032 66);
  --brand-line: oklch(0.83 0.075 66);

  /* Relleno de marca: el naranja literal de la hoja, con tinta oscura encima
     en vez de blanca. Así el color que ve el visitante en los botones es el de
     la hoja de color y no su versión apagada, y aun así son 7,4:1. Se queda en
     piezas pequeñas: como superficie de 300 px de alto, este naranja grita. */
  --brand-fill: var(--marca-naranja);
  --brand-fill-2: oklch(0.68 0.16 62); /* hover, un punto más hondo */
  --brand-fill-ink: oklch(0.22 0.05 66);

  /* Banda de marca (.plate-brand). No depende del tema: el color corporativo
     drenado es el mismo en claro y en oscuro, porque es identidad y no
     ambiente. El acento aclarado del tema oscuro sirve para enlaces y botones
     pequeños, pero como superficie de 300px de alto grita. */
  --band-bg: oklch(0.53 0.124 66); /* blanco encima: 5.45:1 */
  --band-ink: oklch(0.995 0 0);
  --band-ink-2: oklch(0.92 0.045 66);
  /* Tinta profunda tono sobre tono: la sombra del propio naranja, para rótulos
     grandes que texturizan la banda sin competir con la tinta blanca. */
  --band-ink-deep: oklch(0.26 0.062 66);
  --band-line: oklch(1 0 0 / 0.26);
  --band-line-2: oklch(1 0 0 / 0.42);

  /* Placa invertida: secciones que cambian de mundo */
  --inv-bg: oklch(0.19 0.008 250);
  --inv-bg-2: oklch(0.25 0.008 250);
  --inv-ink: oklch(0.97 0.002 250);
  --inv-ink-2: oklch(0.78 0.004 250);
  --inv-ink-3: oklch(0.63 0.004 250);
  --inv-line: oklch(1 0 0 / 0.16);
  --inv-line-2: oklch(1 0 0 / 0.26);

  /* Velo bajo los diálogos modales */
  --scrim: oklch(0.19 0.008 250 / 0.5);

  /* Estado: uso semántico, nunca decorativo */
  --ok: oklch(0.48 0.13 155);
  --ok-bg: oklch(0.95 0.035 155);
  --err: oklch(0.5 0.19 27);
  --err-bg: oklch(0.96 0.03 27);

  /* --------------------------------------------------------------- Forma */
  /* Radios cortos: ficha de catálogo, no burbuja. Nunca >12px en superficie. */
  --r-xs: 2px;
  --r-sm: 4px;
  --r-md: 8px;
  --r-lg: 12px;

  /* --------------------------------------------------------------- Espacio */
  --sp-1: 4px;
  --sp-2: 8px;
  --sp-3: 12px;
  --sp-4: 16px;
  --sp-5: 24px;
  --sp-6: 32px;
  --sp-7: 48px;
  --sp-8: 64px;
  --sp-9: 96px;
  --sp-10: 128px;

  --section-y: clamp(56px, 8vw, 112px);
  --stack-y: clamp(24px, 4vw, 40px);

  --max: 1200px;
  --nav-h: 64px;

  /* --------------------------------------------------------------- Sombra */
  /* Escala corta y contenida. Nunca combinada con borde de 1px como adorno. */
  --sh-1: 0 1px 2px oklch(0.19 0.008 250 / 0.06);
  --sh-2: 0 6px 16px -8px oklch(0.19 0.008 250 / 0.18);
  --sh-3: 0 18px 40px -20px oklch(0.19 0.008 250 / 0.3);

  /* --------------------------------------------------------------- Capas */
  /* Leaflet usa 400-1000 internamente. Todo lo nuestro va por encima o muy por debajo. */
  --z-base: 0;
  --z-raised: 1;
  --z-sticky: 100;
  --z-dropdown: 1100;
  --z-banner: 1200;
  --z-overlay: 1300;
  --z-modal: 1400;
  --z-toast: 1500;
  --z-skip: 1600;

  /* --------------------------------------------------------------- Motion */
  --dur-1: 120ms;
  --dur-2: 180ms;
  --dur-3: 280ms;
  --dur-4: 520ms;
  --ease: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-out: cubic-bezier(0.22, 0.61, 0.36, 1);

  /* --------------------------------------------------------------- Tipo */
  --font-sans: var(--f-sans), 'Archivo', system-ui, -apple-system, sans-serif;

  /* Anchos del eje wdth de Archivo */
  --wd-display: 108%;
  --wd-body: 100%;
  --wd-data: 78%;
}

/* En monitores grandes el lienzo respira un poco más: un solo token y todo el
   sitio (contenedor, bandas, listados) se ensancha a la vez. */
@media (min-width: 1600px) {
  :root {
    --max: 1320px;
  }
}
}

/* themes.css */
@layer tokens {
/* ============================================================================
   Temas y acentos.
   El tema claro vive en tokens.css como valor por defecto, para que el sitio
   se pinte bien aunque no haya JavaScript. Aquí solo van las variaciones.

   data-theme  = claro | oscuro
   data-accent = ambar | verde | azul | grafito

   El acento ámbar es el definitivo (el del logotipo) y no tiene bloque propio:
   vive en tokens.css como valor por defecto, para que el sitio salga bien sin
   JavaScript y sin atributo. Los demás son variantes de prototipo.

   La placa de contraste (.plate-contrast) se invierte respecto a la página: en
   tema claro es una banda oscura y en tema oscuro es una banda clara. El efecto
   de "cambio de mundo" al hacer scroll se mantiene en los dos.
   ========================================================================== */

/* ------------------------------------------------------------------ Oscuro */
:root[data-theme='oscuro'] {
  --bg: oklch(0.17 0.006 250);
  --bg-2: oklch(0.215 0.007 250);
  --bg-3: oklch(0.265 0.008 250);
  --surface: oklch(0.205 0.007 250);
  --bg-blur: oklch(0.17 0.006 250 / 0.85);

  --ink: oklch(0.965 0.002 250);
  --ink-2: oklch(0.785 0.004 250);
  --ink-3: oklch(0.63 0.004 250);

  --line: oklch(1 0 0 / 0.13);
  --line-2: oklch(1 0 0 / 0.26);

  /* La placa de contraste pasa a ser clara */
  --inv-bg: oklch(0.955 0.002 250);
  --inv-bg-2: oklch(0.9 0.003 250);
  --inv-ink: oklch(0.19 0.008 250);
  --inv-ink-2: oklch(0.42 0.006 250);
  --inv-ink-3: oklch(0.56 0.005 250);
  --inv-line: oklch(0.19 0.008 250 / 0.14);
  --inv-line-2: oklch(0.19 0.008 250 / 0.28);

  /* Acento por defecto en oscuro: el naranja de la hoja tal cual, sin bajar de
     luminosidad. Sobre este fondo da 8.19:1, que es donde el color de marca
     puede ser literalmente el de marca. */
  --brand: oklch(0.747 0.166 66); /* #f29400 */
  --brand-deep: oklch(0.83 0.13 66);
  /* En oscuro la placa de contraste es clara, así que el acento que va encima
     tiene que ser el oscuro, no el aclarado. */
  --brand-lift: oklch(0.53 0.124 66);
  --brand-ink: oklch(0.17 0.043 66);
  --brand-soft: oklch(0.3 0.07 66);
  --brand-line: oklch(0.45 0.1 66);

  /* Estado: sobre fondo oscuro los avisos necesitan más luz */
  --ok: oklch(0.78 0.15 155);
  --ok-bg: oklch(0.28 0.05 155);
  --err: oklch(0.72 0.16 27);
  --err-bg: oklch(0.3 0.07 27);

  --sh-1: 0 1px 2px oklch(0 0 0 / 0.5);
  --sh-2: 0 6px 16px -8px oklch(0 0 0 / 0.7);
  --sh-3: 0 18px 40px -20px oklch(0 0 0 / 0.85);
}

/* Aquí solo hay tokens. Los ajustes de componente que dependen del tema (el
   filtro del logotipo, los tiles del mapa) viven en el fichero del componente:
   este va en la capa de tokens y cualquier regla de una capa posterior lo
   pisaría por orden de cascada, no por especificidad. */

/* ------------------------------------------------------------------ Acentos */
/* Cada acento se declara dos veces: en claro tiene que ser oscuro para leerse
   sobre el fondo, y en oscuro tiene que ser claro. Los valores son explícitos y
   no derivados para poder verificar el contraste uno a uno.
   Los tokens --band-* no llevan variante de tema: la banda corporativa es la
   misma en claro y en oscuro. */

:root[data-accent='azul'] {
  --brand: oklch(0.46 0.16 258);
  --brand-deep: oklch(0.38 0.15 258);
  --brand-lift: oklch(0.72 0.13 255);
  --brand-soft: oklch(0.945 0.03 258);
  --brand-line: oklch(0.8 0.07 258);
  --band-bg: oklch(0.46 0.16 258);
  --band-ink-2: oklch(0.9 0.04 258);
  --band-ink-deep: oklch(0.21 0.1 258);
}
:root[data-theme='oscuro'][data-accent='azul'] {
  --brand: oklch(0.75 0.13 250);
  --brand-deep: oklch(0.84 0.11 250);
  --brand-lift: oklch(0.46 0.16 258);
  --brand-ink: oklch(0.16 0.04 258);
  --brand-soft: oklch(0.28 0.06 255);
  --brand-line: oklch(0.42 0.09 255);
}

:root[data-accent='verde'] {
  --brand: oklch(0.44 0.12 158);
  --brand-deep: oklch(0.37 0.11 158);
  --brand-lift: oklch(0.66 0.13 160);
  --brand-soft: oklch(0.945 0.028 158);
  --brand-line: oklch(0.8 0.06 158);
  --band-bg: oklch(0.44 0.12 158);
  --band-ink-2: oklch(0.9 0.03 158);
  --band-ink-deep: oklch(0.2 0.07 158);
}
:root[data-theme='oscuro'][data-accent='verde'] {
  --brand: oklch(0.74 0.15 160);
  --brand-deep: oklch(0.83 0.14 160);
  --brand-lift: oklch(0.44 0.12 158);
  --brand-ink: oklch(0.16 0.03 160);
  --brand-soft: oklch(0.28 0.05 160);
  --brand-line: oklch(0.42 0.08 160);
}

/* Grafito: sin color de acento. El contraste lo lleva la propia tinta y el
   énfasis se resuelve con peso y superficie. Es la opción más severa. */
:root[data-accent='grafito'] {
  --brand: oklch(0.26 0.008 250);
  --brand-deep: oklch(0.16 0.008 250);
  --brand-lift: oklch(0.8 0.004 250);
  --brand-soft: oklch(0.92 0.003 250);
  --brand-line: oklch(0.78 0.004 250);
  --band-bg: oklch(0.24 0.008 250);
  --band-ink-2: oklch(0.86 0.004 250);
  /* Sobre casi negro no hay sombra que valga: la tinta profunda es un gris
     medio que texturiza sin desaparecer. */
  --band-ink-deep: oklch(0.52 0.005 250);
}
:root[data-theme='oscuro'][data-accent='grafito'] {
  --brand: oklch(0.95 0.002 250);
  --brand-deep: oklch(0.82 0.003 250);
  --brand-lift: oklch(0.26 0.008 250);
  --brand-ink: oklch(0.17 0.006 250);
  --brand-soft: oklch(0.3 0.006 250);
  --brand-line: oklch(0.45 0.006 250);
  /* En oscuro un gris casi negro no se distingue del fondo: la banda sube. */
  --band-bg: oklch(0.35 0.006 250);
  --band-ink-deep: oklch(0.6 0.005 250);
}
}

/* reset.css */
@layer reset {
* {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  margin: 0;
  /* Las bandas a sangre usan margin negativo con 50vw; clip evita el scroll
     horizontal que provocaría la barra de desplazamiento. */
  overflow-x: clip;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: 17px;
  font-stretch: var(--wd-body);
  line-height: 1.6;
  font-variant-numeric: tabular-nums;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

img,
svg,
video {
  max-width: 100%;
  height: auto;
  display: block;
}

a {
  color: inherit;
  text-decoration: none;
}

button,
input,
select,
textarea {
  font: inherit;
  font-stretch: inherit;
}

::selection {
  background: var(--brand);
  color: var(--brand-ink);
}

:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
  border-radius: var(--r-xs);
}

/* Sobre placa oscura el foco verde no se separa del fondo: se aclara. */
.plate-contrast :focus-visible {
  outline-color: var(--brand-lift);
}
}

/* typography.css */
@layer base {
/* Una sola familia (Archivo variable), tres registros por eje de anchura:
   display 108% / cuerpo 100% / datos 78%. Sin monoespaciada. */

h1,
h2,
h3,
h4 {
  font-weight: 700;
  color: var(--ink);
  margin: 0 0 0.5em;
  text-wrap: balance;
}

h1,
h2 {
  font-stretch: var(--wd-display);
}

h1 {
  font-size: clamp(2.5rem, 5.2vw, 4.25rem);
  line-height: 1.02;
  letter-spacing: -0.025em;
}

h2 {
  font-size: clamp(1.75rem, 3.2vw, 2.75rem);
  line-height: 1.06;
  letter-spacing: -0.022em;
}

h3 {
  font-size: clamp(1.15rem, 1.6vw, 1.375rem);
  line-height: 1.2;
  letter-spacing: -0.012em;
  font-weight: 600;
}

h4 {
  font-size: 1rem;
  line-height: 1.3;
  font-weight: 600;
}

p {
  margin: 0 0 1em;
  color: var(--ink-2);
  max-width: 68ch;
  text-wrap: pretty;
}

.lead {
  font-size: clamp(1.075rem, 1.5vw, 1.3rem);
  line-height: 1.5;
  color: var(--ink-2);
  max-width: 56ch;
}

.muted {
  color: var(--ink-3);
}

/* Registro de datos: fechas, categorías, referencias, pies. Nunca frases largas. */
.data {
  font-stretch: var(--wd-data);
  font-weight: 500;
  font-size: 0.8125rem;
  letter-spacing: 0.02em;
  line-height: 1.35;
  color: var(--ink-3);
}

.data-up {
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

/* Etiqueta de sección. Existe como pieza puntual, no como gramática repetida. */
.kicker {
  display: block;
  font-stretch: var(--wd-data);
  font-weight: 600;
  font-size: 0.8125rem;
  letter-spacing: 0.04em;
  color: var(--brand);
  margin: 0 0 var(--sp-3);
}

.page-head {
  padding-bottom: var(--sp-5);
  border-bottom: 1px solid var(--line);
  margin-bottom: var(--sp-7);
}
/* Cuando el encabezado es la propia <section>, su margen sustituye al del
   ritmo general en lugar de sumarse. */
section.page-head {
  margin-bottom: var(--sp-7);
}
.page-head h1 {
  margin-bottom: 0.25em;
  max-width: 20ch;
}
.page-head .lead {
  margin: 0;
}

/* ------------------------------------------------------------------ Prosa */
.prose {
  color: var(--ink-2);
  max-width: 68ch;
  font-size: 1.0625rem;
  line-height: 1.7;
}
.prose > * + * {
  margin-top: 1em;
}
/* La prosa a la medida del contenedor en vez de a la de lectura. Solo tiene
   sentido cuando algo ocupa un lado (una imagen flotante) y el texto lo rodea:
   a secas, 1272px de línea son ~125 caracteres y se lee mal. El clear evita que
   el flotante se salga por debajo del bloque si el texto se queda corto. */
.prose.prose-ancha,
/* El tope de medida no lo pone .prose sino la regla `p` de más arriba, que
   alcanza a todo el sitio: sin liberar también los hijos, la prosa se ensancha
   y los párrafos se quedan igual de estrechos dentro. */
.prose.prose-ancha > * {
  max-width: none;
}
.prose.prose-ancha::after {
  content: '';
  display: block;
  clear: both;
}
.prose h2,
.prose h3 {
  color: var(--ink);
  margin-top: 1.8em;
  margin-bottom: 0.5em;
}
.prose h2 {
  font-size: 1.6rem;
}
.prose p {
  margin: 0 0 1em;
}
.prose a {
  color: var(--brand);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
}
.prose a:hover {
  color: var(--brand-deep);
}
.prose ul,
.prose ol {
  color: var(--ink-2);
  padding-left: 1.2em;
  margin: 0 0 1em;
}
.prose li {
  margin-bottom: 0.4em;
}
.prose blockquote {
  margin: 1.6em 0;
  padding: var(--sp-4) var(--sp-5);
  background: var(--bg-2);
  border-radius: var(--r-md);
  color: var(--ink);
  font-size: 1.15rem;
  line-height: 1.45;
}
.prose blockquote p:last-child {
  margin-bottom: 0;
}
.prose img {
  border-radius: var(--r-md);
  max-width: 100%;
  height: auto;
}

/*
 * Fotos dentro del texto. Las fichas de marca las traen del WordPress viejo, y
 * el gestor deja meter más: van a lo ancho de la columna de lectura, con el pie
 * pegado debajo y en el gris de apoyo, para que se lea como pie y no como una
 * frase más del cuerpo.
 */
.prose figure {
  margin: 1.8em 0;
}
.prose figure img {
  display: block;
  width: 100%;
}
.prose figcaption {
  margin-top: var(--sp-2);
  font-size: 0.875rem;
  line-height: 1.5;
  color: var(--ink-3);
}
}

/* motion.css */
@layer base {
/* ============================================================================
   Motion. Una sola idea recorre el sitio: el contenido *entra*, nunca aparece.
   El material es la máscara, no la opacidad: las palabras se descubren por
   detrás de su propia línea base y las fotografías se abren por un recorte.

   Regla que manda sobre el efecto: la animación no puede decidir si el
   contenido se ve. Nada arranca en opacity 0 con una línea de tiempo de scroll,
   porque en cualquier contexto sin scroll real (renderizadores headless,
   previsualizaciones de enlaces, impresión) la línea se evalúa en su posición
   inicial y la sección se queda en blanco. Lo ligado al scroll anima transform
   y clip-path; lo que arranca en carga sí puede usar opacidad, porque una
   animación de carga termina siempre.

   Todo lo caro vive dentro de @supports + prefers-reduced-motion, así que sin
   soporte o con motion reducido queda una página estática correcta.
   ========================================================================== */

/* La altura de la barra se interpola, así que la propiedad tiene que estar
   registrada: una custom property sin registrar salta de golpe a mitad de la
   animación en lugar de recorrer los valores. */
@property --nav-h {
  syntax: '<length>';
  inherits: true;
  initial-value: 64px;
}

/* Curvas. La expo es la de la casa: sale decidida y frena largo. */
:root {
  --ease-quart: cubic-bezier(0.25, 1, 0.5, 1);
  --ease-quint: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-expo: cubic-bezier(0.16, 1, 0.3, 1);
}

/* ------------------------------------------------- Titular por palabras */
/* Cada palabra sube desde debajo de su línea, tapada por su propia caja. Es el
   gesto de marca: se usa en el titular del hero (en carga) y en los rótulos de
   sección (al entrar en pantalla). */
.words {
  display: inline;
}
.words .w {
  display: inline-block;
  overflow: clip;
  vertical-align: bottom;
  /* El clip corta las colas de las g/j si la caja va justa. */
  padding-bottom: 0.12em;
  margin-bottom: -0.12em;
}
.words .w > span {
  display: inline-block;
  will-change: transform;
}

@media (prefers-reduced-motion: no-preference) {
  .words[data-motion='load'] .w > span {
    animation: word-in 780ms var(--ease-expo) backwards;
    animation-delay: calc(var(--i, 0) * 55ms);
  }
}

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    /* Con línea de tiempo de scroll el escalonado no se hace con retardo sino
       corriendo el rango de cada palabra unos puntos más adelante. */
    .words[data-motion='view'] .w > span {
      animation: word-in linear both;
      animation-timeline: view();
      animation-range: entry calc(8% + var(--i, 0) * 5%) entry calc(58% + var(--i, 0) * 5%);
    }
  }
}

/* Cada palabra sube algo más estrecha y se asienta ensanchándose hasta el
   registro de display: el eje wdth de Archivo trabajando en la entrada. Si el
   reflow horizontal molestara, se quita la línea de font-stretch y listo. */
@keyframes word-in {
  from {
    transform: translateY(105%);
    font-stretch: var(--wd-body);
  }
}

/* ------------------------------------------------- Entradas de bloque */
/* Se usa con cuentagotas: dos o tres bloques por página. El hero nunca, que es
   el LCP. Solo transform, nunca opacidad. */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .reveal {
      animation: reveal-rise linear both;
      animation-timeline: view();
      animation-range: entry 0% entry 45%;
    }
    .reveal[data-variant='slide'] {
      animation-name: reveal-slide;
    }

    /* Rejilla que entra escalonada. El retardo va por posición en la rejilla,
       con tope: a partir de la sexta celda el escalón se agota. */
    .stagger > * {
      animation: reveal-rise linear both;
      animation-timeline: view();
      animation-range: entry 0% entry calc(45% + var(--i, 0) * 8%);
    }
  }
}

@keyframes reveal-rise {
  from {
    transform: translateY(22px);
  }
}

@keyframes reveal-slide {
  from {
    transform: translateX(-22px);
  }
}

/* ------------------------------------------------- Fotografía que se abre */
/* La foto del hero se descubre en carga con un barrido vertical y luego respira
   con el scroll. Son dos animaciones sobre elementos distintos (la máscara en
   el marco, la escala en la imagen) para que no compitan. */
@media (prefers-reduced-motion: no-preference) {
  .media-open {
    animation: media-open 1000ms var(--ease-expo) 120ms backwards;
  }
}

@keyframes media-open {
  from {
    clip-path: inset(0 0 100% 0);
  }
  to {
    clip-path: inset(0 0 0 0);
  }
}

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .media-drift img {
      animation: media-drift linear both;
      animation-timeline: view();
      animation-range: entry 0% exit 100%;
    }
  }
}

@keyframes media-drift {
  from {
    transform: scale(1.09);
  }
  to {
    transform: scale(1);
  }
}

/* ------------------------------------------------- Collage de la cabecera */
/* Las tres piezas se descubren una detrás de otra, no a la vez: primero la
   grande, que es la que cuenta la historia. */
@media (prefers-reduced-motion: no-preference) {
  .hero-collage .media-open {
    animation-delay: calc(120ms + var(--i, 0) * 110ms);
  }
}

/* Y con el scroll cada una deriva a su ritmo. El desfase es lo que separa el
   collage de una rejilla de fotos: pocos píxeles, pero el bloque deja de ser
   plano. La deriva va en la img y el barrido en el marco, como en el hero de
   siempre, para que las dos animaciones no se pisen el transform. La escala del
   keyframe no es adorno: es el margen que tapa el hueco al desplazar. Solo
   transform, como manda la casa. */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .hero-collage .pieza img {
      animation: collage-deriva linear both;
      animation-timeline: view();
      animation-range: entry 0% exit 100%;
    }
    .hero-collage .principal img {
      --deriva-de: 0px;
      --deriva-a: -10px;
      --deriva-escala-de: 1.09;
      --deriva-escala-a: 1;
    }
    .hero-collage .sec-a img {
      --deriva-de: -22px;
      --deriva-a: 12px;
    }
    .hero-collage .sec-b img {
      --deriva-de: 16px;
      --deriva-a: -20px;
    }
  }
}

@keyframes collage-deriva {
  from {
    transform: translateY(var(--deriva-de, 0px)) scale(var(--deriva-escala-de, 1.1));
  }
  to {
    transform: translateY(var(--deriva-a, 0px)) scale(var(--deriva-escala-a, 1.1));
  }
}

/* ------------------------------------------------- Transición entre páginas */
/* Cross-fade corto entre documentos. Beneficia sobre todo al sitio PHP, que es
   una MPA de verdad; la navegación cliente de Next no pasa por aquí y no se
   rompe. La cabecera se fija con view-transition-name para que no parpadee al
   cambiar de página: es el mueble, no el contenido. */
@media (prefers-reduced-motion: no-preference) {
  @view-transition {
    navigation: auto;
  }
  ::view-transition-old(root),
  ::view-transition-new(root) {
    animation-duration: 180ms;
    animation-timing-function: var(--ease-expo);
  }
  .site-header {
    view-transition-name: site-header;
  }
}

/* ------------------------------------------------- Cabecera al hacer scroll */
@supports (animation-timeline: scroll()) {
  @media (prefers-reduced-motion: no-preference) {
    .site-header {
      animation: header-condense linear both;
      animation-timeline: scroll(root block);
      animation-range: 0 220px;
    }
  }
}

@keyframes header-condense {
  to {
    --nav-h: 56px;
    border-bottom-color: var(--line-2);
    box-shadow: var(--sh-2);
  }
}

/* ------------------------------------------------- Raíl de repuesto */
/* Donde no hay animation-timeline (Firefox, Safari viejos) las entradas de
   scroll las dispara un IntersectionObserver que marca data-visible: el de
   sitio.js en PHP y RevealObserver en Next. El estado desplazado solo existe
   bajo html.js, así que sin JavaScript la página queda estática y completa.
   La regla de la casa se mantiene: solo transform, nunca opacidad. */
@supports not (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    html.js .reveal:not([data-visible]) {
      transform: translateY(22px);
    }
    html.js .reveal[data-variant='slide']:not([data-visible]) {
      transform: translateX(-22px);
    }
    html.js .stagger:not([data-visible]) > * {
      transform: translateY(22px);
    }
    html.js .words[data-motion='view']:not([data-visible]) .w > span {
      transform: translateY(105%);
    }

    .reveal,
    .stagger > *,
    .words[data-motion='view'] .w > span {
      transition: transform 700ms var(--ease-expo);
    }
    .stagger > * {
      transition-delay: calc(var(--i, 0) * 70ms);
    }
    .words[data-motion='view'] .w > span {
      transition-delay: calc(var(--i, 0) * 55ms);
    }
  }
}

/* ------------------------------------------------- Reducción de movimiento */
@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
  .reveal,
  .stagger > *,
  .words .w > span {
    animation: none;
    transform: none;
  }
}
}

/* layout.css */
@layer layout {
.container {
  width: 100%;
  max-width: var(--max);
  margin: 0 auto;
  padding: 0 var(--sp-5);
}

main.container {
  padding-top: var(--sp-6);
  padding-bottom: var(--sp-9);
}
/* Cuando la página termina en una banda a sangre, el aire de abajo lo pone la
   propia banda: si no, queda una franja vacía entre el color y el faldón. El
   margen del pie también sobra en ese caso: se anula en chrome.css, junto al
   propio pie, porque esa capa va después que esta. */
main.container:has(> section:last-child.bleed) {
  padding-bottom: 0;
}

section {
  margin-bottom: var(--section-y);
}
section:last-child {
  margin-bottom: 0;
}

/* Banda a sangre: rompe el contenedor y vuelve a meter el contenido dentro.
   body tiene overflow-x: clip, así que la barra de scroll no genera desborde. */
.bleed {
  margin-inline: calc(50% - 50vw);
  padding-inline: max(var(--sp-5), calc(50vw - var(--max) / 2 + var(--sp-5)));
}

/* Solo sangra por la derecha: composición asimétrica del hero.
   No sirve calc(50% - 50vw) porque el elemento es una celda de rejilla y ese
   50% se resuelve contra la celda, no contra el contenedor: la foto se salía
   del viewport y se perdía un tercio de la imagen. Se calcula la distancia
   real entre el borde del contenedor y el del viewport. */
.bleed-right {
  margin-right: calc(-1 * ((100vw - min(100vw, var(--max))) / 2 + var(--sp-5)));
}

/* Placa de contraste. Invierte los tokens de tinta para toda la subrama, así
   que en tema claro es una banda oscura y en tema oscuro es una banda clara. */
.plate-contrast {
  background: var(--inv-bg);
  color: var(--inv-ink);
  --ink: var(--inv-ink);
  --ink-2: var(--inv-ink-2);
  --ink-3: var(--inv-ink-3);
  --line: var(--inv-line);
  --line-2: var(--inv-line-2);
  --bg-2: var(--inv-bg-2);
  --bg-3: var(--inv-bg-2);
  --surface: var(--inv-bg-2);
  --brand: var(--brand-lift);
}

/* Placa de marca. Mismo mecanismo, el color corporativo drenado a sangre. */
.plate-brand {
  background: var(--band-bg);
  color: var(--band-ink);
  --ink: var(--band-ink);
  --ink-2: var(--band-ink-2);
  --ink-3: var(--band-ink-2);
  --line: var(--band-line);
  --line-2: var(--band-line-2);
}

.notfound {
  padding: clamp(64px, 12vw, 144px) 0;
  max-width: 34rem;
}
.notfound h1 {
  margin: var(--sp-2) 0 var(--sp-4);
}
.notfound .lead {
  margin-bottom: var(--sp-6);
}

.grid {
  display: grid;
  gap: var(--sp-4);
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
}

.split {
  display: grid;
  grid-template-columns: 0.85fr 1.15fr;
  gap: var(--sp-7);
}

.two-col {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--sp-7);
  align-items: start;
}

/* Texto largo con ficha al lado. La columna de lectura se queda en su medida,
   que es lo que se lee cómodo, y al lado va lo que antes era medio folio en
   blanco: los datos y la salida de la página. */
.lectura {
  display: grid;
  grid-template-columns: minmax(0, 68ch) minmax(240px, 1fr);
  gap: clamp(32px, 5vw, 72px);
  align-items: start;
}
.lectura-ficha {
  position: sticky;
  top: calc(var(--nav-h) + var(--sp-5));
  display: grid;
  gap: var(--sp-4);
  padding: var(--sp-5);
  background: var(--bg-2);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
}
.lectura-ficha dl {
  margin: 0;
  display: grid;
  gap: var(--sp-1);
}
.lectura-ficha dt {
  font-stretch: var(--wd-data);
  font-weight: 500;
  font-size: 0.8125rem;
  letter-spacing: 0.02em;
  color: var(--ink-3);
}
.lectura-ficha dt + dd {
  margin: 0 0 var(--sp-3);
  color: var(--ink);
  font-size: 0.9375rem;
  line-height: 1.45;
}
.lectura-ficha dd:last-of-type {
  margin-bottom: 0;
}
.lectura-ficha dd a {
  color: var(--brand);
  text-decoration: underline;
  text-underline-offset: 3px;
}
.lectura-ficha .btn {
  justify-content: space-between;
  text-align: left;
}
.lectura-ficha .link-arrow {
  justify-self: start;
}

@media (max-width: 1000px) {
  /* Bajo esta anchura la ficha ya no cabe al lado sin estrangular la lectura:
     pasa debajo del texto, antes del resto de la página. */
  .lectura {
    grid-template-columns: 1fr;
    gap: var(--sp-6);
  }
  .lectura-ficha {
    position: static;
  }
}

.stack {
  display: grid;
  gap: var(--sp-4);
}

.section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-5);
  margin-bottom: var(--stack-y);
  padding-bottom: var(--sp-4);
  border-bottom: 1px solid var(--line);
}
.section-head h2 {
  margin: 0;
}

@media (max-width: 900px) {
  .split,
  .two-col {
    grid-template-columns: 1fr;
    gap: var(--sp-6);
  }
}

@media (max-width: 540px) {
  .container {
    padding: 0 var(--sp-4);
  }
  .section-head {
    flex-direction: column;
    align-items: flex-start;
    gap: var(--sp-2);
  }
}
}

/* primitives.css */
@layer primitives {
/* ----------------------------------------------------------------- Botones */
.btn {
  --pad: 12px 20px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5em;
  padding: var(--pad);
  font-weight: 600;
  font-size: 0.9375rem;
  line-height: 1;
  white-space: nowrap;
  border-radius: var(--r-sm);
  border: 1px solid var(--brand-fill);
  background: var(--brand-fill);
  color: var(--brand-fill-ink);
  cursor: pointer;
  transition:
    background var(--dur-2) var(--ease-out),
    border-color var(--dur-2) var(--ease-out),
    color var(--dur-2) var(--ease-out);
}
.btn:hover {
  background: var(--brand-fill-2);
  border-color: var(--brand-fill-2);
}
.btn:active {
  transform: translateY(1px);
}

.btn.secondary {
  background: transparent;
  color: var(--ink);
  border-color: var(--line-2);
}
.btn.secondary:hover {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--bg);
}

/* Sobre la banda de marca el primario se invierte a blanco sólido. */
.plate-brand .btn {
  background: var(--band-ink);
  border-color: var(--band-ink);
  color: var(--band-bg);
}
.plate-brand .btn:hover {
  background: transparent;
  color: var(--band-ink);
}
.plate-brand .btn.secondary {
  background: transparent;
  color: var(--band-ink);
  border-color: var(--band-line-2);
}
.plate-brand .btn.secondary:hover {
  background: var(--band-ink);
  color: var(--band-bg);
  border-color: var(--band-ink);
}

.plate-contrast .btn.secondary:hover {
  background: var(--inv-ink);
  border-color: var(--inv-ink);
  color: var(--inv-bg);
}

.btn.small {
  --pad: 9px 15px;
  font-size: 0.875rem;
}
.btn.block {
  width: 100%;
}
.btn[disabled],
.btn[aria-disabled='true'] {
  opacity: 0.5;
  pointer-events: none;
}

/* ----------------------------------------------------------------- Enlaces */
.arrow {
  display: inline-block;
  transition: transform var(--dur-2) var(--ease-out);
}
.btn:hover .arrow,
.link-arrow:hover .arrow,
a.card:hover .arrow,
.btile:hover .arrow,
.btile:focus-visible .arrow {
  transform: translateX(4px);
}

/* La flecha de cierre de tarjetas y filas responde al hover del padre con el
   mismo gesto: las cosas entran y avanzan hacia la derecha. */
.go {
  display: inline-block;
  transition: transform var(--dur-2) var(--ease-out);
}
.btile:hover .go,
.news-item:hover .go,
.news-lead:hover .go,
.brand-card:hover .go {
  transform: translateX(3px);
}

.link-arrow {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  color: var(--brand);
  font-weight: 600;
  font-size: 0.9375rem;
  border-bottom: 1px solid transparent;
  transition: border-color var(--dur-2) var(--ease-out);
}
.link-arrow:hover {
  border-bottom-color: currentColor;
}

/* ----------------------------------------------------------------- Etiquetas */
.tag {
  display: inline-flex;
  align-items: center;
  gap: 0.45em;
  font-stretch: var(--wd-data);
  font-weight: 600;
  font-size: 0.78rem;
  letter-spacing: 0.04em;
  color: var(--ink-2);
  background: var(--bg-2);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 4px 11px;
}
.tag.brand {
  color: var(--brand);
  background: var(--brand-soft);
  border-color: var(--brand-line);
}

/* ----------------------------------------------------------------- Superficies */
.surface {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
}

.card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  padding: var(--sp-5);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  transition:
    border-color var(--dur-3) var(--ease-out),
    background var(--dur-3) var(--ease-out);
}
a.card:hover {
  border-color: var(--brand);
}
.card h3 {
  margin: 0;
}
.card .excerpt {
  margin: 0;
  font-size: 0.9688rem;
  color: var(--ink-2);
}
.card-kicker {
  font-stretch: var(--wd-data);
  font-weight: 600;
  font-size: 0.78rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--brand);
}

/* ----------------------------------------------------------------- Media */
/* La fotografía se muestra entera y a plena opacidad. Nunca velada, nunca
   atenuada bajo un degradado: es información, no textura. */
.media {
  position: relative;
  display: block;
  overflow: hidden;
  background: var(--bg-3);
  border-radius: var(--r-md);
}
.media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.media.r-16-9 {
  aspect-ratio: 16 / 9;
}
.media.r-4-3 {
  aspect-ratio: 4 / 3;
}
.media.r-3-2 {
  aspect-ratio: 3 / 2;
}
.media.r-1-1 {
  aspect-ratio: 1 / 1;
}
.media.r-21-9 {
  aspect-ratio: 21 / 9;
}
/* Un <figure> alrededor de un .media es lo correcto semánticamente, pero el
   navegador le da margin: 1em 40px por su cuenta: dentro de una columna de
   rejilla eso desalinea la foto respecto al texto de al lado, y en móvil la
   estrecha contra los márgenes del contenedor. */
.media-figure {
  margin: 0;
}

/* La imagen que sangra dentro de una card ocupa el ancho completo del padding. */
.card-media {
  margin: calc(var(--sp-5) * -1) calc(var(--sp-5) * -1) var(--sp-3);
  border-radius: var(--r-md) var(--r-md) 0 0;
  border-bottom: 1px solid var(--line);
}
.card-media img {
  transition: transform var(--dur-4) var(--ease-out);
}
a.card:hover .card-media img {
  transform: scale(1.03);
}

.page-banner {
  margin: 0 0 var(--sp-7);
  border-radius: var(--r-lg);
  overflow: hidden;
  aspect-ratio: 21 / 9;
  background: var(--bg-3);
}
.page-banner img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/*
 * Banner encajado a un lado, con el texto rodeándolo.
 *
 * Para una página que es sobre todo texto y una foto. A ancho completo el
 * banner son 566px de alto y se come la entrada; suelto encima del texto, con
 * la medida que sea, deja media página vacía a la derecha, porque la columna de
 * lectura ocupa 662px de los 1272 disponibles. Flotando, la foto llena ese
 * hueco y el texto pasa a usar el ancho entero.
 *
 * Va en pareja con .prose-ancha: sin liberar el max-width de la prosa, el texto
 * se queda en su columna y el flotante no toca nada.
 */
.page-banner.flotante {
  float: right;
  width: 44%;
  margin: 0 0 var(--sp-5) var(--sp-7);
}
/* Por debajo del corte de dos columnas el flotante deja de tener sentido: la
   línea se quedaría en cuatro palabras al lado de la foto. */
@media (max-width: 900px) {
  .page-banner.flotante {
    float: none;
    width: auto;
    margin: 0 0 var(--sp-5);
  }
}

/* ----------------------------------------------------------------- Ficha de datos */
/* Pares etiqueta/valor en filas separadas por filete. Una tabla de datos no
   necesita una tarjeta por dato. */
.factsheet {
  margin: 0;
  border-top: 1px solid var(--line);
  max-width: 46rem;
}
.factsheet > div {
  display: grid;
  grid-template-columns: 12rem 1fr;
  gap: var(--sp-4);
  padding: var(--sp-4) 0;
  border-bottom: 1px solid var(--line);
}
.factsheet dt {
  margin: 0;
}
.factsheet dd {
  margin: 0;
  color: var(--ink);
}

@media (max-width: 540px) {
  .factsheet > div {
    grid-template-columns: 1fr;
    gap: var(--sp-1);
  }
}

/* ----------------------------------------------------------------- Cifras */
.statrow {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-7);
  border-top: 1px solid var(--line);
  padding-top: var(--sp-5);
}
.stat {
  display: grid;
  gap: 2px;
}
.stat .num {
  font-stretch: var(--wd-display);
  font-size: clamp(1.75rem, 3vw, 2.25rem);
  font-weight: 700;
  line-height: 1;
  letter-spacing: -0.02em;
  color: var(--ink);
}
.stat .lbl {
  font-stretch: var(--wd-data);
  font-weight: 500;
  font-size: 0.9375rem;
  letter-spacing: 0.02em;
  color: var(--ink-2);
}

@media (max-width: 540px) {
  .statrow {
    gap: var(--sp-5) var(--sp-6);
  }
}
}

/* chrome.css */
@layer chrome {
/* ----------------------------------------------------------------- Marca */
/* El logotipo original vectorial: isotipo, SOUNDWARE en versalitas, filete y
   MEDIA, todo en una pieza. Hasta agosto de 2026 aquí se componía el nombre
   con Archivo al lado del isotipo, que es justo lo que el cliente señaló como
   ajeno a su marca. Se genera con scripts/construir-logotipos.mjs. */
.brand {
  display: inline-flex;
  align-items: center;
}
/* 44px en una barra de 64 que al desplazar se condensa a 56: quedan 6px de aire
   arriba y abajo en el estado apretado, que es el mínimo que aguanta. El rótulo
   solo ocupa el tercio central del lockup, así que a 34px las versalitas se
   quedaban en 11px y no se leían. */
.brand .logo {
  display: block;
  height: 44px;
  width: auto;
}
/* Los dos grises del logotipo (#818285 y #b6b7ba) se apagan sobre placa
   oscura, así que ahí entra la versión blanca del propio arte. No es un filtro
   de repintado: es el otro entregable del cliente. */
.brand .logo-oscuro {
  display: none;
}
:root[data-theme='oscuro'] .brand .logo-claro {
  display: none;
}
:root[data-theme='oscuro'] .brand .logo-oscuro {
  display: block;
}
@media (max-width: 640px) {
  .brand .logo {
    height: 36px;
  }
}

/* ----------------------------------------------------------------- Cabecera */
.site-header {
  position: sticky;
  top: 0;
  z-index: var(--z-sticky);
  background: var(--bg-blur);
  backdrop-filter: saturate(140%) blur(12px);
  -webkit-backdrop-filter: saturate(140%) blur(12px);
  border-bottom: 1px solid var(--line);
}
.site-header .bar {
  height: var(--nav-h);
  max-width: var(--max);
  margin: 0 auto;
  padding: 0 var(--sp-5);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-5);
}

.site-nav {
  display: flex;
  align-items: center;
  gap: var(--sp-5);
}
.site-nav a {
  position: relative;
  font-size: 0.9375rem;
  font-weight: 500;
  color: var(--ink-2);
  padding: 4px 0;
  transition: color var(--dur-2) var(--ease-out);
}
.site-nav a:hover {
  color: var(--ink);
}
/* El filete entra por la izquierda y sale por la derecha: en reposo el origen
   está a la derecha, y al entrar el puntero cambia a la izquierda (el cambio de
   origen es instantáneo, solo se transiciona el transform). */
.site-nav a::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: -2px;
  height: 2px;
  background: var(--brand);
  transform: scaleX(0);
  transform-origin: right;
  transition: transform var(--dur-2) var(--ease-out);
}
.site-nav a:hover::after,
.site-nav a:focus-visible::after {
  transform: scaleX(1);
  transform-origin: left;
}
.site-nav a[aria-current='page'] {
  color: var(--ink);
}
.site-nav a[aria-current='page']::after {
  transform: scaleX(1);
  transform-origin: left;
}

.header-cta {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
}

/*
 * Redes de la cabecera.
 *
 * Van a la izquierda del botón porque el botón es lo que se pide de esta web y
 * las redes son de donde uno viene: si compiten por el mismo peso, la llamada
 * a la acción deja de leerse como tal. De ahí que sean del gris de apoyo y solo
 * se enciendan al pasar por encima.
 *
 * Por debajo de 860px desaparecen con el resto de la barra y reaparecen dentro
 * del menú a pantalla completa (.mobile-nav-redes).
 */
.header-redes,
.footer-redes,
.mobile-nav-redes {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  list-style: none;
  margin: 0;
  padding: 0;
}
.header-redes a,
.footer-redes a,
.mobile-nav-redes a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 999px;
  color: var(--ink-3);
  transition: color var(--dur-2) var(--ease-out), background-color var(--dur-2) var(--ease-out);
}
.header-redes a:hover,
.footer-redes a:hover,
.mobile-nav-redes a:hover {
  color: var(--ink);
  background: var(--bg-2);
}
.red-inicial {
  font-size: 0.9rem;
  font-weight: 600;
}
/* El icono va centrado en su círculo de 34px, así que sin esto la fila
   empieza medio dedo a la derecha del texto de la columna. */
.footer-redes {
  margin-left: -8px;
}

/* Botón hamburguesa, con icono real */
.nav-toggle {
  display: none;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  background: transparent;
  border: 1px solid var(--line-2);
  border-radius: var(--r-sm);
  color: var(--ink);
  cursor: pointer;
  transition: border-color var(--dur-2) var(--ease-out);
}
.nav-toggle:hover {
  border-color: var(--ink);
}
.nav-toggle .bars {
  position: relative;
  width: 17px;
  height: 11px;
}
.nav-toggle .bars span {
  position: absolute;
  left: 0;
  width: 100%;
  height: 1.5px;
  background: currentColor;
  border-radius: 2px;
  transition: transform var(--dur-3) var(--ease-out), opacity var(--dur-1) linear;
}
.nav-toggle .bars span:nth-child(1) {
  top: 0;
}
.nav-toggle .bars span:nth-child(2) {
  top: 50%;
  margin-top: -0.75px;
}
.nav-toggle .bars span:nth-child(3) {
  bottom: 0;
}
.nav-toggle[aria-expanded='true'] .bars span:nth-child(1) {
  transform: translateY(4.75px) rotate(45deg);
}
.nav-toggle[aria-expanded='true'] .bars span:nth-child(2) {
  opacity: 0;
}
.nav-toggle[aria-expanded='true'] .bars span:nth-child(3) {
  transform: translateY(-4.75px) rotate(-45deg);
}

/* ------------------------------------------------------- Menú a pantalla completa */
/* Tapa la ventana entera y entra desde la derecha, como un cajón. Cerrado vive
   con hidden (ver porte.css); la clase abierto es lo que dispara la entrada, y
   sobrevive al cierre lo justo para que la salida se vea. Ojo con el ancestro:
   un filter, un transform o un view-transition-name por encima y este fixed se
   mide contra ese ancestro, no contra la ventana. */
.mobile-nav {
  position: fixed;
  inset: 0;
  z-index: var(--z-overlay);
  background: var(--bg);
  padding: 0 var(--sp-5) max(var(--sp-6), env(safe-area-inset-bottom));
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: var(--sp-5);
  transform: translateX(100%);
  visibility: hidden;
  transition: transform 260ms var(--ease-out), visibility 0s linear 260ms;
}
.mobile-nav.abierto {
  transform: none;
  visibility: visible;
  transition: transform 420ms var(--ease-expo), visibility 0s;
}
.mobile-nav-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  min-height: var(--nav-h);
  margin-bottom: var(--sp-2);
}
.mobile-nav-cerrar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  margin-right: -8px;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: none;
  color: var(--ink);
  cursor: pointer;
}
.mobile-nav ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
}
.mobile-nav li {
  border-bottom: 1px solid var(--line);
}
.mobile-nav li a {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--sp-4) 0;
  font-stretch: var(--wd-display);
  font-size: clamp(1.75rem, 7.5vw, 2.25rem);
  font-weight: 700;
  line-height: 1.1;
  letter-spacing: -0.02em;
  color: var(--ink);
}
.mobile-nav li a[aria-current='page'] {
  color: var(--brand);
}
.mobile-nav li a .arrow {
  color: var(--ink-3);
}
/* El botón se queda abajo del todo, donde llega el pulgar. */
.mobile-nav-cta {
  align-self: flex-start;
  margin-top: auto;
}
/*
 * Y las redes debajo del botón, que es donde se buscan cuando ya se ha
 * descartado todo lo demás del menú.
 *
 * Hay que deshacer lo que el panel le pone a sus listas: la columna, el filete
 * de cada entrada y el titular de 2rem de los enlaces. Sin esto los tres iconos
 * salían uno debajo de otro y subrayados, como si fueran menú.
 */
.mobile-nav .mobile-nav-redes {
  flex-direction: row;
  margin-top: var(--sp-4);
  margin-left: -7px;
}
.mobile-nav .mobile-nav-redes li {
  border-bottom: 0;
}
.mobile-nav .mobile-nav-redes li a {
  justify-content: center;
  padding: 0;
  font-size: inherit;
  font-weight: inherit;
  letter-spacing: normal;
}
/* Los enlaces entran detrás del panel, uno tras otro. Es interacción, no
   scroll, así que aquí la opacidad sí vale: nadie se queda sin ver el menú
   porque una animación no llegue a dispararse. */
@media (prefers-reduced-motion: no-preference) {
  .mobile-nav li,
  .mobile-nav-cta {
    transform: translateY(16px);
    opacity: 0;
  }
  .mobile-nav.abierto li,
  .mobile-nav.abierto .mobile-nav-cta {
    transform: none;
    opacity: 1;
    transition: transform 440ms var(--ease-expo), opacity 300ms linear;
    transition-delay: calc(90ms + var(--i, 0) * 45ms);
  }
}
/* El conmutador de tema flota por encima de todo el sitio; con el menú abierto
   estorbaría en mitad del panel. */
body:has(.mobile-nav.abierto) .tema-toggle {
  visibility: hidden;
}

/* ----------------------------------------------------------------- Pie */
.site-footer {
  border-top: 1px solid var(--line);
  margin-top: var(--sp-9);
  background: var(--bg-2);
}
/* Si la página termina en banda a sangre (CTA ámbar), el pie va pegado a
   ella: el margen de cortesía solo tiene sentido sobre fondo de página. */
main.container:has(> section:last-child.bleed) + .site-footer {
  margin-top: 0;
}
.site-footer .cols {
  display: grid;
  grid-template-columns: 1.5fr 1fr 1fr 1fr;
  gap: var(--sp-6);
  padding: var(--sp-8) 0 var(--sp-7);
}
.site-footer .brand {
  margin-bottom: var(--sp-3);
}
/* El claim va como imagen porque el cliente solo lo tiene en manuscrita
   rasterizada; no hay fuente que instalar. Con el logotipo encima, ocupa su
   misma medida óptica y no compite. */
.claim {
  display: block;
  height: 22px;
  width: auto;
  margin: 0 0 var(--sp-4);
}
.claim-oscuro {
  display: none;
}
:root[data-theme='oscuro'] .claim-claro {
  display: none;
}
:root[data-theme='oscuro'] .claim-oscuro {
  display: block;
}
.footer-note {
  font-size: 0.9rem;
  color: var(--ink-3);
  max-width: 34ch;
}
.footer-titulo-gap {
  margin-top: var(--sp-5);
}
/* Rótulos de columna. Iban en el gris más apagado y a 13px, casi el mismo peso
   óptico que los enlaces de debajo: no se leían como encabezados sino como una
   línea más de la lista. Ahora los separa el color de marca y la caja alta. Va
   por token y no por #f29400 literal: ese naranja sobre fondo claro da 2.15:1 y
   no sostiene texto; --brand es su versión bajada de luminosidad a tono
   constante, y en tema oscuro el token ya devuelve el naranja de la hoja. */
/* Van en h2 y no en h4: el pie es hermano del contenido, no hijo de su último
   apartado, y con h4 axe marcaba heading-order en todas las páginas (de un h2
   de sección se saltaba a un h4 sin h3 por medio). Como aquí se pisa la escala
   entera de h2, la regla declara también line-height y letter-spacing: si no,
   heredaba los del titular grande. */
.site-footer h2 {
  font-stretch: 90%;
  font-size: 0.875rem;
  line-height: 1.3;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--brand);
  margin: 0 0 var(--sp-3);
}
.site-footer ul {
  list-style: none;
  margin: 0;
  padding: 0;
}
.site-footer li {
  margin-bottom: var(--sp-2);
  font-size: 0.9375rem;
  color: var(--ink-2);
}
.site-footer a {
  transition: color var(--dur-2) var(--ease-out);
}
.site-footer a:hover {
  color: var(--brand);
}
.site-footer .legal {
  border-top: 1px solid var(--line);
  padding: var(--sp-4) 0 var(--sp-6);
  font-stretch: var(--wd-data);
  font-size: 0.8125rem;
  color: var(--ink-3);
  display: flex;
  justify-content: space-between;
  gap: var(--sp-4);
  flex-wrap: wrap;
  align-items: center;
}

/*
 * Sello del W3C, en su propia línea y centrado, igual que en la web de Datos
 * Media. No va en la fila del copyright a propósito: esa esquina la ocupa el
 * conmutador de tema, que flota fijo sobre el pie, y en cuanto la pantalla se
 * estrecha se le echaría encima.
 */
.sello-w3c {
  flex-basis: 100%;
  display: flex;
  justify-content: center;
  margin-top: var(--sp-2);
}
.sello-w3c img {
  display: block;
  height: 31px;
  width: auto;
}

/* ------------------------------------------------------- Conmutador de tema */
/* Va fijo en la esquina y no en la cabecera a propósito: el cambio de tema se
   juzga mirando la página, no el menú, así que el control tiene que seguir ahí
   mientras se recorre. Nace con hidden en el HTML y lo enseña sitio.js: sin
   JavaScript no hay nada que conmutar y un botón muerto es peor que ninguno. */
.tema-toggle {
  position: fixed;
  right: max(var(--sp-4), env(safe-area-inset-right));
  bottom: max(var(--sp-4), env(safe-area-inset-bottom));
  z-index: var(--z-toast);
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  height: 40px;
  padding: 0 var(--sp-4);
  background: var(--bg-blur);
  backdrop-filter: saturate(140%) blur(12px);
  -webkit-backdrop-filter: saturate(140%) blur(12px);
  border: 1px solid var(--line-2);
  border-radius: 999px;
  box-shadow: var(--sh-2);
  color: var(--ink-2);
  font-stretch: var(--wd-data);
  font-size: 0.8125rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  cursor: pointer;
  transition:
    color var(--dur-2) var(--ease-out),
    border-color var(--dur-2) var(--ease-out);
}
.tema-toggle:hover {
  color: var(--ink);
  border-color: var(--ink-3);
}
.tema-toggle[hidden] {
  display: none;
}

/* Los dos iconos se apilan en la misma casilla y solo se ve el que toca, para
   que el botón no cambie de ancho al pulsarlo. */
.tema-icono {
  display: grid;
  place-items: center;
  width: 18px;
  height: 18px;
}
.tema-icono svg {
  grid-area: 1 / 1;
  color: var(--brand);
}
.tema-luna,
:root[data-theme='oscuro'] .tema-sol {
  display: none;
}
:root[data-theme='oscuro'] .tema-luna {
  display: block;
}

@media (max-width: 540px) {
  /* En móvil se queda el icono solo: el texto se comía media pantalla sobre
     el contenido. */
  .tema-toggle {
    width: 40px;
    padding: 0;
    justify-content: center;
  }
  .tema-texto {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
}

@media print {
  .tema-toggle {
    display: none;
  }
}

/* ----------------------------------------------------------------- Skip link */
.skip-link {
  position: fixed;
  top: -100px;
  left: var(--sp-4);
  z-index: var(--z-skip);
  padding: 10px 16px;
  background: var(--brand);
  color: var(--brand-ink);
  font-weight: 600;
  font-size: 0.9rem;
  border-radius: var(--r-sm);
  transition: top var(--dur-2) var(--ease-out);
}
.skip-link:focus-visible {
  top: 12px;
}

@media (max-width: 900px) {
  .site-footer .cols {
    grid-template-columns: 1fr 1fr;
  }
}

@media (max-width: 860px) {
  .site-nav,
  .header-redes,
  .header-cta .btn {
    display: none;
  }
  .nav-toggle {
    display: inline-flex;
  }
}

@media (max-width: 540px) {
  .site-footer .cols {
    grid-template-columns: 1fr;
    gap: var(--sp-6);
  }
}

/* -------------------------------------------------- Correo dibujado */

/*
 * La dirección de correo se sirve como imagen para que no viaje escrita en el
 * HTML (ver Servicios/CorreoImagen). Se pinta en dos tintas, una por tema, con
 * el mismo apaño que el logotipo: aquí no vale un filtro de repintado, porque
 * lo que cambia es el gris del propio dibujo.
 *
 * El alto va en em y no en píxeles para que siga al texto que la rodea si algún
 * día crece la tipografía del pie.
 */
/* En línea, porque además del pie aparece dentro de frases de los legales:
   "debe remitir a [dirección]". En bloque partía el párrafo en dos. */
.correo {
  display: inline-block;
  vertical-align: text-bottom;
}
.correo img {
  display: block;
  height: 1.25em;
  width: auto;
  /*
   * Un texto dibujado pesa más que el mismo texto compuesto por el navegador:
   * el suavizado del navegador es consciente del gamma y el de la librería de
   * imágenes no, así que al lado del teléfono la dirección se leía en negrita
   * sin serlo. Esto la devuelve al peso de sus vecinas. Va en opacidad y no en
   * un gris más claro porque la mezcla depende del fondo, y esta imagen se usa
   * sobre el pie y sobre la página de contacto, que no son del mismo color. El
   * contraste resultante se queda por encima de 5:1 en los dos temas.
   */
  opacity: 0.82;
}
.correo .correo-oscuro {
  display: none;
}
:root[data-theme='oscuro'] .correo .correo-claro {
  display: none;
}
:root[data-theme='oscuro'] .correo .correo-oscuro {
  display: block;
}

/* ------------------------------------------------- Texto solo para lectores */

/*
 * Un icono sin texto no es nada para un lector de pantalla ni para el buscador.
 * Esto deja el nombre en el documento sin ocuparle sitio a nadie. No se usa
 * display:none ni visibility:hidden a propósito: las dos lo sacan del árbol de
 * accesibilidad, que es justo lo contrario de lo que se busca.
 */
.solo-lector {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}
}

/* features/forms.css */
@layer features {
.form {
  display: grid;
  gap: var(--sp-4);
  max-width: 560px;
}
.form label {
  display: grid;
  gap: var(--sp-1);
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--ink);
}
.form input,
.form textarea,
.form select {
  width: 100%;
  padding: 11px 13px;
  background: var(--surface);
  border: 1px solid var(--line-2);
  border-radius: var(--r-sm);
  color: var(--ink);
  font-weight: 400;
  transition:
    border-color var(--dur-2) var(--ease-out),
    box-shadow var(--dur-2) var(--ease-out);
}
.form input::placeholder,
.form textarea::placeholder {
  /* Mismo contraste que el cuerpo: el placeholder también hay que poder leerlo. */
  color: var(--ink-2);
  opacity: 1;
}
.form input:focus,
.form textarea:focus,
.form select:focus {
  outline: none;
  border-color: var(--brand);
  box-shadow: 0 0 0 3px var(--brand-soft);
}
.form input[type='file'] {
  padding: 9px 12px;
  color: var(--ink-2);
}
.form input[type='file']::file-selector-button {
  margin-right: 12px;
  padding: 6px 12px;
  border: 1px solid var(--line-2);
  border-radius: var(--r-xs);
  background: var(--bg-2);
  color: var(--ink);
  font-weight: 600;
  font-size: 0.85rem;
  cursor: pointer;
}
.form .row {
  display: grid;
  gap: var(--sp-4);
  grid-template-columns: 1fr 1fr;
}
.form .check {
  display: flex;
  gap: var(--sp-2);
  align-items: flex-start;
  font-size: 0.875rem;
  font-weight: 400;
  color: var(--ink-2);
}
.form .check input {
  width: auto;
  margin-top: 3px;
  accent-color: var(--brand);
}
.form .hint {
  font-stretch: var(--wd-data);
  font-size: 0.8125rem;
  font-weight: 400;
  color: var(--ink-3);
}

.notice {
  padding: 12px 14px;
  border-radius: var(--r-sm);
  font-size: 0.9rem;
}
.notice.ok {
  background: var(--ok-bg);
  border: 1px solid var(--ok);
  color: var(--ink);
}
.notice.err {
  background: var(--err-bg);
  border: 1px solid var(--err);
  color: var(--ink);
}

.plate-contrast .notice.ok,
.plate-contrast .notice.err {
  background: transparent;
  color: var(--inv-ink);
}

/*
 * Campo de miel. Sigue en el flujo y con tamaño real para el navegador, solo
 * que fuera de la vista: un display:none o un [hidden] se detectan leyendo el
 * marcado, y entonces el robot lo salta y la trampa no sirve de nada.
 */
.miel {
  position: absolute;
  left: -9999px;
  top: auto;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

@media (max-width: 720px) {
  .form .row {
    grid-template-columns: 1fr;
  }
}
}

/* features/cookies.css */
@layer features {
.cookie-banner {
  position: fixed;
  z-index: var(--z-banner);
  left: var(--sp-4);
  right: var(--sp-4);
  bottom: var(--sp-4);
  display: flex;
  justify-content: center;
  animation: cookie-up var(--dur-4) var(--ease-out) both;
  animation-delay: 0.6s;
}
@keyframes cookie-up {
  from {
    opacity: 0;
    transform: translateY(12px);
  }
}
.cookie-banner-inner {
  display: flex;
  align-items: center;
  gap: var(--sp-5);
  max-width: 860px;
  width: 100%;
  padding: var(--sp-4) var(--sp-5);
  border-radius: var(--r-md);
  background: var(--surface);
  border: 1px solid var(--line-2);
  box-shadow: var(--sh-3);
}
.cookie-copy {
  flex: 1;
}
.cookie-copy p {
  margin: 0;
  font-size: 0.9rem;
  color: var(--ink-2);
  max-width: none;
}
.cookie-copy a {
  color: var(--brand);
  text-decoration: underline;
  text-underline-offset: 3px;
}
.cookie-actions {
  display: flex;
  gap: var(--sp-2);
  flex-wrap: wrap;
  justify-content: flex-end;
}
.cookie-reopen {
  position: fixed;
  z-index: var(--z-banner);
  left: var(--sp-4);
  bottom: var(--sp-4);
  width: 38px;
  height: 38px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--surface);
  border: 1px solid var(--line-2);
  color: var(--ink-3);
  cursor: pointer;
  box-shadow: var(--sh-1);
  transition:
    color var(--dur-2) var(--ease-out),
    border-color var(--dur-2) var(--ease-out);
}
.cookie-reopen:hover {
  color: var(--brand);
  border-color: var(--brand);
}
.cookie-overlay {
  position: fixed;
  inset: 0;
  z-index: var(--z-overlay);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--sp-5);
  background: var(--scrim);
  animation: cookie-fade var(--dur-3) var(--ease-out) both;
}
@keyframes cookie-fade {
  from {
    opacity: 0;
  }
}
.cookie-dialog {
  width: 100%;
  max-width: 560px;
  max-height: calc(100vh - 40px);
  overflow-y: auto;
  padding: var(--sp-6);
  border-radius: var(--r-lg);
  background: var(--surface);
  border: 1px solid var(--line-2);
  box-shadow: var(--sh-3);
  animation: cookie-up var(--dur-3) var(--ease-out) both;
}
.cookie-dialog h3 {
  font-size: 1.4rem;
  margin-bottom: 0.35em;
}
.cookie-dialog > p.muted {
  font-size: 0.9rem;
}
.cookie-cats {
  display: flex;
  flex-direction: column;
  margin: var(--sp-5) 0 var(--sp-5);
}
.cookie-cat {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  padding: var(--sp-4) 0;
  border-top: 1px solid var(--line);
  cursor: pointer;
}
.cookie-cat:last-child {
  border-bottom: 1px solid var(--line);
}
.cookie-cat.locked {
  cursor: default;
}
.cookie-cat-text {
  display: grid;
  gap: 3px;
}
.cookie-cat-text strong {
  font-size: 0.95rem;
  color: var(--ink);
}
.cookie-cat-text span {
  font-size: 0.875rem;
  color: var(--ink-2);
  line-height: 1.5;
}
.switch {
  position: relative;
  flex: none;
  width: 44px;
  height: 24px;
}
.switch input {
  position: absolute;
  inset: 0;
  opacity: 0;
  margin: 0;
  cursor: pointer;
}
.switch input:disabled {
  cursor: default;
}
.switch .track {
  position: absolute;
  inset: 0;
  border-radius: 999px;
  background: var(--bg-3);
  border: 1px solid var(--line-2);
  transition:
    background var(--dur-2) var(--ease-out),
    border-color var(--dur-2) var(--ease-out);
}
.switch .track::after {
  content: '';
  position: absolute;
  top: 3px;
  left: 3px;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--ink-3);
  transition:
    transform var(--dur-2) var(--ease-out),
    background var(--dur-2) var(--ease-out);
}
.switch input:checked + .track {
  background: var(--brand);
  border-color: var(--brand);
}
.switch input:checked + .track::after {
  transform: translateX(20px);
  background: var(--brand-ink);
}
.switch input:focus-visible + .track {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
}
.switch input:disabled + .track {
  opacity: 0.55;
}
.cookie-dialog-actions {
  display: flex;
  gap: var(--sp-2);
  flex-wrap: wrap;
  justify-content: flex-end;
}
.cookie-dialog-footer {
  margin: var(--sp-4) 0 0;
  font-size: 0.8125rem;
  display: flex;
  gap: var(--sp-4);
  flex-wrap: wrap;
}
.cookie-dialog-footer a {
  text-decoration: underline;
  text-underline-offset: 3px;
}

@media (max-width: 720px) {
  .cookie-banner-inner {
    flex-direction: column;
    align-items: stretch;
    gap: var(--sp-3);
  }
  .cookie-actions {
    justify-content: stretch;
  }
  .cookie-actions .btn {
    flex: 1;
  }
  .cookie-dialog {
    padding: var(--sp-5) var(--sp-4);
  }
}
}

/* pages/home.css */
@layer pages {
/* ----------------------------------------------------------------- Hero */
/* Composición asimétrica: el texto respeta el contenedor, la fotografía sangra
   por el borde derecho. Sin etiqueta superior, sin cifras, sin gráfico. */
.hero {
  display: grid;
  grid-template-columns: minmax(0, 0.86fr) minmax(0, 1.14fr);
  gap: clamp(32px, 5vw, 64px);
  align-items: center;
  /* Ocupa casi toda la primera pantalla: una sola idea por pliegue. El tope
     evita que en monitores altos el titular quede flotando en el vacío. */
  min-height: min(78vh, 760px);
  padding: clamp(24px, 4vw, 48px) 0 clamp(32px, 5vw, 64px);
}
.hero-copy {
  max-width: 34rem;
}
.hero h1 {
  margin-bottom: 0.35em;
  font-size: clamp(2.6rem, 5.4vw, 4.6rem);
  line-height: 0.98;
  letter-spacing: -0.03em;
  text-wrap: balance;
}
.hero .lead {
  margin-bottom: var(--sp-6);
  max-width: 46ch;
}
.hero-actions {
  display: flex;
  gap: var(--sp-3);
  flex-wrap: wrap;
}
/* El texto entra detrás del titular, no a la vez: la lectura tiene un orden. */
@media (prefers-reduced-motion: no-preference) {
  .hero .lead,
  .hero-actions {
    animation: hero-follow 700ms var(--ease-expo) backwards;
  }
  .hero .lead {
    animation-delay: 260ms;
  }
  .hero-actions {
    animation-delay: 360ms;
  }
}
@keyframes hero-follow {
  from {
    opacity: 0;
    transform: translateY(14px);
  }
}
/* Collage: una pieza vertical grande y dos pequeñas apiladas a su derecha.
   Cerrado dentro del contenedor, sin sangrar por el borde: contra el filo de la
   ventana las dos pequeñas parecían fotos cortadas por la mitad, no una
   composición. Cada pieza se ve entera y con su radio completo. */
.hero-collage {
  display: grid;
  grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr);
  grid-template-rows: 1fr 1.3fr;
  gap: clamp(10px, 1.2vw, 16px);
}
.hero-collage .pieza {
  position: relative;
  overflow: hidden;
  margin: 0;
  border-radius: var(--r-md);
  background: var(--bg-3);
}
.hero-collage .pieza img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* El hueco manda sobre el ratio del componente. */
.hero-collage .pieza .media {
  height: 100%;
  aspect-ratio: auto;
  border-radius: inherit;
}
.hero-collage .principal {
  grid-row: 1 / -1;
  aspect-ratio: 4 / 5;
  border-radius: var(--r-lg);
}
/* La altura se la reparten las filas, sin ratio propio: quien manda en el alto
   del bloque es la principal, y así las tres cuadran arriba y abajo. */
.hero-collage .sec-a,
.hero-collage .sec-b {
  min-height: 0;
}
/* La chapita nombra al cliente de la foto: lo que separa una instalación real
   de una imagen de catálogo. Fondo sólido, no cristal: encima de una fotografía
   cualquier desenfoque se come el texto. */
.hero-collage .chapita {
  position: absolute;
  left: var(--sp-3);
  bottom: var(--sp-3);
  max-width: calc(100% - var(--sp-3) * 2);
  padding: 5px 10px;
  border-radius: var(--r-sm);
  background: var(--surface);
  color: var(--ink);
  font-stretch: var(--wd-data);
  font-weight: 500;
  font-size: 0.8125rem;
  line-height: 1.3;
  box-shadow: var(--sh-1);
}

/* ------------------------------------------------------- Muro de fabricantes */
.logowall {
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  padding: var(--sp-6) 0;
  display: grid;
  grid-template-columns: 11rem 1fr;
  gap: var(--sp-5) var(--sp-6);
  align-items: center;
}
.logowall-label {
  font-stretch: var(--wd-data);
  font-weight: 500;
  font-size: 0.875rem;
  line-height: 1.4;
  color: var(--ink-3);
  max-width: 22ch;
}
/* La tira desfila en bucle continuo: pista de cuatro copias idénticas y bucle
   cerrado en el 50% del recorrido. El hueco entre copias va como padding final
   de cada una, no como gap de la pista, para que el punto de empalme mida
   exactamente lo mismo que el resto y el salto sea invisible. */
.logowall-viewport {
  min-width: 0;
  overflow: hidden;
}
.logowall-track {
  display: flex;
  width: max-content;
}
.logowall-items {
  display: flex;
  flex-wrap: nowrap;
  align-items: center;
  gap: var(--sp-4) clamp(24px, 3.2vw, 44px);
  padding-inline-end: clamp(24px, 3.2vw, 44px);
}
@media (prefers-reduced-motion: no-preference) {
  .logowall-track {
    animation: logowall-marquee 60s linear infinite;
    will-change: transform;
  }
  .logowall:hover .logowall-track,
  .logowall:focus-within .logowall-track {
    animation-play-state: paused;
  }
}
@keyframes logowall-marquee {
  to {
    transform: translateX(-50%);
  }
}
/* Menos movimiento: fuera copias y fuera desfile, el muro estático de siempre. */
@media (prefers-reduced-motion: reduce) {
  .logowall-track {
    width: auto;
  }
  .logowall-track .logowall-items[aria-hidden] {
    display: none;
  }
  .logowall-track .logowall-items {
    flex-wrap: wrap;
    padding-inline-end: 0;
  }
}
.logowall-item {
  display: inline-flex;
  align-items: center;
  min-height: 34px;
  transition:
    color var(--dur-2) var(--ease-out),
    opacity var(--dur-2) var(--ease-out);
}
/* Logotipo real: se normaliza por altura óptica y por color. Los logotipos de
   los fabricantes vienen en cinco colores distintos y algunos son negros sobre
   transparencia, que en tema oscuro desaparecen. Aquí se llevan todos a una
   sola tinta (la del texto) y el color propio de cada marca vuelve al pasar el
   ratón, que es cuando el logotipo se está mirando de verdad. */
.logowall-item img {
  height: 100%;
  max-height: 34px;
  width: auto;
  object-fit: contain;
  filter: grayscale(1) brightness(0) opacity(0.62);
  transition:
    filter var(--dur-3) var(--ease-out),
    transform var(--dur-3) var(--ease-out);
}
:root[data-theme='oscuro'] .logowall-item img {
  filter: grayscale(1) brightness(0) invert(1) opacity(0.72);
}
.logowall-item:hover img,
.logowall-item:focus-visible img {
  filter: none;
  transform: scale(1.04);
}
/* Sin logotipo cargado, el nombre se compone como marca denominativa. No es un
   hueco: es la misma pieza resuelta con tipografía. */
.logowall-item .wordmark {
  font-stretch: var(--wd-display);
  font-weight: 700;
  font-size: clamp(1.0625rem, 1.6vw, 1.3rem);
  letter-spacing: -0.02em;
  color: var(--ink);
  line-height: 1;
}
.logowall-item:hover .wordmark {
  color: var(--brand);
}

/* ----------------------------------------------------------------- Bento de marcas */
/* Dos formas de celda distintas, no la misma tarjeta repetida: las anchas
   parten en horizontal, las estrechas apilan foto sobre texto. */
.brand-bento {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: var(--sp-4);
}
.btile {
  position: relative;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  transition: border-color var(--dur-3) var(--ease-out);
}
.btile:hover {
  border-color: var(--brand);
}
/* Filete de acento que recorre la celda al apuntarla. Es la misma gramática
   que el titular: algo que entra por un lado, no algo que aparece. */
.btile::after {
  content: '';
  position: absolute;
  inset: 0 0 auto 0;
  height: 2px;
  background: var(--brand);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--dur-3) var(--ease-expo);
  z-index: var(--z-raised);
}
.btile:hover::after,
.btile:focus-visible::after {
  transform: scaleX(1);
}
.btile .btile-media {
  overflow: hidden;
  background: var(--bg-3);
  aspect-ratio: 16 / 10;
  flex: none;
}
/* El hueco manda sobre el ratio del componente: en las celdas anchas la foto
   ocupa toda la altura de la celda, no un 4:3 con relleno debajo. */
.btile .btile-media .media {
  height: 100%;
  aspect-ratio: auto;
  border-radius: 0;
}
.btile .btile-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--dur-4) var(--ease-out);
}
.btile:hover .btile-media img,
.btile:focus-visible .btile-media img {
  transform: scale(1.055);
}
.btile .btile-copy {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  padding: var(--sp-5);
  flex: 1;
}
.btile .cat {
  font-stretch: var(--wd-data);
  font-weight: 600;
  font-size: 0.78rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--brand);
}
.btile .name {
  font-stretch: var(--wd-display);
  font-weight: 700;
  font-size: clamp(1.35rem, 2.2vw, 1.9rem);
  letter-spacing: -0.025em;
  line-height: 1.05;
  color: var(--ink);
}
.btile .desc {
  margin: 0;
  font-size: 0.9688rem;
  color: var(--ink-2);
  max-width: 44ch;
}
.btile .go {
  margin-top: auto;
  padding-top: var(--sp-4);
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  font-weight: 600;
  font-size: 0.9rem;
  color: var(--brand);
}

/* Dos ritmos en dos filas: arriba dos celdas anchas partidas en horizontal,
   abajo tres apiladas. Las cinco marcas caben sin dejar hueco y sin repetir la
   misma tarjeta cinco veces. */
.brand-bento .btile:nth-child(1),
.brand-bento .btile:nth-child(2) {
  grid-column: span 3;
  flex-direction: row;
}
.brand-bento .btile:nth-child(2) {
  flex-direction: row-reverse;
}
.brand-bento .btile:nth-child(1) .btile-media,
.brand-bento .btile:nth-child(2) .btile-media {
  aspect-ratio: auto;
  width: 46%;
  align-self: stretch;
}
.brand-bento .btile:nth-child(n + 3) {
  grid-column: span 2;
}
/* En las celdas estrechas la descripción es lo primero que sobra: el nombre y
   la categoría bastan para elegir, el detalle está en la ficha. */
.brand-bento .btile:nth-child(n + 3) .desc {
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* ----------------------------------------------------------------- Ventajas */
/* El titular acompaña a la lista en lugar de quedarse arriba mirando un hueco
   vacío: se queda fijo mientras las tres afirmaciones pasan por delante. */
.split .adv-sticky {
  position: sticky;
  top: calc(var(--nav-h) + var(--sp-6));
  align-self: start;
}
.adv-list {
  display: flex;
  flex-direction: column;
}
/* Al apuntar una afirmación, el resto se retira. La lista deja de ser un bloque
   de texto y se lee de una en una. */
.adv-list:hover .adv {
  opacity: 0.45;
}
.adv-list .adv:hover {
  opacity: 1;
}
.adv {
  transition:
    opacity var(--dur-3) var(--ease-out),
    border-color var(--dur-3) var(--ease-out);
}
.adv-list .adv:hover {
  border-top-color: var(--brand);
}
.adv {
  padding: var(--sp-5) 0;
  border-top: 1px solid var(--line);
}
.adv:last-child {
  border-bottom: 1px solid var(--line);
}
.adv h3 {
  margin: 0 0 var(--sp-1);
}
.adv p {
  margin: 0;
  font-size: 1rem;
  max-width: 58ch;
}

/* ----------------------------------------------------------------- Novedades */
.news-feature {
  display: grid;
  grid-template-columns: 1.25fr 1fr;
  gap: var(--sp-6);
  align-items: start;
}
.news-main {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  transition: border-color var(--dur-3) var(--ease-out);
}
.news-main:hover {
  border-color: var(--brand);
}
.news-main .media {
  border-radius: 0;
  aspect-ratio: 16 / 9;
}
.news-main .media img {
  transition: transform 700ms var(--ease-expo);
}
.news-main:hover .media img,
.news-main:focus-visible .media img {
  transform: scale(1.045);
}
.news-main .news-body {
  padding: var(--sp-5);
  display: grid;
  gap: var(--sp-2);
}
.news-main h3 {
  font-size: clamp(1.35rem, 2.2vw, 1.75rem);
  font-stretch: var(--wd-display);
  letter-spacing: -0.022em;
  margin: 0;
}
.news-main p {
  margin: 0;
  color: var(--ink-2);
}

.news-side {
  display: flex;
  flex-direction: column;
}
.news-row {
  display: grid;
  grid-template-columns: 84px 1fr;
  gap: var(--sp-4);
  align-items: center;
  padding: var(--sp-4) 0;
  border-top: 1px solid var(--line);
  transition: border-color var(--dur-2) var(--ease-out);
}
.news-row:first-child {
  border-top: 0;
  padding-top: 0;
}
.news-row .thumb {
  border-radius: var(--r-sm);
}
.news-row strong {
  display: block;
  font-weight: 600;
  font-size: 1rem;
  line-height: 1.3;
  color: var(--ink);
  transition: color var(--dur-2) var(--ease-out);
}
.news-row:hover strong {
  color: var(--brand);
}

/* Estado vacío: pieza compuesta, no un párrafo suelto pidiendo perdón. */
.news-empty {
  display: grid;
  gap: var(--sp-3);
  padding: var(--sp-5);
  background: var(--bg-2);
  border: 1px dashed var(--line-2);
  border-radius: var(--r-md);
}
.news-empty p {
  margin: 0;
  font-size: 0.9688rem;
}

/* ----------------------------------------------------------------- Quiénes somos */
/* padding-block, no padding: el inline lo pone .bleed y no debe pisarse. */
/* ----------------------------------------------------------------- Portal */
/* La transición entre las noticias y la placa de empresa: una banda
   fotográfica a sangre que empalma directamente con el fondo oscuro. Con
   soporte de líneas de tiempo de scroll, la fotografía se abre desde un
   recorte hasta borde a borde durante su paso natural por la pantalla, sin
   consumir scroll extra. Sin soporte, sin JavaScript o con movimiento
   reducido, queda la banda estática: el fotograma inicial es la imagen
   completa, nunca un hueco. */
.portal {
  margin-bottom: 0;
  background: var(--inv-bg);
}
.portal-stage {
  position: relative;
  overflow: clip;
  aspect-ratio: 21 / 9;
  background: var(--inv-bg);
}
.portal-frame {
  position: absolute;
  inset: 0;
  transform-origin: 50% 45%;
}
.portal-frame img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* En móvil ni siquiera el recorte: banda fija y a otra cosa. */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) and (min-width: 901px) {
    .portal-frame {
      animation: portal-reveal linear both;
      animation-timeline: view();
      animation-range: entry 0% cover 55%;
    }
  }
}

@keyframes portal-reveal {
  from {
    clip-path: inset(14% 10% round var(--r-lg));
    transform: scale(1.12);
  }
  to {
    clip-path: inset(0 0 round 0);
    transform: scale(1);
  }
}

/* ----------------------------------------------------------------- Empresa */
/* Dos bandas a sangre consecutivas se tocan: el ritmo lo pone su propio
   padding, no el margen genérico de sección, que aquí solo metía una franja
   clara entre la placa oscura y la banda ámbar. */
.about {
  padding-block: clamp(64px, 8vw, 104px);
  margin-bottom: 0;
}
.about-inner {
  display: grid;
  grid-template-columns: 1.05fr 0.95fr;
  gap: clamp(32px, 5vw, 72px);
  align-items: end;
}
.about .quote {
  font-stretch: var(--wd-display);
  font-weight: 700;
  font-size: clamp(1.6rem, 3vw, 2.4rem);
  line-height: 1.1;
  letter-spacing: -0.025em;
  color: var(--ink);
  max-width: 20ch;
  margin: 0 0 var(--sp-5);
}
/* Las cifras dejan de ir en fila bajo el texto y pasan a ser la segunda
   columna: en la placa oscura son la pieza que sostiene el peso de la derecha,
   ahora que la fotografía se ha ido al portal. */
.about .about-text {
  max-width: 52ch;
}
.about .about-text p {
  margin: 0 0 var(--sp-3);
}
.about .about-link {
  margin: var(--sp-5) 0 0;
}
.about .statlist {
  display: grid;
  gap: 0;
  border-top: 1px solid var(--line);
}
.about .statlist .stat {
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: baseline;
  gap: var(--sp-4);
  padding: clamp(14px, 2vw, 22px) 0;
  border-bottom: 1px solid var(--line);
}
.about .statlist .num {
  font-size: clamp(2rem, 3.4vw, 2.75rem);
  min-width: 4.5ch;
}
/* Las etiquetas de las cifras son frases enteras, no microtexto: cuerpo de
   lectura y ancho normal del eje, que sobre la placa oscura lo condensado
   pequeño desaparecía. */
.about .statlist .lbl {
  text-align: right;
  color: var(--ink-2);
  font-stretch: var(--wd-body);
  font-size: 1rem;
  letter-spacing: 0;
}

/* ----------------------------------------------------------------- CTA final */
/* Banda drenada de borde a borde. No es un rectángulo con dos textos: es la
   pieza tipográfica que cierra la página. Titular a escala de display y,
   bajo un filete, las cinco marcas como friso tono sobre tono: la banda dice
   "nuestras marcas" y las marcas están en la banda, enormes, cada una
   enlazando a su ficha y encendiéndose en blanco al pasar. */
.cta-band {
  position: relative;
  overflow: clip;
  padding-block: clamp(44px, 5.5vw, 72px);
}
/* La materia de la banda: una forma de onda tono sobre tono que atraviesa el
   ámbar y deriva muy despacio, como programa en un medidor. Va incrustada
   como data URI con trazo negro y opacidad baja para funcionar sobre
   cualquier color de banda sin tocar el pipeline de assets. El tile empalma
   en bucle exacto (solo armónicos de período completo), así que la deriva de
   un tile por ciclo no tiene costura. Los hijos pintan encima del ::before
   por orden natural, sin z-index. */
.cta-band::before {
  content: '';
  position: absolute;
  inset: 0;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1200 160'%3E%3Cpath stroke='%23000' stroke-width='7' stroke-linecap='round' fill='none' d='M6 68V92M18 61V99M30 53V107M42 44V116M54 41V119M66 44V116M78 54V106M90 66V94M102 72V88M114 69V91M126 57V103M138 42V118M150 31V129M162 30V130M174 38V122M186 52V108M198 66V94M210 76V84M222 74V86M234 65V95M246 53V107M258 38V122M270 23V137M282 13V147M294 15V145M306 27V133M318 46V114M330 64V96M342 76V84M354 76V84M366 73V87M378 68V92M390 67V93M402 71V89M414 76V84M426 75V85M438 73V87M450 73V87M462 71V89M474 64V96M486 49V111M498 31V129M510 14V146M522 8V152M534 14V146M546 30V130M558 51V109M570 69V91M582 76V84M594 72V88M606 68V92M618 61V99M630 53V107M642 44V116M654 41V119M666 44V116M678 54V106M690 66V94M702 72V88M714 69V91M726 57V103M738 42V118M750 31V129M762 30V130M774 38V122M786 52V108M798 66V94M810 76V84M822 74V86M834 65V95M846 53V107M858 38V122M870 23V137M882 13V147M894 15V145M906 27V133M918 46V114M930 64V96M942 76V84M954 76V84M966 73V87M978 68V92M990 67V93M1002 71V89M1014 76V84M1026 75V85M1038 73V87M1050 73V87M1062 71V89M1074 64V96M1086 49V111M1098 31V129M1110 14V146M1122 8V152M1134 14V146M1146 30V130M1158 51V109M1170 69V91M1182 76V84M1194 72V88'/%3E%3C/svg%3E");
  background-repeat: repeat-x;
  background-position: 0 50%;
  background-size: 1200px 160px;
  opacity: 0.18;
  pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
  .cta-band::before {
    animation: cta-onda 90s linear infinite;
  }
}
@keyframes cta-onda {
  to {
    background-position-x: -1200px;
  }
}
.cta-band h2 {
  font-size: clamp(2.1rem, 4.2vw, 3.6rem);
  line-height: 1.04;
  letter-spacing: -0.02em;
}
.cta-marcas {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--sp-3) clamp(22px, 3.2vw, 44px);
  margin-top: clamp(28px, 4vw, 52px);
  padding-top: clamp(18px, 2.5vw, 28px);
  border-top: 1px solid var(--band-line);
}
.cta-marcas a {
  font-stretch: var(--wd-display);
  font-weight: 800;
  font-size: clamp(1.5rem, 3.4vw, 2.6rem);
  line-height: 1;
  letter-spacing: -0.02em;
  white-space: nowrap;
  color: var(--band-ink-deep);
  transition: color var(--dur-3) var(--ease-out);
}
.cta-marcas a:hover,
.cta-marcas a:focus-visible {
  color: var(--band-ink);
}
.cta-inner {
  display: grid;
  grid-template-columns: 1.2fr auto;
  gap: var(--sp-7);
  align-items: end;
}
.cta-band h2 {
  margin: 0 0 var(--sp-3);
  max-width: 18ch;
}
.cta-band p {
  margin: 0;
  color: var(--ink-2);
  max-width: 48ch;
}

/* ----------------------------------------------------------------- Responsive */
@media (max-width: 1000px) {
  .brand-bento {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  .brand-bento .btile:nth-child(n) {
    grid-column: span 1;
    flex-direction: column;
  }
  .brand-bento .btile:nth-child(1) {
    grid-column: span 2;
    flex-direction: row;
  }
  .brand-bento .btile:nth-child(1) .btile-media {
    width: 46%;
  }
  .brand-bento .btile:nth-child(2) .btile-media {
    aspect-ratio: 16 / 10;
    width: auto;
  }
}

@media (max-width: 900px) {
  .hero {
    grid-template-columns: 1fr;
    gap: var(--sp-6);
    padding-top: var(--sp-5);
    /* En una columna el pliegue ya va servido: forzar altura solo dejaba aire
       muerto entre el titular y la foto. */
    min-height: 0;
  }
  /* El titular manda y el collage viene detrás: en móvil lo primero que se lee
     tiene que ser qué hace la empresa, no una fotografía sin pie de foto. */
  .hero-collage {
    grid-template-columns: 1fr 1fr;
    grid-template-rows: auto auto;
  }
  .hero-collage .principal {
    grid-column: 1 / -1;
    grid-row: auto;
    aspect-ratio: 16 / 10;
    border-radius: var(--r-md);
  }
  .hero-collage .sec-a,
  .hero-collage .sec-b {
    aspect-ratio: 4 / 3;
    border-radius: var(--r-md);
  }
  /* En una foto de un palmo el nombre del cliente se parte en dos líneas y tapa
     lo que hay que ver. El crédito se queda en la grande, que es la que cuenta
     el proyecto. */
  .hero-collage .sec-a .chapita,
  .hero-collage .sec-b .chapita {
    display: none;
  }
  .logowall {
    grid-template-columns: 1fr;
    gap: var(--sp-4);
  }
  /* En una sola columna el titular deja de tener una lista al lado por la que
     desfilar: quedarse fijo solo servía para que el texto le pasara por encima
     y se leyeran las dos cosas a la vez. */
  .split .adv-sticky {
    position: static;
  }
  /* Sin columna estrecha que la encoja, la frase se lee de un vistazo y en una
     sola línea. El tope la deja partir si alguien escribe una más larga. */
  .logowall-label {
    max-width: none;
    font-size: clamp(1rem, 0.62rem + 1.9vw, 1.1875rem);
    color: var(--ink-2);
  }
  .news-feature {
    grid-template-columns: 1fr;
  }
  .about-inner {
    grid-template-columns: 1fr;
  }
  .cta-inner {
    grid-template-columns: 1fr;
    gap: var(--sp-5);
  }
}

@media (max-width: 720px) {
  .brand-bento {
    grid-template-columns: 1fr;
  }
  .brand-bento .btile:nth-child(1),
  .brand-bento .btile:nth-child(4) {
    grid-column: auto;
    flex-direction: column;
  }
  .brand-bento .btile:nth-child(1) .btile-media,
  .brand-bento .btile:nth-child(4) .btile-media {
    width: 100%;
    aspect-ratio: 16 / 10;
  }
  .news-row {
    grid-template-columns: 68px 1fr;
    gap: var(--sp-3);
  }
}
}

/* pages/marcas.css */
@layer pages {
/* Listado de marcas: dos columnas grandes, no el auto-fill de tarjeta genérica. */
.brand-list {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--sp-5);
}
.brand-card {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  transition: border-color var(--dur-3) var(--ease-out);
}
.brand-card:hover {
  border-color: var(--brand);
}
.brand-card .media {
  border-radius: 0;
  aspect-ratio: 16 / 9;
  border-bottom: 1px solid var(--line);
}
.brand-card .media img {
  transition: transform var(--dur-4) var(--ease-out);
}
.brand-card:hover .media img {
  transform: scale(1.03);
}
.brand-card-body {
  display: grid;
  gap: var(--sp-2);
  padding: var(--sp-5);
  flex: 1;
  align-content: start;
}
.brand-card h2 {
  font-size: clamp(1.4rem, 2.2vw, 1.9rem);
  margin: 0;
}
.brand-card .excerpt {
  margin: 0;
  color: var(--ink-2);
  font-size: 0.9688rem;
}
.brand-card .go {
  margin-top: var(--sp-3);
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  font-weight: 600;
  font-size: 0.9rem;
  color: var(--brand);
}

/* ------------------------------------------------------------ Ficha de marca */
.brand-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--sp-5);
  flex-wrap: wrap;
  padding-bottom: var(--sp-5);
  border-bottom: 1px solid var(--line);
  margin-bottom: var(--sp-7);
}
/* La identidad de la marca es una sola pieza: logotipo, nombre y entradilla se
   componen juntos y el enlace al fabricante queda enfrente. */
.brand-id {
  min-width: 0;
}
.brand-chapa {
  display: inline-block;
  max-width: 100%;
  box-sizing: border-box;
  margin-bottom: var(--sp-3);
}
.brand-logo {
  display: block;
  max-height: 64px;
  max-width: min(100%, 280px);
  width: auto;
  object-fit: contain;
  object-position: left center;
}
/* Casi todos estos logotipos son tinta negra sobre transparencia y en tema
   oscuro se los tragaba el fondo. Van sobre chapa clara y no invertidos como
   los del muro (.logowall-item img): la ficha es el único sitio donde la marca
   se ve en su propio color, y RTW o DAD lo tienen. La chapa es el envoltorio y
   no un relleno del <img>, para que el logotipo mida lo mismo en los dos temas
   y el conjunto no se salga del ancho en una pantalla estrecha. */
:root[data-theme='oscuro'] .brand-chapa {
  background: var(--inv-bg);
  padding: var(--sp-3) var(--sp-4);
  border-radius: var(--r-sm);
}
/* El nombre en titular de 68px repetía al logotipo, que ya lo lleva escrito, y
   parecía que el logotipo se partía. Pequeño y en negrita: sigue siendo el h1
   de la página, pero el peso de la cabecera se lo lleva la entradilla. */
.brand-head h1 {
  margin: 0;
  font-size: clamp(1.2rem, 1.6vw, 1.45rem);
  line-height: 1.2;
  letter-spacing: -0.01em;
}
.brand-claim {
  margin: 0.3em 0 0;
  font-size: 1.0625rem;
  line-height: 1.45;
  color: var(--ink-2);
  max-width: 56ch;
}

.reseller-list {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: var(--sp-4);
}
.reseller {
  display: grid;
  gap: var(--sp-1);
  padding: var(--sp-5);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
}
.reseller h3 {
  margin: 0 0 var(--sp-1);
}
.reseller p {
  margin: 0;
  font-size: 0.9375rem;
}

/* Volver al listado. Iba con el registro de las fechas y los pies de foto, 13px
   condensados en el gris más flojo: para el único camino de vuelta de la página
   se leía como una nota al pie. */
.volver {
  margin: 0 0 var(--sp-5);
  font-size: 1rem;
  font-weight: 500;
}
.volver a {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  padding: var(--sp-2) 0;
  color: var(--ink-2);
}
.volver a:hover {
  color: var(--brand);
}
.volver .arrow {
  transition: transform var(--dur-3) var(--ease-out);
}
.volver a:hover .arrow {
  transform: translateX(-3px);
}

/* El cuerpo de la ficha usa .lectura de layout.css, el mismo esqueleto que la
   noticia: columna de texto y ficha de datos al lado. */

/* El caso de estudio era una banda a sangre para una sola frase: mucho tambor
   para tan poca música. Ahora acompaña al texto, con el peso que le toca. */
.caso {
  margin-top: var(--sp-7);
  padding: var(--sp-5);
  background: var(--bg-2);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
}
.caso-rotulo {
  margin: 0 0 var(--sp-2);
  font-stretch: var(--wd-data);
  font-weight: 600;
  font-size: 0.8125rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--brand);
}
.caso .prose {
  max-width: none;
}
.caso .prose p:last-child {
  margin-bottom: 0;
}

@media (max-width: 900px) {
  .brand-list {
    grid-template-columns: 1fr;
  }
}
}

/* pages/noticias.css */
@layer pages {
/* Listado editorial: una destacada grande y después una lista densa con
   miniatura. Ni rejilla de tarjetas idénticas ni titulares sueltos sin imagen. */
.news-lead {
  display: grid;
  grid-template-columns: 1.15fr 1fr;
  gap: clamp(24px, 4vw, 48px);
  align-items: center;
}

/* El filete separador lo pone la propia lista, no la destacada: con una sola
   noticia publicada no debe quedar una raya colgando en el vacío. El aire
   grande lo aporta la destacada; cuando la lista viene justo después de la
   cabecera de página, ritmo corto: dos filetes separados por un vacío de
   sección entera leen como un hueco, no como aire. */
.news-lead {
  margin-bottom: var(--section-y);
}
section.page-head:has(+ .news-index) {
  margin-bottom: var(--stack-y);
}
.news-lead .media {
  aspect-ratio: 4 / 3;
}
.news-lead .media img {
  transition: transform var(--dur-4) var(--ease-out);
}
.news-lead:hover .media img {
  transform: scale(1.02);
}
.news-lead h2 {
  font-size: clamp(1.75rem, 3.4vw, 2.75rem);
  margin: var(--sp-3) 0 var(--sp-3);
}
.news-lead p {
  margin: 0;
  max-width: 46ch;
}

.news-index {
  display: flex;
  flex-direction: column;
}
/* Fila editorial anclada a los dos bordes: miniatura generosa a la izquierda,
   titular y entradilla en el centro, y una columna de datos alineada a la
   derecha (fecha, marca, flecha). Sin ella, el texto capado a su medida dejaba
   un vacío de cientos de píxeles hasta la flecha suelta. */
.news-item {
  display: grid;
  grid-template-columns: clamp(200px, 24vw, 300px) 1fr max-content;
  gap: var(--sp-6);
  align-items: center;
  padding: var(--sp-5) 0;
  border-top: 1px solid var(--line);
  transition: background var(--dur-2) var(--ease-out);
}
.news-item:last-child {
  border-bottom: 1px solid var(--line);
}
.news-item .media {
  border-radius: var(--r-sm);
}
.news-item .media img {
  transition: transform var(--dur-4) var(--ease-out);
}
.news-item:hover .media img {
  transform: scale(1.04);
}
.news-item h3 {
  margin: 0 0 var(--sp-1);
  font-size: clamp(1.25rem, 2vw, 1.65rem);
  transition: color var(--dur-2) var(--ease-out);
}
.news-item:hover h3 {
  color: var(--brand);
}
/* Fila sin miniatura (el Twig la omite si la noticia no tiene portada): el
   texto ocupa también la columna de la imagen en lugar de encogerse en ella. */
.news-item > div:first-child {
  grid-column: 1 / 3;
}
.news-item p {
  margin: 0;
  font-size: 0.9375rem;
  max-width: 65ch;
}
.news-meta {
  display: grid;
  justify-items: end;
  gap: var(--sp-2);
  text-align: right;
  font-stretch: var(--wd-data);
}
.news-item .go {
  color: var(--brand);
  font-weight: 600;
  font-size: 0.9rem;
}

/* ---------------------------------------------------------- Paginación */
.pagination {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: var(--sp-2);
  margin-top: var(--sp-7);
  font-stretch: var(--wd-data);
  font-weight: 600;
  font-size: 0.9375rem;
}
.pagination a,
.pagination span[aria-current] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 2.4em;
  padding: 0.45em 0.6em;
  border: 1px solid transparent;
  border-radius: var(--r-sm);
  color: var(--ink-2);
  transition:
    color var(--dur-2) var(--ease-out),
    border-color var(--dur-2) var(--ease-out);
}
.pagination a:hover {
  color: var(--ink);
  border-color: var(--line-2);
}
.pagination span[aria-current] {
  color: var(--brand);
  border-color: currentColor;
}

/* ---------------------------------------------------------- Detalle */
.article-head {
  max-width: 46rem;
  margin-bottom: var(--sp-6);
}
.article-head h1 {
  font-size: clamp(2.1rem, 4.4vw, 3.4rem);
  max-width: 20ch;
  margin-bottom: 0.3em;
}
.article-meta {
  display: flex;
  gap: var(--sp-4);
  flex-wrap: wrap;
  align-items: center;
  font-stretch: var(--wd-data);
  font-size: 0.875rem;
  color: var(--ink-3);
}
.article-cover {
  margin-bottom: var(--sp-7);
  border-radius: var(--r-lg);
  overflow: hidden;
  aspect-ratio: 16 / 9;
  background: var(--bg-3);
}
.article-cover img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.article-foot {
  margin-top: var(--sp-8);
  padding-top: var(--sp-5);
  border-top: 1px solid var(--line);
}

@media (max-width: 900px) {
  .news-lead {
    grid-template-columns: 1fr;
    gap: var(--sp-5);
    padding-bottom: var(--sp-7);
  }
  .news-lead .media {
    order: -1;
  }
  /* La columna de datos baja bajo el texto como una línea de meta y la flecha
     sobra: toda la fila es el enlace. */
  .news-item {
    grid-template-columns: 128px 1fr;
    gap: var(--sp-4);
  }
  .news-item .media {
    grid-row: 1 / 3;
  }
  .news-meta {
    grid-column: 2;
    display: flex;
    justify-content: flex-start;
    gap: var(--sp-3);
    text-align: left;
  }
  .news-item .go {
    display: none;
  }
}

@media (max-width: 540px) {
  .news-item {
    grid-template-columns: 1fr;
  }
  .news-item .media {
    grid-row: auto;
  }
  .news-meta {
    grid-column: auto;
  }
}
}

/* pages/servicios.css */
@layer pages {
/* Filas alternas de fotografía a plena opacidad y texto. Sin numeración: cuatro
   servicios paralelos no son una secuencia. */
.service-list {
  display: flex;
  flex-direction: column;
  gap: clamp(48px, 7vw, 96px);
}
.service {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(28px, 4vw, 56px);
  align-items: center;
}
.service-media {
  border-radius: var(--r-md);
  overflow: hidden;
  aspect-ratio: 4 / 3;
  background: var(--bg-3);
}
.service-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.service.flip .service-media {
  order: -1;
}
.service h2 {
  font-size: clamp(1.5rem, 2.6vw, 2.1rem);
  margin-bottom: 0.35em;
  max-width: 18ch;
}
.service-intro {
  margin: 0 0 var(--sp-5);
  font-size: 1.05rem;
  max-width: 46ch;
}
.service-items {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 0;
  border-top: 1px solid var(--line);
}
.service-items li {
  padding: 10px 0;
  border-bottom: 1px solid var(--line);
  font-size: 0.9688rem;
  color: var(--ink-2);
  line-height: 1.4;
}

@media (max-width: 900px) {
  .service {
    grid-template-columns: 1fr;
  }
  .service-media,
  .service.flip .service-media {
    order: -1;
  }
}
}

/* pages/legal.css */
@layer pages {
/* Un texto legal no tiene datos que poner al lado, así que en vez de ficha la
   columna entera se centra: el documento queda en su medida y sin medio folio
   vacío a la derecha. */
.legal-doc {
  /* La misma medida que la prosa que lleva dentro: si el documento fuera más
     ancho, el texto volvería a dejar aire suelto dentro de su propia caja. */
  max-width: 68ch;
  margin-inline: auto;
}

.legal-updated {
  font-stretch: var(--wd-data);
  font-size: 0.8125rem;
  letter-spacing: 0.03em;
  color: var(--ink-3);
  margin: 0 0 var(--sp-2);
}
.legal-nav {
  display: flex;
  gap: var(--sp-2);
  flex-wrap: wrap;
  margin-bottom: var(--sp-7);
}
.legal-nav a {
  font-stretch: var(--wd-data);
  font-weight: 500;
  font-size: 0.8125rem;
  color: var(--ink-2);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 6px 14px;
  transition:
    color var(--dur-2) var(--ease-out),
    border-color var(--dur-2) var(--ease-out);
}
.legal-nav a:hover {
  color: var(--ink);
  border-color: var(--line-2);
}
.legal-nav a[aria-current='page'] {
  color: var(--brand);
  border-color: var(--brand-line);
  background: var(--brand-soft);
}
}

/* pages/campanas.css */
@layer pages {
/*
 * Páginas de campaña (/campanas/…).
 *
 * Son promociones que se reparten por correo o por anuncio y viven fuera de la
 * navegación, así que no comparten casi nada con el resto del sitio: aquí solo
 * están los dos bloques que no existen en ninguna otra página.
 */

/* Galería: hasta tres fotos en fila, con un pie común debajo. En móvil se
   apilan, que es lo único que cabe. */
.galeria {
  margin: 0;
  display: grid;
  grid-template-columns: repeat(var(--piezas, 1), minmax(0, 1fr));
  gap: var(--sp-3);
}
.galeria[data-piezas='2'] {
  --piezas: 2;
}
.galeria[data-piezas='3'] {
  --piezas: 3;
}
.galeria figcaption {
  grid-column: 1 / -1;
  margin-top: var(--sp-2);
  font-size: 0.875rem;
  line-height: 1.5;
}

@media (max-width: 640px) {
  .galeria {
    grid-template-columns: 1fr;
  }
}

/*
 * Botón de llamada a la acción. Va sobre placa para que se despegue del texto
 * que lo rodea: en una promoción es lo único que se pide de la página, y en
 * medio de dos párrafos un enlace suelto no se ve.
 */
.campana-cta {
  padding: var(--sp-5);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--bg-2);
}
.campana-cta h2 {
  margin-top: 0;
}
.campana-cta p {
  color: var(--ink-2);
  margin: 0 0 var(--sp-4);
}
}
/* La base de la librería, tal cual viene en node_modules. En la web de React la

/* leaflet/dist/leaflet.css */
/* required styles */

.leaflet-pane,
.leaflet-tile,
.leaflet-marker-icon,
.leaflet-marker-shadow,
.leaflet-tile-container,
.leaflet-pane > svg,
.leaflet-pane > canvas,
.leaflet-zoom-box,
.leaflet-image-layer,
.leaflet-layer {
	position: absolute;
	left: 0;
	top: 0;
	}
.leaflet-container {
	overflow: hidden;
	}
.leaflet-tile,
.leaflet-marker-icon,
.leaflet-marker-shadow {
	-webkit-user-select: none;
	   -moz-user-select: none;
	        user-select: none;
	  -webkit-user-drag: none;
	}
/* Prevents IE11 from highlighting tiles in blue */
.leaflet-tile::selection {
	background: transparent;
}
/* Safari renders non-retina tile on retina better with this, but Chrome is worse */
.leaflet-safari .leaflet-tile {
	image-rendering: -webkit-optimize-contrast;
	}
/* hack that prevents hw layers "stretching" when loading new tiles */
.leaflet-safari .leaflet-tile-container {
	width: 1600px;
	height: 1600px;
	-webkit-transform-origin: 0 0;
	}
.leaflet-marker-icon,
.leaflet-marker-shadow {
	display: block;
	}
/* .leaflet-container svg: reset svg max-width decleration shipped in Joomla! (joomla.org) 3.x */
/* .leaflet-container img: map is broken in FF if you have max-width: 100% on tiles */
.leaflet-container .leaflet-overlay-pane svg {
	max-width: none !important;
	max-height: none !important;
	}
.leaflet-container .leaflet-marker-pane img,
.leaflet-container .leaflet-shadow-pane img,
.leaflet-container .leaflet-tile-pane img,
.leaflet-container img.leaflet-image-layer,
.leaflet-container .leaflet-tile {
	max-width: none !important;
	max-height: none !important;
	width: auto;
	padding: 0;
	}

.leaflet-container img.leaflet-tile {
	/* See: https://bugs.chromium.org/p/chromium/issues/detail?id=600120 */
	mix-blend-mode: plus-lighter;
}

.leaflet-container.leaflet-touch-zoom {
	-ms-touch-action: pan-x pan-y;
	touch-action: pan-x pan-y;
	}
.leaflet-container.leaflet-touch-drag {
	-ms-touch-action: pinch-zoom;
	/* Fallback for FF which doesn't support pinch-zoom */
	touch-action: none;
	touch-action: pinch-zoom;
}
.leaflet-container.leaflet-touch-drag.leaflet-touch-zoom {
	-ms-touch-action: none;
	touch-action: none;
}
.leaflet-container {
	-webkit-tap-highlight-color: transparent;
}
.leaflet-container a {
	-webkit-tap-highlight-color: rgba(51, 181, 229, 0.4);
}
.leaflet-tile {
	filter: inherit;
	visibility: hidden;
	}
.leaflet-tile-loaded {
	visibility: inherit;
	}
.leaflet-zoom-box {
	width: 0;
	height: 0;
	-moz-box-sizing: border-box;
	     box-sizing: border-box;
	z-index: 800;
	}
/* workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=888319 */
.leaflet-overlay-pane svg {
	-moz-user-select: none;
	}

.leaflet-pane         { z-index: 400; }

.leaflet-tile-pane    { z-index: 200; }
.leaflet-overlay-pane { z-index: 400; }
.leaflet-shadow-pane  { z-index: 500; }
.leaflet-marker-pane  { z-index: 600; }
.leaflet-tooltip-pane   { z-index: 650; }
.leaflet-popup-pane   { z-index: 700; }

.leaflet-map-pane canvas { z-index: 100; }
.leaflet-map-pane svg    { z-index: 200; }

.leaflet-vml-shape {
	width: 1px;
	height: 1px;
	}
.lvml {
	behavior: url(#default#VML);
	display: inline-block;
	position: absolute;
	}


/* control positioning */

.leaflet-control {
	position: relative;
	z-index: 800;
	pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */
	pointer-events: auto;
	}
.leaflet-top,
.leaflet-bottom {
	position: absolute;
	z-index: 1000;
	pointer-events: none;
	}
.leaflet-top {
	top: 0;
	}
.leaflet-right {
	right: 0;
	}
.leaflet-bottom {
	bottom: 0;
	}
.leaflet-left {
	left: 0;
	}
.leaflet-control {
	float: left;
	clear: both;
	}
.leaflet-right .leaflet-control {
	float: right;
	}
.leaflet-top .leaflet-control {
	margin-top: 10px;
	}
.leaflet-bottom .leaflet-control {
	margin-bottom: 10px;
	}
.leaflet-left .leaflet-control {
	margin-left: 10px;
	}
.leaflet-right .leaflet-control {
	margin-right: 10px;
	}


/* zoom and fade animations */

.leaflet-fade-anim .leaflet-popup {
	opacity: 0;
	-webkit-transition: opacity 0.2s linear;
	   -moz-transition: opacity 0.2s linear;
	        transition: opacity 0.2s linear;
	}
.leaflet-fade-anim .leaflet-map-pane .leaflet-popup {
	opacity: 1;
	}
.leaflet-zoom-animated {
	-webkit-transform-origin: 0 0;
	    -ms-transform-origin: 0 0;
	        transform-origin: 0 0;
	}
svg.leaflet-zoom-animated {
	will-change: transform;
}

.leaflet-zoom-anim .leaflet-zoom-animated {
	-webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1);
	   -moz-transition:    -moz-transform 0.25s cubic-bezier(0,0,0.25,1);
	        transition:         transform 0.25s cubic-bezier(0,0,0.25,1);
	}
.leaflet-zoom-anim .leaflet-tile,
.leaflet-pan-anim .leaflet-tile {
	-webkit-transition: none;
	   -moz-transition: none;
	        transition: none;
	}

.leaflet-zoom-anim .leaflet-zoom-hide {
	visibility: hidden;
	}


/* cursors */

.leaflet-interactive {
	cursor: pointer;
	}
.leaflet-grab {
	cursor: -webkit-grab;
	cursor:    -moz-grab;
	cursor:         grab;
	}
.leaflet-crosshair,
.leaflet-crosshair .leaflet-interactive {
	cursor: crosshair;
	}
.leaflet-popup-pane,
.leaflet-control {
	cursor: auto;
	}
.leaflet-dragging .leaflet-grab,
.leaflet-dragging .leaflet-grab .leaflet-interactive,
.leaflet-dragging .leaflet-marker-draggable {
	cursor: move;
	cursor: -webkit-grabbing;
	cursor:    -moz-grabbing;
	cursor:         grabbing;
	}

/* marker & overlays interactivity */
.leaflet-marker-icon,
.leaflet-marker-shadow,
.leaflet-image-layer,
.leaflet-pane > svg path,
.leaflet-tile-container {
	pointer-events: none;
	}

.leaflet-marker-icon.leaflet-interactive,
.leaflet-image-layer.leaflet-interactive,
.leaflet-pane > svg path.leaflet-interactive,
svg.leaflet-image-layer.leaflet-interactive path {
	pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */
	pointer-events: auto;
	}

/* visual tweaks */

.leaflet-container {
	background: #ddd;
	outline-offset: 1px;
	}
.leaflet-container a {
	color: #0078A8;
	}
.leaflet-zoom-box {
	border: 2px dotted #38f;
	background: rgba(255,255,255,0.5);
	}


/* general typography */
.leaflet-container {
	font-family: "Helvetica Neue", Arial, Helvetica, sans-serif;
	font-size: 12px;
	font-size: 0.75rem;
	line-height: 1.5;
	}


/* general toolbar styles */

.leaflet-bar {
	box-shadow: 0 1px 5px rgba(0,0,0,0.65);
	border-radius: 4px;
	}
.leaflet-bar a {
	background-color: #fff;
	border-bottom: 1px solid #ccc;
	width: 26px;
	height: 26px;
	line-height: 26px;
	display: block;
	text-align: center;
	text-decoration: none;
	color: black;
	}
.leaflet-bar a,
.leaflet-control-layers-toggle {
	background-position: 50% 50%;
	background-repeat: no-repeat;
	display: block;
	}
.leaflet-bar a:hover,
.leaflet-bar a:focus {
	background-color: #f4f4f4;
	}
.leaflet-bar a:first-child {
	border-top-left-radius: 4px;
	border-top-right-radius: 4px;
	}
.leaflet-bar a:last-child {
	border-bottom-left-radius: 4px;
	border-bottom-right-radius: 4px;
	border-bottom: none;
	}
.leaflet-bar a.leaflet-disabled {
	cursor: default;
	background-color: #f4f4f4;
	color: #bbb;
	}

.leaflet-touch .leaflet-bar a {
	width: 30px;
	height: 30px;
	line-height: 30px;
	}
.leaflet-touch .leaflet-bar a:first-child {
	border-top-left-radius: 2px;
	border-top-right-radius: 2px;
	}
.leaflet-touch .leaflet-bar a:last-child {
	border-bottom-left-radius: 2px;
	border-bottom-right-radius: 2px;
	}

/* zoom control */

.leaflet-control-zoom-in,
.leaflet-control-zoom-out {
	font: bold 18px 'Lucida Console', Monaco, monospace;
	text-indent: 1px;
	}

.leaflet-touch .leaflet-control-zoom-in, .leaflet-touch .leaflet-control-zoom-out  {
	font-size: 22px;
	}


/* layers control */

.leaflet-control-layers {
	box-shadow: 0 1px 5px rgba(0,0,0,0.4);
	background: #fff;
	border-radius: 5px;
	}
.leaflet-control-layers-toggle {
	background-image: url(/assets/img/leaflet/layers.png);
	width: 36px;
	height: 36px;
	}
.leaflet-retina .leaflet-control-layers-toggle {
	background-image: url(/assets/img/leaflet/layers-2x.png);
	background-size: 26px 26px;
	}
.leaflet-touch .leaflet-control-layers-toggle {
	width: 44px;
	height: 44px;
	}
.leaflet-control-layers .leaflet-control-layers-list,
.leaflet-control-layers-expanded .leaflet-control-layers-toggle {
	display: none;
	}
.leaflet-control-layers-expanded .leaflet-control-layers-list {
	display: block;
	position: relative;
	}
.leaflet-control-layers-expanded {
	padding: 6px 10px 6px 6px;
	color: #333;
	background: #fff;
	}
.leaflet-control-layers-scrollbar {
	overflow-y: scroll;
	overflow-x: hidden;
	padding-right: 5px;
	}
.leaflet-control-layers-selector {
	margin-top: 2px;
	position: relative;
	top: 1px;
	}
.leaflet-control-layers label {
	display: block;
	font-size: 13px;
	font-size: 1.08333em;
	}
.leaflet-control-layers-separator {
	height: 0;
	border-top: 1px solid #ddd;
	margin: 5px -10px 5px -6px;
	}

/* Default icon URLs */
.leaflet-default-icon-path { /* used only in path-guessing heuristic, see L.Icon.Default */
	background-image: url(/assets/img/leaflet/marker-icon.png);
	}


/* attribution and scale controls */

.leaflet-container .leaflet-control-attribution {
	background: #fff;
	background: rgba(255, 255, 255, 0.8);
	margin: 0;
	}
.leaflet-control-attribution,
.leaflet-control-scale-line {
	padding: 0 5px;
	color: #333;
	line-height: 1.4;
	}
.leaflet-control-attribution a {
	text-decoration: none;
	}
.leaflet-control-attribution a:hover,
.leaflet-control-attribution a:focus {
	text-decoration: underline;
	}
.leaflet-attribution-flag {
	display: inline !important;
	vertical-align: baseline !important;
	width: 1em;
	height: 0.6669em;
	}
.leaflet-left .leaflet-control-scale {
	margin-left: 5px;
	}
.leaflet-bottom .leaflet-control-scale {
	margin-bottom: 5px;
	}
.leaflet-control-scale-line {
	border: 2px solid #777;
	border-top: none;
	line-height: 1.1;
	padding: 2px 5px 1px;
	white-space: nowrap;
	-moz-box-sizing: border-box;
	     box-sizing: border-box;
	background: rgba(255, 255, 255, 0.8);
	text-shadow: 1px 1px #fff;
	}
.leaflet-control-scale-line:not(:first-child) {
	border-top: 2px solid #777;
	border-bottom: none;
	margin-top: -2px;
	}
.leaflet-control-scale-line:not(:first-child):not(:last-child) {
	border-bottom: 2px solid #777;
	}

.leaflet-touch .leaflet-control-attribution,
.leaflet-touch .leaflet-control-layers,
.leaflet-touch .leaflet-bar {
	box-shadow: none;
	}
.leaflet-touch .leaflet-control-layers,
.leaflet-touch .leaflet-bar {
	border: 2px solid rgba(0,0,0,0.2);
	background-clip: padding-box;
	}


/* popup */

.leaflet-popup {
	position: absolute;
	text-align: center;
	margin-bottom: 20px;
	}
.leaflet-popup-content-wrapper {
	padding: 1px;
	text-align: left;
	border-radius: 12px;
	}
.leaflet-popup-content {
	margin: 13px 24px 13px 20px;
	line-height: 1.3;
	font-size: 13px;
	font-size: 1.08333em;
	min-height: 1px;
	}
.leaflet-popup-content p {
	margin: 17px 0;
	margin: 1.3em 0;
	}
.leaflet-popup-tip-container {
	width: 40px;
	height: 20px;
	position: absolute;
	left: 50%;
	margin-top: -1px;
	margin-left: -20px;
	overflow: hidden;
	pointer-events: none;
	}
.leaflet-popup-tip {
	width: 17px;
	height: 17px;
	padding: 1px;

	margin: -10px auto 0;
	pointer-events: auto;

	-webkit-transform: rotate(45deg);
	   -moz-transform: rotate(45deg);
	    -ms-transform: rotate(45deg);
	        transform: rotate(45deg);
	}
.leaflet-popup-content-wrapper,
.leaflet-popup-tip {
	background: white;
	color: #333;
	box-shadow: 0 3px 14px rgba(0,0,0,0.4);
	}
.leaflet-container a.leaflet-popup-close-button {
	position: absolute;
	top: 0;
	right: 0;
	border: none;
	text-align: center;
	width: 24px;
	height: 24px;
	font: 16px/24px Tahoma, Verdana, sans-serif;
	color: #757575;
	text-decoration: none;
	background: transparent;
	}
.leaflet-container a.leaflet-popup-close-button:hover,
.leaflet-container a.leaflet-popup-close-button:focus {
	color: #585858;
	}
.leaflet-popup-scrolled {
	overflow: auto;
	}

.leaflet-oldie .leaflet-popup-content-wrapper {
	-ms-zoom: 1;
	}
.leaflet-oldie .leaflet-popup-tip {
	width: 24px;
	margin: 0 auto;

	-ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)";
	filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678);
	}

.leaflet-oldie .leaflet-control-zoom,
.leaflet-oldie .leaflet-control-layers,
.leaflet-oldie .leaflet-popup-content-wrapper,
.leaflet-oldie .leaflet-popup-tip {
	border: 1px solid #999;
	}


/* div icon */

.leaflet-div-icon {
	background: #fff;
	border: 1px solid #666;
	}


/* Tooltip */
/* Base styles for the element that has a tooltip */
.leaflet-tooltip {
	position: absolute;
	padding: 6px;
	background-color: #fff;
	border: 1px solid #fff;
	border-radius: 3px;
	color: #222;
	white-space: nowrap;
	-webkit-user-select: none;
	-moz-user-select: none;
	-ms-user-select: none;
	user-select: none;
	pointer-events: none;
	box-shadow: 0 1px 3px rgba(0,0,0,0.4);
	}
.leaflet-tooltip.leaflet-interactive {
	cursor: pointer;
	pointer-events: auto;
	}
.leaflet-tooltip-top:before,
.leaflet-tooltip-bottom:before,
.leaflet-tooltip-left:before,
.leaflet-tooltip-right:before {
	position: absolute;
	pointer-events: none;
	border: 6px solid transparent;
	background: transparent;
	content: "";
	}

/* Directions */

.leaflet-tooltip-bottom {
	margin-top: 6px;
}
.leaflet-tooltip-top {
	margin-top: -6px;
}
.leaflet-tooltip-bottom:before,
.leaflet-tooltip-top:before {
	left: 50%;
	margin-left: -6px;
	}
.leaflet-tooltip-top:before {
	bottom: 0;
	margin-bottom: -12px;
	border-top-color: #fff;
	}
.leaflet-tooltip-bottom:before {
	top: 0;
	margin-top: -12px;
	margin-left: -6px;
	border-bottom-color: #fff;
	}
.leaflet-tooltip-left {
	margin-left: -6px;
}
.leaflet-tooltip-right {
	margin-left: 6px;
}
.leaflet-tooltip-left:before,
.leaflet-tooltip-right:before {
	top: 50%;
	margin-top: -6px;
	}
.leaflet-tooltip-left:before {
	right: 0;
	margin-right: -12px;
	border-left-color: #fff;
	}
.leaflet-tooltip-right:before {
	left: 0;
	margin-left: -12px;
	border-right-color: #fff;
	}

/* Printing */

@media print {
	/* Prevent printers from removing background-images of controls. */
	.leaflet-control {
		-webkit-print-color-adjust: exact;
		print-color-adjust: exact;
		}
	}

/* vendor/leaflet.css */
/* Sin @layer a propósito: el CSS de Leaflet se carga sin capa y ganaría a
   cualquier regla que sí estuviera en una. Estos overrides tienen que jugar en
   el mismo terreno. */

.map {
  height: 440px;
  width: 100%;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  overflow: hidden;
  background: var(--bg-2);
}

/* Base clara: los tiles de OSM se usan tal cual, solo desaturados para que el
   verde de los marcadores destaque. */
.map .leaflet-tile {
  filter: saturate(0.55) contrast(0.95) brightness(1.02);
}
.map .leaflet-container {
  background: var(--bg-2);
  font-family: var(--font-sans);
}
.map .leaflet-popup-content-wrapper,
.map .leaflet-popup-tip {
  background: var(--surface);
  color: var(--ink);
  border: 1px solid var(--line-2);
  border-radius: var(--r-sm);
  box-shadow: var(--sh-2);
}
.map .leaflet-popup-content {
  margin: 12px 14px;
  font-size: 0.9rem;
}
.map .leaflet-control-attribution {
  background: oklch(1 0 0 / 0.85);
  color: var(--ink-3);
  font-size: 0.7rem;
}
/* Subrayado: dentro de "Leaflet | © OpenStreetMap" el enlace solo se
   distinguía por el color, y con 1.8:1 contra el texto de al lado eso es un
   incumplimiento de la WCAG 1.4.1. Lo pinta la librería, pero sale en nuestra
   página. */
.map .leaflet-control-attribution a {
  color: var(--ink-2);
  text-decoration: underline;
}
.map .leaflet-bar a {
  color: var(--ink);
  background: var(--surface);
  border-bottom-color: var(--line);
}
.map .leaflet-bar a:hover {
  background: var(--bg-2);
}

/* En tema oscuro los tiles se invierten para no ser una mancha blanca. */
:root[data-theme='oscuro'] .map .leaflet-tile {
  filter: grayscale(0.5) invert(0.92) hue-rotate(180deg) brightness(0.95) contrast(0.9);
}
:root[data-theme='oscuro'] .map .leaflet-control-attribution {
  background: oklch(0.17 0.006 250 / 0.85);
}

/* ============================================================================
   Ajustes propios del porte a PHP.
   Se añaden al final de sitio.css. Aquí solo va lo que existe porque la web ya
   no la pinta React, nunca cambios de diseño: esos se hacen en el CSS fuente.
   ========================================================================== */

@layer chrome {
  /*
   * En React el menú móvil solo estaba en el DOM al abrirlo. Aquí va siempre en
   * el HTML, para que funcione sin JavaScript, y se oculta con el atributo
   * hidden. Sin esta regla, el display:flex de .mobile-nav le gana a hidden y el
   * menú saldría desplegado al cargar.
   */
  .mobile-nav[hidden] {
    display: none;
  }
}
