/* Экран загрузки «Маркер, по словам»: маркер выделяет сначала «Маркеры», затем «онлайн».
   Держится с первого кадра до тех пор, пока Blazor не подменит содержимое #app.
   Разметка живёт в index.html внутри <div id="app">.

   Два свойства этой заставки, ради которых она такая:

   1. Надпись читается с нулевого кадра — движется только подсветка. Загрузка регулярно
      обгоняет анимацию, и обрыв на любом проценте не должен выглядеть недорисованным.

   2. Всё движение — только transform и opacity, то есть целиком на композиторе.
      Прошлая заставка на stroke-dashoffset замирала вместе с главным потоком, который
      Blazor занимает на финальной инициализации; это и читалось как «подвисло».
      Замер через CDP-скринкаст за 1,4 с блокировки потока: transform — 84 кадра,
      stroke-dashoffset — 1, clip-path — 0. Поэтому здесь нет ни того, ни другого.

   Шрифт объявлен отдельным семейством по двум причинам. Во-первых, у 'Blue Curve' в app.css
   стоит font-display: swap, из-за чего надпись успела бы моргнуть системным шрифтом.
   Во-вторых, это субсет ровно под «Маркеры онлайн» — 10 глифов и пробел, 3,5 КБ вместо 39,9 КБ
   у полного Bluecurve-Bold.ttf. Полный файл в приложении нужен только на FantasyLeaguePage,
   и тащить его на критический путь каждой загрузки ради одной надписи незачем.

   Хинтинг намеренно сохранён, хотя без него субсет весил бы 1,3 КБ: с --no-hinting
   растеризация на 62px отличалась от оригинала, а с ним рендер совпадает попиксельно.

   Пересобрать субсет после правки текста заставки (текст должен совпадать с разметкой в index.html):
     python -m fontTools.subset fonts/blue-curve/Bluecurve-Bold.ttf \
         --text="Маркеры онлайн" --flavor=woff2 \
         --output-file=fonts/blue-curve/Bluecurve-Boot.woff2 */
@font-face {
    font-family: 'Blue Curve Boot';
    font-style: normal;
    font-weight: 700;
    font-display: block;
    /* ?v=… обязателен: на /fonts/* в staticwebapp.config.json стоит immutable на год.
       Плейсхолдер подменяет workflow деплоя — он прогоняет sed по этому файлу вместе с index.html.
       URL обязан совпадать с <link rel="preload"> в index.html, иначе предзагрузка уйдёт впустую. */
    src: url('/fonts/blue-curve/Bluecurve-Boot.woff2?v=252d910') format('woff2');
}

.boot {
    position: fixed; inset: 0; z-index: 9999;
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 34px; padding: 24px;
}

.boot__mark {
    font-family: 'Blue Curve Boot', 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    font-weight: 700;
    font-size: clamp(1.6rem, 7vw, 3rem);
    letter-spacing: .015em;
    white-space: nowrap;
    user-select: none;
}

/* Слово — самостоятельная система координат: полоса и подсветка позиционируются
   от него, поэтому под каждое слово не нужно считать смещения вручную. */
.boot__word { position: relative; display: inline-block; }
.boot__gap { display: inline-block; width: .3em; }

.boot__dim { position: relative; color: #7b5560; }

.boot__band {
    position: absolute; left: -3%; top: 12%; width: 106%; height: 78%;
    background: linear-gradient(90deg, rgba(255, 59, 71, .58), rgba(255, 59, 71, .4));
    box-shadow: 0 0 18px rgba(255, 59, 71, .35);
    border-radius: .12em .45em .28em .14em;
    transform: skewX(-7deg) scaleX(1);
    transform-origin: left center;
}

/* Композитная развёртка подсветки. Окно едет вправо, текст внутри — на столько же влево,
   поэтому сам текст стоит неподвижно, а открывается только область видимости.
   Оба движения — transform, и clip-path, который замирает на занятом потоке, здесь не нужен. */
.boot__win {
    position: absolute; inset: 0;
    overflow: hidden;
    transform: translateX(-100%);
}
.boot__lit {
    display: block;
    color: #fff4f5;
    transform: translateX(100%);
}

.boot__card {
    background: #23262b; border-radius: 16px; padding: 32px 40px;
    min-width: 340px; box-shadow: 0 4px 32px #000a;
}
.boot__title { color: #fff; font-size: 1.3rem; text-align: center; margin-bottom: 18px; }
.boot__hint { color: #fff; font-size: 1rem; text-align: center; margin-bottom: 18px; }
.boot__track {
    width: 100%; height: 6px; background: #181a1f;
    border-radius: 4px; overflow: hidden; position: relative;
}
.boot__bar {
    position: absolute; left: 0; top: 0; height: 100%; width: 100%;
    background: #ff3b47; border-radius: 4px; will-change: transform;
    animation: boot-indeterminate 2s cubic-bezier(0.4, 0, 0.2, 1) infinite;
}

/* Цикл 2,6 с: «Маркеры» выделены к 0,18 с, «онлайн» к 0,39 с, дальше оба слова стоят
   выделенными до 2,08 с и только потом полосы гаснут.

   Тайминг подобран под замеренное время жизни заставки, а не на глаз:
     - QA, холодный кеш            1819 мс
     - QA, прогретый кеш       997 и 856 мс
     - анимация стартует на 114-144 мс позже начала документа (разбор CSS и первый кадр)

   То есть в худшем случае на всю отрисовку есть около 710 мс. Первая версия докрашивала
   второе слово к 0,84 с плюс стартовая задержка — не помещалось вообще, и «онлайн»
   выглядело так, будто оно не красится совсем. Сейчас оба слова выделены примерно
   к 0,52 с от начала документа, запас порядка 340 мс, а гашение в типичный сеанс не попадает.

   Если заставка станет ещё короче, сжимать дальше некуда без превращения штриха в мигание:
   тогда правильнее сделать стартовым состоянием «оба слова выделены», а анимацию —
   повторным проходом поверх уже выделенного. */
.boot__word--a .boot__band { animation: boot-band-a 2.6s cubic-bezier(.5, 0, .2, 1) infinite; }
.boot__word--a .boot__win  { animation: boot-win-a  2.6s cubic-bezier(.5, 0, .2, 1) infinite; }
.boot__word--a .boot__lit  { animation: boot-lit-a  2.6s cubic-bezier(.5, 0, .2, 1) infinite; }

.boot__word--b .boot__band { animation: boot-band-b 2.6s cubic-bezier(.5, 0, .2, 1) infinite; }
.boot__word--b .boot__win  { animation: boot-win-b  2.6s cubic-bezier(.5, 0, .2, 1) infinite; }
.boot__word--b .boot__lit  { animation: boot-lit-b  2.6s cubic-bezier(.5, 0, .2, 1) infinite; }

/* opacity выписана и в стартовом, и в удерживающих кадрах не для красоты: если свойство
   стоит только в финальном кадре, браузер берёт неявный 0%-кадр из вычисленного стиля
   и гасит полосу линейно через весь цикл — она читается блёклой вместо красной. */
@keyframes boot-band-a {
    0%       { transform: skewX(-7deg) scaleX(0); opacity: 1; }
    7%, 80%  { transform: skewX(-7deg) scaleX(1); opacity: 1; }
    100%     { transform: skewX(-7deg) scaleX(1); opacity: 0; }
}
@keyframes boot-win-a {
    0%       { transform: translateX(-100%); opacity: 1; }
    7%, 80%  { transform: translateX(0); opacity: 1; }
    100%     { transform: translateX(0); opacity: 0; }
}
@keyframes boot-lit-a {
    0%       { transform: translateX(100%); }
    7%, 100% { transform: translateX(0); }
}

@keyframes boot-band-b {
    0%, 5%    { transform: skewX(-7deg) scaleX(0); opacity: 1; }
    15%, 80%  { transform: skewX(-7deg) scaleX(1); opacity: 1; }
    100%      { transform: skewX(-7deg) scaleX(1); opacity: 0; }
}
@keyframes boot-win-b {
    0%, 5%    { transform: translateX(-100%); opacity: 1; }
    15%, 80%  { transform: translateX(0); opacity: 1; }
    100%      { transform: translateX(0); opacity: 0; }
}
@keyframes boot-lit-b {
    0%, 5%    { transform: translateX(100%); }
    15%, 100% { transform: translateX(0); }
}

@keyframes boot-indeterminate {
    from { transform: translateX(-100%); }
    to   { transform: translateX(100%); }
}

@media (max-width: 500px) {
    .boot { gap: 26px; }
    .boot__card { min-width: 90vw; padding: 24px 8vw; }
}

/* Ветки prefers-reduced-motion здесь намеренно нет: цикл должен крутиться
   у всех одинаково, пока идёт загрузка. */
