/* ==========================================================
   Panel de administración — Mesa de Regalos Digital
   ========================================================== */
:root {
  /* Plano y suave: tarjetas blancas sobre una página gris muy clara,
     botones negros en píldora y un solo color de acento. Antes el panel
     era neumórfico -- todo del mismo gris, separado solo por sombras
     dobles -- y un botón, un campo y una tarjeta apenas se distinguían
     entre sí. Los nombres --rosa* vienen de la primera paleta; hoy son
     el acento, el verde azulado del logo. */
  --fondo:       #f4f4f1;   /* la página, y el relleno de los campos */
  --blanco:      #ffffff;   /* las tarjetas */
  --pista:       #ebebe7;   /* el riel de las pestañas y de la barra */
  --borde:       #e4e4df;
  --rosa:        #14a38b;   /* acento: interruptores, lo elegido, el foco */
  --rosa-oscuro: #0b7265;   /* el acento como letra */
  --rosa-claro:  #e2f3ef;   /* el acento lavado: fondo de lo elegido */
  --tinta:       #1c1f26;
  --gris:        #666c79;
  --gris-fuerte: #555b66;   /* letra secundaria encima de --pista */
  --negro:       #16181d;   /* el botón principal */
  --exito:       #1e7a4c;
  --peligro:     #b04545;
  /* Contrastes medidos, letra sobre fondo: --gris 5,27 sobre blanco y
     4,66 sobre el relleno de un campo; --rosa-oscuro 5,82 y 5,14. Los
     dos pasan el 4,5. --rosa da 3,16 sobre blanco: sirve para un
     interruptor o un filo, no para letra. */

  /* Una sola sombra, hacia abajo y casi invisible. Los nombres son los
     del sistema anterior (relieve, hundido): los usan decenas de reglas
     y cambiarlos aquí las cambia a todas. */
  --neu-oscuro:  rgba(22, 24, 29, .08);
  --neu-luz:     transparent;
  --relieve:       0 1px 2px rgba(22, 24, 29, .04), 0 8px 24px rgba(22, 24, 29, .05);
  --relieve-alto:  0 2px 6px rgba(22, 24, 29, .06), 0 18px 44px rgba(22, 24, 29, .10);
  --relieve-chico: 0 1px 2px rgba(22, 24, 29, .10), 0 0 0 1px rgba(22, 24, 29, .05);
  /* «Hundido» ya no hunde: es el filo de un campo o de un riel. */
  --hundido:       inset 0 0 0 1px var(--borde);
  --sombra:        var(--relieve);

  /* Sistema homogéneo: radios, movimiento y foco */
  --radio-s: 12px;
  --radio-m: 16px;
  --radio-l: 24px;
  --mov-rapido: 120ms cubic-bezier(.2, 0, 0, 1);
  --mov-suave:  240ms cubic-bezier(.2, 0, 0, 1);
  --anillo: 0 0 0 3px rgba(20, 163, 139, .45);

  /* Medidas de los controles. Antes cada botón y cada campo traía la
     suya -- medidos en un teléfono: siete alturas de botón, de 25 a 54
     px, y campos de 37 a 43 --, y en una misma fila no calzaban. Ahora
     un botón y un campo miden lo mismo, y nada que se toque baja de
     44 px, que es lo que pide Apple para un dedo. */
  --alto-control: 44px;
  /* Los botones de las filas de una tabla pueden ser más bajos con
     ratón; con el dedo no (ver el @media de abajo). */
  --alto-control-mini: 36px;
  /* 16 px y no menos: con 15,2 Safari del iPhone acercaba la página
     cada vez que se tocaba un campo, y había que alejarla a mano. */
  --letra-campo: 1rem;
}

@media (pointer: coarse) {
  :root { --alto-control-mini: 44px; }
}

* { margin: 0; padding: 0; box-sizing: border-box; }

body {
  /* Fuente del sistema: carga instantánea y sensación nativa.
     Poppins estaba QUINTA en esta pila, detrás de system-ui,
     -apple-system, Segoe UI y Roboto: no se aplicaba en ningún equipo.
     Pero el <link> sí se pedía, y una hoja de estilos de otro origen
     bloquea el primer pintado hasta resolver DNS, TCP y TLS. Se pagaba
     el viaje por cero bytes útiles, encima del minuto que tarda Render
     en despertar. */
  font-family: system-ui, -apple-system, 'Segoe UI', Roboto,
               sans-serif;
  background: var(--fondo);
  color: var(--tinta);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3 { letter-spacing: -0.02em; line-height: 1.25; }

/* Foco visible homogéneo para navegación con teclado */
:where(a, button, input, select, textarea, summary):focus-visible {
  outline: 2px solid var(--rosa-oscuro);
  outline-offset: 2px;
}

code {
  background: var(--fondo);
  padding: .12rem .5rem;
  border-radius: 999px;
  font-size: .86em;
  color: var(--gris-fuerte);
}

/* Un SVG sin ancho ni alto ocupa todo lo que le den: el icono del boton
   de importar se inflaba a 150px y dejaba el boton hecho un globo. Con
   una medida por defecto ligada al texto, cada icono nace del tamano de
   la letra que lo acompana; las reglas de abajo, mas especificas, siguen
   mandando donde hace falta otra cosa. */
.ico { width: 1.15em; height: 1.15em; flex: none; }

/* ===== Navegación =====
   Una fila: la marca, las secciones con su nombre escrito y, aparte, lo
   que saca del panel (ver el sitio, salir). Antes las secciones eran
   siete iconos sin nombre, que solo se explicaban al pasar el ratón por
   encima -- y en un teléfono no hay ratón. */
.nav-admin {
  position: sticky;
  top: 0;
  z-index: 40;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: .5rem 1rem;
  padding: .55rem clamp(.8rem, 3vw, 1.6rem);
  background: var(--fondo);
  border-bottom: 1px solid var(--borde);
}

.nav-marca {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  font-weight: 700;
  font-size: 1.02rem;
  letter-spacing: -.01em;
  color: var(--tinta);
  text-decoration: none;
  white-space: nowrap;
}
.nav-marca small { font-size: .82rem; font-weight: 500; color: var(--gris); }

.logo-admin { height: 30px; width: auto; }

/* El riel de las secciones. Si no caben -- un teléfono, una ventana
   angosta -- se desliza de lado en vez de apretarse o partirse en dos
   filas. */
.nav-enlaces {
  justify-self: center;
  display: flex;
  gap: 2px;
  max-width: 100%;
  padding: 4px;
  border-radius: 999px;
  background: var(--pista);
  overflow-x: auto;
  scrollbar-width: none;
  overscroll-behavior-x: contain;
}
.nav-enlaces::-webkit-scrollbar { display: none; }

.nav-enlaces a {
  position: relative;
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: .42rem;
  min-height: var(--alto-control);
  padding: 0 1rem;
  border-radius: 999px;
  font-size: .9rem;
  font-weight: 600;
  color: var(--gris-fuerte);
  text-decoration: none;
  white-space: nowrap;
  transition: background var(--mov-rapido), color var(--mov-rapido),
              box-shadow var(--mov-rapido), transform var(--mov-rapido);
}
.nav-enlaces a:hover { color: var(--tinta); }
.nav-enlaces a:active { transform: scale(.97); }
.nav-enlaces a.activo {
  background: var(--blanco);
  color: var(--tinta);
  box-shadow: var(--relieve-chico);
}
.nav-enlaces .nav-icono { display: grid; place-items: center; }
.nav-enlaces .ico { width: 18px; height: 18px; display: block; }

.badge {
  background: var(--rosa-oscuro);
  color: #fff;
  font-size: .72rem;
  font-weight: 700;
  border-radius: 999px;
  min-width: 1.25rem;
  padding: .06rem .4rem;
  line-height: 1.15rem;
  text-align: center;
}

/* Ver el sitio y salir: no son secciones del panel, sacan de él. */
.nav-acciones { display: flex; align-items: center; gap: .15rem; }

.nav-accion {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .4rem;
  min-width: var(--alto-control);
  min-height: var(--alto-control);
  padding: 0 .8rem;
  border-radius: 999px;
  font-size: .9rem;
  font-weight: 600;
  color: var(--gris-fuerte);
  text-decoration: none;
  transition: background var(--mov-rapido), color var(--mov-rapido),
              transform var(--mov-rapido);
}
.nav-accion .ico { width: 20px; height: 20px; display: block; }
.nav-accion:hover { background: var(--pista); color: var(--tinta); }
.nav-accion:active { transform: scale(.95); }
.nav-salir { color: var(--peligro); }
.nav-salir:hover { background: rgba(176, 69, 69, .1); color: var(--peligro); }

/* Angosto: la marca y las salidas arriba, el riel debajo a todo el
   ancho. Las salidas se quedan en icono: su nombre va en aria-label. */
@media (max-width: 1180px) {
  .nav-admin { grid-template-columns: minmax(0, 1fr) auto; }
  .nav-enlaces { grid-column: 1 / -1; grid-row: 2; justify-self: start; }
}
@media (max-width: 640px) {
  .nav-accion { padding: 0; }
  .nav-accion .nav-texto { display: none; }
  /* En el teléfono la barra son dos filas, 120 px: pegada arriba se
     quedaba con la sexta parte de la pantalla. Se va con la página. */
  .nav-admin { position: static; }
}

@media (prefers-reduced-motion: reduce) {
  .nav-enlaces a:active, .nav-accion:active { transform: none; }
}

/* ===== Contenido ===== */
.contenido-admin {
  max-width: 1160px;
  margin: 0 auto;
  padding: 1.6rem clamp(.8rem, 3vw, 1.6rem) 3rem;
}

.encabezado-pagina {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  margin-bottom: 1.3rem;
}

.encabezado-pagina h1 { font-size: 1.6rem; font-weight: 700; }

.vacio {
  background: var(--blanco);
  border-radius: var(--radio-l);
  box-shadow: var(--sombra);
  padding: 2.4rem 2rem;
  text-align: center;
  color: var(--gris);
}

/* ===== Botones =====
   Tres pesos y nada más: el negro es lo que se viene a hacer en esa
   pantalla (uno por pantalla, si se puede); el blanco, lo demás; el rojo,
   lo que borra. */
/* inline-flex y no inline-block: con un alto mínimo, el texto y el icono
   tienen que quedar centrados en vertical, y un inline-block los deja
   pegados arriba. */
.boton {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .45rem;
  min-height: var(--alto-control);
  border: none;
  cursor: pointer;
  font-family: inherit;
  font-size: .95rem;
  font-weight: 600;
  line-height: 1.2;
  text-align: center;
  color: #fff;
  background: var(--negro);
  padding: .55rem 1.25rem;
  border-radius: 999px;
  text-decoration: none;
  transition: background var(--mov-rapido), transform var(--mov-rapido),
              box-shadow var(--mov-rapido);
}

.boton:hover { background: #2c2f37; }

.boton:active {
  transform: scale(.97);
  transition-duration: 60ms;
}

.boton:disabled,
.boton[aria-disabled="true"] { opacity: .55; cursor: not-allowed; }

.boton-suave {
  background: var(--blanco);
  color: var(--tinta);
  box-shadow: var(--relieve-chico);
}
.boton-suave:hover { background: #f7f7f4; }

.boton-peligro {
  background: var(--blanco);
  color: var(--peligro);
  box-shadow: var(--relieve-chico);
}
.boton-peligro:hover { background: #fdf1f1; }

.boton-mini {
  min-height: var(--alto-control-mini);
  padding: .3rem .85rem;
  font-size: .85rem;
}
.boton-grande { min-height: 52px; padding: .8rem 2rem; font-size: 1rem; }

@media (prefers-reduced-motion: reduce) {
  .boton:active { transform: none; }
}

/* ===== Paneles ===== */
.panel {
  background: var(--blanco);
  border-radius: var(--radio-l);
  box-shadow: var(--sombra);
  padding: 1.5rem;
  margin-bottom: 1.1rem;
}

.panel h2 {
  display: flex;
  align-items: center;
  gap: .5rem;
  font-size: 1.12rem;
  font-weight: 700;
  margin-bottom: 1rem;
  color: var(--tinta);
}

@media (max-width: 640px) {
  .panel { padding: 1.15rem; border-radius: 20px; }
}

/* ===== Cabecera del evento (página de edición) ===== */
.cabecera-evento {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
}

.volver-mesas {
  display: inline-block;
  font-size: .82rem;
  color: var(--gris);
  text-decoration: none;
  margin-bottom: .3rem;
}

.volver-mesas:hover { color: var(--rosa-oscuro); }

.cabecera-info h1 {
  font-size: 1.5rem;
  font-weight: 700;
  line-height: 1.25;
}

.cabecera-meta {
  font-size: .88rem;
  color: var(--gris);
  margin-top: .2rem;
}

.cabecera-acciones {
  display: flex;
  align-items: center;
  gap: .45rem;
  flex-wrap: nowrap;   /* estado y acciones, en una sola linea */
}

/* En el teléfono no caben en una línea: el aviso «No cobra: falta …»
   mide más de 340 px sin partirse, y empujaba la cabecera entera a 525
   px sobre una pantalla de 375. Toda la página se podía arrastrar de
   lado. Aquí las etiquetas bajan de línea y el aviso se parte. */
@media (max-width: 640px) {
  .cabecera-acciones { flex-wrap: wrap; }
  /* El estado en su fila y, debajo, los dos botones a partes iguales.
     El corte de fila lo pone un elemento vacío de ancho completo entre
     unos y otros (por `order`): sin él, el primer botón se subía a la
     fila de la etiqueta y el segundo quedaba solo. */
  .cabecera-acciones::before { content: ''; flex-basis: 100%; order: 1; }
  .cabecera-acciones .boton { flex: 1 1 40%; order: 2; }
  .cabecera-acciones .etiqueta-sin-cobro {
    flex-basis: 100%;
    white-space: normal;
    border-radius: var(--radio-s);
    padding: .35rem .7rem;
  }
}

/* Los <form> no forman caja propia: sus botones se alinean junto al resto. */
.cabecera-acciones form { display: contents; }

/* Botón compacto: mismo lenguaje, menos peso visual. Se usa donde varios
   controles conviven en una fila, para que no se amontonen. */
.boton-compacto {
  min-height: var(--alto-control-mini);
  font-size: .85rem;
  padding: .42rem .95rem;
  white-space: nowrap;
}

/* El estado es información, no acción: pesa menos que los botones */
.cabecera-acciones .etiqueta {
  font-size: .72rem;
  padding: .12rem .6rem;
}

/* ===== Distribución en dos columnas ===== */
.distribucion-editar {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 1.2rem;
  align-items: start;
}

.columna-principal { min-width: 0; }

/* Compartir, resumen y recuerdos: tres tarjetas lado a lado en pantallas
   anchas, apiladas en el celular. */
.grupo-compartir {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 1.2rem;
  align-items: start;
}

.grupo-compartir[hidden] { display: none; }

.panel-lateral { margin-bottom: 0; }

.lateral-link {
  margin-bottom: .7rem;
  overflow-wrap: anywhere;
  font-size: .85rem;
}

.boton-bloque {
  display: flex;
  width: 100%;
  text-align: center;
}

.lateral-qr {
  display: grid;
  justify-items: center;
  gap: .6rem;
  margin: 1rem 0 .7rem;
}

.lateral-qr img {
  border: 1px solid var(--borde);
  border-radius: 10px;
  padding: 5px;
  background: #fff;
}

.lista-resumen {
  list-style: none;
}

.lista-resumen li {
  display: flex;
  justify-content: space-between;
  gap: .8rem;
  padding: .5rem 0;
  border-bottom: 1px solid var(--borde);
  font-size: .9rem;
}

.lista-resumen li:last-child { border-bottom: none; }
.lista-resumen span { color: var(--gris); }
.texto-exito { color: var(--exito); }

/* Estado secundario bajo el medio de pago: presente pero sin
   competir con el dato principal de la fila. */
.texto-flojo { color: inherit; opacity: .6; }
.texto-naranja { color: #9a6b1f; }

/* ===== Tarjetas de resumen (contabilidad) ===== */
.tarjetas-resumen {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: .9rem;
  margin-bottom: 1.2rem;
}

.tarjeta-resumen {
  background: var(--blanco);
  border-radius: 14px;
  box-shadow: var(--sombra);
  padding: 1rem 1.2rem;
}

.tarjeta-resumen span {
  font-size: .74rem;
  color: var(--gris);
  text-transform: uppercase;
  letter-spacing: .06em;
}

.tarjeta-resumen strong {
  display: block;
  font-size: 1.3rem;
  margin-top: .25rem;
  color: var(--tinta);
}

/* Lo que espera no puede ser letra chica gris: es la mitad del dinero
   de la mesa el primer día, y el único sitio desde el que se confirma. */
.por-confirmar {
  /* inline-flex con alto minimo: el enlace medía 22 px y se toca con el
     pulgar en un telefono. El borde de abajo se queda pegado al texto,
     no al area. */
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  margin-top: .1rem;
  font-size: .82rem;
  font-weight: 600;
  color: #8a5a12;
  text-decoration: underline;
  text-underline-offset: .25em;
}
.por-confirmar:hover { color: var(--tinta); }
.texto-espera { color: #8a5a12; }

/* La celda no lleva display: flex (dejaría de ser celda, ver
   .celda-acciones más abajo): los botones van en línea dentro de ella. */
.celda-acciones-fila { white-space: nowrap; }
.celda-acciones-fila > form,
.celda-acciones-fila > a {
  display: inline-flex;
  vertical-align: middle;
  margin: .15rem .3rem .15rem 0;
}

.form-asignar {
  display: flex;
  gap: .35rem;
  align-items: center;
  flex-wrap: wrap;
}

.form-asignar select {
  font-family: inherit;
  font-size: var(--letra-campo);
  min-height: var(--alto-control-mini);
  border: 1px solid var(--borde);
  border-radius: var(--radio-s);
  padding: .3rem .6rem;
  max-width: 220px;
}

.panel-publicacion {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  font-size: .92rem;
}

.acciones-publicacion { display: flex; gap: .6rem; flex-wrap: wrap; }

/* ===== Formularios ===== */
.formulario-admin { display: grid; gap: 1rem; }

.formulario-angosto {
  max-width: 520px;
  background: var(--blanco);
  border-radius: 14px;
  box-shadow: var(--sombra);
  padding: 1.5rem;
}

/* align-content: start -- una etiqueta es una grilla, y si la celda de
   al lado es más alta (trae una nota debajo), sus filas se estiraban
   para llenarla: el campo de la fecha medía 64 px al lado de uno de 44. */
.formulario-admin label {
  display: grid;
  gap: .35rem;
  align-content: start;
  font-size: .88rem;
  font-weight: 600;
  color: var(--gris-fuerte);
}

.formulario-admin small { font-weight: 300; color: var(--gris); }

.formulario-admin label { min-width: 0; }

/* :not([type="range"]) -- con cuatro :not() esta regla pesa más que
   `.control-encuadre input[type="range"]`, y el deslizador del encuadre
   cruzaba la tarjeta entera en vez de medir lo que la vista previa que
   mueve. */
.formulario-admin input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not(.slots-campo),
.formulario-admin select,
.formulario-admin textarea {
  width: 100%;
  min-width: 0;
}

/* :not(.slots-campo) -- el campo invisible de las casillas es un
   campo de verdad, pero no debe pintarse como uno: se le excluye aqui
   en vez de pelearle la especificidad desde .slots, que con cuatro
   :not([type]) no habria forma de ganar sin !important. */
.formulario-admin input:not([type="checkbox"]):not([type="radio"]):not([type="file"]):not([type="range"]):not(.slots-campo),
.formulario-admin select,
.formulario-admin textarea {
  font-family: inherit;
  font-size: var(--letra-campo);
  line-height: 1.3;
  min-height: var(--alto-control);
  color: var(--tinta);
  border: none;
  border-radius: 999px;
  padding: .6rem 1.05rem;
  background: var(--fondo);
  /* Sin `outline: none`. La regla global de foco usa :where(), que no
     aporta especificidad, así que cualquier `outline: none` escrito en
     un componente la gana -- y el foco desaparecía justo en medio del
     formulario, donde más se tabula. */
  /* Campo hundido en la superficie */
  box-shadow: var(--hundido);
  transition: box-shadow var(--mov-rapido);
}

.formulario-admin textarea { border-radius: 16px; }

.formulario-admin input[type="file"] {
  font-family: inherit;
  font-size: .88rem;
  color: var(--gris);
}
/* El botón de elegir archivo es del navegador: sin esto salía gris y
   cuadrado, el único control de la pantalla con otro dibujo. */
.contenido-admin input[type="file"]::file-selector-button {
  min-height: var(--alto-control-mini);
  margin-right: .7rem;
  padding: .35rem 1rem;
  border: 0;
  border-radius: 999px;
  background: var(--blanco);
  box-shadow: var(--relieve-chico);
  font-family: inherit;
  font-size: .88rem;
  font-weight: 600;
  color: var(--tinta);
  cursor: pointer;
}
.contenido-admin input[type="file"]::file-selector-button:hover { background: #f7f7f4; }

/* Los enlaces dentro del texto de una tarjeta, con el acento y no con
   el azul del navegador. Los que son botón o pieza llevan su clase. */
.panel a:not([class]) { color: var(--rosa-oscuro); text-underline-offset: 2px; }

.formulario-admin input:not(.slots-campo):focus,
.formulario-admin select:focus,
.formulario-admin textarea:focus {
  box-shadow: var(--hundido), var(--anillo);
}

.formulario-admin textarea { resize: vertical; }

.casilla {
  display: flex !important;
  align-items: center;
  gap: .6rem;
  margin-top: .8rem;
  color: var(--tinta) !important;
}

/* La casilla y el radio se dibujan aquí (más abajo, en «Casillas y
   radios»): los del sistema son distintos en cada navegador y ninguno
   se parece al resto del panel. */

/* Interruptor tipo switch (neumórfico, mismo lenguaje que las casillas) */
.interruptor {
  display: flex;
  align-items: center;
  gap: .8rem;
  cursor: pointer;
  color: var(--tinta);
  font-size: .95rem;
  user-select: none;
}
/* Dentro del formulario, `.formulario-admin label` (0,1,1) le ganaba a
   `.interruptor` (0,1,0) y lo volvía una grilla: el nombre quedaba debajo
   del interruptor y no al lado, y con la letra gris de las etiquetas. */
.formulario-admin .interruptor {
  display: flex;
  align-items: center;
  gap: .8rem;
  font-size: .95rem;
  font-weight: 600;
  color: var(--tinta);
}

/* Varias tarjetas del editor a la vez: las separa el espacio de la
   grilla del formulario, sin sumarle el margen de cada tarjeta. */
.formulario-admin > .panel { margin-bottom: 0; }

.interruptor input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

.interruptor-pista {
  flex-shrink: 0;
  width: 48px;
  height: 27px;
  border-radius: 999px;
  /* Apagado es gris y encendido es el acento. En el sistema anterior
     los dos eran casi el mismo gris y solo cambiaba la sombra: había que
     mirar a qué lado estaba la bolita para saber cuál era. */
  background: #d2d2cb;
  position: relative;
  transition: background var(--mov-suave, 240ms ease);
}

.interruptor-pista::after {
  content: '';
  position: absolute;
  top: 3px;
  left: 3px;
  width: 21px;
  height: 21px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 1px 3px rgba(22, 24, 29, .25);
  transition: transform var(--mov-suave, 240ms ease);
}

.interruptor input:checked + .interruptor-pista {
  background: var(--rosa);
}

.interruptor input:checked + .interruptor-pista::after {
  transform: translateX(21px);
}

.interruptor input:focus-visible + .interruptor-pista {
  box-shadow: var(--anillo);
}

.cuadricula-2 {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1rem;
}

.cuadricula-suelta { align-items: start; }

.nota { font-size: .82rem; color: var(--gris); margin-top: .5rem; }

/* Rótulo de un sub-bloque dentro de un módulo */
.subtitulo-modulo,
.grupo-color-titulo {
  margin: 1rem 0 0;
  font-size: .78rem;
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--gris);
}

/* ===== Bloque plegable (resumen + contenido) ===== */
.plegable {
  margin-top: .9rem;
  border-radius: var(--radio-m);
  background: var(--fondo);
}

.plegable > summary {
  display: flex;
  align-items: center;
  gap: .8rem;
  padding: .6rem 1rem;
  min-height: 52px;
  cursor: pointer;
  list-style: none;          /* fuera el triangulo del navegador */
  border-radius: var(--radio-m);
}

.plegable > summary::-webkit-details-marker { display: none; }

.plegable-titulo {
  font-size: .92rem;
  font-weight: 600;
  color: var(--tinta);
  white-space: nowrap;
}

/* El adorno elegido se ve sin abrir la lista. */
.plegable-valor { flex: 1; min-width: 0; }
.plegable-valor .separador { margin: 0; max-width: none; color: var(--rosa); }
.plegable-valor .separador-nada { text-align: right; }

.plegable-flecha {
  flex: none;
  width: 9px;
  height: 9px;
  border-right: 1.8px solid var(--gris);
  border-bottom: 1.8px solid var(--gris);
  transform: rotate(45deg) translate(-2px, -2px);
  transition: transform var(--mov-rapido);
}

.plegable[open] > summary .plegable-flecha {
  transform: rotate(-135deg) translate(-2px, -2px);
}

.plegable > summary:hover { background: var(--pista); }
.plegable > summary:focus-visible { box-shadow: var(--anillo); }

.plegable > .separadores { padding: 0 .9rem .9rem; margin-top: 0; }
/* Cuando lo plegado es una lista de opciones con nombre (los fondos
   animados), en la cabecera va el nombre de la elegida, a la derecha. */
.plegable-texto {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  text-align: right;
  font-size: .9rem;
  color: var(--gris-fuerte);
}
.plegable > .animaciones { padding: 0 .9rem; }
.plegable > .nota { margin: .6rem 0 0; padding: 0 1rem .9rem; }

/* ===== Selector del adorno bajo la fecha ===== */
.separadores {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: .5rem;
  margin-top: .5rem;
}

.separadores input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

.separador-muestra {
  display: block;
  padding: .8rem .9rem;
  border: 1px solid var(--borde);
  border-radius: 12px;
  background: var(--fondo);
  cursor: pointer;
  transition: border-color var(--mov-rapido), box-shadow var(--mov-rapido),
              transform var(--mov-rapido);
}

.separador-muestra:hover { border-color: var(--rosa); }

.separadores input:checked + .separador-muestra {
  border-color: var(--rosa);
  box-shadow: var(--anillo);
}

.separadores input:focus-visible + .separador-muestra {
  box-shadow: var(--anillo);
}

/* La muestra reusa las reglas de separadores.css; aqui solo se encoge
   para caber en la tarjeta del editor. */
.separadores .separador {
  margin: 0;
  max-width: none;
  gap: .5rem;
  color: var(--rosa);
  min-height: 30px;   /* todas las tarjetas miden igual, con simbolo o sin el */
}

.separador-nada {
  display: block;
  text-align: center;
  font-style: normal;
  font-size: .82rem;
  color: var(--gris);
}

/* Muestra de un set de destellos (en la lista y en el resumen) */
.muestra-destellos {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: .45rem;
  min-height: 30px;
  color: var(--rosa);
}

.muestra-destellos i { font-style: normal; font-size: 1.05rem; }

.muestra-destellos small {
  margin-left: .2rem;
  font-size: .74rem;
  color: var(--gris);
}

/* En el resumen solo van los simbolos, sin el nombre. */
.plegable-valor .muestra-destellos { justify-content: flex-end; }
.plegable-valor .muestra-destellos small { display: none; }

/* ===== Selector de marco de la foto ===== */
.marcos-opciones {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(124px, 1fr));
  gap: .6rem;
  margin: .4rem 0 1rem;
}

/* Rotulo de cada familia de marcos. */
.grupo-marco {
  margin-top: .8rem;
  font-size: .72rem;
  font-weight: 600;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--rosa-oscuro);
}

.marcos-opciones input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

.marco-tarjeta {
  display: block;
  padding: .9rem .6rem .5rem;
  border: 1px solid var(--borde);
  border-radius: 12px;
  background: var(--fondo);
  cursor: pointer;
  transition: border-color var(--mov-rapido), box-shadow var(--mov-rapido);
}

.marco-tarjeta:hover { border-color: var(--rosa); }

/* La respuesta va en el pointer-down, no al soltar. */
.marco-opcion:active .marco-tarjeta {
  transform: scale(.97);
  transition-duration: 60ms;
}

@media (prefers-reduced-motion: reduce) {
  .marco-opcion:active .marco-tarjeta { transform: none; }
}

.marcos-opciones input:checked + .marco-tarjeta,
.marcos-opciones input:focus-visible + .marco-tarjeta {
  border-color: var(--rosa);
  box-shadow: var(--anillo);
}

/* La miniatura lleva el marco de verdad sobre una foto simulada. */
.marco-mini {
  --aire-marco: 5px;
  display: block;
  aspect-ratio: 4 / 3;
  border-radius: 6px;
  /* Los adornos que asoman (anillos, globos, corazones) forman parte
     del marco: recortarlos en la muestra seria mentir. */
  overflow: visible;
}

.marco-mini .marco-mini-foto { border-radius: 4px; }

.marco-mini-foto {
  position: absolute;
  inset: 0;
  background: linear-gradient(135deg, #b9c6d8, #8ea3bd 55%, #6f849f);
}

.marco-tarjeta small {
  display: block;
  margin-top: .4rem;
  text-align: center;
  font-size: .74rem;
  color: var(--gris);
}

/* ===== Vista previa del fondo animado ===== */
.previa-fondo { margin-top: .4rem; }

.previa-fondo iframe {
  display: block;
  width: 100%;
  max-width: 520px;
  height: 190px;
  border: 1px solid var(--borde);
  border-radius: 14px;
  background: #eef1f5;
  /* El canvas es cuadrado y opaco: sin esto asoma por las esquinas. */
  overflow: hidden;
}

/* ===== Selectores de color propios ===== */
.colores-texto {
  display: flex;
  flex-wrap: wrap;
  gap: .55rem;
  margin-top: .7rem;
}

/* Ganan a las reglas generales de .formulario-admin label/input, que
   ponen los campos en columna y al 100% de ancho (y aplastaban la
   muestra de color hasta volverla un óvalo). */
.formulario-admin .color-campo {
  display: flex;
  align-items: center;
  gap: .55rem;
  padding: .5rem .85rem .5rem .55rem;
  border-radius: var(--radio-m);
  background: var(--blanco);
  box-shadow: var(--hundido);
  cursor: pointer;
  font-size: .88rem;
  font-weight: 600;
  line-height: 1.25;
  color: var(--tinta);
  transition: background var(--mov-rapido), box-shadow var(--mov-rapido);
}
.formulario-admin .color-campo:hover { background: var(--fondo); }
.formulario-admin .color-campo:has(input:focus-visible) { box-shadow: var(--anillo); }

.formulario-admin .color-campo small {
  display: block;
  font-size: .74rem;
  color: var(--gris);
}

/* La muestra es el color tal cual, plano: con el brillo y la sombra de
   antes (una esfera) un blanco se veía gris y dos tonos cercanos, el
   mismo. El filo de adentro la separa del fondo cuando es muy clara. El
   input del sistema va encima, invisible: es el campo de verdad, y lo
   que lo abre es selector_color.js. */
.formulario-admin .color-esfera {
  position: relative;
  width: 36px;
  min-width: 36px;
  height: 36px;
  border-radius: 50%;
  flex: none;
  background: var(--color, #888);
  box-shadow: inset 0 0 0 1px rgba(22, 24, 29, .16);
}

.formulario-admin .color-esfera input[type="color"] {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: none;
  opacity: 0;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
}

.formulario-admin .color-campo small { font-weight: 400; }

/* ===== Foto: vistas previas escritorio y móvil ===== */
.previas-foto {
  display: flex;
  gap: 1.6rem;
  align-items: flex-end;
  flex-wrap: wrap;
  margin-bottom: 1.1rem;
}

/* Con container-type el ancho ya no lo aporta el contenido, asi que la
   medida vive en el marco y la pantalla lo llena. */
.previa-marco { margin: 0; width: min(430px, 72vw); }
.previa-marco.marco-chico { width: 122px; }

.previa-marco figcaption {
  text-align: center;
  font-size: .8rem;
  color: var(--gris);
  margin-top: .45rem;
}

.previa-pantalla {
  position: relative;
  overflow: hidden;
  border: 1px solid var(--borde);
  background: linear-gradient(135deg, #eef1f7, #e2e7f0);
  box-shadow: var(--relieve-chico);
}

/* Simula la cabecera ancha del computador */
.previa-escritorio {
  --aire-marco: 9px;
  width: 100%;
  aspect-ratio: 2.2 / 1;
  border-radius: 10px 10px 12px 12px;
  border-top: 8px solid #e3d7d9;
}

/* Simula la pantalla de un celular */
.previa-movil {
  --aire-marco: 5px;
  width: 100%;
  aspect-ratio: 375 / 430;
  border-radius: 16px;
  border: 4px solid #e3d7d9;
}

.previa-pantalla img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center top;  /* mismo encuadre que la página real */
  display: block;
}

.previa-sin-foto {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  font-size: 1.7rem;
  opacity: .55;
}

.con-foto .previa-sin-foto { display: none; }

/* Mismo degradado inferior que la cabecera real, con el color de la paleta */
.previa-velo {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 42%;
  background: linear-gradient(to bottom, transparent, var(--pv-crema, #f7f1e8));
  pointer-events: none;
}

.cargar-foto { flex: 1; min-width: 240px; }

.control-encuadre { margin-bottom: 1rem; }

.control-encuadre input[type="range"] {
  width: min(430px, 100%);
  accent-color: var(--rosa);
  cursor: pointer;
  padding: 0;
  border: none;
  background: transparent;
}

/* ===== Paletas ===== */
.paletas {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(72px, 1fr));
  gap: .6rem;
}

.paleta-opcion {
  position: relative;
  display: flex !important;
  flex-direction: row !important;
  align-items: center;
  justify-content: center;
  gap: .55rem;
  border: none;
  border-radius: var(--radio-m);
  padding: .6rem .5rem;
  cursor: pointer;
  font-size: .85rem;
  color: var(--tinta) !important;
  background: var(--fondo);
  box-shadow: var(--relieve-chico);
  transition: box-shadow var(--mov-rapido), transform var(--mov-rapido);
}

.paleta-opcion:active { transform: scale(.98); }

/* La opción elegida se hunde en la superficie */
.paleta-opcion:has(input:checked) {
  box-shadow: var(--hundido), var(--anillo);
}

/* El radio queda oculto: las muestras son la interfaz; el nombre vive
   en el tooltip (title) y en aria-label */
.paleta-opcion input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

/* ===== Las fichas de opción del editor, todas iguales =====
   Son siete selectores -- marcos, paleta, tipografía, animación, emojis,
   estilo, fondo, destellos, separador -- y hasta aquí solo la paleta y
   las esferas de color enseñaban el foco. El resto no lo enseñaba de
   ninguna manera, o lo enseñaba con el mismo halo con el que marcan lo
   elegido, que es peor: no se distingue dónde estás de qué escogiste.

   Mismo aspecto tiene que ser mismo comportamiento, o la herramienta se
   siente descuidada aunque cada pieza suelta esté bien. */
.paleta-opcion:has(input:focus-visible),
.marco-opcion:has(input:focus-visible),
.fuente-opcion:has(input:focus-visible),
.separador-opcion:has(input:focus-visible) {
  outline: 2px solid var(--rosa-oscuro);
  outline-offset: 2px;
  border-radius: var(--radio-m);
}

/* El separador tenía el foco y lo elegido pintados igual. Ahora el
   contorno dice dónde estás y el borde dice qué escogiste. */
.separadores input:focus-visible + .separador-muestra { box-shadow: none; }

/* Hundirse al tocar, en el acto y en todas. Al separador le faltaba:
   era la única ficha del editor que no acusaba el toque. */
.separador-opcion {
  display: block;
  cursor: pointer;
  transition: transform var(--mov-rapido);
}
.separador-opcion:active { transform: scale(.98); }

@media (prefers-reduced-motion: reduce) {
  .separador-opcion:active { transform: none; }
}

.paleta-muestra { display: inline-flex; }

.paleta-muestra i {
  width: 21px;
  height: 21px;
  border-radius: 50%;
  border: 2px solid #fff;
  margin-left: -7px;
}

.paleta-muestra i:first-child { margin-left: 0; }

/* ===== Tipografías ===== */
.fuentes {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: .7rem;
}

.fuente-opcion {
  display: grid !important;
  grid-template-columns: auto 1fr;
  grid-template-rows: auto auto;
  column-gap: .6rem;
  align-items: center;
  border: none;
  border-radius: var(--radio-m);
  padding: .65rem .85rem;
  cursor: pointer;
  color: var(--tinta) !important;
  background: var(--blanco);
  box-shadow: var(--hundido);
  transition: box-shadow var(--mov-rapido), background var(--mov-rapido),
              transform var(--mov-rapido);
}

.fuente-opcion:hover { background: var(--fondo); }
.fuente-opcion:active { transform: scale(.99); }

/* La elegida: el acento lavado de fondo y su filo. Se distingue por
   tres cosas a la vez -- fondo, filo y el punto del radio --, no solo
   por el color. */
.fuente-opcion:has(input:checked) {
  background: var(--rosa-claro);
  box-shadow: inset 0 0 0 1.5px var(--rosa);
}

.fuente-opcion input { grid-row: span 2; }

.fuente-muestra {
  font-size: 1.35rem;
  line-height: 1.25;
  color: var(--tinta);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.fuente-nombre { font-size: .78rem; color: var(--gris); }

.fuente-apagada { opacity: .55; }

/* ===== Vista previa en vivo de los títulos ===== */
.previa-animacion {
  background: var(--pv-fondo, #fdf3f4);
  border: 1px dashed var(--borde);
  border-radius: 14px;
  min-height: 110px;
  display: grid;
  place-items: center;
  padding: 1.2rem 1rem;
  margin-bottom: 1.1rem;
  overflow: hidden;
  transition: background .3s ease;
}

.previa-texto {
  font-size: clamp(1.7rem, 4vw, 2.5rem);
  line-height: 1.25;
  text-align: center;
  color: var(--pv-color, #7c8798);
}

.previa-texto.pv-brillo,
.previa-texto.pv-latido {
  background: linear-gradient(110deg,
      var(--pv-color, #7c8798) 0%, var(--pv-color, #7c8798) 40%,
      var(--pv-brillo, #e9b7bd) 50%,
      var(--pv-color, #7c8798) 60%, var(--pv-color, #7c8798) 100%);
  background-size: 220% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}

.previa-texto.pv-brillo {
  animation: pv-barrido 4.5s linear infinite,
             pv-flotar 6s ease-in-out infinite;
}

.previa-texto.pv-latido {
  animation: pv-barrido 4.5s linear infinite,
             pv-latido 2.2s ease-in-out infinite;
}

.previa-texto .pv-letra {
  display: inline-block;
  animation: pv-ola 2.1s ease-in-out infinite;
}

@keyframes pv-barrido {
  0%   { background-position: 120% 0; }
  100% { background-position: -120% 0; }
}

@keyframes pv-flotar {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-6px); }
}

@keyframes pv-latido {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.05); }
}

@keyframes pv-ola {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-.35em); }
}

.animaciones {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
  gap: .7rem;
  margin-bottom: .5rem;
}

.animaciones .fuente-opcion {
  grid-template-rows: auto;
}

.animaciones .fuente-nombre { font-size: .88rem; color: var(--tinta); }

.cargar-fuente {
  display: grid;
  gap: .35rem;
  margin-top: 1rem;
  font-size: .88rem;
  font-weight: 500;
  color: var(--gris);
}

/* ===== Pegatinas ===== */
.lista-pegatinas {
  display: flex;
  gap: .9rem;
  flex-wrap: wrap;
  margin: 1rem 0;
}

.pegatina-item {
  position: relative;
  width: 78px;
  height: 78px;
  border: 1px solid var(--borde);
  border-radius: 10px;
  background:
    repeating-conic-gradient(#f3eef0 0% 25%, #ffffff 0% 50%) 0 0 / 16px 16px;
  display: grid;
  place-items: center;
  padding: 8px;
}

.pegatina-item img {
  max-width: 100%;
  max-height: 58px;
  object-fit: contain;
}

.pegatina-item form {
  position: absolute;
  top: -9px;
  right: -9px;
}

.subtitulo-editor {
  font-size: .92rem;
  font-weight: 500;
  color: var(--gris);
  margin: 1rem 0 .5rem;
}

/* El panel de pegatinas se ensancha más allá del contenedor central
   para aprovechar el espacio lateral de la pantalla */
#pegatinas {
  position: relative;
  left: 50%;
  transform: translateX(-50%);
  width: min(1500px, 96vw);
}

/* Escritorio a todo el ancho; el editor móvil debajo, centrado */
.editores-pegatinas {
  display: flex;
  flex-direction: column;
  gap: 1.6rem;
}

.editor-columna { width: 100%; }

.editor-columna-movil {
  align-self: center;
  width: auto;
  text-align: center;
}

.editor-columna h4 {
  font-size: .85rem;
  font-weight: 600;
  color: var(--gris);
  margin-bottom: .4rem;
}

.iframe-pegatinas {
  width: 100%;
  height: 660px;
  border: 1px solid var(--borde);
  border-radius: 12px;
  background: #fff;
}

/* El marco angosto hace que la página interior use su diseño móvil real */
.iframe-movil {
  width: 390px;
  max-width: 100%;
  height: 620px;
  border: 6px solid #e3d7d9;
  border-radius: 22px;
}

/* ===== Código QR ===== */
.zona-qr {
  display: flex;
  gap: 1.4rem;
  align-items: center;
  flex-wrap: wrap;
}

.imagen-qr {
  width: 180px;
  height: 180px;
  border: 1px solid var(--borde);
  border-radius: 12px;
  padding: 6px;
  background: #fff;
}

.qr-detalle { flex: 1; min-width: 240px; display: grid; gap: .6rem; justify-items: start; }
.qr-detalle p { font-size: .92rem; }

/* ===== Barra flotante de guardar =====
   Esta clase ya no coloca nada: la posicion la lleva .deslizar, que es
   quien conoce su tamanno. Aqui solo queda lo que usa el menu de
   secciones -- esconderlo por esta clase -- y el aire del final de
   pagina. Dejarle el `position` y el `transform` de antes era una trampa:
   .deslizar esta mas abajo en la hoja y solo pisaba una de las dos
   propiedades, asi que el control acababa medio fuera de la pantalla. */
.boton-guardar-flotante[hidden] { display: none; }

/* Deja aire al final para que el contenido no quede tapado por la barra */
.contenido-admin:has(.boton-guardar-flotante) { padding-bottom: 6rem; }

/* ===== Tablas ===== */
/* ===== Editor de lista de deseos ===== */
/* Las columnas de base -- nombre, valor y quitar -- son las de los ítems
   de una cotización. Sin ellas esa pantalla no tenía ninguna: solo las
   definían los dos modos de la lista de regalos, y cada ítem de una
   cotización salía apilado, el concepto, el valor y la ✕ en tres filas. */
.fila-deseo {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 150px var(--alto-control-mini);
  gap: .5rem;
  align-items: center;
  margin-bottom: .45rem;
}
@media (max-width: 640px) {
  .fila-deseo { grid-template-columns: minmax(0, 1fr) 96px var(--alto-control-mini); }
}

/* Cada modo usa sus columnas: con valores en la mesa de regalos, con
   detalle en la lista a eleccion. La otra no ocupa espacio. */
.modo-mesa .fila-deseo { grid-template-columns: minmax(0, 1fr) 130px var(--alto-control-mini); }
.modo-eleccion .fila-deseo { grid-template-columns: minmax(0, 1fr) 190px var(--alto-control-mini); }

.segmentos-regalos { margin-bottom: .8rem; }

.fila-encabezado {
  margin-bottom: .2rem;
  font-size: .76rem;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--gris);
}

.fila-deseo input { width: 100%; }

/* El ✕ de cada fila, redondo y del alto de un botón chico. En una
   columna de 30 px, con el alto nuevo de los botones, quedaba una
   cápsula parada. */
.fila-deseo .quitar-fila,
.fila-deseo .quitar-item {
  width: var(--alto-control-mini);
  height: var(--alto-control-mini);
  min-height: 0;
  padding: 0;
  border-radius: 50%;
}

.acciones-deseos {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  margin-top: .6rem;
}

.resumen-deseos {
  font-size: .88rem;
  color: var(--gris);
}

.resumen-deseos strong { color: var(--rosa-oscuro); }

.tabla-envoltura { overflow-x: auto; }

.tabla-datos {
  width: 100%;
  border-collapse: collapse;
  margin-bottom: .8rem;
}

.tabla-datos th {
  text-align: left;
  font-size: .8rem;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--gris);
  padding: .4rem .5rem;
  border-bottom: 1px solid var(--borde);
}

.tabla-datos td {
  padding: .55rem .5rem;
  border-bottom: 1px solid var(--borde);
  font-size: .9rem;
}

.tabla-datos em { color: var(--gris); font-size: .8rem; }
.tabla-datos .celda-mensaje { max-width: 260px; font-size: .84rem; color: var(--gris); }

/* ===== Tarjetas de evento ===== */
.tarjetas-evento {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 320px), 1fr));
  gap: 1.1rem;
}

.tarjeta-evento {
  display: flex;
  flex-direction: column;
  background: var(--blanco);
  border-radius: var(--radio-l);
  box-shadow: var(--sombra);
  padding: 1.3rem;
}

.tarjeta-cabecera {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: .6rem;
}

.tarjeta-cabecera h2 { font-size: 1.15rem; font-weight: 700; min-width: 0; overflow-wrap: anywhere; }
.tarjeta-estado { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: .3rem; flex: none; }

.tarjeta-meta { font-size: .88rem; color: var(--gris); margin-top: .15rem; }
.tarjeta-enlace { font-size: .88rem; margin-top: .45rem; }

/* Lo recaudado, como la cifra que es: el nombre chico y el número
   grande, que es lo que se viene a mirar a esta pantalla. */
.tarjeta-recaudo {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  margin: .95rem 0;
  padding: .75rem 1rem;
  border-radius: var(--radio-m);
  background: var(--fondo);
  font-size: .85rem;
  color: var(--gris);
}
.tarjeta-recaudo strong {
  font-size: 1.45rem;
  font-weight: 700;
  letter-spacing: -.02em;
  font-variant-numeric: tabular-nums;
  color: var(--tinta);
}

/* Las dos acciones de todos los días, grandes y a partes iguales; las
   tres de vez en cuando, debajo y más chicas. El margen automático las
   deja abajo aunque una tarjeta vecina sea más alta. */
.mesa-acciones {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: .5rem;
  margin-top: auto;
}
.mesa-secundarias {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: .5rem;
  margin-top: .5rem;
}
.mesa-secundarias form { display: contents; }
/* Borrar la mesa va al final, a todo el ancho y sin caja: está, pero no
   compite con lo que se usa todos los días ni queda al lado de «Editar». */
.mesa-secundarias .mesa-eliminar {
  grid-column: 1 / -1;
  background: transparent;
  box-shadow: none;
}
.mesa-secundarias .mesa-eliminar:hover { background: #fdf1f1; }

.tarjeta-acciones {
  display: flex;
  gap: .5rem;
  flex-wrap: wrap;
  align-items: center;
}

/* Los <form> no deben formar su propia caja: asi sus botones se alinean
   junto a los enlaces en vez de quedar apretados dentro. */
.tarjeta-acciones form { display: contents; }

/* Acciones solo con icono: el nombre vive en el globo y en aria-label. */
.boton-icono {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 40px;
  height: 40px;
  /* Sin esto el alto mínimo de .boton (44) lo estiraba en un óvalo. El
     círculo se queda en 40 y el área que se toca llega a 44 con el
     ::after de abajo. */
  min-height: 0;
  padding: 0;
  border-radius: 50%;
}

.boton-icono .ico { width: 20px; height: 20px; display: block; }

/* El area sensible llega a 44px sin agrandar el circulo. */
.boton-icono::after {
  content: '';
  position: absolute;
  inset: -2px;
  border-radius: 50%;
}

/* Globo con el nombre de la accion, encima del boton. */
.boton-icono::before {
  content: attr(data-tip);
  position: absolute;
  bottom: calc(100% + 8px);
  left: 50%;
  transform: translateX(-50%) translateY(4px);
  white-space: nowrap;
  font-size: .74rem;
  font-weight: 500;
  color: #fff;
  background: rgba(30, 40, 60, .92);
  padding: .25rem .55rem;
  border-radius: 7px;
  pointer-events: none;
  opacity: 0;
  transition: opacity var(--mov-suave), transform var(--mov-suave);
  z-index: 30;
}

.boton-icono:hover::before,
.boton-icono:focus-visible::before {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}

@media (prefers-reduced-motion: reduce) {
  .boton-icono::before { transition: opacity 1ms; }
}

/* ===== Selector de dos segmentos (mismo peso, mismo tamano) ===== */
.segmentos {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: .4rem;
  max-width: 420px;
  margin: 0 auto 1.1rem;   /* centrado en la pagina */
  padding: 4px;
  border-radius: 999px;
  background: var(--pista);
}

.segmento {
  border: none;
  background: transparent;
  font-family: inherit;
  font-size: .9rem;
  font-weight: 600;
  /* --gris-fuerte y no --gris: encima del riel, que es más oscuro que
     una tarjeta, --gris se queda corto del 4,5 que pide esta letra. */
  color: var(--gris-fuerte);
  padding: .55rem 1rem;
  min-height: var(--alto-control);
  border-radius: 999px;
  cursor: pointer;
  transition: color var(--mov-rapido), transform var(--mov-rapido),
              box-shadow var(--mov-rapido), background var(--mov-rapido);
}

.segmento:active { transform: scale(.97); }

.segmento.activo {
  background: var(--blanco);
  color: var(--tinta);
  box-shadow: var(--relieve-chico);
}

/* ===== Buscadores de la lista ===== */
.buscadores {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: .6rem;
  margin-bottom: .9rem;
}

.buscador {
  display: flex;
  align-items: center;
  gap: .5rem;
  min-height: var(--alto-control);
  padding: 0 .9rem;
  border-radius: 999px;
  background: var(--fondo);
  box-shadow: var(--hundido);
  color: var(--gris);
}

.buscador .ico { width: 17px; height: 17px; flex: none; }

.buscador input {
  flex: 1;
  min-width: 0;
  border: none;
  background: none;
  font-family: inherit;
  font-size: var(--letra-campo);
  line-height: 1.3;
  color: var(--tinta);
  padding: .68rem 0;
}

.buscador:focus-within { box-shadow: var(--hundido), var(--anillo); }

.sin-resultados { text-align: center; padding: .8rem 0 .2rem; }

/* En pantallas angostas los dos buscadores se apilan. */
@media (max-width: 560px) {
  .buscadores { grid-template-columns: 1fr; }
}

/* ===== Lista de usuarios =====
   Quien es va en una columna sola: el nombre arriba y su RUT debajo. Son
   el mismo dato mirado de dos maneras, y en pantalla angosta separarlos
   en dos columnas empujaba los botones fuera del panel. */
/* Las dos lineas se apilan con `display: block` en los hijos y no con
   una rejilla en la celda: un <td> con display distinto de table-cell
   deja de ser celda, el navegador le inventa una fila aparte y la tabla
   se parte en dos. */
.tabla-usuarios .celda-quien { line-height: 1.35; }
.quien-nombre {
  display: block;
  font-weight: 500;
  color: var(--tinta);
}

.tabla-usuarios .celda-rut {
  font-variant-numeric: tabular-nums;   /* los RUT quedan alineados */
  display: block;
  white-space: nowrap;
  font-size: .82rem;
  /* --gris se queda en 3.2:1 sobre la superficie y esta letra es chica;
     este tono da 5.03:1 y sigue leyendose como dato secundario. */
  color: #5a6478;
}

.tabla-usuarios .celda-lapiz { width: 56px; text-align: right; }

.tabla-usuarios .fila-bloqueada td { opacity: .55; }

.marca-bloqueado {
  display: inline-block;
  margin-left: .4rem;
  font-size: .7rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--peligro);
}

/* ===== Ventana de edicion ===== */
.dialogo {
  /* El reset (* { margin: 0 }) anula el margin:auto con que el navegador
     centra un <dialog>, asi que se lo devolvemos. */
  margin: auto;
  width: min(520px, calc(100vw - 2rem));
  max-height: calc(100dvh - 2rem);   /* nunca mas alto que la pantalla */
  overflow-y: auto;
  border: none;
  border-radius: var(--radio-l);
  background: var(--fondo);
  color: var(--tinta);
  box-shadow: 0 24px 60px -20px rgba(30, 40, 60, .45);
  padding: 1.4rem 1.4rem 1.2rem;
}

.dialogo::backdrop {
  background: rgba(26, 24, 30, .45);
  backdrop-filter: blur(3px);
}

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

.dialogo-cabecera h2 { font-size: 1.05rem; font-weight: 600; }

.dialogo-acciones { margin-top: 1.1rem; }
.dialogo-acciones .boton { width: 100%; }

/* Bloquear y eliminar viven separados del resto: son otras acciones, y
   las dos hacen dano. */
.dialogo-peligro {
  margin-top: 1.2rem;
  padding-top: 1rem;
  border-top: 1px solid var(--borde);
}

.dialogo-peligro .nota { margin: 0 0 .7rem; }

.acciones-peligro { display: flex; gap: .6rem; }
.acciones-peligro form { display: contents; }

/* ===== Etiquetas ===== */
.etiqueta {
  font-size: .78rem;
  font-weight: 600;
  border-radius: 999px;
  padding: .2rem .7rem;
  white-space: nowrap;
}

.etiqueta-publicado { background: #e3f5ea; color: var(--exito); }
.etiqueta-borrador  { background: var(--pista); color: var(--gris-fuerte); }
.etiqueta-pendiente { background: #fdf3e2; color: #9a6b1f; }
/* Una mesa que no puede recibir plata. Va antes que Publicada o
   Borrador porque es lo primero que hay que saber: el resto del
   editor no sirve de nada si el botón de regalar no funciona. */
.etiqueta-sin-cobro { background: #fdeaea; color: #8f2f2a; font-weight: 600; }
.etiqueta-bloqueado { background: #fdeaea; color: var(--peligro); }

/* ===== Acciones de usuarios ===== */
.celda-acciones { display: grid; gap: .45rem; justify-items: start; }

.restablecer summary {
  cursor: pointer;
  font-size: .82rem;
  color: var(--rosa-oscuro);
  user-select: none;
}

.form-restablecer {
  display: flex;
  gap: .4rem;
  margin-top: .45rem;
  flex-wrap: wrap;
}

.form-restablecer input {
  font-family: inherit;
  font-size: var(--letra-campo);
  min-height: var(--alto-control-mini);
  border: 1px solid var(--borde);
  border-radius: var(--radio-s);
  padding: .4rem .75rem;
  min-width: 190px;
}

.form-restablecer input:focus {
  border-color: var(--rosa);
  box-shadow: 0 0 0 3px rgba(232, 139, 149, .2);
}

/* ===== Solicitudes ===== */
.solicitud-cabecera {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: .8rem;
  flex-wrap: wrap;
}

.solicitud-cabecera h2 { font-size: 1.05rem; font-weight: 600; color: var(--tinta); }

.solicitud-datos { font-size: .88rem; color: var(--gris); margin: .3rem 0 .5rem; }
.solicitud-datos a { color: var(--rosa-oscuro); }

.solicitud-mensaje {
  background: var(--rosa-claro);
  border-radius: 10px;
  padding: .7rem 1rem;
  font-size: .92rem;
  margin-bottom: .8rem;
}

.solicitud-atendida { opacity: .72; }

/* ===== Mosaico de recuerdos (Masonry en vanilla) ===== */
.mosaico {
  position: relative;
  width: 100%;
}

.mosaico-item {
  position: absolute;
  top: 0;
  left: 0;
  display: block;
  border: none;
  background: none;
  padding: 0;
  cursor: pointer;
  will-change: transform;
}

/* Tras la entrada, los re-acomodos (resize) se animan con suavidad */
.mosaico-fluido .mosaico-item {
  transition:
    transform 420ms cubic-bezier(.22, 1, .36, 1),
    width 420ms cubic-bezier(.22, 1, .36, 1),
    height 420ms cubic-bezier(.22, 1, .36, 1);
}

/* La lámina interior maneja la entrada (desenfoque a foco) y el hover */
.mosaico-lamina {
  position: relative;
  display: block;
  width: 100%;
  height: 100%;
  border-radius: 12px;
  overflow: hidden;
  box-shadow: 0 10px 40px -10px rgba(60, 70, 95, .35);
  opacity: 0;
  transform: translateY(46px);
  filter: blur(10px);
  transition:
    opacity 750ms cubic-bezier(.22, 1, .36, 1),
    transform 750ms cubic-bezier(.22, 1, .36, 1),
    filter 750ms cubic-bezier(.22, 1, .36, 1),
    box-shadow 300ms cubic-bezier(.22, 1, .36, 1);
}

.mosaico-visible .mosaico-lamina {
  opacity: 1;
  transform: none;
  filter: blur(0);
}

.mosaico-item:hover .mosaico-lamina,
.mosaico-item:focus-visible .mosaico-lamina {
  transform: scale(.965);
  box-shadow: 0 18px 50px -12px rgba(60, 70, 95, .5);
}

.mosaico-img {
  position: absolute;
  inset: 0;
  display: block;
  background-size: cover;
  background-position: center;
  background-color: #dfe4ee;
}

.mosaico-autor {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: 1rem .7rem .45rem;
  font-size: .74rem;
  font-weight: 500;
  color: #fff;
  background: linear-gradient(to top, rgba(30, 35, 50, .72), transparent);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  text-align: left;
}

@media (prefers-reduced-motion: reduce) {
  .mosaico-lamina {
    opacity: 1;
    transform: none;
    filter: none;
  }
}

/* Visor de foto (lightbox) */
.visor-recuerdo {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: grid;
  place-items: center;
  padding: 1.4rem;
  background: rgba(40, 30, 35, .78);
  backdrop-filter: blur(6px);
  cursor: zoom-out;
}

.visor-recuerdo[hidden] { display: none; }

.visor-recuerdo img {
  max-width: min(92vw, 980px);
  max-height: 84vh;
  border-radius: 14px;
  box-shadow: 0 30px 80px rgba(0, 0, 0, .5);
}

/* Barra de acciones del visor: descargar y cerrar */
.visor-barra {
  position: absolute;
  top: 16px;
  right: 18px;
  display: flex;
  gap: .5rem;
  cursor: default;
}

.visor-boton {
  display: inline-flex;
  align-items: center;
  gap: .3rem;
  border: none;
  cursor: pointer;
  font-family: inherit;
  font-size: .88rem;
  font-weight: 500;
  color: #2c2530;
  text-decoration: none;
  background: rgba(255, 255, 255, .92);
  padding: .5rem 1rem;
  border-radius: 999px;
  box-shadow: 0 6px 18px rgba(0, 0, 0, .3);
  transition: transform var(--mov-rapido), background var(--mov-rapido);
}

.visor-boton:hover { background: #ffffff; }
.visor-boton:active { transform: scale(.95); }

/* Cabecera de galería con acciones */
.acciones-galeria,
.cabecera-galeria {
  display: flex;
  align-items: center;
  gap: .6rem;
  flex-wrap: wrap;
}

.cabecera-galeria {
  justify-content: space-between;
  margin-bottom: .6rem;
}

.cabecera-galeria h2 { margin-bottom: 0; }

/* Administración de recuerdos (grilla con eliminar) */
.grilla-recuerdos {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
  gap: .7rem;
  margin-top: .8rem;
}

.ficha-recuerdo {
  position: relative;
  aspect-ratio: 4 / 3;
  border-radius: 10px;
  overflow: hidden;
  background: #f3e7e9;
}

.ficha-recuerdo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.ficha-recuerdo form {
  position: absolute;
  top: 5px;
  right: 5px;
}

.ficha-recuerdo .autor {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: .5rem .5rem .3rem;
  font-size: .68rem;
  color: #fff;
  background: linear-gradient(to top, rgba(40, 30, 35, .75), transparent);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Versión compacta para la columna lateral del editor */
.grilla-lateral {
  grid-template-columns: repeat(3, 1fr);
  gap: .45rem;
  max-height: 340px;
  overflow-y: auto;
  padding-right: .2rem;
  margin-top: .2rem;
}

.grilla-lateral .ficha-recuerdo img { cursor: zoom-in; }

.detalle-recuerdos summary {
  cursor: pointer;
  font-size: .88rem;
  font-weight: 500;
  color: var(--rosa-oscuro);
  user-select: none;
}

/* ===== Avisos ===== */
.aviso {
  border-radius: var(--radio-m);
  padding: .8rem 1.2rem;
  margin-bottom: 1rem;
  font-size: .92rem;
  font-weight: 600;
}
/* El aviso con su color de fondo: antes era del mismo gris que la
   página y solo cambiaba la letra, y pasaba por un texto más. */
.aviso-exito { background: #e3f5ea; color: var(--exito); }
.aviso-error { background: #fdecec; color: #8f2f2a; }

/* El código de acceso en la tabla de usuarios, junto a su dado.

   El flex va en una caja dentro de la celda y no en la celda misma. Un
   <td> con display flex deja de comportarse como celda: no se estira
   hasta el alto de la fila, así que su borde de abajo -- la raya que
   separa un usuario del siguiente -- quedaba 16px más arriba que el de
   las celdas vecinas y la línea se veía partida en trozos. */
.celda-codigo { white-space: nowrap; }
.codigo-caja {
  display: flex;
  align-items: center;
  gap: .4rem;
}
.codigo-acceso {
  font-family: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
  font-size: .9rem;
  font-weight: 600;
  letter-spacing: .08em;
  color: var(--tinta);
}
.form-codigo-nuevo { display: contents; }

/* ===== Casillas de código (port de CodeSlots, de React Bits) =====
   Seis cajas y, encima, un campo transparente que se lleva todas las
   teclas: es lo que hace que el teclado numérico del teléfono, el pegar y
   el autocompletado funcionen sin reinventarlos.

   El relleno entra creciendo desde el centro mientras el dígito sube a su
   sitio; el cursor se desliza de una casilla a otra en vez de saltar; con
   el código equivocado se vacía en cascada de derecha a izquierda; y con
   el bueno, un barrido funde los seis rellenos en uno con el visto. */
.slots {
  position: relative;
  display: inline-block;
  --slot: 44px;
  --hueco: 8px;
  --radio: 12px;
  --retraso: 0ms;
}

/* Calificado con .slots: `.caja-login input` tiene dos partes en su
   selector y le ganaba, asi que el campo que debe ser invisible se
   pintaba como un campo normal encima de las casillas. Y por eso hay que
   apagarle aqui todo lo que aquella le pone. */
.slots .slots-campo {
  position: absolute;
  inset: 0;
  z-index: 4;
  width: 100%;
  height: 100%;
  min-height: 0;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: transparent;
  box-shadow: none;
  color: transparent;
  caret-color: transparent;
  font-size: 16px;          /* menos de 16 y el teléfono hace zoom al tocar */
  cursor: text;
  outline: none;
}
.slots .slots-campo:focus { box-shadow: none; }

.slots-fila {
  position: relative;
  display: inline-flex;
  gap: var(--hueco);
  cursor: text;
  -webkit-tap-highlight-color: transparent;
}

.slot {
  position: relative;
  width: var(--slot);
  height: calc(var(--slot) * 1.18);
  border-radius: var(--radio);
  background: var(--rosa-claro);
  overflow: hidden;
  user-select: none;
  transition: background-color 200ms ease, box-shadow 200ms ease;
}
.slot[data-activa] {
  background: color-mix(in srgb, var(--rosa) 12%, var(--rosa-claro));
  box-shadow: 0 0 0 2px var(--rosa);
}

/* El relleno: crece desde el centro cuando el dígito aterriza. */
.slot-relleno {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: var(--rosa);
  transform: scale(0);
  transform-origin: center;
  transition: transform 300ms cubic-bezier(.22, 1, .36, 1) var(--retraso),
              background-color 200ms ease;
}
.slot[data-lleno] .slot-relleno { transform: scale(1); }

/* El dígito sube 8px a la vez que el relleno crece. */
.slot-digito {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: grid;
  place-items: center;
  font-size: calc(var(--slot) * .5);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  line-height: 1;
  color: #fff;
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 300ms ease var(--retraso),
              transform 300ms cubic-bezier(.22, 1, .36, 1) var(--retraso);
}
.slot[data-lleno] .slot-digito { opacity: 1; transform: none; }

/* Una sola pieza que viaja, no una raya que se enciende en cada casilla. */
.slots-cursor {
  position: absolute;
  top: 25%;
  left: -.75px;
  z-index: 3;
  width: 1.5px;
  height: 50%;
  background: var(--rosa-oscuro);
  opacity: 0;
  transition: transform 220ms cubic-bezier(.22, 1, .36, 1);
  pointer-events: none;
}
.slots-cursor[data-ver] { opacity: 1; animation: slots-latido 1s steps(1) infinite; }
@keyframes slots-latido { 0%, 49.9% { opacity: 1; } 50%, 100% { opacity: 0; } }

/* Con el codigo malo: tinte de alarma mientras se vacia. */
.slots[data-estado="error"] .slot { background: color-mix(in srgb, var(--peligro) 18%, var(--rosa-claro)); }
.slots[data-estado="error"] .slot-relleno { background: var(--peligro); }

/* Con el bueno: un barrido funde los seis rellenos en uno. */
.slots-barrido {
  position: absolute;
  inset: 0;
  z-index: 5;
  display: grid;
  place-items: center;
  border-radius: var(--radio);
  background: var(--rosa);
  color: #fff;
  clip-path: inset(0 50% 0 50% round var(--radio));
  opacity: 0;
  pointer-events: none;
  transition: clip-path 300ms cubic-bezier(.22, 1, .36, 1), opacity 120ms ease;
}
.slots[data-estado="enviando"] .slots-barrido {
  clip-path: inset(0 0 0 0 round var(--radio));
  opacity: 1;
}
.slots-barrido svg {
  opacity: 0;
  transform: translateY(8px) scale(.85);
  transition: opacity 200ms ease 140ms,
              transform 300ms cubic-bezier(.22, 1, .36, 1) 140ms;
}
.slots[data-estado="enviando"] .slots-barrido svg { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  .slot-relleno, .slot-digito, .slots-cursor, .slots-barrido,
  .slots-barrido svg { transition: none; }
  .slots-cursor[data-ver] { animation: none; }
}

/* En pantallas estrechas seis casillas de 44 no caben con sus huecos. */
@media (max-width: 400px) {
  .slots { --slot: 40px; --hueco: 6px; }
}

/* ===== Las dos formas de escribir la clave =====
   Los clientes entran con 6 números y los administradores con contraseña
   larga, así que las dos pantallas llevan los dos campos y enseñan uno.
   Sin JavaScript las casillas no escriben nada, de modo que la página
   nace con el campo de siempre: si no hay JS, no cambia y se entra
   igual. */
/* Solo esconden; nunca imponen un display. Poner `display: block` al
   enseñar le quitaba la rejilla al selector y los dos segmentos se
   apilaban a la izquierda, debajo de la pastilla. */
html:not(.con-js) .solo-con-js { display: none; }
html.con-js .solo-sin-js { display: none; }
.con-js .clave-larga { display: none; }
.con-js.clave-larga-activa .clave-pin { display: none; }
.con-js.clave-larga-activa .clave-larga { display: grid; }
/* `hidden` manda sobre todo lo anterior: es lo que mueve el JavaScript,
   y sin esto una regla de display lo dejaría a la vista igualmente. */
[hidden] { display: none !important; }

.campo-clave { display: grid; gap: .45rem; }

/* En el login las casillas ocupan el ancho del campo, para que el RUT, el
   selector y la clave compartan el mismo borde. Sueltas y a la izquierda
   parecían pegadas ahí por descuido. */
.caja-login .clave-pin .slots { display: block; width: 100%; }
.caja-login .clave-pin .slots-fila { display: flex; width: 100%; }
.caja-login .clave-pin .slot { flex: 1; width: auto; }
/* .clave-pin no lleva display propio: se lo pone `.solo-con-js`, y una
   regla aqui, al venir despues y valer lo mismo, la dejaria a la vista
   justo cuando no hay JavaScript para hacerla funcionar. */
.clave-larga { display: grid; gap: .35rem; }
.campo-clave small { font-weight: 300; color: var(--gris); }

/* Un encabezado de campo que no es <label>: las casillas no son un solo
   control al que apuntar, así que el nombre accesible lo lleva el campo
   invisible y esto es únicamente lo que se lee. */
.etiqueta-suelta { font-size: .85rem; font-weight: 600; }

/* ===== El selector PIN / Contraseña =====
   Dos segmentos y una pastilla que se desliza entre ellos. Se desliza y
   no se enciende y se apaga, porque así se ve de dónde a dónde fue: el
   movimiento dice cuántas opciones hay y cuál está puesta, que es lo que
   un par de fondos cambiando de color no cuenta. */
.selector-clave {
  position: relative;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: .25rem;
  padding: .25rem;
  border-radius: 999px;
  background: var(--fondo);
  box-shadow: var(--hundido);
}

.selector-clave-pastilla {
  position: absolute;
  top: .25rem;
  bottom: .25rem;
  left: .25rem;
  width: calc(50% - .25rem);
  border-radius: 999px;
  background: var(--blanco);
  box-shadow: var(--relieve-chico);
  transition: transform 300ms cubic-bezier(.22, 1, .36, 1);
}
.clave-larga-activa .selector-clave-pastilla { transform: translateX(100%); }

.selector-clave-opcion {
  position: relative;
  z-index: 1;
  min-height: var(--alto-control);   /* se toca con el pulgar sin apuntar */
  padding: .4rem .8rem;
  border: 0;
  border-radius: 999px;
  background: none;
  font-family: inherit;
  font-size: .88rem;
  font-weight: 600;
  /* Medidos contra la superficie real, no a ojo: --gris se queda en 3.2
     y --rosa-oscuro en 3.3, por debajo del 4.5 que pide una letra de este
     tamaño. Cuál está puesta no lo dice solo el color, además: la
     pastilla en relieve lo marca igual. */
  color: #5a6478;        /* 5.03:1 */
  cursor: pointer;
  transition: color 200ms ease;
}
.selector-clave-opcion[aria-checked="true"] { color: #167066; }  /* 5.01:1 */
.selector-clave-opcion:focus-visible {
  outline: 2px solid var(--rosa);
  outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
  .selector-clave-pastilla { transition: none; }
}

/* Media clave no se manda. En vez de dejar que el servidor conteste
   «incorrecta» -- que haría pensar que está mal y no incompleta -- las
   casillas se niegan en el sitio. */
.slots[data-estado="falta"] .slot {
  background: color-mix(in srgb, var(--peligro) 18%, var(--rosa-claro));
}
.slots[data-estado="falta"] .slots-fila { animation: slots-niega 320ms ease; }
@keyframes slots-niega {
  0%, 100% { transform: translateX(0); }
  22% { transform: translateX(-5px); }
  55% { transform: translateX(4px); }
  80% { transform: translateX(-2px); }
}
@media (prefers-reduced-motion: reduce) {
  .slots[data-estado="falta"] .slots-fila { animation: none; }
}

.form-codigo { display: grid; justify-items: center; gap: 1rem; }
.nota-codigo { text-align: center; margin-top: 1rem; }
.login-alterno { text-align: center; margin-top: .6rem; font-size: .9rem; }
/* Un enlace suelto se toca como un botón: el relleno le da 44 px de alto
   sin cambiar cómo se ve. Con el texto pelado medía 19. */
.login-alterno a {
  color: var(--rosa-oscuro);
  display: inline-flex;
  align-items: center;
  min-height: var(--alto-control);
  padding: 0 .6rem;
}

/* ===== Login: una tarjeta blanca sobre la página, como el resto ===== */
.cuerpo-login {
  /* --neu-fondo es lo que rellena los campos de esta pantalla y de la de
     entrar con código. El nombre viene del sistema anterior. */
  --neu-fondo: var(--fondo);
  min-height: 100vh;
  display: grid;
  place-items: center;
  background: var(--fondo);
  padding: 1.5rem;
}

.caja-login {
  width: 100%;
  max-width: 400px;
  background: var(--blanco);
  border-radius: 28px;
  box-shadow: var(--relieve-alto);
  padding: 2.2rem 2rem;
  text-align: center;
}

.logo-login-completo {
  width: min(230px, 70%);
  height: auto;
  margin-bottom: .5rem;
}

.login-sub { font-size: .88rem; color: var(--gris); margin-bottom: 1.4rem; }

.caja-login form { display: grid; gap: .95rem; text-align: left; }

.caja-login label {
  display: grid;
  gap: .35rem;
  font-size: .88rem;
  font-weight: 600;
  color: var(--tinta);
}

.caja-login input {
  font-family: inherit;
  font-size: var(--letra-campo);
  line-height: 1.3;
  min-height: var(--alto-control);
  color: var(--tinta);
  border: none;
  border-radius: 999px;
  padding: .65rem 1.1rem;
  background: var(--neu-fondo);
  box-shadow: var(--hundido);
  transition: box-shadow var(--mov-rapido);
}

.caja-login input:focus { box-shadow: var(--hundido), var(--anillo); }

/* El autorrelleno de Chrome pinta el campo de celeste. Una sombra
   interior enorme lo tapa con el gris de los demás campos; el filo va
   primero en la lista para quedar encima de ella. */
.caja-login input:-webkit-autofill,
.caja-login input:-webkit-autofill:hover,
.caja-login input:-webkit-autofill:focus {
  -webkit-box-shadow: var(--hundido), inset 0 0 0 1000px var(--neu-fondo);
  -webkit-text-fill-color: var(--tinta);
  caret-color: var(--tinta);
  border-radius: 999px;
}

.cuerpo-login .boton { padding: .7rem 1.2rem; }

.volver-sitio {
  display: inline-flex;
  align-items: center;
  min-height: var(--alto-control);
  padding: 0 .6rem;
  margin-top: .7rem;
  font-size: .88rem;
  /* #5a6478 y no #7a8299: el gris de antes daba 3,2:1 sobre esta
     superficie, por debajo del 4,5 que pide una letra de este tamaño.
     Es el mismo gris que ya usa el selector de PIN y contraseña. */
  color: #5a6478;
  text-decoration: none;
}

.volver-sitio:hover { color: #1e9089; }

/* ===== Accesibilidad de movimiento y transparencia ===== */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
  }
}

@media (prefers-reduced-transparency: reduce) {
  .nav-admin {
    background: var(--blanco);
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }
}

/* ===== Responsivo ===== */
@media (max-width: 1020px) {
  .distribucion-editar { grid-template-columns: 1fr; }

  /* En pantallas chicas el panel de pegatinas vuelve al ancho normal */
  #pegatinas {
    position: static;
    left: auto;
    transform: none;
    width: auto;
  }
}

@media (max-width: 640px) {
  .cuadricula-2 { grid-template-columns: 1fr; }
  .nav-sesion { margin-left: 0; }
  .panel-publicacion { flex-direction: column; align-items: flex-start; }

  .cabecera-evento { flex-direction: column; align-items: stretch; }
  .cabecera-acciones { justify-content: flex-start; }

  .modo-mesa .fila-deseo { grid-template-columns: minmax(0, 1fr) 96px var(--alto-control-mini); }
  .modo-eleccion .fila-deseo { grid-template-columns: minmax(0, 1fr) 130px var(--alto-control-mini); }

  .previa-marco { width: min(430px, 100%); }

  .iframe-pegatinas { height: 480px; }
  .iframe-movil { width: 100%; max-width: 390px; }
}

/* ============================================================
   Menú de módulos del editor (rueda lateral) + botón ⋮
   ============================================================ */
.modulo[hidden] { display: none !important; }

/* Botón flotante (abajo) con 3 puntitos para reabrir el menú */
.boton-modulos {
  position: fixed;
  bottom: 1.2rem;
  right: 1.2rem;
  z-index: 210;   /* sobre el overlay del menú (200) para poder cerrarlo */
  display: grid;
  place-items: center;
  width: 54px;
  height: 54px;
  flex-shrink: 0;
  border: none;
  cursor: pointer;
  color: #fff;
  background: var(--negro);
  border-radius: 50%;
  box-shadow: var(--relieve-alto);
  transition: box-shadow var(--mov-rapido), transform var(--mov-rapido);
}
.boton-modulos span { font-size: 1.7rem; line-height: 1; font-weight: 700; }
.boton-modulos span[hidden] { display: none; }
.boton-modulos:hover { transform: translateY(-2px); }
.boton-modulos:active { transform: scale(.94); }
.boton-modulos[hidden] { display: none; }

/* Tooltip del botón (aparece arriba, para no salirse por abajo) */
.boton-modulos::before {
  content: attr(data-tip);
  position: absolute;
  bottom: calc(100% + 8px);
  left: 50%;
  transform: translateX(-50%) translateY(4px);
  white-space: nowrap;
  font-size: .74rem;
  font-weight: 500;
  color: #fff;
  background: rgba(30, 40, 60, .92);
  padding: .25rem .55rem;
  border-radius: 7px;
  pointer-events: none;
  opacity: 0;
  transition: opacity var(--mov-suave), transform var(--mov-suave);
}
@media (hover: hover) and (pointer: fine) {
  .boton-modulos:hover::before {
    opacity: 1;
    transform: translateX(-50%) translateY(0);
  }
}
/* Con el foco se ensenna siempre: ahi lo pide quien navega con teclado. */
.boton-modulos:focus-visible::before {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}

/* ===== Menú de secciones (port de StaggeredMenu, de React Bits) =====
   El original es de React + GSAP + Tailwind; aquí no hay nada de eso, así
   que el movimiento lo llevan transiciones de CSS y el JavaScript solo
   pone y quita una clase. Se gana además que una transición retoma desde
   donde está: abrir y cerrar a lo loco no deja el panel a medio camino,
   que es lo que pasaría con @keyframes.

   Lo que se conserva del original: las láminas de color que entran
   escalonadas por delante del panel, las etiquetas que suben rotadas
   desde abajo, y la numeración que aparece detrás de ellas.

   Lo que se cambia, y a propósito: los tiempos. El componente está hecho
   para un menú de cuatro entradas en una portada; aquí son trece, en una
   herramienta que se abre decenas de veces mientras editas. Con sus
   tiempos el panel se asentaba a los 830ms y la última entrada a los
   1250ms -- medido -- y el presupuesto de este proyecto para un cajón
   lateral es 200-500ms. Todo baja en la misma proporción, y el
   escalonado de las entradas se corta a la séptima. */
.menu-modulos {
  position: fixed;
  inset: 0;
  z-index: 200;
}
.menu-modulos[hidden] { display: none; }

/* El velo va en un pseudo-elemento y no en el contenedor: si se
   difuminara el contenedor entero, el panel se difuminaría con él. */
.menu-modulos::before {
  content: '';
  position: absolute;
  inset: 0;
  background: color-mix(in srgb, var(--neu-fondo, #e9ecf3) 72%, transparent);
  -webkit-backdrop-filter: blur(7px);
  backdrop-filter: blur(7px);
  opacity: 0;
  transition: opacity 260ms var(--sal-menu);
}
.menu-modulos.abierto::before { opacity: 1; }
.menu-modulos.cerrando::before { opacity: 0; transition-duration: 320ms; }

/* power4.out y power3.in de GSAP, que es lo que usa el componente. */
.menu-modulos {
  --sal-menu: cubic-bezier(.22, 1, .36, 1);
  --ent-menu: cubic-bezier(.55, 0, 1, .45);
  --ancho-menu: clamp(260px, 38vw, 420px);
}

.menu-capa,
.menu-panel {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  width: var(--ancho-menu);
  transform: translateX(100%);
  transition: transform 340ms var(--sal-menu);
  will-change: transform;
}

/* Las láminas: entran antes que el panel y se quedan detrás, que es de
   donde sale la sensación de profundidad del componente. */
.menu-capa { z-index: 1; }
.menu-capa-1 { background: color-mix(in srgb, var(--rosa) 30%, var(--fondo)); }
.menu-capa-2 { background: var(--rosa); }

.menu-panel {
  z-index: 2;
  background: var(--fondo);
  /* El panel y la página comparten color -- en este tema --blanco y
     --fondo son el mismo gris perla -- así que lo que lo despega no es el
     relleno sino el canto: una sombra que se come el borde y un filo
     claro encima. Sin esto el cajón se confunde con lo que hay detrás. */
  border-left: 1px solid var(--borde);
  box-shadow: -26px 0 44px -22px rgba(30, 40, 60, .38);
  display: flex;
  flex-direction: column;
  gap: 1rem;
  /* Abajo cabe el botón ✕, que flota encima del panel: sin este hueco se
     le sentaba encima a la línea de ayuda. */
  padding: 4.6rem 1.6rem 4.6rem;
  overflow-y: auto;
  overscroll-behavior: contain;
  transition-duration: 420ms;
}

.menu-modulos.abierto .menu-capa {
  transform: none;
  transition-delay: calc(var(--i) * 50ms);
}
.menu-modulos.abierto .menu-panel {
  transform: none;
  transition-delay: 110ms;
}

/* Al cerrar salen todas juntas y rápido: el original tarda 0,32s con una
   curva que arranca lenta y termina seca. Sin retardos, porque escalonar
   una salida solo hace esperar. */
.menu-modulos.cerrando .menu-capa,
.menu-modulos.cerrando .menu-panel {
  transform: translateX(100%);
  transition: transform 320ms var(--ent-menu);
  transition-delay: 0s;
}

.menu-modulos-titulo {
  margin: 0;
  font-size: 1.05rem;
  font-weight: 700;
  letter-spacing: .01em;
  color: var(--tinta);
}
.menu-modulos-ayuda {
  margin: auto 0 0;
  padding-top: 1.4rem;
  font-size: .82rem;
  color: var(--gris);
}

.menu-lista {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: .1rem;
}

/* El recorte es lo que hace el truco: la etiqueta empieza debajo de su
   propia fila y sube hasta su sitio, como si asomara. */
.menu-item {
  position: relative;
  overflow: hidden;
  margin-left: -.6rem;
  line-height: 1;
}

.menu-enlace {
  position: relative;
  display: block;
  width: 100%;
  border: 0;
  background: none;
  cursor: pointer;
  font-family: inherit;
  font-size: clamp(1.15rem, 4.6vw, 1.5rem);
  font-weight: 600;
  letter-spacing: -.02em;   /* texto grande: se aprieta */
  line-height: 1.5;
  color: var(--tinta);
  text-align: left;
  /* .45rem arriba y abajo: con .1rem cada fila medía 31 px de alto, y
     en el teléfono se tocaba la sección de al lado. Así llega a 44. El
     relleno de la izquierda le da aire al anillo del foco; lo compensa
     el margen negativo de la fila, para que el texto siga alineado con
     el título del grupo. */
  padding: .45rem 2.6rem .45rem .6rem;
  min-height: var(--alto-control);
  transition: color var(--mov-rapido);
}
.menu-enlace:hover,
.menu-enlace:focus-visible { color: var(--rosa-oscuro); }
/* El anillo va por dentro: la fila recorta lo que sobresale (es lo que
   hace el truco de la etiqueta que sube), y por fuera solo se veían las
   cuatro esquinas. */
.menu-enlace:focus-visible {
  outline: none;
  box-shadow: inset 0 0 0 2px var(--rosa);
  border-radius: 10px;
}

.menu-etiqueta {
  display: inline-block;
  transform: translateY(140%) rotate(10deg);
  transform-origin: 50% 100%;
  transition: transform 340ms var(--sal-menu);
  will-change: transform;
}
/* El escalonado se corta a la séptima: con trece secciones, seguir
   sumando dejaría la última llegando casi un segundo tarde. A partir de
   ahí entran juntas, que se lee como un grupo y no como una cola. */
.menu-modulos.abierto .menu-etiqueta {
  transform: none;
  transition-delay: calc(150ms + min(var(--i), 6) * 30ms);
}

/* La numeración, detrás de la etiqueta y un paso más tarde. */
.menu-enlace::after {
  content: attr(data-numero);
  position: absolute;
  /* El relleno de arriba más el .35em de siempre: el número queda a la
     misma altura de la etiqueta que antes de agrandar la fila. */
  top: calc(.45rem + .35em);
  right: .4rem;
  font-size: .78rem;
  font-weight: 400;
  letter-spacing: 0;
  color: var(--rosa-oscuro);
  opacity: 0;
  pointer-events: none;
  transition: opacity 400ms var(--sal-menu);
}
.menu-modulos.abierto .menu-enlace::after {
  opacity: .75;
  transition-delay: calc(210ms + min(var(--i), 6) * 26ms);
}

/* En el teléfono el cajón no tapa toda la pantalla: deja a la vista una
   franja de la página, que es lo que dice «esto se abrió encima, y lo de
   atrás sigue ahí». Antes la ocupaba entera, como el componente
   original, y el dueño lo pidió como en una pantalla mediana, donde
   llega a la mitad. En 375 px la mitad no alcanza para «Fotos de los
   invitados», así que es el 84 %. Tocar la franja lo cierra. */
@media (max-width: 720px) {
  .menu-modulos { --ancho-menu: min(84%, 340px); }
  .menu-modulos .menu-panel { padding-left: 1.3rem; padding-right: 1.1rem; }
}

/* Con movimiento reducido no se desliza nada: aparece y ya. El velo sí
   se funde, porque es lo que explica que hay algo encima. */
@media (prefers-reduced-motion: reduce) {
  .menu-capa,
  .menu-panel,
  .menu-etiqueta {
    transition: none;
    transform: none;
  }
  .menu-modulos.cerrando .menu-capa,
  .menu-modulos.cerrando .menu-panel { transform: translateX(100%); transition: none; }
  .menu-enlace::after { transition: none; opacity: .75; }
}

/* ===== El editor: el menú de secciones y lo que se edita =====
   El menú de arriba (el cajón portado de StaggeredMenu) sigue siendo el
   del teléfono. Aquí va lo que se le suma: los nombres de los grupos, la
   sección en la que estás, y la versión de pantalla ancha, donde deja de
   ser un cajón y pasa a ser una columna fija. */
.editor-contenido { min-width: 0; }

.menu-grupo {
  margin: 1rem 0 .1rem;
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .09em;
  line-height: 1.5;
  text-transform: uppercase;
  color: var(--gris);
}
.menu-lista > .menu-grupo:first-child { margin-top: 0; }

.menu-enlace.activo { color: var(--rosa-oscuro); }

/* En el teléfono: dice en qué sección estás y abre el menú. Va como
   botón y no como texto suelto porque es la forma de cambiar de sección
   que se ve sin buscarla; el redondo de abajo queda para el pulgar. */
.seccion-actual {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .8rem;
  width: 100%;
  min-height: var(--alto-control);
  margin: 0 0 .8rem;
  padding: 4px 4px 4px 1.1rem;
  border: 0;
  border-radius: 999px;
  background: var(--pista);
  font-family: inherit;
  font-size: .9rem;
  font-weight: 600;
  color: var(--tinta);
  text-align: left;
  cursor: pointer;
}
.seccion-actual[hidden] { display: none; }
.seccion-actual-texto { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.seccion-actual-cambiar {
  flex: none;
  display: inline-flex;
  align-items: center;
  min-height: 36px;
  padding: 0 .9rem;
  border-radius: 999px;
  background: var(--blanco);
  box-shadow: var(--relieve-chico);
  font-size: .84rem;
}

/* Pantalla ancha: dos columnas. Las reglas del cajón tienen hasta tres
   clases (.menu-modulos.cerrando .menu-panel), así que estas llevan
   .editor delante para pesar lo mismo o más, y van después en el
   archivo. El corte es el mismo que usa el JavaScript del editor. */
@media (min-width: 1181px) {
  .editor {
    display: grid;
    grid-template-columns: 250px minmax(0, 1fr);
    gap: 1.2rem;
    align-items: start;
  }

  /* La columna se ve siempre. De que no lleve `hidden` se encarga el
     JavaScript del editor (acomodar): contra la regla general
     [hidden] { display: none !important } no hay CSS que valga. */
  .editor .menu-modulos {
    display: block;
    position: sticky;
    inset: auto;
    top: 5.4rem;      /* debajo de la barra, que queda pegada arriba */
    z-index: 1;
  }
  .editor .menu-modulos::before,
  .editor .menu-modulos .menu-capa { display: none; }

  .editor .menu-modulos .menu-panel {
    position: static;
    width: auto;
    max-height: calc(100vh - 6.6rem);
    transform: none;
    transition: none;
    gap: 0;
    padding: 1.1rem .8rem;
    border: 0;
    border-radius: var(--radio-l);
    background: var(--blanco);
    box-shadow: var(--sombra);
  }
  .editor .menu-modulos-titulo,
  .editor .menu-modulos-ayuda { display: none; }

  .editor .menu-grupo { padding: 0 .75rem; }
  .editor .menu-item { overflow: visible; margin-left: 0; }

  .editor .menu-modulos .menu-enlace {
    min-height: 40px;
    padding: .5rem .75rem;
    border-radius: var(--radio-s);
    font-size: .95rem;
    font-weight: 500;
    letter-spacing: 0;
    line-height: 1.3;
    color: var(--tinta);
    transition: background var(--mov-rapido), color var(--mov-rapido);
  }
  .editor .menu-modulos .menu-enlace::after { content: none; }
  .editor .menu-modulos .menu-enlace:hover { background: var(--fondo); }
  .editor .menu-modulos .menu-enlace.activo {
    background: var(--rosa-claro);
    color: var(--rosa-oscuro);
    font-weight: 650;
  }
  /* La etiqueta sube rotada al abrirse el cajón; en la columna no hay
     apertura, así que está siempre en su sitio. */
  .editor .menu-modulos .menu-etiqueta { transform: none; transition: none; }

  .boton-modulos,
  .seccion-actual { display: none; }
}


/* ============================================================
   Tablas apilables: en pantallas chicas la tabla se convierte en
   tarjetas, con el nombre del dato al lado. Así nada se corta ni
   obliga a desplazar en horizontal.
   ============================================================ */
@media (max-width: 760px) {
  .tabla-apilable,
  .tabla-apilable tbody,
  .tabla-apilable tr,
  .tabla-apilable td {
    display: block;
    width: 100%;
  }

  .tabla-apilable thead { display: none; }  /* los rótulos van por fila */

  .tabla-apilable tr {
    background: var(--fondo);
    border-radius: var(--radio-m);
    box-shadow: var(--relieve-chico);
    padding: .5rem .9rem;
    margin-bottom: .9rem;
  }

  .tabla-apilable td {
    display: grid;
    grid-template-columns: minmax(84px, 34%) 1fr;
    align-items: start;
    gap: .7rem;
    padding: .5rem 0;
    border-bottom: 1px solid var(--borde);
  }
  .tabla-apilable tr td:last-child { border-bottom: none; }

  /* Rótulo del dato (reemplaza al encabezado de columna) */
  .tabla-apilable td::before {
    content: attr(data-label);
    font-size: .74rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .05em;
    color: var(--gris);
    padding-top: .15rem;
  }
  .tabla-apilable td:not([data-label]) { display: block; }

  /* Las celdas con controles ocupan el ancho completo (rótulo arriba):
     así los selects y botones tienen un objetivo táctil cómodo. */
  .tabla-apilable td:has(form) { display: block; }
  .tabla-apilable td:has(form)::before {
    display: block;
    margin-bottom: .4rem;
  }

  /* Los controles dentro de la tabla usan todo el ancho disponible */
  .tabla-apilable .form-asignar { flex-direction: column; align-items: stretch; }
  .tabla-apilable .form-asignar select { max-width: none; width: 100%; }
  .tabla-apilable .celda-acciones form,
  .tabla-apilable .restablecer { width: 100%; }
  .tabla-apilable .form-restablecer { flex-wrap: wrap; }
  .tabla-apilable .form-restablecer input { min-width: 0; flex: 1 1 100%; }
  .tabla-apilable .celda-mensaje { max-width: none; }
}

/* Aviso dentro de un módulo del editor: algo que ya pasó y hay que
   arreglar ahí mismo, no un error del formulario que se acaba de enviar. */
.nota-alerta {
  background: #fff4f4;
  border-left: 3px solid #d64545;
  border-radius: 8px;
  padding: .7rem .9rem;
  color: #7a2020;
}

.nota-alerta small {
  display: block;
  margin-top: .35rem;
  opacity: .75;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .72rem;
  word-break: break-word;
}

/* Acciones del encabezado del panel: importar queda a la izquierda de
   "Nueva mesa", como accion secundaria. */
.acciones-encabezado {
  display: flex;
  gap: .6rem;
  align-items: center;
  flex-wrap: wrap;
}

.acciones-encabezado form { margin: 0; }

/* Se ve solo con un lector de pantalla. Para quien navega con uno, un
   boton normal es mejor que un control de arrastre -- y de paso es la red
   si el JavaScript del deslizador no llega a cargarse. */
.solo-lectores {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
.solo-lectores:focus-visible {
  position: fixed;
  bottom: 5rem;
  left: 50%;
  transform: translateX(-50%);
  width: auto;
  height: auto;
  margin: 0;
  clip-path: none;
  z-index: 300;
}

/* ===== Deslizar para guardar (port de SlideCommit, de React Bits) =====
   La cápsula no es un tirador que se mueve: es una pieza que ocupa la
   pista entera, recortada con clip-path para que solo asome un trozo.
   Arrastrar mueve el recorte, y por eso al confirmar puede desplegarse
   hasta llenar la pista sin cambiar de elemento. El JavaScript solo
   escribe las variables; la forma la resuelve el CSS. */
.deslizar {
  /* La posicion va aqui y no en .boton-guardar-flotante: esa regla esta
     mas arriba en la hoja, asi que un `position: relative` puesto aqui la
     pisaba y el control se quedaba al final del documento en vez de
     flotando. Mismo `bottom` y mismo alto que el boton de secciones, que
     es lo que los deja a la misma altura. */
  position: fixed;
  bottom: 1.2rem;
  /* Se sujeta por los dos cantos en vez de centrarse: el hueco que queda
     es exactamente el que no ocupa el boton de secciones, y dentro de ese
     hueco se centra solo. Centrarlo en la ventana y restarle ancho no
     servia -- al centrar, solo la mitad de lo que restas protege el lado
     derecho, y por eso en el telefono se montaban. */
  left: 1.2rem;
  right: calc(1.2rem + 54px + .8rem);
  width: auto;
  max-width: 300px;
  margin: 0 auto;
  z-index: 210;
  height: 54px;

  --pad: 4px;
  --contenido: 0px;
  --aplaste-x: 1;
  --aplaste-y: 1;
  --origen: 0px;
  --dice: 1;
  --flecha: 1;
  --sacudida: 0px;
}

.deslizar-pista {
  position: relative;
  width: 100%;
  height: 100%;
  border-radius: 999px;
  background: var(--tinta);
  box-shadow: var(--relieve-chico);
  cursor: grab;
  touch-action: none;          /* el gesto es nuestro, no del scroll */
  user-select: none;
  -webkit-tap-highlight-color: transparent;
  overflow: hidden;
  transform: translateX(var(--sacudida));
}
.deslizar[data-sujeto] .deslizar-pista { cursor: grabbing; }
.deslizar[data-fase="esperando"] .deslizar-pista,
.deslizar[data-fase="hecho"] .deslizar-pista { cursor: default; }

/* Las dos frases van una encima de otra y se cruzan con un desenfoque:
   cambiar el texto de golpe se lee como un parpadeo. */
.deslizar-dice,
.deslizar-error {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  font-size: .92rem;
  font-weight: 500;
  white-space: nowrap;
  pointer-events: none;
  transition: opacity 200ms ease, filter 200ms ease;
}
.deslizar-dice { color: rgba(255, 255, 255, .55); opacity: var(--dice); }
.deslizar-error { color: #ffb4b4; opacity: 0; filter: blur(2px); }
.deslizar[data-fase="error"] .deslizar-dice { opacity: 0; filter: blur(2px); }
.deslizar[data-fase="error"] .deslizar-error { opacity: 1; filter: none; }

.deslizar-capsula {
  position: absolute;
  top: var(--pad);
  left: var(--pad);
  width: calc(100% - var(--pad) * 2);
  height: calc(100% - var(--pad) * 2);
  background: #fff;
  color: var(--tinta);
  outline: none;
  transform: scale(var(--aplaste-x), var(--aplaste-y));
  transform-origin: var(--origen) 50%;
  transition: background-color 200ms ease, color 200ms ease;
}
.deslizar[data-fase="hecho"] .deslizar-capsula { background: var(--exito); color: #fff; }
.deslizar[data-fase="error"] .deslizar-capsula { background: var(--peligro); color: #fff; }
.deslizar-capsula:focus-visible { box-shadow: inset 0 0 0 2px var(--tinta); }

/* Todo lo de dentro se corre junto, para quedar centrado en el trozo que
   se ve y no en la pieza entera. */
.deslizar-dentro {
  position: absolute;
  inset: 0;
  transform: translateX(var(--contenido));
}
.deslizar-dentro > span {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: .45rem;
  font-size: .92rem;
  font-weight: 600;
  white-space: nowrap;
  pointer-events: none;
  transition: filter 200ms ease;
}
.deslizar-flecha { opacity: var(--flecha); }
/* La opacidad de la flecha se calcula desde lo arrastrado, y al
   confirmar la capsula vuelve a casa mientras ensenna el visto: ese
   regreso la hacia reaparecer por debajo. Mientras se guarda y mientras
   se ensenna el resultado no pinta nada, asi que se apaga del todo.
   En error si vuelve, porque el tirador ya esta en su sitio y hay que
   poder intentarlo otra vez. */
.deslizar[data-fase="esperando"] .deslizar-flecha,
.deslizar[data-fase="hecho"] .deslizar-flecha { opacity: 0; }
.deslizar[data-fase="esperando"] .deslizar-flecha { filter: blur(2px); }

.deslizar-girando { opacity: 0; filter: blur(2px); }
.deslizar[data-fase="esperando"] .deslizar-girando { opacity: 1; filter: none; }
.deslizar-girando svg { animation: deslizar-gira 1s linear infinite; }
@keyframes deslizar-gira { to { transform: rotate(360deg); } }

.deslizar-hecho { opacity: 0; transform: scale(.95); transition: opacity 200ms ease, transform 200ms ease; }
/* Solo el visto, sin palabra: crece para no quedarse perdido en medio de
   una pastilla de 300px. */
.deslizar-hecho svg { width: 26px; height: 26px; }
.deslizar[data-fase="hecho"] .deslizar-hecho { opacity: 1; transform: none; }

/* Sin movimiento: nada gira ni se sacude, pero los estados se siguen
   viendo por color y texto, que es lo que hay que poder distinguir. */
@media (prefers-reduced-motion: reduce) {
  .deslizar-pista { transform: none; }
  .deslizar-girando svg { animation: deslizar-late 1.4s ease-in-out infinite; }
  @keyframes deslizar-late { 0%, 100% { opacity: 1; } 50% { opacity: .4; } }
}

/* ===== Selector de método de pago (port de GooeyNav, de React Bits) ===
   El efecto es un truco de filtros: las burbujas se difuminan y después
   se les sube el contraste al máximo, con lo que los bordes difusos se
   recortan otra vez y las que se tocan se funden en una sola mancha.
   Necesita fondo oscuro y mezcla `lighten` -- por eso la pista es
   oscura: sobre el gris perla del panel no hay contra qué recortar. */
/* ===== Selector de método de pago (port de RubberSegment, React Bits) =====
   Una pista con sus opciones y, encima, una capa idéntica en tinta oscura
   recortada con `clip-path` a los bordes del pulgar. Por eso la palabra
   cambia de color exactamente por donde pasa el borde, en vez de
   encenderse de golpe: las dos capas están siempre ahí, y lo único que se
   mueve es el recorte.

   Las dos rejillas tienen las mismas columnas y el mismo relleno, así que
   las etiquetas caen píxel a píxel en el mismo sitio. Si se separan, se
   ve doble.

   El movimiento va en JavaScript, con muelles: aquí no hay transiciones
   que puedan quedarse a medias. */
.seg-pago { margin: .2rem 0 1.1rem; }

.seg-pago-pista {
  --seg-dentro: 4px;
  --seg-radio: 999px;
  --seg-radio-pulgar: 999px;
  position: relative;
  display: grid;
  grid-template-columns: repeat(var(--seg-n, 3), minmax(0, 1fr));
  padding: var(--seg-dentro);
  border-radius: var(--seg-radio);
  /* El riel claro de todas las pestañas del panel, y la elegida en
     negro: es la decisión de la que depende que la mesa cobre, y tiene
     que verse desde lejos cuál está puesta. */
  background: var(--pista);
  /* pan-y: el dedo puede arrastrar el pulgar en horizontal sin que la
     página se vaya con él, y sigue pudiendo desplazar en vertical. */
  touch-action: pan-y;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
}
.seg-pago-pista:has(input:focus-visible) {
  box-shadow: var(--anillo);
}
.seg-pago[data-agarrado] .seg-pago-pista { cursor: grabbing; }

/* La opción y su eco en la capa del pulgar: la misma caja exacta.

   Calificados con .seg-pago: la opción es un <label> dentro de
   .formulario-admin, y `.formulario-admin label` tiene una clase y un
   elemento -- gana a una clase sola. Le imponía su cuerpo de letra a la
   fila de abajo y no a la de arriba, así que las dos capas dejaban de
   calzar y el texto se veía doble en los bordes. */
.seg-pago .seg-pago-opcion,
.seg-pago .seg-pago-eco {
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 0;
  min-height: 40px;
  margin: 0;
  padding: .55rem .4rem;
  border-radius: var(--seg-radio-pulgar);
  /* Tres nombres largos no caben a tamaño fijo en un panel angosto: antes
     se partían en dos filas y la pastilla se quedaba en la de arriba. */
  font-size: clamp(.72rem, 2.4vw, .84rem);   /* 11.5px de suelo */
  font-weight: 600;
  line-height: 1.2;
  white-space: nowrap;
}

.seg-pago .seg-pago-opcion {
  position: relative;
  z-index: 1;
  cursor: pointer;
  color: var(--gris-fuerte);
  transition: color 160ms ease, transform 160ms cubic-bezier(.22, 1, .36, 1);
}
.seg-pago .seg-pago-opcion:active { transform: scale(.96); }
.seg-pago .seg-pago-opcion input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;   /* el radio sigue ahí: teclado y formulario intactos */
}
.seg-pago .seg-pago-opcion span {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}
@media (hover: hover) and (pointer: fine) {
  .seg-pago .seg-pago-opcion:hover { color: var(--tinta); }
}

/* El pulgar. Nace recortado a nada y el JavaScript lo abre donde toca. */
.seg-pago-pulgar {
  position: absolute;
  inset: var(--seg-dentro);
  z-index: 2;
  display: grid;
  grid-template-columns: repeat(var(--seg-n, 3), minmax(0, 1fr));
  background: var(--negro);
  color: #fff;
  pointer-events: none;
  clip-path: inset(0 100% 0 0 round var(--seg-radio-pulgar));
}
.seg-pago[data-arrastrable] .seg-pago-pulgar { cursor: grab; }

/* El movimiento del pulgar lo lleva el JavaScript y ahí ya se apaga; aquí
   solo queda el hundido del toque. El cambio de color se queda: no mueve
   nada y dice cuál está puesta. */
@media (prefers-reduced-motion: reduce) {
  .seg-pago .seg-pago-opcion { transition: color 160ms ease; }
  .seg-pago .seg-pago-opcion:active { transform: none; }
}

/* Con el dedo hace falta un blanco al que se pueda acertar sin apuntar;
   con un ratón, no: 34px basta y el control no se infla en el formulario. */
@media (pointer: coarse) {
  .seg-pago .seg-pago-opcion, .seg-pago .seg-pago-eco { min-height: 44px; }
}

@media (max-width: 400px) {
  .seg-pago-pista { --seg-radio: 16px; --seg-radio-pulgar: 12px; }
  .seg-pago .seg-pago-opcion, .seg-pago .seg-pago-eco { padding: .55rem .25rem; }
}

/* El aviso de cada método, debajo del selector. */
.campos-metodo[hidden] { display: none; }
.campos-metodo { margin-top: .4rem; }

/* Los datos de la cuenta: en dos columnas donde quepan, porque son seis
   campos cortos y en una sola fila cada uno la seccion se hace larguisima. */
.rejilla-transferencia {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: .2rem 1rem;
  margin-top: .6rem;
}

.titulo-bloque {
  margin: 1.6rem 0 .2rem;
  font-size: 1rem;
  font-weight: 600;
  color: var(--tinta);
}

/* ===== Probar el cobro ===== */
.probar-cobro {
  display: flex;
  align-items: center;
  gap: .9rem;
  flex-wrap: wrap;
  margin: .2rem 0 .6rem;
}
.probar-cobro .boton { flex: none; }
.probar-cobro .nota { flex: 1 1 260px; margin: 0; }

.resultado-prueba {
  margin: 0 0 1rem;
  padding: .7rem .9rem;
  border-radius: var(--radio-m);
  font-size: .9rem;
  background: var(--fondo);
  box-shadow: var(--relieve-chico);
}
.resultado-prueba[hidden] { display: none; }
.prueba-esperando { color: var(--gris); }
.prueba-bien { color: var(--exito); }
/* Rojo pero no gritando: un token que no sirve es un dato, no un desastre. */
.prueba-mal { color: var(--peligro); }

/* ===== Importar un respaldo =====
   Subir un ZIP con fotos tarda, y hasta ahora la pagina se quedaba
   quieta sin decir nada: no se sabia si habia pasado algo. El propio
   boton informa -- lo que se pulso es lo que responde -- con una linea
   fina de progreso en el canto de abajo y el porcentaje en la etiqueta.

   La linea va aparte del texto y no le cambia el color de fondo: asi el
   contraste de la etiqueta es el mismo lleno o vacio. */
.boton-importar { position: relative; overflow: hidden; }
.boton-importar > .importar-cara {
  position: relative;          /* por encima de la linea */
  display: inline-flex;
  align-items: center;
  gap: .4rem;
}

.importar-relleno {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 3px;
  background: var(--rosa);
  transform: scaleX(0);
  transform-origin: left center;
  /* Lo justo para que no salte entre dos avisos de progreso, y no tanto
     como para ir por detras de la subida. */
  transition: transform 90ms linear;
  pointer-events: none;
}

/* Mientras trabaja se hunde, que es como este panel dice "ocupado". */
.boton-importar.importando {
  box-shadow: var(--hundido);
  /* Tinta y no gris: esto es el estado de lo que esta pasando, y en gris
     se queda en 3,24 de contraste, por debajo del minimo legible. */
  color: var(--tinta);
  cursor: progress;
}

/* El archivo ya llego entero, pero el servidor sigue descomprimiendo y
   guardando las fotos. La linea late en vez de quedarse llena y quieta,
   que seria decir que termino cuando no. */
.boton-importar.procesando .importar-relleno {
  animation: importar-latido 1.1s ease-in-out infinite;
}

@keyframes importar-latido {
  0%, 100% { opacity: 1; }
  50%      { opacity: .35; }
}

@media (prefers-reduced-motion: reduce) {
  .importar-relleno { transition: none; }
  .boton-importar.procesando .importar-relleno { animation: none; opacity: .6; }
}

.nota-respaldo {
  background: var(--fondo);
  border-radius: var(--radio-s);
  padding: .8rem 1rem;
}

/* El icono y el nombre del medio, separados por un espacio de verdad. */
.via-icono + .via-nombre { margin-left: .3rem; }

/* Como esta la subida de fotos, en el panel del cliente. Ya no es un
   mando: abrirla y cerrarla es del administrador. */
.estado-recuerdos {
  margin: .2rem 0 1rem;
  padding-bottom: .9rem;
  border-bottom: 1px solid var(--borde);
}
.estado-recuerdos strong { color: var(--tinta); font-weight: 600; }

/* El título de la sección y el botón de descargar, en la misma línea.
   En pantalla angosta el botón baja solo, sin apretar el título. */
.encabezado-recibidos {
  justify-content: space-between;
  margin-bottom: .8rem;
}
.encabezado-recibidos h2 { margin: 0; }

/* El estado, como etiqueta y no como más texto gris. Pegado al medio de
   pago se leía como una sola cadena larga; con su propio fondo es un
   objeto aparte que se reconoce sin leerlo. */
.estado-chip {
  display: inline-flex;
  align-items: center;
  padding: .1rem .5rem;
  border-radius: 999px;
  font-size: .76rem;
  font-weight: 600;
  line-height: 1.5;
  letter-spacing: .01em;   /* texto pequeño: se abre un poco */
  white-space: nowrap;
}
.estado-pagado {
  background: color-mix(in srgb, var(--exito) 13%, transparent);
  /* El verde de la marca se queda justo en 4,50 sobre el panel, que es el
     minimo exacto. A este cuerpo de letra conviene margen, no empate. */
  color: color-mix(in srgb, var(--exito) 88%, #000);
}
.estado-rechazado {
  background: color-mix(in srgb, var(--peligro) 12%, transparent);
  color: var(--peligro);
}
.estado-devuelto {
  background: color-mix(in srgb, var(--tinta) 9%, transparent);
  color: var(--tinta);
}
/* Por confirmar es el estado de espera, no un problema: gris, sin
   alarmar, pero en tinta y no en gris claro para que se lea. */
.estado-pendiente {
  background: color-mix(in srgb, var(--tinta) 8%, transparent);
  color: var(--tinta);
}

/* El boton de dar por recibida una transferencia. Verde porque lo que
   hace es sumar plata al total, y esa es la senal que el panel ya usa
   para lo cobrado. */
.boton-confirmar {
  background: var(--fondo);
  color: var(--exito);
  box-shadow: var(--relieve-chico);
  font-size: 1.05rem;
  font-weight: 700;
  line-height: 1;
}

/* Dos acciones en la misma celda: confirmar y borrar. La celda sigue
   siendo celda: con display: flex dejaba de estirarse al alto de la
   fila y su raya de abajo quedaba más arriba que la de las vecinas. Lo
   que se alinea son los formularios de adentro, uno al lado del otro. */
.celda-acciones {
  text-align: right;
  white-space: nowrap;
}
.celda-acciones form {
  display: inline-flex;
  vertical-align: middle;
  margin-left: .3rem;
}

/* ===== Regalos recibidos en el teléfono =====
   Una tabla de siete columnas no cabe en una pantalla angosta: se corta
   por el lado y las fechas se parten en tres líneas. En vez de encogerla
   hasta lo ilegible, cada pago pasa a ser una ficha.

   No lleva fondo ni sombra propios: va dentro de un panel que ya es
   blanco, y una tarjeta blanca sobre otra no se distingue -- solo
   añadiría relleno. Separa una línea fina, que es más barata en altura.

   Tres líneas, cada una con su par: quién / cuánto, qué / cuándo,
   cómo / acciones. Antes eran cuatro y la fecha ocupaba fila propia, así
   que se leían como un bloque en vez de como tres pares.

   Y lo que de verdad las amontonaba no era el espacio sino que todas
   pesaban igual: `.tabla-datos td` fija el cuerpo de letra y tiene más
   especificidad que un `.celda-*` suelto, así que ningún tamaño escrito
   en las celdas llegaba a aplicarse. Por eso aquí van calificadas con
   .tabla-pagos. El mensaje al final, y solo si escribió algo. */
@media (max-width: 720px) {
  .tabla-pagos,
  .tabla-pagos tbody,
  .tabla-pagos tr,
  .tabla-pagos td { display: block; }

  .tabla-pagos thead { display: none; }
  .tabla-envoltura { overflow-x: visible; }

  .tabla-pagos tr {
    display: grid;
    /* minmax(0,...) y no 1fr: una pista 1fr no baja de su contenido
       mínimo, y un nombre de regalo largo desbordaría la ficha. */
    /* Dos columnas y tres líneas, cada una con su par: quién/cuánto,
       qué/cuándo, cómo/acciones. La segunda columna se mide por la fecha,
       que es lo más ancho que va en ella. */
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas:
      "invitado monto"
      "regalo   fecha"
      "via      borrar"
      "mensaje  mensaje";
    align-items: baseline;
    column-gap: .6rem;
    /* Lo que faltaba era aire. Con las cuatro líneas pegadas, todas pesan
       lo mismo y la ficha se lee como un bloque; separadas, se leen como
       dos grupos -- quién y cuánto arriba, qué y cómo abajo. */
    row-gap: .2rem;
    padding: 1rem 0;
    border-top: 1px solid var(--borde);
  }

  .tabla-pagos tbody tr:first-child { border-top: 0; padding-top: .2rem; }

  .tabla-pagos td { border: 0; padding: 0; min-width: 0; overflow-wrap: anywhere; }

  /* El globo de ayuda del botón de borrar mide más que el botón y
     ensanchaba la ficha. En una pantalla táctil no hay puntero que lo
     haga aparecer, así que ahí no pinta nada; la etiqueta para lectores
     de pantalla sigue en su sitio. */
  .tabla-pagos [data-tip]::after,
  .tabla-pagos [data-tip]::before { display: none; }

  .tabla-pagos .celda-invitado { grid-area: invitado; }
  .tabla-pagos .celda-invitado strong { font-size: .97rem; }

  .tabla-pagos .celda-monto {
    grid-area: monto;
    text-align: right;
    font-weight: 700;
    font-size: 1.12rem;
    letter-spacing: -.02em;   /* la cifra crece: se aprieta más */
    white-space: nowrap;
  }

  .tabla-pagos .celda-regalo {
    grid-area: regalo;
    /* Es lo que regalaron: se lee, no se adivina. En gris claro competía
       de tú a tú con la fecha, que no importa ni la mitad. */
    color: var(--tinta);
    font-size: .88rem;
    line-height: 1.35;
  }

  /* Abarca las dos primeras columnas: si se quedara solo con la de la
     izquierda, el ancho que reserva la fecha la partiria en dos lineas
     por un par de pixeles. */
  /* El medio y el estado, en la misma línea pero con pesos distintos: el
     medio es un dato de paso y la etiqueta es el estado. Ya no hace falta
     el punto que los separaba -- los separa el fondo de la etiqueta. */
  /* El nombre del medio se va: la mesa cobra por uno solo, asi que
     repetirlo en cada fila es decir lo mismo trece veces. El icono lo
     recuerda, y el ancho que se libera es justo el que le faltaba a la
     etiqueta de estado para no caerse a otra linea. */
  .via-nombre {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;   /* sigue ahi para un lector de pantalla */
  }
  .via-icono { font-size: 1rem; }

  .tabla-pagos .celda-via {
    grid-area: via;
    display: flex;
    align-items: center;
    gap: .4rem;
    flex-wrap: wrap;
    font-size: .8rem;
    color: var(--gris);
    margin-top: .5rem;
    align-self: center;
  }

  .tabla-pagos .celda-fecha {
    grid-area: fecha;
    /* Ni gris claro: a este tamanno se queda en 3,24 de contraste y hay
       que pasar de 4,5. Es el dato mas flojo de la ficha, pero flojo no
       quiere decir ilegible. */
    color: color-mix(in srgb, var(--tinta) 88%, var(--fondo));
    font-size: .76rem;
    text-align: right;
    white-space: nowrap;   /* una fecha partida en dos no se lee */
    align-self: baseline;
  }

  .tabla-pagos .celda-mensaje {
    grid-area: mensaje;
    max-width: none;
    margin-top: .35rem;
    font-style: italic;
    font-size: .83rem;
    line-height: 1.35;
  }
  /* Sin mensaje no se deja una raya suelta ocupando sitio. */
  .tabla-pagos .celda-mensaje.sin-dato { display: none; }

  /* La papelera baja de peso: sigue teniendo el área de toque que
     necesita, pero sin sombra ni círculo compitiendo con el monto. */
  /* Las acciones no cuelgan del texto: tienen su columna, su aire y un
     área de toque que se puede acertar con el pulgar. */
  .tabla-pagos td:last-child,
  .tabla-pagos .celda-acciones {
    /* Aquí la fila ya no es fila de tabla, es una ficha en grilla, y la
       celda sí puede ser flex. */
    display: flex;
    grid-area: borrar;
    justify-self: end;
    align-self: center;
    gap: .5rem;
    margin-top: .5rem;
  }
  .tabla-pagos .celda-acciones form { display: contents; }
  /* 40 y no 32: esta regla, que tiene más peso que la de .celda-acciones,
     dejaba los tres botones de cada regalo en 32 px y a 8 de distancia,
     y el de confirmar una transferencia queda al lado del de borrarla.
     Con el ::after de .boton-icono, el área de toque llega a 44. */
  .tabla-pagos .celda-acciones .boton-icono,
  .tabla-pagos td:last-child .boton {
    width: 40px;
    height: 40px;
  }
  .tabla-pagos td:last-child .boton {
    background: none;
    box-shadow: none;
    margin: -.4rem 0;
  }
}

/* ===== Catálogo de diseños (editor) =====
   Cada tarjeta es una muestra en chico del diseño: su fondo, los nombres
   de la mesa en su letra y un botón con su color. Los valores llegan en
   variables --d-* desde la plantilla. */
.disenos {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 190px), 1fr));
  gap: .8rem;
  margin-bottom: .4rem;
}

.diseno {
  display: grid;
  align-content: start;
  gap: .12rem;
  padding: .5rem .5rem .75rem;
  border: 0;
  border-radius: var(--radio-m);
  background: var(--blanco);
  box-shadow: var(--hundido);
  font-family: inherit;
  text-align: left;
  color: var(--tinta);
  cursor: pointer;
  transition: background var(--mov-rapido), box-shadow var(--mov-rapido),
              transform var(--mov-rapido);
}
.diseno:hover { background: var(--fondo); }
.diseno:active { transform: scale(.98); }
/* El que está puesto, igual que una opción elegida: fondo, filo y además
   la palabra, que no depende del color. */
.diseno[aria-pressed="true"] {
  background: var(--rosa-claro);
  box-shadow: inset 0 0 0 1.5px var(--rosa);
}
.diseno[aria-pressed="true"] .diseno-detalle::after {
  content: ' · puesto';
  font-weight: 700;
  color: var(--rosa-oscuro);
}

.diseno-muestra {
  display: grid;
  place-items: center;
  align-content: center;
  gap: .5rem;
  min-height: 108px;
  margin-bottom: .45rem;
  padding: .7rem .5rem;
  overflow: hidden;
  border-radius: var(--radio-s);
  background: var(--d-crema);
}
.diseno-nombres {
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-family: var(--d-letra);
  font-size: 1.35rem;
  line-height: 1.25;
  color: var(--d-titulo);
}
.diseno-boton {
  padding: .22rem .95rem;
  border-radius: 999px;
  background: linear-gradient(135deg, var(--d-base), var(--d-fuerte));
  font-size: .72rem;
  font-weight: 600;
  color: #fff;
}
.diseno-nombre { padding: 0 .3rem; font-size: .92rem; font-weight: 650; }
.diseno-detalle { padding: 0 .3rem; font-size: .78rem; color: var(--gris); }

@media (prefers-reduced-motion: reduce) {
  .diseno:active { transform: none; }
}

/* ===== Formas y tamaños: el dibujo de cada opción =====
   Cuatro piezas vacías (<i>) que cada campo acomoda a su modo: una barra
   para los botones, un marco para las tarjetas, filas o cuadros para la
   lista. Así la opción se reconoce sin leer su nombre. */
.forma-muestra {
  display: grid;
  align-content: center;
  justify-content: start;
  gap: 4px;
  height: 36px;
  color: var(--gris-fuerte);
}
.forma-muestra i { display: none; background: currentColor; }

.forma-forma_botones i:first-child {
  display: block;
  width: 64px;
  height: 22px;
}
.forma-forma_botones.forma-pildora i:first-child { border-radius: 999px; }
.forma-forma_botones.forma-redondeado i:first-child { border-radius: 7px; }
.forma-forma_botones.forma-recto i:first-child { border-radius: 1px; }

.forma-forma_tarjetas i:first-child {
  display: block;
  width: 64px;
  height: 32px;
  background: none;
  box-shadow: inset 0 0 0 2px currentColor;
}
.forma-forma_tarjetas.forma-redondeada i:first-child { border-radius: 13px; }
.forma-forma_tarjetas.forma-suave i:first-child { border-radius: 6px; }
.forma-forma_tarjetas.forma-recta i:first-child { border-radius: 1px; }

/* «La del estilo»: un trazo punteado, que dice «lo que venga». */
.forma-forma_botones.forma-estilo i:first-child,
.forma-forma_tarjetas.forma-estilo i:first-child {
  background: none;
  box-shadow: none;
  border: 1.5px dashed currentColor;
  border-radius: 7px;
}

.forma-lista_diseno i { display: block; border-radius: 2px; }
.forma-lista_diseno.forma-estilo i { width: 64px; height: 8px; }
.forma-lista_diseno.forma-estilo i:last-child { display: none; }
.forma-lista_diseno.forma-cuadricula { grid-template-columns: 30px 30px; }
.forma-lista_diseno.forma-cuadricula i { width: 30px; height: 15px; }

.forma-tamano_texto::before {
  content: 'Aa';
  font-weight: 700;
  line-height: 1;
  color: var(--tinta);
}
.forma-tamano_texto.forma-estilo::before { font-size: 1.05rem; }
.forma-tamano_texto.forma-grande::before { font-size: 1.6rem; }

/* ============================================================
   Casillas y radios
   Dibujados aquí y no por el navegador. Siguen siendo el <input> de
   siempre -- teclado, formulario y lectores de pantalla intactos --, solo
   que sin su apariencia de fábrica. El filo gris da 3,3:1 contra el
   blanco, lo que pide un control para verse sin estar marcado.
   ============================================================ */
.casilla input[type="checkbox"],
.fuente-opcion input[type="radio"] {
  -webkit-appearance: none;
  appearance: none;
  flex: none;
  display: inline-grid;
  place-content: center;
  width: 22px;
  height: 22px;
  margin: 0;
  background: var(--blanco);
  box-shadow: inset 0 0 0 1.5px #8d8d86;
  cursor: pointer;
  transition: background var(--mov-rapido), box-shadow var(--mov-rapido);
}
.casilla input[type="checkbox"] { border-radius: 7px; }
.fuente-opcion input[type="radio"] { border-radius: 50%; }

/* El visto bueno: dos lados de un cuadrito girado. */
.casilla input[type="checkbox"]::after {
  content: '';
  width: 11px;
  height: 6px;
  margin-top: -2px;
  border-left: 2.4px solid #fff;
  border-bottom: 2.4px solid #fff;
  transform: rotate(-45deg) scale(0);
  transition: transform 220ms var(--muelle-rebote);
}
.fuente-opcion input[type="radio"]::after {
  content: '';
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: #fff;
  transform: scale(0);
  transition: transform 220ms var(--muelle-rebote);
}
.casilla input[type="checkbox"]:checked,
.fuente-opcion input[type="radio"]:checked {
  background: var(--rosa-oscuro);
  box-shadow: none;
}
.casilla input[type="checkbox"]:checked::after { transform: rotate(-45deg) scale(1); }
.fuente-opcion input[type="radio"]:checked::after { transform: scale(1); }
.fuente-opcion input[type="radio"]:disabled { opacity: .45; cursor: not-allowed; }

/* ============================================================
   Selector de color (selector_color.js)
   Una hoja junto a la muestra: los colores de la mesa, una rejilla para
   elegir de un toque y el código. En el teléfono sube desde abajo.
   ============================================================ */
.selector-color {
  position: absolute;
  z-index: 300;
  width: min(316px, calc(100vw - 16px));
  padding: .9rem;
  border-radius: 22px;
  background: var(--blanco);
  box-shadow: var(--relieve-alto), 0 0 0 1px rgba(22, 24, 29, .06);
}
.selector-color-velo {
  position: fixed;
  inset: 0;
  z-index: 299;
  background: rgba(22, 24, 29, .38);
}

.sc-cabecera {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .6rem;
  margin-bottom: .2rem;
  font-size: .95rem;
  font-weight: 700;
  color: var(--tinta);
}
.sc-cerrar {
  flex: none;
  width: 36px;
  height: 36px;
  border: 0;
  border-radius: 50%;
  background: var(--fondo);
  font-size: .9rem;
  color: var(--gris-fuerte);
  cursor: pointer;
}
.sc-cerrar:hover { background: var(--pista); color: var(--tinta); }

.sc-grupo {
  margin: .7rem 0 .4rem;
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--gris);
}
.sc-muestras {
  display: grid;
  grid-template-columns: repeat(8, minmax(0, 1fr));
  gap: 7px;
}
.sc-muestra {
  aspect-ratio: 1;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--c);
  box-shadow: inset 0 0 0 1px rgba(22, 24, 29, .16);
  cursor: pointer;
  transition: transform 220ms var(--muelle-rebote), box-shadow var(--mov-rapido);
}
.sc-muestra:hover { transform: scale(1.14); }
/* La elegida: un aro oscuro separado por uno blanco, que se ve igual
   sobre un color claro que sobre uno oscuro. */
.sc-muestra[aria-pressed="true"] {
  box-shadow: 0 0 0 2px var(--blanco), 0 0 0 4px var(--tinta);
}
.sc-muestra:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px var(--blanco), 0 0 0 4px var(--rosa);
}

.sc-pie {
  display: flex;
  align-items: center;
  gap: .5rem;
  margin-top: .9rem;
}
.sc-codigo {
  flex: 1;
  display: flex;
  align-items: center;
  gap: .5rem;
  min-width: 0;
  min-height: var(--alto-control);
  padding: 0 .8rem 0 .5rem;
  border-radius: 999px;
  background: var(--fondo);
  box-shadow: var(--hundido);
}
.sc-codigo:focus-within { box-shadow: var(--hundido), var(--anillo); }
.sc-actual {
  flex: none;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--c);
  box-shadow: inset 0 0 0 1px rgba(22, 24, 29, .16);
}
.sc-texto {
  flex: 1;
  min-width: 0;
  border: 0;
  background: none;
  font-family: ui-monospace, Consolas, monospace;
  font-size: var(--letra-campo);
  color: var(--tinta);
}
.sc-texto:focus { outline: none; }
.sc-mas { flex: none; min-height: var(--alto-control); }

/* En el teléfono: una hoja a todo el ancho, pegada abajo, con el hueco
   de la barra de inicio del iPhone descontado. */
@media (max-width: 640px) {
  .selector-color {
    position: fixed;
    inset: auto 0 0 0;
    width: auto;
    padding: 1rem 1rem calc(1rem + env(safe-area-inset-bottom));
    border-radius: 26px 26px 0 0;
  }
  .sc-muestras { gap: 9px; }
}
@media (min-width: 641px) {
  .selector-color-velo { display: none; }
}

/* ============================================================
   iPhone: los bordes de la pantalla
   Con viewport-fit=cover la página llega hasta los bordes, también
   detrás de la isla de arriba y de la barra de inicio de abajo. env()
   dice cuánto hay que correrse; en un equipo sin esos bordes vale cero.
   ============================================================ */
.nav-admin {
  padding-top: max(.55rem, env(safe-area-inset-top));
  padding-left: max(clamp(.8rem, 3vw, 1.6rem), env(safe-area-inset-left));
  padding-right: max(clamp(.8rem, 3vw, 1.6rem), env(safe-area-inset-right));
}
.contenido-admin {
  padding-left: max(clamp(.8rem, 3vw, 1.6rem), env(safe-area-inset-left));
  padding-right: max(clamp(.8rem, 3vw, 1.6rem), env(safe-area-inset-right));
  padding-bottom: calc(3rem + env(safe-area-inset-bottom));
}
/* Lo que va fijo abajo -- guardar y el redondo del menú -- sube lo que
   mida la barra de inicio: si no, el gesto de volver al inicio y el de
   deslizar para guardar caían en el mismo sitio. */
.contenido-admin:has(.boton-guardar-flotante) {
  padding-bottom: calc(6rem + env(safe-area-inset-bottom));
}
.boton-guardar-flotante { margin-bottom: env(safe-area-inset-bottom); }
.boton-modulos {
  bottom: calc(1.2rem + env(safe-area-inset-bottom));
  right: max(1.2rem, env(safe-area-inset-right));
}
.menu-modulos .menu-panel {
  padding-top: max(4.6rem, calc(1.6rem + env(safe-area-inset-top)));
  padding-bottom: calc(4.6rem + env(safe-area-inset-bottom));
}
.cuerpo-login {
  min-height: 100vh;
  min-height: 100dvh;   /* la altura que de verdad se ve, con la barra de Safari puesta */
  padding: max(1.5rem, env(safe-area-inset-top)) 1.5rem
           max(1.5rem, env(safe-area-inset-bottom));
}

/* ============================================================
   Movimiento
   Curvas de muelle y nada brusco: lo que aparece sube un poco mientras
   se aclara, lo que se aprieta cede y vuelve, lo elegido se desliza
   hasta su sitio. Todo dentro de «no-preference»: quien pidió menos
   movimiento en su equipo no ve ninguna de estas animaciones, y nada
   depende de ellas para funcionar.
   ============================================================ */
:root {
  /* La curva de las hojas de iOS: sale rápido y se asienta sin rebotar. */
  --muelle: cubic-bezier(.32, .72, 0, 1);
  /* Con un rebote corto, para piezas chicas: una bolita, un visto bueno. */
  --muelle-rebote: cubic-bezier(.34, 1.56, .64, 1);
}

@media (prefers-reduced-motion: no-preference) {
  /* Entre páginas del panel: fundido en vez de pantallazo blanco, y la
     pastilla de la sección actual se desliza de una a otra. Lo hace el
     navegador (View Transitions); el que no las tiene carga como siempre. */
  @view-transition { navigation: auto; }
  ::view-transition-old(root),
  ::view-transition-new(root) {
    animation-duration: 240ms;
    animation-timing-function: var(--muelle);
  }
  .nav-enlaces a.activo { view-transition-name: seccion-activa; }
  ::view-transition-group(seccion-activa) {
    animation-duration: 420ms;
    animation-timing-function: var(--muelle);
  }

  /* Lo que aparece. Va en las tarjetas y no en su contenedor: una
     animación con transform convierte al elemento en el marco de sus
     descendientes fijos, y el deslizador de guardar -- que vive dentro
     del contenedor -- saltaba de sitio mientras duraba. */
  @keyframes aparece {
    from { opacity: 0; transform: translateY(12px); }
  }
  .encabezado-pagina,
  .panel,
  .tarjeta-evento,
  .tarjeta-resumen,
  .vacio { animation: aparece 440ms var(--muelle) both; }
  /* Escalonadas: una detrás de otra, hasta la sexta. Más allá entran
     juntas, que se lee como un grupo y no como una cola. */
  .tarjeta-evento:nth-child(2), .panel:nth-of-type(2) { animation-delay: 45ms; }
  .tarjeta-evento:nth-child(3), .panel:nth-of-type(3) { animation-delay: 90ms; }
  .tarjeta-evento:nth-child(4), .panel:nth-of-type(4) { animation-delay: 135ms; }
  .tarjeta-evento:nth-child(5) { animation-delay: 180ms; }
  .tarjeta-evento:nth-child(n+6) { animation-delay: 225ms; }
  /* Las secciones del editor entran sin espera: se cambia de una a otra
     muchas veces seguidas. */
  .panel.modulo { animation-delay: 0ms; animation-duration: 360ms; }

  @keyframes aviso-baja {
    from { opacity: 0; transform: translateY(-10px) scale(.98); }
  }
  .aviso { animation: aviso-baja 460ms var(--muelle) both; }

  /* Lo que se aprieta: cede rápido y vuelve con un rebote corto. */
  .boton {
    transition: background var(--mov-rapido), box-shadow var(--mov-rapido),
                transform 340ms var(--muelle-rebote);
  }
  .boton:active { transform: scale(.96); transition-duration: 90ms; }

  @media (hover: hover) {
    .tarjeta-evento {
      transition: transform 340ms var(--muelle), box-shadow 340ms var(--muelle);
    }
    .tarjeta-evento:hover {
      transform: translateY(-3px);
      box-shadow: var(--relieve-alto);
    }
  }

  /* El interruptor de iOS: la bolita se alarga mientras está apretada. */
  .interruptor-pista { transition: background 260ms var(--muelle); }
  .interruptor-pista::after {
    transition: transform 380ms var(--muelle-rebote), width 220ms var(--muelle);
  }
  .interruptor:active .interruptor-pista::after { width: 27px; }
  .interruptor:active input:checked + .interruptor-pista::after {
    transform: translateX(15px);
  }

  /* Las opciones: la elegida da un pulso al quedar marcada. */
  @keyframes pulso-elegida { from { transform: scale(.97); } }
  .fuente-opcion:has(input:checked),
  .diseno[aria-pressed="true"] { animation: pulso-elegida 360ms var(--muelle-rebote); }

  /* Diálogos y la hoja de color: crecen desde donde nacen. */
  @keyframes hoja-aparece {
    from { opacity: 0; transform: translateY(8px) scale(.96); }
  }
  @keyframes hoja-sube { from { transform: translateY(100%); } }
  @keyframes velo-aparece { from { opacity: 0; } }
  dialog[open] { animation: hoja-aparece 340ms var(--muelle); }
  dialog::backdrop { animation: velo-aparece 260ms ease; }
  .selector-color { animation: hoja-aparece 280ms var(--muelle); transform-origin: top left; }
  .selector-color-velo { animation: velo-aparece 260ms ease; }
  @media (max-width: 640px) {
    .selector-color { animation: hoja-sube 420ms var(--muelle); }
  }
}

/* Las pestañas de dos opciones: la pastilla blanca es una sola pieza que
   se desliza, en vez de apagarse en un lado y encenderse en el otro. Va
   con :has(), y sin él -- un navegador antiguo -- quedan como estaban,
   cada opción con su propio fondo. */
@supports selector(:has(a)) {
  .segmentos { position: relative; isolation: isolate; }
  .segmentos::before {
    content: '';
    position: absolute;
    z-index: -1;
    top: 4px;
    bottom: 4px;
    left: 4px;
    width: calc(50% - 4px - .2rem);
    border-radius: 999px;
    background: var(--blanco);
    box-shadow: var(--relieve-chico);
    transition: transform 420ms var(--muelle);
  }
  .segmentos:has(.segmento:last-child.activo)::before {
    transform: translateX(calc(100% + .4rem));
  }
  .segmentos .segmento.activo { background: none; box-shadow: none; }
}

/* Los plegables se abren deslizando, donde el navegador sabe animar un
   <details> hasta su alto natural; en los demás abren de golpe. */
@supports (interpolate-size: allow-keywords) {
  @media (prefers-reduced-motion: no-preference) {
    .plegable { interpolate-size: allow-keywords; }
    .plegable::details-content {
      block-size: 0;
      overflow: clip;
      transition: block-size 380ms var(--muelle),
                  content-visibility 380ms allow-discrete;
    }
    .plegable[open]::details-content { block-size: auto; }
  }
}

@media (prefers-reduced-motion: reduce) {
  .segmentos::before { transition: none; }
  .casilla input[type="checkbox"]::after,
  .fuente-opcion input[type="radio"]::after,
  .sc-muestra { transition: none; }
}

/* ===== Música de la mesa (editor) ===== */
.musica-actual { display: grid; gap: .5rem; margin-bottom: .4rem; }
.musica-actual audio { width: 100%; max-width: 460px; }
.musica-actual .casilla { margin-top: .2rem; }
