/* ────────────────────────────────────────────────────────────────────────────
   «СТЕКЛЯННЫЙ» ЗНАК, КОТОРЫЙ ЗАПОЛНЯЕТСЯ ЦВЕТОМ. ЗАСТАВКА И ЗАГРУЗКА РАЗДЕЛОВ.

   Просьба владельца от 12.11.2026: при открытии страницы знак сначала
   прозрачный, как стекло, потом заполняется красками своего цвета.

   ПОЧЕМУ ЭТОТ ФАЙЛ ЛЕЖИТ В public/, А НЕ В src/styles.
   Заставка стоит в index.html и обязана быть нарисована до того, как
   доедет приложение: в этом её смысл. Стили приложения в dev-режиме
   приезжают вместе со скриптом, то есть позже. Отсюда же правила берёт
   и знак загрузки внутри приложения (src/core/layout/BrandLoader.tsx),
   чтобы движение было описано один раз.

   ЦВЕТА ЗАДАНЫ ЛИТЕРАЛАМИ по той же причине: токенов темы к первому кадру
   ещё может не быть. Тему к этому моменту уже поставил theme-early.js
   (атрибут data-theme на <html>). От цвета подложки знак не зависит вовсе,
   см. ниже про вырез.

   КАК УСТРОЕН ЗНАК. Он нарисован дважды: стеклом и в цвете. Зазор между
   потоком и буквой здесь настоящий вырез (маска), а не мазок цветом фона,
   как в BrandMark: знак загрузки стоит и на странице, и на карточках,
   и под свечением, и мазок чужого цвета был бы виден на каждом из них.

   КАК УСТРОЕНА ЗАЛИВКА. Цветной знак лежит поверх стеклянного и обрезан
   уровнем краски (clipPath с волной по верху).
   Уровень едет вверх вместе с группой, на которой висит обрезка, а сам
   цветной знак внутри неё едет ровно навстречу и потому стоит на месте.
   Так сделано вместо анимации фигур ВНУТРИ маски: Safari такую анимацию
   не перерисовывает, и знак там остался бы стеклянным навсегда. Отсюда
   правило: у каждой пары (rise и unrise, wave и unwave) длительность,
   задержка и кривая обязаны совпадать, иначе цветной знак поедет.

   С КЕМ ОБЯЗАН СОВПАДАТЬ. Разметка знака повторена дважды: в index.html
   (заставка, контуры строками) и в BrandLoader.tsx (контуры константами из
   brand-glyph.ts). Группы, классы, вырез и обрезка у них обязаны быть
   одни и те же: совпадение стережёт web/test/contract.ts, раздел 23.
   ──────────────────────────────────────────────────────────────────────────── */

.brand-loader {
  /* Стекло: кромка, три цвета тела (свет сверху, тень в толще, отсвет
     снизу) и блик. */
  --bl-rim: #a9b9e8;
  --bl-body-a: #f6f8ff;
  --bl-body-b: #d6e0f7;
  --bl-body-c: #eaf0fd;
  --bl-shine: #ffffff;
  display: block;
  overflow: visible;
}

:root[data-theme='dark'] .brand-loader {
  --bl-rim: #4c5fa8;
  --bl-body-a: #22326c;
  --bl-body-b: #0c1432;
  --bl-body-c: #172452;
  --bl-shine: #93a6ec;
}

.brand-loader path {
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Уровень краски (фигура обрезки) закрашен, а не обведён. */
.brand-loader clipPath path {
  fill: #fff;
  stroke: none;
}

/* Вырез под поток: маска, чёрное в ней убирает. */
.brand-loader mask path {
  stroke: #000;
}

.brand-loader .bl-rim {
  stroke: var(--bl-rim);
}

.brand-loader .bl-shine {
  stroke: var(--bl-shine);
  opacity: 0.9;
}

.brand-loader .bl-shine--low {
  opacity: 0.45;
}

.brand-loader .bl-stop-a {
  stop-color: var(--bl-body-a);
}

.brand-loader .bl-stop-b {
  stop-color: var(--bl-body-b);
}

.brand-loader .bl-stop-c {
  stop-color: var(--bl-body-c);
}

/* ── Движение ────────────────────────────────────────────────────────────── */

/* Уровень поднимается снизу вверх, цветной знак едет навстречу. */
.brand-loader__rise {
  animation: bl-rise 0.9s cubic-bezier(0.4, 0, 0.25, 1) 0.08s both;
}

.brand-loader__unrise {
  animation: bl-unrise 0.9s cubic-bezier(0.4, 0, 0.25, 1) 0.08s both;
}

/* Волна по верху уровня бежит вбок, цветной знак опять же навстречу. */
.brand-loader__wave {
  animation: bl-wave 1.1s linear infinite;
}

.brand-loader__unwave {
  animation: bl-unwave 1.1s linear infinite;
}

/* Загрузка внутри приложения может длиться сколько угодно: уровень ходит
   вверх и вниз, а не изображает прогресс, которого знак не знает. */
.brand-loader--loop .brand-loader__rise {
  animation: bl-rise 1.15s cubic-bezier(0.45, 0, 0.55, 1) infinite alternate;
}

.brand-loader--loop .brand-loader__unrise {
  animation: bl-unrise 1.15s cubic-bezier(0.45, 0, 0.55, 1) infinite alternate;
}

/* Залитый знак на заставке не замирает: мягко дышит свечением. Свечение
   висит на самом <svg>, а не на группе внутри: функции filter из CSS
   на внутренних элементах SVG Safari не понимает. */
#boot-splash .brand-loader {
  animation: bl-glow 1.9s ease-in-out 1s infinite;
}

/* Знак занимает по высоте от 8 до 291, волна ходит на 9 вверх и вниз:
   уровень идёт от 302 (пусто) до -8 (залито), без холостого хода. */
@keyframes bl-rise {
  from {
    transform: translateY(302px);
  }
  to {
    transform: translateY(-8px);
  }
}

@keyframes bl-unrise {
  from {
    transform: translateY(-302px);
  }
  to {
    transform: translateY(8px);
  }
}

@keyframes bl-wave {
  from {
    transform: translateX(0);
  }
  to {
    transform: translateX(-150px);
  }
}

@keyframes bl-unwave {
  from {
    transform: translateX(0);
  }
  to {
    transform: translateX(150px);
  }
}

@keyframes bl-glow {
  0%,
  100% {
    filter: drop-shadow(0 0 0 rgb(22 104 255 / 0));
  }
  50% {
    filter: drop-shadow(0 8px 18px rgb(22 104 255 / 0.34));
  }
}

/* ── Заставка на открытии страницы ───────────────────────────────────────── */

#boot-splash {
  position: fixed;
  inset: 0;
  z-index: 2147483000;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background: #f4f6fb;
  opacity: 1;
  transition:
    opacity 0.36s ease,
    visibility 0s linear 0.36s;
}

:root[data-theme='dark'] #boot-splash {
  background: #070c1f;
}

#boot-splash .brand-loader {
  width: 132px;
  height: 132px;
  transition: transform 0.36s cubic-bezier(0.2, 0.7, 0.2, 1);
}

/* Приложение готово: заставка растворяется, знак чуть подаётся вперёд. */
#boot-splash.is-done {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}

#boot-splash.is-done .brand-loader {
  transform: scale(1.1);
}

/* Слова под знаком. Места они не занимают, чтобы знак не прыгал, когда
   они появляются. */
#boot-splash .boot-message {
  position: absolute;
  top: calc(50% + 96px);
  left: 50%;
  width: min(30rem, 100vw - 48px);
  margin: 0;
  transform: translateX(-50%);
  font:
    500 14px/1.5 system-ui,
    -apple-system,
    'Segoe UI',
    sans-serif;
  text-align: center;
  color: #5b6680;
  opacity: 0;
  visibility: hidden;
}

:root[data-theme='dark'] #boot-splash .boot-message {
  color: #9aa6c8;
}

/* Приложение молчит двенадцать секунд: скрипт не доехал или связь очень
   медленная. Скрипта, который сказал бы об этом, как раз и нет, поэтому
   слова проявляет сам CSS. Залитый знак без слов выглядел бы как «вот-вот
   откроется» сколько угодно долго. */
#boot-splash .boot-message--slow {
  animation: boot-late 0.4s ease 12s forwards;
}

@keyframes boot-late {
  to {
    opacity: 1;
    visibility: visible;
  }
}

/* Приложение сказало само, что не загрузилось: знак пустеет и замирает,
   под ним слова об отказе вместо слов об ожидании. Отказ мог застать
   заставку посреди растворения: она возвращается сразу, без перехода. */
#boot-splash.is-failed {
  transition: none;
}

#boot-splash.is-failed .boot-message--failed {
  opacity: 1;
  visibility: visible;
}

/* Приложение работало и упало целиком: заставку вернул splash.ts, и слова
   под знаком другие. «Не загрузилась» о консоли, в которой человек только
   что работал, было бы неправдой. Правила стоят ниже правил отказа и той
   же силы, поэтому перекрывают их. */
#boot-splash.is-crashed .boot-message--failed {
  opacity: 0;
  visibility: hidden;
}

#boot-splash.is-crashed .boot-message--crashed {
  opacity: 1;
  visibility: visible;
}

#boot-splash.is-failed .boot-message--slow {
  animation: none;
}

#boot-splash.is-failed .brand-loader,
#boot-splash.is-failed .brand-loader__rise,
#boot-splash.is-failed .brand-loader__unrise,
#boot-splash.is-failed .brand-loader__wave,
#boot-splash.is-failed .brand-loader__unwave {
  animation: none;
}

#boot-splash.is-failed .brand-loader__rise {
  transform: translateY(302px);
}

#boot-splash.is-failed .brand-loader__unrise {
  transform: translateY(-302px);
}

/* Человек просил меньше движения: знак сразу залит, без волны и свечения. */
@media (prefers-reduced-motion: reduce) {
  .brand-loader__rise,
  .brand-loader--loop .brand-loader__rise {
    animation: none;
    transform: translateY(-8px);
  }

  .brand-loader__unrise,
  .brand-loader--loop .brand-loader__unrise {
    animation: none;
    transform: translateY(8px);
  }

  .brand-loader__wave,
  .brand-loader__unwave,
  #boot-splash .brand-loader {
    animation: none;
  }

  #boot-splash,
  #boot-splash .brand-loader {
    transition: none;
  }
}
