/* Текст посадочных со студией (INT-80). Собирает scripts/landings/studio-lp.cjs
   из макетов SEO-отдела — руками не править, правки вносить в макет и пересобирать. */

/* Студия стоит в масштабе 0.9 (app.css: html { zoom: .9 }), текст в
   макетах — в полном размере: возвращаем ему 1. */
.lpt { zoom: calc(1 / .9); background: var(--lv-bg); color: var(--lv-text-1, #F4F2F7); }
.lpt a { text-decoration: none; }
/* ============================================================
   LUVI — ТОКЕНЫ И UI-КИТ
   Версия 1.0 · 18.09.2026

   Значения вынуты из боевого приложения (luvi-live/css/app.css),
   они совпадают с ним до символа. Компоненты названы с приставкой
   `lv-`, чтобы кит можно было положить в чужую вёрстку и ничего
   там не задеть.

   Порядок в файле: токены, база, типографика, компоненты,
   цветные поверхности, раскладка, телефон.
   ============================================================ */

/* ------------------------------------------------------------
   1. ТОКЕНЫ
   ------------------------------------------------------------ */
:root {
  /* цвет */
  --lv-bg: #0C0B10;
  --lv-surface-1: #15141B;
  --lv-surface-2: #1C1B23;
  --lv-surface-3: #24232C;
  --lv-surface-hover: #2A2933;

  --lv-text-1: #F7F5F1;
  --lv-text-2: #CFCCD6;
  --lv-text-3: #A09CAA;
  --lv-text-ph: #6E6A79;   /* подсказка в поле: темнее обычного текста */

  --lv-border-1: rgba(255, 255, 255, .10);   /* заметная рамка */
  --lv-border-2: rgba(255, 255, 255, .06);   /* тихая рамка */

  --lv-accent: #FD429C;
  --lv-accent-hover: #E0388C;
  --lv-accent-soft: rgba(253, 66, 156, .14);
  --lv-grad: linear-gradient(115deg, #FF8A18 0%, #FB4595 62%, #E83B8A 100%);

  --lv-success: #2FBE7A;
  --lv-warning: #F5A65C;
  --lv-error: #FF6B5E;

  /* отступы раскладки. Ступени 5 нет намеренно: её отсутствие
     не даёт подбирать промежуточные значения на глаз */
  --lv-s1: 4px;  --lv-s2: 8px;   --lv-s3: 12px; --lv-s4: 16px;
  --lv-s6: 24px; --lv-s8: 32px;  --lv-s12: 48px; --lv-s16: 64px;
  /* Ступень только для сайта. В приложении её нет и быть не должно:
     секции лендинга дышат шире экранов сервиса, 64 там мало. */
  --lv-s24: 96px;

  /* радиусы */
  --lv-r-sm: 8px; --lv-r-md: 12px; --lv-r-lg: 16px; --lv-r-full: 999px;

  /* тень одна на систему и только у того, что всплывает над страницей */
  --lv-shadow-overlay: 0 16px 40px rgba(0, 0, 0, .45);
  /* выделение — одно мягкое кольцо, двойного контура быть не должно */
  --lv-ring: 0 0 0 3px rgba(253, 66, 156, .22);

  --lv-font-ui: "Mulish", -apple-system, "Segoe UI", sans-serif;
  --lv-font-head: "Onest", "Mulish", sans-serif;

  --lv-ease-out: cubic-bezier(.23, 1, .32, 1);
  --lv-ease-drawer: cubic-bezier(.32, .72, 0, 1);
  --lv-t-press: 120ms; --lv-t-hover: 160ms; --lv-t-pop: 160ms; --lv-t-drawer: 240ms;

  --lv-z-dropdown: 40; --lv-z-sticky: 50; --lv-z-player: 60; --lv-z-drawer: 80;
  --lv-z-backdrop: 90; --lv-z-sheet: 91; --lv-z-modal: 100;
  --lv-z-toast: 110; --lv-z-tooltip: 120;
}

/* ------------------------------------------------------------
   2. БАЗА
   ------------------------------------------------------------ */
/* Сброс ссылки завёрнут в :where, чтобы весить ноль. Без этого
   селектор `.lv-root a` (класс плюс тег) перебивал любой `.lv-btn--*`
   с его одним классом, и кнопка-ссылка всегда получала наследуемый
   цвет вместо своего. Держалось незаметно только потому, что
   наследуемый цвет совпадал с нужным у основной и у тихой кнопки.
   На первой же кнопке с другим цветом это вылезло. */
.lpt .lv-ico { flex: none; }

/* ------------------------------------------------------------
   3. ТИПОГРАФИКА
   ------------------------------------------------------------ */
.lpt .lv-kicker {
  display: block;
  font: 700 11px/1 var(--lv-font-ui);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--lv-text-3);
}
/* крупный заголовок посадочной страницы */

/* ------------------------------------------------------------
   4. КНОПКА
   Главная кнопка экрана одна и заливается градиентом. Градиент —
   метка действия, а не украшение: второй такой на экране отнимает
   у первого весь смысл.
   ------------------------------------------------------------ */
.lpt .lv-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--lv-s2);
  height: 44px;
  padding: 0 20px;
  border: 1px solid transparent;
  border-radius: var(--lv-r-full);
  background: none;
  color: var(--lv-text-1);
  font: 600 14px/1 var(--lv-font-ui);
  white-space: nowrap;
  cursor: pointer;
  transition: transform var(--lv-t-press) var(--lv-ease-out),
              background var(--lv-t-hover), border-color var(--lv-t-hover), color var(--lv-t-hover);
}
.lpt .lv-btn:active { transform: scale(.97); }
/* Градиент растянут на рамку (border-box): у кнопки прозрачная рамка
   в 1 px, и без этого фон повторялся под ней, давая розовую полоску
   слева и оранжевую справа. */
.lpt .lv-btn--primary { background: var(--lv-grad) border-box; color: #fff; }
.lpt .lv-btn--secondary { background: var(--lv-surface-2); border-color: var(--lv-border-1); }
/* ТЕКСТОВАЯ КНОПКА АКЦЕНТОМ.
   Ни заливки, ни рамки, только цвет. Нужна там, где два действия
   стоят рядом и одно из них легче по весу, но должно быть заметно:
   вход рядом с регистрацией. От ghost отличается тем, что тот тихий
   и серый, а этот заметный. Цель под палец остаётся 44 px, потому
   что высота берётся от самой .lv-btn. */
@media (hover: hover) and (pointer: fine) {
  .lpt .lv-btn--primary:hover { filter: brightness(1.06); }
  .lpt .lv-btn--secondary:hover { background: var(--lv-surface-3); }
}
.lpt .lv-btn:disabled, .lpt .lv-btn[aria-disabled="true"] {
  background: var(--lv-surface-2);
  background-image: none;
  border-color: var(--lv-border-1);
  color: var(--lv-text-3);
  cursor: not-allowed;
  transform: none;
  filter: none;
}
/* Строка под выключенной кнопкой: немая серая кнопка без объяснения —
   это тупик, человек не знает, что ему сделать */
.lpt .lv-btn[data-loading="1"] { pointer-events: none; color: transparent; position: relative; }
.lpt .lv-btn[data-loading="1"]::after {
  content: "";
  position: absolute;
  width: 18px; height: 18px;
  border: 2px solid rgba(255, 255, 255, .35);
  border-top-color: #fff;
  border-radius: 50%;
  animation: lv-spin .7s linear infinite;
}
@keyframes lv-spin { to { transform: rotate(360deg); } }

/* ------------------------------------------------------------
   5. ПОЛЕ ВВОДА
   ------------------------------------------------------------ */
/* подвал поля: подсказка слева, счётчик знаков справа */
/* приставка и окончание внутри поля: валюта, домен, единица */
/* Ошибка прячет обычную подсказку: две строки под полем спорят друг с другом */
/* поле без своей коробки — для панели, которая рисует рамку за него */

/* РАСТУЩЕЕ ПОЛЕ (добавлено 22.09.2026, приложение: стиль и «исключить»).
   Выглядит строкой, но это textarea: со второй строки растёт само и
   останавливается на своём пределе — у стиля три строки, у остальных
   две. Дальше включается ручка в углу, и человек тянет поле сам.

   Ручку показываем только когда текст уже не помещается: на пустом
   поле она намекает, что тянуть надо всегда, и сбивает с толку. Высоту
   считает скрипт (`рост()` в views-studio.js), предел задаётся самим
   полем через `data-rows` — не общей цифрой на всех.

   Здесь был ряд тегов: строка резалась по запятым и каждая примета
   показывалась облачком под полем. Владелец снял это 22.09.2026 —
   облачка дублировали то, что человек только что напечатал. */

/* ------------------------------------------------------------
   6. ВЫБОР: ЧЕКБОКС, РАДИО, ПЕРЕКЛЮЧАТЕЛЬ, ПОЛЗУНОК
   Системные элементы выбора рисуются светлыми и чужими поверх
   тёмного интерфейса — ровно та же беда, из-за которой запрещён
   системный <select>. Поэтому родной input прячем, а вид рисуем
   сами. Прячем прозрачностью и размером, а НЕ `display: none`:
   скрытый через display элемент выпадает из обхода с клавиатуры
   и перестаёт переключаться пробелом.
   ------------------------------------------------------------ */

/* галочка нарисована двумя гранями рамки: своего знака здесь не нужно */
/* «выбрать всё», когда выбрано не всё: чёрточка вместо галочки */

/* Выделение — одно кольцо, как у всего остального. Рамка при этом
   не меняется: двойного контура в системе нет. */

/* подпись под строкой выбора: зачем это включать */
/* группа: строки выбора идут лесенкой, а не в строку */

/* Ползунок. Заливка слева считается через --lv-range-p (0…100):
   у вебкита нет своей «пройденной» части дорожки, её приходится
   рисовать градиентом и обновлять из скрипта. */
/* строка «подпись — значение» над ползунком */

/* ------------------------------------------------------------
   7. СПИСОК, ПОИСК, ЗАГРУЗКА ФАЙЛА
   ------------------------------------------------------------ */
/* Свой выпадающий список взамен системного <select>. Скрипт обязан
   дать клавиатуру: стрелки, Enter, Esc и набор первых букв. Без
   этого список хуже системного, а не лучше. */
/* значок ставится в разметку первым, а стоять должен последним */
/* курсор клавиатуры и наведение мышью — одна и та же подсветка:
   иначе на экране оказывается два «выбранных» пункта сразу */

/* Поиск. Значок слева не нажимается, крестик справа нажимается. */

/* Загрузка файла. Пунктир говорит «сюда можно бросить» — сплошная
   рамка такого не обещает. */
/* принятый файл: строка с именем, весом и крестиком */

/* ------------------------------------------------------------
   8. ПОЛОСА-СООБЩЕНИЕ
   Это не тост. Тост сообщает, что действие уже случилось, и уходит
   сам. Полоса остаётся на экране и объясняет, что не так прямо
   здесь: ошибка всей формы, предупреждение, подтверждение.
   ------------------------------------------------------------ */

/* ------------------------------------------------------------
   9. ЧИП, ТЕГ, СЕГМЕНТ
   ------------------------------------------------------------ */
.lpt .lv-chips { display: flex; gap: var(--lv-s2); flex-wrap: wrap; }
.lpt .lv-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 32px;
  padding: 0 12px;
  border-radius: var(--lv-r-full);
  background: var(--lv-surface-2);
  border: 1px solid var(--lv-border-2);
  color: var(--lv-text-2);
  font: 600 13px/1 var(--lv-font-ui);
  cursor: pointer;
  transition: background var(--lv-t-hover), border-color var(--lv-t-hover),
              color var(--lv-t-hover), transform var(--lv-t-press);
}
@media (hover: hover) and (pointer: fine) {
  .lpt .lv-chip:hover { border-color: var(--lv-border-1); color: var(--lv-text-1); }
}
.lpt .lv-chip:active { transform: scale(.97); }
.lpt .lv-chip[aria-pressed="true"] {
  background: var(--lv-accent-soft);
  border-color: var(--lv-accent);
  color: var(--lv-accent);
}
.lpt .lv-chip:disabled { opacity: .5; cursor: not-allowed; }

/* ------------------------------------------------------------
   10. ПАНЕЛЬ ФОРМЫ
   Главный приём системы: рамку рисует панель, а поля внутри своей
   рамки не имеют. Так уходит «поле в поле» — болезнь сложных форм.
   ------------------------------------------------------------ */
/* 14 px — единственное намеренное исключение из шкалы: 12 ещё тесно,
   16 уже разваливает форму */
/* пока пишут в поле, у панели проявляется контур: без этого не видно,
   где курсор, ведь у полей своей рамки нет */
/* Всё, что лежит ВНУТРИ панели, поднимается на ступень: сама панель
   цвета `--lv-surface-2`, и элементы того же цвета на ней растворяются. */

/* ------------------------------------------------------------
   11. КАРТОЧКА И СТРОКА
   ------------------------------------------------------------ */
.lpt .lv-card {
  padding: var(--lv-s4);
  border: 1px solid var(--lv-border-2);
  border-radius: var(--lv-r-lg);
  background: var(--lv-surface-1);
}
/* Вложенных карточек не делаем: карточка внутри карточки лишает обе
   смысла, глаз перестаёт понимать, что здесь главное */
.lpt .lv-card .lv-card { border: 0; background: none; padding: 0; }

/* плитка сводки: короткий ответ крупной цифрой */

/* ------------------------------------------------------------
   12. МЕНЮ, ШТОРКА, ОКНО, ТОСТ
   ------------------------------------------------------------ */
/* Шторка ВЫШЕ своей подложки. Если поставить её ниже, подложка накроет
   шторку целиком: она будет выглядеть погашенной и не нажмётся нигде.
   Мы на этом обожглись и полгода не замечали */

/* ------------------------------------------------------------
   13. ПУСТОЕ СОСТОЯНИЕ, СКЕЛЕТОН, ПОДСКАЗКА
   ------------------------------------------------------------ */
/* не шире 46 знаков: длинная строка по центру не читается */

/* Своя подсказка, а не системная: системная приходит через полторы
   секунды и рисуется светлой плашкой поверх тёмного интерфейса,
   поэтому люди решают, что подсказки нет вовсе */

/* ------------------------------------------------------------
   14. ЖИВЫЕ ЭЛЕМЕНТЫ: ЭКВАЛАЙЗЕР
   ------------------------------------------------------------ */

/* ------------------------------------------------------------
   15. ЦВЕТНЫЕ ПОВЕРХНОСТИ
   Яркие блоки собраны из размытых пятен под тёмной подложкой,
   без единой картинки: они ничего не весят, тянутся под любой
   размер и не устаревают вместе с фотографией.
   Это и есть тот единственный градиентный элемент на экране.

   Пятен может быть два или три. Два дают диагональ, три — свет,
   который живёт сам по себе. Третье ставится элементом
   `.lv-glow__c`, потому что оба псевдоэлемента уже заняты.
   ------------------------------------------------------------ */
.lpt .lv-glow {
  position: relative;
  overflow: hidden;
  isolation: isolate;
  border-radius: var(--lv-r-lg);
  background: #120F1A;
  --lv-glow-a: #FF8A18;
  --lv-glow-b: #FB4595;
  --lv-glow-c: #7B5CFF;
}
.lpt .lv-glow::before, .lpt .lv-glow::after {
  content: "";
  position: absolute;
  width: 420px; height: 420px;
  border-radius: 50%;
  filter: blur(72px);
  opacity: .8;
  pointer-events: none;
  z-index: -1;
}
.lpt .lv-glow::before {
  left: -80px; top: -180px;
  background: radial-gradient(circle, var(--lv-glow-a) 0%, transparent 70%);
  animation: lv-glow-a 28s ease-in-out infinite alternate;
}
.lpt .lv-glow::after {
  right: -60px; bottom: -220px;
  background: radial-gradient(circle, var(--lv-glow-b) 0%, transparent 70%);
  animation: lv-glow-b 34s ease-in-out infinite alternate;
}
/* третье пятно. Ставится элементом: оба псевдоэлемента уже заняты
   первыми двумя, а трогать разметку ради света не хочется нигде,
   кроме главного блока. */
.lpt .lv-glow__c {
  position: absolute;
  left: 42%; top: -140px;
  width: 360px; height: 360px;
  border-radius: 50%;
  filter: blur(76px);
  opacity: .55;
  pointer-events: none;
  z-index: -1;
  background: radial-gradient(circle, var(--lv-glow-c) 0%, transparent 70%);
  animation: lv-glow-c 40s ease-in-out infinite alternate;
}
@keyframes lv-glow-a { to { transform: translate3d(90px, 60px, 0) scale(1.15); } }
@keyframes lv-glow-b { to { transform: translate3d(-70px, -50px, 0) scale(1.1); } }
@keyframes lv-glow-c { to { transform: translate3d(-120px, 90px, 0) scale(1.2); } }

/* ПОКА БЛОК ИГРАЕТ, СВЕТ ДЫШИТ.
   Раньше здесь был такт на 120 ударов в минуту — полсекунды на удар.
   Выглядело дёрганьем: блок фоновый, а мельтешил сильнее всего на
   экране. Теперь это дыхание — цикл 6 секунд, размах 3 %. Движение
   заметно, только если смотреть на него нарочно, а это ему и нужно.

   Дыхание живёт отдельным свойством `scale`, а не внутри `transform`:
   иначе оно затирало бы медленный дрейф пятен. Складываются они
   только когда записаны порознь. */
/* кнопка отзывается тем же дыханием, но совсем слабо: она главная,
   ей не к лицу прыгать */

/* цветовые версии: одна и та же форма, разный характер */
.lpt .lv-glow--fire   { --lv-glow-a: #FF8A18; --lv-glow-b: #FB4595; --lv-glow-c: #7B5CFF; }  /* фирменный */  /* ночной */  /* спокойный */  /* свежий */  /* тёплый */  /* густой */  /* тихий */

@media (prefers-reduced-motion: reduce) {
  .lpt .lv-glow::before, .lpt .lv-glow::after, .lpt .lv-glow__c { animation: none; }
}

/* блок-герой: крупный заголовок, одна кнопка, под ней строка с песней */
/* Название песни весомое, исполнитель тихий. Вся строка при этом
   уступает кнопке: она подпись к действию, а не действие. */

/* ПЛИТКА.
   Один компонент на все случаи: раздел, жанр, подборка. Разница
   между ними только в пропорции и в том, есть картинка или нет,
   а это модификаторы, а не отдельные компоненты. Одно время обложка
   подборки жила здесь же вторым именем `.lv-cover` — сведено обратно
   20.09.2026, потому что делало ровно то же самое. */   /* обложка подборки */
/* Знак вместо картинки. Держим его в верхних двух третях: нижнюю
   займёт название, и там знак уйдёт под затемнение. */
/* плитка без картинки: цвет берётся из набора lv-glow */

/* ------------------------------------------------------------
   16. БЛОКИ САЙТА
   Всё, из чего собирается посадочная. В приложении эти классы не
   нужны и не используются: у сервиса свой скелет.

   Главное отличие от экранов — воздух. Секция сайта дышит
   ступенью `--lv-s24` (96), которой в приложении нет. Всё
   остальное то же: одна тень только у всплывающего, один градиент
   на экран, сетки через minmax(0, 1fr).
   ------------------------------------------------------------ */

/* ---------- шапка сайта ---------- */
/* Высота шапки живёт переменной: по ней же считается, на сколько
   отступать при переходе по якорю. Шапка прилипшая, и без отступа
   заголовок секции уезжает под неё — человек нажимает «Вопросы» и
   видит не заголовок, а середину первого ответа. */
:root { --lv-shapka: 64px; }
/* Порог тот же, на котором шапка и так перестраивается (прячется
   меню и сжимаются поля), иначе высота и её содержимое разъедутся. */
@media (max-width: 900px) { :root { --lv-shapka: 56px; } }
.lpt :target,
.lpt .lv-section[id] { scroll-margin-top: calc(var(--lv-shapka) + var(--lv-s4)); }
/* Цель у ссылки шапки была ростом со сами буквы: 14 px по вертикали.
   Добираем её полями до 44, сама строка при этом не двигается, потому
   что ряд выравнивает содержимое по центру. */

/* ---------- первый экран ----------
   Заголовок и подзаголовок берут готовые `.lv-display` и `.lv-lead`:
   заводить им вторые имена незачем. Здесь только раскладка. */
/* Высоту первого экрана задаёт не только текст: под ним живёт волна,
   и на мониторе ей нужен разбег. При одних полях экран выходил 560 px
   и свет упирался в стык со следующей секцией. Минимум в 76vh даёт
   волне место, но не заставляет человека листать вслепую: следующий
   заголовок всё равно заглядывает снизу. */
/* Обёртка внутри обязательно во всю ширину. У `.lv-wrap` поля по бокам
   стоят `auto` — так она и встаёт по центру. Но в колонке (и в сетке
   тоже) автополе по поперечной оси отменяет растягивание, и обёртка
   садится по содержимому: замер давал 919 px вместо 1200 и левый край
   заголовка 284 вместо 144. С явной шириной автополя снова просто
   центруют. */
/* Только на большом экране: на телефоне высота и так набирается
   текстом, а лишние поля отодвигали кнопку за нижний край. */

/* ФОН ПЕРВОГО ЭКРАНА: ЖИВОЙ СВЕТ «МОЕЙ ВОЛНЫ».

   Это тот самый холст, что стоит в ленте приложения: шесть широких
   лент света текут поперёк экрана и просвечивают друг через друга.
   Модуль взят из приложения без единой правки и лежит в
   `assets/wave-art.js`, источник — `luvi-live/js/wave-art.js`.
   Файл не переименован и класс холста оставлен родным (`wave__art`,
   а не `lv-*`), чтобы его можно было пересинхронить копированием,
   когда модуль в приложении поменяется.

   Размытые пятна `.lv-glow` тут стояли и были сняты: они дают мягкое
   свечение, но это не та анимация, что в ленте.
   ------------------------------------------------------------ */
/* СЛОЙ РАЗМЫТИЯ.
   Отдельный элемент между фоном и холстом, и вся его работа это
   фильтр. Раньше и насыщенность, и размытие стояли прямо на холсте,
   а на холсте же висит маска (`mask-image`, чтобы низ растворялся).
   WebKit на сочетание «маска и фильтр на одном элементе» отвечает
   тем, что фильтр просто не применяет: на айфоне волна выходила
   резкими лентами, хотя в Chrome была мягкой. Маска осталась на
   холсте, фильтр переехал сюда, и они больше не встречаются.

   Радиус складывается из двух частей. Базовую считает сам скрипт от
   размера холста и кладёт в переменную `--wave-blur` прямо на холст
   (раньше он размывал себя через `ctx.filter`, но этого не умеют
   Safari до 18-й версии и часть мобильных браузеров). Скрипт ставит
   переменную на холсте, а фильтр нам нужен на слое, поэтому значение
   поднимает наверх скрипт страницы — в `--lv-volna-baza`. Вторая
   часть, `--lv-volna-dobavka`, это наша добавка на узких экранах.

   ВАЖНО: базовый радиус не ставить обратно на сам холст. Там маска,
   и WebKit при маске фильтр не применяет. */
/* Текст лежит прямо на свете, и держаться он должен сам. Тень нужна
   не заголовку, а подводке: у заголовка кегль под шестьдесят и он
   читается на чём угодно, а подводка идёт 17 px по самым ярким лентам.
   Замер контраста на телефоне давал 2,9 при норме 4,5. Поэтому ей тень
   плотнее и вес выше обычного. */
/* Настоящий H1 страницы. По размеру это прежний надзаголовок, но в
   двух строках и с поисковым текстом: «Твоя песня готова за минуту»
   осталась крупной фразой, а заголовком первого уровня стало то, что
   человек ищет. Регистр поднимает стиль, в разметке слова обычные. */

/* На телефоне текст занимает всю ширину, и ленты проходят прямо под
   абзацем. Контраст держится, но читать по светящемуся ядру неудобно,
   поэтому свет опускаем ниже текста. */
/* Базовый радиус скрипт берёт от размера холста в точках (wave-art.js,
   `blur` от меньшей стороны). На мониторе холст крупный и выходит
   мягкое свечение; на телефоне он втрое меньше и ужимается на экран,
   поэтому того же радиуса не хватает — ленты читаются как нарисованные
   мазки. Скрипт общий с приложением, трогать его ради лендинга нельзя,
   поэтому недостающую мягкость добавляем поверх. */
/* ВОЛНА НА ТЕЛЕФОНЕ БЕРЁТ РАЗБЕГ ШИРЕ ЭКРАНА.
   Размах лент модуль считает от меньшей стороны холста. На мониторе
   это 748 точек и ленты расходятся решёткой, каждая видна отдельно;
   на телефоне холст узкий, размах падает до 530, шесть лент налезают
   друг на друга и сливаются в одно пятно. Добавка размытия поверх
   делала из пятна кисель.

   Лечим не размытием, а шириной: холст берём вдвое шире экрана и
   сдвигаем влево на половину лишнего. Модуль упирается в свой предел
   в 1100 точек, то есть считает ровно тот же размах, что и на
   мониторе, а мы видим середину этой картины. Ленты снова читаются
   по отдельности, и добавка размытия больше не нужна. */
@media (max-width: 900px) {
  /* Ширину даём слою, а не холсту. Модуль замеряет именно тот блок,
     в который его положили, и от этого замера считает и размер
     холста, и размах лент. Растянуть сам холст стилем значит
     растянуть прежнюю картинку: лент столько же, они только толще
     и мутнее. Проверено замером: у холста оставался прежний радиус
     5,83 вместо 8,23. */
}

/* Тонкая завеса по самому низу: стык со следующей секцией. */

/* СЛАЙДЕР НА ТЕЛЕФОНЕ.
   Ниже 900 сетка карточек становится горизонтальной лентой с
   прилипанием. Девять карточек в столбик съедали два экрана прокрутки;
   лентой они занимают один, а листать её привычнее, чем мотать
   страницу. Лента выходит в края экрана: упираться она должна в
   границу телефона, а не в отступ страницы, иначе не читается как
   лента. Следующая карточка нарочно видна краем, это единственный
   намёк, что тут можно листать.
   ------------------------------------------------------------ */
.lpt .lv-slider { position: relative; }

@media (max-width: 900px) {
  .lpt .lv-slider > .lv-grid {
    display: flex;
    gap: var(--lv-s3);
    overflow-x: auto;
    /* Обязательно явно. По умолчанию, когда одна ось получает auto,
       вторая тоже становится прокручиваемой, и лента начинала ездить
       вверх-вниз внутри себя. */
    overflow-y: hidden;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    margin: 0 calc(var(--lv-s4) * -1);
    padding: 2px var(--lv-s4);
  }
  .lpt .lv-slider > .lv-grid::-webkit-scrollbar { display: none; }
  .lpt .lv-slider > .lv-grid > * { flex: 0 0 78%; scroll-snap-align: start; }
  /* Возможности листаются карточками вдвое уже остальных: их
     девять, и в узкой колонке на экран попадает сразу две с
     половиной, а не одна.

     44 %, а не 39: на 39 в колонке оставалось 128 точек, и подпись
     шла по два-три слова в строку, а заголовок в четыре строки.
     Пять лишних процентов дают 147 точек, строки становятся длиннее,
     а карточка от этого ниже, а не выше. Второй карточки на экране
     всё так же видно край, значит понятно, что лента листается. */
  .lpt .lv-slider--2 > .lv-grid > * { flex: 0 0 44%; }

  /* Лента в два ряда. Девять карточек одной строкой требуют девяти
     свайпов; два ряда сокращают их до пяти, а высота блока при этом
     не меняется, потому что карточки вдвое ниже ленты не бывают.
     Сетка вместо ряда: только она умеет раскладывать поперёк. */
  .lpt .lv-slider--2 > .lv-grid {
    display: grid;
    /* Колонки базовой сетки обязательно сбросить: пока они заданы,
       раскладка поперёк укладывает карточки в них, и ширина выходит
       26 px вместо 78 %. Поймано замером. */
    grid-template-columns: none;
    grid-auto-flow: column;
    grid-template-rows: repeat(2, auto);
    grid-auto-columns: 44%;
    align-items: stretch;
  }
  .lpt .lv-slider--2 > .lv-grid > * { flex: none; }
}

/* КАРТОЧКА ВОЗМОЖНОСТИ.
   Порядок как у Suno: сверху заголовок и довод, картинка внизу и
   крупная. Значок сверху читался служебной пометкой, а картинка снизу
   работает наградой: сначала прочитал, потом увидел.
   Высоту держим одинаковой, иначе в сетке из двух столбцов картинки
   встают на разной высоте и ряд рассыпается. */
/* Порядок: сначала кадр, потом заголовок, потом текст.
   Сперва было наоборот, по образцу Suno. Но у них карточка объясняет
   функцию продукта и картинка там доказательство, а у нас она
   украшение. Когда картинка не доказательство, она должна идти
   первой: глаз цепляется за неё и дальше читает. Так же устроены
   наши плитки поводов, и к ним вопросов не было.

   Кадр вертикальный, три к четырём. Горизонтальный в узкой карточке
   занимал четверть высоты и терялся, а основная аудитория мобильная,
   и формат идёт от неё. */
.lpt .lv-fcard {
  display: flex;
  flex-direction: column;
  padding: 0;
  overflow: hidden;
}
.lpt .lv-fcard__in { padding: var(--lv-s6); }
.lpt .lv-fcard__t { margin: 0; font: 700 23px/1.2 var(--lv-font-head); color: var(--lv-text-1); letter-spacing: -.02em; }
.lpt .lv-fcard__d { margin: var(--lv-s3) 0 0; font: 400 15px/1.6 var(--lv-font-ui); color: var(--lv-text-2); }
/* Кадр квадратный на любой ширине, и ровно в этом формате картинки
   нарисованы, поэтому ничего не обрезается; object-fit оставлен
   страховкой. Формат выбран владельцем из трёх: вертикальный 3:4
   растил карточку до 560 px, горизонтальный 3:2 сплющивал предметы
   вроде микрофона и палочки. Квадрат держит и то и другое.
   object-fit оставлен только как страховка. */
.lpt .lv-fcard__art {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 1;
  object-fit: cover;
}

/* НА ТЕЛЕФОНЕ КАРТОЧКА ВДВОЕ УЖЕ.
   Кадр по-прежнему идёт от края до края карточки, но сама карточка
   занимает не 78 % ширины экрана, а 39 % (см. .lv-slider ниже), и
   квадратный кадр вслед за ней ужимается с 279 точек до 140. Раньше
   он забирал больше половины карточки: было видно картинку и начало
   заголовка, а чтобы дочитать довод, приходилось листать.

   Кегли идут за шириной. В колонке 140 точек заголовок в 21 px
   ложится по два слова в строку, поэтому здесь 17, а текст 13. */
@media (max-width: 900px) {
  .lpt .lv-fcard__in { padding: var(--lv-s3); }
  .lpt .lv-fcard__t { font-size: 17px; line-height: 1.2; }
  /* Кегль подписи ниже обычного намеренно: колонка у карточки
     128 точек, и на 13 px в строку влезало по два-три слова.
     На 12 px с поджатым межбуквенным строка забирает на треть
     больше слов, и карточка становится ниже. Это подпись под
     заголовком в 17 px, а не основной текст страницы. */
  .lpt .lv-fcard__d { margin-top: var(--lv-s2); font-size: 12px; line-height: 1.45; letter-spacing: -.005em; }
}

/* КАРТОЧКА ТРЕКА НА ПОЛКЕ.
   Перенесена из ленты приложения (.shcard в luvi-live/css/app.css),
   чтобы на сайте и в сервисе трек выглядел и вёл себя одинаково.
   Вся карточка это кнопка: тык по центру обложки запускает песню,
   тык по играющей ставит паузу.

   Кружок с треугольником тёмный, а не фирменный розовый: розовый на
   цветной обложке спорит с ней и теряется. Это решение из приложения,
   не менял. Аватарки автора здесь нет намеренно: на 22 px лица
   превращаются в серые пятна.
   ------------------------------------------------------------ */   /* треугольник оптически по центру */

/* играет: обложка притушена, кнопка видна, в ней пляшет эквалайзер */

@media (hover: hover) and (pointer: fine) {
  /* навёл на играющую: вместо эквалайзера пауза, видно, что тык остановит */
}

/* на телефоне курсора нет, поэтому кнопка видна всегда */

/* СЕКЦИЯ НА ПОЛОСЕ.
   Тот же серый, что у поверхностей интерфейса, плюс тонкие линии по
   краям. Длинная страница из одиннадцати секций на одном фоне читается
   сплошным полотном; полоса разбивает её на главы.

   Ставить только туда, где нет карточек: у карточки фон тот же
   surface-1, и на полосе она растворяется. Годятся цифры, вопросы,
   шаги, бегущая строка. И не больше двух полос на страницу, иначе
   вместо глав получается тельняшка.
   ------------------------------------------------------------ */
.lpt .lv-section--band {
  background: var(--lv-surface-1);
  border-top: 1px solid var(--lv-border-2);
  border-bottom: 1px solid var(--lv-border-2);
}
/* Две полосы подряд читаются одной главой, поэтому шов между ними
   убираем. И линию подвала тоже: иначе на стыке выходит двойная
   черта в один пиксель друг от друга. */
.lpt .lv-section--band + .lv-section--band { border-top: 0; }

/* ЛИПКИЙ ПРИЗЫВ.
   Появляется, когда первый экран с его кнопкой уже уехал наверх, и
   прячется, когда до последнего призыва доехали: две кнопки об одном
   и том же на одном экране мешают друг другу.

   На телефоне полоса во всю ширину внизу, в зоне большого пальца.
   На большом экране это плавающая пилюля по центру: полоса во всю
   ширину монитора выглядит баннером, а её и так хватает.
   Отступ снизу учитывает вырез у айфона через safe-area.
   ------------------------------------------------------------ */

/* НА БОЛЬШОМ ЭКРАНЕ ЭТО ПИЛЮЛЯ ПО НИЗУ ОКНА.
   Карточка у правого края тут стояла и снята по решению владельца:
   она перекрывала правую колонку блоков и тянула взгляд вбок посреди
   чтения. Низ окна спокойнее — там её видно, но она не спорит с
   содержимым, и путь до неё одинаковый на любом экране.

   Полосу во всю ширину монитора не делаем: она читается баннером
   согласия на куки. Здесь пилюля по центру, шириной по содержимому.
   Слева живой знак, чтобы пилюля не выглядела картинкой. */

/* ФИРМЕННОЕ СЕРДЦЕ-ЭКВАЛАЙЗЕР.
   Тот же знак, что в логотипе и на аватарке: одиннадцать полос, торцы
   которых обводят сердце. Геометрия не придумана и не посчитана по
   формуле — она снята попиксельно с логотипа (Luvi/СОЦ СЕТИ/аватарка/
   сгенерировать.py), поэтому знак совпадает с фирменным один в один.
   Система координат знака 222 x 216, её и держит viewBox.

   Полосы дышат вокруг своей середины, а не растут снизу: так силуэт
   сердца остаётся читаемым на любом кадре. Размах намеренно
   небольшой — при большом знак рассыпается в случайный частокол.
   Пары полос слева и справа дышат в такт: сердце симметрично, и
   вразнобой оно перестаёт им быть.

   Сверху удар сердца: знак целиком коротко подскакивает дважды, как
   настоящий пульс, и потом держит паузу. Масштаб живёт на обёртке, а
   не на самом svg: два преобразования на одном элементе пришлось бы
   писать одной анимацией.
   ------------------------------------------------------------ */
/* Счёт по типу, а не по порядку среди соседей: первым ребёнком в svg
   стоит defs с градиентом, и обычный nth-child сдвинул бы всю пару. */

@media (max-width: 700px) {
  /* На телефоне уходит серая коробка с рамкой вокруг кнопки: она
     читалась как ещё одна панель поверх страницы и отбирала у кнопки
     половину веса. Вместо неё тёмная полоса в цвет страницы, а на ней
     обычная наша кнопка-пилюля с полями по краям. Кнопка во всю
     кромку без полей тут уже стояла и выглядела не кнопкой, а плитой,
     приклеенной к низу экрана. Сверху полоса растворяется, чтобы
     содержимое уезжало под неё, а не обрывалось по линии. */
  /* Знак и подпись на телефоне не показываем: в полосе живёт одна
     кнопка во всю её ширину, и слева от неё места нет. */
  /* Кнопка во всю ширину полосы, но с обычным скруглением кита: от
     края экрана её отделяют поля самой полосы. Вырез айфона учтён
     полосой, а не кнопкой, иначе подпись внутри уезжала вниз. */
}

/* СВЕТ ПОД КУРСОРОМ.
   Мягкое пятно фирменного цвета идёт за мышью внутри карточки. Приём
   общеизвестный: радиальный градиент в позиции курсора, живёт в вёрстке
   лет десять. Написан здесь свой, чужой код не взят — у React Bits,
   откуда пришла идея посмотреть в эту сторону, лицензия MIT с Commons
   Clause, и распространять их компоненты, в том числе портированные,
   нельзя. Наш пакет публикуется и уходит наружу, поэтому в нём должно
   лежать только наше.

   Позицию пишет JS в --mx и --my. Пока мыши не было, пятно спрятано:
   иначе оно висело бы в углу карточки при первой отрисовке.
   Включается только там, где есть настоящая мышь: на телефоне курсора
   нет, а лишний слой был бы.
   ------------------------------------------------------------ */

/* ПОЯВЛЕНИЕ ПО ПРОКРУТКЕ.
   Блок въезжает снизу, когда дошёл до экрана. Класс навешивает JS, а не
   вёрстка: если скрипт не сработает, всё просто видно сразу, а не
   остаётся прозрачным навсегда. Так уже появляются цифры, здесь то же
   правило доведено до остальной страницы.
   ------------------------------------------------------------ */

/* КОЛЛАЖ-ПОЛОСА.
   Три горизонтальных кадра в ряд, читаются как одна широкая панель.
   Скругление и обрезка живут на контейнере, а не на каждом кадре:
   так у полосы круглые внешние углы и прямые внутренние стыки,
   и она не рассыпается на три отдельные карточки. */

/* ---------- секция ---------- */
.lpt .lv-section { padding: var(--lv-s24) 0; }
.lpt .lv-section__head { max-width: 62ch; margin: 0 0 var(--lv-s12); }
/* Нижняя граница поднята с 26 до 31 px: на телефоне заголовок секции
   отличался от обычного текста только начертанием, и страница читалась
   сплошняком без глав. */
.lpt .lv-section__title {
  margin: 6px 0 0;
  font: 800 clamp(31px, 3.4vw, 40px)/1.1 var(--lv-font-head);
  letter-spacing: -.025em;
  text-wrap: balance;
}
.lpt .lv-section__lead { margin: var(--lv-s3) 0 0; max-width: 68ch; font: 400 16px/1.6 var(--lv-font-ui); color: var(--lv-text-2); }

/* ---------- шаги «как это работает» ---------- */

/* ---------- тариф ---------- */
.lpt .lv-price {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: var(--lv-s6);
  border: 1px solid var(--lv-border-2);
  border-radius: var(--lv-r-lg);
  background: var(--lv-surface-1);
}
.lpt .lv-price--hot { border-color: var(--lv-accent); }
/* Градиентная плашка — одно из трёх принятых исключений из правила
   «один градиент на экран». Второй градиент на странице тарифов это
   кнопка выбранного тарифа, и больше ничего. */
.lpt .lv-price__badge {
  position: absolute;
  top: -11px; left: var(--lv-s6);
  display: inline-flex;
  align-items: center;
  height: 22px;
  padding: 0 10px;
  border-radius: var(--lv-r-full);
  background: var(--lv-grad);
  color: #fff;
  font: 700 11px/1 var(--lv-font-ui);
  letter-spacing: .04em;
  text-transform: uppercase;
}
.lpt .lv-price__name { font: 700 16px/1.2 var(--lv-font-head); color: var(--lv-text-2); }
.lpt .lv-price__sum {
  margin: var(--lv-s3) 0 0;
  font: 800 36px/1 var(--lv-font-head);
  letter-spacing: -.02em;
  font-variant-numeric: tabular-nums;
}
.lpt .lv-price__sum span { font: 400 14px/1 var(--lv-font-ui); color: var(--lv-text-3); }
.lpt .lv-price__note { margin: 6px 0 0; font: 400 13px/1.4 var(--lv-font-ui); color: var(--lv-text-3); }
.lpt .lv-price__feats { margin: var(--lv-s6) 0; padding: 0; display: grid; gap: var(--lv-s3); list-style: none; }
.lpt .lv-price__feats li { display: flex; gap: var(--lv-s2); font: 400 14px/1.5 var(--lv-font-ui); color: var(--lv-text-2); }
.lpt .lv-price__feats .lv-ico { flex: none; margin-top: 2px; color: var(--lv-success); }
.lpt .lv-price > .lv-btn { margin-top: auto; }

/* ---------- частые вопросы ---------- */
.lpt .lv-acc { border-top: 1px solid var(--lv-border-2); }
.lpt .lv-acc__item { border-bottom: 1px solid var(--lv-border-2); }
.lpt .lv-acc__btn {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--lv-s4);
  width: 100%;
  padding: var(--lv-s4) 0;
  border: 0;
  background: none;
  color: var(--lv-text-1);
  font: 700 16px/1.4 var(--lv-font-head);
  text-align: left;
  cursor: pointer;
}
.lpt .lv-acc__btn .lv-ico { flex: none; color: var(--lv-text-3); transition: transform var(--lv-t-hover); }
.lpt .lv-acc__btn[aria-expanded="true"] .lv-ico { transform: rotate(180deg); }
.lpt .lv-acc__btn:focus-visible { outline: none; box-shadow: var(--lv-ring); border-radius: var(--lv-r-sm); }
.lpt .lv-acc__body {
  padding: 0 0 var(--lv-s4);
  max-width: 68ch;
  font: 400 15px/1.6 var(--lv-font-ui);
  color: var(--lv-text-2);
}
.lpt .lv-acc__body[hidden] { display: none; }

/* ---------- отзыв ---------- */

/* ---------- полоса призыва ---------- */
.lpt .lv-cta__title {
  margin: 0;
  font: 800 clamp(31px, 3vw, 40px)/1.15 var(--lv-font-head);
  letter-spacing: -.02em;
  color: #fff;
  text-wrap: balance;
}
.lpt .lv-cta__lead {
  margin: var(--lv-s3) auto 0;
  max-width: 52ch;
  font: 400 16px/1.6 var(--lv-font-ui);
  color: rgba(255, 255, 255, .78);
}
.lpt .lv-cta__acts { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--lv-s3); margin-top: var(--lv-s8); }

/* ПОЛОСА СВЕТА ВО ВСЮ ШИРИНУ.
   Тот же свет, что в карточке, но подложка — вся секция: углов нет,
   края уходят за экран. Пятна при этом надо раздувать. Кружки по
   420 px сидели в середине широкого монитора, а по бокам оставалась
   ровная тёмная плита, и блок читался как карточка, которой забыли
   скруглить углы. Здесь они считаются от ширины экрана. */
.lpt .lv-glow--full { border-radius: 0; }
.lpt .lv-glow--full::before {
  width: 62vw; height: 62vw; max-width: 900px; max-height: 900px;
  left: -10vw; top: -34%;
}
.lpt .lv-glow--full::after {
  width: 64vw; height: 64vw; max-width: 940px; max-height: 940px;
  right: -12vw; bottom: -38%;
}
.lpt .lv-glow--full .lv-glow__c {
  width: 50vw; height: 50vw; max-width: 720px; max-height: 720px;
  left: 38%; top: -26%;
}
/* Секция-призыв. Поля меньше обычной секции: внутри всего три строки,
   и общие 96 px сверху и снизу оставляли посреди света пустоту. */
.lpt .lv-cta-sec { padding: var(--lv-s16) 0; }
/* На телефоне секция низкая и узкая, и пятна в 62vw висели по углам
   почти целиком за краем: оставалась тёмная плита с цветными уголками.
   Раздуваем их до ширины экрана и подтягиваем к середине. */
@media (max-width: 900px) {
  .lpt .lv-cta-sec { padding: var(--lv-s12) 0; }
  .lpt .lv-glow--full::before { width: 100vw; height: 100vw; left: -34vw; top: -40%; }
  .lpt .lv-glow--full::after { width: 104vw; height: 104vw; right: -38vw; bottom: -44%; }
  .lpt .lv-glow--full .lv-glow__c { width: 82vw; height: 82vw; left: 22%; top: -30%; }
}

/* ЭКРАН ПРИЛОЖЕНИЯ С РАЗЛЕТАЮЩИМИСЯ МЕТКАМИ.
   Снимок «Ленты» из рабочего приложения в рамке телефона, а вокруг
   него отлетают в стороны метки: что происходит с треком после того,
   как его выложили. Метки не считают слушателей и ничего не обещают,
   это названия самих действий в ленте.

   Рамка рисуется не картинкой, а рамкой и скруглением: картинка
   телефона на тёмном фоне всегда выдаёт чужой рендер, а так экран
   остаётся нашим. Низ снимка растворяется маской, иначе видно, что
   он обрезан.
   ------------------------------------------------------------ */
/* На большом экране телефон прижат к левому краю своей колонки.
   По центру колонки он упирался в липкую карточку у правого края
   окна, и та закрывала метку «Моя волна», а на 1280 наезжала и на
   сам экран. */
/* Низ обрезается рамкой, без растворения. Маска тут стояла и снята:
   она гасила снимок в цвет рамки, и казалось, что картинка
   выцветает. Телефон и должен обрезать содержимое по краю экрана. */
/* Метки лежат поверх рамки и уходят за её края. */
.lpt .lv-metka {
  position: absolute;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  gap: var(--lv-s2);
  padding: 8px 14px;
  border: 1px solid var(--lv-border-1);
  border-radius: var(--lv-r-full);
  background: rgba(21, 20, 27, .92);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  box-shadow: var(--lv-shadow-overlay);
  font: 600 13px/1.2 var(--lv-font-ui);
  color: var(--lv-text-1);
  white-space: nowrap;
  /* Плавают по кругу вокруг своей точки: каждая со своей задержкой,
     иначе шесть меток качаются в такт и выглядят одной деталью. */
  animation: lv-metka-plyvet 7s ease-in-out infinite alternate;
  animation-delay: var(--zaderzhka, 0s);
}
.lpt .lv-metka svg { color: var(--lv-accent); flex: none; }
@keyframes lv-metka-plyvet {
  from { transform: translate3d(0, 0, 0); }
  to { transform: translate3d(var(--dx, 6px), var(--dy, -10px), 0); }
}
/* Появление: метки выплывают из-за экрана по очереди, когда блок
   попал в поле зрения. До этого их не видно совсем. */
.lpt .lv-metka { opacity: 0; }
@media (prefers-reduced-motion: reduce) {
  .lpt .lv-metka { animation: none; }
}

/* Четыре точки вокруг экрана. Отступы в процентах от ширины самого
   экрана, а не в точках: экран ужимается вместе с окном, и метки
   должны уезжать за его край ровно настолько же. Сдвиги и задержки
   у всех разные, иначе четыре метки качаются в такт. */
.lpt .lv-metka--a { top: -3%; left: -13%;  --dx: -7px;  --dy: -11px; --zaderzhka: 0s;    --pauza: .05s; }
.lpt .lv-metka--b { top: 29%; right: -11%; --dx: 9px;   --dy: -8px;  --zaderzhka: -1.6s; --pauza: .2s; }
.lpt .lv-metka--v { top: 55%; left: -15%;  --dx: -10px; --dy: 7px;   --zaderzhka: -3.1s; --pauza: .35s; }
.lpt .lv-metka--g { top: 77%; right: -9%;  --dx: 8px;   --dy: 10px;  --zaderzhka: -4.4s; --pauza: .5s; }

@media (max-width: 900px) {
  .lpt .lv-metka { font-size: 12px; padding: 7px 12px; }
  /* На телефоне по бокам от экрана остаётся точек сорок, и прежние
     отступы выносили метки за край страницы: появлялась прокрутка
     вбок. Здесь они почти не вылезают. */
  .lpt .lv-metka--a { left: -7%; }
  .lpt .lv-metka--b { right: -6%; }
  .lpt .lv-metka--v { left: -8%; }
  .lpt .lv-metka--g { right: -5%; }
}

/* МУЛЬТИТРЕК: ПЕСНЯ, РАЗОБРАННАЯ НА ДОРОЖКИ.
   Повторяет экран «Сведение» из приложения: имя дорожки, её волна,
   громкость. Волна нарисована столбиками, а не картинкой, потому что
   дорожек шесть и каждая своего цвета — картинкой это полтора
   мегабайта, а так пара килобайт разметки.

   Движение одно и честное: по дорожкам идёт игла, и позади неё волна
   загорается в полный цвет. Столбики нарочно не прыгают: у волны
   форма постоянная, прыгают полосы эквалайзера, а это другое.
   Поэтому анимаций всего семь на весь блок, а не по одной на каждый
   из двухсот столбиков.
   ------------------------------------------------------------ */
/* Копия поверх, обрезанная слева направо: это и есть сыгранная часть. */
/* Игла идёт по всем дорожкам сразу, поэтому лежит на их общей коробке. */

@media (max-width: 700px) {
  /* Имя дорожки уезжает над волной: в колонке 96 px на телефоне
     не остаётся места самой волне. */
}

/* ---------- ряд площадок ---------- */

/* ---------- подвал ---------- */
/* Поля вместо высоты строки: цель вырастает до 44, а список остаётся
   плотным, потому что поля наложены друг на друга отрицательным
   отступом. На телефоне ниже тот же приём. */

/* ---------- бегущая строка ----------
   Два ряда навстречу друг другу. Содержимое внутри ряда продублировано
   вручную, и лента едет ровно на половину: только так шов не виден. */

/* ---------- карточка с картинкой ---------- */
/* height: auto обязателен. Атрибуты width и height на картинке
   браузер превращает в настоящие правила CSS, и заданная высота
   отменяет aspect-ratio: карточка вытягивалась с 222 до 625 px.
   Атрибуты при этом нужны, иначе место под картинку не зарезервировано
   и вёрстка прыгает при загрузке. */

/* ---------- полка с прокруткой вбок ----------
   Для рядов, которые длиннее экрана: треки, обложки, площадки.
   Полоса прокрутки убрана, но сама прокрутка на месте. */
/* Ширина карточки задана, а не растянута по месту: иначе восемь
   обложек делят ряд и съезжают до 130 px, где название обрезается на
   втором слове. В сервисе полка 148 px, здесь чуть шире: на
   посадочной обложка это доказательство, а не строка каталога.
   Ряд при этом перестаёт влезать целиком, и это правильно: видно,
   что треков больше. */

/* ---------- карточка трека ---------- */
/* КАРТОЧКА ТРЕКА НА ПОЛКЕ.
   Анатомия взята с Suno: высокая обложка два к трём, треугольник в
   левом верхнем углу без кружка, одна плашка с прослушиваниями снизу,
   под обложкой название, ниже аватарка и имя автора.

   Кнопкой сделана вся карточка, а треугольник только метка. Так тык
   по центру обложки запускает песню (цель заведомо больше 44 px), а
   на вид карточка остаётся такой же чистой, как у них.

   Обложки у всех авторов разные, поэтому плашки полупрозрачные с
   размытием: сплошная заливка на светлой обложке выглядит заплаткой.
   ------------------------------------------------------------ */
/* затемнение при наведении и во время игры: без него белый
   треугольник теряется на светлой обложке */
/* играет: обложка притушена, вместо треугольника пляшет эквалайзер */

/* ---------- баннер с кадром ---------- */
/* Кадр уходит в фон плавно, иначе на стыке получается шов. */

/* ---------- крупные числа ---------- */
/* Цифры набираются фирменным градиентом. Единственное место, где
   градиент попал в буквы: в своей секции он больше ни с чем не спорит,
   а цифры и есть тот самый акцент, ради которого секция стоит.
   Под @supports, потому что без поддержки обрезки фона прозрачная
   заливка оставила бы пустое место вместо чисел. */
/* Число доезжает до значения, когда его увидели. Ширину держит
   `tabular-nums` на самом числе: без неё строка дёргается на каждом
   кадре, потому что цифры разной ширины. */

@media (max-width: 900px) {
  /* пальцем от 44, как и везде ниже 900 */
  /* длинное название лучше перенести, чем обрезать многоточием */
}

@media (max-width: 900px) {
  .lpt .lv-section { padding: var(--lv-s16) 0; }
  .lpt .lv-section__head { margin-bottom: var(--lv-s8); }
  /* Кружок 44 px над каждым заголовком добавлял на телефоне почти
     двести пикселей пустоты на три шага. Номер уходит в строку
     с заголовком и становится ростом со строку. */
  /* Полоса остаётся полосой и на телефоне: три кадра в ряд. Чтобы они
     не выродились в тонкую ленту, на узком экране берём квадрат
     вместо горизонтали. */
  /* ПОДВАЛ НА ТЕЛЕФОНЕ.
     Ссылке нужна цель под палец, но правило min-height: 44px растащило
     список так, что между строками оказывалось по сорок пустых
     пикселей, и подвал занимал целый экран. Цель добираем невидимым
     полем через отрицательный отступ: палец попадает в 44 px, а на
     глаз строки идут плотно. */
  .lpt .lv-acc__btn { padding: var(--lv-s4) 0; }
}

/* ------------------------------------------------------------
   17. РАСКЛАДКА
   ------------------------------------------------------------ */
.lpt .lv-wrap { max-width: 1200px; margin: 0 auto; padding: 0 var(--lv-s6); }
/* У `1fr` минимум равен ширине содержимого, поэтому одна широкая
   таблица раздувает колонку и уводит вбок всю страницу.
   В системе допустим только `minmax(0, 1fr)` */
.lpt .lv-grid { display: grid; gap: var(--lv-s4); grid-template-columns: repeat(var(--lv-cols, 3), minmax(0, 1fr)); }

/* ------------------------------------------------------------
   18. ТЕЛЕФОН
   Одна точка излома — 900 px. Всё, во что тычут пальцем, от 44 px;
   плеер и таб-бар из этого правила исключены, у них своя сетка.
   ------------------------------------------------------------ */
@media (max-width: 900px) {
  .lpt .lv-btn { height: 48px; }
  .lpt .lv-chip { min-height: 44px; }
  .lpt .lv-wrap { padding: 0 var(--lv-s4); }
  .lpt .lv-grid { --lv-cols: 2; }
  /* шторка снизу: сбоку на телефоне ей негде взяться */
  /* пальцем от 44: коробка выбора не растёт, растёт площадь нажатия */
}

/* Второй порог для сеток. На планшете две колонки ещё держатся, на
   телефоне уже нет: замер дал карточку в 171 px, и заголовок
   «Творчество и эксперименты» не помещался в неё ни одной строкой.
   Ниже 560 любая сетка карточек становится в одну колонку. */
@media (max-width: 560px) {
  .lpt .lv-grid { --lv-cols: 1; }
}/* ============================================================
   LUVI — ГОСТЕВЫЕ СТРАНИЦЫ ИНСТРУМЕНТОВ (дополнение к tokens.css)
   Всё, что не покрывает UI-кит главной. Компонентов поверх кита
   минимум: форма-«мини-студия» и сетка связанных инструментов.
   ============================================================ */

/* Первый экран: текст слева, форма справа; на телефоне — друг под другом */

/* Мини-студия: первый шаг нужной вкладки студии */

/* Текстовые разделы: ширина строки как в статьях */
.lpt .lpt-seo-text { max-width: 760px; }
.lpt .lpt-seo-text p { margin: 0 0 var(--lv-s4); color: var(--lv-text-2); font: 400 17px/1.7 var(--lv-font-ui); }
.lpt .lpt-seo-text p b { color: var(--lv-text-1); }
.lpt .lpt-seo-text a, .lpt .lv-card a, .lpt .lv-acc__body a { color: #FF7DBE; text-underline-offset: 3px; }

/* Карточки возможностей со значком в строке с заголовком */

/* Связанные инструменты — перелинковка между страницами */
.lpt .lpt-tools { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: var(--lv-s3); }
.lpt .lpt-tool { display: grid; grid-template-columns: 40px minmax(0, 1fr); gap: var(--lv-s3); align-items: center; padding: var(--lv-s4); border-radius: var(--lv-r-lg); background: var(--lv-surface-1); border: 1px solid var(--lv-border-2); color: inherit; text-decoration: none; transition: border-color var(--lv-t-hover), background var(--lv-t-hover); }
.lpt .lpt-tool:hover { border-color: var(--lv-border-1); background: var(--lv-surface-2); }
.lpt .lpt-tool:focus-visible { outline: none; box-shadow: var(--lv-ring); }
.lpt .lpt-tool b { display: block; font: 700 16px/1.3 var(--lv-font-head); color: var(--lv-text-1); }
.lpt .lpt-tool span { display: block; margin-top: 2px; font: 400 13px/1.4 var(--lv-font-ui); color: var(--lv-text-3); }

/* «Один текст — три жанра» и прочие примеры с плеером в строке */

/* Пометки для разработчика в макете (в боевой разметке не нужны) */

/* Списки в тексте */
.lpt .lpt-seo-list { margin: 0 0 var(--lv-s4); padding: 0; list-style: none; display: grid; gap: var(--lv-s2); }
.lpt .lpt-seo-list li { display: flex; gap: var(--lv-s2); color: var(--lv-text-2); font: 400 16px/1.6 var(--lv-font-ui); }
.lpt .lpt-seo-list .lv-ico { flex: none; margin-top: 4px; color: var(--lv-success); }

/* Таблица сравнения */
.lpt .lpt-tbl { overflow-x: auto; border: 1px solid var(--lv-border-2); border-radius: var(--lv-r-lg); background: var(--lv-surface-1); }
.lpt .lpt-tbl table { width: 100%; min-width: 640px; border-collapse: collapse; font: 400 15px/1.5 var(--lv-font-ui); }
.lpt .lpt-tbl th, .lpt .lpt-tbl td { padding: 14px 16px; text-align: left; vertical-align: top; border-bottom: 1px solid var(--lv-border-2); }
.lpt .lpt-tbl thead th { font: 700 13px/1.3 var(--lv-font-ui); letter-spacing: .04em; text-transform: uppercase; color: var(--lv-text-3); background: var(--lv-surface-2); }
.lpt .lpt-tbl tbody th { font: 700 15px/1.4 var(--lv-font-head); color: var(--lv-text-1); }
.lpt .lpt-tbl td { color: var(--lv-text-2); }
.lpt .lpt-tbl tr:last-child th, .lpt .lpt-tbl tr:last-child td { border-bottom: 0; }
.lpt .lpt-tbl a { color: #FF7DBE; text-underline-offset: 3px; }

/* Проблема → решение */

/* Тарифы: ключевая для страницы возможность выделена */
.lpt .lpt-tariffs__note { margin-top: var(--lv-s6); }
.lpt .lpt-tariffs__note p { font-size: 15px; margin-bottom: var(--lv-s2); }

/* ============================================================
   v3: ЖИВЫЕ БЛОКИ — экраны студии, картинки, примеры, мультитрек
   ============================================================ */
.lpt .lv-section__head { margin-bottom: var(--lv-s8); }

/* Полоса фактов под первым экраном: только проверенные цифры */
.lpt .lpt-facts { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--lv-s3); }
@media (max-width: 900px) { .lpt .lpt-facts { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.lpt .lpt-fact { padding: var(--lv-s6) var(--lv-s4); border-radius: var(--lv-r-lg); background: var(--lv-surface-1); border: 1px solid var(--lv-border-2); }
.lpt .lpt-fact b { display: block; font: 800 clamp(28px, 3.4vw, 40px)/1 var(--lv-font-head); letter-spacing: -.03em; background: var(--lv-grad); -webkit-background-clip: text; background-clip: text; color: transparent; }
.lpt .lpt-fact span { display: block; margin-top: var(--lv-s2); font: 500 14px/1.4 var(--lv-font-ui); color: var(--lv-text-2); }

/* Экран студии: снимок в рамке, свет позади, метки вокруг */
.lpt .lpt-split { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr); gap: var(--lv-s16); align-items: center; }
@media (max-width: 900px) { .lpt .lpt-split { grid-template-columns: minmax(0, 1fr); gap: var(--lv-s12); } }
.lpt .lpt-split .lv-section__head { margin-bottom: var(--lv-s4); }
.lpt .lpt-split__txt p { margin: 0 0 var(--lv-s4); color: var(--lv-text-2); font: 400 16px/1.65 var(--lv-font-ui); max-width: 56ch; }
.lpt .lpt-split__txt .lpt-seo-list { margin-top: var(--lv-s4); }
.lpt .lpt-shot { position: relative; justify-self: center; width: min(100%, var(--shot-w, 520px)); }
.lpt .lpt-shot::before { content: ""; position: absolute; inset: 8% 4%; border-radius: 40px; background: var(--lv-grad); filter: blur(60px); opacity: .32; z-index: 0; }
.lpt .lpt-shot__ramka { position: relative; z-index: 1; padding: 10px; border-radius: 22px; border: 1px solid var(--lv-border-1); background: var(--lv-surface-1); box-shadow: var(--lv-shadow-overlay); }
.lpt .lpt-shot__ramka img { display: block; width: 100%; height: auto; border-radius: 14px; }
.lpt .lpt-shot .lv-metka { opacity: 0; }
.lpt .lpt-shot.lpt-is-in .lv-metka { opacity: 1; transition: opacity .6s var(--lv-ease-out) var(--pauza, 0s); }
@media (max-width: 900px) { .lpt .lpt-shot .lv-metka--a, .lpt .lpt-shot .lv-metka--v { left: -2%; } .lpt .lpt-shot .lv-metka--b, .lpt .lpt-shot .lv-metka--g { right: -2%; } }

/* Схема «что было → что меняется → что получаете» */
.lpt .lpt-flow { display: flex; flex-wrap: wrap; align-items: center; gap: var(--lv-s2); margin: var(--lv-s4) 0; }
.lpt .lpt-flow__i { padding: 10px 14px; border-radius: var(--lv-r-md); background: var(--lv-surface-2); border: 1px solid var(--lv-border-2); font: 600 14px/1.3 var(--lv-font-ui); color: var(--lv-text-1); }
.lpt .lpt-flow__i small { display: block; font-weight: 400; font-size: 12px; color: var(--lv-text-3); }
.lpt .lpt-flow__i--hot { border-color: var(--lv-accent); }
.lpt .lpt-flow > .lv-ico { color: var(--lv-text-3); }

/* Шаги с экраном: номер, текст со списком, снимок рядом */
.lpt .lpt-stx { display: grid; gap: var(--lv-s16); counter-reset: stx; }
.lpt .lpt-stx__i { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--lv-s12); align-items: center; }
.lpt .lpt-stx__i:nth-child(even) > .lpt-stx__txt { order: 2; }
@media (max-width: 900px) { .lpt .lpt-stx { gap: var(--lv-s12); } .lpt .lpt-stx__i { grid-template-columns: minmax(0, 1fr); gap: var(--lv-s6); } .lpt .lpt-stx__i:nth-child(even) > .lpt-stx__txt { order: 0; } }
.lpt .lpt-stx__n { counter-increment: stx; display: inline-grid; place-items: center; width: 44px; height: 44px; border-radius: 50%; background: var(--lv-grad); color: #fff; font: 800 18px/1 var(--lv-font-head); }
.lpt .lpt-stx__n::before { content: counter(stx); }
.lpt .lpt-stx__t { margin: var(--lv-s4) 0 0; font: 700 clamp(22px, 2.6vw, 28px)/1.2 var(--lv-font-head); letter-spacing: -.02em; }
.lpt .lpt-stx__d { margin: var(--lv-s3) 0 0; color: var(--lv-text-2); font: 400 16px/1.65 var(--lv-font-ui); max-width: 50ch; }
.lpt .lpt-stx__txt .lpt-seo-list { margin-top: var(--lv-s4); }
.lpt .lpt-stx__txt .lpt-seo-list li { font-size: 15px; }
.lpt .lpt-stx__tip { display: inline-flex; gap: 8px; align-items: flex-start; margin-top: var(--lv-s4); padding: 10px 14px; border-radius: var(--lv-r-md); background: rgba(253, 66, 156, .12); color: var(--lv-text-1); font: 500 14px/1.45 var(--lv-font-ui); max-width: 52ch; }
.lpt .lpt-stx__tip .lv-ico { flex: none; margin-top: 1px; color: var(--lv-accent); }
.lpt .lpt-stx .lpt-shot { --shot-w: 460px; }

/* Карточки с картинкой (как «Что умеет» на главной) */
.lpt .lpt-bento .lv-fcard { color: inherit; text-decoration: none; transition: border-color var(--lv-t-hover), transform var(--lv-t-hover); }
.lpt a.lv-fcard:hover { border-color: var(--lv-border-1); transform: translateY(-2px); }
.lpt a.lv-fcard:focus-visible { outline: none; box-shadow: var(--lv-ring); }
.lpt .lv-fcard__go { display: inline-flex; align-items: center; gap: 4px; margin-top: var(--lv-s3); font: 600 13px/1 var(--lv-font-ui); color: #FF7DBE; }
.lpt .lpt-grid-4 { --lv-cols: 4; }
@media (max-width: 1100px) and (min-width: 901px) { .lpt .lpt-grid-4 { --lv-cols: 2; } }
@media (min-width: 901px) { .lpt .lpt-bento .lv-fcard__in { padding: var(--lv-s4); } .lpt .lpt-bento .lv-fcard__t { font-size: 19px; } .lpt .lpt-bento .lv-fcard__d { margin-top: var(--lv-s2); font-size: 14px; line-height: 1.55; } }

/* Фото-карточки поводов: лента, подпись поверх кадра */

/* Примеры запросов с кнопкой «Попробовать» */
.lpt .lpt-prompts { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: var(--lv-s3); }
.lpt .lpt-prompt { display: flex; flex-direction: column; gap: var(--lv-s3); padding: var(--lv-s4); border-radius: var(--lv-r-lg); background: var(--lv-surface-1); border: 1px solid var(--lv-border-2); }
.lpt .lpt-prompt__h { display: flex; align-items: center; gap: var(--lv-s2); flex-wrap: wrap; font: 700 15px/1.3 var(--lv-font-head); color: var(--lv-text-1); }
.lpt .lpt-prompt__h .lv-ico { color: var(--lv-text-3); }
.lpt .lpt-prompt__t { margin: 0; flex: 1; padding: 12px 14px; border-radius: var(--lv-r-md); background: var(--lv-surface-2); color: var(--lv-text-2); font: 400 14px/1.55 var(--lv-font-ui); }
.lpt .lpt-prompt__r { margin: 0; color: var(--lv-text-3); font: 400 13px/1.5 var(--lv-font-ui); }
.lpt .lpt-prompt .lv-btn { align-self: flex-start; }

/* «Как обычно» против «в Luvi» */

/* Мелкие карточки-советы: значок, заголовок, 1–2 строки, пример «так / не так» */
.lpt .lpt-tips { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--lv-s3); }
@media (max-width: 900px) { .lpt .lpt-tips { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 560px) { .lpt .lpt-tips { grid-template-columns: minmax(0, 1fr); } }
.lpt .lpt-tip { padding: var(--lv-s4); border-radius: var(--lv-r-lg); background: var(--lv-surface-1); border: 1px solid var(--lv-border-2); }
.lpt .lpt-tip h3 { margin: 0; font: 700 17px/1.3 var(--lv-font-head); }
.lpt .lpt-tip p { margin: var(--lv-s2) 0 0; color: var(--lv-text-2); font: 400 14px/1.55 var(--lv-font-ui); }
.lpt .lpt-tip__ex { display: grid; gap: 6px; margin-top: var(--lv-s3); }
.lpt .lpt-tip__ex span { padding: 8px 10px; border-radius: var(--lv-r-md); font: 400 13px/1.45 var(--lv-font-ui); white-space: pre-line; }
.lpt .lpt-tip__ex .lpt-bad { background: rgba(255, 90, 90, .08); color: var(--lv-text-2); }
.lpt .lpt-tip__ex .lpt-bad::before { content: "Так хуже: "; color: #FF8A8A; font-weight: 600; }
.lpt .lpt-tip__ex .lpt-good { background: rgba(47, 190, 122, .10); color: var(--lv-text-1); }
.lpt .lpt-tip__ex .lpt-good::before { content: "Так лучше: "; color: var(--lv-success); font-weight: 600; }

/* Пара плееров «ваш голос → готовая песня» / «оригинал → кавер» */

/* Карточки инструментов — с картинкой */
.lpt .lpt-tool__art { width: 56px; height: 56px; border-radius: var(--lv-r-md); object-fit: cover; }
.lpt .lpt-tool--art { grid-template-columns: 56px minmax(0, 1fr); }

/* Три карточки про права */
.lpt .lpt-rights { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--lv-s3); }
@media (max-width: 900px) { .lpt .lpt-rights { grid-template-columns: minmax(0, 1fr); } }

/* Группы ссылок: жанры и поздравления */
.lpt .lpt-linkgroups { display: grid; gap: var(--lv-s6); }
.lpt .lpt-linkgroup h3 { margin: 0 0 var(--lv-s3); font: 600 14px/1.3 var(--lv-font-ui); letter-spacing: .04em; text-transform: uppercase; color: var(--lv-text-3); }

/* Карточки «одна песня — разные жанры»: обложка-кнопка, жанр, плеер */

/* Шапка вошедшего (в макете — ?auth=1). На сайте — существующий аватар с меню. */

/* ---------- Первый экран = студия (вариант Б) ----------
   Сверху короткий заголовок, под ним студия на вкладке страницы: форма слева,
   библиотека справа. На сайте блок .st — настоящий компонент студии. */
.lpt [data-for][hidden] { display: none !important; }
/* ============================================================
   КАРКАС ЭКРАНА СТУДИИ (на сайте его собирает страница /studio)
   Всё внутри — классы Tailwind из боевой сборки (shared/studio-app.css).
   Здесь только то, чего нет в сборке: раскладка колонок, телефон,
   состояния переключателей в макете. Цвета — переменные студии.
   ============================================================ */
.lpt [data-for][hidden] { display: none !important; }

/* меню: в студии hidden lg:flex, на телефоне — верхняя строка */

/* студия: панель слева, «Моё пространство» справа, высота — экран */

/* вкладки режимов: разделитель между неактивными (after:… в студии) */

/* подрежимы «Свой текст / По описанию / Инструментал» */

/* пол вокала */

/* «Без вокала» */

/* выбор языка — стрелка как в студии */

/* лента чипов */

/* «Моё пространство»: подписи у Фильтры/Сортировка/Вид — с 52rem ширины (как @[52rem]:inline) */

/* поле «Свой текст» — моноширинное, как в студии (tokens.css ставит inherit) */

/* меню движков: галочка у выбранного *//* Связка: гостевая студия v3 + SEO-блоки посадки.
   v3.css — стили студии v3 (luvimusic.ru/v3) как есть, ограничены классом .v3.
   Здесь — только то, чего в v3 нет: сетка страницы, гостевые элементы, H1, окно регистрации.
   Классы v3 (sidebar, nav-item, pan, seg, tbtn, track…) здесь не переопределяются. */                       /* в v3: html { zoom: .9 } */

/* сетка страницы — как .app в v3: меню 240px (×0.9) + рабочая область; под студией текст */

/* гостю внизу меню вместо «Пополнить» и аккаунта — вход и регистрация (как .sidebar__topup) */

/* H1 внутри студии (вариант А) */

/* H1 под студией (вариант Б) */
.lpt .lpt-lp-hero { padding: 56px 0 8px; text-align: center; }
.lpt .lpt-lp-hero .lv-kicker { margin-bottom: 12px; }
.lpt .lpt-lp-hero h1 { margin: 0 auto; max-width: 18ch; font-family: "Onest", "Mulish", sans-serif; font-weight: 800; font-size: clamp(32px, 4.4vw, 52px); line-height: 1.08; letter-spacing: -.02em; color: #F7F5F1; }
.lpt .lpt-lp-hero p { margin: 18px auto 0; max-width: 62ch; font-size: 17px; line-height: 1.6; color: #CFCCD6; }

/* панели вкладок, которых не было в снимке v3 (Простой, Мастер, Своим голосом) */

/* кнопка «Создать» у гостя: выглядит как disabled в v3, но нажимается — подсвечивает, чего не хватает */

/* примеры справа (вместо «Моих треков»): карточки .track из v3 */

/* окно регистрации (в прототипе — заглушка окна входа сайта) */

/* телефон */
@media (max-width: 900px) {
  .lpt .lpt-lp-hero { padding-top: 40px; }
  .lpt .lpt-lp-hero p { font-size: 16px; }
}