/* ═══════════════════════════════════════════════════════════════════
   KEVIN & BELÉN · 24 · 01 · 2027
   Paleta: azul marino profundo · dorado · marfil
   Acentos sutiles de azul y violeta. Efectos 3D reales.

   Reglas de animación aplicadas:
   · Solo se animan transform y opacity (nada de layout ni box-shadow).
   · Curvas ease-out para entradas y salidas; nunca ease-in en UI.
   · Hover entre 150-200ms; entradas decorativas hasta 700ms;
     la coreografía del sobre usa el presupuesto de "celebración".
   · Todo :hover con motion va detrás de (hover: hover) and (pointer: fine).
   · prefers-reduced-motion deja los fundidos y quita los desplazamientos.
   · Escalonado de grupos entre 30 y 80ms.
   ═══════════════════════════════════════════════════════════════════ */

:root {
  /* ---- Base ---- */
  --marino-profundo: #08131F;
  --marino:          #0B1A2E;
  --marino-alto:     #112945;

  /* ---- Texto ---- */
  /* Canales en lugar de colores cerrados: así la opacidad se decide en
     cada uso y el tema solo cambia el canal. Es lo que permite tener un
     tema claro sin duplicar cada token con su variante. */
  --tinta-rgb:       244 239 230;   /* el texto y los filetes */
  --oro-rgb:         212 181 112;

  /* Multiplica la opacidad de las sombras de página. En el tema claro una
     sombra al 70% sobre beige es un manchón; con el factor se suavizan
     todas a la vez sin tocar cada valor. El sobre lo fija en 1 aparte,
     porque sigue siendo azul marino en los dos temas. */
  --sombra-k:        1;
  --sombra-rgb:      0 0 0;         /* en el tema claro pasa a marrón cálido */

  --marfil:          #F4EFE6;       /* el texto */
  --papel:           #F4EFE6;       /* el marco de las fotos: es un objeto,
                                       no texto, así que no se invierte con
                                       el tema; solo se aclara para que se
                                       despegue del fondo beige */
  --marfil-medio:    rgb(var(--tinta-rgb) / 0.86);
  --marfil-tenue:    rgb(var(--tinta-rgb) / 0.80);

  /* ---- Dorado (acento principal) ---- */
  --dorado:          #D4B570;   /* aclarado desde #C9A961: en el
                                   cuadro más traslúcido ese daba 4.47:1,
                                   bajo el mínimo para texto chico */
  --dorado-claro:    #E6D3A3;   /* oro luminoso: rellenos y foco */
  /* Dos tokens más para el oro, porque en un tema claro sus dos papeles se
     contradicen: como texto tiene que ser oscuro para leerse, y como relleno
     tiene que ser luminoso para que el texto de encima se lea. En el tema
     oscuro ambos coinciden con el oro claro y no cambia nada. */
  --oro-texto:       #E6D3A3;   /* el oro cuando ES el texto */
  --oro-relleno:     #D4B570;   /* el extremo oscuro de un relleno dorado:
                                   tiene que quedarse claro, porque encima
                                   va texto */
  /* Filete del botón de línea. Es el borde de un control, así que la norma
     pide 3:1 contra su relleno; en el tema oscuro el oro al 70% ya da
     4,26:1, en el claro se lava a 1,99:1 y hay que oscurecerlo. */
  --boton-borde:     rgb(var(--oro-rgb) / 0.70);
  --sobre-oro:       #0B1A2E;   /* el texto cuando va SOBRE oro */
  --error-rgb:       224 133 133;
  --dorado-hondo:    #9C7F42;
  --dorado-vidrio:   rgb(var(--oro-rgb) / 0.14);
  --dorado-linea:    rgb(var(--oro-rgb) / 0.32);

  /* ---- Acentos sutiles (solo toques) ---- */
  --violeta-tenue:   rgba(123, 107, 168, 0.16);
  --azul-tenue:      rgba(74, 111, 165, 0.16);

  /* ---- Superficies ---- */
  --tarjeta:         rgba(17, 41, 69, 0.36);

  /* Superficies de página. Se nombran porque en el tema claro no basta con
     bajarles la opacidad: cambian de lado, de oscuras translúcidas a claras
     translúcidas. */
  --campo-rgb:       6 15 26;                /* fondo de los campos */
  --campo-solido:    #0B1826;   /* el tono del campo en sólido: tapa el
                                   amarillo del autorrelleno */
  /* Filete de los campos aparte del resto: es el borde de un control, y la
     norma pide 3:1 contra su fondo. En el tema oscuro se deja como estaba
     (1,40:1, por debajo; venía así y no se toca sin pedirlo); en el claro se
     sube hasta 3,06:1. */
  --campo-linea:     rgb(var(--tinta-rgb) / 0.13);
  --campo-div:       rgb(var(--tinta-rgb) / 0.11);
  --vidrio-rgb:      8 19 31;                /* pie y bloques tenues */
  --vidrio-fuerte:   rgba(17, 41, 69, 0.55);  /* el reproductor */
  --velo:            rgba(15, 34, 58, 0.30);
  --vineta:          rgba(2, 7, 14, 0.52);    /* el oscurecido de los bordes */
  /* ---- El color de cada sección ----
     Cada sección tiene su acento; de él salen la luz que la baña, el tinte
     de su tarjeta y sus filetes. El oro sigue siendo el de los títulos: el
     color entra como luz, no como pintura. Los tonos salen de las flores
     de la propia invitación, más los verdes que pidió Belén. */
  --acento-a:   118 193 204;   /* calipso, el del sobre */
  --acento-b:    86 164 178;

  /* De dónde viene la luz de cada sección. El color y la intensidad son
     los mismos en todas, pero el punto cambia: si no, se lee como la misma
     imagen repetida siete veces. */
  --foco-x:  26%;  --foco-y:  24%;
  --foco2-x: 88%;  --foco2-y: 82%;
  --tinte-alfa:  0.22;         /* cuánto tiñe el fondo de la sección */
  --carta-tinte: 0.10;         /* y cuánto tiñe la tarjeta */
  --carta-fondo: rgb(var(--vidrio-rgb) / 0.55);

  --vineta-rgb:      4 10 20;                /* el tinte del velo del selector */
  --velo-alfa:       0.42;
  --velo-suelo:      5 13 24;                /* el suelo del texto del carrusel */
  --rep-filo:        rgb(255 255 255 / 0.10);  /* el canto de luz del reproductor */
  --sombra-texto:    rgba(3, 8, 16, 0.55);
  --tarjeta-borde:   rgb(var(--oro-rgb) / 0.18);
  --tarjeta-sombra:  0 24px 60px -24px rgb(var(--sombra-rgb) / calc(0.7 * var(--sombra-k)));
  --tarjeta-sombra-alta: 0 40px 90px -30px rgb(var(--sombra-rgb) / calc(0.85 * var(--sombra-k)));

  /* ---- Tipografía ---- */
  --serif:  'Cormorant Garamond', Georgia, serif;
  --script: 'Pinyon Script', 'Parisienne', cursive;
  --sans:   'Montserrat', -apple-system, sans-serif;

  /* ---- Curvas (valores exactos de la guía) ---- */
  --ease-out:    cubic-bezier(0.23, 1, 0.32, 1);
  --ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);

  /* ---- Duraciones ---- */
  --t-hover:   170ms;  /* interacción: casi imperceptible */
  --t-press:   130ms;  /* pulsación */
  --t-entrada: 950ms;  /* entrada decorativa de sección; a 700 pasaba
                          demasiado rápido y el 3D no se alcanzaba a leer */

  /* ---- 3D ---- */
  --perspectiva: 1400px;

  /* ---- Estados ---- */
  --error: #E08585;
  --exito: #86BE9B;
}

/* ═══════════════════════════════════════════════════════════════════
   TEMA CLARO
   Papel crema en lugar de noche. No es el tema oscuro invertido: la luz
   de ambiente pasa de violeta a champán, porque un violeta translúcido
   sobre beige se ensucia, y el campo de estrellas se retira, porque con
   mezcla screen sobre un fondo claro no se ve nada. Queda el grano, que
   es lo que da el aire de papel.

   El sobre no cambia: es de tela azul marino en los dos temas, y con el
   crema detrás funciona como el marino con dorado de siempre.

   Los colores están elegidos por contraste calculado sobre el fondo
   #F6F1E7, no a ojo: tinta 13,09:1; tinta al 86% 8,69:1; al 68% 4,97:1;
   oro de texto 4,74:1 (hay texto dorado de 0,62rem, así que tiene que
   pasar el 4,5:1 del texto corriente, no el 3:1 del grande).
   ═══════════════════════════════════════════════════════════════════ */

html[data-tema="claro"] {
  /* Barra de desplazamiento, cursores y desplegables nativos en claro */
  color-scheme: light;
}

[data-tema="claro"] {
  /* Casi blanco, no crema. Antes era #FBF9F4, con nueve puntos de
     diferencia entre el rojo y el azul, y eso es lo que se leía amarillo.
     Ahora la diferencia es de dos: queda el calor justo para que no parezca
     una pantalla en blanco, sin virar a crema. */
  --marino-profundo: #FBFBF9;
  --marino:          #FCFCFA;
  --marino-alto:     #F1F1ED;   /* superficie sólida; era #E7DDCA, del papel crema de antes */

  --tinta-rgb:       23 41 63;  /* #17293F, marino profundo como tinta */
  --marfil:          #17293F;

  /* Dos oros: el de texto tiene que llegar a 4,5:1, el decorativo no,
     así que se deja más vivo para que los filetes sigan leyéndose como
     oro y no como marrón. */
  --oro-rgb:         176 138 68;
  /* Oro de texto: 5,4:1 sobre el fondo y 5,9:1 sobre la ficha, que es la
     superficie más clara donde aparece. Hay texto dorado de 0,62rem, así que
     el mínimo es 4,5:1 y no el 3:1 del texto grande. */
  --dorado:          #7A5E1C;
  /* Oro luminoso: aquí solo rellena y dibuja el foco, nunca es texto, así
     que se queda vivo para que la tinta de encima se lea. */
  --dorado-claro:    #D9B96E;
  --dorado-hondo:    #5F4915;
  --oro-texto:       #6F5416;   /* 6,8:1 sobre la ficha */
  --oro-relleno:     #C9A455;   /* 6,7:1 con la tinta de encima */
  --boton-borde:     rgb(111 84 22 / 0.82);   /* 3,7:1 contra su relleno */
  --sobre-oro:       #231A06;   /* 9,1:1 sobre el oro luminoso */
  --error-rgb:       168 48 47;

  /* Sombra cálida y muy suavizada: una sombra negra al 70% sobre beige
     es un manchón gris. El factor las baja todas a la vez. */
  --sombra-rgb:      74 58 38;
  --sombra-k:        0.34;

  /* Las fichas van más claras que el fondo, como papel sobre papel, y se
     delimitan con el filete dorado y la sombra. Siguen translúcidas para
     que la luz de ambiente las atraviese. */
  --tarjeta:         rgb(255 255 255 / 0.60);
  --tarjeta-borde:   rgb(var(--oro-rgb) / 0.40);

  --campo-rgb:       255 255 255;
  --campo-solido:    #FAF9F6;
  --campo-linea:     rgb(var(--tinta-rgb) / 0.50);   /* 3,06:1 */
  --campo-div:       rgb(var(--tinta-rgb) / 0.34);

  --vidrio-rgb:      255 253 248;
  --vidrio-fuerte:   rgb(255 253 248 / 0.74);
  --velo:            rgb(214 176 120 / 0.13);
  --vineta:          rgb(120 96 60 / 0.13);
  --vineta-rgb:      86 68 44;   /* la viñeta de los bordes, en cálido */
  /* El velo del selector, en claro, es niebla de papel densa: con el pardo
     al 0,26 no había escenario y las piezas quedaban sueltas sobre la
     página desenfocada —visto en el teléfono—. La niebla apaga el fondo
     sin ponerlo en penumbra, que en este tema sería un manchón. */
  --velo-rgb:        249 246 240;
  --velo-alfa:       0.78;
  --velo-suelo:      255 253 248;
  --tinte-alfa:      0.52;   /* sobre el crema hace falta bastante más para que se vea color */
  /* Casi blanca, no crema: es lo que pidió Kevin. El color de la sección
     lo aportan los velos del acento, no la base. */
  --carta-fondo:     rgb(255 255 255 / 0.88);
  --carta-tinte:     0.17;
  --rep-filo:        rgb(255 255 255 / 0.9);
  --sombra-texto:    rgb(146 118 74 / 0.30);

  --papel:           #FFFFFF;   /* el marco de las fotos, para que se
                                   despegue del crema */
  --error:           #A8302F;
  --exito:           #2F6B45;

  /* El número de sección lleva opacity: 0.85, que le come contraste; con el
     oro a 5,4:1 le queda margen de sobra. */
}

/* ---- Cielo, grano y viñeta ----
   Se retira el campo de estrellas y queda el grano, en multiply para que
   entinte el papel en lugar de aclararlo. */
[data-tema="claro"] body::before {
  background-image:
    radial-gradient(118% 88% at 50% 44%, transparent 52%, var(--vineta) 100%),
    url('assets/grano.webp');
  background-size: cover, 150px 150px;
  background-repeat: no-repeat, repeat;
  background-blend-mode: normal, multiply;
  opacity: 0.55;
}

/* ---- Luz de ambiente: champán con un rebote de rosa empolvado ---- */
[data-tema="claro"] body::after {
  background:
    radial-gradient(130% 100% at -8% -14%,
      rgb(214 172 104 / 0.34) 0%,
      rgb(206 170 120 / 0.20) 20%,
      rgb(190 168 140 / 0.09) 42%,
      transparent 66%),
    radial-gradient(95% 75% at 108% 112%,
      rgb(178 152 186 / 0.20) 0%,
      transparent 56%);
}

/* ---- Luz de cada sección ----
   El mismo lila del pie, que es el que les gustó. Antes esta regla pintaba
   oro y beige, y como es más específica que la general se comía el lila:
   medido, el rincón de la sección salía en rgb(243,234,220) —cálido— y el
   del pie en rgb(225,222,230) —frío—, con el mismo fondo declarado. */
[data-tema="claro"] .bloque:not(#portada)::after {
  background:
    radial-gradient(52vw 46vh at var(--foco-x) var(--foco-y),
      rgba(158, 120, 238, 0.30) 0%,
      rgba(120, 98, 196, 0.13) 42%,
      transparent 74%),
    radial-gradient(44vw 40vh at var(--foco2-x) var(--foco2-y),
      rgba(150, 126, 226, 0.14) 0%,
      transparent 72%);
}

/* ---- Los cinco lóbulos tras el sobre ----
   Antes eran cinco manchas de oro, malva y beige superpuestas, y sobre el
   crema la mezcla salía turbia: eso es lo que no convencía. Ahora son dos
   familias y nada más —crema dorado y calipso, el del sobre—, repartidas
   para que la luz cálida caiga tras el sobre y la fría se abra a los lados.
   Dos colores que se llevan bien dan aire; cinco a la vez dan barro. */
[data-tema="claro"] .luz-lobulo:nth-child(1) {   /* calipso, arriba a la izquierda */
  background: radial-gradient(circle at 50% 50%, rgb(132 194 200 / 0.34), transparent 70%);
}
[data-tema="claro"] .luz-lobulo:nth-child(2) {   /* crema cálido, tras el sobre */
  background: radial-gradient(circle at 50% 50%, rgb(244 220 168 / 0.52), transparent 72%);
}
[data-tema="claro"] .luz-lobulo:nth-child(3) {   /* calipso suave, abajo */
  background: radial-gradient(circle at 50% 50%, rgb(146 200 202 / 0.26), transparent 74%);
}
[data-tema="claro"] .luz-lobulo:nth-child(4) {   /* marfil, canto izquierdo */
  background: radial-gradient(circle at 50% 50%, rgb(250 238 214 / 0.55), transparent 76%);
}
[data-tema="claro"] .luz-lobulo:nth-child(5) {   /* un toque de oro arriba */
  background: radial-gradient(circle at 50% 50%, rgb(232 200 138 / 0.34), transparent 72%);
}

/* ---- Motas: destellos de oro en lugar de puntos de luz ---- */
/* ---- Los nombres ----
   Su veta es de tonos marfil, hecha para leerse contra la noche; sobre el
   crema desaparecían por completo. Aquí la veta pasa a oro viejo. El tono
   más claro de la veta es el que manda para el contraste, y ninguno baja
   de 3:1 sobre el fondo (#A9863A da 3,03:1; el resto, entre 3,5 y 6,6). */

/* Los nombres van en la tinta del tema, no en oro */
[data-tema="claro"] .nombres-hero { color: var(--marfil); }

[data-tema="claro"] .mota {
  background: radial-gradient(circle,
    rgb(184 146 74 / 0.60) 0%,
    rgb(184 146 74 / 0.26) 42%,
    transparent 72%);
}
[data-tema="claro"] .mota.calida {
  background: radial-gradient(circle,
    rgb(178 148 178 / 0.52) 0%,
    rgb(178 148 178 / 0.22) 42%,
    transparent 72%);
}
[data-tema="claro"] .particulas { opacity: 0; }
[data-tema="claro"] body.carta-abierta .particulas { opacity: 0.72; }


/* ═══════════════════════════════════════════════════════════════════
   RESET Y BASE
   ═══════════════════════════════════════════════════════════════════ */

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

html {
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
  /* clip y no hidden: hidden crearía un contenedor de desplazamiento.
     Esto solo recorta, sin efectos secundarios. */
  overflow-x: clip;

  /* Tema oscuro declarado. Sin esto el navegador supone tema claro y
     dibuja su interfaz nativa en consecuencia: de ahí salía la barra de
     desplazamiento clara. También arregla el cursor de los campos, el
     relleno automático de formularios y los desplegables.

     Y nada más. No se le da estilo propio a la barra a propósito: en
     cuanto se declara ::-webkit-scrollbar, el navegador deja de usar la
     barra flotante del sistema, que en macOS aparece al desplazar y se
     desvanece sola, y la reemplaza por una clásica siempre visible. Se
     probó y el resultado era peor: una franja permanente y más ancha.
     Con color-scheme basta para que la nativa salga oscura. */
  color-scheme: dark;

  /* Se reserva el hueco de la barra siempre. Sin esto, al desbloquear el
     desplazamiento la barra aparece y el contenido se corre de golpe. */
  scrollbar-gutter: stable;
}

/* Nada se desplaza hasta que se abre la carta: el sello es el único paso.
   La clase la pone el script, no el HTML, para que la página siga siendo
   utilizable si el script no llega a ejecutarse. */
html.sin-desplazar,
html.sin-desplazar body {
  overflow: hidden;
  /* touch-action frena también el arrastre con el dedo, que overflow por sí
     solo no siempre detiene en móvil. */
  touch-action: none;
  overscroll-behavior: none;
}

body {
  margin: 0;
  background-color: var(--marino);
  color: var(--marfil);
  font-family: var(--sans);
  font-weight: 400;
  line-height: 1.7;
  /* clip y no hidden. Según la especificación, cuando un eje es hidden y
     el otro visible, el visible pasa a auto: eso convertía el body en un
     contenedor de desplazamiento propio, además del de html, y por eso
     salían dos barras. Con clip el otro eje se queda en visible y no se
     crea ningún contenedor. */
  overflow-x: clip;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* ---- Cielo, grano y viñeta ----
   Tres capas fijas, sin animación: un campo de estrellas generado para
   repetirse sin costura, un grano fino que quita la sensación de color
   plano, y la viñeta que concentra la vista al centro. */
body::before {
  content: '';
  position: fixed;
  /* Con holgura: al desplazarse con el puntero no deben asomar bordes */
  inset: -5%;
  pointer-events: none;
  z-index: 0;
  /* Recorrido mínimo: el cielo es lo más lejano de la escena */
  translate: calc(var(--luz-x, 0px) * 0.09) calc(var(--luz-y, 0px) * 0.09);
  transition: translate 700ms var(--ease-out);
  background-image:
    radial-gradient(118% 88% at 50% 44%, transparent 50%, var(--vineta) 100%),
    url('assets/estrellas.webp'),
    url('assets/grano.webp');
  background-size: cover, 900px 900px, 150px 150px;
  background-repeat: no-repeat, repeat, repeat;
  /* El grano se mezcla en lugar de superponerse: así da textura sin
     aclarar el fondo. */
  background-blend-mode: normal, screen, overlay;
  opacity: 0.9;
}

/* ---- Luz violeta desde la esquina ----
   Un foco fuera de cuadro, arriba a la izquierda, como si algo iluminara
   la página, con un rebote frío en la esquina contraria.

   Empieza apagada y se enciende al abrir el sobre, junto con la música.
   Solo se anima la opacidad: los degradados quedan fijos, porque animar
   un degradado obliga a repintar en cada frame. */
body::after {
  content: '';
  position: fixed;
  /* Más grande que la pantalla: al seguir el puntero no asoman los bordes */
  inset: -34%;
  filter: blur(26px);
  pointer-events: none;
  z-index: 0;
  opacity: 0;
  will-change: transform, opacity;
  /* --luz-x e --luz-y las escribe el script con el movimiento del ratón */
  transform: translate3d(
    calc(var(--luz-x, 0px) + var(--luz-scroll-x, 0px)),
    calc(var(--luz-y, 0px) + var(--luz-scroll-y, 0px)),
    0);
  background:
    /* el foco */
    radial-gradient(130% 100% at -8% -14%,
      rgba(158, 120, 238, 0.56) 0%,
      rgba(130, 100, 210, 0.32) 20%,
      rgba(90, 74, 158, 0.15) 42%,
      transparent 66%),
    /* rebote frío en la esquina contraria */
    radial-gradient(95% 75% at 108% 112%,
      rgba(80, 118, 176, 0.26) 0%,
      transparent 56%);
  /* La opacidad entra despacio al abrir; el desplazamiento sigue al
     puntero con su propio ritmo, más corto. */
  transition: opacity 2400ms var(--ease-out),
              transform 420ms var(--ease-out);
}

/* Se enciende con el giro de la tapa, no de golpe al tocar */
body.carta-abierta::after {
  opacity: 1;
  transition-delay: 420ms;
}

img { max-width: 100%; display: block; }
button { font-family: inherit; }

/* ═══════════════════════════════════════════════════════════════════
   PARTÍCULAS DE LUZ
   Motas que suben despacio por el fondo. Cada una con su tamaño, su
   duración y su deriva, sacados al azar por el script, de modo que
   ninguna repite el recorrido de otra.

   Aparecen al abrir la carta, como el resto de la iluminación. Se animan
   transform y opacity; nada más.
   ═══════════════════════════════════════════════════════════════════ */

.particulas {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  overflow: hidden;
  opacity: 0;
  transition: opacity 2600ms var(--ease-out);
  /* También acompañan al puntero, con poco recorrido */
  translate: calc(var(--luz-x, 0px) * 0.16) calc(var(--luz-y, 0px) * 0.16);
}
body.carta-abierta .particulas { opacity: 1; transition-delay: 600ms; }

.mota {
  position: absolute;
  left: var(--x, 50%);
  bottom: -8vh;
  width: var(--tam, 4px);
  height: var(--tam, 4px);
  border-radius: 50%;
  background: radial-gradient(circle,
    rgba(240, 232, 255, 0.95) 0%,
    rgba(186, 152, 255, 0.45) 42%,
    transparent 72%);
  will-change: transform, opacity;
  animation: subirMota var(--dur, 22s) linear var(--dly, 0s) infinite;
}

/* Algunas van doradas, para que el enjambre no sea de un solo tono */
.mota.calida {
  background: radial-gradient(circle,
    rgba(255, 246, 224, 0.95) 0%,
    rgba(224, 190, 114, 0.42) 42%,
    transparent 72%);
}

/* La deriva lateral evita que suban en línea recta */
@keyframes subirMota {
  0%   { opacity: 0; transform: translate3d(0, 0, 0) scale(0.5); }
  10%  { opacity: var(--alfa, 0.7); }
  50%  { transform: translate3d(var(--deriva, 20px), -55vh, 0) scale(1); }
  88%  { opacity: var(--alfa, 0.7); }
  100% { opacity: 0; transform: translate3d(0, -118vh, 0) scale(0.7); }
}

/* ═══════════════════════════════════════════════════════════════════
   ESTRUCTURA DE SECCIONES
   ═══════════════════════════════════════════════════════════════════ */

.bloque {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: clamp(5rem, 12vh, 9rem) clamp(1.25rem, 5vw, 3rem);
  perspective: var(--perspectiva);
  perspective-origin: 50% 40%;
  /* Las capas de luz sobresalen por los cuatro lados a propósito, para que
     sus degradados no se corten en seco. Aquí se recorta ese exceso.

     Se recortan los dos ejes, no solo el horizontal. La luz de sección
     tiene inset: -38%, así que sobresale un 38% del alto de la sección por
     abajo, y ese desborde alargaba el documento: al abrir el formulario la
     sección de confirmar crecía de 747 a 1500 px, con lo que la luz pasaba
     de rebasar 284 px a rebasar 570, se metía más allá del pie y añadía
     287 px de página vacía. Medido con el navegador. */
  overflow: clip;
}

/* Separador dorado tenue entre secciones */
.bloque + .bloque::before {
  content: '';
  position: absolute;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  width: min(420px, 60%);
  height: 1px;
  background: linear-gradient(90deg,
    transparent,
    var(--dorado-linea) 30%,
    var(--dorado-linea) 70%,
    transparent);
}

/* ---- El color de cada sección ----
   Los valores por defecto están arriba, en el :root principal: aquí
   quedarían DESPUÉS del bloque del tema claro y lo pisarían, que es lo
   que pasaba —el tema pedía 0,52 de tinte y se aplicaba 0,22—. */
/* Todos en la familia del sobre, que es calipso: su tono medido es 187°.
   Cada sección se mueve unos grados y cambia algo de luz, así que se
   distinguen entre sí pero se leen como el mismo juego —que es lo que
   pidió Kevin: que combinen con la carta y el sobre, no que compitan. */
#fecha      { --acento-a: 118 193 204; --acento-b:  86 164 178; }  /* calipso */
#verso      { --acento-a: 123 198 190; --acento-b:  92 170 166; }  /* agua verde */
#nosotros   { --acento-a: 117 182 209; --acento-b:  88 152 184; }  /* agua azul */
#itinerario { --acento-a: 141 214 213; --acento-b: 104 180 186; }  /* aguamarina */
#dresscode  { --acento-a: 124 193 176; --acento-b:  94 166 154; }  /* salvia */
#regalos    { --acento-a: 122 185 204; --acento-b:  90 156 178; }  /* turquesa */
#confirmar  { --acento-a: 126 204 190; --acento-b:  96 174 168; }  /* eucalipto */

/* Y de dónde entra la luz en cada una. Se alternan lados y alturas: leídas
   una tras otra, la luz parece moverse por la página en vez de repetirse. */
#fecha      { --foco-x: 24%; --foco-y: 22%; --foco2-x: 86%; --foco2-y: 84%; }
#verso      { --foco-x: 80%; --foco-y: 18%; --foco2-x: 14%; --foco2-y: 74%; }
#nosotros   { --foco-x: 16%; --foco-y: 72%; --foco2-x: 84%; --foco2-y: 24%; }
#itinerario { --foco-x: 64%; --foco-y: 10%; --foco2-x: 20%; --foco2-y: 86%; }
#dresscode  { --foco-x: 10%; --foco-y: 38%; --foco2-x: 78%; --foco2-y: 90%; }
#regalos    { --foco-x: 88%; --foco-y: 44%; --foco2-x: 24%; --foco2-y: 12%; }
#confirmar  { --foco-x: 32%; --foco-y: 84%; --foco2-x: 82%; --foco2-y: 18%; }

/* .papel se conserva para no romper el markup; da profundidad sutil. */
.papel {
  /* El mismo papel que el pie, para que el fondo sea uno solo de arriba
     abajo. El color lo pone el foco violeta de la regla de arriba. */
  background: var(--marino-profundo);
}

.bloque > * { position: relative; z-index: 1; }

/* ---- La luz de las secciones ----
   El mismo tratamiento que el pie, que es el que les gustó: un solo foco
   violeta muy desenfocado arriba a la izquierda sobre el papel casi
   blanco. Antes cada sección llevaba dos focos de su propio color y la
   mezcla salía turbia; uno solo, y el mismo para todas, da el aire que
   buscaban sin ensuciar.

   La portada no entra en el selector, así que conserva su ambiente. */
.bloque:not(#portada)::after {
  content: '';
  position: absolute;
  inset: -10% -20%;
  z-index: 0;
  pointer-events: none;
  /* El foco se mide en unidades de PANTALLA y no en porcentaje de la
     sección: en el pie, que es bajito, un 38%×44% da una mancha concreta;
     en una sección de 1.400 px el mismo porcentaje la estira tanto que se
     desvanece. Así se ve igual en todas, midan lo que midan. */
  background:
    radial-gradient(52vw 46vh at var(--foco-x) var(--foco-y),
      rgba(158, 120, 238, 0.34) 0%,
      rgba(120, 98, 196, 0.15) 42%,
      transparent 74%),
    radial-gradient(44vw 40vh at var(--foco2-x) var(--foco2-y),
      rgba(150, 126, 226, 0.16) 0%,
      transparent 72%);
  filter: blur(30px);
  opacity: 0;
  translate: calc(var(--luz-x, 0px) * 0.42) calc(var(--luz-y, 0px) * 0.42);
  transition: opacity 1500ms var(--ease-out), translate 440ms var(--ease-out);
}
/* Se encienden al abrir la carta, igual que el pie */
body.carta-abierta .bloque:not(#portada)::after { opacity: 1; }


/* ═══════════════════════════════════════════════════════════════════
   SISTEMA DE APARICIÓN 3D
   Solo transform + opacity. Curva ease-out. Escalonado de 60ms.
   ═══════════════════════════════════════════════════════════════════ */

.reveal {
  width: 100%;
  max-width: 780px;
  margin: 0 auto;
  text-align: center;
  transform-style: preserve-3d;
  opacity: 0;
  transform: rotateX(-18deg) translateZ(-170px) translateY(70px);
  transition:
    opacity   var(--t-entrada) var(--ease-out),
    transform var(--t-entrada) var(--ease-out);
}

.reveal.visible {
  opacity: 1;
  transform: rotateX(0deg) translateZ(0) translateY(0);
}

/* Escalonado de hijos: 90ms entre cada uno, y cada pieza entra levemente
   desenfocada y se enfoca al llegar —una cámara enfocando—. El keyframe
   solo declara el `from` y el relleno es backwards, no both: así, al
   terminar, el elemento vuelve a sus estilos de siempre y no se queda con
   un filter: blur(0) permanente, que en WebKit puede dejar el texto
   rasterizado borroso. */
.reveal.visible > * {
  animation: subirEnfoca 760ms var(--ease-out) backwards;
}
.reveal.visible > *:nth-child(1) { animation-delay:  90ms; }
.reveal.visible > *:nth-child(2) { animation-delay: 180ms; }
.reveal.visible > *:nth-child(3) { animation-delay: 270ms; }
.reveal.visible > *:nth-child(4) { animation-delay: 360ms; }
.reveal.visible > *:nth-child(5) { animation-delay: 450ms; }
.reveal.visible > *:nth-child(6) { animation-delay: 540ms; }
.reveal.visible > *:nth-child(7) { animation-delay: 630ms; }

@keyframes subirEnfoca {
  from { opacity: 0; transform: translateZ(-60px) translateY(30px); filter: blur(7px); }
}

/* ═══════════════════════════════════════════════════════════════════
   TARJETA DE VIDRIO (superficie base de las secciones)
   ═══════════════════════════════════════════════════════════════════ */

#fecha .reveal,
#verso .reveal,
#itinerario .reveal,
#dresscode .reveal,
#regalos .reveal,
#confirmar > div.reveal {
  /* Dos capas: un velo violeta muy tenue del lado del foco de la página,
     sobre el marino semitransparente. Con la base al 36% la luz de la
     sección se cuela desde atrás; el velo la sostiene también donde esa
     luz está apagada, para que el tinte no aparezca y desaparezca. */
  /* Casi sin velo: apenas un 4% para que el vidrio no se vea gris del todo
     cuando la luz de la sección está apagada. El color lo aporta esa luz al
     pasar por detrás, y por eso cambia con el scroll.
     La saturación alta es lo que hace que el violeta se lea al atravesar. */
  /* Transparentes: la tarjeta ya no es una superficie, es un marco. Así
     el fondo de la página pasa entero por detrás y se lee como una sola
     pieza, que es lo que se pidió. Sin relleno no hace falta desenfocar
     lo de atrás, así que se retira el backdrop-filter: era el efecto más
     caro de la página y ya no pintaba nada. */
  background: none;
  border: 1px solid var(--tarjeta-borde);
  border-radius: 3px;
  box-shadow: var(--tarjeta-sombra);
  padding: clamp(2.5rem, 6vw, 4.5rem) clamp(1.5rem, 5vw, 3.5rem);
}

/* "Nuestra Boda" va más traslúcida que las demás y con más violeta: es la
   primera sección tras la carta, la que hereda el ambiente de la apertura. */
#fecha .reveal {
  /* Sin velo violeta. Antes llevaba uno y lo que hacía era teñir el cuadro
     de morado de forma constante. El morado tiene que venir de la luz que
     pasa por detrás, que se desplaza con el scroll: así el color cambia al
     avanzar en vez de quedarse plano.
     La saturación alta del filtro es la que hace que ese violeta se lea al
     atravesar el vidrio. */
  background: none;
  border-color: rgb(var(--acento-a) / 0.24);
}

/* Y su luz de sección entra con más fuerza */
/* (La luz propia de #fecha se retiró con la del resto de las secciones.) */

/* ---- Las estrellas de El Lugar, también en papel ----
   En noche la sección flota sobre el cielo estrellado; en claro quedaba
   plana. El mismo campo de estrellas, entintado: el asset trae estrellas
   claras para fondo oscuro, así que se invierte y se dora con un filtro,
   y se mezcla en multiply para que entinte el papel en vez de aclararlo.
   Más denso arriba —es cielo— y desvanecido hacia el pie de la tarjeta. */
[data-tema="claro"] #itinerario .reveal { isolation: isolate; }
[data-tema="claro"] #itinerario .reveal::before {
  content: '';
  position: absolute;
  inset: 1px;              /* dentro del borde de la tarjeta */
  z-index: -1;
  border-radius: 2px;
  /* El mismo tile dos veces, a dos escalas: dos planos de estrellas que
     derivan a velocidades distintas —paralaje— y el campo cobra vida. */
  background:
    url('assets/estrellas.webp') repeat,
    url('assets/estrellas.webp') repeat;
  background-size: 900px 900px, 620px 620px;
  /* Fucsia: el sepia deja las estrellas en pardo (~40° de tono) y la
     rotación de +280° las lleva al magenta. */
  filter: invert(0.72) sepia(1) saturate(7.5) hue-rotate(283deg) brightness(0.9);
  opacity: 0.55;
  -webkit-mask-image: linear-gradient(180deg, #000 0%, rgb(0 0 0 / 0.5) 62%, rgb(0 0 0 / 0.2) 100%);
  mask-image: linear-gradient(180deg, #000 0%, rgb(0 0 0 / 0.5) 62%, rgb(0 0 0 / 0.2) 100%);
  pointer-events: none;
  /* Deriva en bucle perfecto (recorridos múltiplos de cada tile) y una
     respiración lenta de la luz. */
  animation:
    estrellasDeriva 60s linear infinite,
    estrellasRespira 5.5s var(--ease-in-out) infinite alternate;
}
@keyframes estrellasDeriva {
  from { background-position: 0 0, 0 0; }
  to   { background-position: -900px 450px, 620px -930px; }
}
@keyframes estrellasRespira {
  from { opacity: 0.4; }
  to   { opacity: 0.68; }
}
@media (prefers-reduced-motion: reduce) {
  [data-tema="claro"] #itinerario .reveal::before { animation: none; }
}

/* Marco dorado interior */
#fecha .reveal::after,
#verso .reveal::after,
#itinerario .reveal::after,
#dresscode .reveal::after,
#regalos .reveal::after,
#confirmar > div.reveal::after {
  content: '';
  position: absolute;
  inset: 10px;
  border: 1px solid rgb(var(--oro-rgb) / 0.13);
  border-radius: 2px;
  pointer-events: none;
}

/* ═══════════════════════════════════════════════════════════════════
   TIPOGRAFÍA COMPARTIDA
   ═══════════════════════════════════════════════════════════════════ */

.seccion-script,
.nuestra-boda,
.itin-titulo {
  font-family: var(--script);
  font-size: clamp(3rem, 7.5vw, 4.8rem);
  font-weight: 400;
  line-height: 1.15;
  margin: 0 0 1.6rem;
  color: var(--dorado);
  /* Dos halos: el dorado de siempre y uno del acento, más abierto. El
     título sigue siendo de oro, pero respira el color de su sección. */
  text-shadow:
    0 2px 24px rgb(var(--oro-rgb) / 0.22),
    0 6px 44px rgb(var(--acento-a) / 0.3);
}

/* «Nuestra Boda» deja la caligrafía: cursiva editorial de alto contraste,
   la misma de los nombres de la portada. Más moderna, y hermana el título
   con «Kevin y Belén». El oro y los halos se quedan. */
.nuestra-boda {
  font-family: 'Playfair Display', var(--serif);
  font-style: italic;
  font-size: clamp(2.3rem, 6vw, 3.6rem);
  letter-spacing: 0.01em;
}

.seccion-sub {
  font-family: var(--serif);
  font-size: clamp(1.5rem, 4vw, 2.15rem);
  font-weight: 400;
  letter-spacing: 0.05em;
  color: var(--marfil);
  margin: 0 0 1.5rem;
}

/* Sombra apenas perceptible: con la tarjeta traslúcida el fondo se
   asoma, y esto despega el texto sin oscurecerlo. */
.verso-texto,
.intro-boda,
.dc-texto,
.reg-texto,
.conf-texto,
.lugar-dir,
.lugar-nombre { text-shadow: 0 1px 12px var(--sombra-texto); }

.dc-texto,
.reg-texto,
.conf-texto,
.intro-boda {
  font-family: var(--serif);
  font-size: clamp(1.12rem, 2.7vw, 1.38rem);
  font-weight: 400;
  line-height: 1.95;
  letter-spacing: 0;         /* cuerpo: tracking neutro */
  color: var(--marfil-medio);
  margin: 0 0 1.5rem;
}

/* ═══════════════════════════════════════════════════════════════════
   BOTONES
   Hover: 170ms, solo transform + color. Gate de hover más abajo.
   ═══════════════════════════════════════════════════════════════════ */

.btn-linea {
  display: inline-block;
  padding: 0.95rem 2.6rem;
  font-family: var(--sans);
  font-size: 0.82rem;
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--oro-texto);
  /* Relleno tenue y borde más marcado: sobre un cuadro traslúcido un
     contorno a 0.32 de opacidad casi no se veía, y estos botones son el
     elemento principal de Regalos y de Confirmar. */
  background: rgb(var(--oro-rgb) / 0.09);
  /* 0.70 y no menos: en el cuadro de "Nuestra Boda", el más traslúcido,
     a 0.55 el contorno daba 2.6:1 y no alcanzaba el mínimo de 3:1 que
     necesita el borde de un control para distinguirse. */
  border: 1px solid var(--boton-borde);
  border-radius: 2px;
  cursor: pointer;
  transform-style: preserve-3d;
  transition:
    color        var(--t-hover) var(--ease-out),
    border-color var(--t-hover) var(--ease-out),
    background   var(--t-hover) var(--ease-out),
    transform    var(--t-hover) var(--ease-out);
}

.btn-linea:focus-visible {
  outline: 2px solid var(--dorado);
  outline-offset: 3px;
}

/* La pulsación es más rápida que la entrada: el sistema responde seco. */
.btn-linea:active { transform: translateZ(6px) scale(0.985); transition-duration: var(--t-press); }

.btn-linea.grande {
  padding: 1.15rem 3.2rem;
  font-size: 0.8rem;
}

/* ═══════════════════════════════════════════════════════════════════
   1 · PORTADA
   ═══════════════════════════════════════════════════════════════════ */

#portada {
  min-height: 100vh;
  min-height: 100svh;
  padding-top: clamp(2rem, 5vh, 4rem);
  padding-bottom: clamp(2rem, 5vh, 4rem);
  background:
    radial-gradient(ellipse 80% 60% at 50% 35%, var(--marino-alto) 0%, transparent 65%),
    linear-gradient(170deg, var(--marino) 0%, var(--marino-profundo) 100%);
  overflow: hidden;
}

/* Halos suaves detrás del sobre (reemplazan las flores).
   Se animan con transform únicamente. */
#portada::before,
#portada::after {
  content: '';
  position: absolute;
  border-radius: 50%;
  pointer-events: none;
  z-index: 0;
  filter: blur(70px);          /* estático, no animado */
  will-change: transform;
}
#portada::before {
  width: min(460px, 70vw);
  aspect-ratio: 1;
  top: 6%;
  left: -8%;
  background: var(--azul-tenue);
  animation: flotarHalo 18s var(--ease-in-out) infinite;
  /* translate es independiente de transform y se compone con él, así que
     puede seguir al puntero sin estorbar a la animación de flotado. */
  translate: calc(var(--luz-x, 0px) * 0.6) calc(var(--luz-y, 0px) * 0.6);
  transition: translate 420ms var(--ease-out);
}
#portada::after {
  width: min(380px, 60vw);
  aspect-ratio: 1;
  bottom: 4%;
  right: -6%;
  background: var(--violeta-tenue);
  animation: flotarHalo 24s var(--ease-in-out) infinite reverse;
  /* Sentido contrario y menor recorrido: la diferencia entre capas es lo
     que produce la sensación de profundidad. */
  translate: calc(var(--luz-x, 0px) * -0.38) calc(var(--luz-y, 0px) * -0.38);
  transition: translate 480ms var(--ease-out);
}

@keyframes flotarHalo {
  0%, 100% { transform: translate3d(0, 0, 0) scale(1); }
  50%      { transform: translate3d(30px, -40px, 0) scale(1.12); }
}

/* --- LA CARTA ---------------------------------------------------------
   Tres piezas recortadas del sobre abierto original (sobre-atras.png y
   sobre-frente.png), cada una en su propio archivo:

     El sobre vuelve a ser azul: lo pidió Belén. Las imágenes calipso
     (*-verde.webp, tono 188°) siguen en el repositorio por si cambian de
     idea — volver a ellas es cambiar estos tres nombres. El recorte del
     borde está arreglado en las dos versiones: se hizo sobre los azules
     originales y de ahí se derivaron los otros. El giro se hizo sobre la imagen y no con el
     hue-rotate del CSS porque ese satura hasta el tope y saca un verde
     casi negro — medido: 0,85 de saturación pasaba a 0,98.

     carta-cuerpo.png    654x486  la pared interior y el fondo
     carta-tapa.png      654x364  el triángulo, por su CARA INTERIOR
     carta-bolsillo.png           el frente con la muesca en V

   La caja mide lo mismo que el cuerpo, así que el sobre cerrado la llena.
   La tapa cuelga por fuera del borde superior y gira sobre su bisagra,
   que coincide con ese borde: cerrada apunta hacia abajo y tapa el
   bolsillo; abierta queda de pie, exactamente como en la foto original.

   Se usa la cara interior porque es la que se ve al abrir. Cerrada se ve
   su reverso, que en un tejido así es indistinguible.
   ------------------------------------------------------------------- */

.carta {
  position: relative;
  width: 100%;
  /* Limitada por alto además de por ancho: con razón 654/486, un ancho
     de 46vh deja unos 34vh de alto, y así el hero completo cabe en
     pantallas bajas sin cortar el reproductor. */
  max-width: min(520px, 46vh);
  aspect-ratio: 654 / 486;
  margin: 0 auto;
  z-index: 1;              /* por delante de .carta-luz */

  /* Aplanada a propósito, sin preserve-3d. No hacía falta: .carta-escena no
     propaga la perspectiva de .bloque, así que la tapa gira sin perspectiva
     igual con 3D que sin él (comparado cuadro a cuadro en WebKit y en
     Chromium: diferencia de 0 en 1,15 millones de píxeles).

     Lo único que aportaba era el problema: dentro de un contexto 3D todas
     las piezas del sobre quedan en el mismo plano y el orden de pintado no
     está definido, así que cada motor decide. En iOS la foto se pintaba
     DELANTE del bolsillo y parecía meterse en el sobre desde afuera en vez
     de salir de dentro. Aplanada, el orden lo fija el z-index por norma:
     cuerpo 1, foto 2, bolsillo 3, tapa 6, sello 8. */
  transform-style: flat;

  /* El sobre es de tela azul marino en los dos temas, así que su sombreado
     interior no se suaviza con el tema claro: la sombra de la tapa, la del
     canto de la foto y la del sello siguen siendo oscuras. */
  --sombra-k: 1;

  animation: entrarCarta 1000ms var(--ease-out) 200ms both;
}

@keyframes entrarCarta {
  from { opacity: 0; transform: perspective(1400px) rotateX(24deg) translateY(36px) scale(0.92); }
  to   { opacity: 1; transform: perspective(1400px) rotateX(0deg)  translateY(0)    scale(1); }
}

/* --- Campo de luz alrededor del sobre ---
   Va en un hermano anterior a la carta, nunca dentro: en .carta compartía
   plano con las piezas del sobre y el orden lo decidía la profundidad 3D,
   no el z-index, así que o se pintaba sobre la tela o desaparecía.

   Son cinco lóbulos independientes, no un solo degradado. Cada uno lleva
   su propio factor de seguimiento del puntero, su deriva lenta y su
   respiración de intensidad, todos distintos. Al mover el ratón se
   separan a ritmos diferentes, de modo que el campo se dispersa y se
   recompone en lugar de viajar rígido.

   Son grandes y muy desenfocados a propósito: así se leen como una
   atmósfera continua y no como manchas circulares. */

/* --- La rama azul de "Nosotros" ---
   Entra tumbada por el canto derecho y se extiende hacia la izquierda, por el
   costado que quedaba vacío sobre la baraja de fotos.

   El giro es de -84° y no de -90°: la imagen original crece hacia arriba desde
   el tallo, así que al girarla el tallo queda a la derecha, entrando por el
   borde, y las flores se abren hacia dentro. Los seis grados que faltan evitan
   que quede clavada en la horizontal, que se lee como un recorte y no como una
   rama.

   Se posiciona con el ancho SIN girar; al girar, ese ancho pasa a ser el alto
   visible y el alto pasa a ser lo que se extiende a lo ancho. */
.flores-nosotros {
  position: absolute;
  /* Origen al centro: girando desde otro punto la caja se va lejos del sitio
     donde se la posiciona, y así quedaba un 74% fuera de pantalla. Con el
     centro, la caja girada queda centrada donde está la sin girar, y basta
     colocar esa.

     La caja girada mide 1,80 veces el ancho a lo ancho y 1,17 a lo alto
     (cos y sen de 84° sobre una imagen de razón 0,587). */
  top: -1%;
  right: 4.5%;
  width: clamp(150px, 19vw, 268px);
  height: auto;
  z-index: 1;
  pointer-events: none;
  opacity: 0;
  transform-origin: 50% 50%;
  transform: rotate(-84deg) translateY(24px);
  filter: drop-shadow(0 18px 34px rgb(var(--sombra-rgb) / calc(0.42 * var(--sombra-k))));
  transition:
    opacity   1200ms var(--ease-out) 320ms,
    transform 1200ms var(--ease-out) 320ms;
}

#nosotros .reveal.visible ~ .flores-nosotros {
  opacity: 0.9;
  transform: rotate(-84deg) translateY(0);
}

/* En el teléfono el texto de la sección ocupa todo el ancho, así que la rama no
   puede cruzar por delante: se recoge en la esquina de arriba, por encima del
   nombre de la sección, y entra igual por el canto derecho. */
@media (max-width: 640px) {
  .flores-nosotros {
    top: -3%;
    right: -6%;
    width: clamp(96px, 26vw, 132px);
  }
}

/* --- La flor de la sección de la fecha ---
   La ficha mide 780 px y su texto solo ocupa 384: quedan casi 200 px vacíos a
   cada lado, y eso es lo que se veía desangelado. La flor ocupa ese margen como
   una lámina botánica al costado de una tarjeta, sin acercarse al texto.

   Va en el hueco izquierdo, no centrada ni repetida a los dos lados: una sola
   pieza descentrada acompaña; dos la enmarcarían y la volverían simétrica.

   Entra con la sección, no al cargar, y con su propio retardo para que llegue
   después del texto. */
.flor-fecha {
  position: absolute;
  /* Pegada al canto izquierdo, con el corte del tallo fuera de cuadro:
     la rama horizontal entra de la pantalla, no de un borde visible. */
  left: -1.5rem;
  top: 26%;
  width: clamp(300px, 31vw, 470px);
  height: auto;
  z-index: 1;
  pointer-events: none;
  opacity: 0;
  /* Entra deslizando desde la izquierda, de donde viene la rama */
  transform: translateX(-30px) rotate(calc(var(--flor-f-giro, -4deg) - 2deg));
  filter: drop-shadow(0 14px 26px rgb(var(--sombra-rgb) / calc(0.45 * var(--sombra-k))));
  transition:
    opacity   1100ms var(--ease-out) 420ms,
    transform 1100ms var(--ease-out) 420ms;
}

#fecha .reveal.visible ~ .flor-fecha {
  opacity: 0.9;
  transform: translateX(0) rotate(var(--flor-f-giro, -4deg));
}

/* --- La anémona, al costado del versículo ---
   Se ancla por su canto DERECHO y no por el izquierdo: lo que no puede tocar
   es la tinta del versículo, y esa empieza siempre 57 px dentro de la ficha
   —medido de 1024 a 1600—. Anclada por la derecha, la flor crece hacia el
   margen vacío y el aire hasta la primera letra no cambia con el ancho. */
.flor-anemona {
  position: absolute;
  /* La ficha mide 780 y va centrada: su canto está en 50% - 390. Con 345 la
     flor entra 45 px sobre el marco y aún quedan 12 hasta la letra. */
  right: calc(50% + 345px);
  /* Algo por debajo del centro: a media altura quedaría enfrentada al texto
     y se leería como un adorno puesto; más abajo lo acompaña. */
  top: 42%;
  width: clamp(120px, 12vw, 176px);
  height: auto;
  z-index: 1;
  pointer-events: none;
  opacity: 0;
  transform: translateY(20px) rotate(calc(var(--flor-a-giro, -8deg) - 4deg));
  filter: drop-shadow(0 16px 30px rgb(var(--sombra-rgb) / calc(0.5 * var(--sombra-k))));
  transition:
    opacity   1150ms var(--ease-out) 520ms,
    transform 1150ms var(--ease-out) 520ms;
}

#verso .reveal.visible ~ .flor-anemona {
  opacity: 0.92;
  transform: translateY(0) rotate(var(--flor-a-giro, -8deg));
}

/* Bajo los 992 px el margen izquierdo se acaba —a 900 quedan 53 px hasta el
   canto de la ficha, a 760 solo 38—, y la flor anclada al versículo saldría
   casi entera fuera de la pantalla. Baja entonces a la esquina de abajo a la
   izquierda, que sigue libre en toda esa franja. */
@media (max-width: 62em) {
  .flor-anemona {
    right: auto;
    left: -3vw;
    top: auto;
    /* No sangra por abajo: la sección lleva overflow clip, así que asomar por
       el canto inferior no deja la flor «saliendo», la corta con una recta.
       Por el costado sí puede, porque ahí el corte coincide con el borde de
       la pantalla y se lee como que sigue fuera. */
    bottom: 0.7rem;
    width: clamp(96px, 15vw, 136px);
    --flor-a-giro: -7deg;
  }
}

/* --- El lisianthus del lado de Belén ---
   No es el espejo de las orquídeas, a propósito. La izquierda es una masa
   ancha y baja; esta es un tallo esbelto y más alto, de una sola flor. Así las
   dos esquinas se equilibran en diagonal en vez de quedar simétricas, que es
   lo que haría que se viera puesto y no compuesto.

   Entra después de las orquídeas, no a la vez: primero el lado de Kevin, luego
   el de Belén. Ese escalonado es lo que da la sensación de que la escena se
   arma sola.

   Se inclina al contrario que las orquídeas, abriéndose hacia fuera, para que
   las dos parezcan crecer desde los cantos y no apuntar al centro. */
/* El envoltorio <picture> del ramo no debe generar caja: sin esto recibe
   el position:relative de los hijos del bloque, mide 0x0, y el ramo
   (absoluto y con max-width 100%) desaparece dentro de él. */
#portada picture { display: contents; }

.flor-belen {
  position: absolute;
  /* En pantalla ancha el ramo entra CORTADO por el canto izquierdo de la
     ventana, a la altura del sobre, con el tallo fuera de cuadro (la imagen
     va espejada para que el tallo apunte a la izquierda). El punto exacto
     lo mide el script contra el sobre real; esto es solo el arranque. */
  left: -8rem;
  top: 42%;
  bottom: auto;
  /* Más presencia: el ramo de tulipanes venía viéndose chico — el PNG
     traía margen alrededor (ya recortado) y este ancho era conservador. */
  width: clamp(160px, 17vw, 270px);
  height: auto;
  /* Por delante del sobre: la rama queda apoyada SOBRE la tela, no
     asomando por detrás. El 3 le gana al contexto 3D de la carta. */
  z-index: 3;
  /* Sin velo: apoyada sobre la tela, cualquier transparencia la apagaba */
  --flor-b-alfa: 0.98;
  pointer-events: none;
  opacity: 0;
  /* Casi tumbada: entra por el canto derecho con los tallos saliendo por
     fuera, de derecha a izquierda. */
  /* Girada al lado contrario que en el teléfono: la imagen viene espejada */
  --flor-b-giro: 74deg;
  --flor-b-dx: -26px;   /* entra deslizando desde la izquierda */
  transform-origin: 50% 50%;
  filter: drop-shadow(0 16px 30px rgb(var(--sombra-rgb) / calc(0.5 * var(--sombra-k))));
  animation: entrarFlorBelen 1700ms var(--ease-out) 1750ms both;
}

/* La opacidad final sale de una variable, igual que en las orquídeas: la
   animación usa fill: both y sostiene el valor, así que declararla aparte no
   serviría. Se ajusta por tramo. */
@keyframes entrarFlorBelen {
  from { opacity: 0; transform: translate3d(var(--flor-b-dx, 26px), 34px, 0) rotate(calc(var(--flor-b-giro, -10deg) - 6deg)) scale(0.94); }
  to   { opacity: var(--flor-b-alfa, 0.88); transform: translate3d(0, 0, 0) rotate(var(--flor-b-giro, -10deg)) scale(1); }
}

/* Al abrir el sobre se aparta un poco, como las orquídeas: cede el escenario
   sin desaparecer. */
body.carta-abierta .flor-belen {
  scale: 0.97;
  transition: scale 950ms var(--ease-out) 700ms;
}

.carta-escena {
  position: relative;
  display: flex;
  justify-content: center;
  width: 100%;
  margin: clamp(1.6rem, 4vh, 2.6rem) auto clamp(1rem, 2.4vh, 1.6rem);
}

.carta-luz {
  position: absolute;
  left: 50%;
  top: 50%;
  width: min(1150px, 124vw);
  height: min(880px, 108vh);
  transform: translate(-50%, -50%);
  z-index: 0;
  pointer-events: none;
  opacity: 0;
  transition: opacity 2400ms var(--ease-out);
}
body.carta-abierta .carta-luz { opacity: 1; transition-delay: 420ms; }

.luz-lobulo {
  position: absolute;
  border-radius: 50%;
  /* El desenfoque va en cada lóbulo, no en el conjunto: así se difuminan
     entre ellos al superponerse. */
  filter: blur(58px);
  will-change: transform, opacity;
  /* --mx y --my: cuánto de lo que hace el puntero le toca a este lóbulo */
  translate: calc(var(--luz-x, 0px) * var(--mx))
             calc(var(--luz-y, 0px) * var(--my));
  transition: translate 520ms var(--ease-out);
  animation:
    derivarLobulo var(--dur) var(--ease-in-out) infinite alternate,
    respirarLobulo var(--pulso) var(--ease-in-out) infinite alternate;
}

/* Cada lóbulo: sitio, tamaño, color, reparto del puntero y tiempos.
   Todos nacen en el perímetro del sobre o fuera; lo que cae detrás de la
   tela no se ve, porque la tela es opaca. */
.luz-lobulo:nth-child(1) {
  left: 4%;  top: 6%;  width: 46%; height: 52%;
  background: radial-gradient(circle at 50% 50%, rgb(104 196 208 / 0.44), transparent 68%);
  --mx: 0.72; --my: 0.60; --dur: 17s; --pulso: 11s;
}
.luz-lobulo:nth-child(2) {
  left: 58%; top: 40%; width: 42%; height: 46%;
  background: radial-gradient(circle at 50% 50%, rgb(120 178 200 / 0.40), transparent 70%);
  --mx: -0.48; --my: 0.34; --dur: 23s; --pulso: 15s;
  animation-delay: -6s, -3s;
}
.luz-lobulo:nth-child(3) {
  left: 20%; top: 56%; width: 40%; height: 38%;
  background: radial-gradient(circle at 50% 50%, rgb(96 172 186 / 0.34), transparent 72%);
  --mx: 0.30; --my: -0.55; --dur: 19s; --pulso: 13s;
  animation-delay: -11s, -7s;
}
.luz-lobulo:nth-child(4) {
  left: -2%; top: 34%; width: 26%; height: 50%;
  background: radial-gradient(circle at 50% 50%, rgb(130 200 206 / 0.30), transparent 74%);
  --mx: 0.90; --my: -0.22; --dur: 27s; --pulso: 9s;
  animation-delay: -3s, -5s;
}
.luz-lobulo:nth-child(5) {
  left: 52%; top: -4%; width: 34%; height: 34%;
  background: radial-gradient(circle at 50% 50%, rgb(112 186 198 / 0.28), transparent 72%);
  --mx: -0.34; --my: 0.68; --dur: 21s; --pulso: 17s;
  animation-delay: -14s, -10s;
}

/* Deriva lenta: el campo nunca queda del todo quieto */
@keyframes derivarLobulo {
  from { transform: translate3d(0, 0, 0) scale(1); }
  to   { transform: translate3d(6%, -5%, 0) scale(1.16); }
}

/* Respiración: la intensidad sube y baja, cada uno a su tiempo */
@keyframes respirarLobulo {
  from { opacity: 0.55; }
  to   { opacity: 1; }
}

/* Sombra de apoyo */
.carta::after {
  content: '';
  position: absolute;
  left: 6%; right: 6%; bottom: -5%;
  height: 32px;
  background: radial-gradient(ellipse at center, rgb(var(--sombra-rgb) / calc(0.6 * var(--sombra-k))), transparent 74%);
  filter: blur(15px);
  z-index: 0;
}

/* Pared interior: es la foto real del interior del sobre */
.carta-cuerpo {
  position: absolute;
  inset: 0;
  z-index: 1;
  background: url('assets/carta-cuerpo.webp') center / 100% 100% no-repeat;
  /* Se retiró el contorno con box-shadow: al ser el cuerpo rectangular,
     calcaba su borde con exactitud y se leía como un marco dibujado. La
     luz irregular de .carta-luz hace ese trabajo mejor. */
}

/* Bolsillo delantero. Su alto sale de la razón de la imagen recortada
   (1.4139) llevada al ancho de la caja. */
.carta-bolsillo {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 95.18%;
  z-index: 3;
  background: url('assets/carta-bolsillo.webp') center bottom / 100% 100% no-repeat;
  /* Sin translateZ. Se le había puesto 6px "para dejar el orden explícito",
     y el efecto fue el contrario: al ser la única pieza con profundidad, se
     adelantó también a la tapa cerrada y al sello, que quedaron detrás.
     Las cinco piezas van al mismo plano y el orden lo dan sus z-index, que
     ya estaban bien: cuerpo 1, lámina 2, bolsillo 3, tapa 6, sello 8. */
}

/* La tapa: cuelga hacia arriba del borde superior y gira sobre él */
.carta-tapa {
  position: absolute;
  left: 0; right: 0;
  bottom: 100%;                 /* justo encima de la caja */
  height: 74.90%;               /* 364 / 486 */
  z-index: 6;
  background: url('assets/carta-tapa.webp') center / 100% 100% no-repeat;
  transform-origin: 50% 100%;   /* la bisagra es el borde de abajo */
  transform: rotateX(180deg);   /* en reposo está cerrada */
  will-change: transform;
}

.carta.abierta .carta-tapa {
  animation: abrirTapa 1150ms var(--ease-in-out) 300ms both;
}

/* El z-index cae al pasar de canto, para que la lámina la sobrepase */
@keyframes abrirTapa {
  0%   { transform: rotateX(180deg); z-index: 6; }
  49%  { z-index: 6; }
  50%  { z-index: 0; }
  100% { transform: rotateX(0deg);   z-index: 0; }
}

/* La tapa NO lleva capa oscura encima. Llevaba una, de 0,42 abajo a 0,16
   arriba, puesta para igualar su reverso al tono del frente. Medido, no hacía
   falta y era la causa de que el sobre cerrado se viera de dos colores: la
   tapa sola da luma 26,3 y el bolsillo 26,2, así que ya coincidían. La capa
   restaba hasta 1,7 de luma justo en el canto de la costura, que es donde el
   ojo compara, y de ahí salía la línea. */

/* Recorta al ras del borde inferior del sobre, con holgura arriba para que
   la foto pueda subir por encima de la carta. El recorte es fijo: no se
   anima nada aquí, así que no puede quedarse a medias. Eso importa porque
   la versión anterior animaba clip-path sobre la lámina y en iOS el último
   fotograma no se repintaba: la foto quedaba cortada por arriba, sin cielo.

   La línea de corte no va en el borde de la caja sino un 1,6% por dentro.
   Las piezas del sobre tienen el canto inferior difuminado: en
   carta-bolsillo.webp las últimas siete filas suben de alfa 0 a 255, así
   que el borde opaco está a un 0,86% del alto de la carta por encima del
   borde de la caja. Recortando al ras, la foto asomaba por esa franja
   semitransparente. Con el 1,6% queda casi el doble de holgura, y lo que
   se recorta de más está detrás del bolsillo opaco, donde no se ve.

   top: -100% con bottom: 1,6% deja el contenedor en 1,984 veces el alto de
   la carta, y los porcentajes de la lámina se calculan sobre esa altura. */
.carta-ranura {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 1.6%;
  top: -100%;
  overflow: hidden;
  z-index: 2;
  pointer-events: none;
}

/* La lámina con la foto: empieza con su borde superior justo en el fondo de
   la V, o sea invisible, y sube al abrir.

   El -15,97% sale de la geometría, no del tanteo: la V del bolsillo tiene
   su vértice al 48,62% del alto de la carta (medido en el canal alfa de
   carta-bolsillo.webp) y la foto mide el 82,53% de ese alto, así que para
   apoyar su borde superior en el vértice tiene que asomar un 33,55% del
   alto de la carta por debajo de la línea de corte. Sobre el contenedor,
   que mide 1,984 veces la carta, eso es el 16,91%. Ese tramo lo recorta el
   contenedor. Lleva 0,8 puntos de sobra por debajo del vértice, para que
   ni el redondeo ni el giro de 1,5° dejen asomar una tira. */
.carta-lamina {
  position: absolute;
  left: 50%;
  bottom: -16.91%;
  /* El ancho es el 46% de la carta; el alto va en porcentaje y no con
     aspect-ratio porque los motores no coinciden: WebKit aplica la razón a
     la caja de contenido y le suma los 6 px del marco, Chromium la aplica a
     la caja completa. Medido, la foto salía al 87,83% del alto de la carta
     en WebKit contra el 82,61% en Chromium, y esos cinco puntos la hacían
     asomar por la V antes de subir. Con el alto fijado los dos coinciden.

     41,263% del contenedor, que mide el doble que la carta, es el 82,527%
     del alto de la carta: el 46% de ancho por la razón 3/4 de la carta.

     Kevin pidió la foto más grande: del 46% al 54% de ancho. El alto sube
     en la misma proporción para no deformarla: 41,263 × 54/46 = 48,44.

     El 58% que se probó primero era demasiado: tapaba la solapa de lado a
     lado y ya no se leía como una foto saliendo del sobre, sino pegada
     encima. */
  width: 54%;
  height: 48.44%;
  overflow: hidden;
  background: var(--marino-alto);
  border: 6px solid var(--papel);
  border-radius: 2px;
  /* Sombra de contacto, ceñida y hacia abajo: la echa sobre la pared
     interior y sobre la tapa, que quedan detrás. Una sombra amplia la
     haría flotar. */
  box-shadow:
    0 3px 8px rgb(var(--sombra-rgb) / calc(0.55 * var(--sombra-k))),
    0 14px 26px -8px rgb(var(--sombra-rgb) / calc(0.5 * var(--sombra-k)));
  transform: translateX(-50%) rotate(-1.5deg);
  /* Sin will-change. Promovía la lámina a su propia capa, y en iOS una capa
     promovida puede componerse por encima de hermanos sin promover pese al
     z-index. La animación es de una sola vez y el navegador la promueve solo
     mientras corre; el aviso previo no aportaba nada y sí podía estorbar. */
}

/* El tramo de abajo queda en penumbra, como corresponde a lo que aún está
   metido en el sobre. Es lo que hace que se lea saliendo de la ranura y no
   apoyada encima. */
.carta-lamina::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(to top,
    rgba(4, 10, 18, 0.72) 0%,
    rgba(4, 10, 18, 0.34) 12%,
    rgba(4, 10, 18, 0.10) 26%,
    transparent 42%);
  opacity: 1;
  transition: opacity 1300ms var(--ease-out);
}
/* Al salir, la penumbra cede: lo que ya está fuera recibe luz */
.carta.abierta .carta-lamina::after {
  opacity: 0.34;
  transition-delay: 950ms;
}

.carta-lamina img { width: 100%; height: 100%; object-fit: cover; }

.carta.abierta .carta-lamina {
  animation: subirLamina 1300ms var(--ease-out) 950ms both;
}

/* Sube hasta asomar por encima del sobre, pero su borde de abajo queda
   metido en el bolsillo: así se lee que sale de dentro. */
/* Sin avance en Z, ni 14 px ni ninguno: la lámina tiene que quedar detrás
   del bolsillo, y ahora que .carta está aplanada eso lo decide el z-index.
   Cuando .carta era preserve-3d, cualquier translateZ positivo la adelantaba
   al bolsillo y este dejaba de taparle el canto: la foto salía entera. */
/* Sube un 73,58% de su propio alto: la lleva desde el vértice de la V hasta
   la misma posición final que ya tenía, con el 26% de abajo dentro del
   bolsillo. El recorte del contenedor deja de tocarla cuando su canto
   inferior pasa el borde del sobre, a un 38,7% de la subida. */
/* Cuánto sube, en porcentaje del alto de la propia foto. Se probaron
   cinco valores mirando el resultado —62,7 / 56 / 50 / 44 / 38— porque lo
   que decide no es una cuenta sino dónde queda el MARCO BLANCO de la foto
   respecto de la V del bolsillo: subiendo de más, su borde inferior asoma
   y la diagonal de la V lo corta en seco, que es lo que se veía mal.

   Ahora sube el 58%, que es lo que se pidió: asoma más y la pareja entera
   queda por encima de la V. Comprobado con 62, 66, 70 y 74 —a partir de
   ahí la foto se despega del sobre y su canto inferior se acerca al
   bolsillo—, así que 58 es lo que gana sin romper el marco. */
@keyframes subirLamina {
  from { transform: translateX(-50%) translateY(0)    rotate(-1.5deg); }
  to   { transform: translateX(-50%) translateY(-58%) rotate(-1.5deg); }
}

/* --- El sello: centrado en el vértice de la tapa cerrada ---
   Con la tapa cerrada, su vértice cae al 74.9% del alto de la tapa
   medido desde el borde superior de la caja. */
.carta-sello {
  position: absolute;
  left: 50%;
  top: 63%;
  width: clamp(74px, 15%, 96px);
  aspect-ratio: 1;
  z-index: 8;
  display: grid;
  place-items: center;
  padding: 0;
  background: none;
  border: none;
  cursor: pointer;
  transform: translate(-50%, -50%);
  animation: entrarSello 700ms var(--ease-out) 1000ms both;
}

.carta-sello img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  filter: drop-shadow(0 6px 14px rgb(var(--sombra-rgb) / calc(0.7 * var(--sombra-k))));
  transition: transform var(--t-hover) var(--ease-out);
}

@keyframes entrarSello {
  from { opacity: 0; transform: translate(-50%, -50%) scale(1.9) rotate(-20deg); }
  to   { opacity: 1; transform: translate(-50%, -50%) scale(1)   rotate(0deg); }
}

.carta-sello:active img { transform: scale(0.94); transition-duration: 100ms; }
.carta-sello:focus-visible { outline: 2px solid var(--dorado); outline-offset: 8px; border-radius: 50%; }
.carta-sello:disabled { cursor: default; }

.sello-halo {
  position: absolute;
  inset: 4%;
  border: 1px solid var(--dorado);
  border-radius: 50%;
  opacity: 0;
  pointer-events: none;
  animation: expandirHalo 2800ms var(--ease-out) 1700ms infinite;
}
.sello-halo-2 { animation-delay: 3100ms; }

@keyframes expandirHalo {
  0%   { opacity: 0.5; transform: scale(1); }
  100% { opacity: 0;   transform: scale(2); }
}

/* Al abrir, el sello se desprende hacia el espectador */
.carta.abierta .carta-sello {
  animation: soltarSello 560ms var(--ease-out) both;
  pointer-events: none;
}
.carta.abierta .sello-halo { animation: none; opacity: 0; }

@keyframes soltarSello {
  from { opacity: 1; transform: translate(-50%, -50%) scale(1)    translateZ(0); }
  to   { opacity: 0; transform: translate(-50%, -50%) scale(1.55) translateZ(130px); }
}

/* Pista bajo la carta */
.hero-pista {
  margin: 0;
  font-family: var(--serif);
  font-size: clamp(1rem, 2.4vw, 1.18rem);
  font-style: italic;
  color: var(--marfil-medio);
  animation: aparecerPista 900ms var(--ease-out) 1600ms both;
  transition: opacity 400ms var(--ease-out);
}
/* Se retira con una animación, no con una declaración: la de entrada usa
   fill: both y sostiene opacity 1, que le gana a un opacity: 0 suelto. Es
   el mismo detalle que ya apareció con el encabezado en móvil y con la
   opacidad de las flores. */
.hero-pista.oculta {
  pointer-events: none;
  animation: retirarPista 500ms var(--ease-out) both;
}

@keyframes retirarPista {
  from { opacity: 1; transform: translateY(0); }
  to   { opacity: 0; transform: translateY(-6px); }
}

@keyframes aparecerPista {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* --- Reproductor de música -------------------------------------------
   Píldora de vidrio: botón, título con ecualizador y barra que se puede
   arrastrar. Aparece recién cuando la carta se abrió.
   El ecualizador solo se mueve mientras suena, y anima scaleY, que es
   una transformación: nada de alto ni de sombras.
   ------------------------------------------------------------------- */

.reproductor {
  display: flex;
  align-items: center;
  gap: clamp(0.9rem, 3vw, 1.4rem);
  width: 100%;
  max-width: 25rem;
  margin-top: clamp(1.3rem, 3.2vh, 2.2rem);
  padding: 0.85rem 1.3rem 0.85rem 0.9rem;
  text-align: left;
  background: var(--vidrio-fuerte);
  -webkit-backdrop-filter: blur(18px) saturate(130%);
  backdrop-filter: blur(18px) saturate(130%);
  border: 1px solid var(--tarjeta-borde);

  border-radius: 999px;
  /* Tres capas: la sombra que la despega, un canto de luz en el borde de
     arriba y un poso dorado abajo. Es lo que la hace parecer una pieza y
     no un rectángulo redondeado — sobre todo en el tema claro, donde el
     crema sobre crema la dejaba plana. */
  box-shadow:
    var(--tarjeta-sombra),
    inset 0 1px 0 var(--rep-filo),
    inset 0 -20px 26px -24px rgb(var(--oro-rgb) / 0.55);

  /* Entra cuando la carta ya se abrió */
  opacity: 0;
  transform: translateY(16px);
  transition: opacity 600ms var(--ease-out), transform 600ms var(--ease-out);
  pointer-events: none;
}

body.carta-abierta .reproductor {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
  transition-delay: 1600ms;
}

/* --- Botón --- */
.rep-boton {
  position: relative;          /* ancla del aro que late */
  flex: 0 0 auto;
  width: 48px;
  height: 48px;
  display: grid;
  place-items: center;
  padding: 0;
  color: var(--sobre-oro);
  background: linear-gradient(140deg, var(--dorado-claro), var(--oro-relleno));
  border: none;
  border-radius: 50%;
  cursor: pointer;
  /* Luz arriba y sombra abajo dentro del propio disco: sin eso el botón es
     un círculo de color; con eso parece una pieza de metal. */
  box-shadow:
    0 6px 18px -6px rgb(var(--oro-rgb) / 0.6),
    inset 0 1px 0 rgb(255 255 255 / 0.55),
    inset 0 -7px 11px -7px rgb(60 40 8 / 0.45);
  transition: transform var(--t-hover) var(--ease-out),
              box-shadow var(--t-hover) var(--ease-out);
}
.rep-boton svg { width: 19px; height: 19px; }
.rep-boton .ic-play { margin-left: 2px; }   /* el triángulo pesa a la izquierda */
.rep-boton .ic-pause { display: none; }
body.sonando .rep-boton .ic-play  { display: none; }
body.sonando .rep-boton .ic-pause { display: block; }

/* Respuesta al presionar (Apple §1) */
.rep-boton:active { transform: scale(0.94); transition-duration: 100ms; }
.rep-boton:focus-visible { outline: 2px solid var(--dorado-claro); outline-offset: 3px; }

/* Aro que late mientras suena, para dar señal de vida */
.rep-boton::after {
  content: '';
  position: absolute;
  inset: -5px;
  border: 1px solid var(--dorado);
  border-radius: 50%;
  opacity: 0;
  pointer-events: none;
}
body.sonando .rep-boton::after {
  animation: latirAro 2400ms var(--ease-out) infinite;
}
@keyframes latirAro {
  0%   { opacity: 0.45; transform: scale(1); }
  100% { opacity: 0;    transform: scale(1.5); }
}

/* --- Cuerpo --- */
.rep-cuerpo { flex: 1 1 auto; min-width: 0; }

.rep-cabecera {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.8rem;
  margin-bottom: 0.5rem;
}

.rep-titulo {
  margin: 0;
  font-family: var(--serif);
  font-size: 0.98rem;
  font-style: italic;
  line-height: 1.2;
  color: var(--marfil);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* --- Ecualizador --- */
.rep-barras {
  flex: 0 0 auto;
  display: flex;
  align-items: flex-end;
  gap: 2.5px;
  height: 14px;
}
.rep-barras span {
  width: 2.5px;
  height: 100%;
  background: linear-gradient(180deg, var(--dorado-claro) 0%, var(--oro-relleno) 100%);
  border-radius: 99px;
  transform-origin: bottom;
  opacity: 0.6;
  transition: transform 260ms var(--ease-out), opacity 260ms var(--ease-out);
}

/* En reposo cada barra tiene su altura: las cinco iguales y bajitas se
   leían como unos puntos suspensivos, no como un ecualizador. */
.rep-barras span:nth-child(1) { transform: scaleY(0.30); }
.rep-barras span:nth-child(2) { transform: scaleY(0.64); }
.rep-barras span:nth-child(3) { transform: scaleY(0.42); }
.rep-barras span:nth-child(4) { transform: scaleY(0.80); }
.rep-barras span:nth-child(5) { transform: scaleY(0.36); }

/* Cada barra con su propio ritmo: el conjunto se ve orgánico */
body.sonando .rep-barras span {
  opacity: 1;
  animation: saltarBarra 900ms var(--ease-in-out) infinite alternate;
}
body.sonando .rep-barras span:nth-child(1) { animation-duration: 780ms;  animation-delay:   0ms; }
body.sonando .rep-barras span:nth-child(2) { animation-duration: 1120ms; animation-delay:  90ms; }
body.sonando .rep-barras span:nth-child(3) { animation-duration: 640ms;  animation-delay: 200ms; }
body.sonando .rep-barras span:nth-child(4) { animation-duration: 980ms;  animation-delay:  60ms; }
body.sonando .rep-barras span:nth-child(5) { animation-duration: 860ms;  animation-delay: 260ms; }

@keyframes saltarBarra {
  from { transform: scaleY(0.2); }
  to   { transform: scaleY(1); }
}

/* --- Barra de avance --- */
.rep-pista {
  position: relative;
  height: 4px;
  border-radius: 999px;
  /* Del oro y no de la tinta: sobre el crema, un surco gris azulado se veía
     frío al lado del avance dorado, como si fueran de dos juegos. */
  background: rgb(var(--oro-rgb) / 0.26);
  /* Hundida, no dibujada encima: el surco es lo que hace que el avance
     parezca ir POR dentro de la barra. */
  box-shadow: inset 0 1px 2px rgb(var(--sombra-rgb) / calc(0.4 * var(--sombra-k)));
  cursor: pointer;
  touch-action: none;          /* el arrastre lo maneja el script */
}
/* Zona de toque más generosa que el trazo visible */
.rep-pista::before {
  content: '';
  position: absolute;
  inset: -11px 0;
}
.rep-pista:focus-visible {
  outline: 2px solid var(--dorado);
  outline-offset: 6px;
  border-radius: 999px;
}

.rep-avance {
  display: block;
  height: 100%;
  width: 100%;
  border-radius: 999px;
  background: linear-gradient(90deg,
    var(--dorado-hondo) 0%, var(--oro-relleno) 58%, var(--dorado-claro) 100%);
  box-shadow: 0 0 9px -1px rgb(var(--oro-rgb) / 0.55);
  transform: scaleX(0);
  transform-origin: left center;
  /* Avance normal: suave. Al arrastrar el script quita la transición. */
  transition: transform 220ms linear;
}
.rep-pista.arrastrando .rep-avance { transition: none; }

/* La cabeza del avance, siempre encendida mientras suena: dice por dónde
   va la canción sin tener que apuntar. Se apoya en --pos, que el script ya
   escribe en la pista para el tirador. Se apaga cuando aparece el tirador,
   que ocupa su mismo sitio. */
.rep-pista::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 0;
  width: 7px;
  height: 7px;
  margin-left: -3.5px;
  border-radius: 50%;
  background: var(--dorado-claro);
  box-shadow: 0 0 11px 1px rgb(var(--oro-rgb) / 0.7);
  opacity: 0;
  transform: translate(var(--pos, 0px), -50%) scale(0.4);
  transition: transform 220ms linear, opacity 260ms var(--ease-out);
  pointer-events: none;
}
body.sonando .rep-pista::after {
  opacity: 1;
  transform: translate(var(--pos, 0px), -50%) scale(1);
}
.rep-pista:hover::after,
.rep-pista:focus-visible::after,
.rep-pista.arrastrando::after { opacity: 0; }

/* Tirador: aparece al apuntar o al arrastrar */
.rep-tirador {
  position: absolute;
  top: 50%;
  left: 0;
  width: 10px;
  height: 10px;
  margin-left: -5px;
  border-radius: 50%;
  background: var(--dorado-claro);
  box-shadow: 0 2px 8px rgb(var(--sombra-rgb) / calc(0.6 * var(--sombra-k)));
  /* --pos lo escribe el script, en px sobre el ancho de la pista */
  transform: translate(var(--pos, 0px), -50%) scale(0);
  transition: transform 160ms var(--ease-out);
  pointer-events: none;
}
.rep-pista.arrastrando .rep-tirador,
.rep-pista:focus-visible .rep-tirador {
  transform: translate(var(--pos, 0px), -50%) scale(1);
}
/* Mientras se arrastra el tirador sigue al dedo sin retardo */
.rep-pista.arrastrando .rep-tirador { transition: none; }

/* --- Tiempos --- */
.rep-tiempos {
  display: flex;
  justify-content: space-between;
  margin-top: 0.45rem;
  font-family: var(--sans);
  font-size: 0.64rem;
  font-weight: 400;
  letter-spacing: 0.1em;
  font-variant-numeric: tabular-nums;   /* los dígitos no bailan */
  color: var(--marfil-tenue);
}

/* ═══════════════════════════════════════════════════════════════════
   AMBIENTES MUSICALES
   El reproductor deja de ser un botón con una barra: anuncia la banda
   sonora al abrirse, permite elegir un ánimo y cuenta por qué la canción
   de entrada es esa. Todo con los mismos colores; no hay ningún color
   nuevo, solo los tokens del tema.
   ═══════════════════════════════════════════════════════════════════ */

/* El panel y la nota se cuelgan del reproductor.

   z-index 3 y no el 1 que trae por ser hijo de .bloque: las flores de la
   portada están en 2, y con el panel abierto el lisianthus se pintaba encima
   de las opciones. El reproductor y las flores no se solapan nunca, así que
   subirlo no le quita protagonismo a nada. */
.reproductor { position: relative; z-index: 3; }

/* Brillo dorado al emerger: un solo pulso, no un adorno permanente */
.reproductor::before {
  content: '';
  position: absolute;
  inset: -14% -6%;
  border-radius: inherit;
  pointer-events: none;
  background: radial-gradient(60% 120% at 50% 100%,
    rgb(var(--oro-rgb) / 0.42) 0%,
    rgb(var(--oro-rgb) / 0.16) 38%,
    transparent 72%);
  filter: blur(14px);
  opacity: 0;
}
body.carta-abierta .reproductor::before {
  animation: destelloReproductor 2200ms var(--ease-out) 1500ms both;
}
@keyframes destelloReproductor {
  0%   { opacity: 0; }
  26%  { opacity: 1; }
  100% { opacity: 0; }
}

/* --- Título, ambiente y obertura comparten sitio --- */
.rep-nombres {
  position: relative;
  flex: 1 1 auto;
  min-width: 0;
}

.rep-ambiente {
  margin: 0 0 0.1rem;
  font-family: var(--sans);
  font-size: 0.62rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--oro-texto);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* El título es un botón, pero no debe parecerlo: solo se subraya cuando
   además abre la nota. */
.rep-titulo {
  display: block;
  max-width: 100%;
  padding: 0;
  font-family: var(--serif);
  font-size: 0.98rem;
  font-style: italic;
  line-height: 1.2;
  text-align: left;
  color: var(--marfil);
  background: none;
  border: 0;
  cursor: default;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  transition: color var(--t-hover) var(--ease-out);
}
.rep-titulo.con-nota {
  cursor: pointer;
  /* Filete de puntos: insinúa que hay algo detrás sin gritar "botón" */
  border-bottom: 1px dotted rgb(var(--oro-rgb) / 0.5);
}
.rep-titulo:focus-visible { outline: 2px solid var(--dorado-claro); outline-offset: 3px; }

/* La obertura ocupa el mismo hueco que el título y se cruza con él */
.rep-obertura {
  position: absolute;
  inset: 0;
  margin: 0;
  display: flex;
  align-items: center;
  gap: 0.4rem;
  font-family: var(--serif);
  font-size: 0.9rem;
  font-style: italic;
  line-height: 1.2;
  color: var(--marfil-medio);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  opacity: 0;
  pointer-events: none;
  transition: opacity 620ms var(--ease-out);
}
.ober-marca {
  flex: 0 0 auto;
  width: 15px;
  height: 15px;
  color: var(--oro-texto);
}
body.en-obertura .rep-obertura { opacity: 1; }
/* Mientras habla la obertura, el título espera */
body.en-obertura .rep-titulo,
body.en-obertura .rep-ambiente { opacity: 0; }
.rep-titulo, .rep-ambiente { transition: opacity 620ms var(--ease-out), color var(--t-hover) var(--ease-out); }

.rep-pie {
  margin: 0.3rem 0 0;
  font-family: var(--sans);
  font-size: 0.58rem;
  letter-spacing: 0.1em;
  color: var(--marfil-tenue);
}

/* --- Botón de ambientes --- */
.rep-menu {
  position: relative;
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  padding: 0;
  color: var(--oro-texto);
  background: rgb(var(--oro-rgb) / 0.08);
  /* Aro fino y un rescoldo interior: el mismo tratamiento que el sello y los
     botones de línea, en vez de un relleno plano. */
  border: 1px solid rgb(var(--oro-rgb) / 0.32);
  border-radius: 999px;
  box-shadow: inset 0 0 10px -4px rgb(var(--oro-rgb) / 0.45);
  cursor: pointer;
  transition: transform var(--t-hover) var(--ease-out),
              background var(--t-hover) var(--ease-out),
              border-color var(--t-hover) var(--ease-out),
              box-shadow var(--t-hover) var(--ease-out);
}
.rep-menu svg {
  width: 15px;
  height: 15px;
  transition: transform 320ms var(--ease-out);
}
.rep-menu:active { transform: scale(0.92); transition-duration: var(--t-press); }
.rep-menu:focus-visible { outline: 2px solid var(--dorado-claro); outline-offset: 3px; }
.rep-menu[aria-expanded="true"] {
  color: var(--sobre-oro);
  background: var(--dorado-claro);
  border-color: var(--dorado-claro);
  box-shadow: 0 0 16px -4px rgb(var(--oro-rgb) / 0.65);
}
/* La nota se yergue al abrirse: un cuarto de vuelta corto, no un giro completo */
.rep-menu[aria-expanded="true"] svg { transform: rotate(-14deg) scale(1.06); }
@media (hover: hover) and (pointer: fine) {
  .rep-menu:hover {
    background: rgb(var(--oro-rgb) / 0.18);
    border-color: rgb(var(--oro-rgb) / 0.50);
  }
}

/* --- El selector de ambiente: velo + carrusel ---
   Se abre tocando el reproductor. El velo difumina la escena, el reproductor se
   queda encendido por encima y sobre él flota un carrusel de discos.

   El desplazamiento es scroll-snap del navegador: la inercia y el rebote son
   los del sistema. El script solo escribe --k, que es cuánto de centrada está
   cada tarjeta, y de ahí salen su tamaño, su opacidad y su halo. Nada más se
   anima: transform, opacity y el filtro del velo. */

.sel-velo {
  position: absolute;
  inset: 0;
  z-index: 4;
  /* Solo el apagado. El desenfoque NO va aquí: backdrop-filter no difumina en
     WebKit dentro de esta anidación —comprobado, en Chromium sí y en el WebKit
     del teléfono no— y el fondo quedaba nítido justo donde más importa. */
  /* El color del velo tiene su propia variable: en noche es la viñeta, pero
     en claro es niebla de papel, no un pardo translúcido. */
  background: rgb(var(--velo-rgb, var(--vineta-rgb, 4 10 20)) / var(--velo-alfa, 0.42));
  opacity: 0;
  transition: opacity 380ms var(--ease-out);
}
.sel-velo.visible { opacity: 1; }

/* El desenfoque se aplica al contenido de la portada, que sí funciona en los dos
   motores. Sin transición a propósito: animar un filtro cuesta repintados, y el
   salto queda tapado por el velo entrando. */
/* (El desenfoque al abrir el selector ya no se aplica pieza por pieza de
   la portada: el reproductor flota sobre todas las secciones, así que se
   difumina la página entera, como con los modales.) */

/* El reproductor queda encendido por encima del velo: aro de oro y un rescoldo
   alrededor. Es lo que dice "esto es lo que estás manejando". */
body.sel-abierto .reproductor {
  z-index: 6;
  border-color: rgb(var(--oro-rgb) / 0.62);
  box-shadow:
    var(--tarjeta-sombra),
    0 0 0 1px rgb(var(--oro-rgb) / 0.28),
    0 0 34px -6px rgb(var(--oro-rgb) / 0.42);
}
.reproductor {
  transition:
    opacity 600ms var(--ease-out),
    transform 600ms var(--ease-out),
    border-color 420ms var(--ease-out),
    box-shadow 420ms var(--ease-out);
}

.sel-carrusel {
  position: absolute;
  left: 0;
  right: 0;
  top: 43%;
  z-index: 7;
  transform: translateY(-50%);
  pointer-events: none;   /* solo el riel recibe el dedo */
  opacity: 0;
  transition: opacity 340ms var(--ease-out);
}
.sel-carrusel.visible { opacity: 1; }

/* El suelo del texto.
   Sin esto el texto cae directamente sobre el sobre desenfocado, y se lee
   distinto según lo que quede detrás: medido, la línea de abajo caía sobre una
   zona de luma 0,04 en el tema claro —casi negra— con tinta azul oscura encima,
   1,24 de contraste. Con la banda, el fondo del texto es siempre el mismo.
   Se desvanece por los cuatro lados, así que no se lee como una barra sino como
   luz cayendo sobre la franja del carrusel. */
.sel-carrusel::before {
  content: '';
  position: absolute;
  /* Más vuelo por abajo que por arriba: la línea de ayuda es lo último del
     carrusel y con poco vuelo caía dentro del desvanecido, sobre un fondo de
     luma 0,47 en vez de 0,70 — y ahí no llegaba al mínimo. */
  inset: -10% -6% -22%;
  z-index: -1;   /* detrás del texto, delante del velo */
  background: linear-gradient(180deg,
    rgb(var(--velo-suelo) / 0)    0%,
    rgb(var(--velo-suelo) / 0.70) 8%,
    rgb(var(--velo-suelo) / 0.76) 45%,
    rgb(var(--velo-suelo) / 0.72) 88%,
    rgb(var(--velo-suelo) / 0)    100%);
  -webkit-mask-image: linear-gradient(90deg, rgb(0 0 0 / 0) 0%, #000 5%, #000 95%, rgb(0 0 0 / 0) 100%);
  mask-image: linear-gradient(90deg, rgb(0 0 0 / 0) 0%, #000 5%, #000 95%, rgb(0 0 0 / 0) 100%);
  pointer-events: none;
}

.sel-titulo,
.sel-ayuda {
  margin: 0 auto;
  text-align: center;
  color: var(--marfil-medio);
}
.sel-titulo {
  max-width: 26rem;
  margin-bottom: clamp(0.9rem, 2.4vh, 1.5rem);
  font-family: var(--serif);
  font-size: clamp(1.12rem, 3.1vw, 1.52rem);
  font-style: italic;
  line-height: 1.3;
  color: var(--marfil);
  /* Entra un poco después que el carrusel */
  opacity: 0;
  transform: translateY(-8px);
  transition: opacity 420ms var(--ease-out) 120ms, transform 420ms var(--ease-out) 120ms;
}
.sel-carrusel.visible .sel-titulo { opacity: 1; transform: translateY(0); }

.sel-ayuda {
  margin-top: clamp(0.7rem, 2vh, 1.1rem);
  font-family: var(--sans);
  font-size: clamp(0.78rem, 1.8vw, 0.86rem);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  /* Tinta plena y no atenuada: es la línea que queda sobre la parte más oscura
     del sobre desenfocado, y atenuada no llegaba al mínimo en el tema claro. */
  color: var(--marfil);
  opacity: 0;
  transition: opacity 420ms var(--ease-out) 260ms;
}
.sel-carrusel.visible .sel-ayuda { opacity: 1; }

/* ---- El escenario del selector, en claro ----
   En noche el velo oscuro ya hace de escenario y la banda solo asienta el
   texto. En claro la banda pasa a ser el escenario: una franja de papel casi
   sólida, con un filo dorado arriba y otro abajo y una sombra suave, como la
   faja de una invitación impresa. El desvanecido vertical se acorta a casi
   nada para que el filo caiga sobre banda y no sobre aire. */
[data-tema="claro"] .sel-carrusel::before {
  background: linear-gradient(180deg,
    rgb(var(--velo-suelo) / 0)    0%,
    rgb(var(--velo-suelo) / 0.94) 1.5%,
    rgb(var(--velo-suelo) / 0.97) 50%,
    rgb(var(--velo-suelo) / 0.94) 98.5%,
    rgb(var(--velo-suelo) / 0)    100%);
  box-shadow:
    0  30px 50px -30px rgb(74 58 38 / 0.4),
    0 -22px 44px -30px rgb(74 58 38 / 0.28);
}
[data-tema="claro"] .sel-carrusel::after {
  content: '';
  position: absolute;
  inset: -10% -6% -22%;   /* el mismo vuelo que la banda */
  z-index: -1;
  background:
    linear-gradient(90deg,
      rgb(var(--oro-rgb) / 0) 0%, rgb(var(--oro-rgb) / 0.55) 16%,
      rgb(var(--oro-rgb) / 0.55) 84%, rgb(var(--oro-rgb) / 0) 100%)
      0 1.5% / 100% 1px no-repeat,
    linear-gradient(90deg,
      rgb(var(--oro-rgb) / 0) 0%, rgb(var(--oro-rgb) / 0.55) 16%,
      rgb(var(--oro-rgb) / 0.55) 84%, rgb(var(--oro-rgb) / 0) 100%)
      0 98.5% / 100% 1px no-repeat;
  pointer-events: none;
}
/* Con la banda debajo asegurada, la jerarquía vuelve a su sitio: el título
   serif manda y la línea de ayuda deja de gritar en tinta plena. */
[data-tema="claro"] .sel-titulo {
  font-size: clamp(1.3rem, 3.6vw, 1.7rem);
}
[data-tema="claro"] .sel-ayuda {
  font-size: 0.72rem;
  letter-spacing: 0.24em;
  color: rgb(var(--tinta-rgb) / 0.62);
}

/* Mientras el selector está abierto, el conmutador de tema se retira: es un
   mando de la página y quedaba flotando encima de la escena. Con visibility
   y no con opacity: su animación de entrada lleva fill forwards y una
   opacity normal no puede con ella. */
body.sel-abierto .tema {
  visibility: hidden;
  pointer-events: none;
}

/* El riel */
.sel-riel {
  --sel-card: clamp(128px, 30vw, 168px);
  display: flex;
  align-items: flex-start;
  gap: clamp(0.5rem, 1.6vw, 0.9rem);
  /* Las de los extremos se apagan contra el canto del riel, para que el
     carrusel no acabe en seco. El desvanecido va cerca del borde y no adentro:
     con 14% las tarjetas vecinas del celular caían dentro, y su nombre quedaba
     apagado dos veces —por el desvanecido y por su propia opacidad—. */
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
  overflow-x: auto;
  overflow-y: hidden;
  /* Los extremos también se centran: el relleno lateral es lo que se lo permite */
  padding: 0.4rem calc((100% - var(--sel-card)) / 2) 0.6rem;
  scroll-snap-type: x mandatory;
  scroll-behavior: auto;
  pointer-events: auto;
  /* La barra estorbaría: el imán y el arrastre ya dicen que se desplaza */
  scrollbar-width: none;
  -ms-overflow-style: none;
  overscroll-behavior-x: contain;
}
.sel-riel::-webkit-scrollbar { display: none; }
.sel-riel:focus-visible { outline: none; }
.sel-riel:focus-visible .sel-tarjeta[aria-selected="true"] .sel-aro {
  box-shadow: 0 0 0 2px var(--dorado-claro);
}

.sel-tarjeta {
  flex: 0 0 var(--sel-card);
  scroll-snap-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.6rem;
  padding: 0;
  background: none;
  border: 0;
  cursor: pointer;
  /* Todo sale de --k, que el script actualiza con el desplazamiento. La
     atenuación va en el disco y en el nombre por separado: aplicada a la
     tarjeta entera apagaba el nombre igual que el medallón, y los nombres
     tienen que leerse aunque estén al costado. */
  transform:
    scale(calc(0.7 + 0.3 * var(--k, 0)))
    rotate(calc(var(--lado, 1) * (1 - var(--k, 0)) * -5deg));
  transition: opacity 120ms linear, transform 120ms linear;
}

/* El disco */
.sel-disco {
  position: relative;
  display: grid;
  place-items: center;
  width: var(--sel-card);
  height: var(--sel-card);
  border-radius: 50%;
  overflow: hidden;
  opacity: calc(0.66 + 0.34 * var(--k, 0));
  /* Opaco. Con el disco translúcido se veía la escena desenfocada por dentro y
     no se leía como un medallón, sino como un agujero. La luz cae de arriba a
     la izquierda, igual que en el resto de la página. */
  /* Se apoya en --marino-alto y --marino, que son los tonos de superficie del
     tema: con --campo-rgb el disco quedaba casi negro y se leía como un agujero
     en vez de un medallón. La luz cae de arriba a la izquierda, igual que en el
     resto de la página. */
  background:
    radial-gradient(circle at 30% 24%,
      rgb(var(--oro-rgb) / calc(0.14 + 0.12 * var(--k, 0))) 0%,
      transparent 62%),
    linear-gradient(158deg, var(--marino-alto) 0%, var(--marino) 100%);
  /* El halo crece con --k: la del centro es la única que se enciende */
  box-shadow:
    0 calc(10px + 14px * var(--k, 0)) calc(24px + 26px * var(--k, 0)) calc(-14px + -4px * var(--k, 0))
      rgb(var(--sombra-rgb) / calc((0.45 + 0.25 * var(--k, 0)) * var(--sombra-k))),
    0 0 calc(26px * var(--k, 0)) rgb(var(--oro-rgb) / calc(0.5 * var(--k, 0)));
}

.sel-foto {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* El aro de oro, por encima de la foto */
.sel-aro {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  border: 1px solid rgb(var(--oro-rgb) / calc(0.40 + 0.45 * var(--k, 0)));
  /* Un segundo aro interior, muy fino: es lo que da el aire de medallón */
  box-shadow: inset 0 0 0 calc(3px + 2px * var(--k, 0)) rgb(var(--tinta-rgb) / 0.10),
              inset 0 0 0 calc(4px + 2px * var(--k, 0)) rgb(var(--oro-rgb) / calc(0.20 + 0.32 * var(--k, 0)));
  z-index: 2;
}

/* Un brillo que gira despacio en el disco del ambiente que suena. Va en el
   ambiente ELEGIDO y no en el centrado a propósito: así dice cuál está sonando
   mientras se pasa por delante de los demás. Es un degradado cónico girando:
   solo transform, nada que repintar. */
.sel-tarjeta[aria-selected="true"] .sel-disco::after {
  content: '';
  position: absolute;
  inset: -18%;
  z-index: 0;
  border-radius: 50%;
  background: conic-gradient(from 0deg,
    transparent 0deg,
    rgb(var(--oro-rgb) / 0.42) 46deg,
    rgb(var(--oro-rgb) / 0.06) 96deg,
    transparent 168deg,
    transparent 360deg);
  animation: girarBrillo 7s linear infinite;
  pointer-events: none;
}
@keyframes girarBrillo {
  to { transform: rotate(360deg); }
}

/* Mientras no hay foto, la marca dibujada ocupa el disco */
.sel-marca {
  position: relative;
  z-index: 1;
  width: 38%;
  height: 38%;
  color: var(--oro-texto);
  opacity: calc(0.55 + 0.45 * var(--k, 0));
}

.sel-nombre {
  margin-top: 0.3rem;
  font-family: var(--serif);
  font-size: clamp(1.15rem, 3vw, 1.42rem);
  line-height: 1.2;
  text-align: center;
  color: var(--marfil);
  /* Se atenúa mucho menos que el disco: al costado sigue leyéndose */
  opacity: calc(0.84 + 0.16 * var(--k, 0));
}
.sel-frase {
  max-width: 15.5rem;
  min-height: 2.6em;   /* el alto no baila al cambiar de tarjeta */
  font-family: var(--sans);
  font-size: clamp(0.84rem, 1.9vw, 0.92rem);
  line-height: 1.45;
  text-align: center;
  color: var(--marfil-medio);
  /* Solo se lee la de la tarjeta centrada */
  opacity: calc(var(--k, 0) * var(--k, 0));
}

.sel-tarjeta.es-silencio .sel-nombre { font-style: italic; }
.sel-tarjeta.vacia { cursor: default; }
.sel-tarjeta.vacia .sel-disco { filter: grayscale(0.7); }

@media (prefers-reduced-motion: reduce) {
  .sel-tarjeta[aria-selected="true"] .sel-disco::after { animation: none; }
  .sel-velo, .sel-carrusel, .sel-titulo, .sel-ayuda {
    transition: opacity 140ms linear !important;
    transform: none !important;
  }
  .sel-tarjeta { transition: none !important; }
  .sel-riel { scroll-behavior: auto; }
}

/* --- La nota de la canción --- */


/* En el tema claro el panel va de papel, no de vidrio oscuro. Bastante opaco:
   se abre por encima del sobre, y con más transparencia la tela azul se colaba
   por detrás del texto. */
[data-tema="claro"] {
  --panel-fondo: rgb(255 253 248 / 0.985);
}

@media (max-width: 640px) {
  /* El ecualizador cede el sitio al botón de ambientes: uno adorna, el otro
     hace falta, y en 246 px de reproductor no caben los dos. */
  .rep-barras { display: none; }
  .rep-menu { width: 28px; height: 28px; }
  .rep-obertura { font-size: 0.8rem; }
  .rep-titulo { font-size: 0.9rem; }
  /* La nota se ancla a la derecha, como el panel: el reproductor arranca a
     128 px del borde y desde ahí una nota de 330 se salía 66 px. */
}

@media (prefers-reduced-motion: reduce) {
  .reproductor::before { animation: none !important; opacity: 0 !important; }
  .rep-obertura, .rep-titulo, .rep-ambiente { transition: opacity 160ms linear !important; }
}


/* ═══════════════════════════════════════════════════════════════════
   ENCABEZADO DEL HERO · entrada de cine
   Las palabras suben una tras otra desde abajo, girando en X, con
   140 ms entre cada una. Solo transform y opacity.
   ═══════════════════════════════════════════════════════════════════ */

.hero-intro {
  max-width: min(58rem, 94vw);
  text-align: center;
  perspective: 900px;
}

/* "Nos casamos": el texto vive en un span para poder desplazarlo sin
   animar letter-spacing, que provocaría reflujo en cada frame. */
/* «NOS CASAMOS» en las versalitas espaciadas de siempre, pero con cuerpo
   de verdad, lámina dorada y un filete a cada lado. Antes era diminuto y
   sobre el papel claro apenas se notaba. El apartarse del sobre no cambia:
   la medición usa el rectángulo real, sea del tamaño que sea. */
.hero-etiqueta {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: clamp(0.7rem, 2vw, 1.1rem);
  margin: 0 0 clamp(0.9rem, 2vh, 1.5rem);
  overflow: hidden;
  font-family: var(--sans);
  font-size: clamp(0.92rem, 2.2vw, 1.28rem);
  font-weight: 400;
  letter-spacing: 0.4em;
  text-indent: 0;
  text-transform: uppercase;
  line-height: 1.25;
  color: var(--dorado);
}
.hero-etiqueta::before,
.hero-etiqueta::after {
  content: '';
  flex: none;
  width: clamp(2rem, 5.5vw, 3.6rem);
  height: 1px;
  /* Aparecen cuando la palabra ya está arriba, en fundido simple */
  animation: aparecerFilete 900ms var(--ease-out) 750ms both;
}
.hero-etiqueta::before { background: linear-gradient(90deg,  rgb(var(--oro-rgb) / 0) 0%, rgb(var(--oro-rgb) / 0.8) 100%); }
.hero-etiqueta::after  { background: linear-gradient(270deg, rgb(var(--oro-rgb) / 0) 0%, rgb(var(--oro-rgb) / 0.8) 100%); }
@keyframes aparecerFilete { from { opacity: 0; } }

.hero-etiqueta span {
  display: inline-block;
  /* El tracking cuelga tras la última letra: se descuenta para que el
     texto quede óptico entre los dos filetes. */
  margin-right: -0.4em;
  animation: subirEtiqueta 1100ms var(--ease-out) 150ms both;
  /* Lámina: el trazo va del oro hondo al claro y de vuelta. El halo va en
     drop-shadow y no en text-shadow, que con el recorte al texto se
     pintaría como mancha detrás del degradado. */
  background: linear-gradient(100deg, var(--dorado) 0%, var(--dorado-claro) 52%, var(--dorado) 100%);
  -webkit-background-clip: text;
          background-clip: text;
  -webkit-text-fill-color: transparent;
  filter: drop-shadow(0 2px 16px rgb(var(--oro-rgb) / 0.3));
}

@keyframes subirEtiqueta {
  from { opacity: 0; transform: translateY(115%); }
  to   { opacity: 1; transform: translateY(0); }
}

.nombres-hero {
  margin: 0;
  /* Playfair Display en cursiva, caja normal.
     Aquí hubo dos descartes de Belén, y cada uno enseñó algo: la
     caligrafía dorada se leía «antigua», y las versalitas muy espaciadas
     —Italiana— se leían «básicas, muy cuadradas». Tenía razón en las dos:
     en mayúsculas y con tanto aire, una palabra es un rectángulo.

     Esto es lo contrario: caja normal y cursiva, así que la silueta tiene
     curva y remate. El alto contraste entre trazo grueso y fino es lo que
     la hace de revista y no de plantilla. Se eligió entre cinco cursivas
     probadas sobre esta misma portada —Playfair, Bodoni Moda, Sacramento,
     Ephesis y Cormorant Infant—.

     Va en la tinta del tema, así que sirve para papel y noche sin tocar
     nada. El oro queda para la «y», el sello y los títulos. */
  font-family: 'Playfair Display', var(--serif);
  font-style: italic;
  /* El mínimo baja de 2,6 a 2,1 rem: la cursiva de Playfair es más ancha
     que las versalitas y a 390 px los nombres quedaban tocando los cantos. */
  font-size: clamp(2.1rem, 8.6vw, 5.4rem);
  font-weight: 400;
  letter-spacing: 0.01em;
  text-transform: none;
  line-height: 1.14;
  color: var(--marfil);
  /* En una sola línea: el clamp por vw ya los achica en pantallas
     angostas, así que no deben partirse en renglones. Y si aun así no
     caben, el script los encoge con --escala-nom: en una sola línea, un
     texto más ancho que su sitio se sale por los dos lados a la vez. */
  white-space: nowrap;
  scale: var(--escala-nom, 1);
}

/* El exterior se desplaza al abrir; el interior hace la entrada.
   La sombra vive aquí, separada del recorte del degradado: un filter
   sobre el mismo elemento que recorta el fondo al texto interfiere. */
.nombres-hero .palabra {
  display: inline-block;
  transform: translateX(0);
  /* Apenas una sombra: con tinta plana y trazo fino, una sombra marcada
     emborrona las letras en vez de despegarlas. */
  filter: drop-shadow(0 2px 14px rgb(var(--sombra-rgb) / calc(0.28 * var(--sombra-k))));
  transition: transform 1300ms var(--ease-out) 560ms,
              opacity   900ms var(--ease-out) 560ms;
}

.nombres-hero .pal-in {
  display: inline-block;
  color: var(--marfil);          /* base sólida: siempre visible */
  animation: entrarPalabra 1200ms var(--ease-out) both;
  /* 140 ms entre palabras, tras la etiqueta */
  animation-delay: calc(var(--i) * 140ms + 480ms);
}

/* (La veta metálica se retiró: los nombres van en tinta plana. El oro se
   quedó para los títulos de sección y el sello.) */

/* La "y" va dorada plana, sin veta */
.nombres-hero .union .pal-in {
  background: none;
  color: var(--dorado);
  -webkit-text-fill-color: var(--dorado);
}

/* --- Al abrir la carta los nombres se apartan ---
   La tapa abierta sube unos 290 px y taparía el nombre. Cada palabra se
   corre hacia su lado para enmarcar el sobre en vez de quedar detrás.
   A la altura del nombre la tapa mide unos 210 px de ancho, así que con
   correr cada palabra la mitad de eso basta para despejarla. */
/* Cuánto se apartan al abrir. El valor lo calcula el script en --reparto,
   porque depende de lo que MIDEN los nombres con la tipografía cargada, y
   eso el CSS no lo sabe: con un tope fijo se salían 84 px de la pantalla a
   1100 px de ancho. El script deja siempre un margen a los lados. */
body.carta-abierta .nombres-hero .pal-izq {
  transform: translateX(calc(-1 * var(--reparto, 0px))) translateY(-8px);
}
body.carta-abierta .nombres-hero .pal-der {
  transform: translateX(var(--reparto, 0px)) translateY(-8px);
}
/* La «y» es un enlace, no un nombre. Va en caligrafía y en oro: hace de
   contrapunto a la tinta de los nombres y devuelve el dorado a la portada
   en el único sitio donde no compite con nada. */
.nombres-hero .union {
  font-family: var(--script);
  font-size: 0.62em;
  font-weight: 400;
  letter-spacing: 0.02em;
  text-transform: lowercase;
  color: var(--oro-texto);
  opacity: 0.9;
  /* La caligrafía se apoya más abajo que la cursiva */
  vertical-align: -0.04em;
}
/* Sobre la tapa abierta se atenúa más, para no estorbar */
body.carta-abierta .nombres-hero .union {
  opacity: 0.4;
  transform: translateY(-4px) scale(0.9);
}

@keyframes entrarPalabra {
  from { opacity: 0; transform: rotateX(-62deg) translateY(0.5em) translateZ(-70px); }
  to   { opacity: 1; transform: rotateX(0deg)   translateY(0)     translateZ(0); }
}

/* Filete dorado que se traza solo, de dentro hacia fuera */
.hero-filete {
  display: block;
  width: min(280px, 60%);
  height: 1px;
  margin: clamp(1rem, 2.4vh, 1.7rem) auto clamp(0.9rem, 2vh, 1.4rem);
  background: linear-gradient(90deg, transparent, var(--dorado), transparent);
  transform: scaleX(0);
  animation: trazarFilete 1300ms var(--ease-out) 1000ms both;
}

@keyframes trazarFilete {
  from { transform: scaleX(0); opacity: 0; }
  to   { transform: scaleX(1); opacity: 1; }
}

.fecha-hero {
  margin: 0;
  font-family: var(--sans);
  font-size: clamp(0.8rem, 2.5vw, 1.02rem);
  font-weight: 400;
  letter-spacing: 0.5em;
  text-indent: 0.5em;
  color: var(--dorado);
  animation: entrarFecha 1000ms var(--ease-out) 1250ms both;
}

@keyframes entrarFecha {
  from { opacity: 0; transform: translateY(14px) scale(1.04); }
  to   { opacity: 1; transform: translateY(0)    scale(1); }
}

/* --- Orquídeas del hero ---
   Abajo a la izquierda, recortadas por el borde, del mismo lado que la
   luz para que la escena tenga una sola dirección de iluminación. */
.flores-hero {
  position: absolute;
  left: max(-4rem, -7vw);
  bottom: -3vh;
  width: clamp(150px, 18vw, 275px);
  height: auto;
  z-index: 2;
  pointer-events: none;
  opacity: 0;
  filter: drop-shadow(0 18px 34px rgb(var(--sombra-rgb) / calc(0.55 * var(--sombra-k))));
  animation: entrarFlores 1600ms var(--ease-out) 1500ms both;
}

/* La opacidad final sale de una variable para poder ajustarla por tramo:
   declararla aparte no serviría, porque esta animación usa fill: both y
   sostiene su propio valor. */
@keyframes entrarFlores {
  from { opacity: 0; transform: translateY(46px) rotate(-5deg) scale(0.94); }
  to   { opacity: var(--flor-alfa, 0.94); transform: translateY(0) rotate(0deg) scale(1); }
}

/* ═══════════════════════════════════════════════════════════════════
   NUMERACIÓN DE SECCIONES
   Cifra romana con filetes: da orden editorial sin competir con el
   título.
   ═══════════════════════════════════════════════════════════════════ */

.seccion-numero {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1.1rem;
  margin: 0 0 1.5rem;
  font-family: var(--serif);
  font-size: 0.96rem;
  font-weight: 500;
  letter-spacing: 0.34em;
  text-indent: 0.34em;
  /* El oro de texto y no el de adorno: es letra pequeña, y sobre el papel
     casi blanco de ahora el --dorado se quedaba en 4,08 de contraste. */
  color: var(--oro-texto);
}
.seccion-numero::before,
.seccion-numero::after {
  content: '';
  width: clamp(28px, 7vw, 58px);
  height: 1px;
  /* Del acento hacia el oro: el filete hace de bisagra entre el color de
     la sección y el dorado de sus títulos. */
  background: linear-gradient(90deg,
    rgb(var(--acento-a) / 0.7), var(--dorado-linea));
}
.seccion-numero::after {
  background: linear-gradient(90deg,
    var(--dorado-linea), rgb(var(--acento-a) / 0.7));
}

/* ═══════════════════════════════════════════════════════════════════
   4 · EL LUGAR
   Ceremonia y recepción en el mismo sitio: una sola ficha.
   ═══════════════════════════════════════════════════════════════════ */

.lugar { margin-top: 0.5rem; }

/* --- Medallón del lugar ---
   Recorte circular con aro dorado y un halo verde propio, tomado del
   jardín de la foto: así el color no queda encerrado en el círculo, sino
   que tiñe un poco el aire alrededor. */
.lugar-medallon {
  position: relative;
  width: clamp(116px, 26vw, 152px);
  aspect-ratio: 1;
  margin: 0 auto 1.8rem;
  padding: 0;
  border-radius: 50%;
  transform-style: preserve-3d;
  transition: transform var(--t-hover) var(--ease-out);
}

/* Resplandor verde detrás, del tono del césped */
.lugar-medallon::before {
  content: '';
  position: absolute;
  inset: -34%;
  z-index: -1;
  border-radius: 50%;
  background: radial-gradient(circle at 50% 46%,
    rgba(122, 168, 88, 0.30) 0%,
    rgba(96, 140, 76, 0.13) 44%,
    transparent 72%);
  filter: blur(22px);
  pointer-events: none;
}

.lugar-medallon img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 50%;
  /* Aro dorado, y una segunda línea tenue por fuera para dar grosor sin
     engordar el trazo. */
  box-shadow:
    0 0 0 2px var(--dorado),
    0 0 0 7px rgb(var(--oro-rgb) / 0.16),
    0 14px 30px -8px rgb(var(--sombra-rgb) / calc(0.65 * var(--sombra-k)));
}

.lugar-nombre {
  margin: 0 0 1rem;
  font-family: var(--serif);
  font-size: clamp(2.1rem, 5.6vw, 3rem);
  font-weight: 400;
  line-height: 1.15;
  letter-spacing: -0.012em;
  color: var(--marfil);
}

.lugar-dir {
  margin: 0 0 0.6rem;
  font-family: var(--serif);
  font-size: clamp(1.12rem, 2.7vw, 1.34rem);
  line-height: 1.75;
  color: var(--marfil-medio);
}

.lugar-nota {
  margin: 0 0 2.6rem;
  font-family: var(--sans);
  font-size: 0.8rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--marfil-tenue);
}

.lugar-horas {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: clamp(1.4rem, 5vw, 3.2rem);
  margin: 0 0 2.8rem;
  perspective: 900px;
}

.hora-item { transform-style: preserve-3d; }

.hora-sep {
  width: 1px;
  height: 56px;
  background: linear-gradient(180deg, transparent, var(--dorado-linea), transparent);
}

.hora-etiqueta {
  margin: 0 0 0.5rem;
  font-family: var(--sans);
  font-size: 0.74rem;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--dorado);
}

.hora-valor {
  margin: 0;
  font-family: var(--serif);
  font-size: clamp(2.5rem, 7vw, 3.5rem);
  font-weight: 300;
  line-height: 1;
  letter-spacing: -0.02em;
  color: var(--marfil);
}

.reveal.visible .hora-item:nth-of-type(1) { animation: girarHora 640ms var(--ease-out) 320ms both; }
.reveal.visible .hora-item:nth-of-type(2) { animation: girarHora 640ms var(--ease-out) 400ms both; }

@keyframes girarHora {
  from { opacity: 0; transform: rotateX(-70deg) translateZ(-40px); }
  to   { opacity: 1; transform: rotateX(0deg)   translateZ(0); }
}

.lugar-acciones {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.9rem;
}

/* Segunda acción, con menos peso que la principal */
.btn-tenue {
  color: var(--marfil-medio);
  background: rgb(var(--tinta-rgb) / 0.05);
  border-color: rgb(var(--tinta-rgb) / 0.42);
}

/* ═══════════════════════════════════════════════════════════════════
   NOTA SOBRE EL 3D LIGADO AL SCROLL

   Aquí había un bloque que ataba la entrada de las secciones y del pie a
   la posición de desplazamiento, con animation-timeline: view().

   Se eliminó porque dejaba las dos últimas secciones a medio animar. El
   tramo terminaba en "cover 42%", un punto que las últimas nunca alcanzan:
   el scroll se agota antes. Con fill: both se quedaban congeladas a mitad
   del recorrido, con la opacidad incompleta y la rotación en X sin
   deshacer, que es lo que las hacía verse apagadas y trapezoidales. El
   pie, con su tramo hasta "cover 60%", quedaba en opacidad 0,2.

   La entrada la gobierna el observador de intersección, que dispara una
   transición y siempre la termina, sin depender de cuánto se pueda
   desplazar la página. El movimiento ligado al scroll lo aportan las
   luces de sección, que sí lo hacen bien porque su cálculo tiene en
   cuenta el final del documento.
   ═══════════════════════════════════════════════════════════════════ */

/* ═══════════════════════════════════════════════════════════════════
   2 · FECHA Y CUENTA REGRESIVA
   ═══════════════════════════════════════════════════════════════════ */

.intro-boda { font-style: italic; margin-bottom: 2rem; }

.mes {
  font-family: var(--serif);
  font-size: clamp(1.4rem, 3.4vw, 1.85rem);
  font-weight: 400;
  letter-spacing: 0.34em;
  text-indent: 0.34em;
  text-transform: uppercase;
  color: var(--marfil);
  margin: 0 0 1.5rem;
}

.fila-dia {
  display: flex;
  align-items: center;
  justify-content: center;

  /* El hueco y la holgura se declaran una vez y el largo del filete sale de
     ellos: así queda centrado en el hueco a cualquier tamaño, en vez de ser
     un ancho fijo que hay que ir cuadrando. Antes el filete medía 46 px en un
     hueco de 28 y se metía dentro del texto: cruzaba la O de DOMINGO y el 2
     de 2027. Medido en los píxeles pintados. */
  --hueco:   clamp(1.7rem, 5vw, 3.4rem);
  --holgura: clamp(0.5rem, 1.4vw, 0.9rem);

  gap: var(--hueco);
  margin: 0 0 2.6rem;
}

.fila-dia span {
  font-family: var(--sans);
  font-size: clamp(0.68rem, 2vw, 0.84rem);
  font-weight: 400;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--marfil-medio);
  position: relative;

  /* El espaciado de 0,28em se añade también después de la última letra, así
     que la caja acaba 0,28em más allá de la tinta. Sin compensarlo, el hueco
     de la izquierda salía 3,8 px más ancho que el de la derecha y los dos
     filetes no quedaban simétricos. */
  margin-right: -0.28em;
}
.fila-dia span:first-child::after,
.fila-dia span:last-child::before {
  content: '';
  position: absolute;
  top: 50%;
  width: calc(var(--hueco) - 2 * var(--holgura));
  height: 1px;
  background: var(--dorado-linea);
}
/* Arrancan en el borde de la caja, no dentro: el filete queda centrado en el
   hueco y no llega al texto por ninguno de los dos lados.

   El de la izquierda descuenta además los 0,28em del espaciado sobrante. El
   margen negativo del span arregla el espaciado del layout, pero este filete
   se ancla al borde de la caja, que sigue incluyendo ese aire; sin
   descontarlo su holgura salía 3,8 px mayor que la del otro. */
.fila-dia span:first-child::after  { left: 100%;  margin-left: calc(var(--holgura) - 0.28em); }
.fila-dia span:last-child::before  { right: 100%; margin-right: var(--holgura); }

.fila-dia strong {
  font-family: var(--serif);
  font-size: clamp(4.4rem, 14vw, 7rem);
  font-weight: 300;
  line-height: 1;
  letter-spacing: -0.025em;   /* display grande: tracking negativo */
  color: var(--dorado);
  text-shadow: 0 4px 30px rgb(var(--oro-rgb) / 0.3);
}

.faltan-script {
  font-family: var(--script);
  font-size: clamp(2rem, 5vw, 2.7rem);
  color: var(--marfil-medio);
  margin: 0 0 1.5rem;
}

/* --- Reloj: cada bloque gira en 3D al entrar (escalonado 70ms) --- */
.reloj {
  display: flex;
  align-items: flex-start;
  justify-content: center;
  gap: clamp(1rem, 4vw, 2.6rem);
  margin: 0 0 2.8rem;
  perspective: 900px;
}

.reloj > div {
  min-width: clamp(62px, 18vw, 92px);
  padding: 1.1rem 0.5rem;
  /* Difuminado suave morado → azul → fucsia, velado sobre el fondo de la
     ficha: pastel en papel, resplandor tenue en noche. */
  background:
    linear-gradient(135deg,
      rgb(158 120 238 / 0.2)  0%,
      rgb(59 130 246 / 0.14) 48%,
      rgb(213 57 158 / 0.16) 100%),
    var(--carta-fondo);
  border: 1px solid rgb(158 120 238 / 0.35);
  border-radius: 2px;
  transform-style: preserve-3d;
  transition: transform var(--t-hover) var(--ease-out);
}
.reveal.visible .reloj > div {
  /* backwards, por lo mismo: si no, el hover no se veía */
  animation: girarReloj 620ms var(--ease-out) backwards;
}
.reveal.visible .reloj > div:nth-child(1) { animation-delay: 420ms; }
.reveal.visible .reloj > div:nth-child(2) { animation-delay: 490ms; }
.reveal.visible .reloj > div:nth-child(3) { animation-delay: 560ms; }

@keyframes girarReloj {
  from { opacity: 0; transform: rotateX(-84deg) translateZ(-40px); }
  to   { opacity: 1; transform: rotateX(0deg)   translateZ(0); }
}

.reloj b {
  display: block;
  font-family: var(--serif);
  font-size: clamp(2.4rem, 7vw, 3.3rem);
  font-weight: 300;
  line-height: 1;
  letter-spacing: -0.015em;
  color: var(--oro-texto);
}

.reloj i {
  display: block;
  margin-top: 0.5rem;
  font-family: var(--sans);
  font-size: 0.68rem;
  font-style: normal;
  font-weight: 400;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--marfil-tenue);
}

/* --- Calendario --- */
.calendario {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: clamp(3px, 1vw, 7px);
  max-width: 330px;
  margin: 0 auto;
}

.calendario .h {
  font-family: var(--sans);
  font-size: clamp(0.62rem, 1.6vw, 0.74rem);
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--dorado);
  opacity: 0.75;
  padding-bottom: 0.5rem;
}

.calendario .d {
  aspect-ratio: 1;
  display: grid;
  place-items: center;
  font-family: var(--serif);
  font-size: clamp(0.95rem, 2.4vw, 1.15rem);
  color: var(--marfil-medio);
  border-radius: 2px;
}

/* El día de la boda: el mismo degradado morado→azul→fucsia del reloj,
   aquí a plena tinta. El resplandor pulsa con opacity en un ::after,
   no con box-shadow animado. */
.calendario .d.boda {
  position: relative;
  color: #FFF;
  /* UN solo degradado continuo, todo morado: del lila luminoso al
     morado hondo, sin parches. */
  background: linear-gradient(140deg,
    #9B7BF0 0%, #8463E4 45%, #6C48D6 100%);
  font-weight: 600;
  box-shadow: 0 4px 16px rgb(132 99 228 / 0.55);
}
.calendario .d.boda::after {
  content: '';
  position: absolute;
  inset: -4px;
  border-radius: 4px;
  box-shadow:
    0 0 22px 4px rgb(132 99 228 / 0.55),
    0 0 32px 8px rgb(155 123 240 / 0.3);
  pointer-events: none;
  animation: pulsoDia 3s var(--ease-in-out) infinite;
}

@keyframes pulsoDia {
  0%, 100% { opacity: 0.25; }
  50%      { opacity: 1; }
}

/* Al entrar el calendario en vista, la fecha se enciende con tres latidos
   decrecientes —un foco de cine— y queda en su brillo de siempre. */
.reveal.visible .calendario .d.boda {
  animation: focoCine 1.9s var(--ease-in-out) 900ms backwards;
}
@keyframes focoCine {
  0%   { transform: scale(1);    filter: brightness(1); }
  16%  { transform: scale(1.22); filter: brightness(1.6); }
  36%  { transform: scale(1);    filter: brightness(1); }
  52%  { transform: scale(1.13); filter: brightness(1.35); }
  70%  { transform: scale(1);    filter: brightness(1); }
  84%  { transform: scale(1.06); filter: brightness(1.15); }
  100% { transform: scale(1);    filter: brightness(1); }
}
@media (prefers-reduced-motion: reduce) {
  .calendario .d.boda::after { animation: none; opacity: 0.6; }
  .reveal.visible .calendario .d.boda { animation: none; }
}

/* ═══════════════════════════════════════════════════════════════════
   3 · VERSÍCULO
   ═══════════════════════════════════════════════════════════════════ */

.verso-texto {
  font-family: var(--serif);
  font-size: clamp(1.2rem, 3.2vw, 1.6rem);
  font-style: italic;
  font-weight: 400;
  line-height: 2.05;
  color: var(--marfil);
  margin: 0 0 1.6rem;
}

.verso-cita {
  font-family: var(--sans);
  font-size: 0.8rem;
  font-weight: 400;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--dorado);
  margin: 0;
}

.acuarela {
  margin: 2.2rem auto 0;
  max-width: 420px;
  border-radius: 2px;
  overflow: hidden;
  transform-style: preserve-3d;
  box-shadow: var(--tarjeta-sombra);
  transition: transform var(--t-hover) var(--ease-out);
}
.acuarela img { width: 100%; height: auto; }
.acuarela.vacio { display: none; }
.acuarela.pequena { max-width: 100%; margin: 0 0 1.4rem; }

/* ═══════════════════════════════════════════════════════════════════
   4 · ITINERARIO
   ═══════════════════════════════════════════════════════════════════ */

#itinerario .reveal { max-width: 1000px; display: block; }

.itin-titulo { margin-bottom: 3rem; }

/* ═══════════════════════════════════════════════════════════════════
   5 · DRESS CODE
   ═══════════════════════════════════════════════════════════════════ */

.paleta {
  display: flex;
  justify-content: center;
  gap: clamp(0.6rem, 2.5vw, 1.1rem);
  margin-top: 2.2rem;
  perspective: 800px;
}

.paleta span {
  width: clamp(46px, 12vw, 66px);
  aspect-ratio: 1;
  border-radius: 2px;
  border: 1px solid rgb(var(--tinta-rgb) / 0.14);
  box-shadow: 0 10px 24px -8px rgb(var(--sombra-rgb) / calc(0.7 * var(--sombra-k)));
  transform-style: preserve-3d;
  transition: transform var(--t-hover) var(--ease-out);
}

/* Paleta: marino, azul, violeta sutil, dorado, marfil */
.swatch-oscuro { background: #0B1A2E; }
.swatch-medio  { background: #23456F; }
.swatch-claro  { background: #7B6BA8; }
.swatch-dorado { background: #D4B570; }
.swatch-crema  { background: #F4EFE6; }

/* Escalonado 70ms */
.reveal.visible .paleta span {
  /* backwards y no both: con both el fotograma final sostenía el transform
     y el efecto al pasar el cursor no llegaba a aplicarse. Con backwards
     solo se sostiene el estado previo al arranque, y al terminar mandan las
     declaraciones. El fotograma final coincide con el reposo, así que no
     hay salto. */
  animation: voltearMuestra 560ms var(--ease-out) backwards;
}
.reveal.visible .paleta span:nth-child(1) { animation-delay: 360ms; }
.reveal.visible .paleta span:nth-child(2) { animation-delay: 430ms; }
.reveal.visible .paleta span:nth-child(3) { animation-delay: 500ms; }
.reveal.visible .paleta span:nth-child(4) { animation-delay: 570ms; }
.reveal.visible .paleta span:nth-child(5) { animation-delay: 640ms; }

@keyframes voltearMuestra {
  from { opacity: 0; transform: rotateY(-90deg) translateZ(-46px); }
  to   { opacity: 1; transform: rotateY(0deg)   translateZ(0); }
}

/* ═══════════════════════════════════════════════════════════════════
   6 · REGALOS
   ═══════════════════════════════════════════════════════════════════ */

#regalos .reg-texto { margin-bottom: 2.2rem; }

/* ═══════════════════════════════════════════════════════════════════
   7 · CONFIRMAR ASISTENCIA
   ═══════════════════════════════════════════════════════════════════ */

.conf-limite {
  font-family: var(--sans);
  font-size: 0.8rem;
  font-weight: 400;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--dorado);
  margin: 0 0 2.2rem;
}

.form-rsvp {
  width: 100%;
  max-width: 560px;
  margin: 2.2rem auto 0;
  padding: clamp(2rem, 5vw, 3rem);
  text-align: left;
  background:
    linear-gradient(147deg,
      rgba(150, 116, 226, 0.05) 0%,
      transparent 60%),
    var(--tarjeta);
  -webkit-backdrop-filter: blur(26px) saturate(175%);
  backdrop-filter: blur(26px) saturate(175%);
  border: 1px solid var(--tarjeta-borde);
  border-radius: 3px;
  box-shadow: var(--tarjeta-sombra);
  transform-style: preserve-3d;
  display: none;
}

/* Acción deliberada del usuario: puede tomarse su tiempo (480ms). */
.form-rsvp.abierto {
  display: block;
  animation: abrirFormulario 480ms var(--ease-out) both;
}

@keyframes abrirFormulario {
  from { opacity: 0; transform: rotateX(-20deg) translateZ(-100px) translateY(-16px); }
  to   { opacity: 1; transform: rotateX(0deg)   translateZ(0)      translateY(0); }
}

/* --- Campos ---------------------------------------------------------- */

.campo {
  margin: 0 0 1.6rem;
  padding: 0;
  border: none;
}
.campo:last-of-type { margin-bottom: 1.9rem; }
.campo.oculto { display: none; }

.campo > label,
.campo-grupo > legend {
  display: flex;
  align-items: baseline;
  gap: 0.55rem;
  width: 100%;
  margin: 0 0 0.6rem;
  padding: 0;
  font-family: var(--sans);
  font-size: 0.76rem;
  font-weight: 500;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--oro-texto);
}

/* Marcas de obligatorio y opcional, en minúscula para no gritar */
.marca-req,
.marca-opt {
  font-size: 0.64rem;
  font-style: normal;
  font-weight: 400;
  letter-spacing: 0.1em;
  text-transform: lowercase;
}
.marca-req { color: rgb(var(--error-rgb) / 0.85); }
.marca-opt { color: var(--marfil-tenue); }

/* --- Entradas de texto ---
   La caja es del contenedor (.campo-caja, la tarjeta de vidrio con su
   medallón); el input va desnudo dentro. El line-height explícito sanea
   el cursor: con `normal`, Cormorant arma una línea alta y Safari puede
   dibujar el caret descolgado. */
.campo input[type="text"],
.campo input[type="tel"],
.campo textarea {
  width: 100%;
  padding: 0.88rem 1rem 0.88rem 0.8rem;
  font-family: var(--serif);
  font-size: 1.05rem;
  line-height: 1.4;
  color: var(--marfil);
  background: none;
  border: 0;
  border-radius: 13px;
}

.campo input::placeholder,
.campo textarea::placeholder {
  color: rgb(var(--tinta-rgb) / 0.32);
  font-style: italic;
}

.campo input:focus,
.campo textarea:focus { outline: none; }

.campo textarea {
  resize: vertical;
  min-height: 96px;
  line-height: 1.6;
}

/* ---- La tarjeta de vidrio de cada entrada ---- */
.campo-caja {
  position: relative;
  display: flex;
  align-items: center;
  background:
    linear-gradient(150deg, rgb(var(--acento-a, 118 193 204) / 0.05) 0%, transparent 60%),
    rgb(var(--campo-rgb) / 0.6);
  border: 1px solid var(--campo-linea);
  border-radius: 14px;
  transition:
    border-color var(--t-hover) var(--ease-out),
    box-shadow   var(--t-hover) var(--ease-out),
    background   var(--t-hover) var(--ease-out);
}
.campo-caja:focus-within {
  border-color: transparent;
  background: rgb(var(--campo-rgb) / 0.85);
  box-shadow:
    0 0 0 4px rgb(var(--oro-rgb) / 0.1),
    0 10px 26px -14px rgb(var(--sombra-rgb) / calc(0.6 * var(--sombra-k)));
}

/* El medallón del icono: dice de qué va el campo antes de leer la etiqueta */
.campo-icono {
  flex: none;
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  margin-left: 0.55rem;
  color: var(--oro-texto);
  border: 1px solid rgb(var(--oro-rgb) / 0.28);
  border-radius: 11px;
  background: radial-gradient(circle at 32% 26%, rgb(var(--oro-rgb) / 0.18) 0%, transparent 70%);
  transition: color var(--t-hover), border-color var(--t-hover);
}
.campo-icono svg { width: 19px; height: 19px; }
.campo-caja:focus-within .campo-icono {
  color: var(--dorado);
  border-color: rgb(var(--oro-rgb) / 0.6);
}

/* En el mensaje, el icono acompaña a la primera línea, no al centro */
.caja-multilinea { align-items: flex-start; }
.caja-multilinea .campo-icono { margin-top: 0.62rem; }

/* El anillo que gira al enfocar: un degradado cónico oro→violeta pintado
   solo en el canto (la máscara descuenta el centro). Si el navegador no
   anima la variable tipada, queda un anillo quieto, que también vale. */
@property --anillo { syntax: '<angle>'; inherits: false; initial-value: 0deg; }
.campo-caja::after {
  content: '';
  position: absolute;
  inset: -1px;
  padding: 1.5px;
  border-radius: 15px;
  background: conic-gradient(from var(--anillo),
    rgb(var(--oro-rgb)) 0deg,
    #9E78EE 120deg,
    rgb(var(--oro-rgb) / 0.45) 200deg,
    #C9A455 280deg,
    rgb(var(--oro-rgb)) 360deg);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
          mask-composite: exclude;
  opacity: 0;
  transition: opacity 220ms var(--ease-out);
  pointer-events: none;
}
.campo-caja:focus-within::after {
  opacity: 1;
  animation: giraAnillo 2.8s linear infinite;
}
@keyframes giraAnillo { to { --anillo: 360deg; } }
@media (prefers-reduced-motion: reduce) {
  .campo-caja:focus-within::after { animation: none; }
}

/* Campo con problema: el borde lo señala sin depender solo del color */
.campo.con-error .campo-caja,
.campo.con-error input,
.campo.con-error textarea { border-color: var(--error); }
.campo.con-error .campo-caja:focus-within {
  box-shadow: 0 0 0 4px rgba(224, 133, 133, 0.18);
}
.campo.con-error .campo-caja::after { content: none; }

.campo-aviso {
  margin: 0.5rem 0 0;
  font-family: var(--sans);
  font-size: 0.72rem;
  color: var(--error);
  min-height: 0;
}
.campo-aviso:empty { display: none; }

.campo-pista {
  margin: 0.5rem 0 0;
  font-family: var(--sans);
  font-size: 0.7rem;
  color: var(--marfil-tenue);
}

.campo-cuenta {
  margin: 0.45rem 0 0;
  font-family: var(--sans);
  font-size: 0.68rem;
  font-variant-numeric: tabular-nums;
  text-align: right;
  color: var(--marfil-tenue);
  transition: color var(--t-hover) var(--ease-out);
}
.campo-cuenta.al-limite { color: var(--dorado); }

/* --- Teléfono con prefijo fijo ---
   El prefijo vive fuera del campo, así no se puede borrar por descuido y
   el valor queda limpio para validarlo. */
.campo-tel {
  display: flex;
  align-items: stretch;
  background: rgb(var(--campo-rgb) / 0.6);
  border: 1px solid var(--campo-linea);
  border-radius: 14px;
  transition:
    border-color var(--t-hover) var(--ease-out),
    box-shadow   var(--t-hover) var(--ease-out);
}
/* El foco se dibuja en el contenedor: el campo y el prefijo se leen como
   una sola pieza. */
.campo-tel:focus-within {
  border-color: var(--dorado);
  box-shadow: 0 0 0 3px rgb(var(--oro-rgb) / 0.16);
}

.tel-prefijo {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex: 0 0 auto;
  padding: 0 0.85rem 0 1rem;
  border-right: 1px solid var(--campo-div);
  font-family: var(--sans);
  font-size: 0.92rem;
  letter-spacing: 0.04em;
  color: var(--marfil-medio);
  user-select: none;
}

.bandera {
  width: 22px;
  height: auto;
  border-radius: 1.5px;
  box-shadow: 0 0 0 1px rgb(var(--sombra-rgb) / calc(0.35 * var(--sombra-k)));
}

.tel-codigo { font-variant-numeric: tabular-nums; }

/* El campo dentro pierde su propio marco: ya lo lleva el contenedor */
.campo-tel input[type="tel"] {
  flex: 1 1 auto;
  min-width: 0;
  background: none;
  border: none;
  border-radius: 0;
  letter-spacing: 0.06em;
}
.campo-tel input[type="tel"]:focus {
  background: none;
  box-shadow: none;
  border: none;
}

/* --- Opciones sí / no --- */
.campo-grupo { min-width: 0; }   /* fieldset no encoge sin esto */

.opciones-asistencia {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: 0.7rem;
}

.opcion-radio { position: relative; }

.opcion-radio input[type="radio"] {
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
}

.opcion-radio label {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  margin: 0;
  padding: 0.85rem 1rem;
  font-family: var(--sans);
  font-size: 0.8rem;
  font-weight: 500;
  letter-spacing: 0.08em;
  color: var(--marfil-medio);
  background: rgb(var(--campo-rgb) / 0.55);
  border: 1px solid var(--campo-linea);
  border-radius: 12px;
  cursor: pointer;
  transform-style: preserve-3d;
  transition:
    color        var(--t-hover) var(--ease-out),
    background   var(--t-hover) var(--ease-out),
    border-color var(--t-hover) var(--ease-out),
    transform    var(--t-hover) var(--ease-out);
}

/* Casilla con el icono: da confirmación visible al elegir */
.op-marca {
  flex: 0 0 auto;
  width: 20px;
  height: 20px;
  display: grid;
  place-items: center;
  border: 1px solid rgb(var(--tinta-rgb) / 0.24);
  border-radius: 50%;
  color: transparent;
  transition:
    color            var(--t-hover) var(--ease-out),
    border-color     var(--t-hover) var(--ease-out),
    background-color var(--t-hover) var(--ease-out);
}
.op-marca svg { width: 12px; height: 12px; }

/* El rótulo se queda con el resto del ancho y no se parte en dos líneas */
.op-texto { flex: 1 1 auto; }

.opcion-radio input:checked + label {
  color: var(--marfil);
  background: rgb(var(--oro-rgb) / 0.12);
  border-color: var(--dorado);
  transform: translateZ(14px);
}
.opcion-radio input:checked + label .op-marca {
  color: var(--marino);
  background-color: var(--dorado);
  border-color: var(--dorado);
}
.opcion-radio input:focus-visible + label {
  outline: 2px solid var(--dorado);
  outline-offset: 2px;
}

/* --- Contador de acompañantes --- */
.contador {
  display: inline-flex;
  align-items: stretch;
  background: rgb(var(--campo-rgb) / 0.6);
  border: 1px solid var(--campo-linea);
  border-radius: 14px;
  overflow: hidden;
}
.contador:focus-within {
  border-color: var(--dorado);
  box-shadow: 0 0 0 3px rgb(var(--oro-rgb) / 0.16);
}

.contador-btn {
  width: 46px;
  display: grid;
  place-items: center;
  padding: 0;
  color: var(--oro-texto);
  background: none;
  border: none;
  cursor: pointer;
  transition: background-color var(--t-hover) var(--ease-out),
              color var(--t-hover) var(--ease-out);
}
.contador-btn svg { width: 15px; height: 15px; }
.contador-btn:active { background-color: rgb(var(--oro-rgb) / 0.2); transition-duration: 100ms; }
.contador-btn:focus-visible { outline: 2px solid var(--dorado); outline-offset: -2px; }
.contador-btn:disabled { color: var(--marfil-tenue); cursor: not-allowed; }

.contador input[type="number"] {
  width: 4.2rem;
  padding: 0.8rem 0;
  text-align: center;
  font-family: var(--serif);
  font-size: 1.15rem;
  line-height: 1.4;
  color: var(--marfil);
  font-variant-numeric: tabular-nums;
  background: none;
  border: none;
  border-left: 1px solid var(--campo-div);
  border-right: 1px solid var(--campo-div);
  border-radius: 0;
  /* Las flechas nativas sobran: ya están los dos botones */
  -moz-appearance: textfield;
  appearance: textfield;
}
.contador input[type="number"]::-webkit-outer-spin-button,
.contador input[type="number"]::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}
.contador input[type="number"]:focus { background: none; box-shadow: none; }

/* --- Botón de envío --- */
.btn-enviar {
  position: relative;
  width: 100%;
  margin-top: 0.4rem;
  padding: 1.15rem;
  font-family: var(--sans);
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--sobre-oro);
  background: linear-gradient(135deg, var(--dorado-claro), var(--oro-relleno));
  border: none;
  border-radius: 3px;
  cursor: pointer;
  overflow: hidden;
  transform-style: preserve-3d;
  transition: transform var(--t-hover) var(--ease-out),
              box-shadow var(--t-hover) var(--ease-out);
}

/* Brillo que cruza el botón al pasar el cursor */
.btn-enviar::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(105deg,
    transparent 34%,
    rgba(255, 255, 255, 0.42) 50%,
    transparent 66%);
  transform: translateX(-100%);
  pointer-events: none;
}

.btn-enviar:active { transform: translateZ(4px) scale(0.99); transition-duration: var(--t-press); }
.btn-enviar:focus-visible { outline: 2px solid var(--dorado-claro); outline-offset: 3px; }

.btn-texto { position: relative; z-index: 1; }

/* Estado enviando: el texto cede el sitio al giro */
.btn-giro {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 19px;
  height: 19px;
  margin: -9.5px 0 0 -9.5px;
  border: 2px solid rgba(11, 26, 46, 0.28);
  border-top-color: var(--marino);
  border-radius: 50%;
  opacity: 0;
}
.btn-enviar.enviando { cursor: progress; }
.btn-enviar.enviando .btn-texto { opacity: 0; }
.btn-enviar.enviando .btn-giro {
  opacity: 1;
  animation: girarEspera 700ms linear infinite;
}
@keyframes girarEspera { to { transform: rotate(360deg); } }

.btn-enviar:disabled { opacity: 0.62; cursor: not-allowed; transform: none; }

.form-msg {
  margin: 1.2rem 0 0;
  font-family: var(--sans);
  font-size: 0.82rem;
  line-height: 1.6;
  text-align: center;
  color: var(--exito);
}
.form-msg:empty { display: none; }
.form-msg.error { color: var(--error); }

/* --- Pantalla de gracias --- */
.gracias {
  width: 100%;
  max-width: 560px;
  margin: 2.2rem auto 0;
  padding: clamp(2.5rem, 6vw, 3.5rem);
  text-align: center;
  background:
    linear-gradient(147deg,
      rgba(150, 116, 226, 0.05) 0%,
      transparent 60%),
    var(--tarjeta);
  -webkit-backdrop-filter: blur(26px) saturate(175%);
  backdrop-filter: blur(26px) saturate(175%);
  border: 1px solid var(--dorado-linea);
  border-radius: 3px;
  box-shadow: var(--tarjeta-sombra-alta);
  animation: entrarGracias 620ms var(--ease-out) both;
}

@keyframes entrarGracias {
  from { opacity: 0; transform: rotateX(-18deg) translateZ(-90px) scale(0.95); }
  to   { opacity: 1; transform: rotateX(0)      translateZ(0)     scale(1); }
}

/* ═══════════════════════════════════════════════════════════════════
   PIE
   ═══════════════════════════════════════════════════════════════════ */

#pie {
  position: relative;
  z-index: 1;
  perspective: 900px;
  overflow: hidden;
  padding: clamp(3.5rem, 9vh, 5.5rem) 1.5rem;
  text-align: center;
  background: var(--marino-profundo);
  border-top: 1px solid var(--dorado-linea);
}

/* El pie también lleva luz, para que el efecto llegue hasta el final */
#pie::before {
  content: '';
  position: absolute;
  inset: -50% -30%;
  z-index: 0;
  pointer-events: none;
  background: radial-gradient(38% 44% at 32% 30%,
    rgba(158, 120, 238, 0.28) 0%,
    rgba(120, 98, 196, 0.12) 42%,
    transparent 76%);
  filter: blur(30px);
  opacity: 0;
  translate: calc(var(--luz-x, 0px) * 0.42) calc(var(--luz-y, 0px) * 0.42);
  transition: opacity 1500ms var(--ease-out), translate 440ms var(--ease-out);
}
body.carta-abierta #pie::before { opacity: 1; }

/* Orquídeas de cierre: espejadas y al lado opuesto del hero, para que
   las dos apariciones no se lean como la misma imagen repetida. */
.flores-pie {
  position: absolute;
  right: max(-3.5rem, -6vw);
  bottom: -2rem;
  width: clamp(140px, 19vw, 260px);
  height: auto;
  z-index: 0;
  pointer-events: none;
  opacity: 0.5;
  transform: scaleX(-1);
  filter: drop-shadow(0 14px 26px rgb(var(--sombra-rgb) / calc(0.5 * var(--sombra-k))));
}

.pie-nombres {
  position: relative;
  z-index: 1;
  font-family: var(--script);
  font-size: clamp(2.4rem, 7vw, 3.5rem);
  color: var(--dorado);
  margin: 0 0 0.7rem;
  text-shadow: 0 2px 20px rgb(var(--oro-rgb) / 0.25);
}

.pie-fecha {
  position: relative;
  z-index: 1;
  font-family: var(--sans);
  font-size: 0.72rem;
  font-weight: 400;
  letter-spacing: 0.42em;
  text-indent: 0.42em;
  color: var(--marfil-medio);
  margin: 0;
}

/* ═══════════════════════════════════════════════════════════════════
   CONFETI (momento de celebración)
   ═══════════════════════════════════════════════════════════════════ */

.confetti {
  position: fixed;
  top: -20px;
  width: 8px;
  height: 8px;
  pointer-events: none;
  z-index: 999;
  animation: caerConfeti 3.2s linear forwards;
}

@keyframes caerConfeti {
  0%   { transform: translateY(0) rotateZ(0deg) rotateY(0deg); opacity: 1; }
  100% { transform: translateY(105vh) rotateZ(720deg) rotateY(360deg); opacity: 0; }
}

/* ═══════════════════════════════════════════════════════════════════
   3.5 · NOSOTROS · BARAJA 3D
   Las fotos entran abanicándose desde una pila y cada una se adelanta
   al pasar el cursor. Solo transform y opacity.
   ═══════════════════════════════════════════════════════════════════ */

.baraja {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 100%;
  max-width: 1080px;
  margin: clamp(2rem, 5vh, 3.4rem) auto 0;
  padding: 2.5rem 0;
  perspective: 1600px;
  perspective-origin: 50% 45%;
}

.baraja-carta {
  /* Posición de reposo del abanico, por carta */
  --ry: 0deg;
  --rz: 0deg;
  --z: 0px;
  --y: 0px;

  position: relative;
  flex: 0 0 auto;
  width: clamp(140px, 19vw, 244px);
  aspect-ratio: 3 / 4;
  margin: 0 clamp(-34px, -2.2vw, -16px);
  padding: 0;
  overflow: hidden;
  background: var(--marino-alto);
  border: 6px solid var(--papel);
  border-radius: 2px;
  box-shadow: 0 26px 54px -18px rgb(var(--sombra-rgb) / calc(0.78 * var(--sombra-k)));
  opacity: 0;
  will-change: transform;
  transform: translateY(var(--y)) rotateY(var(--ry)) rotateZ(var(--rz)) translateZ(var(--z));
  transition: transform 240ms var(--ease-out),
              box-shadow 240ms var(--ease-out);
}

.baraja-carta img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Abanico simétrico: las del centro quedan al frente */
.baraja-carta:nth-child(1) { --ry:  17deg; --rz: -3deg; --z: -76px; --y:  12px; z-index: 1; }
.baraja-carta:nth-child(2) { --ry:   6deg; --rz: -1deg; --z: -14px; --y:  -6px; z-index: 3; }
.baraja-carta:nth-child(3) { --ry:  -6deg; --rz:  1deg; --z: -14px; --y:  -6px; z-index: 2; }
.baraja-carta:nth-child(4) { --ry: -17deg; --rz:  3deg; --z: -76px; --y:  12px; z-index: 1; }

/* Entrada: desde la pila hacia el abanico. var() se resuelve por carta. */
.baraja.visible .baraja-carta {
  /* La opacidad se declara aquí: con backwards, al terminar la animación
     manda la declaración, y en .baraja-carta la opacidad de reposo es 0.
     Sin esta línea las fotos se desvanecerían al acabar de entrar. */
  opacity: 1;
  animation: abrirBaraja 900ms var(--ease-out) backwards;
}
.baraja.visible .baraja-carta:nth-child(1) { animation-delay:  60ms; }
.baraja.visible .baraja-carta:nth-child(2) { animation-delay: 170ms; }
.baraja.visible .baraja-carta:nth-child(3) { animation-delay: 280ms; }
.baraja.visible .baraja-carta:nth-child(4) { animation-delay: 390ms; }

/* Salen de una pila cerrada: todas al centro, sin abanico, y desde el
   fondo. El recorrido en Z es el que hace visible la profundidad. */
@keyframes abrirBaraja {
  from {
    opacity: 0;
    transform: translateY(58px) rotateY(0deg) rotateZ(0deg) translateZ(-300px) scale(0.86);
  }
  60% { opacity: 1; }
  to {
    opacity: 1;
    transform: translateY(var(--y)) rotateY(var(--ry)) rotateZ(var(--rz)) translateZ(var(--z));
  }
}

/* ═══════════════════════════════════════════════════════════════════
   HOVER — solo en dispositivos con puntero fino.
   Evita estados pegados en pantallas táctiles.
   ═══════════════════════════════════════════════════════════════════ */

@media (hover: hover) and (pointer: fine) {
  /* La carta se endereza y se adelanta: telegrafía "mírame" */
  .baraja-carta:hover {
    transform: translateY(-16px) rotateY(0deg) rotateZ(0deg) translateZ(96px);
    box-shadow: 0 44px 80px -22px rgb(var(--sombra-rgb) / calc(0.9 * var(--sombra-k)));
    z-index: 10;
  }
  .btn-linea:hover {
    color: var(--marino);
    background: var(--dorado);
    border-color: var(--dorado);
    transform: translateZ(22px) translateY(-2px);
  }

  .ctrl:hover { color: var(--dorado); transform: scale(1.12); }

  .ctrl.play:hover {
    background: var(--dorado-vidrio);
    transform: translateZ(18px) scale(1.05);
  }

  .reloj > div:hover { transform: translateZ(22px) translateY(-3px); }

  .acuarela:hover { transform: translateZ(26px) scale(1.015); }

  .paleta span:hover { transform: translateZ(26px) translateY(-6px) scale(1.06); }

  .opcion-radio label:hover {
    border-color: var(--dorado-linea);
    color: var(--marfil);
    transform: translateZ(12px);
  }

  .btn-enviar:hover { transform: translateZ(24px) translateY(-2px); }

  .lugar-medallon:hover { transform: translateZ(22px) scale(1.04); }
}

/* ═══════════════════════════════════════════════════════════════════
   RESPONSIVE
   ═══════════════════════════════════════════════════════════════════ */

/* La baraja se apila en vertical: un abanico de 4 no cabe en móvil */
@media (max-width: 760px) {
  .baraja {
    flex-direction: column;
    padding: 1.5rem 0;
    perspective: 1100px;
  }
  .baraja-carta {
    width: min(74%, 270px);
    margin: clamp(-26px, -3vw, -14px) 0;
  }
  .baraja-carta:nth-child(1) { --ry:  11deg; --rz: -2deg; --z: 0px; --y: 0px; }
  .baraja-carta:nth-child(2) { --ry: -11deg; --rz:  2deg; --z: 0px; --y: 0px; }
  .baraja-carta:nth-child(3) { --ry:  11deg; --rz: -2deg; --z: 0px; --y: 0px; }
  .baraja-carta:nth-child(4) { --ry: -11deg; --rz:  2deg; --z: 0px; --y: 0px; }
}

/* ═══════════════════════════════════════════════════════════════════
   PANTALLAS ANGOSTAS
   La mayoría abrirá esto desde el teléfono, así que aquí no se recorta:
   se recompone.
   ═══════════════════════════════════════════════════════════════════ */

@media (max-width: 900px) {
  /* Los nombres NO se apartan a los lados.
     Medido: la tapa abierta mide 189 px de alto en un teléfono, y a la
     altura del nombre su triángulo abarca unos 160 px de ancho. Apartar
     cada palabra lo suficiente para esquivarla las saca de la pantalla,
     y subirlas por encima del vértice las manda fuera por arriba. No hay
     hueco. Así que al abrir, el encabezado cede el escenario al sobre y
     se retira hacia arriba: los nombres ya se leyeron antes de tocar. */
  /* Aquí los nombres NO se apartan, y no por olvido: en el teléfono ocupan
     337 de los 390 px de ancho, así que el hueco que queda son 3 px por
     lado —invisibles— y bajar el aire mínimo para ganar diez más los deja
     al filo de la pantalla. Además el sobre no queda ENTRE ellos sino
     debajo, de modo que apartarse tampoco despejaría nada. */
  body.carta-abierta .nombres-hero .pal-izq,
  body.carta-abierta .nombres-hero .pal-der,
  body.carta-abierta .nombres-hero .union { transform: none; opacity: 1; }

  /* Los nombres se quedan a la vista con la carta abierta, como en el
     escritorio. Para que quepan, el filete, la fecha y la pista se retiran y
     además CEDEN SU ALTO, y el sobre baja a ocupar ese hueco.

     Medido a 393x659: nombres 65 + tapa y sobre 403 + reproductor 77, con sus
     huecos, son 564 de los 611 que deja el relleno de la portada. Cabe. Pero
     con el filete (30), la fecha (22) y la pista (27) ocupando sitio, no.

     El alto se anima con transición y no con animación porque la entrada de
     esas piezas usa fill: both y sostiene opacity y transform; el alto no lo
     toca, así que ahí la transición sí manda. */
  .hero-filete,
  .fecha-hero,
  .hero-pista {
    /* Punto de partida para el alto: sin un valor de origen, max-height: 0
       no tiene desde dónde animar. Holgado, para no recortar nada. */
    max-height: 6rem;
  }

  body.carta-abierta .hero-filete,
  body.carta-abierta .fecha-hero,
  body.carta-abierta .hero-pista {
    max-height: 0;
    margin-top: 0;
    margin-bottom: 0;
    overflow: hidden;
    transition:
      max-height    560ms var(--ease-out) 260ms,
      margin-top    560ms var(--ease-out) 260ms,
      margin-bottom 560ms var(--ease-out) 260ms;
  }

  /* La opacidad, con animación de salida en las dos que traen fill: both */
  body.carta-abierta .hero-filete { animation: retirarFilete 340ms var(--ease-out) 180ms both; }
  body.carta-abierta .fecha-hero  { animation: retirarFecha  340ms var(--ease-out) 180ms both; }

  @keyframes retirarFilete { from { opacity: 1; transform: scaleX(1); } to { opacity: 0; transform: scaleX(0.55); } }
  @keyframes retirarFecha  { from { opacity: 1; transform: translateY(0); } to { opacity: 0; transform: translateY(-8px); } }

  /* El sobre baja lo que mide su tapa abierta más un margen, para que la
     tapa deje de solaparse con los nombres. La tapa mide el 74,90% del alto
     de la carta y la carta el 486/654 de su ancho: 0,5566 veces el ancho. */
  body.carta-abierta .carta-escena {
    margin-top: calc(0.5566 * var(--ancho-carta, 310px) + 1.4rem);
    margin-bottom: 0.4rem;
    transition: margin 700ms var(--ease-out) 260ms;
  }
  body.carta-abierta .reproductor { margin-top: 0.7rem; }
}

@media (max-width: 640px) {
  .bloque { padding: 4.2rem 1.15rem; }

  /* Menos profundidad: en pantalla chica una perspectiva fuerte deforma */
  .reveal { transform: rotateX(-9deg) translateZ(-70px) translateY(36px); }
  .bloque { perspective: 900px; }

  /* --- Portada --- */
  .hero-intro { max-width: 100%; }
  .nombres-hero {
    /* Sin nowrap: en pantalla angosta es mejor que parta a que se salga */
    white-space: normal;
    font-size: clamp(2.9rem, 15vw, 4.2rem);
    line-height: 1.1;
  }
  .hero-etiqueta { letter-spacing: 0.3em; }
  .hero-etiqueta span { margin-right: -0.3em; }
  .fecha-hero { letter-spacing: 0.36em; text-indent: 0.36em; }

  #portada {
    padding-top: clamp(1.5rem, 3.5vh, 2.5rem);
    padding-bottom: clamp(1.5rem, 3.5vh, 2.5rem);
  }
  /* Un solo sitio para el ancho del sobre: lo usa la carta y también el
     margen que la baja al abrirse, que se calcula a partir de él. */
  #portada { --ancho-carta: min(310px, 80vw); }
  .carta { max-width: var(--ancho-carta); }
  .carta-escena { margin-top: clamp(1.4rem, 3.5vh, 2.2rem); }
  .hero-filete { margin: 1rem auto 0.8rem; }

  /* El campo de luz se ajusta al sobre pequeño */
  .carta-luz { width: 118vw; height: 74vh; }

  /* En el teléfono la ficha no deja hueco al costado —25 px— pero su esquina
     de arriba sí está libre, porque el número de sección va centrado. La flor
     se recoge ahí, más chica y asomando por el canto. */
  .flor-fecha {
    /* En la esquina de arriba, horizontal, asomando desde el canto
       izquierdo con el corte del tallo fuera de cuadro. La única tinta
       cercana es la frase de arriba y queda por debajo de la rama. */
    top: 1.8%;
    left: -1.4rem;
    width: clamp(200px, 58vw, 280px);
    --flor-f-giro: -5deg;
  }
  #fecha .reveal.visible ~ .flor-fecha {
    opacity: 0.82;
    transform: translateX(0) rotate(-5deg);
  }

  /* En el teléfono no hay margen al costado: la ficha del versículo ocupa
     casi todo el ancho y la tinta arranca a 43 px del canto. La flor baja
     entonces a la esquina de abajo a la izquierda, que sí queda libre, y
     asoma mordida por el borde: entera parecería puesta ahí. */
  .flor-anemona {
    right: auto;
    left: -4vw;
    top: auto;
    bottom: 0.5rem;
    width: clamp(76px, 22vw, 104px);
    --flor-a-giro: -7deg;
  }
  #verso .reveal.visible ~ .flor-anemona { opacity: 0.88; }

  /* El delfinio, en la esquina de abajo a la derecha. La regla anterior lo
     tumbaba 64° por el canto, que era lo que pedía la flor de antes —alta y
     estrecha, 620x1013—; el delfinio es casi cuadrado (993x1141) y así se
     iba casi entero fuera de pantalla: medido, quedaban 48 px visibles de
     140. Abajo a la derecha hay sitio: las orquídeas están a la izquierda y
     el reproductor al centro. */
  .flor-belen {
    /* En la esquina de arriba del sobre, apoyada ENCIMA de la tela: el
       plano alto (z-index 3) es el que evita que el sobre se la coma,
       que era lo que pasaba cuando vivía detrás. */
    top: 36%;
    bottom: auto;
    /* la base de escritorio ancla por la izquierda: aquí vuelve a auto */
    left: auto;
    right: -0.6rem;
    --flor-b-dx: 26px;
    width: clamp(104px, 29vw, 148px);
    --flor-b-alfa: 0.82;
    --flor-b-giro: -72deg;
    transform-origin: 50% 50%;
  }

  /* El sobre, más abajo: deja aire arriba para que la flor entre por la
     derecha a su altura y las dos flores queden en diagonal con él al medio. */
  .carta-escena { margin-top: clamp(3.4rem, 9vh, 5.2rem); }
  .luz-lobulo { filter: blur(42px); }

  /* La flor se queda abajo mientras el sobre está cerrado, igual que en
     escritorio. Solo se aparta al abrirlo, que es cuando aparece el
     reproductor y necesita el sitio.

     Se mueve con translate y scale, no con transform: la animación de
     entrada usa fill: both y sostiene su propio transform, así que uno
     declarado aparte no se vería. translate y scale son propiedades
     independientes y se componen con ella. */
  /* La flor se queda abajo, sin moverse. Antes subía 17vh para dejar sitio
     al reproductor, pero la solución buena no es mover la flor: es acomodar
     el reproductor al hueco que ella deja a su derecha. Así la flor
     conserva su sitio y el conjunto se lee mejor. */
  .flores-hero {
    width: clamp(120px, 34vw, 170px);
    left: -2.4rem;
    bottom: -2vh;
    top: auto;
    --flor-alfa: 0.72;
    transition: scale 950ms var(--ease-out);
  }

  /* Al abrir solo respira un poco: ya no hace falta que se aparte */
  body.carta-abierta .flores-hero {
    scale: 0.96;
    transition-delay: 700ms;
  }

  .flores-pie {
    width: clamp(110px, 30vw, 150px);
    opacity: 0.4;
  }

  /* --- Reproductor ---
     Se aparta a la derecha para caber en el hueco que deja la flor. El
     margen izquierdo es proporcional al ancho, igual que la flor, de modo
     que la holgura se mantiene entre 13 y 17 px en todos los tamaños:
     medido de 360 a 430 px. align-self: stretch lo hace ocupar desde ese
     margen hasta el borde derecho. */
  .reproductor {
    /* Ancho explícito en vez de align-self: stretch. Medido, stretch no
       descontaba el margen izquierdo y el reproductor se salía 92 px por
       la derecha. Con el ancho calculado y pegado al borde derecho queda
       exactamente en el hueco. */
    align-self: flex-end;
    width: calc(100% - clamp(5rem, 28vw, 8rem));
    max-width: none;
    margin-left: 0;
    margin-right: 0;
    gap: 0.7rem;
    padding: 0.7rem 1rem 0.7rem 0.7rem;
  }
  .rep-boton { width: 42px; height: 42px; }
  .rep-boton svg { width: 17px; height: 17px; }
  .rep-titulo { font-size: 0.9rem; }

  /* --- Fecha --- */
  /* En móvil el hueco se aprieta; el largo del filete lo sigue solo */
  .fila-dia { --hueco: clamp(1.2rem, 7vw, 1.9rem); --holgura: 0.42rem; }

  .reloj { gap: 0.55rem; }
  .reloj > div { min-width: 0; flex: 1 1 0; padding: 0.85rem 0.25rem; }

  .calendario { max-width: 100%; }

  /* --- Lugar --- */
  .lugar-medallon { width: clamp(104px, 30vw, 128px); margin-bottom: 1.4rem; }
  .lugar-horas { gap: 1.1rem; }
  .lugar-acciones { flex-direction: column; }
  .lugar-acciones .btn-linea { width: 100%; }

  .paleta { gap: 0.45rem; }

  /* --- Formulario --- */
  .opciones-asistencia { grid-template-columns: 1fr; }
  .form-rsvp { padding: 1.6rem 1.2rem; }
  .campo > label,
  .campo-grupo > legend { flex-wrap: wrap; gap: 0.35rem; }
  .tel-prefijo { padding: 0 0.65rem 0 0.8rem; }
  .contador { width: 100%; }
  .contador input[type="number"] { flex: 1 1 auto; width: auto; }

  /* Los botones ocupan el ancho: más fáciles de acertar con el pulgar */
  .btn-linea { width: 100%; text-align: center; }
  .btn-linea.grande { padding: 1.05rem 1.5rem; }
}


/* Teléfonos angostos */
@media (max-width: 380px) {
  .nombres-hero { font-size: 2.6rem; }
  #portada { --ancho-carta: 88vw; }
  .rep-tiempos { font-size: 0.6rem; }
}

/* Teléfonos de pantalla corta. Va después del bloque de 380 px a propósito:
   ese fija el ancho del sobre en 88vw y, puesto antes, se lo pisaba. Medido:
   a 375x635 la carta salía de 330 px en vez de 262.

   Teléfonos de pantalla corta. Con la carta abierta hay que acomodar en muy
   poco alto los nombres, la tapa abierta, el sobre y el reproductor. Medido a
   360x600, con el sobre a 310 px el reproductor se salía 19 px por abajo. */
@media (max-width: 640px) and (max-height: 660px) {
  #portada { --ancho-carta: min(262px, 72vw); }
  .nombres-hero { font-size: clamp(2.3rem, 12.5vw, 3.3rem); }
  body.carta-abierta .carta-escena { margin-bottom: 0.2rem; }
  body.carta-abierta .reproductor { margin-top: 0.45rem; }
}

/* Pantallas bajas: teléfono en horizontal, o ventana recortada */
@media (max-height: 700px) and (min-width: 641px) {
  .carta { max-width: min(430px, 44vh); }
  .hero-intro { margin-bottom: 0; }
}

/* ═══════════════════════════════════════════════════════════════════
   MOVIMIENTO REDUCIDO
   Variante más suave, no cero: se conservan los fundidos de opacidad
   y se eliminan los desplazamientos y rotaciones.
   ═══════════════════════════════════════════════════════════════════ */

@media (prefers-reduced-motion: reduce) {
  /* Los fundidos se mantienen, cortos */
  .reveal {
    transform: none;
    transition: opacity 240ms var(--ease-out);
  }
  .reveal.visible { transform: none; }
  .reveal.visible > * { animation: aparecer 240ms var(--ease-out) both; }

  @keyframes aparecer { from { opacity: 0; } to { opacity: 1; } }

  /* Entradas de la portada: solo fundido, sin recorrido 3D */
  .nombres-hero,
  .nombres-hero .pal-in,
  .hero-etiqueta span,
  .hero-filete,
  .fecha-hero,
  .flores-hero,
  .hero-intro,
  .carta,
  .carta-lamina,
  .carta-sello,
  .carta-tapa,
  .reveal.visible .reloj > div,
  .reveal.visible .paleta span,
  .form-rsvp.abierto,
  .gracias {
    animation: aparecer 240ms var(--ease-out) both !important;
    transform: none !important;
  }

  /* La flor de Belén también entra solo con fundido, pero conservando su
     giro: si entrara en la lista de arriba, el transform: none la dejaría
     vertical y en el teléfono se metería sobre el sobre y el reproductor. */
  .flor-belen {
    /* Fotograma final propio en vez de reusar aparecer: ese acaba en opacidad
       1 y, con fill: both, le ganaba a la declaración de 0,88 y 0,80, así que
       la flor salía a plena opacidad. */
    animation: aparecerFlorB 240ms var(--ease-out) both !important;
    transform: rotate(var(--flor-b-giro, -10deg)) !important;
  }

  @keyframes aparecerFlorB {
    from { opacity: 0; }
    to   { opacity: var(--flor-b-alfa, 0.88); }
  }
  body.carta-abierta .flor-belen { scale: 1; transition: none; }

  /* La tapa queda abierta de una vez, sin giro */
  .carta.abierta .carta-tapa { animation: none; transform: rotateX(0deg); z-index: 0; }
  .carta.abierta .carta-lamina {
    animation: none;
    transform: translateX(-50%) translateY(-73.58%) rotate(-1.5deg);
  }
  .carta.abierta .carta-sello { animation: none; opacity: 0; }
  .sello-halo { animation: none; opacity: 0.35; }
  .carta-sello:active img { transform: none; }
  .hero-pista { animation: none; }

  /* Los bucles decorativos se detienen */
  #portada::before,
  #portada::after,
  .calendario .d.boda::after { animation: none; }

  /* Sin desplazamiento en hover: solo cambios de color */
  .btn-linea:hover,
  .ctrl:hover,
  .ctrl.play:hover,
  .reloj > div:hover,
  .acuarela:hover,
  .paleta span:hover,
  .opcion-radio label:hover,
  .btn-enviar:hover,
  .opcion-radio input[type="radio"]:checked + label { transform: none; }

  .confetti,
  .particulas { display: none; }

  /* El filete queda trazado, sin dibujarse */
  .hero-filete { transform: scaleX(1); }

  /* Los nombres se apartan sin recorrido visible */
  .nombres-hero .palabra { transition-duration: 200ms; }

  /* Las luces de sección quedan encendidas, sin pulso */
  body.carta-abierta .bloque:not(#portada)::after { opacity: 0.75; transform: none; }

  /* La luz se enciende de inmediato, sin fundido de dos segundos */
  body::after,
  .carta-luz { transition-duration: 200ms; transition-delay: 0ms; }

  .lugar-medallon:hover { transform: none; }

  /* Nada acompaña al puntero */
  body::before,
  #portada::before,
  #portada::after,
  #pie::before,
  .carta-luz,
  .bloque:not(#portada)::after { translate: none; }

  /* El ecualizador se queda quieto a media altura */
  body.sonando .rep-barras span { animation: none; transform: scaleY(0.6); }
  body.sonando .rep-boton::after { animation: none; opacity: 0.3; }
  .rep-boton:active { transform: none; }

  html { scroll-behavior: auto; }

  /* Baraja: las fotos aparecen en su sitio, sin abanicarse */
  .baraja.visible .baraja-carta {
    animation: aparecer 240ms var(--ease-out) both;
    opacity: 1;
  }
  .baraja-carta:hover { transform: translateY(var(--y)) rotateY(var(--ry)) rotateZ(var(--rz)); }
}

/* ═══════════════════════════════════════════════════════════════════
   TRANSPARENCIA REDUCIDA
   Las superficies traslúcidas se vuelven sólidas y se quita el
   desenfoque: el vidrio deja de ser legible para algunas personas.
   ═══════════════════════════════════════════════════════════════════ */

@media (prefers-reduced-transparency: reduce) {
  /* Las tarjetas de sección ya NO entran aquí: desde que son transparentes
     no tienen nada que reducir, y rellenarlas devolvía el beige de la
     paleta anterior. En el iPhone de Kevin, con «Reducir transparencia»
     puesto, la tarjeta salía beige mientras en el computador salía
     transparente — y el CSS era el mismo. */
  .form-rsvp,
  .gracias {
    background: var(--marino-alto);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }

  .reloj > div,
  .campo input[type="text"],
  .campo input[type="tel"],
  .campo input[type="number"],
  .campo textarea,
  .opcion-radio label {
    background: var(--marino-profundo);
  }

  /* Los halos de fondo se apagan */
  #portada::before,
  #portada::after,
  .carta-luz,
  body::after,
  #pie::before,
  .particulas,
  .lugar-medallon::before,
  .bloque:not(#portada)::after { display: none; }

}

/* ═══════════════════════════════════════════════════════════════════
   SELECTOR DE TEMA
   Dos muestras del color de fondo dentro de un estuche con filete de oro.
   Se elige mostrar el color y no un icono de sol y luna porque lo que
   cambia es justamente el papel: la muestra ES la respuesta.

   Radio de 3px y filete fino, como las fichas y el formulario. Fijo
   arriba a la derecha, donde no compite con el título centrado.
   ═══════════════════════════════════════════════════════════════════ */

.tema {
  /* Absoluto y no fijo: se queda arriba, con la portada, y se va al
     desplazar. Fijo tapaba contenido —medido, el control se comía el 4 del
     calendario y se cruzaba con el reproductor—, y en una invitación que se
     lee de arriba abajo una sola vez no hace falta que viaje por la
     pantalla. Quien quiera cambiarlo después sube. */
  position: absolute;
  top: clamp(0.85rem, 2.4vh, 1.5rem);
  right: clamp(0.85rem, 2.4vw, 1.5rem);
  z-index: 40;
  display: flex;
  gap: 4px;
  padding: 4px;
  background: var(--tarjeta);
  -webkit-backdrop-filter: blur(14px) saturate(140%);
  backdrop-filter: blur(14px) saturate(140%);
  border: 1px solid var(--tarjeta-borde);
  border-radius: 3px;
  box-shadow: 0 10px 28px -12px rgb(var(--sombra-rgb) / calc(0.55 * var(--sombra-k)));

  /* Entra tras el título, sin llamar la atención antes de tiempo */
  opacity: 0;
  animation: aparecerTema 700ms var(--ease-out) 900ms forwards;
}

@keyframes aparecerTema {
  from { opacity: 0; transform: translateY(-8px); }
  to   { opacity: 1; transform: translateY(0); }
}

.tema-opcion {
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  padding: 0;
  background: none;
  border: 0;
  border-radius: 2px;
  cursor: pointer;
  /* Solo transform y opacidad; el aro va en la muestra */
  transition: transform var(--t-hover) var(--ease-out);
}

.tema-opcion:active { transform: scale(0.92); transition-duration: var(--t-press); }
.tema-opcion:focus-visible { outline: 2px solid var(--dorado-claro); outline-offset: 2px; }

/* El nombre existe para el lector de pantalla; en pantalla manda el color */
.tema-nombre {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.tema-muestra {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  /* El aro de oro marca la elegida. Va en box-shadow y no en border para
     que aparecer y desaparecer no mueva la muestra un píxel. */
  box-shadow:
    0 0 0 1px rgb(var(--tinta-rgb) / 0.28),
    0 0 0 0 var(--dorado);
  transition: box-shadow 200ms var(--ease-out);
}

.tema-noche { background: linear-gradient(145deg, #16304F 0%, #0B1A2E 100%); }
.tema-papel { background: linear-gradient(145deg, #FFFCF4 0%, #EFE7D8 100%); }

/* La muestra de papel necesita su propio filete: sobre el fondo claro del
   tema claro, un círculo casi blanco sin contorno desaparece. */
.tema-papel { box-shadow: 0 0 0 1px rgb(74 58 38 / 0.34), 0 0 0 0 var(--dorado); }

.tema-opcion[aria-pressed="true"] .tema-muestra {
  box-shadow:
    0 0 0 1px rgb(var(--tinta-rgb) / 0.28),
    0 0 0 3px var(--dorado);
}
.tema-opcion[aria-pressed="true"] .tema-papel {
  box-shadow:
    0 0 0 1px rgb(74 58 38 / 0.34),
    0 0 0 3px var(--dorado);
}

@media (hover: hover) and (pointer: fine) {
  .tema-opcion:hover { transform: translateY(-1px); }
}

/* El cambio se cruza en lugar de saltar. La transición se enciende solo
   durante el cambio y se apaga después: dejarla puesta en * estorbaría a
   todo lo demás que se anima en la página. */
@media (prefers-reduced-motion: no-preference) {
  html.tema-cambiando,
  html.tema-cambiando *,
  html.tema-cambiando *::before,
  html.tema-cambiando *::after {
    transition:
      background-color 320ms var(--ease-out),
      background-image 320ms var(--ease-out),
      border-color     320ms var(--ease-out),
      color            320ms var(--ease-out),
      box-shadow       320ms var(--ease-out) !important;
  }
}

@media (max-width: 640px) {
  .tema {
    /* Más arriba que en escritorio: con la carta abierta los nombres suben
       hasta y=57 y el control acababa en 58, así que se rozaban. */
    top: 0.5rem;
    gap: 3px;
    padding: 3px;
  }
  .tema-opcion { width: 34px; height: 34px; }   /* dedo, no puntero */
}

/* ═══════════════════════════════════════════════════════════════════
   CONTRASTE ALTO
   Fondos casi sólidos y bordes definidos.
   ═══════════════════════════════════════════════════════════════════ */

@media (prefers-contrast: more) {
  :root {
    --marfil-medio: rgb(var(--tinta-rgb) / 0.95);
    --marfil-tenue: rgb(var(--tinta-rgb) / 0.8);
    --tarjeta: var(--marino-alto);
  }

  /* El oro tiene que ir en direcciones opuestas según el tema: sobre la
     noche gana contraste aclarándose, sobre el papel oscureciéndose. Este
     bloque va después del tema claro y con la misma especificidad, así que
     sin separarlos le habría pisado los valores y el oro habría quedado en
     1,32:1 sobre la ficha. */
  :root:not([data-tema="claro"]) {
    --dorado: #E0BE72;
    --dorado-linea: rgba(224, 190, 114, 0.75);
    --tarjeta-borde: rgba(224, 190, 114, 0.6);
  }

  [data-tema="claro"] {
    --dorado:        #5F4915;   /* 6,4:1 sobre la ficha opaca */
    --oro-texto:     #4E3A10;   /* 8,1:1 */
    --dorado-linea:  rgb(95 73 21 / 0.75);
    --tarjeta-borde: rgb(95 73 21 / 0.60);
    --boton-borde:   rgb(78 58 16 / 0.90);
  }

  /* Las tarjetas ya NO se rellenan. Rellenarlas era lo correcto cuando
     eran cristal translúcido y el texto se apoyaba en ellas; ahora son un
     marco y el texto se apoya en el papel de la página, que ya cumple:
     medido sobre los píxeles pintados, 32 combinaciones de texto, tema,
     motor y ancho, todas por encima del mínimo. Con este bloque además la
     tinta y el oro se refuerzan, así que aquí queda mejor todavía.

     A Kevin le salía una losa gris en el teléfono —tiene «Aumentar
     contraste» puesto— mientras en el computador veía el diseño. */

  /* Lo que SÍ depende de la transparencia: el cristal de los modales y del
     panel lateral. Ahí sí se vuelve casi opaco. */
  .modal-hoja {
    background: var(--marino-alto);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
  .modal-velo { background: rgb(var(--vineta-rgb) / 0.82); }

  .campo input[type="text"],
  .campo input[type="tel"],
  .campo input[type="number"],
  .campo textarea,
  .opcion-radio label {
    background: var(--marino-profundo);
    border-color: rgb(var(--tinta-rgb) / 0.55);
  }

  /* Sin transparencia: con la ficha opaca, el 85% dejaba "obligatorio" en
     4,35:1 en el tema oscuro y 3,95:1 en el claro. A opacidad plena pasa. */
  .marca-req { color: rgb(var(--error-rgb)); }
}

/* ═══════════════════════════════════════════════════════════════════
   MODALES
   Suben desde abajo sobre el fondo desenfocado. Se cierran tocando
   fuera, con Escape o con su aspa.

   Cuelgan del <body> y no de su sección a propósito: dentro heredarían
   el `overflow: clip` y la perspectiva 3D del bloque, y un elemento fijo
   dentro de algo transformado deja de comportarse como fijo.
   ═══════════════════════════════════════════════════════════════════ */

.modal {
  position: fixed;
  inset: 0;
  z-index: 120;
  display: flex;
  align-items: flex-end;      /* en el teléfono, hoja que sube desde abajo */
  justify-content: center;
}
.modal[hidden] { display: none; }

.modal-velo {
  position: absolute;
  inset: 0;
  background: rgb(var(--vineta-rgb, 4 10 20) / 0.55);
  /* El velo no es zona de desplazamiento: sin esto, el gesto que empieza
     en él arrastraba la página de atrás en el teléfono. */
  touch-action: none;
  opacity: 0;
  transition: opacity 340ms var(--ease-out);
}
[data-tema="claro"] .modal-velo { background: rgb(74 58 38 / 0.42); }
.modal.abierto .modal-velo { opacity: 1; }

/* El desenfoque del fondo NO se hace con backdrop-filter en el velo.
   Medido: en Chromium el detalle del texto de detrás baja al 41%, pero en
   WebKit se queda en el 74% — o sea, no desenfoca. Y @supports no sirve
   para distinguirlo, porque WebKit sí SOPORTA la propiedad: simplemente
   no la aplica en este contexto. Así que se desenfoca el contenido, que
   se comporta igual en los dos motores. */

.modal-hoja {
  position: relative;
  z-index: 1;
  width: min(34rem, 100%);
  max-height: 92dvh;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 1.6rem clamp(1.15rem, 4vw, 2.1rem) clamp(1.6rem, 5vh, 2.4rem);
  text-align: center;

  /* Cristal: el color de la sección se cuela por detrás y la hoja no se
     lee como un rectángulo pegado encima. */
  background:
    radial-gradient(90% 60% at 15% 0%, rgb(var(--acento-a, 152 116 230) / 0.20) 0%, transparent 62%),
    radial-gradient(70% 50% at 92% 100%, rgb(var(--acento-b, 78 116 172) / 0.16) 0%, transparent 66%),
    var(--vidrio-fuerte);
  -webkit-backdrop-filter: blur(22px) saturate(135%);
  backdrop-filter: blur(22px) saturate(135%);
  border: 1px solid var(--tarjeta-borde);
  border-bottom: 0;
  border-radius: 26px 26px 0 0;
  box-shadow:
    0 -24px 60px -30px rgb(var(--sombra-rgb) / calc(0.9 * var(--sombra-k))),
    inset 0 1px 0 var(--rep-filo);

  transform: translateY(100%);
  transition: transform 460ms var(--ease-out);
}
/* Asentada queda SIN transform (none, no translateY(0)): con un transform
   residual en el ancestro, Safari puede pintar el cursor de los campos
   corrido. La transición interpola a none igual (matriz identidad). */
.modal.abierto .modal-hoja { transform: none; }

/* La barrita de arriba: dice «esto sube y baja» sin escribirlo */
.modal-asa {
  display: block;
  width: 44px;
  height: 4px;
  margin: -0.5rem auto 1rem;
  border-radius: 99px;
  background: rgb(var(--tinta-rgb) / 0.22);
}

.modal-cerrar {
  position: absolute;
  top: 0.9rem;
  right: 0.9rem;
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  color: var(--marfil-medio);
  background: rgb(var(--tinta-rgb) / 0.06);
  border: 1px solid rgb(var(--tinta-rgb) / 0.12);
  border-radius: 50%;
  cursor: pointer;
  transition: color 200ms, background 200ms, transform 220ms var(--ease-out);
}
.modal-cerrar:hover { color: var(--marfil); background: rgb(var(--tinta-rgb) / 0.12); transform: rotate(90deg); }
.modal-cerrar svg { width: 16px; height: 16px; }

.modal-cabecera { margin-bottom: 1.2rem; }
.modal-eyebrow {
  margin: 0 0 0.5rem;
  font-family: var(--sans);
  font-size: 0.6rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--marfil-tenue);
}
.modal-cabecera .seccion-script { margin-bottom: 0; font-size: clamp(2.4rem, 8vw, 3.4rem); }

.modal-cuerpo { text-align: left; }

/* ---- El cursor corrido del formulario ----
   La hoja desplazaba su propio contenido (overflow-y: auto) y a la vez
   lleva backdrop-filter: en Safari del teléfono esa mezcla pinta el caret
   corrido por el monto del desplazamiento. El desplazamiento pasa al
   cuerpo, que no filtra nada; el asa, el aspa y el título quedan quietos
   arriba, que además se agradece en un formulario largo. */
#modalRsvp .modal-hoja {
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
#modalRsvp .modal-cuerpo {
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  /* Aire lateral para que el anillo de foco no se recorte contra el canto */
  padding: 2px 3px 0.4rem;
  /* La barra de desplazamiento no se muestra nunca: la pista del chevron
     y el desvanecido del borde ya cuentan que hay más abajo. */
  scrollbar-width: none;
}
#modalRsvp .modal-cuerpo::-webkit-scrollbar { display: none; }

/* Mientras queda formulario por ver, el contenido se desvanece contra el
   borde inferior: se lee como «esto continúa», sin barra ni línea de corte. */
#modalRsvp .modal-cuerpo.con-fade {
  -webkit-mask-image: linear-gradient(180deg, #000 0%, #000 calc(100% - 44px), rgb(0 0 0 / 0.22) 100%);
          mask-image: linear-gradient(180deg, #000 0%, #000 calc(100% - 44px), rgb(0 0 0 / 0.22) 100%);
}

/* El chevron que respira sobre el borde de la hoja */
.hoja-pista {
  position: absolute;
  left: 50%;
  bottom: 0.55rem;
  transform: translateX(-50%);
  z-index: 3;
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  color: var(--oro-texto);
  border: 1px solid rgb(var(--oro-rgb) / 0.4);
  border-radius: 50%;
  background: rgb(var(--campo-rgb) / 0.55);
  -webkit-backdrop-filter: blur(10px) saturate(130%);
  backdrop-filter: blur(10px) saturate(130%);
  box-shadow: 0 6px 18px -8px rgb(var(--sombra-rgb) / calc(0.7 * var(--sombra-k)));
  pointer-events: none;
  transition: opacity 320ms var(--ease-out), transform 320ms var(--ease-out);
}
.hoja-pista svg {
  width: 16px;
  height: 16px;
  animation: pistaRespira 1.9s var(--ease-in-out) infinite;
}
.hoja-pista.oculta {
  opacity: 0;
  transform: translateX(-50%) translateY(8px);
}
@keyframes pistaRespira {
  0%, 100% { transform: translateY(-2px); opacity: 0.5; }
  50%      { transform: translateY(3px);  opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .hoja-pista svg { animation: none; }
}

/* ---- El autorrelleno, sin el beige del sistema ----
   Al aceptar el nombre que sugiere el teléfono, WebKit pinta el campo con
   su amarillo de autofill y se ve sucio sobre el vidrio. El relleno se
   tapa con una sombra interior del tono del campo (transparente de verdad
   no se puede: el amarillo lo pinta el navegador por debajo de todo). */
#modalRsvp input:-webkit-autofill,
#modalRsvp input:-webkit-autofill:hover,
#modalRsvp input:-webkit-autofill:focus {
  -webkit-box-shadow: inset 0 0 0 1000px var(--campo-solido, #0B1826);
  -webkit-text-fill-color: var(--marfil);
  caret-color: var(--marfil);
  transition: background-color 9999999s step-end, color 9999999s step-end;
}

/* Mientras hay un modal abierto la página no se desplaza por detrás.
   El hueco que deja la barra al esconderse lo repone el script con un
   relleno del mismo ancho: así el contenido no salta.

   Se hace así y no con scrollbar-gutter: stable, que parecía más limpio
   pero reserva el hueco SIEMPRE, y entonces el bloque contenedor de los
   elementos fijos mide 1425 en vez de 1440 — el panel lateral quedaba a
   15 px del borde derecho en vez de pegado. Medido. */
/* En html Y body: en el teléfono el overflow del body solo no frena el
   gesto; el corte de verdad lo da el touchmove del script, y esto acompaña. */
html.modal-abierto,
body.modal-abierto { overflow: hidden; }

/* El fondo, desenfocado. Se aplica al contenido y no al velo por lo
   dicho arriba. Solo a los hijos directos del cuerpo: el modal es
   hermano suyo, así que queda nítido. */
body > .bloque,
body > footer,
body > .tema {
  transition: filter 320ms var(--ease-out);
}
body.modal-abierto > .bloque,
body.modal-abierto > footer,
body.modal-abierto > .tema {
  filter: blur(10px) saturate(0.92);
  pointer-events: none;
}

/* De tableta hacia arriba deja de ser una hoja de abajo y se centra */
@media (min-width: 40em) {
  .modal { align-items: center; padding: 1.5rem; }
  .modal-hoja {
    border-bottom: 1px solid var(--tarjeta-borde);
    border-radius: 24px;
    max-height: 88dvh;
    transform: translateY(38px) scale(0.985);
    opacity: 0;
    transition: transform 460ms var(--ease-out), opacity 300ms var(--ease-out);
  }
  .modal.abierto .modal-hoja { transform: translateY(0) scale(1); opacity: 1; }
  .modal-asa { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .modal-hoja, .modal-velo { transition-duration: 1ms; }
}

/* ═══════════════════════════════════════════════════════════════════
   LOS ACOMPAÑANTES, UNO A UNO
   ═══════════════════════════════════════════════════════════════════ */

.acomp-lista {
  list-style: none;
  margin: 0.9rem 0 0;
  padding: 0;
  display: grid;
  gap: 0.55rem;
}

.acomp-fila {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  /* Entra cayendo desde arriba, como si se sumara a la fila */
  animation: entraAcomp 340ms var(--ease-out) both;
}
@keyframes entraAcomp {
  from { opacity: 0; transform: translateY(-8px); }
}
.acomp-fila.se-va { animation: saleAcomp 220ms ease-in both; }
@keyframes saleAcomp {
  to { opacity: 0; transform: translateX(14px); }
}

.acomp-n {
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  flex: none;
  font-family: var(--serif);
  font-size: 0.78rem;
  /* Tinta y no oro: oro sobre un disco de oro daba 3,55 de contraste */
  color: var(--marfil-medio);
  background: rgb(var(--oro-rgb) / 0.12);
  border: 1px solid rgb(var(--oro-rgb) / 0.28);
  border-radius: 50%;
}

.acomp-fila input {
  flex: 1;
  min-width: 0;
}

/* ═══════════════════════════════════════════════════════════════════
   DATOS PARA TRANSFERIR
   Cada dato se copia al tocarlo. Nadie transcribe a mano un número de
   cuenta de once cifras desde el teléfono sin equivocarse.
   ═══════════════════════════════════════════════════════════════════ */

.transfer {
  width: min(34rem, 100%);
  margin: clamp(2rem, 5vh, 3rem) auto 0;
  padding: clamp(1.3rem, 4vw, 1.9rem);
  text-align: center;
  background:
    radial-gradient(80% 60% at 12% 0%, rgb(var(--acento-a) / 0.18) 0%, transparent 66%),
    radial-gradient(70% 60% at 95% 100%, rgb(var(--acento-b) / 0.16) 0%, transparent 66%),
    var(--vidrio-fuerte);
  -webkit-backdrop-filter: blur(16px) saturate(130%);
  backdrop-filter: blur(16px) saturate(130%);
  border: 1px solid var(--tarjeta-borde);
  border-radius: 20px;
  box-shadow: var(--tarjeta-sombra), inset 0 1px 0 var(--rep-filo);
}

.transfer-cabecera { margin-bottom: 1.15rem; }

.transfer-marca {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  margin: 0 auto 0.7rem;
  color: var(--oro-texto);
  border-radius: 50%;
  border: 1px solid rgb(var(--oro-rgb) / 0.3);
  background: radial-gradient(circle at 32% 26%, rgb(var(--oro-rgb) / 0.22) 0%, transparent 70%);
}
.transfer-marca svg { width: 22px; height: 22px; }

.transfer-titulo {
  margin: 0;
  font-family: var(--serif);
  font-size: clamp(1.02rem, 2.6vw, 1.2rem);
  font-style: italic;
  color: var(--marfil);
}
.transfer-sub {
  margin: 0.3rem 0 0;
  font-family: var(--sans);
  font-size: 0.72rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--marfil-tenue);
}

.transfer-datos {
  display: grid;
  gap: 0.8rem;
  margin: 0 0 1.1rem;
}

/* ---- La credencial ----
   Los datos de la cuenta como una tarjeta física: fondo de noche en los DOS
   temas —por eso los tonos van escritos y no en variables—, filo dorado y
   el número como protagonista. Cada zona se sigue copiando al tocarla. */
.credencial {
  position: relative;
  overflow: hidden;
  isolation: isolate;
  display: grid;
  gap: 1.2rem;
  padding: 1.15rem 1.2rem 1.1rem;
  text-align: left;
  border: 1px solid rgb(201 164 85 / 0.55);
  border-radius: 16px;
  background:
    radial-gradient(120% 90% at 14% 0%, rgb(201 164 85 / 0.17) 0%, transparent 55%),
    radial-gradient(90% 70% at 100% 100%, rgb(74 111 165 / 0.22) 0%, transparent 60%),
    linear-gradient(152deg, #16304F 0%, #0B1A2E 58%, #081524 100%);
  box-shadow:
    0 22px 44px -20px rgb(3 8 16 / calc(0.65 * var(--sombra-k, 1))),
    inset 0 1px 0 rgb(255 255 255 / 0.10);
}
/* El barrido de luz de una tarjeta metálica, quieto: es acabado, no adorno */
.credencial::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(115deg,
    transparent 30%, rgb(255 255 255 / 0.05) 46%, transparent 62%);
}

.cred-cabecera,
.cred-pie {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 1rem;
}
.cred-tipo, .cred-rut { text-align: right; }
.cred-tipo dd { text-align: right; }

/* El dato ya no es una caja: es una zona de la tarjeta que se toca */
.dato {
  position: relative;
  padding: 0;
  text-align: left;
  background: none;
  border: 0;
  border-radius: 10px;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: background 220ms;
}
.dato:focus-visible { outline: 2px solid var(--dorado); outline-offset: 4px; }

.dato dt {
  font-family: var(--sans);
  font-size: 0.6rem;
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--marfil-tenue);
}
.dato dd {
  margin: 0.25rem 0 0;
  font-family: var(--serif);
  font-size: 1.18rem;
  color: var(--marfil);
  overflow-wrap: anywhere;
  /* Cifras alineadas: Cormorant las trae antiguas, con subidas y bajadas,
     y un RUT o un número de cuenta así se lee y se transcribe mal. */
  font-variant-numeric: lining-nums tabular-nums;
  font-feature-settings: 'lnum' 1, 'tnum' 1;
}

/* Dentro de la credencial los colores son los de la tarjeta, en ambos temas */
.credencial dt { color: rgb(217 185 110 / 0.92); }
.credencial dd { color: #F6F1E7; }
.credencial .dato:focus-visible { outline-color: #D9B96E; }

/* El número, grabado como en una tarjeta de verdad */
.cred-numero dd {
  font-size: clamp(1.5rem, 6.4vw, 1.85rem);
  letter-spacing: 0.12em;
  text-shadow: 0 1px 1px rgb(0 0 0 / 0.45);
}

/* El correo, fuera de la tarjeta: una línea de papelería */
.dato-correo {
  padding: 0.7rem 0.9rem;
  border: 1px solid rgb(var(--oro-rgb) / 0.35);
  border-radius: 12px;
  background: rgb(var(--oro-rgb) / 0.05);
}
.dato-correo dt { color: var(--oro-texto); }
.dato-correo dd { font-size: 1.05rem; }

/* El aviso de copiado nace del propio dato, no de una esquina de la
   pantalla: se ve dónde ocurrió lo que se pidió. */
.dato::after {
  content: 'Copiado';
  position: absolute;
  top: 50%;
  right: 0.75rem;
  transform: translateY(-50%) scale(0.8);
  font-family: var(--sans);
  font-size: 0.6rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--sobre-oro);
  background: var(--oro-relleno);
  padding: 0.22rem 0.5rem;
  border-radius: 99px;
  opacity: 0;
  pointer-events: none;
  transition: opacity 200ms, transform 260ms var(--ease-out);
}
.dato.copiado::after { opacity: 1; transform: translateY(-50%) scale(1); }

/* Un destello que barre el dato al copiarlo. El halo va en box-shadow y no
   en padding: da aire alrededor del texto sin mover nada de sitio. */
.dato.copiado {
  background: rgb(var(--oro-rgb) / 0.16);
  box-shadow: 0 0 0 8px rgb(var(--oro-rgb) / 0.16);
}

.btn-copiar-todo {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.55rem;
  padding: 0.85rem 1.4rem;
  font-family: var(--sans);
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--oro-texto);
  background: rgb(var(--oro-rgb) / 0.08);
  border: 1px solid rgb(var(--oro-rgb) / 0.38);
  border-radius: 99px;
  cursor: pointer;
  transition: color 220ms, background 220ms, border-color 220ms, transform 240ms var(--ease-out);
}
.btn-copiar-todo:hover { background: rgb(var(--oro-rgb) / 0.16); border-color: rgb(var(--oro-rgb) / 0.7); transform: translateY(-2px); }
.btn-copiar-todo.listo { color: var(--sobre-oro); background: var(--oro-relleno); border-color: transparent; }

.cop-icono { display: grid; place-items: center; width: 17px; height: 17px; }
.cop-icono svg { grid-area: 1 / 1; width: 17px; height: 17px; transition: opacity 200ms, transform 260ms var(--ease-out); }
.cop-icono .ic-listo { opacity: 0; transform: scale(0.6); }
.btn-copiar-todo.listo .ic-copia { opacity: 0; transform: scale(0.6); }
.btn-copiar-todo.listo .ic-listo { opacity: 1; transform: scale(1); }

/* ═══════════════════════════════════════════════════════════════════
   LA LUZ QUE SIGUE AL PUNTERO
   El script escribe --mx y --my con la posición del ratón dentro del
   botón; aquí solo se pinta. En pantallas táctiles no se enciende nunca,
   y eso está bien: no hay puntero al que seguir.
   ═══════════════════════════════════════════════════════════════════ */

.con-luz { position: relative; overflow: hidden; isolation: isolate; }
.con-luz::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background: radial-gradient(9rem 9rem at var(--mx, 50%) var(--my, 50%),
    rgb(var(--oro-rgb) / 0.28) 0%, transparent 70%);
  opacity: 0;
  transition: opacity 320ms var(--ease-out);
  pointer-events: none;
}
@media (hover: hover) {
  .con-luz:hover::before { opacity: 1; }
}

/* Dentro del modal, el formulario deja de ser una tarjeta: la tarjeta es
   el propio modal. Sin esto quedaba un cristal dentro de otro cristal,
   con dos bordes y dos sombras. */
.modal-cuerpo .form-rsvp {
  display: block;
  max-width: none;
  margin: 0;
  padding: 0;
  background: none;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  transform: none;
  opacity: 1;
}
.modal-cuerpo .gracias { text-align: center; padding: 1rem 0 0.5rem; }

/* ═══════════════════════════════════════════════════════════════════
   PANEL LATERAL
   Mismo mecanismo que el modal —mismo velo, mismo cierre, mismo
   desenfoque de fondo— pero entra por el costado en vez de subir.
   Las reglas van después de la media query del modal a propósito: si
   fueran antes, esa media query las pisaría en pantalla ancha.
   ═══════════════════════════════════════════════════════════════════ */

.modal.lateral {
  align-items: stretch;
  justify-content: flex-end;
  padding: 0;
}

/* Nota medida: en sistemas con barra de desplazamiento clásica siempre
   visible (Windows, o macOS con «mostrar siempre»), Chromium deja el
   panel a 15 px del borde derecho, porque html lleva overflow-x: clip y
   eso recorta también a los elementos fijos. Se probó cambiarlo a hidden:
   arregla WebKit pero no Chromium, y ese clip está puesto para no crear
   un contenedor de desplazamiento, del que depende la coreografía del
   scroll. No compensa. Con barras flotantes —el ajuste por defecto de
   macOS y de todos los teléfonos— el panel queda pegado. */

.modal.lateral .modal-hoja {
  /* Nunca el ancho completo: si el panel tapa toda la pantalla no queda
     un «fuera» donde tocar para cerrarlo, y en el teléfono el aspa es lo
     único que queda. Ese 88% es la salida. */
  width: min(25rem, 88%);
  height: 100dvh;
  max-height: none;
  /* Arriba nunca menos de 4rem: con 2,6rem el aspa de cerrar caía en la
     misma línea que el título y el subtítulo —visto en el teléfono—. */
  padding: clamp(4rem, 7vh, 4.6rem) clamp(1.1rem, 4vw, 1.7rem) clamp(1.6rem, 5vh, 2.2rem);
  border: 1px solid var(--tarjeta-borde);
  border-right: 0;
  border-radius: 22px 0 0 22px;
  box-shadow: -24px 0 60px -30px rgb(var(--sombra-rgb) / calc(0.9 * var(--sombra-k)));
  transform: translateX(100%);
  opacity: 1;
  transition: transform 480ms var(--ease-out);
}
.modal.lateral.abierto .modal-hoja { transform: translateX(0); }

/* Dentro del panel la tarjeta de datos ya no es tarjeta: el panel lo es */
.modal.lateral .transfer {
  width: 100%;
  margin: 0;
  padding: 0;
  background: none;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  border: 0;
  border-radius: 0;
  box-shadow: none;
}
.modal.lateral .transfer-datos { grid-template-columns: 1fr; }
.modal.lateral .btn-copiar-todo { width: 100%; }

/* Las piezas entran escalonadas detrás del panel: se nota que el panel
   trae algo, no que aparece un bloque de golpe. Primero la credencial,
   después el correo y al final el botón. */
.modal.lateral.abierto .credencial,
.modal.lateral.abierto .dato-correo,
.modal.lateral.abierto .btn-copiar-todo {
  animation: entraDato 460ms var(--ease-out) both;
}
.modal.lateral.abierto .credencial     { animation-delay: 180ms; }
.modal.lateral.abierto .dato-correo    { animation-delay: 280ms; }
.modal.lateral.abierto .btn-copiar-todo { animation-delay: 350ms; }
@keyframes entraDato {
  from { opacity: 0; transform: translateX(16px); }
}

/* Las dos acciones de Regalos, en una fila que las iguala: misma altura,
   mismo aire, y en el teléfono una debajo de otra en vez de apretadas. */
.reg-acciones {
  display: flex;
  align-items: stretch;
  justify-content: center;
  flex-wrap: wrap;
  gap: 0.8rem;
  margin-top: 1.6rem;
}
.reg-acciones .btn-linea {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  margin: 0;
}
.btn-banco svg { width: 17px; height: 17px; flex: none; }

@media (max-width: 30em) {
  .reg-acciones { flex-direction: column; align-items: stretch; }
}

@media (prefers-reduced-motion: reduce) {
  .modal.lateral .modal-hoja { transition-duration: 1ms; }
  .modal.lateral.abierto .credencial,
  .modal.lateral.abierto .dato-correo,
  .modal.lateral.abierto .btn-copiar-todo { animation: none; }
}

/* El contenido del panel lateral, centrado en su alto: colgando de arriba
   dejaba media pantalla vacía. */
.modal.lateral .modal-hoja {
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.transfer-pie {
  margin-top: 1.6rem;
  padding-top: 1.1rem;
  border-top: 1px solid rgb(var(--tinta-rgb) / 0.1);
  font-family: var(--script);
  font-size: 1.5rem;
  line-height: 1.2;
  text-align: center;
  color: var(--oro-texto);
}
.transfer-pie small {
  display: block;
  margin-top: 0.3rem;
  font-family: var(--sans);
  font-size: 0.6rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--marfil-tenue);
}

/* ---- La flor del cierre ----
   Es la que estaba en la portada. Se muda aquí porque «Confirmar» era la
   única sección larga con nada más que texto, y porque el delfinio nuevo
   ocupa su sitio de antes. Va al lado contrario que la flor de la fecha,
   para que las dos no caigan siempre a la izquierda. */
.flor-cierre {
  position: absolute;
  /* Entera dentro del encuadre: pegada al canto se le cortaba la flor por
     la mitad. Ahora solo el tallo sale por abajo, que es lo natural. */
  left: clamp(0.5rem, 2vw, 2.5rem);
  bottom: 0;
  width: clamp(96px, 11vw, 158px);
  height: auto;
  z-index: 0;
  pointer-events: none;
  opacity: 0.8;
  transform: rotate(9deg) scaleX(-1);
  filter: drop-shadow(0 14px 26px rgb(var(--sombra-rgb) / calc(0.45 * var(--sombra-k))));
}

/* En pantallas estrechas se achica, no se recorta: cortada por el canto se
   lee como un error de maquetación. */
/* En el teléfono baja hasta el canto inferior. Más arriba quedaba justo
   detrás del botón de confirmar, que tiene el fondo al 9% de opacidad —o
   sea, casi transparente—: medido, los pétalos se veían a través en el 5%
   de su superficie con diferencias de hasta 215 sobre 255. */
@media (max-width: 46em) {
  /* Delante de la ficha, no detrás: en el teléfono la ficha ocupa casi todo
     el ancho y la flor quedaba medio tapada. La ficha va en z-index 1, así
     que con 2 pasa al frente. */
  .flor-cierre {
    width: clamp(74px, 21vw, 104px);
    left: 0.6rem;
    bottom: -5vh;
    opacity: 0.9;
    z-index: 2;
  }
}
@media (prefers-reduced-motion: no-preference) {
  .flor-cierre { transition: opacity 700ms var(--ease-out); }
}

/* ═══════════════════════════════════════════════════════════════════
   EL REPRODUCTOR, FLOTANTE
   Vive fuera de las secciones y acompaña toda la invitación: se puede
   tocar desde cualquier parte sin volver a la portada.
   ═══════════════════════════════════════════════════════════════════ */

.rep-flotante {
  position: fixed;
  left: 0;
  right: 0;
  bottom: max(1rem, env(safe-area-inset-bottom, 0px));
  z-index: 60;
  display: flex;
  justify-content: center;
  padding: 0 clamp(0.7rem, 3vw, 1.5rem);
  /* La capa no recibe el puntero; solo la píldora. Si no, una franja
     invisible de lado a lado se comería los toques del pie de página. */
  pointer-events: none;
}

.rep-flotante .reproductor {
  margin-top: 0;
  width: auto;
  max-width: min(30rem, 100%);
  padding: 0.6rem 0.7rem 0.6rem 0.6rem;
  gap: 0.75rem;
  pointer-events: auto;
  /* Cristal más sólido que antes: ahora se apoya sobre el contenido de
     cualquier sección, no sobre el fondo tranquilo de la portada. */
  background:
    radial-gradient(120% 180% at 8% 0%, rgb(var(--oro-rgb) / 0.16) 0%, transparent 60%),
    var(--vidrio-fuerte);
  box-shadow:
    0 20px 46px -22px rgb(var(--sombra-rgb) / calc(0.95 * var(--sombra-k))),
    0 2px 10px -4px rgb(var(--sombra-rgb) / calc(0.5 * var(--sombra-k))),
    inset 0 1px 0 var(--rep-filo),
    inset 0 -22px 26px -26px rgb(var(--oro-rgb) / 0.5);
  transition:
    opacity 600ms var(--ease-out),
    transform 600ms var(--ease-out),
    box-shadow 340ms var(--ease-out),
    max-width 420ms var(--ease-out);
}

/* ---- El anillo de avance ----
   Rodea al botón. El script escribe --avance de 0 a 1. */
/* .rep-boton .rep-aro y no solo .rep-aro: existe una regla `.rep-boton svg
   { width: 19px }` para los iconos de play y pausa, y alcanzaba también al
   anillo —de ahí que saliera diminuto y descolgado en una esquina—. */
.rep-boton .rep-aro {
  position: absolute;
  width: calc(100% + 12px);
  height: calc(100% + 12px);
  left: -6px;
  top: -6px;
  overflow: visible;
  transform: rotate(-90deg);   /* que empiece arriba y no a las tres */
  pointer-events: none;
}
.rep-aro circle {
  fill: none;
  stroke-width: 2.2;
  stroke-linecap: round;
}
.aro-surco { stroke: rgb(var(--oro-rgb) / 0.32); }

/* En el flotante el anillo de avance ocupa el sitio del aro que latía: dos
   círculos concéntricos animados a la vez se leen como un error. */
.rep-flotante .rep-boton::after { display: none; }
.aro-avance {
  stroke: var(--dorado-claro);
  /* 2·π·27 = 169.65 */
  stroke-dasharray: 169.65;
  stroke-dashoffset: calc(169.65 * (1 - var(--avance, 0)));
  filter: drop-shadow(0 0 4px rgb(var(--oro-rgb) / 0.7));
  transition: stroke-dashoffset 240ms linear;
}
.rep-pista.arrastrando ~ * .aro-avance,
.reproductor:has(.rep-pista.arrastrando) .aro-avance { transition: none; }

/* ---- Cuerpo compacto ----
   Flotando sobre el contenido, el reproductor tiene que pesar poco: el
   título y el ecualizador siempre; los tiempos y la barra solo cuando se
   le presta atención. El anillo ya cuenta el avance mientras tanto. */
.rep-flotante .rep-cabecera { margin-bottom: 0; }
.rep-flotante .rep-titulo { font-size: 0.92rem; }

/* El detalle —barra y tiempos— se pliega con grid-template-rows: así el
   contenido conserva su alto propio y solo se abre el hueco, sin números
   mágicos. Se pliega la CAJA, no cada pieza: plegar la barra y los tiempos
   por separado les rompía su propio diseño. */
.rep-flotante .rep-detalle {
  display: grid;
  grid-template-rows: 0fr;
  opacity: 0;
  transition: grid-template-rows 380ms var(--ease-out), opacity 240ms var(--ease-out);
}
.rep-flotante .rep-detalle > .rep-envoltura { min-height: 0; overflow: hidden; }

.rep-flotante .reproductor:hover .rep-detalle,
.rep-flotante .reproductor:focus-within .rep-detalle,
.rep-flotante .reproductor.abierta .rep-detalle {
  grid-template-rows: 1fr;
  opacity: 1;
}

.rep-flotante .reproductor:hover,
.rep-flotante .reproductor:focus-within {
  box-shadow:
    0 26px 60px -22px rgb(var(--sombra-rgb) / var(--sombra-k)),
    0 0 0 1px rgb(var(--oro-rgb) / 0.3),
    inset 0 1px 0 var(--rep-filo);
}

/* La nota de la canción se abre hacia arriba: abajo no hay sitio */


/* En pantallas angostas ocupa el ancho disponible y el título se recorta */
@media (max-width: 30em) {
  .rep-flotante .reproductor { width: 100%; gap: 0.6rem; }
  .rep-flotante .rep-tiempos { display: none; }
}

/* Al abrir el selector, el fondo entero se difumina —igual que con los
   modales— porque ahora el reproductor flota sobre todas las secciones y
   no solo sobre la portada. */
body.sel-abierto > .bloque,
body.sel-abierto > footer {
  filter: blur(10px) saturate(0.92);
  pointer-events: none;
}
body > .bloque, body > footer { transition: filter 320ms var(--ease-out); }

/* El velo y el carrusel pasan a ser fijos: ya no cuelgan de la portada */
.sel-velo, .sel-carrusel { position: fixed; }
.sel-carrusel { top: 50%; }

/* Mientras el selector está abierto la píldora se realza sobre el velo */
body.sel-abierto .rep-flotante { z-index: 110; }

/* ═══════════════════════════════════════════════════════════════════
   CARRUSEL DE FOTOS — «Nosotros»
   Un coverflow: la foto centrada de frente y las de los lados girando
   hacia dentro. El riel es desplazamiento nativo con imán, así que
   hereda la inercia y el rebote del sistema —que ninguna librería
   imita bien— y no hay nada que descargar.
   El script solo escribe --k por foto (1 centrada, 0 lejos) y --lado
   (a qué lado cae). Todo lo demás es CSS.
   ═══════════════════════════════════════════════════════════════════ */

.galeria {
  position: relative;
  width: 100%;
  margin-top: clamp(1.6rem, 4vh, 2.6rem);
}

.gal-riel {
  display: flex;
  align-items: center;
  gap: clamp(0.8rem, 2.6vw, 1.8rem);
  /* Los extremos también se centran: el relleno lateral es lo que lo permite */
  padding: clamp(1.4rem, 4vh, 2.4rem) calc((100% - var(--gal-ancho)) / 2);
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  -ms-overflow-style: none;
  overscroll-behavior-x: contain;
  transform-style: preserve-3d;
  cursor: grab;
}
.gal-riel::-webkit-scrollbar { display: none; }
.gal-riel:active { cursor: grabbing; }
.gal-riel:focus-visible { outline: none; }
.gal-riel:focus-visible .gal-foto[data-activa] .gal-marco {
  box-shadow: 0 0 0 2px var(--dorado-claro);
}

.galeria { --gal-ancho: clamp(230px, 42vw, 340px); }

.gal-foto {
  position: relative;
  flex: 0 0 var(--gal-ancho);
  margin: 0;
  scroll-snap-align: center;
  aspect-ratio: 3 / 4;
  transform-style: preserve-3d;
  /* Todo sale de --k. La de al lado gira hacia dentro y se hunde; la
     centrada queda de frente y delante. */
  /* La perspectiva va en la propia foto y no en el contenedor: el riel
     lleva overflow-x, y un elemento con overflow distinto de visible aplana
     a sus hijos —el preserve-3d se ignora—, así que la perspectiva del
     padre no llegaba y el giro se veía como un simple achatamiento. */
  transform:
    perspective(1200px)
    translateZ(calc(-130px * (1 - var(--k, 0))))
    rotateY(calc(var(--lado, 1) * (1 - var(--k, 0)) * -34deg))
    scale(calc(0.88 + 0.12 * var(--k, 0)));
  transition: transform 140ms linear;
  z-index: 1;
}
.gal-foto[data-activa] { z-index: 3; }

.gal-foto img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 3px;
  background: var(--papel);
  /* Las de los lados, un punto apagadas: la mirada va a la del centro */
  filter: saturate(calc(0.72 + 0.28 * var(--k, 0))) brightness(calc(0.86 + 0.14 * var(--k, 0)));
  box-shadow:
    0 calc(14px + 26px * var(--k, 0)) calc(30px + 40px * var(--k, 0)) calc(-16px - 8px * var(--k, 0))
      rgb(var(--sombra-rgb) / calc((0.45 + 0.35 * var(--k, 0)) * var(--sombra-k)));
  transition: filter 200ms var(--ease-out), box-shadow 200ms var(--ease-out);
  user-select: none;
  -webkit-user-drag: none;
}

/* El marco de papel: un borde blanco como el de una copia impresa, y un
   filete de oro que solo se enciende en la centrada. */
.gal-foto::before {
  content: '';
  position: absolute;
  inset: calc(-8px - 2px * var(--k, 0));
  border-radius: 4px;
  background: var(--papel);
  box-shadow: inset 0 0 0 1px rgb(var(--oro-rgb) / calc(0.12 + 0.5 * var(--k, 0)));
  transform: translateZ(-1px);
  transition: inset 200ms var(--ease-out);
}

/* El reflejo bajo la foto centrada: es lo que la despega del papel */
.gal-foto::after {
  content: '';
  position: absolute;
  left: 8%;
  right: 8%;
  bottom: -14px;
  height: 16px;
  border-radius: 50%;
  background: radial-gradient(ellipse at 50% 0%,
    rgb(var(--sombra-rgb) / calc(0.5 * var(--sombra-k))) 0%, transparent 72%);
  opacity: var(--k, 0);
  filter: blur(5px);
  transform: translateZ(-2px);
  pointer-events: none;
}

/* ---- Flechas ---- */
.gal-flecha {
  position: absolute;
  top: 50%;
  z-index: 5;
  display: grid;
  place-items: center;
  width: 46px;
  height: 46px;
  transform: translateY(-50%);
  color: var(--oro-texto);
  background: var(--vidrio-fuerte);
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
  border: 1px solid rgb(var(--oro-rgb) / 0.32);
  border-radius: 50%;
  cursor: pointer;
  box-shadow: var(--tarjeta-sombra);
  transition: background 220ms, border-color 220ms, transform 240ms var(--ease-out), opacity 220ms;
}
.gal-antes { left: clamp(0.2rem, 2vw, 1.6rem); }
.gal-despues { right: clamp(0.2rem, 2vw, 1.6rem); }
.gal-flecha:hover { border-color: rgb(var(--oro-rgb) / 0.7); transform: translateY(-50%) scale(1.08); }
.gal-flecha:active { transform: translateY(-50%) scale(0.96); }
.gal-flecha[disabled] { opacity: 0.3; pointer-events: none; }
.gal-flecha svg { width: 19px; height: 19px; }

/* En pantallas sin puntero las flechas sobran: se desliza con el dedo */
@media (hover: none) {
  .gal-flecha { display: none; }
}

/* ---- Puntos ---- */
.gal-puntos {
  display: flex;
  justify-content: center;
  gap: 0.5rem;
  margin-top: clamp(0.8rem, 2vh, 1.3rem);
}
.gal-punto {
  width: 7px;
  height: 7px;
  padding: 0;
  border: 0;
  border-radius: 99px;
  background: rgb(var(--tinta-rgb) / 0.24);
  cursor: pointer;
  transition: width 320ms var(--ease-out), background 320ms var(--ease-out);
}
.gal-punto:hover { background: rgb(var(--oro-rgb) / 0.6); }
.gal-punto[aria-selected="true"] {
  width: 26px;
  background: var(--oro-relleno);
}
/* Zona de toque más generosa que el punto visible */
.gal-punto { position: relative; }
.gal-punto::after { content: ''; position: absolute; inset: -10px -6px; }

@media (prefers-reduced-motion: reduce) {
  .gal-foto { transition: none; }
  .gal-riel { scroll-behavior: auto; }
}

/* ═══════════════════════════════════════════════════════════════════
   AL ABRIR, EL CENTRO SE DESPEJA
   La tapa abierta sube hasta la altura de la etiqueta: medido en
   escritorio, la tapa ocupa y 75..305 mientras el filete estaba en 223 y
   la fecha en 242 —o sea, enterrados— y «NOS CASAMOS» quedaba pegado a su
   punta. Así que al abrir se retiran la etiqueta, el filete y la fecha, y
   en el centro quedan solo el sobre y los nombres a sus lados.

   Esto ya existía para el teléfono, pero dentro de su media query. Aquí
   vale para todos los tamaños, que es donde hacía falta.
   ═══════════════════════════════════════════════════════════════════ */

/* «NOS CASAMOS» se queda: es lo que anuncia la invitación, y sin él la
   portada abierta arranca con dos nombres sueltos y nada que los presente.
   Lo que se retira son el filete y la fecha, que sí quedaban enterrados
   bajo la tapa.

   Para que se quede tiene que apartarse: la punta de la tapa abierta le
   comía el centro y se leía «N ... S». Sube lo justo para librarla, y el
   cuánto lo mide el script en --sube-etiqueta, porque la carta escala con
   el ancho de la ventana y un número fijo sólo serviría a un tamaño.
   Se probó también bajando el sobre —que es lo que hace el teléfono— pero
   ahí no sirve: al bajar la carta el bloque se recentra y la etiqueta
   vuelve al mismo sitio, contra la punta. */
body.carta-abierta .hero-etiqueta {
  transform: translateY(calc(-1 * var(--sube-etiqueta, 0px)));
  /* Se aparta pronto y sin esperar: la punta de la tapa llega a su altura
     a los 1160 ms, así que la subida tiene que estar hecha antes. Con 180
     de espera y 560 de recorrido termina sobre los 740, con margen. */
  transition: transform 560ms var(--ease-out) 180ms;
}

.hero-filete,
.fecha-hero {
  /* Punto de partida para el alto: sin un valor de origen, max-height: 0
     no tiene desde dónde animar. Holgado, para no recortar nada. */
  max-height: 6rem;
}

body.carta-abierta .hero-filete,
body.carta-abierta .fecha-hero {
  max-height: 0;
  margin-top: 0;
  margin-bottom: 0;
  overflow: hidden;
  transition:
    max-height    560ms var(--ease-out) 260ms,
    margin-top    560ms var(--ease-out) 260ms,
    margin-bottom 560ms var(--ease-out) 260ms;
}

/* La opacidad va por animación en las que entran con fill: both, porque
   ahí una declaración suelta no gana. */
body.carta-abierta .hero-filete { animation: retirarFilete 340ms var(--ease-out) 180ms both; }
body.carta-abierta .fecha-hero  { animation: retirarFecha  340ms var(--ease-out) 180ms both; }

@keyframes retirarFilete   { from { opacity: 1; transform: scaleX(1); }     to { opacity: 0; transform: scaleX(0.55); } }
@keyframes retirarFecha    { from { opacity: 1; transform: translateY(0); } to { opacity: 0; transform: translateY(-8px); } }

/* ═══════════════════════════════════════════════════════════════════
   EL REPRODUCTOR: NEGRO CON MORADO Y AZUL
   Deja de seguir el tema de la página y pasa a ser una pieza con voz
   propia: casi negro, con el botón y el avance en un degradado de morado
   a azul. Es lo que pidió Kevin, y de paso resuelve algo que traía: al
   flotar sobre todas las secciones, un cristal claro se confundía con el
   papel en unas y no en otras. Negro se lee igual en las siete.
   ═══════════════════════════════════════════════════════════════════ */

.rep-flotante {
  --rep-fondo:  17 15 26;      /* el casi negro de la píldora */
  --rep-a:      #8B5CF6;       /* morado */
  --rep-b:      #3B82F6;       /* azul */
  --rep-tinta:  #ECE9F7;
  --rep-linea:  rgb(236 233 247 / 0.16);
}

.rep-flotante .reproductor {
  background:
    radial-gradient(120% 200% at 6% 0%, rgb(139 92 246 / 0.22) 0%, transparent 62%),
    rgb(var(--rep-fondo) / 0.94);
  border: 1px solid var(--rep-linea);
  color: var(--rep-tinta);
  box-shadow:
    0 20px 46px -22px rgb(0 0 0 / 0.8),
    0 2px 10px -4px rgb(0 0 0 / 0.5),
    inset 0 1px 0 rgb(255 255 255 / 0.09);
}
.rep-flotante .reproductor:hover,
.rep-flotante .reproductor:focus-within {
  box-shadow:
    0 26px 60px -22px rgb(0 0 0 / 0.9),
    0 0 0 1px rgb(139 92 246 / 0.45),
    inset 0 1px 0 rgb(255 255 255 / 0.1);
}

/* --- El botón: disco de morado a azul --- */
.rep-flotante .rep-boton {
  color: #fff;
  background: linear-gradient(145deg, var(--rep-a) 0%, var(--rep-b) 100%);
  box-shadow:
    0 8px 22px -8px rgb(99 74 246 / 0.85),
    inset 0 1px 0 rgb(255 255 255 / 0.35),
    inset 0 -7px 12px -8px rgb(0 0 0 / 0.55);
}
.rep-flotante .rep-boton:focus-visible { outline-color: var(--rep-a); }

/* El anillo de avance, del mismo degradado. Un trazo no admite degradado
   directo, así que el color va en el surco y el arco lleva el morado
   claro, que es el que se lee sobre el negro. */
.rep-flotante .aro-surco  { stroke: rgb(236 233 247 / 0.18); }
.rep-flotante .aro-avance {
  stroke: #A78BFA;
  filter: drop-shadow(0 0 5px rgb(139 92 246 / 0.9));
}

/* --- Texto y ecualizador --- */
.rep-flotante .rep-titulo,
.rep-flotante .rep-ambiente { color: var(--rep-tinta); }
.rep-flotante .rep-titulo.con-nota { text-decoration-color: rgb(167 139 250 / 0.7); }
.rep-flotante .rep-tiempos { color: rgb(236 233 247 / 0.66); }

.rep-flotante .rep-barras span {
  background: linear-gradient(180deg, #A78BFA 0%, var(--rep-b) 100%);
}

/* --- La barra de avance --- */
.rep-flotante .rep-pista {
  background: rgb(236 233 247 / 0.16);
  box-shadow: inset 0 1px 2px rgb(0 0 0 / 0.5);
}
.rep-flotante .rep-avance {
  background: linear-gradient(90deg, var(--rep-a) 0%, #7DA6FF 100%);
  box-shadow: 0 0 9px -1px rgb(139 92 246 / 0.8);
}
.rep-flotante .rep-tirador,
.rep-flotante .rep-pista::after {
  background: #C4B5FD;
  box-shadow: 0 0 11px 1px rgb(139 92 246 / 0.8);
}

/* --- El botón de ambientes y la nota --- */
.rep-flotante .rep-menu {
  color: #C4B5FD;
  background: rgb(139 92 246 / 0.16);
  border-color: rgb(167 139 250 / 0.34);
}
.rep-flotante .rep-menu:hover { background: rgb(139 92 246 / 0.28); border-color: rgb(167 139 250 / 0.6); }




/* ═══════════════════════════════════════════════════════════════════
   EN EL TELÉFONO: UN BOTÓN FLOTANTE ABAJO A LA DERECHA
   La píldora entera ocupa demasiado en una pantalla estrecha y encima
   tapaba el pie de las secciones. Aquí se recoge a su disco, con el
   avance en el anillo, y el botón de ambientes queda de satélite.
   ═══════════════════════════════════════════════════════════════════ */

@media (max-width: 44em) {
  .rep-flotante {
    justify-content: flex-end;
    padding: 0 clamp(0.9rem, 4vw, 1.4rem);
    bottom: max(1.1rem, env(safe-area-inset-bottom, 0px));
  }

  .rep-flotante .reproductor {
    width: auto;
    max-width: none;
    padding: 0;
    gap: 0.55rem;
    flex-direction: column-reverse;
    align-items: center;
    background: none;
    border: 0;
    box-shadow: none;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }

  /* Del cuerpo solo sobrevive el anillo, que va dentro del botón */
  .rep-flotante .rep-cuerpo { display: none; }

  /* Sin cuerpo no hay píldora que contornear: el degradado del borde
     dibujaba una cápsula alta alrededor del disco y el satélite, una forma
     que en el teléfono no existe. Aquí la luz la lleva el disco y basta. */
  .rep-flotante .reproductor::after { display: none; }

  .rep-flotante .rep-boton {
    width: 58px;
    height: 58px;
    box-shadow:
      0 12px 28px -8px rgb(0 0 0 / 0.55),
      0 4px 14px -4px rgb(99 74 246 / 0.7),
      inset 0 1px 0 rgb(255 255 255 / 0.35),
      inset 0 -8px 14px -9px rgb(0 0 0 / 0.55);
  }
  .rep-flotante .rep-boton svg:not(.rep-aro) { width: 22px; height: 22px; }

  /* El anillo, más grueso y algo más separado: a 58 px el trazo de 2,2
     apenas se distinguía del canto del disco. */
  .rep-flotante .rep-aro circle { stroke-width: 3.2; }
  .rep-flotante .rep-boton .rep-aro {
    width: calc(100% + 16px); height: calc(100% + 16px); left: -8px; top: -8px;
  }

  /* El satélite de ambientes, más chico y por encima del disco */
  .rep-flotante .rep-menu {
    width: 34px;
    height: 34px;
    background: rgb(var(--rep-fondo) / 0.92);
    border-color: rgb(167 139 250 / 0.45);
    box-shadow: 0 8px 18px -8px rgb(0 0 0 / 0.6);
  }

  /* La nota sale hacia arriba y hacia la izquierda: pegada al canto
     derecho se saldría de la pantalla. */
  
}

/* ═══════════════════════════════════════════════════════════════════
   AJUSTES DEL REPRODUCTOR Y DEL SELECTOR
   Tres cosas que pidió Kevin: la píldora más traslúcida pero los botones
   no; la barra de avance deja de ser un mando; y el selector de ambientes
   toma los colores del reproductor para que combinen.
   ═══════════════════════════════════════════════════════════════════ */

/* --- La píldora, de cristal oscuro --- */
.rep-flotante .reproductor {
  background:
    radial-gradient(120% 200% at 6% 0%, rgb(139 92 246 / 0.26) 0%, transparent 62%),
    rgb(var(--rep-fondo) / 0.58);
  -webkit-backdrop-filter: blur(22px) saturate(150%);
  backdrop-filter: blur(22px) saturate(150%);
}

/* Los botones se quedan sólidos: son la parte que se toca, y un botón
   translúcido sobre un fondo cambiante deja de leerse como botón. */
.rep-flotante .rep-boton {
  background: linear-gradient(145deg, var(--rep-a) 0%, var(--rep-b) 100%);
}
.rep-flotante .rep-menu {
  background: rgb(var(--rep-fondo) / 0.92);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}

/* --- La barra ya no es un mando --- */
.rep-flotante .rep-pista {
  cursor: default;
  /* Deja pasar el puntero: así tocar ahí abre el selector, en vez de
     adelantar la canción sin querer. */
  pointer-events: none;
}
.rep-flotante .rep-pista::before,      /* la zona de toque ampliada */
.rep-flotante .rep-tirador { display: none; }

/* --- El selector de ambientes, en morado y azul --- */
.sel-carrusel { --sel-a: #8B5CF6; --sel-b: #3B82F6; --sel-claro: #C4B5FD; }

.sel-disco {
  background:
    radial-gradient(circle at 30% 24%,
      rgb(196 181 253 / calc(0.16 + 0.16 * var(--k, 0))) 0%, transparent 62%),
    linear-gradient(150deg, rgb(23 20 38 / 0.96) 0%, rgb(38 28 66 / 0.96) 100%);
  box-shadow:
    0 calc(10px + 14px * var(--k, 0)) calc(24px + 26px * var(--k, 0)) calc(-14px + -4px * var(--k, 0))
      rgb(0 0 0 / calc(0.5 + 0.25 * var(--k, 0))),
    0 0 calc(30px * var(--k, 0)) rgb(139 92 246 / calc(0.7 * var(--k, 0)));
}

.sel-aro {
  border-color: rgb(167 139 250 / calc(0.34 + 0.5 * var(--k, 0)));
  box-shadow:
    inset 0 0 0 calc(3px + 2px * var(--k, 0)) rgb(255 255 255 / 0.06),
    inset 0 0 0 calc(4px + 2px * var(--k, 0)) rgb(139 92 246 / calc(0.22 + 0.36 * var(--k, 0)));
}

.sel-marca { color: var(--sel-claro); }

.sel-tarjeta[aria-selected="true"] .sel-disco::after {
  background: conic-gradient(from 0deg,
    transparent 0deg,
    rgb(167 139 250 / 0.55) 46deg,
    rgb(59 130 246 / 0.12) 96deg,
    transparent 168deg,
    transparent 360deg);
}

.sel-riel:focus-visible .sel-tarjeta[aria-selected="true"] .sel-aro {
  box-shadow: 0 0 0 2px var(--sel-claro);
}

/* La nota de la canción vive dentro del reproductor, que ahora es negro
   siempre. Su texto tiene que ser claro siempre también: heredaba la tinta
   del tema y en modo papel quedaba azul oscuro sobre casi negro —medido,
   rgba(23,41,63,.86) sobre rgba(17,15,26,.97)—, o sea, invisible. */





/* ═══════════════════════════════════════════════════════════════════
   EL REPRODUCTOR VA ENCENDIDO
   Tres luces a la vez: un barrido que gira dentro del disco, un halo
   morado que sale hacia fuera y el contorno de la píldora en degradado.
   Antes esto solo pasaba con el ratón encima; ahora es como se ve siempre,
   también en el teléfono, que es donde más se mira la invitación y donde
   no hay ratón que lo despierte.
   El ratón sigue haciendo algo: crece un punto y el halo aprieta. Y con
   movimiento reducido el barrido no gira, pero la luz se queda.
   ═══════════════════════════════════════════════════════════════════ */

/* --- El barrido del disco --- */
.rep-flotante .rep-boton::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: conic-gradient(from 0deg,
    transparent 0deg,
    rgb(255 255 255 / 0.40) 34deg,
    rgb(196 181 253 / 0.22) 74deg,
    transparent 130deg,
    transparent 360deg);
  opacity: 1;
  animation: barrerLuz 2.6s linear infinite;
  pointer-events: none;
}

@keyframes barrerLuz { to { transform: rotate(360deg); } }

@media (hover: hover) {
  .rep-flotante .rep-boton {
    transition:
      transform 260ms var(--ease-out),
      box-shadow 340ms var(--ease-out);
  }

  /* El halo. Va en box-shadow y no en un pseudoelemento de detrás: un
     elemento con z-index negativo dentro del botón quedaría tapado por el
     fondo de la píldora, mientras que la sombra siempre se pinta fuera. */
  .rep-flotante .rep-boton:hover,
  .rep-flotante .rep-boton:focus-visible {
    transform: scale(1.06);
    box-shadow:
      0 0 0 1px rgb(196 181 253 / 0.72),
      0 0 22px 3px rgb(139 92 246 / 0.70),
      0 0 52px 8px rgb(99 102 241 / 0.45),
      0 10px 26px -8px rgb(76 29 149 / 0.9),
      inset 0 1px 0 rgb(255 255 255 / 0.5),
      inset 0 -7px 12px -8px rgb(0 0 0 / 0.5);
  }
  .rep-flotante .rep-boton:active { transform: scale(0.97); transition-duration: 110ms; }
}

/* --- El contorno de la píldora ---
   Un degradado no se puede poner en `border`, así que se pinta un
   rectángulo del tamaño del borde y se le recorta el centro con dos
   máscaras que se restan. */
@supports ((mask-composite: exclude) or (-webkit-mask-composite: xor)) {
  .rep-flotante .reproductor::after {
    content: '';
    position: absolute;
    inset: -1px;
    z-index: 2;
    border-radius: inherit;
    padding: 1.4px;
    background: conic-gradient(from 210deg,
      #8B5CF6 0deg, #3B82F6 90deg, #C4B5FD 180deg, #6366F1 270deg, #8B5CF6 360deg);
    -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
    -webkit-mask-composite: xor;
    mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
    mask-composite: exclude;
    opacity: 1;
    transition: opacity 380ms var(--ease-out);
    pointer-events: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  /* El barrido deja de girar pero no se apaga: quien pide menos movimiento
     pide eso, menos movimiento, no una pieza más apagada que las demás. */
  .rep-flotante .rep-boton::before { animation: none; }
  .rep-flotante .rep-boton:hover { transform: none; }
}

/* El disco, de cristal.
   Bajarle la opacidad a secas no bastaba: detrás no está la página sino el
   fondo de la propia píldora, así que quitarle color solo lo oscurecía. Lo
   que lo hace parecer vidrio es sumar un velo claro por arriba —como la luz
   que se posa en un cristal curvo— sobre un color ya tenue. */
.rep-flotante .rep-boton {
  background:
    linear-gradient(160deg,
      rgb(255 255 255 / 0.30) 0%,
      rgb(255 255 255 / 0.06) 42%,
      rgb(255 255 255 / 0) 62%),
    linear-gradient(145deg,
      rgb(139 92 246 / 0.42) 0%,
      rgb(59 130 246 / 0.42) 100%);
  -webkit-backdrop-filter: blur(16px) saturate(180%);
  backdrop-filter: blur(16px) saturate(180%);
  border: 1px solid rgb(196 181 253 / 0.34);
  /* El halo va aquí y no en el bloque del encendido porque esta regla es la
     última que toca box-shadow: allí arriba lo pisaría esta. */
  box-shadow:
    0 0 0 1px rgb(196 181 253 / 0.55),
    0 0 18px 2px rgb(139 92 246 / 0.55),
    0 0 42px 6px rgb(99 102 241 / 0.35),
    0 10px 26px -8px rgb(76 29 149 / 0.9),
    inset 0 1px 0 rgb(255 255 255 / 0.45),
    inset 0 -7px 12px -8px rgb(0 0 0 / 0.5);
}
/* El icono, con un filo oscuro detrás para que no dependa del cristal */
.rep-flotante .rep-boton svg:not(.rep-aro) {
  filter: drop-shadow(0 1px 2px rgb(20 12 48 / 0.6));
}
