/* =============================================================================
   ASCOR SECURITY — Componentes

   REGLA CENTRAL DEL REDISEÑO (agosto 2026): menos cajas, más flujo.

   El contenido fluye en listas, líneas de tiempo y texto directo sobre el
   marino. Solo TRES superficies pueden dibujar un fondo:

     1. .section--zona   banda de sección (#0E1830, curva superior) — layout.css
     2. .cta-tarjeta     la tarjeta de cierre (#16306B, radio asimétrico)
     3. .input/.select/.textarea   los campos de formulario

   Cualquier otra cosa va sin fondo y sin borde. Si al agregar un bloque nuevo
   necesitas dibujarle un rectángulo alrededor para que se entienda, el problema
   es la jerarquía del contenido, no la falta de una caja.

   AMPLIACIÓN DE SEPTIEMBRE 2026 (rediseño fotográfico, a pedido del cliente):
   se suman cuatro superficies más, todas ligadas a fotografía real o al
   proceso —.tarjeta (servicios), .paso (proceso), .cierre (formulario de la
   portada) y el marco redondeado de las fotos—. La regla de arriba sigue
   valiendo para todo lo demás. Ver CLAUDE.md §4ter.
   ========================================================================== */

/* -----------------------------------------------------------------------------
   BOTONES — píldora, mínimo táctil 48px
   -------------------------------------------------------------------------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-3);
  min-height: 48px;
  padding: 14px 26px;
  border-radius: var(--radius-pill);
  border: 1px solid transparent;
  font-family: var(--font-body);
  font-size: var(--fs-sm);
  font-weight: 600;
  letter-spacing: 0.01em;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
  transition: background-color 200ms var(--ease-out),
              border-color 200ms var(--ease-out),
              color 200ms var(--ease-out),
              transform 200ms var(--ease-out);
}

.btn:active { transform: scale(0.98); }
.btn svg { flex: none; }

.btn--primary {
  background: var(--royal-500);
  color: var(--text-on-royal);   /* blanco sobre royal-500: 5.13:1 */
}
.btn--primary:hover { background: var(--royal-400); color: var(--text-on-royal); }

.btn--ghost {
  background: rgba(255, 255, 255, 0.05);
  color: var(--claridad);
}
.btn--ghost:hover { background: rgba(255, 255, 255, 0.10); color: var(--claridad); }

/* Aquí estaba .btn--wa. Se eliminó con los botones de WhatsApp: la vía informal
   es ahora la burbuja flotante y nada más, para que cada pantalla tenga un solo
   CTA primario. Si algún día vuelve un botón de WhatsApp en línea, el par de
   colores auditado es fondo #25D366 con texto #06210F — 4.5:1. El blanco sobre
   ese verde da 3.09:1 y no cumple. */

.btn--lg { min-height: 52px; padding: 16px 30px; font-size: var(--fs-base); }
.btn--block { width: 100%; }

.btn[aria-disabled="true"], .btn:disabled {
  opacity: 0.55;
  cursor: not-allowed;
  pointer-events: none;
}

/* NO poner `white-space: nowrap` aquí: en móvil los botones ocupan el 100% y un
   texto largo tiene que poder envolver. El único que lo lleva es .header__cta,
   que vive dentro de un contenedor flex que sí lo comprime (ver layout.css). */
.btn-row { display: flex; flex-wrap: wrap; gap: var(--sp-3); }

@media (max-width: 420px) {
  .btn-row > .btn { width: 100%; }
}

/* Enlace con flecha */
.link-arrow {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: var(--tap-min);
  font-weight: 600;
  font-size: var(--fs-sm);
  color: var(--royal-300);
  text-decoration: none;
}
.link-arrow svg { transition: transform var(--dur) var(--ease-out); }
.link-arrow:hover svg { transform: translateX(4px); }

/* -----------------------------------------------------------------------------
   CHIP — especializaciones y atributos de marca
   -------------------------------------------------------------------------- */
.pill-row { display: flex; flex-wrap: wrap; gap: var(--sp-2); list-style: none; padding: 0; margin-bottom: 0; }

.pill {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: 34px;
  padding: var(--sp-2) var(--sp-4);
  border-radius: var(--radius-pill);
  background: rgba(255, 255, 255, 0.05);
  font-size: var(--fs-xs);
  font-weight: 500;
  color: var(--text-muted);
  white-space: nowrap;
}

.pill::before {
  content: '';
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--royal-400);
  flex: none;
}

/* -----------------------------------------------------------------------------
   HERO
   -------------------------------------------------------------------------- */
.hero {
  position: relative;
  padding-top: calc(var(--header-h) + var(--safe-top) + var(--sp-7));
  padding-bottom: var(--sp-8);
  overflow: hidden;      /* recorta el orbe: sin esto, scroll lateral en móvil */
  isolation: isolate;
}

/* Sube el contenido por encima del orbe, que va en z-index 0.

   EL :not(.hero__media) NO ES DECORATIVO — quitarlo rompe los seis heroes
   interiores. `.hero > *:not(.orbe)` pesa dos clases y `.hero__media` una, así
   que esta regla le ganaba por especificidad y le devolvía `position: relative`
   a la foto de fondo. Al salir de `position: absolute`, la fotografía dejaba de
   cubrir el hero y pasaba a ocupar su propio hueco en el flujo: en escritorio
   quedaba a la izquierda empujando el texto a la derecha, y en móvil quedaba
   como una miniatura al costado del titular.

   Entró con el rediseño de agosto de 2026 y se publicó: la regla se agregó para
   el orbe de la portada —el único hero que tiene orbe— sin ver que también
   alcanzaba a la foto de los otros seis. Compiló limpio, no dio scroll lateral
   y no rompió ninguna prueba automática, igual que el bug de los íconos de
   `SVG.documento`: solo se ve mirando una captura. */
.hero > *:not(.orbe):not(.hero__media) { position: relative; z-index: 1; }

/* --- Hero de portada: sin caja y sin foto de fondo --------------------------
   El titular va directo sobre el marino y la fotografía baja a ocupar su propio
   bloque con máscara orgánica. Antes la imagen iba de fondo a pantalla completa
   con un overlay que se comía casi toda la foto: se pagaba el peso de una
   imagen de 2048px para mostrar, en la práctica, un rectángulo azul. */
.hero__cols { display: grid; gap: var(--sp-6); }

/* Móvil: la foto cierra el hero, así que el relleno inferior de 48px más el de
   la sección siguiente dejaban casi 100px de marino vacío entre dos bloques.
   En PC lo redefine la regla de altura de pantalla, más abajo. */
.hero:not(.hero--inner) { padding-bottom: var(--sp-5); }

.hero__content { max-width: var(--measure); }

.hero h1 { font-size: var(--fs-hero); margin-bottom: var(--sp-5); }

.hero__sub {
  font-size: var(--fs-lg);
  line-height: var(--lh-snug);
  color: var(--text-muted);
  max-width: var(--measure-narrow);
  margin-bottom: var(--sp-6);
}

@media (min-width: 1024px) {
  /* Escritorio: dos columnas derivadas del móvil, no un diseño aparte.
     El texto se acota a 620px como pide el sistema; la foto toma el resto.

     Eran 560px hasta la corrección de PC. Con la segunda rampa tipográfica el
     h1 mide 45–48px en vez de 40, y a 560px de ancho «Protegemos lo que más te
     importa» se partía en tres líneas cortas con la palabra-acento sola en la
     última: el titular más importante del sitio quedaba escalonado. */
  .hero__cols {
    grid-template-columns: minmax(0, 620px) minmax(0, 1fr);
    align-items: center;
    gap: var(--sp-9);
  }
  .hero__cols .hero__content { max-width: 620px; }

  /* EL HERO OCUPA LA PRIMERA PANTALLA — y solo el de portada.

     En PC el hero medía unos 560px de alto dentro de una ventana de 900: la
     sección siguiente asomaba cortada por abajo y la primera impresión del
     sitio era una franja a media altura con marino vacío debajo. En móvil el
     problema no existe porque el contenido ya llena la pantalla de sobra.

     El tope de 820px es lo que impide que en un monitor de 1440px de alto el
     hero se estire hasta separar el titular de las cifras.

     `min-height` y no `height`: si el contenido crece —una traducción más
     larga, un titular de tres líneas— el hero crece con él en vez de
     desbordarse. El :not() deja fuera a los heroes interiores, que tienen su
     propia altura calculada sobre la fotografía de fondo. */
  .hero:not(.hero--inner) {
    display: flex;
    align-items: center;
    min-height: min(92svh, 820px);
    padding-bottom: var(--sp-9);
  }
  .hero:not(.hero--inner) > .container { width: 100%; }
}

/* --- Hero interior: conserva la fotografía de fondo -------------------------
   Aquí la foto SÍ va de fondo, con el overlay ya aligerado en tokens.css. Se
   mantiene por dos razones: es la única imagen de esas páginas —quitarla
   perdería su texto alternativo, que es contenido indexado— y sostiene el
   ancho completo que un hero corto necesita para no verse anémico. */
.hero--inner {
  display: flex;
  align-items: flex-end;
  min-height: min(52svh, 460px);
  padding-top: calc(var(--header-h) + var(--safe-top) + var(--sp-8));
  padding-bottom: var(--sp-8);
}

.hero__media {
  position: absolute;
  inset: 0;
  z-index: -2;
}

/* <picture> es un contenedor en línea por defecto: lo forzamos a llenar
   el contenedor para que object-fit del <img> tenga altura de referencia. */
.hero__media picture,
.gallery picture { display: block; width: 100%; height: 100%; }

.hero__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 35%;
}

.hero__media::after {
  content: '';
  position: absolute;
  inset: 0;
  background: var(--overlay-full);
}

/* Barra acento royal a la izquierda — firma de marca (manual p.6).
   Va fuera del flujo: así el texto arranca en la MISMA columna que el resto
   de las secciones y toda la página queda alineada a una sola retícula. */
.bar-accent { position: relative; }

.bar-accent::before {
  content: '';
  position: absolute;
  left: calc(-1 * var(--bar-offset));
  top: 0.2em;
  bottom: 0.2em;
  width: var(--bar-accent-w);
  border-radius: 2px;
  background: var(--royal-500);
}

/* -----------------------------------------------------------------------------
   FOTOGRAFÍA DE CONTENIDO — marco redondeado (rediseño fotográfico, sep. 2026)
   -------------------------------------------------------------------------- */
/* Aquí vivía .media-organica, la máscara 120/32 del hero de la portada. Con
   fotografía real la máscara se comía justo lo que la foto tiene que mostrar
   —el guardia y el vehículo llegan hasta los bordes del encuadre— y el
   encargo pidió bordes redondeados. Salió junto con --mascara-a.

   Todas las fotos de contenido comparten este marco: radio, fondo de espera
   mientras carga y recorte. `overflow: hidden` en el contenedor es lo que
   recorta: el border-radius no alcanza al <img> hijo por sí solo. */
.hero__foto,
.foto,
.collage figure,
.galeria-home figure {
  position: relative;
  margin: 0;
  overflow: hidden;
  border-radius: var(--radius-media);
  background: var(--marino-700);
}

.hero__foto picture,
.foto picture,
.collage picture,
.galeria-home picture { display: block; width: 100%; height: 100%; }

.hero__foto img,
.foto img,
.collage img,
.galeria-home img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Un filete interior de 1px separa la foto nocturna del marino: sin él, los
   cielos oscuros de casi todas las fotos se funden con el fondo y el borde
   redondeado desaparece. Va en ::after y no como border para no restarle
   píxeles a la imagen. */
.hero__foto::after,
.foto::after,
.collage figure::after,
.galeria-home figure::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.07);
  pointer-events: none;
}

/* Hero: 4:3 en móvil, que es la proporción del archivo — sin recorte. En PC
   se acerca al cuadrado para ganar altura junto al titular; el foco se corre a
   la izquierda para no perder el capó con el logo ni al guardia de la derecha. */
/* Móvil 3:2 y no 4:3: debajo del titular, una foto de 4:3 ocupaba media
   pantalla y se leía como un bloque suelto antes de la sección siguiente
   (pedido del cliente, 25 sep 2026). 3:2 conserva guardia y vehículo. */
.hero__foto { aspect-ratio: 3 / 2; box-shadow: var(--shadow-lg); }
.hero__foto img { object-position: 55% 50%; }

@media (min-width: 1024px) {
  .hero__foto { aspect-ratio: 11 / 10; }
  .hero__foto img { object-position: 45% 50%; }
}

/* -----------------------------------------------------------------------------
   FRANJA DE MÉTRICAS — tres cifras con divisores verticales, sin tarjetas
   -------------------------------------------------------------------------- */
.metricas {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  margin-top: var(--sp-7);
  padding-top: var(--sp-5);
  border-top: 1px solid var(--divisor);
}

/* El divisor va como borde izquierdo de los ítems 2 y 3: así nunca sobra una
   línea al final de la fila, que es lo que pasa al ponerlo como borde derecho. */
.metricas > * + * {
  border-left: 1px solid var(--divisor);
  padding-left: var(--sp-4);
  margin-left: var(--sp-4);
}

.metrica__valor {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: clamp(1.25rem, 1.05rem + 0.85vw, 1.75rem);
  line-height: 1.1;
  letter-spacing: var(--tracking-display);
  color: var(--claridad);
  overflow-wrap: normal;    /* nunca partir una cifra a la mitad */
  word-break: keep-all;
}

.metrica__etiqueta {
  margin-top: var(--sp-2);
  font-size: var(--fs-xs);
  line-height: 1.35;
  color: var(--text-muted);
}

/* En escritorio la franja es el pie del hero y lo que sostiene visualmente el
   titular. Con las cifras a 28px se leía como una nota al pie: el peso lo tenía
   el botón y las tres cifras quedaban de relleno. Sube solo el valor, no la
   etiqueta — si suben las dos, el bloque compite con el h1. */
@media (min-width: 1024px) {
  .metricas { margin-top: var(--sp-8); padding-top: var(--sp-6); }

  /* El separador NO se agranda con el resto. La franja vive dentro de la
     columna de texto del hero (620px), así que cada cifra dispone de unos
     175px: cada píxel que se le da al divisor se le quita a la cifra, y a
     32px de separación «3 zonas» (la cifra que hubo hasta octubre de 2026) se
     partía en dos líneas. Hoy la más larga es «Chile», pero el límite sigue
     valiendo para cualquier cifra de siete caracteres. Una cifra partida
     es exactamente lo que el chequeo de titulares prohíbe. */
  .metricas > * + * { padding-left: var(--sp-5); margin-left: var(--sp-5); }

  /* Tope 36px por lo mismo: es el cuerpo más grande con el que la cifra más
     larga de la portada («3 zonas») entra en una línea. */
  .metrica__valor { font-size: clamp(2rem, 1.556rem + 0.694vw, 2.25rem); }
}

/* -----------------------------------------------------------------------------
   LISTA FLUIDA — el patrón que reemplaza a las grillas de tarjetas
   -------------------------------------------------------------------------- */
/* Una fila = ícono en círculo con tinte + título + subtítulo + chevron, separada
   de la siguiente por una línea de 1px. Sirve para servicios, riesgos,
   segmentos, requisitos y vías de contacto: seis figuras que antes se resolvían
   con cuatro componentes distintos (.card, .step, .checks, .pathswitch) y que
   en pantalla se leían como cuatro lenguajes en una misma página. */
.lista {
  list-style: none;
  padding: 0;
  margin: 0;
}

.lista > li { border-top: 1px solid var(--divisor); }
.lista > li:first-child { border-top: 0; }

.lista__item {
  display: grid;
  grid-template-columns: var(--circulo-icono) minmax(0, 1fr) auto;
  gap: var(--sp-4);
  align-items: center;
  min-height: 64px;
  padding-block: var(--sp-4);
  color: inherit;
  text-decoration: none;
  -webkit-tap-highlight-color: transparent;
  transition: color var(--dur-fast) var(--ease-out);
}

/* Sin chevron el hueco de la tercera columna descuadraba el texto respecto de
   las filas que sí lo llevan. */
.lista__item--simple { grid-template-columns: var(--circulo-icono) minmax(0, 1fr); }

.lista__icono {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--circulo-icono);
  height: var(--circulo-icono);
  border-radius: 50%;
  background: var(--tinte-royal);
  color: var(--royal-300);      /* 7.50:1 sobre el círculo con tinte */
  flex: none;
}

.lista__icono svg { width: 20px; height: 20px; }

/* min-width: 0 — sin esto un título largo sin espacios estira la columna y
   empuja al chevron fuera de la fila. */
.lista__texto { min-width: 0; }

/* El título puede venir como <span> o como <h3> según lo pida el esquema de
   encabezados de la página: los estilos se declaran completos para que el h3
   no herede el peso 800 ni la tipografía display de base.css. */
.lista__t {
  display: block;
  font-family: var(--font-body);
  font-size: var(--fs-fila);
  font-weight: 500;
  line-height: 1.35;
  letter-spacing: 0;
  color: var(--claridad);
  text-wrap: pretty;
  transition: color var(--dur-fast) var(--ease-out);
}

.lista__d {
  display: block;
  margin-top: 3px;
  font-size: var(--fs-xs);
  line-height: 1.45;
  color: var(--text-muted);
}

.lista__item .chev { color: var(--text-subtle); flex: none; transition: color var(--dur-fast) var(--ease-out); }

a.lista__item:hover .lista__t,
a.lista__item:focus-visible .lista__t { color: var(--royal-300); }
a.lista__item:hover .chev { color: var(--royal-300); }

/* Variante de verificación: el ícono es un check y no hay destino al que ir. */
.lista--checks .lista__icono { color: var(--royal-300); }

@media (min-width: 1024px) {
  /* Dos columnas donde hay 6 o más ítems. Los dos primeros pierden el divisor
     superior porque ambos son primera fila. */
  .lista--2col {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: var(--sp-8);
  }
  .lista--2col > li:nth-child(-n+2) { border-top: 0; }
}

/* -----------------------------------------------------------------------------
   LÍNEA DE TIEMPO — compromisos, proceso, postulación
   -------------------------------------------------------------------------- */
/* El nodo numera visualmente, así que los pasos NO llevan "01 ·" escrito. El
   primero va relleno en royal para marcar el punto de entrada; el resto usa el
   mismo tinte que los íconos de lista. */
.hitos { list-style: none; padding: 0; margin: 0; display: grid; gap: var(--sp-6); }

.hitos > li {
  position: relative;
  display: grid;
  grid-template-columns: var(--nodo) minmax(0, 1fr);
  gap: var(--sp-4);
}

/* La línea une el nodo de esta fila con el de la siguiente. Va en ::before del
   propio ítem —no en un elemento aparte— para que el último no la dibuje. */
.hitos > li:not(:last-child)::before {
  content: '';
  position: absolute;
  top: var(--nodo);
  bottom: calc(-1 * var(--sp-6));
  left: calc(var(--nodo) / 2 - 1px);
  width: 2px;
  background: rgba(107, 128, 254, 0.3);
}

.hitos__nodo {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--nodo);
  height: var(--nodo);
  border-radius: 50%;
  background: var(--tinte-royal);
  color: var(--royal-300);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-sm);
  flex: none;
}

.hitos > li:first-child .hitos__nodo {
  background: var(--royal-500);
  color: var(--text-on-royal);   /* 5.13:1 */
}

.hitos__nodo svg { width: 20px; height: 20px; }

.hitos__t {
  font-family: var(--font-display);
  font-size: var(--fs-h3);
  font-weight: 700;
  line-height: 1.25;
  padding-top: 0.35em;   /* alinea la primera línea con el centro del nodo */
}

.hitos__d {
  margin-top: var(--sp-2);
  font-size: var(--fs-sm);
  color: var(--text-muted);
}

@media (min-width: 1024px) {
  /* En escritorio la línea de tiempo NO se pasa a columnas: se mantiene
     vertical con más aire. Partirla en dos rompe la lectura secuencial, que es
     lo único que este patrón aporta sobre una lista. */
  .hitos { gap: var(--sp-7); }
  .hitos > li:not(:last-child)::before { bottom: calc(-1 * var(--sp-7)); }
}

/* -----------------------------------------------------------------------------
   ACORDEÓN / FAQ — <details> nativo, funciona sin JS
   -------------------------------------------------------------------------- */
.faq { display: grid; gap: 0; }

.faq details {
  border: 0;
  border-bottom: 1px solid var(--divisor);
  background: none;
}

.faq summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  min-height: 56px;
  padding: var(--sp-4) 0;
  font-family: var(--font-body);
  font-weight: 500;
  font-size: var(--fs-fila);
  cursor: pointer;
  list-style: none;
  -webkit-tap-highlight-color: transparent;
}

.faq summary::-webkit-details-marker { display: none; }

.faq summary::after {
  content: '';
  flex: none;
  width: 10px; height: 10px;
  border-right: 2px solid var(--royal-300);
  border-bottom: 2px solid var(--royal-300);
  rotate: 45deg;
  margin-top: -4px;
  transition: rotate var(--dur) var(--ease-out);
}

.faq details[open] summary::after { rotate: 225deg; margin-top: 4px; }

.faq__body { padding: 0 0 var(--sp-5); color: var(--text-muted); font-size: var(--fs-sm); }

/* -----------------------------------------------------------------------------
   FORMULARIOS
   -------------------------------------------------------------------------- */
.form { display: grid; gap: var(--sp-5); }
.form__row { display: grid; gap: var(--sp-5); }

@media (min-width: 640px) { .form__row--2 { grid-template-columns: 1fr 1fr; } }

.field { display: flex; flex-direction: column; gap: var(--sp-2); }

/* Etiqueta en Inter, caja de oración. Antes iba en monoespaciada, mayúsculas y
   con tracking: catorce etiquetas gritadas es lo que hacía que el formulario
   pareciera un formulario de trámite. */
.field label {
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--text-muted);
}

.field .opcional { color: var(--text-subtle); font-weight: 400; }

.input, .select, .textarea {
  width: 100%;
  min-height: 52px;
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--borde-campo);
  border-radius: var(--radius-campo);
  background: rgba(255, 255, 255, 0.05);
  color: var(--claridad);
  font-size: 16px; /* 16px evita el zoom automático en iOS Safari */
  line-height: 1.4;
  transition: border-color var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out);
  appearance: none;
  -webkit-appearance: none;
}

.textarea { min-height: 132px; resize: vertical; padding-top: var(--sp-4); }

.input::placeholder, .textarea::placeholder { color: var(--text-subtle); }

.input:focus, .select:focus, .textarea:focus {
  border-color: var(--royal-500);
  box-shadow: 0 0 0 3px rgba(61, 90, 254, 0.25);
  outline: none;
}

.input[aria-invalid="true"], .textarea[aria-invalid="true"], .select[aria-invalid="true"] {
  border-color: var(--danger);
}

.select {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='9' viewBox='0 0 14 9' fill='none'%3E%3Cpath d='M1 1l6 6 6-6' stroke='%23A8B3C7' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--sp-4) center;
  padding-right: var(--sp-8);
}

.select option { background: var(--marino-800); color: var(--claridad); }

.field__error {
  display: none;
  font-size: var(--fs-xs);
  color: var(--danger);
}

.field__error.is-visible { display: block; }

/* Envoltorio del consentimiento. Reproduce la caja de .field pero SIN heredar
   `.field label`, que impondría el tamaño y el color de una etiqueta al párrafo
   legal. Aquí solo hace falta un sitio donde mostrar el error. */
.consent { display: flex; flex-direction: column; gap: var(--sp-2); }
.field__hint { font-size: var(--fs-xs); color: var(--text-subtle); }

.checkbox {
  display: grid;
  grid-template-columns: 24px 1fr;
  gap: var(--sp-3);
  align-items: start;
  font-size: var(--fs-xs);
  line-height: 1.55;
  color: var(--text-muted);
  cursor: pointer;
  min-height: var(--tap-min);
  padding-block: var(--sp-2);
}

.checkbox input {
  width: 24px; height: 24px;
  margin-top: 0.1em;
  accent-color: var(--royal-500);
  cursor: pointer;
}

/* Honeypot anti-spam: oculto para humanos, visible para bots. Tiene que seguir
   siendo invisible para funcionar — no aplica tamaño táctil. */
.hp-field {
  position: absolute !important;
  left: -9999px;
  width: 1px; height: 1px;
  opacity: 0;
  pointer-events: none;
}

.form__status {
  display: none;
  padding: var(--sp-4) var(--sp-5);
  border-radius: var(--radius-campo);
  font-size: var(--fs-sm);
}

.form__status.is-visible { display: block; }
.form__status--ok { background: rgba(47, 191, 113, 0.12); color: #9BE9C0; }
.form__status--error { background: rgba(255, 92, 108, 0.12); color: #FFB3BB; }

.spinner {
  width: 16px; height: 16px;
  border: 2px solid rgba(255,255,255,0.35);
  border-top-color: #fff;
  border-radius: 50%;
  animation: spin 0.7s linear infinite;
}

@keyframes spin { to { transform: rotate(360deg); } }

/* -----------------------------------------------------------------------------
   MARCO DE EMBEDS DE GOHIGHLEVEL
   -------------------------------------------------------------------------- */
/* El calendario y el mapa viven en un iframe de otro dominio: su tipografía, su
   espaciado y sus colores se configuran en el builder de GoHighLevel, no aquí.
   Lo único que hace este marco es darles el radio y el fondo del sitio para que
   no se lean como un recorte pegado encima.

   SIN altura fija: form_embed.js de GHL mide el contenido y ajusta el alto del
   iframe. Un contenedor con `height` propia deja el calendario cortado o
   flotando en un hueco. */
.ghl-embed {
  width: 100%;
  padding: 12px;
  border-radius: var(--radius-media);
  overflow: hidden;
  background: var(--bg-elevated);
  min-height: 200px;
}

/* El widget de reservas se estiraba a todo el ancho del contenedor (1087px en
   un notebook) y se veía desproporcionado: es un calendario mensual, no una
   tabla de datos. Acotado y centrado se lee como un bloque intencional. */
[data-ghl-calendar] { max-width: 820px; margin-inline: auto; }

.ghl-embed iframe { width: 100%; border: 0; display: block; border-radius: var(--radius-campo); }

.ghl-embed__fallback {
  padding: var(--sp-6);
  text-align: center;
  color: var(--text-muted);
  font-size: var(--fs-sm);
}

/* Preventivo: las pistas de configuración citan rutas largas y sin espacios
   (assets/js/config.js, ghl.forms.cotizacion.url) que en 360px no caben.
   Solo se muestran en localhost, así que esto no afecta al visitante. */
.ghl-embed__fallback code {
  overflow-wrap: anywhere;
  word-break: break-word;
}

/* -----------------------------------------------------------------------------
   VIDEO
   -------------------------------------------------------------------------- */
.video-block {
  margin: 0 auto;
  max-width: 860px;
}

.video-block video {
  display: block;
  width: 100%;
  /* Sin esto el navegador usa el width/height del atributo como tamaño fijo
     antes de tener los metadatos, y en móvil se desborda. La proporción
     declarada reserva el hueco igual, sin el desbordamiento. */
  height: auto;
  aspect-ratio: 16 / 9;
  border-radius: var(--radius-media);
  background: var(--marino-900);
}

.video-block figcaption {
  margin-top: var(--sp-4);
  font-size: var(--fs-sm);
  color: var(--text-muted);
}

/* -----------------------------------------------------------------------------
   GALERÍA
   -------------------------------------------------------------------------- */
.gallery {
  display: grid;
  gap: var(--sp-5);
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

@media (min-width: 1024px) {
  .gallery { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--sp-6); }
}

.gallery figure {
  position: relative;
  margin: 0;
  border-radius: var(--radius-foto);
  overflow: hidden;
  aspect-ratio: 4 / 5;
  background: var(--marino-700);
}

/* La primera foto va a ancho completo y con máscara orgánica: ancla la retícula
   y evita que nueve rectángulos iguales se lean como una hoja de contactos.
   Usa la silueta ALTERNA: la del hero de la portada es la A, y repetir la misma
   curva en las dos fotos grandes del sitio delataría la plantilla. */
.gallery figure:first-child {
  grid-column: 1 / -1;
  aspect-ratio: 16 / 10;
  border-radius: var(--mascara-b);
}

@media (max-width: 400px) {
  .gallery figure:first-child { border-radius: 24px 76px 24px 76px; }
}

@media (min-width: 1024px) {
  .gallery figure:first-child { grid-column: span 2; aspect-ratio: 8 / 5; }
}

.gallery img { width: 100%; height: 100%; object-fit: cover; transition: transform var(--dur-slow) var(--ease-out); }
.gallery figure:hover img { transform: scale(1.04); }

.gallery figcaption {
  position: absolute;
  inset: auto 0 0 0;
  padding: var(--sp-6) var(--sp-4) var(--sp-4);
  background: var(--overlay-bottom);
  font-size: var(--fs-xs);
  font-weight: 500;
  color: var(--claridad);
}

/* LA FOTO GRANDE NECESITA MÁS RELLENO A LA IZQUIERDA QUE LAS DEMÁS.

   Es la única que usa la máscara orgánica, y en --mascara-b la esquina inferior
   IZQUIERDA tiene 120px de radio. La leyenda va pegada al fondo con
   `inset: auto 0 0 0`, así que el `overflow: hidden` de la figura le recorta el
   arranque: a la altura del texto, la curva se come unos 57px y en pantalla se
   leía «nal en terreno» en vez de «Personal en terreno».

   No se arregla quitando el recorte —la máscara ES el recorte— sino sacando el
   texto de la curva. */
.gallery figure:first-child figcaption { padding-left: 4.5rem; }

@media (max-width: 400px) {
  /* Ahí la máscara baja a 76px de radio y el relleno baja con ella. */
  .gallery figure:first-child figcaption { padding-left: 3rem; }
}

/* -----------------------------------------------------------------------------
   BREADCRUMB
   -------------------------------------------------------------------------- */
/* Oculta en móvil: ocupaba una línea completa sobre el h1 de cada página
   interior para repetir una ruta de dos niveles que el menú ya da. En
   escritorio no compite con nada y sí ayuda a ubicarse.
   El marcado sigue en el HTML, así que el schema BreadcrumbList y los lectores
   de pantalla no pierden nada: solo deja de pintarse. */
.crumbs { display: none; }

@media (min-width: 768px) {
  .crumbs {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-2);
    font-size: var(--fs-xs);
  }
}

.crumbs a { color: var(--text-subtle); text-decoration: none; }
.crumbs a:hover { color: var(--claridad); }
.crumbs span[aria-current] { color: var(--text-muted); }
/* --text-subtle, no --plomo: a 12.8px el token de marca daba 3.88:1 contra el
   marino, bajo los 4.5:1 que WCAG exige a un texto normal. --text-subtle da
   5.53:1 y es el color que el resto del texto secundario pequeño ya usa. */
.crumbs .sep { color: var(--text-subtle); }

.crumbs a,
.crumbs span[aria-current] {
  display: inline-flex;
  align-items: center;
  min-height: 32px;   /* WCAG 2.5.8 pide 24px: cumplen */
}

/* -----------------------------------------------------------------------------
   TARJETA CTA — la única tarjeta que queda en el sitio
   -------------------------------------------------------------------------- */
/* Radio asimétrico 24/24/24/6: la esquina viva de abajo a la izquierda es lo
   que la distingue de un rectángulo redondeado genérico y la ancla al lado por
   el que se lee.

   OJO CON LA PALABRA-ACENTO AQUÍ. El fondo es --azul-600, y sobre él:
     --royal-500  2.45:1   no cumple
     --royal-400  3.68:1   solo como texto grande
     --royal-300  5.73:1   cumple AA como texto normal
   Por eso .cta-tarjeta redefine .accent. Es el mismo problema que tenía la
   antigua banda CTA, resuelto por color en vez de por fondo: aquel bloque
   oscurecía la base hasta --marino-900 para salvar al royal-500. */
.cta-tarjeta {
  position: relative;
  padding: var(--sp-7) var(--sp-5);
  border-radius: var(--radius-card) var(--radius-card) var(--radius-card) 6px;
  background: var(--azul-600);
  overflow: hidden;
}

.cta-tarjeta .accent { color: var(--royal-300); }
.cta-tarjeta h2 { margin-bottom: var(--sp-4); }
.cta-tarjeta p { color: #D5DDEA; max-width: var(--measure-narrow); margin-bottom: var(--sp-6); }

@media (min-width: 1024px) {
  /* En PC la tarjeta pasa a horizontal: el texto a la izquierda y el botón a la
     derecha, alineado al centro. Apilada ocupaba 1160px de ancho con el
     contenido metido en el 40% izquierdo y el resto vacío — el bloque de cierre
     de CADA página se veía a medio llenar. */
  .cta-tarjeta {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    column-gap: var(--sp-8);
    padding: var(--sp-8) var(--sp-8);
  }

  .cta-tarjeta h2 { grid-column: 1; margin-bottom: var(--sp-3); }
  .cta-tarjeta p { grid-column: 1; margin-bottom: 0; max-width: 52ch; }

  /* El botón ocupa la segunda columna y las dos filas del texto. */
  .cta-tarjeta .btn {
    grid-column: 2;
    grid-row: 1 / -1;
    white-space: nowrap;
  }
}

/* -----------------------------------------------------------------------------
   AVISOS
   -------------------------------------------------------------------------- */
/* Descargo legal: texto pequeño y apagado bajo el bloque que acota. Sin caja,
   sin borde punteado y sin ícono de advertencia. Los dos que existen —el de la
   portada, que acota los compromisos de 60 minutos y 72 horas, y el de Nosotros,
   que aclara que la referencia normativa no es asesoría legal— están a la
   espera del visto bueno de un abogado por decisión del cliente. Se les cambió
   la presentación; el texto NO se toca. */
.aviso-legal {
  margin-top: var(--sp-5);
  padding-left: var(--sp-4);
  border-left: 2px solid var(--divisor);
  font-size: var(--fs-xs);
  line-height: 1.5;
  color: var(--text-subtle);
  max-width: var(--measure);
}

/* Aviso operativo: el bloque <noscript>. Este sí necesita destacar, porque
   avisa de algo que está roto para quien lo lee. */
.notice {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--sp-2);
  padding: var(--sp-4) var(--sp-5);
  border-radius: var(--radius-campo);
  background: rgba(244, 183, 64, 0.10);
  font-size: var(--fs-xs);
  color: var(--text-muted);
}

/* -----------------------------------------------------------------------------
   TABLA — solo en la página de cookies
   -------------------------------------------------------------------------- */
.table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; border-radius: var(--radius-campo); background: var(--bg-elevated); }

table { width: 100%; border-collapse: collapse; font-size: var(--fs-sm); min-width: 520px; }

thead th {
  text-align: left;
  padding: var(--sp-4) var(--sp-5);
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--claridad);
  border-bottom: 1px solid var(--divisor);
}

tbody td { padding: var(--sp-4) var(--sp-5); border-top: 1px solid var(--divisor); color: var(--text-muted); vertical-align: top; }

/* =============================================================================
   REDISEÑO FOTOGRÁFICO — septiembre 2026
   Tarjetas de servicio, pasos del proceso, collage, galería de portada y
   cierre con formulario. Ver CLAUDE.md §4ter: estas son las superficies que se
   sumaron a las tres del rediseño de agosto, y por qué.
   ========================================================================== */

/* --- Split con foto -----------------------------------------------------------
   .split--centro alinea las dos columnas al centro y NO pega el titular: el
   sticky de layout.css existe para titulares de dos líneas junto a una lista
   larga, y junto a una foto de alto parecido solo produce un salto raro. */
@media (min-width: 1024px) {
  .split--centro { align-items: center; }
  /* `relative` y NO `static`: también anula el sticky, pero la primera columna
     puede ser una FOTO, y su filete interior (::after con inset: 0) se ubica
     contra el ancestro posicionado más cercano. Con `static` ese ancestro
     pasaba a ser la sección entera y el filete dibujaba un marco redondeado
     alrededor de toda la banda. Mismo mecanismo que la trampa nº10.
     `top: auto` porque el `top` del sticky sigue declarado y, con `relative`,
     desplazaba la foto 108px hacia abajo, encima de la sección siguiente. */
  .split--centro > *:first-child { position: relative; top: auto; }
  .split--foto { grid-template-columns: minmax(0, 5fr) minmax(0, 6fr); }
  .split--collage { grid-template-columns: minmax(0, 5fr) minmax(0, 6fr); }
}

/* Foto del equipo (16:9): en móvil 4:3; en PC casi cuadrada junto al texto.
   El grupo está en la mitad izquierda del encuadre, de ahí el foco al 30%. */
/* En móvil el texto va ANTES que la foto: si no, la foto del hero y esta
   quedaban seguidas, dos bloques de imagen apilados con marino entre medio.
   16:9 es la proporción del archivo: en móvil no se recorta nada. */
.foto--personas { aspect-ratio: 16 / 9; }
.foto--personas img { object-position: 30% 50%; }
.split--foto > .foto { order: 2; }
@media (min-width: 1024px) {
  .foto--personas { aspect-ratio: 1 / 1; }
  .split--foto > .foto { order: 0; }
}

.foto--puesto { aspect-ratio: 16 / 10; }

/* Una cabecera de sección dentro de un split ya tiene el gap de la retícula
   como separación: su margin-bottom propio sumaba 24px más y en móvil dejaba
   la foto de Trabaja con nosotros flotando lejos del texto. */
.split--centro > .section__head { margin-bottom: 0; }
@media (min-width: 1024px) { .foto--puesto { aspect-ratio: 4 / 3; } }
.foto--puesto img { object-position: 30% 50%; }

/* --- Beneficios: tres puntos con ícono lineal -------------------------------
   Apilados en móvil; en fila desde 640px, donde cada uno cabe en dos líneas. */
.beneficios {
  list-style: none;
  padding: 0;
  margin: var(--sp-6) 0 0;
  display: grid;
  gap: var(--sp-4);
}

.beneficios li {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  font-size: var(--fs-sm);
  font-weight: 500;
  line-height: 1.35;
  color: var(--claridad);
}

.beneficios__icono {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: var(--circulo-icono);
  height: var(--circulo-icono);
  border-radius: 50%;
  background: var(--tinte-royal);
  color: var(--royal-300);
}

@media (min-width: 640px) {
  .beneficios { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .beneficios li { flex-direction: column; align-items: flex-start; }
}

/* --- Tarjetas de servicio ---------------------------------------------------
   Fondo --marino-900: más oscuro que el marino Y que la banda elevada, así la
   misma tarjeta se lee igual sobre .section--zona (portada) y sobre el marino
   (catálogo y páginas de servicio).

   Columnas explícitas, nunca auto-fit (§5): 1 en móvil, 2 desde 640px, 3 desde
   1024px. El 640 es nuevo fuera de formularios y está justificado: a 820px
   (iPad) una sola columna daba seis fotos de 780px de ancho, cinco pantallas
   de scroll para seis servicios. */
.tarjetas {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  gap: var(--sp-5);
  grid-template-columns: minmax(0, 1fr);
}

@media (min-width: 640px) { .tarjetas { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1024px) { .tarjetas { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--sp-6); } }

.tarjeta {
  display: flex;
  flex-direction: column;
  height: 100%;
  border-radius: var(--radius-card);
  overflow: hidden;
  background: var(--marino-900);
  border: 1px solid rgba(255, 255, 255, 0.08);
  color: inherit;
  text-decoration: none;
  -webkit-tap-highlight-color: transparent;
  transition: transform var(--dur) var(--ease-out),
              border-color var(--dur) var(--ease-out),
              box-shadow var(--dur) var(--ease-out);
}

.tarjeta__foto {
  position: relative;
  display: block;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  background: var(--marino-700);
}

@media (min-width: 640px) { .tarjeta__foto { aspect-ratio: 16 / 10; } }

.tarjeta__foto picture { display: block; width: 100%; height: 100%; }
.tarjeta__foto img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--dur-slow) var(--ease-out);
}

/* Funde el borde inferior de la foto con el cuerpo de la tarjeta: sin esto la
   foto termina en un corte recto contra el marino, justo donde se monta el
   círculo del ícono. */
.tarjeta__foto::after {
  content: '';
  position: absolute;
  inset: 45% 0 0 0;
  background: linear-gradient(to top, var(--marino-900), rgba(6, 11, 24, 0));
  pointer-events: none;
}

.tarjeta__cuerpo {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  flex: 1;
  padding: var(--sp-7) var(--sp-5) var(--sp-5);
}

/* El círculo del ícono monta sobre el borde de la foto. Royal relleno con
   blanco encima: 5.13:1, el mismo par que el botón primario. */
.tarjeta__icono {
  position: absolute;
  top: calc(-1 * var(--circulo-icono) / 2);
  left: var(--sp-5);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--circulo-icono);
  height: var(--circulo-icono);
  border-radius: 50%;
  background: var(--royal-500);
  color: var(--text-on-royal);
  box-shadow: 0 0 0 4px var(--marino-900);
}

.tarjeta__icono svg { width: 20px; height: 20px; }

.tarjeta__t {
  font-family: var(--font-display);
  font-size: var(--fs-h3);
  font-weight: 700;
  line-height: 1.25;
  color: var(--claridad);
}

.tarjeta__d {
  font-size: var(--fs-sm);
  line-height: 1.5;
  color: var(--text-muted);
}

/* margin-top: auto empuja «Ver más» al fondo: con descripciones de largo
   distinto, los seis enlaces quedan alineados en la misma línea. */
.tarjeta__mas {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  margin-top: auto;
  padding-top: var(--sp-3);
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--royal-300);
}

.tarjeta__mas svg { transition: transform var(--dur) var(--ease-out); }

.tarjeta:hover,
.tarjeta:focus-visible {
  border-color: rgba(107, 128, 254, 0.4);
  box-shadow: var(--shadow-lg);
}

@media (hover: hover) and (prefers-reduced-motion: no-preference) {
  .tarjeta:hover { transform: translateY(-4px); }
  .tarjeta:hover .tarjeta__foto img { transform: scale(1.04); }
  .tarjeta:hover .tarjeta__mas svg { transform: translateX(4px); }
}

/* Encuadre por servicio: las fotos se generan en 4:3 y la tarjeta es 16:10,
   así que se recorta un poco de alto. El foco deja al sujeto dentro. */
.tarjeta[href$="guardias-os10.html"] img { object-position: 35% 40%; }
.tarjeta[href$="asesoria-y-estudio-de-seguridad.html"] img { object-position: 50% 35%; }

/* --- Pasos del proceso ------------------------------------------------------ */
.pasos {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  gap: var(--sp-4);
  grid-template-columns: minmax(0, 1fr);
}

@media (min-width: 640px) { .pasos { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1024px) { .pasos { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--sp-6); } }

.paso {
  position: relative;
  padding: var(--sp-6) var(--sp-5);
  border-radius: var(--radius-card);
  background: var(--bg-elevated);
  border: 1px solid rgba(255, 255, 255, 0.06);
}

.paso__cabeza {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: var(--sp-5);
}

/* royal-400 sobre --bg-elevated: 5.15:1. */
.paso__num {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: var(--fs-h2);
  line-height: 1;
  letter-spacing: var(--tracking-display);
  color: var(--royal-400);
}

.paso__icono {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--circulo-icono);
  height: var(--circulo-icono);
  border-radius: 50%;
  background: var(--tinte-royal);
  color: var(--royal-300);
}

.paso__icono svg { width: 20px; height: 20px; }

.paso__t {
  font-family: var(--font-display);
  font-size: var(--fs-h3);
  font-weight: 700;
  line-height: 1.25;
}

.paso__d {
  margin-top: var(--sp-2);
  font-size: var(--fs-sm);
  color: var(--text-muted);
}

/* La primera etapa lleva el borde en royal: marca el punto de entrada, igual
   que el primer nodo relleno de la línea de tiempo. */
.paso:first-child { border-color: rgba(107, 128, 254, 0.45); }

/* Flecha entre etapas, solo cuando están en una fila. Es un chevron dibujado
   con dos bordes y centrado en el hueco entre tarjetas. */
@media (min-width: 1024px) {
  .paso:not(:last-child)::after {
    content: '';
    position: absolute;
    z-index: 1;
    top: 50%;
    right: calc(-1 * var(--sp-6) / 2 - 5px);
    width: 10px;
    height: 10px;
    border-top: 2px solid var(--royal-400);
    border-right: 2px solid var(--royal-400);
    transform: translateY(-50%) rotate(45deg);
  }
}

/* --- Collage de cobertura ---------------------------------------------------
   Una foto grande a la izquierda que ocupa las dos filas y dos chicas
   apiladas. Radios distintos a propósito —la grande con la esquina viva de la
   tarjeta de cierre— para que no se lea como tres recortes de una plantilla. */
.collage {
  display: grid;
  grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
  grid-template-rows: repeat(2, minmax(0, 1fr));
  gap: var(--sp-3);
  aspect-ratio: 4 / 3;
}

@media (min-width: 1024px) { .collage { aspect-ratio: 5 / 4; } }

.collage .collage__a { grid-row: 1 / 3; border-radius: var(--radius-media) var(--radius-media) var(--radius-media) 8px; }
.collage .collage__b,
.collage .collage__c { border-radius: var(--radius-foto); }

.collage__a img { object-position: 55% 50%; }
.collage__b img { object-position: 50% 48%; }
.collage__c img { object-position: 42% 50%; }

/* --- Galería de portada -----------------------------------------------------
   Una grande (2×2) y dos apaisadas a su lado. Sin textos encima.
   Eran cinco hasta el 25 de septiembre de 2026: IMG_2626 e IMG_2636 salieron
   a pedido del cliente porque ya son las fotos de Monitoreo y de Escolta en las
   tarjetas de servicio, y en la portada se leían repetidas. */
.galeria-home {
  display: grid;
  gap: var(--sp-3);
  grid-template-columns: repeat(2, minmax(0, 1fr));
  grid-auto-rows: clamp(130px, 30vw, 220px);
}

.galeria-home figure:first-child { grid-column: 1 / -1; grid-row: span 2; }

@media (min-width: 1024px) {
  .galeria-home {
    grid-template-columns: repeat(4, minmax(0, 1fr));
    /* 19vw y no 15vw: con dos fotos apaisadas junto a la grande, filas más
       bajas dejaban casillas de 2,9:1 y la foto de la torre perdía el auto
       por abajo. A 1440px quedan en ~2,3:1. */
    grid-auto-rows: clamp(200px, 19vw, 300px);
    gap: var(--sp-4);
  }
  .galeria-home figure:first-child { grid-column: span 2; }
  .galeria-home figure:not(:first-child) { grid-column: span 2; }
}

.galeria-home img { transition: transform var(--dur-slow) var(--ease-out); }
/* Foco por foto: en la torre (IMG_2624) el guardia está arriba y el auto
   abajo; al 62% entran los dos. WA0037 es vertical y el supervisor está a
   media altura. */
.galeria-home figure:nth-child(2) img { object-position: 50% 62%; }
.galeria-home figure:nth-child(3) img { object-position: 50% 40%; }

@media (hover: hover) and (prefers-reduced-motion: no-preference) {
  .galeria-home figure:hover img,
  .collage figure:hover img { transform: scale(1.03); }
  .collage img { transition: transform var(--dur-slow) var(--ease-out); }
}

/* --- Cierre con formulario (portada) ----------------------------------------
   Móvil: texto arriba y formulario debajo. PC: texto a la izquierda, centrado
   en alto, y formulario a la derecha sobre una franja un poco más oscura.

   Llevó foto (IMG_2633) hasta el 25 de septiembre de 2026. Se quitó a pedido
   del cliente: es la misma foto de la tarjeta de Control de acceso, y en la
   portada ya se repetía demasiado. Sin foto, la columna izquierda se sostiene
   con la lista de tres garantías de la visita. */
.cierre {
  display: grid;
  border-radius: var(--radius-media);
  overflow: hidden;
  background: var(--bg-elevated);
  border: 1px solid rgba(255, 255, 255, 0.06);
}

.cierre__texto { padding: var(--sp-7) var(--sp-5) 0; }
.cierre__texto h2 { margin-bottom: var(--sp-3); }
.cierre__texto p { color: var(--text-muted); max-width: var(--measure-narrow); }
.cierre__texto .lista { margin-block: var(--sp-5); }

.cierre__form { padding: var(--sp-5) var(--sp-5) var(--sp-6); }

@media (min-width: 1024px) {
  .cierre { grid-template-columns: minmax(0, 5fr) minmax(0, 6fr); }

  .cierre__texto {
    align-self: center;
    padding: var(--sp-8) var(--sp-7);
  }

  .cierre__form {
    padding: var(--sp-8) var(--sp-7);
    background: rgba(6, 11, 24, 0.35);
    border-left: 1px solid rgba(255, 255, 255, 0.06);
  }
}

/* --- Galería: encuadre por foto --------------------------------------------
   La página galería usa casillas 4:5 (y 8:5 la destacada). Las fotos verticales
   y las que tienen al sujeto a un costado necesitan su propio foco. */
.gallery__foto--2638 img,
.gallery__foto--2639 img { object-position: 28% 50%; }
.gallery__foto--2630 img { object-position: 60% 55%; }
.gallery__foto--wa0044 img { object-position: 35% 50%; }
.gallery__foto--2642 img { object-position: 30% 50%; }

/* -----------------------------------------------------------------------------
   ENTRADA AL HACER SCROLL
   -------------------------------------------------------------------------- */
/* 12px y 250ms. Antes eran 18px y 600ms: a esa duración el bloque todavía se
   estaba acomodando cuando el pulgar ya había seguido bajando, y en móvil se
   percibía como lentitud del sitio, no como una animación. */
@media (prefers-reduced-motion: no-preference) {
  .reveal {
    opacity: 0;
    transform: translateY(12px);
    transition: opacity 250ms var(--ease-out), transform 250ms var(--ease-out);
  }
  .reveal.is-in { opacity: 1; transform: none; }
  .reveal[data-delay="1"] { transition-delay: 60ms; }
  .reveal[data-delay="2"] { transition-delay: 120ms; }
  .reveal[data-delay="3"] { transition-delay: 180ms; }
  .reveal[data-delay="4"] { transition-delay: 240ms; }
}

/* Sin JS: todo visible */
.no-js .reveal { opacity: 1; transform: none; }

/* -----------------------------------------------------------------------------
   UTILIDADES — evitan estilos en línea para poder endurecer la CSP
   -------------------------------------------------------------------------- */
.u-mt-4 { margin-top: var(--sp-4); }
.u-mt-5 { margin-top: var(--sp-5); }
.u-mt-6 { margin-top: var(--sp-6); }
.u-mt-7 { margin-top: var(--sp-7); }
.u-mb-6 { margin-bottom: var(--sp-6); }
.u-mx-auto { margin-inline: auto; }
.u-text-center { text-align: center; }
.u-center { justify-content: center; }
.u-pt-header { padding-top: calc(var(--header-h) + var(--safe-top) + var(--section-y)); }

.u-center-screen {
  display: flex;
  align-items: center;
  min-height: 64svh;
}

.u-text-center .lead { max-width: var(--measure-narrow); }

/* Ícono de confirmación de gracias.html: check blanco sobre royal relleno. */
.icono-exito {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 64px; height: 64px;
  border-radius: 50%;
  background: var(--royal-500);
  color: var(--text-on-royal);
  margin-bottom: var(--sp-5);
}

.icono-exito svg { width: 30px; height: 30px; }

/* -----------------------------------------------------------------------------
   PROSA — páginas legales
   -------------------------------------------------------------------------- */
.prose { max-width: var(--measure-wide); color: var(--text-muted); }
.prose h2 {
  font-size: var(--fs-h3);
  color: var(--claridad);
  margin-top: var(--sp-7);
  margin-bottom: var(--sp-4);
}
.prose h2:first-of-type { margin-top: var(--sp-5); }
.prose p { margin-bottom: var(--sp-4); font-size: var(--fs-sm); }
.prose code {
  font-family: var(--font-mono);
  font-size: 0.85em;
  padding: 0.15em 0.4em;
  border-radius: 6px;
  background: rgba(255,255,255,0.07);
  color: var(--royal-300);
}
.prose .table-wrap { margin-block: var(--sp-5); }

/* -----------------------------------------------------------------------------
   OBJETIVOS TÁCTILES — WCAG 2.5.8 (mínimo 24px; buscamos 44px donde se pueda)
   -------------------------------------------------------------------------- */
.footer__legal a {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap-min);
  padding-inline: 2px;
}
