/* ==============================================================
   pages/caso.css — estilos exclusivos de esta página
   Se carga solo en su HTML correspondiente (PageSpeed).
   Requiere: tokens.css, base.css, components.css, layout.css

   Plantilla ÚNICA de Casos de Uso (casos/caso.html). Todo lo que
   cambia entre casos lo inyecta caso.js desde /data/casos.json;
   aquí no hay nada específico de un caso.
   Especificación: docs/plantilla-casos-uso-noedelaflor.md §4 y §5.

   Las medidas vienen del diseño de Figma (frame de 1440px) y quedan
   como variables editables, igual que en el resto de las páginas.
   ============================================================== */

/* --- Hero del caso --------------------------------------------------- */
/* Especificación §4 (Hero) y §5 (carga escalonada).
   Fondo carbón con el efecto de puntos (dots-effect.js, data-dots-effect),
   igual que todos los Hero del sitio. A diferencia de los Hero de las
   páginas legales / Acerca de mí (una sola columna centrada), este es
   partido: texto a la izquierda y mockup a la derecha desde 1024px.
   Mobile y tablet (<1024px): se apila, primero el texto y debajo la imagen.

   Reparto del ancho en Figma (1440px): texto 365 + gap 112 + mockup 600
   = 1077px de bloque interno, centrado. Las columnas van en `fr` para que
   la proporción se conserve en cualquier viewport intermedio. */
.cs-hero {
  --cs-hero-pad-y: clamp(var(--space-6), 4.3vw, 62px);   /* 62px en desktop */
  --cs-hero-pad-x: 20px;                  /* gutter mobile (alineado con nav/footer) */
  --cs-hero-inner-max: 1077px;            /* 365 + 112 + 600 (Figma) */
  --cs-hero-cols: minmax(0, 365fr) minmax(0, 600fr);   /* texto : mockup */
  --cs-hero-col-gap: clamp(var(--space-5), 7.8vw, 112px);
  --cs-hero-gap-title: 32px;              /* título → frase (hueco de tinta de 32px en Figma) */
  --cs-hero-gap-frase: 32px;              /* frase → lista de 2 items */
  --cs-hero-meta-gap: 12px;               /* entre los 2 items de la lista (28px de línea a línea) */
  --cs-hero-star-gap: 8px;                /* estrella → texto del item */
  --cs-hero-star-size: 16px;
  --cs-hero-media-max: 600px;             /* ancho del mockup en desktop (Figma) */
  --cs-hero-media-mobile-max: 560px;      /* tope del mockup apilado en mobile */
  --cs-hero-gap-stack: clamp(var(--space-5), 5vw, 56px); /* texto → imagen al apilarse */

  /* Placeholder de carga (§5): siluetas de tablet y celular en CSS */
  --cs-skel-border: 1px;
  --cs-skel-color: var(--color-crema-30);
  --cs-skel-pulse: 2400ms;                /* respiración del contorno, muy lenta */
  --cs-skel-fade: var(--ease-base);       /* 480ms — token global de transición */

  position: relative;                     /* contiene el canvas absoluto */
  overflow: hidden;
  background-color: var(--color-carbon);
  color: var(--color-crema);
  padding: var(--cs-hero-pad-y) var(--cs-hero-pad-x);
}

/* Canvas del efecto de puntos: detrás de todo, nunca captura el puntero
   (misma regla que los demás Hero; se repite aquí porque cada página
   carga solo su propia hoja) */
.cs-hero .dots-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

.cs-hero__inner {
  position: relative;                     /* por encima del canvas */
  max-width: var(--cs-hero-inner-max);
  margin-inline: auto;
  display: grid;
  grid-template-columns: minmax(0, 1fr);  /* mobile: una columna */
  gap: var(--cs-hero-gap-stack);
  align-items: center;
}

/* --- Columna de texto ------------------------------------------------ */
.cs-hero__content > * { margin: 0; }

/* El nombre del negocio va en oro sólido, sin itálica — mismo tratamiento
   que el título de Privacidad (.legal-hero__title--oro). Fraunces Regular
   (400), que ya viene en el <link> de fuentes: no agrega peso nuevo. */
.cs-hero__title {
  font-family: var(--font-display);
  font-weight: var(--weight-body);        /* 400 */
  /* 28px → 43px. Medido contra Figma: el título ocupa 339px de ancho, que
     corresponde a ~42px, y a 43px todavía cabe en una sola línea dentro de
     la columna de 365px (se pasa a 2 líneas a partir de ~45px). Es el mismo
     paso que usa el título del CTA final de esta misma página. */
  font-size: var(--fs-h1);
  line-height: var(--leading-tight);
  font-variation-settings: "SOFT" 0, "WONK" 1;
  color: var(--color-oro);
  margin-bottom: var(--cs-hero-gap-title);
}

.cs-hero__frase {
  font-size: var(--fs-body);              /* 16px → 18px */
  line-height: 1.5;
  margin-bottom: var(--cs-hero-gap-frase);
}

/* Lista de 2 items (paquete + ciudad / nicho) con la estrella dorada del
   sitio como viñeta — mismo patrón que los chips del Hero de Inicio
   (.hero__chip), no el check de las cards de Microservicios. */
.cs-hero__meta {
  display: flex;
  flex-direction: column;
  gap: var(--cs-hero-meta-gap);
}

.cs-hero__meta-item {
  display: flex;
  align-items: center;
  gap: var(--cs-hero-star-gap);
  font-size: var(--fs-caption);           /* 12px */
  line-height: 1.35;
}

.cs-hero__star {
  flex-shrink: 0;
  width: var(--cs-hero-star-size);
  height: var(--cs-hero-star-size);
}

/* --- Columna del mockup + carga escalonada (§5) ---------------------- */
/* El contenedor reserva su espacio desde el primer frame con la proporción
   del lienzo estándar normalizado (2417×1800), así que la silueta y la
   imagen final ocupan exactamente la misma caja: cero layout shift. */
.cs-hero__media {
  position: relative;
  width: 100%;
  max-width: var(--cs-hero-media-mobile-max);
  margin-inline: auto;
  aspect-ratio: 2417 / 1800;
}

/* Siluetas de la tablet y el celular: solo contorno, crema a baja opacidad,
   con un pulso muy suave. Posiciones y tamaños en porcentajes, calcados
   del frame estándar (medidos sobre el lienzo de 2417×1800):
     tablet  x 0     y 0     2096 × 1600
     celular x 1724  y 380    691 × 1408
   El radio va en la forma `horizontal% / vertical%` para que la esquina
   siga siendo circular a cualquier escala. */
.cs-hero__skeleton {
  position: absolute;
  inset: 0;
  animation: cs-skel-pulse var(--cs-skel-pulse) var(--curve-standard) infinite;
}

.cs-hero__skeleton::before,
.cs-hero__skeleton::after {
  content: "";
  position: absolute;
  border: var(--cs-skel-border) solid var(--cs-skel-color);
}

.cs-hero__skeleton::before {              /* tablet */
  left: 0;
  top: 0;
  width: 86.72%;                          /* 2096 / 2417 */
  height: 88.89%;                         /* 1600 / 1800 */
  border-radius: 4.4% / 5.75%;            /* r ≈ 92px del lienzo */
}

.cs-hero__skeleton::after {               /* celular */
  left: 71.33%;                           /* 1724 / 2417 */
  top: 21.11%;                            /*  380 / 1800 */
  width: 28.59%;                          /*  691 / 2417 */
  height: 78.22%;                         /* 1408 / 1800 */
  border-radius: 15.92% / 7.81%;          /* r ≈ 110px del lienzo */
}

@keyframes cs-skel-pulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.45; }
}

/* La imagen entra con un fade del token global (480ms) cuando termina de
   decodificar (caso.js usa img.decode() antes de mostrarla). Si ya venía
   en caché, decode() resuelve de inmediato y la silueta no se alcanza a
   notar. object-fit: contain la deja intacta aunque el archivo se desvíe
   un pixel de la proporción del lienzo. */
.cs-hero__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  opacity: 0;
  transition: opacity var(--cs-skel-fade) var(--curve-out);
}

.cs-hero__media.is-loaded .cs-hero__img { opacity: 1; }

.cs-hero__media.is-loaded .cs-hero__skeleton {
  opacity: 0;
  animation: none;
  transition: opacity var(--cs-skel-fade) var(--curve-out);
}

/* Si la imagen falla, se queda la silueta estática: sin pulso y sin ícono
   de imagen rota (la imagen nunca llega a opacidad 1). */
.cs-hero__media.is-error .cs-hero__skeleton { animation: none; }

/* --- Bloques El Reto / La Solución / El Resultado -------------------- */
/* Especificación §4. Un solo fondo crema para los 3 bloques, con el mismo
   ritmo vertical del resto del sitio (192px arriba y abajo).
   Zigzag de posiciones FIJAS por sección (no alternancia automática):
     El Reto      → imagen izquierda, texto derecha
     La Solución  → texto izquierda, imagen derecha
     El Resultado → imagen izquierda, texto derecha
   Las posiciones no cambian aunque falte la imagen de otra sección.

   Reparto del ancho en Figma (1440px), dentro del frame de 1280px:
     [imagen 638] [gap 59] [texto 535] [aire 48] = 1280
   El bloque de texto queda 48px adentro del borde del frame, del lado
   opuesto a la imagen; la imagen sí llega al borde. */
.cs-bloques {
  --cs-pad-y: clamp(var(--space-7), 13.3vw, 192px);
  --cs-pad-x: 20px;
  --cs-content-max: 1280px;
  --cs-bloque-gap: clamp(var(--space-6), 5.6vw, 80px);   /* entre los 3 bloques */
  --cs-cols-img: 638fr;
  --cs-cols-text: 535fr;
  --cs-col-gap: clamp(var(--space-5), 4.1vw, 59px);
  --cs-text-inset: clamp(0px, 3.3vw, 48px);  /* aire entre el texto y el borde del frame */
  --cs-title-to-text: clamp(var(--space-5), 6vw, 86px);    /* 87px de tinta en Figma */
  --cs-text-to-link: clamp(var(--space-5), 5.6vw, 80px);
  --cs-img-ratio: 2417 / 1800;            /* frame estándar de export (§3) */
  --cs-link-gap: 12px;                    /* texto → flecha */
  --cs-link-arrow: 24px;

  background-color: var(--color-crema);
  color: var(--color-carbon);
  padding: var(--cs-pad-y) var(--cs-pad-x);
}

.cs-bloques__inner {
  max-width: var(--cs-content-max);
  margin-inline: auto;
  display: flex;
  flex-direction: column;
  gap: var(--cs-bloque-gap);
}

/* Mobile y tablet (<1024px): apilado, primero título + texto y debajo la
   imagen — mismo criterio que el Hero. El orden del DOM ya es ese, así que
   aquí no hace falta tocar nada. */
.cs-bloque {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--cs-col-gap);
  align-items: center;
}

.cs-bloque__content > * { margin: 0; }

/* Apilado (<1024px): el bloque de texto se topa en el ancho de lectura en vez
   de estirarse al ancho completo del contenedor — en tablet (~1000px) daría
   líneas de más de 100 caracteres. Alineado a la izquierda, no centrado, para
   que arranque en el mismo borde que la imagen de abajo.
   No sale del diseño de Figma (que solo define 1440px y mobile); es el mismo
   ancho de lectura que ya usa la regla de imagen faltante. */
.cs-bloque__content { max-width: var(--container-narrow); }   /* 44rem */

.cs-bloque__title {
  font-family: var(--font-display);
  font-weight: var(--weight-bold);        /* Fraunces Bold (700) */
  /* 20px → 24px. Los 3 títulos medidos en Figma ("El Reto" 84px,
     "La Solución" 137px, "El Resultado" 148px de ancho) dan exactamente
     23.5px, así que va en el paso h3 — el mismo de las preguntas del FAQ,
     que también son Fraunces Bold. */
  font-size: var(--fs-h3);
  line-height: var(--leading-tight);
  font-variation-settings: "SOFT" 0, "WONK" 1;
  margin-bottom: var(--cs-title-to-text);
}

.cs-bloque__text {
  font-size: var(--fs-body);              /* 16px → 18px */
  line-height: 1.5;
}

.cs-bloque__figure {
  margin: 0;
  aspect-ratio: var(--cs-img-ratio);      /* reserva el espacio antes de cargar (CLS) */
}

.cs-bloque__img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

/* Link condicional "Visitar sitio →" (§6): al final de El Resultado,
   alineado a la derecha. Regla de links del sitio (estilo-noedelaflor.md §5):
   texto carbón sobre crema y subrayado SIEMPRE visible en oro, que engrosa
   de 1px a 2px en hover — igual que .legal-copy__link. La flecha va fuera
   del texto subrayado (así lo muestra el diseño). */
.cs-bloque__cta {
  display: flex;
  justify-content: flex-end;
  margin-top: var(--cs-text-to-link);
}

/* El `display: flex` de arriba le gana al `[hidden] { display: none }` de la
   hoja del navegador (los estilos de autor pesan más), así que el estado
   oculto hay que declararlo aquí: sin esta regla el link "Visitar sitio" se
   vería siempre, incluso con sitio_activo en false. */
.cs-bloque__cta[hidden] { display: none; }

.cs-bloque__link {
  display: inline-flex;
  align-items: center;
  gap: var(--cs-link-gap);
  font-size: var(--fs-body);
  line-height: 1.5;
  color: var(--color-carbon);
  text-decoration: none;
}

.cs-bloque__link-text {
  text-decoration: underline;
  text-decoration-color: var(--color-oro);
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  transition: text-decoration-thickness var(--ease-base) var(--curve-standard);
}

.cs-bloque__link:hover .cs-bloque__link-text,
.cs-bloque__link:focus-visible .cs-bloque__link-text { text-decoration-thickness: 2px; }

.cs-bloque__link-arrow {
  flex-shrink: 0;
  width: var(--cs-link-arrow);
  height: var(--cs-link-arrow);
  transition: transform var(--ease-base) var(--curve-standard);
}

.cs-bloque__link:hover .cs-bloque__link-arrow { transform: translateX(4px); }

/* Regla de imagen faltante (§4): si el campo screenshot_* viene "", la
   sección no reserva espacio de imagen y el texto pasa a un bloque a ancho
   de lectura, centrado. caso.js pone la clase y oculta el <figure>. */
.cs-bloque--sin-imagen { grid-template-columns: minmax(0, 1fr); }

.cs-bloque--sin-imagen .cs-bloque__figure { display: none; }

.cs-bloque--sin-imagen .cs-bloque__content {
  /* width: 100% es obligatorio: margin-inline: auto en un item de grid lo
     saca de `stretch` y lo encoge a su ancho de contenido, así que sin esto
     un párrafo corto quedaría en una columna angosta en vez de llegar al
     ancho de lectura. */
  width: 100%;
  max-width: var(--container-narrow);     /* 44rem — ancho de lectura */
  margin-inline: auto;
}

/* --- Desktop (≥1024px): Hero partido y bloques en zigzag ------------- */
@media (min-width: 64em) {
  .cs-hero__inner {
    grid-template-columns: var(--cs-hero-cols);
    gap: var(--cs-hero-col-gap);
  }

  .cs-hero__media {
    max-width: var(--cs-hero-media-max);
    margin-inline: 0;
  }

  .cs-bloque {
    grid-template-columns: minmax(0, var(--cs-cols-img)) minmax(0, var(--cs-cols-text));
  }

  /* En desktop el ancho lo fija la columna del grid (535px) */
  .cs-bloque__content { max-width: none; }

  /* El Reto y El Resultado: imagen a la izquierda, texto a la derecha.
     El orden del DOM es texto → imagen (para el apilado de mobile), así
     que en desktop se colocan por columna explícita. */
  .cs-bloque--img-izq {
    padding-right: var(--cs-text-inset);
  }

  .cs-bloque--img-izq .cs-bloque__figure  { grid-column: 1; grid-row: 1; }
  .cs-bloque--img-izq .cs-bloque__content { grid-column: 2; grid-row: 1; }

  /* La Solución: texto a la izquierda, imagen a la derecha */
  .cs-bloque--img-der {
    grid-template-columns: minmax(0, var(--cs-cols-text)) minmax(0, var(--cs-cols-img));
    padding-left: var(--cs-text-inset);
  }

  .cs-bloque--img-der .cs-bloque__content { grid-column: 1; grid-row: 1; }
  .cs-bloque--img-der .cs-bloque__figure  { grid-column: 2; grid-row: 1; }

  /* Sin imagen: vuelve a una sola columna centrada, sin el aire lateral
     que compensaba a la imagen */
  .cs-bloque--sin-imagen,
  .cs-bloque--sin-imagen.cs-bloque--img-der {
    grid-template-columns: minmax(0, 1fr);
    padding-inline: 0;
  }

  .cs-bloque--sin-imagen .cs-bloque__content { grid-column: 1; }
}

/* --- Movimiento reducido (§5) ---------------------------------------- */
/* Sin pulso en la silueta y sin fade: la imagen aparece directo. */
@media (prefers-reduced-motion: reduce) {
  .cs-hero__skeleton { animation: none; }
  .cs-hero__img,
  .cs-hero__media.is-loaded .cs-hero__skeleton,
  .cs-bloque__link-text,
  .cs-bloque__link-arrow { transition: none; }
}
