/* =================================================================
   COMPONENTES — piezas reutilizables en cualquier ruta
   ================================================================= */

/* =================================================================
   1. BOTONES Y ENLACES
   ================================================================= */

.btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.55rem;
  min-height: var(--tap);
  padding: 0.95rem 1.7rem;
  font-family: var(--font-body);
  font-size: var(--label-lg);
  font-weight: var(--weight-bold);
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  border-radius: var(--radius-sm);
  overflow: hidden;
  z-index: 0;
  transition: color var(--transition), border-color var(--transition);
}
.btn svg { transition: transform var(--transition); }
.btn:hover svg { transform: translateX(4px); }
/* El relleno entra desde la izquierda: el gesto del sistema */
.btn::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: var(--z-below);
  transform: translateX(-101%);
  transition: transform var(--dur-slow) var(--ease-out);
}
.btn:hover::before { transform: translateX(0); }

.btn-accent { background: var(--color-accent); color: var(--color-white); }
.btn-accent::before { background: var(--color-primary); }
.btn-dark { background: var(--color-primary); color: var(--color-text-inverse); }
.btn-dark::before { background: var(--color-accent); }
.btn-light { background: var(--color-surface); color: var(--color-primary); }
.btn-light::before { background: var(--color-primary); }
.btn-light:hover { color: var(--color-text-inverse); }
.btn-block { width: 100%; }

.btn-play {
  display: inline-flex;
  align-items: center;
  gap: 0.8rem;
  min-height: var(--tap);
  font-size: var(--label-lg);
  font-weight: var(--weight-bold);
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--color-white);
  transition: color var(--transition);
}
.play-ring {
  display: grid;
  place-items: center;
  width: var(--size-ring);
  height: var(--size-ring);
  border: var(--border-medium) solid rgb(var(--rgb-white) / .55);
  border-radius: 50%;
  transition: background var(--transition), border-color var(--transition), transform var(--transition);
}
.btn-play:hover .play-ring {
  background: var(--color-accent);
  border-color: var(--color-accent);
  transform: scale(1.08);
}

.link-arrow {
  display: inline-flex;
  align-items: center;
  gap: var(--space-xs);
  padding-bottom: 3px;
  font-size: var(--label-lg);
  font-weight: var(--weight-bold);
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--color-accent-ink);
  border-bottom: 2px solid transparent;
  transition: border-color var(--transition), gap var(--transition);
}
.link-arrow:hover { border-color: var(--color-accent-ink); gap: 0.85rem; }
.link-arrow.sm { font-size: var(--label-md); }

/* Fila de enlaces al pie de una sección. Cuando hay dos salidas de una
   misma sección (la principal y la completa), van en la misma línea y a
   la misma altura, no una debajo de la otra como si fueran una lista. */
.link-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-sm) var(--space-lg);
}

/* =================================================================
   2. FIGURA — MEJORA A + B
   -----------------------------------------------------------------
   Todo lo que sea una imagen del sitio pasa por acá.

   B · proporción en vez de altura fija. El boceto fijaba 11 alturas
       distintas en px (130 / 250 / 380 / 520…). Eso genera CLS y
       obliga a recortar cada foto a medida antes de subirla.
       Ahora se declara la proporción y el navegador reserva el
       espacio antes de que la imagen cargue.

   A · un solo grado fotográfico para todo el sitio, más grano
       reforzado. No sabemos si va a llegar un render profesional o
       una foto de celular a contraluz: el tratamiento común los
       acerca. Sin esto, una galería con material mixto se ve como
       tres sitios distintos pegados.

   --object-position sale del JSON: una fachada mal encuadrada se
   corrige con un dato, no con CSS ni pidiéndole otra foto al cliente.
   ================================================================= */

.figure {
  position: relative;
  display: block;
  overflow: hidden;
  aspect-ratio: var(--ratio, var(--ratio-obra));
  background-color: var(--color-bg-alt);
}
/* El <img> real SIEMPRE lleva loading="lazy" y decoding="async" en el HTML
   (ver ejemplo en obras.css y ARQUITECTURA.md), salvo el que sea el LCP de
   la página — un hero, por ejemplo — que va eager + fetchpriority="high".
   No hay nada que hacer acá en CSS para eso; queda documentado porque es
   parte del contrato del componente, no un detalle suelto de cada página. */
.figure img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: var(--object-position);
  filter: var(--img-grade);
  transition: transform var(--dur-slower) var(--ease-out), filter var(--transition);
}

/* Grano sobre la imagen. Es el nivelador: sube el ruido de la foto
   buena hasta la textura de la foto floja. */
.figure::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: var(--grain-opacity-img);
  background-image: var(--grain-svg);
  background-size: var(--grain-size) var(--grain-size);
}

/* Velo inferior, para cuando va texto encima de la imagen */
.figure.scrim::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: var(--z-base);
  background: var(--scrim-card);
}

/* Proporciones */
.figure.r-hero    { --ratio: var(--ratio-hero); }
.figure.r-pano    { --ratio: var(--ratio-pano); }
.figure.r-obra    { --ratio: var(--ratio-obra); }
.figure.r-panel   { --ratio: var(--ratio-panel); }
.figure.r-etapa   { --ratio: var(--ratio-etapa); }
.figure.r-retrato { --ratio: var(--ratio-retrato); }
.figure.r-avatar  { --ratio: var(--ratio-avatar); border-radius: 50%; }
.figure.r-plano   { --ratio: var(--ratio-plano); }

/* Material flojo: se puede marcar desde el JSON por foto */
.figure.grade-strong img { filter: var(--img-grade-strong); }

/* =================================================================
   3. FICHA TÉCNICA — MEJORA C
   -----------------------------------------------------------------
   La capa NO fotográfica del sistema.

   De las 16 obras, las de 2014–2018 probablemente nunca tengan una
   buena foto. Si la tarjeta depende de la imagen, esas obras quedan
   como un error. Pero AP sí tiene el dato: año, unidades, zona,
   tipo. Este componente convierte el dato en el peso visual.

   Es además lo más honesto con lo que vende la empresa: trayectoria
   medible, no fotos lindas.

   auto-fit en vez de repeat(4): el boceto asumía exactamente 4
   celdas, y varias obras tienen unidades o superficie en null.
   Ahora funciona con 1, 2, 3 o 4 sin tocar nada.
   ================================================================= */

/* Flex y no grid: las líneas de 1px son el fondo del contenedor asomando
   por el gap, así que cualquier hueco de la grilla se ve como un bloque
   gris vacío. Con auto-fit eso pasaba en cuanto la cantidad de celdas no
   era múltiplo de las columnas — cuatro datos en tres columnas dejaban
   media fila muerta, en teléfono, en las cuatro fichas del sitio. En
   flex la última fila reparte el sobrante entre las celdas que hay y no
   queda hueco que tapar, con 1, 2, 3 o 4 datos. */
.ficha {
  display: flex;
  flex-wrap: wrap;
  gap: var(--border-hair);
  background: var(--color-line-soft);
  border: var(--border-hair) solid var(--color-line-soft);
}
/* display:flex le gana al display:none que el navegador le da a [hidden],
   así que hay que declararlo. Lo necesita la ficha de obra: una obra sin
   unidades ni superficie tiene una sola cifra y el bloque no se muestra. */
.ficha[hidden] { display: none; }
.ficha li {
  flex: 1 1 var(--col-ficha);
  background: var(--color-surface);
  padding: 0.85rem 0.9rem;
}
/* line-height desde token y no el 1 escrito a mano que tenía el boceto:
   la mayoría de los valores son un número corto y de una línea, pero
   algunos son texto ("≈50 m² por unidad") y con interlínea 1 las dos
   líneas se tocaban. --leading-display es la interlínea de título del
   sistema y en una sola línea se ve idéntica. */
.ficha strong {
  display: block;
  font-family: var(--font-display);
  font-size: var(--text-num-md);
  font-weight: var(--weight-black);
  line-height: var(--leading-display);
  letter-spacing: var(--track-snug);
  color: var(--color-primary);
}
.ficha span {
  font-size: var(--label-xs);
  font-weight: var(--weight-semi);
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--color-text-muted);
}
/* ---------- Celda de texto ----------
   .ficha está hecha para cifras: el número entra en Chivo 900 al tamaño
   de un número y ocupa el lugar que tendría un icono. Pero la ficha de
   obra de la trayectoria muestra cuatro datos y sólo dos son números
   (año y unidades): tipo y zona son texto, y "Desarrollo residencial" a
   --text-num-md se parte en tres renglones y tapa la celda de al lado.

   La celda de texto conserva la familia y la caja —misma grilla, mismo
   label abajo, misma altura— y sólo baja el peso y el tamaño del valor
   al del nombre de obra. Es la diferencia entre una cifra que se compara
   y una palabra que se lee. */
.ficha .dato-texto strong {
  font-size: var(--text-nombre);
  font-weight: var(--weight-bold);
  line-height: var(--leading-snug);
}

/* Sobre fondo oscuro */
.ficha.on-dark { background: var(--line-inv-2); border-color: var(--line-inv-2); }
.ficha.on-dark li { background: var(--color-primary); }
.ficha.on-dark strong { color: var(--color-text-inverse); }
.ficha.on-dark span { color: var(--ink-inv-3); }

/* ---------- Número suelto grande ----------
   Mismo gesto, sin grilla. Franja de datos, bloques de cifras. */
.cifra {
  display: block;
  font-family: var(--font-display);
  font-weight: var(--weight-black);
  line-height: 1;
  letter-spacing: var(--track-snug);
}
.cifra-label {
  display: block;
  margin-top: 0.3rem;
  font-size: var(--label-sm);
  font-weight: var(--weight-semi);
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--color-text-muted);
}

/* ---------- Etiqueta suelta ---------- */
.tag {
  display: inline-block;
  padding: 0.25rem 0.5rem;
  font-size: var(--label-xs);
  font-weight: var(--weight-bold);
  letter-spacing: var(--track-wider);
  text-transform: uppercase;
  color: var(--color-accent-ink);
  background: var(--wash-accent);
}
.tag.solid { background: var(--color-accent); color: var(--color-white); }
.tag.dark { background: var(--color-primary); color: var(--color-text-inverse); }

/* =================================================================
   4. FRANJA DE DATOS
   ================================================================= */

.statband {
  background: var(--color-primary);
  border-bottom: var(--border-mark) solid var(--color-accent);
}
.statband-list { display: grid; grid-template-columns: 1fr 1fr; }
.statband-list li {
  display: flex;
  align-items: center;
  gap: 0.8rem;
  padding: 1.35rem 0.4rem;
  border-bottom: var(--border-hair) solid var(--line-inv-2);
}
.statband-list li:nth-child(odd) { border-right: var(--border-hair) solid var(--line-inv-2); }
.statband-list li:nth-last-child(-n+2) { border-bottom: 0; }

.stat-ico {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: var(--size-badge);
  height: var(--size-badge);
  border: var(--border-medium) solid var(--line-inv-1);
  border-radius: 50%;
  color: var(--color-accent);
}
.stat-ico svg { width: var(--size-ico-md); height: var(--size-ico-md); }

.statband-list strong {
  display: block;
  font-family: var(--font-display);
  font-size: var(--text-num-sm);
  font-weight: var(--weight-black);
  line-height: 1.1;
  letter-spacing: var(--track-snug);
  text-transform: uppercase;
  color: var(--color-text-inverse);
}
.statband-list span {
  display: block;
  margin-top: 2px;
  font-size: var(--label-sm);
  font-weight: var(--weight-semi);
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--ink-inv-3);
}

/* ---------- Franja de cifras, sin iconos ----------
   Variante de .statband para cuando el dato tiene que pesar solo.
   .statband-list acompaña cada dato con un .stat-ico en un aro: sirve
   cuando el dato es una condición ("Director de Obra propio"). Cuando
   los datos SON números —2014, 16, +140— el aro los achica y les agrega
   una decoración que no aporta. Acá el número ocupa el lugar del icono.

   tabular-nums: los tres números se leen en columna y se comparan.
   Con cifras proporcionales el 1 angosto desalinea la fila. */
.cifras-row {
  display: grid;
  gap: var(--border-hair);
  background: var(--line-inv-2);
}
.cifras-row li {
  padding: var(--space-md) var(--space-sm);
  background: var(--color-primary);
}
.cifras-row .cifra {
  font-size: var(--text-num-lg);
  font-variant-numeric: tabular-nums;
  color: var(--color-text-inverse);
}
.cifras-row .cifra-label { color: var(--ink-inv-3); }

/* Sobre fondo claro (misma pieza, otra sección) */
.cifras-row.on-light { background: var(--color-line-soft); }
.cifras-row.on-light li { background: var(--color-surface); }
.cifras-row.on-light .cifra { color: var(--color-primary); }
.cifras-row.on-light .cifra-label { color: var(--color-text-muted); }

/* =================================================================
   5. LÍNEAS DE NEGOCIO (ex "sectores")
   -----------------------------------------------------------------
   El boceto tenía 6 tarjetas y las reglas de borde estaban atadas a
   nth-child(3n) y repeat(6,1fr). AP vende DOS cosas. Ahora la grilla
   es auto-fit y los bordes no dependen de la cantidad.
   ================================================================= */

.construimos { padding: var(--space-xl) 0; background: var(--color-surface); }

.sector-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  border-top: var(--border-hair) solid var(--color-line-soft);
  border-left: var(--border-hair) solid var(--color-line-soft);
}
.sector {
  display: grid;
  align-content: start;
  padding: 1.6rem 1.2rem;
  border-right: var(--border-hair) solid var(--color-line-soft);
  border-bottom: var(--border-hair) solid var(--color-line-soft);
  transition: background var(--transition);
}
.sector:hover { background: var(--color-bg); }
.sector-ico {
  display: grid;
  place-items: center;
  width: 48px; height: 48px;
  margin-bottom: 0.8rem;
  color: var(--color-accent);
  transition: transform var(--transition);
}
.sector-ico svg { width: 100%; height: 100%; }
.sector:hover .sector-ico { transform: translateY(-3px); }
.sector h3 {
  margin-bottom: 0.5rem;
  font-size: var(--text-lg);
  font-weight: var(--weight-black);
  text-transform: uppercase;
}
.sector p { font-size: var(--text-sm); line-height: var(--leading-normal); }

/* Centrada: variante para cuando son 3 o más piezas cortas */
.sector-row.center .sector { text-align: center; }
.sector-row.center .sector-ico { margin-inline: auto; }

/* ---------- .vias — la bifurcación del home ----------
   El bloque más importante de la portada. AP le vende dos cosas
   distintas a dos personas distintas, y el visitante tiene que
   reconocer cuál de las dos es la suya antes de scrollear.

   Por eso NO es un .sector normal agrandado: es el mismo componente
   con el volumen subido —titular propio (h2, no h3), lista de
   condiciones y CTA propio en cada mitad—. Lo que no cambia es el
   peso relativo: las dos mitades tienen exactamente el mismo ancho,
   el mismo fondo y el mismo tipo de botón. Ninguna de las dos es la
   opción "principal", porque para AP no lo son.

   El filete de ladrillo arriba de cada mitad marca dónde empieza
   cada camino. */
.vias .sector {
  align-content: space-between;
  gap: var(--space-md);
  padding: var(--space-md) var(--space-sm) var(--space-lg);
  border-top: var(--border-mark) solid var(--color-accent);
}
.vias .sector:hover { background: var(--color-bg); }
.vias .sector h2 {
  margin-bottom: 0;
  font-size: var(--text-xl);
  text-transform: uppercase;
}
.via-cuerpo .eyebrow { margin-bottom: 0; }
.vias .sector > p { font-size: var(--text-sm); line-height: var(--leading-normal); }
.via-cuerpo { display: grid; gap: var(--space-sm); }

/* Condiciones de cada camino. Guion de ladrillo en vez de bullet:
   es una lista de hechos, no una lista de beneficios. */
.via-puntos { display: grid; gap: var(--space-xs); }
.via-puntos li {
  position: relative;
  padding-left: var(--space-md);
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
  color: var(--color-primary-light);
}
.via-puntos li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0.7em;
  width: var(--space-sm);
  height: var(--border-medium);
  background: var(--color-accent);
}

/* =================================================================
   6. LA EMPRESA
   ================================================================= */

.nosotros { padding: var(--space-xl) 0; background: var(--color-bg); }
.nosotros-grid { display: grid; gap: 3rem; }
.nosotros-media { position: relative; }
.nosotros-media .figure { --ratio: var(--ratio-retrato); border-radius: var(--radius-md); }

.nosotros-card {
  position: relative;
  margin: -3rem 0 0 auto;
  width: min(280px, 84%);
  padding: 1.35rem 1.4rem;
  background: var(--color-primary);
  color: var(--color-text-inverse);
  border-left: var(--border-flag) solid var(--color-accent);
  box-shadow: var(--shadow-lg);
}
.nosotros-card-num {
  display: block;
  margin-bottom: 0.3rem;
  font-family: var(--font-display);
  font-size: var(--text-num-lg);
  font-weight: var(--weight-black);
  line-height: 1;
  letter-spacing: var(--track-tight);
  color: var(--color-accent);
}
.nosotros-card p { font-size: var(--text-sm); color: var(--ink-inv-2); max-width: none; }

.nosotros-copy h2 { margin-bottom: 1.1rem; }
.nosotros-copy .lead { margin-bottom: var(--space-sm); }
.nosotros-copy > p { margin-bottom: 1.8rem; }

.nosotros-mini {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(90px, 1fr));
  gap: var(--space-sm);
  padding: 1.3rem 0;
  margin-bottom: 1.8rem;
  border-top: var(--border-hair) solid var(--color-line);
  border-bottom: var(--border-hair) solid var(--color-line);
}
.nosotros-mini strong {
  display: block;
  font-family: var(--font-display);
  font-size: var(--text-num-lg);
  font-weight: var(--weight-black);
  line-height: 1;
  letter-spacing: var(--track-tight);
  color: var(--color-accent);
}
.nosotros-mini span {
  display: block;
  margin-top: 0.3rem;
  font-size: var(--label-sm);
  font-weight: var(--weight-semi);
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--color-text-muted);
}

/* =================================================================
   7. PROCESO EN PASOS
   -----------------------------------------------------------------
   El boceto usaba repeat(5,1fr) y una línea conectora en
   left:10%; width:80%, calculada para exactamente 5 pasos. Si los
   pasos salen de datos y son 4 o 6, se desalinea sin avisar.
   Ahora la grilla es auto-fit y la línea se dibuja con el mismo
   cálculo sea cual sea la cantidad.
   ================================================================= */

.proceso {
  position: relative;
  padding: var(--space-xl) 0;
  background: var(--color-primary-dark);
  color: var(--color-text-inverse);
  overflow: hidden;
}
.proceso-plano {
  position: absolute;
  right: -60px; top: 50%;
  transform: translateY(-50%);
  width: 340px;
  color: var(--color-accent);
  opacity: 0.3;
  pointer-events: none;
}
.proceso .wrap { position: relative; z-index: var(--z-base); }

.proceso-steps { position: relative; display: grid; gap: 0; }
.proceso-steps li {
  position: relative;
  padding: 1.2rem 0 1.2rem 4rem;
  border-bottom: var(--border-hair) solid var(--line-inv-2);
}
.proceso-steps li:last-child { border-bottom: 0; }

.step-dot {
  position: absolute;
  left: 0; top: 1.15rem;
  display: grid;
  place-items: center;
  width: var(--size-dot);
  height: var(--size-dot);
  font-family: var(--font-display);
  font-size: var(--text-lg);
  font-weight: var(--weight-black);
  color: var(--color-accent);
  border: var(--border-medium) solid var(--color-accent);
  border-radius: 50%;
  transition: background var(--transition), color var(--transition);
}
.proceso-steps li:hover .step-dot { background: var(--color-accent); color: var(--color-white); }
.proceso-steps h3 {
  margin-bottom: 0.3rem;
  font-size: var(--text-lg);
  font-weight: var(--weight-black);
  text-transform: uppercase;
  color: var(--color-text-inverse);
}
.proceso-steps p { font-size: var(--text-sm); color: var(--ink-inv-2); }

/* ---------- .detallada — el proceso como pliego, no como friso ----------
   La fila horizontal de arriba funciona para cinco rótulos de una
   línea. En /llave-en-mano/ cada paso dice qué pasa Y quién lo hace:
   son dos o tres renglones más un responsable con nombre y apellido, y
   en una columna de un sexto de pantalla eso se vuelve ilegible.

   Esta variante deja el recorrido vertical también en desktop, que es
   como se lee un pliego de condiciones: el número al costado, la línea
   entre pasos, y el responsable cerrando cada uno. El público de esa
   página está comparando riesgo, no mirando un gráfico.

   Las reglas se escriben acá y no en el breakpoint a propósito:
   con .detallada suman más especificidad que las de ≥768px, así que la
   variante mantiene la columna sin tener que duplicarse en el media
   query ni depender del orden del archivo. */
.proceso-steps.detallada { grid-auto-flow: row; grid-auto-columns: auto; gap: 0; }
.proceso-steps.detallada::before { content: none; }
.proceso-steps.detallada li {
  padding: var(--space-md) 0 var(--space-md) calc(var(--size-dot) + var(--space-md));
  border-bottom: var(--border-hair) solid var(--line-inv-2);
}
.proceso-steps.detallada li:last-child { border-bottom: 0; }
.proceso-steps.detallada .step-dot {
  position: absolute;
  left: 0;
  top: var(--space-md);
  margin-bottom: 0;
}
.proceso-steps.detallada p { max-width: var(--measure); }

/* Quién lo hace. Va en la etiqueta en mayúsculas del sistema y no en
   el cuerpo del paso porque es de otra clase de dato: el paso describe
   qué pasa, esto responde de quién es la responsabilidad. */
.paso-quien {
  margin-top: var(--space-xs);
  font-size: var(--label-sm);
  font-weight: var(--weight-bold);
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--color-accent-light);
}
.paso-quien span {
  margin-right: var(--space-2xs);
  font-weight: var(--weight-semi);
  color: var(--ink-inv-3);
}

/* =================================================================
   8. RESPALDO · FAQ · EQUIPO
   ================================================================= */

.confianza-grid { display: grid; }

.ventaja {
  padding: 2.4rem var(--gutter) 2.6rem;
  background: var(--color-accent-deep);
  color: var(--color-white);
}
.ventaja .eyebrow { color: var(--ink-on-accent-3); }
.ventaja h2 { color: var(--color-white); margin-bottom: var(--space-md); }
.ventaja ul { display: grid; gap: 0.8rem; }
.ventaja li {
  position: relative;
  padding-left: 1.9rem;
  padding-bottom: 0.8rem;
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  color: var(--ink-on-accent-2);
  border-bottom: var(--border-hair) solid var(--line-on-accent);
}
.ventaja li:last-child { border-bottom: 0; padding-bottom: 0; }
/* Tilde dibujado, no un carácter: no depende de la fuente */
.ventaja li::before {
  content: '';
  position: absolute;
  left: 0; top: 0.35rem;
  width: 11px; height: 6px;
  border-left: 2px solid var(--color-white);
  border-bottom: 2px solid var(--color-white);
  transform: rotate(-45deg);
}

.faq-col { padding: 2.4rem var(--gutter) 2.6rem; background: var(--color-surface); }
.faq-list { margin-bottom: 1.4rem; }
.faq-item { border-bottom: var(--border-hair) solid var(--color-line-soft); }
.faq-item summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm);
  padding: 0.95rem 0;
  min-height: var(--tap-sm);
  font-size: var(--text-sm);
  font-weight: var(--weight-semi);
  cursor: pointer;
  list-style: none;
  transition: color var(--transition);
}
.faq-item summary::-webkit-details-marker { display: none; }
/* Cruz que gira a menos: dos degradés, sin icono ni fuente */
.faq-item summary::after {
  content: '';
  flex: 0 0 12px;
  width: 12px; height: 12px;
  background:
    linear-gradient(var(--color-accent), var(--color-accent)) center / 100% 2px no-repeat,
    linear-gradient(var(--color-accent), var(--color-accent)) center / 2px 100% no-repeat;
  transition: transform var(--dur-slow) var(--ease-out);
}
.faq-item[open] summary::after { transform: rotate(135deg); }
.faq-item summary:hover { color: var(--color-accent-ink); }
.faq-item p { padding: 0 0 var(--space-sm); font-size: var(--text-sm); }

.equipo-col { padding: 2.4rem var(--gutter) 2.6rem; background: var(--color-bg-alt); }
.equipo-list { display: grid; gap: 0.2rem; margin-bottom: 1.2rem; }
.equipo-list li {
  display: flex;
  align-items: center;
  gap: 0.9rem;
  padding: 0.85rem 0;
  border-bottom: var(--border-hair) solid var(--color-line-soft);
}
.equipo-list .figure,
.equipo-list img {
  flex: 0 0 auto;
  width: var(--size-avatar);
  height: var(--size-avatar);
  border-radius: 50%;
}
.equipo-list img { border: 2px solid var(--color-surface); box-shadow: var(--shadow-sm); }

/* MEJORA C — sin foto no se rompe.
   Las fotos del equipo están pendientes y puede que nunca lleguen
   las tres. El monograma es una pieza del sistema, no un parche. */
.monograma {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: var(--size-avatar);
  height: var(--size-avatar);
  border-radius: 50%;
  background: var(--color-primary);
  color: var(--color-accent-light);
  font-family: var(--font-display);
  font-size: var(--label-lg);
  font-weight: var(--weight-black);
  letter-spacing: var(--track-brand);
}

/* ---------- .destacada — una sola persona, con peso ----------
   /llave-en-mano/ nombra a UNA persona, y ese nombre es el
   argumento de la sección: quién firma la dirección técnica de la
   obra. Como fila de lista se lee como un ítem más; con superficie y
   el filete de ladrillo a la izquierda se lee como la credencial que
   es. Misma pieza, sin componente nuevo. */
.equipo-list.destacada { max-width: var(--measure); margin-bottom: var(--space-md); }
.equipo-list.destacada li {
  gap: var(--space-sm);
  padding: var(--space-sm);
  background: var(--color-surface);
  border: var(--border-hair) solid var(--color-line);
  border-left: var(--border-flag) solid var(--color-accent);
}

.equipo-list strong {
  display: block;
  font-family: var(--font-display);
  font-size: var(--text-nombre);
  font-weight: var(--weight-bold);
  letter-spacing: var(--track-snug);
}
/* BUG CORREGIDO: este selector era `.equipo-list span` y le ganaba a
   `.monograma` (misma cantidad de clases, pero con el elemento suma
   especificidad y además viene después). Resultado: el monograma
   perdía el display:grid y el color de acento — las iniciales salían
   arriba a la izquierda del círculo, en gris. El rol es el span que
   está DENTRO del bloque de texto; el monograma es hermano de ese
   bloque, no parte de él. */
.equipo-list li > div span { display: block; font-size: var(--label-md); color: var(--color-text-muted); }

/* ---------- .equipo-grid — el equipo completo, con retrato ----------
   .equipo-list es una fila con un avatar de 54px: sirve para nombrar a
   una persona al costado de un argumento (/llave-en-mano/). En
   /nosotros/ el equipo ES la sección, y ahí el avatar chico tiene un
   problema concreto: las fotos están pendientes y van a llegar
   (guidelines.md §5 promete retratos e imágenes en obra). Si el hueco
   que se reserva hoy es un círculo de 54px, el día que llegue la foto
   hay que rediseñar la sección para que valga algo.

   Por eso el retrato 9:10: reserva EXACTAMENTE el espacio de la foto
   final, así cargarla es cambiar un .figure.is-empty por un <img> y no
   se mueve nada. Mientras no esté, el estado vacío de .figure se apoya
   en el nombre, que es el dato que sí existe.

   La cantidad de columnas no está escrita: sale de --col-equipo y de
   cuántas personas tenga empresa.json → equipo. */
.equipo-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(var(--col-equipo), 1fr));
  gap: var(--space-sm);
  margin-bottom: var(--space-lg);
}
.equipo-grid li {
  background: var(--color-surface);
  border: var(--border-hair) solid var(--color-line-soft);
}
.equipo-grid .figure { --ratio: var(--ratio-retrato); }
.equipo-grid .persona {
  display: grid;
  gap: var(--space-2xs);
  padding: var(--space-sm);
}
.equipo-grid strong {
  font-family: var(--font-display);
  font-size: var(--text-lg);
  font-weight: var(--weight-bold);
  line-height: var(--leading-snug);
  letter-spacing: var(--track-snug);
  color: var(--color-primary);
}
/* Scoped a .persona: sin eso este selector también alcanzaría al
   .figure-fallback-label del retrato vacío, que ya tiene su estilo. */
.equipo-grid .persona span {
  font-size: var(--label-sm);
  font-weight: var(--weight-bold);
  letter-spacing: var(--track-wider);
  text-transform: uppercase;
  color: var(--color-accent-ink);
}

/* =================================================================
   8b. HECHOS VERIFICABLES
   -----------------------------------------------------------------
   Misma construcción que .ficha (la línea se hace con el gap), pero
   para un hecho en vez de un número: un título corto arriba y abajo
   la afirmación completa, tal como está redactada en
   data/empresa.json.

   Existe para no volver a caer en la fila de sellitos del boceto
   —escudos, tildes y medallas— donde el respaldo se dibuja en vez de
   afirmarse. Acá cada celda dice una cosa que se puede chequear:
   la habilitación, quién firma la dirección de obra, qué cobertura
   tiene el personal, cuántos años dura la garantía.

   Se usa dos veces en el home, con las dos pieles: sobre hormigón en
   Respaldo, y sobre ladrillo en Profili.
   ================================================================= */

.hechos {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: var(--border-hair);
  margin-bottom: var(--space-md);
  background: var(--color-line-soft);
  border: var(--border-hair) solid var(--color-line-soft);
}
.hechos li {
  display: grid;
  align-content: start;
  gap: var(--space-xs);
  padding: var(--space-md) var(--space-sm);
  background: var(--color-surface);
}
.hechos strong {
  font-family: var(--font-body);
  font-size: var(--label-sm);
  font-weight: var(--weight-bold);
  letter-spacing: var(--track-wider);
  text-transform: uppercase;
  color: var(--color-accent-ink);
}
.hechos span {
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
  color: var(--color-primary-light);
}

/* Sobre la banda de ladrillo */
.hechos.on-accent {
  background: var(--line-on-accent);
  border-color: var(--line-on-accent);
}
.hechos.on-accent li { background: var(--color-accent-deep); }
.hechos.on-accent strong { color: var(--ink-on-accent-1); }
.hechos.on-accent span { color: var(--ink-on-accent-2); }

/* =================================================================
   9. FRANJA DE PROVEEDORES
   ================================================================= */

.clientes { padding: var(--space-lg) 0; background: var(--color-surface); }
.clientes-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
  gap: 1.4rem var(--space-sm);
  align-items: center;
  margin-top: 1.4rem;
}
/* La celda reserva el alto del logo aunque hoy sólo tenga el nombre:
   los archivos los manda el cliente (guidelines.md §4) y cuando se
   carguen, cambiar un nombre por un <img> no tiene que mover la
   franja ni las secciones de abajo. */
.clientes-row li {
  display: grid;
  place-items: center;
  min-height: var(--size-logo);
  text-align: center;
  font-family: var(--font-display);
  font-size: var(--text-nombre);
  font-weight: var(--weight-bold);
  text-transform: uppercase;
  color: var(--color-primary);
  /* 0.42 daba 2.7:1 sobre --color-surface (no pasa AA para texto
     chico): 0.6 es el mínimo que llega a 4.5:1 y sigue leyéndose
     como el estado "sin logo todavía", no como un dato. */
  opacity: 0.6;
  transition: opacity var(--transition);
}
.clientes-row li:hover { opacity: 0.9; }
/* Variante logo: normaliza logos de origen y color dispar */
.clientes-row img {
  max-height: var(--size-logo);
  width: auto;
  margin: 0 auto;
  filter: grayscale(1) contrast(1.1);
}

/* =================================================================
   10. CONTACTO Y FORMULARIO
   ================================================================= */

.contacto { padding: var(--space-xl) 0 0; background: var(--color-bg); }
.contacto-grid { display: grid; gap: var(--space-lg); padding-bottom: var(--space-xl); }
.contacto-copy h2 { margin-bottom: var(--space-sm); }
.contacto-copy .lead { margin-bottom: 1.8rem; }

.contacto-datos { display: grid; }
.contacto-datos li {
  display: flex;
  align-items: flex-start;
  gap: 0.9rem;
  padding: 0.9rem 0;
  border-bottom: var(--border-hair) solid var(--color-line-soft);
}
.ci {
  flex: 0 0 var(--size-badge);
  height: var(--size-badge);
  display: grid;
  place-items: center;
  border: var(--border-hair) solid var(--color-line);
  color: var(--color-accent-ink);
}
.ci svg { width: var(--size-ico-sm); height: var(--size-ico-sm); }
/* Estado "todavía no hay canal": el <span class="ci"> del placeholder
   viene sin ícono, y el marco vacío se lee como un ícono que no cargó,
   no como andamio. El andamio es el .ph que está al lado. Apenas
   config/contacto.js tenga un canal, renderContacto escribe el SVG
   adentro y el marco vuelve solo. */
.ci:empty { display: none; }
.contacto-datos strong {
  display: block;
  margin-bottom: 2px;
  font-family: var(--font-body);
  font-size: var(--label-sm);
  font-weight: var(--weight-bold);
  letter-spacing: var(--track-wider);
  text-transform: uppercase;
  color: var(--color-text-muted);
}
.contacto-datos a,
.contacto-datos div > span {
  font-size: var(--text-sm);
  font-weight: var(--weight-semi);
  color: var(--color-primary);
  transition: color var(--transition);
}
.contacto-datos a:hover { color: var(--color-accent-ink); }
/* Misma pieza en el footer (fondo oscuro) y en /contacto/ (fondo
   claro): --color-text-muted está calibrado para claro y sobre carbón
   profundo cae a 3.4:1. */
.footer-col .contacto-datos strong { color: var(--ink-inv-3); }

.contacto-form {
  padding: 1.75rem var(--gutter) 1.9rem;
  background: var(--color-surface);
  border: var(--border-hair) solid var(--color-line);
  border-top: var(--border-flag) solid var(--color-accent);
  box-shadow: var(--shadow-md);
}
.contacto-form h3 {
  margin-bottom: 1.3rem;
  font-weight: var(--weight-black);
  text-transform: uppercase;
}
.contacto-form label {
  display: block;
  margin-bottom: 0.35rem;
  font-size: var(--label-sm);
  font-weight: var(--weight-bold);
  letter-spacing: var(--track-wider);
  text-transform: uppercase;
  color: var(--color-text-muted);
}
.contacto-form input,
.contacto-form select,
.contacto-form textarea {
  width: 100%;
  min-height: var(--tap-sm);
  padding: 0.8rem 0.9rem;
  margin-bottom: 1.05rem;
  background: var(--color-bg);
  border: var(--border-hair) solid var(--color-line);
  border-radius: var(--radius-sm);
  font-size: var(--text-sm);
  transition: border-color var(--transition), background var(--transition);
}
.contacto-form textarea { min-height: 110px; resize: vertical; }
.contacto-form input:focus,
.contacto-form select:focus,
.contacto-form textarea:focus {
  border-color: var(--color-accent);
  background: var(--color-surface);
  outline: none;
}
.contacto-form input.has-error,
.contacto-form textarea.has-error {
  border-color: var(--color-error);
  background: var(--color-error-bg);
}
.form-note {
  margin-top: 0.9rem;
  font-size: var(--label-md);
  text-align: center;
  max-width: none;
}
.form-note.is-error { color: var(--color-error); font-weight: var(--weight-semi); }
.form-note.is-pending { color: var(--color-text-muted); font-weight: var(--weight-semi); }

.oficina-map { border-top: var(--border-hair) solid var(--color-line); }
/* Mobile first también acá: en 375px el panorámico 21:9 deja una franja
   de 160px donde no se distingue una calle. El apaisado 3:2 es el mismo
   ratio con el que el sitio reserva renders y fotos, y da un mapa
   usable; desde 768 vuelve el panorámico, que es lo que la banda
   necesita a lo ancho. Los dos valores salen de tokens.css. */
.oficina-map iframe {
  width: 100%;
  aspect-ratio: var(--ratio-panel);
  border: 0;
  filter: var(--map-filter);
}

/* =================================================================
   11. BANDAS DE LLAMADA
   ================================================================= */

/* Sobre claro, con borde punteado */
.cta-band {
  display: grid;
  gap: var(--space-sm);
  align-items: center;
  padding: 1.6rem;
  border: var(--border-medium) dashed var(--color-line);
  background: rgb(var(--rgb-surface) / .55);
}
.cta-band p { font-size: var(--text-base); color: var(--color-primary-light); }

/* Sobre oscuro, con bandera de acento */
.cta-band.on-dark {
  gap: 1.2rem;
  margin-top: var(--space-lg);
  background: var(--wash-inv);
  border: var(--border-hair) solid var(--line-inv-1);
  border-left: var(--border-flag) solid var(--color-accent);
}
.cta-band.on-dark strong {
  display: block;
  margin-bottom: 0.4rem;
  font-family: var(--font-display);
  font-size: var(--text-lg);
  font-weight: var(--weight-bold);
  line-height: var(--leading-snug);
  letter-spacing: var(--track-snug);
  color: var(--color-text-inverse);
}
.cta-band.on-dark span { font-size: var(--text-sm); color: var(--ink-inv-2); }

/* ---------- Cierre a dos puertas ----------
   El home abre con la bifurcación y cierra con la misma elección. Las
   dos bandas quedan apiladas por dentro (no en 1fr auto como una
   .cta-band suelta) para que el botón de cada una arranque en la misma
   línea y ninguna parezca la opción por defecto. */
.cta-doble { display: grid; gap: var(--space-sm); }
.cta-doble .cta-band { margin-top: 0; }

/* =================================================================
   11b. PROFILI
   -----------------------------------------------------------------
   El diferencial más fuerte de AP y el argumento central para el
   inversor: la propiedad no termina en la entrega de llaves.
   No existía en el boceto. Banda propia, con el hormigón sombreado
   para que se despegue de la sección anterior sin usar otra franja
   oscura (ya hay tres).
   ================================================================= */

.profili { padding: var(--space-xl) 0; background: var(--color-bg-alt); }
.profili .sec-head { max-width: 720px; }
.profili .sec-sub strong { color: var(--color-accent-ink); font-weight: var(--weight-bold); }

/* ---------- Profili sobre ladrillo — el único acento pleno del home ----------
   "El ladrillo se usa para marcar, no para decorar": esta es la banda
   que marca. Es una sola en toda la página y cae sobre el argumento
   más fuerte que tiene la empresa —que la propiedad no termina en la
   entrega de llaves—, que en el material del cliente estaba en un
   renglón suelto. Si mañana aparece una segunda banda de ladrillo en
   el home, esta deja de significar algo.

   La piel de ladrillo se declara UNA vez y la comparten dos secciones:
   .profili.on-accent (home, /desarrollos/, /gran-martina/) y
   .banda.accent (§11c), que es la misma banda sin el nombre de Profili
   encima. En /llave-en-mano/ el argumento que decide no es Profili
   —comercializar y administrar es cosa del inversor— sino la garantía
   y el respaldo, y ahí cae la única banda de acento de esa página.
   Sigue siendo una sola por página: si aparece una segunda, esta deja
   de significar algo. */
.profili.on-accent,
.banda.accent {
  background: var(--color-accent-deep);
  color: var(--color-white);
}
.profili.on-accent .eyebrow,
.banda.accent .eyebrow { color: var(--ink-on-accent-3); }
.profili.on-accent h2,
.banda.accent h2 { color: var(--color-white); }
.profili.on-accent .sec-sub,
.profili.on-accent .lead,
.banda.accent .sec-sub,
.banda.accent .lead { color: var(--ink-on-accent-2); }
.profili.on-accent .sec-sub strong,
.profili.on-accent .lead strong,
.banda.accent .sec-sub strong,
.banda.accent .lead strong { color: var(--color-white); font-weight: var(--weight-bold); }
.profili.on-accent .lead,
.banda.accent .lead { margin-bottom: var(--space-md); }

/* =================================================================
   11c. BANDA DE SECCIÓN NEUTRA
   -----------------------------------------------------------------
   .construimos, .nosotros, .proceso y .profili traen su propio fondo
   porque son secciones con nombre y con contenido fijo. Cuando hace
   falta una banda que sólo aporte el ritmo vertical del sistema y un
   fondo —el respaldo y el cierre del home— esta es la pieza, para no
   tener que reutilizar una sección con nombre ajeno sólo por su
   padding.

   El home apila cinco bandas: carbón, hormigón, carbón, hormigón
   sombreado y ladrillo. Es la estructura del diseño (franjas que
   separan el relato como plantas de un edificio), no una decoración
   que se pueda barajar.
   ================================================================= */

.banda { padding: var(--space-xl) 0; background: var(--color-bg); }
.banda.alt { background: var(--color-bg-alt); }
.banda.surface { background: var(--color-surface); }
.banda.dark {
  background: var(--color-primary);
  color: var(--color-text-inverse);
}
/* .banda.accent — la banda de ladrillo pleno, una por página. La piel
   está declarada arriba, junto a .profili.on-accent, para que las dos
   secciones no puedan divergir. Ver §11b. */

/* =================================================================
   11d. BARRA DE ACCIÓN FIJA — SÓLO MOBILE
   -----------------------------------------------------------------
   La usan las dos páginas que piden un dato al visitante:
   /gran-martina/ (el inversor) y /llave-en-mano/ (el particular). Los
   clientes de AP llegan desde Instagram y WhatsApp, en el teléfono, y
   las dos páginas son largas —hero, datos, argumento, proceso o
   avance de obra, FAQ, formulario—: sin esto, la única acción queda
   al fondo de todo.

   NO es el botón flotante de WhatsApp (.whatsapp-float): ese vuelve
   cuando exista el número institucional. Este es una barra de ancho
   completo con la acción que sí existe hoy —bajar al formulario de
   interés—, y por eso convive con el sistema de bandas en vez de
   flotar como una burbuja encima.

   Desde 768px desaparece: en desktop el formulario se alcanza con un
   scroll y la barra sólo taparía contenido.

   --cta-fijo-h lo comparten la barra y el padding del <body>: la
   barra es fixed, así que sin ese padding taparía el final del
   footer. Por eso la altura es un token y no un valor suelto.
   ================================================================= */

.cta-fijo {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: var(--z-float);
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  min-height: var(--cta-fijo-h);
  padding: var(--space-xs) var(--gutter);
  background: var(--color-primary-dark);
  border-top: var(--border-mark) solid var(--color-accent);
  box-shadow: var(--shadow-lg);
}
.cta-fijo-texto { display: grid; min-width: 0; }
.cta-fijo strong {
  font-family: var(--font-display);
  font-size: var(--text-nombre);
  font-weight: var(--weight-black);
  line-height: var(--leading-snug);
  letter-spacing: var(--track-snug);
  text-transform: uppercase;
  color: var(--color-text-inverse);
}
.cta-fijo span {
  font-size: var(--label-xs);
  font-weight: var(--weight-semi);
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--ink-inv-3);
}
.cta-fijo .btn {
  flex: 0 0 auto;
  min-height: var(--tap-sm);
  padding: var(--space-xs) var(--space-md);
  font-size: var(--label-md);
}
/* La clase la pone el HTML de la página que usa la barra, no el JS:
   así el espacio ya está reservado en el primer frame y el footer no
   salta cuando termina de cargar la página. */
body.has-cta-fijo { padding-bottom: var(--cta-fijo-h); }

/* =================================================================
   12. FONDOS DECORATIVOS
   ================================================================= */

.blueprint-bg {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image:
    linear-gradient(var(--wash-inv) 1px, transparent 1px),
    linear-gradient(90deg, var(--wash-inv) 1px, transparent 1px),
    radial-gradient(ellipse at 80% 10%, rgb(var(--rgb-ladrillo) / .22) 0%, transparent 58%);
  background-size:
    var(--pattern-blueprint-size) var(--pattern-blueprint-size),
    var(--pattern-blueprint-size) var(--pattern-blueprint-size),
    100% 100%;
}

/* =================================================================
   13. PLACEHOLDERS
   -----------------------------------------------------------------
   Dos cosas distintas, a propósito:

   .ph   material que el cliente todavía no mandó. Es andamio: se ve
         como andamio y se borra cuando llega el material. Si algo
         sigue rayado, falta un dato.

   .figure.is-empty  el mismo componente de imagen, en el estado "sin foto
         todavía". Se documenta junto al resto de .figure más arriba
         (§2); ver ahí el detalle y MEJORA C.
   ================================================================= */

.ph {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-sm);
  text-align: center;
  font-family: var(--font-body);
  font-size: var(--label-sm);
  font-weight: var(--weight-semi);
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--color-text-muted);
  background-color: var(--color-bg-alt);
  background-image: repeating-linear-gradient(
    -45deg, transparent 0 10px, rgb(var(--rgb-carbon) / .05) 10px 20px);
  border: var(--border-hair) dashed var(--color-line);
  border-radius: var(--radius-md);
}
.ph::after { content: attr(data-ph); max-width: 44ch; line-height: var(--leading-normal); }

.ph-hero  { width: 100%; height: 100%; }
.ph-media { width: 100%; aspect-ratio: var(--ratio-retrato); border-radius: var(--radius-lg); }
.ph-block { width: 100%; min-height: 220px; margin-top: var(--space-lg); }
/* Reserva de un render/foto apaisada (3:2). Ocupa exactamente el espacio
   de la imagen final, así reemplazarla no mueve nada del layout. */
.ph-panel { width: 100%; aspect-ratio: var(--ratio-panel); }
.ph-inline {
  display: inline-flex;
  padding: 0.35rem 0.6rem;
  font-size: var(--label-xs);
  letter-spacing: var(--track-wide);
}
.ph-light {
  color: var(--ink-inv-2);
  background-color: var(--wash-inv);
  background-image: repeating-linear-gradient(
    -45deg, transparent 0 10px, rgb(var(--rgb-hormigon) / .07) 10px 20px);
  border-color: var(--line-inv-1);
}

/* ---------- .figure sin imagen: estado incorporado, no un ícono roto ----------
   Vive DENTRO de .figure (misma caja, mismo aspect-ratio, mismo grano):
   no es un componente aparte que haya que acoplar a mano. Se activa
   agregando .is-empty a la .figure y reemplazando el <img> por un
   .figure-fallback con una etiqueta.

     <span class="figure r-obra is-empty">
       <span class="figure-fallback"><span class="figure-fallback-label">
         Edificio Clave de Sol
       </span></span>
     </span>

   Sirve para dos casos con la misma pieza visual:
   · temporal — una foto que todavía no mandó el cliente (equipo, hero).
   · permanente — una obra de 2014–2018 que puede no tener NUNCA una foto
     decente. No es un error del sitio: es una pieza terminada, apoyada en
     el dato que sí existe (el nombre), no en la que falta. Con 12 de las
     16 obras hoy en este estado, la grilla tiene que verse prolija así,
     no “rota”. MEJORA C de la fase de tokens.

   Fondo oscuro a propósito: junto a tarjetas con foto real (más claras,
   más saturadas) este estado no compite ni intenta disimularse — se lee
   como una pieza distinta y deliberada, no como una carga que falló. */
.figure.is-empty {
  background-color: var(--color-primary);
  background-image: var(--pattern-diagonal-dark);
}
.figure-fallback {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-sm);
  text-align: center;
}
.figure-fallback-label {
  font-family: var(--font-display);
  font-size: var(--label-sm);
  font-weight: var(--weight-bold);
  line-height: var(--leading-snug);
  letter-spacing: var(--track-wider);
  text-transform: uppercase;
  color: var(--ink-inv-2);
}
/* Variante clara: cuando .figure ya está sobre un fondo oscuro (por ejemplo
   el slider de avance de obra, en en-obra) el estado vacío se invierte para
   no desaparecer contra la sección. */
.figure.is-empty.on-dark {
  background-color: var(--wash-inv);
  background-image: var(--pattern-diagonal);
}

/* =================================================================
   14. EN RESERVA — sin uso hoy
   -----------------------------------------------------------------
   El mock de páginas rotadas venía del catálogo PDF, que se purgó
   porque no existe. El COMPONENTE sirve, y va a servir para los
   planos y renders de Gran Martina. Queda acá, marcado, para no
   volver a dibujarlo. No se usa en ninguna ruta todavía.
   ================================================================= */

.pliego { position: relative; width: 168px; height: 200px; }
.pliego-hoja { position: absolute; display: block; box-shadow: var(--shadow-lg); }
.pliego-atras {
  inset: 14px 0 0 22px;
  background: rgb(var(--rgb-white) / .9);
  transform: rotate(4deg);
}
.pliego-frente {
  inset: 0 22px 14px 0;
  background: var(--color-primary);
  overflow: hidden;
  transform: rotate(-3deg);
  transition: transform var(--dur-slow) var(--ease-out);
}
.pliego:hover .pliego-frente { transform: rotate(-6deg) translateY(-6px); }
.pliego-frente img { width: 100%; height: 100%; opacity: 0.55; }

/* =================================================================
   BREAKPOINTS
   ================================================================= */

@media (min-width: 768px) {
  .statband-list { grid-template-columns: repeat(4, 1fr); }
  .statband-list li {
    padding: 1.6rem var(--space-sm);
    border-bottom: 0;
    border-right: var(--border-hair) solid var(--line-inv-2);
  }
  .statband-list li:last-child { border-right: 0; }

  .cifras-row { grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }

  .nosotros-grid { grid-template-columns: 0.92fr 1.08fr; gap: 3.5rem; align-items: center; }

  .proceso-steps {
    grid-auto-flow: column;
    grid-auto-columns: 1fr;
    gap: 1.2rem;
  }
  .proceso-steps li { padding: 0; border-bottom: 0; }
  /* La línea conectora ya no depende de que sean 5 pasos */
  .proceso-steps::before {
    content: '';
    position: absolute;
    top: calc(var(--size-dot) / 2);
    left: 10%;
    width: 80%;
    height: 1px;
    background: linear-gradient(90deg, var(--color-accent), rgb(var(--rgb-ladrillo) / .15));
  }
  .step-dot {
    position: relative;
    left: auto; top: auto;
    margin-bottom: var(--space-sm);
    background: var(--color-primary-dark);
    z-index: var(--z-base);
  }
  .proceso-plano { width: 400px; right: -110px; }

  .confianza-grid { grid-template-columns: 1fr 1fr; }
  .equipo-col { grid-column: span 2; }

  .contacto-grid { grid-template-columns: 1fr 1fr; gap: 3.5rem; align-items: start; }
  .contacto-form { padding: 2.2rem 2rem; }
  .oficina-map iframe { aspect-ratio: var(--ratio-pano); }

  .cta-band { grid-template-columns: 1fr auto; padding: 1.9rem 2rem; }
  /* Las dos puertas del cierre quedan lado a lado, y cada una apilada
     por dentro: si heredaran el 1fr auto de .cta-band, el texto se
     estrangularía contra el botón dentro de media pantalla. */
  .cta-doble { grid-template-columns: 1fr 1fr; align-items: stretch; }
  .cta-doble .cta-band { grid-template-columns: 1fr; align-content: space-between; }

  .vias .sector { padding: var(--space-lg) var(--space-md) var(--space-xl); }
  .vias .sector > .btn { justify-self: start; }
  .hechos li { padding: var(--space-lg) var(--space-md); }

  /* En desktop el formulario está a un scroll: la barra sólo taparía
     contenido. Se va, y con ella el padding que le reservaba lugar. */
  .cta-fijo { display: none; }
  body.has-cta-fijo { padding-bottom: 0; }
}

@media (min-width: 1100px) {
  .confianza-grid { grid-template-columns: 1fr 1.15fr 0.95fr; }
  .equipo-col { grid-column: auto; }
  .ventaja, .faq-col, .equipo-col { padding: 3rem 2.2rem 3.2rem; }

  .construimos, .nosotros, .proceso, .profili, .banda { padding: var(--space-2xl) 0; }
  /* Dos columnas exactas: la bifurcación no puede caer en tres ni en
     una sola por el auto-fit. Son dos caminos, siempre. */
  .vias { grid-template-columns: 1fr 1fr; }
  .contacto { padding-top: var(--space-2xl); }
}
