/* =============================================================
   TEN TEN BEAUTY — hoja de estilo
   Sistema: claro y aireado · blanco + cielo · Montserrat Light
   Fuente del sistema: Brand Book Ten ten Beauty.pdf (ver DESIGN.md)
   ============================================================= */

/* ---------- 1 · Tokens ---------- */
:root {
  /* --- Colores de LINEA (HEX exacto del Brand Book, casados a Pantone).
         Regla dura: solo significan familia de producto. Nunca los uses
         como color de interfaz. Ver DESIGN.md § "La regla del color". --- */
  --tt-frizz:        #FFA400;  /* ANTI FRIZZ  · PMS 137C  */
  --tt-curls:        #00A0DF;  /* CURLS       · PMS 299C  */
  --tt-color:        #9E28B5;  /* COLOR CARE  · PMS 2592C */
  --tt-repair:       #76BC21;  /* REPAIR      · PMS 388C  */
  --tt-gray:         #939598;  /* COMPLEMENTARY · PMS 424C */

  /* --- Neutros (interfaz). El casi-negro es el de las portadas del
         Brand Book; los derivados van en OKLCH. --- */
  --ink:             #231F20;
  --ink-soft:        oklch(0.42 0.006 285);
  /* 0.545 y no 0.58: a 0.58 el texto secundario (pies de foto, notas de canal,
     .eyebrow) daba 4.28:1 sobre --surface y 4.17:1 sobre --paper-soft, debajo
     del 4.5 que pide WCAG AA para texto normal. A 0.545 pasa sobre los tres
     fondos claros del sitio. Si lo aclaras, vuelve a medir. */
  --ink-mute:        oklch(0.545 0.005 285);
  --ink-faint:       oklch(0.72 0.004 285);

  --paper:           oklch(0.992 0.002 250);  /* fondo de pagina */
  --paper-soft:      oklch(0.972 0.004 240);  /* secciones alternas */
  --surface:         #FFFFFF;                 /* tarjetas y planos de producto */

  --rule:            oklch(0.90 0.004 250);
  --rule-soft:       oklch(0.945 0.003 250);

  /* --- Tipografia (Brand Book pag. 16: Montserrat Light + Bold) --- */
  --font: "Montserrat", "Helvetica Neue", system-ui, -apple-system, sans-serif;

  --fs-caption: 0.75rem;
  --fs-small:   0.875rem;
  --fs-body:    1rem;
  --fs-lead:    clamp(1.0625rem, 1rem + 0.3vw, 1.25rem);
  --fs-h4:      1.25rem;
  --fs-h3:      clamp(1.375rem, 1.1rem + 1.1vw, 1.875rem);
  --fs-h2:      clamp(1.875rem, 1.2rem + 2.6vw, 3.25rem);
  --fs-h1:      clamp(2.25rem, 1.3rem + 4.2vw, 4.75rem);

  /* El "tono" tipografico de la marca: ligero, ancho, versalitas.
     Sale de las portadas del propio Brand Book. */
  --track-wide: 0.16em;
  --track-mid:  0.08em;

  /* --- Espaciado (base 4px) --- */
  --sp-1: 4px;   --sp-2: 8px;   --sp-3: 12px;  --sp-4: 16px;
  --sp-5: 24px;  --sp-6: 32px;  --sp-7: 48px;  --sp-8: 64px;
  --sp-9: 96px;  --sp-10: 128px; --sp-11: 192px;

  /* --- Layout --- */
  --maxw:        1280px;
  --maxw-narrow: 940px;
  --maxw-prose:  680px;
  --pad-x:       clamp(20px, 4vw, 64px);
  --section-y:   clamp(72px, 8vw, 136px);

  /* --- Radios y movimiento --- */
  --r-sm: 4px;  --r-md: 10px;  --r-lg: 18px;
  --ease: cubic-bezier(0.22, 1, 0.36, 1);
  --t-fast: 180ms;  --t-base: 320ms;  --t-slow: 640ms;
}

/* ---------- 2 · Reset ---------- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}
body {
  margin: 0;
  font-family: var(--font);
  font-weight: 400;
  font-size: var(--fs-body);
  line-height: 1.65;
  color: var(--ink-soft);
  background: var(--paper);
  -webkit-font-smoothing: antialiased;
}
/* `height:auto` NO es decorativo. Los <img> llevan width/height en el HTML para
   que el navegador reserve el espacio y no haya salto de layout (CLS); esos
   atributos entran como `height:1000px` y, si el CSS no pisa la altura, GANAN
   sobre `aspect-ratio` (que solo calcula la dimension que falta). Sin esta
   linea las fotos de las tarjetas de linea se pintaban de 1000px de alto.
   Las alturas explicitas por clase (.hero__photo, .brand-mark img...) siguen
   ganando por especificidad. */
img, picture, svg { display: block; max-width: 100%; }
img { height: auto; }
a { color: inherit; }
h1, h2, h3, h4 { margin: 0; color: var(--ink); line-height: 1.12; font-weight: 300; }
p { margin: 0; }
ul, ol { margin: 0; padding: 0; list-style: none; }
button { font: inherit; color: inherit; }

:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 3px;
  border-radius: var(--r-sm);
}

.visually-hidden {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* [hidden] tiene que GANARLE a cualquier display de componente.
   La regla del user-agent es `[hidden]{display:none}` con especificidad 0-1-0,
   asi que un `.btn{display:inline-flex}` la pisa y el elemento se pinta igual
   aunque el JS le haya puesto hidden=true. Paso aqui con el boton de WhatsApp
   (2026-08-10): se veia en pantalla con el atributo puesto. */
[hidden] { display: none !important; }

/* ---------- 3 · Primitivas ---------- */
.wrap {
  width: 100%;
  max-width: var(--maxw);
  margin-inline: auto;
  padding-inline: var(--pad-x);
}
.wrap--narrow { max-width: var(--maxw-narrow); }

.section { padding-block: var(--section-y); }
.section--soft { background: var(--paper-soft); }

/* Ojo tipografico de la marca: ligero, muy espaciado, versalitas. */
.eyebrow {
  font-size: var(--fs-caption);
  font-weight: 600;
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--ink-mute);
  margin-bottom: var(--sp-4);
}
.h-display {
  font-size: var(--fs-h1);
  font-weight: 300;
  letter-spacing: -0.015em;
}
.h-section {
  font-size: var(--fs-h2);
  font-weight: 300;
  letter-spacing: -0.01em;
}
/* `.lead` siempre va debajo de un titular, asi que el margen es del componente
   y no un `style=` suelto en el HTML: sin estilos en linea, la CSP puede ir con
   `style-src 'self'` en vez de tener que abrir 'unsafe-inline'. */
.lead {
  margin-top: var(--sp-5);
  font-size: var(--fs-lead);
  font-weight: 300;
  color: var(--ink-soft);
  max-width: var(--maxw-prose);
}

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  padding: var(--sp-4) var(--sp-6);
  font-size: var(--fs-small);
  font-weight: 600;
  letter-spacing: var(--track-mid);
  text-transform: uppercase;
  text-decoration: none;
  border: 1px solid var(--ink);
  border-radius: 999px;
  cursor: pointer;
  transition: background var(--t-fast) var(--ease),
              color var(--t-fast) var(--ease),
              transform var(--t-fast) var(--ease);
}
.btn:hover { transform: translateY(-1px); }
.btn--solid { background: var(--ink); color: var(--paper); }
.btn--solid:hover { background: var(--ink-soft); border-color: var(--ink-soft); }
.btn--ghost { background: transparent; color: var(--ink); }
.btn--ghost:hover { background: var(--ink); color: var(--paper); }
.btn--onphoto {
  background: var(--surface);
  color: var(--ink);
  border-color: var(--surface);
}
.btn--onphoto:hover { background: var(--ink); color: var(--surface); border-color: var(--ink); }

/* ---------- 4 · Header ---------- */
.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: color-mix(in oklch, var(--paper) 88%, transparent);
  backdrop-filter: saturate(180%) blur(12px);
  border-bottom: 1px solid var(--rule-soft);
}
.site-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-5);
  min-height: 68px;
}
.brand-mark { display: block; flex: none; }
.brand-mark img { width: auto; height: 42px; }

.nav { display: flex; align-items: center; gap: var(--sp-6); }
.nav a {
  font-size: var(--fs-caption);
  font-weight: 600;
  letter-spacing: var(--track-mid);
  text-transform: uppercase;
  color: var(--ink-soft);
  text-decoration: none;
  padding-block: var(--sp-2);
  border-bottom: 1px solid transparent;
  transition: color var(--t-fast) var(--ease),
              border-color var(--t-fast) var(--ease);
}
.nav a:hover { color: var(--ink); border-bottom-color: var(--ink); }
/* main.js marca la seccion visible con aria-current. Sin esta regla el estado
   se calculaba y no se veia: el atributo estaba puesto y el nav no cambiaba. */
.nav a[aria-current] { color: var(--ink); border-bottom-color: var(--ink); }

/* Debajo de 860px los cuatro enlaces no caben en una fila junto al logotipo
   (~320px de texto contra ~300px libres). En vez de esconder el nav completo
   —la pagina mide ~8,800px en celular y quedaba sin ningun salto— se dejan
   fuera los tres informativos, que el scroll recorre igual, y se conserva el
   unico que es una ACCION, como pildora. */
.nav__cta { white-space: nowrap; }

@media (max-width: 860px) {
  .nav a:not(.nav__cta) { display: none; }
  /* 🚨 Va como `.nav a.nav__cta` y NO como `.nav__cta` a secas.
     Arriba esta `.nav a { border-bottom: 1px solid transparent }` con
     especificidad 0-1-1; un `.nav__cta` suelto es 0-1-0 y PIERDE — y las media
     queries no suman especificidad. Resultado: la pildora se pintaba con
     borde arriba y a los lados pero con el de abajo transparente, o sea
     "cortada por abajo". Mismo tipo de bug que el de `[hidden]`: la regla
     general le gana a la del componente. */
  .nav a.nav__cta {
    padding: var(--sp-2) var(--sp-4);
    border: 1px solid var(--ink);
    border-radius: 999px;
    color: var(--ink);
  }
  .nav a.nav__cta:hover,
  .nav a.nav__cta:focus-visible {
    background: var(--ink);
    color: var(--paper);
    border-color: var(--ink);
  }
}

/* ---------- 5 · Hero ---------- */
/* 🚨 HERO APILADO — foto arriba, copy abajo. NO lo vuelvas superpuesto.
   Se intento con texto encima (centrado, y luego anclado arriba) y las dos
   veces el titular quedo SOBRE los envases: en estas tomas el producto arranca
   como al 25% de alto, asi que la banda de cielo limpia no alcanza para
   eyebrow + titular + bajada + botones (~300px contra ~207px disponibles).
   Subir el alto del hero no lo arregla, solo agranda todo en proporcion.
   Apilado se lee perfecto, deja ver la foto COMPLETA (que es el punto de
   tener fotografia buena) y se comporta igual en celular que en escritorio.
   Si algun dia hay una toma con cielo vacio arriba, o una VERTICAL para
   celular, ahi si se puede volver a superponer. */
.hero { background: var(--paper); }
.hero__photo {
  width: 100%;
  height: clamp(340px, 54vh, 660px);
  object-fit: cover;
  /* 🚨 MEDIDO, no a ojo. En la toma EXTENDIDA el producto arranca al 32.5%
     del alto (en la original de 16:9 arrancaba al 15.6%, y por eso `cover`
     le cortaba las tapas en cuanto el viewport pasaba de ~1900px).
     Con 30% el recorte superior va de 16.4% a 22.3% entre 1280px y 3440px:
     siempre por debajo del 32.5%, con margen de sobra en todo el rango.
     Si cambias el `height` o la foto, vuelve a correr
     scratchpad/medir-outpaints.py antes de tocar este numero. */
  object-position: center 30%;
}
.hero__inner {
  text-align: center;
  padding-block: var(--sp-8) var(--sp-9);
}
.hero h1 { max-width: 18ch; margin-inline: auto; }
.hero__sub {
  margin: var(--sp-5) auto 0;
  max-width: 52ch;
  font-size: var(--fs-lead);
  font-weight: 300;
  color: var(--ink-soft);
}
.hero__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--sp-4);
  margin-top: var(--sp-7);
}

/* ⚠️ 720px esta DUPLICADO: aqui y en el `media` del <source> del hero en
   index.html. Es el precio de hacer direccion de arte (dos encuadres) y no
   solo cambio de tamano. Si mueves uno, mueve el otro o el celular pedira la
   toma vertical y el CSS la encajara con la proporcion de la apaisada. */
@media (max-width: 720px) {
  /* La toma de celular es VERTICAL (3:4). Se encaja a 4:5 para dejarle algo
     mas de aire al titular arriba del pliegue; el recorte resultante es del
     ~2%, muy lejos del 35.3% donde arranca el producto. */
  .hero__photo { height: auto; aspect-ratio: 4 / 5; }
  .hero__inner { text-align: left; padding-block: var(--sp-7) var(--sp-8); }
  .hero h1 { max-width: none; margin-inline: 0; }
  .hero__sub { margin-inline: 0; }
  .hero__actions { justify-content: flex-start; margin-top: var(--sp-6); }
}

/* Tira de los 4 colores: firma visual de la marca, y anticipa la seccion
   de lineas sin decir una palabra. El orden es el del Brand Book. */
.colorbar { display: flex; height: 8px; }
.colorbar span { flex: 1; }
.colorbar span:nth-child(1) { background: var(--tt-frizz); }
.colorbar span:nth-child(2) { background: var(--tt-curls); }
.colorbar span:nth-child(3) { background: var(--tt-color); }
.colorbar span:nth-child(4) { background: var(--tt-repair); }

/* ---------- 6 · Las cuatro lineas ---------- */
.lineas {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--sp-5);
  margin-top: var(--sp-8);
}
/* 🚨 La TINTA de cada tarjeta se elige por contraste, no por gusto.
   Blanco sobre estos Pantone reprueba WCAG AA en tres de los cuatro paneles
   (medido: Anti Frizz 1.99, Repair 2.34, Curls 2.96 — el minimo para texto
   normal es 4.5). Con --ink esos tres suben a 8.20 / 6.97 / 5.51. Color Care
   es el caso opuesto: en morado la tinta da 2.66 y el blanco 6.13.
   Por eso NO hay una sola tinta para las cuatro: hay una por panel.
   Los HEX estan casados a Pantone y no se tocan (ver DESIGN.md), asi que lo
   que se ajusta es el texto. Si algun dia entra una quinta familia, mide antes
   de elegir; no copies el valor de la vecina.
   Los textos van a opacidad PLENA: la jerarquia la dan tamano, peso y tracking
   —que es como funciona esta marca— y no bajarle alpha al texto, que era
   justamente lo que tumbaba el contraste. */
.linea {
  --linea-color: var(--tt-gray);
  --linea-tinta: var(--ink);
  position: relative;
  display: flex;
  flex-direction: column;
  border-radius: var(--r-lg);
  background: var(--linea-color);
  color: var(--linea-tinta);
  overflow: hidden;
  transition: transform var(--t-base) var(--ease),
              box-shadow var(--t-base) var(--ease);
}

/* 🚨 Dentro del panel de color va una TARJETA BLANCA con la foto y la letra
   chica (Teddy, 2026-08-12: el texto informativo "no contrasta bien").
   Medido: la tinta sobre estos Pantone da 5.51-8.20, o sea que PASA AA — el
   problema no era el ratio, era poner texto de 12px sobre un campo saturado.
   Sobre blanco sube a 16.3 y, sobre todo, el fondo deja de competir.
   De regalo: la foto ya no necesita recorte, porque viene sobre blanco de
   estudio y ahora aterriza sobre blanco. Ver scripts/recortar_blanco.py. */
.linea__cabecera { padding: var(--sp-6) var(--sp-6) var(--sp-5); }
.linea__panel {
  display: flex;
  flex-direction: column;
  flex: 1;
  margin: 0 var(--sp-3) var(--sp-3);
  background: var(--surface);
  border-radius: var(--r-md);
  overflow: hidden;
}
.linea__foto {
  width: 100%;
  aspect-ratio: 1;        /* = LIENZO_LINEA en scripts/procesar-cutouts.py */
  object-fit: contain;
  transition: transform var(--t-slow) var(--ease);
}
.linea:hover .linea__foto { transform: scale(1.035); }
.linea__cuerpo {
  display: flex;
  flex-direction: column;
  flex: 1;
  padding: 0 var(--sp-5) var(--sp-5);
}
.linea:hover {
  transform: translateY(-4px);
  box-shadow: 0 18px 48px -18px color-mix(in oklch, var(--linea-color) 70%, transparent);
}
/* El mapeo vive en `[data-linea]` a secas, no en `.linea[data-linea]`, para que
   lo pueda consumir cualquier componente: la tarjeta de la landing, la del
   catalogo y la ficha de producto. Poner `data-linea="curls"` en un contenedor
   basta para que todo lo de adentro tome el color y la tinta correctos. */
[data-linea="repair"]     { --linea-color: var(--tt-repair); --linea-tinta: var(--ink); }
[data-linea="anti-frizz"] { --linea-color: var(--tt-frizz);  --linea-tinta: var(--ink); }
[data-linea="curls"]      { --linea-color: var(--tt-curls);  --linea-tinta: var(--ink); }
/* El unico panel lo bastante oscuro para llevar texto blanco. */
[data-linea="color-care"] { --linea-color: var(--tt-color);  --linea-tinta: var(--surface); }

.linea__lead {
  font-size: var(--fs-caption);
  font-weight: 700;
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--linea-tinta);
}
.linea__nombre {
  margin-top: var(--sp-2);
  font-size: var(--fs-h2);
  font-weight: 300;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--linea-tinta);
}
.linea__collection {
  font-size: var(--fs-caption);
  font-weight: 300;
  letter-spacing: 0.42em;
  text-transform: uppercase;
  color: var(--linea-tinta);
}
/* La promesa y los beneficios viven DENTRO de la tarjeta blanca, asi que van en
   tinta normal y no en `--linea-tinta` (que es la tinta calculada para el panel
   de color). Sobre blanco: 16.3 la tinta y 6.6 el gris de apoyo. */
.linea__promesa {
  margin-top: var(--sp-5);
  font-size: var(--fs-small);
  font-weight: 400;
  color: var(--ink);
  max-width: 34ch;
}
/* `margin-top:auto` y no un valor fijo: la rejilla estira las cuatro tarjetas
   a la mas alta, y sin esto la mas corta quedaba con un hueco muerto entre la
   promesa y la lista. Asi el bloque de beneficios se pega abajo y las cuatro
   comparten linea de base. */
.linea__benes {
  margin-top: auto;
  padding-top: var(--sp-4);
  /* La familia entra por la linea, no por el texto: en color el numero daria
     1.8:1 sobre blanco (medido en el naranja) y es letra de 12px. */
  border-top: 2px solid var(--linea-color);
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--sp-1) var(--sp-5);
  counter-reset: bene;
}
.linea__benes li {
  display: flex;
  gap: var(--sp-2);
  align-items: baseline;
  font-size: var(--fs-caption);
  font-weight: 400;
  color: var(--ink);
  counter-increment: bene;
}
.linea__benes li::before {
  content: counter(bene);
  flex: none;
  min-width: 1.1em;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--ink-mute);
}

@media (max-width: 780px) {
  .lineas { grid-template-columns: 1fr; }
  .linea__cabecera { padding: var(--sp-5) var(--sp-5) var(--sp-4); }
  .linea__cuerpo { padding: 0 var(--sp-4) var(--sp-5); }
}

/* ---------- 7 · La familia (un packshot por tipo de producto) ---------- */
.familia {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--sp-5);
  margin-top: var(--sp-8);
}
.familia figure {
  margin: 0;
  border: 1px solid var(--rule-soft);
  border-radius: var(--r-lg);
  overflow: hidden;
  background: var(--surface);
}
/* `contain` sobre blanco: son recortes con transparencia, no tomas con fondo.
   Con `cover` se le cortaria producto a los envases. */
.familia img {
  width: 100%;
  aspect-ratio: 1;
  object-fit: contain;
  transition: transform var(--t-slow) var(--ease);
}
.familia figure:hover img { transform: scale(1.03); }
.familia figcaption {
  padding: var(--sp-5);
  border-top: 1px solid var(--rule-soft);
}
.familia figcaption b {
  display: block;
  font-size: var(--fs-caption);
  font-weight: 700;
  letter-spacing: var(--track-mid);
  text-transform: uppercase;
  color: var(--ink);
}
.familia figcaption span {
  display: block;
  margin-top: var(--sp-1);
  font-size: var(--fs-small);
  font-weight: 300;
  color: var(--ink-mute);
}
.familia__mas { margin-top: var(--sp-7); }

/* 2 columnas antes que 1: en celular una sola columna dejaba packshots
   enormes y obligaba a scrollear cuatro pantallas para ver el regimen
   completo, que es justo lo que la seccion quiere mostrar de un golpe. */
@media (max-width: 1000px) {
  .familia { grid-template-columns: repeat(2, 1fr); }
}

/* ---------- 9 · Beneficios ---------- */
/* 4 columnas fijas en escritorio: son 8 beneficios, asi caen en dos filas
   parejas. Con `auto-fit` daba 5 columnas y la segunda fila quedaba coja. */
.benes-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--sp-5);
  margin-top: var(--sp-8);
}
@media (max-width: 900px) { .benes-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 480px) { .benes-grid { grid-template-columns: 1fr; } }
.bene {
  padding: var(--sp-6);
  background: var(--surface);
  border: 1px solid var(--rule-soft);
  border-radius: var(--r-md);
}
.bene b {
  display: block;
  font-size: var(--fs-body);
  font-weight: 600;
  color: var(--ink);
}
.bene span {
  display: block;
  margin-top: var(--sp-2);
  font-size: var(--fs-small);
  font-weight: 300;
  color: var(--ink-mute);
}
.bene--heroe {
  background: var(--ink);
  border-color: var(--ink);
}
.bene--heroe b { color: var(--surface); }
.bene--heroe span { color: color-mix(in oklch, var(--surface) 76%, transparent); }

/* ---------- 10 · Mayoreo ---------- */
.mayoreo {
  display: grid;
  grid-template-columns: 1.2fr 1fr;
  gap: clamp(32px, 5vw, 72px);
  align-items: center;
}
.mayoreo__media {
  border-radius: var(--r-lg);
  overflow: hidden;
}
.mayoreo__media img { width: 100%; aspect-ratio: 5 / 4; object-fit: cover; }
/* Tarjetas de canal (Amazon / Mercado Libre).
   Monocromas a proposito: meter el naranja de Amazon o el amarillo de MELI
   chocaria con la regla del color (los colores saturados de esta marca
   significan familia de producto) y ademas envejece mal cuando el
   marketplace cambia su identidad. */
.canales {
  margin-top: var(--sp-7);
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--sp-4);
}
.canal {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  padding: var(--sp-6);
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--r-md);
  text-decoration: none;
  transition: background var(--t-fast) var(--ease),
              border-color var(--t-fast) var(--ease),
              transform var(--t-fast) var(--ease);
}
.canal:hover {
  background: var(--ink);
  border-color: var(--ink);
  transform: translateY(-2px);
}
.canal__nombre {
  font-size: var(--fs-h4);
  font-weight: 300;
  color: var(--ink);
}
.canal__nota {
  font-size: var(--fs-small);
  font-weight: 300;
  color: var(--ink-mute);
}
.canal__cta {
  margin-top: var(--sp-3);
  font-size: var(--fs-caption);
  font-weight: 700;
  letter-spacing: var(--track-mid);
  text-transform: uppercase;
  color: var(--ink);
}
.canal:hover .canal__nombre,
.canal:hover .canal__cta { color: var(--surface); }
.canal:hover .canal__nota { color: color-mix(in oklch, var(--surface) 76%, transparent); }
@media (max-width: 900px) {
  .mayoreo { grid-template-columns: 1fr; }
}

/* ---------- 11 · Cierre ---------- */
.cierre {
  position: relative;
  display: grid;
  align-items: center;
  min-height: clamp(460px, 62vh, 660px);
  overflow: hidden;
  isolation: isolate;
}
.cierre__photo {
  position: absolute; inset: 0; z-index: -2;
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: center 45%;
}
/* Velo DIRECCIONAL: opaco sobre el cielo de la izquierda (donde va el texto) y
   transparente sobre los envases de la derecha, para no ensuciar el producto.
   Un velo plano al 42% oscurecia la foto entera y aun asi dejaba el titular
   ilegible encima de las etiquetas. */
.cierre::before {
  content: "";
  position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(
    100deg,
    color-mix(in oklch, var(--ink) 70%, transparent) 0%,
    color-mix(in oklch, var(--ink) 55%, transparent) 36%,
    color-mix(in oklch, var(--ink) 16%, transparent) 64%,
    transparent 82%
  );
}
.cierre__inner { max-width: var(--maxw); }
.cierre h2 { max-width: 16ch; }
.cierre h2, .cierre p { color: var(--surface); }
.cierre p {
  margin-top: var(--sp-5);
  max-width: 44ch;
  font-size: var(--fs-lead);
  font-weight: 300;
  color: color-mix(in oklch, var(--surface) 92%, transparent);
}
.cierre__actions {
  display: flex; flex-wrap: wrap;
  gap: var(--sp-4); margin-top: var(--sp-7);
}

/* En celular el recorte vertical se come el cielo de la izquierda, asi que el
   velo pasa a ser de abajo hacia arriba y el texto se apoya en la base. */
@media (max-width: 780px) {
  .cierre { align-items: end; min-height: clamp(520px, 76vh, 680px); }
  .cierre__inner { padding-bottom: var(--sp-8); }
  /* En celular ya entra una toma VERTICAL propia (ver el <picture> del cierre
     en index.html), asi que el encuadre viene resuelto de origen y no hay que
     desplazarlo: antes iba a `22% center` para rescatar cielo limpio de una
     toma apaisada recortada a la fuerza. ⚠️ Este 780px esta duplicado con el
     `media` de ese <source>. */
  .cierre__photo { object-position: center; }
  /* El bloque de texto va abajo y ocupa del ~37% al ~90% del alto de la
     seccion (titular + bajada + dos botones ≈ 340px de 641px). Por eso el velo
     deja limpio el tercio de arriba —donde se ven los envases y los bloques de
     color— y sube rapido justo antes de donde empieza el texto. Aqui manda la
     legibilidad: es la seccion de CTA. */
  .cierre::before {
    background: linear-gradient(
      to bottom,
      transparent 0%,
      color-mix(in oklch, var(--ink) 14%, transparent) 28%,
      color-mix(in oklch, var(--ink) 72%, transparent) 48%,
      color-mix(in oklch, var(--ink) 90%, transparent) 100%
    );
  }
}

/* ---------- 12 · Footer ---------- */
.site-footer {
  background: var(--ink);
  color: color-mix(in oklch, var(--surface) 68%, transparent);
  padding-block: var(--sp-9) var(--sp-7);
  font-size: var(--fs-small);
  font-weight: 300;
}
.site-footer__top {
  display: grid;
  grid-template-columns: 1.4fr 1fr 1fr;
  gap: var(--sp-7);
  padding-bottom: var(--sp-7);
  border-bottom: 1px solid color-mix(in oklch, var(--surface) 16%, transparent);
}
.site-footer img { height: 52px; width: auto; }
.site-footer__intro { margin-top: var(--sp-4); max-width: 34ch; }
/* h3 y no h4: con h4 el documento saltaba de h2 (ultima seccion) a h4 y dejaba
   un hueco en la jerarquia de encabezados. El tamano lo da el CSS, no la etiqueta. */
.site-footer h3 {
  font-size: var(--fs-caption);
  font-weight: 700;
  letter-spacing: var(--track-mid);
  text-transform: uppercase;
  color: var(--surface);
  margin-bottom: var(--sp-3);
}
/* Los enlaces del footer son lista de navegacion, no texto corrido, asi que
   les aplica el minimo de 24px de alto de objetivo tactil (WCAG 2.2 AA 2.5.8).
   El padding vertical los lleva de 18px a 26px sin mover el diseno. */
.site-footer li a { display: inline-block; padding-block: var(--sp-1); }
.site-footer a { text-decoration: none; transition: color var(--t-fast) var(--ease); }
.site-footer a:hover { color: var(--surface); }
.site-footer__legal {
  margin-top: var(--sp-6);
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-3) var(--sp-6);
  justify-content: space-between;
  font-size: var(--fs-caption);
  color: color-mix(in oklch, var(--surface) 52%, transparent);
}
.site-footer__legal-nav { display: flex; flex-wrap: wrap; gap: 0 var(--sp-5); }
/* padding vertical por el minimo de 24px de objetivo tactil: son enlaces
   sueltos de navegacion, no van dentro de un parrafo (ahi la regla no aplica). */
.site-footer__legal-nav a {
  display: inline-block;
  padding-block: var(--sp-2);
  text-decoration: underline;
  text-underline-offset: 3px;
}
@media (max-width: 780px) {
  .site-footer__top { grid-template-columns: 1fr; gap: var(--sp-6); }
}

/* ---------- 14 · Paginas legales ----------
   Las genera scripts/generar-paginas.py desde content/. Van en una sola
   columna de prosa: son para leerse, no para lucirse. */
.legal { padding-block: var(--section-y); }
.wrap--prose { max-width: 760px; }
.legal h1 { margin-bottom: var(--sp-6); }
.legal h2 {
  margin-top: var(--sp-8);
  margin-bottom: var(--sp-4);
  font-size: var(--fs-h3);
  font-weight: 300;
}
.legal p { margin-bottom: var(--sp-4); max-width: var(--maxw-prose); }
.legal a { color: var(--ink); text-underline-offset: 3px; }
.legal__fecha {
  font-size: var(--fs-caption);
  font-weight: 600;
  letter-spacing: var(--track-mid);
  text-transform: uppercase;
  color: var(--ink-mute);
}
.legal__entrada {
  margin-top: var(--sp-5);
  font-size: var(--fs-lead);
  font-weight: 300;
  color: var(--ink-soft);
}
.legal__volver {
  margin-top: var(--sp-8);
  padding-top: var(--sp-5);
  border-top: 1px solid var(--rule);
  font-size: var(--fs-small);
}
.legal__volver a { display: inline-block; padding-block: var(--sp-2); }

/* ---------- 15 · Catalogo y fichas de producto ----------
   Los genera scripts/generar-paginas.py desde data/productos.json.
   El acento por familia sale de `data-linea` en un contenedor: eso define
   --linea-color y --linea-tinta (ver la seccion 6), y de ahi cuelga todo. */

/* --- Portada del catalogo --- */
.cat-intro { padding-block: var(--sp-9) var(--sp-7); }
.cat-intro .h-display { max-width: 16ch; }
.cat-saltos {
  display: flex; flex-wrap: wrap; gap: var(--sp-3);
  margin-top: var(--sp-7);
}
.cat-chip {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-4);
  border: 1px solid var(--rule);
  border-radius: 999px;
  background: var(--surface);
  font-size: var(--fs-caption);
  font-weight: 600;
  letter-spacing: var(--track-mid);
  text-transform: uppercase;
  color: var(--ink);
  text-decoration: none;
  transition: border-color var(--t-fast) var(--ease), transform var(--t-fast) var(--ease);
}
.cat-chip:hover { border-color: var(--ink); transform: translateY(-1px); }
/* El punto es el UNICO lugar del chip donde aparece el color de familia: el
   texto sigue en tinta, que es la regla de color del sistema. */
.cat-chip__punto {
  width: 10px; height: 10px; border-radius: 50%;
  background: var(--linea-color, var(--tt-gray));
}

/* --- Una seccion por familia --- */
.cat-linea { padding-block: var(--sp-8); }
.cat-linea + .cat-linea { padding-top: 0; }
.cat-linea__head {
  display: flex; flex-wrap: wrap; gap: var(--sp-5);
  align-items: end; justify-content: space-between;
  padding-bottom: var(--sp-5);
  /* La franja de color de la familia, a lo ancho del contenedor. */
  border-bottom: 3px solid var(--linea-color);
}
.cat-linea__lead {
  font-size: var(--fs-caption); font-weight: 700;
  letter-spacing: var(--track-wide); text-transform: uppercase;
  color: var(--ink-mute);
}
.cat-linea__nombre {
  margin-top: var(--sp-1);
  font-size: var(--fs-h2); font-weight: 300;
  letter-spacing: 0.02em; text-transform: uppercase;
}
.cat-linea__collection {
  font-size: var(--fs-caption); font-weight: 300;
  letter-spacing: 0.42em; text-transform: uppercase;
  color: var(--ink-mute);
}
.cat-linea__promesa {
  font-size: var(--fs-small); font-weight: 300;
  color: var(--ink-soft); max-width: 38ch;
  padding-bottom: var(--sp-1);   /* que no se pegue a la franja de color */
}

/* --- Rejilla y tarjeta de producto --- */
.prod-grid {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: var(--sp-4);
  margin-top: var(--sp-6);
}
.prod-grid--chica { grid-template-columns: repeat(4, 1fr); }
@media (max-width: 1000px) { .prod-grid, .prod-grid--chica { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 640px)  { .prod-grid, .prod-grid--chica { grid-template-columns: repeat(2, 1fr); } }

.pcard {
  display: flex; flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--rule-soft);
  border-radius: var(--r-md);
  overflow: hidden;
  transition: transform var(--t-base) var(--ease), box-shadow var(--t-base) var(--ease);
}
.pcard:hover {
  transform: translateY(-3px);
  box-shadow: 0 16px 40px -20px color-mix(in oklch, var(--linea-color) 65%, transparent);
}
.pcard__link {
  display: flex; flex-direction: column; flex: 1;
  padding: 0 var(--sp-4) var(--sp-4);
  text-decoration: none;
}
/* 🚨 El plano NO lleva color detras del envase (Teddy, 2026-08-12). La foto es
   la de estudio, con su fondo blanco: cualquier lavado de color se veria como
   un cuadro blanco encima del color. El acento de familia se mueve al MARCO
   —banda arriba y sombra al pasar el cursor—, igual que en la ficha. */
.pcard__foto {
  display: block;
  margin-inline: calc(var(--sp-4) * -1);
  background: var(--surface);
  border-top: 3px solid var(--linea-color);
  border-bottom: 1px solid var(--rule-soft);
}
/* Marco 3/4 con `contain`: cada foto viene encuadrada a la silueta de SU envase
   (ver encuadrar_a_la_silueta), asi que un frasco alto llena el marco por altura
   y el tarro ancho por anchura. Con un cuadrado, el frasco —que mide como 1:4—
   quedaba diminuto entre dos franjas de blanco. */
.pcard__foto img {
  width: 100%; aspect-ratio: 3 / 4; object-fit: contain;
  transition: transform var(--t-slow) var(--ease);
}
.pcard:hover .pcard__foto img { transform: scale(1.04); }
.pcard__tipo {
  display: block; margin-top: var(--sp-4);
  font-size: var(--fs-small); font-weight: 600; color: var(--ink);
}
.pcard__pres {
  display: block; margin-top: var(--sp-1);
  font-size: var(--fs-caption); font-weight: 300; color: var(--ink-mute);
}
.pcard__amz {
  display: block;
  padding: var(--sp-3) var(--sp-4);
  border-top: 1px solid var(--rule-soft);
  font-size: var(--fs-caption); font-weight: 700;
  letter-spacing: var(--track-mid); text-transform: uppercase;
  color: var(--ink); text-decoration: none;
  transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.pcard__amz:hover { background: var(--ink); color: var(--paper); }
/* En dos columnas de celular la tarjeta queda en ~140px utiles y la flecha se
   caia sola al segundo renglon. Se prohibe el corte y se recupera el ancho
   apretando el tracking, que a este tamano no se nota. */
@media (max-width: 640px) {
  .pcard__amz { white-space: nowrap; letter-spacing: 0.02em; }
}

.cat-cierre__acciones { display: flex; flex-wrap: wrap; gap: var(--sp-4); margin-top: var(--sp-6); }

/* Los 8 kits en 4 columnas: son mas anchos que un envase suelto (traen 2-4
   productos en la toma) y a 5 por fila se leian como manchas. */
.prod-grid--bundles { grid-template-columns: repeat(4, 1fr); margin-top: var(--sp-7); }
@media (max-width: 1000px) { .prod-grid--bundles { grid-template-columns: repeat(2, 1fr); } }
.pcard--bundle .pcard__foto { background: color-mix(in oklch, var(--linea-color) 10%, var(--surface)); }
.pcard--bundle .pcard__foto img { aspect-ratio: 1; }
.cat-chip--kits { border-style: dashed; }

/* --- Ficha de producto --- */
.miga { padding-block: var(--sp-5) 0; font-size: var(--fs-caption); color: var(--ink-mute); }
.miga .wrap { display: flex; flex-wrap: wrap; gap: var(--sp-2); align-items: center; }
/* padding vertical por el minimo de 24px de objetivo tactil: son enlaces de
   navegacion sueltos, no van dentro de un parrafo. */
.miga a {
  display: inline-block;
  padding-block: var(--sp-2);
  color: var(--ink-mute);
  text-underline-offset: 3px;
}
.miga a:hover { color: var(--ink); }
.miga [aria-current] { color: var(--ink); font-weight: 600; }

.ficha__hero { padding-block: var(--sp-6) var(--sp-9); }
.ficha__hero-inner {
  display: grid; grid-template-columns: 0.85fr 1fr;
  gap: clamp(28px, 5vw, 72px); align-items: center;
}
/* Las fotos de la sesion 2026-08 vienen sobre BLANCO de estudio, asi que el
   color de familia ya no puede ir detras del envase —se veria un cuadro blanco
   encima del color—. Pasa al MARCO: una banda arriba y el borde de la
   miniatura activa. El acento sigue ahi, sin ensuciar el producto. */
.galeria__marco {
  border: 1px solid var(--rule-soft);
  border-top: 4px solid var(--linea-color);
  border-radius: var(--r-lg);
  overflow: hidden;
  background: var(--surface);
  /* Las grandes van APILADAS aqui dentro (ver galeria() en
     scripts/generar-paginas.py): todas cargadas, se alterna con una clase. Por
     eso el marco necesita alto propio — las hijas van absolutas y no lo dan. */
  position: relative;
  aspect-ratio: 1;
}
.galeria__grande {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  object-fit: contain;
  /* `opacity` y no `display:none`: un elemento en display:none NO descarga su
     imagen, y precargarlas es justamente el punto de apilarlas. */
  opacity: 0;
  transition: opacity var(--t-fast) var(--ease);
}
.galeria__grande.es-activa { opacity: 1; }
/* Sin JS ninguna clase se mueve, pero la primera ya trae `es-activa` del
   generador, asi que la ficha se ve igual. */
.galeria__thumbs {
  display: flex;
  gap: var(--sp-3);
  margin-top: var(--sp-3);
}
.galeria__thumb {
  flex: 0 0 auto;
  width: 84px;
  padding: 0;
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--r-sm);
  overflow: hidden;
  cursor: pointer;
  transition: border-color var(--t-fast) var(--ease), transform var(--t-fast) var(--ease);
}
.galeria__thumb img { width: 100%; aspect-ratio: 1; object-fit: contain; }
.galeria__thumb:hover { transform: translateY(-2px); }
.galeria__thumb.es-activa { border-color: var(--linea-color); border-width: 2px; }
.ficha__linea {
  font-size: var(--fs-caption); font-weight: 700;
  letter-spacing: var(--track-wide); text-transform: uppercase;
  color: var(--ink-mute); margin-bottom: var(--sp-3);
}
.chips { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-top: var(--sp-5); }
.chip {
  padding: var(--sp-1) var(--sp-3);
  border: 1px solid var(--rule);
  border-radius: 999px;
  font-size: var(--fs-caption); font-weight: 600;
  letter-spacing: var(--track-mid); text-transform: uppercase;
  color: var(--ink-soft);
}
.ficha__promesa {
  margin-top: var(--sp-5);
  font-size: var(--fs-lead); font-weight: 300; color: var(--ink);
  max-width: 40ch;
}
.ficha__usos { margin-top: var(--sp-4); color: var(--ink-soft); max-width: 52ch; }
.ficha__acciones { display: flex; flex-wrap: wrap; gap: var(--sp-4); margin-top: var(--sp-6); }
.ficha__nota { margin-top: var(--sp-4); font-size: var(--fs-caption); color: var(--ink-mute); }

/* Los 10 beneficios, numerados. El #1 es el que define a la familia. */
.benes-lista {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--sp-3) var(--sp-6);
  margin-top: var(--sp-7);
  counter-reset: b;
}
.benes-lista li {
  display: flex; gap: var(--sp-3); align-items: baseline;
  padding-bottom: var(--sp-3);
  border-bottom: 1px solid var(--rule-soft);
  font-weight: 300; color: var(--ink-soft);
  counter-increment: b;
}
.benes-lista li::before {
  content: counter(b, decimal-leading-zero);
  flex: none; min-width: 2.2em;
  font-size: var(--fs-caption); font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--ink-faint);
}
.benes-lista .es-lead { color: var(--ink); font-weight: 600; }
.benes-lista .es-lead::before { color: var(--linea-color); }
@media (max-width: 640px) { .benes-lista { grid-template-columns: 1fr; } }

.ficha__usos-cols { display: grid; grid-template-columns: repeat(2, 1fr); gap: clamp(28px, 4vw, 64px); }
.uso__titulo { font-size: var(--fs-h4); font-weight: 600; margin-bottom: var(--sp-3); }
.uso p { color: var(--ink-soft); font-weight: 300; }
@media (max-width: 780px) { .ficha__usos-cols { grid-template-columns: 1fr; } }

.specs {
  margin-top: var(--sp-7);
  display: grid; grid-template-columns: repeat(2, 1fr);
  gap: 0 clamp(28px, 4vw, 64px);
}
.spec {
  display: flex; justify-content: space-between; gap: var(--sp-4);
  padding-block: var(--sp-4);
  border-bottom: 1px solid var(--rule-soft);
}
.spec dt { font-size: var(--fs-small); color: var(--ink-mute); font-weight: 300; }
.spec dd {
  margin: 0; font-size: var(--fs-small); font-weight: 600;
  color: var(--ink); text-align: right;
}
@media (max-width: 780px) { .specs { grid-template-columns: 1fr; } }

.ficha__volver { margin-top: var(--sp-7); font-size: var(--fs-small); }
.ficha__volver a { display: inline-block; padding-block: var(--sp-2); color: var(--ink); }

@media (max-width: 860px) {
  .ficha__hero-inner { grid-template-columns: 1fr; }
  .ficha__foto { max-width: 420px; }
}

/* ---------- 13 · Reveal ----------
   Solo se esconde si el JS arranco (`html.js`, lo pone boot.js SIN defer).
   Sin JS o con el script bloqueado, el contenido se ve: nunca dependemos
   de un IntersectionObserver para que la pagina sea legible. */
.js .reveal {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity var(--t-slow) var(--ease),
              transform var(--t-slow) var(--ease);
}
.js .reveal.is-visible { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  .js .reveal { opacity: 1; transform: none; }
}
