/* Space Grotesk, autoalojada (SIL Open Font License). Antes venía de
   fonts.googleapis.com, lo que enviaba la IP de cada visitante a Google en
   cada carga. Ahora sale de assets/fonts/ y la web no habla con Google hasta
   que el usuario acepta las cookies.

   Es una fuente VARIABLE: un solo archivo por subconjunto cubre del peso 300
   al 700, así que los cuatro pesos que usa la web (400/500/600/700) salen de
   estos dos ficheros y no de ocho. De ahí el `font-weight: 300 700`.

   El `unicode-range` hace que latin-ext solo se descargue si aparece algún
   carácter que latin no cubre; en español normal no llega a pedirse. */
@font-face {
  font-family: 'Space Grotesk';
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url(../assets/fonts/space-grotesk-v22-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Space Grotesk';
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url(../assets/fonts/space-grotesk-v22-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

:root {
  --brand: #639487;
  --brand-dk: #547e71;
  --accent: #e8513a;
  --mustard: #d9a441;
  --ink: #111;
  --gray-1: #666;
  --gray-2: #888;
  --gray-3: #999;
  --gray-bg: #f0f0ee;
  --gray-border: #ddd;
  --nav-h: 130px;
  /* Alto visible bajo el menú fijo: lo usan las secciones-pantalla */
  --vis-h: calc(100svh - var(--nav-h));
  /* Margen lateral único de toda la página: nav, cabeceras, filas y fichas
     alinean su texto a esta misma columna. */
  --pad-x: 32px;
  /* Aire de cabecera de sección: idéntico en todas (.section-head) */
  --head-top: 56px;
  --head-bottom: 28px;
  /* Paso de la trama de puntos: lo comparten la sección del video y el negro
     de opiniones, para que las dos tramas sean la misma rejilla. */
  --vj-dot: 5px;
}

* { box-sizing: border-box; }

@media (prefers-reduced-motion: no-preference) {
  html {
    scroll-behavior: smooth;
  }
}

/* Las anclas se detienen bajo el menú fijo, no debajo de él */
html { scroll-padding-top: var(--nav-h); }

/* Lenis smooth scrolling (classes added to <html> by the library when active).
   Native CSS smooth-scroll must yield to Lenis's per-frame positioning. */
html.lenis, html.lenis body { height: auto; }
.lenis.lenis-smooth { scroll-behavior: auto !important; }
.lenis.lenis-stopped { overflow: hidden; }

html, body {
  margin: 0;
  background: #fff;
  color: var(--ink);
  font-family: 'Space Grotesk', system-ui, sans-serif;
}

img, iframe { max-width: 100%; }

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

/* Foco de teclado visible en toda la página (botones, enlaces, acordeón) */
:focus-visible {
  outline: 2.5px solid var(--accent);
  outline-offset: 3px;
}
.telefono-band:focus-visible, .btn-accent:focus-visible { outline-color: var(--ink); }

/* Ritmo entre secciones: sin márgenes sueltos. Cada sección se separa de la
   anterior con su filete de 1.5px y con el aire uniforme de su cabecera, de
   modo que todas las secciones empiezan igual. */

/* Nav */
.nav {
  position: sticky;
  top: 0;
  z-index: 100;
  background: #fff;
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 14px var(--pad-x);
  border-bottom: 1.5px solid var(--ink);
  flex-wrap: wrap;
  gap: 12px;
}
.logo { height: 100px; width: auto; display: block; }
/* El relleno de la píldora lo llevan TODOS los enlaces, no solo el activo. Si
   solo lo tuviera el activo, cada cambio de sección ensancharía uno 24px y
   estrecharía otro, y el menú entero se desplazaría de lado. Por eso el gap va a
   cero: ese relleno ya hace de separación (12+12 = los 24px de aire de antes). */
.nav-links { display: flex; gap: 0; font-size: 18px; }
.nav-link {
  color: #555;
  padding: 3px 12px;
  border-radius: 999px;
  transition: color 0.25s ease;
}
.nav-link:hover { color: var(--ink); }
.nav-link.active { color: #fff; background: var(--brand); }
.nav-link.active:hover { color: #fff; }

/* Buttons */
.btn {
  position: relative;
  z-index: 0;
  overflow: hidden;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 12px 24px;
  background: var(--ink);
  color: #fff;
  border-radius: 6px;
  font-weight: 600;
  font-size: 15px;
  border: none;
  cursor: pointer;
  --fill: var(--accent);
  transition: color 0.35s ease;
}
.btn::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--fill);
  transform: translateY(101%);
  transition: transform 0.4s cubic-bezier(.65,0,.35,1);
}
.btn > * { position: relative; z-index: 1; }
.btn:hover::before { transform: translateY(0); }
.btn:hover .icon { transform: translateX(3px); }
.btn-ghost { background: transparent; color: var(--ink); border: 1.5px solid var(--ink); --fill: var(--mustard); }
.btn-ghost:hover { color: #fff; }
.btn-accent { background: var(--accent); --fill: var(--ink); }
.btn-sm { padding: 12px 22px; font-size: 14px; flex-shrink: 0; }
.btn-lg { font-size: 17px; padding: 14px 28px; }

.icon { width: 1em; height: 1em; vertical-align: -0.13em; flex-shrink: 0; transition: transform 0.35s cubic-bezier(.65,0,.35,1); }

/* Grano de película. El patrón es un SVG con feTurbulence incrustado como
   data-URI: no añade ninguna petición y se repite en mosaico, así que el
   grano mide lo mismo en una foto grande que en una pequeña. Va en ::after
   porque .placeholder-box ya usa ::before para su aspa gris.
   `overlay` sobre un ruido gris medio aclara y oscurece por igual, así que
   da textura sin ensuciar el contraste de la foto.
   Los dos feColorMatrix hacen falta: el primero quita el color del ruido y
   el segundo fuerza el alfa a 1, porque feTurbulence genera también un canal
   alfa ruidoso y sin esto medio grano sale transparente y no se ve nada. */
.team-photo::after,
.photo-mask::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3CfeColorMatrix type='matrix' values='1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 1'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23g)'/%3E%3C/svg%3E");
  background-size: 140px 140px;
  mix-blend-mode: overlay;
  opacity: 0.22;
}

/* Placeholder gris compartido: lo usan las fotos de la banda superior (con
   parallax) y los huecos pendientes de foto real (equipo, historia). */
.placeholder-box {
  position: relative;
  background: var(--gray-bg);
  color: var(--gray-3);
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  font-size: 11px;
  font-family: ui-monospace, monospace;
  letter-spacing: 0.02em;
}
.placeholder-box::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to top right, transparent calc(50% - 0.5px), var(--gray-border), transparent calc(50% + 0.5px));
}
.placeholder-box span { position: relative; background: var(--gray-bg); padding: 2px 6px; }

@media (max-width: 768px) {
  :root { --nav-h: 94px; --pad-x: 24px; --head-top: 44px; --head-bottom: 24px; }
  .logo { height: 64px; }
  .nav-links { font-size: 15px; }
  .nav-link { padding: 3px 8px; }
}

/* Por debajo de ~540px el nav ya no cabe en una fila y envuelve solo. Con la
   cuarta entrada (AEOL) ese envoltorio salía a tres filas y 185px de menú
   pegado arriba, comiéndose la portada. Aquí se decide el corte en vez de
   sufrirlo: el logo y el botón de llamar comparten fila, y los enlaces se
   reparten la de abajo de lado a lado. Dos filas y 130px — menos incluso de lo
   que ocupaba antes con tres entradas. */
@media (max-width: 540px) {
  .nav-links {
    order: 3;
    /* Los 8px de relleno de cada enlace meterían el texto de los extremos hacia
       dentro; la fila se ensancha esos 16px y se recoloca para que "Inicio" y
       "Contacto" sigan cayendo en la columna de la página. */
    flex-basis: calc(100% + 16px);
    margin: 0 -8px;
    justify-content: space-between;
  }
}

/* Hero — portada a pantalla completa, solo el titular centrado */
.hero {
  min-height: calc(100vh - var(--nav-h));
  min-height: var(--vis-h);
  padding: 32px var(--pad-x);
  display: grid;
  grid-template-areas:
    "headline headline"
    "text buttons";
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-rows: 1fr auto;
  column-gap: 32px;
  row-gap: 28px;
  /* Alto que se come todo lo que no es el titular: los 32px de padding
     arriba y abajo, el row-gap y la fila de texto + botones. */
  --hero-reserve: 155px;
  position: relative;
  /* CUÁNTO SE MARCA LA TRAMA SOBRE EL BLANCO: sube o baja solo este número.
     0.03 apenas se intuye · 0.05 discreta · 0.08 marcada · 0.12 evidente
     Sobre blanco el punto es oscuro, y el ojo lo ve antes que el punto claro
     sobre negro: para la misma sensación, aquí hace falta menos que en
     --trama-negro. */
  --trama-blanco: 0.05;
}
/* La misma rejilla de las otras dos secciones, ahora en negativo: punto
   oscuro sobre el blanco de la portada. Sin umbral, como en opiniones: no
   hay imagen debajo que haga crecer o encoger el punto, es solo textura. */
.hero::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-image: radial-gradient(circle at 50% 50%, rgba(17, 17, 17, var(--trama-blanco)) 0%, transparent 60%);
  background-size: var(--vj-dot) var(--vj-dot);
}
/* El contenido, por encima de la trama */
.hero > * { position: relative; z-index: 1; }
.headline {
  grid-area: headline;
  align-self: center;
  justify-self: center;
  /* El titular crece hasta llenar la portada. Su línea más larga
     ("CERCA DE CASA.") mide 7.20 de ancho, y la caja entera 3 × line-height
     de alto, por cada unidad de font-size (medido con Space Grotesk);
     dividimos por algo más para dejar holgura si la webfont tarda o no carga.
     Manda el ancho en pantallas estrechas y el alto en las anchas, así que el
     tamaño es el menor de los dos y nunca desborda.
     Si se cambia el texto del titular hay que volver a medir la línea más
     larga y actualizar el 7.33. */
  --fit-w: calc((100vw - 2 * var(--pad-x)) / 7.33);
  --fit-h: calc((var(--vis-h) - var(--hero-reserve)) / 2.66);
  /* Y sobre ese tamaño "a sangre", el titular se queda al 85%: llena menos
     la portada y deja respirar el aire de alrededor. */
  --fit-scale: 0.85;
  --fit-min: 48px;
  font-size: calc(clamp(var(--fit-min), min(var(--fit-w), var(--fit-h)), 400px) * var(--fit-scale));
  font-weight: 700;
  /* Apretado a 0.86: gana tamaño sin que la caja verde de APRUEBA toque las
     líneas de arriba y abajo. */
  line-height: 0.86;
  letter-spacing: -0.03em;
  text-align: center;
  margin: 0;
}
.tilt {
  display: inline-block;
  background: var(--brand);
  color: #fff;
  padding: 0 0.14em;
  rotate: -3.5deg;
}
/* Puntuación final de todos los titulares (punto o interrogante) */
.dot { color: var(--accent); }
.hero-text { grid-area: text; align-self: end; font-size: 16px; color: var(--gray-1); max-width: 380px; margin: 0; }
.hero-buttons { grid-area: buttons; align-self: end; justify-self: end; display: flex; gap: 10px; }

@media (max-width: 768px) {
  .hero {
    grid-template-areas: "headline" "text" "buttons";
    grid-template-columns: 1fr;
    grid-template-rows: 1fr auto auto;
    row-gap: 24px;
    /* Aquí el texto y los botones van en filas separadas: reservan más */
    --hero-reserve: 247px;
  }
  .hero-buttons { justify-self: start; flex-wrap: wrap; }
  /* El mínimo baja a 40px: con el suelo de 48 el titular se saldría por los
     lados en pantallas de 320. */
  .headline { --fit-min: 40px; }
}

/* Banda de fotos — no es una sección: es un filete ancho a sangre entre la
   portada y los permisos. Las dos fotos parten la pantalla por la mitad.
   Ahora mismo estas reglas no se usan: el panel solo escribe la banda cuando
   están las DOS fotos, y de momento no hay ninguna. Se quedan aquí porque la
   banda vuelve sola en cuanto se suban desde el panel. */
.photo-band {
  display: grid;
  grid-template-columns: 1fr 1fr;
  height: 480px;
  border-top: 1.5px solid var(--ink);
  border-bottom: 1.5px solid var(--ink);
}
.photo-mask {
  position: relative;
  overflow: hidden;
  height: 100%;
}
.photo-mask + .photo-mask { border-left: 1.5px solid var(--ink); }
/* Sobresale por arriba y por abajo para que el parallax nunca deje hueco */
.photo-placeholder {
  position: absolute;
  top: -50%;
  left: 0;
  width: 100%;
  height: 200%;
}
.photo-placeholder img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

@media (max-width: 768px) {
  .photo-band { grid-template-columns: 1fr; height: auto; }
  .photo-mask { height: 280px; }
  .photo-mask + .photo-mask { border-left: none; border-top: 1.5px solid var(--ink); }
}

/* Cabecera de sección: misma composición y mismo aire en permisos,
   nosotros, historia y contacto. */
.section-head { padding: var(--head-top) var(--pad-x) var(--head-bottom); }
.kicker { font-size: 12px; font-weight: 600; letter-spacing: 0.14em; text-transform: uppercase; color: var(--mustard); margin: 0 0 10px; }
.subheadline { font-size: clamp(32px, 6vw, 64px); font-weight: 700; line-height: 0.95; letter-spacing: -0.03em; margin: 0; }
.section-text { font-size: 16px; color: var(--gray-1); max-width: 520px; margin: 16px 0 0; }

.permisos, .nosotros, .contacto,
.aeol-pasos, .aeol-precio, .aeol-dudas { border-top: 1.5px solid var(--ink); }

/* Accordion */
.accordion { border-top: 1.5px solid var(--ink); }
.accordion-row { border-bottom: 1.5px solid var(--ink); }
.accordion-trigger {
  width: 100%;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  padding: 18px var(--pad-x);
  cursor: pointer;
  background: #fff;
  color: var(--ink);
  border: none;
  font-family: inherit;
  text-align: left;
  transition: background-color 0.35s ease, color 0.35s ease;
}
@media (hover: hover) {
  .accordion-row:not(.open) .accordion-trigger:hover { background: rgba(99, 148, 135, 0.16); }
}
.accordion-row.open .accordion-trigger { background: var(--brand); color: #fff; }
.accordion-left { display: flex; align-items: baseline; gap: 20px; }
.permiso-code { font-size: 60px; font-weight: 700; line-height: 1; width: 110px; color: var(--mustard); display: inline-block; transition: color 0.35s ease; }
.accordion-row.open .permiso-code { color: #fff; }
.permiso-desc { font-size: 16px; color: var(--gray-1); transition: color 0.35s ease; }
.accordion-row.open .permiso-desc { color: rgba(255,255,255,0.75); }
.accordion-icon { font-size: 26px; color: var(--mustard); display: inline-block; transition: transform 0.35s ease, color 0.35s ease; }
.accordion-row.open .accordion-icon { color: #fff; transform: rotate(45deg); }
/* El panel es un recortador con height animado por JS (Safari no interpola
   tracks de grid en fr); el padding vive en el inner para que 0 sea 0. */
.accordion-panel {
  height: 0;
  overflow: hidden;
  transition: height 0.45s cubic-bezier(0.33, 1, 0.68, 1);
}
.accordion-row.open .accordion-panel { height: auto; }
.accordion-panel-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  background: var(--accent);
  color: #fff;
  padding: 24px var(--pad-x);
}
.accordion-detalle {
  list-style: none;
  margin: 0;
  padding: 0;
  max-width: 640px;
  display: grid;
  gap: 8px;
  font-size: 15px;
  color: rgba(255, 255, 255, 0.8);
}
.accordion-detalle strong { color: #fff; font-weight: 600; }

@media (prefers-reduced-motion: reduce) {
  .accordion-trigger, .permiso-code, .permiso-desc, .accordion-icon,
  .accordion-panel { transition: none; }
}

@media (max-width: 768px) {
  .permiso-code { font-size: 40px; width: 70px; }
  .accordion-left { gap: 12px; }
  .accordion-panel-inner { flex-direction: column; align-items: flex-start; gap: 16px; }
}

/* Video Jara — sección de una pantalla: el video ocupa el encuadre entero,
   pasado por una trama de puntos en blanco y negro (halftone), y la única
   nota de color es la caja verde de JARA. Solo las letras
   animan, y lo hacen enganchadas al scroll — entran desde los bordes
   conforme la sección sube y acaban apiladas y centradas sobre el video,
   cada línea en su caja oscura.
   El HTML nace con .is-static (fallback completo); scroll-effects.js la
   quita solo cuando activa los efectos. */
.video-jara { background: var(--ink); color: #fff; }
.video-jara-sticky {
  position: relative;
  height: var(--vis-h);
  overflow: hidden;
}
/* El video ocupa el encuadre entero de la sección (sin marco negro): recorta
   por los lados lo que haga falta para llenar la pantalla. */
.video-jara-cover {
  position: absolute;
  inset: 0;
  overflow: hidden;
  background: #000;
  /* Ajustes del efecto trama (halftone):
     --vj-cut  dureza del umbral: más alto es más punto marcado, pero también
       aplasta la imagen — por encima de ~2 el video deja de leerse
     --vj-trama  cuánto se marca la rejilla sobre el video
     --vj-c / --vj-b  contraste y brillo previos del video: comprimen la
       imagen hacia el gris medio, que es donde la trama puede dibujar
       puntos de todos los tamaños (con el video tal cual, las escenas
       claras se irían enteras a blanco) */
  --vj-cut: 1.4;
  --vj-trama: 0.07;
  --vj-c: 0.95;
  --vj-b: 0.95;
}
/* Truco del halftone en CSS puro: el filtro del padre se aplica al resultado
   ya compuesto de sus hijos, así que el contrast() convierte la mezcla
   video + puntos en tonos casi puros y el punto crece o se encoge según lo
   oscura que sea la imagen debajo. */
.video-jara-halftone {
  position: absolute;
  inset: 0;
  background: #000;
  filter: contrast(var(--vj-cut));
}
.video-jara-video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  filter: grayscale(1) contrast(var(--vj-c)) brightness(var(--vj-b));
}
/* Rejilla: cada celda es un punto negro que se difumina a blanco. En
   hard-light, el centro del punto multiplica (oscurece) y el borde hace
   screen (aclara); el contrast() del padre remata el umbral. */
.video-jara-dots {
  position: absolute;
  inset: 0;
  background-image: radial-gradient(circle at 50% 50%, #000 0%, #fff 75%);
  background-size: var(--vj-dot) var(--vj-dot);
  mix-blend-mode: hard-light;
  opacity: var(--vj-trama);
  pointer-events: none;
}
/* Grano fino por encima del umbral, para que la trama no se vea perfecta */
.video-jara-grain {
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0.12;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}
/* Con la trama, las zonas claras quedan blancas: este velo inferior asegura
   que la frase de abajo se lea siempre, y cierra la sección contra el negro
   del resto de la página. */
.video-jara-cover::after {
  content: "";
  position: absolute;
  inset: auto 0 0;
  height: 30%;
  pointer-events: none;
  background: linear-gradient(to bottom, rgba(17, 17, 17, 0) 0%, rgba(17, 17, 17, 0.85) 100%);
}
/* Overlay del texto: encima del video pero sin capturar clics, para que los
   controles del video (modo estático) sigan siendo utilizables. */
.video-jara-inner {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
}
/* Mismo formato tipográfico que el titular de portada (.headline) */
.video-jara-title {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.3em;
  font-size: clamp(48px, 9vw, 120px);
  font-weight: 700;
  line-height: 0.92;
  letter-spacing: -0.03em;
  text-transform: uppercase;
  margin: 0;
}
/* JARA replica el "APRUEBA" del hero (.tilt): caja verde inclinada, para que
   el estilo sea homogéneo en toda la página. */
.vj-line {
  display: block;
  background: var(--brand); /* si cambia, actualizar scroll-effects.js */
  padding: 0 0.14em;
  rotate: -3.5deg;
}
.vj-char { display: inline-block; will-change: transform; }
.video-jara-sub {
  position: absolute;
  left: 50%;
  bottom: 2.5vh;
  translate: -50% 0;
  width: max-content;
  max-width: min(520px, 84vw);
  font-size: 16px;
  color: rgba(255, 255, 255, 0.7);
  text-align: center;
  margin: 0;
}

/* El estado estático (.is-static) mantiene el mismo layout; sin GSAP solo
   cambia que no hay animación y el video conserva sus controles (la trama es
   suave, así que se siguen viendo bien). */

/* En pantallas pequeñas la trama se cierra un poco para que no se vea basta */
@media (max-width: 700px) {
  :root { --vj-dot: 4px; }
}

/* Texto solo para lectores de pantalla */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Nosotros */
.team-grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  border-top: 1.5px solid var(--ink);
}
.team-card {
  display: flex;
  flex-direction: column;
  border-bottom: 1.5px solid var(--ink);
  border-right: 1.5px solid var(--ink);
}
.team-card:nth-child(3n) { border-right: none; }
/* Los retratos vienen cuadrados: la ficha respeta ese formato y no recorta
   caras. Si el archivo aún no está, main.js quita el <img> y se ve el hueco. */
.team-photo {
  aspect-ratio: 1 / 1;
  overflow: hidden;
  border-bottom: 1.5px solid var(--ink);
}
.team-photo img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Vienen de sitios muy distintos (carné, estudio, exterior nevado): el
     blanco y negro los iguala, como pedía el diseño original. */
  filter: grayscale(1) contrast(1.04);
}
/* Mismo margen lateral que el resto: el texto de la primera ficha alinea
   con la cabecera de sección. */
.team-info { padding: 16px var(--pad-x) 20px; }
.team-name { font-size: 24px; font-weight: 700; letter-spacing: -0.01em; margin: 0; }
.team-apellidos { font-size: 14px; color: var(--gray-2); margin: 2px 0 0; }
.team-nota { font-size: 15px; color: var(--gray-1); margin: 12px 0 0; }
.team-meta {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  margin: 14px 0 0;
  font-size: 12px;
  color: var(--gray-1);
}

/* La historia es el único sitio de la web donde hablan los fundadores en
   primera persona. Va sola y centrada, a cuerpo de lectura en voz alta, sin
   foto que le compita: entre la retícula del equipo y el bloque de contacto,
   es el momento tranquilo de la página. */
.historia {
  border-top: 1.5px solid var(--ink);
  padding: clamp(40px, 6vh, 72px) var(--pad-x);
}
/* A la izquierda, no centrado: .historia y .section-head comparten el mismo
   var(--pad-x), así que el relato arranca en la misma vertical que el titular
   de la sección y que el resto de la página. */
.historia-texto {
  text-align: left;
  text-wrap: pretty;
}
.historia-texto p {
  /* En mayúscula, como los titulares de sección. El texto en data.json se
     escribe normal: la caja alta la pone el CSS, para que en el panel se lea
     y se corrija como una frase cualquiera. */
  text-transform: uppercase;
  /* El mismo cuerpo que el gancho de las opiniones (.op-hook): son las dos
     piezas de la página que hablan a bocajarro, y se leen igual de grandes. */
  font-size: clamp(26px, 3.6vw, 50px);
  /* A este tamaño la caja alta pide cerrar, no abrir: el mismo apretado que
     los titulares. Sin descendentes, el renglón también cabe más justo. */
  line-height: 1.15;
  letter-spacing: -0.02em;
  color: var(--ink);
  /* La medida va en ch y sobre el propio párrafo, no sobre el contenedor:
     así se calcula con SU cuerpo de letra y acompaña al clamp en cada
     tamaño de pantalla. En el contenedor se mediría contra sus 16px.
     40ch llena casi todo el ancho en un portátil; el tope sigue puesto para
     que en un monitor muy grande la línea no se vaya a lo ilegible. */
  max-width: 40ch;
  margin: 0 0 0.6em;
}
/* Las fechas van en el naranja de la casa. Se marcan desde el panel con
   *asteriscos*, que rich() convierte en <strong>: quien escriba el texto
   decide qué se resalta sin tocar el CSS. Solo cambia el color, no el peso:
   en mayúscula y a 50px, la negrita encima sería un grito. */
.historia-texto p strong {
  color: var(--accent);
  font-weight: inherit;
}
/* El segundo resalte, en mostaza: _texto_ desde el panel. Se le quita la
   cursiva de serie del <em> — igual que en el naranja, aquí solo cambia el
   color. */
.historia-texto p em {
  color: var(--mustard);
  font-style: normal;
  font-weight: inherit;
}
/* Con dos clases a propósito: la firma también es un <p> dentro de
   .historia-texto, así que con `.historia-firma` a secas perdía por
   especificidad y se quedaba con la mayúscula, el cuerpo y el negro del
   párrafo. */
.historia-texto .historia-firma {
  /* La firma se queda en caja baja: es lo único que dice una persona en su
     propia voz, y el contraste con el bloque la separa del relato. */
  text-transform: none;
  /* 17px, el mismo cuerpo que el cuerpo de texto de las opiniones. A 14px se
     quedaba en nada al lado de un párrafo que ahora llega a 50px. */
  font-size: 17px;
  line-height: 1.4;
  letter-spacing: 0;
  color: var(--gray-2);
  max-width: none;
  margin: 2.4em 0 0;
}

/* El encendido palabra a palabra lo monta scroll-effects.js: parte cada
   párrafo en <span class="palabra"> y las lleva de apagadas a tinta plena
   con la rueda. Sin JS, sin GSAP o con reduced-motion no se parte nada y el
   texto se lee entero desde el principio, que es su estado natural aquí. */
.historia-texto .palabra { opacity: 1; }

.timeline { list-style: none; margin: 0; padding: 0; border-top: 1.5px solid var(--ink); }
/* Sin filas, la lista dejaría suelto su border-top: una raya sola bajo la
   historia. Se esconde entera, y vuelve sola en cuanto se añada un año. */
.timeline:not(:has(li)) { display: none; }
.timeline li {
  display: flex;
  align-items: baseline;
  gap: 28px;
  padding: 16px var(--pad-x);
  border-bottom: 1.5px solid var(--ink);
}
/* El filete de cierre lo pone el border-top de Contacto: si no, doble línea */
.timeline li:last-child { border-bottom: none; }
.timeline-year { font-size: 22px; font-weight: 700; min-width: 90px; }
.timeline-hoy { color: var(--accent); }
.timeline-event { font-size: 15px; color: var(--gray-1); }

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

  /* La ficha pasa a FILA: retrato cuadrado a la izquierda, texto al lado.
     En una sola columna el retrato conservaba su aspect-ratio 1/1, así que
     medía de alto lo que mide de ancho la pantalla: en un móvil de 430 px eran
     430 px de cara por persona, casi metro y medio de fotos seguidas antes de
     llegar a leer un nombre.
     Se resuelve estrechando el retrato, no aplastándolo: si se le cambiara la
     proporción a apaisada, el object-fit: cover recortaría por arriba y por
     abajo y les cortaría la frente y la barbilla. Son fotos de estudio
     cuadradas y aquí se mantienen cuadradas, solo que pequeñas. */
  .team-card {
    flex-direction: row;
    /* flex-start y no stretch: con stretch la foto se estira hasta la altura
       de la ficha, así que cada una medía distinto — la de Cecilia 36 px más
       alta, porque su rol ocupa dos líneas. Con flex-start cada foto se queda
       con el alto que se le da abajo, y las tres miden igual. */
    align-items: flex-start;
    border-right: none;
    /* Los hijos de una rejilla y de un flex arrancan con min-width: auto, o
       sea negándose a bajar de su ancho de contenido. Con textos editables
       desde el panel (un apellido largo, un rol de tres líneas) eso acaba
       sacando la ficha de la pantalla. Va aquí y en .team-info por si acaso;
       con los textos de hoy no hace falta. */
    min-width: 0;
  }
  .team-photo {
    /* Ancho y alto de la MISMA expresión, en vez de dejar que el alto salga
       del aspect-ratio. Safari no recalcula el aspect-ratio de un elemento
       flex cuando cambia su base al redimensionar la ventana: se quedaba con
       la altura vieja hasta recargar la página. Chrome sí lo recalcula, así
       que el fallo solo se veía en Safari. Con las dos medidas escritas no
       hay nada que recalcular: siempre es cuadrada.
       38vw porque en móvil la rejilla va a sangre y la ficha mide una
       pantalla; si algún día se le pone margen lateral, hay que revisarlo. */
    flex: none;
    width: min(38vw, 190px);
    height: min(38vw, 190px);
    /* El filete separador va en .team-info y no aquí: con la foto alineada
       arriba, un borde en la foto solo llegaría hasta donde llega la foto y
       dejaría la ficha partida a media altura. */
    border-bottom: none;
  }
  /* A la izquierda va menos aire porque ya lo pone el filete; a la derecha se
     mantiene el margen de página para que la columna de texto cierre donde
     cierran las demás secciones. */
  /* .team-meta sí necesita envolver: son dos textos con space-between y en una
     columna estrecha no caben en la misma línea — el rol de Cecilia («directora
     y profesora de teórica y prácticas») se le echaba encima a «Algeciras». */
  .team-info { flex: 1 1 auto; min-width: 0; padding: 14px var(--pad-x) 16px 18px; border-left: 1.5px solid var(--ink); }
  .team-meta { flex-wrap: wrap; gap: 4px 12px; }

  .timeline li { gap: 16px; }
  .timeline-year { min-width: 64px; font-size: 18px; }
}

/* Opiniones — pantalla oscura, hermana de la del vídeo: una sola opinión a
   la vez, tratada como un titular más de la página. Se lee el gancho a
   cuerpo grande y el resto se despliega con "seguir leyendo".
   El HTML nace con .is-static (las nueve seguidas, sin mandos, que es lo
   que ve quien llega sin JS o con reduced-motion); main.js quita la clase
   solo cuando monta el rotador. Mismo trato que .video-jara.
   No lleva filete superior: contra el negro no se vería, y el cambio de
   color ya separa la sección. */
.opiniones {
  position: relative;
  background: var(--ink);
  color: #fff;
  min-height: var(--vis-h);
  display: flex;
  flex-direction: column;
  padding: var(--head-top) var(--pad-x) 28px;
  /* CUÁNTO SE MARCA LA TRAMA SOBRE EL NEGRO: sube o baja solo este número.
     0.06 apenas se intuye · 0.12 discreta · 0.17 marcada · 0.25 evidente */
  --trama-negro: 0.06;
}
/* La misma rejilla de la sección del video, sobre el negro. Aquí no hay
   imagen debajo que haga crecer o encoger el punto, así que no hay umbral:
   solo la trama. Y va en claro sobre oscuro —al revés que sobre el video—
   porque un punto negro sobre negro no se vería. */
.opiniones::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-image: radial-gradient(circle at 50% 50%, rgba(255, 255, 255, var(--trama-negro)) 0%, transparent 60%);
  background-size: var(--vj-dot) var(--vj-dot);
}
/* El contenido, por encima de la trama */
.opiniones > * { position: relative; z-index: 1; }
.opiniones .kicker { color: var(--mustard); }
.op-stage {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 40px 0;
}
.op-list { list-style: none; margin: 0; padding: 0; }
/* Solo la opinión activa ocupa sitio; el resto ni se maqueta */
.op-item { display: none; transition: opacity 0.4s ease, transform 0.4s ease; }
.op-item.is-active { display: block; }
.op-item.out { opacity: 0; transform: translateY(14px); }

.op-quote { margin: 0; }
/* El gancho es lo único que se ve siempre: mismo formato que .headline.
   Los hay de una línea y de tres, así que main.js marca el tramo en
   data-len y el largo baja un punto de cuerpo. */
.op-hook {
  display: block;
  font-weight: 700;
  font-size: clamp(26px, 3.6vw, 50px);
  line-height: 1.12;
  letter-spacing: -0.03em;
  max-width: 20ch;
}
.op-item[data-len="media"] .op-hook {
  font-size: clamp(22px, 2.6vw, 36px);
  line-height: 1.18;
  max-width: 30ch;
}
/* Punto rojo si la opinión cabe entera (como los titulares de la página);
   suspensivos rojos si hay resto, que desaparecen al desplegarlo. */
.op-dot { color: var(--accent); }
.op-item.abierta .op-dot { display: none; }

/* Recortador con la altura animada por JS, igual que el acordeón de
   permisos: el padding vive dentro para que 0 sea 0. */
.op-rest-wrap {
  height: 0;
  overflow: hidden;
  transition: height 0.45s cubic-bezier(0.33, 1, 0.68, 1);
}
.op-rest-wrap p {
  margin: 0;
  padding-top: 18px;
  font-size: 17px;
  line-height: 1.6;
  color: rgba(255, 255, 255, 0.72);
  max-width: 60ch;
}
/* Los botones de la sección son los de la casa (.btn .btn-ghost): mismo
   filete, mismo radio y el mismo relleno que sube al pasar el ratón. Sobre
   negro solo cambia el color del filete y del texto, porque el borde de
   tinta no se vería. */
.opiniones .btn-ghost { border-color: rgba(255, 255, 255, 0.45); color: #fff; }
.opiniones .btn-ghost:hover { border-color: var(--mustard); }
.op-more { margin-top: 24px; }

.op-who { display: flex; align-items: baseline; gap: 14px; flex-wrap: wrap; margin: 30px 0 0; }
/* El nombre repite la caja verde inclinada del hero (.tilt) y de JARA */
.op-name {
  display: inline-block;
  background: var(--brand);
  color: #fff;
  padding: 2px 12px;
  rotate: -2deg;
  font-size: 17px;
  font-weight: 700;
  text-transform: uppercase;
}
.op-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  border-top: 1.5px solid rgba(255, 255, 255, 0.25);
  padding-top: 18px;
}
.op-idx { font-size: 13px; font-family: ui-monospace, monospace; color: rgba(255, 255, 255, 0.6); }
.op-idx b { color: #fff; }
.op-nav { display: flex; gap: 10px; }
/* Las flechas son el mismo botón, en cuadrado */
.op-btn { width: 46px; height: 46px; padding: 0; justify-content: center; font-size: 18px; }
/* Barra del turno: avanza sola y se congela mientras haya un resto abierto */
.op-prog { height: 3px; background: rgba(255, 255, 255, 0.18); margin-top: 16px; }
.op-prog i { display: block; height: 100%; width: 0; background: var(--accent); }

/* Llamada a dejar reseña en Google, al cierre de las opiniones. Mismo filete
   blanco translúcido que .op-bar para que se lea como parte de la sección y no
   como un añadido. Solo existe si hay enlace: el panel deja la región vacía. */
.op-cta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px 20px;
  flex-wrap: wrap;
  border-top: 1.5px solid rgba(255, 255, 255, 0.25);
  margin-top: 22px;
  padding-top: 20px;
}
.op-cta-texto { font-size: 16px; color: rgba(255, 255, 255, 0.7); margin: 0; max-width: 470px; }
.op-cta-texto strong { color: #fff; font-weight: 600; }
.op-cta-botones { display: flex; gap: 10px; flex-wrap: wrap; }

/* Estado estático: las nueve opiniones seguidas, en párrafo corrido y sin
   mandos (las flechas no harían nada sin JS). */
.opiniones.is-static .op-stage { justify-content: flex-start; }
.opiniones.is-static .op-item { display: block; }
.opiniones.is-static .op-item + .op-item {
  margin-top: 26px;
  padding-top: 26px;
  border-top: 1.5px solid rgba(255, 255, 255, 0.22);
}
.opiniones.is-static .op-quote {
  font-size: clamp(19px, 2.2vw, 27px);
  font-weight: 700;
  line-height: 1.25;
  letter-spacing: -0.02em;
  max-width: 46ch;
}
.opiniones.is-static .op-quote::before { content: "“"; }
.opiniones.is-static .op-quote::after { content: "”"; }
.opiniones.is-static .op-hook {
  display: inline;
  font-size: inherit;
  line-height: inherit;
  letter-spacing: inherit;
  max-width: none;
}
.opiniones.is-static .op-who { margin-top: 16px; }
.opiniones.is-static .op-idx,
.opiniones.is-static .op-nav,
.opiniones.is-static .op-prog { display: none; }

@media (prefers-reduced-motion: reduce) {
  .op-item, .op-rest-wrap, .op-more, .op-btn { transition: none; }
}

@media (max-width: 768px) {
  .op-stage { padding: 28px 0; }
  .op-who { gap: 10px; }
  .op-btn { width: 42px; height: 42px; }
  .op-bar { gap: 12px; }
}

/* Contacto: pantalla completa — los mapas absorben el alto sobrante */
.contacto {
  min-height: var(--vis-h);
  display: flex;
  flex-direction: column;
}
.sedes-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  border-top: 1.5px solid var(--ink);
  flex: 1;
}
.sede-card { display: flex; flex-direction: column; }
.sede-card:first-child { border-right: 1.5px solid var(--ink); }
/* El embed de Google trae su propia paleta (agua azul, POIs de colores) que
   compite con el rojo de los teléfonos. Lo pasamos a gris para que el único
   color de la ficha sea el de la marca. */
.sede-map {
  width: 100%;
  height: 320px;
  border: 0;
  display: block;
  border-bottom: 1.5px solid var(--ink);
  filter: grayscale(1) contrast(1.05) brightness(1.02);
}
/* El mapa ya no absorbe el alto sobrante: lo absorben los datos, y los chips
   se anclan al filete inferior para no dejar una cola de blanco muerto. */
.sede-datos {
  flex: 1;
  display: flex;
  flex-direction: column;
  padding: 22px var(--pad-x) 28px;
}
/* En columna flex el botón se estiraría a todo el ancho: lo dejamos con su
   ancho natural, como el resto de botones de la página. */
.sede-datos .btn { align-self: flex-start; }
.sede-nombre { font-size: clamp(28px, 3.5vw, 42px); font-weight: 700; letter-spacing: -0.02em; margin: 0; }
.sede-dir { color: var(--gray-1); font-size: 14px; margin: 4px 0 18px; }
.sede-horario { font-size: 14px; color: var(--gray-1); line-height: 1.7; margin: 18px 0; }
.sede-chips { display: flex; gap: 10px; flex-wrap: wrap; margin: 0; margin-top: auto; }
.chip {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.02em;
  border: 1.5px solid var(--ink);
  border-radius: 999px;
  padding: 6px 14px;
  transition: background-color 0.2s ease, color 0.2s ease;
}
.chip:hover { background: var(--ink); color: #fff; }

/* Confirmación de "copiado" en escritorio (main.js): en vez de inventar otro
   estado, se dispara el mismo relleno que el botón ya hace en hover. */
.btn.copiado::before { transform: translateY(0); }
.telefono-band.copiado .telefono-nota { color: #fff; }

.telefono-band {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 16px;
  flex-wrap: wrap;
  background: var(--brand);
  color: #fff;
  padding: 40px var(--pad-x);
}
.telefono-num { font-size: clamp(40px, 7vw, 88px); font-weight: 700; letter-spacing: -0.03em; line-height: 1; }
.telefono-nota { font-size: 14px; color: rgba(255, 255, 255, 0.8); }

@media (max-width: 768px) {
  .sedes-grid { grid-template-columns: 1fr; }
  .sede-card:first-child { border-right: none; border-bottom: 1.5px solid var(--ink); }
  .sede-map { height: 220px; }
  .telefono-band { padding: 28px var(--pad-x); }
}

/* AEOL Cloud (aeol.html) — la única página aparte del sitio. No estrena
   lenguaje: filetes de 1.5px, cabeceras .section-head y la caja verde inclinada
   de la marca. Todo lo de aquí vive fuera de la home y no la afecta. */

/* La cabecera de la página lleva el h1, así que respira un poco más que una
   cabecera de sección normal antes del primer filete. La mitad derecha, que si
   no quedaría vacía, la ocupa el botón de entrar: alineado abajo con el final
   del texto, para que los dos apoyen en la misma línea. */
.aeol-intro {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: end;
  column-gap: 32px;
}
.aeol-intro .section-head { padding-bottom: calc(var(--head-bottom) + 20px); }
.aeol-acceso {
  padding: 0 var(--pad-x) calc(var(--head-bottom) + 20px);
  text-align: right;
}
.aeol-acceso-txt { font-size: 15px; color: var(--gray-1); margin: 0 0 14px; }

/* Los tres pasos: la misma rejilla con filetes de .team-grid, sin fotos. */
.pasos-grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  border-top: 1.5px solid var(--ink);
}
.paso-card {
  padding: 28px var(--pad-x) 34px;
  border-right: 1.5px solid var(--ink);
}
.paso-card:nth-child(3n) { border-right: none; }
/* El número mostaza grande del acordeón de permisos, un punto más pequeño:
   aquí van tres en fila y a 60px se comerían el texto. */
.paso-num {
  display: block;
  font-size: 44px;
  font-weight: 700;
  line-height: 1;
  color: var(--mustard);
}
.paso-titulo { font-size: 20px; font-weight: 600; letter-spacing: -0.01em; margin: 14px 0 0; }
.paso-text { font-size: 15px; color: var(--gray-1); line-height: 1.6; margin: 8px 0 0; max-width: 340px; }

/* Los dos precios, en la rejilla de dos con filete de .sedes-grid. */
.precio-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  border-top: 1.5px solid var(--ink);
}
/* Columna flex + margin-top:auto en el botón: los dos botones quedan a la misma
   altura aunque un texto ocupe una línea más que el otro (el truco de .sede-chips). */
.precio-card {
  display: flex;
  flex-direction: column;
  padding: 26px var(--pad-x) 34px;
}
.precio-card:first-child { border-right: 1.5px solid var(--ink); }
.precio-card .btn { align-self: flex-start; margin-top: auto; }
.precio-quien {
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--gray-1);
  margin: 0 0 14px;
}
/* El precio de alumno va en la caja verde inclinada, el mismo gesto que el
   APRUEBA de la portada y el rótulo del vídeo: es la oferta que se destaca.
   El otro va en negro plano, para que la jerarquía se lea de un vistazo. */
.precio-num {
  font-size: clamp(52px, 8vw, 96px);
  font-weight: 700;
  letter-spacing: -0.03em;
  line-height: 1.15;
  margin: 0;
}
.precio-num-plano { color: var(--ink); }
.precio-cuando { font-size: 14px; color: var(--gray-2); margin: 12px 0 0; }
.precio-detalle { font-size: 15px; color: var(--gray-1); line-height: 1.6; margin: 16px 0 26px; max-width: 420px; }
.precio-detalle strong { color: var(--ink); font-weight: 600; }

.precio-avisos { padding: 26px var(--pad-x) 40px; display: grid; gap: 18px; }
.precio-nota {
  font-size: 14px;
  color: var(--gray-1);
  line-height: 1.7;
  max-width: 520px;
  margin: 0;
  padding-left: 16px;
  border-left: 1.5px solid var(--gray-border);
}

/* Dudas: cuatro pares en dos columnas. Un <dl> basta, sin acordeón: las
   respuestas son de dos líneas y esconderlas solo añadiría clics. */
.dudas-lista {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0;
  margin: 0;
  border-top: 1.5px solid var(--ink);
}
.duda {
  padding: 24px var(--pad-x) 28px;
  border-right: 1.5px solid var(--ink);
  border-bottom: 1.5px solid var(--ink);
}
.duda:nth-child(2n) { border-right: none; }
/* Si las dudas son impares, la última se queda sola en su fila: que ocupe el
   ancho entero en vez de dejar medio hueco vacío con el filete colgando. */
.duda:last-child:nth-child(odd) { grid-column: 1 / -1; border-right: none; }
.duda-p { font-size: 17px; font-weight: 600; margin: 0; }
.duda-r { font-size: 15px; color: var(--gray-1); line-height: 1.6; margin: 8px 0 0; max-width: 420px; }
/* El teléfono de la respuesta se subraya: dentro de un párrafo, sin subrayado
   no se distingue de la frase. En escritorio main.js lo pasa a copiar. */
.duda-r a, .paso-text a { color: var(--ink); font-weight: 600; text-decoration: underline; text-underline-offset: 3px; }

.aeol-legal {
  font-size: 12px;
  color: var(--gray-2);
  line-height: 1.6;
  margin: 0;
  padding: 22px var(--pad-x) 30px;
  max-width: 640px;
}

@media (max-width: 768px) {
  /* Ya no cabe la columna del botón al lado del titular: se apila debajo, y el
     aire que sobra lo quita la cabecera para no dejar un hueco muerto. */
  .aeol-intro { grid-template-columns: 1fr; }
  .aeol-intro .section-head { padding-bottom: 20px; }
  .aeol-acceso { text-align: left; padding-bottom: var(--head-bottom); }
  .pasos-grid, .dudas-lista, .precio-grid { grid-template-columns: 1fr; }
  .paso-card, .duda { border-right: none; }
  .paso-card { border-bottom: 1.5px solid var(--ink); }
  .paso-card:last-child { border-bottom: none; }
  .precio-card:first-child { border-right: none; border-bottom: 1.5px solid var(--ink); }
}

/* ═══════════════════════════════════════════════════════════════════════════
   Footer, consentimiento de cookies y páginas legales
   ═══════════════════════════════════════════════════════════════════════════ */

/* Footer — cierra las cinco páginas. Va DESPUÉS de </main>, no dentro: la
   banda verde del teléfono sigue siendo lo último del contenido. */
.footer {
  border-top: 1.5px solid var(--ink);
  padding: 32px var(--pad-x) 36px;
  font-size: 13px;
  line-height: 1.7;
  color: var(--gray-1);
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 12px 32px;
  align-items: start;
}
.footer-identidad { margin: 0; max-width: 520px; }
/* La razón social y el CIF son lo que exige la LSSI: se leen en negro, no en
   gris, porque son el dato identificativo y no una nota al pie. */
.footer-razon { color: var(--ink); font-weight: 600; }
.footer-legal {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 18px;
  margin: 0;
  padding: 0;
  list-style: none;
  justify-self: end;
}
.footer-legal a,
.footer-cookies-btn {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 3px;
  font-size: 13px;
  font-weight: 500;
}
/* El de cookies es un <button> y no un <a>: no lleva a ninguna página, reabre
   el banner. Se le quitan los estilos de botón para que pase por enlace. */
.footer-cookies-btn {
  background: none;
  border: none;
  padding: 0;
  font-family: inherit;
  cursor: pointer;
}
.footer-legal a:hover, .footer-cookies-btn:hover { color: var(--accent); }
/* La página en la que ya estás no se enlaza a sí misma */
.footer-legal [aria-current="page"] {
  color: var(--gray-2);
  text-decoration: none;
  font-weight: 500;
}
.footer-copy { grid-column: 1 / -1; margin: 0; font-size: 12px; color: var(--gray-2); }

@media (max-width: 768px) {
  .footer { grid-template-columns: 1fr; gap: 18px; }
  .footer-legal { justify-self: start; }
}

/* ── Banner de cookies ──────────────────────────────────────────────────────
   Barra inferior, NO modal: no bloquea la página ni atrapa el foco. Nace con
   el atributo `hidden` en el HTML y solo consent.js se lo quita, para que no
   parpadee en quien ya decidió. Con JavaScript desactivado no aparece nunca
   — y tampoco se carga nada de Google, que es el comportamiento correcto. */
.cookies {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 9000;
  background: var(--gray-bg);
  border-top: 1.5px solid var(--ink);
  padding: 20px var(--pad-x);
  box-shadow: 0 -8px 24px rgba(0, 0, 0, 0.08);
}
.cookies[hidden] { display: none; }
.cookies-inner {
  max-width: 1100px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 16px 32px;
  align-items: center;
}
.cookies-titulo { font-size: 17px; font-weight: 700; margin: 0 0 4px; color: var(--ink); }
.cookies-texto { font-size: 14px; line-height: 1.6; color: var(--gray-1); margin: 0; max-width: 620px; }
.cookies-texto a { color: var(--ink); font-weight: 600; text-decoration: underline; text-underline-offset: 3px; }
/* Los TRES botones son .btn-ghost, del mismo tamaño y el mismo peso visual.
   Es deliberado y es el punto legal más importante del banner: rechazar tiene
   que costar exactamente lo mismo que aceptar. Destacar «Aceptar» en rojo y
   dejar «Rechazar» en gris pequeño es justo el patrón que sanciona la AEPD. */
.cookies-botones { display: flex; flex-wrap: wrap; gap: 10px; }
.cookies-botones .btn { flex: 0 0 auto; }

.cookies-panel {
  grid-column: 1 / -1;
  border-top: 1.5px solid var(--ink);
  margin-top: 4px;
  padding-top: 16px;
}
.cookies-panel[hidden] { display: none; }
.cookies-opcion {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 4px 12px;
  padding: 12px 0;
  border-bottom: 1px solid var(--gray-border);
}
.cookies-opcion:last-of-type { border-bottom: none; }
.cookies-opcion input { width: 18px; height: 18px; margin: 2px 0 0; accent-color: var(--accent); cursor: pointer; }
.cookies-opcion input:disabled { cursor: not-allowed; opacity: 0.55; }
.cookies-opcion label { font-size: 15px; font-weight: 600; color: var(--ink); cursor: pointer; }
.cookies-opcion input:disabled + label { cursor: not-allowed; }
.cookies-opcion p { grid-column: 2; font-size: 13px; line-height: 1.6; color: var(--gray-1); margin: 0; }
.cookies-guardar { margin-top: 16px; }

@media (max-width: 768px) {
  .cookies { max-height: 85vh; overflow-y: auto; padding: 18px var(--pad-x); }
  .cookies-inner { grid-template-columns: 1fr; }
  .cookies-botones .btn { flex: 1 1 auto; justify-content: center; }
}

/* ── Mapa bloqueado ─────────────────────────────────────────────────────────
   Ocupa el hueco EXACTO del iframe que sustituye, así que al cargarse el mapa
   la página no pega ningún salto. El gris replica el de .photo-placeholder;
   no se le pone esa clase porque aquello es para fotos que faltan, y aquí no
   falta nada: es una carga que el usuario todavía no ha autorizado. */
.sede-map-off {
  /* Lleva tambien la clase .sede-map, de la que hereda el ancho, los 320px de
     alto y el filete inferior: por eso el hueco calza exacto y al cargar el
     mapa la pagina no pega ningun salto. Se le quita el filtro de grises, que
     alli tine el mapa y aqui apagaria el boton. */
  filter: none;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  text-align: center;
  padding: 20px;
  background: var(--gray-bg);
  border-bottom: 1.5px solid var(--ink);
}
.sede-map-aviso { font-size: 13px; line-height: 1.6; color: var(--gray-1); margin: 0; max-width: 280px; }

/* ── Páginas legales ────────────────────────────────────────────────────────
   Columna de lectura estrecha: son textos largos y densos, y a 70 caracteres
   por línea se leen; a todo el ancho de la pantalla, no. */
.legal {
  /* Sin aire arriba: el .section-head de encima ya pone el suyo
     (--head-bottom) y sumar los dos dejaria un hueco muerto. */
  padding: 0 var(--pad-x) 72px;
  max-width: 760px;
  font-size: 16px;
  line-height: 1.75;
  color: var(--gray-1);
}
.legal h2 {
  font-size: 22px;
  font-weight: 700;
  color: var(--ink);
  line-height: 1.25;
  margin: 44px 0 12px;
  padding-top: 20px;
  border-top: 1.5px solid var(--ink);
}
.legal h2:first-of-type { margin-top: 8px; }
.legal h3 { font-size: 17px; font-weight: 600; color: var(--ink); margin: 28px 0 6px; }
.legal p, .legal li { margin: 0 0 14px; }
.legal ul, .legal ol { padding-left: 22px; margin: 0 0 18px; }
.legal li { margin-bottom: 8px; }
.legal strong { color: var(--ink); font-weight: 600; }
.legal a { color: var(--ink); font-weight: 600; text-decoration: underline; text-underline-offset: 3px; }
.legal a:hover { color: var(--accent); }

.legal-fecha { font-size: 13px; color: var(--gray-2); margin: 0 0 8px; }

/* Aviso de borrador. Es mostaza y no rojo porque no es un error: es una nota
   de trabajo que tiene que desaparecer antes de publicar. */
.legal-borrador {
  border: 1.5px solid var(--mustard);
  background: #fdf6e6;
  padding: 16px 18px;
  margin: 0 0 32px;
  font-size: 14px;
  line-height: 1.65;
  color: var(--ink);
}
.legal-borrador strong { display: block; margin-bottom: 4px; }

/* Datos que faltan y que alguien tiene que rellenar. Van en rojo y en
   monoespaciada para que canten en medio del texto. */
.legal-pendiente {
  background: #fdece9;
  color: var(--accent);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.85em;
  font-weight: 600;
  padding: 2px 6px;
  border-radius: 3px;
}

/* La ficha del responsable: mismo filete que el resto del sistema */
.legal-datos {
  border: 1.5px solid var(--ink);
  padding: 20px 22px;
  margin: 0 0 24px;
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 6px 20px;
  font-size: 15px;
}
.legal-datos dt { font-weight: 600; color: var(--ink); }
.legal-datos dd { margin: 0; }

/* La tabla de cookies se sale en móvil: scrollea ella sola dentro de su caja,
   sin arrastrar el ancho de la página. */
.legal-tabla-wrap { overflow-x: auto; margin: 0 0 24px; border: 1.5px solid var(--ink); }
.legal-tabla { border-collapse: collapse; width: 100%; min-width: 560px; font-size: 14px; }
.legal-tabla th, .legal-tabla td { padding: 10px 14px; text-align: left; border-bottom: 1px solid var(--gray-border); vertical-align: top; }
.legal-tabla th { background: var(--gray-bg); color: var(--ink); font-weight: 600; white-space: nowrap; }
.legal-tabla tr:last-child td { border-bottom: none; }
.legal-tabla code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.9em; color: var(--ink); }

@media (max-width: 768px) {
  .legal { font-size: 15px; }
  .legal h2 { font-size: 20px; }
  .legal-datos { grid-template-columns: 1fr; gap: 2px; }
  .legal-datos dd { margin-bottom: 10px; }
}
