/*
 * Сплэш загрузки PlanSchedule: анимация «Сборка» фирменного знака ВРесурсе.
 *
 * ЭТО ЕДИНСТВЕННЫЙ ИСТОЧНИК СТИЛЕЙ ЛОАДЕРА. Файл лежит в `sources/web` (корень статики), потому что его
 * подключают ОБА предзагрузочных HTML — `web/index.html` (до загрузки бандла) и `web/ie.html` — обычным
 * `<link rel="stylesheet">`. Ждать бандла (`dist/styles.css` грузится уже после `config/config.js`) они не
 * могут: смысл сплэша в том, чтобы он был на экране ДО приложения. React-версия (`LoadingSplash` в
 * `sources/src/App.tsx`) использует те же классы и получает те же стили как глобальный CSS документа — React
 * монтируется в тот же документ (`createRoot` заменяет содержимое `#root`), отдельного импорта в бандл не
 * нужно: он дал бы вторую копию этих правил в `dist/styles.css` при нулевой пользе.
 *
 * ГЕОМЕТРИЯ — из мастера `extsolutions/planschedule/styles/logo-vresurse-mark.svg` (viewBox 0 0 48 40,
 * штрих 2, скругления 3/3.5; в лоадере при знаке 96×80 — `stroke-width: 1`, то есть те же 2 CSS px).
 * Разметка знака дублируется в двух HTML и в JSX (инлайновый SVG обязателен:
 * анимируются отдельные фигуры, внешний `<img>`/`<use>` до них не достаёт) — расхождение ловит статический
 * тест `docs/tests/functional/loaderFavicon.test.ts`, он сверяет все три места и мастер.
 *
 * ПОЧЕМУ ТАК:
 *  - цвет — одна переменная `--loader-logo-color` (меняется одной строкой), `stroke`/`fill` наследуются
 *    фигурами от корня `svg`, поэтому в разметке нет презентационных атрибутов;
 *  - `transform` в анимации нет вообще: квадраты проявляются только `opacity`. Раньше они росли
 *    `scale(0.6 → 1)`, но тогда концы уже нарисованных линий на мгновение оказывались там, где край фигуры
 *    будет только после роста (линия «висит в воздухе»), а на затухании — наоборот, фигура сжималась под
 *    неподвижной линией. Статичная геометрия убирает этот класс зазоров в принципе;
 *  - базовое (без анимации) состояние фигур — полный видимый знак; вступление рисуют кадры с
 *    `animation-fill-mode: both` (до старта действует кадр 0 % — фигура скрыта). Поэтому выключение анимации
 *    (`prefers-reduced-motion`) автоматически даёт целый статичный знак, а не пустое место;
 *  - `pathLength="100"` в разметке нормирует длину каждого пути: `stroke-dasharray/offset: 100 → 0` — это
 *    «нарисовать от начала до конца» независимо от реальной длины конкретного пути. Штрих НЕ
 *    `non-scaling-stroke`: при нём длины `stroke-dasharray` считаются в CSS-пикселях, а `pathLength` — в
 *    единицах viewBox, и линия обрывалась примерно на половине (вертикальные концы не доезжали до квадратов
 *    и круга). Штрих `stroke-width: 1` при знаке 96×80 (масштаб viewBox 2×) даёт те же 2 CSS px.
 *
 * Проверка: docs/tests/completed/loader-favicon-2026-10-26.md.
 */

/* Центрирование сплэша. Живёт здесь (а не в инлайн-стилях HTML), чтобы React-версия не зависела от
   хост-страницы: `#loading` — единственный узел положения, `transform` на нём нет. */
#loading {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  align-items: center;
  justify-content: center;
}

/* Знак. 96×80 = ровно 2×(48×40) — пропорция viewBox не искажается. Штрих — 1 единица viewBox = 2 CSS px,
   ровно как утверждённая тонкая линия. НЕ `vector-effect: non-scaling-stroke` и НЕ `stroke-width: 2`: при
   не-масштабируемом штрихе Chromium считает `stroke-dasharray` в CSS-пикселях, а `pathLength` — в единицах
   viewBox; dash длиной 100 покрывал лишь половину пути, и вертикальные концы линий не доходили до фигур.
   Фиксированная геометрия знака (96×80, масштаб 2×) делает эквивалентность 1 unit = 2 px постоянной. */
.loader-mark {
  --loader-logo-color: #0047bb;
  --loader-logo-cycle: 1.5s;
  display: block;
  width: 96px;
  height: 80px;
  overflow: visible;
  fill: none;
  stroke: var(--loader-logo-color);
  stroke-width: 1;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Подпись для скринридера: сам знак — декоративная картинка (`aria-hidden` в разметке), состояние
   загрузки объявляет живой регион. Визуально скрыто стандартным приёмом (не `display:none` — иначе
   содержимое не попадёт в дерево доступности). */
.loader-mark__label {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Квадраты: проявляются по очереди со сдвигом 0,09 / 0,17 / 0,26 с. */
.loader-mark__box {
  opacity: 1;
  animation: loader-logo-box var(--loader-logo-cycle) infinite ease-out both;
}

.loader-mark__box--top {
  animation-delay: 0.09s;
}

.loader-mark__box--left {
  animation-delay: 0.17s;
}

.loader-mark__box--right {
  animation-delay: 0.26s;
}

/* Провода: левый рисуется с 0,32 с, правый с 0,43 с. Перемычка — с 0,47 с, когда оба нижних квадрата уже
   полностью проявлены (правый — 0,26 + 0,14·1,5 = 0,47 с): она не появляется раньше соединяемых фигур.
   Пунктир статичный, с штрихами на обоих концах. */
.loader-mark__link {
  stroke-dasharray: 100;
  stroke-dashoffset: 0;
  animation: loader-logo-draw var(--loader-logo-cycle) infinite ease-in-out both;
}

.loader-mark__link--left {
  animation-delay: 0.32s;
}

.loader-mark__link--right {
  animation-delay: 0.43s;
}

.loader-mark__link--bottom {
  stroke-dasharray: 1 2 1;
  animation-name: loader-logo-dash;
  animation-delay: 0.47s;
  animation-timing-function: linear;
}

/* Круг — с 0,58 с; галочка прорисовывается с 0,78 с и завершается ровно к 78 % цикла (1,17 с) —
   с этого момента знак собран целиком, затем плавно гаснет. */
.loader-mark__circle {
  opacity: 1;
  animation: loader-logo-fade var(--loader-logo-cycle) infinite ease-out both;
  animation-delay: 0.58s;
}

.loader-mark__check {
  stroke-dasharray: 100;
  stroke-dashoffset: 0;
  animation: loader-logo-check var(--loader-logo-cycle) infinite ease-out both;
  animation-delay: 0.78s;
}

@keyframes loader-logo-box {
  0% {
    opacity: 0;
  }

  14% {
    opacity: 1;
  }

  78% {
    opacity: 1;
  }

  100% {
    opacity: 0;
  }
}

@keyframes loader-logo-draw {
  0% {
    stroke-dashoffset: 100;
    opacity: 0;
  }

  10% {
    opacity: 1;
  }

  40% {
    stroke-dashoffset: 0;
    opacity: 1;
  }

  78% {
    stroke-dashoffset: 0;
    opacity: 1;
  }

  100% {
    stroke-dashoffset: 0;
    opacity: 0;
  }
}

/* Перемычка — статичный пунктир `1 2 1`: штрихи на обоих концах упираются в квадраты, между ними
   один просвет. `stroke-dashoffset` здесь не анимируется намеренно: на 8-пиксельной перемычке любой
   сдвиг пунктира отрывал один из концов от квадрата («линия не доходит»). */
@keyframes loader-logo-dash {
  0% {
    opacity: 0;
  }

  20% {
    opacity: 1;
  }

  78% {
    opacity: 1;
  }

  100% {
    opacity: 0;
  }
}

@keyframes loader-logo-fade {
  0%,
  100% {
    opacity: 0;
  }

  12% {
    opacity: 1;
  }

  78% {
    opacity: 1;
  }
}

@keyframes loader-logo-check {
  0% {
    stroke-dashoffset: 100;
    opacity: 0;
  }

  8% {
    opacity: 1;
  }

  26% {
    stroke-dashoffset: 0;
    opacity: 1;
  }

  78% {
    stroke-dashoffset: 0;
    opacity: 1;
  }

  100% {
    stroke-dashoffset: 0;
    opacity: 0;
  }
}

/* Системное «уменьшить движение»: анимации нет, знак показан целиком. Сброс свойств продублирован
   явно — не полагаемся на то, что базовые правила останутся «полными» после будущих правок. */
@media (prefers-reduced-motion: reduce) {
  .loader-mark * {
    animation: none !important;
    transition: none !important;
  }

  .loader-mark__box {
    opacity: 1;
    transform: none;
  }

  .loader-mark__link,
  .loader-mark__check {
    stroke-dashoffset: 0;
    opacity: 1;
  }

  /* В статичном знаке перемычка — сплошная, как в брендовом мастере: пунктир нужен только в анимации,
     в reduced-motion знак обязан быть целым. */
  .loader-mark__link--bottom {
    stroke-dasharray: none;
  }

  .loader-mark__circle {
    opacity: 1;
  }
}
