/* ═══════════════════════════════════════════════════════════
   PLANTILLA HOPPE — base.css
   Todo lo que se repite en cualquier landing: reset, tipografía,
   grilla, botones, formulario, header, pie y el sistema de reveals.

   NADA de colores escritos a mano acá abajo: todo sale de las
   variables del bloque TEMA. Para hacer una landing nueva se
   pisan esas variables en tema.css y el sitio entero cambia.

   Dos reglas que no se tocan:
   · Nada de overflow en html/body — rompe cualquier position:sticky.
   · Nada de módulos ES — el sitio se abre con doble clic (file://).
   ═══════════════════════════════════════════════════════════ */

/* ───────── 1. TEMA (esto es lo que se pisa) ───────── */
:root{
  /* Fondos, de más oscuro a más claro */
  --bg:          #080A11;
  --bg-2:        #0B0E17;
  --surface:     #10141F;
  --surface-2:   #161B29;
  --line:        rgba(255,255,255,.09);
  --line-strong: rgba(255,255,255,.16);

  /* Texto: principal, secundario y apagado */
  --text:        #EEF1F7;
  --text-2:      #C3CAD9;
  --muted:       #8D96AC;

  /* Un solo acento. --accent-2 es su versión clara (texto sobre fondo
     oscuro), --accent-deep la profunda (degradados de botón). */
  --accent:      #7C5CFF;
  --accent-2:    #AC9BFF;
  --accent-deep: #4B31C7;
  --on-accent:   #fff;              /* texto arriba del acento */
  --glow:        rgba(124,92,255,.38);
  --glow-soft:   rgba(124,92,255,.14);

  /* Velo de los paneles de vidrio. En temas claros se cambia por
     blancos con poca opacidad. */
  --vidrio:      linear-gradient(165deg,rgba(255,255,255,.06),rgba(255,255,255,.02));
  --vidrio-fuerte:linear-gradient(165deg,rgba(255,255,255,.10),rgba(255,255,255,.03));
  --campo-bg:    rgba(8,10,17,.45);

  /* Tipografía. La serif es la que le da carácter: cambiarla cambia
     el rubro entero. */
  --font:  'Inter', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  --serif: 'Instrument Serif', Georgia, 'Times New Roman', serif;

  --fs-h1:  clamp(2.4rem, 6.1vw, 5.6rem);
  --fs-h2:  clamp(1.9rem, 4.4vw, 3.7rem);
  --fs-h3:  clamp(1.55rem, 3.2vw, 2.7rem);
  --fs-lead:clamp(1rem, 1.5vw, 1.28rem);
  --tracking-h: -.035em;            /* subilo a 0 en temas serios */

  --pad:    clamp(1.25rem, 5vw, 5rem);
  --maxw:   1320px;
  --radius: 18px;
  --radius-sm: 12px;
  --radius-pill: 100px;             /* ponelo en 8px y el sitio se vuelve sobrio */

  --ease:      cubic-bezier(.22,1,.36,1);
  --ease-out:  cubic-bezier(.16,1,.3,1);
  /* La curva de material: arranca decidida y frena larga. Es la de las
     píldoras y la de cualquier cosa que cambie de tamaño al apuntarla.
     Va aparte de --ease porque ésa rebota, y una barra que rebota al
     estirarse se lee a juguete. */
  --ease-mat:  cubic-bezier(.4,0,.2,1);

  --header-h: 76px;

  /* Sombras del texto. En temas claros se ponen en `none`. */
  --sh-depth: 0 8px 34px rgba(0,0,0,.65);
  --sh-lit:   0 0 26px rgba(124,92,255,.40);
  --sh-hover: 0 0 24px rgba(172,155,255,.9), 0 0 62px rgba(124,92,255,.45);
  --sh-suave: 0 2px 14px rgba(8,10,17,.6);

  --sombra-panel: 0 40px 90px -60px #000;
}

/* ───────── 2. RESET ───────── */
*,*::before,*::after{ box-sizing:border-box; margin:0; padding:0 }

html{
  scroll-behavior:smooth;
  -webkit-text-size-adjust:100%;
  background:var(--bg);
}
/* OJO: nada de overflow acá. El desborde horizontal se controla en
   cada sección decorativa, nunca en la raíz. */
html.lenis{ scroll-behavior:auto }
.lenis.lenis-smooth{ scroll-behavior:auto }
.lenis.lenis-stopped{ overflow:hidden }

body{
  font-family:var(--font);
  font-weight:400;
  line-height:1.6;
  color:var(--text);
  background:transparent;
  -webkit-font-smoothing:antialiased;
  -moz-osx-font-smoothing:grayscale;
  text-rendering:optimizeLegibility;
}
body.is-loading{ overflow:hidden; height:100vh }

img,svg,canvas,video{ display:block; max-width:100% }
img{ height:auto }
a{ color:inherit; text-decoration:none }
button,input,select,textarea{ font:inherit; color:inherit }
ul{ list-style:none }

::selection{ background:var(--accent); color:var(--on-accent) }
:focus-visible{ outline:2px solid var(--accent); outline-offset:3px; border-radius:4px }

::-webkit-scrollbar{ width:10px }
::-webkit-scrollbar-track{ background:var(--bg) }
::-webkit-scrollbar-thumb{ background:var(--surface-2); border-radius:10px; border:3px solid var(--bg) }
::-webkit-scrollbar-thumb:hover{ background:var(--accent-deep) }

main{ position:relative; z-index:1 }

/* ───────── 3. FONDO DE RESPALDO ─────────
   Tres manchas de color que respiran. Sirve como fondo definitivo en
   las landings de cliente (no gastamos WebGL en ellas) y como respaldo
   si el equipo no da para el canvas. Sólo transform: sale gratis. */
.bg-static{
  position:fixed; inset:-15%;
  z-index:0; pointer-events:none;
  background:
    radial-gradient(46% 40% at 22% 18%, var(--glow-soft), transparent 68%),
    radial-gradient(40% 36% at 78% 42%, var(--glow-soft), transparent 70%),
    radial-gradient(52% 44% at 42% 88%, var(--glow-soft), transparent 70%),
    linear-gradient(180deg,var(--bg-2),var(--bg));
  animation:bgDrift 34s ease-in-out infinite alternate;
  will-change:transform;
}
@keyframes bgDrift{
  0%  { transform:translate3d(0,0,0) scale(1) }
  100%{ transform:translate3d(-3%,-4%,0) scale(1.08) }
}

/* ───────── 4. UTILIDADES ───────── */
.container{
  width:100%; max-width:var(--maxw);
  margin-inline:auto; padding-inline:var(--pad);
}
.seccion{ position:relative; padding-block:clamp(4.5rem,10vw,9rem) }

.sr-only{
  position:absolute; width:1px; height:1px; padding:0; margin:-1px;
  overflow:hidden; clip:rect(0 0 0 0); clip-path:inset(50%); white-space:nowrap; border:0;
}

.eyebrow{
  font-size:.72rem; letter-spacing:.22em; text-transform:uppercase;
  color:var(--accent); font-weight:500;
  margin-bottom:1.4rem;
  display:flex; align-items:center; gap:.75rem;
}
.eyebrow::before{
  content:''; width:32px; height:1px;
  background:linear-gradient(90deg,var(--accent),transparent);
}

.h1{
  font-size:var(--fs-h1); font-weight:600;
  line-height:1.02; letter-spacing:var(--tracking-h);
}
.h2{
  font-size:var(--fs-h2); font-weight:600;
  line-height:1.04; letter-spacing:var(--tracking-h);
  margin-bottom:1.6rem; max-width:18ch;
}
.h3{ font-size:var(--fs-h3); font-weight:600; line-height:1.1; letter-spacing:var(--tracking-h) }
.h1 em,.h2 em,.h3 em{
  font-family:var(--serif); font-style:italic; font-weight:400;
  letter-spacing:-.01em; color:var(--accent-2);
}

.lead{
  font-size:var(--fs-lead); color:var(--text-2);
  max-width:56ch; line-height:1.65; font-weight:300;
}
.lead em{ font-family:var(--serif); font-style:italic; color:var(--text); font-size:1.06em }

/* Sombras del texto: profundidad siempre, brillo de acento cuando el
   bloque cruza la pantalla (la clase .is-lit la pone el scroll). */
.h1,.h2,.h3{ text-shadow:var(--sh-depth) }
.lead,p{ text-shadow:var(--sh-suave) }
.h-word{ transition:text-shadow .55s var(--ease) }
.split-lines.is-lit .h-word{ text-shadow:var(--sh-lit), var(--sh-depth) }
@media (hover:hover){ .h-word:hover{ text-shadow:var(--sh-hover), var(--sh-depth) } }

/* ───────── 5. BOTONES ───────── */
.btn{
  --btn-bg:var(--accent);
  position:relative; display:inline-flex;
  align-items:center; justify-content:center; gap:.5rem;
  padding:.85rem 1.6rem; border:0; border-radius:var(--radius-pill);
  background:var(--btn-bg); color:var(--on-accent);
  font-size:.9rem; font-weight:500; letter-spacing:-.01em;
  cursor:pointer; overflow:hidden; isolation:isolate; white-space:nowrap;
  transition:transform .45s var(--ease), box-shadow .45s var(--ease);
  box-shadow:0 6px 26px -8px var(--glow);
  will-change:transform;
}
.btn span{ position:relative; z-index:2 }
.btn::before{
  content:''; position:absolute; inset:0; z-index:1;
  background:radial-gradient(120% 140% at 50% 120%, var(--accent-2) 0%, var(--accent) 45%, var(--accent-deep) 100%);
  opacity:0; transition:opacity .45s var(--ease);
}
.btn:hover{ transform:translateY(-2px); box-shadow:0 14px 40px -10px var(--glow) }
.btn:hover::before{ opacity:1 }
.btn:active{ transform:translateY(0) scale(.985) }

.btn--lg{ padding:1.05rem 2.1rem; font-size:.98rem }
.btn--sm{ padding:.62rem 1.15rem; font-size:.82rem }
.btn--full{ width:100%; margin-top:.5rem }

.btn--ghost{
  background:transparent; border:1px solid var(--line-strong);
  color:var(--text); box-shadow:none; backdrop-filter:blur(8px);
}
.btn--ghost::before{ background:var(--glow-soft) }
.btn--ghost:hover{ border-color:var(--accent); box-shadow:0 10px 34px -14px var(--glow) }

/* Latido doble. El resplandor viaja en el box-shadow y no en un
   pseudo-elemento porque .btn recorta lo de adentro. Al pasar el mouse
   se corta del todo, así el :hover recupera su propio transform. */
.btn--beat{ animation:btnBeat 2.6s var(--ease) infinite; transform-origin:50% 50% }
.btn--beat:hover,.btn--beat:focus-visible,.btn--beat:active{ animation:none }
@keyframes btnBeat{
  0%,64%,100%{ transform:scale(1);     box-shadow:0 6px 26px -8px var(--glow) }
  10%        { transform:scale(1.035); box-shadow:0 16px 48px -10px var(--glow) }
  22%        { transform:scale(.998);  box-shadow:0 6px 26px -8px var(--glow) }
  34%        { transform:scale(1.022); box-shadow:0 12px 40px -10px var(--glow) }
}

/* ───────── 6. HEADER + PROGRESO ───────── */
.scroll-progress{
  position:fixed; top:0; left:0; right:0; height:2px;
  z-index:900; pointer-events:none;
}
.scroll-progress i{
  display:block; height:100%; width:100%;
  transform:scaleX(0); transform-origin:0 50%;
  background:linear-gradient(90deg,var(--accent-deep),var(--accent),var(--accent-2));
  box-shadow:0 0 12px var(--glow);
}

.header{
  position:fixed; top:0; left:0; right:0; z-index:800;
  height:var(--header-h);
  display:flex; align-items:center; justify-content:space-between; gap:1.5rem;
  padding-inline:var(--pad);
  transition:transform .5s var(--ease), background-color .5s var(--ease);
  will-change:transform;
}
.header.is-stuck{
  background:color-mix(in srgb, var(--bg) 70%, transparent);
  backdrop-filter:blur(16px) saturate(140%);
  -webkit-backdrop-filter:blur(16px) saturate(140%);
  border-bottom:1px solid var(--line);
}
.header.is-hidden{ transform:translateY(-110%) }

.header__logo{ display:flex; align-items:center; gap:.55rem; font-size:1rem; font-weight:600; letter-spacing:-.02em }
.header__logo svg{ color:var(--accent) }
.header__logo em{ font-family:var(--serif); font-style:italic; font-weight:400; color:var(--text-2) }

.header__nav{ display:flex; gap:2rem; font-size:.86rem; color:var(--text-2) }
.header__nav a{ position:relative; padding-block:.3rem; transition:color .3s }
.header__nav a::after{
  content:''; position:absolute; left:0; bottom:0; width:100%; height:1px;
  background:var(--accent); transform:scaleX(0); transform-origin:100% 50%;
  transition:transform .45s var(--ease);
}
.header__nav a:hover{ color:var(--text) }
.header__nav a:hover::after{ transform:scaleX(1); transform-origin:0 50% }
@media (max-width:860px){ .header__nav{ display:none } }

/* ───────── 7. HERO ───────── */
.hero{
  position:relative; min-height:100svh;
  display:flex; flex-direction:column; justify-content:center;
  padding-top:var(--header-h);
  overflow:hidden; isolation:isolate;
}
.hero__inner{ position:relative; z-index:2 }
.hero__title{ max-width:16ch; margin-bottom:1.6rem }
.hero__lead{ margin-bottom:2.4rem }
.hero__acciones{ display:flex; flex-wrap:wrap; gap:.9rem }

/* Grilla de fondo del hero. Puro degradado repetido: no repinta. */
.hero__grid{
  position:absolute; inset:-10%; z-index:0; pointer-events:none; opacity:.5;
  background-image:
    linear-gradient(var(--line) 1px, transparent 1px),
    linear-gradient(90deg, var(--line) 1px, transparent 1px);
  background-size:clamp(48px,7vw,96px) clamp(48px,7vw,96px);
  mask-image:radial-gradient(70% 60% at 50% 45%, #000 20%, transparent 78%);
  -webkit-mask-image:radial-gradient(70% 60% at 50% 45%, #000 20%, transparent 78%);
}

/* Foco que sigue al puntero. Un solo degradado, escrito una vez por
   frame desde motor.js. Es lo que le saca al fondo el aire de quieto. */
.hero__lux{
  position:absolute; inset:0; z-index:0; pointer-events:none;
  background:radial-gradient(420px 420px at var(--lx,50%) var(--ly,42%),
    var(--glow), transparent 72%);
  opacity:0; transition:opacity .8s var(--ease);
}
.hero.is-lux .hero__lux{ opacity:1 }

.hero__media{ position:relative; z-index:1 }
.hero__media img{ width:100%; border-radius:var(--radius); box-shadow:var(--sombra-panel) }

/* ───────── 8. TARJETAS ───────── */
.tarjetas{ display:grid; gap:clamp(1rem,2.4vw,1.6rem) }
.tarjetas--3{ grid-template-columns:repeat(3,1fr) }
.tarjetas--4{ grid-template-columns:repeat(4,1fr) }
@media (max-width:900px){ .tarjetas--3,.tarjetas--4{ grid-template-columns:1fr 1fr } }
@media (max-width:560px){ .tarjetas--3,.tarjetas--4{ grid-template-columns:1fr } }

.tarjeta{
  position:relative; padding:clamp(1.4rem,2.6vw,2rem);
  border:1px solid var(--line); border-radius:var(--radius);
  background:var(--vidrio); backdrop-filter:blur(10px);
  transition:transform .5s var(--ease), border-color .5s var(--ease), background-color .5s var(--ease);
  will-change:transform;
}
.tarjeta:hover{ transform:translateY(-4px); border-color:var(--accent); background:var(--vidrio-fuerte) }
.tarjeta h4{ font-size:1.1rem; font-weight:600; margin-bottom:.6rem; letter-spacing:-.02em }
.tarjeta p{ font-size:.94rem; color:var(--text-2); line-height:1.6 }
.tarjeta__num{
  display:block; font-family:var(--serif); font-size:2.2rem;
  color:var(--accent); line-height:1; margin-bottom:.8rem;
}

/* ───────── 9. GALERÍA ───────── */
.galeria{ display:grid; grid-template-columns:repeat(3,1fr); gap:clamp(.6rem,1.4vw,1rem) }
@media (max-width:760px){ .galeria{ grid-template-columns:1fr 1fr } }
/* ⚠ La figura es una GRILLA de una sola celda y la foto se estira a
   ocupar toda su altura. Sin esto, en cualquier mosaico donde una
   figura ocupe dos filas la foto se queda con la altura que le da su
   proporción y abajo aparece un bloque vacío del color de --surface.
   No hay error, no hay hueco negro: la foto simplemente "no se ve"
   porque parece parte del fondo. Ya pasó en el hotel. */
.galeria figure{
  position:relative; overflow:hidden;
  border-radius:var(--radius); background:var(--surface);
  display:grid; grid-template:1fr / 1fr;
}
.galeria img{
  grid-area:1/1;
  width:100%; height:100%; aspect-ratio:4/3; object-fit:cover;
  transition:transform .8s var(--ease), filter .8s var(--ease);
}
.galeria figure > img{ min-height:0 }
.galeria figure:hover img{ transform:scale(1.06) }
.galeria figcaption{
  position:absolute; left:0; right:0; bottom:0; padding:1.5rem 1rem .8rem;
  font-size:.82rem; color:#fff;
  background:linear-gradient(180deg, transparent, rgba(0,0,0,.72));
}

/* ───────── 10. FAQ ───────── */
/* Alineada con el título de la sección, no centrada: centrada se lee
   como un bloque suelto que no pertenece a nada. */
.faq{ max-width:820px }
.faq details{
  border-bottom:1px solid var(--line);
  padding-block:1.15rem;
}
.faq summary{
  display:flex; align-items:center; justify-content:space-between; gap:1rem;
  cursor:pointer; list-style:none;
  font-size:1.02rem; font-weight:500; letter-spacing:-.015em;
  transition:color .3s;
}
.faq summary::-webkit-details-marker{ display:none }
.faq summary::after{
  content:'+'; flex:none; font-size:1.4rem; line-height:1;
  color:var(--accent); transition:transform .4s var(--ease);
}
.faq details[open] summary::after{ transform:rotate(45deg) }
.faq summary:hover{ color:var(--accent-2) }
.faq details p{ margin-top:.8rem; color:var(--text-2); font-size:.95rem; max-width:64ch }

/* ───────── 11. PRECIO ───────── */
.precio{
  max-width:560px; margin-inline:auto; text-align:center;
  padding:clamp(1.8rem,4vw,3rem);
  border:1px solid var(--line-strong); border-radius:var(--radius);
  background:var(--vidrio-fuerte); backdrop-filter:blur(12px);
  box-shadow:var(--sombra-panel);
}
.precio__cifra{
  font-size:clamp(2.6rem,7vw,4.2rem); font-weight:600;
  letter-spacing:-.04em; line-height:1; margin-block:.4rem .3rem;
}
.precio__cifra sup{ font-size:.42em; vertical-align:super; margin-right:.1em; color:var(--muted) }
.precio__nota{ font-size:.8rem; color:var(--muted); margin-bottom:1.8rem }
.precio__lista{ text-align:left; display:flex; flex-direction:column; gap:.65rem; margin-bottom:1.8rem }
.precio__lista li{ display:flex; gap:.6rem; align-items:flex-start; font-size:.92rem; color:var(--text-2) }
.precio__lista li::before{ content:'✓'; color:var(--accent); flex:none; font-weight:600 }
.precio__lista li.no{ color:var(--muted) }
.precio__lista li.no::before{ content:'+'; color:var(--muted) }

/* ───────── 12. FORMULARIO ───────── */
.contacto__grid{
  display:grid; grid-template-columns:1fr 1fr;
  gap:clamp(2.5rem,6vw,6rem); align-items:start;
}
@media (max-width:860px){ .contacto__grid{ grid-template-columns:1fr } }

.contacto__lista{ margin-top:2.4rem; display:flex; flex-direction:column; gap:1rem }
.contacto__lista li{ display:flex; align-items:center; gap:.8rem; color:var(--text-2); font-size:.92rem }
.contacto__lista svg{ color:var(--accent); flex:none }
.contacto__lista a{ transition:color .3s }
.contacto__lista a:hover{ color:var(--accent-2) }

.form{
  padding:clamp(1.5rem,3.5vw,2.6rem); border-radius:var(--radius);
  border:1px solid var(--line);
  background:var(--vidrio); backdrop-filter:blur(12px);
  box-shadow:var(--sombra-panel);
}
/* Trampa para bots: invisible para gente, irresistible para robots. */
.form__hp{ position:absolute; left:-9999px; opacity:0; pointer-events:none }
.form__row{ display:grid; grid-template-columns:1fr 1fr; gap:1rem }
@media (max-width:560px){ .form__row{ grid-template-columns:1fr } }

.field{ position:relative; margin-bottom:1rem }
.field input,.field select,.field textarea{
  width:100%; padding:1.35rem 1rem .6rem;
  background:var(--campo-bg); border:1px solid var(--line); border-radius:var(--radius-sm);
  font-size:.92rem; appearance:none;
  transition:border-color .35s var(--ease), background-color .35s var(--ease), box-shadow .35s var(--ease);
}
.field textarea{ resize:vertical; min-height:120px; padding-top:1.6rem }
.field select{
  padding-top:1.35rem; cursor:pointer;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%238D96AC' stroke-width='1.5' fill='none' stroke-linecap='round'/%3E%3C/svg%3E");
  background-repeat:no-repeat; background-position:right 1rem center; background-size:12px;
}
.field select option{ background:var(--surface); color:var(--text) }

/* La etiqueta flota cuando el campo tiene foco o contenido. El truco es
   :not(:placeholder-shown), así que TODO input necesita placeholder=" ". */
.field label{
  position:absolute; left:1rem; top:1.05rem;
  font-size:.92rem; color:var(--muted); pointer-events:none;
  transition:transform .3s var(--ease), font-size .3s var(--ease), color .3s var(--ease);
  transform-origin:0 50%;
}
.field label.label--static,
.field input:focus + label,
.field input:not(:placeholder-shown) + label,
.field textarea:focus + label,
.field textarea:not(:placeholder-shown) + label,
.field select:focus + label,
.field select:valid + label{
  transform:translateY(-.72rem) scale(.76); color:var(--accent);
}
.field input:focus,.field textarea:focus,.field select:focus{
  outline:none; border-color:var(--accent);
  background:var(--glow-soft); box-shadow:0 0 0 3px var(--glow-soft);
}
.field.has-error input,.field.has-error textarea,.field.has-error select{
  border-color:#ff6b81; box-shadow:0 0 0 3px rgba(255,107,129,.12);
}
.form__note{ font-size:.72rem; color:var(--muted); margin-top:1rem; line-height:1.5 }
.form__status{ font-size:.86rem; margin-top:.9rem; min-height:1.2em }
.form__status.is-ok{ color:var(--accent) }
.form__status.is-err{ color:#ff8b9c }

/* ───────── 13. PIE ───────── */
.footer{ position:relative; z-index:2; border-top:1px solid var(--line); padding-block:2.5rem 6rem }
.footer__inner{ display:flex; flex-direction:column; gap:.4rem; align-items:center; text-align:center }
.footer__brand{
  display:flex; align-items:center; gap:.6rem;
  font-size:1.05rem; font-weight:600; letter-spacing:-.02em; margin-bottom:.25rem;
}
.footer__brand em{ font-family:var(--serif); font-style:italic; font-weight:400; color:var(--accent) }
.footer__inner p{ font-size:.85rem; color:var(--text-2) }
.footer__inner small{ font-size:.72rem; color:var(--muted) }
.footer__legal{
  display:flex; align-items:center; gap:.5rem; flex-wrap:wrap; justify-content:center;
  margin-top:.5rem; font-size:.75rem; color:var(--muted);
}

/* ───────── 14. WHATSAPP FLOTANTE ───────── */
.wa{
  position:fixed; right:clamp(1rem,3vw,2rem); bottom:clamp(1rem,3vw,2rem);
  z-index:850; width:56px; height:56px; border-radius:50%;
  display:grid; place-items:center;
  background:#25D366; color:#fff;
  box-shadow:0 10px 30px -8px rgba(37,211,102,.5);
  opacity:0; transform:scale(.6) translateY(10px); pointer-events:none;
  transition:opacity .5s var(--ease), transform .5s var(--ease);
}
.wa.is-visible{ opacity:1; transform:none; pointer-events:auto }
.wa:hover{ transform:scale(1.08) }

/* ───────── 15. SELLO DE DEMO ─────────
   Va sólo en las landings de muestra. Dice la verdad (esto es un
   ejemplo, no un cliente) y de paso devuelve el tráfico al estudio. */
.sello-demo{
  position:fixed; left:50%; bottom:1rem; transform:translateX(-50%);
  z-index:860; display:flex; align-items:center; gap:.6rem;
  padding:.5rem .95rem; border-radius:var(--radius-pill);
  background:rgba(8,10,17,.82); border:1px solid rgba(255,255,255,.14);
  backdrop-filter:blur(12px);
  font-size:.72rem; color:#EEF1F7; letter-spacing:.02em;
  box-shadow:0 14px 40px -18px #000;
}
.sello-demo b{ font-weight:600 }
.sello-demo a{ color:#AC9BFF; border-bottom:1px solid transparent; transition:border-color .3s }
.sello-demo a:hover{ border-color:currentColor }
/* En vertical se corre a la izquierda y se acorta: si queda centrado
   choca con el botón de WhatsApp y parte el texto en dos renglones. */
@media (max-width:640px){
  .sello-demo{ left:1rem; transform:none; font-size:.66rem; padding:.42rem .7rem; gap:.4rem }
  .sello-demo .sello-demo__larga{ display:none }
}

/* ───────── 16. REVEALS ─────────
   El estado inicial vive en CSS para que no haya parpadeo: el elemento
   ya nace escondido y GSAP sólo lo trae. Si el JS no carga, la red de
   seguridad de motor.js los muestra igual. */
.reveal-up{ opacity:0; transform:translateY(38px) }
.split-lines{ overflow:hidden }
.h-word{ display:inline-block; will-change:transform }
.h-word--io{ will-change:transform, opacity }
.flow-in .fw{ display:inline-block; will-change:transform, opacity }
.assemble .as-w{ display:inline-block; white-space:nowrap }
.assemble .as-ch{ display:inline-block; will-change:transform, opacity; transition:text-shadow .55s var(--ease) }
.assemble.is-lit .as-ch{ text-shadow:var(--sh-lit), var(--sh-depth) }

/* Sin JS no escondemos nada: el contenido tiene que leerse igual. */
html.no-js .reveal-up{ opacity:1; transform:none }

/* ═══════════════════════════════════════════════════════════
   18. CAJA DE EFECTOS
   Todo lo de acá abajo es OPCIONAL y se enciende desde el HTML con
   una clase o un data-atributo. Ninguna landing usa todos: cada una
   elige cinco o seis y por eso no se parecen entre sí.

   Regla que no se negocia: sólo transform y opacity. Nada que obligue
   al navegador a recalcular el layout mientras se scrollea.
   ═══════════════════════════════════════════════════════════ */

/* ───────── 18.1 CORTINA DE ENTRADA ─────────
   El panel que tapa la página el primer segundo y se va. Es lo que
   hace que la landing "arranque" en vez de simplemente estar.

   La animación de seguridad es obligatoria: si el JS no corre (CDN
   caída, error), la cortina se va sola a los 2,6 s. Preferimos un
   segundo de más antes que una página en blanco para siempre. */
.cortina{
  position:fixed; inset:0; z-index:1000;
  display:grid; place-items:center;
  background:var(--bg-2);
  animation:cortinaSeguro .7s var(--ease) 2.6s forwards;
}
@keyframes cortinaSeguro{ to{ opacity:0; visibility:hidden } }
.cortina__marca{
  font-size:clamp(1.1rem,3vw,1.7rem); font-weight:500;
  letter-spacing:-.02em; color:var(--text);
  display:flex; align-items:center; gap:.6rem;
}
.cortina__marca em{ font-family:var(--serif); font-style:italic; font-weight:400; color:var(--accent) }
/* La línea que se llena debajo del nombre: da la sensación de carga
   sin mentir sobre ningún porcentaje. */
.cortina__barra{
  position:absolute; left:50%; bottom:clamp(3rem,12vh,7rem);
  width:min(200px,40vw); height:1px; transform:translateX(-50%);
  background:var(--line-strong); overflow:hidden;
}
.cortina__barra i{
  display:block; height:100%; width:100%;
  background:var(--accent); transform:scaleX(0); transform-origin:0 50%;
}
/* Modo "dos": se parte al medio y se abre como un telón. */
.cortina--dos{ background:none }
.cortina--dos .cortina__mitad{
  position:absolute; left:0; right:0; height:50.5%;
  background:var(--bg-2);
}
/* Arriba la primera, abajo la segunda. Va por hermandad y no por
   :first-child/:last-child, que es como estaba: apenas se agrega
   cualquier cosa después de las mitades —la marca, la barrita— la
   segunda deja de ser :last-child, se queda sin `bottom` y las dos se
   apilan arriba. La mitad de abajo de la pantalla queda destapada
   antes de tiempo y no hay ningún error en ningún lado. */
.cortina--dos .cortina__mitad{ top:0 }
.cortina--dos .cortina__mitad ~ .cortina__mitad{ top:auto; bottom:0 }
/* En el telón la marca queda flotando por encima de las dos mitades. */
.cortina--dos .cortina__marca{
  position:absolute; inset:0; z-index:2;
  justify-content:center; align-items:center;
}
.cortina--dos .cortina__barra{ z-index:2 }

/* ───────── 18.1 bis EL FONDO VIVO ─────────
   Un canvas fijo detrás de todo. Qué dibuja lo decide data-fondo:
   puntos, ondas, seda o trama. Canvas 2D, no WebGL: pesa nada y anda en
   cualquier equipo. Va tapando a .bg-static (mismo z-index, más abajo
   en el HTML).

   Cada landing usa uno **distinto**. Es lo que más rápido se lee como
   "esto es otro sitio", más que el color y más que la tipografía. */
.fondo{
  position:fixed; inset:0; z-index:0;
  width:100%; height:100%; pointer-events:none;
}

/* ───────── 18.2 CURSOR FINO ─────────
   Un anillo que sigue al puntero y crece sobre lo que se puede tocar.
   Sólo en equipos con mouse: en un celular no existe el hover. */
.cursor{
  position:fixed; top:0; left:0; z-index:999; pointer-events:none;
  width:34px; height:34px; margin:-17px 0 0 -17px;
  border:1.5px solid var(--accent); border-radius:50%;
  opacity:0; transition:opacity .3s var(--ease), background-color .3s var(--ease);
  will-change:transform;
}
.cursor.is-on{ opacity:.85 }
.cursor.is-link{ background:var(--glow-soft) }
.cursor__punto{
  position:fixed; top:0; left:0; z-index:999; pointer-events:none;
  width:5px; height:5px; margin:-2.5px 0 0 -2.5px;
  background:var(--accent); border-radius:50%;
  opacity:0; transition:opacity .3s var(--ease);
  will-change:transform;
}
.cursor__punto.is-on{ opacity:1 }

/* Sobre lo que lo pide (data-cursor-txt="Ver") el anillo se llena y
   muestra una palabra. Es la única forma de "cursor con contenido" que
   no se ve barata: un dibujito literal siguiendo al mouse, sí. */
.cursor__txt{
  position:absolute; inset:0;
  display:flex; align-items:center; justify-content:center;
  font-size:12px; font-weight:500; letter-spacing:-.01em; line-height:1;
  color:var(--on-accent); opacity:0; white-space:nowrap;
}
.cursor.is-txt{
  background:var(--accent); border-color:var(--accent);
  opacity:1;
}
.cursor.is-txt ~ .cursor__punto{ opacity:0 }

/* ───────── 18.3 TARJETAS QUE SE INCLINAN ─────────
   La tarjeta se ladea hacia el puntero y le aparece un reflejo que lo
   sigue. Es el efecto que más "caro" se ve por lo poco que cuesta. */
[data-tilt]{ transform-style:preserve-3d; will-change:transform }
[data-tilt]::after{
  content:''; position:absolute; inset:0; border-radius:inherit;
  pointer-events:none; z-index:3;
  background:radial-gradient(240px 240px at var(--mx,50%) var(--my,50%), var(--glow), transparent 70%);
  opacity:0; transition:opacity .45s var(--ease);
}
[data-tilt].is-tilt::after{ opacity:.55 }

/* ───────── 18.4 IMAGEN QUE SE DESCUBRE ─────────
   La foto no aparece: se destapa, como si alguien corriera una hoja.
   Adentro la imagen viene un poco más grande y se acomoda a la vez. */
[data-descubrir]{ overflow:hidden }
[data-descubrir] img{ will-change:transform }

/* ───────── 18.5 LECTURA ─────────
   El párrafo se enciende palabra por palabra al ritmo del scroll.
   Sirve donde hay que hacer leer de verdad: manifiestos, promesas,
   el párrafo que explica de qué se trata todo. */
.lectura{ font-size:clamp(1.15rem,2.4vw,1.75rem); line-height:1.5; max-width:24ch; font-weight:400 }
.lectura .lw{ display:inline-block; will-change:opacity }
.lectura--ancha{ max-width:34ch }
/* Variante manifiesto: el párrafo ES la sección, así que va al tamaño
   de un titular y ocupa media pantalla. Los <strong> de adentro
   sobreviven al partido en palabras (ver splitPalabras) y son los que
   arman el ritmo: se lee primero lo grueso y después el resto. */
.lectura--manifiesto{
  font-size:clamp(1.25rem,2.9vw,2.35rem);
  line-height:1.32; max-width:26ch; font-weight:300;
  letter-spacing:-.025em;
}
.lectura--manifiesto strong{ font-weight:600; letter-spacing:-.03em }

/* ───────── 18.6 PASOS CON LÍNEA QUE SE DIBUJA ─────────
   La línea baja al ritmo del scroll y va prendiendo cada punto.
   Convierte un listado aburrido en algo que se mira. */
.pasos{ position:relative; padding-left:2.6rem; max-width:720px; list-style:none }
.pasos::before{
  content:''; position:absolute; left:9px; top:.7rem; bottom:1.4rem;
  width:1px; background:var(--line);
}
.pasos__linea{
  position:absolute; left:9px; top:.7rem; bottom:1.4rem; width:1px;
  background:var(--accent); transform:scaleY(0); transform-origin:50% 0;
}
.paso{ position:relative; padding-bottom:clamp(1.6rem,3vw,2.4rem) }
.paso:last-child{ padding-bottom:0 }
.paso__punto{
  position:absolute; left:-2.6rem; top:.28rem;
  width:19px; height:19px; border-radius:50%;
  border:1px solid var(--line-strong); background:var(--bg);
  display:grid; place-items:center;
}
.paso__punto::after{
  content:''; width:7px; height:7px; border-radius:50%;
  background:var(--accent); transform:scale(0);
  transition:transform .45s var(--ease);
}
.paso.is-on .paso__punto{ border-color:var(--accent) }
.paso.is-on .paso__punto::after{ transform:scale(1) }
.paso b{ display:block; font-size:1.05rem; font-weight:600; letter-spacing:-.02em; margin-bottom:.3rem }
.paso p{ font-size:.94rem; color:var(--text-2); max-width:52ch }
.paso span{ font-size:.72rem; letter-spacing:.18em; text-transform:uppercase; color:var(--muted) }

/* ───────── 18.7 SELLO QUE GIRA ─────────
   El circulito con texto alrededor. No informa nada nuevo: está para
   que la página nunca esté del todo quieta. */
.sello{ position:relative; width:clamp(96px,11vw,132px); aspect-ratio:1 }
/* Hijo directo, no `.sello svg`: el ícono del centro también es un svg
   y con el selector suelto se estiraba al tamaño del aro y giraba. */
.sello > svg{ width:100%; height:100%; animation:selloGira 22s linear infinite }
.sello text{ font-size:11.4px; letter-spacing:.26em; fill:var(--accent); text-transform:uppercase }
.sello__centro{
  position:absolute; inset:0; display:grid; place-items:center;
  color:var(--accent); pointer-events:none;
}
.sello__centro svg{ width:22px; height:22px }
@keyframes selloGira{ to{ transform:rotate(360deg) } }

/* ───────── 18.8 CINTA DE TEXTO ─────────
   Corre sola y se acelera cuando el visitante scrollea rápido: el
   sitio parece responder a lo que la persona hace. */
.cinta{ overflow:hidden; border-block:1px solid var(--line); padding-block:clamp(.9rem,2vw,1.4rem) }
.cinta__pista{ display:flex; width:max-content; will-change:transform }
.cinta__pista > span{
  display:flex; align-items:center; gap:clamp(1.6rem,4vw,3rem);
  padding-right:clamp(1.6rem,4vw,3rem); white-space:nowrap;
}
.cinta b{ font-weight:400; color:var(--accent) }
.cinta--grande .cinta__pista{ font-size:clamp(2rem,7vw,5rem); font-weight:500; letter-spacing:-.035em }
.cinta--grande em{ font-family:var(--serif); font-style:italic; color:var(--accent) }
.cinta--chica .cinta__pista{ font-size:.78rem; letter-spacing:.24em; text-transform:uppercase; color:var(--muted) }

/* ───────── 18.9 APILADO ─────────
   Las tarjetas se quedan pegadas y la que sigue se monta encima. Se
   apaga en vertical: apilar en un celular es marearse. */
.apilado{ display:grid; gap:clamp(1rem,2vw,1.4rem) }
@media (min-width:901px){
  .apilado{ gap:0 }
  .apilado > *{ position:sticky; top:calc(var(--header-h) + 2.4rem); will-change:transform }
  .apilado > * + *{ margin-top:clamp(1.4rem,3vw,2.4rem) }
}

/* ───────── 18.10 REVEALS LATERALES ─────────
   Otra manera de entrar, para que no toda la página entre igual. */
.reveal-lado{ opacity:0; transform:translateX(-46px) }
.reveal-lado--der{ transform:translateX(46px) }
.reveal-escala{ opacity:0; transform:scale(.94) }
/* En pantallas angostas el elemento ocupa todo el ancho: correrlo de
   costado saca la página fuera de la pantalla y aparece la barra
   horizontal. Ahí entra sólo apareciendo, sin desplazamiento — el
   destino del motor (x:0) ya es su lugar, así que no queda nada
   colgado. */
@media (max-width:760px){
  .reveal-lado,.reveal-lado--der{ transform:none }
}
html.no-js .reveal-lado,
html.no-js .reveal-escala{ opacity:1; transform:none }

/* ───────── 18.11 BRILLO QUE BARRE ─────────
   Un reflejo que cruza la foto al pasar el mouse. Mini detalle, pero
   es de esos que hacen que algo "se sienta" terminado. */
.brillo{ position:relative; overflow:hidden }
.brillo::after{
  content:''; position:absolute; top:0; bottom:0; left:-60%; width:45%;
  background:linear-gradient(100deg, transparent, rgba(255,255,255,.28), transparent);
  transform:skewX(-18deg); pointer-events:none; opacity:0;
}
@media (hover:hover){
  .brillo:hover::after{ opacity:1; animation:brilloPasa .9s var(--ease) }
}
@keyframes brilloPasa{ to{ left:120% } }

/* ───────── 18.12 FLOTAR ─────────
   Sube y baja, muy poco, para siempre. */
[data-flotar]{ animation:flota 6s ease-in-out infinite alternate; will-change:transform }
@keyframes flota{ to{ transform:translateY(-12px) } }

/* ───────── 18.15 BANDA A TODO EL ANCHO ─────────
   Una foto que ocupa el ancho completo, sin contenedor. Va como hija
   directa de la <section> —nunca dentro de .container—, así toma el
   ancho del cuerpo sin recurrir a 100vw, que suma el ancho de la barra
   de scroll y abre desborde horizontal.

   El movimiento no está acá: la foto de adentro lleva data-parallax y
   data-zoom y los mueve el motor con el scroll. Por eso la imagen ya
   está grande al cargar y después se acomoda de a poco, en vez de
   aparecer de golpe a mitad de página. */
.banda{
  position:relative; overflow:hidden; isolation:isolate;
  height:clamp(300px, 62vh, 660px);
}
.banda img{
  position:absolute; left:0; top:-12%;
  width:100%; height:124%;
  object-fit:cover; object-position:center;
  border-radius:0; box-shadow:none;
  will-change:transform;
}
/* La foto sobresale por arriba y por abajo (124 % de alto) justamente
   para que el parallax tenga de dónde correrse sin dejar el borde
   blanco a la vista. */
@media (max-width:760px){
  .banda{ height:clamp(260px, 46vh, 420px) }
}

/* ───────── 18.16 SUBRAYADO QUE SE DIBUJA ─────────
   Una línea que cruza por debajo del título cuando la sección entra.
   Es el efecto más sobrio del sistema: no mueve nada de lugar, no tapa
   nada, y sirve en el rubro donde cualquier otra cosa se leería como
   show. Va en el <h2>, nunca en un párrafo. */
.subraya{ position:relative; padding-bottom:.5em }
.subraya::after{
  content:''; position:absolute; left:0; bottom:.12em;
  width:100%; height:2px; background:var(--accent);
  transform:scaleX(0); transform-origin:0 50%;
  transition:transform 1.1s var(--ease);
}
.subraya.is-on::after{ transform:scaleX(1) }
/* Sin JS la línea tiene que estar igual: un título a medio subrayar se
   lee como un error de maquetación. */
.no-js .subraya::after{ transform:scaleX(1) }

/* ───────── 18.17 NUMERAL FANTASMA ─────────
   El número de la sección, enorme y casi transparente, detrás del
   título. No informa nada que no diga ya el volanta: está para dar
   escala y profundidad en una página que por lo demás es toda texto.
   Con data-parallax se corre despacio y la sección deja de sentirse
   pegada al papel. */
.numeral{
  position:absolute; z-index:0; pointer-events:none; user-select:none;
  top:-.3em; left:-.06em;
  font-size:clamp(7rem, 20vw, 17rem); line-height:.8;
  font-weight:600; letter-spacing:-.06em;
  color:var(--text); opacity:.05;
}
@media (max-width:760px){ .numeral{ font-size:clamp(5rem,26vw,9rem); opacity:.045 } }
/* El contenido que va encima necesita su propio contexto o el numeral
   se le monta arriba al texto. */
.con-numeral{ position:relative; isolation:isolate }
.con-numeral > *:not(.numeral){ position:relative; z-index:1 }

/* ───────── 18.14 TÍTULO EN 3D CON LUZ QUE PASA ─────────
   Tres capas encima del mismo titular:
   1. las letras caen girando sobre su base (eso es el 3D),
   2. una luz de color las cruza en onda, letra por letra,
   3. la letra que tiene el puntero encima se levanta.

   La luz viaja con animation-delay: cada letra tiene la misma
   animación corrida unos milisegundos, y eso se lee como una sola luz
   atravesando la palabra. Un degradado en el contenedor no serviría:
   las letras están transformadas y se saldrían del recorte. */
.titulo-3d{ perspective:900px }
.titulo-3d .t3-w{ display:inline-block; white-space:nowrap }
.titulo-3d .t3-ch{
  display:inline-block; will-change:transform;
  background-image:linear-gradient(100deg,
    var(--text) 0 40%, var(--accent) 50%, var(--text) 60% 100%);
  background-size:280% 100%;
  background-position:110% 0;
  -webkit-background-clip:text; background-clip:text;
  color:transparent;
  animation:t3Luz 6s var(--ease) infinite;
}
@keyframes t3Luz{
  0%,   72%, 100%{ background-position:110% 0 }
  30%,  42%      { background-position:-10% 0 }
}
/* Si el navegador no sabe recortar el fondo al texto, el título tiene
   que verse igual: color plano y sin luz. */
@supports not ((-webkit-background-clip:text) or (background-clip:text)){
  .titulo-3d .t3-ch{ background:none; color:var(--text); animation:none }
}

/* ───────── 18.13 NAVEGACIÓN QUE SE ENTERA ─────────
   El enlace de la sección que se está mirando queda marcado. Nadie lo
   nota conscientemente y todos lo extrañan cuando no está. */
.header__nav a.is-active{ color:var(--text) }
.header__nav a.is-active::after{ transform:scaleX(1); transform-origin:0 50% }

/* ═══════════════════════════════════════════════════════════
   18.18 — 18.22  EL LENGUAJE DE MASCOTA
   Cinco piezas que van juntas y arman un tipo de landing distinto
   al resto de la plantilla: fondo de color plano con filigrana,
   personaje anclado, titular gigante en contorno, píldoras que se
   estiran y una fila de clientes al pie.

   Se usan cuando la marca TIENE una cara. Si la landing es de un
   servicio serio, no se tocan: este lenguaje grita, y gritar sólo
   funciona cuando lo que se vende también grita.
   ═══════════════════════════════════════════════════════════ */

/* ───────── 18.18 FILIGRANA ─────────
   La marca de agua que llena el fondo de color. Va DIBUJADA POR
   CÓDIGO —un <pattern> de SVG que cada tema define en --filigrana—
   y nunca como foto: es un fondo que ocupa toda la pantalla, así
   que una imagen acá es el archivo más pesado del sitio.

   La deriva es de dos minutos y de tres píxeles. No se ve moverse;
   se nota si no está, porque el fondo queda muerto. */
.filigrana{
  position:absolute; inset:-6%; z-index:0; pointer-events:none;
  background-image:var(--filigrana);
  background-size:var(--filigrana-tam,540px);
  background-repeat:repeat;
  opacity:var(--filigrana-op,.075);
  animation:filigranaDeriva 120s linear infinite;
  will-change:transform;
}
/* Fija a la ventana, para cuando el fondo de color es de toda la
   página y no de una sección. Si se moviera con el scroll, el fondo
   se leería como una tela pasando por detrás; quieta, se lee como una
   pared, que es lo que tiene que ser. */
.filigrana--fija{ position:fixed; inset:-4%; }
@keyframes filigranaDeriva{
  0%  { transform:translate3d(0,0,0) }
  50% { transform:translate3d(-2%,-1.4%,0) }
  100%{ transform:translate3d(0,0,0) }
}

/* ───────── 18.19 LA MASCOTA ─────────
   El personaje va SIEMPRE en position:absolute y anclado a un
   borde, nunca en el flujo: tiene que poder superponerse al titular
   gigante, y eso en flujo no pasa.

   `pointer-events:none` no es un detalle — el PNG es un rectángulo
   con transparencia, y sin esto se come los clics de media pantalla,
   incluidos los de las píldoras que tiene al lado. */
.mascota{
  position:absolute; z-index:3; pointer-events:none;
  bottom:var(--mascota-y,0);
  right:var(--mascota-x,0);
  width:var(--mascota-w,42%);
  max-width:var(--mascota-max,660px);
  filter:drop-shadow(0 46px 64px rgba(0,0,0,.34));
}
.mascota--izq{ right:auto; left:var(--mascota-x,0) }
.mascota img{ width:100%; height:auto }

/* ── El personaje que recorre la página (CAMINO VIEJO) ──
   Una sola instancia, FIJA a la ventana, que atraviesa el sitio entero
   atado al scroll. No es una mascota por sección: es la misma que
   acompaña.

   ⚠ ESTO YA NO SE USA EN QUINDA Y NO ES EL CAMINO RECOMENDADO. El
   personaje pasó ADENTRO de la escena 3D —se declara con
   data-personaje en el canvas y lo arma producto3d.js— porque desde
   el DOM no hay forma de que un producto le pase por delante ni de
   que una parte del cuerpo se mueva sin mover el resto. Queda acá
   para una demo sin escena 3D, donde una imagen quieta bien puesta
   sigue siendo mejor que nada.

   Va fija y no absoluta porque tiene que estar SIEMPRE, no aparecer y
   desaparecer. Un personaje que se va cuando cambia la sección no
   acompaña a nadie.

   El transform lo escribe el bucle cuadro a cuadro: acá no se le pone
   ninguno o se pisan. Y `bottom:0` con el ancla abajo, porque el
   personaje se para en el piso de la pantalla. */
.mascota--viaje{
  position:fixed; z-index:3; pointer-events:none;
  right:0; bottom:0;
  width:var(--mascota-w,30%);
  max-width:var(--mascota-max,440px);
  transform-origin:80% 100%;
  opacity:0;
  filter:
    drop-shadow(0 -2px 26px var(--luz-producto,transparent))
    drop-shadow(0 40px 46px rgba(0,0,0,.42));
  transition:opacity .8s var(--ease);
  will-change:transform;
}
.mascota--viaje.is-ready{ opacity:1 }

/* Las poses se cruzan por opacidad, apiladas en el mismo lugar. */
.mascota__pose{
  position:absolute; inset:auto 0 0 0;
  display:block; opacity:0;
}
.mascota__pose:first-child{ position:relative }
.mascota__pose img{ width:100%; height:auto; display:block }

/* Las orejas van encima del cuerpo, ancladas en su base: el giro sale
   de ahí y no del centro, o la oreja se traslada en vez de pivotar. */
.mascota__orejas{
  position:absolute; left:0; top:0;
  transform-origin:50% 96%;
  will-change:transform;
}

/* El sitio se puede mirar antes de tener los PNG: el hueco se dibuja
   con el tamaño y la posición finales, así el layout ya se juzga. */
.mascota--hueco{
  aspect-ratio:var(--mascota-ratio,3/5);
  border:1px dashed rgba(255,255,255,.32);
  border-radius:var(--radius);
  display:grid; place-items:center; text-align:center;
  font-size:.72rem; letter-spacing:.16em; text-transform:uppercase;
  color:rgba(255,255,255,.5); padding:1rem;
  background:rgba(255,255,255,.04);
}

/* ───────── 18.20 TITULAR EN CONTORNO ─────────
   Sólo el contorno de la letra, a tamaño de cartel, sangrando por
   los dos costados. La mascota se le pone delante y ahí aparece la
   profundidad: dos planos y una sola imagen.

   El corte va en un envoltorio con overflow:hidden y NUNCA en
   html/body (rompe todo position:sticky de la página). */
.outline-marco{ position:relative; overflow:hidden; width:100% }
.titulo-outline{
  margin:0; white-space:nowrap; user-select:none;
  font-size:var(--outline-tam,clamp(3.4rem,17.5vw,15rem));
  line-height:.82; font-weight:700;
  letter-spacing:var(--outline-track,-.045em);
  text-transform:uppercase;
  color:transparent;
  -webkit-text-stroke:var(--outline-grosor,clamp(1px,.17vw,3px)) var(--outline-color,#fff);
  text-stroke:var(--outline-grosor,clamp(1px,.17vw,3px)) var(--outline-color,#fff);
}
/* Sin contorno de texto la letra sería invisible: se rellena. */
@supports not ((-webkit-text-stroke:1px #fff) or (text-stroke:1px #fff)){
  .titulo-outline{ color:var(--outline-color,#fff) }
}
.titulo-outline--lleno{
  color:var(--outline-color,#fff);
  -webkit-text-stroke:0; text-stroke:0;
}

/* ───────── 18.21 PÍLDORAS QUE SE ESTIRAN ─────────
   Tres barras blancas apiladas. Al apuntar una se estira hacia la
   derecha y las otras dos se achican. Ese segundo movimiento es
   todo el efecto: sin las vecinas retrocediendo, una barra que se
   agranda se lee a botón común.

   Se anima `width`, que es layout, y está bien acá: son tres cajas
   en una columna flex alineadas a la izquierda, así que cambiar el
   ancho de una no mueve ni una sola caja más. Y ocurre al apuntar,
   no en un bucle de scroll. Cualquier otra manera —escalar en X,
   recortar— le rompe las puntas redondas a la píldora.

   Las dos reglas de hover tienen la MISMA especificidad a propósito:
   gana la última, que es la de la píldora apuntada. Sin ese orden
   haría falta un !important. */
.pildoras{
  --pil-base:64%; --pil-max:86%; --pil-min:57%;
  position:relative; z-index:2;
  display:flex; flex-direction:column; align-items:flex-start;
  gap:var(--pil-gap,clamp(.55rem,1.3vw,1rem));
  width:100%;
}
.pildora{
  display:block; width:var(--pil-base); min-width:min(100%,20rem);
  padding:var(--pil-pad,clamp(1rem,2.3vw,1.65rem) clamp(1.5rem,3.4vw,2.6rem));
  border-radius:var(--radius-pill);
  background:var(--pil-bg,#fff);
  color:var(--pil-txt,#0C0C0C);
  font-size:var(--pil-fs,clamp(1rem,2.3vw,1.75rem));
  font-weight:500; line-height:1.18; letter-spacing:-.025em;
  text-align:left;
  box-shadow:0 12px 32px -26px rgba(0,0,0,.6);
  transition:width .35s var(--ease-mat), box-shadow .35s var(--ease-mat),
             transform .35s var(--ease-mat);
  will-change:width;
}
@media (hover:hover){
  .pildoras:hover .pildora{ width:var(--pil-min) }
  .pildora:hover{
    width:var(--pil-max);
    box-shadow:0 30px 60px -34px rgba(0,0,0,.75);
  }
}
/* Al tocar no hay hover que valga: lo maneja initPildoras con clases. */
.pildoras.hay-activa .pildora{ width:var(--pil-min) }
.pildora.is-activa{
  width:var(--pil-max);
  box-shadow:0 30px 60px -34px rgba(0,0,0,.75);
}
/* En vertical no hay lugar para estirarse: van todas al ancho completo
   y el efecto pasa a ser el realce, no el largo. */
@media (max-width:760px){
  .pildoras{ --pil-base:100%; --pil-max:100%; --pil-min:100% }
  .pildora.is-activa{ transform:translateX(6px) }
}

/* ───────── 18.22 FILA DE CLIENTES ─────────
   ⚠ Van NOMBRES INVENTADOS, nunca logos de marcas reales: es un
   sitio de muestra, y poner ahí una marca que existe es decir que
   fue cliente. Escritos con la tipografía del sitio, en gris. */
.logos{
  display:flex; flex-wrap:wrap; align-items:center;
  gap:clamp(1.4rem,4.5vw,3.6rem);
  opacity:.46; filter:grayscale(1);
  transition:opacity .5s var(--ease);
}
.logos:hover{ opacity:.7 }
.logos span{
  font-size:clamp(.9rem,1.9vw,1.3rem); font-weight:600;
  letter-spacing:-.02em; white-space:nowrap;
}
.logos span em{ font-family:var(--serif); font-style:italic; font-weight:400 }

/* ═══════════════════════════════════════════════════════════
   18.23  TITULAR VIVO
   El titular más caro del sistema, y el único que se mueve SOLO
   —sin scroll, sin mouse, sin haber entrado todavía—.

   Son tres capas encima de la misma letra:

     1 · COLOR. Un degradado de tres paradas recortado al texto que
         viaja de derecha a izquierda. No es un brillo blanco encima:
         es la letra la que cambia de color, que es lo que separa
         "título con efecto" de "título con reflejo pegado".
     2 · MOVIMIENTO. Cada letra sube y baja con la misma animación
         corrida unos milisegundos. Eso no se lee como letras
         saltando: se lee como UNA ola cruzando la palabra. Es
         `transform`, así que no repinta nada.
     3 · 3D. Las letras entran cayendo sobre su base (eso lo hace
         motor.js) y el bloque entero tiene perspectiva, así que el
         giro del hover se ve con profundidad y no plano.

   ⚠ EL DEGRADADO SE PINTA EN CADA LETRA, NO EN EL TÍTULO. Las letras
   están transformadas: un degradado en el contenedor se recortaría
   contra la caja sin transformar y saldría cortado en diagonal.

   ⚠ VA EN EL <h1> DEL HERO Y EN NINGÚN OTRO LADO. Cada letra es un
   elemento con su propia animación de color, que sí repinta. Uno por
   página no se siente; seis títulos así arrastran un celular.

   Los colores los pone el tema con --tv-1/2/3. Si no los pone,
   quedan el color de texto y el acento, que ya sirve.
   ═══════════════════════════════════════════════════════════ */
.titulo-vivo{
  perspective:1000px;
  --tv-1: var(--text);
  --tv-2: var(--accent);
  --tv-3: var(--text);
  --tv-luz: 7s;      /* cuánto tarda el color en dar una vuelta */
  --tv-ola: 4.6s;    /* cuánto tarda la ola en cruzar la palabra */
  --tv-alto: -7px;   /* cuánto sube la letra en el punto alto */
}
.titulo-vivo .tv-w{ display:inline-block; white-space:nowrap }
.titulo-vivo .tv-ch{
  display:inline-block; will-change:transform;
  background-image:linear-gradient(100deg,
    var(--tv-1) 0 38%, var(--tv-2) 50%, var(--tv-3) 62% 100%);
  background-size:300% 100%;
  background-position:118% 0;
  -webkit-background-clip:text; background-clip:text;
  color:transparent;
  animation:
    tvLuz var(--tv-luz) var(--ease) infinite,
    tvOla var(--tv-ola) ease-in-out infinite;
}
@keyframes tvLuz{
  0%, 66%, 100%{ background-position:118% 0 }
  28%, 38%     { background-position:-18% 0 }
}
@keyframes tvOla{
  0%, 100%{ transform:translate3d(0,0,0) }
  50%     { transform:translate3d(0,var(--tv-alto),0) }
}

/* ── Variante BRASA: la letra además late, como algo encendido.
   El pulso es de `scale`, no de brillo: cambiar el brillo obliga a
   repintar y encima sobre fondo oscuro se lee a parpadeo de cartel. */
.titulo-vivo--brasa{ --tv-luz:5.4s; --tv-ola:3.4s; --tv-alto:-9px }
.titulo-vivo--brasa .tv-ch{ animation-timing-function:var(--ease), ease-in-out }

/* ── Variante METAL: el degradado tiene filo. Un plástico transiciona
   suave; un metal pulido corta, porque lo que se ve en él es el
   reflejo del ambiente con sus bordes. Cinco paradas y dos de ellas
   pegadas es todo lo que hace falta. */
.titulo-vivo--metal .tv-ch{
  background-image:linear-gradient(96deg,
    var(--tv-1) 0 30%,
    var(--tv-2) 40% 44%,
    var(--tv-3) 47%,
    var(--tv-2) 50% 54%,
    var(--tv-1) 64% 100%);
  background-size:340% 100%;
}
.titulo-vivo--metal{ --tv-luz:8s; --tv-ola:5.8s; --tv-alto:-5px }

/* Si el navegador no sabe recortar el fondo al texto, el título tiene
   que verse igual de legible: color plano y sin color que viaje. */
@supports not ((-webkit-background-clip:text) or (background-clip:text)){
  .titulo-vivo .tv-ch{ background:none; color:var(--text); animation:tvOla var(--tv-ola) ease-in-out infinite }
}

/* ═══════════════════════════════════════════════════════════
   18.25  TARJETA QUE ENTRA GIRANDO
   El cuarto modo de entrada, y el único con volumen: la tarjeta llega
   girada sobre su eje vertical y se endereza, como una carta que
   alguien apoya en la mesa.

   Para qué sirve, más allá de que se vea bien: una grilla de tres
   tarjetas iguales que suben las tres a la vez se lee como UN bloque.
   Girando y desfasadas se leen como TRES cosas, y eso es exactamente lo
   que hay que comunicar cuando la grilla dice «tres formatos».

   ⚠ NO COMBINAR CON data-tilt EN EL MISMO ELEMENTO. Los dos escriben
   rotateX/rotateY sobre la misma tarjeta y el que gana es el último que
   corrió: la tarjeta se queda torcida o pega un salto al salir el
   mouse. El volumen del hover, acá, lo pone el CSS sobre la FOTO.

   La opacidad arranca en 0 en CSS y el resto lo pone el JS: así no hay
   parpadeo antes de que corra el motor, y sin JS la tarjeta se ve
   igual, derecha y quieta.
   ═══════════════════════════════════════════════════════════ */
.reveal-giro{ opacity:0; will-change:transform, opacity }
html.no-js .reveal-giro{ opacity:1; transform:none }

/* ═══════════════════════════════════════════════════════════
   18.24  TEXTO CON DESTELLO
   Lo mismo, pero para un párrafo: una luz cruza el bajada del hero
   cada tanto. Va SIN partir en letras —un párrafo son cientos— así
   que el degradado se pinta en el bloque entero, que acá se puede
   porque el párrafo no está transformado.

   ⚠ --dest-base NO PUEDE SER currentColor. El elemento tiene
   color:transparent para que se vea el degradado, así que
   currentColor valdría transparente y el texto desaparecería.
   ═══════════════════════════════════════════════════════════ */
.destella{
  --dest-base: var(--text-2);
  --dest-luz:  var(--accent-2, var(--accent));
  background-image:linear-gradient(100deg,
    var(--dest-base) 0 42%, var(--dest-luz) 50%, var(--dest-base) 58% 100%);
  background-size:280% 100%;
  background-position:120% 0;
  -webkit-background-clip:text; background-clip:text;
  color:transparent;
  animation:destPasa 9s var(--ease) infinite;
}
@keyframes destPasa{
  0%, 72%, 100%{ background-position:120% 0 }
  34%, 44%     { background-position:-20% 0 }
}
.destella em{ color:inherit }
@supports not ((-webkit-background-clip:text) or (background-clip:text)){
  .destella{ background:none; color:var(--text-2); animation:none }
}

/* ═══════════════════════════════════════════════════════════
   18.26  REFLEJO EN LOS TÍTULOS DE SECCIÓN
   La misma luz de color que cruza el <h1>, pero llevada a los <h2>.

   Es el titular vivo SIN sus otras dos capas: sin ola y sin caída en
   3D. Y eso no es una versión recortada por vagancia, es la decisión:
   el hero es el único lugar donde el título tiene la pantalla entera
   para hacer un show. Un <h2> comparte el aire con la sección que
   anuncia, y ahí el movimiento tiene que ser algo que se nota de
   reojo, no algo que se mira. Además el <h2> ya tiene su propia
   entrada (.split-lines, .subraya): dos entradas encima del mismo
   texto se pelean.

   ⚠ SE PINTA EN CADA LETRA, NO EN EL TÍTULO. .split-lines envuelve
   cada palabra en un <span> que GSAP transforma; un degradado pintado
   en el <h2> se recortaría contra la caja sin transformar y saldría
   cortado en diagonal.

   ⚠ ARRANCA PAUSADO Y SÓLO CORRE EL TÍTULO QUE SE ESTÁ VIENDO.
   Animar `background-position` repinta el elemento en cada cuadro —no
   es como `transform`, que lo resuelve la placa—. Un título son unas
   veinte letras: una a la vez no se siente, las seis de la página a la
   vez son ciento veinte elementos repintando para que se vean cinco
   que están fuera de pantalla. Eso lo maneja initReflejo con un
   IntersectionObserver.

   Los colores los pone el tema con --rf-1/2/3. Sin tema, quedan el
   color de texto y el acento, que en cualquiera de las paletas ya es
   el color de la marca.
   ═══════════════════════════════════════════════════════════ */
.reflejo{
  --rf-1: var(--text);
  --rf-2: var(--accent);
  --rf-3: var(--text);
  --rf-luz: 6.5s;
}
/* La palabra entera, que es lo que no se puede partir. Ver el comentario
   de initReflejo: sin esto el renglón corta entre dos letras
   cualesquiera y el título sale con palabras cortadas al medio. */
.reflejo .rf-w{ display:inline-block; white-space:nowrap }
.reflejo .rf-ch{
  display:inline-block;
  background-image:linear-gradient(100deg,
    var(--rf-1) 0 38%, var(--rf-2) 50%, var(--rf-3) 62% 100%);
  background-size:300% 100%;
  background-position:118% 0;
  -webkit-background-clip:text; background-clip:text;
  color:transparent;
  /* ⚠ ACÁ NO VA var(--ease). La curva del sistema es de salida fuerte:
     arranca disparada y frena al final. Eso está bien para algo que se
     mueve UNA vez, y está mal para una luz que cruza, porque el
     recorrido entero se come en los primeros 300 ms y lo que queda es
     un parpadeo. Con una curva pareja la luz tarda casi dos segundos
     en cruzar el renglón y se lee como un reflejo que pasa. */
  animation:rfLuz var(--rf-luz) cubic-bezier(.5,.06,.42,.96) infinite;
  animation-play-state:paused;
}
.reflejo.is-viendo .rf-ch{ animation-play-state:running }
@keyframes rfLuz{
  0%, 64%, 100%{ background-position:118% 0 }
  26%, 36%     { background-position:-18% 0 }
}
/* El <em> en serif de los titulares tiene su propio color en varios
   temas —es la palabra que el titular quiere destacar—. Como la letra
   pasa a color:transparent, ese color se perdería y el énfasis
   quedaría sólo en la cursiva.

   La solución no es dejar el <em> afuera del efecto: sería el único
   pedazo quieto del título. Adentro del <em> se dan vuelta las
   paradas. La palabra descansa en el color del acento y la luz que la
   cruza es la del texto, así que es la MISMA luz recorriendo el
   renglón, sólo que revelada al revés donde el titular cambia de voz. */
.reflejo em{
  color:inherit;
  --rf-1: var(--accent-2, var(--accent));
  --rf-2: var(--text);
  --rf-3: var(--accent-2, var(--accent));
}
/* ── Variante METAL, la misma que tiene .titulo-vivo: el degradado
   tiene filo. Un plástico transiciona suave; un metal pulido corta,
   porque lo que se ve en él es el reflejo del ambiente con sus bordes.
   Va donde el <h1> del hero ya es metal, para que los <h2> hablen el
   mismo idioma y no parezcan otro sitio. */
.reflejo--metal .rf-ch{
  background-image:linear-gradient(96deg,
    var(--rf-1) 0 30%,
    var(--rf-2) 40% 44%,
    var(--rf-3) 47%,
    var(--rf-2) 50% 54%,
    var(--rf-1) 64% 100%);
  background-size:340% 100%;
}

@supports not ((-webkit-background-clip:text) or (background-clip:text)){
  .reflejo .rf-ch{ background:none; color:var(--text); animation:none }
}

/* ═══════════════════════════════════════════════════════════
   18.27  TARJETA QUE DA LA VUELTA
   Una tarjeta con dos caras de verdad: la de adelante dice qué es, y
   al apuntarla gira sobre su eje vertical y aparece el dorso, que es
   la misma cosa dicha en color y con el paso siguiente.

   Por qué el dorso NO puede tener información que no esté adelante:
   una cara que sólo aparece con el mouse encima no existe para nadie
   que entre desde el teléfono, y no existe para el buscador. El dorso
   suma —el color de la marca, el nombre grande, el enlace a la acción—
   pero nunca es donde se guarda el dato.

   Tres cosas que sostienen esto y que no se ven:

   1 · LA PERSPECTIVA VA EN LA GRILLA, NO EN CADA TARJETA. Con la
       perspectiva puesta en cada una, las seis giran mirando cada una
       a su propia cámara y el conjunto se lee a seis animaciones
       sueltas. Con un solo punto de fuga para la grilla, la de la
       izquierda gira hacia adentro y la de la derecha hacia afuera: se
       leen como seis objetos en una misma habitación. Eso obliga a que
       todo lo que hay en el medio lleve transform-style:preserve-3d, o
       la cadena 3D se aplana y no gira nada.

   2 · LAS DOS CARAS SE APILAN EN UNA GRILLA DE UNA CELDA. Es la misma
       solución que la galería: las dos ocupan 1/1, así que la tarjeta
       mide lo que mide la cara MÁS ALTA. Con posición absoluta —que es
       como se hace habitualmente— la tarjeta mide lo que mide el
       frente y el dorso se desborda o se corta, y sólo se descubre en
       el idioma donde el texto es más largo.

   3 · EL DORSO NO LLEVA backdrop-filter. Un filtro de fondo dentro de
       una cadena 3D toma el fondo equivocado —el de antes de girar— y
       la cara sale de un gris sucio. El frente lo conserva porque
       nunca está de espaldas; el dorso va con color pleno, que además
       es lo que se quiere: el golpe de color es el efecto.
   ═══════════════════════════════════════════════════════════ */
.tarjetas--gira{ perspective:1500px; perspective-origin:50% 38% }

.tarjeta-gira{
  /* La piel pasa a las caras: si se quedara acá, se vería el borde y
     el fondo de la tarjeta detrás del dorso mientras gira. */
  padding:0; border:0; background:none; backdrop-filter:none;
  transform-style:preserve-3d;
  transition:none;
}
.tarjeta-gira:hover{ transform:none; background:none; border-color:transparent }

.gira{
  position:relative; height:100%;
  display:grid; grid-template:1fr / 1fr;
  transform-style:preserve-3d;
  transition:transform .9s cubic-bezier(.42,.02,.24,1);
}
@media (hover:hover){ .tarjeta-gira:hover .gira{ transform:rotateY(180deg) } }
.tarjeta-gira.is-vuelta .gira{ transform:rotateY(180deg) }

.gira__cara{
  grid-area:1/1;
  display:flex; flex-direction:column;
  padding:clamp(1.4rem,2.6vw,2rem);
  border:1px solid var(--line); border-radius:var(--radius);
  backface-visibility:hidden; -webkit-backface-visibility:hidden;
  transition:border-color .5s var(--ease);
}
/* ⚠ ACÁ NO HAY backdrop-filter, Y ES EL SEGUNDO INTENTO.
   El frente lo tenía, copiado de .tarjeta, y NO FUNCIONA: adentro de
   una cadena preserve-3d el filtro de fondo no se aplica —o toma el
   fondo equivocado— y lo único que queda es el vidrio translúcido sin
   desenfoque. En un tema oscuro plano no se nota; en Quinda, donde
   detrás de las tarjetas pasan las latas en 3D, la tarjeta pasó a ser
   un rectángulo transparente con una lata nítida adentro y el texto
   encima. No hay ningún error: simplemente el desenfoque no está.

   El reemplazo es una capa de color abajo del vidrio. --gira-fondo por
   omisión es el fondo de la página, o sea tarjeta opaca y legible
   siempre; el tema puede bajarla a un color con alfa cuando quiere que
   se siga viendo lo que hay atrás. */
.gira__frente{ background:var(--vidrio), var(--gira-fondo, var(--bg)) }
.tarjeta-gira:hover .gira__frente{ border-color:var(--gira-color,var(--accent)) }

/* Cuando el frente es una foto a sangre, el relleno se lo queda el
   bloque de texto de adentro. El overflow puede ir en la cara porque es
   una hoja de la cadena 3D: no tiene descendientes transformados a los
   que aplanar. */
.gira__cara--foto{ padding:0; overflow:hidden }

.gira__dorso{
  transform:rotateY(180deg);
  background:var(--gira-color,var(--accent));
  color:var(--gira-tinta,var(--on-accent));
  border-color:transparent;
  justify-content:space-between;
}
.gira__dorso h4,
.gira__dorso p,
.gira__dorso a{ color:inherit }
.gira__dorso h4{
  font-size:clamp(1.3rem,2.6vw,1.9rem); font-weight:600;
  letter-spacing:-.03em; line-height:1.08; margin:0;
}
.gira__dorso p{ font-size:.9rem; opacity:.9; margin:.5rem 0 0 }
.gira__paso{
  margin-top:auto; padding-top:1.2rem;
  font-size:.85rem; font-weight:600; letter-spacing:.02em;
  text-decoration:none; display:inline-flex; align-items:center; gap:.45rem;
}
.gira__paso::after{ content:'→'; transition:transform .35s var(--ease) }
.gira__dorso:hover .gira__paso::after{ transform:translateX(5px) }

/* Sin JS y sin mouse la tarjeta es una tarjeta común: se ve el frente
   entero y el dorso nunca molesta. */
html.no-js .gira{ transform:none }

/* ───────── 19. MENOS MOVIMIENTO ─────────
   Quien lo pide ve la página quieta y completa, no una página rota. */
/* ═══════════════════════════════════════════════════════════
   GRANO Y VIÑETA
   Las dos capas que más sacan el "look de plantilla". Van encima
   de todo el contenido y debajo del cursor y de la cortina.

   El grano es una sola textura de ruido que salta entre ocho
   posiciones. Salta con `transform`, que no repinta nada: cuesta
   lo mismo que una capa quieta. La viñeta es un degradado fijo.

   Las dos son decorativas y las inyecta el JS: si no hay JS no
   aparecen y no pasa nada.
   ═══════════════════════════════════════════════════════════ */
:root{
  --grano-op:  .055;
  /* En tema oscuro la viñeta cierra con negro; los temas claros la
     pisan con su propio valor (o la apagan del todo). */
  /* El negro no puede empezar antes de que el ovalo pase el borde del
     texto, o el titular se lee gris sucio. Solo esquinas. */
  --vineta: radial-gradient(100% 88% at 50% 45%, transparent 62%, rgba(0,0,0,.45) 100%);
}

.grano,.vineta{ position:fixed; pointer-events:none }

.grano{
  /* Se extiende más allá de la pantalla porque se mueve: si midiera
     justo, cada salto dejaría un borde vacío. */
  inset:-140px; z-index:940;
  opacity:var(--grano-op);
  mix-blend-mode:overlay;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='r'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23r)'/%3E%3C/svg%3E");
  animation:granear 1.1s steps(1,end) infinite;
  will-change:transform;
}
@keyframes granear{
  0%   { transform:translate3d(0,0,0) }
  12%  { transform:translate3d(-3%,-5%,0) }
  25%  { transform:translate3d(-8%,2%,0) }
  37%  { transform:translate3d(4%,-3%,0) }
  50%  { transform:translate3d(-2%,6%,0) }
  62%  { transform:translate3d(6%,4%,0) }
  75%  { transform:translate3d(-6%,-2%,0) }
  87%  { transform:translate3d(2%,5%,0) }
  100% { transform:translate3d(0,0,0) }
}

.vineta{ inset:0; z-index:939; background:var(--vineta) }

/* En pantallas chicas el grano se ve el doble de grueso —los píxeles
   son más chicos— y encima la mezcla de capas es de lo más caro que
   hay en un teléfono. Va más suave. */
@media (max-width:760px){
  :root{ --grano-op:.035 }
}
/* Equipos flojos: no hay grano. Es lo primero que conviene resignar. */
.tier-low .grano{ display:none }

@media (prefers-reduced-motion:reduce){
  .grano{ animation:none }
  html{ scroll-behavior:auto }
  *,*::before,*::after{
    animation-duration:.01ms !important; animation-iteration-count:1 !important;
    transition-duration:.01ms !important; scroll-behavior:auto !important;
  }
  .reveal-up,.reveal-lado,.reveal-escala{ opacity:1; transform:none }
  .bg-static{ animation:none }
  .btn--beat{ animation:none }
  .hero__lux{ display:none }
  .cortina{ display:none }
  .cursor,.cursor__punto{ display:none }
  .sello svg{ animation:none }
  .lectura .lw{ opacity:1 !important }
  .pasos__linea{ transform:scaleY(1) }
  .fondo{ display:none }
  .subraya::after{ transform:scaleX(1) }
  .numeral{ opacity:.05 }
  .titulo-3d .t3-ch{ animation:none; background:none; color:var(--text) }
  .titulo-vivo .tv-ch{ animation:none; background:none; color:var(--text); transform:none }
  .reflejo .rf-ch{ animation:none; background:none; color:var(--text) }
  /* La tarjeta no gira: se muestra el frente y listo. Un giro de 180°
     es exactamente el tipo de movimiento que molesta a quien pidió
     menos, y acá no se pierde nada porque el dato está adelante. */
  .gira{ transition:none }
  .tarjeta-gira:hover .gira,
  .tarjeta-gira.is-vuelta .gira{ transform:none }
  .destella{ animation:none; background:none; color:var(--text-2) }
  .reveal-giro{ opacity:1; transform:none }
  /* El lenguaje de mascota, quieto: la filigrana deja de derivar, el
     titular gigante ya está donde tiene que estar y las píldoras
     cambian de sombra pero no de largo —un ancho que se mueve es
     justo el tipo de movimiento que molesta a quien pidió menos—. */
  .filigrana{ animation:none }
  .pildora{ transition:box-shadow .2s linear }
  .pildoras:hover .pildora,
  .pildoras.hay-activa .pildora,
  .pildora:hover,
  .pildora.is-activa{ width:var(--pil-base) }
  .titulo-outline{ transform:none !important; opacity:1 !important }
}
