/*
 * App-shell styles: loader shown during bootstrap, error screen shown when
 * the SPA fails to render. Served from public/ as a static asset so it is
 * available even if the Vite bundle fails to load.
 */
.app-loader,
.app-error {
  /* Light defaults. Mirror SPA's light palette (Element Plus convention). */
  --shell-color-primary: #006ADC;
  --shell-color-primary-dark: #0058b8;
  --shell-color-primary-50: #ecf3fc;
  --shell-color-primary-100: #dcebfb;
  --shell-color-primary-200: #99c2ef;
  --shell-color-text: #606266;
  --shell-color-text-muted: #909399;
  --shell-color-border: #dcdfe6;
  --shell-color-bg: #fff;
  --shell-font-family: Roboto, -apple-system, BlinkMacSystemFont, "Segoe UI",
                       Helvetica, Arial, sans-serif;

  position: fixed;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  font-size: 14px;
  background: var(--shell-color-bg);
  color: var(--shell-color-text);
}

/*
 * Dark theme overrides. <html class="dark"> is applied very early by
 * app-shell.js based on localStorage['theme'] === '"dark"', mirroring the
 * SPA's useTheme convention so loader/error render in the correct palette
 * from the first paint.
 */
html.dark .app-loader,
html.dark .app-error {
  --shell-color-primary-dark: #2b83e2;
  --shell-color-primary-50: #18222c;
  --shell-color-primary-100: #152d47;
  --shell-color-primary-200: #12355b;
  --shell-color-text: #e5eaf3;
  --shell-color-text-muted: #a3a6ad;
  --shell-color-border: #414243;
  --shell-color-bg: #141414;
}

/* Override .app-error { display: flex } when hidden attribute is set. */
.app-error[hidden] {
  display: none;
}

.app-loader__spinner {
  width: 44px;
  height: 44px;
  animation:
    app-loader-spin 1.4s cubic-bezier(0.65, 0.05, 0.36, 1) infinite,
    app-loader-breathe 2.8s ease-in-out infinite;
  will-change: transform;
  margin-bottom: 14px;
}

@keyframes app-loader-spin {
  0% {
    transform: rotate(0deg);
  }

  100% {
    transform: rotate(360deg);
  }
}

@keyframes app-loader-breathe {
  0%,
  100% {
    opacity: 1;
  }

  50% {
    opacity: 0.85;
  }
}

.app-loader__text {
  font: 400 13px/1 var(--shell-font-family);
  color: var(--shell-color-primary);
  letter-spacing: 0.01em;
  user-select: none;
  transform: translateX(5px);
}

.app-loader__text i {
  display: inline-block;
  font-style: normal;
  animation: app-loader-dot 1.4s ease-in-out infinite;
}

.app-loader__text i:nth-child(1) {
  animation-delay: 0s;
}

.app-loader__text i:nth-child(2) {
  animation-delay: 0.18s;
}

.app-loader__text i:nth-child(3) {
  animation-delay: 0.36s;
}

@keyframes app-loader-dot {
  0%,
  60%,
  100% {
    opacity: 0.25;
    transform: translateY(0);
  }
  30% {
    opacity: 1;
    transform: translateY(-2px);
  }
}

@media (prefers-reduced-motion: reduce) {
  .app-loader__spinner {
    animation: app-loader-spin 2.4s linear infinite;
  }

  .app-loader__text i {
    animation: none;
    opacity: 1;
    transform: none;
  }
}

.app-error__icon {
  margin: 6px 0;
}

.app-error__title,
.app-error__desc {
  margin: 0;
  font-family: var(--shell-font-family);
  line-height: 1.5;
}

.app-error__title {
  font-weight: 500;
  font-size: 16px;
  margin-top: 8px;
  margin-bottom: 4px;
}

.app-error__desc {
  font-weight: 400;
  color: var(--shell-color-text-muted);
}

.app-error__btn {
  margin-top: 8px;
  padding: 0 16px;
  background: transparent;
  border: 1px solid var(--shell-color-border);
  border-radius: 8px;
  font-family: var(--shell-font-family);
  font-weight: 500;
  line-height: 30px;
  cursor: pointer;
  transition: color 0.2s, border-color 0.2s, background-color 0.2s;
  color: inherit;
}

.app-error__btn:hover {
  color: var(--shell-color-primary);
  border-color: var(--shell-color-primary-200);
  background: var(--shell-color-primary-50);
}

.app-error__btn:active {
  color: var(--shell-color-primary-dark);
  border-color: var(--shell-color-primary);
  background: var(--shell-color-primary-100);
}
