/* ===================================================================
   SANCLER · SPRINT 2 · movimiento
   assets/css/sprint2.css — solo lo carga la MUESTRA (home ES + ficha
   de shampoo). Se propaga a las 56 cuando Luca apruebe.

   REGLA DE LA CASA, Y VA PRIMERO: el estado por defecto es VISIBLE.
   Toda animacion cuelga de `html.js`, que pone un script en línea del
   <head>. Sin JS —o con el JS caído— la página se lee entera; antes,
   `.reveal{opacity:0}` dejaba invisible todo lo que hay bajo el
   pliegue si el observador no llegaba a correr.
   El bloque de movimiento reducido va AL FINAL del fichero, que es el
   único sitio donde gana sin pelear con especificidades. (No se nombra
   aquí la at-rule: una medición que busque el texto literal se queda
   con este comentario y da la posición equivocada. Ya pasó: alguien
   midió «3 %» y era esta línea. Para medirlo de verdad hay que buscar
   `@media(` y no la palabra suelta.)
   Cero tokens nuevos: --green/--sage/--cream/--paper/--line/--wa.
   =================================================================== */

/* ---------- 1 · sin JS, todo visible ---------- */
.reveal{opacity:1;transform:none}
html.js .reveal{opacity:0;transform:translateY(30px);
  transition:opacity 1s cubic-bezier(.2,.7,.2,1),transform 1s cubic-bezier(.2,.7,.2,1)}
html.js .reveal.in{opacity:1;transform:none}
.hero-inner>*{opacity:1;transform:none;animation:none}
html.js .hero-inner>*{opacity:0;transform:translateY(26px);
  animation:heroUp 1s cubic-bezier(.2,.7,.2,1) forwards}

/* ---------- 2 · HERO en vídeo ---------- */
.hero--video{min-height:clamp(560px,86vh,820px);display:flex;align-items:center;
  position:relative;overflow:hidden;background:var(--green)}
.hero--video .hero-video{position:absolute;inset:0;width:100%;height:100%;
  object-fit:cover;object-position:center 42%;z-index:0}
/* Dos velos: uno general para que el texto siempre tenga contraste y otro
   desde abajo, porque el producto del vídeo vive en la mitad inferior. */
.hero--video::before{content:"";position:absolute;inset:0;z-index:1;
  background:linear-gradient(180deg,rgba(5,22,21,.62),rgba(5,22,21,.30) 42%,rgba(5,22,21,.72))}
.hero--video .wrap{position:relative;z-index:2;width:100%}
.hero--video .hero-inner{max-width:680px}
.hero--video h1{font-size:clamp(34px,5.8vw,60px);line-height:1.06;color:#fff;
  text-shadow:0 2px 34px rgba(0,0,0,.42)}
.hero--video .hero-price{margin-top:14px;font-family:var(--serif);
  font-size:clamp(20px,3vw,26px);color:#fff}
.hero--video .hero-cta{margin-top:26px}
.hero--video .hero-proof{margin-top:18px}

/* ---------- 3 · NAV sticky que se contrae ---------- */
header{position:sticky;top:0;z-index:40;transition:background .3s ease,box-shadow .3s ease}
html.js header.is-fijo{background:rgba(8,40,39,.94);backdrop-filter:blur(10px);
  box-shadow:0 1px 0 rgba(169,195,182,.16)}
html.js header.is-fijo .hdr{padding-top:8px;padding-bottom:8px}
html.js header .hdr{transition:padding .3s cubic-bezier(.2,.7,.2,1)}
html.js header.is-fijo .brand img{height:38px;width:auto;transition:height .3s cubic-bezier(.2,.7,.2,1)}
html.js header .brand img{transition:height .3s cubic-bezier(.2,.7,.2,1)}

/* ---------- 4 · BANDA de la oferta · coreografía ---------- */
/* TIEMPOS · el escalonado entero cierra en <=1,5 s desde que la banda entra en
   viewport. Medido antes: terminaba a ~1,9 s, y quien llega por el ancla
   `#oferta` viene de un enlace que le prometio la oferta — es justo el que no
   puede esperar. Se comprimen retardos y duraciones; NO se toca el orden
   (envases -> GRATIS -> tachado -> cifra) ni las curvas, que son criterio de
   motion-design y no se inventan aqui. */
html.js .oferta-band__l>*,
html.js .oferta-band__r>*{opacity:0;transform:translateY(18px);
  transition:opacity .5s cubic-bezier(.2,.7,.2,1),transform .5s cubic-bezier(.2,.7,.2,1)}
html.js .oferta-band.in .oferta-band__l>*,
html.js .oferta-band.in .oferta-band__r>*{opacity:1;transform:none}
html.js .oferta-band.in .oferta-band__l>*:nth-child(1){transition-delay:.04s}
html.js .oferta-band.in .oferta-band__l>*:nth-child(2){transition-delay:.12s}
html.js .oferta-band.in .oferta-band__r>*:nth-child(1){transition-delay:.20s}
html.js .oferta-band.in .oferta-band__r>*:nth-child(2){transition-delay:.28s}
html.js .oferta-band.in .oferta-band__r>*:nth-child(3){transition-delay:.34s}
html.js .oferta-band.in .oferta-band__r>*:nth-child(4){transition-delay:.34s}
html.js .oferta-band.in .oferta-band__r>*:nth-child(5){transition-delay:.34s}

/* La cifra: lo que se paga, grande; lo que se tacha, al lado; el ahorro, en
   salvia. Nada cuenta hacia arriba: el numero es el numero. */
.oferta-precio{display:flex;flex-wrap:wrap;align-items:baseline;gap:10px 14px;margin-top:2px}
.oferta-precio__ahora{font-family:var(--serif);font-size:clamp(30px,4.6vw,42px);color:#fff;line-height:1}
.oferta-precio__antes{font-family:var(--serif);font-size:clamp(17px,2.4vw,21px);
  color:rgba(244,239,228,.62);text-decoration:line-through;text-decoration-thickness:1px}
.oferta-precio__ahorro{font-family:var(--sans);font-size:12px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--sage-2);border:1px solid rgba(169,195,182,.42);
  border-radius:40px;padding:5px 12px}
.oferta-precio__que{margin-top:10px;font-family:var(--sans);font-size:12.5px;
  letter-spacing:.04em;color:rgba(169,195,182,.9)}

/* ---------- 5 · «Los seis» escalonado por filas ---------- */
html.js .pgrid .pcard{opacity:0;transform:translateY(26px);
  transition:opacity .8s cubic-bezier(.2,.7,.2,1),transform .8s cubic-bezier(.2,.7,.2,1)}
html.js .pgrid .pcard.in{opacity:1;transform:none}

/* ---------- 6 · CINTA en marquee ---------- */
html.js .promo-bar.is-marquee .promo-bar__track{justify-content:flex-start;overflow:hidden}
html.js .promo-bar.is-marquee .promo-bar__msg{position:static;opacity:1;transform:none;
  white-space:nowrap;padding:0;text-overflow:clip;flex:0 0 auto}
html.js .promo-bar.is-marquee .promo-bar__cinta{display:flex;align-items:center;gap:0;
  animation:cintaCorre var(--cinta-dur,38s) linear infinite;will-change:transform}
html.js .promo-bar.is-marquee:hover .promo-bar__cinta{animation-play-state:paused}
@keyframes cintaCorre{from{transform:translateX(0)}to{transform:translateX(-50%)}}
/* Copias de relleno de la cinta (sprint2.js `montarCinta`): a mas ancho de
   pantalla hacen falta mas para tapar la pista. Su texto vive en CSS
   generado (`content:attr()`), no en un nodo real, para no inflar el
   conteo de palabras del gate ni la lectura de pantalla — solo la primera
   copia (sin esta clase) es texto de verdad. */
html.js .promo-bar.is-marquee .promo-bar__msg--eco::before{content:attr(data-txt) "\00A0\00B7\00A0"}

/* ---------- 7 · HECHOS · el filete se dibuja, nada cuenta ---------- */
.facts-list>div{position:relative}
html.js .facts-list>div::after{content:"";position:absolute;left:0;bottom:-1px;height:1px;
  width:0;background:var(--sage);opacity:.85;
  transition:width 1.1s cubic-bezier(.2,.7,.2,1)}
html.js .facts.in .facts-list>div::after{width:100%}
html.js .facts.in .facts-list>div:nth-child(2)::after{transition-delay:.12s}
html.js .facts.in .facts-list>div:nth-child(3)::after{transition-delay:.24s}
html.js .facts.in .facts-list>div:nth-child(4)::after{transition-delay:.36s}
/* Los hechos no son cifras que suban: tres de los cuatro son palabras, y ver
   «2022» contando desde cero se lee como un error del navegador. */
html.js .facts-list dd{opacity:0;transform:translateY(10px);
  transition:opacity .6s ease,transform .6s cubic-bezier(.2,.7,.2,1)}
html.js .facts.in .facts-list dd{opacity:1;transform:none}


/* ---------- 2b · HERO · scrim y encuadre ----------
   El titular caia sobre las etiquetas gigantes del video («LEAVE-IN»,
   «Sancler») y se peleaba con ellas. Scrim de IZQUIERDA a DERECHA, verde
   oscuro, ~75 % -> 0 % hasta el 60 % del ancho: cubre el bloque de texto y
   deja limpio el producto, que vive a la derecha del encuadre. */
/* Los numeros NO son a ojo: se compuso este degradado sobre 10 fotogramas
   reales del v3 y se midio el contraste de #fff en la caja del titular.
   Con .78/.62/.28 el peor pixel daba 1,98 — por debajo incluso del 3 que pide
   el texto grande. Peor caso de los 10 fotogramas con este perfil:
     #fff 7,01 · #cfe0d6 (el <em>) 5,10 · crema 6,11 — los tres por encima del
   4,5 de texto normal, no solo del 3 de texto grande. Mas alla del 70 % del
   ancho no hay velo: el producto se ve limpio. */
.hero--video .hero-scrim{position:absolute;inset:0;z-index:1;pointer-events:none;
  background:linear-gradient(90deg,rgba(6,26,25,.96) 0%,rgba(6,26,25,.90) 36%,
    rgba(6,26,25,.52) 56%,rgba(6,26,25,0) 70%)}
.hero--video::before{background:linear-gradient(180deg,rgba(5,22,21,.40),rgba(5,22,21,.18) 44%,rgba(5,22,21,.50))}
/* «ahora en Nueva York» no se parte: el H1 se corta antes. */
.hero--video h1{max-width:15ch}
/* Sobre imagen, el sage del <em> no pasa (1,36:1 medido por el diseñador).
   #cfe0d6, tono de la paleta viva. Cero tokens nuevos. */
.hero--video h1 em{color:#cfe0d6}
.hero--video .hero-inner{max-width:min(680px,58%)}
/* El cartel 4:5 manda en movil y no existe en escritorio. `center top` y las
   medidas declaradas vienen de la spec del diseñador (CLS 0). */
.hero-cartel{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  object-position:center top;z-index:0;display:none}
.hero-cartel[hidden]{display:none!important}
/* Sin JS no hay fuentes de video (las pone el JS para no gastar 2 MB en
   movil), asi que el cartel hace de hero tambien en escritorio: nunca un
   hueco verde. */
html:not(.js) .hero-cartel{display:block}
html:not(.js) .hero--video .hero-video{display:none}
@media(max-width:700px){
  .hero-cartel{display:block}
  .hero--video .hero-video{display:none}
  .hero--video.is-video-movil .hero-cartel{display:none}
  .hero--video.is-video-movil .hero-video{display:block}
}

/* Movil: el video es 2,67:1 y el hero medía 820 px de alto, asi que
   `object-fit:cover` lo ampliaba ~4x y lo que se veia era un frasco borroso.
   El hero baja a 70 vh, el encuadre se ancla al bodegon y el texto se apoya en
   un scrim INFERIOR, que es donde esta el texto en vertical. */
@media(max-width:700px){
  /* GEOMETRIA DEL CARTEL: 390x820, la del render del diseñador. Lo puse a
     70 vh (591 px) copiando la solucion del video y el encuadre se descuadro:
     el envase quedaba a media altura y el titular encima de la etiqueta. El
     contraste de la spec esta medido a 820; cambiar el alto cambia el encuadre
     y ya no vale lo medido. El video recortado si va a 70 vh, que es su caso.
     `svh` para que la barra del navegador no lo recorte en iOS. */
  .hero--video{min-height:min(820px,100svh)}
  .hero--video.is-video-movil{min-height:70vh}
  .hero--video .hero-video{object-position:center 42%}
  .hero--video .hero-inner{max-width:none}
  /* 33 px y la medida corta: el reparto de lineas del render del diseñador
     («Cuidado capilar / natural dominicano, / ahora en Nueva York»). */
  .hero--video h1{max-width:15ch;font-size:33px;line-height:1.1}
  /* El bloque de texto se APOYA en el suelo del scrim. Sin esto el hero lo
     centraba verticalmente y quedaban 150 px de vacio debajo. */
  .hero--video{align-items:flex-end}
  /* CTA solido crema, como la spec: verde sobre crema da 13,63:1 y el boton
     verde sobre la foto oscura se perdia. 48 px de alto minimo (zona tactil). */
  .hero--video .hero-cta .btn{background:var(--cream);border-color:var(--cream);
    color:var(--green);min-height:48px}
  /* Receta del diseñador, copiada literal de SPEC-POSTER-HERO-MOVIL.md. No se
     retoca: sus paradas estan medidas contra los pixeles reales (peor caso
     7,31:1) y la de abajo se apaga al 62 %, que es donde empieza la etiqueta
     del envase. Subirla ahoga el producto — ya pasó y esta en el descarte. */
  .hero--video .hero-scrim{background:
    linear-gradient(180deg, rgba(5,22,21,.50) 0%,  rgba(5,22,21,.14) 18%, rgba(5,22,21,0) 34%),
    linear-gradient(0deg,   rgba(5,22,21,.96) 0%,  rgba(5,22,21,.93) 34%,
                            rgba(5,22,21,.80) 45%, rgba(5,22,21,.34) 54%, rgba(5,22,21,0) 62%)}
  .hero--video .hero-price{color:var(--cream)}
  .hero--video .wrap{display:flex;align-items:flex-end;padding-bottom:clamp(28px,6vh,48px)}
}

/* ---------- 3b · FICHA · el aire de arriba ----------
   Medido: a 1440 habia 389 px entre el pie del nav y la galeria, y a 390
   habia 74. Es la primera pantalla de la pagina de producto: ese aire es
   producto que no se ve. Baja a 24 px en movil (el maximo que pidio la
   revision) y a 56 en escritorio, que mantiene el respiro sin vaciar la
   pantalla. */
.fhero{padding-top:56px}
/* Y la rejilla arranca ARRIBA, no centrada: la columna de compra mide 1242 px
   y la galeria 721, asi que `align-items:center` empujaba la foto 260 px hacia
   abajo y dejaba ese vacio de crema en la primera pantalla. La foto del
   producto tiene que estar donde mira el ojo al llegar. */
.fhero .wrap{align-items:start}
@media(max-width:700px){ .fhero{padding-top:24px} }

/* ---------- 3c · FICHA · el 32 oz deja de gritar ----------
   Medido a 390: el boton de WhatsApp del formato salon medía **345 px** de
   ancho y el CTA principal «Añadir al carrito» **259**. El canal secundario
   era mas grande que la compra, encima sobre una tarjeta verde oscura que se
   llevaba la mirada. Carrito primero: la fila pierde el fondo y se queda en
   un renglon con separador, y el boton pasa a contorno y tamaño normal.
   El enlace no se toca: el 32 oz se sigue cotizando por WhatsApp. */
.tam .tam-row.is-pro{background:transparent;border-top:1px solid var(--line);
  border-radius:0;padding-left:0;padding-right:0}
.tam .tam-row.is-pro .btn-wa{background:transparent;border:1px solid var(--line);
  color:var(--green);font-size:13px;padding:9px 14px;min-height:44px;
  width:auto;flex:0 0 auto;align-self:center}
.tam .tam-row.is-pro .btn-wa:hover{border-color:var(--green);background:transparent}
.tam .tam-row.is-pro .btn-wa svg{display:none}
@media(max-width:700px){
  .tam .tam-row.is-pro .btn-wa{width:auto;max-width:60%}
}

/* ---------- 4b · BANDA v2.1 ----------
   Fondo salvia claro, tres packshots con su margen y su encuadre, boton
   solido y la cifra con la coreografia. El verde oscuro se quedaba con un
   boton fantasma y 250 px de vacio bajo el titular; el vacio lo ocupa ahora
   el trio, que ademas es lo que la oferta pide mirar. */
.oferta-band{background:var(--sage-3);color:var(--green)}
.oferta-band__eyebrow{color:var(--green);opacity:.72}
.oferta-band h2{color:var(--green);max-width:24ch}
.oferta-band p{color:var(--ink)}
.oferta-band__code{color:var(--green);font-weight:500}
.oferta-band__fine,.oferta-band p.oferta-band__fine{color:rgba(28,37,35,.66)}
.nw{white-space:nowrap}
/* Boton SOLIDO: sobre salvia, el fantasma no se veia. */
.oferta-band a.oferta-band__cta{background:var(--green);border-color:var(--green);color:var(--cream)}
.oferta-band a.oferta-band__cta:hover{background:var(--green-2);border-color:var(--green-2)}

.oferta-trio{display:grid;grid-template-columns:repeat(3,1fr);gap:10px;margin-top:22px;
  align-items:stretch}
/* Paneles ALTOS: a 165x220 el envase era un palito. 360 px en escritorio y
   220 en movil, con recortes apretados (s23_trio_packshots.py: el envase
   ocupa el 80 % del alto). La proporcion la fija el alto, no el aspect-ratio,
   para que el trio ancle la columna izquierda. */
.oferta-trio__p{position:relative;margin:0;border-radius:4px;overflow:hidden;
  background:rgba(255,255,255,.42);height:360px}
.oferta-trio__p img{width:100%;height:100%;object-fit:cover;object-position:center;display:block}
.oferta-trio__gratis{position:absolute;left:50%;top:14px;transform:translateX(-50%);
  font-family:var(--sans);font-size:11px;letter-spacing:.2em;text-transform:uppercase;
  color:#fff;background:#0f7a41;border-radius:40px;padding:6px 14px;white-space:nowrap}

/* La cifra: el tachado se DIBUJA, no viene puesto. */
.oferta-precio__antes{position:relative;text-decoration:none}
.oferta-precio__antes>span{position:relative}
.oferta-precio__antes>span::after{content:"";position:absolute;left:-2px;right:-2px;top:52%;
  height:1.5px;background:currentColor;transform:scaleX(1);transform-origin:left center}
html.js .oferta-precio__antes>span::after{transform:scaleX(0);
  transition:transform .34s cubic-bezier(.2,.7,.2,1) .78s}
html.js .oferta-band.in .oferta-precio__antes>span::after{transform:scaleX(1)}
.oferta-precio__ahora{color:var(--green)}
.oferta-precio__antes{color:rgba(28,37,35,.55)}
.oferta-precio__ahorro{color:var(--green);border-color:rgba(8,40,39,.32)}
.oferta-precio__que{color:rgba(28,37,35,.78)}
html.js .oferta-precio__ahora{transform:translateY(8px) scale(.97);opacity:0;
  transition:opacity .34s ease 1.02s,transform .34s cubic-bezier(.2,.7,.2,1) 1.02s}
html.js .oferta-band.in .oferta-precio__ahora{transform:none;opacity:1}

/* Coreografia del trio: los envases entran escalonados y GRATIS cae encima. */
html.js .oferta-trio__p{opacity:0;transform:translateY(18px)}
html.js .oferta-band.in .oferta-trio__p{opacity:1;transform:none;
  transition:opacity .42s cubic-bezier(.2,.7,.2,1),transform .42s cubic-bezier(.2,.7,.2,1)}
html.js .oferta-band.in .oferta-trio__p:nth-child(1){transition-delay:.06s}
html.js .oferta-band.in .oferta-trio__p:nth-child(2){transition-delay:.16s}
html.js .oferta-band.in .oferta-trio__p:nth-child(3){transition-delay:.26s}
html.js .oferta-trio__gratis{opacity:0;transform:translateX(-50%) translateY(-22px)}
html.js .oferta-band.in .oferta-trio__gratis{opacity:1;transform:translateX(-50%) translateY(0);
  transition:opacity .26s ease .50s,transform .34s cubic-bezier(.34,1.56,.64,1) .50s}

@media(max-width:700px){
  .oferta-trio{gap:8px;margin-top:18px}
  .oferta-trio__p{height:220px}
  .oferta-trio__gratis{font-size:9.5px;padding:5px 9px;letter-spacing:.14em;top:9px}
  .oferta-precio__que{font-size:12px}
}

/* ===================================================================
   REDUCED MOTION · AL FINAL, que es donde gana.
   Quien pide menos movimiento ve la pagina entera, quieta y completa.
   =================================================================== */
/* ---------- ARREGLO · la galeria de la ficha desbordaba 30,7 px ----------
   Medido a 390 en /productos/shampoo/: `.pgal` media 380,7 px dentro de una
   caja de contenido de 350. No se veia como scroll lateral porque el cuerpo
   lleva `overflow-x:clip`; se veia como una foto cortada por la derecha.

   La causa no es la galeria: es la rejilla. `.fhero .wrap` es un grid de una
   sola columna en movil, y una pista `auto` se dimensiona por el contenido
   minimo de lo que lleva dentro, que puede ser MAYOR que el ancho disponible.
   Probado uno a uno: `min-width:0` en `.pgal`, en la pista, en la diapositiva
   y en los puntos NO cambia nada (380,7 en los cuatro casos); lo que lo cierra
   es declarar la pista de la rejilla con minimo cero.

   Acotado a <900 px para no tocar la rejilla de dos columnas del escritorio,
   que vive en el <style> de la pagina y es correcta. */
@media (max-width: 899px) {
  .fhero .wrap { grid-template-columns: minmax(0, 1fr); }
}

@media(prefers-reduced-motion:reduce){
  html.js .reveal,
  html.js .reveal.in,
  html.js .hero-inner>*,
  html.js .oferta-band__l>*,
  html.js .oferta-band__r>*,
  html.js .pgrid .pcard,
  html.js .facts-list dd,
  html.js .oferta-trio__p,
  html.js .oferta-trio__gratis,
  html.js .oferta-precio__ahora{opacity:1!important;transform:none!important;
    transition:none!important;animation:none!important}
  /* el tachado se ve puesto, no dibujandose */
  html.js .oferta-precio__antes>span::after{transform:scaleX(1)!important;transition:none!important}
  html.js .oferta-trio__gratis{transform:translateX(-50%)!important}
  html.js .facts-list>div::after{width:100%!important;transition:none!important}
  html.js .promo-bar.is-marquee .promo-bar__cinta{animation:none!important;transform:none!important}
  html.js header .hdr,
  html.js header .brand img{transition:none!important}
  .hero--video .hero-video{display:none}
  .hero--video{background:var(--green) url("/video/sancler-hero-v3-poster.jpg") center/cover no-repeat}
}
