/*
 * Прелоадер Phoenix Service — «Banter loader» (девять квадратиков
 * перестраиваются, как фигуры тетриса). Прислал Денис как SCSS; здесь он
 * переведён в обычный CSS: ключевые кадры посчитаны из карты движений
 * оригинала, размеры — через переменные. Глобальные правила оригинала
 * (box-sizing для всех элементов и тёмный фон body) не взяты — они
 * перекрасили бы весь сайт.
 *
 * Отдельный файл, а не часть сборки: нужен до загрузки React — сразу при
 * открытии сайта. Потом тем же элементом #boot-loader управляет
 * GlobalLoader (client/src/components/GlobalLoader.tsx) — показывает его при
 * любой загрузке страницы или данных.
 */

.boot-loader {
  position: fixed;
  inset: 0;
  z-index: 90;
  display: grid;
  place-items: center;
  background: #f3f6fa;
  /* Касания проходят насквозь: прелоадер ничего не блокирует */
  pointer-events: none;
  opacity: 1;
  visibility: visible;
  transition: opacity 0.25s ease, visibility 0s linear 0s;
}
html.dark .boot-loader {
  background: #111621;
}
/* Загрузка внутри уже открытого сайта: страница видна сквозь дымку */
.boot-loader.is-soft {
  background: rgba(243, 246, 250, 0.55);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
}
html.dark .boot-loader.is-soft {
  background: rgba(17, 22, 33, 0.55);
}
.boot-loader.is-hidden {
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.25s ease, visibility 0s linear 0.25s;
}
.boot-loader.is-hidden .banter-loader__box {
  animation-play-state: paused;
}

.banter-loader {
  --bl-box: 16px;
  --bl-gap: 5px;
  --bl-step: calc(var(--bl-box) + var(--bl-gap));
  /* Тёмно-синий (Денис, 2026-09-25) */
  --bl-color: #1b3a6b;
  position: relative;
  width: calc(var(--bl-box) * 3 + var(--bl-gap) * 2);
  height: calc(var(--bl-box) * 3 + var(--bl-gap) * 2);
}
/* На тёмном фоне тёмно-синий не виден — синий светлее */
html.dark .banter-loader {
  --bl-color: #5b8db8;
}
.banter-loader__box {
  float: left;
  position: relative;
  width: var(--bl-box);
  height: var(--bl-box);
  margin-right: var(--bl-gap);
}
.banter-loader__box::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  background: var(--bl-color);
}
.banter-loader__box:nth-child(3n) {
  margin-right: 0;
  margin-bottom: var(--bl-gap);
}
.banter-loader__box:nth-child(1)::before,
.banter-loader__box:nth-child(4)::before {
  margin-left: var(--bl-step);
}
.banter-loader__box:nth-child(3)::before {
  margin-top: calc(var(--bl-step) * 2);
}
.banter-loader__box:last-child {
  margin-bottom: 0;
}

@keyframes bl-move-1 { 9.0909% { transform: translate(calc(var(--bl-step) * -1), 0); } 18.1818% { transform: translate(0, 0); } 27.2727% { transform: translate(0, 0); } 36.3636% { transform: translate(calc(var(--bl-step) * 1), 0); } 45.4545% { transform: translate(calc(var(--bl-step) * 1), calc(var(--bl-step) * 1)); } 54.5455% { transform: translate(calc(var(--bl-step) * 1), calc(var(--bl-step) * 1)); } 63.6364% { transform: translate(calc(var(--bl-step) * 1), calc(var(--bl-step) * 1)); } 72.7273% { transform: translate(calc(var(--bl-step) * 1), 0); } 81.8182% { transform: translate(0, 0); } 90.9091% { transform: translate(calc(var(--bl-step) * -1), 0); } 100% { transform: translate(0, 0); } }
@keyframes bl-move-2 { 9.0909% { transform: translate(0, 0); } 18.1818% { transform: translate(calc(var(--bl-step) * 1), 0); } 27.2727% { transform: translate(0, 0); } 36.3636% { transform: translate(calc(var(--bl-step) * 1), 0); } 45.4545% { transform: translate(calc(var(--bl-step) * 1), calc(var(--bl-step) * 1)); } 54.5455% { transform: translate(calc(var(--bl-step) * 1), calc(var(--bl-step) * 1)); } 63.6364% { transform: translate(calc(var(--bl-step) * 1), calc(var(--bl-step) * 1)); } 72.7273% { transform: translate(calc(var(--bl-step) * 1), calc(var(--bl-step) * 1)); } 81.8182% { transform: translate(0, calc(var(--bl-step) * 1)); } 90.9091% { transform: translate(0, calc(var(--bl-step) * 1)); } 100% { transform: translate(0, 0); } }
@keyframes bl-move-3 { 9.0909% { transform: translate(calc(var(--bl-step) * -1), 0); } 18.1818% { transform: translate(calc(var(--bl-step) * -1), 0); } 27.2727% { transform: translate(0, 0); } 36.3636% { transform: translate(calc(var(--bl-step) * -1), 0); } 45.4545% { transform: translate(calc(var(--bl-step) * -1), 0); } 54.5455% { transform: translate(calc(var(--bl-step) * -1), 0); } 63.6364% { transform: translate(calc(var(--bl-step) * -1), 0); } 72.7273% { transform: translate(calc(var(--bl-step) * -1), 0); } 81.8182% { transform: translate(calc(var(--bl-step) * -1), calc(var(--bl-step) * -1)); } 90.9091% { transform: translate(0, calc(var(--bl-step) * -1)); } 100% { transform: translate(0, 0); } }
@keyframes bl-move-4 { 9.0909% { transform: translate(calc(var(--bl-step) * -1), 0); } 18.1818% { transform: translate(calc(var(--bl-step) * -1), 0); } 27.2727% { transform: translate(calc(var(--bl-step) * -1), calc(var(--bl-step) * -1)); } 36.3636% { transform: translate(0, calc(var(--bl-step) * -1)); } 45.4545% { transform: translate(0, 0); } 54.5455% { transform: translate(0, calc(var(--bl-step) * -1)); } 63.6364% { transform: translate(0, calc(var(--bl-step) * -1)); } 72.7273% { transform: translate(0, calc(var(--bl-step) * -1)); } 81.8182% { transform: translate(calc(var(--bl-step) * -1), calc(var(--bl-step) * -1)); } 90.9091% { transform: translate(calc(var(--bl-step) * -1), 0); } 100% { transform: translate(0, 0); } }
@keyframes bl-move-5 { 9.0909% { transform: translate(0, 0); } 18.1818% { transform: translate(0, 0); } 27.2727% { transform: translate(0, 0); } 36.3636% { transform: translate(calc(var(--bl-step) * 1), 0); } 45.4545% { transform: translate(calc(var(--bl-step) * 1), 0); } 54.5455% { transform: translate(calc(var(--bl-step) * 1), 0); } 63.6364% { transform: translate(calc(var(--bl-step) * 1), 0); } 72.7273% { transform: translate(calc(var(--bl-step) * 1), 0); } 81.8182% { transform: translate(calc(var(--bl-step) * 1), calc(var(--bl-step) * -1)); } 90.9091% { transform: translate(0, calc(var(--bl-step) * -1)); } 100% { transform: translate(0, 0); } }
@keyframes bl-move-6 { 9.0909% { transform: translate(0, 0); } 18.1818% { transform: translate(calc(var(--bl-step) * -1), 0); } 27.2727% { transform: translate(calc(var(--bl-step) * -1), 0); } 36.3636% { transform: translate(0, 0); } 45.4545% { transform: translate(0, 0); } 54.5455% { transform: translate(0, 0); } 63.6364% { transform: translate(0, 0); } 72.7273% { transform: translate(0, calc(var(--bl-step) * 1)); } 81.8182% { transform: translate(calc(var(--bl-step) * -1), calc(var(--bl-step) * 1)); } 90.9091% { transform: translate(calc(var(--bl-step) * -1), 0); } 100% { transform: translate(0, 0); } }
@keyframes bl-move-7 { 9.0909% { transform: translate(calc(var(--bl-step) * 1), 0); } 18.1818% { transform: translate(calc(var(--bl-step) * 1), 0); } 27.2727% { transform: translate(calc(var(--bl-step) * 1), 0); } 36.3636% { transform: translate(0, 0); } 45.4545% { transform: translate(0, calc(var(--bl-step) * -1)); } 54.5455% { transform: translate(calc(var(--bl-step) * 1), calc(var(--bl-step) * -1)); } 63.6364% { transform: translate(0, calc(var(--bl-step) * -1)); } 72.7273% { transform: translate(0, calc(var(--bl-step) * -1)); } 81.8182% { transform: translate(0, 0); } 90.9091% { transform: translate(calc(var(--bl-step) * 1), 0); } 100% { transform: translate(0, 0); } }
@keyframes bl-move-8 { 9.0909% { transform: translate(0, 0); } 18.1818% { transform: translate(calc(var(--bl-step) * -1), 0); } 27.2727% { transform: translate(calc(var(--bl-step) * -1), calc(var(--bl-step) * -1)); } 36.3636% { transform: translate(0, calc(var(--bl-step) * -1)); } 45.4545% { transform: translate(0, calc(var(--bl-step) * -1)); } 54.5455% { transform: translate(0, calc(var(--bl-step) * -1)); } 63.6364% { transform: translate(0, calc(var(--bl-step) * -1)); } 72.7273% { transform: translate(0, calc(var(--bl-step) * -1)); } 81.8182% { transform: translate(calc(var(--bl-step) * 1), calc(var(--bl-step) * -1)); } 90.9091% { transform: translate(calc(var(--bl-step) * 1), 0); } 100% { transform: translate(0, 0); } }
@keyframes bl-move-9 { 9.0909% { transform: translate(calc(var(--bl-step) * -1), 0); } 18.1818% { transform: translate(calc(var(--bl-step) * -1), 0); } 27.2727% { transform: translate(0, 0); } 36.3636% { transform: translate(calc(var(--bl-step) * -1), 0); } 45.4545% { transform: translate(0, 0); } 54.5455% { transform: translate(0, 0); } 63.6364% { transform: translate(calc(var(--bl-step) * -1), 0); } 72.7273% { transform: translate(calc(var(--bl-step) * -1), 0); } 81.8182% { transform: translate(calc(var(--bl-step) * -2), 0); } 90.9091% { transform: translate(calc(var(--bl-step) * -1), 0); } 100% { transform: translate(0, 0); } }

.banter-loader__box:nth-child(1) { animation: bl-move-1 4s infinite; }
.banter-loader__box:nth-child(2) { animation: bl-move-2 4s infinite; }
.banter-loader__box:nth-child(3) { animation: bl-move-3 4s infinite; }
.banter-loader__box:nth-child(4) { animation: bl-move-4 4s infinite; }
.banter-loader__box:nth-child(5) { animation: bl-move-5 4s infinite; }
.banter-loader__box:nth-child(6) { animation: bl-move-6 4s infinite; }
.banter-loader__box:nth-child(7) { animation: bl-move-7 4s infinite; }
.banter-loader__box:nth-child(8) { animation: bl-move-8 4s infinite; }
.banter-loader__box:nth-child(9) { animation: bl-move-9 4s infinite; }

/* Кто просил систему «уменьшить движение» — квадратики стоят на месте:
   прелоадер виден, но не мельтешит. Что идёт загрузка, видно по мягкому
   мерцанию яркости — без перемещений. */
@keyframes bl-fade { from { opacity: 1; } to { opacity: 0.45; } }
@media (prefers-reduced-motion: reduce) {
  .banter-loader__box {
    animation: none !important;
  }
  .banter-loader {
    animation: bl-fade 1.2s ease-in-out infinite alternate;
  }
}
