/* =========================================================
   Solved Design System — SECCIONES DE CONTENIDO
   Los patrones de sección larga traídos de la home de Stripe, después de los
   cuatro de la primera tanda (titular a dos tintas, banda de cifras,
   encabezado asimétrico y escena ancha), que viven en ds/site.css y ds/scene.css.

   QUÉ SE COPIA Y QUÉ NO
   Se copia la ESTRUCTURA: el reparto, el ritmo vertical, dónde cae el hairline,
   qué se recorta y qué se deja entero. No se copia su paleta, ni su tipografía,
   ni su material de gradiente, ni su copy. Todo lo de aquí se pinta con los
   tokens de ds/tokens.css.

   MEDIDO EN stripe.com/es EL 14 DE AGOSTO DE 2026
   Sale de leer el DOM en vivo, no de mirar capturas:

     contenedor      max-width 1266px · padding-inline 16px · riel 1px #E5EDF5
     ritmo vertical  padding-block 96px (variantes de 80 y de 48)
     titulares       56/1.03/-1.4 · 44/1.15/-0.88 · 32/1.1/-0.64 · 26/1.12/-0.26
     cuerpo          16px/1.4, sin tracking
     pesos           TODO a 300. El énfasis es 400. No hay un solo 700.
     tinta           #061B31 · apagado #50617A · cita #64748D
     enlace          16px, peso 400, sin subrayado

   Dos cosas que conviene saber, porque explican de dónde vienen las reglas de
   este sistema y confirman que no eran caprichos:
     · el contenedor de 1266px de --container es EXACTAMENTE el suyo;
     · su escala tipográfica es la de ds/tokens.css, hasta el tracking.
   Lo que no coincide es la tinta: la nuestra es el negro del logo (#111214) y
   la suya un azul muy oscuro. No se toca.

   OJO AL MONTAR: ds/site.css aplana toda <section class> en escritorio con
   section[class] (0-1-1). Estos patrones viven dentro de .frame / .wrap, así
   que no les afecta, pero si alguno se saca a una <section> propia, esa regla
   gana a cualquier clase suelta.

   Requiere ds/tokens.css. El único patrón con script es el carril, y sólo para
   las flechas: ds/sections.js. Guideline viva en /guidelines/secciones.stripe.html.
   ========================================================= */

/* =========================================================
   1 · BANDA DE CASO DE CLIENTE
   Logo, una frase y el enlace a la historia en una fila; debajo, la foto a
   todo el ancho del contenedor; debajo, el pie de datos.

   La frase es UNA, en presente y con el cliente de sujeto —"Fritoper controla
   la merma de sus tres centros con Solved"—, no una cita entrecomillada. La
   cita tiene su propio patrón (5) y mezclarlos deja la sección sin foco.
   ========================================================= */
.case-band{ display:block; }

.case-band__head{
  display:flex;
  align-items:center;
  gap:16px;
  padding-bottom:18px;
}
/* Caja apaisada, no cuadrada: los logos de cliente que hay en assets vienen
   horizontales (316×112 y parecidos). Metidos en un cuadrado de 40px se quedan
   en una mancha de 14px de alto y no se lee de quién es el caso. */
.case-band__logo{
  flex:0 0 auto;
  width:96px; height:34px;
  object-fit:contain;
  object-position:left center;
}
.case-band__claim{
  margin:0;
  font:var(--type-body-lg);
  letter-spacing:var(--tracking-body);
  color:var(--ds-text);
  text-wrap:balance;
}
/* El enlace se va al extremo y se queda ahí: es el único destino de la banda. */
.case-band__cta{ margin-left:auto; flex:0 0 auto; }

/* La foto va a sangre dentro del contenedor y sin radio arriba: la banda no es
   una tarjeta, es una franja. Proporción fija para que dos casos seguidos
   midan lo mismo aunque las fotos no. */
/* height:auto no sobra: los atributos width/height del <img> entran como
   presentational hint y fijan la altura, y con la altura fijada aspect-ratio
   no calcula nada. Sin esto la foto se estira a su alto de atributo. */
.case-band__media{
  display:block;
  width:100%; height:auto;
  aspect-ratio:21/9;
  object-fit:cover;
  border-radius:var(--ds-radius-panel);
  background:var(--ds-surface-soft);
}

/* Pie de datos: pares etiqueta + valor, la etiqueta en tinta y el valor en
   gris, en la misma línea. Es el mismo gesto de las dos tintas del titular,
   bajado a tamaño de pie. */
.case-band__facts{
  display:grid;
  grid-template-columns:repeat(auto-fit,minmax(200px,1fr));
  gap:12px 40px;
  margin-top:18px;
}
.case-band__fact{
  margin:0;
  font:var(--type-caption);
  letter-spacing:var(--tracking-caption);
  color:var(--ds-text-mute);
}
.case-band__fact b{
  font-weight:var(--font-weight-regular);
  color:var(--ds-text);
}

@media (max-width:899px){
  .case-band__head{ flex-wrap:wrap; gap:12px; }
  .case-band__cta{ margin-left:0; width:100%; }
  .case-band__media{ aspect-ratio:16/9; }
}

/* =========================================================
   2 · LISTA DE CASOS
   Filas de una línea —logo, frase, botón de abrir— separadas por hairline.
   Es lo que se pone cuando hay varios clientes que contar y ninguno da para
   una banda entera: cuatro bandas seguidas convierten la home en un catálogo.

   El botón lleva destino de verdad o no se pinta. Un "+" que no abre nada
   cuesta más confianza de la que gana, igual que .scene__expand.
   ========================================================= */
.case-list{
  border-top:var(--frame-width) solid var(--frame);
}
.case-list__item{
  display:flex;
  align-items:center;
  gap:14px;
  padding-block:18px;
  border-bottom:var(--frame-width) solid var(--frame);
  color:inherit;
  text-decoration:none;
  transition:background var(--ds-motion);
}
a.case-list__item:hover{ background:var(--ds-surface-soft); }
a.case-list__item:focus-visible{
  outline:2px solid var(--color-primary);
  outline-offset:-2px;
}
.case-list__logo{
  flex:0 0 auto;
  width:78px; height:28px;
  object-fit:contain;
  object-position:left center;
}
.case-list__claim{
  margin:0;
  font:var(--type-body-md);
  letter-spacing:var(--tracking-body);
  color:var(--ds-text);
}
.case-list__open{
  margin-left:auto;
  flex:0 0 auto;
  display:grid;
  place-items:center;
  width:32px; height:32px;
  border:1px solid var(--color-hairline);
  border-radius:var(--ds-radius-control);
  background:var(--ds-surface);
  color:var(--ds-text-2);
  transition:border-color var(--ds-motion), color var(--ds-motion);
}
a.case-list__item:hover .case-list__open{
  border-color:var(--color-hairline-input);
  color:var(--color-primary);
}
.case-list__open svg{ width:15px; height:15px; display:block; }

@media (max-width:600px){
  .case-list__item{ align-items:flex-start; padding-block:14px; }
  .case-list__claim{ font:var(--type-body-sm,var(--type-caption)); }
  .case-list__open{ align-self:center; }
}

/* =========================================================
   3 · CARRIL RECORTADO
   Una fila de tarjetas que se sale por el riel derecho del encuadre, con los
   controles arriba a la derecha. El corte es el componente: dice que la lista
   sigue, y por eso la última tarjeta visible se ve cortada A PROPÓSITO.

   Lo que lo rompe: centrar el carril, o darle padding-right para que la última
   tarjeta entre entera. Si entran todas, esto no es un carril — es una rejilla,
   y hay que usar una rejilla.

   Va con scroll nativo y scroll-snap. Los botones mueven el scroll; sin JS
   siguen estando el arrastre y el teclado, así que la sección nunca depende de
   que el script cargue.

   Los controles van con [hidden] en el marcado y los enciende ds/sections.js
   —y los vuelve a apagar si no hay nada que desplazar—. Misma regla que
   .scene__expand: la afordancia sólo se pinta si hace algo.
   ========================================================= */
.rail{ position:relative; }

.rail__controls{
  display:flex;
  justify-content:flex-end;
  gap:8px;
  margin-bottom:20px;
}
/* display:flex gana a la presentación por defecto de [hidden], que es 0-0-0. */
.rail__controls[hidden]{ display:none; }
.rail__btn{
  display:grid;
  place-items:center;
  width:38px; height:38px;
  padding:0;
  border:1px solid var(--color-hairline);
  border-radius:var(--ds-radius-control);
  background:var(--ds-surface);
  color:var(--ds-text-2);
  cursor:pointer;
  transition:border-color var(--ds-motion), color var(--ds-motion), background var(--ds-motion);
}
.rail__btn:hover:not(:disabled){
  border-color:var(--color-hairline-input);
  color:var(--color-primary);
}
.rail__btn:focus-visible{ outline:2px solid var(--color-primary); outline-offset:2px; }
.rail__btn:disabled{ opacity:.4; cursor:default; }
.rail__btn svg{ width:16px; height:16px; display:block; }

/* El truco del recorte: el carril se sale del contenedor por la derecha con un
   margen negativo del ancho del padding del encuadre, y ahí lo corta el riel.
   No lleva overflow visible: lo que sobra se ve cortado, no se ve fuera. */
.rail__track{
  display:grid;
  grid-auto-flow:column;
  grid-auto-columns:minmax(280px,1fr);
  gap:20px;
  margin-right:calc(var(--frame-pad-inline) * -1);
  padding-right:var(--frame-pad-inline);
  overflow-x:auto;
  overscroll-behavior-x:contain;
  scroll-snap-type:x mandatory;
  scrollbar-width:none;
}
.rail__track::-webkit-scrollbar{ display:none; }
.rail__item{ scroll-snap-align:start; }

/* Cuatro por pantalla en escritorio, y la cuarta cortada por el riel. */
@media (min-width:900px){
  .rail__track{ grid-auto-columns:calc((100% - 60px) / 3.4); }
}
@media (max-width:899px){
  .rail__track{ grid-auto-columns:min(74%,320px); }
  .rail__controls{ display:none; }   /* en táctil se arrastra */
}
/* En móvil el encuadre estrecha su padding a 16px (ds/site.css, ≤768px) pero
   --frame-pad-inline sigue valiendo 32. Sin esto el carril se sale 16px por la
   derecha de la caja que lo contiene y aparece scroll horizontal en la página
   entera. El riel lateral tampoco se pinta a ese ancho: el corte lo hace el
   borde de la ventana. */
@media (max-width:768px){
  .rail__track{ margin-right:-16px; padding-right:16px; }
}

/* La tarjeta del carril: imagen arriba con radio, texto debajo. Sin marco:
   el marco lo dibujaría la tarjeta y aquí quien manda es la fila. */
.rail-card{ display:block; color:inherit; text-decoration:none; }
.rail-card__media{
  display:block;
  width:100%; height:auto;         /* ver la nota de .case-band__media */
  aspect-ratio:4/3;
  object-fit:cover;
  border-radius:var(--ds-radius-panel);
  background:var(--ds-surface-soft);
}
.rail-card__title{
  margin:14px 0 0;
  font:var(--type-body-md);
  letter-spacing:var(--tracking-body);
  color:var(--ds-text);
  text-wrap:balance;
}
.rail-card__link{
  display:inline-block;
  margin-top:8px;
  font:var(--type-caption);
  letter-spacing:var(--tracking-caption);
  color:var(--color-primary);
}
a.rail-card:hover .rail-card__link{ text-decoration:underline; }
a.rail-card:focus-visible{ outline:2px solid var(--color-primary); outline-offset:4px; border-radius:var(--ds-radius-panel); }

/* =========================================================
   4 · TRÍO DE APOYO
   Tres columnas con icono, un párrafo a dos tintas y un enlace. Es la sección
   de cierre: implantación, integraciones, soporte.

   El párrafo empieza con la idea en tinta y sigue en gris DENTRO DE LA MISMA
   FRASE. No es un título con su texto debajo: es una sola oración que cambia de
   color a mitad. Ese es el patrón, y partirlo en dos bloques lo deshace.
   ========================================================= */
.trio{
  display:grid;
  grid-template-columns:repeat(3,minmax(0,1fr));
  gap:40px;
}
/* LA CELDA, COMPARTIDA CON LA REJILLA DE ARGUMENTOS (al final del fichero).
   Los selectores van agrupados a propósito: `.reasons` es esta misma celda con
   el número de columnas abierto, así que si el cuadro del icono o el escalón
   del énfasis cambian, tienen que cambiar en los dos. Con dos bloques separados
   eso se olvida a la primera. */
.trio__ico,
.reasons__ico{
  display:grid;
  place-items:center;
  width:34px; height:34px;
  margin-bottom:16px;
  border:1px solid var(--color-hairline);
  border-radius:var(--ds-radius-control);
  color:var(--color-primary);
}
.trio__ico svg,
.reasons__ico svg{ width:17px; height:17px; display:block; }
.trio p,
.reasons p{
  margin:0;
  font:var(--type-body-md);
  letter-spacing:var(--tracking-body);
  color:var(--ds-text-mute);
  text-wrap:pretty;
}
/* El énfasis es peso 400 sobre un cuerpo de 300. No es negrita: es el escalón
   que ya existe en el sistema, y es lo que hace Stripe —en toda su home no hay
   un solo 700—. */
.trio p .em,
.reasons p .em{
  font-weight:var(--font-weight-regular);
  color:var(--ds-text);
}
/* LA FOTO DE LA CELDA
   El trío cierra la home y era la única sección de texto seguido: tres iconos
   de 34px y tres párrafos. La foto no ilustra la frase —eso sería decoración—,
   enseña el sitio donde pasa lo que la frase cuenta, que es lo mismo que hacen
   las escenas. Va arriba, antes del icono, con la proporción de la banda para
   que las tres celdas midan igual aunque el texto no.

   Misma regla que en assets/planta/: persona usando un dispositivo en planta o
   almacén. Una nave vacía aquí no aporta nada. */
.trio__foto{
  display:block;
  width:100%;
  /* 3:2, QUE ES LA PROPORCIÓN DEL ORIGINAL.
     A 16:9 el recorte se comía la cabeza de quien salía en la foto, y peor
     cuanto más estrecha la columna: `cover` recorta por arriba y por abajo, y
     en una foto de una persona eso es exactamente donde está la cara. Con la
     misma proporción que el fichero no hay recorte a ningún ancho, así que la
     celda se comporta igual en escritorio, en el carrusel del móvil y en
     cualquier punto intermedio. Si se cambia una foto, que venga a 3:2. */
  aspect-ratio:3/2;
  object-fit:cover;
  border-radius:var(--ds-radius-panel);
  margin-bottom:20px;
  background:var(--ds-surface-soft);
}

.trio__link,
.reasons__link{
  display:inline-block;
  margin-top:14px;
  font:var(--type-body-md);
  letter-spacing:var(--tracking-body);
  color:var(--color-primary);
  text-decoration:none;
}
.trio__link:hover,
.reasons__link:hover{ text-decoration:underline; }

@media (max-width:899px){
  /* EN MÓVIL, CARRUSEL.
     Apiladas, las tres celdas con foto medían más de tres pantallas y el
     testimonio de abajo quedaba a un scroll largo de distancia. En carril se
     ven las tres en el mismo gesto y se entiende que son tres, no una lista
     que no acaba. El ancho de celda deja asomar la siguiente: es lo que dice
     que hay más sin necesidad de flechas ni puntos.

     Con scroll-snap para que cada arrastre pare en una celda entera, y sin
     barra visible —el asomo de la siguiente ya es la pista—. */
  .trio{
    grid-template-columns:none;
    grid-auto-flow:column;
    grid-auto-columns:84%;
    gap:16px;
    overflow-x:auto;
    overscroll-behavior-x:contain;
    scroll-snap-type:x mandatory;
    scrollbar-width:none;
    -webkit-overflow-scrolling:touch;
  }
  .trio::-webkit-scrollbar{ display:none }
  .trio > *{ scroll-snap-align:start }
}

/* =========================================================
   5 · CITA CENTRADA
   Logo del cliente, la cita grande y la firma. Una sola por página.

   Va en gris, no en tinta —Stripe la pinta #64748D— y eso es deliberado: una
   cita a tamaño de titular y en negro compite con el titular de la sección. En
   gris se lee como lo que es, la voz de otro.

   Resuelve el problema de tener sólo tres testimonios: este patrón funciona
   con UNO. La rejilla de tres exige tres buenos; esta exige uno.
   ========================================================= */
.pull-quote{
  max-width:56ch;
  margin-inline:auto;
  text-align:center;
}
.pull-quote__logo{
  height:26px;
  width:auto;
  margin:0 auto 28px;
  display:block;
  object-fit:contain;
}
.pull-quote blockquote{ margin:0; }
.pull-quote blockquote p{
  margin:0;
  font:var(--type-display-md);
  letter-spacing:var(--tracking-display-md);
  color:var(--ds-text-mute);
  text-wrap:balance;
}
.pull-quote figcaption{
  display:flex;
  align-items:center;
  justify-content:center;
  gap:12px;
  margin-top:26px;
}
.pull-quote__av{
  width:38px; height:38px;
  border-radius:var(--ds-radius-pill);
  object-fit:cover;
}
.pull-quote__by{
  text-align:left;
  font:var(--type-caption);
  letter-spacing:var(--tracking-caption);
  color:var(--ds-text-mute);
}
.pull-quote__by b{
  display:block;
  font-weight:var(--font-weight-medium);
  color:var(--ds-text);
}

/* Enlace al caso. Va SÓLO en las citas cuya persona tiene landing de vídeo
   —Carnavi, Panificadora Alcalá y Prilux—; las demás no lo llevan porque no
   hay adónde ir, que es la misma regla del trío y de .reasons. Se separa de la
   firma con una línea fina para que no se lea como parte del cargo. */
.pull-quote__caso{
  display:inline-block;
  margin-top:22px;
  padding-top:18px;
  border-top:1px solid var(--color-hairline);
  font:var(--type-body-md);
  letter-spacing:var(--tracking-body);
  color:var(--color-primary);
  text-decoration:none;
}
.pull-quote__caso:hover{ text-decoration:underline; text-underline-offset:3px }
.pull-quote__caso:focus-visible{ outline:2px solid var(--color-primary); outline-offset:3px; border-radius:3px }

@media (max-width:600px){
  .pull-quote blockquote p{
    font:var(--type-heading-md);
    letter-spacing:var(--tracking-body);
  }
}

@media (prefers-reduced-motion:reduce){
  .case-list__item,.case-list__open,.rail__btn,.rail__track{ transition:none; scroll-behavior:auto; }
}

/* =========================================================
   BANDA CON FOTO DE FONDO
   Una foto de planta a sangre dentro del encuadre, con la cifra del caso
   encima. Es la única pieza del sistema donde el texto va sobre imagen, así
   que se aplican las dos reglas que eso obliga:

   1. NUNCA texto directamente sobre la foto. Va sobre un velo (`__scrim`), que
      es el mismo criterio que el lavado del shader de la hero: la legibilidad
      no se deja al azar de lo que haya en la foto. Se probó sin velo en la
      hero y hubo que revertirlo.
   2. La foto es AMBIENTE, no documento. Nunca se pone en una página de cliente
      dando a entender que es SU planta: por eso el `alt` describe la escena y
      no nombra a nadie, y por eso el pie del caso —los datos— vive fuera de la
      banda, en su propia franja de cifras.

   La proporción es apaisada y fija para que la banda no cambie de alto con la
   foto que se le ponga.
   ========================================================= */
.photo-band{
  position:relative;
  border-radius:var(--r-3, 14px);
  overflow:hidden;
  display:grid;
  /* Fila DEFINIDA, no `auto`. Con una fila automática el `height:100%` de la
     foto no tiene contra qué resolver, así que cae a su proporción natural
     —857px en vez de 430—, el velo colapsa a 0 y el texto se va fuera del
     recorte. Con `1fr` la fila mide lo que el contenedor, que sí tiene alto
     por el aspect-ratio. Y por eso el contenedor NO lleva `align-items:end`:
     eso impediría que foto y velo se estiren; abajo se ancla sólo el texto.

     `minmax(0,1fr)` y no `1fr` a secas: una pista `1fr` lleva un mínimo
     automático igual al contenido, así que la foto —857px por su proporción—
     volvía a estirar la fila y estábamos donde empezamos. El `0` es lo que le
     permite encogerse por debajo del contenido y quedarse en los 430. */
  grid-template-rows:minmax(0,1fr);
  min-height:300px;
  aspect-ratio:1200/430;
}
/* La banda es mucho más apaisada que cualquier foto (2,8:1 contra 4:3), así
   que `cover` recorta bastante. El ancla va en una variable porque el punto
   bueno depende de la foto: por defecto tira hacia arriba, que es donde suelen
   estar las caras, y cada uso lo ajusta con `--photo-band-pos` si hace falta. */
.photo-band__img{
  grid-area:1/1;
  width:100%; height:100%;
  object-fit:cover;
  object-position:var(--photo-band-pos, 50% 28%);
  display:block;
}
/* El velo: oscuro abajo, transparente arriba. Es un degradado y no un tinte
   plano porque el texto sólo ocupa la franja de abajo, y un tinte uniforme
   apagaría la foto entera sin necesidad. */
.photo-band__scrim{
  grid-area:1/1;
  background:linear-gradient(to top,
    rgba(12,16,24,.86) 0%,
    rgba(12,16,24,.62) 34%,
    rgba(12,16,24,.12) 68%,
    rgba(12,16,24,0) 100%);
}
/* Lo único que se ancla abajo. Foto y velo se estiran a toda la fila. */
.photo-band__in{
  grid-area:1/1;
  align-self:end;
  width:100%;
  padding:28px 32px;
  display:flex;
  align-items:flex-end;
  justify-content:space-between;
  gap:28px;
  flex-wrap:wrap;
}
.photo-band__claim{
  margin:0;
  max-width:44ch;
  color:#fff;
  font:var(--type-heading-md);
  letter-spacing:var(--tracking-body);
  text-wrap:balance;
}
/* La cifra grande. Sin negrita, como todo el sistema: lo que la hace pesar es
   el tamaño, no el trazo. */
.photo-band__fig{
  margin:0;
  flex:0 0 auto;
  text-align:right;
  color:#fff;
}
.photo-band__fig b{
  display:block;
  font:var(--type-display-md);
  letter-spacing:var(--tracking-display-md);
  font-weight:var(--font-weight-thin, 300);
}
.photo-band__fig span{
  display:block;
  margin-top:4px;
  font:var(--type-caption);
  letter-spacing:var(--tracking-caption);
  color:rgba(255,255,255,.76);
}

@media (max-width:719px){
  .photo-band{ aspect-ratio:4/3; min-height:0 }
  .photo-band__in{ padding:20px; flex-direction:column; align-items:flex-start; gap:14px }
  .photo-band__fig{ text-align:left }
}

/* =========================================================
   REJILLA DE ARGUMENTOS
   La celda del trío (4) con el número de celdas abierto. Mismo cuadro de icono,
   misma frase a dos tintas, mismo enlace: lo único que cambia es que el trío
   son tres columnas iguales y esto reparte sobre las doce del sistema.

   POR QUÉ NO ES UN `.trio` CON MÁS HIJOS
   El trío es la sección de cierre y su reparto de tres es parte de lo que es.
   Con cinco argumentos, un `repeat(3,1fr)` deja un hueco en la segunda fila —y
   con cinco columnas iguales la frase se parte a veintitantos caracteres—. Aquí
   el reparto se declara por celda con `data-span`, **el mismo atributo y los
   mismos valores que las escenas** (4 · 6 · 8 · 12), así que cinco argumentos
   son dos repartos permitidos apilados: 4+4+4 arriba y 6+6 abajo, sin hueco.

   LA FRASE ES UNA, Y CAMBIA DE TINTA A MITAD
   Se hereda tal cual del trío y es la regla que más fácil se rompe: no es un
   título en negrita con su párrafo debajo, es una sola oración que empieza en
   tinta y sigue en gris. El corte va donde ya lo marca la puntuación —los dos
   puntos—, igual que en el titular a dos tintas. Partirla en dos bloques
   deshace el patrón, y subir el énfasis a negrita lo deshace dos veces: el
   escalón es peso 400 sobre cuerpo 300.

   El enlace es opcional por celda: sólo lo lleva el argumento que tiene una
   página a la que llevar. Una flecha que no va a ningún sitio cuesta más
   confianza de la que gana — misma regla que `.scene__expand`.
   ========================================================= */
.reasons{
  display:grid;
  grid-template-columns:repeat(12,minmax(0,1fr));
  gap:44px 20px;
}
/* Mismos valores que .scene[data-span]: la rejilla del sistema es una sola. */
.reasons > [data-span="4"]{ grid-column:span 4 }
.reasons > [data-span="6"]{ grid-column:span 6 }
.reasons > [data-span="8"]{ grid-column:span 8 }
.reasons > [data-span="12"]{ grid-column:span 12 }
/* Sin `data-span` la celda ocupa un tercio: el caso del trío, por si alguien
   monta la rejilla sin declarar el reparto. */
.reasons > *{ grid-column:span 4 }

/* La celda —icono, frase a dos tintas y enlace— NO se define aquí: vive con la
   del trío, en el patrón 4, con los selectores agrupados. Aquí sólo el reparto. */

/* El botón que cierra la sección. Va pegado a la rejilla y no al `.wrap` para
   que el hueco sea el del componente y no dependa de lo que venga detrás. */
.reasons + .ds-btn{ margin-top:48px; }

/* Los dos tramos de abajo anulan el `data-span`, y para eso tienen que
   igualarle la especificidad: `[data-span="4"]` puntúa 0-2-0 y una media query
   no suma nada, así que con `.reasons > *` (0-1-0) el reparto de escritorio se
   quedaba puesto y la rejilla no se recomponía. Por eso el selector de aquí es
   `[data-span]` a secas —también 0-2-0, y gana por ir después—. */
@media (max-width:1100px){
  /* A dos columnas el reparto de cinco vuelve a dejar hueco, así que mandan las
     columnas: 2+2+1, con el último a lo ancho para que no quede una celda coja
     al lado de un vacío. */
  .reasons{ grid-template-columns:repeat(2,minmax(0,1fr)); gap:36px 24px; }
  .reasons > *,
  .reasons > [data-span]{ grid-column:span 1 }
  .reasons > *:last-child:nth-child(odd){ grid-column:span 2 }
}
@media (max-width:719px){
  .reasons{ grid-template-columns:1fr; gap:28px; }
  .reasons > *,
  .reasons > [data-span],
  .reasons > *:last-child:nth-child(odd){ grid-column:span 1 }
}

/* =========================================================
   6 · HUECO DE IMAGEN — provisional, y se ve que lo es
   ---------------------------------------------------------
   Marca el sitio de una foto que todavía no existe y lleva escrito dentro el
   prompt con el que pedirla. Es deliberadamente feo: un hueco que pareciera
   diseño acabaría publicándose. Cuando llegue la imagen se sustituye el bloque
   entero por su <img> y esta clase desaparece de la página.

   `--slot-ar` fija la proporción para que el hueco ocupe exactamente lo que
   ocupará la foto y el reflow al sustituirla sea cero.
   ========================================================= */
.img-slot{
  --slot-ar:4/3;
  aspect-ratio:var(--slot-ar);
  display:grid;
  align-content:center;
  gap:10px;
  padding:24px;
  border:1px dashed var(--color-hairline-input);
  border-radius:var(--ds-radius-card, 12px);
  background:
    repeating-linear-gradient(45deg,
      var(--color-canvas-soft) 0 10px,
      var(--color-canvas) 10px 20px);
}
.img-slot__tag{
  justify-self:start;
  font:var(--type-micro-cap);
  letter-spacing:1.2px;
  text-transform:uppercase;
  color:var(--color-ink-mute);
  border:1px solid var(--color-hairline);
  background:var(--color-canvas);
  border-radius:var(--ds-radius-control, 6px);
  padding:5px 8px;
}
.img-slot__prompt{
  margin:0;
  font-family:'SF Mono',ui-monospace,'Cascadia Mono','Roboto Mono',monospace;
  font-size:11.5px;
  line-height:1.55;
  font-weight:var(--font-weight-regular);
  color:var(--color-ink-secondary);
  max-width:62ch;
}
.img-slot__prompt b{ font-weight:var(--font-weight-medium); color:var(--color-ink) }

/* =========================================================
   7 · CONMUTADOR DE PANELES
   ---------------------------------------------------------
   Pestañas + panel. Una sola regla de color: el activo va en la tinta de marca
   y el resto en gris. NO se tiñe cada rol con su color — el color de módulo
   codifica módulo, conformidad y prioridad (ds/tokens.css), y usarlo para otra
   cosa rompe el sistema.

   Sin JS las tres pestañas siguen siendo botones y los tres paneles se
   muestran uno detrás de otro: el contenido está completo en el marcado, el
   script sólo lo pliega. Por eso los `hidden` los pone el script y no el HTML.
   ========================================================= */
.switch__tabs{
  display:flex;
  flex-wrap:wrap;
  gap:8px;
  padding:0 0 28px;
  border-bottom:1px solid var(--color-hairline);
  margin-bottom:32px;
}
.switch__tab{
  appearance:none;
  cursor:pointer;
  display:inline-flex;
  align-items:center;
  gap:9px;
  padding:11px 18px;
  border:1px solid var(--color-hairline);
  border-radius:999px;
  background:var(--color-canvas);
  color:var(--ds-text-mute);
  font:var(--type-body-md);
  letter-spacing:var(--tracking-body);
  transition:background .16s ease, color .16s ease, border-color .16s ease;
}
.switch__tab svg{ width:16px; height:16px; flex:none }
.switch__tab:hover{ color:var(--ds-text); border-color:var(--color-hairline-input) }
.switch__tab[aria-selected="true"]{
  background:var(--color-primary);
  border-color:var(--color-primary);
  color:var(--color-on-primary);
}
.switch__tab:focus-visible{ outline:2px solid var(--color-primary); outline-offset:2px }

.switch__panel{
  display:grid;
  grid-template-columns:minmax(0,5fr) minmax(0,7fr);
  gap:44px;
  align-items:center;
}
.switch__panel[hidden]{ display:none }
.switch__txt{ display:flex; flex-direction:column; gap:16px }
.switch__txt h3{
  margin:0;
  font:var(--type-display-md);
  letter-spacing:var(--tracking-display-md, -.4px);
  color:var(--ds-text);
}
.switch__txt p{
  margin:0;
  font:var(--type-body-lg);
  letter-spacing:var(--tracking-body);
  color:var(--ds-text-mute);
  text-wrap:pretty;
}
.switch__txt p .em{ font-weight:var(--font-weight-regular); color:var(--ds-text) }
.switch__list{ margin:0; padding:0; list-style:none; display:flex; flex-direction:column; gap:10px }
.switch__list li{
  display:grid;
  grid-template-columns:18px minmax(0,1fr);
  gap:10px;
  font:var(--type-body-md);
  letter-spacing:var(--tracking-body);
  color:var(--ds-text-mute);
}
.switch__list svg{ width:14px; height:14px; margin-top:4px; color:var(--color-primary) }

/* Cambio de panel: entra desde abajo, corto. Se anima el CONTENIDO, no la
   caja, que es la distinción del sistema. */
@media (prefers-reduced-motion:no-preference){
  .switch__panel:not([hidden]) > *{ animation:roleIn .32s cubic-bezier(.2,.7,.3,1) both }
  .switch__panel:not([hidden]) > *:nth-child(2){ animation-delay:.05s }
}
@keyframes roleIn{ from{ opacity:0; transform:translateY(10px) } to{ opacity:1; transform:none } }

@media (max-width:900px){
  .switch__panel{ grid-template-columns:1fr; gap:28px }
}

/* Modificador opcional `.switch--compacto`: menos aire en la barra de
   pestañas y foto recortada a 4:3 en vez de cuadrada — la imagen 1:1 es la
   que fija el alto de la fila (mucho más que el texto), así que reducir sólo
   el párrafo o la lista no bajaba nada. Recorte por CSS, sin tocar el
   fichero; el original sigue siendo 1100×1100 por si se usa cuadrado en otro
   sitio. Nace en /auditorias/ (9 sep 2026), petición del cliente. */
.switch--compacto .switch__tabs{ padding-bottom:18px; margin-bottom:20px }
.switch--compacto .switch__panel{ gap:32px }
.switch--compacto .switch__txt{ gap:12px }
.switch--compacto .switch__list{ gap:8px }
.switch--compacto .switch__panel > img{
  aspect-ratio:4/3;
  object-fit:cover;
  object-position:50% 30%;
}

/* — .section--ambitos-compacto —
   Petición del cliente el 11 de septiembre de 2026, tercera vuelta: el tope
   pasa del 80% al 90% del alto de la ventana, y esta vez se pide REESTRUCTURAR
   la sección, no sólo apretar valores. Las dos pasadas anteriores llegaron a
   apretar tanto (pestañas, foto y aire al mínimo) que la sección se leía
   comprimida; con 10 puntos más de margen no hace falta ese aprieto.

   Lo que se mantiene de la reestructuración real —no es aire, es maquetación—:
   el titular sigue en una columna más ancha (1.5fr/.5fr en vez de la 1.05/.85
   del patrón general, SÓLO en esta sección) para entrar en tres líneas en vez
   de cuatro. Ésa es la pieza que no escala con `vh` —depende del ancho, no del
   alto— y la que de verdad decide si la sección cabe en una ventana baja.

   Lo que se devuelve a un aire normal: las pestañas vuelven al aire de
   `.switch--compacto` sin apretar más, y la foto y el padding de la sección
   suben de tope — siguen en `vh` para comprimirse solos en una ventana baja,
   pero con un mínimo y un máximo más generosos. Comprobado contra una ventana
   de 903px: la sección queda en ~640px (71%), con margen de sobra hasta el
   90% en una ventana bastante más baja. */
.section--ambitos-compacto > .wrap{ padding-block:clamp(32px, 6vh, 72px); }
.section--ambitos-compacto .section-head--split{
  padding-bottom:24px;
  /* El margen heredado de `.section-head` en solved.css (48px, la 2.0) se
     cuela detrás del padding-bottom de este patrón —`.section-head--split`
     nunca lo anula, sólo toca margin-inline— y sumado daba 48px de aire
     fantasma entre el titular y las pestañas que ninguna regla de aquí
     explicaba. Se anuló a 0 el 15 de septiembre de 2026 y se corrigió de
     más: la línea quedaba pegada a los botones, sin aire entre la regla y
     la pestaña activa (18 sep 2026, aviso del cliente). 24px, la misma
     medida que el padding-bottom de arriba, separa la línea de los
     botones sin volver a colar el hueco de 48px que se quitó. */
  margin-bottom:24px;
}
/* El 1.5fr/.5fr sólo por encima de los 900px, que es donde `.section-head
   --split` deja de apilarse en una columna (ds/site.css). Sin el min-width,
   0-2-0 le gana en especificidad al 1fr de `@media (max-width:899px)` —que
   también es 0-1-0, la media query no suma nada— y el titular se quedaba en
   dos columnas estrechas en el móvil, partiendo cada palabra. */
@media (min-width:900px){
  .section--ambitos-compacto .section-head--split{
    grid-template-columns:minmax(0,1.5fr) minmax(0,.5fr);
  }
}
/* En la home la foto lleva maqueta de la plataforma dentro (ds/ambitos.css) y
   pide más ancho que el 5/7 del patrón: el texto de cada pestaña es un titular
   y una frase, así que la columna de texto puede ceder. Sólo por encima de
   900px, que es donde hay dos columnas. */
@media (min-width:900px){
  .section--ambitos-compacto .switch__panel{ grid-template-columns:minmax(0,4fr) minmax(0,8fr) }
}
/* !important en la altura, y no es gusto: las cuatro fotos del panel llevan
   `style="height:auto"` en el propio HTML —herencia de antes de este
   componente—, y un inline siempre gana a una regla externa por mucha clase
   que lleve delante. Sin el !important, esta regla no hacía nada: la foto se
   quedaba en su alto natural (1100×1100, cuadrada) en cuanto cargaba, que es
   más alta que el recorte 4:3 que decía sustituir. Costó una comprobación
   con la imagen a medio cargar, que enmascaraba el fallo. */
.section--ambitos-compacto .switch__panel > img{
  aspect-ratio:auto;
  height:clamp(220px, 34vh, 340px) !important;
}

/* =========================================================
   8 · ESCALERA DE PASOS
   ---------------------------------------------------------
   Tres pasos con un riel que los une. La numeración NO es decoración: aquí hay
   secuencia real —primero se mira cómo trabajan, luego se configura, luego se
   pilota—, que es la única condición del sistema para numerar.

   El riel se dibuja al entrar en pantalla (clase .is-in, la pone el script con
   IntersectionObserver). Sin JS queda pintado entero, que es el estado bueno.
   ========================================================= */
.steps{
  display:grid;
  grid-template-columns:repeat(3,minmax(0,1fr));
  gap:20px;
  position:relative;
}
/* Variante de cuatro pasos. El riel se dibuja por celda, así que no hay que
   tocar nada más: cada paso sigue llegando hasta el borde de la siguiente. */
.steps--4{ grid-template-columns:repeat(4,minmax(0,1fr)) }
@media (max-width:1000px){
  .steps--4{ grid-template-columns:repeat(2,minmax(0,1fr)); gap:36px 20px }
  /* En dos filas el riel dejaría de unir nada: el de la celda 2 apuntaría al
     vacío del final de la fila. Se apaga. */
  .steps--4 .step::before, .steps--4 .step::after{ display:none }
}
.step{ display:flex; flex-direction:column; gap:14px; position:relative }

/* El riel se dibuja POR PASO, no de un extremo a otro de la rejilla: el número
   va pegado al borde izquierdo de su columna (la celda es un flex en columna,
   no está centrada), así que un tramo colocado con porcentajes del contenedor
   nace descuadrado. De 44px —34 del círculo más 10 de aire— hasta -20px, que
   es el `gap` de la rejilla, o sea justo donde empieza el círculo siguiente.
   El último paso no lleva riel: no hay adónde ir. */
.step:not(:last-child)::before,
.step:not(:last-child)::after{
  content:"";
  position:absolute;
  top:17px; left:44px; right:-20px;
  height:1px;
}
.step:not(:last-child)::before{ background:var(--color-hairline) }
.step:not(:last-child)::after{
  background:var(--color-primary);
  transform:scaleX(0);
  transform-origin:left center;
  transition:transform .7s cubic-bezier(.4,.1,.2,1);
}
.steps.is-in .step:not(:last-child)::after{ transform:scaleX(1) }
.steps.is-in .step:nth-child(2)::after{ transition-delay:.35s }
@media (prefers-reduced-motion:reduce){
  .step:not(:last-child)::after{ transition:none }
}
.step__n{
  display:grid;
  place-items:center;
  width:34px; height:34px;
  border:1px solid var(--color-hairline);
  border-radius:999px;
  background:var(--color-canvas);
  color:var(--color-primary);
  font:var(--type-body-lg);
  letter-spacing:0;
  position:relative; z-index:1;
}
.step h3{
  margin:0;
  font:var(--type-heading-md);
  letter-spacing:var(--tracking-heading, -.2px);
  color:var(--ds-text);
}
.step p{
  margin:0;
  font:var(--type-body-md);
  letter-spacing:var(--tracking-body);
  color:var(--ds-text-mute);
  text-wrap:pretty;
}
.step__when{
  font:var(--type-caption);
  letter-spacing:.2px;
  color:var(--color-ink-mute-2);
}
@media (max-width:820px){
  .steps{ grid-template-columns:1fr; gap:32px }
  .step::before,.step::after{ display:none }
}

/* =========================================================
   10 · ESCENA CON BOCADILLO — persona usando el producto
   ---------------------------------------------------------
   Resuelve un problema que no tenía solución limpia: enseñar a alguien usando
   Solved en planta SIN inventar la interfaz. La foto o el vídeo son ambiente
   —el aparato sale con la pantalla apagada o de espaldas, nunca legible— y la
   interfaz de verdad va en un bocadillo flotante, que es la pantalla de
   ds/app.css montada en HTML.

   La clave de por qué esto funciona y una superposición sobre la pantalla del
   aparato no: el bocadillo NO tiene que casar píxel a píxel con el dispositivo.
   Flota sobre el plano y se lee como una capa aparte. NO lleva pico: no es un
   bocadillo de conversación, es la pantalla del producto sobrepuesta. Con pico
   parecía un tooltip y le daba aire de infografía a una escena documental.

   El aparato del bocadillo NO lleva marco: dentro de un bocadillo, el marco de
   dispositivo sobra y compite con la tablet que ya sale en la foto.
   ========================================================= */
.stage{
  --stage-ar:16/9;
  position:relative;
  aspect-ratio:var(--stage-ar);
  overflow:hidden;
  border-radius:var(--ds-radius-card, 12px);
  border:1px solid var(--color-hairline);
  background:var(--color-canvas-soft);
}
.stage__media,
.stage__media > *{ position:absolute; inset:0; width:100%; height:100% }
.stage__media img,
.stage__media video{ display:block; object-fit:cover }
/* Velo en degradado por el lado donde vive el bocadillo: el mismo criterio que
   .photo-band y que el lavado del shader de la hero. Sin él, una pantalla
   blanca sobre una foto clara pierde el borde. */
.stage__media::after{
  content:"";
  position:absolute; inset:0;
  background:linear-gradient(90deg, rgba(17,18,20,0) 30%, rgba(17,18,20,.45) 100%);
  pointer-events:none;
}

/* -- Variante "todavía no hay foto" -----------------------------------------
   El plano de la escena es un hueco de imagen (patrón 6) en vez de una foto.
   Se quita el velo —que existe para que el bocadillo se despegue de una foto,
   y sobre un hueco sólo ensucia el prompt— y se reserva la mitad derecha, que
   es donde vive el bocadillo, para que el prompt se siga leyendo entero.
   Cuando llegue la foto se sustituye el bloque por su <img> y esta clase
   desaparece de la página. */
.stage--hueco .stage__media::after{ display:none }
.stage--hueco .img-slot{ border:0; border-radius:0; padding-right:46% }
@media (max-width:820px){
  .stage--hueco .img-slot{ padding-right:24px }
}

@media (max-width:820px){
  .stage{ aspect-ratio:4/3 }
  .stage__bocadillo{ position:static; transform:none; width:auto; margin:0; border-radius:0 }
  .stage__media::after{ background:linear-gradient(180deg, rgba(17,18,20,0) 40%, rgba(17,18,20,.45) 100%) }
}

/* =========================================================
   CUADROS DE LA REJILLA DE ARGUMENTOS — .reasons--cuadro
   ---------------------------------------------------------
   La misma celda de siempre (icono, frase a dos tintas y enlace), metida en un
   cuadro de hairline. La rejilla nació sin marco porque iba suelta sobre el
   papel, justo debajo de su encabezado. Cuando va después de las escenas
   —marcos de radio 16 con producto dentro— el texto suelto se lee como el pie
   de la rejilla de arriba y no como seis piezas propias; el cuadro las separa.

   Radio de ficha (12) y no de escena (16), a propósito: esto es texto, no una
   ventana al producto, y el sistema distingue las dos cosas por el radio.

   La calle baja de 44 a 20: con marco, el aire va dentro del cuadro. Y el
   enlace se pega abajo con `margin-top:auto`, así que las flechas de una fila
   quedan a la misma altura aunque las frases midan distinto.
   ========================================================= */
.reasons--cuadro{ gap:20px; }
.reasons--cuadro > *{
  display:flex;
  flex-direction:column;
  padding:26px 24px;
  border:1px solid var(--color-hairline);
  border-radius:var(--ds-radius-card);
  background:var(--ds-surface);
}
.reasons--cuadro .reasons__link{ margin-top:auto; padding-top:14px; }

/* =========================================================
   11 · COMPOSICIÓN DE PLANTA — la pieza grande de una página de módulo
   La escena a escala de página: foto de faena a sangre, la pantalla del
   producto entrando por la izquierda y una píldora flotando encima. Es lo que
   en una campaña se llamaría «la creatividad principal», montada en HTML.

   DE DÓNDE SALE
   De la creatividad de portada de `mitti.com/es/gestion-de-activos`, leída de
   sus capturas el 3 de septiembre de 2026. Se copia la ESTRUCTURA —foto a
   sangre, la ficha del activo a gran escala fundida con el plano, la persona
   con el dispositivo a un lado y una tarjeta pequeña flotando—, nunca su
   paleta, su tipografía ni su interfaz.

   POR QUÉ EN HTML Y NO COMO IMAGEN
   Es la regla que este repositorio lleva escrita desde el principio: una foto
   con interfaz pegada encima no es la interfaz de Solved, y en una web que
   vende software de planta eso se nota. Montada así, la pantalla es la de
   `ds/app.css` —texto de verdad, nítido a cualquier tamaño, con los mismos
   datos que el resto del sitio—, se corrige un dato sin volver a renderizar
   nada y no envejece con la próxima release.

   LAS TRES REGLAS QUE LA SOSTIENEN
   1. **La pantalla no se retoca para que pegue con la foto.** Nada de bajarle
      la opacidad ni de teñirla: sigue siendo blanca y con sus colores de
      módulo. El fundido con el plano se hace RECORTÁNDOLA —máscara que la
      desvanece por el lado que se acerca a la persona—, no destiñéndola.
   2. **Entra cortada por el borde izquierdo**, que es la misma regla del
      fragmento de `ds/scene.css`: lo que dice "esto continúa" es el corte.
   3. **El texto nunca va directo sobre la foto**: velo en degradado, igual que
      en `.photo-band` y que el lavado del shader de la hero.

   EL ENCUADRE DE LA FOTO ES PARTE DEL COMPONENTE
   La persona y su dispositivo van en el TERCIO DERECHO y la mitad izquierda
   queda despejada, porque ahí entra la pantalla. Una foto con el sujeto
   centrado no vale: la tapa la capa de producto.

   Y LA FOTO SE PIDE LUMINOSA. El contraste lo pone el velo de esta hoja, no la
   fotografía: pedirla en penumbra por el lado de la pantalla duplica el trabajo
   del velo y devuelve imágenes oscuras y sucias.

   EL APARATO DE LA FOTO PUEDE ENSEÑAR SU CÁMARA, PERO NUNCA SOLVED
   A diferencia de `.stage` —donde el aparato sale apagado o de espaldas—, aquí
   la pantalla del dispositivo sale encendida con el visor de la cámara y la
   máquina dentro, que es lo que cuenta el gesto y lo que hace la referencia.
   La regla que sigue intacta es la de fondo: **la interfaz de Solved no se
   fotografía nunca**, va en la capa de producto montada en HTML. Por eso el
   prompt de la foto pide visor y disparador y prohíbe menús, botones con
   palabras y cualquier texto en la pantalla: en cuanto ahí aparece algo que
   parece una aplicación, la foto está inventando producto.
   ========================================================= */
.compo{
  --compo-ar:1600/1000;
  position:relative;
  margin:0;
  border-radius:var(--r-3, 14px);
  overflow:hidden;
  aspect-ratio:var(--compo-ar);
  min-height:340px;
  background:var(--color-canvas-soft);
  container-type:inline-size;
}
.compo__foto,
.compo__foto > *{ position:absolute; inset:0; width:100%; height:100% }
.compo__foto img{ display:block; object-fit:cover; object-position:var(--compo-pos, 50% 45%) }

/* Velo doble: oscurece por la izquierda —donde entra la pantalla y donde vive
   el pie— y deja limpio el tercio derecho, que es donde está la persona. El
   tramo de abajo va flojo: existe para asentar el panel sobre el suelo, no
   para tapar nada. Estaba al 66 % de cuando la composición llevaba pie, y sin
   pie eso era un viñeteado que ensuciaba el hormigón.

   OJO AL PEDIR LA FOTO: el velo es el que pone el contraste, así que la foto
   se pide LUMINOSA. Pedirla en penumbra por ese lado es el error que se cometió
   la primera vez —salían imágenes oscuras y sucias— y además duplica el trabajo
   del velo. La legibilidad no se deja al azar de lo que haya en la foto; para
   eso está esta capa. */
.compo__velo{
  position:absolute; inset:0;
  background:
    linear-gradient(90deg, rgba(12,16,24,.56) 0%, rgba(12,16,24,.30) 46%, rgba(12,16,24,0) 74%),
    linear-gradient(to top, rgba(12,16,24,.30) 0%, rgba(12,16,24,0) 38%);
  pointer-events:none;
}

/* La capa de producto. Ancho fijo en cqw para que la pantalla mantenga su
   escala respecto al plano: en porcentaje del contenedor, la app se estiraba y
   el texto interior bajaba de los 10px que es el suelo del sistema. */
.compo__ui{
  position:absolute;
  left:var(--compo-ui-x, -4cqw);
  /* Anclada POR ARRIBA y a media altura, y se sale por abajo: la corta el
     borde del plano, que es lo que hace la referencia y lo que dice «esto
     continúa». Dos cosas dependen de ello y por eso el ancla es el borde
     superior y no el inferior:
       · el activo es lo que la página vende, así que la tarjeta no puede
         subir por encima de la mitad de la imagen y taparlo;
       · con la tarjeta anclada abajo, su alto —que cambia con el contenido—
         decidía dónde empezaba, y cualquier fila de más la hacía trepar.
     Con `top` fijo, lo que cambia con el contenido es cuánto se recorta. */
  top:var(--compo-ui-t, 50%);
  width:var(--compo-ui-w, 52cqw);
  border-radius:12px;
  overflow:hidden;
  box-shadow:0 30px 70px rgba(12,16,24,.42), 0 2px 10px rgba(12,16,24,.2);
  /* El fundido con el plano. Va en la máscara y NO en la opacidad: bajarle la
     opacidad a una pantalla es lo que la convierte en un adorno y deja el
     texto del producto ilegible.

     Dónde empieza el fundido se ajusta con `--compo-ui-fade`, y hay que
     mirarlo contra la foto que toque: al 64 % se comía la última columna de la
     tabla y el cuarto contador, que es contenido y no aire. El fundido tiene
     que empezar donde la pantalla ya no dice nada. */
  -webkit-mask-image:linear-gradient(90deg, #000 0 var(--compo-ui-fade, 78%), transparent 100%);
          mask-image:linear-gradient(90deg, #000 0 var(--compo-ui-fade, 78%), transparent 100%);
}
.compo__ui .app{ position:relative; inset:auto }

/* Corchetes de encuadre: el visor con el que se apunta a la máquina. Es
   grafismo, no una afordancia — no se pulsa y no promete nada. */
.compo__mira{
  position:absolute;
  left:var(--compo-mira-x, 8cqw); top:var(--compo-mira-y, 7cqw);
  width:var(--compo-mira-s, 12cqw); aspect-ratio:1;
  pointer-events:none;
  background:
    linear-gradient(#fff,#fff) left top/1.6cqw 1.5px no-repeat,
    linear-gradient(#fff,#fff) left top/1.5px 1.6cqw no-repeat,
    linear-gradient(#fff,#fff) right top/1.6cqw 1.5px no-repeat,
    linear-gradient(#fff,#fff) right top/1.5px 1.6cqw no-repeat,
    linear-gradient(#fff,#fff) left bottom/1.6cqw 1.5px no-repeat,
    linear-gradient(#fff,#fff) left bottom/1.5px 1.6cqw no-repeat,
    linear-gradient(#fff,#fff) right bottom/1.6cqw 1.5px no-repeat,
    linear-gradient(#fff,#fff) right bottom/1.5px 1.6cqw no-repeat;
  opacity:.85;
}

/* LA CAPA DEL FRENTE — lo que pone la pantalla ENTRE el activo y la persona
   Es **la persona recortada con su silueta**, en un PNG/WebP con alfa, puesta
   encima de la capa de producto. Debajo va la fotografía entera; en medio, el
   panel; arriba, el recorte. Tres planos de verdad.

   Se probó antes con una máscara recta —la misma foto repetida y cortada por
   una vertical— y se descartó: el corte no sigue el contorno, así que el panel
   desaparecía de golpe en una línea en vez de pasar por detrás del brazo. Con
   la silueta, la mano y la tablet muerden el panel como en la referencia.

   EL RECORTE SE CALCULA, NO SE PINTA A MANO: `scripts/recorte-persona.mjs`
   saca el alfa por color —la manga de alta visibilidad y la tablet oscura son
   inconfundibles contra una nave blanca—, cierra la silueta, rellena la
   pantalla de la tablet y se queda con el trozo grande. Si se cambia la foto,
   se vuelve a pasar el script y se ajustan sus dos constantes.

   El recorte va **alineado al píxel con el fondo** y con el mismo
   `object-position`: es la misma fotografía, así que cualquier desajuste se
   ve como un fantasma doble. */
.compo__frente{
  position:absolute; inset:0;
  pointer-events:none;
}
.compo__frente img{ width:100%; height:100%; object-fit:cover; object-position:var(--compo-pos, 50% 45%); display:block }

/* ESTILO HIELO — el panel translúcido de la referencia
   La única pieza del sitio donde la pantalla del producto se retoca, y va
   declarada como excepción para que nadie la copie a una escena: aquí las
   SUPERFICIES se vuelven vidrio esmerilado, pero **el texto y los colores de
   módulo no se tocan**. Destiñe el papel, no la tinta: una pantalla con el
   texto al 60 % deja de ser producto y pasa a ser un adorno. */
.compo--hielo .compo__ui{
  border-radius:16px;
  border:1px solid rgba(255,255,255,.5);
  background:rgba(255,255,255,.42);
  -webkit-backdrop-filter:blur(26px) saturate(1.25);
          backdrop-filter:blur(26px) saturate(1.25);
  box-shadow:0 34px 80px rgba(12,16,24,.3), inset 0 1px 0 rgba(255,255,255,.6);
}
.compo--hielo .compo__ui .app{ background:transparent }
.compo--hielo .compo__ui .app__kpi{
  background:rgba(255,255,255,.34);
  border-color:rgba(255,255,255,.6);
}
/* Sin sombra propia: la sombra la lleva ya el panel de vidrio, y dos sombras
   encima de una foto clara convierten el conjunto en una mancha. */
.compo--hielo .compo__ui{ overflow:hidden }

/* La píldora flotante es la `.res-pill` de ds/scene.css, que ya viene
   posicionada: aquí se usa tal cual y su sitio se declara en el marcado con
   `style`, igual que en las escenas. No hace falta clase propia. */

.compo__pie{
  position:absolute;
  left:4%; bottom:5%; max-width:min(46ch, 52cqw);
  color:#fff;
  font:var(--type-body-md);
  letter-spacing:var(--tracking-body);
  text-shadow:0 1px 12px rgba(17,18,20,.5);
}

/* Por debajo de tablet la pantalla no cabe sin bajar de los 10px de texto, así
   que se enseña menos: la capa crece en proporción y se corta más. La foto
   pasa a un encuadre más cuadrado, como en `.stage`. */
@container (max-width: 760px){
  .compo{ --compo-ui-w:96cqw; --compo-ui-x:-10cqw; --compo-ui-t:44% }
  .compo__mira{ display:none }
  /* Sin sitio para tres planos: la capa del frente se apaga y la pantalla
     queda sobre la foto, que es lo que cabe. */
  .compo__frente{ display:none }
}
@media (max-width:820px){
  .compo{ aspect-ratio:4/3 }
  .compo__pie{ position:static; color:var(--ds-text-2); text-shadow:none; padding:14px 2px 0; max-width:none }
}

/* Variante "todavía no hay foto": mismo criterio que `.stage--hueco`. El velo
   y los corchetes se apagan —sin foto no tienen qué velar ni qué encuadrar— y
   el rótulo y el prompt se suben POR ENCIMA de la capa de producto, sobre una
   placa opaca. Si se quedan debajo, la pantalla los tapa y el hueco deja de
   avisar de que falta la foto, que es lo único que tiene que hacer. */
.compo--hueco .compo__velo,
.compo--hueco .compo__mira{ display:none }
.compo--hueco .compo__foto .img-slot{ border:0; border-radius:0; align-content:end }
.compo--hueco .img-slot__tag,
.compo--hueco .img-slot__prompt{ position:relative; z-index:4 }
.compo--hueco .img-slot__prompt{
  background:var(--color-canvas);
  border:1px solid var(--color-hairline);
  border-radius:var(--ds-radius-card, 12px);
  padding:12px 14px;
}
.compo--hueco .compo__pie{ display:none }

/* =========================================================
   11 · REJILLA DE BARRAS — el gráfico, en el material de la hero
   ---------------------------------------------------------
   La página de KPIs enseñaba sus barras sólo dentro de la maqueta de producto:
   a tamaño de captura, con la tipografía de la aplicación y recortadas por el
   marco. Esto es lo mismo dicho en la voz de la web —el ancho del encuadre, la
   tipografía del sistema y las hairlines de siempre—, y con el material del
   elemento de la hero (ds/hero-wave.js, forma "barras"): columna con bulto,
   oscura en la base, clara en la punta y con la luz entrando por arriba a la
   izquierda.

   NO ES UNA CAPTURA NI PRETENDE SERLO. La maqueta enseña el producto; esto
   enseña el dato. Por eso aquí no hay barra de aplicación, ni sidebar, ni
   cursor: hay un gráfico, dibujado con las reglas de la web.

   EL COLOR ES EL DEL MÓDULO DEL QUE SALE EL DATO, que es la regla de siempre
   (ds/tokens.css). Las tres tintas de la columna no son tres tonos elegidos
   para que combinen: son incidencias, acciones y registros. El cian del módulo
   KPIs no pinta ninguna barra —codificaría un módulo que no es el del dato—;
   se queda donde le toca, en la hero y en la línea de base.

   LAS ALTURAS VAN EN EL MARCADO, en `--v` (porcentaje de la columna) y `--s`
   (peso de cada tramo). Son los mismos números que la maqueta de producto de
   la home: cuando el dato se repite en el sitio, se repite igual.
   ========================================================= */
.kpiviz{
  display:grid;
  grid-template-columns:minmax(0,7fr) minmax(0,5fr);
  gap:64px;
  align-items:end;
}

.kpibars{ margin:0; }
.kpibars__leyenda{
  display:flex; flex-wrap:wrap; gap:6px 20px;
  margin:0 0 24px;
  padding:0; list-style:none;
}
.kpibars__lg{
  display:inline-flex; align-items:center; gap:8px;
  font:var(--type-caption); letter-spacing:var(--tracking-caption);
  color:var(--ds-text-mute);
}
.kpibars__lg::before{
  content:""; width:10px; height:10px; flex:none;
  border-radius:3px; background:var(--seg);
}

.kpibars__grid,
.kpibars__meses{
  display:grid;
  grid-template-columns:repeat(6,minmax(0,1fr));
  gap:clamp(10px,2.2vw,40px);
}
.kpibars__grid{
  align-items:stretch;
  height:clamp(200px,22vw,286px);
  border-bottom:1px solid var(--color-hairline);
}
/* La celda se estira hasta la línea de base y la columna se apoya en ella. Es
   lo que hace que el porcentaje de `--v` tenga contra qué medirse: con la celda
   ajustada al contenido, la altura de la columna se mediría contra sí misma y
   saldría cero. */
.kpibars__col{ display:flex; align-items:flex-end; }
/* La columna es el filamento de la hero puesto de pie: base firme —radio 2— y
   punta redondeada. El bulto y la luz los ponen las dos capas de degradado que
   van encima del color del módulo, no una sombra. */
.kpibars__pila{
  width:100%;
  height:calc(var(--v) * 1%);
  display:flex; flex-direction:column;
  border-radius:10px 10px 2px 2px;
  overflow:hidden;
}
.kpibars__seg{
  flex:var(--s);
  background:
    linear-gradient(102deg, rgba(255,255,255,.40), rgba(255,255,255,0) 48%),
    linear-gradient(to top, rgba(9,20,33,.24), rgba(9,20,33,0) 36%, rgba(255,255,255,.30) 100%),
    var(--seg);
}
.kpibars__meses{ margin-top:12px; }
.kpibars__mes{
  font:var(--type-micro-cap); letter-spacing:var(--tracking-micro-cap);
  text-transform:uppercase; color:var(--ds-text-mute); text-align:center;
}

/* Las categorías, en horizontal. Misma barra, tumbada: la punta redondeada se
   va al extremo derecho y la luz sigue entrando por arriba. */
.kpicats{ margin:0; display:flex; flex-direction:column; gap:18px; }
.kpicats__t{
  font:var(--type-caption); letter-spacing:var(--tracking-caption);
  color:var(--ds-text-mute); margin:0 0 2px;
}
.kpicats__fila{ display:grid; grid-template-columns:1fr auto; gap:6px 12px; align-items:baseline; }
.kpicats__lab{ font:var(--type-body-md); color:var(--ds-text-2); }
.kpicats__n{ font:var(--type-body-md); color:var(--ds-text); font-variant-numeric:tabular-nums; }
.kpicats__pista{
  grid-column:1 / -1;
  height:8px; border-radius:999px;
  background:var(--color-canvas-soft);
  overflow:hidden;
}
.kpicats__valor{
  display:block; height:100%; width:calc(var(--p) * 1%);
  border-radius:999px;
  background:
    linear-gradient(180deg, rgba(255,255,255,.38), rgba(255,255,255,0) 62%),
    var(--seg);
}

/* El color de cada tinta, del módulo del que sale el dato. */
.kpiviz [data-module="incidencias"]{ --seg:var(--module-incidencias) }
.kpiviz [data-module="acciones"]   { --seg:var(--module-acciones) }
.kpiviz [data-module="registros"]  { --seg:var(--module-registros) }
.kpiviz [data-module="kpis"]       { --seg:var(--module-kpis) }

@media (max-width:900px){
  .kpiviz{ grid-template-columns:1fr; gap:44px; align-items:stretch; }
  .kpibars__grid{ height:clamp(180px,42vw,240px); gap:8px; }
  .kpibars__meses{ gap:8px; }
}


/* =========================================================
   12 · ROTADOR DE CAPACIDADES
   ---------------------------------------------------------
   Lista de capacidades a la izquierda y la pantalla que la demuestra a la
   derecha. La activa se abre, avanza sola y arrastra el panel: es la forma de
   enseñar cuatro pantallas en el sitio de una sin que la página se alargue.
   Traído de la sección «Una única plataforma…» de mitti.com/es/gestion-de-activos
   —de la que se copia la estructura, no la paleta ni la interfaz—, con dos
   cosas que allí no están: el riel de avance, que dice cuánto queda y que esto
   se mueve solo, y el enlace al módulo dentro de cada capacidad.

   EL PANEL ES UNA `.scene`, no un componente nuevo. El lienzo teñido, el
   recorte del fragmento (`data-crop`) y el marco de dispositivo ya están
   resueltos allí, y duplicarlos aquí habría dado dos sistemas de pantalla que
   envejecen por separado. Lo único que se le quita a la escena es el reparto
   en la rejilla de doce columnas —dentro del rotador manda el rotador— y su
   rótulo, que aquí lo pone la lista.

   Sin JS: los cuatro paneles quedan uno detrás de otro y las cuatro
   descripciones abiertas. El contenido está entero en el marcado; el script
   sólo lo pliega, y por eso los `hidden` los pone él.
   ========================================================= */
.rotador{
  --rot-dur:7s;
  display:grid;
  grid-template-columns:minmax(0,5fr) minmax(0,7fr);
  gap:48px;
  align-items:center;
}
.rotador__lista{ display:flex; flex-direction:column; }

/* El riel vive en el item, no en la lista: así el tramo encendido es
   exactamente el alto de la capacidad abierta, que es lo que lo hace legible.
   Y su duración también: `--rot-dur` se declara aquí de reserva, pero el script
   la escribe en el item activo, porque una capacidad puede durar más que las
   otras (`data-dur`) cuando su pantalla es una animación larga. */
.rotador__item{
  position:relative;
  padding:20px 0 20px 22px;
  border-left:2px solid var(--color-hairline);
}
.rotador__item::before{
  content:"";
  position:absolute; left:-2px; top:0; width:2px; height:100%;
  background:var(--color-primary);
  transform:scaleY(0); transform-origin:top;
}
.rotador__item[data-activo="true"]::before{ animation:rotAvance var(--rot-dur) linear forwards }
.rotador[data-pausa="true"] .rotador__item::before{ animation-play-state:paused }
@keyframes rotAvance{ from{ transform:scaleY(0) } to{ transform:scaleY(1) } }

.rotador__btn{
  appearance:none; -webkit-appearance:none;
  display:block; width:100%; padding:0;
  border:0; background:none; cursor:pointer; text-align:left;
  font:var(--type-heading-md);
  letter-spacing:var(--tracking-body);
  color:var(--ds-text-mute);
  transition:color .18s ease;
}
.rotador__btn:hover{ color:var(--ds-text) }
.rotador__btn[aria-selected="true"]{ color:var(--ds-text) }
.rotador__btn:focus-visible{ outline:2px solid var(--color-primary); outline-offset:4px }

.rotador__cuerpo{ display:grid; gap:10px; padding-top:10px }
.rotador__cuerpo[hidden]{ display:none }
.rotador__cuerpo p{
  margin:0;
  font:var(--type-body-md);
  letter-spacing:var(--tracking-body);
  color:var(--ds-text-mute);
  text-wrap:pretty;
}
.rotador__cuerpo a{
  justify-self:start;
  font:var(--type-body-md);
  color:var(--color-primary);
  text-decoration:none;
}
.rotador__cuerpo a:hover{ text-decoration:underline }

/* La vista apila los paneles en la misma celda: sin salto de alto al cambiar
   de capacidad, que es lo que delata a un acordeón mal hecho. */
.rotador__vista{ display:grid }
.rotador__vista > .scene{
  grid-area:1 / 1;
  grid-column:auto;          /* el reparto de doce columnas no manda aquí */
  aspect-ratio:4/3;
  align-self:stretch;
}
.rotador__vista > .scene[hidden]{ display:none }
.rotador__vista .scene__title{ position:absolute; width:1px; height:1px; overflow:hidden; clip-path:inset(50%); white-space:nowrap }

/* UNA CAPACIDAD ES UN ACORDEÓN: cuenta su gesto una vez y se queda ahí. Sin
   esto, cada pieza de dentro corre en bucle (`infinite`, el valor de reserva
   de `--iter`) todo el tiempo que la capacidad siga elegida — bastaba con no
   tocar el ratón para verla repetirse una y otra vez.

   `--iter` y el atributo `data-terminado` los pone `ds/rotador.js`, no esta
   hoja — a propósito: puesto aquí en CSS puro, se aplicaría también SIN
   JavaScript, y sin script el rotador no oculta ningún panel (se ven las
   cuatro capacidades apiladas y abiertas, ver el comentario de
   `ds/rotador.js`); capar ahí la vuelta a una sola dejaría cuatro piezas
   corriendo una vez y quietas para siempre, que es peor que el bucle
   continuo de toda la vida. Con JS, `ds/rotador.js` fija `--iter:1` sobre el
   panel activo al elegirlo, lo reinicia a 0 (`getAnimations().currentTime`),
   dispara un `data-terminado` cuando el reloj de la capacidad (`data-dur`)
   se cumple —ni antes, que cortaría el gesto, ni después, que enseñaría el
   reinicio del bucle que cada pieza lleva pensado para sí misma, no para
   pararse— y lo quita al reelegir la capacidad, para que vuelva a contarse
   entera. El estado que deja `data-terminado` es el MISMO que ya describe
   cada `@media (prefers-reduced-motion:reduce)` de ds/scene.css, ds/app.css,
   ds/plantilla.css, ds/documentos.css y ds/celdas.css —el «estado resuelto,
   el que cuenta la historia entera»—, duplicado bajo `.scene[data-terminado]
   …` en cada una de esas hojas. */

@media (prefers-reduced-motion:no-preference){
  .rotador__vista > .scene:not([hidden]){ animation:rotEntra .34s cubic-bezier(.2,.7,.3,1) both }
}
@keyframes rotEntra{ from{ opacity:0 } to{ opacity:1 } }

/* Con movimiento reducido no hay avance automático (lo apaga el script) ni
   riel animado: el tramo se pinta entero y quieto. */
@media (prefers-reduced-motion:reduce){
  .rotador__item[data-activo="true"]::before{ animation:none; transform:scaleY(1) }
}

@media (max-width:900px){
  .rotador{ grid-template-columns:1fr; gap:28px }
  .rotador__vista{ order:-1 }
  /* En una columna el panel mide la mitad de ancho, y a 4:3 eso deja 270px de
     alto: el móvil de la primera capacidad salía cortado por la pantalla, que
     es lo que la escena enseña. Cuadrado cabe entero. */
  .rotador__vista > .scene{ aspect-ratio:1/1 }
}

/* =========================================================
   13 · BIBLIOTECA DE RECURSOS
   Cuatro columnas de enlaces bajo su rótulo. Cierra una página de solución con
   el contenido que el sitio ya tiene: los posts del blog y las fichas del
   glosario que responden lo que la página deja abierto.

   DE DÓNDE SALE
   Del bloque de plantillas de `mitti.com/es/gestion-de-la-calidad`, que reparte
   su biblioteca en cuatro columnas temáticas. Se copia el REPARTO, no el
   contenido: allí son plantillas descargables y aquí son páginas del propio
   sitio, que es lo que hay. Un enlace a un recurso que no existe cuesta más
   confianza de la que gana — la misma regla que `.scene__expand`.

   NO ES UNA REJILLA DE ARGUMENTOS. La celda de `.reasons` es una frase a dos
   tintas con un enlace al final; ésta es un rótulo con una lista debajo. Se
   separan porque lo que hacen es distinto: aquélla argumenta, ésta indexa.
   ========================================================= */
.reslib{
  display:grid;
  grid-template-columns:repeat(4,minmax(0,1fr));
  gap:36px 20px;
}
/* El rótulo se separa con una línea, no con un peso: los tres pesos del sistema
   no incluyen negrita, y una columna de enlaces ya pesa por sí sola. */
.reslib h3{
  margin:0 0 14px;
  padding-bottom:12px;
  font:var(--type-body-lg);
  letter-spacing:var(--tracking-body);
  color:var(--ds-text);
  border-bottom:1px solid var(--color-hairline);
}
.reslib ul{
  margin:0; padding:0;
  list-style:none;
  display:flex; flex-direction:column; gap:10px;
}
/* En gris, y en tinta sólo al pasar por encima: son veinte enlaces seguidos y
   veinte líneas en azul se leen como un error de maquetación, no como una
   lista. Mismo criterio que la cita centrada. */
.reslib a{
  font:var(--type-body-md);
  letter-spacing:var(--tracking-body);
  color:var(--ds-text-mute);
  text-decoration:none;
  text-wrap:pretty;
}
.reslib a:hover{ color:var(--color-primary); text-decoration:underline }

@media (max-width:1100px){ .reslib{ grid-template-columns:repeat(2,minmax(0,1fr)); gap:32px 24px } }
@media (max-width:719px){  .reslib{ grid-template-columns:1fr; gap:28px } }

/* --- EL ROTADOR COMO BLOQUE APARTE ------------------------------------------
   `.rotador-bloque` (9 sep 2026, petición del cliente en /auditorias/): cuando
   el rotador no abre su propia sección sino que va debajo de otra pieza —allí,
   el vídeo de IA—, necesita más aire del que separa dos piezas de la misma
   sección, o las dos se leen como una. Es el ritmo de sección (96px) dentro de
   una sección, y por eso lleva además el hilo de arriba: sin él, el aire solo
   parece un error de maquetación.

   No es una sección nueva: la regla del cliente es que una landing de módulo
   tiene dos secciones de contenido, y ésta ya es una de las dos. */
.rotador-bloque{
  margin-top:72px;
  padding-top:56px;
  border-top:1px solid var(--color-hairline);
}
@media (max-width:900px){
  .rotador-bloque{ margin-top:48px; padding-top:40px }
}

/* =========================================================
   14 · TARJETA DE CASO EN CARRIL — «con la confianza de…»
   ---------------------------------------------------------
   DE DÓNDE SALE
   La sección «Con la confianza de 80.000 organizaciones» de mitti.com/es:
   una foto de la industria del cliente con su logo encima, dos KPIs y un
   botón redondo al caso completo anclados sobre la propia foto; la cita y
   la firma debajo, ya fuera de ella. El carril que las mueve es el patrón 3
   (.rail) de esta misma hoja — misma mecánica, sólo cambia la tarjeta.

   Sólo entran los clientes con caso en vídeo — hoy Carnavi, Panificadora
   Alcalá y Prilux (ver .pull-quote__caso más arriba): son los únicos con
   foto de industria propia, dos KPIs verificados y un sitio adonde llevar
   el botón. Los que sólo tienen cita sin vídeo (Fritoper, Lácteos Romar) no
   encajan en esta tarjeta — les falta la mitad de lo que pide el patrón, y
   forzarlos habría sido inventar un KPI o un enlace que no existe. */
.rail__track--cases{ grid-auto-columns:minmax(320px,82%); gap:24px; }
@media (min-width:640px){
  .rail__track--cases{ grid-auto-columns:minmax(420px,78%); }
}
/* En pantalla de ordenador el corte deja de tener sentido: sólo hay tres
   casos, y una tercera tarjeta a medio enseñar no dice «hay más», dice que
   falta encontrar el borde. Petición del cliente el 11 de septiembre de
   2026: las dos primeras se ven ENTERAS y, al avanzar un clic —que mueve
   exactamente una tarjeta, ds/sections.js—, la tercera entra entera también.
   Se quita también el sangrado a la derecha del carril genérico (patrón 3):
   ese margen negativo existe para que la tarjeta cortada llegue justo al
   borde de la ventana, y aquí ya no hay tarjeta cortada que alinear. */
@media (min-width:1100px){
  .rail__track--cases{
    grid-auto-columns:calc((100% - 24px) / 2);
    margin-right:0;
    padding-right:0;
  }
}

.case-card{ display:block; color:inherit; text-decoration:none; }
.case-card__photo{
  position:relative; aspect-ratio:16/9; border-radius:var(--ds-radius-panel);
  overflow:hidden; background:var(--color-canvas-steel);
}
/* :not(.case-card__logo) y no sólo .case-card__photo img: el logo es OTRO
   <img> dentro de la misma caja, y sin la exclusión esta regla le ganaba en
   especificidad a .case-card__logo y lo estiraba a los cuatro bordes. */
.case-card__photo img:not(.case-card__logo){
  position:absolute; inset:0; width:100%; height:100%; object-fit:cover;
}
/* El velo sostiene el contraste de los KPIs abajo y del logo arriba a la
   izquierda: la foto es el argumento (industria del cliente), no un fondo a
   oscurecer del todo, así que el degradado izquierdo se apaga antes de
   llegar a la mitad de la tarjeta. */
.case-card__photo::after{
  content:""; position:absolute; inset:0;
  background:
    linear-gradient(180deg, rgba(11,18,32,.06) 0%, rgba(11,18,32,.82) 76%),
    linear-gradient(90deg, rgba(11,18,32,.5) 0%, rgba(11,18,32,0) 42%);
}
/* Fondo blanco, no chip oscuro: los tres logos de cliente (`clients-color`)
   llevan tinta y marca en oscuro sobre transparente — pensados para asentar
   sobre blanco, como en la franja de arriba — y sobre un chip negro
   translúcido se leían apagados. box-sizing:content-box a propósito: el
   sistema pone *{box-sizing:border-box} y con eso el padding se come la
   altura declarada — a 24px con 10px arriba y abajo quedaban 4px de imagen
   de verdad, invisible. Con content-box los 24px son del logo y el padding
   se suma fuera, que es lo que pide el chip. */
.case-card__logo{
  position:absolute; z-index:1; top:20px; left:20px; box-sizing:content-box;
  height:24px; width:auto; max-width:130px; object-fit:contain;
  background:rgba(255,255,255,.94); padding:10px 14px; border-radius:var(--ds-radius-control);
  box-shadow:0 2px 10px rgba(11,18,32,.28);
}
.case-card__kpis{
  position:absolute; z-index:1; left:20px; right:64px; bottom:20px;
  display:flex; gap:20px;
}
.case-card__kpi{ padding-left:16px; border-left:1px solid rgba(255,255,255,.35); }
.case-card__kpi:first-child{ padding-left:0; border-left:0; }
.case-card__kpi b{
  display:block; font:var(--type-heading-md); font-weight:var(--font-weight-medium); color:#fff;
}
.case-card__kpi span{
  display:block; margin-top:2px; font:var(--type-caption); color:rgba(255,255,255,.78);
}
.case-card__go{
  position:absolute; z-index:1; right:20px; bottom:20px;
  width:40px; height:40px; border-radius:50%;
  background:rgba(17,18,20,.6); display:flex; align-items:center; justify-content:center;
  color:#fff; transition:background var(--ds-motion);
}
.case-card__go svg{ width:16px; height:16px; }
.case-card:hover .case-card__go{ background:var(--color-primary); }

.case-card__foot{
  display:flex; align-items:flex-start; justify-content:space-between; gap:32px;
  margin-top:20px;
}
.case-card__quote{
  flex:1 1 auto; margin:0; font-size:18px; line-height:1.5;
  font-weight:var(--font-weight-regular); color:var(--ds-text); text-wrap:balance;
}
.case-card__by{
  flex:0 0 auto; max-width:220px; margin:0; font:var(--type-caption);
  letter-spacing:var(--tracking-caption); color:var(--ds-text-mute); text-align:right;
}
.case-card__by b{ display:block; margin-bottom:2px; font-weight:var(--font-weight-medium); color:var(--ds-text); }

@media (max-width:680px){
  .case-card__kpis{ right:20px; gap:14px; }
  .case-card__kpi b{ font-size:17px; }
  .case-card__foot{ flex-direction:column; gap:12px; }
  .case-card__by{ max-width:none; text-align:left; }
}

/* — .case-card--banda —
   La misma tarjeta del carril (arriba), sin KPIs y en formato ancho y bajo:
   /incidencias/, 11 sep 2026, segunda vuelta sobre la primera petición del
   cliente. Aquí sólo hace falta EL TESTIMONIO —cita, firma y logo—, no las
   cifras del caso: eso ya está en la propia sección, un piso más arriba.
   Cita y firma se suben a la foto en vez de ir debajo, que es lo que permite
   bajar el alto: sin un bloque de texto aparte, la tarjeta mide lo que mide
   su foto. El botón redondo (`.case-card__go`) sí se queda —es lo único que
   dice «esto se puede abrir» sin un texto de por medio—, así que el bloque de
   texto deja su esquina libre. */
.case-card--banda{ max-width:900px; margin-inline:auto; }
.case-card--banda .case-card__photo{ aspect-ratio:28/9; }
.case-card--banda .case-card__banda-txt{
  position:absolute; z-index:1; left:28px; right:76px; bottom:24px;
}
.case-card--banda .case-card__quote{
  margin:0 0 10px; color:#fff; font-size:17px; line-height:1.45; text-wrap:balance;
}
.case-card--banda .case-card__by{
  max-width:none; text-align:left; color:rgba(255,255,255,.78);
}
.case-card--banda .case-card__by b{ color:#fff; }

@media (max-width:680px){
  .case-card--banda .case-card__photo{ aspect-ratio:4/3; }
  .case-card--banda .case-card__banda-txt{ left:20px; right:64px; bottom:20px; }
  .case-card--banda .case-card__quote{ font-size:15px; }
}

/* — .section--confianza-compacta —
   Petición del cliente el 11 de septiembre de 2026: el encabezado «Con la
   confianza…» y el carril de casos son la MISMA sección y juntos no pueden
   pasar del 80% del alto de la ventana. El aire y la foto se miden en vh, no
   en px, para que la sección se comprima sola en una pantalla baja en vez de
   depender de un valor que sólo cuadra en un tamaño — comprobado en el
   navegador contra una ventana de 852px de alto, queda en ~650px (76%). */
.section--confianza-compacta > .wrap{ padding-block:clamp(28px, 5vh, 56px); }
.section--confianza-compacta .section-head--split{ padding-bottom:14px; }
.section--confianza-compacta .section-head--split .ds-btn{ margin-top:10px !important; }
.section--confianza-compacta .case-card__photo{
  aspect-ratio:auto;
  height:clamp(170px, 28vh, 280px);
}
.section--confianza-compacta .case-card__foot{ margin-top:12px; }
/* Dos líneas y se corta con puntos suspensivos: con la foto ya recortada a
   28vh, una cita de tres líneas volvía a empujar la tarjeta por encima del
   80%. */
.section--confianza-compacta .case-card__quote{
  display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical;
  overflow:hidden; font-size:16px; line-height:1.45;
}
