:root {
  --sage: #ccccc0;
  --sage-2: #d8d8cc;
  --forest: #305040;
  --olive: #545424;
  --olive-dark: #303018;
  --ink: #18180c;
  --berry: #c8503c;
  --arc-gold: #a88b4a; /* acento del arco otoño (C-04/06/08) — reemplaza el rojo en hovers */
  --paper: #f2f0e8;
  /* atardecer = verde dorado sutil, ya no ámbar/naranja */
  --dusk: #b9b88a;
  --dusk-2: #8c9464;
  --dawn: #e7e4d3;
  /* noche azul de Tepoztlán (rev3) — azul índigo profundo, nunca negro puro */
  --night-blue: #1a2740;
  --night-blue-2: #33465a;
  --dawn-blue: #243a55;
  --dawn-blue-2: #3d5b74;
  --dawn-blue-3: #2b4056;
  --hero-gutter: clamp(1.35rem, 4vw, 4.5rem);
  --gutter: clamp(1.35rem, 4vw, 4.5rem);
  --spot-ink: var(--ink);
}

* {
  box-sizing: border-box;
}

html {
  min-height: 100%;
  background: var(--sage);
  color: var(--forest);
  font-family: "EB Garamond", Georgia, serif;
  text-rendering: geometricPrecision;
  scroll-behavior: smooth;
}

body {
  min-height: 100%;
  margin: 0;
  background:
    radial-gradient(circle at 14% 24%, rgba(242, 240, 232, 0.2), transparent 31rem),
    linear-gradient(180deg, var(--sage) 0%, var(--sage-2) 100%);
}

/* 2026-07-10 (Jara: costura dura entre Gracias→Fotos) — aunque --bg-live
   es matemáticamente idéntico entre secciones vecinas en cada frame, cada
   .section pintaba el color POR SU CUENTA; el paper-grain (mix-blend-mode)
   y el stacking context de #gracias (overflow:hidden) rompían el continuo
   justo en el borde DOM, visible como línea dura. Fix: una sola superficie
   pintada (body) — las secciones quedan transparentes y sólo aportan texto,
   así el grano/blend corre sobre UN fondo, sin costuras posibles. */
.js-motion body {
  background: var(--bg-live, var(--sage));
  transition: background-color 140ms linear;
}

a {
  color: inherit;
}

.lbl {
  margin: 0;
  font-family: "Cormorant", Georgia, serif;
  font-size: clamp(1.35rem, 2vw, 1.9rem);
  line-height: 1;
}

.lbl em {
  font-style: italic;
}

.meta {
  font-variant-caps: small-caps;
  letter-spacing: 0.04em;
}

.placeholder-tag {
  display: inline-block;
  padding: 0.25rem 0.7rem;
  border: 1px dashed color-mix(in srgb, var(--spot-ink) 55%, transparent);
  border-radius: 999px;
  font-size: 0.8rem;
  font-variant-caps: small-caps;
  letter-spacing: 0.04em;
  /* audit Fable 2026-07-10 #1: 0.75 caía bajo AA (3.14:1) contra los
     stops de día/dusk del arco recalibrado — es info funcional, no
     decorativa. */
  opacity: 0.92;
}

/* ------------------------------------------------------------
   Reveal on scroll
   ------------------------------------------------------------ */
.reveal {
  opacity: 0;
  transform: translateY(20px);
  transition: opacity 620ms ease, transform 620ms ease;
}

.reveal.in {
  opacity: 1;
  transform: translateY(0);
}

/* ------------------------------------------------------------
   Color-grade día→noche→amanecer-azul (motor de scroll, rev3)
   ÚNICO sistema de fondo cuando js-motion está activo: --bg-live/
   --fg-live (JS, script.js gradeAt()) pisan a las clases .section--*
   por especificidad. Esas clases quedan SOLO como fallback estático
   para prefers-reduced-motion / sin JS (ver más abajo, misma paleta
   narrativa de la tabla §3 del handoff rev3).
   ------------------------------------------------------------ */
.js-motion .hero,
.js-motion .section,
.js-motion .footer {
  /* el color ahora vive SOLO en body (ver arriba) — transparente aquí para
     no duplicar la pintura y evitar cualquier costura entre secciones. */
  background: transparent;
  color: var(--fg-live, var(--forest));
  transition: color 260ms ease;
}

.js-motion .section--evening .lbl,
.js-motion .section--evening h2,
.js-motion .section--night .lbl,
.js-motion .section--night h2,
.js-motion .section--day-2 .lbl,
.js-motion .section--day-2 h2 {
  color: var(--fg-live, var(--paper));
}

/* ------------------------------------------------------------
   Sol → luna viajero (elemento firma, rev3 — arco real)
   Vive en el "cielo": fixed + z-index bajo, DETRÁS del contenido.
   El contenido de cada sección (.hero__inner / .section__inner /
   .footer) recibe su propio stacking context con z-index mayor
   (ver más abajo) para que el disco nunca tape una card — solo se
   asoma contra el color de fondo plano, como el cielo real.
   ------------------------------------------------------------ */
.celestial {
  /* top/left quedan en 0 y FIJOS a propósito: animar top/left dispara
     layout (reflow) en cada frame de scroll — con CPU 4x eso costó
     ~60 long tasks >50ms. El movimiento real va por `transform:
     translate()` con unidades vw/vh (--cel-left/--cel-top), que es
     compositor-only, igual que el parallax del hero. */
  position: fixed;
  top: 0;
  left: 0;
  width: clamp(2rem, 4vw, 3.2rem);
  height: clamp(2rem, 4vw, 3.2rem);
  transform: translate(var(--cel-left, 15vw), var(--cel-top, 8vh));
  opacity: var(--cel-op, 1);
  pointer-events: none;
  z-index: 1;
  display: none;
  transition: opacity 500ms ease;
}

.js-motion .celestial {
  display: block;
}

.celestial__halo,
.celestial__disc {
  position: absolute;
  inset: 0;
  border-radius: 50%;
}

.celestial__halo {
  background: radial-gradient(circle, color-mix(in srgb, var(--cel-core, var(--dawn)) 32%, transparent) 0%, transparent 72%);
  transform: scale(1.7);
  transition: background 900ms ease;
}

.celestial__disc {
  background: radial-gradient(circle at 35% 32%, var(--cel-core, var(--dawn)) 0%, var(--cel-edge, var(--dusk)) 78%);
  box-shadow: 0 0 0.9rem color-mix(in srgb, var(--cel-core, var(--dawn)) 26%, transparent);
  transition: background 900ms ease, box-shadow 900ms ease, clip-path 900ms ease;
}

/* ---- LUNA: asset independiente, cuarto menguante (2026-07-12 v9, Jara) ----
   CERO motion propio. Posición FIJA dentro de `.night-hills` (su
   position:relative la ancla) — la "postal perfecta" entre la firma y la
   montaña, calibrada en el hueco de la ilustración. Ya no se mueve por JS
   en cada frame de scroll: eso era la causa del glitch al revertir scroll
   (un frame con getBoundingClientRect aún no medible hacía "saltar" la
   luna). Solo aparece con un fade de opacidad (.reveal, IntersectionObserver)
   al descubrir la sección — nunca slide/translate. */
.moon {
  /* 2026-07-12 v10 (Jara): capa de cielo FIJA de nivel superior (hermana del
     sol), fuera de .night-hills. left/top los fija JS (recalcMoon) para caer
     en el hueco de la ilustración al final del scroll; la opacidad sube con el
     scroll desde "De nosotros para ti". CERO motion — solo fade. z-index:1
     (como el sol y las estrellas): brilla a través del cielo transparente de
     la ilustración en la postal y se OCULTA tras el follaje/cerros al llegar
     al footer (se "pone" natural, sin flotar sobre los árboles). */
  position: fixed;
  left: 50%;
  top: 60%;
  width: clamp(2.2rem, 4.4vw, 3.6rem);
  height: clamp(2.2rem, 4.4vw, 3.6rem);
  transform: translate(-50%, -50%);
  opacity: 0;
  pointer-events: none;
  z-index: 1;
}

.moon__halo,
.moon__disc {
  position: absolute;
  inset: 0;
  border-radius: 50%;
}

/* Halo luminoso amplio — el resplandor suave que la vuelve "brillante" y no
   un disco gris opaco (Jara 2026-07-12). */
/* 2026-07-13 v13 (Jara): halo bajado — el 0.82/scale3.05 se veía "irreal y
   exagerado, absurdamente luminoso". Glow suave presente, sin blowout. */
.moon__halo {
  background: radial-gradient(circle, rgba(238, 246, 253, 0.46) 0%, rgba(216, 232, 244, 0.16) 46%, transparent 72%);
  transform: scale(2.15);
}

/* Luna estética (2026-07-10 v5, Jara: "que no parezca pac-man"). Dos capas:
   (1) el disco base = esfera tenue (earthshine) — la cara oscura NO se recorta
   dura, apenas se insinúa como cuerpo redondo; (2) ::after = el creciente
   iluminado con TERMINADOR SUAVE (degradado, no borde duro), cuarto menguante
   → limbo brillante a la izquierda. */
.moon__disc {
  background: radial-gradient(circle at 50% 50%, rgba(214, 228, 238, 0.16) 0%, rgba(214, 228, 238, 0.05) 66%, transparent 78%);
  /* doble glow: cerca (nítido) + lejos (difuso) → resplandor lunar real */
  box-shadow: 0 0 1.1rem rgba(232, 244, 252, 0.4), 0 0 2.2rem rgba(212, 230, 246, 0.22);
}

.moon__disc::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: radial-gradient(circle at 34% 40%, #ffffff 0%, #f3f9fd 58%, #dae7f2 90%);
  /* halo propio del creciente iluminado — lo hace lucir encendido, no gris */
  filter: drop-shadow(0 0 7px rgba(244, 250, 255, 0.9));
  /* terminador suave curvo: el sombreado entra por la derecha de forma
     gradual (54%→72%) — sin recorte tipo pac-man. */
  -webkit-mask: radial-gradient(115% 100% at 128% 50%, transparent 0 54%, rgba(0, 0, 0, 0.45) 63%, #000 72%);
  mask: radial-gradient(115% 100% at 128% 50%, transparent 0 54%, rgba(0, 0, 0, 0.45) 63%, #000 72%);
}

/* ------------------------------------------------------------
   Estrellas (rev3) — capa fija, opacidad ligada a --stars-op
   (mismo p del grade, ver script.js). Detrás del contenido igual
   que el sol/luna.
   ------------------------------------------------------------ */
/* ------------------------------------------------------------
   Paper grain / wash (2026-07-10) — Jara: que el color "pinte"
   ligeramente el canvas, no un sólido plano digital. Grano de papel
   fijo, DEBAJO del contenido (z:0) y encima del color de fondo, con
   mezcla suave → el fill se lee como pigmento sobre papel, sin tocar
   el color/lo oscuro (la noche sigue profunda). Textura estática. */
.paper-grain {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  opacity: 0.5;
  mix-blend-mode: soft-light;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 180px 180px;
}

.stars {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  /* altura estable: la barra del navegador móvil ya no reacomoda el campo
     de estrellas (usa el viewport grande, fijo). */
  height: 100vh;
  height: 100lvh;
  z-index: 1;
  pointer-events: none;
  opacity: var(--stars-op, 0);
  transition: opacity 700ms ease;
  /* R4 + 2026-07-10 (Jara: "más estrellas en las últimas secciones"):
     campo más denso y repartido por TODA la altura (antes solo cubría el
     65% superior; ahora llega hasta abajo, así Gracias/Fotos se ven más
     estrelladas). Mezcla de brillos/tamaños para que no se vea en retícula. */
  background-image:
    radial-gradient(1.6px 1.6px at 13% 16%, var(--paper) 50%, transparent 54%),
    radial-gradient(2.4px 2.4px at 24% 61%, var(--paper) 50%, transparent 54%),
    radial-gradient(1.6px 1.6px at 22% 17%, var(--paper) 50%, transparent 54%),
    radial-gradient(1.8px 1.8px at 83% 16%, var(--paper) 50%, transparent 54%),
    radial-gradient(1.5px 1.5px at 21% 41%, var(--paper) 50%, transparent 54%),
    radial-gradient(2.2px 2.2px at 11% 93%, var(--paper) 50%, transparent 54%),
    radial-gradient(1.6px 1.6px at 69% 78%, var(--paper) 50%, transparent 54%),
    radial-gradient(2.0px 2.0px at 89% 50%, var(--paper) 50%, transparent 54%),
    radial-gradient(2.6px 2.6px at 61% 87%, var(--paper) 50%, transparent 54%),
    radial-gradient(2.0px 2.0px at 15% 5%, var(--paper) 50%, transparent 54%),
    radial-gradient(2.8px 2.8px at 63% 27%, var(--paper) 50%, transparent 54%),
    radial-gradient(1.5px 1.5px at 53% 86%, var(--paper) 50%, transparent 54%),
    radial-gradient(1.8px 1.8px at 57% 84%, var(--paper) 50%, transparent 54%),
    radial-gradient(2.6px 2.6px at 37% 7%, var(--paper) 50%, transparent 54%),
    radial-gradient(2.0px 2.0px at 38% 38%, var(--paper) 50%, transparent 54%),
    radial-gradient(2.8px 2.8px at 82% 39%, var(--paper) 50%, transparent 54%),
    radial-gradient(1.6px 1.6px at 66% 20%, var(--paper) 50%, transparent 54%),
    radial-gradient(2.8px 2.8px at 32% 57%, var(--paper) 50%, transparent 54%),
    radial-gradient(1.8px 1.8px at 42% 7%, var(--paper) 50%, transparent 54%),
    radial-gradient(2.2px 2.2px at 8% 91%, var(--paper) 50%, transparent 54%),
    radial-gradient(2.4px 2.4px at 67% 73%, var(--paper) 50%, transparent 54%),
    radial-gradient(1.6px 1.6px at 12% 77%, var(--paper) 50%, transparent 54%),
    radial-gradient(2.8px 2.8px at 72% 51%, var(--paper) 50%, transparent 54%),
    radial-gradient(1.6px 1.6px at 78% 55%, var(--paper) 50%, transparent 54%),
    radial-gradient(2.0px 2.0px at 66% 26%, var(--paper) 50%, transparent 54%),
    radial-gradient(1.4px 1.4px at 47% 25%, var(--paper) 50%, transparent 54%),
    radial-gradient(2.8px 2.8px at 3% 41%, var(--paper) 50%, transparent 54%),
    radial-gradient(2.8px 2.8px at 26% 16%, var(--paper) 50%, transparent 54%),
    radial-gradient(2.6px 2.6px at 50% 4%, var(--paper) 50%, transparent 54%),
    radial-gradient(1.8px 1.8px at 37% 36%, var(--paper) 50%, transparent 54%),
    radial-gradient(1.6px 1.6px at 41% 54%, var(--paper) 50%, transparent 54%),
    radial-gradient(2.8px 2.8px at 13% 62%, var(--paper) 50%, transparent 54%),
    radial-gradient(1.6px 1.6px at 60% 44%, var(--paper) 50%, transparent 54%),
    radial-gradient(2.8px 2.8px at 75% 21%, var(--paper) 50%, transparent 54%),
    radial-gradient(2.2px 2.2px at 87% 45%, var(--paper) 50%, transparent 54%),
    radial-gradient(2.4px 2.4px at 93% 47%, var(--paper) 50%, transparent 54%),
    radial-gradient(1.5px 1.5px at 40% 40%, var(--paper) 50%, transparent 54%),
    radial-gradient(2.2px 2.2px at 34% 75%, var(--paper) 50%, transparent 54%),
    radial-gradient(2.2px 2.2px at 57% 88%, var(--paper) 50%, transparent 54%),
    radial-gradient(1.5px 1.5px at 52% 80%, var(--paper) 50%, transparent 54%),
    radial-gradient(2.4px 2.4px at 64% 40%, var(--paper) 50%, transparent 54%),
    radial-gradient(1.6px 1.6px at 84% 90%, var(--paper) 50%, transparent 54%),
    radial-gradient(1.8px 1.8px at 73% 12%, var(--paper) 50%, transparent 54%),
    radial-gradient(2.6px 2.6px at 89% 16%, var(--paper) 50%, transparent 54%),
    radial-gradient(1.4px 1.4px at 81% 60%, var(--paper) 50%, transparent 54%),
    radial-gradient(2.6px 2.6px at 67% 18%, var(--paper) 50%, transparent 54%),
    radial-gradient(1.8px 1.8px at 97% 46%, var(--paper) 50%, transparent 54%),
    radial-gradient(2.4px 2.4px at 9% 83%, var(--paper) 50%, transparent 54%),
    radial-gradient(2.0px 2.0px at 5% 69%, var(--paper) 50%, transparent 54%),
    radial-gradient(2.4px 2.4px at 48% 35%, var(--paper) 50%, transparent 54%),
    radial-gradient(2.2px 2.2px at 36% 74%, var(--paper) 50%, transparent 54%),
    radial-gradient(1.8px 1.8px at 68% 73%, var(--paper) 50%, transparent 54%),
    radial-gradient(1.5px 1.5px at 4% 94%, var(--paper) 50%, transparent 54%),
    radial-gradient(1.8px 1.8px at 13% 11%, var(--paper) 50%, transparent 54%),
    radial-gradient(2.6px 2.6px at 57% 53%, var(--paper) 50%, transparent 54%),
    radial-gradient(2.8px 2.8px at 41% 79%, var(--paper) 50%, transparent 54%),
    radial-gradient(2.2px 2.2px at 93% 24%, var(--paper) 50%, transparent 54%),
    radial-gradient(2.4px 2.4px at 39% 27%, var(--paper) 50%, transparent 54%),
    radial-gradient(2.8px 2.8px at 6% 79%, var(--paper) 50%, transparent 54%),
    radial-gradient(2.0px 2.0px at 23% 32%, var(--paper) 50%, transparent 54%),
    radial-gradient(1.6px 1.6px at 29% 37%, var(--paper) 50%, transparent 54%),
    radial-gradient(1.4px 1.4px at 91% 92%, var(--paper) 50%, transparent 54%),
    radial-gradient(1.8px 1.8px at 55% 83%, var(--paper) 50%, transparent 54%),
    radial-gradient(1.6px 1.6px at 65% 57%, var(--paper) 50%, transparent 54%),
    radial-gradient(2.2px 2.2px at 34% 52%, var(--paper) 50%, transparent 54%),
    radial-gradient(2.4px 2.4px at 86% 48%, var(--paper) 50%, transparent 54%),
    radial-gradient(2.2px 2.2px at 96% 7%, var(--paper) 50%, transparent 54%),
    radial-gradient(2.0px 2.0px at 53% 48%, var(--paper) 50%, transparent 54%),
    radial-gradient(2.0px 2.0px at 76% 58%, var(--paper) 50%, transparent 54%),
    radial-gradient(2.4px 2.4px at 97% 29%, var(--paper) 50%, transparent 54%),
    radial-gradient(1.5px 1.5px at 10% 19%, var(--paper) 50%, transparent 54%),
    radial-gradient(2.2px 2.2px at 45% 70%, var(--paper) 50%, transparent 54%),
    radial-gradient(1.8px 1.8px at 68% 73%, var(--paper) 50%, transparent 54%),
    radial-gradient(1.6px 1.6px at 89% 74%, var(--paper) 50%, transparent 54%),
    radial-gradient(1.5px 1.5px at 46% 60%, var(--paper) 50%, transparent 54%),
    radial-gradient(2.6px 2.6px at 51% 42%, var(--paper) 50%, transparent 54%),
    radial-gradient(2.0px 2.0px at 95% 76%, var(--paper) 50%, transparent 54%),
    radial-gradient(2.6px 2.6px at 23% 14%, var(--paper) 50%, transparent 54%);
  background-repeat: no-repeat;
  animation: twinkle 6s steps(12) infinite;
}

@keyframes twinkle {
  0%, 100% { opacity: var(--stars-op, 0); }
  50% { opacity: calc(var(--stars-op, 0) * 0.55); }
}

/* Estrellas fugaces (2026-07-10, Jara: "punch inmersivo") — streak con
   cola difuminada, cruza el cielo rápido y desaparece. Ciclos largos
   (18-27s) con la parte visible comprimida al final del ciclo → se
   sienten ocasionales/aleatorias, no un patrón repetitivo obvio.
   Heredan opacidad de .stars (var(--stars-op)) así solo aparecen de
   noche, igual que el resto del cielo estrellado. */
.shooting-star {
  position: absolute;
  width: 2px;
  height: 2px;
  border-radius: 50%;
  background: var(--paper);
  box-shadow: 0 0 4px 0.5px color-mix(in srgb, var(--paper) 55%, transparent);
  opacity: 0;
}

.shooting-star::before {
  content: "";
  position: absolute;
  top: 50%;
  right: 100%;
  width: 60px;
  height: 1px;
  background: linear-gradient(90deg, transparent, color-mix(in srgb, var(--paper) 50%, transparent));
  transform: translateY(-50%) rotate(180deg);
  transform-origin: right center;
}

/* 2026-07-12 v10 (Jara): TODAS sobre el cerro (top pequeño = cielo alto, nunca
   por debajo de la cordillera de la postal) y con cadencia garantizada — 4
   trazos activos con ciclos ~14-17s y delays escalonados, de modo que una
   fugaz cruza más o menos cada ~5s (siempre < 8s) sin volverse tormenta.
   El resto (--5..11, postal) se ocultan para no saturar. */
/* 2026-07-13 (Jara): cadencia GARANTIZADA — 4 trazos con ciclo idéntico (24s)
   y delays escalonados cada 6s → en régimen una fugaz cruza ~cada 6s (siempre
   < 8s), sin volverse tormenta. Todas top 6-16% = cielo alto, siempre sobre la
   cordillera de la postal (el ridge cae ~y476 en móvil; estas cruzan y<300). */
.shooting-star--1 {
  top: 9%;
  left: 20%;
  animation: shoot-a 24s linear infinite;
}
.shooting-star--2 {
  top: 6%;
  left: 58%;
  animation: shoot-b 24s linear infinite;
}
.shooting-star--3 {
  top: 16%;
  left: 38%;
  animation: shoot-c 24s linear infinite;
}
.shooting-star--4 {
  top: 12%;
  left: 76%;
  animation: shoot-d 24s linear infinite;
}
/* 4 destellos repartidos en fases 12/37/62/87% del mismo ciclo de 24s → una
   fugaz cruza ~cada 6s (nunca > 8s) y, al llegar a la postal, la primera cae
   en ≤6s (no hay zona muerta inicial). Alternan izq/der para no parecer patrón. */
@keyframes shoot-a {
  0%, 11%   { opacity: 0; transform: translate(0, 0); }
  12%       { opacity: var(--stars-op, 0); }
  15.5%     { opacity: var(--stars-op, 0); transform: translate(190px, 104px); }
  16.5%, 100% { opacity: 0; transform: translate(205px, 112px); }
}
@keyframes shoot-b {
  0%, 36%   { opacity: 0; transform: translate(0, 0); }
  37%       { opacity: var(--stars-op, 0); }
  40.5%     { opacity: var(--stars-op, 0); transform: translate(-165px, 118px); }
  41.5%, 100% { opacity: 0; transform: translate(-180px, 128px); }
}
@keyframes shoot-c {
  0%, 61%   { opacity: 0; transform: translate(0, 0); }
  62%       { opacity: var(--stars-op, 0); }
  65.5%     { opacity: var(--stars-op, 0); transform: translate(160px, 92px); }
  66.5%, 100% { opacity: 0; transform: translate(172px, 100px); }
}
@keyframes shoot-d {
  0%, 86%   { opacity: 0; transform: translate(0, 0); }
  87%       { opacity: var(--stars-op, 0); }
  90.5%     { opacity: var(--stars-op, 0); transform: translate(-150px, 126px); }
  91.5%, 100% { opacity: 0; transform: translate(-164px, 136px); }
}
.shooting-star--5,
.shooting-star--6,
.shooting-star--7,
.shooting-star--8,
.shooting-star--9,
.shooting-star--10,
.shooting-star--11,
.shooting-star--postal-1,
.shooting-star--postal-2 {
  display: none;
}

/* 2026-07-13 v14 (Jara: "no veo fugaces en la escena mágica del postal").
   En desktop la escena (luna + cerro) cae en el tercio ALTO del viewport, así
   que las fugaces a top 6-16% cruzan justo alrededor de la luna. Pero en móvil
   la ilustración se centra a mitad de pantalla (~52% de alto) y esas mismas
   fugaces cruzaban muy arriba (~10%), desconectadas de la escena. Aquí las
   bajo a la franja de cielo que rodea la luna del postal (34-44%), sin pasar
   del ridge (el translate de los keyframes las lleva ~11-16% más abajo y se
   apagan antes de tocar la cordillera). Sigue siendo el mismo campo nocturno
   (heredan --stars-op), solo cambia la altura donde cruzan en móvil. */
@media (max-width: 860px) {
  .shooting-star--1 { top: 38%; }
  .shooting-star--2 { top: 35%; }
  .shooting-star--3 { top: 44%; }
  .shooting-star--4 { top: 40%; }
}

@keyframes shoot-1 {
  0%, 91% { opacity: 0; transform: translate(0, 0); }
  92% { opacity: var(--stars-op, 0); }
  96% { opacity: var(--stars-op, 0); transform: translate(200px, 110px); }
  97%, 100% { opacity: 0; transform: translate(215px, 120px); }
}
@keyframes shoot-2 {
  0%, 93% { opacity: 0; transform: translate(0, 0); }
  94% { opacity: var(--stars-op, 0); }
  97.5% { opacity: var(--stars-op, 0); transform: translate(-170px, 130px); }
  98.5%, 100% { opacity: 0; transform: translate(-185px, 140px); }
}
@keyframes shoot-3 {
  0%, 90% { opacity: 0; transform: translate(0, 0); }
  91% { opacity: var(--stars-op, 0); }
  95% { opacity: var(--stars-op, 0); transform: translate(160px, 95px); }
  96%, 100% { opacity: 0; transform: translate(172px, 103px); }
}

/* ------------------------------------------------------------
   Ambient motion — pájaros de tinta en el cielo del hero (2026-07-10)
   Vuelan lento y en loop por la franja alta (sobre el título, en el
   cielo salvia). Trazo de tinta, mismo registro que la ilustración.
   Aleteo sutil + bob vertical para que no se sientan "pegados". Detrás
   del contenido (z-index bajo). Congelados en reduced-motion.
   ------------------------------------------------------------ */
.hero__sky {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  z-index: 1;
}

.ink-bird {
  position: absolute;
  left: 0;
  width: clamp(1.4rem, 2.2vw, 2rem);
  will-change: transform;
}

.ink-bird svg {
  display: block;
  width: 100%;
  height: auto;
  overflow: visible;
}

.ink-bird path {
  fill: none;
  stroke: color-mix(in srgb, var(--ink) 78%, transparent);
  stroke-width: 1.5;
  stroke-linecap: round;
  /* aleteo: el trazo "late" comprimiéndose en vertical, como alas */
  transform-origin: 50% 60%;
  animation: bird-flap 1.1s ease-in-out infinite;
}

/* 3 pájaros: alturas, tamaños, velocidades y delays distintos → bandada
   suelta, nunca en lockstep. El más chico va más alto, lento y tenue
   (profundidad). Cruzan de izquierda a derecha y reaparecen. */
/* Tops en la franja ALTA del cielo (≤11%) + bob vertical chico → nunca
   bajan a la zona del título (que arranca ~19% del alto). */
.ink-bird--1 {
  top: 8%;
  transform: scale(1);
  animation: bird-cross-1 34s linear infinite;
}
.ink-bird--2 {
  top: 11%;
  transform: scale(0.72);
  opacity: 0.7;
  animation: bird-cross-2 46s linear infinite;
  animation-delay: -8s;
}
.ink-bird--3 {
  top: 5%;
  transform: scale(0.55);
  opacity: 0.5;
  animation: bird-cross-3 58s linear infinite;
  animation-delay: -22s;
}

/* 2 pájaros más (2026-07-10, pedido de Jara) — separados de los 3
   originales en altura, delay y duración para que la bandada no se
   sienta repetida ni agrupada. */
.ink-bird--4 {
  top: 3%;
  transform: scale(0.85);
  opacity: 0.85;
  animation: bird-cross-4 40s linear infinite;
  animation-delay: -31s;
}
.ink-bird--5 {
  top: 10%;
  transform: scale(0.45);
  opacity: 0.4;
  animation: bird-cross-5 64s linear infinite;
  animation-delay: -12s;
}

@keyframes bird-cross-1 {
  0%   { transform: translate(-8vw, 0) scale(1); }
  45%  { transform: translate(46vw, -10px) scale(1); }
  100% { transform: translate(112vw, 6px) scale(1); }
}
@keyframes bird-cross-2 {
  0%   { transform: translate(-8vw, 0) scale(0.72); }
  50%  { transform: translate(48vw, 9px) scale(0.72); }
  100% { transform: translate(112vw, -5px) scale(0.72); }
}
@keyframes bird-cross-3 {
  0%   { transform: translate(-8vw, 0) scale(0.55); }
  55%  { transform: translate(52vw, -7px) scale(0.55); }
  100% { transform: translate(112vw, 3px) scale(0.55); }
}
@keyframes bird-cross-4 {
  0%   { transform: translate(-8vw, 0) scale(0.85); }
  48%  { transform: translate(47vw, 8px) scale(0.85); }
  100% { transform: translate(112vw, -6px) scale(0.85); }
}
@keyframes bird-cross-5 {
  0%   { transform: translate(-8vw, 0) scale(0.45); }
  52%  { transform: translate(50vw, -9px) scale(0.45); }
  100% { transform: translate(112vw, 5px) scale(0.45); }
}
@keyframes bird-flap {
  0%, 100% { transform: scaleY(1); }
  50%      { transform: scaleY(0.55); }
}

@media (prefers-reduced-motion: reduce) {
  .ink-bird,
  .ink-bird path {
    animation: none;
  }
  /* estáticos, distribuidos en el cielo como un dibujo fijo */
  .ink-bird--1 { transform: translate(24vw, 0) scale(1); }
  .ink-bird--2 { transform: translate(60vw, 8px) scale(0.72); }
  .ink-bird--3 { transform: translate(78vw, -6px) scale(0.55); }
  .ink-bird--4 { transform: translate(10vw, 4px) scale(0.85); }
  .ink-bird--5 { transform: translate(90vw, -3px) scale(0.45); }
}

/* ------------------------------------------------------------
   Hero
   ------------------------------------------------------------ */
.hero {
  min-height: 100svh;
  display: grid;
  place-items: center;
  padding: clamp(2rem, 5.5vw, 5.5rem) var(--hero-gutter);
  overflow: hidden;
  /* Hero inmersivo (Route A): full-bleed + push-in. Factores leídos por
     script.js desde estas vars.
     2026-07-10 — Jara: el parallax diferencial (back/mid/fore a
     velocidades distintas) se veía "duplicado y barrido". Causa raíz
     confirmada con Playwright: l1_back/l2_mid/l3_fore fueron pintadas
     como UNA escena cohesiva (trazos de tinta traslapados entre capas),
     no como siluetas aisladas — separarlas a velocidades distintas
     desalinea esos trazos y crea un fantasma duplicado. No es de
     calibración, es del arte: NINGÚN factor >0 lo arregla. Parallax
     diferencial DESACTIVADO (las 3 capas viajan juntas); se conserva
     solo el push-in unificado (--pf-zoom), que sí funciona porque
     escala el conjunto sin mover una capa respecto a otra. */
  --pf-back: 0;
  --pf-mid: 0;
  --pf-fore: 0;
  /* 2026-07-12 (Jara): uniformidad EXACTA hero↔Gracias. El overscan (1.1)
     era un crop del 10% en reposo y el push-in (0.11) crecía a +22% en
     scroll — hacían la ilustración del hero más grande que la de Gracias.
     Sin translate que amortiguar, ambos sobran: contain 1.0 = idéntica. */
  --pf-zoom: 0;
  --pf-overscan: 1;
}

.hero__inner {
  position: relative;
  z-index: 2;
  width: min(100%, 74rem);
  min-width: 0;
  display: grid;
  grid-template-columns: minmax(0, 1.08fr) minmax(18rem, 0.92fr);
  grid-template-areas:
    "label details"
    "title title"
    "scene scene"
    "index index"
    "countdown countdown"
    "cta cta";
  align-items: end;
  column-gap: clamp(2rem, 5vw, 6.5rem);
  row-gap: clamp(0.9rem, 2.2vw, 2rem);
  animation: hero-in 760ms ease-out both;
}

.hero__inner > * {
  min-width: 0;
}

.hero__label {
  grid-area: label;
  align-self: start;
  margin: 0;
  font-family: "Cormorant", Georgia, serif;
  font-size: clamp(1.45rem, 2.1vw, 2.45rem);
  font-style: italic;
  line-height: 1;
}

.hero__title {
  grid-area: title;
  max-width: 100%;
  min-width: 0;
  margin: 0;
  font-family: "Cormorant", Georgia, serif;
  /* 2026-07-10 GPT-5.5 pass: el display type no debe crecer con el
     monitor hasta comerse el hero. En pantallas grandes se vuelve una
     firma editorial discreta para dejar que la ilustración respire. */
  font-size: clamp(4.9rem, 8.4vw, 9rem);
  font-weight: 400;
  letter-spacing: 0;
  line-height: 0.84;
}

.hero__title span {
  display: block;
}

.hero__title span + span {
  margin-top: clamp(0.18em, 2vw, 0.28em);
  padding-left: clamp(0.1em, 3vw, 0.24em);
}

.hero__title em {
  font-style: italic;
}

.hero__details {
  grid-area: details;
  justify-self: end;
  align-self: start;
  margin-top: 0.15rem;
  font-variant-caps: small-caps;
  letter-spacing: 0.04em;
  text-align: right;
  color: var(--forest);
}

.hero__details p {
  margin: 0;
  font-size: clamp(1.18rem, 1.7vw, 1.72rem);
  line-height: 1.12;
}

.hero__details p + p {
  margin-top: 0.22rem;
  letter-spacing: 0.01em;
}

.hero__scene {
  grid-area: scene;
  position: relative;
  /* Route A: full-bleed — la ilustración es el ENTORNO, no una foto en
     caja. Rompe el padding del hero a lo ancho del viewport; ahí el
     push-in y la profundidad se sienten inmersivos (un panel acotado los
     aplanaba). Mobile-first: esta aspect-ratio está calibrada para
     pantallas angostas (Jara: "se ve muy bien en mobile") — con
     viewports anchos, 100vw a esta proporción da ~760px de alto (84%
     del viewport, hero total ~1.8x la altura de pantalla) y abruma. El
     tope de altura para desktop vive en el media query de abajo. */
  /* Fix ancho/crop en desktop real (2026-07-10, reporte Jara con
     screenshots de Opera): 100vw en CSS incluye el ancho del scrollbar
     clásico (no-overlay) del navegador — mide MÁS que el viewport visual
     real (window.innerWidth). El truco de full-bleed con margin-inline
     negativo entonces desalinea la escena del resto del contenido y la
     recorta contra el borde. Playwright headless no lo reproduce (usa
     scrollbar overlay, sin espacio reservado) — por eso no salió en mis
     verificaciones previas. Fix: usar --true-vw, medido en JS con
     window.innerWidth real (initTrueViewport() en script.js, on load +
     resize), en vez de la unidad 100vw. */
  /* 2026-07-12 (Jara): hero EXACTAMENTE del tamaño de la ilustración de
     Gracias (night-hills) — misma fórmula de ancho en cada breakpoint. */
  width: min(92vw, 74rem);
  max-width: none;
  margin-inline: auto;
  /* H3 (audit 2026-07-10): proporción NATIVA de la ilustración (1744x981).
     Antes 1744/920 (más ancha) + object-fit:cover recortaba el follaje
     arriba/abajo en móvil. Con la nativa, el box calza exacto con la
     imagen → cero crop en móvil, se ve completa. El tope de altura desktop
     (media query abajo) usa cover a propósito para el band recortado. */
  aspect-ratio: 1744 / 981;
  margin-block: clamp(0.4rem, 2vw, 1.2rem) 0;
  overflow: hidden;
}

@media (min-width: 640px) {
  .hero__scene {
    /* 2026-07-10 (Jara): en desktop la ilustración YA NO es full-bleed. El
       band full-width + cover se estiraba y perdía la escena mientras más
       ancho/horizontal era el monitor. Ahora se acota y se centra: proporción
       NATIVA (1744/981) + contain → se ve COMPLETA a cualquier ancho, flotando
       sobre el papel del hero como pieza editorial, no como franja estirada.
       El ancho tope mantiene la altura contenida para no "abrumar" el fold. */
    width: min(92vw, 74rem);
    max-width: none;
    margin-inline: auto;
    aspect-ratio: 1744 / 981;
  }

  .hero__layer {
    /* contain = nada de crop ni estiramiento; el PNG transparente se funde
       con el papel del hero. */
    object-fit: contain;
    object-position: 50% 50%;
  }
}

@media (min-width: 1200px) {
  .hero {
    padding-top: clamp(2.6rem, 4vw, 4.4rem);
    padding-bottom: clamp(2.6rem, 4vw, 4.8rem);
  }

  .hero__inner {
    width: min(100%, 74rem);
    row-gap: clamp(0.7rem, 1.35vw, 1.35rem);
  }

  .hero__label {
    font-size: clamp(1.35rem, 1.35vw, 1.85rem);
  }

  .hero__title {
    font-size: clamp(6rem, 6.2vw, 7.65rem);
    line-height: 0.88;
  }

  .hero__details p {
    font-size: clamp(1.08rem, 1.16vw, 1.38rem);
  }

  .hero__scene {
    /* 2026-07-10 v2 (Jara): la restricción de 46rem quedó demasiado angosta —
       el header (título/fecha, a 82rem) no alineaba con la ilustración y se
       veía desbalanceado. Ahora la escena se alinea a los márgenes del
       contenido del hero (misma columna) y crece "sobrada", sin volver al
       full-bleed estirado. */
    margin-top: clamp(0.25rem, 1vw, 0.8rem);
  }
}

@media (min-width: 1700px) {
  .hero__inner {
    width: min(100%, 74rem);
  }

  .hero__title {
    font-size: clamp(6.1rem, 5vw, 7rem);
  }

  .hero__scene {
    /* night-hills renderiza 74rem incluso aquí (su regla 80rem es dead code,
       la base 74rem la pisa por orden) — igualamos a lo que Gracias muestra. */
    width: min(92vw, 74rem);
    max-width: none;
  }

  /* Gracias iguala al hero también en pantallas anchas */
  .night-hills {
    width: min(92vw, 80rem);
  }
}

.hero__layer-wrap {
  position: absolute;
  inset: 0;
  /* colchón de escala: ~6% de margen para que ninguna capa deje hueco
     al trasladarse (D1) ni revele una "copia" del layer de abajo (D6) */
}

.hero__layer-wrap:nth-of-type(1) {
  transform: scale(var(--pf-overscan, 1.06)) translateY(var(--parallax-back, 0px)) scale(var(--hero-zoom, 1));
}

.hero__layer-wrap:nth-of-type(2) {
  transform: scale(var(--pf-overscan, 1.06)) translateY(var(--parallax-mid, 0px)) scale(var(--hero-zoom, 1));
}

.hero__layer-wrap:nth-of-type(3) {
  transform: scale(var(--pf-overscan, 1.06)) translateY(var(--parallax-fore, 0px)) scale(var(--hero-zoom, 1));
}

.hero__layer {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  /* 2026-07-10 (Jara): con la altura topada en desktop, cover recortaba
     parejo desde el centro (50% 50%) y se perdían los picos del cerro
     arriba. Sesgado hacia arriba para conservar la silueta de montaña;
     lo que se pierde es más terreno/base de árboles, que importa menos. */
  object-position: 50% 22%;
  filter: saturate(0.94) contrast(1.02);
  opacity: 0;
  transform: translateY(28px);
  animation: hero-layer-in 900ms cubic-bezier(0.19, 1, 0.22, 1) both;
}

.js-motion .hero__scene .hero__layer-wrap {
  will-change: transform;
}

.hero__layer--back {
  animation-delay: 120ms;
}

.hero__layer--mid {
  animation-delay: 320ms;
}

.hero__layer--fore {
  animation-delay: 520ms;
}

@keyframes hero-layer-in {
  from {
    opacity: 0;
    transform: translateY(28px);
  }

  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.hero__countdown {
  grid-area: countdown;
  display: flex;
  gap: clamp(0.9rem, 2vw, 1.6rem);
  margin-top: clamp(0.4rem, 2vw, 1.2rem);
}

.cd-unit {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  font-variant-caps: small-caps;
  font-size: 0.95rem;
  letter-spacing: 0.03em;
}

.cd-unit b {
  font-family: "Cormorant", Georgia, serif;
  font-size: clamp(1.6rem, 2.4vw, 2.1rem);
  font-weight: 500;
  line-height: 1;
}

.hero__index {
  grid-area: index;
  width: 100%;
  min-width: 0;
  margin-top: clamp(0.3rem, 1.5vw, 1rem);
}

.hero__index ol {
  list-style: none;
  margin: 0;
  padding: 0;
  width: 100%;
  min-width: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.3em 1.4em;
}

.hero__index a {
  font-family: "Cormorant", Georgia, serif;
  font-style: italic;
  font-size: clamp(1.05rem, 1.4vw, 1.35rem);
  text-decoration: none;
  border-bottom: 1px solid transparent;
  padding-bottom: 0.1em;
  transition: color 180ms ease, border-color 180ms ease;
}

.hero__index a:hover,
.hero__index a:focus-visible {
  color: var(--berry);
  border-color: var(--berry);
}

.hero__cta {
  grid-area: cta;
  width: fit-content;
  min-height: 3.35rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-top: clamp(0.5rem, 2.5vw, 2rem);
  padding: 0.8rem 1.55rem 0.9rem;
  border: 1px solid rgba(48, 80, 64, 0.72);
  border-color: color-mix(in srgb, var(--forest) 72%, transparent);
  border-radius: 999px;
  background: transparent;
  color: var(--forest);
  font-family: "EB Garamond", Georgia, serif;
  font-size: clamp(1.05rem, 1.25vw, 1.22rem);
  font-variant-caps: small-caps;
  letter-spacing: 0.055em;
  line-height: 1;
  text-decoration: none;
  transition:
    background-color 180ms ease,
    border-color 180ms ease,
    color 180ms ease,
    transform 180ms ease;
}

.hero__cta:hover {
  border-color: var(--berry);
  background: rgba(200, 80, 60, 0.1);
  color: var(--forest);
  transform: translateY(-1px);
}

.hero__cta:focus-visible,
a:focus-visible,
button:focus-visible,
input:focus-visible {
  outline: 2px solid var(--berry);
  outline-offset: 4px;
}

@keyframes hero-in {
  from {
    opacity: 0;
    transform: translateY(12px);
  }

  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* ------------------------------------------------------------
   Section shell + fixed day/dusk/night/dawn backgrounds
   ------------------------------------------------------------ */
.section {
  padding: clamp(3.5rem, 9vw, 7rem) var(--gutter);
}

.section__inner {
  position: relative;
  z-index: 2;
  width: min(100%, 72rem);
  margin-inline: auto;
}

.section__head {
  max-width: 40rem;
  margin-bottom: clamp(2rem, 5vw, 3.5rem);
}

.section h2 {
  margin: 0.2em 0 0.5em;
  font-family: "Cormorant", Georgia, serif;
  font-weight: 400;
  font-size: clamp(2.6rem, 5.5vw, 4.2rem);
  line-height: 0.98;
}

.section__lead {
  margin: 0;
  font-size: clamp(1.08rem, 1.4vw, 1.28rem);
  line-height: 1.55;
  max-width: 34rem;
}

.section__lead--lg {
  max-width: 44rem;
  font-size: clamp(1.2rem, 1.7vw, 1.5rem);
}

/* Fallback estático (prefers-reduced-motion / sin JS) — audit Fable
   #3 (2026-07-10): recalibrado MUESTREANDO gradeAt() del arco live en el
   borde real de cada sección (script /tmp/seamfix.cjs, gradeAt expuesto
   en window), no a ojo — así cada fin de gradiente ≈ el inicio del
   siguiente y no hay costura dura ni desalineación de a qué hora llega
   cada tono (el arco vivo se recalibró hoy con noche más tardía). */
.section--day {
  background: linear-gradient(180deg, #c6c3ac 0%, #c3c1a2 100%); /* RSVP — mediodía cayendo */
}

/* Ubicación (C-03, orden nuevo) — sage cálido, tarde temprana */
.section--day-loc {
  background: linear-gradient(180deg, #c3c1a2 0%, #b6b48c 100%);
}

.section--day-2 {
  background: linear-gradient(180deg, #4d6a7a 0%, #3a566d 100%); /* Regalos — AHORA anochece (azul), va antes de Gracias */
  color: var(--paper);
}

.section--day-2 .lbl,
.section--day-2 h2 {
  color: var(--paper);
}

.section--day-3 {
  background: linear-gradient(180deg, #b6b48c 0%, #a9a878 100%); /* Hoteles — caqui → olivo seco (tarde) */
}

.section--dusk {
  background: linear-gradient(180deg, #9c9862 0%, #56808a 100%); /* Itinerario — olivo dorado → crepúsculo azul-gris */
  color: var(--ink);
}

.section--evening {
  background: linear-gradient(180deg, #a9a878 0%, #9c9862 100%); /* Funky Formal — AHORA hora dorada (claro), texto oscuro */
  color: var(--ink);
}

.section--evening .lbl,
.section--evening h2 {
  color: var(--ink);
}

.section--night {
  background: linear-gradient(180deg, #3d5364 0%, #21344e 100%); /* Gracias — llega tarde, azul profundizando */
  color: var(--paper);
  position: relative;
  overflow: hidden;
}

/* Cerro del Tepozteco de noche, iluminado por la luna (D4/TAREA D) —
   reutiliza l1_back.png como silueta oscura + rim-light frío arriba.
   Vive dentro de #gracias (z-index bajo, detrás de .section__inner). */
.night-hills {
  /* 2026-07-10 v2 (Jara): una sola columna, cierra la sección DEBAJO de la
     firma. Usa la ILUSTRACIÓN COMPLETA (montañas + follaje), tintada de
     noche — l1_back sola recortaba el follaje inferior "desde la mitad".
     Se ve COMPLETA (contain, nunca crop) y GRANDE: rompe el ancho de la
     columna de texto y se alinea a los márgenes de la página (sobrado),
     no full-bleed. La luna es el ORBE del scroll (#celestial), que "aterriza"
     sobre los picos aquí — NO hay luna extra de CSS. */
  position: relative;
  /* mismo tamaño que la ilustración del hero (Jara): hero__scene = 74rem
     desktop / 80rem en pantallas anchas. */
  width: min(92vw, 74rem);
  margin-left: 50%;
  transform: translateX(-50%) translateZ(0);
  aspect-ratio: 1744 / 981;
  /* 2026-07-12 (Jara): la firma sobre la luna se quitó (duplicaba el
     footer) — este margin ahora abre el aire entre la carta y la
     ilustración directamente. */
  margin-top: clamp(3rem, 7vw, 6rem);
  margin-bottom: 0;
  background: url(./assets/ilustracion-boda-luciayjoseluis.png) center bottom / contain no-repeat;
  /* tinte nocturno: baja luz, desatura y enfría hacia el índigo de la sección */
  filter: brightness(0.62) saturate(0.55) contrast(1.05) hue-rotate(-8deg);
  opacity: 0.95;
  z-index: 1;
  pointer-events: none;
}

.section--night .lbl,
.section--night h2 {
  color: var(--paper);
}

.section--dawn {
  background: linear-gradient(180deg, #21344e 0%, #2b4056 100%); /* Fotos — sale de la noche, aclara a índigo suave, NUNCA crema */
  color: var(--paper);
}

.section--dawn .lbl,
.section--dawn h2 {
  color: var(--paper);
}

/* ------------------------------------------------------------
   RSVP
   ------------------------------------------------------------ */
.section__inner--rsvp {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(20rem, 0.92fr);
  gap: clamp(2rem, 5vw, 5rem);
  /* audit Fable #5: align-items:start dejaba la columna izquierda corta
     con un hueco vacío bajo el sprig cuando el form (derecha) era más
     alto. Stretch + el sprig anclado abajo (ver .section__head aquí
     mismo) balancea ambas columnas sin forzar contenido nuevo. */
  align-items: stretch;
}

.section__inner--rsvp .section__head {
  display: flex;
  flex-direction: column;
  margin-bottom: 0;
}

.section__inner--rsvp .section__head .spot--ramita {
  margin-top: auto;
  padding-top: 1.5rem;
}

.deadline {
  margin-top: 1.4rem;
  font-size: 1.05rem;
}

.deadline .meta {
  display: block;
  font-size: 0.85rem;
  /* audit Fable #1: "Fecha límite" medía 3.48:1 — sube a AA */
  opacity: 0.92;
}

.spot {
  display: inline-flex;
}

.spot--ramita {
  margin-top: 2rem;
  width: 3.2rem;
}

.spot svg {
  width: 100%;
  height: auto;
  display: block;
}

.rsvp-card {
  background: var(--paper);
  /* Contorno orgánico hand-drawn (2026-07-10, Jara: las cards se veían
     genéricas/wordpress). border-radius asimétrico por esquina → no es un
     rectángulo ejecutivo, se siente dibujado a mano, on-vibe con la tinta
     de Polly. Borde un pelo más presente y cálido (tinta, no gris). */
  border: 1.5px solid color-mix(in srgb, var(--forest) 40%, transparent);
  border-radius: 1.6rem 0.5rem 1.5rem 0.6rem / 0.6rem 1.5rem 0.5rem 1.6rem;
  padding: clamp(1.6rem, 3vw, 2.6rem);
  display: flex;
  flex-direction: column;
  gap: 1.3rem;
}

.field {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}

.field label {
  font-variant-caps: small-caps;
  letter-spacing: 0.03em;
  font-size: 0.95rem;
}

.field input {
  border: none;
  border-bottom: 1px solid color-mix(in srgb, var(--forest) 55%, transparent);
  background: transparent;
  padding: 0.5rem 0.1rem;
  font-family: "EB Garamond", Georgia, serif;
  font-size: 1.05rem;
  color: var(--ink);
  transition: border-color 180ms ease;
}

.field input:focus {
  border-color: var(--berry);
  outline: none;
}

.field-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.1rem;
}

.asiste {
  border: none;
  margin: 0;
  padding: 0;
  display: flex;
  gap: 1.6rem;
}

.asiste legend {
  font-variant-caps: small-caps;
  letter-spacing: 0.03em;
  margin-bottom: 0.4rem;
  padding: 0;
}

.radio {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.98rem;
}

.radio input[type="radio"] {
  /* audit Fable #4: sin accent-color el radio checked sale azul default
     del browser, único pixel fuera de paleta en toda la página */
  accent-color: var(--forest);
}

.add-guest {
  align-self: flex-start;
  background: none;
  border: none;
  padding: 0;
  color: var(--forest);
  font-family: "EB Garamond", Georgia, serif;
  font-style: italic;
  font-size: 1rem;
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
  transition: color 180ms ease;
}

.add-guest:hover {
  color: var(--berry);
}

.add-guest:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

.extra-guests {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.guest-row {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  padding-top: 0.6rem;
  border-top: 1px dashed color-mix(in srgb, var(--forest) 35%, transparent);
}

.guest-hint {
  margin: 0;
  font-size: 0.85rem;
  font-style: italic;
  opacity: 0.75;
}

.btn-primary {
  align-self: flex-start;
  /* 2026-07-12 (Jara): antes verde sólido → contrastaba demasiado. Ahora
     outline que hereda el color de la sección (combina con cualquier fondo)
     y se rellena con el oro del arco al hover. */
  border: 1.5px solid color-mix(in srgb, currentColor 45%, transparent);
  border-radius: 999px;
  background: transparent;
  color: inherit;
  padding: 0.75rem 1.7rem;
  font-family: "EB Garamond", Georgia, serif;
  font-size: 1.05rem;
  font-variant-caps: small-caps;
  letter-spacing: 0.05em;
  cursor: pointer;
  transition: background-color 180ms ease, border-color 180ms ease, transform 180ms ease;
}

.btn-primary:hover {
  background: var(--arc-gold);
  border-color: var(--arc-gold);
  color: var(--ink);
  transform: translateY(-1px);
}

.rsvp-status {
  margin: 0;
  min-height: 1.2em;
  font-style: italic;
}

.rsvp-status[data-state="ok"] {
  color: var(--berry);
}

.rsvp-status[data-state="err"] {
  color: #a33;
}

/* ------------------------------------------------------------
   Regalos
   ------------------------------------------------------------ */
.gift-grid {
  list-style: none;
  margin: 0 0 clamp(2rem, 5vw, 3.5rem);
  padding: 0;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1.4rem;
}

.gift-card {
  padding: 1.1rem 1.1rem 1.4rem;
  /* Contorno orgánico hand-drawn (2026-07-10) — como las cards de RSVP/pago,
     mata el look de retícula de producto "template". Variación por paridad
     para que no se vean 7 rectángulos clonados. */
  border: 1px solid color-mix(in srgb, var(--forest) 18%, transparent);
  border-radius: 4px;
  transition: background-color 220ms ease, border-color 220ms ease, transform 220ms ease;
}

.gift-grid > .gift-card:last-child {
  /* audit Fable #5: 7 cards en grid de 3 dejaban a la VII huérfana con
     2/3 de fila vacía. "Sorpréndenos" es el catch-all — cierra la
     retícula a lo ancho en vez de verse como un accidente de layout. */
  grid-column: span 2;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.3fr);
  column-gap: 1.4rem;
  align-items: start;
}

.gift-grid > .gift-card:last-child .gift-card__slot {
  aspect-ratio: 1 / 1;
  margin-bottom: 0;
}

.gift-grid > .gift-card:last-child .gift-num,
.gift-grid > .gift-card:last-child h3,
.gift-grid > .gift-card:last-child p {
  grid-column: 2;
}

.gift-card:hover {
  background: color-mix(in srgb, var(--paper) 55%, transparent);
  border-color: var(--arc-gold);
  transform: translateY(-4px);
}

.gift-card:hover .gift-card__slot {
  border-color: var(--arc-gold);
}

.gift-card:hover .gift-card__wm {
  color: var(--arc-gold);
  opacity: 0.3;
}

/* Slot de regalo — ahora contiene un ícono de tinta custom (2026-07-10),
   swappable por la ilustración oficial de Polly. Panel tonal suave +
   contorno orgánico a juego con la card. */
.gift-card__slot {
  position: relative;
  aspect-ratio: 4 / 3;
  margin-bottom: 0.9rem;
  overflow: hidden;
  border: 1px solid color-mix(in srgb, var(--forest) 15%, transparent);
  border-radius: 4px;
  background: linear-gradient(155deg, color-mix(in srgb, var(--paper) 70%, transparent) 0%, color-mix(in srgb, var(--sage-2) 55%, transparent) 100%);
  display: grid;
  place-items: center;
  transition: border-color 220ms ease;
}

/* Ícono de tinta del regalo — mismo trazo que las aves del hero. */
.gift-ink {
  width: 46%;
  max-width: 5.5rem;
  height: auto;
  fill: none;
  stroke: color-mix(in srgb, var(--ink) 68%, transparent);
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  transition: stroke 220ms ease, transform 260ms ease;
}

.gift-card:hover .gift-ink {
  stroke: var(--arc-gold);
  transform: scale(1.07) rotate(-2deg);
}

/* Fotos stock (2026-07-10) dentro del slot — llenan el panel entero,
   ligero zoom al hover a juego con el resto de fotos del sitio
   (hoteles, etc). El fallback de íconos (.gift-ink) sigue arriba
   intacto, sin usarse mientras haya <img> en el slot. */
.gift-card__slot img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  filter: saturate(0.92) contrast(1.02);
  transition: transform 300ms ease;
}

.gift-card:hover .gift-card__slot img {
  transform: scale(1.06);
}

.gift-card__wm {
  font-family: "Cormorant", Georgia, serif;
  font-style: italic;
  font-size: clamp(3.4rem, 8vw, 5.2rem);
  line-height: 1;
  color: var(--forest);
  opacity: 0.16;
  transition: color 220ms ease, opacity 220ms ease;
}

.placeholder-tag--corner {
  position: absolute;
  left: 0.6rem;
  bottom: 0.6rem;
  padding: 0.15rem 0.55rem;
  font-size: 0.68rem;
  background: color-mix(in srgb, var(--paper) 75%, transparent);
}

.gift-num {
  display: block;
  margin-bottom: 0.4rem;
  font-family: "Cormorant", Georgia, serif;
  font-style: italic;
  font-size: 1.6rem;
  color: var(--berry);
}

.gift-card h3 {
  margin: 0.3em 0 0.3em;
  font-family: "Cormorant", Georgia, serif;
  font-weight: 500;
  font-size: 1.35rem;
}

.gift-card p {
  margin: 0;
  font-size: 0.98rem;
}

.pay-panel {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.6rem;
}

.pay-method {
  background: var(--paper);
  border: 1.5px solid color-mix(in srgb, var(--forest) 38%, transparent);
  /* contorno orgánico (ver .rsvp-card) */
  border-radius: 1.4rem 0.5rem 1.6rem 0.6rem / 0.6rem 1.5rem 0.5rem 1.4rem;
  padding: clamp(1.4rem, 2.5vw, 2rem);
}

/* La segunda tarjeta de pago con radios distintos → variación hand-drawn,
   que no se vean dos rectángulos idénticos clonados. */
.pay-method:nth-of-type(2) {
  border-radius: 0.6rem 1.5rem 0.5rem 1.6rem / 1.5rem 0.5rem 1.6rem 0.6rem;
}

.pay-data {
  margin: 0.8rem 0 0;
  display: grid;
  gap: 0.5rem;
}

.pay-data div {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  border-bottom: 1px dashed color-mix(in srgb, var(--forest) 25%, transparent);
  padding-bottom: 0.4rem;
}

.pay-data dt {
  opacity: 0.7;
}

.pay-data dd {
  margin: 0;
  text-align: right;
}

.pay-method--soon .placeholder-tag {
  margin-top: 0.8rem;
}

/* ------------------------------------------------------------
   Hoteles
   ------------------------------------------------------------ */
.hotel-grid {
  list-style: none;
  margin: 0 0 clamp(2rem, 5vw, 3rem);
  padding: 0;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1.4rem;
}

.hotel-card {
  padding: 1.1rem 1.1rem 1.4rem;
  border: 1px solid color-mix(in srgb, var(--forest) 18%, transparent);
  border-radius: 4px;
  transition: background-color 220ms ease, border-color 220ms ease, transform 220ms ease;
}

.hotel-card:hover {
  background: color-mix(in srgb, var(--paper) 55%, transparent);
  border-color: var(--arc-gold);
  transform: translateY(-4px);
}

.hotel-card__photo {
  aspect-ratio: 4 / 3;
  margin-bottom: 0.9rem;
  border-radius: 4px;
  overflow: hidden;
}

.hotel-card__photo img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 300ms ease;
}

.hotel-card__photo--right img {
  /* audit Fable #6: la foto de Posada del Tepozteco es un screenshot
     promocional con panel de texto naranja a la izquierda Y un botón
     "VISITAR SITIO WEB" horneado cerca del borde inferior. object-position
     desplazado hacia arriba-derecha + zoom mayor saca ambos del encuadre
     4:3, dejando solo la arquitectura/flores real. */
  object-position: 82% 12%;
  transform: scale(1.55);
  transform-origin: 82% 12%;
}

.hotel-card:hover .hotel-card__photo img {
  transform: scale(1.05);
}

.hotel-card:hover .hotel-card__photo--right img {
  transform: scale(1.6);
  transform-origin: 82% 12%;
}

.hotel-card h3 {
  margin: 0 0 0.3em;
  font-family: "Cormorant", Georgia, serif;
  font-weight: 500;
  font-size: 1.25rem;
}

.hotel-card__meta {
  margin: 0 0 0.5rem;
  font-size: 0.88rem;
  /* audit Fable #1: "10 min en coche · tel" medía 3.45:1 — sube a AA */
  opacity: 0.92;
}

.hotel-card a {
  font-size: 0.92rem;
  text-decoration: underline;
  text-underline-offset: 2px;
  transition: color 180ms ease;
}

.hotel-card a:hover {
  color: var(--arc-gold);
}

.hotel-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1.4rem 2rem;
  margin-bottom: clamp(1.8rem, 4vw, 2.6rem);
}

.hotel-loose {
  display: grid;
  gap: 0.3rem;
  font-size: 0.92rem;
}

.hotel-loose a {
  text-decoration: underline;
  transition: color 180ms ease;
}

.hotel-loose a:hover {
  color: var(--berry);
}

/* Mapa (D10) — colapsa el hueco gigante; bloque compacto con
   estética de mapa (pin --berry) en vez de rectángulo vacío. */
.hotel-map {
  position: relative;
  display: flex;
  align-items: center;
  gap: 1.4rem;
  max-height: 11rem;
  padding: 1.3rem 1.5rem;
  border: 1px solid color-mix(in srgb, var(--forest) 22%, transparent);
  border-radius: 4px;
  background:
    repeating-linear-gradient(115deg, color-mix(in srgb, var(--forest) 6%, transparent) 0 1px, transparent 1px 26px),
    linear-gradient(155deg, color-mix(in srgb, var(--paper) 65%, transparent) 0%, color-mix(in srgb, var(--sage-2) 45%, transparent) 100%);
}

.hotel-map__scene {
  flex: none;
  display: grid;
  place-items: center;
  width: 3.4rem;
}

.hotel-map__pin {
  width: 2.2rem;
  height: auto;
  filter: drop-shadow(0 3px 5px color-mix(in srgb, var(--ink) 25%, transparent));
}

.hotel-map__info {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
}

.hotel-map__place {
  margin: 0;
  font-family: "Cormorant", Georgia, serif;
  font-size: 1.3rem;
}

.hotel-map__info a {
  font-size: 0.92rem;
  text-decoration: underline;
  text-underline-offset: 2px;
  transition: color 180ms ease;
}

.hotel-map__info a:hover {
  color: var(--berry);
}

/* ------------------------------------------------------------
   Itinerario
   ------------------------------------------------------------ */
/* Layout 2 columnas en desktop (D8): timeline izquierda, mesa de
   Polly a la derecha. En móvil una sola columna, orden de DOM
   (mesa antes del timeline) sin cambios. */
.itinerario-layout {
  display: block;
}

/* C-06: layout centrado en una sola columna (Lucy). */
.itinerario-layout {
  max-width: 44rem;
  margin-inline: auto;
  text-align: center;
}

.itinerario-mesa {
  margin: 0 0 clamp(2.2rem, 5vw, 3.4rem);
}

.itinerario-mesa img {
  display: block;
  width: 100%;
  height: auto;
  max-width: 34rem;
  margin-inline: auto;
}

.timeline {
  list-style: none;
  margin: 0;
  padding: 0;
  /* C-06: sin franja lateral. */
}

.tl-item {
  position: relative;
  /* audit Fable #5: el padding-bottom + fireflies + aliens del After
     acumulaban ~150px de espacio muerto antes de Tornaboda. Compactado. */
  padding: 0.6rem 0.9rem clamp(1.1rem, 2.2vw, 1.8rem);
  border-radius: 4px;
  transition: background-color 220ms ease, transform 220ms ease;
}

.tl-day {
  display: block;
  font-size: 0.85rem;
  /* audit Fable #1: labels de día caían a 3.32:1 en el puente verde→azul móvil */
  opacity: 0.92;
  margin-bottom: 0.2rem;
}

.tl-time {
  display: inline-block;
  transition: color 220ms ease, font-weight 220ms ease;
}

.tl-content h3 {
  margin: 0.15em 0 0.2em;
  font-family: "Cormorant", Georgia, serif;
  font-weight: 500;
  font-size: 1.5rem;
}

.tl-content p {
  margin: 0;
}

/* Hover/focus dinámico en TODOS los items (D7) — el After deja de
   ser el único destacado; ahora cada item reacciona igual.
   Solo transform/opacity/color, sin reflow. */
.tl-item:hover,
.tl-item:focus-within,
.tl-item:focus-visible {
  background: color-mix(in srgb, currentColor 8%, transparent);
  transform: translateY(-2px);
  outline: none;
}

.tl-item:hover .tl-time,
.tl-item:focus-within .tl-time,
.tl-item:focus-visible .tl-time {
  color: var(--arc-gold);
  font-weight: 600;
}

.fireflies {
  position: relative;
  height: 1.5rem;
  margin-top: 0.4rem;
}

/* Luciérnagas (2026-07-10 v2, Jara: "muy pocas, pequeñitas, intermitente").
   Antes eran puntos rojos (--berry) con pulso continuo → se leían como
   manchas. Ahora: diminutas, glow cálido verde-oro, y encendido INTERMITENTE
   (mayormente apagadas, destellos breves y desfasados) → sólo 1-2 brillan a
   la vez, como luciérnagas reales. */
.fireflies span {
  position: absolute;
  /* 2026-07-11 (Jara: "imperceptibles") — más grandes y con más glow, y
     encendido más frecuente/prolongado (varias visibles a la vez), pero
     todavía con parpadeo intermitente. */
  width: 2px;
  height: 2px;
  border-radius: 50%;
  background: #eef4b4;
  box-shadow: 0 0 4px 1px rgba(214, 232, 128, 0.6), 0 0 2px 0.5px rgba(255, 255, 210, 0.8);
  opacity: 0;
  animation: firefly 5.5s ease-in-out infinite;
}

.fireflies span:nth-child(1) { left: 6%; top: 24%; animation-delay: 0.2s; animation-duration: 5.2s; }
.fireflies span:nth-child(2) { left: 20%; top: 66%; animation-delay: 1.4s; animation-duration: 6.1s; }
.fireflies span:nth-child(3) { left: 33%; top: 30%; animation-delay: 3.0s; animation-duration: 4.8s; }
.fireflies span:nth-child(4) { left: 47%; top: 70%; animation-delay: 0.7s; animation-duration: 6.6s; }
.fireflies span:nth-child(5) { left: 58%; top: 22%; animation-delay: 2.3s; animation-duration: 5.6s; }
.fireflies span:nth-child(6) { left: 69%; top: 58%; animation-delay: 4.0s; animation-duration: 5.0s; }
.fireflies span:nth-child(7) { left: 80%; top: 34%; animation-delay: 1.9s; animation-duration: 6.3s; }
.fireflies span:nth-child(8) { left: 91%; top: 62%; animation-delay: 3.4s; animation-duration: 4.9s; }

.fireflies--wide {
  height: 6rem;
  margin-bottom: 1rem;
}

@keyframes firefly {
  0%, 100% { opacity: 0; transform: scale(0.55); }
  8% { opacity: 1; transform: scale(1.2); }
  20% { opacity: 0.15; transform: scale(0.8); }
  30% { opacity: 0; transform: scale(0.6); }
  60% { opacity: 0; transform: scale(0.6); }
  70% { opacity: 0.95; transform: scale(1.1); }
  82% { opacity: 0.12; transform: scale(0.8); }
  90% { opacity: 0; transform: scale(0.55); }
}

/* Aliens 8-bit — easter egg del After, heredado de v1, re-tintado a la paleta de la boda */
#aliens-stage {
  min-height: 2.6rem;
  margin-top: 0.8rem;
}

.aliens-row {
  display: flex;
  gap: 1rem;
}

.alien {
  image-rendering: pixelated;
  /* colores originales v1 (funky): #D4247A / #1A7B7B / #E8A830 — comentado, swap trivial si Jara los pide */
}

.aliens-dance .alien {
  animation: alien-dance 0.6s steps(2) infinite;
  animation-delay: var(--alien-delay, 0s);
}

@keyframes alien-dance {
  0%, 100% { transform: translateY(0) scaleX(1); }
  50% { transform: translateY(-4px) scaleX(-1); }
}

/* ------------------------------------------------------------
   Funky Formal
   ------------------------------------------------------------ */
.funky-more {
  margin-bottom: clamp(1.8rem, 4vw, 2.6rem);
}

.funky-more p:not(.lbl) {
  margin-top: 1rem;
  max-width: 44rem;
  font-size: clamp(1.02rem, 1.3vw, 1.14rem);
  line-height: 1.65;
}

.spot-row {
  list-style: none;
  margin: 0 0 clamp(1.8rem, 4vw, 2.6rem);
  padding: 0;
  display: flex;
  gap: clamp(1.4rem, 4vw, 3rem);
}

.spot-row .spot {
  flex-direction: column;
  align-items: center;
  gap: 0.4rem;
  width: 4.2rem;
}

.spot-row svg {
  width: 3.4rem;
}

.spot-row .meta {
  font-size: 0.78rem;
}

.dress-rules {
  list-style: none;
  margin: 0 0 clamp(1.4rem, 3vw, 2rem);
  padding: 0;
  display: flex;
  gap: 1.6rem;
  flex-wrap: wrap;
  font-style: italic;
}

.funky-mood {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1rem;
}

.funky-slot {
  aspect-ratio: 3 / 4;
  border-radius: 4px;
  overflow: hidden;
}

.funky-slot img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 300ms ease;
}

.funky-slot:hover img {
  transform: scale(1.05);
}

/* ------------------------------------------------------------
   Gracias
   ------------------------------------------------------------ */
.section__inner--gracias {
  /* Una sola columna (2026-07-10, Jara): label → h2 → carta → firma →
     ilustración. Sin grid de 2 columnas. */
  max-width: 46rem;
  margin-inline: auto;
  position: relative;
  display: block;
}

.gracias-letter {
  margin-top: 1.6rem;
  display: grid;
  gap: 1rem;
  font-size: clamp(1.05rem, 1.4vw, 1.22rem);
  line-height: 1.65;
}

/* ------------------------------------------------------------
   Fotos
   ------------------------------------------------------------ */
.foto-grid {
  display: grid;
  grid-template-columns: 1.3fr 1fr 1fr;
  grid-template-areas:
    "a b c"
    "a d d"
    "e e e";
  gap: 1rem;
}

/* Marco editorial (D10) — textura papel + numeral, no dashed de
   "subir imagen". Fondo azul-noche de Fotos, así que el tono usa
   paper/dawn-blue en vez de forest. */
.foto-slot {
  position: relative;
  overflow: hidden;
  border: 1px solid color-mix(in srgb, var(--paper) 25%, transparent);
  border-radius: 4px;
  background: linear-gradient(155deg, color-mix(in srgb, var(--paper) 14%, transparent) 0%, color-mix(in srgb, var(--dawn-blue-2) 55%, transparent) 100%);
  display: grid;
  place-items: center;
  aspect-ratio: 4 / 5;
  transition: border-color 220ms ease, transform 220ms ease;
}

.foto-slot:hover {
  border-color: var(--berry);
  transform: translateY(-3px);
}

.foto-slot__wm {
  font-family: "Cormorant", Georgia, serif;
  font-style: italic;
  font-size: clamp(2.6rem, 6vw, 4.4rem);
  color: var(--paper);
  opacity: 0.22;
}

.foto-slot:hover .foto-slot__wm {
  color: var(--berry);
  opacity: 0.4;
}

.foto-slot .placeholder-tag--corner {
  background: color-mix(in srgb, var(--night-blue) 55%, transparent);
  border-color: color-mix(in srgb, var(--paper) 55%, transparent);
  color: var(--paper);
}

.foto-slot--a {
  grid-area: a;
  aspect-ratio: auto;
}

.foto-slot--b {
  grid-area: b;
}

.foto-slot--c {
  grid-area: c;
}

.foto-slot--d {
  grid-area: d;
  aspect-ratio: 16 / 9;
}

.foto-slot--e {
  grid-area: e;
  aspect-ratio: 21 / 9;
}

/* ------------------------------------------------------------
   Footer
   ------------------------------------------------------------ */
.footer {
  position: relative;
  z-index: 2;
  background: var(--dawn-blue-3);
  color: var(--paper);
  text-align: center;
  padding: clamp(2.5rem, 6vw, 4rem) var(--gutter);
}

.footer__names {
  margin: 0;
  font-family: "Cormorant", Georgia, serif;
  font-size: clamp(1.8rem, 3vw, 2.4rem);
}

.footer__date {
  margin: 0.3rem 0 0;
}

.footer__credit {
  margin: 1rem 0 0;
  font-size: 0.9rem;
  opacity: 0.8;
}

.footer__credit a {
  text-decoration: underline;
}

.footer__credit a:hover {
  color: var(--berry);
}

/* ------------------------------------------------------------
   Responsive
   ------------------------------------------------------------ */
@media (max-width: 860px) {
  body {
    background: var(--sage);
  }

  .hero {
    min-height: 100svh;
    place-items: start center;
    padding-block: clamp(2.5rem, 9vh, 4.7rem) clamp(1.2rem, 4vh, 2.5rem);
  }

  .hero__inner {
    width: 100%;
    min-height: calc(100svh - clamp(3.7rem, 13vh, 7.2rem));
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas:
      "label"
      "title"
      "details"
      "scene"
      "countdown"
      "index"
      "cta";
    align-content: space-between;
    row-gap: clamp(0.95rem, 2.7vh, 1.7rem);
  }

  .hero__label {
    justify-self: start;
    font-size: clamp(1.3rem, 7vw, 1.85rem);
  }

  .hero__title {
    width: min(100%, calc(100vw - (2 * var(--hero-gutter))));
    font-size: clamp(4.55rem, 19.2vw, 6.4rem);
    line-height: 0.78;
  }

  .hero__title span + span {
    /* 2026-07-12 (Jara): "José Luis" quedaba mucho más chico que "Lucía"
       con el 0.72em — mismo tamaño de fuente para ambas líneas. */
    margin-top: 0.2em;
    padding-left: 0;
  }

  .hero__details {
    justify-self: start;
    text-align: left;
  }

  .hero__details p {
    font-size: clamp(1.13rem, 5.8vw, 1.42rem);
  }

  .hero__scene {
    /* 2026-07-12 (Jara): centrar contra el viewport igual que night-hills
       (margin-inline:auto no centra cuando la escena 96vw > celda de grid en
       mobile → se corría a la derecha). Mismo mecanismo que Gracias. */
    width: min(96vw, 40rem);
    margin-left: 50%;
    transform: translateX(-50%);
    margin-block: clamp(0.2rem, 2vh, 0.8rem) 0;
  }

  .hero__cta {
    justify-self: start;
    margin-top: clamp(0.15rem, 1.5vh, 0.8rem);
  }

  .hero__index ol {
    gap: 0.3em 1em;
  }

  .section__inner--rsvp {
    grid-template-columns: minmax(0, 1fr);
  }

  .gift-grid {
    grid-template-columns: 1fr 1fr;
  }

  .pay-panel {
    grid-template-columns: minmax(0, 1fr);
  }

  .hotel-grid {
    grid-template-columns: 1fr 1fr;
  }

  .hotel-actions {
    flex-direction: column;
    align-items: flex-start;
  }

  .field-row {
    grid-template-columns: minmax(0, 1fr);
  }

  .funky-mood {
    grid-template-columns: repeat(2, 1fr);
  }

  .section__inner--gracias {
    max-width: 38rem;
    display: block;
  }

  .section__inner--gracias .night-hills {
    /* mobile: ocupa casi todo el ancho, centrado contra el viewport */
    width: min(96vw, 40rem);
    aspect-ratio: 1744 / 981;
    /* 2026-07-12 (Jara): punto medio entre el aire "generoso" original
       (clamp 6-10rem, pegaba la luna al texto) y el ajuste matemático
       exacto (clamp 2-3rem, quitaba todo el aire que a Jara le gustaba).
       Este valor deja aire visible arriba de la luna sin perder el
       centrado en el hueco texto↔montaña. */
    margin-top: clamp(4rem, 18vw, 6rem);
  }

  .section__inner--gracias .moon {
    /* 2026-07-12 (Jara): "más arriba, justo en el centro" — con el aire ya
       calibrado (margin-top arriba), el centro real texto↔montaña cae en
       el borde superior de la caja, no dentro de ella. */
    top: 0%;
  }

  .foto-grid {
    grid-template-columns: 1fr 1fr;
    grid-template-areas:
      "a a"
      "b c"
      "d d"
      "e e";
  }

  .foto-slot--a,
  .foto-slot--d,
  .foto-slot--e {
    aspect-ratio: 16 / 10;
  }
}

@media (max-width: 430px) {
  :root {
    --hero-gutter: clamp(1.1rem, 5.6vw, 1.35rem);
  }

  .hero__title {
    font-size: clamp(4.05rem, 19.2vw, 5.1rem);
  }

  /* 2026-07-11 (Jara): en celular, regalos y hoteles en 1 columna hacían un
     scroll interminable. Se mantienen 2 columnas (grid amigable) con gap y
     padding más ajustados para que quepan cómodas. */
  .gift-grid,
  .hotel-grid {
    /* minmax(0,1fr) para que las columnas queden EXACTAS aunque un URL/tel
       largo quiera empujar el ancho. */
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 0.8rem;
  }

  .gift-card,
  .hotel-card {
    padding: 0.7rem 0.7rem 1rem;
    min-width: 0;
  }

  .hotel-card a {
    overflow-wrap: anywhere;
  }

  /* Último card (Sorpréndenos) = celda normal en el grid de 2 columnas
     (con 8 regalos la retícula cierra en 4×2 sin huérfanos). Reset del
     layout wide de desktop (span 2). */
  .gift-grid > .gift-card:last-child {
    grid-column: auto;
    display: block;
  }
  .gift-grid > .gift-card:last-child .gift-card__slot {
    aspect-ratio: 1 / 1.05;
    margin-bottom: 0.9rem;
  }
  .gift-grid > .gift-card:last-child .gift-num,
  .gift-grid > .gift-card:last-child h3,
  .gift-grid > .gift-card:last-child p {
    grid-column: auto;
  }
}

@media (max-width: 360px) {
  .hero__title {
    font-size: 3.85rem;
  }

  .hero__cta {
    width: min(100%, calc(100vw - (2 * var(--hero-gutter))));
    padding-inline: 1rem;
  }
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    scroll-behavior: auto !important;
    transition-duration: 1ms !important;
  }

  .reveal {
    opacity: 1;
    transform: none;
  }

  .celestial,
  .stars {
    display: none !important;
  }

  .hero__layer-wrap:nth-of-type(1),
  .hero__layer-wrap:nth-of-type(2),
  .hero__layer-wrap:nth-of-type(3) {
    transform: none !important;
  }

  .js-motion .hero,
  .js-motion .section,
  .js-motion .footer {
    background: revert;
    color: revert;
  }
}


/* ------------------------------------------------------------
   Ubicación — mapa Quinta Estela (C-03, 2026-07-12)
   Thumbnail estático (screenshot real de Google Maps) envuelto en
   <a> que abre el mapa interactivo en tab nueva.
   ------------------------------------------------------------ */
.ubicacion-map {
  position: relative;
  display: block;
  max-width: 46rem;
  margin-inline: auto;
  border-radius: 6px;
  overflow: hidden;
  border: 1px solid color-mix(in srgb, var(--forest) 22%, transparent);
  box-shadow: 0 6px 24px rgba(24, 24, 12, 0.10);
  transition: transform 260ms ease, box-shadow 260ms ease;
}
.ubicacion-map img {
  display: block;
  width: 100%;
  height: auto;
}
.ubicacion-map__tag {
  position: absolute;
  left: 0.7rem;
  bottom: 0.7rem;
  padding: 0.3rem 0.7rem;
  font-size: 0.8rem;
  background: color-mix(in srgb, var(--paper) 90%, transparent);
  color: var(--forest);
  border-radius: 4px;
}
.ubicacion-map:hover {
  transform: translateY(-3px);
  box-shadow: 0 10px 30px rgba(24, 24, 12, 0.16);
}
.ubicacion-map:hover .ubicacion-map__tag {
  color: var(--arc-gold);
}


/* ------------------------------------------------------------
   After — foto de la pareja (C-07, 2026-07-12) — reemplaza los
   aliens 8-bit. Minimalista: contenida, esquinas suaves, viñeta
   que la funde con el azul noche de la sección.
   ------------------------------------------------------------ */
.after-photo {
  position: relative;
  margin: 1.1rem auto 0;
  max-width: 22rem;
  border-radius: 8px;
  overflow: hidden;
  box-shadow: 0 10px 34px rgba(0, 0, 0, 0.34);
}
.after-photo img {
  display: block;
  width: 100%;
  height: auto;
  filter: brightness(0.9) saturate(0.9);
}
.after-photo::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 8px;
  box-shadow: inset 0 0 2.6rem 0.5rem rgba(26, 39, 64, 0.55);
  pointer-events: none;
}


/* ------------------------------------------------------------
   Fix legibilidad tarjetas de pago (2026-07-12, Jara): las cards
   .pay-method tienen fondo crema fijo, pero heredaban el texto claro
   de Regalos (ahora azul noche) → invisible. Texto forzado a forest
   en ambos modos.
   ------------------------------------------------------------ */
.section .pay-method,
.section .pay-method .lbl,
.section .pay-method .lbl em,
.section .pay-method .meta,
.section .pay-method dt,
.section .pay-method dd,
.section .pay-method p {
  color: var(--forest);
}

/* Botón "Regístrate aquí" del After (C-07 v2) — hereda color de la
   sección (auto-contraste), hover con oro del arco. */
.after-cta {
  display: inline-block;
  margin-top: 1.1rem;
  padding: 0.7rem 1.7rem;
  border: 1.5px solid color-mix(in srgb, currentColor 55%, transparent);
  border-radius: 999px;
  font-family: "Cormorant", Georgia, serif;
  font-size: 1.1rem;
  letter-spacing: 0.02em;
  text-decoration: none;
  color: inherit;
  transition: background-color 200ms ease, border-color 200ms ease, color 200ms ease, transform 200ms ease;
}
.after-cta:hover,
.after-cta:focus-visible {
  background: var(--arc-gold);
  border-color: var(--arc-gold);
  color: var(--ink);
  transform: translateY(-2px);
  outline: none;
}


/* +2 estrellas fugaces (2026-07-12, Jara: "aumenta ligeramente") */
.shooting-star--6 { top: 11%; left: 68%; animation: shoot-1 9s ease-in infinite; animation-delay: 5.5s; }
.shooting-star--7 { top: 20%; left: 8%;  animation: shoot-3 8s ease-in infinite; animation-delay: 11s; }

/* Funky Formal: click para ver la referencia en grande (lightbox) */
.funky-slot { cursor: zoom-in; }
.lightbox {
  position: fixed; inset: 0; z-index: 60;
  display: grid; place-items: center; padding: 4vmin;
  background: rgba(16, 22, 36, 0.92);
  -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px);
}
.lightbox[hidden] { display: none; }
.lightbox__img {
  max-width: 94vw; max-height: 90vh; border-radius: 8px;
  box-shadow: 0 24px 70px rgba(0, 0, 0, 0.55);
}
.lightbox__close {
  position: absolute; top: 3vmin; right: 4vmin;
  width: 2.6rem; height: 2.6rem; border: none; border-radius: 50%;
  background: rgba(242, 240, 232, 0.16); color: var(--paper);
  font-size: 1.9rem; line-height: 1; cursor: pointer;
  transition: background 180ms ease;
}
.lightbox__close:hover { background: rgba(242, 240, 232, 0.32); }

/* Sorpréndenos = link a la sub-página de regalos */
.gift-card__link { display: contents; color: inherit; text-decoration: none; }
.gift-card--link { cursor: pointer; }
.gift-card--link:hover { border-color: var(--arc-gold); }
.gift-card--link p { color: var(--arc-gold); }

.regalos-cta { display: flex; justify-content: center; margin-top: clamp(1.6rem, 4vw, 2.6rem); }


/* Menos aire entre Mesa de regalos y Gracias (2026-07-12, Jara) */
#regalos { padding-bottom: clamp(2rem, 5vw, 3.6rem); }
#gracias { padding-top: clamp(1.4rem, 3.5vw, 3rem); }
/* Menos aire DESPUÉS de la luna, antes del footer (2026-07-12, Jara: la
   luna necesita moverse arriba en la caja para no pisar la montaña, y en
   pantallas anchas/bajas el bloque luna+footer no cabía completo en un
   viewport al hacer scroll hasta el fondo — la punta de la caja de la
   ilustración se cortaba). El padding-bottom base de .section (hasta 7rem
   en desktop) se recorta aquí para recuperar ese margen. */
#gracias { padding-bottom: clamp(1rem, 2.5vw, 2rem); }
#gracias .fireflies--wide { height: 3rem; margin-bottom: 0.2rem; }


/* +fugaces (2026-07-12, Jara: se vean también en la postal) — ciclos más
   cortos = más frecuentes, y algunas más abajo para cruzar cerca de la luna. */
.shooting-star--8  { top: 38%; left: 62%; animation: shoot-2 6s ease-in infinite; animation-delay: 2s; }
.shooting-star--9  { top: 44%; left: 22%; animation: shoot-1 6.5s ease-in infinite; animation-delay: 5s; }
.shooting-star--10 { top: 33%; left: 84%; animation: shoot-3 5.5s ease-in infinite; animation-delay: 8s; }
.shooting-star--11 { top: 52%; left: 48%; animation: shoot-2 7s ease-in infinite; animation-delay: 3.5s; }

/* Fugaces garantizadas de la postal (2026-07-12, Jara: "el momento más
   bello y mágico" no puede depender del azar de ciclos de 6-10s que llevan
   corriendo desde el load — si el usuario tarda en llegar a Gracias, puede
   caer en un hueco largo sin ver ninguna). Estas dos arrancan en pausa y
   solo se disparan (una sola vez, sin loop, casi de inmediato) cuando la
   luna entra en viewport — ver initPostalStars() en script.js. Las --8..11
   de arriba se dejan corriendo como ambiente aleatorio adicional. */
@keyframes shoot-postal-a {
  0% { opacity: 0; transform: translate(0, 0); }
  10% { opacity: var(--stars-op, 0.6); }
  38% { opacity: var(--stars-op, 0.6); transform: translate(150px, 84px); }
  50%, 100% { opacity: 0; transform: translate(164px, 92px); }
}
@keyframes shoot-postal-b {
  0% { opacity: 0; transform: translate(0, 0); }
  10% { opacity: var(--stars-op, 0.6); }
  38% { opacity: var(--stars-op, 0.6); transform: translate(-140px, 78px); }
  50%, 100% { opacity: 0; transform: translate(-153px, 86px); }
}
.shooting-star--postal-1,
.shooting-star--postal-2 {
  animation-play-state: paused;
  animation-timing-function: ease-in;
  animation-duration: 2.4s;
  animation-iteration-count: 1;
  animation-fill-mode: forwards;
}
.shooting-star--postal-1 { top: 41%; left: 60%; animation-name: shoot-postal-a; }
.shooting-star--postal-2 { top: 47%; left: 34%; animation-name: shoot-postal-b; animation-delay: 0.9s; }

#stars.postal-active .shooting-star--postal-1,
#stars.postal-active .shooting-star--postal-2 {
  animation-play-state: running;
}
