﻿/* Градиентные фоны в духе современных mesh-обоев: несколько мягких цветных
   пятен поверх базового тона. Рисуются CSS-градиентами, без изображений и без
   canvas, поэтому не нагружают кадр и работают при reduced-motion. */
.mesh-field{position:fixed;inset:0;z-index:0;pointer-events:none;overflow:hidden;
  opacity:0;transition:opacity .6s ease}
.mesh-field[data-gradient]{opacity:calc(var(--mesh-strength, .55))}
/* До входа настроек ещё нет: начальная страница показывает палитру по
   умолчанию сразу, не дожидаясь ответа /api/ui-settings. Признак data-mesh
   ставит скрипт, поэтому выбранные частицы не включают градиент обратно. */
.mesh-field:not([data-mesh]){--mesh-1:#2f6bff;--mesh-2:#17c8a6;--mesh-3:#7b3ff2;--mesh-4:#1fa2d6;
  opacity:.4}
.mesh-field>span{position:absolute;display:block;border-radius:50%;
  filter:blur(var(--mesh-blur,90px));mix-blend-mode:screen;will-change:transform}
:root[data-theme="light"] .mesh-field>span{mix-blend-mode:multiply;opacity:.55}

/* Пятна расставлены так, чтобы углы экрана не пустовали, а центр оставался
   спокойным: на нём лежит текст. */
.mesh-field>span:nth-child(1){width:62vw;height:62vw;left:-16vw;top:-22vw;background:var(--mesh-1)}
.mesh-field>span:nth-child(2){width:54vw;height:54vw;right:-14vw;top:-10vw;background:var(--mesh-2)}
.mesh-field>span:nth-child(3){width:58vw;height:58vw;left:8vw;bottom:-28vw;background:var(--mesh-3)}
.mesh-field>span:nth-child(4){width:46vw;height:46vw;right:-10vw;bottom:-18vw;background:var(--mesh-4)}

/* Свечение живёт само: пятна медленно плывут и дышат по замкнутому кругу.
   Период в десятки секунд и малая амплитуда — движение заметно боковым
   зрением, но не отвлекает от чтения. */
@keyframes mesh-drift{
  0%,100%{transform:translate3d(0,0,0) scale(1)}
  25%{transform:translate3d(7vw,-4vh,0) scale(1.18)}
  50%{transform:translate3d(2vw,6vh,0) scale(.88)}
  75%{transform:translate3d(-7vw,3vh,0) scale(1.1)}
}
/* Встречное направление у соседних пятен: если все плывут синхронно, картинка
   качается целиком и выглядит как сдвиг страницы, а не как живой свет. */
@keyframes mesh-drift-alt{
  0%,100%{transform:translate3d(0,0,0) scale(1)}
  25%{transform:translate3d(-6vw,5vh,0) scale(.86)}
  50%{transform:translate3d(-2vw,-4vh,0) scale(1.22)}
  75%{transform:translate3d(7vw,-2vh,0) scale(1.04)}
}
:root[data-animations="on"] .mesh-field[data-moving="true"]>span{
  animation:mesh-drift var(--mesh-speed,19s) ease-in-out infinite}
/* Разные длительности и сдвиг фазы: кратные периоды сошлись бы в одну точку,
   и движение стало бы заметно повторяющимся. */
:root[data-animations="on"] .mesh-field[data-moving="true"]>span:nth-child(2){
  animation-name:mesh-drift-alt;animation-duration:23s;animation-delay:-7s}
:root[data-animations="on"] .mesh-field[data-moving="true"]>span:nth-child(3){
  animation-duration:29s;animation-delay:-13s}
:root[data-animations="on"] .mesh-field[data-moving="true"]>span:nth-child(4){
  animation-name:mesh-drift-alt;animation-duration:26s;animation-delay:-17s}
.mesh-field>span:nth-child(2){animation-delay:-9s}
.mesh-field>span:nth-child(3){animation-delay:-19s}
.mesh-field>span:nth-child(4){animation-delay:-28s}

/* Зернистость снимает полосы на градиентах — тот же приём, что у печатных
   постеров. SVG-шум инлайновый: внешних файлов не добавляем. */
.mesh-field:after{content:"";position:absolute;inset:-50%;opacity:.16;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E")}
:root[data-theme="light"] .mesh-field:after{opacity:.1}

/* Палитры. Каждая — четыре согласованных оттенка одного настроения. */
.mesh-field[data-gradient="aurora"]{--mesh-1:#2f6bff;--mesh-2:#17c8a6;--mesh-3:#7b3ff2;--mesh-4:#1fa2d6}
.mesh-field[data-gradient="ember"]{--mesh-1:#f6821f;--mesh-2:#e2413f;--mesh-3:#b3277a;--mesh-4:#f2a93b}
.mesh-field[data-gradient="dusk"]{--mesh-1:#6d3bd4;--mesh-2:#2b4ea8;--mesh-3:#c13e86;--mesh-4:#3c2f86}
.mesh-field[data-gradient="mint"]{--mesh-1:#12a97e;--mesh-2:#2fbfd6;--mesh-3:#8ad13f;--mesh-4:#0f8f9c}
.mesh-field[data-gradient="plum"]{--mesh-1:#9333a8;--mesh-2:#d6418c;--mesh-3:#5a2fb0;--mesh-4:#e0609b}
.mesh-field[data-gradient="slate"]{--mesh-1:#47618c;--mesh-2:#5d7fa6;--mesh-3:#36506f;--mesh-4:#6f88ad}

/* На светлой теме чистые тона выжигают текст: берём приглушённые версии. */
:root[data-theme="light"] .mesh-field[data-gradient="aurora"]{--mesh-1:#8fb4ff;--mesh-2:#86e4d3;--mesh-3:#bfa2fb;--mesh-4:#9bd4ee}
:root[data-theme="light"] .mesh-field[data-gradient="ember"]{--mesh-1:#ffc890;--mesh-2:#f6a5a4;--mesh-3:#e9a0c8;--mesh-4:#ffd9a0}
:root[data-theme="light"] .mesh-field[data-gradient="dusk"]{--mesh-1:#bda6f0;--mesh-2:#a3b7e6;--mesh-3:#eaa7c9;--mesh-4:#aba3e0}
:root[data-theme="light"] .mesh-field[data-gradient="mint"]{--mesh-1:#8fdcc5;--mesh-2:#a3e0ea;--mesh-3:#cbe9a0;--mesh-4:#93d2da}
:root[data-theme="light"] .mesh-field[data-gradient="plum"]{--mesh-1:#dca6e8;--mesh-2:#f0a8c9;--mesh-3:#bfa3e8;--mesh-4:#f3bcd3}
:root[data-theme="light"] .mesh-field[data-gradient="slate"]{--mesh-1:#aebdd6;--mesh-2:#bccbdd;--mesh-3:#9fb1c9;--mesh-4:#c3d0e0}

/* Шапка начальной страницы читается поверх градиента только с подложкой. */
.landing{background:transparent}
.landing-top{z-index:6}

/* --- Начальная страница: тёмное полотно со свечением ---
   Экран входа показывается до выбора оформления, поэтому фон задаётся здесь
   и не зависит от темы кабинета: иначе первый экран выглядел бы по-разному
   у разных посетителей. */
body.landing-view{background:#080a10}
/* Сильное размытие — ключ к мягкости: границы пятен не читаются, свет
   переходит в тень плавно, без видимых краёв. */
body.landing-view .mesh-field{--mesh-blur:170px;opacity:1}
/* Свет разлит по верхней половине широкой пеленой и гаснет книзу. Пятна
   перекрываются и вытянуты по горизонтали, поэтому читается сплошное
   свечение, а не несколько отдельных источников. Низ экрана остаётся тёмным:
   на нём лежат кнопки и список возможностей. */
/* Кобальт и глубокая синь ночной смены. Прежде здесь лежали четыре розовых
   пятна почти в полную силу (.62 и .5): полотно читалось как сплошная заливка,
   и карточки плавали в цвете. Теперь это свет над тёмным залом — тот же приём,
   что у крупных мягких пятен backgrounds.supply: источник угадывается, но ни
   одно пятно не узнаётся по краю. */
/* Свет имеет источник: яркое ядро над заголовком, вокруг — более холодная и
   тёмная синь. Прежде четыре пятна лежали почти равномерно, и верх экрана
   читался как ровная заливка. Теперь виден перепад от центра к углам — то,
   чем живут мягкие градиенты вроде backgrounds.supply. */
body.landing-view .mesh-field>span:nth-child(1){
  width:88vw;height:62vh;left:6vw;top:-30vh;border-radius:50%;
  background:#2563eb;opacity:.5}
body.landing-view .mesh-field>span:nth-child(2){
  width:44vw;height:34vh;left:28vw;top:-12vh;border-radius:50%;
  background:#60a5fa;opacity:.3}
body.landing-view .mesh-field>span:nth-child(3){
  width:66vw;height:52vh;right:-22vw;top:-6vh;left:auto;border-radius:50%;
  background:#1e3a8a;opacity:.52}
body.landing-view .mesh-field>span:nth-child(4){
  display:block;width:62vw;height:46vh;left:-24vw;top:2vh;right:auto;bottom:auto;
  border-radius:50%;background:#1e40af;opacity:.46}
/* Затухание света книзу. Псевдоэлемент лежит ВНУТРИ слоя фона, поэтому
   накрывает пятна, но не содержимое страницы: сам слой находится под ним
   (z-index:0), и заголовок остаётся чистым. */
body.landing-view .mesh-field:before{content:"";position:absolute;inset:0;z-index:1;
  background:linear-gradient(180deg,transparent 24%,rgba(8,10,16,.66) 70%,#080a10 94%)}

/* Токены первого экрана. Карточки, кнопки и разделители лендинга построены
   на --surface/--border/--ink, поэтому достаточно переопределить сами токены:
   вся страница становится тёмной одной правкой, без дублирования правил. */
body.landing-view{
  /* Нейтрали с синим подтоном — ночной зал, а не серый короб. Насыщенность
     держится низкой: поверхность не должна читаться как цвет. */
  --surface:#11141c;--surface-soft:#161a24;--surface-hover:#1c212c;
  --border:#232936;--field-border:#2b323f;
  --ink:#eef0f5;--ink-secondary:#b3bac8;--muted:#98a0b1;--faint:#737c8d;
  /* Кобальт из мира ночных приборов. На тёмной поверхности как текст идёт
     светлая ступень (--accent-ink): сам #3b82f6 даёт на ней 3.6:1. */
  --accent:#3b82f6;--accent-hover:#5a97f8;--accent-soft:#11213c;--accent-ink:#8ab8fc;
  --primary-ink:#fff;--good-bg:#11291f;--good-ink:#4cc38a;
  /* Скидка — отдельный токен, не зелёный «успех»: рядом с ценой зелёный
     ярлык читался как статус. Янтарь даёт тёплую искру на синем полотне и
     не спорит с акцентом. Статусы внутри панели остаются зелёными. */
  --save-bg:#2e2210;--save-ink:#f0b45c;
  --landing-icon-bg:#11213c;--landing-icon-ink:#7fb0fb;
  --landing-contrast-ink:#fff;--landing-note:#858d9d;
  color-scheme:dark;
}

/* Текст на тёмном полотне: белый заголовок и голубые курсивные вставки.
   Цвет вставок светлее самого акцента — на полотне сверху лежит синее
   свечение, и #3b82f6 на нём почти не отличался бы от белого соседа. */
#login-screen .hero-display{color:#fff}
#login-screen .hero-display em{color:#8ab8fc}
#login-screen .hero-role{color:#eef0f5}
#login-screen .hero-kicker,#login-screen .hero-lead{color:#98a0b1}

/* Карточки на тёмном полотне: полупрозрачные, чтобы свечение просвечивало
   сквозь них, а не обрывалось плоским прямоугольником. */
body.landing-view .feature-card,body.landing-view .step-card,
body.landing-view .shot-card,body.landing-view .faq-item,
body.landing-view .price-card,body.landing-view .period-switch{
  background:color-mix(in srgb,var(--surface) 72%,transparent);
  backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px)}
body.landing-view .shot-view,body.landing-view .shot-card img{
  background:color-mix(in srgb,var(--surface-soft) 80%,transparent)}
/* Выделенный тариф отмечен рамкой акцента: розовая тень под карточкой красила
   полотно вокруг неё. */
body.landing-view .price-card.featured{
  border-color:color-mix(in srgb,var(--accent) 45%,var(--border))}

/* Шапка: стеклянная полоса вместо белой плашки. */
body.landing-view .landing-top{
  background:color-mix(in srgb,#080a10 72%,transparent);
  border-bottom-color:#1a1f2a}

/* Кнопки. Основная — заливка акцентом, второстепенная — контурная: сплошная
   белая на тёмном фоне перетягивала бы внимание. Цветное свечение под главной
   кнопкой убрано, её и так видно по заливке. */
body.landing-view .button.primary{background:var(--accent);color:#fff}
body.landing-view .button.primary:hover:not(:disabled){background:var(--accent-hover)}
body.landing-view .button.secondary{background:color-mix(in srgb,#fff 7%,transparent);
  border-color:#2e3542;color:var(--ink)}
body.landing-view .button.secondary:hover:not(:disabled){
  background:color-mix(in srgb,#fff 12%,transparent);border-color:#3d4556}

/* Подвал и разделители. */
body.landing-view .landing-footer{border-top-color:#1a1f2a;color:var(--faint)}

/* --- Переключатель срока: подложка скользит между кнопками ---
   Заливка живёт на отдельном элементе, а не на самой кнопке: переносить
   background с одной кнопки на другую нечем анимировать, а подложку можно
   сдвинуть transform'ом — дёшево и плавно. Её положение и ширину ставит JS
   по реальным размерам кнопки, поэтому разная длина подписей не ломает
   выравнивание. */
/* Подложка переключателя взята от карточки тарифа, только слабее: света сверху
   чуть больше, книзу он гаснет. Ровная заливка рядом с подсвеченной карточкой
   выглядела деталью с другой страницы. */
body.landing-view .period-switch{position:relative;isolation:isolate;
  background:linear-gradient(180deg,rgba(59,130,246,.14),rgba(255,255,255,.05) 70%);
  border-color:rgba(255,255,255,.1)}
body.landing-view .period-thumb{position:absolute;z-index:-1;top:6px;left:0;
  height:calc(100% - 12px);width:0;border-radius:10px;background:var(--accent);
  opacity:0;
  transform:translate3d(var(--thumb-x,0),0,0);
  transition:transform .3s cubic-bezier(.22,1,.36,1),
             width .3s cubic-bezier(.22,1,.36,1),opacity .2s ease}
body.landing-view .period-thumb[data-ready]{opacity:1}
/* Пока подложка не измерена (нет JS), активная кнопка красится сама —
   переключатель остаётся понятным, а не выглядит сломанным. */
body.landing-view .period-thumb[data-ready]~.period-option.selected{background:transparent}
body.landing-view .period-option{position:relative;transition:color .25s ease}
body.landing-view .period-option.selected{color:#fff}

/* --- Смена тарифа: приём Reve (разбор 60fps) ---
   Содержимое уходит вбок, размываясь, и въезжает с другой стороны, проявляясь
   из размытия. Анимируются только opacity, transform и filter — свойства,
   которые не вызывают пересчёт раскладки, поэтому переход держит кадр.
   Уход короче входа (190 мс против 520): так переключение откликается сразу,
   а приходящий вариант успевает прочитаться. */
body.landing-view .price-body{display:contents}
body.landing-view .price-card.is-leaving .price-value,
body.landing-view .price-card.is-leaving .price-note,
body.landing-view .price-card.is-leaving .price-list,
body.landing-view .price-card.is-leaving .price-button{
  animation:reve-leave .19s cubic-bezier(.3,0,.8,.15) forwards}
body.landing-view .price-card.is-leaving.leave-left .price-value,
body.landing-view .price-card.is-leaving.leave-left .price-note,
body.landing-view .price-card.is-leaving.leave-left .price-list,
body.landing-view .price-card.is-leaving.leave-left .price-button{
  animation-name:reve-leave-back}
@keyframes reve-leave{
  to{opacity:0;transform:translate3d(-28px,0,0) scale(.97);filter:blur(10px)}
}
@keyframes reve-leave-back{
  to{opacity:0;transform:translate3d(28px,0,0) scale(.97);filter:blur(10px)}
}
/* Вход: карточка въезжает из-за края и проявляется из размытия. */
body.landing-view .price-card.is-entering .price-value,
body.landing-view .price-card.is-entering .price-note,
body.landing-view .price-card.is-entering .price-button{
  animation:reve-enter .62s cubic-bezier(.16,.84,.26,1) backwards}
body.landing-view .price-card.is-entering.enter-left .price-value,
body.landing-view .price-card.is-entering.enter-left .price-note,
body.landing-view .price-card.is-entering.enter-left .price-button{
  animation-name:reve-enter-back}
/* Цена приходит первой, подпись и кнопка — следом: порядок задаёт, куда
   смотреть, вместо того чтобы показать всё разом. */
body.landing-view .price-card.is-entering .price-note{animation-delay:.07s}
body.landing-view .price-card.is-entering .price-button{animation-delay:.16s}
@keyframes reve-enter{
  from{opacity:0;transform:translate3d(34px,0,0) scale(.97);filter:blur(12px)}
  to{opacity:1;transform:none;filter:blur(0)}
}
@keyframes reve-enter-back{
  from{opacity:0;transform:translate3d(-34px,0,0) scale(.97);filter:blur(12px)}
  to{opacity:1;transform:none;filter:blur(0)}
}
/* Строки списка набираются сверху вниз с шагом 45 мс — та же лесенка, что
   в карусели Reve. Задержка хранится на самой строке: список перерисовывается
   целиком, и привязка к :nth-child играла бы анимацию при любом обновлении. */
body.landing-view .price-card.is-entering .price-list li{
  animation:reve-row .54s cubic-bezier(.16,.84,.26,1) backwards;
  animation-delay:calc(.1s + var(--row-index,0) * 55ms)}
body.landing-view .price-card.is-entering.enter-left .price-list li{
  animation-name:reve-row-back}
@keyframes reve-row{
  from{opacity:0;transform:translate3d(26px,0,0);filter:blur(8px)}
  to{opacity:1;transform:none;filter:blur(0)}
}
@keyframes reve-row-back{
  from{opacity:0;transform:translate3d(-26px,0,0);filter:blur(8px)}
  to{opacity:1;transform:none;filter:blur(0)}
}
/* Вспышка свечения в момент подмены — «затвор» из разбора: короткий импульс
   света подтверждает, что вариант сменился. Объявлена ниже постоянного
   дрейфа (price-glow-drift), иначе тот перебил бы её своей специфичностью;
   обе анимации перечислены вместе, поэтому дрейф не прерывается. */
@keyframes reve-flash{
  0%{opacity:.4;filter:blur(74px)}
  36%{opacity:1;filter:blur(38px)}
  100%{opacity:1;filter:blur(44px)}
}
/* Ярлык скидки проступает на месте: перелёт с увеличением обещал нажатие,
   которого у подписи нет. */
body.landing-view .price-save{animation:price-save-pop .3s cubic-bezier(.22,1,.36,1)}
@keyframes price-save-pop{
  from{opacity:0;transform:translateY(-4px)}
  to{opacity:1;transform:none}
}

/* --- Карточка тарифа: тёмное полотно со своим свечением внутри --- */
body.landing-view .price-card{position:relative;overflow:hidden;isolation:isolate;
  width:min(820px,100%);padding:clamp(40px,6vw,72px) clamp(24px,5vw,64px);
  border-radius:28px;background:#0c0f16;border:1px solid #1c222e;
  backdrop-filter:none;-webkit-backdrop-filter:none;text-align:center}
/* Прежде здесь дрейфовали три розовых пятна — цветная каша на пол-карточки.
   Свечение осталось, но стало одним источником: кобальтовое пятно вверху по
   центру, ровно над ценой, и то же пятно слабее снизу, чтобы низ карточки не
   обрывался чёрной полосой. Направление повторяет полотно лендинга — свет
   приходит сверху, поэтому карточка читается как вырезанное из него окно, а
   не как чёрный прямоугольник, положенный поверх.
   Пятна радиальные и размыты своим же радиусом: отдельный filter: blur здесь
   создал бы слой композитинга на всю карточку ради неподвижной картинки. */
body.landing-view .price-glow{position:absolute;inset:0;z-index:-1;
  background:
    radial-gradient(86% 58% at 50% -6%,rgba(96,165,250,.3),rgba(59,130,246,.12) 48%,rgba(59,130,246,0) 76%),
    radial-gradient(78% 46% at 50% 106%,rgba(37,99,235,.26),rgba(37,99,235,0) 74%),
    linear-gradient(180deg,#141b28,#0c0f16 58%);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.1)}
/* Цена — самая крупная строка карточки, поэтому ей довольно размера: курсивная
   засечка и подсветка добавляли приём там, где он ничего не различал. */
body.landing-view .price-value{justify-content:center;gap:12px;border-bottom:0;
  padding-bottom:0;margin:0 0 clamp(24px,4vh,36px)}
body.landing-view .price-lead{font-size:clamp(16px,1.8vw,20px);color:#9aa2b3;
  font-weight:400;align-self:center}
body.landing-view .price-value strong{font-weight:500;
  font-size:clamp(36px,4.8vw,56px);letter-spacing:-.03em;color:#fff;
  font-variant-numeric:tabular-nums}
body.landing-view .price-value span:not(.price-lead):not(.price-save){
  color:#c3cad8;font-size:clamp(14px,1.6vw,18px)}
/* Список возможностей: галочки вместо маркеров, выровнены по левому краю
   общего блока — иначе строки разной длины «пляшут» относительно центра. */
body.landing-view .price-list{width:fit-content;max-width:100%;margin:0 auto;
  gap:clamp(12px,2vh,18px);text-align:left}
body.landing-view .price-list li{padding-left:34px;
  font-size:clamp(15px,1.7vw,19px);color:#eef0f5;line-height:1.45}
body.landing-view .price-list li:before{content:"";left:2px;top:.34em;
  width:17px;height:9px;border:0;border-left:2.4px solid #fff;
  border-bottom:2.4px solid #fff;border-radius:1px;background:none;
  transform:rotate(-45deg)}
/* Кнопка белая на тёмной карточке: самый светлый элемент читается как главное
   действие, и акцент остаётся свободен для состояний внутри панели. */
body.landing-view .price-button{margin:clamp(28px,5vh,44px) auto 0;
  width:fit-content;min-height:48px;padding:0 24px;border-radius:10px;
  background:#fff;color:#0c0f16;font-weight:500;border:0;
  box-shadow:0 8px 24px rgba(0,0,0,.28)}
body.landing-view .price-button:hover:not(:disabled){background:#f0f0f4}

/* --- Стрелки листания на тёмном полотне ---
   Стеклянные, под стать карточкам: сплошная плашка рядом с подсвеченной
   карточкой читалась бы как вторая кнопка действия. */
body.landing-view .plan-arrow{
  background:color-mix(in srgb,#fff 6%,transparent);
  border-color:rgba(255,255,255,.12);color:#c3cad8;
  backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px)}
body.landing-view .plan-arrow:hover:not(:disabled){
  background:rgba(255,255,255,.1);
  border-color:rgba(255,255,255,.2);color:#fff}
/* Карточка занимает всю ширину узкого экрана: стрелки переносятся под неё,
   иначе они отжали бы цену и список. */
@media(max-width:900px){
  .plan-row{flex-wrap:wrap}
  .plan-row .price-card{order:1;flex:1 0 100%}
  .plan-arrow{order:2;width:46px;height:46px}
  .plan-arrow svg{width:19px;height:19px}
}
body.landing-view .price-note,body.landing-view .price-foot{color:#98a0b1}
/* Значок внутри карточки: при overflow:hidden выступающий за край обрезался
   бы наполовину. */
body.landing-view .price-badge{position:static;transform:none;
  display:inline-block;margin:0 auto clamp(20px,3vh,30px);
  background:rgba(255,255,255,.12);color:#fff;
  border:1px solid rgba(255,255,255,.18);backdrop-filter:blur(6px)}

/* Светлая тема не осветляет первый экран: полотно задумано тёмным, и белый
   текст на светлом фоне стал бы нечитаемым. */
:root[data-theme="light"] body.landing-view{background:#080a10}

/* --- Кабинет: то же полотно, что на первом экране ---
   Приём с лендинга: сильное размытие, крупные перекрывающиеся пятна и
   затухание книзу. Мелкие пятна по углам с размытием 90px читались как
   четыре отдельных источника, а не как разлитый свет. Цвета берутся из
   выбранной палитры (--mesh-1…4), поэтому правило работает и для aurora по
   умолчанию, и для любой другой. Лендинг свои размеры задаёт ниже по файлу
   и этим правилом не затрагивается. */
body:not(.landing-view) .mesh-field{--mesh-blur:140px}
body:not(.landing-view) .mesh-field>span:nth-child(1){
  width:92vw;height:68vh;left:-20vw;top:-26vh}
body:not(.landing-view) .mesh-field>span:nth-child(2){
  width:64vw;height:54vh;right:-14vw;top:-12vh}
body:not(.landing-view) .mesh-field>span:nth-child(3){
  width:72vw;height:52vh;left:-8vw;bottom:-22vh;top:auto}
body:not(.landing-view) .mesh-field>span:nth-child(4){
  width:58vw;height:44vh;right:-10vw;bottom:-16vh;top:auto}
/* Низ экрана притушен: на нём лежат таблицы и формы, и пёстрый фон под ними
   мешал бы читать. Псевдоэлемент внутри слоя, поэтому накрывает только пятна.
   Тон затемнения привязан к фону темы: в светлой гасить нечем, там слой
   прозрачен и работает только общая прозрачность --mesh-strength. */
body:not(.landing-view) .mesh-field:before{content:"";position:absolute;inset:0;z-index:1;
  background:linear-gradient(180deg,transparent 30%,
    color-mix(in srgb,var(--bg) 55%,transparent) 76%,
    color-mix(in srgb,var(--bg) 88%,transparent) 100%)}
@media(max-width:720px){
  /* Размытие — самая дорогая операция кадра, на телефоне оно меньше. */
  body:not(.landing-view) .mesh-field{--mesh-blur:70px}}

@media(prefers-reduced-motion:reduce){
  /* Градиент остаётся — он статичен и не мешает; двигаться он перестаёт. */
  .mesh-field>span{animation:none!important}
}
@media(max-width:720px){
  /* На телефоне размытие в 90px — самая дорогая операция кадра. */
  .mesh-field{--mesh-blur:60px}
  .mesh-field>span{animation:none!important}
}
