/* =====================================================================
   style.css — Estilos base de la invitación
   ---------------------------------------------------------------------
   Orden del archivo:
   0. Variables y reset
   1. Utilidades
   2. Pantalla de carga
   3. Video intro + transición
   4. Botón de música
   5. Fondos decorativos
   6. Hero
   7. Secciones genéricas / glassmorphism
   8. Cuenta regresiva
   9. Tarjetas de evento y botones
  10. Galería
  11. Cierre, globos, confeti, footer
   Los breakpoints viven en responsive.css
   ===================================================================== */

/* =====================================================================
   FUENTE "SHINE BUBBLE" (títulos, opcional)
   ---------------------------------------------------------------------
   Si el archivo assets/fonts/ShineBubble.woff2 existe, este @font-face lo
   registra y --font-titulos-shine queda disponible para usarla. Mientras
   no exista, el navegador ignora la regla y sigue con Fredoka (fallback):
   nada se rompe si el archivo todavía no está.
   Cómo activarla: 1) poner el archivo ahí con ese nombre exacto,
   2) en config.js, tipografias.titulos: "'Shine Bubble', 'Fredoka', cursive".
   ===================================================================== */
@font-face {
  font-family: 'Shine Bubble';
  /* Licencia de uso confirmada (hanscostudio.com). El nombre del archivo
     sigue diciendo "(Demo)" porque así se descargó, pero no afecta el uso. */
  src: url('../assets/fonts/Shine Bubble Decoration - (Demo) hanscostudio.com.ttf') format('truetype');
  font-weight: normal;
  font-style: normal;
  font-display: swap;
}

/* =====================================================================
   0. VARIABLES Y RESET
   ===================================================================== */
:root {
  /* Colores — los sobreescribe config.js al cargar */
  --azul-bebe: #8ecae6;
  --celeste: #bde0fe;
  --celeste-claro: #e7f5ff;
  --blanco: #ffffff;
  --amarillo-pastel: #ffe8a3;
  --gris-claro: #f2f4f7;
  --texto-oscuro: #2b3a4a;
  --texto-suave: #6b7c8f;
  --acento: #5aa9d6;
  --color-titulos: #5584AC;  /* color de la fuente Shine Bubble en los títulos */

  /* Tipografías — también configurables */
  --font-titulos: 'Fredoka', cursive;
  --font-display: 'Baloo 2', cursive;
  --font-texto: 'Poppins', sans-serif;

  /* Sombras suaves */
  --sombra-sm: 0 4px 14px rgba(43, 58, 74, .08);
  --sombra-md: 0 10px 30px rgba(43, 58, 74, .12);
  --sombra-lg: 0 20px 60px rgba(43, 58, 74, .18);
  --radio: 22px;

  /* Alturas seguras en móvil (barra de navegador de iOS/Android) */
  --vh100: 100svh;
}

* { box-sizing: border-box; }

html {
  scroll-behavior: smooth;
  color-scheme: light; /* la paleta pastel no se invierte en modo oscuro */
}

/* Formato celular es el primordial: bloquea el arrastre lateral nativo
   (el "rubber-band" de iOS/Android que corre la página al costado y la
   desarma un instante hasta que vuelve sola). Deja pasar el pinch-zoom
   y el swipe de la galería (Swiper la maneja con JS, no con este gesto
   nativo, así que no se ve afectada). */
html {
  overflow-x: hidden;
  touch-action: pan-y pinch-zoom;
}

body {
  margin: 0;
  font-family: var(--font-texto);
  color: var(--texto-oscuro);
  background: linear-gradient(180deg, var(--celeste-claro) 0%, var(--blanco) 45%, var(--gris-claro) 100%);
  overflow-x: hidden;
  touch-action: pan-y pinch-zoom;
  overscroll-behavior-x: none;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* Bloquea el scroll mientras corren el loader y el video */
body.no-scroll { overflow: hidden; height: 100%; }

img { max-width: 100%; display: block; }

h1, h2, h3 { font-family: var(--font-titulos); font-weight: 600; margin: 0; }

/* Respeto a quien pide menos movimiento (accesibilidad) */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
}

/* =====================================================================
   1. UTILIDADES
   ===================================================================== */
.hidden { display: none !important; }

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

/* Foco visible para navegación por teclado */
a:focus-visible, button:focus-visible {
  outline: 3px solid var(--acento);
  outline-offset: 3px;
  border-radius: 8px;
}

/* =====================================================================
   2. PANTALLA DE CARGA
   ===================================================================== */
.loader {
  position: fixed; inset: 0; z-index: 9000;
  display: flex; align-items: center; justify-content: center;
  overflow: hidden;
}

.loader__sky {
  position: absolute; inset: 0;
  background:
    radial-gradient(120% 80% at 50% 0%, #ffffff 0%, var(--celeste-claro) 35%, var(--celeste) 75%, var(--azul-bebe) 100%);
}

/* Brillo suave que respira detrás del nombre */
.loader__sky::after {
  content: ''; position: absolute; inset: 0;
  background: radial-gradient(50% 40% at 50% 45%, rgba(255, 255, 255, .85), transparent 70%);
  animation: respirar 3.2s ease-in-out infinite;
}

@keyframes respirar {
  0%, 100% { opacity: .55; transform: scale(1); }
  50%      { opacity: .9;  transform: scale(1.06); }
}

.loader__content {
  position: relative; z-index: 3; text-align: center; padding: 0 24px;
  animation: entradaCarga .9s cubic-bezier(.22, 1, .36, 1) both;
}

@keyframes entradaCarga {
  from { opacity: 0; transform: translateY(18px) scale(.96); filter: blur(6px); }
  to   { opacity: 1; transform: none; filter: blur(0); }
}

.loader__eyebrow {
  display: block; font-size: .78rem; letter-spacing: .32em;
  text-transform: uppercase; color: var(--texto-suave);
  /* Margen generoso: en iOS el borde blanco del título de abajo (12px)
     puede desbordar un poco más que en Chrome — este espacio evita que
     lo tape aunque eso pase. */
  margin-bottom: 18px;
}

.loader__name {
  font-family: var(--font-titulos);
  font-size: clamp(2.8rem, 14vw, 5rem);
  font-weight: 600; line-height: 1;
  color: var(--color-titulos);
  --stroke-w: 12px;
  /* Sin text-shadow: combinado con el borde grueso, en iOS Safari
     generaba un halo gigante en vez de un contorno prolijo. El borde
     solo ya da contraste de sobra. */
}

.loader__text {
  font-size: clamp(.95rem, 4vw, 1.15rem);
  color: var(--texto-suave); margin: 14px 0 26px;
}

.loader__bar {
  width: 130px; height: 4px; margin: 0 auto;
  background: rgba(255, 255, 255, .6); border-radius: 99px; overflow: hidden;
}
.loader__bar span {
  display: block; height: 100%; width: 40%; border-radius: 99px;
  background: linear-gradient(90deg, var(--acento), var(--amarillo-pastel));
  animation: barra 1.1s ease-in-out infinite;
}
@keyframes barra {
  0%   { transform: translateX(-110%); }
  100% { transform: translateX(280%); }
}

/* --- Botón de inicio (el toque que desbloquea video + música) --- */
.btn-start {
  display: inline-flex; align-items: center; gap: 10px;
  margin: 4px auto 0; padding: 15px 34px;
  border: 0; border-radius: 99px; cursor: pointer;
  font-family: var(--font-display); font-weight: 700; font-size: 1.05rem;
  color: #fff; background: linear-gradient(135deg, var(--acento), var(--azul-bebe));
  box-shadow: 0 14px 34px rgba(47, 128, 194, .38);
  animation: aparecerBoton .55s cubic-bezier(.22, 1, .36, 1) both, latidoBoton 2.2s ease-in-out .6s infinite;
  transition: transform .2s ease;
}
.btn-start:active { transform: scale(.96); }

@keyframes aparecerBoton {
  from { opacity: 0; transform: translateY(14px) scale(.9); }
  to   { opacity: 1; transform: none; }
}
@keyframes latidoBoton {
  0%, 100% { box-shadow: 0 14px 34px rgba(47, 128, 194, .38); transform: scale(1); }
  50%      { box-shadow: 0 18px 44px rgba(47, 128, 194, .55); transform: scale(1.045); }
}

.loader__nota {
  margin: 12px 0 0; font-size: .8rem; color: var(--texto-suave);
  animation: aparecerBoton .6s ease .25s both;
}

/* --- Estrellas (las genera animations.js) --- */
.loader__stars, .bg-decor__stars { position: absolute; inset: 0; pointer-events: none; }

.star {
  position: absolute; border-radius: 50%;
  background: #fff;
  box-shadow: 0 0 8px rgba(255, 255, 255, .9), 0 0 16px rgba(255, 236, 170, .6);
  animation: brillar var(--dur, 3s) ease-in-out infinite;
  animation-delay: var(--delay, 0s);
  opacity: 0;
}
@keyframes brillar {
  0%, 100% { opacity: 0;   transform: scale(.6); }
  50%      { opacity: .95; transform: scale(1); }
}

/* --- Globos flotantes del loader --- */
.loader__balloons { position: absolute; inset: 0; pointer-events: none; }

.balloon {
  position: absolute; bottom: -140px;
  width: var(--w, 44px); height: calc(var(--w, 44px) * 1.22);
  background: var(--c, var(--celeste));
  border-radius: 50% 50% 48% 48% / 55% 55% 45% 45%;
  box-shadow: inset -6px -8px 14px rgba(0, 0, 0, .08), 0 8px 18px rgba(43, 58, 74, .12);
  animation: flotar var(--dur, 9s) linear infinite;
  animation-delay: var(--delay, 0s);
  opacity: .9;
}
/* Hilito del globo */
.balloon::after {
  content: ''; position: absolute; top: 100%; left: 50%;
  width: 1px; height: 26px; background: rgba(43, 58, 74, .25);
  transform: translateX(-50%);
}
@keyframes flotar {
  0%   { transform: translateY(0) translateX(0) rotate(-4deg); }
  50%  { transform: translateY(-55vh) translateX(14px) rotate(4deg); }
  100% { transform: translateY(-115vh) translateX(-10px) rotate(-3deg); }
}

/* =====================================================================
   3. VIDEO INTRO + TRANSICIÓN
   ===================================================================== */
/* El video es horizontal y la pantalla del celular es vertical: en vez de
   recortarlo o dejar barras negras, se enmarca en blanco arriba y abajo.
   Así parece parte de la invitación y no un video "pegado". */
.intro {
  position: fixed; inset: 0; z-index: 8500;
  background: linear-gradient(180deg, var(--blanco) 0%, var(--celeste-claro) 55%, var(--blanco) 100%);
  display: flex; align-items: center; justify-content: center;
}

/* Resplandor de color del propio cuadro del video, muy suave, detrás del
   blanco: da vida a las franjas sin ensuciarlas. */
.intro__backdrop {
  position: absolute; inset: -10%;
  background-size: cover; background-position: center;
  filter: blur(70px) brightness(1.7) saturate(140%);
  opacity: .2;
  transform: scale(1.15);
}

/* El alto/ancho quedan libres (solo con topes) para que la caja del <video>
   mida exactamente lo que ocupa la imagen. Así el borde redondeado y la
   sombra caen sobre el video y no sobre la pantalla entera. */
.intro__video {
  position: relative; z-index: 1;
  width: auto; height: auto;
  max-width: 100%; max-height: 100%;
  object-fit: contain;
  border-radius: 18px;
  box-shadow: 0 24px 60px rgba(38, 57, 75, .22);
}

/* Viñeta clara: cierra los bordes de las franjas blancas */
.intro__vignette {
  position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(120% 90% at 50% 50%, transparent 45%, rgba(255, 255, 255, .85) 100%);
}

/* Rótulos de las franjas blancas.
   Ocultos por defecto: solo aparecen cuando de verdad sobra espacio
   arriba y abajo (celular vertical), ver responsive.css */
.intro__frame {
  position: absolute; left: 0; right: 0; z-index: 2;
  display: none; flex-direction: column; align-items: center; gap: 4px;
  padding: 0 24px; text-align: center;
  animation: aparecerSkip .8s ease .4s both;
}
.intro__frame--top    { top: calc(26px + env(safe-area-inset-top, 0px)); }
.intro__frame--bottom { bottom: calc(38px + env(safe-area-inset-bottom, 0px)); }

.intro__frame-name {
  font-family: var(--font-titulos); font-weight: 600;
  font-size: clamp(1.5rem, 7vw, 2.1rem); line-height: 1.1;
  color: var(--color-titulos);
  --stroke-w: 6.6px;
}
.intro__frame-sub {
  font-family: var(--font-display); font-weight: 700;
  font-size: 1.05rem; color: var(--acento);
}
.intro__frame-date { font-size: .82rem; color: var(--texto-suave); }

/* Nariz roja en versión chica para el rótulo superior */
.nose--mini { width: 18px; height: 18px; margin-bottom: 6px; }

/* Progreso del video (20 s) */
.intro__progress {
  position: absolute; left: 0; right: 0; z-index: 2;
  bottom: calc(env(safe-area-inset-bottom, 0px));
  height: 3px; background: rgba(47, 128, 194, .12);
}
.intro__progress span {
  display: block; height: 100%; width: 0;
  background: var(--grad-arcoiris);
  transition: width .25s linear;
}

.intro__skip {
  position: absolute; right: 16px; z-index: 3;
  bottom: calc(20px + env(safe-area-inset-bottom, 0px));
  padding: 10px 18px; border-radius: 99px;
  font-family: var(--font-texto); font-size: .85rem; color: var(--acento);
  background: rgba(255, 255, 255, .82);
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
  border: 1px solid rgba(47, 128, 194, .25);
  box-shadow: var(--sombra-sm);
  cursor: pointer; transition: background .25s ease, transform .25s ease;
  animation: aparecerSkip .5s ease both;
}
.intro__skip:hover { background: #fff; transform: translateY(-2px); }
@keyframes aparecerSkip { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; } }

/* Destello blanco de la transición cinematográfica */
.transition-flash {
  position: fixed; inset: 0; z-index: 8600; pointer-events: none;
  background: radial-gradient(60% 60% at 50% 50%, #fff 0%, rgba(255, 255, 255, .6) 45%, transparent 75%);
  opacity: 0;
}

/* =====================================================================
   4. BOTÓN FLOTANTE DE MÚSICA
   ===================================================================== */
.music-fab {
  position: fixed; z-index: 7000;
  right: 16px; bottom: calc(16px + env(safe-area-inset-bottom, 0px));
  width: 54px; height: 54px; border-radius: 50%; border: 0;
  display: grid; place-items: center;
  color: #fff; font-size: 1.15rem;
  background: linear-gradient(140deg, var(--acento), var(--azul-bebe));
  box-shadow: var(--sombra-md);
  cursor: pointer;
  transition: transform .25s ease, box-shadow .25s ease;
}
.music-fab:hover { transform: scale(1.08); box-shadow: var(--sombra-lg); }
.music-fab:active { transform: scale(.95); }

/* Anillo pulsante mientras suena la música */
.music-fab__pulse {
  position: absolute; inset: -6px; border-radius: 50%;
  border: 2px solid var(--azul-bebe); opacity: 0;
}
.music-fab.is-playing .music-fab__pulse { animation: pulso 1.8s ease-out infinite; }
@keyframes pulso {
  0%   { opacity: .8; transform: scale(.9); }
  100% { opacity: 0;  transform: scale(1.35); }
}

/* Barritas animadas cuando suena */
.music-fab.is-playing i { animation: bailar 1.2s ease-in-out infinite; }
@keyframes bailar {
  0%, 100% { transform: rotate(-8deg) scale(1); }
  50%      { transform: rotate(8deg) scale(1.12); }
}

/* Aviso inicial "Activar música" */
.music-hint {
  position: fixed; z-index: 6999;
  right: 80px; bottom: calc(28px + env(safe-area-inset-bottom, 0px));
  background: rgba(255, 255, 255, .9);
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
  color: var(--texto-oscuro); font-size: .82rem;
  padding: 8px 14px; border-radius: 99px;
  box-shadow: var(--sombra-sm); white-space: nowrap;
  animation: aparecerHint .5s ease both, latir 2.4s ease-in-out 1s infinite;
}
@keyframes aparecerHint { from { opacity: 0; transform: translateX(10px); } to { opacity: 1; } }
@keyframes latir { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-3px); } }

/* =====================================================================
   5. FONDOS DECORATIVOS
   ===================================================================== */
.invitacion { position: relative; z-index: 1; }

.bg-decor { position: fixed; inset: 0; z-index: 0; pointer-events: none; overflow: hidden; }

.bg-decor__blob {
  position: absolute; border-radius: 50%;
  filter: blur(60px); opacity: .5;
  will-change: transform;
}
.bg-decor__blob--1 { width: 380px; height: 380px; top: -80px;  left: -120px; background: var(--celeste); }
.bg-decor__blob--2 { width: 320px; height: 320px; top: 45%;    right: -140px; background: var(--amarillo-pastel); opacity: .42; }
.bg-decor__blob--3 { width: 420px; height: 420px; bottom: -160px; left: -100px; background: var(--azul-bebe); opacity: .35; }

/* =====================================================================
   6. HERO
   ===================================================================== */
.hero {
  position: relative;
  min-height: var(--vh100);
  display: flex; flex-direction: column;
  align-items: center; justify-content: flex-end;
  padding: 0 20px calc(38px + env(safe-area-inset-bottom, 0px));
  text-align: center; overflow: hidden;
}

.hero__photo-wrap {
  position: absolute; inset: 0; z-index: -1;
  will-change: transform;
}

.hero__photo {
  width: 100%; height: 100%;
  object-fit: cover;
  /* Zoom mayor a propósito: con poco zoom casi no hay margen vertical para
     mover el encuadre. Con más zoom, --foto-alza sí tiene rango real para
     subir la imagen en píxeles concretos (no en % , que apenas se nota). */
  transform: scale(1.19);
  /* Cuántos px se "sube" la imagen dentro de su marco — a más número,
     más se ve de la parte de abajo de la foto y más arriba queda la carita. */
  --foto-alza: 90px;
  object-position: center calc(50% - var(--foto-alza));
  animation: revelarCara 4.5s ease-out .2s both;
}

@keyframes revelarCara {
  0%   { object-position: center calc(50% - 10px); }
  100% { object-position: center calc(50% - var(--foto-alza)); }
}

/* Sin animación si el usuario pide menos movimiento: directo al encuadre final */
@media (prefers-reduced-motion: reduce) {
  .hero__photo { animation: none; }
}

/* Degradado que funde la foto con el fondo de la página.
   La foto de portada es muy colorida, así que la mitad inferior se aclara
   bastante: sin eso el título pierde contraste y no se lee. */
.hero__photo-glow {
  position: absolute; inset: 0;
  background:
    linear-gradient(180deg,
      rgba(255, 255, 255, .18) 0%,
      rgba(255, 255, 255, .04) 24%,
      rgba(231, 245, 255, .80) 52%,
      rgba(255, 255, 255, .95) 74%,
      var(--blanco) 100%);
}

/* Halo blanco difuso detrás del texto: separa el título de la foto sin
   dibujar una caja visible. */
.hero__content {
  position: relative; max-width: 640px;
  padding: 22px 18px 0;
}
.hero__content::before {
  content: ''; position: absolute; inset: -12% -18% -6%;
  background: radial-gradient(60% 55% at 50% 55%, rgba(255, 255, 255, .92) 0%, rgba(255, 255, 255, .7) 45%, transparent 72%);
  filter: blur(6px);
  z-index: -1;
}

.hero__eyebrow {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: .8rem; letter-spacing: .22em; text-transform: uppercase;
  color: var(--acento); background: rgba(255, 255, 255, .75);
  padding: 7px 16px; border-radius: 99px; margin-bottom: 20px;
  box-shadow: var(--sombra-sm);
  backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
}

/* Color sólido, igual técnica que la portada: el degradado con
   background-clip:text + borde grueso rompía el render (letras fundidas
   en manchas blancas) — este combo no es confiable en Chrome/Safari. */
.hero__title {
  font-family: var(--font-titulos); font-weight: 600;
  font-size: clamp(2.6rem, 13vw, 5.2rem);
  line-height: .98; letter-spacing: -.02em;
  color: var(--color-titulos);
  --stroke-w: 12px;
  /* Sin text-shadow: mismo bug que .loader__name en iOS Safari
     (halo/bultos en vez de contorno prolijo con el borde grueso). */
}

.hero__subtitle {
  font-size: clamp(.95rem, 4vw, 1.1rem); color: var(--texto-suave);
  margin: 14px auto 6px; max-width: 30ch; white-space: pre-line;
}

.hero__date {
  font-family: var(--font-display); font-weight: 600;
  font-size: clamp(1rem, 4.4vw, 1.25rem); color: var(--texto-oscuro);
  margin-bottom: 22px;
}
.hero__date i { color: var(--acento); margin-right: 6px; }

@keyframes rebote {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-10px); }
}

/* =====================================================================
   BOTÓN FLOTANTE "VER MÁS"
   ---------------------------------------------------------------------
   Reemplaza los avisos sueltos de "desliza para descubrir": un único
   botón fijo, presente desde que arranca la invitación hasta el final,
   que salta al borde exacto de la siguiente .pantalla por toque (lo
   controla app.js). Es texto, no una flecha: se entiende sin ícono.
   Centrado abajo para no chocar con el botón de música (bottom-right).
   ===================================================================== */
.next-fab {
  position: fixed; z-index: 6900;
  left: 50%; bottom: calc(18px + env(safe-area-inset-bottom, 0px));
  transform: translateX(-50%);
  border-radius: 99px; border: 1px solid rgba(255, 255, 255, .9);
  padding: 12px 28px;
  font-family: var(--font-display); font-weight: 700; font-size: .92rem;
  color: var(--acento);
  background: rgba(255, 255, 255, .88);
  box-shadow: var(--sombra-md);
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
  cursor: pointer;
  animation: reboteFab 1.9s ease-in-out infinite;
  transition: opacity .3s ease, transform .25s ease, box-shadow .25s ease, background .25s ease, color .25s ease;
}
.next-fab:hover { color: #fff; background: var(--acento); box-shadow: var(--sombra-lg); }
.next-fab:active { transform: translateX(-50%) scale(.94); }

@keyframes reboteFab {
  0%, 100% { transform: translateX(-50%) translateY(0); }
  50%      { transform: translateX(-50%) translateY(-8px); }
}

/* =====================================================================
   6.5. LAS "5 PANTALLAS"
   ---------------------------------------------------------------------
   `.pantalla` es solo una marca para que app.js sepa dónde empieza cada
   uno de los 5 bloques y salte al borde exacto (nunca a la mitad de una
   tarjeta o un párrafo) — por sí sola no impone ningún estilo, para no
   pisar el layout propio de .hero ni de "Detalles del evento".
   `.pantalla-grupo` sí trae el layout: la usan los 3 bloques que
   agrupan 2 secciones (bienvenida+contador, rsvp+galería, final+cierre)
   para repartirles el alto con flex en vez de que cada una cargue su
   propio padding grande — eso era lo que dejaba tanto aire sin usar.

   El padding-bottom generoso (no es capricho) reserva el hueco donde
   flotan "Ver más" y el botón de música: cuando una pantalla mide más
   que la pantalla real del celular, lo último que se ve (la tarjeta
   "Lugar", el botón "Cómo llegar", la última foto de la galería) queda
   justo debajo de esos botones fijos y se tapan. Con este hueco, ese
   choque no puede pasar en ninguna de las 5.
   ===================================================================== */
.pantalla-grupo {
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: clamp(18px, 5vh, 48px);
  padding: 26px 0 calc(96px + env(safe-area-inset-bottom, 0px));
}
/* Las secciones agrupadas ya reciben su espaciado del gap de arriba. */
.pantalla-grupo > .section { padding: 0; }

/* En la última pantalla el botón "Ver más" ya está oculto (no hay a
   dónde seguir bajando), así que no hace falta reservarle el hueco:
   solo queda el botón de música, abajo a la derecha, que no choca con
   el texto centrado del footer. Recuperar ese espacio es lo que permite
   que el cierre entre completo sin recortar nada. */
.pantalla:last-child.pantalla-grupo {
  padding-bottom: calc(26px + env(safe-area-inset-bottom, 0px));
}

/* "Detalles del evento" es una sola sección pero también pantalla
   completa: centra su contenido en vez de dejar aire fijo arriba/abajo.
   Selector con ID a propósito: gana por especificidad sin tener que
   tocar la regla general .section (que usan otras secciones sueltas). */
#evento.pantalla {
  min-height: var(--vh100);
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 24px 0 calc(96px + env(safe-area-inset-bottom, 0px));
}

/* --- Pantalla de ubicación: el mapa se come todo el alto sobrante --- */
#ubicacion.pantalla {
  min-height: var(--vh100);
  display: flex;
  flex-direction: column;
  gap: 12px;
  /* Menos hueco abajo que las otras pantallas: acá lo último es la
     tarjeta de dirección, que es ancha y baja — con este margen ya no
     llega a meterse debajo del botón "Ver más" (centrado), y todo lo
     que se ahorra se lo lleva el mapa, que es lo que interesa ver. */
  padding: 20px 0 calc(78px + env(safe-area-inset-bottom, 0px));
}
#ubicacion .section__title { margin-bottom: 0; }

/* flex:1 + min-height:0 es lo que deja al mapa estirarse hasta llenar
   el hueco: sin el min-height:0 un hijo flex nunca se encoge por debajo
   de su contenido y el mapa empujaría la tarjeta fuera de la pantalla. */
.mapa {
  position: relative;
  flex: 1;
  min-height: 190px;
  margin: 0 16px;
  border-radius: var(--radio);
  overflow: hidden;
  background: var(--gris-claro);
  box-shadow: var(--sombra-lg);
  border: 1px solid rgba(255, 255, 255, .8);
}

/* `inset: 0` y no `height: 100%`: el contenedor saca su alto de `flex: 1`,
   y contra un alto así los porcentajes no resuelven — el iframe se
   quedaba en los 150px que traen de fábrica y el mapa aparecía como una
   franja con el resto en blanco. Anclado a los cuatro bordes, llena
   siempre lo que mida el contenedor. */
.mapa__frame {
  position: absolute; inset: 0; z-index: 1;
  width: 100%; height: 100%;
  border: 0; display: block;
  /* El mapa necesita sus propios gestos: el pan-y global del body le
     bloquearía el arrastre lateral. */
  touch-action: auto;
}

/* Se ve solo mientras el mapa carga (o si nunca carga: queda de aviso,
   con el botón "Cómo llegar" abajo como salida). */
.mapa__aviso {
  position: absolute; inset: 0; z-index: 0;
  display: grid; place-items: center;
  margin: 0; padding: 20px; text-align: center;
  color: var(--texto-suave); font-size: .9rem;
}

/* Doble clase a propósito: el .glass de responsive.css es más nuevo y le
   ganaría a un solo `.ubicacion__datos`, devolviéndole el padding grande
   de tarjeta — y ese relleno es justo lo que le estaba robando alto al
   mapa. Compacto acá, el mapa se queda con lo que sobra. */
.ubicacion__datos.glass {
  display: flex; flex-direction: column; align-items: center; gap: 10px;
  padding: 12px 14px;
  text-align: center;
}

.ubicacion__texto {
  margin: 0; font-size: .86rem; line-height: 1.4;
  color: var(--texto-oscuro);
}
.ubicacion__texto strong { color: var(--acento); font-size: .98rem; }
.ubicacion__texto span[data-cfg] { display: block; color: var(--texto-suave); }
/* El pin va en la misma línea que el nombre: así la tarjeta gasta una
   línea menos de alto y el mapa gana ese espacio. */
.ubicacion__pin { font-size: 1rem; margin-right: 4px; }

/* Botón más bajo que el estándar: acá compite con el mapa por el alto. */
.ubicacion__datos .btn-premium { padding: 11px 26px; font-size: .95rem; }

/* =====================================================================
   7. SECCIONES GENÉRICAS + GLASSMORPHISM
   ===================================================================== */
.section { position: relative; padding: 72px 0; }
.section--welcome  { padding-top: 40px; }
.section--cierre   { padding: 90px 0 40px; overflow: hidden; }

.section__title {
  font-size: clamp(1.8rem, 7.5vw, 2.6rem);
  color: var(--color-titulos); margin-bottom: 10px;
  --stroke-w: 7.5px;
}

.section__lead { color: var(--texto-suave); font-size: .98rem; margin-bottom: 26px; }

.section__icon {
  font-size: 1.6rem; color: var(--acento);
  display: block; margin-bottom: 12px;
  filter: drop-shadow(0 6px 14px rgba(90, 169, 214, .35));
}

/* Tarjeta de vidrio (glassmorphism ligero) */
.glass {
  background: rgba(255, 255, 255, .62);
  backdrop-filter: blur(14px) saturate(140%);
  -webkit-backdrop-filter: blur(14px) saturate(140%);
  border: 1px solid rgba(255, 255, 255, .8);
  border-radius: var(--radio);
  box-shadow: var(--sombra-md);
  padding: 30px 24px;
}
.glass--soft { background: rgba(255, 255, 255, .52); }

.welcome__text {
  font-size: clamp(1rem, 4.2vw, 1.12rem); line-height: 1.75;
  color: var(--texto-oscuro); margin: 0 auto 18px; max-width: 46ch;
}
.welcome__sign { font-family: var(--font-display); color: var(--texto-suave); margin: 0; }
.welcome__sign strong { color: var(--acento); font-size: 1.15rem; }

.final__text {
  font-size: clamp(1rem, 4.2vw, 1.1rem); line-height: 1.8;
  color: var(--texto-oscuro); max-width: 44ch; margin: 0 auto;
}

/* =====================================================================
   8. CUENTA REGRESIVA
   ===================================================================== */
.countdown {
  display: grid; grid-template-columns: repeat(4, 1fr);
  gap: 10px; max-width: 620px; margin: 0 auto;
}

.countdown__box {
  position: relative;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  padding: 18px 6px 14px;
  background: rgba(255, 255, 255, .7);
  backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
  border: 1px solid rgba(255, 255, 255, .85);
  border-radius: 18px; box-shadow: var(--sombra-sm);
  overflow: hidden;
}
/* Brillito superior */
.countdown__box::before {
  content: ''; position: absolute; top: 0; left: 0; right: 0; height: 3px;
  background: linear-gradient(90deg, var(--celeste), var(--amarillo-pastel), var(--azul-bebe));
}

.countdown__icon { font-size: .95rem; color: var(--acento); margin-bottom: 6px; opacity: .8; }

.countdown__num {
  font-family: var(--font-display); font-weight: 800;
  font-size: clamp(1.6rem, 8vw, 2.4rem); line-height: 1;
  color: var(--texto-oscuro); font-variant-numeric: tabular-nums;
}

.countdown__label {
  font-size: .68rem; letter-spacing: .16em; text-transform: uppercase;
  color: var(--texto-suave); margin-top: 6px;
}

/* Latido cuando cambia el número (lo aplica countdown.js) */
.countdown__num.tick { animation: tick .45s cubic-bezier(.22, 1, .36, 1); }
@keyframes tick {
  0%   { transform: translateY(-8px) scale(.9); opacity: .4; }
  100% { transform: none; opacity: 1; }
}

.countdown__done {
  text-align: center; font-family: var(--font-display); font-weight: 700;
  font-size: clamp(1.3rem, 6vw, 2rem); color: var(--acento); margin-top: 18px;
}

/* =====================================================================
   9. TARJETAS DE EVENTO Y BOTONES
   ===================================================================== */
.info-card {
  height: 100%; text-align: center; padding: 26px 20px;
  transition: transform .35s cubic-bezier(.22, 1, .36, 1), box-shadow .35s ease;
}
.info-card:hover { transform: translateY(-6px); box-shadow: var(--sombra-lg); }

/* La tarjeta de Lugar cierra la grilla y se lee junto al botón "Cómo llegar" */
.info-card--lugar { box-shadow: 0 14px 36px rgba(47, 128, 194, .18); }

.info-card__emoji { font-size: 2rem; display: block; margin-bottom: 10px; }
.info-card__title {
  font-family: var(--font-display); font-weight: 700;
  font-size: 1.15rem; color: var(--acento); margin-bottom: 8px;
}
.info-card__text { color: var(--texto-oscuro); font-size: .95rem; margin: 0; line-height: 1.6; }

/* Botón premium reutilizable */
.btn-premium {
  display: inline-flex; align-items: center; gap: 10px;
  padding: 15px 32px; border: 0; border-radius: 99px;
  font-family: var(--font-display); font-weight: 700; font-size: 1.02rem;
  color: #fff; text-decoration: none; cursor: pointer;
  position: relative; overflow: hidden;
  box-shadow: var(--sombra-md);
  transition: transform .28s cubic-bezier(.22, 1, .36, 1), box-shadow .28s ease;
}
.btn-premium:hover { transform: translateY(-3px) scale(1.02); box-shadow: var(--sombra-lg); color: #fff; }
.btn-premium:active { transform: translateY(0) scale(.98); }

/* Brillo que barre el botón */
.btn-premium::after {
  content: ''; position: absolute; top: 0; left: -60%;
  width: 40%; height: 100%;
  background: linear-gradient(100deg, transparent, rgba(255, 255, 255, .55), transparent);
  transform: skewX(-20deg);
  animation: brilloBoton 3.4s ease-in-out infinite;
}
@keyframes brilloBoton {
  0%, 65% { left: -60%; }
  100%    { left: 130%; }
}

.btn-premium--maps { background: linear-gradient(135deg, var(--acento), var(--azul-bebe)); }
.btn-premium--wa   { background: linear-gradient(135deg, #25d366, #128c7e); font-size: 1.08rem; padding: 17px 36px; }

.btn-ghost {
  margin-top: 22px; padding: 11px 24px;
  background: rgba(255, 255, 255, .7); color: var(--acento);
  border: 1px solid rgba(90, 169, 214, .35); border-radius: 99px;
  font-family: var(--font-texto); font-size: .9rem; cursor: pointer;
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
  transition: background .25s ease, transform .25s ease;
}
.btn-ghost:hover { background: #fff; transform: translateY(-2px); }

.rsvp { max-width: 560px; margin: 0 auto; }

/* =====================================================================
   10. GALERÍA (Swiper)
   ===================================================================== */
.gallery { padding: 10px 0 54px; overflow: visible; }

.gallery .swiper-slide {
  width: 78%; max-width: 420px;
  transition: transform .45s cubic-bezier(.22, 1, .36, 1), opacity .45s ease;
  opacity: .55; transform: scale(.9);
}
.gallery .swiper-slide-active { opacity: 1; transform: scale(1); }

.gallery__figure {
  position: relative; margin: 0;
  border-radius: var(--radio); overflow: hidden;
  box-shadow: var(--sombra-lg);
  background: var(--gris-claro);
  /* Cuadrado: las fotos vienen mezcladas (horizontales y verticales) y así
     ninguna queda recortada de forma brutal. */
  aspect-ratio: 1 / 1;
}

/* El selector lleva el padre a propósito: Swiper aplica
   `.swiper-zoom-container > img { object-fit: contain; max-height: 100% }`,
   que dejaba franjas blancas. Esta regla gana por especificidad. */
.gallery__figure > .gallery__img {
  width: 100%; height: 100%;
  max-width: none; max-height: none;
  object-fit: cover; object-position: center;
  transition: transform .8s cubic-bezier(.22, 1, .36, 1);
}
.gallery__figure:hover .gallery__img { transform: scale(1.06); }

/* Marco interior sutil */
.gallery__figure::after {
  content: ''; position: absolute; inset: 0; border-radius: var(--radio);
  border: 1px solid rgba(255, 255, 255, .55); pointer-events: none;
}

.gallery .swiper-pagination-bullet { background: var(--acento); opacity: .3; }
.gallery .swiper-pagination-bullet-active { opacity: 1; width: 22px; border-radius: 99px; }

.gallery .swiper-button-prev,
.gallery .swiper-button-next {
  width: 42px; height: 42px; border-radius: 50%;
  background: rgba(255, 255, 255, .8); color: var(--acento);
  box-shadow: var(--sombra-sm);
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
}
.gallery .swiper-button-prev::after,
.gallery .swiper-button-next::after { font-size: 1rem; font-weight: 700; }

/* =====================================================================
   11. CIERRE, GLOBOS, CONFETI, FOOTER
   ===================================================================== */
/* Mismo cambio que .hero__title: color sólido en vez de degradado —
   con background-clip:text el borde grueso fundía las letras. */
.cierre__title {
  font-family: var(--font-titulos);
  font-size: clamp(2.2rem, 11vw, 4rem); line-height: 1;
  color: var(--color-titulos);
  --stroke-w: 9px;
  margin-bottom: 12px;
}
.cierre__name {
  font-family: var(--font-display); font-weight: 700;
  font-size: clamp(1.3rem, 6vw, 1.9rem); color: var(--texto-oscuro); margin: 0;
}
.cierre__date { color: var(--texto-suave); font-size: .95rem; margin-top: 4px; }

/* Globos que ascienden al final */
.balloons-up { position: absolute; inset: 0; pointer-events: none; overflow: hidden; }
.balloons-up .balloon { animation-duration: var(--dur, 8s); }

/* Canvas del confeti: cubre todo pero deja pasar los clics */
.confetti-canvas {
  position: fixed; inset: 0; z-index: 6500;
  width: 100%; height: 100%; pointer-events: none;
}

.footer {
  text-align: center; padding: 26px 20px calc(26px + env(safe-area-inset-bottom, 0px));
  color: var(--texto-suave); font-size: .82rem;
}
.footer i { color: var(--rojo, #ff8fa3); }

/* =====================================================================
   13. BORDE BLANCO DE LOS TÍTULOS — técnica de doble capa
   ---------------------------------------------------------------------
   `paint-order: stroke fill` (borde detrás de la letra) no es confiable
   en Safari — ahí el borde tapaba o deformaba las letras. En vez de
   depender de esa propiedad, se apilan dos copias del mismo texto:
   una solo-borde detrás (absoluta) y el relleno normal encima. El orden
   de apilamiento (z-index) sí lo respetan todos los navegadores por igual.
   Las dos capas las genera app.js (envolverTitulosConBorde) a partir del
   texto que ya está en pantalla — no hace falta tocar el HTML a mano.
   ===================================================================== */
.stroke-title { position: relative; }

.stroke-title__outline {
  position: absolute; inset: 0; width: 100%;
  color: transparent;
  -webkit-text-stroke: var(--stroke-w, 6px) var(--blanco);
  text-stroke: var(--stroke-w, 6px) var(--blanco);
  pointer-events: none;
  z-index: 0;
}

.stroke-title__fill {
  position: relative;
  z-index: 1;
}

/* =====================================================================
   12. TEMÁTICA PLIM PLIN — arcoíris, nubes y nariz roja
   ---------------------------------------------------------------------
   Capa decorativa sobre la base pastel. Para cambiar de temática
   basta con editar `colores` y `arcoiris` en config.js.
   ===================================================================== */
:root {
  --rojo: #e63946;
  --verde: #6ec46e;
  --violeta: #a06cd5;
  --naranja: #ff9f45;
  --grad-arcoiris: linear-gradient(90deg,
      #e63946 0%, #ff9f45 20%, #ffd23f 40%, #6ec46e 60%, #2f80c2 80%, #a06cd5 100%);
}

/* --- Nariz roja del loader --- */
.nose {
  display: block; width: 30px; height: 30px; margin: 0 auto 14px;
  border-radius: 50%;
  background: radial-gradient(circle at 34% 30%, #ff7a7a, var(--rojo) 62%, #b32833 100%);
  box-shadow: 0 8px 20px rgba(230, 57, 70, .38), inset -3px -4px 8px rgba(0, 0, 0, .18);
  animation: naricita 2.4s ease-in-out infinite;
}
@keyframes naricita {
  0%, 100% { transform: scale(1) translateY(0); }
  50%      { transform: scale(1.12) translateY(-4px); }
}

/* --- Franja de arcoíris bajo cada título de sección --- */
.section__title::after {
  content: ''; display: block;
  width: 72px; height: 5px; margin: 12px auto 0;
  border-radius: 99px; background: var(--grad-arcoiris);
  opacity: .9;
}
/* El título del cierre ya tiene su propio arcoíris de fondo */
.cierre__title::after { content: none; }

/* --- Nubes de fondo (las genera animations.js) --- */
.bg-decor__clouds { position: absolute; inset: 0; }

.cloud {
  position: absolute;
  width: var(--w, 110px); height: calc(var(--w, 110px) * .38);
  background: #fff; border-radius: 99px;
  opacity: var(--op, .15);
  filter: blur(.4px);
  animation: navegar var(--dur, 60s) linear infinite;
  animation-delay: var(--delay, 0s);
}
/* Los dos bultos superiores de la nube */
.cloud::before, .cloud::after {
  content: ''; position: absolute; background: #fff; border-radius: 50%;
}
.cloud::before { width: 52%; height: 130%; top: -62%; left: 12%; }
.cloud::after  { width: 38%; height: 100%; top: -46%; right: 14%; }

@keyframes navegar {
  from { transform: translateX(-30vw); }
  to   { transform: translateX(130vw); }
}

/* --- Arcoíris del cierre --- */
.rainbow {
  position: absolute; left: 50%; bottom: -26%;
  width: min(620px, 130vw); aspect-ratio: 2 / 1;
  transform: translateX(-50%);
  border-radius: 100% 100% 0 0 / 100% 100% 0 0;
  background: var(--grad-arcoiris);
  -webkit-mask: radial-gradient(100% 100% at 50% 100%, transparent 52%, #000 53%, #000 100%);
          mask: radial-gradient(100% 100% at 50% 100%, transparent 52%, #000 53%, #000 100%);
  opacity: .3;
  pointer-events: none;
  animation: arcoiris 4s ease-in-out infinite;
}
@keyframes arcoiris {
  0%, 100% { opacity: .26; transform: translateX(-50%) scale(1); }
  50%      { opacity: .42; transform: translateX(-50%) scale(1.03); }
}

/* --- Acentos de color en las tarjetas del evento (rotan el arcoíris) --- */
.info-cards > div:nth-child(6n+1) .info-card { border-top: 4px solid var(--rojo); }
.info-cards > div:nth-child(6n+2) .info-card { border-top: 4px solid var(--naranja); }
.info-cards > div:nth-child(6n+3) .info-card { border-top: 4px solid var(--amarillo-pastel); }
.info-cards > div:nth-child(6n+4) .info-card { border-top: 4px solid var(--verde); }
.info-cards > div:nth-child(6n+5) .info-card { border-top: 4px solid var(--acento); }
.info-cards > div:nth-child(6n+6) .info-card { border-top: 4px solid var(--violeta); }
