/* palmiermedia.com — hoja común. Tokens de docs/arquitectura.md §2-§4. */

/* ---------- fuentes (servidas desde el propio servidor; Thunder tal cual la da el autor) ---------- */
@font-face {
  font-family: 'Thunder';
  src: url('../fuentes/thunder/Thunder-BoldLC.woff2') format('woff2');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Aileron';
  src: url('../fuentes/aileron/Aileron-Regular.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Aileron';
  src: url('../fuentes/aileron/Aileron-SemiBold.woff2') format('woff2');
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}

/* Big Shoulders Display, variable (wght 100-900, OFL): solo para el titular del cierre, que engorda con el scroll. */
@font-face {
  font-family: 'Big Shoulders Display';
  src: url('../fuentes/big-shoulders-display/big-shoulders-display-latin-wght-normal.woff2') format('woff2-variations'),
       url('../fuentes/big-shoulders-display/big-shoulders-display-latin-wght-normal.woff2') format('woff2');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Big Shoulders Display';
  src: url('../fuentes/big-shoulders-display/big-shoulders-display-latin-ext-wght-normal.woff2') format('woff2-variations'),
       url('../fuentes/big-shoulders-display/big-shoulders-display-latin-ext-wght-normal.woff2') format('woff2');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ---------- tokens ---------- */
:root {
  --papel: #f4f4f2;
  --velo: #e8e7e6;
  --filete: #d5d5d3;
  --gris: #929291;   /* decoración, nunca texto */
  --sombra: #676665;
  --tinta: #1d1c1b;
  --oliva: #4a5245;
  --banda: #4a5245;
  --sobre-banda: #eeeeec;
  --sobre-oliva: #eeeeec;
  --oliva-claro: #aab59c; /* fijo en los dos modos: tarjeta «claro» y números sobre tinta */

  --f-display: 'Thunder', 'Arial Narrow', sans-serif;
  --f-texto: 'Aileron', 'Helvetica Neue', Arial, sans-serif;

  --e-salida: cubic-bezier(.19, 1, .22, 1);
  --e-suave: cubic-bezier(.22, 1, .36, 1);
  --t-micro: 160ms;
  --t-base: 320ms;
  --t-slow: 620ms;

  --margen: clamp(16px, 5vw, 72px);
  --ancho: 1320px;
  --radio-foto: 18px;
  --radio-control: 999px;
  --radio-panel: 20px; /* menú y paquete: un radio por tipo (norma 8) */

  color-scheme: light;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) {
    --papel: #161615;
    --velo: #212120;
    --filete: #343432;
    --gris: #6f6f6d;
    --sombra: #a3a29f;
    --tinta: #eeeeec;
    --oliva: #aab59c;
    --sobre-oliva: #161615;
    color-scheme: dark;
  }
}
:root[data-theme='dark'] {
  --papel: #161615;
  --velo: #212120;
  --filete: #343432;
  --gris: #6f6f6d;
  --sombra: #a3a29f;
  --tinta: #eeeeec;
  --oliva: #aab59c;
  --sobre-oliva: #161615;
  color-scheme: dark;
}

/* ---------- base ---------- */
*,
*::before,
*::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }
/* clip y no hidden: no rompe los sticky. Las tarjetas giradas y la palabra del puente no dan scroll lateral. */
html, body { overflow-x: clip; }
body {
  margin: 0;
  background: var(--papel);
  color: var(--tinta);
  font: 400 1.0625rem/1.55 var(--f-texto);
  -webkit-font-smoothing: antialiased;
}
img { display: block; max-width: 100%; height: auto; }
a { color: inherit; }
:focus-visible { outline: 2px solid var(--oliva); outline-offset: 3px; }

.saltar {
  position: absolute; left: 8px; top: -60px; z-index: 50;
  padding: 10px 14px; background: var(--tinta); color: var(--papel);
}
.saltar:focus { top: 8px; }

.titular {
  margin: 0 0 .4em;
  font: 700 clamp(3rem, 9vw, 7.5rem)/.9 var(--f-display);
  text-transform: uppercase;
  letter-spacing: .005em;
}
.titular--hero { font-size: clamp(3.4rem, 12vw, 10rem); }
.acento { font-style: normal; color: inherit; opacity: .85; }
/* «CRECER»/«CRÉIXER» en oliva, en el h1 de las tres variantes de la entrada (regla de oro nº 11: tinta fija,
   nunca mix-blend). Sobre fondo sólido cumple 7,4:1 claro / 8,4:1 oscuro (docs/arquitectura.md §2); la
   variante «foto» lo sobreescribe abajo con el oliva claro fijo, igual que .frases-scroll__resalte. */
.titular__resalte { color: var(--oliva); }

.seccion {
  width: min(100% - 2 * var(--margen), var(--ancho));
  margin-inline: auto;
  padding-block: clamp(64px, 10vw, 140px);
}
.banda {
  width: 100%;
  padding-inline: max(var(--margen), (100% - var(--ancho)) / 2);
  background: var(--banda);
  color: var(--sobre-banda);
}
/* El foco global es --oliva, el mismo tono que la banda: dentro de ella no se veía (medido con Tab en el 08). */
.banda :focus-visible { outline-color: currentColor; }

/* ---------- botones ---------- */
.boton {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 48px; padding: 0 24px;
  border: 1.5px solid currentColor; border-radius: var(--radio-control);
  font-weight: 600; text-decoration: none;
  transition: background-color var(--t-micro) var(--e-suave), color var(--t-micro) var(--e-suave);
}
.boton--principal { background: var(--oliva); border-color: var(--oliva); color: var(--sobre-oliva); }
.boton--principal:hover { background: var(--tinta); border-color: var(--tinta); color: var(--papel); }
.boton--claro { color: var(--sobre-banda); }
.boton--claro:hover { background: var(--sobre-banda); color: var(--banda); }
/* Relleno sobre la banda (08, hallazgo 2): la acción de la sección manda sobre la píldora. Al pasar, se vacía. El foco
   va en claro a mano: con currentColor saldría del tono de la banda y no se vería. */
.boton--claro.boton--relleno { background: var(--sobre-banda); border-color: var(--sobre-banda); color: var(--banda); }
.boton--claro.boton--relleno:hover { background: transparent; color: var(--sobre-banda); }
.banda .boton--claro.boton--relleno:focus-visible { outline-color: var(--sobre-banda); }
.enlace-flecha { display: inline-block; margin-top: 32px; font-weight: 600; text-underline-offset: 4px; }
.enlace-flecha::after { content: ' →'; }
.enlace-flecha--atras::after { content: ''; }
.enlace-flecha--atras::before { content: '← '; }
.enlace-flecha--abajo::after { content: ' ↓'; }
.enlace-flecha[hidden] { display: none; }

/* ---------- cabecera y menú ---------- */
.cabecera {
  display: flex; align-items: center; justify-content: space-between; gap: 24px;
  width: min(100% - 2 * var(--margen), var(--ancho));
  margin-inline: auto; padding-block: 18px;
}
.cabecera__marca { display: block; position: relative; line-height: 0; text-decoration: none; }
.logo { width: 52px; height: auto; }
/* Los dos logos (oliva y claro) en la misma celda; cuál se ve lo decide el tema (reglas de abajo). */
.cabecera__logos { display: grid; }
.cabecera__logos .logo { grid-area: 1 / 1; }

/* Marca FIJA (con JS, todas las páginas): solo la marca acompaña el scroll; nav, idiomas, modo y «Menú» se van con
   la cabecera. Sin JS se queda en su sitio, sin fijar. Ocupa el mismo sitio que en la cabecera: su borde izquierdo
   (left) y su fila (top 18 px = padding de la cabecera, alto = alto de la fila), así que al empezar a bajar no salta.
   Arriba del todo se ve el logo de la cabecera, del color del tema; al bajar lo sustituye .marca-fija, en modo
   Diferencia. La cabecera__marca sigue siendo el enlace (invisible debajo): .marca-fija no recibe clics.
   z-index 30: por encima del contenido (sus z-index no pasan de 3) y por debajo del flotante (35), el menú (40),
   la píldora (41) y la pelota. */
html[data-js='si'] {
  --cabecera-fila: calc(52px * 80 / 93); /* escritorio: la fila la marca el logo (44,7 px) */
}
@media (max-width: 859px) {
  html[data-js='si'] { --cabecera-fila: 48px; } /* móvil: la marca el botón «Menú» */
}
/* Sin la marca en el flujo, el nav y el botón siguen a la derecha y la cabecera conserva su alto. */
html[data-js='si'] .cabecera { justify-content: flex-end; min-height: calc(var(--cabecera-fila) + 36px); }
html[data-js='si'] .cabecera__marca {
  position: fixed; z-index: 30; top: 18px; left: max(var(--margen), (100% - var(--ancho)) / 2);
  display: flex; align-items: center; height: var(--cabecera-fila);
  transform-origin: 0 0; transition: scale .3s var(--e-suave);
}
/* Al bajar (pasados 24 px, todas las páginas) se queda al 80 %: 42 × 36 px pegados a la esquina, para pisar
   menos titulares al pasar por debajo. */
html[data-js='si']:not([data-cima]) .cabecera__marca { scale: .8; }

/* Logo al bajar, en modo Diferencia (Mario, 28 sep 2026; patrón de felixrotonda, .brand-logo-blend).
   Es el logo CLARO (#eeeeec) mezclado con difference: sobre papel claro sale casi negro, sobre la franja negra o
   una foto oscura sale claro, y en modo oscuro igual (decide el fondo, no el tema). El oliva con invert(1) daría
   lila sobre negro y oliva apagado sobre papel: peor en los dos extremos.
   TRAMPA: el blend solo se mezcla con la página si NINGÚN ancestro crea contexto de apilamiento (fixed, z-index,
   transform/scale, opacity < 1, filter, isolation, will-change…); si no, sale un color plano. Por eso es hijo
   directo de <body> (plantillas.mjs, justo después de </header>) y no vive en .cabecera__marca, que es fija con
   z-index y escala. La escala y el fundido van sobre ESTE mismo elemento, que eso no rompe el blend.
   Mismo z-index que la marca y después en el DOM: se pinta encima de ella. pointer-events: none → el clic cae
   en .cabecera__marca, que está justo debajo con la misma caja y la misma escala. */
.marca-fija { display: none; }
html[data-js='si'] .marca-fija {
  display: flex; align-items: center;
  position: fixed; z-index: 30; top: 18px; left: max(var(--margen), (100% - var(--ancho)) / 2);
  height: var(--cabecera-fila);
  transform-origin: 0 0; pointer-events: none;
  mix-blend-mode: difference;
  opacity: 0; transition: opacity .3s var(--e-suave), scale .3s var(--e-suave);
}
.marca-fija__logo { display: block; width: 52px; height: auto; }
html[data-js='si']:not([data-cima]) .marca-fija { opacity: 1; scale: .8; }
html[data-js='si']:not([data-cima]) .cabecera__logos { opacity: 0; }
/* Al bajar leyendo se aparta hacia arriba y vuelve al subir (sitio.js, iniciarCima → data-marca-fuera; nunca en la
   cima). Sin fondo: sigue en Diferencia. El enlace invisible de debajo deja de recibir clics mientras está fuera.
   Con movimiento reducido solo se funde, sin desplazarse. */
html[data-js='si'] .marca-fija { transition: opacity .3s var(--e-suave), scale .3s var(--e-suave), translate .3s var(--e-suave); }
html[data-js='si'][data-marca-fuera] .marca-fija { opacity: 0; translate: 0 calc(-100% - 18px); }
html[data-js='si'][data-marca-fuera] .cabecera__marca { pointer-events: none; }
@media (prefers-reduced-motion: reduce) {
  html[data-js='si'][data-marca-fuera] .marca-fija { translate: none; }
}
/* «PALMIER MEDIA» en Thunder arriba del todo; al bajar se funde y entra el logo (rescate de producción).
   Sin JS no existe: se ve el logo. Va fuera de flujo, sobre la marca, para no empujar el nav; su tamaño cabe
   en el hueco hasta el botón «Menú» desde 320 (4,242 × 40 = 170 px) y, en escritorio, en el que deja el nav. */
/* Solo en la home: en las demás páginas la marca fija es el logo, sin palabra. */
.cabecera__palabra { display: none; }
html[data-js='si'] .p-inicio .cabecera__palabra {
  display: block; position: absolute; left: 0; top: 50%; translate: 0 -50%;
  font: 700 40px/1 var(--f-display); text-transform: uppercase; letter-spacing: .005em; white-space: nowrap;
  color: var(--tinta);
  opacity: 0; visibility: hidden; pointer-events: none;
  transition: opacity .3s var(--e-suave), visibility 0s linear .3s;
}
/* La palabra solo se ve arriba del todo, sobre el papel: tinta normal, sin blend. El fundido palabra ↔ logo:
   la palabra se va y entra .marca-fija (arriba), en las mismas 0,3 s. */
html[data-js='si'] .cabecera__logos { transition: opacity .3s var(--e-suave); }
html[data-js='si'][data-cima] .p-inicio .cabecera__palabra {
  opacity: 1; visibility: visible;
  transition: opacity .3s var(--e-suave), visibility 0s linear 0s;
}
html[data-js='si'][data-cima] .p-inicio .cabecera__logos { opacity: 0; }
@media (min-width: 860px) {
  /* 30 px a 860 (≈127 px, lo que deja el nav) → 52 px desde ~1200 (≈221 px, a la altura del logo). */
  html[data-js='si'] .p-inicio .cabecera__palabra { font-size: clamp(30px, 6.5vw - 26px, 52px); }
}
/* Entre 860 y 959 px el nav de escritorio no deja sitio: a 860 la palabra pisaba «Diagnóstico» 35 px (medido).
   Ahí se queda el logo, sin palabra. */
@media (min-width: 860px) and (max-width: 959px) {
  html[data-js='si'] .p-inicio .cabecera__palabra { display: none; }
  html[data-js='si'][data-cima] .p-inicio .cabecera__logos { opacity: 1; }
}
.logo--oscuro { display: none; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) .logo--claro { display: none; }
  :root:not([data-theme='light']) .logo--oscuro { display: block; }
}
:root[data-theme='dark'] .logo--claro { display: none; }
:root[data-theme='dark'] .logo--oscuro { display: block; }

.menu { display: flex; align-items: center; gap: 32px; }
.menu__lista { display: flex; gap: 24px; margin: 0; padding: 0; list-style: none; }
.menu__lista a { text-decoration: none; font-weight: 600; }
.menu__lista a:hover { text-decoration: underline; text-underline-offset: 4px; }
/* Con «Bodas» (08) el nav de escritorio son seis entradas: entre 860 y 1199 px se partía «Qué hacemos» y el bloque
   pisaba el logo y la palabra (medido). Mismo mecanismo, valores más prietos. */
@media (min-width: 860px) {
  .menu__lista a { white-space: nowrap; }
}
@media (min-width: 860px) and (max-width: 1199px) {
  .menu { gap: 20px; }
  .menu__lista { gap: 14px; font-size: .9rem; }
}
.menu__ajustes { display: flex; align-items: center; gap: 16px; }
.idiomas { display: flex; gap: 10px; font-weight: 600; font-size: .9rem; }
.idiomas a { color: var(--sombra); text-decoration: none; }
.idiomas a:hover { color: var(--tinta); }
/* ---------- conmutador de tema: ventanita de 66 × 42 con una palmera; el cambio se abre en cortina circular ----------
   Sin JS no haría nada: se esconde y el tema sigue al sistema. Radio 10 px y no el de control (999): la escena es
   un paisaje y la píldora le comería las esquinas. */
.modo { display: none; }
html[data-js='si'] .modo {
  display: block; position: relative; flex: none; width: 66px; height: 42px; margin: 0; padding: 0;
  border: 1.5px solid var(--filete); border-radius: 10px; overflow: hidden;
  background: transparent; color: var(--tinta); cursor: pointer; -webkit-tap-highlight-color: transparent;
  transition: border-color var(--t-base) var(--e-suave);
}
html[data-js='si'] .modo:hover { border-color: var(--oliva); }
.modo__escena { display: block; width: 100%; height: 100%; }
.modo__escena * { transition: fill .6s var(--e-suave), stroke .6s var(--e-suave), opacity .4s var(--e-suave), transform .8s var(--e-salida); }

/* Capas del cambio (las crea sitio.js y las quita al terminar): a pantalla completa, por encima de todo (menú 40,
   píldora 41, pelota 42) y por debajo del botón pulsado (.modo--encima). Hijas de <body>: no tocan los ancestros
   de .marca-fija. En escritorio ningún ancestro del botón crea contexto de apilamiento, así que su z-index sube;
   en el móvil el botón vive en .menu (fixed, z 40) y lo que sube es el menú entero mientras dura el cambio. */
.modo-capa { position: fixed; z-index: 90; pointer-events: none; }
html[data-js='si'] .modo.modo--encima { z-index: 100; }
@media (max-width: 859px) { html[data-modo-cambia] .menu { z-index: 95; } }
/* Debajo de una capa el tema cambia de golpe: la vista nueva tiene que estar pintada al destapar. La escena del
   botón queda fuera: es lo que se ve durante el cambio. */
html.sin-transicion :not(.modo, .modo *), html.sin-transicion ::before, html.sin-transicion ::after { transition: none !important; }

/* Cortina y escena de la palmera. */
.modo-capa--cortina { inset: 0; }
/* View Transitions: sin fundido por defecto; el círculo lo anima sitio.js sobre la vista nueva. */
::view-transition-old(root), ::view-transition-new(root) { animation: none; mix-blend-mode: normal; }
.t-palmera { --cielo: #c9d2bd; --astro: #f4f4f2; --silueta: #4a5245; }
.modo[aria-pressed='true'] .t-palmera { --cielo: #20241e; --astro: #eeeeec; --silueta: #0d0e0c; }
.t-palmera__cielo { fill: var(--cielo); }
.t-palmera__suelo { fill: var(--silueta); }
.t-palmera__tronco, .t-palmera__copa path { fill: none; stroke: var(--silueta); stroke-linecap: round; }
.t-palmera__tronco { stroke-width: 2.4; }
.t-palmera__copa path { stroke-width: 2.1; }
.t-palmera__copa { transform-box: view-box; transform-origin: 24px 14px; }
.t-palmera__sol { fill: var(--astro); }
.t-palmera__luna { transform: translateY(30px); transition-delay: .12s !important; }
.t-palmera__luna-disco { fill: var(--astro); }
.t-palmera__luna-sombra { fill: var(--cielo); }
.t-palmera__estrellas circle { fill: var(--astro); opacity: 0; }
.modo[aria-pressed='true'] .t-palmera__sol { transform: translateY(30px); }
.modo[aria-pressed='true'] .t-palmera__luna { transform: none; }
.modo[aria-pressed='true'] .t-palmera__estrellas circle { opacity: 1; transition-delay: calc(.35s + var(--d, 0s)); }
.t-palmera__estrellas circle:nth-child(2) { --d: .08s; }
.t-palmera__estrellas circle:nth-child(3) { --d: .16s; }
.t-palmera__estrellas circle:nth-child(4) { --d: .24s; }
.t-palmera__estrellas circle:nth-child(5) { --d: .32s; }
.modo[aria-pressed='true'] .t-palmera__estrellas circle:nth-child(odd) { animation: modo-titila 2.4s ease-in-out 1.2s infinite; }
@keyframes modo-titila { 50% { opacity: .35; } }
/* La copa se mece al cambiar. Dos nombres para que la animación se reinicie en cada clic. */
.modo[data-animado][aria-pressed='true'] .t-palmera__copa { animation: modo-mece-a .9s var(--e-suave); }
.modo[data-animado][aria-pressed='false'] .t-palmera__copa { animation: modo-mece-b .9s var(--e-suave); }
@keyframes modo-mece-a { 30% { transform: rotate(-7deg); } 65% { transform: rotate(3deg); } }
@keyframes modo-mece-b { 30% { transform: rotate(-7deg); } 65% { transform: rotate(3deg); } }

/* Movimiento reducido: sitio.js cambia el tema sin capas. Las escenas conservan sus fundidos (norma 5); solo se
   apaga lo que se repite solo. */
@media (prefers-reduced-motion: reduce) {
  .modo * { animation: none !important; }
}

/* Píldora: solo en el móvil. Junta el menú y WhatsApp; nada más flota (arquitectura §1). */
.pildora { display: none; }
/* Botón «Menú» de la cabecera: solo móvil y solo con JS (sin JS el menú ya se ve entero y el botón no haría nada). */
.cabecera__menu { display: none; }

@media (max-width: 859px) {
  .menu {
    position: fixed; inset: auto 12px 84px; z-index: 40;
    flex-direction: column; align-items: stretch; gap: 20px;
    padding: 24px; border-radius: var(--radio-panel);
    background: var(--papel); border: 1px solid var(--filete);
    box-shadow: 0 20px 60px rgb(0 0 0 / .18);
  }
  .menu__lista { flex-direction: column; gap: 14px; font-size: 1.15rem; }
  .menu__ajustes { justify-content: space-between; }
  html[data-js='si'] .menu:not([data-abierto]) { display: none; }
  /* Abierto desde la cabecera: cuelga bajo ella, alineado con sus márgenes, y se va con el scroll como ella. */
  .cabecera { position: relative; }
  .menu[data-desde='cabecera'] { position: absolute; inset: calc(100% - 6px) 0 auto; }

  html[data-js='si'] .cabecera__menu {
    display: inline-flex; align-items: center; min-height: 48px; padding: 0 20px;
    border: 1.5px solid var(--filete); border-radius: var(--radio-control);
    background: transparent; color: var(--tinta); font: 600 1rem/1 var(--f-texto); cursor: pointer;
  }
  .cabecera__menu[aria-expanded='true'] { border-color: var(--tinta); }
  .cabecera__menu:focus-visible { outline: 2px solid var(--tinta); outline-offset: 3px; }

  .pildora {
    position: fixed; left: 50%; bottom: max(14px, env(safe-area-inset-bottom)); z-index: 41;
    transform: translateX(-50%);
    display: flex; gap: 4px; padding: 5px;
    border-radius: var(--radio-control);
    background: var(--tinta); box-shadow: 0 10px 30px rgb(0 0 0 / .25);
  }
  .pildora__menu,
  .pildora__wa {
    min-height: 48px; padding: 0 22px; border: 0; border-radius: var(--radio-control);
    font: 600 1rem/1 var(--f-texto); display: inline-flex; align-items: center; text-decoration: none;
  }
  .pildora__menu { background: transparent; color: var(--papel); cursor: pointer; }
  .pildora__wa { background: var(--oliva); color: var(--sobre-oliva); }
  body { padding-bottom: 90px; }
  /* Home: mientras el WhatsApp de la entrada se ve, la píldora está fuera de pantalla hacia abajo y sin foco
     (sitio.js, iniciarEntrada; mismo trato que el flotante del escritorio). Sale y entra en 0,3 s; cuando la
     destapa la pelota, sin transición (la base no lleva ninguna). */
  html[data-js='si'] .pildora[data-arriba] {
    opacity: 0; transform: translateX(-50%) translateY(calc(100% + 40px)); visibility: hidden; pointer-events: none;
    transition: opacity .3s cubic-bezier(.22, 1, .36, 1), transform .3s cubic-bezier(.22, 1, .36, 1), visibility 0s linear .3s;
  }
  /* Mientras «Tu paquete» está en pantalla, la píldora se aparta: lo tapaba y el paquete ya lleva su WhatsApp
     (critico-ux 06). Lo marca sitio.js (iniciarPildoraPaquete). */
  html[data-js='si'] .pildora[data-junto-paquete] {
    opacity: 0; transform: translateX(-50%) translateY(calc(100% + 40px)); visibility: hidden; pointer-events: none;
    transition: opacity .3s cubic-bezier(.22, 1, .36, 1), transform .3s cubic-bezier(.22, 1, .36, 1), visibility 0s linear .3s;
  }
  html[data-js='si'] .pildora[data-entra] {
    transition: opacity .3s cubic-bezier(.22, 1, .36, 1), transform .3s cubic-bezier(.22, 1, .36, 1), visibility 0s linear 0s;
  }
}
/* La pelota (solo home, una vez por sesión): en el móvil abre la píldora; en el escritorio se convierte en el
   WhatsApp flotante. Solo existe mientras sitio.js la anima: sin JS o con movimiento reducido no hay [data-activa]
   y el botón sale entero. Fuera del @media para que sirva a los dos anchos; el z-index del móvil se conserva. */
.bola { display: none; }
html[data-js='si'] .bola[data-activa] {
  display: block; position: fixed; left: 0; top: 0; z-index: 42;
  width: 34px; height: 34px; border-radius: 50%;
  background: var(--oliva); opacity: 0; pointer-events: none;
  transform-origin: 50% 100%; will-change: transform;
}
html[data-js='si'] .bola[data-morph] { border-radius: var(--radio-control); }
/* Escritorio, tema claro: anillo de papel para que la pelota se dibuje también sobre negro y sobre oliva.
   En oscuro se quita (abajo, mismo patrón que la paleta: sistema o conmutador). */
@media (min-width: 860px) {
  html[data-js='si'] .bola[data-activa] { z-index: 36; box-shadow: 0 0 0 2px #f4f4f2; }
}

/* WhatsApp flotante: solo escritorio y solo home. Por encima del contenido (35), por debajo del menú (40) y del
   «saltar» (50). Se esconde cuando entran los botones del cierre o el pie (sitio.js, iniciarFlotante).
   --flota-margen: 24 px hasta 1920 y crece hasta 40 px a 2560 (a 1440, igual que antes). La barra de la galería
   de la home lo usa para terminar antes del botón. */
.flota-wa { display: none; }
@media (min-width: 860px) {
  .p-inicio { --flota-margen: clamp(24px, 2.5vw - 24px, 40px); }
  .flota-wa {
    position: fixed; z-index: 35;
    right: max(var(--flota-margen, 24px), env(safe-area-inset-right));
    bottom: max(var(--flota-margen, 24px), env(safe-area-inset-bottom));
    display: inline-flex; align-items: center; gap: 10px;
    /* 48 → 56 px y 1rem → 1.125rem entre 1920 y 2560; por debajo de 1920, como antes. */
    min-height: clamp(48px, 24px + 1.25vw, 56px); padding: 0 22px 0 18px; border-radius: var(--radio-control);
    background: var(--oliva); color: var(--sobre-oliva);
    font: 600 clamp(1rem, .625rem + .3125vw, 1.125rem)/1 var(--f-texto); text-decoration: none;
    /* Tema claro: anillo de papel (se lee sobre negro y sobre oliva) + sombra. En oscuro, abajo. */
    box-shadow: 0 0 0 2px #f4f4f2, 0 10px 30px rgb(0 0 0 / .25);
    transition: opacity .24s cubic-bezier(.22, 1, .36, 1), transform .24s cubic-bezier(.22, 1, .36, 1), visibility 0s linear 0s,
      background-color .24s cubic-bezier(.22, 1, .36, 1), color .24s cubic-bezier(.22, 1, .36, 1);
  }
  .flota-wa__icono { flex: none; }
  .flota-wa:focus-visible { outline: 2px solid var(--tinta); outline-offset: 3px; }
  .flota-wa[data-oculta] {
    opacity: 0; transform: translateY(16px); visibility: hidden; pointer-events: none;
    transition: opacity .24s cubic-bezier(.22, 1, .36, 1), transform .24s cubic-bezier(.22, 1, .36, 1), visibility 0s linear .24s,
      background-color .24s cubic-bezier(.22, 1, .36, 1), color .24s cubic-bezier(.22, 1, .36, 1);
  }
  /* Tema claro, sobre Bodas (sección oscura): se invierte a papel con texto e icono oliva (sitio.js pone el
     atributo; el icono va en currentColor). */
  .flota-wa[data-sobre-oscuro] { background: #f4f4f2; color: #4a5245; }
  /* Mientras el WhatsApp de la entrada se ve: fuera de pantalla hacia abajo y sin foco (sitio.js,
     iniciarEntrada). Sale y entra con un deslizamiento de 0,3 s ([data-entra] solo dura la entrada). */
  html[data-js='si'] .flota-wa[data-arriba] {
    opacity: 0; transform: translateY(calc(100% + var(--flota-margen, 24px) + 12px)); visibility: hidden; pointer-events: none;
    transition: opacity .3s cubic-bezier(.22, 1, .36, 1), transform .3s cubic-bezier(.22, 1, .36, 1), visibility 0s linear .3s;
  }
  html[data-js='si'] .flota-wa[data-entra]:not([data-oculta]) {
    transition: opacity .3s cubic-bezier(.22, 1, .36, 1), transform .3s cubic-bezier(.22, 1, .36, 1), visibility 0s linear 0s,
      background-color .24s cubic-bezier(.22, 1, .36, 1), color .24s cubic-bezier(.22, 1, .36, 1);
  }
  /* Mientras la pelota corre: invisible pero clicable (convertir manda: el clic llega al botón). */
  html[data-js='si'] .flota-wa[data-bola-corre] { opacity: 0; transition: none; }
  /* Tema oscuro (sistema sin elección, o elegido): sin anillo, sombra a la mitad y sin inversión sobre Bodas. */
  :root[data-theme='dark'] .flota-wa { box-shadow: 0 10px 30px rgb(0 0 0 / .125); }
  :root[data-theme='dark'] .flota-wa[data-sobre-oscuro] { background: var(--oliva); color: var(--sobre-oliva); }
  :root[data-theme='dark'] .bola[data-activa] { box-shadow: none; }
}
@media (min-width: 860px) and (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) .flota-wa { box-shadow: 0 10px 30px rgb(0 0 0 / .125); }
  :root:not([data-theme='light']) .flota-wa[data-sobre-oscuro] { background: var(--oliva); color: var(--sobre-oliva); }
  :root:not([data-theme='light']) .bola[data-activa] { box-shadow: none; }
}
.pildora__wa-texto { transition: opacity .12s linear; }
.pildora[data-bola-corre] .pildora__wa-texto { opacity: 0; }

/* ---------- home ---------- */
.promesa { padding-top: clamp(24px, 6vw, 80px); }
.promesa__subtitulo { font-size: clamp(1.05rem, 1.6vw, 1.2rem); color: var(--sombra); margin: 4px 0 20px; }
.promesa__pregunta { font-size: 1.25rem; font-weight: 600; margin: 0 0 12px; }
.promesa__nota { margin: 16px 0 28px; font-size: .95rem; color: var(--sombra); }
.opciones { display: flex; flex-wrap: wrap; gap: 10px; margin: 0 0 22px; padding: 0; list-style: none; }
/* Pastillas (P4, duelo r3). Dos capas iguales en la misma celda: la de oliva se derrama desde el toque con
   clip-path al marcar (CSS puro sobre :checked, sin JS también). Frases largas: la pastilla parte línea. */
.opcion { position: relative; display: inline-flex; max-width: 100%; cursor: pointer; -webkit-tap-highlight-color: transparent; }
.opcion input { position: absolute; left: 0; top: 0; width: 1px; height: 1px; margin: 0; opacity: 0; pointer-events: none; }
.opcion__cara {
  position: relative; display: inline-grid; max-width: 100%;
  border-radius: var(--radio-control); overflow: hidden; isolation: isolate;
  box-shadow: inset 0 0 0 1.5px var(--filete);
  transition: box-shadow var(--t-micro) var(--e-suave);
}
.opcion:hover .opcion__cara { box-shadow: inset 0 0 0 1.5px var(--tinta); }
.opcion input:focus-visible + .opcion__cara { outline: 2px solid var(--oliva); outline-offset: 3px; }
.opcion__capa { grid-area: 1 / 1; display: inline-flex; align-items: center; gap: 8px; min-height: 46px; padding: 10px 18px 10px 14px; line-height: 1.3; }
.opcion__ico { width: 18px; height: 18px; flex: none; fill: none; stroke: currentColor; stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }
.opcion__lleno {
  position: relative; overflow: hidden;
  background: var(--oliva); color: var(--sobre-oliva);
  clip-path: circle(0% at var(--x, 50%) var(--y, 50%));
  transition: clip-path .75s var(--e-salida);
}
.opcion input:checked + .opcion__cara .opcion__lleno { clip-path: circle(150% at var(--x, 50%) var(--y, 50%)); }
.opcion__check { stroke-dasharray: 19; stroke-dashoffset: 19; transition: stroke-dashoffset .45s var(--e-suave); }
.opcion input:checked + .opcion__cara .opcion__check { stroke-dashoffset: 0; transition-delay: .16s; }
/* Brillo que cruza la pastilla al marcarla (la clase la pone sitio.js) */
.opcion__lleno::after {
  content: ''; position: absolute; top: -30%; bottom: -30%; left: 0; width: 45%;
  background: linear-gradient(100deg, transparent 0%, rgb(255 255 255 / .5) 50%, transparent 100%);
  transform: translateX(-160%) skewX(-18deg); pointer-events: none;
}
.opcion__cara--brilla .opcion__lleno::after { animation: opcion-brillo .9s var(--e-suave) .14s both; }
@keyframes opcion-brillo { to { transform: translateX(360%) skewX(-18deg); } }
.opcion__chispa {
  position: absolute; left: 0; top: 0; width: 3px; height: 11px; margin: -5.5px 0 0 -1.5px;
  border-radius: 2px; background: var(--oliva); opacity: 0; pointer-events: none;
}
.opcion__chispa--clara { background: var(--oliva-claro); }

/* El mensaje que crece con lo marcado (lo pinta sitio.js; sin JS lleva [hidden]). Vacío: fuera de la vista pero
   presente, para que el aria-live anuncie el primer cambio. */
.mensaje {
  max-width: 520px; margin: 0 0 18px; padding: 12px 16px 14px;
  border-radius: 18px 18px 18px 4px; background: var(--velo); color: var(--tinta);
  transform-origin: 0 100%;
}
.mensaje[hidden] { display: none; }
.mensaje[data-vacio] { position: absolute; width: 1px; height: 1px; margin: 0; padding: 0; overflow: hidden; clip-path: inset(50%); }
.mensaje__de { margin: 0 0 4px; font-size: .75rem; font-weight: 600; letter-spacing: .08em; text-transform: uppercase; color: var(--oliva); }
.mensaje__texto { margin: 0; font-size: 1rem; }
.mensaje[data-completo] .mensaje__texto { white-space: pre-line; font-size: .95rem; }
.mensaje__item { display: inline-block; max-width: 100%; padding: 0 8px; border-radius: 10px; background: var(--oliva); color: var(--sobre-oliva); font-weight: 600; }
.mensaje__item--nuevo { animation: mensaje-entra .6s var(--e-salida); }
.mensaje__par { display: inline-block; max-width: 100%; }
@keyframes mensaje-entra {
  from { clip-path: inset(0 100% 0 0 round 10px); transform: translateY(6px); }
  to { clip-path: inset(0 0 0 0 round 10px); transform: none; }
}

/* Fondo a sangre (ritmo de fondos entre secciones, arquitectura §2): el contenido conserva su margen de
   siempre porque vive en .diagnostico__cuerpo, no directo en la sección. */
.diagnostico {
  background: var(--velo);
  width: 100%;
  padding-inline: max(var(--margen), (100% - var(--ancho)) / 2);
}
/* Versión A (29 sep 2026): el lado (estado, «Cambiar lo que marqué», momento) arriba y las tres cards debajo, a lo
   ancho. Una sola columna a todo ancho. */
.diagnostico__cuerpo { display: grid; grid-template-columns: minmax(0, 1fr); gap: clamp(32px, 5vw, 48px); }
/* Lo marcado arriba (sitio.js, pintarDiagnostico): la lista bajo «Esto es lo que marcaste:» y la flecha que sube. */
.diagnostico__marcado { margin: 12px 0 0; padding-left: 1.2em; display: grid; gap: 6px; font-weight: 600; }
.diagnostico__marcado[hidden] { display: none; }
.diagnostico__enlace::after { content: ' ↑'; }

/* Bloque 06. Columna izquierda: estado, enlace a la pregunta 1 y la pregunta 2 (momento). */
.diagnostico__lado { display: grid; gap: 16px; align-content: start; min-width: 0; }
.diagnostico__lado > .diagnostico__estado > p { margin: 0; }
/* Pregunta 2: mismas pastillas que la 1 (.opcion), en columna para que cada frase se lea entera en 375. */
.momentos { margin: 8px 0 0; padding: 0; border: 0; min-width: 0; }
.momentos__pregunta { padding: 0; margin: 0 0 12px; font-size: 1.25rem; font-weight: 600; }
.momentos__opciones { flex-direction: column; align-items: flex-start; margin: 0; }
.opcion input[type='radio'] + .opcion__cara .opcion__ico circle { fill: none; }

/* «Tu paquete», versión A · tres escalones numerados (docs/arquitectura-muestras/paquetes.html, elegida por Mario el
   29 sep 2026). Las tres cards siempre, en orden fijo y mismo ancho; se enciende la del paquete ([data-encendida],
   lo pone sitio.js). Apagada: velo + filete, número gris, nombre y línea en sombra; nunca opacity. */
.paquetes { min-width: 0; }
.paquetes [hidden] { display: none; }
.paquetes__titulo { margin: 0 0 16px; font-size: 1rem; }
.paquetes__anuncio { position: absolute; width: 1px; height: 1px; margin: 0; padding: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.paquetes__pide { margin: 0 0 16px; font-weight: 600; color: var(--oliva); }
.paquetes__lista { list-style: none; margin: 0; padding: 0; display: grid; gap: 12px; }
@media (min-width: 900px) {
  .paquetes__lista { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 24px; align-items: start; }
}

/* Apagada sobre papel: la sección ya es --velo y, con el mismo fondo, la card solo se distinguía por el filete. */
.paq {
  min-width: 0; border-radius: var(--radio-panel); padding: 28px;
  background: var(--papel); border: 1px solid var(--filete); color: var(--sombra);
  transition: background-color var(--t-base) var(--e-suave), color var(--t-base) var(--e-suave), border-color var(--t-base) var(--e-suave);
}
@media (max-width: 599px) { .paq { padding: 20px; } }
.paq[role='button'] { cursor: pointer; }
.paq[role='button']:hover { border-color: var(--sombra); }
.paq[role='button']:focus-visible { outline: 2px solid var(--oliva); outline-offset: 3px; }
.paq[data-encendida] { background: var(--oliva); border-color: var(--oliva); color: var(--sobre-oliva); }
/* El foco global es --oliva: sobre la card encendida no se vería. */
.paq[data-encendida] :focus-visible { outline-color: var(--sobre-oliva); }

.paq__cabeza { display: flex; align-items: flex-end; gap: 14px; }
.paq__num { display: inline-block; font: 700 72px/.85 var(--f-display); color: var(--gris); transform-origin: left center; }
.paq[data-encendida] .paq__num { color: var(--sobre-oliva); }
.paq__tipo { padding-bottom: 6px; font-size: 14px; line-height: 1.3; }
.paq__nombre { display: block; margin: 14px 0 0; font: 700 40px/1 var(--f-display); text-transform: uppercase; letter-spacing: .01em; }
.paq__linea { margin: 6px 0 0; font-size: 15px; line-height: 1.4; }

.paq__lista { margin: 20px 0 0; padding: 0; list-style: none; overflow-wrap: anywhere; }
.paq__lista li { position: relative; padding-left: 18px; margin-top: 10px; }
.paq__lista li::before { content: ''; position: absolute; left: 0; top: .62em; width: 8px; height: 1px; background: currentColor; }
.paq__cierre { margin: 16px 0 0; font-weight: 600; }
.paq__garantia { margin: 16px 0 0; padding-top: 16px; border-top: 1px solid color-mix(in srgb, currentColor 30%, transparent); font-size: 14px; }

.paq__mensaje { margin-top: 16px; }
.paq__mensaje summary { display: inline-flex; align-items: center; gap: 8px; min-height: 44px; cursor: pointer; list-style: none; font-weight: 600; }
.paq__mensaje summary::-webkit-details-marker { display: none; }
.paq__flecha { display: inline-block; transition: transform var(--t-micro) var(--e-suave); }
.paq__mensaje[open] .paq__flecha { transform: rotate(90deg); }
.paq__texto {
  margin: 4px 0 0; padding: 14px 16px; border-radius: 12px; white-space: pre-line; font-size: 14px;
  background: color-mix(in srgb, currentColor 10%, transparent);
}
/* Botón invertido sobre la oliva: papel con texto oliva (en oscuro, los mismos tokens lo resuelven). */
.paq .paq__wa {
  display: flex; width: 100%; min-height: 52px; margin-top: 16px; padding: 12px 20px; text-align: center;
  background: var(--papel); border-color: var(--papel); color: var(--oliva);
}
.paq .paq__wa:hover { background: transparent; border-color: currentColor; color: var(--sobre-oliva); }
.paq__correo {
  display: inline-flex; align-items: center; min-height: 44px; margin-top: 6px;
  color: inherit; font-size: 15px; text-decoration: underline; text-underline-offset: 3px;
}

/* Apagada: solo con JS se pliega (norma 9). Sin JS se lee todo: tipo, nombre y línea. */
html[data-js='si'] .paq:not([data-encendida]) .paq__tipo { display: none; }
html[data-js='si'] .paq[data-encendida] .paq__linea { display: none; }

/* «Hablemos»: bloque aparte, con la piel de la card encendida, cuando no hay paquete de catálogo. */
.paq--hablemos { margin-top: 24px; }
.paq__hablemos-texto { margin: 12px 0 0; max-width: 60ch; }
@media (min-width: 900px) { .paq--hablemos .paq__wa { width: auto; display: inline-flex; min-width: 320px; } }

/* Latido al encender: solo el número, solo por un gesto del visitante (sitio.js), nunca con movimiento reducido. */
.paq__num--late { animation: paq-late .42s var(--e-suave); }
@keyframes paq-late { 45% { transform: scale(1.06); } }
@media (prefers-reduced-motion: reduce) { .paq__num--late { animation: none; } }

@media (max-width: 899px) {
  .paq__num { font-size: 56px; }
  /* Apagada en móvil: fila de ~64 px con número, nombre y línea. */
  html[data-js='si'] .paq:not([data-encendida]) {
    display: grid; grid-template-columns: 40px minmax(0, 1fr); column-gap: 12px; align-items: center;
    min-height: 64px; padding: 10px 20px;
  }
  html[data-js='si'] .paq:not([data-encendida]) .paq__cabeza { display: contents; }
  html[data-js='si'] .paq:not([data-encendida]) .paq__num { grid-row: 1 / span 2; font-size: 32px; }
  html[data-js='si'] .paq:not([data-encendida]) .paq__nombre { grid-column: 2; margin: 0; font-size: 22px; }
  html[data-js='si'] .paq:not([data-encendida]) .paq__linea { grid-column: 2; margin: 2px 0 0; font-size: 13px; line-height: 1.3; }
}

/* ---------- qué hacemos: tarjetas que se apilan (K, duelo 4) ----------
   El apilado es sticky puro: sin JS se lee igual. sitio.js (iniciarTarjetas) añade giro, escala y sombra.
   En el móvil la tarjeta acaba por encima de la píldora (3svh + 72svh + desfase), para que su enlace no quede debajo. */
.servicios__titular { font-size: clamp(4rem, 15vw, 13rem); line-height: .86; }
/* Sin relleno bajo la lista: el relleno no cuenta para cuándo se sueltan las sticky, y tras soltarse la pila dejaba
   ~200 px de pantalla vacía antes de «Quiénes somos» (critico-ux, 11). flow-root es imprescindible: sin él el margen
   de la última tarjeta se escapa de la lista, la lista acaba antes y las tres primeras se sueltan antes de que llegue
   la cuarta (se rompió así el 29 sep y lo vio Mario). */
.servicios__lista { list-style: none; margin: clamp(32px, 5vw, 56px) 0 0; padding: 0; display: flow-root; }
.servicio {
  position: sticky;
  top: calc(3vh + var(--i) * 14px);
  top: calc(3svh + var(--i) * 14px);
  /* Hueco por tarjeta (arreglo 5, 28 sep): con 14svh cada enlace solo se dejaba pulsar ~300 px de scroll antes de
     que lo tapara la siguiente. Con ~76svh queda ≥ ~700 px. El apilado no cambia: solo dura más cada tarjeta. */
  margin-bottom: 76vh; margin-bottom: 76svh;
}
/* La última lleva el mismo hueco que las demás: el hueco cuenta para cuándo se suelta cada tarjeta sticky, y con 0 en
   la última las tres primeras se soltaban antes de que ella llegara (quedaba sola, sin pila). Así se sueltan juntas. */
.servicio__tarjeta {
  position: relative;
  display: grid; grid-template-rows: minmax(150px, 1fr) auto; gap: 16px;
  min-height: min(72vh, 640px); min-height: min(72svh, 640px);
  padding: 12px 12px 22px;
  border-radius: var(--radio-panel);
  transform-origin: 50% 0;
}
html[data-js='si'] .servicio__tarjeta { will-change: transform; }
.servicio__tarjeta--sin-foto { grid-template-rows: 1fr; align-content: end; }
/* La foto no aporta alto (va absoluta): así la fila 1fr se reparte lo que deja el texto. */
.servicio__foto { position: relative; margin: 0; min-height: 0; border-radius: var(--radio-foto); overflow: hidden; }
.servicio__foto img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.servicio__texto { align-self: end; padding: 0 10px; }
.servicio__num { margin: 0; font: 700 1.6rem/1 var(--f-display); }
.servicio__titulo {
  margin: .05em 0 .2em;
  font: 700 clamp(2.8rem, 12vw, 7rem)/.88 var(--f-display);
  text-transform: uppercase; overflow-wrap: break-word;
}
.servicio__desc { margin: 0; max-width: 42ch; }
.enlace-flecha--servicio { margin-top: 14px; font-size: .95rem; }
/* Icono de WhatsApp delante del texto: en línea (no flex) para que el texto siga partiendo como antes; toma el
   color del enlace por currentColor y baja lo justo para centrarse con la minúscula. */
.enlace-flecha__icono { width: 1.2em; height: 1.2em; margin-right: .35em; vertical-align: -.28em; }
.servicio__sombra { position: absolute; inset: 0; border-radius: inherit; background: #1d1c1b; opacity: 0; pointer-events: none; }
.servicio__tarjeta :focus-visible { outline-color: currentColor; }
/* Cuatro pieles. La «claro» va en tinta fija: en modo noche --tinta es clara y no se leería. */
.servicio__tarjeta--papel { background: var(--papel); color: var(--tinta); border: 1px solid var(--filete); }
.servicio__tarjeta--papel .servicio__num { color: var(--oliva); }
.servicio__tarjeta--oliva { background: var(--oliva); color: var(--sobre-oliva); }
.servicio__tarjeta--tinta { background: var(--tinta); color: var(--papel); }
.servicio__tarjeta--tinta .servicio__num { color: var(--oliva-claro); }
.servicio__tarjeta--claro { background: var(--oliva-claro); color: #1d1c1b; }
@media (min-width: 860px) {
  .servicio {
    top: calc(10vh + var(--i) * 26px);
    top: calc(10svh + var(--i) * 26px);
    margin-bottom: 66vh; margin-bottom: 66svh;
  }
  .servicio__tarjeta {
    grid-template-rows: none; grid-template-columns: 1.15fr 1fr; gap: 0; padding: 16px;
    min-height: min(76vh, 720px); min-height: min(76svh, 720px);
  }
  .servicio__tarjeta--sin-foto { grid-template-columns: 1fr; }
  .servicio__texto { padding: 32px 40px 28px; }
  .servicio__num { font-size: 2.4rem; }
  /* Tope en rem: la columna de texto no crece más allá de --ancho, y «HERRAMIENTAS» tiene que caber. */
  .servicio__titulo { font-size: clamp(3.6rem, 5.6vw, 5.5rem); }
  .servicio__desc { font-size: 1.08rem; }
}
/* Movimiento reducido: estado final, una tarjeta tras otra sin pegarse. */
@media (prefers-reduced-motion: reduce) {
  .servicio { position: static; margin-bottom: 16px; }
}

.cierre__principal { display: flex; flex-wrap: wrap; gap: 12px; margin-block: 24px; }
.cierre__redes { color: var(--sombra); }

/* Globo «escribiendo…» sobre el WhatsApp del cierre (variante 2). Solo con JS, ratón o teclado; nunca tapa el
   botón: sale por encima y no recibe punteros. */
.cierre__wa { position: relative; display: inline-flex; }
.globo { display: none; }
html[data-js='si'] .globo {
  display: block; position: absolute; left: 0; bottom: calc(100% + 14px); z-index: 2;
  width: max-content; max-width: min(340px, 80vw); padding: 10px 14px;
  border-radius: 18px 18px 18px 4px; background: var(--velo); color: var(--tinta);
  box-shadow: 0 1px 0 var(--filete); font-size: .95rem; line-height: 1.4; pointer-events: none;
  opacity: 0; transform: scale(.15) translateY(10px); transform-origin: 20px calc(100% + 14px);
  transition: transform .55s cubic-bezier(.34, 1.56, .64, 1), opacity .2s var(--e-suave);
}
html[data-js='si'] .globo::after {
  content: ''; position: absolute; left: -7px; bottom: 0; width: 14px; height: 14px;
  background: inherit; clip-path: polygon(100% 0, 100% 100%, 0 100%);
}
html[data-js='si'] .globo--abierto { opacity: 1; transform: none; }
.globo__puntos { display: none; gap: 5px; padding: 6px 2px; }
.globo__puntos i { width: 8px; height: 8px; border-radius: 50%; background: var(--gris); animation: globo-punto 1s var(--e-suave) infinite; }
.globo__puntos i:nth-child(2) { animation-delay: .15s; }
.globo__puntos i:nth-child(3) { animation-delay: .3s; }
@keyframes globo-punto { 0%, 60%, 100% { transform: translateY(0); opacity: .5; } 30% { transform: translateY(-6px); opacity: 1; } }
.globo--escribe .globo__puntos { display: flex; }
.globo--escribe .globo__msg { display: none; }
.globo__p { display: inline-block; opacity: 0; transform: translateY(.5em); }
.globo--lista .globo__p {
  opacity: 1; transform: none;
  transition: opacity .3s var(--e-suave), transform .4s var(--e-salida); transition-delay: calc(var(--i) * 45ms);
}

/* Carta que asoma del buzón al pasar por el correo (variante 3, sin avión). CSS puro: sin JS también. El botón
   lleva fondo de papel para tapar la carta mientras está dentro. */
.buzon { position: relative; display: inline-flex; isolation: isolate; }
.boton--correo { position: relative; z-index: 1; background: var(--papel); }
.carta {
  position: absolute; z-index: 0; left: 18%; right: 18%; bottom: 4px; height: 44px;
  display: flex; flex-direction: column; gap: 4px; padding: 6px 10px;
  border-radius: 4px; background: #fff; color: #1d1c1b; box-shadow: 0 0 0 1px var(--filete);
  pointer-events: none; transform-origin: 50% 100%;
  transition: transform .5s var(--e-salida);
}
.carta__hola { font: 600 .68rem/1 var(--f-texto); white-space: nowrap; overflow: hidden; }
.carta__raya { display: block; height: 3px; border-radius: 2px; background: #d5d5d3; }
.carta__raya--corta { width: 55%; }
@media (hover: hover) { .buzon:hover .carta { transform: translateY(-64%) rotate(-3deg); } }
.buzon:has(.boton--correo:focus-visible) .carta { transform: translateY(-64%) rotate(-3deg); }

/* Garabato a mano bajo los enlaces del texto (variante 6). La clase la pone sitio.js: sin JS, subrayado normal. */
.garabato { position: relative; display: inline-block; text-decoration: none; }
.garabato__trazo {
  position: absolute; left: -2%; bottom: -.12em; width: 104%; height: .24em;
  overflow: visible; fill: none; stroke: var(--oliva); pointer-events: none;
}
.garabato__trazo path {
  vector-effect: non-scaling-stroke; stroke-width: 2.5; stroke-linecap: round; stroke-linejoin: round;
  stroke-dasharray: 1; stroke-dashoffset: 1; transition: stroke-dashoffset .45s var(--e-suave);
}
.garabato:is(:hover, :focus-visible) .garabato__trazo path { stroke-dashoffset: 0; }
/* Reposo: un filete fino para que se siga viendo que es un enlace. */
.garabato::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: -.05em; height: 1px;
  background: currentColor; opacity: .45; transition: opacity var(--t-micro) var(--e-suave);
}
.garabato:is(:hover, :focus-visible)::after { opacity: 0; }

/* Movimiento reducido: estado final, sin animar (las cinco microinteracciones). */
@media (prefers-reduced-motion: reduce) {
  .opcion__lleno, .opcion__check, .opcion__cara, .mensaje__item, .carta, .garabato__trazo path,
  .pildora__wa-texto { transition: none !important; }
  .opcion input:checked + .opcion__cara .opcion__check { transition-delay: 0s; }
  .opcion__cara--brilla .opcion__lleno::after, .mensaje__item--nuevo { animation: none; }
  html[data-js='si'] .globo, .globo__p, .globo--lista .globo__p { transition: none !important; }
  .globo__puntos i { animation: none; }
}

/* ---------- cierre: titular que engorda letra a letra (P1, duelo 4 r3) ----------
   Sin JS o con movimiento reducido: grosor 800 fijo y la sección con su alto normal. Con JS (data-vivo) la
   sección se alarga y TODO el cierre queda fijo en pantalla: los botones no esperan al efecto. */
.cierre__titular {
  font-family: 'Big Shoulders Display', var(--f-display);
  font-weight: 800;
  font-variation-settings: 'wght' 800;
  text-transform: uppercase;
  font-size: min(19vw, 26vh, 16rem); /* «HABLEMOS» a wght 900 mide 4,06 em: a 375 cabe hasta ~79 px (con 22vw se partía) */
  white-space: nowrap;
  line-height: .86;
  letter-spacing: .012em;
  margin: 0 0 .12em;
}
.cierre__letra { display: inline-block; font-variation-settings: 'wght' var(--w, 800); opacity: var(--o, 1); }
html[data-js='si'] .cierre[data-vivo] { height: 220vh; padding-block: 0; }
html[data-js='si'] .cierre[data-vivo] .cierre__fijo {
  position: sticky; top: 0;
  min-height: 100vh; min-height: 100svh;
  display: flex; flex-direction: column; justify-content: center;
  padding-block: clamp(24px, 6vh, 64px);
}

/* ---------- /trabajo/ y casos ---------- */
.filtros { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 32px; }
.filtro {
  min-height: 44px; padding: 0 18px; border: 1.5px solid var(--filete); border-radius: var(--radio-control);
  background: transparent; color: var(--tinta); font: 600 .95rem var(--f-texto); cursor: pointer;
}
.filtro[aria-pressed='true'] { background: var(--oliva); border-color: var(--oliva); color: var(--sobre-oliva); }
.tarjetas-casos { display: grid; gap: clamp(16px, 3vw, 32px); margin: 0; padding: 0; list-style: none; }
@media (min-width: 700px) { .tarjetas-casos { grid-template-columns: repeat(2, 1fr); } }
.trabajo__cta { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 20px 32px; margin-top: clamp(40px, 6vw, 72px); padding: clamp(28px, 4vw, 48px); border-radius: var(--radio-foto); background: var(--oliva); color: var(--sobre-oliva); }
.tarjeta-caso[hidden] { display: none; }

/* ---------- home · trabajo: galería horizontal fija (P3, duelo 4 r3) ----------
   A sangre dentro de .seccion. Sin JS o con movimiento reducido: fila con scroll lateral PROPIO (la página
   nunca). Con JS (data-vivo, solo si la pista no cabe) la galería mide una pantalla + lo que sobresale la pista,
   su interior se pega y la pista avanza con translate. */
.galeria { position: relative; margin-block: 0 24px; margin-inline: calc(50% - 50vw); }
/* El titular vive dentro de la galería (arreglo 4, 28 sep): comparte la pantalla fija con la pista, arriba.
   Su tamaño se topa también por el alto para que titular + tarjeta quepan en una pantalla. */
.galeria__titular {
  padding-inline: max(var(--margen), (100vw - var(--ancho)) / 2);
  font-size: min(clamp(3rem, 9vw, 7.5rem), 7vh);
  font-size: min(clamp(3rem, 9vw, 7.5rem), 7svh);
}
.galeria__pista {
  list-style: none; margin: 0;
  padding: 0 max(var(--margen), (100vw - var(--ancho)) / 2);
  display: flex; align-items: center;
  gap: clamp(12px, 2.5vw, 36px);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: thin;
}
/* Tarjetas a escala de momento fuerte (arreglo 4): en móvil ~86vw × ~60svh; en escritorio ~68svh de alto en 4:3.
   La foto llena la tarjeta (cover): en móvil la tarjeta es vertical y el 4:3 de .foto-hover se anula aquí. */
.galeria__pieza {
  flex: 0 0 auto; scroll-snap-align: start;
  width: 86vw; height: 60vh; height: 60svh;
}
@media (min-width: 860px) {
  .galeria__pieza { width: min(86vw, 68vh * 4 / 3); width: min(86vw, 68svh * 4 / 3); height: 68vh; height: 68svh; }
}
.galeria__pieza > a { display: block; height: 100%; }
.galeria .foto-hover { aspect-ratio: auto; height: 100%; }
/* En una galería que pasa bajo el cursor, el pie que sale al hover parpadea: cliente y rubro siempre a la vista. */
.galeria .foto-hover figcaption { translate: 0 0; opacity: 1; }
.galeria__pieza--cta {
  border-radius: var(--radio-foto); background: var(--oliva); color: var(--sobre-oliva);
  display: grid; align-content: end; justify-items: start; gap: 16px; padding: clamp(20px, 3vw, 32px);
}
.galeria__cta-titulo { margin: 0; font: 700 clamp(2.6rem, 6vw, 5rem)/.9 var(--f-display); text-transform: uppercase; }
.galeria__cta-boton { background: var(--sobre-oliva); border-color: var(--sobre-oliva); color: var(--oliva); }
.galeria__cta-boton:hover { background: transparent; color: var(--sobre-oliva); }
.galeria__barra { display: none; }
html[data-js='si'] .galeria[data-vivo] { height: var(--galeria-alto, 300vh); }
/* Titular arriba y pista debajo, centrados juntos en la pantalla fija: sin media pantalla vacía. */
html[data-js='si'] .galeria[data-vivo] .galeria__fijo {
  position: sticky; top: 0; height: 100vh; height: 100svh;
  display: flex; flex-direction: column; justify-content: center; overflow: clip;
}
html[data-js='si'] .galeria[data-vivo] .galeria__pista {
  overflow: visible; scroll-snap-type: none; width: max-content;
  will-change: transform; position: relative; z-index: 1;
}
html[data-js='si'] .galeria[data-vivo] .galeria__barra {
  display: block; position: absolute; left: var(--margen); right: var(--margen); bottom: 24px;
  height: 2px; background: var(--filete);
}
/* Home, escritorio: la barra termina antes del WhatsApp flotante (margen + ~147 px de botón + ~20 de aire = 190 a
   1440). Por encima de 1920 sigue al margen del botón. */
@media (min-width: 860px) {
  html[data-js='si'] .p-inicio .galeria[data-vivo] .galeria__barra { right: calc(var(--flota-margen, 24px) + 166px); }
}
.galeria__barra i { position: absolute; inset: 0; background: var(--oliva); transform: scaleX(var(--p, 0)); transform-origin: left; }
.tarjeta-caso a { text-decoration: none; }

/* Arsenal nuevo · hover de fotos (MOREMEDIA): zoom DENTRO de la máscara redondeada y pie que sube.
   Sin aberración cromática (la que traía el 5.2). */
.foto-hover {
  position: relative; margin: 0; overflow: hidden;
  border-radius: var(--radio-foto);
  aspect-ratio: 4 / 3;
  isolation: isolate; /* Safari: mantiene el recorte redondeado mientras la imagen escala */
}
.foto-hover img,
.foto-hover video {
  display: block; width: 100%; height: 100%; object-fit: cover;
  transition: scale var(--t-micro) var(--e-salida); /* salida un paso por debajo; la entrada, en el hover */
}
.foto-hover figcaption {
  position: absolute; inset: auto 0 0; padding: 64px 20px 18px;
  display: flex; justify-content: space-between; align-items: baseline; gap: 12px;
  /* Velo con meseta: sobre capturas claras de webs (AIGNEP) el .72 que se apagaba hacia arriba dejaba pasar el
     texto de la captura bajo el rubro. Opaco donde van nombre y rubro, y se funde solo por encima. */
  background: linear-gradient(to top, rgb(22 22 21 / .86), rgb(22 22 21 / .72) 55%, rgb(22 22 21 / 0));
  color: #eeeeec;
  translate: 0 0;
  transition: translate var(--t-micro) var(--e-salida), opacity var(--t-micro) var(--e-salida);
}
.tarjeta-caso__cliente { font: 700 clamp(1.8rem, 3.4vw, 2.6rem)/1 var(--f-display); text-transform: uppercase; }
/* Hover que mueve: solo con ratón (cosecha 7fc41cf). El pie (cliente y rubro) va siempre a la vista: Mario, 29 sep
   2026 (07, P9), tras el critico-ux; el hover se queda con el zoom. Se repite en la visita: entra en --t-base, sale en --t-micro. */
@media (hover: hover) and (pointer: fine) {
  a:hover .foto-hover img,
  a:focus-visible .foto-hover img,
  a:hover .foto-hover video,
  a:focus-visible .foto-hover video { scale: 1.06; transition-duration: var(--t-base); }
}

.caso__rubro { color: var(--sombra); font-weight: 600; }
.caso__resumen { font-size: 1.25rem; max-width: 40ch; }
/* Página de caso. Móvil: texto, WhatsApp y galería en una columna. ≥ 1024: texto fijo a la izquierda (el WhatsApp
   queda a la vista mientras se baja por la galería) y galería a la derecha. */
.caso__subtitulo { margin: 32px 0 8px; font: 700 clamp(1.4rem, 3vw, 1.8rem)/1.1 var(--f-display); text-transform: uppercase; }
.caso__necesitaba { margin: 0; max-width: 60ch; }
.caso__hicimos { margin: 0; padding-left: 1.2em; max-width: 60ch; }
.caso__hicimos li + li { margin-top: 6px; }
.caso__acciones { display: flex; flex-wrap: wrap; align-items: center; gap: 16px 24px; margin-top: 32px; }
.caso__acciones .enlace-flecha { margin-top: 0; }
.caso__galeria { list-style: none; margin: 40px 0 0; padding: 0; display: grid; gap: 16px; }
.caso__medio { margin: 0; border-radius: var(--radio-foto); overflow: hidden; }
.caso__medio img,
.caso__medio video { display: block; width: 100%; height: auto; }
@media (min-width: 1024px) {
  /* La rejilla es caso__cuerpo, no la sección: el texto pegado se suelta al acabar la galería y el «Volver»,
     fuera de ella, nunca queda debajo del botón (antes compartían rejilla y el sticky bajaba hasta tapar el enlace). */
  .caso__cuerpo { display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); column-gap: clamp(40px, 5vw, 80px); align-items: start; }
  .caso__galeria { margin-top: 0; }
}
/* Fija solo si cabe entera: a 1024 × 768 la columna mide ~800 px y el enlace quedaba fuera (medido, 07). */
@media (min-width: 1024px) and (min-height: 900px) { .caso__texto { position: sticky; top: 120px; } }

.legal p, .no-encontrada p { max-width: 60ch; }

/* ---------- pie ---------- */
.pie {
  width: min(100% - 2 * var(--margen), var(--ancho));
  margin-inline: auto; padding-block: 48px;
  border-top: 1px solid var(--filete);
  display: flex; flex-wrap: wrap; gap: 8px 32px; align-items: baseline;
  color: var(--sombra); font-size: .95rem;
}
.pie__marca { margin: 0; color: var(--tinta); font-weight: 600; }
.pie__texto { margin: 0; flex: 1; }
.pie__legal { display: flex; gap: 20px; }
/* La dirección escrita, no solo el botón (P6, critico-ux del 11): sin programa de correo, «Correo» no abre nada y
   hay que poder copiarla. En el pie de todas las páginas y bajo los botones del cierre. */
.pie__correo { color: var(--tinta); }
.cierre__direccion { margin: 0 0 8px; }

/* ---------- movimiento base: aparece al entrar (2.4), solo con JS ---------- */
html[data-js='si'] [data-revela] {
  opacity: 0; translate: 0 24px;
  transition: opacity var(--t-slow) var(--e-salida), translate var(--t-slow) var(--e-salida);
}
html[data-js='si'] [data-revela][data-visible] { opacity: 1; translate: 0 0; }

/* ---------- arsenal nuevo · parallax por secciones, velocidad en el HTML ----------
   La plantilla escribe data-parallax="0.15" y style="--vel:0.15" (helper parallax() del motor):
   positivo va más lento que el scroll, negativo más rápido.
   CSS nativo (animation-timeline: view()) donde existe; si no, sitio.js lo mueve con rAF. */
[data-parallax] { will-change: translate; }
@supports (animation-timeline: view()) {
  [data-parallax] {
    animation: parallax linear both;
    animation-timeline: view();
  }
  @keyframes parallax {
    from { translate: 0 calc(var(--vel) * 30vh); }
    to { translate: 0 calc(var(--vel) * -30vh); }
  }
}

/* ---------- arsenal nuevo · secciones que se apilan ----------
   Cada [data-apila] se queda fija cuando su borde de ABAJO llega al de la pantalla (sitio.js pone --apila-top =
   alto de pantalla − alto de la sección, nunca más de 0), y la siguiente pasa por encima. Con top: 0 a secas,
   una sección más alta que la pantalla quedaba tapada antes de enseñar su final (los retratos, 26 sep 2026).
   Sin JS no se apila: se lee todo. */
html[data-js='si'] [data-apila] { position: sticky; top: var(--apila-top, 0px); }
/* Una sticky está posicionada y se pinta ENCIMA de toda hermana estática, venga antes o después.
   Posicionar todas las secciones devuelve el orden al HTML: la siguiente tapa a la anterior. */
main .seccion:not([data-apila]) { position: relative; }
/* La pila (la escribe el motor) encierra las apiladas y la que las tapa: al acabar, el sticky se suelta
   y ya no asoma por debajo de lo que viene después (lo vio Mario el 26 sep 2026). */
.pila { position: relative; }

/* ---------- arsenal nuevo · franja ligada al scroll (variante de 57 y 6.3) ----------
   Avanza en horizontal mientras la página baja (se lee en diagonal, y eso a Mario le gusta: 26 sep 2026).
   --velocidad (desde los datos) escala el recorrido: 1 = el primero que se probó, que le pareció rápido.
   Una versión fija con recorrido largo se probó y se descartó: «exagerado de lento» y perdía la diagonal. */
.franja { width: 100%; padding-inline: 0; overflow: clip; background: var(--banda); color: var(--sobre-banda); }
/* clip y no hidden: hidden crea un contenedor de scroll, view() lo toma por scroller y la línea de tiempo
   se queda clavada en el 50 % (medido el 26 sep 2026 con Playwright). Vale para todo padre de un [data-parallax]. */
.franja__pista {
  display: flex; gap: 0.6em; margin: 0; padding: 0 var(--margen); list-style: none; white-space: nowrap;
  font: 700 clamp(3rem, 10vw, 9rem)/1 var(--f-display); text-transform: uppercase;
}
.franja__pista li:not(:last-child)::after { content: '·'; margin-left: .6em; color: var(--gris); }
@supports (animation-timeline: view()) {
  .franja__pista {
    width: max-content;
    animation: franja linear both;
    animation-timeline: view();
    animation-range: cover 5% cover 55%;
  }
  /* Termina con la pista entera recorrida (100vw - 100 % = su propio ancho): antes se movía un tramo fijo y el
     último rubro no llegaba a leerse (Mario, 27 sep 2026). --velocidad solo decide desde dónde entra. */
  @keyframes franja {
    from { translate: calc(var(--velocidad, 0.5) * 40vw) 0; }
    to { translate: calc(100vw - 100%) 0; }
  }
}

/* ---------- parallax dentro de un marco: la foto crece lo que se desplaza, así nunca asoma el fondo ---------- */
/* La foto va absoluta: si estuviera en el flujo, un retrato vertical le impondría su alto al marco y el
   100 % de su altura se volvería circular (medido: 28-50 px de hueco en los retratos). El marco lo manda
   su aspect-ratio. */
.marco-parallax { position: relative; overflow: clip; border-radius: var(--radio-foto); }
.marco-parallax img[data-parallax] {
  position: absolute; left: 0; width: 100%; object-fit: cover;
  --holgura: calc(max(var(--vel), var(--vel) * -1) * 30vh);
  top: calc(-1 * var(--holgura));
  height: calc(100% + 2 * var(--holgura));
}

/* ---------- quiénes somos: los dos retratos en blanco y negro ---------- */
/* Los dos Instagram en fila bajo el texto; en 375 bajan uno debajo del otro si no caben. */
.nosotros__redes { display: flex; flex-wrap: wrap; column-gap: 28px; row-gap: 12px; margin: 32px 0 0; }
.nosotros__redes .enlace-flecha { margin-top: 0; }
.nosotros__personas { display: grid; grid-template-columns: repeat(2, 1fr); gap: clamp(12px, 3vw, 40px); margin-top: 40px; }
.persona { margin: 0; }
.persona .marco-parallax { aspect-ratio: 2 / 3; }
.persona:nth-child(2) { margin-top: clamp(40px, 10vw, 140px); }
.persona figcaption { margin-top: 12px; font-weight: 600; display: flex; justify-content: space-between; align-items: baseline; gap: 16px; }
.persona__instagram { margin-top: 0; font-weight: 400; }
/* Contador bajo Felix (muestrario, variante 7): Thunder a escala de titular, rótulo en Aileron. */
.contador { margin: clamp(16px, 2.5vw, 32px) 0 0; }
.contador__cifra {
  display: block; font: 700 clamp(72px, 11vw, 200px)/.8 var(--f-display); letter-spacing: .01em; color: var(--oliva);
}
/* Ancho fijo del dígito: la cuenta 0→5 no mueve el «+» ni el rótulo. */
.contador__num { display: inline-block; min-width: .6em; font-variant-numeric: tabular-nums; }
.contador__rotulo {
  display: block; max-width: 24ch; margin-top: 10px; font: 400 clamp(.85rem, 1.1vw, 1rem)/1.35 var(--f-texto);
  color: var(--tinta); overflow-wrap: break-word;
}
.contador__leido {
  position: absolute; width: 1px; height: 1px; margin: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}

/* ---------- movimiento reducido: se apagan parallax, franja y apilado (arquitectura §4) ---------- */
@media (prefers-reduced-motion: reduce) {
  [data-parallax],
  .franja__pista { animation: none; translate: none; }
  .franja__pista { flex-wrap: wrap; white-space: normal; }
  [data-apila] { position: static; }
}

/* ---------- bodas: Felix a sangre ---------- */
/* Diafragma (P2, duelo 4 r3): sin JS o con movimiento reducido, foto entera y sin número f. Con JS (data-vivo) la
   sección se alarga, la escena se pega y sitio.js abre el recorte en hexágono. */
.bodas__escena { display: grid; gap: 32px; align-items: end; }
@media (min-width: 860px) { .bodas__escena { grid-template-columns: 1.2fr 1fr; } }
.bodas__foto { position: relative; margin: 0; aspect-ratio: 4 / 5; border-radius: var(--radio-foto); overflow: hidden; background: #1d1c1b; }
.bodas__recorte { position: absolute; inset: 0; }
.bodas__recorte img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 40%; }
.bodas__iris { display: none; position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
.bodas__iris g { transform-box: view-box; transform-origin: 0 0; }
.bodas__iris line { stroke: rgb(238 238 236 / .2); stroke-width: 1.2; }
.bodas__iris polygon { fill: none; stroke: var(--oliva-claro); stroke-width: 1.6; }
.bodas__f { display: none; margin: 0 0 12px; font: 700 clamp(32px, 4.2vw, 80px)/.8 var(--f-display); letter-spacing: .01em; color: var(--oliva-claro); }
.bodas__f span { display: inline-block; min-width: 2.2ch; }
.bodas__texto p { max-width: 42ch; }
/* Firma de Felix junto al botón: cara pequeña (firma, no protagonista), nombre y oficio. */
.bodas__accion { display: flex; flex-wrap: wrap; align-items: center; gap: 16px 28px; margin-top: 24px; }
.bodas__firma { display: flex; align-items: center; gap: 12px; margin: 0; }
.bodas__cara { flex: none; width: 72px; height: 72px; border-radius: 50%; object-fit: cover; }
.bodas__quien { display: flex; flex-direction: column; line-height: 1.25; }
.bodas__nombre { font-weight: 600; font-size: 20px; }
.bodas__oficio { font-size: .9rem; }
@media (min-width: 860px) { .bodas__cara { width: 96px; height: 96px; } .bodas__nombre { font-size: 22px; } }
/* El diafragma vive en .bodas__pista (data-diafragma): ella se alarga a 300vh y la escena se pega dentro. La sección
   solo pierde el padding de arriba; el de abajo queda para la tira. */
html[data-js='si'] .bodas:has(> .bodas__pista[data-vivo]) { padding-top: 0; }
html[data-js='si'] .bodas__pista[data-vivo] { height: 300vh; }
html[data-js='si'] .bodas__pista[data-vivo] .bodas__escena {
  position: sticky; top: 0; height: 100vh; height: 100svh;
  align-content: center; gap: 20px; overflow: clip; padding-block: 16px;
}
html[data-js='si'] .bodas__pista[data-vivo] .bodas__foto { aspect-ratio: auto; height: min(32svh, 520px); }
/* Móvil: la escena fija deja abajo el alto de la píldora (48 + 10 de relleno + 14 de margen), o el botón a la web de
   Felix queda debajo de ella (medido a 375×667 en el 08). */
@media (max-width: 859px) {
  html[data-js='si'] .bodas__pista[data-vivo] .bodas__escena { padding-bottom: calc(84px + env(safe-area-inset-bottom)); gap: 12px; }
  html[data-js='si'] .bodas__pista[data-vivo] .bodas__foto { height: 30svh; }
  html[data-js='si'] .bodas__pista[data-vivo] .bodas__f { margin-bottom: 4px; }
  html[data-js='si'] .bodas__pista[data-vivo] .bodas__accion { margin-top: 14px; row-gap: 10px; }
}
@media (max-width: 859px) and (max-height: 600px) {
  html[data-js='si'] .bodas__pista[data-vivo] .bodas__foto { height: 22svh; }
  html[data-js='si'] .bodas__pista[data-vivo] .bodas__escena { gap: 8px; }
}
html[data-js='si'] .bodas__pista[data-vivo] .bodas__iris,
html[data-js='si'] .bodas__pista[data-vivo] .bodas__f { display: block; }
@media (min-width: 860px) {
  html[data-js='si'] .bodas__pista[data-vivo] .bodas__escena { align-items: center; gap: clamp(40px, 6vw, 110px); }
  html[data-js='si'] .bodas { --bodas-foto: min(80svh, 740px); }
  html[data-js='si'] .bodas__pista[data-vivo] .bodas__foto { height: var(--bodas-foto); }
  /* Hueco foto → tira (director, 08): ~72 px a 1440 y ~96 a 3440. La escena fija deja bajo la foto la mitad de lo que
     sobra de la pantalla; el margen de la tira lo descuenta. La pista (el recorrido del diafragma) no cambia. */
  html[data-js='si'] .bodas:has(> .bodas__pista[data-vivo]) .tira-fotos {
    margin-top: calc(clamp(72px, 2vw + 43px, 96px) - (100svh - var(--bodas-foto)) / 2);
  }
}

/* ---------- tira de fotos enlazadas (componente propio; hoy vive en Bodas) ----------
   Ocupa el ancho del contenedor de su sección (en .banda, --ancho; tope 2200 a 3440). 2×2 en móvil, 4 en fila desde
   860. Proporción común 4:5; cada foto trae su encuadre en object-position desde los datos. Sin movimiento propio:
   hover subraya el rótulo; el foco de teclado, contorno en el color del texto de la banda. */
.tira-fotos {
  list-style: none; margin: clamp(40px, 6vw, 88px) 0 0; padding: 0;
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 20px 12px;
}
@media (min-width: 860px) { .tira-fotos { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: clamp(16px, 1.6vw, 28px); } }
.tira-fotos__item { margin: 0; }
.tira-fotos__enlace { display: block; color: inherit; text-decoration: none; border-radius: var(--radio-foto); }
.tira-fotos__enlace:focus-visible { outline: 2px solid currentColor; outline-offset: 4px; }
.tira-fotos__marco { display: block; aspect-ratio: 4 / 5; overflow: hidden; border-radius: var(--radio-foto); background: #1d1c1b; }
.tira-fotos__marco img { display: block; width: 100%; height: 100%; object-fit: cover; }
.tira-fotos__rotulo {
  display: block; margin-top: 10px; font-weight: 600; font-size: .95rem; letter-spacing: .02em;
  text-decoration: underline transparent; text-underline-offset: 4px; text-decoration-thickness: 1.5px;
  transition: text-decoration-color var(--t-micro) var(--e-suave);
}
.tira-fotos__enlace:is(:hover, :focus-visible) .tira-fotos__rotulo { text-decoration-color: currentColor; }
/* Flecha (08, hallazgo 6): el rótulo se lee como enlace. Texto alternativo vacío: el lector no dice «flecha». */
.tira-fotos__rotulo::after { content: ' →'; content: ' →' / ''; }

/* ---------- promesa, variante «foto»: la imagen a sangre ocupa la primera pantalla ----------
   El velo es un degradado translúcido de tinta fija detrás del texto (regla de oro 11: nunca mix-blend). */
.promesa--foto {
  position: relative;
  min-height: 100svh;
  width: 100%;
  display: flex; flex-direction: column; justify-content: flex-end;
  padding-block: clamp(28px, 8vw, 96px) clamp(28px, 6vw, 56px);
  padding-inline: max(var(--margen), (100% - var(--ancho)) / 2);
  overflow: clip;
  color: #eeeeec;
}
.promesa-foto__fondo,
.frases-scroll__fondo { position: absolute; inset: 0; z-index: 0; }
.promesa-foto__foto,
.frases-scroll__foto { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
html[data-js='si'] .promesa-foto__foto { opacity: 0; transition: opacity var(--t-slow) var(--e-salida); }
/* La foto de frases suma clip-path y filter a la misma transición: son las tres piezas del paso
   «cerrada → abierta» (recorte, gris, y qué foto se ve). Van juntas aquí y no en la regla genérica de
   más abajo porque esa es más específica (html[data-js='si'] le gana) y se comería el transition si
   solo declarara opacity. */
html[data-js='si'] .frases-scroll__foto {
  opacity: 0;
  transition: opacity var(--t-slow) var(--e-salida), clip-path var(--t-slow) var(--e-salida),
    filter var(--t-slow) var(--e-salida);
}
html[data-js='si'] .promesa-foto__foto[data-activa],
html[data-js='si'] .frases-scroll__foto[data-activa] { opacity: 1; }
/* Sin JS no hay ciclo: se ve una foto fija a pantalla completa, y la sección se lee igual.
   En «promesa--foto» es la última (single hero, cierre del ciclo). En las frases con foto pegada
   tiene que ser la PRIMERA: es la que abre la historia («cerrada», gris) y coincide con la primera
   frase del problema; con la última (la pareja, en color) detrás de las frases del problema, la
   historia se leía al revés. */
.promesa-foto__foto:last-of-type { opacity: 1; }
/* Sin JS todas están a opacidad 1 y apiladas, y la primera va recortada: por el marco asomaba la pareja en color
   (medido el 27 sep). Sin JS solo queda la primera; las demás son decorativas (alt=""), no contenido. */
html:not([data-js='si']) .frases-scroll__foto:not(:first-of-type) { display: none; }
.promesa-foto__velo {
  position: absolute; inset: 0;
  background: linear-gradient(180deg, rgb(29 28 27 / .12) 0%, rgb(29 28 27 / .58) 55%, rgb(29 28 27 / .88) 100%);
}
.promesa-foto__cabecera { position: relative; z-index: 1; max-width: 46ch; }
@media (min-width: 860px) {
  /* A lo ancho de la sección, como en la variante «promesa»: si se queda en 46ch el título de cinco
     palabras se parte en cinco líneas y empuja la pregunta y el WhatsApp fuera de la primera pantalla
     (medido en 1440×900: h1 de y=177 a 897, WhatsApp en y=1279). */
  .promesa-foto__cabecera { max-width: none; width: 100%; }
}
.promesa--foto .titular--hero,
.promesa--foto .promesa__pregunta { color: #eeeeec; }
.promesa--foto .promesa__nota,
.promesa--foto .promesa__subtitulo { color: rgb(238 238 236 / .8); }
.promesa--foto .opcion__cara { box-shadow: inset 0 0 0 1.5px rgb(238 238 236 / .55); }
.promesa--foto .opcion:hover .opcion__cara { box-shadow: inset 0 0 0 1.5px rgb(238 238 236 / .9); }
/* Sobre foto: el globo del mensaje en velo oscuro fijo (en los dos temas la foto es oscura). */
.promesa--foto .mensaje { background: rgb(22 22 21 / .78); color: #eeeeec; }
.promesa--foto .mensaje__de { color: #aab59c; }
/* Sobre foto (siempre oscura, en los dos temas): oliva claro fijo, no var(--oliva) — mismo motivo que
   .frases-scroll__resalte (comentario más abajo). */
.promesa--foto .titular__resalte { color: #aab59c; }

@media (max-width: 859px) {
  /* La píldora fija (menú + WhatsApp) tapa el botón si el hero lo apoya justo en el borde inferior
     (medido en 375×812: botón en y 750–798, debajo de la píldora). El mismo aire que reserva body
     (90px) para que quede libre. */
  .promesa--foto { padding-bottom: calc(clamp(28px, 6vw, 56px) + 90px); }
}

/* ---------- promesa, variante «lado»: composición asimétrica, foto vertical real a la derecha ----------
   Móvil: el orden de siempre y la foto asoma como una franja de 80-100px que invita a bajar. Escritorio:
   7/12 texto y 5/12 foto, con --radio-foto y sin marco ni sombra. Todo (h1+opciones+WhatsApp) tiene que caber
   en 900px de alto a 1440×900: si no cabe, cede el alto de la foto antes que el tamaño del h1 (max-height con
   width:100% deja que el aspect-ratio ceda por altura y el object-fit:cover absorba el recorte). */
.promesa--lado {
  padding-block: clamp(24px, 5vw, 56px);
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.promesa-lado__foto {
  border-radius: var(--radio-foto);
  overflow: hidden;
  height: 90px;
}
.promesa-lado__foto img { width: 100%; height: 100%; object-fit: cover; }
.titular--lado { font-size: clamp(2.6rem, 14vw, 3.6rem); }
.titular__linea { display: block; }

@media (min-width: 860px) {
  .promesa--lado {
    display: grid;
    grid-template-columns: 7fr 5fr;
    align-items: center;
    gap: clamp(24px, 4vw, 56px);
  }
  .promesa-lado__foto {
    height: auto;
    aspect-ratio: 2 / 3;
    max-height: min(600px, 64vh);
    justify-self: end;
    width: 100%;
  }
  /* A escala y en dos líneas: la línea más ancha mide ~6,1 veces el cuerpo, y la columna es ~7/12; 7,4vw cabe
     de 860 a 1440 (medido el 27 sep). */
  .titular--lado { font-size: min(8.5rem, 7.4vw); }
  .titular--lado .titular__linea { white-space: nowrap; }
}

@media (max-width: 859px) {
  /* Mismo respiro que la variante «foto»: la píldora fija no tape el WhatsApp. */
  .promesa--lado { padding-bottom: calc(clamp(24px, 5vw, 56px) + 90px); }
}

/* ---------- frases con foto pegada: cada frase entra sola, la foto va pasando por las tres ----------
   Comparte estructura con la variante «foto» pero es su propia sección: en la variante «promesa» es la
   única imagen del sitio; en la variante «foto» continúa el mismo ciclo de fotos del hero. */
.frases-scroll { position: relative; width: 100%; }
.frases-scroll__pegado { position: sticky; top: 0; height: 100svh; overflow: clip; }
/* Fondo propio: sin él, un hueco del recorte «cerrada» dejaría ver el papel del tema (claro u oscuro)
   en vez de un negro de foto — el recorte deja de leerse como ventana pequeña. Fijo, no var(--tinta):
   esa variable se invierte en modo oscuro y aquí el texto siempre es claro sobre foto. */
.frases-scroll__fondo { background: #1d1c1b; }
.frases-scroll__velo {
  position: absolute; inset: 0;
  background: linear-gradient(180deg, rgb(29 28 27 / .28) 0%, rgb(29 28 27 / .42) 50%, rgb(29 28 27 / .5) 100%);
}
.frases-scroll__lista { position: relative; z-index: 1; margin: calc(-1 * 100svh) 0 0; padding: 0; list-style: none; }
.frases-scroll__frase {
  min-height: 100svh; margin: 0; padding: var(--margen);
  display: flex; align-items: center; justify-content: center; text-align: center;
  font: 700 clamp(3rem, 10vw, 11rem)/.95 var(--f-display); text-transform: uppercase;
  color: #eeeeec;
}
.frases-scroll__texto { max-width: 16ch; }
/* Oliva CLARO fijo, no var(--oliva): esta sección es siempre oscura en los dos temas, y el oliva de
   marca (var(--oliva)) da 1,2–1,33:1 sobre la foto velada — ilegible. #aab59c es el mismo matiz,
   más claro; con el velo local de abajo sostiene ≥4,5:1 contra cualquier foto (regla de oro 11). */
.frases-scroll__resalte { color: #aab59c; }
/* Velo local solo bajo la frase final (la del remate con «CRECER»/«CRÉIXER»): el degradado de fondo
   de .frases-scroll__velo solista no basta contra una foto clara, y esta es la única frase que tiene
   que leerse SIEMPRE, sea cual sea la foto. Tinta fija, nunca mix-blend (regla de oro 11). */
.frases-scroll__frase--final .frases-scroll__texto { position: relative; z-index: 1; }
.frases-scroll__frase--final .frases-scroll__texto::before {
  content: '';
  position: absolute;
  inset: -.35em -.5em;
  z-index: -1;
  border-radius: 32px;
  background: radial-gradient(120% 130% at 50% 50%, rgb(18 17 16 / .82) 0%, rgb(18 17 16 / .6) 65%, transparent 100%);
}

/* ---------- fotos del bloque de frases: de «cerrada» (pequeña, recortada, gris) a «abierta» (a sangre, en
   color). El estado es del dato (data-estado, calculado en la plantilla); qué foto se ve la decide sitio.js
   con data-activa, que sigue siendo el respaldo si no hay animación de scroll disponible. ---------- */
.frases-scroll__foto { clip-path: inset(0); }
.frases-scroll__foto[data-estado='cerrada'] {
  clip-path: inset(20% round 10px);
  filter: grayscale(1) brightness(.62) contrast(.94);
}
.frases-scroll__foto[data-estado='abierta'] {
  clip-path: inset(0);
  filter: none;
}
/* La foto en el umbral (marcada data-abre-foto en la plantilla) no cruza por fundido de opacidad: sitio.js
   la hace visible en cuanto su frase empieza a entrar (aún «cerrada», idéntica a la anterior — el salto de
   opacidad no se nota porque el aspecto es el mismo) y desde ahí el --progreso-abre (0→1, calculado en rAF
   desde el rect de esa frase) abre el recorte y quita el gris de forma continua. Sin esta regla heredaría el
   fundido genérico de arriba, que es justo lo que el rectángulo fantasma delataba. Solo con movimiento
   permitido: sin él, sitio.js no calcula progreso y esta foto vuelve al ciclo normal (fundido + salto de
   data-estado), que es lo pedido para prefers-reduced-motion. */
@media (prefers-reduced-motion: no-preference) {
  html[data-js='si'] .frases-scroll__foto[data-abre-foto] {
    transition: none;
    clip-path: inset(calc(20% - 20% * var(--progreso-abre, 0)) round 10px);
    filter:
      grayscale(calc(1 - var(--progreso-abre, 0)))
      brightness(calc(.62 + .38 * var(--progreso-abre, 0)))
      contrast(calc(.94 + .06 * var(--progreso-abre, 0)));
  }
}
.frases-scroll__frase--remate { font-weight: 700; } /* el remate se distingue por el oliva, no por cursiva falsa */

/* Con movimiento reducido, la frase aparece con fundido y sin desplazarse (el degradado de fondo no se toca). */
@media (prefers-reduced-motion: reduce) {
  html[data-js='si'] .frases-scroll__frase[data-revela] {
    translate: 0 0;
    transition: opacity var(--t-base) var(--e-suave);
  }
  /* Sin viaje de máscara: el recorte y el gris de cada foto saltan a su estado final, y solo el
     cruce entre fotos (data-activa) se sigue leyendo como fundido. */
  .frases-scroll__foto { transition: opacity var(--t-base) var(--e-suave) !important; }
}

@media (max-width: 859px) {
  /* La píldora fija tapa el final de la frase si el texto llega hasta el borde inferior — mismo
     margen que reserva body (90px) en el resto del sitio. */
  .frases-scroll__frase { padding-bottom: calc(var(--margen) + 90px); }
}

/* Las secciones que se apilan necesitan fondo propio para tapar a la anterior. Ritmo de fondos entre
   secciones (arquitectura §2): «qué hacemos» en velo, «quiénes somos» en papel/noche. */
.servicios[data-apila],
.nosotros[data-apila] { width: 100%; padding-inline: max(var(--margen), (100% - var(--ancho)) / 2); }
.servicios[data-apila] { background: var(--velo); }
.nosotros[data-apila] { background: var(--papel); }

/* ---------- persiana: cada línea sube desde su máscara al entrar (muestrario, variante 3) ----------
   Las líneas las crea sitio.js (iniciarPersiana); sin JS no existen y el texto se ve tal cual.
   El relleno negativo de la máscara deja sitio a la tilde de «QUÉ» sin mover la maqueta. */
.persiana__mascara { display: block; overflow: clip; padding-block: .14em .08em; margin-block: -.14em -.08em; }
.persiana__linea { display: block; }
@media (prefers-reduced-motion: no-preference) {
  html[data-js='si'] [data-persiana] .persiana__linea {
    translate: 0 115%;
    transition: translate var(--t-slow) var(--e-salida);
    transition-delay: calc(var(--n, 0) * 90ms);
  }
  html[data-js='si'] [data-persiana][data-visible] .persiana__linea { translate: 0 0; }
}

/* ---------- puente «ABIERTO»: la foto se abre desde la O (G, duelo 3) ----------
   Sin JS o con movimiento reducido: la palabra en grande y debajo la foto abierta con su rótulo.
   Con el efecto (data-vivo, lo pone sitio.js): escena fija y recorrido largo, que sale de --recorrido (datos). */
.puente { position: relative; background: var(--papel); }
.puente__escena { width: min(100% - 2 * var(--margen), var(--ancho)); margin-inline: auto; padding-block: clamp(64px, 10vw, 140px); }
.puente__palabra { margin: 0 0 24px; font: 700 clamp(4.5rem, 24vw, 18rem)/.86 var(--f-display); text-transform: uppercase; }
.puente__svg { display: none; }
.puente__abierta { position: relative; margin: 0; border-radius: var(--radio-foto); overflow: hidden; }
.puente__abierta img { width: 100%; height: 70vh; height: 70svh; object-fit: cover; }
/* Velo en tinta fija: se lee sobre cualquier foto (regla de oro nº 11, nunca mix-blend). */
.puente__rotulo {
  position: absolute; left: 0; right: 0; bottom: 0;
  padding: 30% clamp(24px, 5vw, 64px) clamp(28px, 5vw, 64px);
  color: #eeeeec;
  background: linear-gradient(to top, rgb(29 28 27 / .86) 0%, rgb(29 28 27 / .55) 45%, rgb(29 28 27 / 0) 100%);
}
.puente__rotulo-texto { margin: 0; max-width: 12ch; font: 700 clamp(3rem, 11vw, 9rem)/.88 var(--f-display); text-transform: uppercase; }

/* Una foto dentro de una letra pide fondo claro: papel fijo en los dos temas mientras se ve la palabra. Cuando la
   foto ya cubre la pantalla (data-cubierta, lo pone sitio.js) vuelve al papel del tema, que en oscuro es oscuro. */
.puente[data-vivo] { height: calc(var(--recorrido, 330) * 1vh); height: calc(var(--recorrido, 330) * 1svh); background: #f4f4f2; }
.puente[data-vivo][data-cubierta] { background: var(--papel); }
.puente[data-vivo] .puente__escena {
  position: sticky; top: 0; width: 100%; height: 100vh; height: 100svh; padding: 0; overflow: hidden;
}
/* La palabra de verdad sigue ahí para lectores de pantalla; la que se ve es la del SVG. */
.puente[data-vivo] .puente__palabra {
  position: absolute; width: 1px; height: 1px; margin: 0; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap;
}
.puente[data-vivo] .puente__svg { display: block; position: absolute; inset: 0; width: 100%; height: 100%; }
.puente[data-vivo] .puente__abierta { position: absolute; inset: 0; border-radius: 0; pointer-events: none; z-index: 3; }
.puente[data-vivo] .puente__abierta img { display: none; }
.puente[data-vivo] .puente__rotulo { opacity: 0; will-change: transform, opacity; }
@media (max-width: 859px) {
  /* La píldora fija tapa el pie de la pantalla: el rótulo se queda por encima. */
  .puente[data-vivo] .puente__rotulo { padding-bottom: calc(clamp(28px, 5vw, 64px) + 90px); }
}

/* ---------- pantallas muy anchas (decisión F, 28 sep) ----------
   Por encima de 2000 px las secciones tranquilas quedaban como islas: titulares a 120 px en un contenedor de
   1320 y más de 1000 px de papel a los lados. Todo lo de aquí vale EXACTAMENTE lo mismo que antes a 2000 px y
   crece de forma continua hasta ×1,4 a 3440; por debajo de 2000 no entra. Pendiente de crecimiento = 0,4 × tamaño
   / 1440 px. Va al final del archivo para ganar por orden a las reglas de la misma especificidad. */
@media (min-width: 2000px) {
  /* Contenedor: 1320 hasta ~2130 de ventana (62vw alcanza 1320 ahí), luego 62vw, tope 2200. */
  :root { --ancho: max(1320px, min(62vw, 2200px)); }

  /* Texto corrido: hasta ×1,15 y medida de línea máx. 70ch (las medidas más cortas ya declaradas mandan). */
  body { font-size: min(1.222rem, 1.0625rem + (100vw - 2000px) * .00177); }
  main p { max-width: 70ch; }

  /* Titulares de sección: 7,5rem (120 px) → 10,5rem a 3440. Fuera el hero y los que tienen tamaño propio. */
  .titular:not(.titular--hero, .galeria__titular, .servicios__titular, .cierre__titular) {
    font-size: min(10.5rem, 7.5rem + (100vw - 2000px) * .0333);
  }
  .titular.servicios__titular { font-size: min(18.2rem, 13rem + (100vw - 2000px) * .0578); }
  /* HABLEMOS: 256 → ~358 px; siguen mandando los topes de 19vw y 26vh para que quepa en ancho y en alto. */
  .titular.cierre__titular { font-size: min(19vw, 26vh, 22.4rem, 16rem + (100vw - 2000px) * .0711); }

  /* Pila de Qué hacemos: alto relativo a la pantalla, sin el tope de 720 px. Título y texto crecen con la columna. */
  .servicio__tarjeta { min-height: 76vh; min-height: 76svh; }
  .servicio__titulo { font-size: min(7.7rem, 5.5rem + (100vw - 2000px) * .0244); }
  .servicio__desc { font-size: min(1.242rem, 1.08rem + (100vw - 2000px) * .0018); }

  /* Diafragma de Bodas: 80svh sin el tope de 740 px. */
  html[data-js='si'] .bodas { --bodas-foto: 80svh; }
  html[data-js='si'] .bodas__pista[data-vivo] .bodas__foto { height: 80vh; height: 80svh; }
}
