/* Sistema visual del panel de administracion de Casa Lavalle.
 *
 * ORDEN DE CARGA OBLIGATORIO en el <head>:
 *   1. vendor/fullcalendar/skeleton.css
 *   2. vendor/fullcalendar/theme.css
 *   3. vendor/fullcalendar/palette.css
 *   4. este archivo
 * Y al final del <body>, en este orden: vendor/fullcalendar/global.js y luego
 * vendor/fullcalendar/theme.js. theme.js es el complemento del tema classic:
 * sin el no existe ni una clase .fc-classic-* en el DOM y los overrides de
 * mas abajo no pintan nada.
 *
 * El bloque de tokens esta duplicado respecto a publico/recursos/publico.css a
 * proposito. Los dos subdominios se despliegan a carpetas distintas dentro de
 * public_html y no comparten ninguna ruta. Si un token cambia, cambia en los
 * dos archivos.
 *
 * Todo literal hexadecimal vive en :root. pruebas/test-tokens.php lo comprueba.
 *
 * Sobre el movimiento: §7 dice que en una herramienta de uso diario la
 * animacion es latencia con otro nombre, y esa postura se mantiene. Lo que hay
 * aqui no decora, informa: la entrada del panel, la silueta de carga, el boton
 * que se sabe ocupado y el campo que dice donde esta el cursor. Nada entra ni
 * sale al cambiar de mes.
 */

:root {
  /* Paleta de marca (§7 del blueprint) */
  --azul-lavalle:    #09394C;
  --marfil:          #F7F4EF;
  --carbon:          #2C2C2C;
  --gris-piedra:     #A7A19A;
  --bronce-anzures:  #9C7A45;
  --blanco:          #FFFFFF;
  --rojo-alerta:     #8C2F26;
  --linea:           #E4DFD7;

  /* Derivados con alfa. --gris-piedra da 2.3:1 sobre marfil y nunca es texto:
     el texto secundario es carbon con opacidad, 8.5:1. */
  --carbon-70:  #2C2C2CB3;
  --carbon-50:  #2C2C2C80;
  --carbon-14:  #2C2C2C24;
  --carbon-08:  #2C2C2C14;
  --carbon-04:  #2C2C2C0A;
  --azul-30:    #09394C4D;
  --azul-08:    #09394C14;
  --azul-04:    #09394C0A;
  --bronce-30:  #9C7A454D;
  --bronce-17:  #9C7A452B;
  --bronce-08:  #9C7A4514;
  --rojo-30:    #8C2F264D;
  --rojo-08:    #8C2F2614;
  --linea-60:   #E4DFD799;
  --blanco-70:  #FFFFFFB3;
  --blanco-30:  #FFFFFF4D;
  --blanco-16:  #FFFFFF29;
  --blanco-08:  #FFFFFF14;

  /* Azul opaco al 92%. Es lo que hace que la barra superior sea vidrio y no
     pintura: con backdrop-filter detras, el marfil de la pagina se transparenta
     lo justo para que se note que hay contenido pasando debajo. Solido seria un
     bloque y transparente del todo dejaria el texto blanco sobre marfil. */
  --azul-92:    #09394CEB;

  /* Dos vecinos del azul de marca para degradados y estados. No son colores
     nuevos del sistema: son el mismo tono con la luminosidad movida, y existen
     como token porque un degradado escrito a mano en una regla seria un hex
     fuera de :root y lo prohibe pruebas/test-tokens.php. */
  --azul-hondo: #062836;
  --azul-alto:  #0C4C64;

  --fuente-ui:         "Inter Tight", -apple-system, BlinkMacSystemFont, "Segoe UI", Arial, sans-serif;
  --fuente-editorial:  "Newsreader", Georgia, serif;
  --fuente-mono:       ui-monospace, SFMono-Regular, Menlo, monospace;

  --e1: 4px;
  --e2: 8px;
  --e3: 12px;
  --e4: 16px;
  --e6: 24px;
  --e8: 32px;
  --e12: 48px;

  --radio: 4px;
  --radio-int: 2px;

  /* Profundidad. §7 reserva la sombra al panel y al desplegable, y esa regla se
     mantiene para lo que de verdad flota. --sombra-canto no es una sombra en el
     sentido de §7: son 2px que definen el canto de una superficie que ya tiene
     borde, y sin ella tarjeta, aviso y tabla pesan exactamente igual. */
  --sombra-canto:   0 1px 2px rgba(44, 44, 44, .05);
  --sombra-alzada:  0 2px 4px rgba(44, 44, 44, .06), 0 6px 16px rgba(44, 44, 44, .07);
  --sombra-panel:   0 2px 12px rgba(44, 44, 44, .10);
  --sombra-menu:    0 8px 28px rgba(44, 44, 44, .16);
  --sombra-elevada: 0 16px 40px rgba(44, 44, 44, .18);
  --sombra-barra:   0 1px 0 rgba(44, 44, 44, .04), 0 6px 20px rgba(44, 44, 44, .08);

  --anillo-foco:  0 0 0 3px var(--bronce-17);
  --anillo-error: 0 0 0 3px var(--rojo-08);

  /* ease-out-quart. Sin rebote y sin elastico: la casa no rebota. */
  --curva: cubic-bezier(.22, .78, .28, 1);
  --transicion:       120ms var(--curva);
  --transicion-media: 200ms var(--curva);
  --transicion-larga: 320ms var(--curva);

  /* Radio de pastilla. La escala del sistema sigue siendo 4px para superficies;
     esto es solo para lo que es un disco o una pildora por definicion: avatar,
     punto de estado, control segmentado. */
  --radio-pastilla: 999px;

  /* --- FullCalendar 7 classic, reasignado a la paleta de la casa --- */
  --fc-classic-button:               var(--blanco);
  --fc-classic-button-border:        var(--linea);
  /* Es el fondo del boton en hover, no el del boton activo. Marfil sobre
     blanco casi no se ve; el bronce al 8% es el mismo hover que .boton. */
  --fc-classic-button-strong:        var(--bronce-08);
  --fc-classic-button-strong-border: var(--bronce-anzures);
  --fc-classic-button-outline:       var(--bronce-anzures);
  --fc-classic-button-foreground:    var(--carbon);

  --fc-classic-primary:            var(--azul-lavalle);
  --fc-classic-primary-foreground: var(--blanco);

  --fc-classic-background-event: var(--gris-piedra);
  --fc-classic-highlight:        var(--bronce-17);
  --fc-classic-today:            var(--bronce-08);
  --fc-classic-now:              var(--bronce-anzures);
  --fc-classic-ring-color:       var(--bronce-anzures);

  --fc-classic-background: var(--blanco);
  --fc-classic-faint:      var(--marfil);
  --fc-classic-muted:      var(--carbon-08);
  --fc-classic-strong:     var(--carbon-14);

  --fc-classic-foreground:       var(--carbon);
  --fc-classic-faint-foreground: var(--carbon-50);
  --fc-classic-muted-foreground: var(--carbon-70);

  --fc-classic-border:        var(--linea);
  --fc-classic-strong-border: var(--gris-piedra);
}

/* ---------- Tipografias ---------- */

@font-face {
  font-family: "Inter Tight";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("fuentes/inter-tight-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Inter Tight";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("fuentes/inter-tight-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: "Newsreader";
  font-style: normal;
  font-weight: 200 800;
  font-display: swap;
  src: url("fuentes/newsreader-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Newsreader";
  font-style: normal;
  font-weight: 200 800;
  font-display: swap;
  src: url("fuentes/newsreader-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ---------- Base ---------- */

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

/* El atributo hidden gana sobre cualquier regla de display de esta hoja.
   Sin este !important, .aviso { display: flex } le gana a la regla [hidden]
   del navegador (una hoja de autor siempre vence a la del agente de usuario) y
   el aviso de error del calendario queda visible desde el primer pintado,
   pase lo que pase con la peticion. Es lo que hacia que la pagina publica
   dijera "Error al cargar la disponibilidad" con el calendario funcionando. */
[hidden] { display: none !important; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  /* 14px y no 16px: esto es una herramienta densa, no una pagina editorial. */
  font: 400 14px/1.5 var(--fuente-ui);
  color: var(--carbon);
  background: var(--marfil);
}

/* Escala con contraste real entre pasos: 28 / 17 / 14 / 12. Antes 24 y 16
   caian casi en la misma mancha que el cuerpo. */
h1 {
  margin: 0;
  font: 300 28px/1.15 var(--fuente-editorial);
  letter-spacing: -0.02em;
}

h2 {
  margin: 0 0 var(--e4);
  font: 500 17px/1.25 var(--fuente-ui);
  letter-spacing: -0.01em;
}

a {
  color: var(--azul-lavalle);
  text-decoration-color: var(--azul-30);
  text-underline-offset: 3px;
  transition: color var(--transicion), text-decoration-color var(--transicion);
}

a:hover {
  color: var(--bronce-anzures);
  text-decoration-color: var(--bronce-anzures);
}

/* El foco visible nunca se quita sin reemplazo: es la unica manera de operar
   esto con teclado. */
:focus-visible {
  outline: 2px solid var(--bronce-anzures);
  outline-offset: 2px;
}

.secundario { color: var(--carbon-70); }

/* Tercer escalon de la jerarquia. No se distingue del cuerpo por tamano, que
   ya esta en el minimo legible, sino por caja alta, tracking y color. */
.etiqueta {
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--carbon-70);
}

.solo-lectores {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ---------- Barra superior ---------- */

/* Primer elemento enfocable de cada pantalla. Fuera de la vista hasta que el
   tabulador lo alcanza, y entonces entra. Con la barra fija y una tabla de
   ochenta filas debajo, sin esto llegar al contenido cuesta cuatro tabuladores
   en cada pagina. Se mueve con transform y no con top: §7 prohibe animar una
   propiedad de maquetacion, y top lo es. */
.salto-contenido {
  position: fixed;
  top: var(--e3);
  left: var(--e3);
  z-index: 60;
  padding: var(--e2) var(--e4);
  background: var(--blanco);
  color: var(--azul-lavalle);
  border: 1px solid var(--bronce-anzures);
  border-radius: var(--radio);
  box-shadow: var(--sombra-menu);
  font-weight: 500;
  text-decoration: none;
  transform: translateY(-300%);
  transition: transform var(--transicion-media);
}

.salto-contenido:focus { transform: translateY(0); }

/* La barra tiene tres zonas: marca, secciones y sesion empujada a la derecha.
   Es fija porque el calendario y la bitacora son mas largos que la pantalla y
   quedarse sin navegacion a mitad de un mes obliga a subir hasta arriba. */
.barra {
  position: sticky;
  top: 0;
  z-index: 30;
  display: flex;
  align-items: center;
  gap: var(--e6);
  min-height: 56px;
  padding: 0 var(--e4);
  background: var(--azul-lavalle);
  color: var(--blanco);
  transition: box-shadow var(--transicion-media);
}

/* El vidrio, solo donde el navegador lo sostiene. Sin @supports, un navegador
   sin backdrop-filter se queda con el azul al 92% y deja ver el contenido
   crudo por debajo: ilegible. Con la guarda, ese caso recibe el azul solido de
   arriba y no pierde nada mas que el efecto. */
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .barra {
    background: var(--azul-92);
    -webkit-backdrop-filter: blur(14px) saturate(140%);
    backdrop-filter: blur(14px) saturate(140%);
  }
}

/* La sombra aparece solo cuando hay algo desplazado debajo. Es informacion,
   no adorno: dice que la barra esta flotando sobre contenido, no apoyada en el
   principio de la pagina. La pone interfaz.js. */
.barra-desplazada { box-shadow: var(--sombra-barra); }

.barra a { text-decoration: none; }

.barra-marca {
  display: flex;
  align-items: center;
  flex: none;
  border-radius: var(--radio);
}

/* El logotipo es el SVG oficial, en azul sobre claro, y la barra es ese mismo
   azul: hasta ahora se estaba pintando invisible sobre su propio color. El
   filtro lo lleva a blanco puro, que es --blanco, sin tocar el trazo ni
   componerlo en fuente. No es un logotipo nuevo: es el mismo, en la unica
   variante que se puede leer sobre el color de la casa. */
.barra-logo {
  display: block;
  height: 24px;
  width: auto;
  filter: brightness(0) invert(1);
}

.barra-nav {
  display: flex;
  align-items: center;
  gap: var(--e1);
}

.barra-nav a {
  position: relative;
  display: inline-flex;
  align-items: center;
  height: 34px;
  padding: 0 var(--e3);
  border-radius: var(--radio);
  font-weight: 500;
  color: var(--blanco-70);
  transition: color var(--transicion), background-color var(--transicion);
}

.barra-nav a:hover {
  color: var(--blanco);
  background: var(--blanco-08);
}

/* La seccion activa ya se anunciaba con aria-current y no se veia. Ahora se
   dice dos veces: relleno para separarla del resto y filete de bronce, que es
   el unico acento de marca que entra en la barra. */
.barra-nav a[aria-current="page"] {
  color: var(--blanco);
  background: var(--blanco-16);
}

.barra-nav a[aria-current="page"]::after {
  content: "";
  position: absolute;
  left: var(--e3);
  right: var(--e3);
  bottom: 5px;
  height: 2px;
  border-radius: var(--radio-pastilla);
  background: var(--bronce-anzures);
}

/* Los dos enlaces que en escritorio viven dentro del menu de usuario. En
   pantalla chica no hay menu de usuario, asi que bajan a la navegacion.
   El selector lleva 'a' delante porque .barra-nav a ya declara display y con
   solo la clase le ganaba en especificidad: los dos enlaces se colaban en la
   barra de escritorio, duplicando lo que ya estaba en el menu. */
.barra-nav a.barra-nav-movil { display: none; }

.barra-hamburguesa {
  display: none;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  margin-left: auto;
  padding: 0;
  color: var(--blanco);
  background: transparent;
  border: 1px solid var(--blanco-16);
  border-radius: var(--radio);
  cursor: pointer;
  transition: background-color var(--transicion), border-color var(--transicion);
}

.barra-hamburguesa:hover {
  background: var(--blanco-08);
  border-color: var(--blanco-30);
}

/* El icono que se ve lo decide aria-expanded y no una clase aparte: el estado
   ya esta en el atributo que el lector de pantalla anuncia, y duplicarlo en una
   clase seria una segunda fuente de verdad que se puede desincronizar. */
.barra-hamburguesa .icono-cerrar { display: none; }
.barra-hamburguesa[aria-expanded="true"] .icono-menu { display: none; }
.barra-hamburguesa[aria-expanded="true"] .icono-cerrar { display: block; }

.barra-sesion {
  position: relative;
  display: flex;
  align-items: center;
  margin-left: auto;
  flex: none;
}

.barra-usuario {
  display: inline-flex;
  align-items: center;
  gap: var(--e2);
  height: 40px;
  padding: 0 var(--e2);
  color: var(--blanco);
  font: 500 13px/1 var(--fuente-ui);
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--radio-pastilla);
  cursor: pointer;
  transition: background-color var(--transicion), border-color var(--transicion);
}

.barra-usuario:hover {
  background: var(--blanco-08);
  border-color: var(--blanco-16);
}

.barra-usuario[aria-expanded="true"] {
  background: var(--blanco-16);
  border-color: var(--blanco-30);
}

.barra-nombre {
  max-width: 160px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.barra-usuario .icono-flecha {
  width: 16px;
  height: 16px;
  color: var(--blanco-70);
  transition: transform var(--transicion-media);
}

/* La flecha gira cuando el menu esta abierto. Es el mismo estado que ya dice
   aria-expanded, dicho para quien mira en vez de para quien escucha. */
.barra-usuario[aria-expanded="true"] .icono-flecha { transform: rotate(180deg); }

/* ---------- Avatar ---------- */

/* Tres tamanos y ni uno mas: 28 en la barra y en la tabla de equipo, 40 en la
   cabecera del menu, 96 en Mi cuenta. La foto se guarda a 256 px, asi que el
   mas grande sigue teniendo el doble de pixeles de los que pinta. */
.avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  overflow: hidden;
  border-radius: var(--radio-pastilla);
  background: var(--azul-alto);
  color: var(--blanco);
  font-weight: 500;
  line-height: 1;
  text-transform: uppercase;
  box-shadow: inset 0 0 0 1px var(--blanco-30);
}

.avatar-imagen {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.avatar-sm { width: 28px; height: 28px; font-size: 12px; }
.avatar-md { width: 40px; height: 40px; font-size: 15px; }
.avatar-xl { width: 96px; height: 96px; font-size: 34px; }

/* ---------- Menu de usuario ---------- */

.menu-usuario {
  position: absolute;
  top: calc(100% + var(--e2));
  right: 0;
  z-index: 40;
  min-width: 250px;
  padding: var(--e2);
  background: var(--blanco);
  color: var(--carbon);
  border: 1px solid var(--linea);
  border-radius: var(--radio);
  box-shadow: var(--sombra-menu);
  animation: menu-entra var(--transicion-media) var(--curva) both;
}

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

.menu-usuario-cabecera {
  display: flex;
  align-items: center;
  gap: var(--e3);
  padding: var(--e2) var(--e3) var(--e3);
  margin-bottom: var(--e2);
  border-bottom: 1px solid var(--linea);
}

.menu-usuario-datos {
  display: grid;
  min-width: 0;
}

.menu-usuario-nombre {
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.menu-usuario-correo {
  font-size: 12px;
  color: var(--carbon-70);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Con .barra delante porque .barra a le gana en especificidad a .menu-opcion y
   dejaria el texto blanco sobre blanco. */
.barra .menu-opcion {
  display: flex;
  align-items: center;
  gap: var(--e3);
  padding: var(--e2) var(--e3);
  border-radius: var(--radio);
  color: var(--carbon);
  font-weight: 500;
  transition: background-color var(--transicion), color var(--transicion);
}

.barra .menu-opcion:hover {
  background: var(--marfil);
  color: var(--azul-lavalle);
}

.barra .menu-opcion-salir:hover {
  background: var(--rojo-08);
  color: var(--rojo-alerta);
}

.menu-opcion .icono {
  width: 18px;
  height: 18px;
  flex: none;
  color: var(--carbon-50);
}

.menu-opcion:hover .icono { color: currentColor; }

/* ---------- Estructura ---------- */

/* .envoltura es la caja de contenido de cualquier pantalla y no impone
   columnas. Antes era la reticula de dos columnas del calendario, asi que
   Equipo y Bitacora no la podian usar y llevaban su propio ancho maximo por
   separado. Ahora la reticula es un modificador y el ancho otro. */
.envoltura {
  width: 100%;
  margin: 0 auto;
  padding: var(--e6) var(--e4) var(--e12);
}

.envoltura-calendario {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 420px;
  gap: var(--e4);
  align-items: start;
  max-width: 1440px;
  transition: grid-template-columns var(--transicion-media);
}

/* Con el panel cerrado la segunda columna reservaba 360 px de nada y el
   calendario se quedaba en dos tercios de la pantalla con un hueco al lado.
   :has() pregunta por el estado real del panel, que ya vive en su atributo
   hidden, sin que JavaScript tenga que avisar de nada. Un navegador sin :has()
   se queda con la reticula de dos columnas de siempre, que era lo que habia. */
.envoltura-calendario:has(> .panel[hidden]) {
  grid-template-columns: minmax(0, 1fr);
}

.envoltura-media { max-width: 1000px; }
.envoltura-ancha { max-width: 1200px; }

.tarjeta {
  padding: var(--e6);
  background: var(--blanco);
  border: 1px solid var(--linea);
  border-radius: var(--radio);
  box-shadow: var(--sombra-canto);
}

/* Dos tarjetas seguidas necesitan aire entre ellas; una sola no lo nota. */
.tarjeta + .tarjeta { margin-top: var(--e4); }

/* La entrada de la tarjeta. §7 prohibia toda secuencia orquestada al cargar y
   esto es lo unico que se admitio en su lugar: un solo movimiento, de 320ms,
   que ocurre una vez y sobre transform y opacity. No hay retardos escalonados
   ni nada que llegue despues de que la pagina es usable, porque el contenido
   ya esta en el DOM y en su sitio: lo unico que hace la animacion es que no
   aparezca de golpe. Se apaga entera bajo prefers-reduced-motion. */
.tarjeta-aparece {
  animation: tarjeta-entra var(--transicion-larga) var(--curva) both;
}

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

/* El alta vive en panel lateral y no en modal centrado: el panel deja el
   calendario visible mientras se escribe, que es lo que alguien necesita al
   agendar. */
.panel {
  position: sticky;
  top: calc(56px + var(--e4));
  padding: var(--e6);
  background: var(--blanco);
  border: 1px solid var(--linea);
  border-radius: var(--radio);
  box-shadow: var(--sombra-panel);
  transition: transform var(--transicion-media), opacity var(--transicion-media);
}

/* El asistente es mas alto que el panel de doce campos que habia, y el panel
   esta pegado: sin un tope y su propio desplazamiento, el paso 1 empujaba los
   botones de abajo fuera de la pantalla y no habia forma de llegar a ellos. */
.panel {
  max-height: calc(100vh - 56px - var(--e8));
  overflow-y: auto;
  overscroll-behavior: contain;
}

.panel[hidden] { display: none; }

.panel-cerrado {
  transform: translateX(var(--e3));
  opacity: 0;
}

.panel-cabecera {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--e3);
  padding-bottom: var(--e3);
  border-bottom: 1px solid var(--linea);
}

#panel-titulo { margin: 0; }

/* ---------- Formularios ---------- */

.campo {
  display: block;
  margin-bottom: var(--e3);
}

.campo > label {
  display: block;
  margin-bottom: var(--e1);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.04em;
  color: var(--carbon-70);
}

input, select, textarea {
  width: 100%;
  min-height: 36px;
  padding: var(--e2);
  font: 400 14px/1.4 var(--fuente-ui);
  color: var(--carbon);
  background: var(--blanco);
  border: 1px solid var(--gris-piedra);
  border-radius: var(--radio);
  transition: border-color var(--transicion), box-shadow var(--transicion),
              background-color var(--transicion);
}

input:hover, select:hover, textarea:hover { border-color: var(--bronce-anzures); }

/* El campo activo se dice dos veces: el borde cambia y el halo lo separa de
   los de arriba y abajo. Con solo el outline del navegador, en una columna de
   nueve campos, se pierde de vista cual esta enfocado. */
input:focus, select:focus, textarea:focus {
  border-color: var(--bronce-anzures);
  box-shadow: var(--anillo-foco);
}

/* :user-invalid y no :invalid: un campo obligatorio esta invalido desde que
   carga la pagina, y pintarlo de rojo antes de que nadie lo toque es reganar
   por adelantado. */
input:user-invalid, select:user-invalid, textarea:user-invalid {
  border-color: var(--rojo-alerta);
}

input:user-invalid:focus, select:user-invalid:focus, textarea:user-invalid:focus {
  box-shadow: var(--anillo-error);
}

input[disabled], select[disabled], textarea[disabled] {
  background: var(--marfil);
  color: var(--carbon-50);
  cursor: not-allowed;
}

textarea { min-height: 72px; resize: vertical; }

/* Los controles nativos heredan el acento del sistema operativo si no se les
   dice otra cosa: azul de Windows o de macOS dentro de una paleta que no lo
   tiene. */
input[type="checkbox"], input[type="radio"] { accent-color: var(--azul-lavalle); }

/* ---------- Botones ---------- */

.boton {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--e2);
  min-height: 36px;
  padding: var(--e2) var(--e4);
  font: 500 14px/1 var(--fuente-ui);
  color: var(--carbon);
  background: var(--blanco);
  border: 1px solid var(--linea);
  border-radius: var(--radio);
  box-shadow: var(--sombra-canto);
  cursor: pointer;
  transition: border-color var(--transicion), background-color var(--transicion),
              color var(--transicion), box-shadow var(--transicion),
              transform var(--transicion);
}

.boton:hover {
  border-color: var(--bronce-anzures);
  background: var(--bronce-08);
  box-shadow: var(--sombra-alzada);
  transform: translateY(-1px);
}

/* El boton se hunde al presionar, y cae un pixel por debajo de su reposo, no
   solo por debajo del hover. Sin esto el clic no acusa recibo hasta que
   responde el servidor, y en una red lenta se acaba pulsando dos veces. */
.boton:active {
  transform: translateY(1px);
  box-shadow: none;
}

.boton:focus-visible { box-shadow: var(--anillo-foco); }

/* El degradado son ocho puntos de luminosidad entre el borde de arriba y el de
   abajo, no un efecto: le da al boton principal el volumen que lo separa del
   secundario a un metro de la pantalla. El filete interior blanco es el brillo
   del canto superior, la misma idea que --sombra-canto pero por dentro. */
.boton-solido {
  color: var(--blanco);
  background: linear-gradient(180deg, var(--azul-alto), var(--azul-lavalle));
  border-color: var(--azul-hondo);
  box-shadow: var(--sombra-canto), inset 0 1px 0 var(--blanco-16);
}

.boton-solido:hover {
  color: var(--blanco);
  background: linear-gradient(180deg, var(--bronce-anzures), var(--bronce-anzures));
  border-color: var(--bronce-anzures);
  box-shadow: var(--sombra-alzada), inset 0 1px 0 var(--blanco-16);
}

.boton-peligro {
  color: var(--rojo-alerta);
  border-color: var(--rojo-30);
  background: var(--blanco);
}

.boton-peligro:hover {
  color: var(--rojo-alerta);
  background: var(--rojo-08);
  border-color: var(--rojo-alerta);
}

.boton[disabled] {
  opacity: .5;
  cursor: not-allowed;
  box-shadow: none;
}

/* Ocupado y deshabilitado a la vez: el boton se bloquea mientras guarda, pero
   atenuarlo al 50% apagaria justo la senal que lo explica. */
.boton[aria-busy="true"][disabled] {
  opacity: 1;
  cursor: progress;
}

.boton[disabled]:hover {
  border-color: var(--linea);
  background: var(--blanco);
  box-shadow: none;
  transform: none;
}

.boton-solido[disabled]:hover {
  background: linear-gradient(180deg, var(--azul-alto), var(--azul-lavalle));
  border-color: var(--azul-hondo);
}

.boton[disabled]:active { transform: none; }

/* Guardar tarda lo que tarde la red. Sin senal de ocupado, la unica lectura
   posible es que el clic no registro. El texto se apaga y gira un disco en su
   lugar: no se cambia la palabra, para que el boton no cambie de ancho. */
.boton[aria-busy="true"] { color: transparent; cursor: progress; }

.boton[aria-busy="true"]::after {
  content: "";
  position: absolute;
  width: 14px;
  height: 14px;
  border: 2px solid var(--carbon-14);
  border-top-color: var(--carbon);
  border-radius: 50%;
  animation: gira 600ms linear infinite;
}

.boton-solido[aria-busy="true"]::after {
  border-color: var(--blanco-30);
  border-top-color: var(--blanco);
}

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

.acciones {
  display: flex;
  gap: var(--e2);
  margin-top: var(--e4);
  padding-top: var(--e4);
  border-top: 1px solid var(--linea);
}

/* Eliminar se va al extremo contrario del boton principal. Son las dos acciones
   que menos se parecen y el resto del tiempo estarian a un dedo de distancia. */
#btn-eliminar { margin-right: auto; }

/* ---------- Estados del evento ---------- */

/* FullCalendar 7 no expone clases semanticas: las suyas van hasheadas
   (.fc-classic-YjJ). El unico enganche estable es el refiner className del
   evento, y tiene que ser una CADENA: con un arreglo, refineClassName()
   devuelve '' y la clase no llega al DOM (ver admin.js).

   Los dos --fc-event-* llevan !important y no es descuido. FullCalendar
   escribe esas dos variables como estilo EN LINEA sobre cada evento
   (style="--fc-event-color: var(--fc-classic-event)"), y un estilo en linea le
   gana a cualquier regla de clase por especificidad. !important en una hoja de
   autor es lo unico que gana a un estilo en linea sin !important, y sin el la
   marca del bloque, el punto de los eventos con hora y el borde salen todos del
   color por defecto del tema, que es el mismo para los cuatro estados.

   background-color, border y color NO lo necesitan: ahi competimos contra la
   clase hasheada del tema, misma especificidad, y esta hoja carga despues.

   El estado nunca se comunica solo por color: cada bloque lleva su etiqueta. */

/* El color del texto lo tiene que heredar TODO lo que hay dentro del bloque.
   FullCalendar pinta el titulo en un hijo con clase propia, y esa clase usa
   --fc-event-contrast-color en unos casos y el color de texto normal del tema en
   otros, segun el bloque quepa en una linea o en varias. El resultado se ve en
   pantalla: el mismo evento confirmado salia con el titulo blanco cuando cabia
   en una linea y con el titulo en carbon, ilegible sobre el azul, cuando no.
   Heredar del contenedor lo deja en un solo color, sea cual sea el caso. */
.evento-confirmado *,
.evento-tentativo *,
.evento-montaje *,
.evento-cancelado * {
  color: inherit;
}

.evento-confirmado,
.evento-tentativo,
.evento-montaje,
.evento-cancelado {
  padding: 2px var(--e2);
  border-radius: var(--radio-int);
  overflow: hidden;
  cursor: pointer;
  transition: box-shadow var(--transicion), transform var(--transicion);
}

/* El bloque se levanta 1px al pasar el puntero. Es la unica pista de que se
   puede abrir: sin ella, un evento y una celda vacia se ven igual de inertes.

   El fondo y el borde se vuelven a declarar aqui, identicos al reposo, y eso no
   es redundante: el tema aplica .fc-classic-4yP:hover (mutedHoverClass) a los
   eventos que dibuja como punto en vez de bloque solido, y esa regla pinta
   --fc-classic-muted, que en este :root es --carbon-08. Con especificidad (0,2,0)
   le gana a .evento-confirmado (0,1,0), asi que al pasar el puntero el fondo se
   iba a un velo casi transparente mientras el texto seguia blanco: blanco sobre
   casi blanco. Solo se ve cuando la celda es estrecha, que es cuando FullCalendar
   cambia a la forma de punto. Estas reglas empatan en especificidad y esta hoja
   carga despues del tema, asi que ganan por orden.

   El color NO se intensifica al pasar el puntero a proposito: el color comunica
   el estado del evento, y moverlo acercaria confirmado a tentativo. La pista de
   que el bloque se puede abrir es el levantamiento y la sombra, no el tono. */
.evento-confirmado:hover,
.evento-tentativo:hover,
.evento-montaje:hover,
.evento-cancelado:hover {
  transform: translateY(-1px);
  box-shadow: var(--sombra-panel);
}

.evento-confirmado:hover {
  background-color: var(--azul-lavalle);
}

.evento-tentativo:hover {
  background-color: var(--marfil);
  border-color: var(--bronce-anzures);
}

.evento-montaje:hover {
  background-color: var(--gris-piedra);
  border-color: var(--gris-piedra);
}

.evento-cancelado:hover {
  background-color: var(--rojo-08);
  border-color: var(--rojo-alerta);
}

.evento-confirmado {
  --fc-event-color: var(--azul-lavalle) !important;
  --fc-event-contrast-color: var(--blanco) !important;
  background-color: var(--azul-lavalle);
  border: none;
  color: var(--blanco);
}

.evento-tentativo {
  --fc-event-color: var(--bronce-anzures) !important;
  --fc-event-contrast-color: var(--carbon) !important;
  background-color: var(--marfil);
  border: 1.5px solid var(--bronce-anzures);
  color: var(--carbon);
}

/* Relleno solido, no el beige de --linea. Montaje y desmontaje son horas en que
   la casa esta tomada igual que durante el evento, y en beige sobre blanco se
   leian como una linea de separacion en vez de como ocupacion. Gris piedra
   solido con texto carbon da 5.5:1 y es el mismo color que ya tenia la barra de
   6 px del telefono, asi que el bloque y la barra por fin dicen lo mismo.

   Sube de peso, no de tono: el tono nuevo se lo lleva cancelado, y en una barra
   de 6 px sin texto el color es lo unico que separa un estado de otro. */
.evento-montaje {
  --fc-event-color: var(--gris-piedra) !important;
  --fc-event-contrast-color: var(--carbon) !important;
  background-color: var(--gris-piedra);
  border: 1px solid var(--gris-piedra);
  color: var(--carbon);
}

/* Rojo, y por eso §7 movio la linea de --rojo-alerta de "solo acciones
   destructivas" a incluir este estado. Un evento cancelado no es una accion,
   pero es la unica fila de la reticula que hay que ver sin buscarla: en gris
   con tachado se perdia entre montaje y desmontaje, que tambien eran grises.
   Punteado y no solido para que siga siendo el estado mas leve de los cuatro.
   --rojo-alerta sobre --rojo-08 da 7.2:1. */
.evento-cancelado {
  --fc-event-color: var(--rojo-alerta) !important;
  --fc-event-contrast-color: var(--rojo-alerta) !important;
  background-color: var(--rojo-08);
  border: 1px dotted var(--rojo-alerta);
  color: var(--rojo-alerta);
  text-decoration: line-through;
}

/* El envoltorio unico del contenido del bloque. Lo pinta contenidoEvento() y
   existe para que la etiqueta y el titulo no se conviertan en dos columnas de
   la caja flexible en la que FullCalendar los mete. */
.evento-cuerpo {
  display: block;
  min-width: 0;
  /* En una columna de 50 px, 'Presentacion' no cabe en ningun punto de corte y
     el navegador la deja salirse de la celda: en el telefono los bloques del
     sabado se montaban sobre el canto de la tarjeta. 'anywhere' parte la
     palabra donde haga falta, que es feo pero cabe. */
  overflow-wrap: anywhere;
}

/* inline y no inline-block: la etiqueta va en el mismo flujo que el titulo, no
   en su propio bloque. */
.evento-etiqueta {
  display: inline;
  margin-right: var(--e1);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  opacity: .85;
}

/* ---------- Leyenda ---------- */

/* La leyenda se hunde sobre marfil dentro de la tarjeta blanca: es referencia,
   no contenido, y el tercer plano de profundidad lo dice sin escribirlo. */
.leyenda {
  display: flex;
  flex-wrap: wrap;
  gap: var(--e3) var(--e6);
  margin: var(--e6) calc(var(--e6) * -1) calc(var(--e6) * -1);
  padding: var(--e3) var(--e6);
  border-top: 1px solid var(--linea);
  border-radius: 0 0 var(--radio) var(--radio);
  background: var(--marfil);
  font-size: 12px;
  color: var(--carbon-70);
}

.leyenda > li {
  display: flex;
  align-items: center;
  gap: var(--e2);
  list-style: none;
}

.leyenda-muestra {
  display: inline-block;
  width: 12px;
  height: 12px;
  border-radius: var(--radio-int);
  flex: none;
}

.leyenda-confirmado { background: var(--azul-lavalle); }
.leyenda-tentativo  { background: var(--marfil); border: 1.5px solid var(--bronce-anzures); }
.leyenda-montaje    { background: var(--gris-piedra); }
.leyenda-cancelado  { background: var(--rojo-08); border: 1px dotted var(--rojo-alerta); }

/* ---------- Esqueleto de carga ---------- */

/* Entre la peticion y el primer pintado no habia nada: la tarjeta quedaba en
   blanco y la pagina parecia rota. Un spinner tampoco sirve, no dice que viene.
   La silueta de la reticula si: el ojo ya sabe donde van a caer los dias. */
.esqueleto[hidden] { display: none; }

.esqueleto-barra {
  height: 34px;
  width: 220px;
  margin: 0 auto var(--e4);
  border-radius: var(--radio);
}

.esqueleto-reticula {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 1px;
  padding: 1px;
  background: var(--linea);
  border: 1px solid var(--linea);
  border-radius: var(--radio);
}

.esqueleto-celda { height: 92px; }

.esqueleto-barra,
.esqueleto-celda {
  background-color: var(--blanco);
  background-image: linear-gradient(
    100deg,
    var(--blanco) 20%,
    var(--marfil) 42%,
    var(--linea-60) 50%,
    var(--marfil) 58%,
    var(--blanco) 80%
  );
  background-size: 300% 100%;
  animation: esqueleto-brillo 1600ms linear infinite;
}

/* Se anima la posicion del fondo, no una propiedad de maquetacion. */
@keyframes esqueleto-brillo {
  from { background-position: 150% 0; }
  to   { background-position: -150% 0; }
}

/* ---------- Tablas (equipo, bitacora) ---------- */

/* Lo que no cabe se recorre dentro de la tarjeta, no por encima de ella. Los
   margenes negativos llevan la zona de recorrido hasta el canto de la tarjeta
   para que la ultima columna no quede cortada a media celda. */
.tabla-envoltura {
  overflow-x: auto;
  margin: 0 calc(var(--e6) * -1) calc(var(--e6) * -1);
  padding: 0 var(--e6) var(--e6);
}

.tabla {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
}

.tabla th, .tabla td {
  padding: var(--e3);
  text-align: left;
  border-bottom: 1px solid var(--linea);
}

.tabla th {
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--carbon-70);
  background: var(--marfil);
  white-space: nowrap;
}

/* El encabezado se queda arriba al recorrer, pero solo dentro de un contenedor
   que de verdad hace scroll. Suelto en la pagina, sticky se ancla al viewport y
   la cabecera acaba flotando sobre el contenido de la tabla de equipo. */
.tarjeta-scroll .tabla th {
  position: sticky;
  top: 0;
  z-index: 1;
}

.tabla tbody tr { transition: background-color var(--transicion); }
.tabla tbody tr:hover { background: var(--azul-04); }
.tabla tbody tr:last-child td { border-bottom: none; }

/* Las filas llevan el mismo alto minimo que un objetivo tactil aunque la celda
   traiga solo texto: con avatares de 28 px dentro, una fila apretada los pega
   al filete de abajo. */
.tabla tbody td { vertical-align: middle; }

/* ---------- Avisos, vacio y error ---------- */

/* Sin franja lateral de color. Ese borde de 3px es el detalle que hace que un
   aviso se lea como plantilla: el estado se dice con el borde completo, el
   fondo tenido y la palabra escrita. */
.aviso {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--e2) var(--e3);
  padding: var(--e3) var(--e4);
  border: 1px solid var(--linea);
  border-radius: var(--radio);
  background: var(--blanco);
}

.aviso-error {
  color: var(--carbon);
  border-color: var(--rojo-30);
  background: var(--rojo-08);
}

.aviso-exito {
  border-color: var(--azul-30);
  background: var(--azul-08);
}

/* El traslape no es un error: es una decision que alguien tiene que tomar con
   la informacion enfrente. Se despliega en bloque, con la lista de lo que
   choca y la salida explicita abajo. */
.aviso-traslape {
  display: block;
  border-color: var(--bronce-30);
  background: var(--bronce-08);
}

.aviso-vacio {
  display: block;
  padding: var(--e8) var(--e4);
  border: none;
  background: none;
  text-align: center;
}

.vacio-titulo {
  margin: 0;
  font: 300 20px/1.3 var(--fuente-editorial);
  color: var(--carbon);
}

.vacio-cuerpo {
  margin: var(--e2) auto 0;
  max-width: 46ch;
  color: var(--carbon-70);
}

/* ---------- Utilidades de maquetacion ----------
 *
 * Estas clases existen porque el .htaccess del admin sirve
 * Content-Security-Policy: default-src 'self' sin 'unsafe-inline'. Esa politica
 * no solo bloquea el <script> en linea: tambien bloquea cada atributo
 * style="..." del marcado. Todo lo que antes vivia en un style= vive aqui. */

/* ---------- Paginas de acceso ---------- */

/* Una sola tarjeta centrada. La version anterior partia la pantalla en dos y
   sostenia medio lienzo de color con el lema y la direccion de la casa. Se
   retiro por peticion directa: la pantalla de entrada no tiene que presentar
   el recinto, solo dejar pasar. El color de la casa no se perdio, se repartio:
   dos halos muy abiertos en el fondo, que se leen como luz y no como un bloque
   de pintura, y sobre ellos el logotipo azul en su fondo claro de siempre. */
.pagina-acceso {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
  padding: var(--e8) var(--e4);
  background:
    radial-gradient(112% 74% at 50% -16%, var(--azul-08), transparent 62%),
    radial-gradient(86% 62% at 88% 116%, var(--bronce-08), transparent 64%),
    var(--marfil);
}

.acceso {
  width: 100%;
  max-width: 400px;
}

.tarjeta-acceso {
  width: 100%;
  padding: var(--e12) var(--e8) var(--e8);
  box-shadow: var(--sombra-elevada);
}

/* La cabecera va centrada y el formulario no. Centrar tambien las etiquetas
   romperia la columna de lectura de los campos, que se recorre de arriba abajo
   por su borde izquierdo. */
.acceso-cabecera {
  margin-bottom: var(--e8);
  text-align: center;
}

.acceso-logo {
  display: block;
  height: 28px;
  width: auto;
  margin: 0 auto var(--e6);
}

/* El rotulo dice que es esto y el h1 dice que se hace aqui. En dos escalones
   distintos se leen como una sola linea: Casa Lavalle, Calendario, Iniciar
   sesion. */
.acceso-rotulo {
  margin: 0;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--bronce-anzures);
}

.acceso-titulo {
  margin: var(--e2) 0 0;
}

.acceso-subtitulo {
  max-width: 32ch;
  margin: var(--e3) auto 0;
  line-height: 1.55;
}

.acceso-salida {
  margin-top: var(--e6);
  padding-top: var(--e4);
  border-top: 1px solid var(--linea);
  font-size: 13px;
  text-align: center;
}

.acciones-acceso {
  margin-top: var(--e6);
}

.boton-ancho { width: 100%; }

/* Un campo que se muestra pero no se edita: viene de la invitacion. */
.entrada-fija {
  background: var(--marfil);
  color: var(--carbon-70);
}

/* ---------- Iconos ---------- */

/* 18px y no 16: a 16 el trazo de 1.5 se ve grueso y a 20 el icono pesa mas que
   la palabra que acompana. Heredan color, asi que no hay una regla de color
   por icono en ningun sitio. */
.icono {
  width: 18px;
  height: 18px;
  flex: none;
}

/* El boton con icono aprieta el padding del lado del icono: con el mismo
   padding que un boton de solo texto, el icono queda flotando lejos de su
   palabra y el boton se ve descentrado. */
.boton-icono {
  padding-left: var(--e3);
  padding-right: var(--e4);
}

.boton-icono .icono { color: currentColor; }

/* ---------- Marco del calendario ---------- */

/* FullCalendar 7 hashea todas sus clases, asi que su cromo solo se puede tocar
   por los tokens --fc-classic-*. Lo unico que queda de este lado es el
   contenedor: separarlo del encabezado y darle su propio canto para que la
   reticula no arranque pegada al titulo. */
#calendario {
  margin-top: var(--e4);
  transition: opacity var(--transicion-media);
}

/* Mientras la primera peticion esta en vuelo la reticula existe en el DOM pero
   todavia no tiene eventos, y quien manda en pantalla es la silueta de carga.
   Se oculta con opacity para que las dos no se pisen, y sin clics para que no
   se pueda abrir el panel de un evento que aun no termina de llegar.
   admin.js quita aria-busy en cuanto hay respuesta, buena o mala. */
#calendario[aria-busy="true"] {
  opacity: 0;
  pointer-events: none;
}

/* ---------- Campo de contrasena ---------- */

.entrada-clave {
  position: relative;
  display: block;
}

/* El hueco del boton se reserva con padding del campo, no con un ancho fijo
   del contenedor: asi el texto largo nunca pasa por debajo del ojo. */
.entrada-clave input {
  padding-right: 44px;
}

.boton-ojo {
  position: absolute;
  top: 50%;
  right: var(--e1);
  transform: translateY(-50%);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  padding: 0;
  color: var(--carbon-50);
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--radio);
  cursor: pointer;
  transition: color var(--transicion), background-color var(--transicion),
              border-color var(--transicion);
}

.boton-ojo:hover {
  color: var(--azul-lavalle);
  background: var(--bronce-08);
  border-color: var(--bronce-30);
}

/* Presionado quiere decir "la contrasena esta a la vista". Es un estado que
   conviene que se note: quien lo deja encendido sin querer esta ensenando su
   contrasena a la sala. */
.boton-ojo[aria-pressed="true"] {
  color: var(--azul-lavalle);
  background: var(--azul-08);
  border-color: var(--azul-30);
}

/* Un solo icono a la vez, decidido por el mismo atributo que anuncia el estado
   al lector de pantalla. */
.boton-ojo .icono-ojo-cerrado { display: none; }
.boton-ojo[aria-pressed="true"] .icono-ojo { display: none; }
.boton-ojo[aria-pressed="true"] .icono-ojo-cerrado { display: block; }

.aviso-mayusculas {
  display: flex;
  align-items: center;
  gap: var(--e2);
  margin: var(--e2) 0 0;
  font-size: 12px;
  font-weight: 500;
  color: var(--bronce-anzures);
}

.aviso-mayusculas::before {
  content: "";
  width: 6px;
  height: 6px;
  flex: none;
  border-radius: var(--radio-pastilla);
  background: var(--bronce-anzures);
}

/* ---------- Notas de campo ---------- */

.campo-nota {
  margin: var(--e2) 0 0;
  font-size: 12px;
  line-height: 1.5;
  color: var(--carbon-70);
}

/* ---------- Perfil ---------- */

.perfil-identidad {
  display: flex;
  align-items: center;
  gap: var(--e6);
  padding-bottom: var(--e6);
  margin-bottom: var(--e6);
  border-bottom: 1px solid var(--linea);
}

.perfil-retrato { flex: none; }

.perfil-retrato .avatar {
  box-shadow: inset 0 0 0 1px var(--carbon-08), 0 0 0 4px var(--marfil), 0 0 0 5px var(--linea);
}

/* La foto recien elegida entra con un pulso corto. Sin el, cambiar de imagen en
   el mismo sitio no se distingue de que no haya pasado nada. */
.perfil-retrato-nuevo {
  animation: retrato-entra var(--transicion-larga) var(--curva) both;
}

@keyframes retrato-entra {
  from { opacity: .4; transform: scale(.94); }
  to   { opacity: 1;  transform: scale(1); }
}

.perfil-retrato-acciones {
  display: grid;
  gap: var(--e2);
  min-width: 0;
}

.perfil-botones {
  display: flex;
  flex-wrap: wrap;
  gap: var(--e2);
}

/* El input de archivo se saca de la vista pero no del orden de foco: el label
   de al lado es su cara y el anillo de foco se le presta cuando el input lo
   recibe. display:none lo sacaria tambien del tabulador. */
.entrada-archivo {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.entrada-archivo:focus-visible + .boton {
  border-color: var(--bronce-anzures);
  box-shadow: var(--anillo-foco);
}

/* ---------- Persona en una celda ---------- */

.celda-persona {
  display: inline-flex;
  align-items: center;
  gap: var(--e3);
  min-width: 0;
}

.encabezado-seccion {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  gap: var(--e4);
  margin-bottom: var(--e6);
  padding-bottom: var(--e4);
  border-bottom: 1px solid var(--linea);
}

/* El subtitulo bajo el h1 de la seccion. Cuelga del titulo, no es un parrafo
   suelto, y por eso comparte su bloque en vez de llevar su propio margen. */
.encabezado-seccion p {
  margin: var(--e2) 0 0;
}

.encabezado-calendario {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--e4);
  margin-bottom: var(--e4);
}

/* Avisos con separacion cuando van sueltos en la pagina */

.aviso-bloque { margin-bottom: var(--e4); }
.aviso-bloque-sup { margin-top: var(--e4); }

.aviso-titulo {
  display: block;
  margin: 0 0 var(--e2);
  font-weight: 500;
}

/* Botones secundarios dentro de un aviso o una celda */

.boton-mini {
  min-height: 28px;
  padding: var(--e1) var(--e3);
  font-size: 12px;
}

.boton-en-aviso { margin-left: auto; }

/* Equipo */

.rejilla-equipo {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 340px;
  gap: var(--e6);
  align-items: start;
}

.bloque-enlace { margin-top: var(--e3); }

.etiqueta-enlace {
  display: block;
  margin-bottom: var(--e1);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.04em;
  color: var(--carbon-70);
}

.campo-enlace {
  font-family: var(--fuente-mono);
  font-size: 12px;
  background: var(--marfil);
}

.estado-activo,
.estado-invitado {
  display: inline-flex;
  align-items: center;
  gap: var(--e2);
  font-weight: 500;
  white-space: nowrap;
}

.estado-activo::before,
.estado-invitado::before {
  content: "";
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex: none;
}

.estado-activo { color: var(--azul-lavalle); }
.estado-activo::before { background: var(--azul-lavalle); }

.estado-invitado { color: var(--bronce-anzures); }
.estado-invitado::before { background: var(--bronce-anzures); }

.forma-en-celda { display: inline; }

/* Bitacora */

.tarjeta-scroll {
  overflow: auto;
  max-height: 70vh;
  padding: 0;
}

.celda-fecha {
  white-space: nowrap;
  font-size: 13px;
  font-variant-numeric: tabular-nums;
}

.celda-ip {
  font-family: var(--fuente-mono);
  font-size: 12px;
  color: var(--carbon-70);
}

/* La columna de cambios pintaba el JSON crudo, llaves y comillas incluidas. Lo
   que hay ahora son pares clave y valor: la misma informacion, sin obligar a
   nadie a leer JSON para saber que cambio un nombre. */
.celda-cambios {
  max-width: 380px;
  font-size: 12px;
}

.cambio-bloque {
  display: grid;
  gap: 3px;
}

.cambio-bloque + .cambio-bloque {
  margin-top: var(--e2);
  padding-top: var(--e2);
  border-top: 1px solid var(--linea-60);
}

.cambio-titulo {
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--carbon-50);
}

/* Antes se atenua y despues no: en una fila con los dos lados, el estado
   vigente tiene que ganar de un vistazo. */
.cambio-antes .cambio-valor { color: var(--carbon-70); }

.cambio-par {
  display: flex;
  gap: var(--e2);
  align-items: baseline;
  min-width: 0;
}

.cambio-clave {
  flex: none;
  min-width: 74px;
  color: var(--carbon-50);
}

.cambio-valor {
  min-width: 0;
  font-weight: 500;
  overflow-wrap: anywhere;
}

/* El nombre legible manda y el slug queda debajo para poder rastrear. */
.accion-nombre {
  display: block;
  font-weight: 500;
}

.accion-slug {
  display: block;
  margin-top: 2px;
  font-family: var(--fuente-mono);
  font-size: 11px;
  color: var(--carbon-50);
}

.tabla-vacia {
  padding: var(--e8);
  text-align: center;
}

/* ---------- Editor de evento en tres pasos ---------- */

/* El riel de pasos. Son botones y no rotulos: en un evento que ya existe los
   tres estan llenos, y obligar a recorrerlos para corregir una nota seria peor
   que la columna de doce campos que habia antes. */
.pasos {
  display: flex;
  gap: var(--e1);
  margin: var(--e4) 0 var(--e6);
  padding: 0;
  list-style: none;
}

.paso {
  flex: 1;
  min-width: 0;
}

.paso-boton {
  display: flex;
  align-items: center;
  gap: var(--e2);
  width: 100%;
  min-height: 36px;
  padding: var(--e2) var(--e1) 0;
  font: 500 12px/1.2 var(--fuente-ui);
  text-align: left;
  color: var(--carbon-70);
  background: none;
  border: none;
  border-top: 2px solid var(--linea);
  cursor: pointer;
  transition: color var(--transicion), border-color var(--transicion);
}

.paso-boton:hover {
  color: var(--carbon);
  border-top-color: var(--gris-piedra);
}

.paso-numero {
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  font-size: 11px;
  color: var(--carbon-70);
  background: var(--carbon-08);
  border-radius: var(--radio-pastilla);
  transition: color var(--transicion), background-color var(--transicion);
}

.paso-nombre {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Un paso por el que ya se paso. En una edicion lo estan los tres desde el
   primer momento, y eso es informacion: dice que no queda nada pendiente. */
.paso-hecho {
  color: var(--carbon);
  border-top-color: var(--bronce-30);
}

.paso-hecho .paso-numero {
  color: var(--blanco);
  background: var(--bronce-anzures);
}

.paso-boton[aria-current="step"] {
  color: var(--azul-lavalle);
  border-top-color: var(--azul-lavalle);
}

.paso-boton[aria-current="step"] .paso-numero {
  color: var(--blanco);
  background: var(--azul-lavalle);
}

.paso-pregunta {
  margin: 0 0 var(--e3);
  font: 500 15px/1.3 var(--fuente-ui);
  letter-spacing: -0.01em;
}

.paso-ayuda {
  margin: 0 0 var(--e4);
  font-size: 12px;
  line-height: 1.5;
  color: var(--carbon-70);
}

/* El eco. Un campo de fecha ensena '05/09/2026' y no dice que es sabado, y
   casi todo lo que se agenda aqui cae en fin de semana: equivocarse de dia se
   descubre cuando llega el cliente. */
.paso-eco {
  margin: var(--e3) 0 0;
  padding: var(--e2) var(--e3);
  font-size: 13px;
  color: var(--carbon);
  background: var(--azul-04);
  border-left: 2px solid var(--azul-30);
  border-radius: var(--radio-int);
}

.paso-eco-mal {
  color: var(--rojo-alerta);
  background: var(--rojo-08);
  border-left-color: var(--rojo-alerta);
}

/* Un momento: el rotulo a la izquierda, el dia y la hora a la derecha. En una
   sola linea se lee como una frase, no como dos campos que hay que rellenar. */
.momento {
  display: grid;
  grid-template-columns: 76px minmax(0, 1fr);
  align-items: center;
  gap: var(--e3);
  margin-bottom: var(--e3);
}

.momento-sup { margin-top: var(--e4); }

.momento-rotulo {
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.04em;
  color: var(--carbon-70);
}

.momento-campos {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 132px;
  gap: var(--e2);
}

/* Dentro de un momento la etiqueta de cada campo no se pinta: el rotulo de la
   izquierda ya dice de que momento se habla, y un control de fecha y uno de
   hora no se confunden a la vista. Siguen en el marcado con .solo-lectores,
   asi que el lector de pantalla las oye. */
.campo-suelto { margin-bottom: 0; }

/* Una ficha no es un boton del sistema: no manda nada, rellena campos que
   siguen a la vista y se pueden corregir encima. Por eso pesa menos. */
.fichas {
  display: flex;
  flex-wrap: wrap;
  gap: var(--e1);
  margin-top: var(--e2);
}

.ficha {
  min-height: 28px;
  padding: 0 var(--e3);
  font: 500 12px/1 var(--fuente-ui);
  color: var(--carbon-70);
  background: var(--marfil);
  border: 1px solid var(--linea);
  border-radius: var(--radio-pastilla);
  cursor: pointer;
  transition: color var(--transicion), background-color var(--transicion),
              border-color var(--transicion);
}

.ficha:hover {
  color: var(--carbon);
  background: var(--bronce-08);
  border-color: var(--bronce-anzures);
}

.separador {
  height: 1px;
  margin: var(--e6) 0;
  border: none;
  background: var(--linea);
}

/* Los espacios como tarjetas y no como cuatro casillas en fila. Es la segunda
   decision del alta y la que mas se equivoca: a tamano de casilla se elegian
   de mas y de menos, y el traslape se descubria despues. */
.espacios-rejilla {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--e2);
}

.espacio-tarjeta {
  display: flex;
  align-items: center;
  gap: var(--e2);
  min-height: 48px;
  padding: var(--e2) var(--e3);
  font-size: 13px;
  background: var(--blanco);
  border: 1px solid var(--linea);
  border-radius: var(--radio);
  cursor: pointer;
  transition: background-color var(--transicion), border-color var(--transicion),
              box-shadow var(--transicion);
}

.espacio-tarjeta:hover { border-color: var(--bronce-anzures); }

/* :has() y no una clase puesta desde JavaScript: el estado ya vive en la
   casilla, y duplicarlo en una clase es la forma segura de que se desincronice
   el dia que alguien marque la casilla desde otro sitio. */
.espacio-tarjeta:has(input:checked) {
  background: var(--azul-08);
  border-color: var(--azul-lavalle);
  box-shadow: inset 0 0 0 1px var(--azul-lavalle);
}

.espacio-tarjeta:has(input:focus-visible) { box-shadow: var(--anillo-foco); }

/* La casilla no hereda el ancho completo de los campos de texto. */
.espacio-tarjeta input[type="checkbox"] {
  width: auto;
  min-height: auto;
  flex: none;
}

.espacio-nombre { min-width: 0; }

/* Tres estados excluyentes en una pastilla. Un desplegable de tres opciones
   esconde dos de las tres y cuesta dos clics; aqui se ven las tres y cuesta
   uno. */
.segmentado {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 2px;
  padding: 2px;
  background: var(--marfil);
  border: 1px solid var(--linea);
  border-radius: var(--radio-pastilla);
}

.segmentado-opcion {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 32px;
  font-size: 13px;
  font-weight: 500;
  color: var(--carbon-70);
  border-radius: var(--radio-pastilla);
  cursor: pointer;
  transition: color var(--transicion), background-color var(--transicion);
}

/* El radio se transparenta y quien pinta el estado es la etiqueta. No se apaga
   con display:none: eso lo saca del orden de tabulacion y el grupo dejaria de
   recorrerse con las flechas, que es como se opera un grupo de radios. */
.segmentado-opcion input[type="radio"] {
  position: absolute;
  width: 1px;
  height: 1px;
  min-height: 0;
  opacity: 0;
  pointer-events: none;
}

.segmentado-opcion:hover { color: var(--carbon); }

.segmentado-opcion:has(input:checked) {
  color: var(--blanco);
  background: var(--azul-lavalle);
}

.segmentado-opcion:has(input:focus-visible) { box-shadow: var(--anillo-foco); }

/* Cancelado no es un estado mas de la lista: es el que apaga el evento. */
.segmentado-opcion:has(#estado-cancelado:checked) { background: var(--rojo-alerta); }

/* La respuesta a "esta libre esa fecha", en el mismo paso donde se eligen las
   fechas y los espacios. */
.disponibilidad {
  margin-top: var(--e4);
  padding: var(--e3);
  font-size: 13px;
  background: var(--marfil);
  border: 1px solid var(--linea);
  border-radius: var(--radio);
}

.disponibilidad-texto {
  margin: 0;
  font-weight: 500;
}

.disponibilidad-esperando { color: var(--carbon-70); }

.disponibilidad-libre {
  color: var(--azul-lavalle);
  background: var(--azul-04);
  border-color: var(--azul-30);
}

.disponibilidad-choca {
  color: var(--carbon);
  background: var(--bronce-08);
  border-color: var(--bronce-anzures);
}

.lista-traslapes {
  margin: var(--e2) 0 var(--e3);
  padding-left: var(--e4);
  font-size: 13px;
}

.lista-traslapes:last-child { margin-bottom: 0; }

/* El resumen del paso 3. No es adorno: es lo unico que enseña de una vez lo
   que se decidio en los dos pasos anteriores, que ya no estan en pantalla. */
.resumen {
  margin-top: var(--e6);
  padding: var(--e4);
  background: var(--marfil);
  border: 1px solid var(--linea);
  border-radius: var(--radio);
}

.resumen-titulo {
  margin: 0 0 var(--e3);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--carbon-70);
}

.resumen-lista { margin: 0; }

.resumen-fila {
  display: grid;
  grid-template-columns: 96px minmax(0, 1fr);
  gap: var(--e3);
  padding: var(--e2) 0;
  border-bottom: 1px solid var(--linea-60);
}

.resumen-fila:first-child { padding-top: 0; }

.resumen-fila:last-child {
  padding-bottom: 0;
  border-bottom: none;
}

.resumen-fila dt {
  font-size: 12px;
  color: var(--carbon-70);
}

.resumen-fila dd {
  margin: 0;
  font-size: 13px;
  font-weight: 500;
}

.panel-pie {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: var(--e2);
  margin-top: var(--e6);
  padding-top: var(--e4);
  border-top: 1px solid var(--linea);
}

/* ---------- Movil ---------- */

@media (max-width: 900px) {
  h1 { font-size: 24px; }

  .envoltura { padding: var(--e4) var(--e3) var(--e8); }
  .envoltura-calendario { grid-template-columns: 1fr; }
  .rejilla-equipo { grid-template-columns: 1fr; }

  .tarjeta { padding: var(--e4); }

  .tabla-envoltura {
    margin: 0 calc(var(--e4) * -1) calc(var(--e4) * -1);
    padding: 0 var(--e4) var(--e4);
  }

  /* El panel deja de ser lateral: no hay lado. Pasa a ser la siguiente tarjeta
     de la columna y deja de pegarse, porque pegado taparia el calendario que
     esta editando. Y suelta su tope de alto: aqui quien recorre es la pagina,
     y un panel con desplazamiento propio dentro de otro que tambien se
     desplaza es la trampa clasica del movil. */
  .panel {
    position: static;
    padding: var(--e4);
    max-height: none;
    overflow: visible;
  }

  /* El rotulo del momento se pone encima de sus campos: con 80 px fijos a la
     izquierda, al dia y a la hora les quedaban 200 y el selector nativo de
     fecha no cabe. */
  .momento {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--e1);
  }

  .momento-campos { grid-template-columns: minmax(0, 1fr) 116px; }

  .barra {
    gap: var(--e3);
    padding: 0 var(--e3);
  }

  /* Sin espacio para las secciones en linea, la navegacion se pliega detras del
     boton y baja como un panel. Los dos enlaces del menu de usuario bajan con
     ella: en esta anchura no cabe un menu colgando de un avatar. */
  .barra-nav {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    display: none;
    flex-direction: column;
    gap: 2px;
    padding: var(--e2);
    background: var(--azul-lavalle);
    border-top: 1px solid var(--blanco-16);
    box-shadow: var(--sombra-barra);
  }

  .barra-nav-abierta { display: flex; }

  .barra-nav a {
    height: 44px;
    padding: 0 var(--e3);
  }

  /* En vertical el filete de estado se pone de canto: debajo de un renglon de
     una lista se leeria como un separador, no como la seccion en curso. */
  .barra-nav a[aria-current="page"]::after {
    left: 0;
    right: auto;
    top: var(--e2);
    bottom: var(--e2);
    width: 2px;
    height: auto;
  }

  .barra-nav a.barra-nav-movil { display: inline-flex; }
  .barra-hamburguesa { display: inline-flex; }
  .barra-sesion { display: none; }

  /* La tarjeta de acceso pierde su margen holgado: en un telefono ese aire es
     lo primero que empuja el boton de Entrar fuera de la pantalla. */
  .pagina-acceso { padding: var(--e6) var(--e3); }
  .tarjeta-acceso { padding: var(--e8) var(--e6) var(--e6); }

  .perfil-identidad {
    flex-direction: column;
    align-items: flex-start;
    gap: var(--e4);
  }

  .esqueleto-celda { height: 56px; }

  /* 44x44 minimo en tactil, igual que el sitio principal. */
  .boton, input, select { min-height: 44px; }
  .boton-ojo { width: 40px; height: 40px; }
  .espacio-tarjeta { min-height: 56px; }
  .paso-boton { min-height: 44px; }
  .ficha { min-height: 40px; }
  .segmentado-opcion { min-height: 40px; }

  /* La cabecera pegajosa no sirve con el teclado virtual abierto. */
  .tarjeta-scroll .tabla th { position: static; }
}

/* ---------- Transicion de vista, de fechas y de paso ---------- */

/* Se anima el CUERPO de la vista, nunca el contenedor entero. La barra de
   botones y el titulo del mes tienen que quedarse quietos: si se mueven, el
   boton que se acaba de pulsar se va de debajo del cursor, y en un panel donde
   se navega mes a mes eso se nota al segundo clic.

   FullCalendar 7 hashea sus clases estructurales (.fc-ei, .fc-vB), asi que no
   hay selector estable para ese cuerpo. El enganche lo da viewDidMount, que
   entrega el elemento raiz de la vista. Mismo razonamiento que el className de
   los eventos: en la 7 se pide el asa, no se adivina el nombre.

   Cambiar de vista y cambiar de mes no son el mismo gesto y no se animan igual.
   Cambiar de vista sustituye la reticula entera: entra de abajo, 280ms, que es
   lo que tarda en leerse una forma nueva. Navegar conserva la forma y solo mueve
   el tiempo: entra de un lado, 200ms, y el lado dice hacia donde se fue. Sin esa
   direccion las dos serian la misma animacion contando cosas distintas. */

@keyframes vista-entra {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}

@keyframes vista-avanza {
  from { opacity: 0; transform: translateX(14px); }
  to   { opacity: 1; transform: none; }
}

@keyframes vista-retrocede {
  from { opacity: 0; transform: translateX(-14px); }
  to   { opacity: 1; transform: none; }
}

.vista-entra     { animation: vista-entra     280ms var(--curva) both; }
.vista-avanza    { animation: vista-avanza    200ms var(--curva) both; }
.vista-retrocede { animation: vista-retrocede 200ms var(--curva) both; }

/* Los 14px de desplazamiento asoman por el borde mientras dura la animacion y
   el navegador contesta con una barra de scroll horizontal que aparece y
   desaparece. 'clip' recorta sin crear contenedor desplazable, y la clase solo
   vive los 200ms: fuera de ellos el popover de "+N mas" vuelve a poder salirse
   del contenedor. */
.calendario-animando { overflow-x: clip; }

/* El asistente de alta se mueve con el mismo vocabulario y por la misma razon:
   avanzar y retroceder son gestos distintos y el lado lo dice. 160ms y no 200
   porque aqui el contenido es una columna de campos, no una reticula, y a 200
   se siente lento cuando se recorren los tres pasos seguidos.

   Se anima solo el paso que ENTRA. Animar tambien el que sale obliga a
   sostener los dos en pantalla, y con campos de formulario eso significa dos
   juegos de etiquetas superpuestas y el foco puesto en uno que ya se va. */
@keyframes paso-avanza {
  from { opacity: 0; transform: translateX(12px); }
  to   { opacity: 1; transform: none; }
}

@keyframes paso-retrocede {
  from { opacity: 0; transform: translateX(-12px); }
  to   { opacity: 1; transform: none; }
}

.paso-avanza    { animation: paso-avanza    160ms var(--curva) both; }
.paso-retrocede { animation: paso-retrocede 160ms var(--curva) both; }

/* ---------- Movimiento ---------- */

/* En una herramienta que se usa a diario la animacion es latencia con otro
   nombre. Lo que se mueve aqui informa: el panel al entrar, la silueta de
   carga, el disco del boton ocupado. Y aqui se apaga todo. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    scroll-behavior: auto !important;
  }

  /* El esqueleto pierde el brillo pero no la silueta: sigue diciendo que algo
     esta por llegar, sin nada moviendose. */
  .esqueleto-barra,
  .esqueleto-celda {
    background-image: none;
    background-color: var(--marfil);
  }

  .evento-confirmado:hover,
  .evento-tentativo:hover,
  .evento-montaje:hover,
  .evento-cancelado:hover,
  .boton:hover,
  .boton:active {
    transform: none;
  }

  /* Las tres animaciones que se agregaron con el rediseno se apagan enteras, no
     se aceleran: una entrada de 0.01ms sigue siendo un parpadeo. Se anula la
     animacion y el elemento aparece ya en su sitio, que es su estado final. */
  .tarjeta-aparece,
  .menu-usuario,
  .perfil-retrato-nuevo {
    animation: none !important;
    opacity: 1;
    transform: none;
  }

  /* Lo mismo para las cinco del cambio de vista y de paso: acelerada, una
     entrada sigue siendo un parpadeo de opacidad, y el parpadeo es justo lo que
     esta consulta pide no ver. La reticula y el paso aparecen ya puestos. */
  .vista-entra,
  .vista-avanza,
  .vista-retrocede,
  .paso-avanza,
  .paso-retrocede {
    animation: none !important;
    opacity: 1;
    transform: none;
  }

  /* El enlace de salto sigue apareciendo: es la unica forma de saber que se
     enfoco. Lo que se pierde es el deslizamiento, no el elemento. */
  .salto-contenido { transition: none !important; }

  /* El disco sigue girando: es la unica senal de que el guardado no murio, y
     una sola vuelta congelada mentiria. */
  .boton[aria-busy="true"]::after {
    animation-duration: 600ms !important;
    animation-iteration-count: infinite !important;
  }
}
