/* =========================================================
   FUENTES
   "@font-face" le dice al navegador: "existe una fuente con
   este nombre y su archivo está aquí". Los archivos están en
   la carpeta fonts/ del proyecto, así que no dependemos de
   ningún servicio de internet.
   Están en formato WOFF2 (comprimido para web) y recortadas
   a las letras del español, para que pesen muy poco.
   ========================================================= */

/* Letra de pincel de la invitación en papel (nombres y frases).
   OJO: es una versión demo "solo uso personal". Pendiente de
   permiso del diseñador antes de publicar la web. */
@font-face {
  font-family: "Molliquam";
  src: url("fonts/molliquam.woff2") format("woff2");
  /* "block": durante un instante muy corto el navegador espera
     a la fuente en vez de enseñar otra letra. Así los nombres
     no aparecen primero con una letra fea y luego "saltan". */
  font-display: block;
}

/* Letra tipo máquina de escribir para los textos. */
@font-face {
  font-family: "Cutive";
  src: url("fonts/cutive.woff2") format("woff2");
  /* "swap": si tarda, se lee primero con otra letra y se cambia
     al llegar. Para textos largos es mejor que esperar. */
  font-display: swap;
}

/* Letra para fecha y datos en mayúsculas espaciadas.
   Es una fuente "variable": un solo archivo contiene todos los
   grosores del 100 (finísimo) al 700 (negrita). */
@font-face {
  font-family: "Josefin Sans";
  src: url("fonts/josefin-sans.woff2") format("woff2");
  font-weight: 100 700;
  font-display: swap;
}

/* =========================================================
   VARIABLES DE DISEÑO
   Guardamos colores y tipografías en "variables" (--nombre).
   Si mañana quieres otro verde, lo cambias solo aquí y
   se actualiza en toda la web.
   Colores sacados de la invitación en papel "Puzzle Travel".
   ========================================================= */
:root {
  --color-fondo: #f4efe6;        /* lino claro, como la tela de las fotos */
  --color-papel: #ffffff;        /* blanco del círculo de la invitación */
  --color-kraft: #c9a87c;        /* papel kraft del sobre */
  --color-salvia-sobre: #a7b9a5; /* interior del sobre */
  --color-mapa: #9dbb98;         /* continentes del mapa */
  --color-mapa-costa: #7d9f78;   /* contorno de la costa */
  --color-texto: #2f342f;        /* casi negro, como la tinta de "¡Nos casamos!" */
  --color-texto-suave: #5c5a55;  /* gris cálido para textos secundarios */
  --color-borde: #e4ddd0;        /* línea fina, a juego con el lino */

  /* Los colores de la invitación son más claros; aquí están un
     poco oscurecidos para que se lean bien en el móvil al sol. */
  --color-agua: #3f968a;         /* verde agua de los nombres */
  --color-coral: #c4644f;        /* coral de la fecha */
  --color-salvia: #5f7a61;       /* verde salvia del interior del sobre (botón) */
  --color-salvia-oscuro: #4e6650;/* salvia al pasar el ratón por el botón */
  --color-salvia-claro: #e8eee6; /* salvia muy suave para fondos de selección */
  --color-error: #a33a2c;        /* rojo apagado para los errores */
  --color-hueco: #e9e0d0;        /* sitio vacío de la pieza que falta */
  --color-hueco-activo: #e1d5c1; /* el hueco al tocarlo */
  --color-pieza: #e9a896;        /* la pieza del invitado: coral pastel */

  /* Cada lista de fuentes empieza por la nuestra; las siguientes
     son "plan B" por si el archivo no llegara a cargar. */
  --fuente-pincel: "Molliquam", "Segoe Script", "Brush Script MT", cursive;
  --fuente-texto: "Cutive", "Courier New", Georgia, serif;
  --fuente-datos: "Josefin Sans", "Century Gothic", "Avenir", system-ui, sans-serif;

  /* Curvas de velocidad de las animaciones. Las que trae CSS de serie
     ("ease-out", "ease-in-out") son muy suaves; estas tienen más "pegada":
     - salida rápida y frenada suave, para lo que aparece o responde a un toque;
     - acelerar y frenar, para lo que se mueve por la pantalla. */
  --curva-salida: cubic-bezier(0.23, 1, 0.32, 1);
  --curva-movimiento: cubic-bezier(0.77, 0, 0.175, 1);
}

/* "border-box" hace que el ancho de una caja incluya su relleno
   y su borde. Sin esto, un campo con width:100% + relleno se
   saldría de la pantalla en el móvil. */
*,
*::before,
*::after {
  box-sizing: border-box;
}

/* ---------- Ajustes para que en el móvil se sienta como una app ---------- */
html {
  /* Quita el destello gris/azul que pinta el móvil al tocar algo.
     Cada botón tiene su propia respuesta al tocarlo (:active). */
  -webkit-tap-highlight-color: transparent;
  /* Evita que el iPhone agrande el texto por su cuenta al girar el móvil. */
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

/* Botones y elementos que se tocan:
   - "touch-action: manipulation": el móvil no espera a ver si es un
     doble toque (para hacer zoom), así responden al instante.
   - "user-select: none": al dejar el dedo pulsado no se selecciona el
     texto del botón (los textos normales SÍ se pueden seleccionar). */
button,
summary,
.opcion,
.casilla {
  touch-action: manipulation;
  -webkit-user-select: none;
  user-select: none;
}

body {
  margin: 0;
  background-color: var(--color-fondo);
  color: var(--color-texto);
  font-family: var(--fuente-texto);
  font-size: 1rem;      /* 1rem = tamaño base del navegador (normalmente 16px) */
  line-height: 1.7;     /* la letra de máquina pide algo más de aire entre líneas */
}

/* Contenedor principal: limitamos el ancho para que en un
   ordenador las líneas no sean larguísimas, y lo centramos. */
.pagina {
  max-width: 34rem;
  margin: 0 auto;
  padding: 3rem 1.25rem 2rem;
  /* Con el móvil en horizontal, la muesca queda a un lado: max() usa el
     margen mayor entre el nuestro y el que pide la muesca. */
  padding-left: max(1.25rem, env(safe-area-inset-left));
  padding-right: max(1.25rem, env(safe-area-inset-right));
  padding-bottom: max(2rem, env(safe-area-inset-bottom));
}

/* =========================================================
   INVITACIÓN
   ========================================================= */
.invitacion {
  text-align: center;
  margin-bottom: 2.5rem;
}

/* ---------- Puzzle ---------- */
/* "position: relative" convierte la caja en el punto de referencia
   para colocar encima el dibujo y el círculo (que van "absolute").
   "aspect-ratio" mantiene la forma 4:5 del dibujo en cualquier ancho. */
.puzzle {
  position: relative;
  aspect-ratio: 4 / 5;
  margin-bottom: 2rem;
  /* Igual que en el círculo: dentro, 1cqi = 1% del ancho del puzzle. */
  container-type: inline-size;
}

/* El dibujo ocupa toda la caja del puzzle. */
.puzzle__dibujo {
  position: absolute;
  inset: 0;          /* = top, right, bottom y left a 0 */
  width: 100%;
  height: 100%;
  /* Esquinas redondeadas: "clip-path: inset(0 round 16px)" recorta el
     dibujo (piezas y mapa) con esquinas de 16 px. Solo el dibujo: el
     hueco va aparte y no se recorta, así puede latir libremente. */
  clip-path: inset(0 round 16px);
}

/* Los continentes en verde salvia, con un borde algo más oscuro
   para que la costa se distinga bien. */
.puzzle__mapa {
  fill: var(--color-mapa);
  stroke: var(--color-mapa-costa);
  stroke-width: 0.8;
  stroke-linejoin: round;
}

/* Las ranuras se dibujan con una línea del color del fondo
   encima de piezas y mapa: parece que hay un corte fino entre piezas. */
.puzzle__ranuras {
  fill: none;
  stroke: var(--color-fondo);
  stroke-width: 3;
  stroke-linejoin: round;
}

/* Línea de puntos de la ruta del avión.
   stroke-dasharray "0 8" + puntas redondas = puntos redondos
   separados 8 unidades. */
.puzzle__ruta {
  fill: none;
  stroke: var(--color-texto);
  stroke-width: 2.2;
  stroke-linecap: round;
  stroke-dasharray: 0 8;
  opacity: 0.75;
}

/* El avión, con un borde del mismo color y esquinas redondeadas
   para suavizar las puntas de las alas. */
.puzzle__avion {
  fill: var(--color-texto);
  stroke: var(--color-texto);
  stroke-width: 1.2;
  stroke-linejoin: round;
}

/* ---------- Círculo blanco con los nombres ---------- */
.circulo {
  position: absolute;
  /* Centrado: empieza en la mitad y retrocede la mitad de su
     propio tamaño (translate -50%). */
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 84%;
  aspect-ratio: 1;          /* tan alto como ancho → círculo perfecto */
  border-radius: 50%;
  background-color: var(--color-papel);
  /* Sombra muy suave para que parezca un papel encima del puzzle. */
  box-shadow: 0 1px 2px rgb(47 52 47 / 0.08), 0 8px 24px rgb(47 52 47 / 0.10);

  /* Flex en columna: apila el contenido y lo centra en vertical. */
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 8%;

  /* "container-type" permite que el texto de dentro use la unidad
     "cqi" (1cqi = 1% del ancho del círculo). Así las letras crecen
     y encogen junto con el círculo y nunca se salen de él. */
  container-type: inline-size;
}

/* El papel con grano ocupa todo el círculo, por detrás del texto.
   "overflow: hidden" en el círculo recorta las esquinas del cuadrado. */
.circulo {
  overflow: hidden;
}

.circulo__papel {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

/* El texto, por encima del papel. "position: relative" lo pone
   en la misma capa que el papel, y al ir después queda delante. */
.circulo > :not(.circulo__papel) {
  position: relative;
}

/* "¡Nos casamos!" en pincel negro, como en el interior del sobre. */
.circulo__antetitulo {
  margin: 0;
  font-family: var(--fuente-pincel);
  font-size: 15cqi;
  line-height: 1.2;
}

.circulo__nombres {
  /* Los márgenes laterales negativos dejan que los nombres usen
     parte del relleno del círculo: a la altura del centro el círculo
     es casi todo ancho, así que "Alejandro" cabe más grande. */
  margin: 0.05em -5cqi 0.1em;
  color: var(--color-agua);
  font-family: var(--fuente-pincel);
  font-weight: normal;
  font-size: 31cqi;
  line-height: 0.95;
}

/* El "&" un poco más pequeño, para que destaquen los nombres. */
.circulo__y {
  font-size: 0.7em;
}

/* Fecha en coral, mayúsculas muy espaciadas, como "18.MAYO.22"
   en la invitación en papel. */
.circulo__fecha {
  margin: 0;
  color: var(--color-coral);
  font-family: var(--fuente-datos);
  font-size: 10.5cqi;
  font-weight: 600;
  letter-spacing: 0.12em;
  line-height: 1.2;
  /* El espaciado también se añade tras la última letra; este
     margen negativo lo compensa para que quede bien centrada. */
  margin-right: -0.12em;
}

/* "Sábado" pequeñito encima de la fecha. */
.circulo__dia {
  display: block;
  margin-bottom: 0.35em;
  color: var(--color-texto-suave);
  font-size: 0.45em;
  letter-spacing: 0.35em;
  text-transform: uppercase;
}

/* Oculta un texto a la vista pero lo deja para los lectores de
   pantalla. Es la receta estándar: una caja de 1px recortada. */
.solo-lectores {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* ---------- El hueco: la pieza que falta ---------- */
/* El botón se coloca justo encima de la esquina inferior izquierda
   del puzzle. Los porcentajes salen del dibujo (400×500): la zona del
   hueco empieza en y=372 (372/500 = 74.4%) y mide 128×128 unidades
   (128/400 = 32% de ancho, 128/500 = 25.6% de alto). */
.hueco {
  position: absolute;
  left: 0;
  top: 74.4%;
  width: 32%;
  height: 25.6%;
  padding: 0;
  border: none;
  background: none;
  color: var(--color-coral);
  cursor: pointer;
  /* Quita el destello gris al tocar en móviles; ya damos nuestra
     propia respuesta visual. */
  -webkit-tap-highlight-color: transparent;
}

.hueco__dibujo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
}

/* El hueco: un poco más oscuro que el fondo, con borde de rayas,
   como el sitio vacío que deja una pieza. */
.hueco__forma {
  fill: var(--color-hueco);
  stroke: var(--color-coral);
  stroke-width: 3.2;        /* se ve la mitad (1,6): la otra la recorta el clipPath */
  stroke-dasharray: 5 4;
  stroke-linejoin: round;
  /* "transform-box: fill-box" hace que el centro del latido sea el
     centro de la propia forma, no la esquina del dibujo. */
  transform-box: fill-box;
  transform-origin: center;
}

/* Latido suave para invitar a tocar. Solo si la persona NO ha pedido
   "reducir movimiento" en su móvil (ajuste de accesibilidad).
   - Empieza cuando ya no está el sobre delante (html sin "con-sobre").
   - Late 3 veces (cada vez, un latido doble y una pausa) y se para:
     las normas de accesibilidad piden que nada se mueva sin fin,
     porque distrae y molesta a algunas personas.
   - Deja de latir cuando el formulario ya está abierto. */
@media (prefers-reduced-motion: no-preference) {
  html:not(.con-sobre) .hueco[aria-expanded="false"] .hueco__forma {
    animation: latido 2.4s ease-in-out 0.6s 3;
  }
}

@keyframes latido {
  0%, 55%, 100% { transform: scale(1); }
  20%           { transform: scale(1.05); }
  35%           { transform: scale(0.99); }
}

/* Al tocar, el hueco se oscurece y se hunde un poco: así se nota al
   instante que la web ha recibido el toque. */
.hueco {
  transition: transform 140ms var(--curva-salida);
}

.hueco:active:not(:disabled) {
  transform: scale(0.97);
}

.hueco:active .hueco__forma {
  fill: var(--color-hueco-activo);
}

/* Al pasar el ratón, lo mismo. Va dentro de esta condición porque en
   el móvil el "hover" se queda pegado después de tocar: solo se aplica
   en aparatos con ratón (hover: hover) y puntero preciso (pointer: fine). */
@media (hover: hover) and (pointer: fine) {
  .hueco:hover .hueco__forma {
    fill: var(--color-hueco-activo);
  }
}

/* Contorno visible al llegar con el teclado (tabulador). */
.hueco:focus-visible {
  outline: none;
}
.hueco:focus-visible .hueco__forma {
  stroke-width: 6;
  stroke-dasharray: none;
}

/* El texto ocupa solo el cuadrado de la pieza (sin las lengüetas):
   empieza 28 unidades más abajo (28/128) y mide 100 de 128. */
.hueco__texto {
  position: absolute;
  left: 0;
  top: 21.9%;
  width: 78.1%;
  height: 78.1%;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 8%;
  font-family: var(--fuente-pincel);
  font-size: 9.5cqi;
  line-height: 1;
  text-wrap: balance;
}

/* La pieza que encaja: escondida hasta que se confirma. */
.hueco__pieza {
  fill: var(--color-pieza);
  /* La misma ranura fina que separa las demás piezas. */
  stroke: var(--color-fondo);
  stroke-width: 3;
  stroke-linejoin: round;
  opacity: 0;
}

.hueco__corazon {
  fill: #ffffff;
  stroke: none;
}


/* ---------- Puzzle completo (después de confirmar) ---------- */
/* app.js añade la clase "puzzle--completo" al enviar el formulario. */
.puzzle--completo .hueco {
  cursor: default;
}
.puzzle--completo .hueco__forma,
.puzzle--completo .hueco__texto {
  visibility: hidden;
}
.puzzle--completo .hueco__pieza {
  opacity: 1;
}

/* La pieza baja desde arriba, girando un poco, y encaja.
   Espera un instante (delay) para que dé tiempo a subir hasta el puzzle. */
@media (prefers-reduced-motion: no-preference) {
  .puzzle--completo .hueco__pieza {
    transform-box: fill-box;
    transform-origin: center;
    animation: encajar 0.75s cubic-bezier(0.2, 0.8, 0.2, 1) 0.45s both;
  }
}

@keyframes encajar {
  from {
    opacity: 0;
    transform: translate(18%, -45%) rotate(-14deg) scale(1.12);
  }
  70% {
    opacity: 1;
    transform: translate(0, 2%) rotate(1deg) scale(1);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/* ---------- Texto y datos bajo el puzzle ---------- */
.invitacion__texto {
  margin: 0 0 2rem;
  color: var(--color-texto-suave);
}

/* ---------- Cuenta atrás (sale al confirmar que vienes) ---------- */
.contador {
  margin: 0 0 2rem;
}

.contador__titulo {
  margin: 0 0 0.75rem;
  color: var(--color-texto-suave);
}

/* Cuatro cajitas en fila: días, horas, minutos y segundos. */
.contador__cifras {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 0.5rem;
  max-width: 22rem;
  margin: 0 auto;
}

.contador__unidad {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.2rem;
  margin: 0;
}

/* Los números con la letra de la fecha, en coral.
   "tabular-nums" da a todas las cifras el mismo ancho: así el
   número no "baila" cada segundo al cambiar, por ejemplo, de 1 a 0. */
.contador__numero {
  font-family: var(--fuente-datos);
  font-size: 1.9rem;
  font-weight: 600;
  line-height: 1;
  color: var(--color-coral);
  font-variant-numeric: tabular-nums;
}

.contador__nombre {
  font-family: var(--fuente-datos);
  font-size: 0.7rem;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--color-texto-suave);
}

/* Bloque de hora y lugar, con líneas finas arriba y abajo. */
.detalles {
  margin: 0;
  padding: 1.5rem 0;
  border-top: 1px solid var(--color-borde);
  border-bottom: 1px solid var(--color-borde);
}

.detalles__fila + .detalles__fila {
  margin-top: 1.1rem; /* espacio solo ENTRE filas, no antes de la primera */
}

/* Etiquetas "Hora", "Lugar": pequeñas y muy espaciadas. */
.detalles dt {
  color: var(--color-texto-suave);
  font-family: var(--fuente-datos);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.3em;
  text-transform: uppercase;
}

.detalles dd {
  margin: 0.2rem 0 0;
  font-family: var(--fuente-datos);
  font-size: 1.05rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

/* ---------- Regalo: número de cuenta ---------- */
.regalo {
  padding: 1.5rem 0;
  border-bottom: 1px solid var(--color-borde);
}

/* El título, igual que "Hora" y "Lugar". */
.regalo__titulo {
  margin: 0;
  color: var(--color-texto-suave);
  font-family: var(--fuente-datos);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.3em;
  text-transform: uppercase;
}

.regalo__texto {
  margin: 0.5rem 0 0.9rem;
  color: var(--color-texto-suave);
  text-wrap: balance;
}

/* El número, con la letra de los datos. "balance" hace que, si no
   cabe en una línea, se parta en dos mitades iguales (nunca a mitad
   de un grupo de cuatro cifras, porque solo se parte en los espacios). */
.regalo__iban {
  margin: 0 0 0.9rem;
  font-family: var(--fuente-datos);
  font-size: 1.05rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  font-variant-numeric: tabular-nums;
  text-wrap: balance;
}

/* ---------- Botón con borde (secundario) ----------
   Para acciones de apoyo: "Cómo llegar", "Copiar número" y
   "Confirmar otra persona". Verde oscuro para que se lea bien
   (contraste suficiente también con letra pequeña).
   Sirve igual para <button> que para enlaces <a>. */
.boton-borde {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px; /* tamaño mínimo cómodo para el dedo */
  padding: 0.6rem 1.2rem 0.5rem;
  border: 1px solid var(--color-salvia-oscuro);
  border-radius: 8px;
  background-color: transparent;
  color: var(--color-salvia-oscuro);
  font-family: var(--fuente-datos);
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  text-decoration: none;
  cursor: pointer;
  touch-action: manipulation;
}

/* "display: inline-flex" taparía el atributo hidden: lo respetamos. */
.boton-borde[hidden] {
  display: none;
}

.boton-borde:active {
  background-color: var(--color-salvia-claro);
}

@media (hover: hover) and (pointer: fine) {
  .boton-borde:hover {
    background-color: var(--color-salvia-claro);
  }
}

/* Separación de cada botón con borde respecto a lo de encima. */
.detalles__mapa {
  margin-top: 0.75rem;
}

.gracias__otra {
  margin-top: 1.25rem;
}

.regalo__aviso {
  margin: 0.5rem 0 0;
  text-wrap: balance;
  color: var(--color-salvia);
  font-size: 0.9rem;
}

.regalo__aviso:empty {
  display: none;
}

/* "balance" reparte el texto entre líneas de forma equilibrada,
   para que no quede una palabra suelta en la última línea. */
.invitacion__texto,
.tarjeta__subtitulo,
.detalles dd,
.gracias__texto {
  text-wrap: balance;
}

/* =========================================================
   TARJETA DEL FORMULARIO
   ========================================================= */
.tarjeta {
  margin-top: 2.5rem;
  /* Al llevar la vista hasta el formulario, deja un poco de aire arriba. */
  scroll-margin-top: 1.5rem;
  background-color: var(--color-papel);
  border: 1px solid var(--color-borde);
  border-radius: 12px;
  padding: 2rem 1.25rem;
}

/* Al abrirse, el formulario aparece suavemente desde un poco más abajo. */
@media (prefers-reduced-motion: no-preference) {
  .tarjeta:not([hidden]) {
    animation: aparecer 0.3s var(--curva-salida);
  }
}

/* "Reducir movimiento" no es "nada de animación": quitamos lo que se
   mueve, pero un fundido suave ayuda a entender qué ha aparecido. */
@media (prefers-reduced-motion: reduce) {
  .tarjeta:not([hidden]),
  .gracias:not([hidden]) {
    animation: fundido 0.2s ease;
  }
}

@keyframes fundido {
  from { opacity: 0; }
}

@keyframes aparecer {
  from { opacity: 0; transform: translateY(12px); }
}

/* Título en mayúsculas espaciadas, la misma letra que la fecha
   y los datos de la invitación. */
.tarjeta__titulo {
  margin: 0;
  color: var(--color-salvia-oscuro);
  font-family: var(--fuente-datos);
  font-weight: 600;
  font-size: 1.3rem;
  letter-spacing: 0.18em;
  line-height: 1.4;
  text-transform: uppercase;
  text-align: center;
  text-wrap: balance;
}

/* Los títulos reciben el foco desde app.js (para los lectores de
   pantalla); no hace falta dibujarles un contorno. */
.circulo__nombres:focus,
.tarjeta__titulo:focus,
.gracias__titulo:focus {
  outline: none;
}

.tarjeta__subtitulo {
  margin: 0.75rem 0 1.75rem;
  color: var(--color-texto-suave);
  font-size: 0.9rem;
  text-align: center;
}

/* =========================================================
   CAMPOS DEL FORMULARIO
   ========================================================= */
.campo {
  margin: 0 0 1.25rem;
  padding: 0;
  border: none; /* el <fieldset> trae un borde por defecto; lo quitamos */
}

/* Las etiquetas usan la letra de "datos", como "Fecha" o "Lugar". */
.campo label,
.campo legend {
  display: block;
  margin-bottom: 0.45rem;
  padding: 0;
  font-family: var(--fuente-datos);
  font-weight: 600;
  font-size: 0.8rem;
  letter-spacing: 0.15em;
  text-transform: uppercase;
}

.campo__opcional {
  color: var(--color-texto-suave);
  font-weight: normal;
  letter-spacing: 0.05em;
  text-transform: none;
}

.campo input[type="text"],
.campo textarea {
  width: 100%;
  padding: 0.75rem 0.85rem;
  border: 1px solid var(--color-borde);
  border-radius: 8px;
  background-color: var(--color-fondo);
  color: var(--color-texto);
  /* Usar 1rem (16px) evita que el iPhone haga zoom
     automático al tocar el campo. */
  font-family: inherit;
  font-size: 1rem;
}

.campo textarea {
  resize: vertical; /* solo se puede estirar hacia abajo, no a lo ancho */
}

/* ":focus" = el campo en el que estás escribiendo ahora.
   Lo resaltamos con el color de acento para que se note. */
.campo input[type="text"]:focus,
.campo textarea:focus {
  outline: none;
  border-color: var(--color-salvia);
  box-shadow: 0 0 0 3px var(--color-salvia-claro);
}

/* Campo con error: app.js le añade el atributo aria-invalid="true". */
.campo input[aria-invalid="true"],
.campo textarea[aria-invalid="true"] {
  border-color: var(--color-error);
}

/* Campo trampa: fuera de la pantalla, invisible para las personas. */
.campo-trampa {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* El aviso de error de envío va centrado bajo el botón. */
.formulario__error {
  text-align: center;
}

.campo__error {
  margin: 0.35rem 0 0;
  color: var(--color-error);
  font-size: 0.85rem;
}

/* Si no hay texto de error, el párrafo no ocupa espacio. */
.campo__error:empty {
  display: none;
}

/* ---------- Opciones Sí / No ---------- */
/* "grid" con columnas automáticas: si caben (mínimo 11rem cada
   una), los dos botones van uno al lado del otro; en móviles
   estrechos se colocan uno debajo del otro, sin partir el texto.
   "min(11rem, 100%)": si ni una sola cabe (móvil pequeño con la letra
   muy grande), la caja ocupa todo el ancho y no se sale de la tarjeta. */
.opciones {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(11rem, 100%), 1fr));
  gap: 0.75rem;
}

/* Cada opción es una caja grande y fácil de tocar con el dedo.
   Dentro va texto normal, no la letra de las etiquetas. */
.campo .opcion {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0;
  padding: 0.75rem;
  border: 1px solid var(--color-borde);
  border-radius: 8px;
  background-color: var(--color-fondo);
  font-family: var(--fuente-texto);
  font-size: 1rem;
  font-weight: normal;
  letter-spacing: normal;
  text-transform: none;
  cursor: pointer;
}

.campo .opcion:active {
  background-color: var(--color-salvia-claro);
}

.opcion input {
  margin: 0;
  accent-color: var(--color-salvia); /* colorea el circulito del radio */
}

/* ":has(input:checked)" = "la caja que contiene el radio marcado".
   Así resaltamos la opción elegida sin necesidad de JavaScript. */
.opcion:has(input:checked) {
  border-color: var(--color-salvia);
  background-color: var(--color-salvia-claro);
}

/* ---------- Aviso de privacidad ---------- */
.privacidad {
  margin: 0.5rem 0 1.25rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--color-borde);
  color: var(--color-texto-suave);
  font-size: 0.9rem;
  line-height: 1.6;
}

.privacidad__resumen {
  margin: 0 0 0.5rem;
}

/* El texto que abre el desplegable, subrayado como un enlace. */
.privacidad__detalle summary {
  /* 44 px de alto como mínimo: el tamaño cómodo para un dedo.
     inline-flex + align-items centran el texto en esa altura. */
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  color: var(--color-salvia-oscuro);
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
}

.privacidad__detalle summary:focus-visible {
  outline: 2px solid var(--color-salvia);
  outline-offset: 2px;
}

.privacidad__detalle ul {
  margin: 0.5rem 0 0.75rem;
  padding-left: 1.1rem;
}

.privacidad__detalle li + li {
  margin-top: 0.4rem;
}

.privacidad__detalle strong {
  color: var(--color-texto);
  font-weight: normal;
}

/* Casilla de aceptación: el cuadradito y el texto, lado a lado.
   Anulamos el estilo de mayúsculas de las etiquetas del formulario. */
.campo--casilla {
  margin: 0.75rem 0 0;
}

.campo .casilla {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  margin: 0;
  color: var(--color-texto);
  font-family: var(--fuente-texto);
  font-size: 0.9rem;
  font-weight: normal;
  letter-spacing: normal;
  line-height: 1.5;
  text-transform: none;
  cursor: pointer;
}

.casilla input {
  flex-shrink: 0;           /* el cuadradito no encoge con textos largos */
  width: 1.2rem;
  height: 1.2rem;
  margin: 0.1rem 0 0;
  accent-color: var(--color-salvia);
}

/* ---------- Botón ---------- */
.boton {
  width: 100%;
  margin-top: 0.5rem;
  padding: 1rem 0.9rem 0.9rem; /* Josefin queda un pelín alta: compensamos arriba */
  border: none;
  border-radius: 8px;
  background-color: var(--color-salvia);
  color: #ffffff;
  font-family: var(--fuente-datos);
  font-size: 0.95rem;
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  cursor: pointer;
}

/* Mientras se envía: el botón se apaga un poco y no se puede
   volver a pulsar (app.js lo desactiva con "disabled"). */
.boton:disabled {
  opacity: 0.7;
  cursor: progress;
}

/* Respuesta al tocar: el botón se hunde un poco y se oscurece, en
   cuanto el dedo lo pisa (no al soltarlo). */
.boton {
  transition: transform 140ms var(--curva-salida), background-color 140ms var(--curva-salida);
}

.boton:active:not(:disabled) {
  transform: scale(0.97);
  background-color: var(--color-salvia-oscuro);
}

@media (hover: hover) and (pointer: fine) {
  .boton:hover:not(:disabled) {
    background-color: var(--color-salvia-oscuro);
  }
}

/* El botón de reserva va con borde y sin relleno, para que no
   compita con la invitación: es solo un "por si acaso". */
.boton--reserva {
  margin-top: 2rem;
  border: 1px solid var(--color-salvia);
  background-color: transparent;
  color: var(--color-salvia-oscuro);
}

.boton--reserva:active:not(:disabled) {
  background-color: var(--color-salvia-claro);
}

@media (hover: hover) and (pointer: fine) {
  .boton--reserva:hover:not(:disabled) {
    background-color: var(--color-salvia-claro);
  }
}

/* El contorno que marca el botón elegido con el teclado: verde
   oscuro, para que se vea bien sobre el blanco y el lino. */
.boton:focus-visible,
.boton-borde:focus-visible {
  outline: 3px solid var(--color-salvia-oscuro);
  outline-offset: 3px;
}

/* =========================================================
   MENSAJE DE AGRADECIMIENTO
   ========================================================= */
@media (prefers-reduced-motion: no-preference) {
  .gracias:not([hidden]) {
    animation: aparecer 0.4s var(--curva-salida) 0.9s both;
  }
}

.gracias {
  margin: 1.5rem 0 2rem;
  text-align: center;
  scroll-margin-top: 1.5rem;
}

.gracias__titulo {
  margin: 0 0 0.5rem;
  color: var(--color-agua);
  font-family: var(--fuente-pincel);
  font-weight: normal;
  font-size: 2.6rem;
  line-height: 1.1;
}

.gracias__texto {
  margin: 0;
  color: var(--color-texto-suave);
}

/* =========================================================
   PIE DE PÁGINA
   ========================================================= */
.pie {
  margin-top: 2.5rem;
  text-align: center;
  color: var(--color-texto-suave);
  font-family: var(--fuente-datos);
  font-size: 0.8rem;
  letter-spacing: 0.25em;
  text-transform: uppercase;
}

/* =========================================================
   PORTADA: EL SOBRE QUE SE ABRE
   Solo se ve si el <html> tiene la clase "con-sobre", que pone
   el mini-script del <head>. Sin esa clase, no existe.
   ========================================================= */
.portada {
  display: none;
}

html.con-sobre .portada {
  /* "fixed" la clava a la pantalla, por encima de todo (z-index alto). */
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1.75rem;
  padding: 1.25rem;
  background-color: var(--color-fondo);
}

/* Mientras está el sobre, la página de detrás no se puede desplazar. */
html.con-sobre body {
  overflow: hidden;
}

/* Con el sobre delante tampoco se puede "tirar hacia abajo para
   recargar": un tirón sin querer reiniciaría la animación. */
html.con-sobre {
  overscroll-behavior: none;
}

/* En ordenador, al quitar el sobre aparece la barra de desplazamiento
   y empujaría la invitación unos píxeles. "stable" reserva siempre su
   hueco, así la hoja aterriza exactamente donde queda el puzzle. */
html {
  scrollbar-gutter: stable;
}

/* ---------- Botón "Saltar" ---------- */
.portada__saltar {
  position: absolute;
  /* env(safe-area-inset-top) = el espacio de la "muesca" de algunos
     iPhone. max() elige el mayor, para no quedar debajo de ella. */
  top: max(0.5rem, env(safe-area-inset-top));
  right: max(0.5rem, env(safe-area-inset-right));
  min-height: 44px; /* tamaño mínimo cómodo para un dedo */
  padding: 0.5rem 1rem;
  border: none;
  background: none;
  color: var(--color-texto-suave);
  font-family: var(--fuente-datos);
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  cursor: pointer;
}

.portada__saltar:focus-visible {
  outline: 2px solid var(--color-salvia);
  outline-offset: 2px;
}

.portada__pista {
  margin: 0;
  color: var(--color-texto-suave);
  font-size: 0.95rem;
}

/* ---------- El sobre ---------- */
.sobre {
  width: min(84vw, 22rem);
  aspect-ratio: 10 / 7;
  padding: 0;
  border: none;
  background: none;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  /* Sombra bajo el sobre, como si estuviera sobre la mesa. */
  filter: drop-shadow(0 12px 18px rgb(47 52 47 / 0.2));
}

.sobre:focus-visible {
  outline: 3px solid var(--color-salvia);
  outline-offset: 10px;
}

.sobre__dibujo {
  display: block;
  width: 100%;
  height: 100%;
  overflow: visible; /* deja ver la carta y la solapa cuando salen por arriba */
}

.sobre__interior,
.sobre__solapa-abierta {
  fill: var(--color-salvia-sobre);
}

.sobre__carta rect {
  fill: var(--color-papel);
}

/* "¡Nos casamos!" en pincel negro, como en la invitación. */
.sobre__carta-antetitulo {
  fill: var(--color-texto);
  font-family: var(--fuente-pincel);
  font-size: 18px;
}

.sobre__carta-nombres {
  fill: var(--color-agua);
  font-family: var(--fuente-pincel);
  font-size: 30px;
}

.sobre__lados   { fill: url(#kraft-lados); }
.sobre__abajo   { fill: url(#kraft-abajo); }
.sobre__solapa  { fill: url(#kraft-solapa); }

/* Las dos solapas de arriba se pliegan con "scaleY" (estirar o
   aplastar en vertical). "transform-box: fill-box" hace que el punto
   de giro se mida sobre la propia forma: la cerrada se pliega hacia
   su borde de arriba y la abierta se despliega desde su borde de abajo. */
.sobre__solapa,
.sobre__solapa-abierta {
  transform-box: fill-box;
}
.sobre__solapa          { transform-origin: top center; }
.sobre__solapa-abierta  { transform-origin: bottom center; transform: scaleY(0); }

/* Cordel: las vueltas se rellenan con la textura de yute. */
.sobre__cordel rect,
.sobre__nudo {
  fill: url(#yute);
}

.sobre__lazo,
.sobre__cabos {
  fill: none;
  stroke: url(#yute);
  stroke-width: 3.2;
  stroke-linecap: round;
}

.sobre__hilo {
  fill: none;
  stroke: #8c6b45;
  stroke-width: 1;
}

/* Etiqueta colgante de papel blanco. */
.sobre__etiqueta-papel {
  fill: var(--color-papel);
  filter: drop-shadow(0 1.5px 1.5px rgb(47 52 47 / 0.25));
}

.sobre__etiqueta-agujero {
  fill: var(--color-fondo);
  stroke: var(--color-kraft);
  stroke-width: 1.2;
}

.sobre__etiqueta-texto {
  fill: var(--color-coral);
  font-family: var(--fuente-pincel);
  font-size: 22px;
}

/* ---------- La hoja que crece y se da la vuelta ---------- */
/* "fixed": se coloca respecto a la pantalla. app.js le da la posición
   y el tamaño exactos de la carta y luego los del puzzle.
   "perspective" da profundidad al giro: sin ella, la hoja parecería
   estrecharse en vez de girar hacia nosotros. */
.hoja {
  position: fixed;
  z-index: 1;
  perspective: 1400px;
  color: var(--color-agua);
  font-family: var(--fuente-pincel);
  line-height: 1;
  text-align: center;
}

.hoja[hidden] {
  display: none;
}

/* La pieza que gira (app.js la anima con rotateY).
   "preserve-3d" mantiene las dos caras en 3D al girar. */
.hoja__giro {
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;
}

/* Cada cara ocupa toda la hoja. "backface-visibility: hidden" hace
   que una cara no se vea cuando está de espaldas: así, a mitad del
   giro, desaparece el frente y aparece el dorso. */
.hoja__cara {
  position: absolute;
  inset: 0;
  overflow: hidden;
  border-radius: 3px;
  box-shadow: 0 6px 20px rgb(47 52 47 / 0.18);
  -webkit-backface-visibility: hidden; /* Safari lo necesita con prefijo */
  backface-visibility: hidden;
}

/* El dorso empieza ya dado la vuelta: al girar la hoja 180°, queda
   de frente. Lleva el color de fondo de la página detrás del puzzle. */
.hoja__cara--dorso {
  transform: rotateY(180deg);
  border-radius: 0;
  box-shadow: none;
  background-color: var(--color-fondo);
  /* La hoja usa letra de pincel en verde; el puzzle copiado debe
     verse igual que en la página, así que recuperamos sus estilos. */
  color: var(--color-texto);
  font-family: var(--fuente-texto);
  line-height: 1.7;
}

/* La copia del puzzle ocupa todo el dorso, se estire como se estire. */
.puzzle--copia {
  width: 100%;
  height: 100%;
  aspect-ratio: auto;
}

.hoja__papel {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

/* El pliegue: una raya fina en mitad de la hoja, como la marca de
   haberla doblado. Desaparece mientras la hoja se despliega. */
.hoja__pliegue {
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  height: 2px;
  background: linear-gradient(rgb(90 65 40 / 0.16), rgb(255 255 255 / 0.9));
}

/* El texto de la hoja copia la colocación de la carta del sobre.
   La letra de los nombres mide 1em (app.js la ajusta al ancho de la
   carta) y todo lo demás se mide en "em", así crece en proporción. */
.hoja__texto {
  position: absolute;
  inset: 0;
}

.hoja__antetitulo,
.hoja__nombres {
  position: absolute;
  left: 0;
  right: 0;
}

.hoja__antetitulo {
  top: 0.98em;       /* 0,59 de la hoja ÷ 0,6 (su tamaño de letra) */
  color: var(--color-texto);
  font-size: 0.6em;   /* 18 de 30, como en la carta */
}

.hoja__nombres {
  top: 1.47em;
}

/* ---------- Animaciones ---------- */
/* Todas dentro de "no-preference": si el móvil pide reducir el
   movimiento, no hay animación y app.js abre el sobre al instante. */
@media (prefers-reduced-motion: no-preference) {

  /* Mientras espera, el sobre se balancea muy poco, dos veces, como
     invitando a tocarlo, y luego se queda quieto (nada se mueve sin fin). */
  .portada:not(.portada--abriendo) .sobre {
    animation: balanceo 4s ease-in-out 1s 2;
  }

  /* Al tocarlo, app.js añade "portada--abriendo" y empieza la
     secuencia. Cada parte espera (delay) a que acabe la anterior:
       0,0 s  el cordel y la etiqueta se sueltan
       0,3 s  la solapa se abre
       0,9 s  la invitación sale del sobre
       1,6 s  app.js toma el relevo: la hoja crece hasta el tamaño
              del puzzle y se funde con la invitación de verdad */
  .portada--abriendo .sobre__cordel,
  .portada--abriendo .sobre__etiqueta {
    animation: soltar 0.25s var(--curva-salida) forwards;
  }

  /* La solapa cerrada se pliega hacia arriba... */
  .portada--abriendo .sobre__solapa {
    animation: plegar 0.3s ease-in 0.3s forwards;
  }

  /* ...y justo después se despliega la abierta, mostrando el salvia. */
  .portada--abriendo .sobre__solapa-abierta {
    animation: desplegar 0.3s ease-out 0.6s forwards;
  }

  .portada--abriendo .sobre__carta {
    animation: sacar-carta 0.7s cubic-bezier(0.2, 0.8, 0.2, 1) 0.9s forwards;
  }

  .portada--abriendo .portada__pista,
  .portada--abriendo .portada__saltar {
    animation: soltar 0.2s var(--curva-salida) forwards;
  }
}

@keyframes balanceo {
  0%, 70%, 100% { transform: rotate(0); }
  78%           { transform: rotate(-1.5deg); }
  86%           { transform: rotate(1.2deg); }
  93%           { transform: rotate(-0.5deg); }
}

@keyframes soltar {
  to { opacity: 0; }
}

@keyframes plegar {
  to { transform: scaleY(0); }
}

@keyframes desplegar {
  to { transform: scaleY(1); }
}

/* Dentro de un SVG, los "px" son unidades del dibujo: el sobre
   mide 210 de alto, así que la carta sube casi la mitad. */
@keyframes sacar-carta {
  to { transform: translateY(-100px); }
}
