/*
 * Сплэш загрузки 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-mark.svg` (viewBox 0 0 48 48, штрих 3.6,
 * скругления 3.5 / 4.5): шапка-плашка и «занятый день» залиты, крайние дни — контур. Разметка знака
 * дублируется в двух HTML и в JSX (инлайновый SVG обязателен: анимируются отдельные фигуры, внешний
 * `<img>`/`<use>` до них не достаёт) — расхождение ловит статический тест
 * `docs/tests/functional/loaderFavicon.test.ts`, он сверяет все три места, мастер и числа фаз.
 *
 * ПОЧЕМУ ТАК:
 *  - цвет — одна переменная `--loader-logo-color` (меняется одной строкой); `stroke` наследуется фигурами
 *    от `.loader-mark`, заливка задана отдельными правилами, поэтому в разметке нет презентационных
 *    атрибутов и перекраска знака не требует правки трёх HTML/JSX;
 *  - анимируются только `opacity` и `transform` — это композиторные свойства: кадры не вызывают ни
 *    layout, ни paint, сплэш не конкурирует за главный поток с загрузкой бандла. Шапка «въезжает» слева
 *    (`scaleX` от левого края), колонки дней растут из нижнего края канвы (`scaleY` от `bottom`);
 *    геометрия фигур при этом статична (`x/y/width/height` не меняются), поэтому знак нигде не «прыгает»;
 *  - `transform-box: fill-box` обязателен: без него проценты `transform-origin` считаются от габарита
 *    всего SVG, и маленькие колонки росли бы из середины общей канвы, а не из собственного низа;
 *  - базовое (без анимации) состояние фигур — полный видимый знак; вступление рисуют кадры с
 *    `animation-fill-mode: both` (до старта действует кадр 0 % — фигура скрыта). Поэтому выключение
 *    анимации (`prefers-reduced-motion`) автоматически даёт целый статичный знак, а не пустое место;
 *  - фазы идут по смыслу «сборки расписания»: сначала шапка (это неделя), затем дни слева направо;
 *    к 78 % цикла знак собран целиком, дальше плавно гаснет и цикл повторяется.
 *
 * Проверка: docs/tests/functional/loaderFavicon.test.ts.
 */

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

/* Знак. 96×96 = ровно 2×(48×48) — пропорция viewBox не искажается, штрих мастера (3.6 единицы) остаётся
   тем же отношением к габариту, что и в сайдбаре. */
.loader-mark {
  --loader-logo-color: #4f831b;
  --loader-logo-cycle: 1.5s;
  display: block;
  width: 96px;
  height: 96px;
  overflow: visible;
  fill: none;
  stroke: var(--loader-logo-color);
  stroke-width: 3.6;
  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;
}

/* Общие свойства фаз: длительность — от переменной цикла, режим `both` держит и стартовый (скрытый),
   и конечный (погасший) кадр. */
.loader-mark__head,
.loader-mark__slot,
.loader-mark__day {
  transform-box: fill-box;
  animation-duration: var(--loader-logo-cycle);
  animation-iteration-count: infinite;
  animation-timing-function: ease-out;
  animation-fill-mode: both;
}

/* Шапка недели — плашка: въезжает слева, растягиваясь из точки у левого края. */
.loader-mark__head {
  fill: var(--loader-logo-color);
  stroke: none;
  transform-origin: left center;
  animation-name: loader-logo-head;
}

/* Дни: контурные колонки и залитый «занятый день» растут из низа канвы. */
.loader-mark__slot,
.loader-mark__day {
  transform-origin: bottom center;
  animation-name: loader-logo-grow;
}

.loader-mark__slot--left {
  animation-delay: 0.22s;
}

.loader-mark__day {
  fill: var(--loader-logo-color);
  stroke: none;
  animation-delay: 0.34s;
}

.loader-mark__slot--right {
  animation-delay: 0.46s;
}

@keyframes loader-logo-head {
  0% {
    opacity: 0;
    transform: scaleX(0.2);
  }

  14% {
    opacity: 1;
    transform: scaleX(1);
  }

  78% {
    opacity: 1;
    transform: scaleX(1);
  }

  100% {
    opacity: 0;
    transform: scaleX(1);
  }
}

@keyframes loader-logo-grow {
  0% {
    opacity: 0;
    transform: scaleY(0);
  }

  16% {
    opacity: 1;
    transform: scaleY(1);
  }

  78% {
    opacity: 1;
    transform: scaleY(1);
  }

  100% {
    opacity: 0;
    transform: scaleY(1);
  }
}

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

  .loader-mark__head,
  .loader-mark__slot,
  .loader-mark__day {
    opacity: 1;
    transform: none;
  }
}
