/*
 * НАБОР ДВИЖЕНИЯ — один на PayPage и консоль (оператор 30.09, выбор из галереи:
 * BG-I · BTN-D · ACT-B · ALERT-A · SAVE-B · LOAD-A · NUM-A · LIVE-B · IN-A; справка — docs/motion-pack-2026-09-30.md).
 *
 * Движение = смысл: «в работе», «ждёт действия», «только что изменилось», «загружается», «новая тревога».
 * Каждый примитив — класс; цвет берётся из акцента поверхности: `--motion-accent` = `--pay-accent-fill`
 * на странице заявки, `--admin-info` в консоли (задать свой можно на любом узле). Анимируются только
 * transform, opacity и background-position (у `border-beam` — движение по контуру `offset-distance`,
 * тот же трансформ); вспышка тревоги — разовый переход цвета фона при ВСТАВКЕ узла, не цикл.
 * CSP без unsafe-inline: ни одного inline-стиля, всё здесь.
 *
 *   .stardust > i ×4                              — BG-I: фон «звёздная пыль» (разметка в оболочке страницы)
 *   .live-dot(.is-live|.is-idle) · .halo          — LIVE-B: точка статуса; «в работе» — вращающийся ореол
 *   .live-progress                                — тонкая неопределённая полоса «идёт процесс»
 *   .border-beam > .beam                          — ACT-B: свет, бегущий по рамке (узел .beam — в разметке)
 *   .btn-flow                                     — BTN-D: главная кнопка — медленный перелив акцента
 *   .alert-in                                     — ALERT-A: новая тревога въезжает снизу, фон коротко краснеет
 *   .skeleton (.live-shimmer — прежнее имя)       — LOAD-A: заглушка загрузки с бликом
 *   .number-tick                                  — NUM-A: число сменилось — вспышка и подъём (ставит motion.js)
 *   .fade-up                                      — IN-A: появление ВСТАВЛЕННОГО узла (не на обновлении)
 *   тост «✓ Сохранено» (SAVE-B) — отдельный компонент `shared/toast.{js,css}`.
 *
 * prefers-reduced-motion: всё стоит. Признаки («в работе», «ждёт действия») остаются видимыми
 * неподвижно — ореол, подсвеченная рамка; звёзды стоят; смена числа и новая тревога — только подсветка.
 */
:root{
 --motion-accent:var(--pay-accent-fill,var(--admin-info,currentColor));
 --motion-sheen:color-mix(in srgb,var(--motion-accent) 42%,#fff);
 --motion-alert:var(--pay-red,var(--admin-bad,#e5484d));
 --motion-ease-out:cubic-bezier(.16,1,.3,1);
 /* BG-I: светлые искры на тёмной теме; на светлой — едва заметные тёмные крапины (решение 30.09). */
 --star-color:#cfd6ff;--star-peak:.75;--star-rest:.28;
 /* BTN-D: три тона семейства акцента; каждый держит белый текст ≥ 4.5:1 (поверхность переопределяет). */
 --flow-1:var(--motion-accent);--flow-2:var(--motion-accent);--flow-3:var(--motion-accent);
}
:root[data-theme=light]{--star-color:#5b6978;--star-peak:.32;--star-rest:.12}

/* ---- BG-I: звёздная пыль -------------------------------------------------------- */
/* Слой за всем содержимым: fixed, z-index −1 в корневом контексте (фон страницы — у корня), клики мимо.
   Четыре слоя по 9 точек = 36 точек; точки — радиальные градиенты, нарисованные один раз; мерцает и
   всплывает слой целиком (opacity + transform — только композитор, без перерисовки). Скрытая вкладка —
   анимации браузер останавливает сам. */
.stardust{position:fixed;inset:0;z-index:-1;overflow:hidden;pointer-events:none;contain:strict}
.stardust>i{position:absolute;inset:-12px 0 0;opacity:var(--star-rest);will-change:opacity,transform;
 --d:radial-gradient(circle,var(--star-color) 0 1px,transparent 1.6px);
 --D:radial-gradient(circle,var(--star-color) 0 1.4px,transparent 2px);
 background-repeat:no-repeat;animation:motion-twinkle var(--star-period,7s) ease-in-out var(--star-delay,0s) infinite}
.stardust>i:nth-child(1){--star-period:7s;background-image:var(--d),var(--d),var(--D),var(--d),var(--d),var(--D),var(--d),var(--d),var(--d);
 background-size:4px 4px;background-position:8% 12%,23% 64%,41% 28%,57% 83%,69% 9%,83% 47%,94% 76%,14% 91%,36% 51%}
.stardust>i:nth-child(2){--star-period:9s;--star-delay:-2.3s;background-image:var(--d),var(--D),var(--d),var(--d),var(--d),var(--d),var(--D),var(--d),var(--d);
 background-size:4px 4px;background-position:4% 38%,18% 19%,29% 79%,48% 6%,62% 58%,76% 88%,88% 22%,97% 54%,52% 36%}
.stardust>i:nth-child(3){--star-period:11s;--star-delay:-5.1s;background-image:var(--d),var(--d),var(--d),var(--D),var(--d),var(--d),var(--d),var(--D),var(--d);
 background-size:4px 4px;background-position:11% 58%,27% 7%,34% 95%,45% 71%,61% 33%,72% 17%,80% 66%,91% 5%,66% 97%}
.stardust>i:nth-child(4){--star-period:8s;--star-delay:-6.4s;background-image:var(--d),var(--d),var(--D),var(--d),var(--d),var(--d),var(--d),var(--d),var(--D);
 background-size:4px 4px;background-position:2% 84%,16% 44%,31% 15%,39% 62%,54% 20%,67% 74%,79% 36%,86% 93%,99% 14%}
@keyframes motion-twinkle{0%,100%{opacity:var(--star-rest);transform:translateY(0)}50%{opacity:var(--star-peak);transform:translateY(-10px)}}
/* «Starlight headliner» (30.09, shared/starlight.js): в тёмной теме слой получает холст — неподвижные точки-волокна
   с медленным мерцанием и редкой падающей звездой; CSS-точки тогда прячутся. Размер холста — только здесь (CSP). */
.stardust>canvas{position:absolute;inset:0;display:block;width:100%;height:100%}
.stardust.is-starlight>i{display:none}
/* ⚠ Слой стоит на z-index −1 корневого контекста: фон BODY рисуется ПОВЕРХ него, и небо было не видно там, где страница
   красила body (консоль, превью). Фон страницы — у корня (html), body при слое прозрачен. Корень обязан нести фон сам. */
body:has(>.stardust){background:transparent}

/* ---- LIVE-B: точка статуса и ореол ---------------------------------------------- */
/* Точка — всегда тот же размер (обновление не сдвигает строку); «в работе» — вокруг неё вращается тонкое
   кольцо (::after за пределами точки, раскладку не трогает). `.halo` — самостоятельное кольцо (маяк в чипе). */
.live-dot{--live-size:7px;--halo-gap:3px;--halo-period:1.1s;position:relative;display:inline-block;flex:none;width:var(--live-size);height:var(--live-size);border-radius:50%;background:currentColor;vertical-align:middle}
.live-dot.is-live::after,.halo::after{content:"";position:absolute;inset:calc(-1 * var(--halo-gap));border-radius:50%;pointer-events:none;box-sizing:border-box;
 border:1.5px solid color-mix(in srgb,currentColor 25%,transparent);border-top-color:currentColor;animation:motion-halo var(--halo-period) linear infinite}
.live-dot.is-idle{background:transparent;box-shadow:inset 0 0 0 1.5px currentColor;opacity:.75}
.halo{--halo-size:12px;--halo-gap:0px;--halo-period:1s;position:relative;display:inline-block;flex:none;width:var(--halo-size);height:var(--halo-size);vertical-align:middle}
@keyframes motion-halo{to{transform:rotate(360deg)}}

.live-progress{position:relative;display:block;height:2px;overflow:hidden;border-radius:2px;background:color-mix(in srgb,currentColor 16%,transparent)}
.live-progress::after{content:"";position:absolute;inset:0 auto 0 0;width:38%;border-radius:inherit;background:currentColor;animation:motion-progress 1.6s cubic-bezier(.65,0,.35,1) infinite}
@keyframes motion-progress{0%{transform:translateX(-100%)}100%{transform:translateX(270%)}}

/* ---- ACT-B: свет по рамке -------------------------------------------------------- */
/* Хозяин — `.border-beam` (position задаёт он сам или этот класс); внутри — пустой `<span class="beam">`:
   кольцо толщиной --beam-width лежит на рамке хозяина (--beam-border, 1px) и вырезано маской, по нему бежит пятно света по контуру скругления. */
.border-beam{position:relative;isolation:isolate}
.border-beam>.beam{--beam-width:1.5px;--beam-size:120px;--beam-period:7s;--beam-radius:16px;position:absolute;inset:calc(-1 * var(--beam-border,1px));z-index:0;border-radius:inherit;padding:var(--beam-width);pointer-events:none;overflow:hidden;
 -webkit-mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);-webkit-mask-composite:xor;mask:linear-gradient(#000 0 0) content-box exclude,linear-gradient(#000 0 0)}
.border-beam>.beam::before{content:"";position:absolute;top:0;left:0;width:var(--beam-size);height:var(--beam-size);opacity:0;
 background:radial-gradient(closest-side,var(--motion-sheen),var(--motion-accent) 45%,transparent 100%)}
@supports (offset-path:rect(0 1px 1px 0 round 1px)){
 .border-beam>.beam::before{opacity:1;offset-path:rect(0 100% 100% 0 round var(--beam-radius));offset-anchor:50% 50%;offset-rotate:0deg;animation:motion-beam var(--beam-period) linear infinite}
}
@keyframes motion-beam{from{offset-distance:0%}to{offset-distance:100%}}

/* ---- BTN-D: перелив цвета главной кнопки ----------------------------------------- */
/* Градиент из трёх тонов акцента медленно течёт (сдвиг фона). Специфичность выше `.primary` поверхности;
   наведение и выключенное состояние оставлены поверхности (сплошная заливка — ясный отклик). */
.btn-flow.btn-flow:not(:disabled):not(:hover){background-color:var(--flow-1);background-image:linear-gradient(90deg,var(--flow-1),var(--flow-2),var(--flow-3),var(--flow-1));background-size:300% 100%;animation:motion-flow var(--flow-period,6s) linear infinite}
@keyframes motion-flow{from{background-position:0 0}to{background-position:150% 0}}

/* ---- ALERT-A: въезд и вспышка новой тревоги --------------------------------------- */
/* Ставит motion.js / панель тревог ТОЛЬКО на вставленную строку. Вспышка — от красного оттенка к своему
   фону узла (конечный кадр не задан — берётся фон самого узла). */
.alert-in{animation:motion-alert-in .5s cubic-bezier(.2,.9,.3,1.2) both,motion-alert-flash 1.6s ease-out .25s backwards}
@keyframes motion-alert-in{from{opacity:.001;transform:translateY(12px)}to{opacity:1;transform:none}}
@keyframes motion-alert-flash{from{background-color:color-mix(in srgb,var(--motion-alert) 30%,transparent)}}

/* ---- LOAD-A: заглушка загрузки ---------------------------------------------------- */
.skeleton,.live-shimmer.skeleton{display:block;border-radius:10px;color:transparent;
 background:linear-gradient(100deg,var(--skeleton-base,color-mix(in srgb,currentColor 9%,transparent)) 30%,var(--skeleton-sheen,color-mix(in srgb,currentColor 17%,transparent)) 50%,var(--skeleton-base,color-mix(in srgb,currentColor 9%,transparent)) 70%);
 background-size:300% 100%;animation:motion-skeleton 1.6s linear infinite}
@keyframes motion-skeleton{from{background-position:100% 0}to{background-position:0 0}}
/* Прежнее имя: мерцание текста-заглушки (кабинет клиента) — оставлено как есть. */
.live-shimmer:not(.skeleton){animation:motion-dim 1.8s ease-in-out infinite}
@keyframes motion-dim{0%,100%{opacity:1}50%{opacity:.45}}

/* ---- NUM-A: число только что изменилось ------------------------------------------- */
/* Узел с `data-num` — строчно-блочный, чтобы подъём (transform) работал и не двигал соседей. */
[data-num]{display:inline-block;max-width:100%;position:relative}
.number-tick{isolation:isolate;animation:motion-tick .6s var(--motion-ease-out) both}
.number-tick::after{content:"";position:absolute;inset:-2px -6px;z-index:-1;border-radius:6px;pointer-events:none;background:color-mix(in srgb,var(--motion-accent) 26%,transparent);animation:motion-tick-flash .9s ease-out both}
@keyframes motion-tick{from{opacity:.35;transform:translateY(.32em)}to{opacity:1;transform:none}}
@keyframes motion-tick-flash{from{opacity:1}to{opacity:0}}

/* ---- IN-A: вставленный узел ------------------------------------------------------- */
/* Стартует из «почти видимого» (.001), чтобы узел не пропадал, если анимация не пошла. */
.fade-up{animation:motion-fade-up .34s var(--motion-ease-out) both}
@keyframes motion-fade-up{from{opacity:.001;transform:translateY(8px)}to{opacity:1;transform:none}}

@media (prefers-reduced-motion:reduce){
 .stardust>i{animation:none;opacity:calc((var(--star-rest) + var(--star-peak)) / 2);transform:none}
 .live-dot.is-live::after,.halo::after{animation:none}
 .live-progress::after{animation:none;width:100%;opacity:.55;transform:none}
 .border-beam>.beam::before{animation:none;opacity:0}
 .border-beam>.beam{background:color-mix(in srgb,var(--motion-accent) 55%,transparent)}
 .btn-flow.btn-flow:not(:disabled):not(:hover){animation:none;background-position:0 0}
 .alert-in{animation:motion-alert-flash 1.6s ease-out backwards}
 .skeleton,.live-shimmer.skeleton{animation:none}
 .live-shimmer:not(.skeleton){animation:none;opacity:.7}
 .number-tick{isolation:isolate;animation:none}
 .fade-up{animation:none}
}
