/* ==========================================================================
   casos_exito.css — estilos EXCLUSIVOS de casos_exito.html
   Cargado solo desde esa página (ver <link> en casos_exito.html), después de
   styles.css. Cero selectores compartidos con Home/Servicios (#sistema,
   .services-*, .service-card) — motor y nombres de clase completamente
   propios, para que esta página pueda corregirse sin tocar app.js/styles.css
   ni arriesgar ninguna otra página del sitio.
   ========================================================================== */

/* ---------- Hero full-bleed (vídeo de fondo) ----------
   .cases-hero__content se ancla con position:absolute + top:47%/translateY(-50%) — el
   47% es fijo independientemente de cuánto mida el bloque de copy (a diferencia de un
   margin dentro de un flex centrado, cuyo efecto depende de cuánto "sobra" alrededor del
   contenido). Esto SOLO mueve el contenedor del copy; el CTA en sí sigue siendo un <a>
   normal con position:static dentro de él (brief #12). */
.cases-hero {
  position: relative;
  width: 100%;
  margin-top: 96px; /* despeja el nav fijo — mismo valor que scroll-margin-top global */
  min-height: clamp(640px, 92svh, 1080px);
  overflow: hidden;
  background: #08090C;
}
.cases-hero__media { position: absolute; inset: 0; }
.cases-hero__video {
  width: 100%;
  height: 100%;
  display: block;
  object-fit: cover;
  object-position: 58% 50%;
}
.cases-hero__overlay {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    linear-gradient(90deg, rgba(var(--bg-rgb), .94) 0%, rgba(var(--bg-rgb), .88) 26%, rgba(var(--bg-rgb), .6) 46%, rgba(var(--bg-rgb), .22) 68%, rgba(var(--bg-rgb), .04) 100%),
    linear-gradient(180deg, rgba(var(--bg-rgb), .3) 0%, transparent 20%, transparent 74%, rgba(var(--bg-rgb), .4) 100%);
}
.cases-hero__content {
  position: absolute;
  z-index: 2;
  left: 0;
  right: 0;
  top: 47%;
  transform: translateY(-50%);
  padding-left: clamp(48px, 4.6vw, 92px);
  padding-right: clamp(32px, 4vw, 72px);
}
/* Hero simplificado: solo H1 + subclaim (sin eyebrow ni CTA — retirados del markup,
   no solo ocultos). El anclaje top:47%/translateY(-50%) de .cases-hero__content sigue
   centrando correctamente el bloque aunque su altura se haya reducido. */
.cases-hero__copy {
  display: flex;
  flex-direction: column;
  max-width: 760px;
}
.cases-hero__title {
  font-family: 'Heebo', sans-serif;
  max-width: 760px;
  margin: 0;
  font-size: clamp(4.8rem, 7.2vw, 8rem);
  font-weight: 900; /* Heebo solo carga pesos discretos (…,800,900) — 850 no existe como
    cara real y el navegador lo resolvería a 900 de todas formas; se usa el valor real. */
  line-height: .9;
  letter-spacing: -.055em;
  color: var(--text);
}
.cases-hero__subclaim {
  max-width: clamp(620px, 44vw, 700px);
  margin: clamp(24px, 2.4vw, 32px) 0 0;
  font-size: clamp(1.05rem, 1.35vw, 1.35rem);
  line-height: 1.45;
  color: var(--text-secondary);
}

@media (max-width: 1023px) {
  .cases-hero { min-height: clamp(600px, 88svh, 940px); }
}
@media (max-width: 640px) {
  .cases-hero {
    min-height: clamp(560px, 84svh, 800px);
    margin-top: 88px;
  }
  .cases-hero__video { object-position: 65% center; }
  .cases-hero__overlay {
    background:
      linear-gradient(180deg, rgba(var(--bg-rgb), .5) 0%, rgba(var(--bg-rgb), .38) 32%, rgba(var(--bg-rgb), .58) 68%, rgba(var(--bg-rgb), .86) 100%),
      linear-gradient(90deg, rgba(var(--bg-rgb), .5) 0%, rgba(var(--bg-rgb), .12) 100%);
  }
  /* Mobile mantiene el copy anclado abajo (patrón ya aprobado en rondas anteriores):
     se sustituye el top:47%/translateY por bottom:0 con su propia safe area explícita
     (>=52px pedidos por el brief), en vez del centrado que usa desktop/tablet. */
  .cases-hero__content {
    top: auto;
    bottom: 0;
    transform: none;
    padding-left: clamp(20px, 5.5vw, 24px);
    padding-right: clamp(20px, 5.5vw, 24px);
    padding-bottom: calc(52px + 2vh);
  }
  .cases-hero__copy { max-width: none; }
  .cases-hero__title { font-size: clamp(3rem, 12vw, 4rem); }
  .cases-hero__subclaim { max-width: none; }
}

:root { --nav-height: 96px; }

/* ---------- Intro de #cases (editorial breve, sin cabecera enorme) ---------- */
.cases-showcase {
  background: var(--bg);
  /* .section hereda padding-block (80-128px) en los 4 lados; el de abajo es puro hueco
     muerto entre el final del track y Patterns — mismo fix que
     .services-section{padding-bottom:0} en Home. Deliberadamente SIN overflow:hidden
     aquí: un ancestro con overflow!=visible por encima de .cases-horizontal-stage
     (position:sticky) rompe el pinning por completo (bug real detectado en QA — el
     stage dejaba de fijarse y simplemente scrolleaba con la página). El contenedor real
     de Servicios (.services-section) tampoco lo usa, por la misma razón; el overflow
     horizontal ya queda contenido por .cases-horizontal-viewport. */
  padding-bottom: 0;
}
/* STORIES: gran título editorial alineado a la derecha (sin eyebrow, sin línea violeta
   — h2 funciona como la pieza tipográfica principal). Spacing hasta el primer case
   deliberadamente corto (55-85px, no el hueco de una cabecera de sección normal). */
.cases-intro {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  width: min(100%, 860px);
  margin-left: auto;
  margin-right: 0;
  text-align: right;
  padding-top: clamp(90px, 8vw, 116px);
  padding-bottom: clamp(55px, 6vw, 85px);
}
.cases-intro h2 {
  margin: 0;
  color: #08090B;
  font-family: 'Heebo', sans-serif;
  font-size: clamp(5rem, 8vw, 9rem);
  font-weight: 900;
  line-height: .82;
  letter-spacing: -.06em;
}
.cases-intro p {
  max-width: 680px;
  margin: clamp(26px, 2.5vw, 36px) 0 0;
  font-size: clamp(1.05rem, 1.4vw, 1.35rem);
  line-height: 1.45;
  color: var(--text-secondary);
  text-align: right;
}

/* ---------- Horizontal scroll-linked rail ----------
   Terminología explícita (track/stage/viewport/rail — nunca "carousel"/"slider"): el
   scroll vertical de la página es solo el INPUT que hace avanzar un recorrido
   HORIZONTAL. Mismo principio que #sistema en Home (ver casos_exito.js
   initCasesHorizontalScroll — instancia propia, jamás cargada en index.html):
   outer vertical track → stage pinned/sticky → viewport que recorta → rail que se
   traduce en X según progreso real de scroll, medido con scrollWidth real (nunca con
   el número de casos ni con vh × N). */
.cases-horizontal-stage {
  position: sticky;
  top: var(--nav-height);
  height: calc(100vh - var(--nav-height));
  height: calc(100svh - var(--nav-height));
  min-height: 460px;
  max-height: 820px;
  display: flex;
  align-items: center;
  overflow: clip;
  touch-action: pan-y;
}
/* Es el viewport quien recorta el rail (nunca body). Antes de que JS confirme el motor,
   este mismo elemento ES el fallback accesible: overflow-x:auto + scroll-snap nativo
   (brief #53) — recién cuando initCasesHorizontalScroll() añade
   .cases-scroll-linked-ready pasa a overflow:clip (brief #54, "no ocultarlo antes de
   saber que JS funciona"). */
.cases-horizontal-viewport {
  position: relative;
  width: 100%;
  min-width: 0;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scroll-padding-left: var(--pad-inline);
  scrollbar-width: none; -ms-overflow-style: none;
}
.cases-horizontal-viewport::-webkit-scrollbar { display: none; }
.cases-horizontal-viewport.cases-scroll-linked-ready { overflow: clip; }

#cases .cases-horizontal-rail {
  display: flex;
  align-items: center;
  width: max-content;
  gap: clamp(28px, 2.5vw, 44px);
  padding-inline: var(--pad-inline);
  will-change: transform;
  transform: translate3d(0, 0, 0);
  scroll-snap-type: x mandatory;
}
.cases-horizontal-viewport.cases-scroll-linked-ready .cases-horizontal-rail { scroll-snap-type: none; }

/* Indicador de progreso — discreto, línea inferior. Solo visible una vez el motor JS
   confirma el modo scroll-linked; antes de eso (o sin JS) el rail ya es accesible vía
   scroll-snap nativo y la barra no tiene progreso real que mostrar. */
.cases-progress {
  position: absolute;
  left: var(--pad-inline);
  right: var(--pad-inline);
  bottom: clamp(18px, 2.6vh, 34px);
  height: 2px;
  background: var(--border);
  border-radius: 2px;
  overflow: hidden;
  opacity: 0;
  transition: opacity .3s ease;
}
.cases-horizontal-stage.cases-scroll-linked-ready .cases-progress { opacity: 1; }
.cases-progress__bar {
  height: 100%;
  width: 100%;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left;
  will-change: transform;
}

/* ---------- Case panel: unidad editorial única (principio Globant/GUT — título, claim,
   explicación, acción DENTRO de la misma pieza) ----------
   Un único <article> por caso: contenido + media en el MISMO elemento, nunca piezas
   sueltas en el rail (brief #21). Fondo oscuro sobre sección clara — mismo lenguaje que
   Servicios (dark editorial panel sobre light section). Radius contenido (12px), borde
   sutil, SIN sombra/glassmorphism. Tamaño casi uniforme entre los 5 (±5-8%, brief #28):
   una sola regla de tamaño para todos, la variedad viene de alternar qué lado ocupa la
   media (brief #27), no de dimensiones distintas como en Servicios. */
#cases-horizontal-rail .case-panel {
  scroll-snap-align: start;
  flex: 0 0 min(76vw, 1120px);
  box-sizing: border-box;
  height: min(620px, calc(100svh - var(--nav-height) - 110px));
  min-height: 500px;
  display: grid;
  overflow: hidden;
  background: #0A0C0F;
  border: 1px solid rgba(255, 255, 255, .08);
  border-radius: 12px;
  color: #F4F5F7;
}
.case-panel:hover { border-color: rgba(255, 255, 255, .16); }
/* SURA es el único caso con 3 KPIs (2 filas de métricas en vez de 1): con la altura
   estándar, ese contenido extra llenaba casi toda la caja y el centrado vertical de
   .case-panel__content (justify-content:center) dejaba de tener margen que repartir
   arriba/abajo — el texto quedaba pegado a los bordes de la card. Un pelín más de alto
   solo para esta variante, dentro del "±5-8%" que el diseño ya contempla (ver comentario
   más arriba en esta misma regla). */
#cases-horizontal-rail .case-panel:has(.case-metrics-row--three) {
  height: min(660px, calc(100svh - var(--nav-height) - 90px));
  min-height: 540px;
}
/* content/media 52/48 — mismo split para los 5, solo cambia qué columna ocupa cada
   elemento (según el orden real en el DOM de cada caso, brief #27). */
.case-panel--media-right { grid-template-columns: minmax(0, 52%) minmax(0, 48%); }
.case-panel--media-left { grid-template-columns: minmax(0, 48%) minmax(0, 52%); }

.case-panel__media { position: relative; background: #14171C; min-height: 0; }
.case-panel__media img,
.case-panel__video {
  width: 100%;
  height: 100%;
  display: block;
  object-fit: cover;
  transition: transform .5s cubic-bezier(.2, .7, .3, 1);
}
.case-panel:hover .case-panel__media img,
.case-panel:hover .case-panel__video { transform: scale(1.02); }

.case-panel__content {
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-width: 0;
  min-height: 0;
  padding: clamp(30px, 3vw, 46px);
}

.case-panel__meta {
  display: block;
  font-family: 'Heebo', sans-serif;
  font-size: .8125rem;
  font-weight: 600;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: clamp(10px, 1.2vw, 16px);
}
.case-panel__title {
  font-family: 'Heebo', sans-serif;
  font-size: clamp(2.2rem, 3vw, 3.3rem);
  font-weight: 800;
  line-height: .98;
  letter-spacing: -.04em;
  color: #FFFFFF;
  margin-bottom: clamp(14px, 1.6vw, 20px);
}
.case-panel__label {
  font-family: 'Heebo', sans-serif;
  font-size: .75rem;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: .4em;
}
/* Explicación: legible de verdad — nunca line-clamp/overflow-hidden/font diminuta. */
.case-panel__text {
  font-size: clamp(1rem, 1.1vw, 1.125rem);
  line-height: 1.52;
  color: rgba(244, 245, 247, .7);
  max-width: 46ch;
}
.case-panel__block { margin-bottom: clamp(18px, 2.2vw, 24px); }
.case-panel__related {
  margin-top: clamp(16px, 2vw, 22px);
  font-size: .875rem;
  color: rgba(244, 245, 247, .6);
}
.case-panel__related a { color: #FFFFFF; font-weight: 600; }

/* KPI zone: separada con un divisor sutil, siempre visible (nunca cortada). */
.case-metrics-row {
  display: flex;
  flex-wrap: wrap;
  gap: clamp(22px, 2.6vw, 38px);
  margin-top: clamp(20px, 2.4vw, 28px);
  padding-top: clamp(18px, 2vw, 24px);
  border-top: 1px solid rgba(255, 255, 255, .12);
}
.case-metric { display: flex; flex-direction: column; }
.case-metric strong {
  font-family: 'Heebo', sans-serif;
  font-size: clamp(2rem, 3vw, 3.4rem);
  font-weight: 800;
  line-height: .95;
  letter-spacing: -.04em;
  color: var(--accent);
}
.case-metric span {
  font-size: .8125rem;
  color: rgba(244, 245, 247, .5);
  margin-top: .35rem;
}
/* SURA es el único caso con 3 KPIs, y sus valores son más largos ("$15,5 → $2,3",
   "2 días → 2h") que el resto ("+35%"). 2 columnas + el tercero debajo (brief #30/#43)
   en vez de forzar 3 columnas apretadas — con un tamaño de número algo más contenido
   para que ningún valor se parta en 3-4 líneas. */
.case-metrics-row--three .case-metric {
  flex: 1 1 calc(50% - 19px);
  min-width: 132px;
}
.case-metrics-row--three .case-metric strong {
  font-size: clamp(1.5rem, 2.2vw, 2.4rem);
}
/* La segunda fila de KPIs (el tercero, "debajo") sumaba su propio row-gap/margin/padding
   de sobra encima del ya ajustado espacio vertical de la card — se recorta aquí para
   recuperar el margen superior/inferior que la altura extra de arriba por sí sola no
   terminaba de devolver. */
.case-metrics-row--three {
  row-gap: clamp(12px, 1.4vw, 16px);
  margin-top: clamp(14px, 1.6vw, 18px);
  padding-top: clamp(14px, 1.6vw, 18px);
}
@media (prefers-reduced-motion: reduce) {
  .case-panel__media img,
  .case-panel__video { transition: none; }
  .case-panel:hover .case-panel__media img,
  .case-panel:hover .case-panel__video { transform: none; }
}

/* Tablet (<=1100px): el split 52/48 empieza a comprimir demasiado el copy — se cambia
   internamente a media-top (brief #52), mismo criterio que Servicios usa para
   --media-side → columna. El rail sigue horizontal, solo cambia el layout INTERNO. */
@media (max-width: 1100px) {
  /* STORIES sigue alineado a la derecha en tablet (brief #41 — nunca vuelve a
     text-align:left); solo se ajusta el hueco hasta el primer case (45-65px). */
  .cases-intro { padding-bottom: clamp(45px, 6vw, 65px); }
  #cases-horizontal-rail .case-panel {
    flex-basis: min(82vw, 760px);
    height: min(600px, calc(100svh - var(--nav-height) - 100px));
    min-height: 480px;
    display: flex;
    flex-direction: column;
  }
  #cases-horizontal-rail .case-panel:has(.case-metrics-row--three) {
    height: min(640px, calc(100svh - var(--nav-height) - 80px));
    min-height: 520px;
  }
  .case-panel--media-right,
  .case-panel--media-left { grid-template-columns: none; }
  .case-panel--media-left .case-panel__media { order: -1; }
  .case-panel__media { flex: 0 0 42%; }
  .case-panel__content { flex: 1 1 auto; padding: clamp(26px, 3.4vw, 34px); }
  .case-panel__title { font-size: clamp(1.8rem, 2.8vw, 2.3rem); }
  #cases .cases-horizontal-rail { gap: clamp(22px, 3vw, 32px); }
}

/* ---------- Mobile (<=767px): secuencia editorial VERTICAL, no rail horizontal ----------
   Decisión de UX, no un parche: el recorrido horizontal scroll-linked se apoya en un stage
   sticky de ~1 viewport de alto con overflow:clip, y una card de caso en mobile no cabe
   ahí. SURA es el caso límite — meta + título + descripción larga + 3 KPIs + servicio
   relacionado + vídeo 16:9 — y meterlo en un viewport solo se consigue encogiendo la
   tipografía, recortando texto, superponiendo contenido sobre el vídeo o anidando scrolls.
   Ninguna de las cuatro es aceptable, así que por debajo de 768px el motor horizontal se
   apaga (ver casos_exito.js: en este rango ni se inicializa) y los MISMOS .case-panel, con
   el mismo HTML y los mismos ids, se leen en vertical, donde la card puede crecer lo que
   necesite. Desktop y tablet conservan intacto el rail horizontal.

   Todo lo que sigue desmonta el andamiaje horizontal (track con altura calculada, stage
   sticky, viewport que recorta, rail en flex con transform) y lo devuelve al flujo normal.
   Los !important son deliberados y mínimos: track.height y rail.transform son estilos INLINE
   que escribe el JS del modo horizontal, y una hoja de estilos no puede ganarles de otra
   forma si se llega aquí desde un resize. */
@media (max-width: 767px) {
  /* Gutter fluido: 20px hasta ~363px, 24px a partir de ~436px. Alimenta a la vez el
     padding del rail y (vía el 100% de la card) el ancho del panel, así que izquierda y
     derecha siempre coinciden. */
  #cases { --cases-mobile-gutter: clamp(20px, 5.5vw, 24px); }

  /* STORIES mobile: target exacto del brief #41 — sigue a la derecha, título más
     compacto, hueco hasta el primer case 36-48px. */
  .cases-intro { width: 100%; align-items: flex-end; text-align: right; padding-bottom: clamp(36px, 8vw, 48px); }
  .cases-intro h2 { font-size: clamp(4rem, 18vw, 6rem); }
  .cases-intro p { max-width: min(92%, 520px); }

  .cases-horizontal-track { height: auto !important; }
  .cases-horizontal-stage {
    position: relative;
    top: auto;
    height: auto;
    min-height: 0;
    max-height: none;
    display: block;
    overflow: visible;
  }
  /* También en su variante .cases-scroll-linked-ready: si el usuario llega aquí girando el
     móvil desde horizontal, la clase puede seguir puesta el instante previo a que el JS la
     retire, y un overflow:clip heredado recortaría cards ya verticales. */
  .cases-horizontal-viewport,
  .cases-horizontal-viewport.cases-scroll-linked-ready {
    overflow: visible;
    width: 100%;
  }
  #cases .cases-horizontal-rail {
    width: 100%;
    max-width: 100%;
    min-width: 0;
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    transform: none !important;
    will-change: auto;
    /* El gutter vive AQUÍ y solo aquí: la card usa el 100% del ancho interior, sin volver a
       descontar el gutter por su cuenta (nada de calc(100vw - 48px), que lo restaría dos
       veces, ni 100vw, que ignora el contenedor y mete overflow con scrollbar). */
    padding-inline: var(--cases-mobile-gutter);
    padding-block: 0;
    gap: clamp(28px, 7vw, 36px);
    scroll-snap-type: none;
  }
  .cases-progress { display: none; }
  /* En horizontal el stage centraba verticalmente el rail y ya generaba aire por debajo.
     En vertical la última card termina donde termina la sección, y como Patterns es del
     MISMO #0A0C0F que las cards, ambas se fundían en una sola mancha oscura sin corte
     visible. Este es el único respiro que separa el final del recorrido de la sección
     siguiente (rango del brief: 32-48px). */
  .cases-showcase { padding-bottom: 40px; }

  #cases-horizontal-rail .case-panel,
  #cases-horizontal-rail .case-panel:has(.case-metrics-row--three) {
    width: 100%;
    max-width: 100%;
    min-width: 0;
    flex: none;
    height: auto;
    min-height: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    /* isolation:isolate crea un stacking context propio por card: ningún z-index interno
       (ni el de la card siguiente) puede colarse por encima del vídeo de otra. */
    position: relative;
    isolation: isolate;
    overflow: hidden;
    /* Deep link (#sura-colombia, …): en vertical el anchor nativo del navegador ya hace el
       trabajo, solo hay que despejar el nav fijo. Token real del nav mobile, con fallback. */
    scroll-margin-top: calc(var(--mobile-nav-height, 68px) + 20px);
  }
  /* Orden editorial idéntico en las 5 cards: primero se lee, después se ve. En desktop dos
     de ellas llevan la media a la izquierda; ese order:-1 del tramo tablet se anula aquí
     con la misma especificidad, o seguiría ganando por ser más específico que .case-panel__media. */
  .case-panel__content { order: 1; }
  .case-panel__media,
  .case-panel--media-left .case-panel__media { order: 2; }

  .case-panel__content {
    flex: 0 0 auto;
    min-width: 0;
    max-width: 100%;
    justify-content: flex-start;
    /* El padding-bottom (30px) es lo único que separa "Servicio relacionado" del vídeo:
       cumple el mínimo de 24px visuales sin necesidad de márgenes extra. */
    padding: 28px 24px 30px;
  }
  .case-panel__meta {
    font-size: .8125rem;
    line-height: 1.35;
    margin-bottom: 12px;
  }
  .case-panel__title { font-size: clamp(2rem, 9vw, 2.55rem); margin-bottom: 18px; }
  .case-panel__text { font-size: clamp(.95rem, 3.8vw, 1rem); }
  .case-panel__related { position: static; margin-top: 22px; margin-bottom: 0; }

  /* KPIs: UNA columna por defecto en móvil.
     Causa raíz del solape reportado en BRS: en 2 columnas la pista mide ~136px a 390px,
     pero "+$400K/mes" es un token que no puede partirse y necesita 164px — el <strong> se
     pintaba FUERA de su celda y se montaba encima del KPI vecino ("$34 → $18"). Las cajas
     .case-metric no llegaban a solaparse (por eso un test de bounding boxes lo daba por
     bueno), pero el TEXTO sí. Con una columna cada métrica dispone del ancho completo de
     la card, así que no depende de la longitud del valor: vale igual para los casos de hoy
     y para cualquier métrica que se publique mañana. */
  .case-metrics-row,
  .case-metrics-row--three {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 20px;
    margin-top: 22px;
    padding-top: 20px;
  }
  .case-metric,
  .case-metrics-row--three .case-metric {
    min-width: 0;
    max-width: 100%;
  }
  .case-metric strong {
    font-size: clamp(1.9rem, 7.6vw, 2.5rem);
    max-width: 100%;
    /* Los valores NO se parten a mitad de token: "+$400K/mes" o "$15,5 → $2,3" se leen
       enteros o no se leen. Con una sola columna ya caben, así que no hace falta romperlos. */
    overflow-wrap: normal;
    word-break: normal;
  }
  /* Con la fila completa disponible, los 3 KPIs de SURA ya no necesitan el tamaño reducido
     que compensaba las 2 columnas. */
  .case-metrics-row--three .case-metric strong { font-size: clamp(1.9rem, 7.6vw, 2.5rem); }

  .case-panel__media {
    position: relative;
    flex: none;
    width: 100%;
    max-width: 100%;
    aspect-ratio: 16 / 9;
    height: auto;
    min-height: 0;
    overflow: hidden;
  }
  .case-panel__media img,
  .case-panel__video {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
  }
}

/* 480-767px: hay ancho de sobra para dos columnas en los casos de valores cortos (+35%,
   3×, $4,72…). BRS y SURA se quedan en una: su tipografía escala con vw, así que a 480px
   "+$400K/mes" necesita ~197px contra los ~182px de pista — volvería a desbordar. */
@media (min-width: 480px) and (max-width: 767px) {
  .case-metrics-row { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .case-metrics-row--wide,
  .case-metrics-row--three { grid-template-columns: minmax(0, 1fr); }
}

@media (max-width: 360px) {
  .case-panel__content { padding: 22px 20px 24px; }
}

/* Hover solo donde hay un puntero real. En touch, :hover se queda "pegado" tras un tap y
   la media se quedaba con scale(1.02) aplicado — un zoom fantasma que el usuario no pidió
   y que además desalinea el encuadre dentro de la card. */
@media (hover: none), (pointer: coarse) {
  .case-panel:hover .case-panel__media img,
  .case-panel:hover .case-panel__video,
  .case-panel__media img,
  .case-panel__video { transform: none !important; }
  .case-panel:hover { border-color: rgba(255, 255, 255, .08); }
}

/* Floating CTAs mientras se leen los casos: en móvil el WhatsApp (abajo-derecha) y el FAB
   de cookies (abajo-izquierda) se plantaban justo encima de las cards. Se apagan solo
   mientras el centro del viewport está dentro de #cases (ver initCasesFloatingHide en
   casos_exito.js) y vuelven en Patterns/contacto — mismo patrón y mismos tiempos que el ya
   aprobado body.contact-in-view de styles.css, no un sistema nuevo. */
@media (max-width: 767px) {
  body.is-reading-cases .whatsapp-float,
  body.is-reading-cases .cookie-fab {
    opacity: 0;
    pointer-events: none;
    transform: translateY(12px);
    transition: opacity 200ms ease, transform 200ms ease;
  }
}

/* ---------- Patterns — cierre editorial oscuro, mismo negro que Equipo ----------
   Vive como sección normal del documento, FUERA de .cases-horizontal-track/-stage (ver
   HTML): en cuanto el track termina su altura calculada, el flujo normal continúa aquí
   sin ningún hueco extra propio (ver .cases-showcase{padding-bottom:0} arriba). Los 4
   accordions reutilizan el componente global .growth-service-accordion ya usado en el
   FAQ de las páginas de servicio — su CSS vive en styles.css (compartido, no
   duplicado aquí) y ya resuelve icono +/− animado, motion, focus-visible y semántica
   nativa <details>/<summary>. */
/* padding-top:0 en la sección: .patterns-inner es quien pone TODO el padding-block real
   (ver debajo) — .patterns-section hereda "padding-block: var(--section-pad)" (80-128px)
   de .section, que se SUMABA al padding-top de .patterns-inner (144px a desktop) dando
   ~270px muertos antes del eyebrow "PATTERNS". Bug real detectado en esta limpieza:
   ahora .patterns-inner es la única fuente de espaciado vertical de la sección. */
.patterns-section { background: #0A0C0F; color: #F4F5F7; padding-block: 0; }
.patterns-inner {
  display: grid;
  grid-template-columns: minmax(260px, 1fr) minmax(380px, 1.5fr);
  gap: clamp(40px, 6vw, 110px);
  align-items: start;
  /* Top reducido (antes compensaba también el eyebrow, ya retirado del HTML); bottom
     igual que antes — el brief solo señala exceso de aire ARRIBA, no abajo. */
  padding-top: clamp(90px, 8vw, 130px);
  padding-bottom: clamp(120px, 10vw, 150px);
}
/* Con el eyebrow "PATTERNS" retirado del HTML, el h2 es ahora el primer elemento de
   .patterns-head: margin-top:1rem que antes daba aire bajo el eyebrow ya no aplica (se
   quita); margin-bottom se mantiene para el respiro título→subclaim, y de paso deja
   .patterns-head y .patterns-list arrancando a la misma altura (brief: alinear
   verticalmente con el comienzo de los acordeones). */
.patterns-head h2 { margin: 0 0 1.25rem; color: #F4F5F7; }
.patterns-head .lede { color: rgba(244, 245, 247, .64); max-width: 420px; }
/* .growth-service-accordion ya trae su propio border-top + :last-child border-bottom
   (rgba(255,255,255,.08) vía var(--border) en tema oscuro) — solo se ajusta el tamaño
   del título aquí, específico de Patterns (brief #64: 1.4-2.1rem). */
.patterns-list .growth-service-accordion__title {
  font-size: clamp(1.4rem, 2vw, 2.1rem);
  font-weight: 700;
}
.patterns-list .growth-service-accordion__content p {
  font-size: clamp(1rem, 1.1vw, 1.0625rem);
  line-height: 1.55;
}

@media (max-width: 1100px) {
  .patterns-inner { padding-top: clamp(64px, 7vw, 90px); padding-bottom: clamp(90px, 9vw, 110px); }
}
@media (max-width: 900px) {
  .patterns-inner { grid-template-columns: 1fr; gap: 2rem; }
}
@media (max-width: 640px) {
  .patterns-inner { padding-top: clamp(48px, 10vw, 64px); padding-bottom: clamp(72px, 14vw, 88px); }
  .patterns-list .growth-service-accordion__title { font-size: clamp(1.05rem, 5vw, 1.2rem); }
}

/* ---------- CTA final ("Tu turno" retirado del HTML) ----------
   #contacto es compartida con Home (misma regla en styles.css, 128px de padding-top),
   pero solo en ESTA página se pide "subir" el bloque título+subclaim+formulario para
   que se perciba como una única unidad de conversión — override específico por ID, solo
   para casos_exito.html (Home no se toca). El h2→lede ya recibe su margin-bottom desde
   la regla compartida #contacto h2 en styles.css. */
#contacto { padding-top: clamp(64px, 7vw, 96px); }
