html,
body {
  min-height: 100%;
}

/*
 * Bloquea el desplazamiento únicamente
 * mientras se construye el contenido.
 */
body.loading {
  overflow: hidden;
}

/*
 * Pantalla de carga.
 */
.loader {
  position: fixed;
  inset: 0;

  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;

  background-color: #e9e3d7;

  opacity: 1;
  visibility: visible;
  pointer-events: auto;

  z-index: 9999;

  transition:
    opacity 300ms ease,
    visibility 0s linear 0s;
}

/*
 * Imagen del loader.
 */
.loader img {
  width: min(200px, 45vw);
  height: auto;

  object-fit: contain;
}

/*
 * Estado final.
 *
 * visibility cambia después de que termina
 * la transición de opacity.
 */
body.loaded .loader {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;

  transition:
    opacity 300ms ease,
    visibility 0s linear 300ms;
}

/*
 * Estado de error.
 *
 * El loader permanece visible y muestra
 * el mensaje correspondiente.
 */
body.load-error .loader {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;

  transition: none;
}

/*
 * Mensaje de error.
 */
.loader-error {
  max-width: 28rem;
  margin: 0;
  padding: 2rem;

  font-family:
    "Roboto",
    sans-serif;

  font-size: 1rem;
  line-height: 1.5;
  text-align: center;

  color: #3b342b;
}

/*
 * Texto accesible oculto visualmente.
 */
.sr-only {
  position: absolute;

  width: 1px;
  height: 1px;

  padding: 0;
  margin: -1px;

  overflow: hidden;

  clip: rect(0, 0, 0, 0);
  clip-path: inset(50%);

  white-space: nowrap;

  border: 0;
}

/*
 * Respeta la preferencia del usuario
 * respecto a las animaciones.
 */
@media (
  prefers-reduced-motion:
  reduce
) {
  .loader,
  body.loaded .loader {
    transition: none;
  }
}