/*
	==========================================================================
	ВИДЖЕТ «ИИ-АССИСТЕНТ» КЛИЕНТСКОГО САЙТА — САМОДОСТАТОЧНЫЙ МОДУЛЬ
	==========================================================================

	ЗАЧЕМ ОТДЕЛЬНЫЙ ФАЙЛ, А НЕ ПАРА ПРАВИЛ В stheme.css.

	У проекта уже есть строгое разделение: `ste-*` — интерфейс СЕРВИСА,
	`st-*` — стили САМОГО САЙТА. Виджет не относится ни к тому, ни к другому:
	он живет НА сайте, но не является его содержимым; он рисуется поверх всего,
	у него своя геометрия, свои состояния и свой жизненный цикл. Смешать его
	с темой сайта значило бы, что смена темы ломает чат, а правка чата задевает
	верстку страниц.

	Отсюда ТРЕТИЙ ПРЕФИКС — `stw-` — и свой бандл (stwidget.css + stwidget.js),
	подключаемый ровно там, где ассистент подключен.

	СВЯЗЬ С ТЕМОЙ САЙТА — ЧЕРЕЗ ПЕРЕМЕННЫЕ, А НЕ ЧЕРЕЗ ОБЩИЕ КЛАССЫ.
	По умолчанию цвета берутся из палитры сайта (--st-accent, --st-surface
	и т.д.), поэтому виджет «из коробки» выглядит частью сайта и работает
	в обеих палитрах. Настройки владельца приходят отдельным <style> с более
	высокой специфичностью ([data-st-mode="…"] #корень) и перебивают тему —
	ПРИОРИТЕТ ВЛАДЕЛЬЦА НАД ТЕМОЙ, а не наоборот.

	АНИМАЦИИ. Их выбирает владелец, но выключает ПОСЕТИТЕЛЬ: блок
	@media (prefers-reduced-motion: reduce) в конце файла гасит их
	безусловно — это требование доступности, а не настройка.
*/

.stw {
	/* ==== ЦВЕТА: УМОЛЧАНИЕ = ТЕМА САЙТА ====
	   Переопределения владельца приезжают отдельным <style> и перебивают
	   эти значения; тема сайта, в свою очередь, перебивает жесткие запасные
	   цвета в правой части каждого var() */
	/*
		ЦВЕТА КНОПКИ ПРИЕЗЖАЮТ ПОСЧИТАННЫМИ С СЕРВЕРА (websiteAiVars),
		а значения ниже — страховка на случай, если <style> виджета
		почему-то не доехал.

		ПОЧЕМУ ЗНАЧОК БОЛЬШЕ НЕ БЕРЕТСЯ ИЗ `--st-accent-text`: у темной
		палитры темы это почти черный (#0F1218), и на брендовом зеленом
		значок выходил тусклым. Сервер считает его от ФАКТИЧЕСКОГО фона
		кнопки — на цветной белый, на светлой темный
	*/
	--stw-btn-bg: var(--st-accent, #2F8F5B);
	--stw-btn-bg2: var(--stw-btn-bg);
	--stw-btn-fg: #FFFFFF;
	--stw-btn-glow: var(--stw-btn-bg);

	/*
		==== ЦВЕТА СОСТОЯНИЙ НЕ ССЫЛАЮТСЯ НА ЦВЕТА ПОКОЯ ====
		(правка 2026-08-07 — НЕ УПРОЩАТЬ ОБРАТНО)

		Здесь напрашивается `--stw-btn-bg-hover: var(--stw-btn-bg)`, и раньше
		так и было. Теперь так НЕЛЬЗЯ: наведение подменяет САМИ базовые
		переменные (`.stw-btn:hover { --stw-btn-bg: var(--stw-btn-bg-hover) }`),
		и обратная ссылка замкнула бы кольцо. Кольцевые ссылки CSS объявляет
		недействительными ЦЕЛИКОМ и разом — кнопка осталась бы вообще
		без цвета.

		Подмена базовых переменных нужна ради ЖИВОЙ ФОРМЫ: полотно читает
		`--stw-btn-bg`/`--stw-btn-bg2` на каждом кадре, и только так оно
		перекрашивается вместе с заливкой.

		Значения ниже — страховка на случай, если <style> виджета не доехал:
		сервер (websiteAiVars) присылает все шесть посчитанными ВСЕГДА
	*/
	--stw-btn-bg-hover: var(--st-accent, #2F8F5B);
	--stw-btn-bg2-hover: var(--st-accent, #2F8F5B);
	--stw-btn-glow-hover: var(--st-accent, #2F8F5B);
	--stw-btn-fg-hover: #FFFFFF;
	--stw-btn-bg-active: var(--st-accent, #2F8F5B);
	--stw-btn-bg2-active: var(--st-accent, #2F8F5B);
	--stw-btn-glow-active: var(--st-accent, #2F8F5B);
	--stw-btn-fg-active: #FFFFFF;

	/*
		==== ЦВЕТА ПАНЕЛИ: ТЕМА ПАНЕЛИ → ЦВЕТА САЙТА ====

		Значения ниже — НИЖНЯЯ ступень каскада, а не «как оно выглядит».
		Сверху ложатся переменные выбранной темы панели и цвета владельца
		(websiteAiPanelVars). Пустая тема `site` не выводит ничего вовсе —
		и тогда работает ровно эта цепочка к цветам сайта (--st-*).
		Именно в этом смысл темы «Как на сайте», и ломать ее подстановкой
		жестких цветов сюда нельзя
	*/
	--stw-panel-bg: var(--st-surface, #FFFFFF);
	--stw-head-bg: var(--st-surface-alt, #EEF2F6);
	--stw-text: var(--st-text-base, #1B1F27);
	--stw-muted: var(--st-muted, #78818F);
	--stw-border: var(--st-border, #E3E8EF);
	--stw-accent: var(--st-accent, #2F8F5B);
	--stw-accent-text: var(--st-accent-text, #FFFFFF);

	/*
		РЕПЛИКИ И ПЛИТКИ ССЫЛАЮТСЯ НА ПОВЕРХНОСТЬ, А НЕ НА СВОИ ЦВЕТА.

		Так панель остается согласованной, пока владелец не тронул ни одного
		поля: ответ ассистента лежит на альтернативной поверхности, реплика
		посетителя — на акценте, плитка — на поверхности с контуром.
		Стоит задать цвет — переменная приезжает посчитанной с сервера
		и цепочка обрывается на ней
	*/
	--stw-bot-bg: var(--stw-head-bg);
	--stw-bot-fg: var(--stw-text);
	--stw-user-bg: var(--stw-accent);
	--stw-user-fg: var(--stw-accent-text);
	--stw-tile-bg: var(--stw-panel-bg);
	--stw-tile-fg: var(--stw-text);
	--stw-tile-border: var(--stw-border);

	--stw-radius: var(--st-radius, 16px);
	--stw-radius-sm: var(--st-radius-sm, 10px);
	--stw-shadow: 0 18px 48px rgba(15, 20, 30, 0.24);
	--stw-font: var(--st-font, 'Inter', 'Segoe UI', system-ui, -apple-system, sans-serif);

	/* Размеры приходят инлайном от сервера: одно и то же число нужно
	   и превью в панели настроек, и самому виджету, поэтому оно живет
	   в конфиге ($_AI['sizes'] / $_AI['widths']), а не здесь */
	--stw-btn-size: 58px;
	--stw-panel-width: 400px;
	--stw-gap-x: 24px;
	--stw-gap-y: 24px;

	/*
		ГЕОМЕТРИЯ ПАНЕЛИ приезжает тем же инлайном (websiteAiStyle).
		Значения ниже повторяют ПРЕЖНЕЕ поведение шторки: без скругления,
		во всю высоту. Блок, созданный до появления подач, обязан выглядеть
		ровно как раньше
	*/
	--stw-panel-radius: 0px;
	--stw-panel-height: 100%;
	--stw-panel-gap: 20px;
	--stw-msg-width: 88%;

	/*
		РАЗМЕР ЗНАЧКА ПРИХОДИТ ГОТОВЫМИ ПИКСЕЛЯМИ.

		Владелец задает его ДОЛЕЙ от кнопки (иначе смена размера кнопки
		заставляла бы подбирать значок заново), но умножение делает СЕРВЕР.
		Здесь был `calc()` с дробным множителем — и любая мелочь в записи
		дроби делала весь `calc()` невалидным, а значок молча оставался
		прежнего размера. 24px — прежнее соотношение (58 × 0.42)
	*/
	--stw-btn-icon-size: 24px;
	--stw-btn-angle: 135deg;

	/* Тень кнопки отделена от общей тени панели: у них разные настройки
	   и разный смысл — панель всегда над страницей, а кнопка может
	   и лежать на ней плоско */
	--stw-btn-shadow: 0 18px 48px rgba(15, 20, 30, 0.28);

	/*
		КОРЕНЬ ЗАКРЕПЛЕН ЗА ОКНОМ, А НЕ ЗА СТРАНИЦЕЙ: кнопка ассистента
		обязана оставаться на месте при прокрутке — в этом весь смысл
		плавающего виджета.

		`pointer-events: none` на корне и `auto` на его детях: корень
		растянут на весь экран и без этого перехватывал бы каждый клик
		по сайту
	*/
	position: fixed;
	inset: 0;
	z-index: 1200;
	pointer-events: none;
	font-family: var(--stw-font);
	color: var(--stw-text);
	line-height: 1.45;
	text-align: left;
}

.stw *,
.stw *::before,
.stw *::after {
	box-sizing: border-box;
}

/*
	==========================================================================
	ПОЧЕМУ У ЭЛЕМЕНТОВ УПРАВЛЕНИЯ СЕЛЕКТОРЫ ВИДА `.stw .stw-btn`
	==========================================================================
	(найдено 2026-08-09 — НЕ «УПРОЩАТЬ», УБРАВ ПРЕФИКС)

	Виджет живет ВНУТРИ корня сайта, а у сайта есть свой сброс элементов
	(stheme.css):

		.st-site button,
		.st-site input,
		.st-site select,
		.st-site textarea { font: inherit; color: inherit; margin: 0 }

	Его вес — КЛАСС + ТИП (0,1,1), а у одиночного `.stw-btn-main` — только
	класс (0,1,0). Значит сброс сайта ПЕРЕБИВАЛ собственные цвета и размеры
	шрифта виджета: текст на акцентной кнопке наследовался от панели
	и выходил темным по темному, подсказка в поле ввода была не того
	кегля, что задан.

	Симптом обманчив: цвет ВЫЧИСЛЕН правильно и переменная на месте —
	просто до элемента не доезжает.

	Лечение — вес: `.stw .stw-btn-main` это (0,2,0), и сброс сайта его
	не достает. Префикс нужен ТОЛЬКО базовым правилам самих элементов
	управления (button / input / textarea / select) и их модификаторам
	(`--rec`, `--first`, `--on`, `--main`): всё, что уже написано через
	атрибут корня или псевдокласс, и так тяжелее.

	ВАЖНО ПРИ ДОБАВЛЕНИИ НОВОЙ КНОПКИ ИЛИ ПОЛЯ: пишите правило сразу
	с префиксом. Забудете — цвет и кегль молча возьмутся от сайта
*/

/*
	УЗЕЛ-НОСИТЕЛЬ КОНФИГУРАЦИИ. Пустой, служебный, лежит рядом с корнем
	виджета: в его `data-stw-config` сервер кладет JSON, который читает
	HSSteWidget.boot().

	АТРИБУТ, А НЕ <script type="application/json">: вставщик модальных окон
	сервиса перебирает ВСЕ теги <script> и делает `eval()`, не глядя
	на `type`, — JSON падал там с «Unexpected token ':'» и уносил с собой
	все окно конструктора.

	`display: none` ДУБЛИРУЕТ атрибут `hidden` НАМЕРЕННО: `hidden` — всего
	лишь умолчание браузера и проигрывает любому правилу темы сайта,
	задающему `display` элементам по тегу или потомству
*/
.stw-boot {
	display: none !important;
}

/* ==== КНОПКА-ВИДЖЕТ ==================================================== */

.stw .stw-btn {
	position: absolute;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 10px;
	min-width: var(--stw-btn-size);
	height: var(--stw-btn-size);
	padding: 0;
	margin: 0;
	border: 0;
	/*
		ФОН КНОПКИ РИСУЕТ СЛОЙ `__bg`, А НЕ САМА КНОПКА (2026-08-06).

		Заливок стало шесть — цвет, градиент, стекло, контур, неон, аврора, —
		и половине из них нужен `overflow: hidden` (блик, движущийся градиент).
		Повесь его на кнопку — и кольцо с искрами, которым положено выходить
		за край, оказались бы обрезаны. Слой решает обе задачи разом
	*/
	background-color: transparent;
	color: var(--stw-btn-fg);
	box-shadow: var(--stw-btn-shadow);
	cursor: pointer;
	pointer-events: auto;
	font: inherit;
	font-weight: 600;
	transition: color 0.2s ease, box-shadow 0.25s ease, scale 0.2s ease, rotate 0.2s ease, translate 0.2s ease;
}

/* ==== ФОРМА КНОПКИ ===================================================== */
/*
	Скругление считается ОТ РАЗМЕРА КНОПКИ, поэтому крупная и мелкая
	выглядят одинаково — на фиксированных пикселях мелкая казалась бы
	заметно круглее
*/
.stw[data-stw-shape="circle"] .stw-btn { border-radius: 999px; }
.stw[data-stw-shape="squircle"] .stw-btn { border-radius: calc(var(--stw-btn-size) / 3); }
.stw[data-stw-shape="square"] .stw-btn { border-radius: 4px; }
.stw[data-stw-shape="pill"] .stw-btn { border-radius: 999px; }

/* КАПЛЯ — асимметричные радиусы. Именно четыре разных угла дают «живую»
   органическую форму: одинаковые превратили бы ее обратно в скругленный
   квадрат */
.stw[data-stw-shape="blob"] .stw-btn {
	border-radius: 62% 38% 46% 54% / 54% 46% 62% 38%;
}

/* Зеркальная капля: те же радиусы, развернутые. Нужна не ради счета
   вариантов — рядом с текстом справа и слева уместны разные наклоны */
.stw[data-stw-shape="blob2"] .stw-btn {
	border-radius: 38% 62% 54% 46% / 46% 54% 38% 62%;
}

/* ЛИСТ — два острых угла по диагонали, два скругленных */
.stw[data-stw-shape="leaf"] .stw-btn {
	border-radius: 60% 6px 60% 6px;
}

/* ЯЙЦО — верх уже низа. Мягкая форма без единого угла */
.stw[data-stw-shape="egg"] .stw-btn {
	border-radius: 50% 50% 48% 48% / 62% 62% 38% 38%;
}

/* АРКА — круглый верх на прямом основании. Единственная форма, которая
   явно «стоит» на странице, поэтому уместна в нижних позициях кнопки */
.stw[data-stw-shape="arch"] .stw-btn {
	border-radius: 999px 999px 14px 14px;
}

/*
	КАПЛЯ ВОДЫ — три круглых угла и один острый.

	ОСТРЫЙ УГОЛ СЛЕВА СНИЗУ, А НЕ СПРАВА: кнопка чаще всего стоит в правом
	нижнем углу экрана, и носик смотрит внутрь страницы, а не в край
*/
.stw[data-stw-shape="drop"] .stw-btn {
	border-radius: 50% 50% 50% 6px;
}

/*
	ШЕСТИУГОЛЬНИК — clip-path, а не border-radius: углов у радиуса нет
	в принципе.

	ЦЕНА ЧЕСТНО: обрезка работает по прямоугольнику кнопки, поэтому
	с подписью («значок и текст») шестиугольник растянется в вытянутую
	плашку. Это не поломка, а свойство формы — панель настроек
	предупреждает об этом рядом с выбором
*/
.stw[data-stw-shape="hex"] .stw-btn {
	border-radius: 0;
	clip-path: polygon(25% 2%, 75% 2%, 100% 50%, 75% 98%, 25% 98%, 0% 50%);
}

.stw[data-stw-shape="diamond"] .stw-btn {
	border-radius: 0;
	clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%);
}

.stw[data-stw-shape="shield"] .stw-btn {
	border-radius: 0;
	clip-path: polygon(50% 100%, 4% 72%, 4% 8%, 96% 8%, 96% 72%);
}

/*
	ВСПЫШКА — двенадцатилучевая звезда.

	САМАЯ «ДОРОГАЯ» ФОРМА ПО ЧИТАЕМОСТИ: лучи съедают углы, и значок
	крупнее ~55 % начинает в них упираться. Панель об этом не
	предупреждает отдельно — размер значка виден в образце сразу
*/
.stw[data-stw-shape="burst"] .stw-btn {
	border-radius: 0;
	clip-path: polygon(
		50% 0%, 61% 13%, 78% 8%, 79% 26%, 95% 30%, 87% 45%,
		100% 57%, 84% 65%, 88% 82%, 70% 82%, 63% 98%, 50% 87%,
		37% 98%, 30% 82%, 12% 82%, 16% 65%, 0% 57%, 13% 45%,
		5% 30%, 21% 26%, 22% 8%, 39% 13%
	);
}

/* ВОСЬМИУГОЛЬНИК — самая «спокойная» из вырезанных форм: углы есть,
   но ни один не торчит, и значок в них не упирается при любом размере */
.stw[data-stw-shape="octagon"] .stw-btn {
	border-radius: 0;
	clip-path: polygon(30% 0%, 70% 0%, 100% 30%, 100% 70%, 70% 100%, 30% 100%, 0% 70%, 0% 30%);
}

/*
	ЗВЕЗДА. Лучи съедают углы сильнее вспышки, поэтому крупный значок
	в ней не помещается — размер значка виден в образце сразу, отдельного
	предупреждения не нужно
*/
.stw[data-stw-shape="star"] .stw-btn {
	border-radius: 0;
	clip-path: polygon(
		50% 0%, 61% 35%, 98% 35%, 68% 57%, 79% 91%,
		50% 70%, 21% 91%, 32% 57%, 2% 35%, 39% 35%
	);
}

/*
	ОБЛАЧКО ЧАТА — форма, которая сама говорит, что кнопка про разговор.

	СКРУГЛЕНИЯ ПРИБЛИЖЕНЫ ГРАНЯМИ: у `clip-path: polygon()` скругленных
	углов нет в принципе, а хвостик иначе не вырезать вовсе. На размерах
	кнопки (48…80 px) четырнадцати точек хватает — грани не читаются
*/
.stw[data-stw-shape="bubble"] .stw-btn {
	border-radius: 0;
	clip-path: polygon(
		50% 0%, 78% 4%, 96% 22%, 100% 46%, 96% 70%, 78% 88%,
		50% 92%, 30% 90%, 10% 100%, 14% 84%, 4% 70%, 0% 46%,
		4% 22%, 22% 4%
	);
}

/* Режим «иконка + текст»: подпись занимает место, поэтому кнопка перестает
   быть квадратной и получает горизонтальные поля */
.stw[data-stw-mode="text"] .stw-btn {
	padding: 0 20px;
}

/*
	ПУСТАЯ КНОПКА — ни значка, ни подписи. Нужна под живой формой:
	полотно и есть вся картинка, а значок поверх него только мешает.

	СКРЫВАЕТСЯ СОДЕРЖИМОЕ, А НЕ САМА КНОПКА: она остается коробкой
	нужного размера, ловит клики и по-прежнему представляется программе
	экранного доступа через aria-label
*/
.stw[data-stw-mode="none"] .stw-btn__icon,
.stw[data-stw-mode="none"] .stw-btn__label {
	display: none;
}

.stw[data-stw-mode="icon"] .stw-btn__label {
	display: none;
}

/* ==== СЛОЙ ЗАЛИВКИ ===================================================== */

.stw-btn__bg {
	position: absolute;
	inset: 0;
	z-index: 0;
	border-radius: inherit;
	/* Обрезаем ЗДЕСЬ и только здесь: блик и движущийся градиент за краем
	   заливки недопустимы, а кольцу с искрами наружу как раз можно */
	overflow: hidden;
	background-color: var(--stw-btn-bg);
	/* `filter` в переходе нужен «осветлению» при наведении: без него
	   пересвет включался бы рывком */
	transition: background-color 0.2s ease, filter 0.2s ease;
	pointer-events: none;
}

/* Значок и подпись обязаны лежать ПОВЕРХ заливки: слой абсолютный
   и без явного порядка накрыл бы их собой */
.stw-btn__icon,
.stw-btn__label {
	position: relative;
	z-index: 2;
}

.stw-btn__icon {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	font-size: var(--stw-btn-icon-size);
	line-height: 1;
	/* `transform` держит «переворот значка»: у него своя ось вращения
	   с перспективой, и отдельным свойством `rotate` его не задать */
	transition: rotate 0.35s ease, scale 0.2s ease, transform 0.45s ease;
}

/*
	==== ГЛАВНЫЕ ГРАБЛИ ЗНАЧКА, СТОИВШИЕ ДВУХ «НЕРАБОТАЮЩИХ» НАСТРОЕК ====
	(найдено 2026-08-07)

	В САМОМ КОНЦЕ plugins.bundle.css стоит правило:

		.ki-duotone,.ki-outline,.ki-solid,.ki-filled {
			line-height: 1;
			font-size: 1rem;
			color: var(--bs-text-muted);
		}

	Оно бьет ПО САМОМУ ЭЛЕМЕНТУ `<i>`, а не наследуется, поэтому:
	  - `font-size: 1rem` перебивал размер, заданный родителю, и ползунок
	    «размер значка» не менял РОВНО НИЧЕГО;
	  - `color: var(--bs-text-muted)` перебивал цвет кнопки, и значок
	    всегда был серым — сколько бы контраст ни считался на сервере.

	Оба симптома выглядели как «настройка не работает», хотя значения
	доезжали правильными: их просто перекрывали ниже по каскаду.

	Специфичность правила — 0,1,0 (один класс). Здесь 0,1,1 (класс + тег),
	и этого достаточно; `!important` не нужен.

	ПРАВИЛО НА БУДУЩЕЕ: KeenIcons в этом проекте НАВЯЗЫВАЕТ значкам свой
	цвет и размер. Везде, где `<i class="ki-*">` должен слушаться родителя,
	это надо снимать явно — как уже сделано у `.ste-acc__icon i`
	и `.st-ai-card__icon i`
*/
.stw-btn__icon i {
	font-size: var(--stw-btn-icon-size);
	color: inherit;
}

/* СВОЙ SVG ВЫВОДИТСЯ КАРТИНКОЙ, А НЕ ВСТРАИВАЕТСЯ В РАЗМЕТКУ (см. комментарий
   к a_platforms_website_ai_icon): внутри загруженного файла могут быть скрипты,
   а через <img> браузер их не исполняет вовсе.
   Размер тот же, что у шрифтового значка: владелец крутит ОДИН ползунок
   и не должен гадать, какой из двух видов значка он сейчас настраивает */
.stw-btn__icon img {
	display: block;
	width: var(--stw-btn-icon-size);
	height: var(--stw-btn-icon-size);
	object-fit: contain;
}

.stw-btn__label {
	white-space: nowrap;
}

/* ==== СТИЛИ ЗАЛИВКИ ==================================================== */
/*
	Градиент собирается из ДВУХ переменных и угла, а не из готовой строки:
	угол настраивается отдельно, а «перелив» крутит те же два цвета через
	третью остановку. Готовая строка заперла бы и то, и другое
*/
.stw[data-stw-fill="gradient"] .stw-btn__bg,
.stw[data-stw-fill="neon"] .stw-btn__bg {
	background-image: linear-gradient(var(--stw-btn-angle), var(--stw-btn-bg), var(--stw-btn-bg2));
}

/*
	АВРОРА — движение ВСТРОЕНО В СТИЛЬ, а не вынесено в анимацию покоя:
	неподвижная «аврора» — это просто градиент, и отдельным вариантом
	ей быть незачем
*/
.stw[data-stw-fill="aurora"] .stw-btn__bg {
	background-image: linear-gradient(var(--stw-btn-angle), var(--stw-btn-bg), var(--stw-btn-bg2), var(--stw-btn-bg));
	background-size: 240% 240%;
	animation: stw-flow 9s ease-in-out infinite;
}

/*
	МЕШ-ГРАДИЕНТ — несколько радиальных пятен вместо одной оси.

	Настоящий mesh рисуется сеткой контрольных точек и в CSS недоступен,
	но три смещенных радиальных градиента дают тот же характер: свет
	приходит «из углов», а не переливается по прямой. Заметно живее
	обычного линейного при том же наборе из двух цветов
*/
.stw[data-stw-fill="mesh"] .stw-btn__bg {
	background-image:
		radial-gradient(circle at 22% 24%, var(--stw-btn-bg2), transparent 58%),
		radial-gradient(circle at 80% 30%, var(--stw-btn-bg), transparent 55%),
		radial-gradient(circle at 55% 88%, var(--stw-btn-bg2), transparent 62%);
	background-color: var(--stw-btn-bg);
}

/* КРУГОВОЙ — конический градиент по кругу. На круглой кнопке читается
   как переход, замкнутый сам на себя, без начала и конца */
.stw[data-stw-fill="conic"] .stw-btn__bg {
	background-image: conic-gradient(from var(--stw-btn-angle), var(--stw-btn-bg), var(--stw-btn-bg2), var(--stw-btn-bg));
}

/*
	МЕТАЛЛИК — резкие светлые полосы поперек градиента.

	Ощущение металла дают именно РЕЗКИЕ границы остановок (одна и та же
	доля повторяется дважды): плавные переходы читались бы как обычный
	градиент, а не как блик на шлифованной поверхности
*/
.stw[data-stw-fill="metal"] .stw-btn__bg {
	background-image: linear-gradient(
		var(--stw-btn-angle),
		var(--stw-btn-bg) 0%,
		var(--stw-btn-bg2) 28%,
		rgba(255, 255, 255, 0.55) 42%,
		rgba(255, 255, 255, 0.55) 46%,
		var(--stw-btn-bg2) 60%,
		var(--stw-btn-bg) 100%
	);
}

/*
	ИЗ ЦЕНТРА — свет приходит из одной точки, а не с одной стороны.

	Смещение центра вверх обязательно: ровно посередине пятно читается
	как дефект печати, а сдвинутое — как отражение источника света
*/
.stw[data-stw-fill="radial"] .stw-btn__bg {
	background-image: radial-gradient(circle at 50% 34%, var(--stw-btn-bg2), var(--stw-btn-bg) 74%);
}

/*
	ПЕРЛАМУТР — конический градиент с БЕЛОЙ остановкой посередине.

	Именно белая вставка отличает его от «кругового»: без нее это тот же
	переход между двумя красками, а с ней появляется характерный
	голографический отлив
*/
.stw[data-stw-fill="holo"] .stw-btn__bg {
	background-image: conic-gradient(
		from var(--stw-btn-angle),
		var(--stw-btn-bg),
		var(--stw-btn-bg2),
		rgba(255, 255, 255, 0.9),
		var(--stw-btn-bg2),
		var(--stw-btn-bg)
	);
}

/*
	ЛУЧИ — повторяющийся конический градиент.

	ШАГ 30° (двенадцать лучей) ВЫБРАН ПОД РАЗМЕР КНОПКИ: у мелкого шага
	лучи на 48 px сливаются в рябь, у крупного их видно всего четыре
	и рисунок перестает читаться как расходящийся свет
*/
.stw[data-stw-fill="sunburst"] .stw-btn__bg {
	background-image: repeating-conic-gradient(
		from var(--stw-btn-angle),
		var(--stw-btn-bg) 0deg 15deg,
		var(--stw-btn-bg2) 15deg 30deg
	);
}

/* ПОЛОСЫ — тот же угол, что у градиента: владелец крутит один ползунок
   и разворачивает рисунок, а не ищет вторую настройку наклона */
.stw[data-stw-fill="stripes"] .stw-btn__bg {
	background-image: repeating-linear-gradient(
		var(--stw-btn-angle),
		var(--stw-btn-bg) 0 7px,
		var(--stw-btn-bg2) 7px 14px
	);
}

/* ТОЧКИ — сетка поверх сплошного цвета. Размер ячейки фиксирован
   в пикселях: привяжи его к размеру кнопки — и крупная кнопка получила бы
   те же четыре точки, только больше */
.stw[data-stw-fill="dots"] .stw-btn__bg {
	background-color: var(--stw-btn-bg);
	background-image: radial-gradient(circle, var(--stw-btn-bg2) 1.6px, transparent 1.9px);
	background-size: 9px 9px;
}

/*
	ОБЪЕМНАЯ — свет сверху, тень снизу, обе ВНУТРЕННИЕ.

	Работает на любом цвете, потому что рисуется полупрозрачным белым
	и черным поверх заливки, а не осветлением самого цвета: у темной
	кнопки осветлять было бы нечего
*/
.stw[data-stw-fill="emboss"] .stw-btn__bg {
	background-color: var(--stw-btn-bg);
	background-image: linear-gradient(var(--stw-btn-angle), var(--stw-btn-bg2), var(--stw-btn-bg));
	box-shadow:
		inset 0 2px 6px rgba(255, 255, 255, 0.45),
		inset 0 -4px 10px rgba(0, 0, 0, 0.35);
}

/*
	СТЕКЛО. Полупрозрачная подложка цветом кнопки плюс размытие того,
	что под ней. `color-mix` вместо готовой rgba(): цвет приходит
	переменной, и разложить его на каналы в CSS нечем
*/
.stw[data-stw-fill="glass"] .stw-btn__bg {
	background-color: color-mix(in srgb, var(--stw-btn-bg) 26%, transparent);
	backdrop-filter: blur(14px) saturate(1.5);
	-webkit-backdrop-filter: blur(14px) saturate(1.5);
	box-shadow: inset 0 0 0 1px color-mix(in srgb, #FFFFFF 34%, transparent);
}

/* КОНТУР. Рамка рисуется внутренней тенью, а не border: border сдвинул бы
   содержимое кнопки на свою толщину */
.stw[data-stw-fill="outline"] .stw-btn__bg {
	background-color: transparent;
	box-shadow: inset 0 0 0 2px var(--stw-btn-bg);
}

/*
	БЕЗ ЗАЛИВКИ. Кнопка остается коробкой нужного размера и ловит клики,
	но не рисует НИЧЕГО: ни фона, ни рамки, ни тени.

	ТЕНЬ СНИМАЕТСЯ ЗДЕСЬ ЖЕ, И ЭТО НЕ МЕЛОЧЬ: без нее под живой сферой
	висел бы серый прямоугольный ореол — самое заметное, что выдает
	«кнопку под картинкой». Свечение при этом ОСТАЕТСЯ рабочим: оно
	повторяет цвет и часто как раз и нужно вокруг сферы
*/
.stw[data-stw-fill="none"] .stw-btn__bg {
	background-color: transparent;
	background-image: none;
	box-shadow: none;
}

.stw[data-stw-fill="none"][data-stw-glow="none"] .stw-btn {
	box-shadow: none;
}

/* НЕОН — градиент плюс собственное свечение цветом кнопки. Свечение здесь
   ВСТРОЕНО в стиль и складывается с настройкой «свечение», если владелец
   включил и ее */
.stw[data-stw-fill="neon"] .stw-btn {
	box-shadow: var(--stw-btn-shadow),
		0 0 14px -2px var(--stw-btn-glow),
		0 0 34px -6px var(--stw-btn-glow);
}

/* ==== ТЕНЬ И СВЕЧЕНИЕ ================================================== */
/*
	РАЗНЫЕ ОСИ, И ЭТО НЕ ПРИДИРКА: тень сажает кнопку на страницу,
	свечение отрывает ее от страницы. Нужны обе сразу — значит одним
	списком быть не могут
*/
.stw[data-stw-shadow="none"] { --stw-btn-shadow: 0 0 0 0 rgba(0, 0, 0, 0); }
.stw[data-stw-shadow="flat"] { --stw-btn-shadow: 0 2px 5px rgba(15, 20, 30, 0.22); }
.stw[data-stw-shadow="soft"] { --stw-btn-shadow: 0 10px 26px rgba(15, 20, 30, 0.20); }
.stw[data-stw-shadow="deep"] { --stw-btn-shadow: 0 18px 48px rgba(15, 20, 30, 0.30); }
/*
	ДЛИННАЯ. Смещение вниз БОЛЬШЕ размытия, и это ее единственное отличие
	от «глубокой»: у той пятно расплывается вокруг кнопки, у этой —
	уезжает вниз, и кнопка читается высоко поднятой над страницей.
	Отрицательный разброс держит пятно уже самой кнопки
*/
.stw[data-stw-shadow="long"] { --stw-btn-shadow: 0 26px 26px -14px rgba(15, 20, 30, 0.50); }

/* КОНТУРНОЕ — свет держится ВПЛОТНУЮ к кромке. Единственный вариант,
   который виден на светлой странице: широкие ореолы на белом тонут */
.stw[data-stw-glow="tight"] .stw-btn {
	box-shadow: var(--stw-btn-shadow), 0 0 8px 0 var(--stw-btn-glow);
}

.stw[data-stw-glow="soft"] .stw-btn {
	box-shadow: var(--stw-btn-shadow), 0 0 22px -4px var(--stw-btn-glow);
}

.stw[data-stw-glow="strong"] .stw-btn {
	box-shadow: var(--stw-btn-shadow),
		0 0 14px -2px var(--stw-btn-glow),
		0 0 42px -6px var(--stw-btn-glow);
}

/*
	ШИРОКИЙ ОРЕОЛ. ПОЛОЖИТЕЛЬНЫЙ РАЗБРОС во втором слое (а не отрицательный,
	как у «яркого») — именно он уводит свет далеко за кнопку. Слоев три:
	один растянутый читался бы как размытое пятно рядом, а не как сияние
	самой кнопки
*/
.stw[data-stw-glow="aura"] .stw-btn {
	box-shadow: var(--stw-btn-shadow),
		0 0 12px -2px var(--stw-btn-glow),
		0 0 34px 2px var(--stw-btn-glow),
		0 0 72px 10px var(--stw-btn-glow);
}

/* ==== РАМКА И БЛИК: СВОЙ СЛОЙ ========================================= */
/*
	==== ПОЧЕМУ ПОНАДОБИЛСЯ ЧЕТВЕРТЫЙ СЛУЖЕБНЫЙ СЛОЙ (2026-08-08) ====

	Псевдоэлементы у элемента ровно два, и все ближние заняты:
	`__bg::before/::after` — анимации покоя («вращение фона», «блеск»),
	`__fx::before/::after` — кольца, `__spark::before/::after` — искры.
	Пятая ось (рамка) и шестая (блик) сели бы поверх чужих, и сочетания
	вроде «блеск + блик» молча теряли бы одно из двух.

	СЛОЙ ЛЕЖИТ ПОВЕРХ ЖИВОЙ ФОРМЫ И ПОД ЗНАЧКОМ. Это не вкусовщина:
	блик — отражение на ПОВЕРХНОСТИ предмета, под полотном его быть
	не может; значок же обязан остаться читаемым.

	ОБРЕЗАЕТСЯ (`overflow: hidden`) — иначе диагональный блик вылезал бы
	за скругление углом. Форму берет у кнопки: у вырезанных `clip-path`
	она приходит от самой кнопки, у остальных — через `border-radius`
*/
.stw-btn__edge {
	position: absolute;
	inset: 0;
	z-index: 1;
	border-radius: inherit;
	overflow: hidden;
	pointer-events: none;
}

.stw-btn__edge::before {
	content: '';
	position: absolute;
	inset: 0;
	pointer-events: none;
}

/*
	РАМКА — ВНУТРЕННЯЯ ТЕНЬ, А НЕ `border`. Свойство `border` съедает свою
	толщину из содержимого и сдвигает значок; внутренняя тень рисуется
	поверх, ничего не двигая. Тот же прием, что у заливки «Контур», —
	но на отдельном слое, поэтому сочетается с любой заливкой
*/
.stw[data-stw-border="hair"] .stw-btn__edge {
	box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.55);
}

.stw[data-stw-border="bold"] .stw-btn__edge {
	box-shadow: inset 0 0 0 3px rgba(255, 255, 255, 0.75);
}

.stw[data-stw-border="dark"] .stw-btn__edge {
	box-shadow: inset 0 0 0 2px rgba(10, 14, 22, 0.40);
}

/* СВЕТЯЩАЯСЯ — цветом кнопки, с растушевкой ВНУТРЬ: снаружи за это
   отвечает «Свечение», и дублировать его тут было бы нечестно */
.stw[data-stw-border="glow"] .stw-btn__edge {
	box-shadow:
		inset 0 0 0 2px var(--stw-btn-glow),
		inset 0 0 14px -2px var(--stw-btn-glow);
}

/* ДВОЙНАЯ — светлая линия и тёмный зазор под ней. Зазор обязателен:
   две светлые линии подряд слились бы в одну жирную */
.stw[data-stw-border="double"] .stw-btn__edge {
	box-shadow:
		inset 0 0 0 2px rgba(255, 255, 255, 0.85),
		inset 0 0 0 5px rgba(10, 14, 22, 0.28);
}

/*
	БЛИК. Все варианты — полупрозрачный БЕЛЫЙ поверх заливки, а не
	осветление ее цвета: у темной кнопки осветлять было бы нечего,
	а белый работает на любой (то же правило, что у заливки «Объемная»)
*/
.stw[data-stw-gloss="top"] .stw-btn__edge::before {
	background-image: linear-gradient(180deg, rgba(255, 255, 255, 0.45), transparent 56%);
}

.stw[data-stw-gloss="bottom"] .stw-btn__edge::before {
	background-image: linear-gradient(0deg, rgba(255, 255, 255, 0.38), transparent 48%);
}

/*
	ДИАГОНАЛЬНЫЙ — узкая полоса поперек кнопки, как отсвет окна на стекле.
	ГРАНИЦЫ ОСТАНОВОК РЕЗКИЕ С ОДНОЙ СТОРОНЫ И МЯГКИЕ С ДРУГОЙ: ровно
	симметричная полоса читается как дефект печати, а не как отражение
*/
.stw[data-stw-gloss="glare"] .stw-btn__edge::before {
	background-image: linear-gradient(
		118deg,
		transparent 30%,
		rgba(255, 255, 255, 0.42) 42%,
		rgba(255, 255, 255, 0.42) 48%,
		transparent 66%
	);
}

/*
	ОБОДОК — светлая кайма ИЗНУТРИ края, по всему кругу. Так выглядит
	стекло: свет уходит в полное внутреннее отражение и собирается
	у стенки. Радиальным градиентом, а не тенью: тень дала бы ровную
	линию, а здесь нужен именно плавный набор яркости к краю
*/
.stw[data-stw-gloss="rim"] .stw-btn__edge::before {
	background-image: radial-gradient(
		closest-side,
		transparent 62%,
		rgba(255, 255, 255, 0.10) 82%,
		rgba(255, 255, 255, 0.50) 100%
	);
}

/* ==== ЖИВАЯ ФОРМА (CANVAS) ============================================= */
/*
	ГЕНЕРАТИВНОЕ ПОЛОТНО ВНУТРИ КНОПКИ — сфера в духе голосовых
	ассистентов. Рисует его stwidget.js (HSSteWidget.orb), здесь только
	место и правила слоя.

	ЛЕЖИТ ПОВЕРХ ЗАЛИВКИ И ПОД ЗНАЧКОМ: заливка дает основу и форму,
	живое полотно — движение, значок обязан остаться читаемым поверх
	обоих. Обрезается по форме кнопки — иначе клякса вылезала бы
	за скругление.

	`filter: blur()` НЕ ИСПОЛЬЗУЕТСЯ: он заставляет браузер растеризовать
	слой заново на каждом кадре. Мягкость дают сами радиальные градиенты
	в холсте — они бесплатны
*/
.stw-btn__orb {
	position: absolute;
	inset: 0;
	z-index: 1;
	width: 100%;
	height: 100%;
	border-radius: inherit;
	overflow: hidden;
	pointer-events: none;
}

/*
	АНИМИРОВАННЫЙ ЗНАЧОК LOTTIE. Плеер вставляет внутрь свой <svg>
	и растягивает его до размеров контейнера, поэтому коробка задается
	здесь — тем же размером, что у остальных двух видов значка.
	Владелец крутит ОДИН ползунок и не гадает, какой вид он настраивает
*/
.stw-btn__lottie {
	display: block;
	width: var(--stw-btn-icon-size);
	height: var(--stw-btn-icon-size);
}

.stw-btn__lottie svg {
	display: block;
	width: 100% !important;
	height: 100% !important;
}

/* ==== СЛОЙ ЭФФЕКТОВ: КОЛЬЦА И ИСКРЫ ==================================== */
/*
	Лежит ПОД значком и НАД заливкой, ничего не перехватывает и наружу
	не обрезается. Кольца рисуют его псевдоэлементы, искры — вложенный
	`__spark` со своими двумя: четыре независимых слоя из двух узлов
*/
.stw-btn__fx {
	position: absolute;
	inset: 0;
	z-index: 1;
	border-radius: inherit;
	pointer-events: none;
}

.stw-btn__fx::before,
.stw-btn__fx::after {
	content: '';
	position: absolute;
	inset: 0;
	border-radius: inherit;
	pointer-events: none;
}

/* Без кольца псевдоэлементы не должны существовать вовсе: пустая рамка
   поверх кнопки ловила бы глаз на пустом месте */
.stw[data-stw-ring="none"] .stw-btn__fx::before,
.stw[data-stw-ring="none"] .stw-btn__fx::after {
	display: none;
}

/* ОРЕОЛ — неподвижное мягкое кольцо цветом кнопки */
.stw[data-stw-ring="halo"] .stw-btn__fx::before {
	box-shadow: 0 0 0 7px color-mix(in srgb, var(--stw-btn-glow) 20%, transparent);
}

.stw[data-stw-ring="halo"] .stw-btn__fx::after {
	display: none;
}

/*
	КРУГИ НА ВОДЕ — два кольца, расходящиеся по очереди. Задержка
	у второго ровно в половину цикла: с равной задержкой они шли бы
	слитно и читались как одно толстое кольцо
*/
.stw[data-stw-ring="ripple"] .stw-btn__fx::before,
.stw[data-stw-ring="ripple"] .stw-btn__fx::after {
	box-shadow: 0 0 0 2px var(--stw-btn-glow);
	animation: stw-ripple 2.8s ease-out infinite;
}

.stw[data-stw-ring="ripple"] .stw-btn__fx::after {
	animation-delay: 1.4s;
}

/*
	ВРАЩАЮЩЕЕСЯ КОЛЬЦО. Конический градиент, из которого маской вырезана
	середина, — так получается именно КОЛЬЦО толщиной 2 px, а не крутящийся
	закрашенный круг под кнопкой
*/
.stw[data-stw-ring="spin"] .stw-btn__fx::before {
	inset: -3px;
	background: conic-gradient(from 0deg, transparent 0deg, var(--stw-btn-glow) 90deg, transparent 200deg);
	mask: radial-gradient(farthest-side, transparent calc(100% - 2px), #000 calc(100% - 2px));
	-webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 2px), #000 calc(100% - 2px));
	animation: stw-spin 3.2s linear infinite;
}

.stw[data-stw-ring="spin"] .stw-btn__fx::after {
	display: none;
}

/*
	ПУНКТИРНОЕ КОЛЬЦО. Штрихи — повторяющийся конический градиент,
	середина вырезана маской: тот же прием, что у вращающегося кольца.
	`border: dashed` не годится — у него штрихи привязаны к прямоугольнику
	и на круге ложатся неровно
*/
.stw[data-stw-ring="dashed"] .stw-btn__fx::before {
	inset: -4px;
	background: repeating-conic-gradient(var(--stw-btn-glow) 0deg 9deg, transparent 9deg 20deg);
	mask: radial-gradient(farthest-side, transparent calc(100% - 2px), #000 calc(100% - 2px));
	-webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 2px), #000 calc(100% - 2px));
	animation: stw-spin 9s linear infinite;
}

.stw[data-stw-ring="dashed"] .stw-btn__fx::after {
	display: none;
}

/* ДВА ВСТРЕЧНЫХ — кольца из дуг, вращающиеся в разные стороны.
   Встречное движение читается как механизм, а не как «что-то крутится» */
.stw[data-stw-ring="dual"] .stw-btn__fx::before,
.stw[data-stw-ring="dual"] .stw-btn__fx::after {
	background: conic-gradient(from 0deg, transparent 0deg, var(--stw-btn-glow) 70deg, transparent 150deg);
	mask: radial-gradient(farthest-side, transparent calc(100% - 2px), #000 calc(100% - 2px));
	-webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 2px), #000 calc(100% - 2px));
	animation: stw-spin 3.6s linear infinite;
}

.stw[data-stw-ring="dual"] .stw-btn__fx::before { inset: -3px; }

.stw[data-stw-ring="dual"] .stw-btn__fx::after {
	inset: -8px;
	animation-direction: reverse;
	animation-duration: 5.2s;
	opacity: 0.6;
}

/*
	ТОЧКА ПО ОРБИТЕ. Вращается не сама точка, а СЛОЙ вокруг центра
	кнопки — точка нарисована в его фоне у верхнего края.
	Так орбита остается идеально круглой на любой форме кнопки.

	ЗДЕСЬ БЫЛО `box-shadow: 0 calc(-50% + 1px) 0 -1px …`, И ЭТО НЕ РАБОТАЛО
	ВОВСЕ (найдено 2026-08-07): смещения тени процентов не принимают,
	браузер молча выбрасывал объявление целиком — кольцо «Точка по орбите»
	не рисовало ничего. Симптом ровно такой, будто пункт списка пустой.
	ПРАВИЛО НА БУДУЩЕЕ: проценты в box-shadow не существуют, ни в одном
	из четырех значений
*/
.stw[data-stw-ring="orbit"] .stw-btn__fx::before {
	inset: -9px;
	border-radius: 999px;
	background: radial-gradient(circle 3px at 50% 0, var(--stw-btn-glow) 0 100%, transparent 100%);
	animation: stw-spin 2.8s linear infinite;
}

.stw[data-stw-ring="orbit"] .stw-btn__fx::after {
	display: none;
}

/* ДУГА — незамкнутое кольцо, как индикатор загрузки. Единственное
   из колец, что читается как «идет работа», а не как украшение */
.stw[data-stw-ring="arc"] .stw-btn__fx::before {
	inset: -5px;
	background: conic-gradient(from 0deg, var(--stw-btn-glow) 0deg 100deg, transparent 100deg);
	mask: radial-gradient(farthest-side, transparent calc(100% - 3px), #000 calc(100% - 3px));
	-webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 3px), #000 calc(100% - 3px));
	animation: stw-spin 1.6s linear infinite;
}

.stw[data-stw-ring="arc"] .stw-btn__fx::after {
	display: none;
}

/*
	ДЫШАЩЕЕ КОЛЬЦО. От «Ореола» отличается не яркостью, а ТЕМ, ЧТО ЖИВЕТ:
	ореол — резкая неподвижная линия, здесь мягкое кольцо, которое медленно
	расширяется и сжимается, не уходя с места (в отличие от «кругов
	на воде», где кольца улетают прочь и растворяются).

	РАЗМАХ НАМЕРЕННО МАЛЫЙ (1 → 1.12): большой превращает вариант
	в те же круги на воде, только вечные
*/
.stw[data-stw-ring="aura"] .stw-btn__fx::before {
	box-shadow:
		0 0 0 4px color-mix(in srgb, var(--stw-btn-glow) 26%, transparent),
		0 0 12px 6px color-mix(in srgb, var(--stw-btn-glow) 18%, transparent);
	animation: stw-ring-breath 3.4s ease-in-out infinite;
}

.stw[data-stw-ring="aura"] .stw-btn__fx::after {
	display: none;
}

/*
	ЧЕТЫРЕ ДУГИ ПО СТОРОНАМ СВЕТА — «рамка прицела»: кнопка читается
	как взятая в фокус, а не украшенная.

	ПОВТОРЯЮЩИЙСЯ КОНИЧЕСКИЙ ГРАДИЕНТ С ШАГОМ 90°, из которого маской
	вырезана середина, — тот же прием, что у пунктирного кольца.
	ВРАЩЕНИЕ ЗДЕСЬ НЕ НУЖНО: крутящийся прицел перестает быть прицелом.
	Второй слой (`::after`) дает вторую, более тонкую рамку с поворотом
	на 45° — без нее рисунок выглядит незаконченным на круглой кнопке
*/
.stw[data-stw-ring="corners"] .stw-btn__fx::before {
	inset: -5px;
	background: repeating-conic-gradient(var(--stw-btn-glow) 0deg 26deg, transparent 26deg 90deg);
	mask: radial-gradient(farthest-side, transparent calc(100% - 2px), #000 calc(100% - 2px));
	-webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 2px), #000 calc(100% - 2px));
	rotate: -13deg;
}

.stw[data-stw-ring="corners"] .stw-btn__fx::after {
	inset: -9px;
	background: repeating-conic-gradient(var(--stw-btn-glow) 0deg 12deg, transparent 12deg 90deg);
	mask: radial-gradient(farthest-side, transparent calc(100% - 1px), #000 calc(100% - 1px));
	-webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 1px), #000 calc(100% - 1px));
	rotate: 39deg;
	opacity: 0.6;
}

@keyframes stw-ring-breath {
	0%, 100% { scale: 1; opacity: 0.85; }
	50% { scale: 1.12; opacity: 0.45; }
}

@keyframes stw-ripple {
	0% { scale: 1; opacity: 0.55; }
	100% { scale: 1.75; opacity: 0; }
}

@keyframes stw-spin {
	100% { rotate: 360deg; }
}

/*
	ИСКРЫ — ЧИСТЫЙ CSS, БЕЗ КАНВАСА И БЕЗ ЕДИНОГО УЗЛА НА ЧАСТИЦУ.

	Точки нарисованы радиальными градиентами в фоне двух псевдоэлементов,
	мерцают они в противофазе. Так «частицы» стоят виджету двух слоев
	композитора вместо цикла перерисовки — на слабом телефоне посетителя
	это разница между плавной страницей и подтормаживающей
*/
.stw-btn__spark {
	position: absolute;
	inset: -34%;
	pointer-events: none;
}

.stw-btn__spark::before,
.stw-btn__spark::after {
	content: '';
	position: absolute;
	inset: 0;
	background-repeat: no-repeat;
	opacity: 0;
}

.stw[data-stw-spark="none"] .stw-btn__spark {
	display: none;
}

.stw[data-stw-spark="soft"] .stw-btn__spark::before,
.stw[data-stw-spark="rich"] .stw-btn__spark::before {
	background-image:
		radial-gradient(circle, var(--stw-btn-glow) 0 40%, transparent 45%),
		radial-gradient(circle, var(--stw-btn-glow) 0 40%, transparent 45%),
		radial-gradient(circle, var(--stw-btn-glow) 0 40%, transparent 45%);
	background-size: 5px 5px, 4px 4px, 6px 6px;
	background-position: 12% 22%, 84% 30%, 68% 86%;
	animation: stw-spark 3.2s ease-in-out infinite;
}

.stw[data-stw-spark="soft"] .stw-btn__spark::after,
.stw[data-stw-spark="rich"] .stw-btn__spark::after {
	background-image:
		radial-gradient(circle, var(--stw-btn-glow) 0 40%, transparent 45%),
		radial-gradient(circle, var(--stw-btn-glow) 0 40%, transparent 45%),
		radial-gradient(circle, var(--stw-btn-glow) 0 40%, transparent 45%);
	background-size: 4px 4px, 6px 6px, 5px 5px;
	background-position: 22% 82%, 90% 66%, 46% 8%;
	animation: stw-spark 3.2s ease-in-out infinite;
	animation-delay: 1.6s;
}

/* «Часто» — тот же рисунок вдвое быстрее и заметно ярче: своего набора
   точек ему не нужно, разница читается темпом */
.stw[data-stw-spark="rich"] .stw-btn__spark::before,
.stw[data-stw-spark="rich"] .stw-btn__spark::after {
	animation-duration: 1.9s;
	filter: brightness(1.25);
}

.stw[data-stw-spark="rich"] .stw-btn__spark::after {
	animation-delay: 0.95s;
}

@keyframes stw-spark {
	0%, 100% { opacity: 0; scale: 0.75; }
	45% { opacity: 0.95; scale: 1.08; }
	70% { opacity: 0; scale: 1.2; }
}

/*
	==== ИСКРЫ С ПОВЕДЕНИЕМ: ВСПЛЫВАЮЩИЕ, ПАДАЮЩИЕ, ПО КРУГУ ====

	Точки те же — меняется только то, как движется слой с ними.
	Двигать СЛОЙ, а не каждую точку, здесь принципиально: перемещение
	одного элемента композитор делает бесплатно, а анимация двух десятков
	`background-position` пересчитывала бы фон на каждом кадре
*/
.stw[data-stw-spark="rise"] .stw-btn__spark::before,
.stw[data-stw-spark="rise"] .stw-btn__spark::after,
.stw[data-stw-spark="fall"] .stw-btn__spark::before,
.stw[data-stw-spark="fall"] .stw-btn__spark::after {
	background-image:
		radial-gradient(circle, var(--stw-btn-glow) 0 40%, transparent 45%),
		radial-gradient(circle, var(--stw-btn-glow) 0 40%, transparent 45%),
		radial-gradient(circle, var(--stw-btn-glow) 0 40%, transparent 45%);
	background-size: 5px 5px, 4px 4px, 6px 6px;
	background-position: 18% 50%, 52% 50%, 84% 50%;
}

.stw[data-stw-spark="rise"] .stw-btn__spark::before {
	animation: stw-spark-rise 2.6s ease-out infinite;
}

.stw[data-stw-spark="rise"] .stw-btn__spark::after {
	background-position: 34% 50%, 68% 50%, 8% 50%;
	animation: stw-spark-rise 2.6s ease-out infinite;
	animation-delay: 1.3s;
}

.stw[data-stw-spark="fall"] .stw-btn__spark::before {
	animation: stw-spark-fall 3s ease-in infinite;
}

.stw[data-stw-spark="fall"] .stw-btn__spark::after {
	background-position: 34% 50%, 68% 50%, 8% 50%;
	animation: stw-spark-fall 3s ease-in infinite;
	animation-delay: 1.5s;
}

@keyframes stw-spark-rise {
	0% { opacity: 0; translate: 0 28%; }
	25% { opacity: 0.9; }
	100% { opacity: 0; translate: 0 -34%; }
}

@keyframes stw-spark-fall {
	0% { opacity: 0; translate: 0 -34%; }
	25% { opacity: 0.9; }
	100% { opacity: 0; translate: 0 28%; }
}

/*
	РАЗЛЕТАЮЩИЕСЯ. Слой не едет в сторону, а РАСТЕТ из размера кнопки —
	точки расходятся от нее во все стороны разом. Единственный вариант
	искр, который читается как «сработало», а не как фоновое мерцание.

	СТАРТ МЕНЬШЕ ЕДИНИЦЫ (0.55) ОБЯЗАТЕЛЕН: начни разлет с натуральной
	величины — и точки появлялись бы уже далеко от кнопки, будто прилетели
	откуда-то извне
*/
.stw[data-stw-spark="burst"] .stw-btn__spark::before,
.stw[data-stw-spark="burst"] .stw-btn__spark::after {
	background-image:
		radial-gradient(circle, var(--stw-btn-glow) 0 40%, transparent 45%),
		radial-gradient(circle, var(--stw-btn-glow) 0 40%, transparent 45%),
		radial-gradient(circle, var(--stw-btn-glow) 0 40%, transparent 45%),
		radial-gradient(circle, var(--stw-btn-glow) 0 40%, transparent 45%);
	background-size: 5px 5px, 4px 4px, 6px 6px, 4px 4px;
	background-position: 16% 20%, 86% 26%, 74% 84%, 22% 78%;
	animation: stw-spark-burst 2.4s ease-out infinite;
}

.stw[data-stw-spark="burst"] .stw-btn__spark::after {
	background-position: 50% 8%, 94% 54%, 48% 92%, 6% 46%;
	animation-delay: 1.2s;
}

@keyframes stw-spark-burst {
	0% { opacity: 0; scale: 0.55; }
	20% { opacity: 0.95; }
	100% { opacity: 0; scale: 1.45; }
}

/* ПО КРУГУ — слой вращается целиком, точки идут по орбите вокруг кнопки */
.stw[data-stw-spark="orbit"] .stw-btn__spark::before,
.stw[data-stw-spark="orbit"] .stw-btn__spark::after {
	background-image:
		radial-gradient(circle, var(--stw-btn-glow) 0 40%, transparent 45%),
		radial-gradient(circle, var(--stw-btn-glow) 0 40%, transparent 45%),
		radial-gradient(circle, var(--stw-btn-glow) 0 40%, transparent 45%);
	background-size: 5px 5px, 4px 4px, 6px 6px;
	background-position: 50% 6%, 92% 62%, 12% 70%;
	opacity: 0.9;
	animation: stw-spin 6s linear infinite;
}

.stw[data-stw-spark="orbit"] .stw-btn__spark::after {
	background-position: 22% 16%, 78% 14%, 50% 94%;
	animation-duration: 9s;
	animation-direction: reverse;
	opacity: 0.6;
}

/* ==== ПОЗИЦИЯ КНОПКИ НА ЭКРАНЕ ========================================= */
/*
	Ключ читается как «вертикаль + горизонталь»: b/m/t — снизу, по центру,
	сверху; l/r — слева, справа. Отступы задает владелец, поэтому они
	приходят переменными, а не константами
*/
.stw[data-stw-pos$="r"] .stw-btn { right: var(--stw-gap-x); }
.stw[data-stw-pos$="l"] .stw-btn { left: var(--stw-gap-x); }

/*
	==== КНОПКА УСТУПАЕТ ПОЛОСЕ СОГЛАСИЯ НА COOKIE (2026-08-15) ====

	Полоса согласия закреплена у нижнего края и до ответа посетителя стоит
	ВЫШЕ виджета (`z-index: 1300` против 1200). Нижнее положение кнопки —
	ровно тот же угол, поэтому без сдвига она оказывалась ПОД полосой:
	до ассистента было не добраться, пока не принято согласие.

	ВЫСОТУ ПОЛОСЫ КЛАДЕТ СКРИПТ (`--st-cookie-h`: `initCookie` в stsite.js
	на сайте, `syncCookieHeight` в steditor.js в предпросмотре
	конструктора) — она зависит от длины текста, ширины полосы и размера
	шрифта, и числом ее не выразить. Согласие дано, полосы нет —
	переменная обнуляется, и кнопка возвращается на место.

	ВЕРХНЕЕ ПОЛОЖЕНИЕ НЕ ТРОГАЕМ: полоса всегда у НИЖНЕГО края
*/
.stw[data-stw-pos^="b"] .stw-btn { bottom: calc(var(--stw-gap-y) + var(--st-cookie-h, 0px)); }
.stw[data-stw-pos^="t"] .stw-btn { top: var(--stw-gap-y); }

.stw[data-stw-pos^="m"] .stw-btn {
	top: 50%;
	transform: translateY(-50%);
}

/* ==== АНИМАЦИИ КНОПКИ ================================================== */
/*
	ТРИ НЕЗАВИСИМЫЕ ОСИ: покой, наведение, нажатие. Разведены атрибутами,
	чтобы владелец мог собрать любую пару («пульсирует, но не растет»).

	ВАЖНО ПРО КОМБИНАЦИЮ С ПОЗИЦИЕЙ «ПО ЦЕНТРУ»: там кнопка уже сдвинута
	transform'ом, и анимации, трогающие transform, обязаны этот сдвиг
	сохранять — иначе кнопка прыгает к краю на первом же кадре. Отсюда
	отдельные наборы кадров для центрального положения
*/
/*
	ПУЛЬСАЦИЯ — РАСХОДЯЩЕЕСЯ КОЛЬЦО НА СЛОЕ ЭФФЕКТОВ, А НЕ box-shadow
	КНОПКИ (переделано 2026-08-06).

	Прежние кадры переписывали box-shadow целиком, а значит НАМЕРТВО
	спорили и со свечением, и с настройкой тени: включи владелец свечение
	вместе с пульсацией — одно из двух молча пропадало. На своем слое
	кольцо ни с чем не конкурирует.

	КОЛЬЦО КОЛЬЦУ РОЗНЬ: слоя всего два, поэтому пульсация занимает
	СВОБОДНЫЙ из них. Без кольца — первый, при «ореоле» и «вращающемся
	кольце» (они заняли первый, а второй погасили) — второй. С «кругами
	на воде» заняты оба, и пульсация не показывается: две волны из одной
	кнопки — это и есть сами круги на воде
*/
.stw[data-stw-idle="pulse"][data-stw-ring="none"] .stw-btn__fx::before,
.stw[data-stw-idle="pulse"][data-stw-ring="halo"] .stw-btn__fx::after,
.stw[data-stw-idle="pulse"][data-stw-ring="spin"] .stw-btn__fx::after {
	display: block;
	inset: 0;
	background: none;
	mask: none;
	-webkit-mask: none;
	box-shadow: 0 0 0 2px var(--stw-btn-glow);
	animation: stw-ripple 2.4s ease-out infinite;
}

/* Блик: светлая полоса проходит по кнопке слева направо. Живет на слое
   заливки — он и обрезан по форме кнопки, и не мешает кольцу снаружи */
.stw[data-stw-idle="shine"] .stw-btn__bg::after {
	content: '';
	position: absolute;
	inset: 0;
	background: linear-gradient(115deg, rgba(255, 255, 255, 0) 35%, rgba(255, 255, 255, 0.45) 50%, rgba(255, 255, 255, 0) 65%);
	translate: -120% 0;
	animation: stw-shine 3.6s ease-in-out infinite;
	pointer-events: none;
}

@keyframes stw-shine {
	0%, 60% { translate: -120% 0; }
	100% { translate: 120% 0; }
}

/* Дрейф: кнопка едва заметно всплывает и опускается */
.stw[data-stw-idle="drift"] .stw-btn {
	animation: stw-drift 4s ease-in-out infinite;
}

@keyframes stw-drift {
	0%, 100% { translate: 0 0; }
	50% { translate: 0 -6px; }
}

/* Дыхание: кнопка медленно набирает и отдает объем */
.stw[data-stw-idle="breathe"] .stw-btn {
	animation: stw-breathe 3.6s ease-in-out infinite;
}

@keyframes stw-breathe {
	0%, 100% { scale: 1; }
	50% { scale: 1.06; }
}

/*
	ПЕРЕЛИВ ЦВЕТА. Работает и на СПЛОШНОЙ заливке: второй цвет сервер
	подставляет всегда (осветленный или затемненный основной), поэтому
	владельцу не нужно сперва выбирать градиент, чтобы увидеть анимацию
*/
.stw[data-stw-idle="flow"] .stw-btn__bg {
	background-image: linear-gradient(var(--stw-btn-angle), var(--stw-btn-bg), var(--stw-btn-bg2), var(--stw-btn-bg));
	background-size: 220% 220%;
	animation: stw-flow 7s ease-in-out infinite;
}

@keyframes stw-flow {
	0%, 100% { background-position: 0% 50%; }
	50% { background-position: 100% 50%; }
}

/* Покачивание: кнопка качается вокруг своего центра */
.stw[data-stw-idle="wobble"] .stw-btn {
	animation: stw-wobble 3.4s ease-in-out infinite;
}

@keyframes stw-wobble {
	0%, 100% { rotate: 0deg; }
	25% { rotate: -5deg; }
	75% { rotate: 5deg; }
}

/*
	МАЯЧОК — пульсирует само СВЕЧЕНИЕ, а не размер. Единственная анимация
	покоя, которая ничего не двигает: она уместна там, где кнопка стоит
	рядом с текстом и любое движение отвлекало бы от чтения
*/
.stw[data-stw-idle="beacon"] .stw-btn {
	animation: stw-beacon 2.6s ease-in-out infinite;
}

@keyframes stw-beacon {
	0%, 100% { box-shadow: var(--stw-btn-shadow), 0 0 10px -4px var(--stw-btn-glow); }
	50% { box-shadow: var(--stw-btn-shadow), 0 0 30px 2px var(--stw-btn-glow); }
}

/* Подпрыгивание: короткий взлет с задержкой между прыжками — иначе
   кнопка читалась бы как непрерывно дрожащая */
.stw[data-stw-idle="bounce"] .stw-btn {
	animation: stw-bounce 2.2s ease-in-out infinite;
}

@keyframes stw-bounce {
	0%, 55%, 100% { translate: 0 0; }
	20% { translate: 0 -10px; }
	35% { translate: 0 -3px; }
}

/* Маятник: качание вокруг ВЕРХНЕЙ точки, а не центра, — именно это
   отличает подвешенный предмет от лежащего */
.stw[data-stw-idle="swing"] .stw-btn {
	transform-origin: 50% 0;
	animation: stw-swing 3.2s ease-in-out infinite;
}

@keyframes stw-swing {
	0%, 100% { rotate: 6deg; }
	50% { rotate: -6deg; }
}

/*
	ЖЕЛЕ — ширина и высота меняются В ПРОТИВОФАЗЕ.

	Именно противофаза дает ощущение упругого объема: расти в обе стороны
	сразу — это обычное «дыхание», оно уже есть отдельным пунктом
*/
.stw[data-stw-idle="jelly"] .stw-btn {
	animation: stw-jelly 2.6s ease-in-out infinite;
}

@keyframes stw-jelly {
	0%, 100% { scale: 1 1; }
	30% { scale: 1.08 0.92; }
	60% { scale: 0.94 1.06; }
}

/* Наклон в объеме: перспектива обязательна — без нее поворот по X
   выглядит просто сплющиванием */
.stw[data-stw-idle="tilt3d"] .stw-btn {
	animation: stw-tilt3d 4.4s ease-in-out infinite;
}

@keyframes stw-tilt3d {
	0%, 100% { transform: perspective(220px) rotateX(0deg) rotateY(0deg); }
	33% { transform: perspective(220px) rotateX(11deg) rotateY(-13deg); }
	66% { transform: perspective(220px) rotateX(-9deg) rotateY(12deg); }
}

/*
	КРУГОВОЕ ДВИЖЕНИЕ — кнопка ходит по маленькому кругу, НЕ ВРАЩАЯСЬ
	вокруг себя. Значок при этом остается читаемым, в отличие от поворота
*/
.stw[data-stw-idle="orbit"] .stw-btn {
	animation: stw-idle-orbit 5s linear infinite;
}

@keyframes stw-idle-orbit {
	0%, 100% { translate: 0 0; }
	25% { translate: 4px -4px; }
	50% { translate: 0 -7px; }
	75% { translate: -4px -4px; }
}

/*
	СЕРДЦЕБИЕНИЕ — ДВА УДАРА И ПАУЗА, а не ровная пульсация: ровная уже
	есть отдельным пунктом («Пульсация» рисует расходящееся кольцо).
	Пауза занимает больше половины цикла — без нее кнопка читается
	как дрожащая
*/
.stw[data-stw-idle="heartbeat"] .stw-btn {
	animation: stw-heartbeat 2.4s ease-in-out infinite;
}

@keyframes stw-heartbeat {
	0%, 40%, 100% { scale: 1; }
	8% { scale: 1.12; }
	16% { scale: 1; }
	24% { scale: 1.08; }
}

/* МЕРЦАНИЕ — меняется только прозрачность. Ничего не двигается вовсе,
   поэтому уместно там, где кнопка стоит рядом с текстом */
.stw[data-stw-idle="twinkle"] .stw-btn {
	animation: stw-twinkle 2.8s ease-in-out infinite;
}

@keyframes stw-twinkle {
	0%, 100% { opacity: 1; }
	50% { opacity: 0.62; }
}

/*
	==== ВРАЩЕНИЕ ЗАЛИВКИ — НА ПСЕВДОЭЛЕМЕНТЕ, А НЕ НА САМОМ СЛОЕ ====

	ГРАБЛИ, РАДИ КОТОРЫХ ЭТО СДЕЛАНО ИМЕННО ТАК. Слой заливки повторяет
	форму кнопки и обрезает СЕБЯ (`overflow: hidden` живет на нем).
	Крути его самого — у квадратной и вырезанной формы вылезли бы пустые
	углы, а увеличить его нельзя: у КНОПКИ обрезки нет (кольцу и искрам
	положено выходить наружу), и увеличенный слой торчал бы за краем.

	Псевдоэлемент же обрезается родителем, поэтому может быть заметно
	больше кнопки и вращаться свободно. `inset: -50%` дает запас, при
	котором углы прямоугольника не заходят внутрь ни при каком повороте
*/
.stw[data-stw-idle="spinbg"] .stw-btn__bg::before {
	content: '';
	position: absolute;
	inset: -50%;
	background-image: conic-gradient(from 0deg, var(--stw-btn-bg), var(--stw-btn-bg2), var(--stw-btn-bg));
	animation: stw-spin 7s linear infinite;
	pointer-events: none;
}

/*
	«БЕЗ ЗАЛИВКИ» СТАРШЕ ВРАЩЕНИЯ ЗАЛИВКИ. Псевдоэлемент рисует свой
	собственный градиент и правилом `background-image: none` у слоя
	не гасится — иначе владелец, убравший заливку под живой сферой,
	получил бы вращающийся круг обратно и не понял, откуда он взялся
*/
.stw[data-stw-fill="none"] .stw-btn__bg::before {
	display: none;
}

/*
	ПЕРЕБОР ОТТЕНКОВ. Фильтр висит на СЛОЕ ЗАЛИВКИ, а не на кнопке:
	на кнопке он перекрасил бы и значок, и подпись, а их цвет посчитан
	на сервере под контраст с фоном
*/
.stw[data-stw-idle="hue"] .stw-btn__bg {
	animation: stw-hue 9s linear infinite;
}

@keyframes stw-hue {
	0% { filter: hue-rotate(0deg); }
	100% { filter: hue-rotate(360deg); }
}

/* ==== НАВЕДЕНИЕ И НАЖАТИЕ ============================================== */
/*
	Идут через ОТДЕЛЬНЫЕ свойства `scale`/`rotate`/`translate`, а НЕ через
	`transform`: сводный transform спорит с центрирующим сдвигом позиции
	«по центру» и с анимациями покоя, которые тоже двигают кнопку
*/
.stw[data-stw-hover="grow"] .stw-btn:hover { scale: 1.08; }
.stw[data-stw-hover="tilt"] .stw-btn:hover { rotate: -6deg; }
.stw[data-stw-hover="lift"] .stw-btn:hover { translate: 0 -5px; }

.stw[data-stw-hover="glow"] .stw-btn:hover {
	box-shadow: var(--stw-btn-shadow),
		0 0 16px -2px var(--stw-btn-glow),
		0 0 46px -4px var(--stw-btn-glow);
}

/* Поворот значка, а не кнопки: подпись рядом с ним осталась бы читаемой
   только в этом случае */
.stw[data-stw-hover="spin"] .stw-btn:hover .stw-btn__icon { rotate: 360deg; }

.stw[data-stw-hover="shrink"] .stw-btn:hover { scale: 0.92; }

/*
	ПЕРЕВОРОТ ЗНАЧКА. Идет через `transform`, а не через отдельное
	свойство `rotate`: поворот вокруг вертикальной оси требует перспективы,
	а она задается только сводным transform. Конфликта с позицией
	«по центру» здесь нет — свойство висит на ЗНАЧКЕ, а сдвиг на кнопке
*/
.stw[data-stw-hover="flip"] .stw-btn:hover .stw-btn__icon {
	transform: perspective(220px) rotateY(180deg);
}

/* ОСВЕТЛЕНИЕ — фильтр на слое заливки: цвет значка посчитан под фон
   на сервере, и осветлять его вместе с фоном нельзя */
.stw[data-stw-hover="bright"] .stw-btn:hover .stw-btn__bg {
	filter: brightness(1.18) saturate(1.12);
}

.stw[data-stw-hover="wobble"] .stw-btn:hover {
	animation: stw-wobble 0.7s ease-in-out;
}

.stw[data-stw-hover="jelly"] .stw-btn:hover {
	animation: stw-jelly 0.6s ease-in-out;
}

/*
	ВСПЛЕСК КОЛЬЦА ПРИ НАВЕДЕНИИ.

	Занимает ВТОРОЙ слой эффектов (`::after`), а не первый: первый почти
	всегда отдан выбранному кольцу, и всплеск затер бы его.
	Наведение и кольцо — независимые настройки, ломать одну другой нельзя
*/
.stw[data-stw-hover="ringpop"] .stw-btn:hover .stw-btn__fx::after {
	display: block;
	inset: 0;
	background: none;
	mask: none;
	-webkit-mask: none;
	box-shadow: 0 0 0 2px var(--stw-btn-glow);
	animation: stw-ripple 0.7s ease-out;
}

.stw[data-stw-active="press"] .stw-btn:active { scale: 0.94; }

/* Утопить: кнопка уходит вниз и теряет тень — как вдавленная клавиша */
.stw[data-stw-active="sink"] .stw-btn:active {
	translate: 0 3px;
	scale: 0.97;
	box-shadow: none;
}

/* Тряска — отказ или «не сейчас». Короткая и с малой амплитудой:
   на большой она читается как поломка интерфейса */
.stw[data-stw-active="shake"] .stw-btn:active {
	animation: stw-shake 0.35s ease-in-out;
}

@keyframes stw-shake {
	0%, 100% { translate: 0 0; }
	20% { translate: -4px 0; }
	40% { translate: 4px 0; }
	60% { translate: -3px 0; }
	80% { translate: 2px 0; }
}

/* «Хлопок» — короткая отдача, поэтому кадрами, а не статикой: нажатие
   и отпускание должны отличаться, а `:active` описывает только удержание */
.stw[data-stw-active="pop"] .stw-btn:active {
	animation: stw-pop 0.32s ease-out;
}

@keyframes stw-pop {
	0% { scale: 1; }
	35% { scale: 0.9; }
	100% { scale: 1.06; }
}

/* ВСПЫШКА — короткий пересвет заливки. Кнопка при этом не двигается
   вовсе: отклик виден, а положение под пальцем не уезжает */
.stw[data-stw-active="flash"] .stw-btn:active .stw-btn__bg {
	animation: stw-flash 0.4s ease-out;
}

@keyframes stw-flash {
	0% { filter: brightness(1); }
	25% { filter: brightness(1.7); }
	100% { filter: brightness(1); }
}

/* СПЛЮЩИВАНИЕ — ширина и высота в противофазе, как у настоящего удара
   по упругому телу. От «желе» отличается тем, что происходит один раз */
.stw[data-stw-active="squash"] .stw-btn:active {
	animation: stw-squash 0.32s ease-out;
}

@keyframes stw-squash {
	0% { scale: 1 1; }
	40% { scale: 1.12 0.86; }
	100% { scale: 1 1; }
}

/*
	==== СОСТОЯНИЕ МЕНЯЕТ ПЕРЕМЕННЫЕ, А НЕ ОТДЕЛЬНЫЕ СВОЙСТВА ====
	(правка 2026-08-07)

	БЫЛО: `.stw-btn:hover .stw-btn__bg { background-color: var(--stw-btn-bg-hover) }`.
	И это была НАСТОЯЩАЯ ОШИБКА, а не стилистика: правило стоит НИЖЕ
	описаний заливок и красило слой БЕЗУСЛОВНО. Владелец выключал заливку
	(«Без заливки»), оставлял одну живую форму — и при наведении под ней
	все равно вспыхивал цветной кружок. Со стороны: «выключил, а оно есть».

	СТАЛО: состояние подменяет БАЗОВЫЕ переменные кнопки. Отсюда сразу три
	следствия, и все три нужны:

	  1) заливка «Без заливки» остается пустой в любом состоянии — красить
	     нечего, переменная никого не интересует;
	  2) ЖИВАЯ ФОРМА перекрашивается вместе с кнопкой: полотно читает
	     `--stw-btn-bg`/`--stw-btn-bg2` на каждом кадре;
	  3) кольцо, искры и свечение (они живут на `--stw-btn-glow`) идут
	     за состоянием сами, без единого дополнительного правила.

	Переменные объявляются на КНОПКЕ, а не на корне: `.stw` растянут
	на весь экран, и `:hover` у него значил бы «мышь где угодно на странице»
*/
.stw-btn:hover {
	--stw-btn-bg: var(--stw-btn-bg-hover);
	--stw-btn-bg2: var(--stw-btn-bg2-hover);
	--stw-btn-glow: var(--stw-btn-glow-hover);
	--stw-btn-fg: var(--stw-btn-fg-hover);
}

.stw-btn:active {
	--stw-btn-bg: var(--stw-btn-bg-active);
	--stw-btn-bg2: var(--stw-btn-bg2-active);
	--stw-btn-glow: var(--stw-btn-glow-active);
	--stw-btn-fg: var(--stw-btn-fg-active);
}

.stw-btn:focus-visible {
	outline: 3px solid var(--stw-accent);
	outline-offset: 3px;
}

/* Панель открыта — кнопка не нужна: она бы стояла поверх чата */
/*
	==== ПЛАВАЮЩАЯ КНОПКА ПРЯЧЕТСЯ ПРИ ОТКРЫТОЙ ПАНЕЛИ ====

	`:not(.stw-logo__btn)` — НЕСУЩЕЕ (2026-08-09). Логотип внутри панели
	собран из ТОЙ ЖЕ разметки `.stw-btn`, и без исключения он гас вместе
	с кнопкой: на пустом экране логотипа не было, а при закрытии панели
	он на мгновение проступал — ровно в тот момент, когда класс `stw--open`
	уже снят, а панель еще не уехала.

	ПРАВИЛО: любое правило, адресованное ПЛАВАЮЩЕЙ кнопке, обязано
	исключать логотип — он живет по другим законам
*/
.stw.stw--open .stw-btn:not(.stw-logo__btn) {
	opacity: 0;
	pointer-events: none;
}

/* ==== ЗАТЕМНЕНИЕ ПОД ПАНЕЛЬЮ =========================================== */
/*
	Нужно ради ДВУХ вещей сразу: отделить чат от страницы визуально
	и дать закрыть его кликом мимо. На узком экране оно же не дает
	случайно проматывать страницу под панелью
*/
.stw-scrim {
	position: absolute;
	inset: 0;
	background-color: rgba(10, 14, 20, 0.35);
	opacity: 0;
	pointer-events: none;
	transition: opacity 0.25s ease;
}

.stw.stw--open .stw-scrim {
	opacity: 1;
	pointer-events: auto;
}

/*
	ПЛОТНОСТЬ ЗАТЕМНЕНИЯ — ВЫБОР ВЛАДЕЛЬЦА. У карточки, которая нарочно
	не перекрывает страницу, честный вариант — `none`: затемнение под ней
	означало бы «страница выключена», а она как раз работает
*/
.stw[data-stw-scrim="none"] .stw-scrim { background-color: transparent; }
.stw[data-stw-scrim="soft"] .stw-scrim { background-color: rgba(10, 14, 20, 0.18); }
.stw[data-stw-scrim="dim"] .stw-scrim { background-color: rgba(10, 14, 20, 0.35); }
.stw[data-stw-scrim="dark"] .stw-scrim { background-color: rgba(6, 9, 14, 0.62); }

/* РАЗМЫТИЕ — САМЫЙ ДОРОГОЙ ИЗ ВАРИАНТОВ: браузер пересчитывает его
   на каждый кадр прокрутки страницы под панелью. Поэтому оно отдельным
   выбором, а не добавкой к каждому затемнению */
.stw[data-stw-scrim="blur"] .stw-scrim {
	background-color: rgba(10, 14, 20, 0.22);
	backdrop-filter: blur(8px);
	-webkit-backdrop-filter: blur(8px);
}

/* Затемнение не перехватывает клики, пока панель закрыта, — иначе
   `none` все равно накрыл бы страницу невидимой пленкой */
.stw[data-stw-scrim="none"].stw--open .stw-scrim {
	pointer-events: none;
}

/* ==== ПАНЕЛЬ ЧАТА ====================================================== */
/*
	==== ЧЕТЫРЕ ПОДАЧИ ОДНОЙ ПАНЕЛИ (2026-08-09) ====

	Общее у них ровно одно — колонка «шапка / экран / форма», и она описана
	здесь. Всё, что различается (где стоит, откуда выезжает, чем ограничена
	по высоте), задают правила ниже по атрибуту `data-stw-panel-mode`.

	ПОЧЕМУ ЭТО НЕ ЧЕТЫРЕ РАЗНЫХ КОМПОНЕНТА: содержимое у них одинаковое
	до последнего узла, и разведи мы их по классам — четыре копии правил
	ленты, формы и плиток разъехались бы на первой же правке
*/
.stw-panel {
	position: absolute;
	display: flex;
	flex-direction: column;
	background-color: var(--stw-panel-bg);
	border-radius: var(--stw-panel-radius);
	box-shadow: var(--stw-shadow);
	pointer-events: auto;
	visibility: hidden;
	opacity: 0;
	/*
		СКРУГЛЕНИЕ ТРЕБУЕТ ОБРЕЗКИ: шапка и форма ложатся в углы своими
		заливками и без `overflow: hidden` торчали бы квадратными.
		Прокрутку это не ломает — она живет на внутренней ленте
	*/
	overflow: hidden;
	transition: transform 0.3s ease, opacity 0.25s ease, visibility 0.3s ease;
}

/*
	==== ОТКРЫТОЕ СОСТОЯНИЕ РАЗВЕДЕНО НА ДВА ПРАВИЛА ====
	(правка 2026-08-09 — НЕ СЛИВАТЬ ОБРАТНО)

	ЗДЕСЬ ТОЛЬКО ВИДИМОСТЬ. Сдвиг снимается ОТДЕЛЬНЫМ правилом в самом конце
	раздела, и вот почему.

	ГРАБЛИ, КОТОРЫЕ ЭТО СТОИЛО: закрытое положение задают правила подачи
	вида `.stw[data-stw-panel-mode="drawer"][data-stw-side="right"] .stw-panel`
	— это ЧЕТЫРЕ простых селектора. А `.stw.stw--open .stw-panel` — ТРИ.
	Значит `transform: translateX(105%)` перебивал `transform: none`,
	и панель оставалась уехавшей за край экрана. Снаружи это выглядело как
	«кнопка нажимается, экран темнеет, а чата нет»: затемнение-то никаким
	`transform` не управляется.

	ПРАВИЛО НА БУДУЩЕЕ: любое правило, задающее закрытое положение подачи,
	обязано быть НЕ СПЕЦИФИЧНЕЕ пары `[data-stw-panel-mode][data-stw-side]`,
	иначе его придется отменять поименно
*/
.stw.stw--open .stw-panel {
	visibility: visible;
	opacity: 1;
}

/*
	==== ПОДАЧА 1: ШТОРКА СБОКУ (умолчание) ====

	В закрытом состоянии панель уведена ЗА свой край на 105%: ровно 100%
	оставляли бы на экране полоску тени
*/
.stw[data-stw-panel-mode="drawer"] .stw-panel {
	top: 0;
	bottom: 0;
	width: min(var(--stw-panel-width), 100%);
	/* У шторки скругление снаружи не видно — гасим его на внешней стороне,
	   иначе панель выглядит отклеившейся от края экрана */
	border-radius: 0;
}

.stw[data-stw-panel-mode="drawer"][data-stw-side="right"] .stw-panel {
	right: 0;
	transform: translateX(105%);
	border-left: 1px solid var(--stw-border);
	border-top-left-radius: var(--stw-panel-radius);
	border-bottom-left-radius: var(--stw-panel-radius);
}

.stw[data-stw-panel-mode="drawer"][data-stw-side="left"] .stw-panel {
	left: 0;
	transform: translateX(-105%);
	border-right: 1px solid var(--stw-border);
	border-top-right-radius: var(--stw-panel-radius);
	border-bottom-right-radius: var(--stw-panel-radius);
}

/*
	==== ПОДАЧА 2: КАРТОЧКА У КНОПКИ ====

	Стоит НАД кнопкой и с ее стороны: панель, всплывающая с другого края
	экрана, читается как чужое окно, а не как ответ на нажатие.

	ВЫСОТА ОГРАНИЧЕНА ДВАЖДЫ — заданной владельцем и остатком экрана
	(`max-height`): «высокая» карточка на ноутбуке иначе уезжала бы
	под кнопку
*/
.stw[data-stw-panel-mode="float"] .stw-panel {
	width: min(var(--stw-panel-width), calc(100vw - var(--stw-panel-gap) * 2));
	height: var(--stw-panel-height);
	max-height: calc(100vh - var(--stw-btn-size) - var(--stw-gap-y) - var(--stw-panel-gap) * 2);
	border: 1px solid var(--stw-border);
	bottom: calc(var(--stw-gap-y) + var(--stw-btn-size) + 14px);
	transform: translateY(12px) scale(0.98);
}

.stw[data-stw-panel-mode="float"][data-stw-side="right"] .stw-panel { right: var(--stw-gap-x); }
.stw[data-stw-panel-mode="float"][data-stw-side="left"] .stw-panel { left: var(--stw-gap-x); }

/* Кнопка сверху экрана — карточке место ПОД ней, а не за краем окна.
   Позиция кнопки известна тем же атрибутом, что и всегда */
.stw[data-stw-panel-mode="float"][data-stw-pos^="t"] .stw-panel {
	bottom: auto;
	top: calc(var(--stw-gap-y) + var(--stw-btn-size) + 14px);
	transform: translateY(-12px) scale(0.98);
}

.stw[data-stw-panel-mode="float"][data-stw-pos^="m"] .stw-panel {
	bottom: auto;
	top: 50%;
	transform: translateY(-50%) scale(0.98);
}

.stw[data-stw-panel-mode="float"][data-stw-pos^="m"].stw--open .stw-panel {
	transform: translateY(-50%);
}

/*
	==== ПОДАЧ БЫЛО ЧЕТЫРЕ, ОСТАЛОСЬ ДВЕ ====
	(2026-08-10)

	ЗДЕСЬ СТОЯЛИ «ЛИСТ СНИЗУ» И «ВО ВЕСЬ ЭКРАН». Правила удалены целиком,
	а не оставлены «на всякий случай»: мертвый CSS живет годами и при
	следующей правке геометрии его чинят наравне с рабочим.

	`sheet` не пережил вида `hero`: у листа высота — доля окна, а фигура
	приветствия растет вместе с ней, и на низком листе экран превращался
	в заливку с кнопкой.

	`full` заменен КНОПКОЙ «развернуть» в шапке — правило `.stw--wide`
	ниже делает ровно то же самое, но по решению ПОСЕТИТЕЛЯ и обратимо
*/

/*
	==== «РАЗВЕРНУТЬ» ПЕРЕБИВАЕТ ЛЮБУЮ ПОДАЧУ ====

	Это ВРЕМЕННОЕ действие посетителя, а не смена настройки владельца,
	поэтому правило одно и специфичностью выше всех четырех подач:
	класс на корне + атрибут
*/
.stw.stw--wide[data-stw-panel-mode] .stw-panel {
	inset: 0;
	width: 100%;
	height: 100%;
	max-height: 100%;
	border-radius: 0;
	transform: none;
}

/*
	==== РАЗВЕРНУТАЯ ПАНЕЛЬ ОГРАНИЧИВАЕТ СОДЕРЖИМОЕ ПО ШИРИНЕ ====
	(2026-08-10, по замечанию владельца)

	ГРАБЛИ, РАДИ КОТОРЫХ ЭТО НАПИСАНО. Все размеры внутри панели считаются
	ОТ ЕЕ ШИРИНЫ: фигура приветствия — 130% ширины (вид `hero`), фигура
	голосового экрана — 70%. В панели 480 px это 620 и 340 — ровно то, что
	задумано. Разверни панель на монитор 1920 — и та же формула дает
	фигуру в 2500 px: она занимала весь экран и лезла за все края разом.

	ЧИНИТЬ ФОРМУЛЫ ПОД ШИРОКИЙ СЛУЧАЙ БЫЛО БЫ НЕВЕРНО: дело не в них,
	а в том, что у РАЗВЕРНУТОЙ панели нет естественной меры ширины.
	Мера возвращается здесь — колонкой в центре, и все проценты внутри
	снова считаются от разумного числа. Ни одну формулу выше трогать
	не пришлось.

	ФОН ПАНЕЛИ ПРИ ЭТОМ ОСТАЕТСЯ ВО ВСЮ ШИРИНУ: ограничены содержимые
	узлы, а не сама панель, — иначе развернутый вид читался бы как окно
	поменьше на пустом месте.

	ДВА РАЗНЫХ ПРЕДЕЛА, И ЭТО НАРОЧНО: у приветствия и голосового экрана
	мера — ФИГУРА (она обязана остаться крупной, но не во весь монитор),
	у переписки — СТРОКА ТЕКСТА. Строка в 1900 px нечитаема: глаз
	не находит начало следующей
*/
.stw.stw--wide .stw-screen--welcome,
.stw.stw--wide .stw-screen--voice {
	width: 100%;
	max-width: 640px;
	margin-inline: auto;
}

.stw.stw--wide .stw-log,
.stw.stw--wide .stw-form {
	width: 100%;
	max-width: 900px;
	margin-inline: auto;
}

/* ==== АНИМАЦИЯ ПОЯВЛЕНИЯ ============================================== */
/*
	Владелец выбирает ХАРАКТЕР появления, а не переписывает позицию:
	закрытое состояние каждой подачи уже задано выше, и анимация лишь
	меняет то, ЧЕМ панель отличается от открытой
*/
/*
	`[data-stw-panel-mode]` В СЕЛЕКТОРЕ — НЕ УКРАШЕНИЕ, А ВЕС.

	Характер появления обязан перебить закрытое положение подачи
	(`.stw[…mode][…side] .stw-panel` — четыре простых селектора), поэтому
	и здесь их четыре. Без «пустого» атрибута подачи получилось бы три,
	и владелец, выбравший «Проявляется», все равно видел бы выезд сбоку
*/
.stw[data-stw-panel-anim="fade"][data-stw-panel-mode] .stw-panel { transform: none; }

.stw[data-stw-panel-anim="scale"][data-stw-panel-mode] .stw-panel {
	transform: scale(0.96);
	transform-origin: center;
}

.stw[data-stw-panel-anim="rise"][data-stw-panel-mode] .stw-panel { transform: translateY(24px); }

/* «Без анимации» — это мгновенно, а не «быстро»: посетитель, выбравший
   такую панель, не должен видеть даже короткого движения */
.stw[data-stw-panel-anim="none"][data-stw-panel-mode] .stw-panel {
	transform: none;
	transition: none;
}

/*
	==== СНЯТИЕ СДВИГА — ПОСЛЕДНИМ И С ТЕМ ЖЕ ВЕСОМ ====

	Стоит ПОСЛЕ всех правил закрытого положения (подачи и характера
	появления) и имеет ровно столько же простых селекторов, сколько они, —
	значит выигрывает по порядку, а не по весу. Так одно правило снимает
	сдвиг у любой подачи и любой анимации разом.

	ИСКЛЮЧЕНИЕ ОДНО: карточка у кнопки посреди экрана открывается
	не в «ноль», а в `translateY(-50%)` — она центрируется сдвигом.
	Ее правило специфичнее (пять селекторов) и потому выше этого
*/
.stw.stw--open[data-stw-panel-mode] .stw-panel {
	transform: none;
}

/* ==== СВОЙ ФОН ПАНЕЛИ ================================================== */
/*
	Слой отдельный, потому что на самой панели держатся цвет темы
	и скругление. Правила слоев те же, что у фона сайта и секции
	(steditorBackgroundCss): ::before — фон, ::after — затемнение видео
*/
.stw-panel__bg {
	position: absolute;
	inset: 0;
	z-index: 0;
	display: block;
	overflow: hidden;
	border-radius: inherit;
	pointer-events: none;
}

.stw-panel__bg.st-bg-on::before,
.stw-panel__bg.st-bg-on::after {
	content: '';
	position: absolute;
	inset: 0;
	pointer-events: none;
}

.stw-panel__bg.st-bg-on::before { z-index: 0; }
.stw-panel__bg.st-bg-on::after { z-index: 1; }

/*
	АНИМАЦИЯ ПЕРЕЛИВАЮЩЕГОСЯ ГРАДИЕНТА ОПИСАНА ЗДЕСЬ ОТДЕЛЬНО.

	Кадры (`stBgShift`) и все прочие правила фона приходят из stheme.css,
	но САМО ВКЛЮЧЕНИЕ анимации там написано под конкретных носителей —
	`.st-site` и `.st-section`. Панель ассистента не является ни тем,
	ни другим, и без этой строки ее градиент стоял бы неподвижно, хотя
	владелец анимацию включил.

	Кадры повторно НЕ объявляются: имя то же, файл темы на странице есть
	всегда — виджет живет внутри корня сайта
*/
.stw-panel__bg.st-bg-animate.st-bg-on::before {
	animation: stBgShift var(--st-bg-speed, 12s) ease infinite;
}

/* Содержимое обязано лежать НАД фоном: слой абсолютный и без этого
   накрыл бы шапку с лентой */
.stw-panel > *:not(.stw-panel__bg) {
	position: relative;
	z-index: 1;
}

/*
	ДЕКОРАТИВНАЯ ПОДСВЕТКА ТЕМЫ — мягкое пятно в верхнем углу панели.
	Есть не у всех тем: `--stw-shade` приходит только оттуда, где она
	задумана, и без нее правило не рисует ничего (цвет не определен)
*/
.stw-panel::before {
	content: '';
	position: absolute;
	top: -20%;
	right: -10%;
	width: 70%;
	height: 45%;
	z-index: 0;
	background-image: radial-gradient(closest-side, var(--stw-shade, transparent), transparent);
	opacity: 0.5;
	pointer-events: none;
}

.stw-panel__head {
	display: flex;
	align-items: center;
	gap: 10px;
	padding: 14px 16px;
	background-color: var(--stw-head-bg);
	border-bottom: 1px solid var(--stw-border);
}

/*
	ОФОРМЛЕНИЕ ШАПКИ. «Без плашки» и «полупрозрачная» существуют ради
	тем со своим фоном: плотная плашка резала бы такую панель пополам
*/
.stw[data-stw-head="clean"] .stw-panel__head {
	background-color: transparent;
	border-bottom-color: transparent;
}

.stw[data-stw-head="glass"] .stw-panel__head {
	background-color: color-mix(in srgb, var(--stw-panel-bg) 62%, transparent);
	backdrop-filter: blur(10px);
	-webkit-backdrop-filter: blur(10px);
}

.stw[data-stw-head="accent"] .stw-panel__head {
	background-color: var(--stw-accent);
	color: var(--stw-accent-text);
	border-bottom-color: transparent;
}

/* На акцентной шапке приглушенный текст и кнопки берут ЕЕ цвет, а не цвет
   панели: серый по фирменному фону не читается почти никогда */
.stw[data-stw-head="accent"] .stw-panel__sub,
.stw[data-stw-head="accent"] .stw-panel__act {
	color: var(--stw-accent-text);
	opacity: 0.82;
}

.stw[data-stw-head="accent"] .stw-panel__act:hover {
	background-color: rgba(255, 255, 255, 0.18);
	color: var(--stw-accent-text);
	opacity: 1;
}

.stw-panel__titles {
	flex: 1 1 auto;
	min-width: 0;
}

.stw-panel__title {
	font-size: 1rem;
	font-weight: 700;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

/* Подзаголовок — вторая строка, а не продолжение первой: «Онлайн-консультант»
   рядом с названием превратило бы шапку в кашу */
.stw-panel__sub {
	margin-top: 1px;
	color: var(--stw-muted);
	font-size: 0.76rem;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.stw .stw-panel__act {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 34px;
	height: 34px;
	padding: 0;
	border: 0;
	border-radius: var(--stw-radius-sm);
	background-color: transparent;
	color: var(--stw-muted);
	cursor: pointer;
	transition: background-color 0.15s ease, color 0.15s ease;
}

.stw-panel__act:hover {
	background-color: var(--stw-panel-bg);
	color: var(--stw-text);
}

.stw-panel__act svg {
	width: 18px;
	height: 18px;
	fill: none;
	stroke: currentColor;
	stroke-width: 1.8;
	stroke-linecap: round;
	stroke-linejoin: round;
}

/*
	==== У КНОПКИ «РАЗВЕРНУТЬ» ДВА ЗНАЧКА, ВИДЕН ВСЕГДА ОДИН ====
	(исправлено 2026-08-15)

	В разметке кнопки лежат ОБА значка — стрелки наружу («развернуть»)
	и стрелки внутрь («свернуть»), — а правила, которое прячет ненужный,
	не было вовсе: посетитель видел их наложенными друг на друга.

	ЗНАЧОК ПОКАЗЫВАЕТ ДЕЙСТВИЕ, А НЕ СОСТОЯНИЕ (то же правило, что
	у кнопки палитры на сайте): панель свернута — предлагаем развернуть,
	развернута — предлагаем свернуть
*/
.stw .stw-ico-shrink {
	display: none;
}

.stw.stw--wide .stw-ico-grow {
	display: none;
}

.stw.stw--wide .stw-ico-shrink {
	display: block;
}

/* ==== ЭКРАНЫ ПАНЕЛИ ==================================================== */
/*
	ЭКРАН ПОКАЗАН РОВНО ОДИН, И РЕШАЕТ ЭТО ОДИН АТРИБУТ на самой панели.
	`display: none` вместо прозрачности намеренно: скрытый экран не должен
	ни занимать место, ни ловить фокус табуляцией — иначе посетитель
	«проваливается» клавишей Tab в невидимую карточку слайдера
*/
.stw-screen {
	display: none;
	flex: 1 1 auto;
	min-height: 0;
	flex-direction: column;
}

.stw-panel[data-stw-screen="welcome"] .stw-screen--welcome,
.stw-panel[data-stw-screen="chat"] .stw-screen--chat,
.stw-panel[data-stw-screen="voice"] .stw-screen--voice {
	display: flex;
}

/* Форма ввода живет ТОЛЬКО на экране чата: на приветствии печатать
   некуда, на голосовом экране печатать нечем */
.stw-panel:not([data-stw-screen="chat"]) .stw-form {
	display: none;
}

/* ==== ЛОГОТИП АССИСТЕНТА (КНОПКА В УВЕЛИЧЕННОМ ВИДЕ) =================== */
/*
	==== НЕ УПРОЩАТЬ ДО КАРТИНКИ ====

	Внутри лежит РОВНО ТА ЖЕ разметка `.stw-btn`, и все оформление
	(форма, заливка, живая форма, кольцо, искры) достается ей от атрибутов
	корня виджета даром. Здесь снимается только то, чем логотип от кнопки
	ОТЛИЧАЕТСЯ
*/
.stw-logo {
	/* Размер приходит инлайном отдельной переменной (websiteAiLogoStyle),
	   а `--stw-btn-size` выводится ЗДЕСЬ: инлайн перебил бы медиазапрос
	   узкого экрана, и на телефоне логотип остался бы во весь экран */
	--stw-btn-size: var(--stw-logo-size, 128px);

	flex: 0 0 auto;
	width: var(--stw-btn-size);
	height: var(--stw-btn-size);
	/* Кликов не ждет: это знак, а не орган управления. Заодно снимает
	   :hover со всей цепочки правил кнопки одним движением */
	pointer-events: none;
}

/*
	`.stw-btn` ЗАКРЕПЛЕНА ЗА ОКНОМ И ЛОВИТ КЛИКИ — логотипу не нужно ни то,
	ни другое.

	ВНИМАНИЕ НА `pointer-events`: у самой кнопки стоит `auto`, и оно
	ПЕРЕБИВАЕТ `none` родителя (это свойство наследуется не как обычные,
	а именно так — потомок вправе снова включить себе события).
	Сними эту строку — и наведение на логотип заработало бы обратно
*/
.stw .stw-logo__btn {
	/*
		==== `relative`, А НЕ `static` — ЭТО НЕСУЩЕЕ ====
		(правка 2026-08-09, стоила «пропавшего логотипа»)

		У настоящей кнопки `position: absolute` — она закреплена в углу
		экрана. Логотипу закрепление не нужно, и напрашивается `static`.
		НО ВСЕ ЧЕТЫРЕ СЛУЖЕБНЫХ СЛОЯ (`__bg`, `__orb`, `__fx`, `__edge`)
		сами абсолютные с `inset: 0` и ищут ближайшего ПОЗИЦИОНИРОВАННОГО
		предка. При `static` они пролетали мимо логотипа и растягивались
		по всей панели: заливка, живая форма и свечение оказывались
		размером с окно чата, а на месте логотипа не было ничего.

		`relative` оставляет логотип в потоке И делает его точкой отсчета
	*/
	position: relative;
	display: block;
	width: 100%;
	height: 100%;
	min-width: 0;
	margin: 0;
	padding: 0;
	border: 0;
	pointer-events: none;
	cursor: default;
}

/*
	==== СНЯТИЕ КООРДИНАТ ПЛАВАЮЩЕЙ КНОПКИ. НЕ УДАЛЯТЬ ====
	(правка 2026-08-09 — «логотип съехал влево и вверх»)

	ПОБОЧНЫЙ ЭФФЕКТ ПЕРЕХОДА НА `position: relative`. Место кнопки на экране
	задают правила вида `.stw[data-stw-pos$="r"] .stw-btn { right: 24px }` —
	у них ТРИ простых селектора, и логотип они достают, а `.stw .stw-logo__btn`
	с двумя — нет.

	У АБСОЛЮТНОГО элемента `right` — это «прижать к правому краю»,
	а у ОТНОСИТЕЛЬНОГО — «сдвинуть ВЛЕВО на столько же». Логотип уезжал
	ровно на отступ кнопки от края экрана: влево на `--stw-gap-x`, вверх
	на `--stw-gap-y`. Совпадение чисел и было главной уликой.

	`transform: none` снимает центрирование положения «по центру экрана»
	(`translateY(-50%)`). Анимации покоя это НЕ ломает: кадры анимации
	приоритетнее обычных объявлений
*/
.stw[data-stw-pos] .stw-logo__btn {
	inset: auto;
	transform: none;
}

/* Значка и подписи у логотипа нет НИКОГДА, даже если у кнопки они есть:
   на экране панели подпись «Чат» под собственным логотипом — шум */
.stw-logo .stw-btn__icon,
.stw-logo .stw-btn__label {
	display: none !important;
}

/*
	РЕАКЦИИ СНЯТЫ, АНИМАЦИЯ ПОКОЯ ОСТАВЛЕНА. Наведение на логотип
	не значит ничего, а вот дыхание и перелив — ровно то, ради чего
	владелец эту форму и настраивал
*/
.stw-logo .stw-btn:hover,
.stw-logo .stw-btn:active {
	scale: 1;
	rotate: 0deg;
	translate: 0 0;
	filter: none;
}

/* Мелкий логотип в шапке: тень и свечение на 26 пикселях превращаются
   в грязное пятно вокруг значка */
.stw-logo--head {
	--stw-logo-size: 30px;
}

.stw-logo--head .stw-btn {
	box-shadow: none;
}

/* ==== ПУСТОЙ ЧАТ: ЛОГОТИП, ПРИВЕТСТВИЕ И ПЛИТКИ ======================== */

.stw-empty {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 14px;
	padding: 8px 0 4px;
	text-align: center;
}

/*
	ПРИВЕТСТВЕННАЯ ЧАСТЬ УХОДИТ, КАК ТОЛЬКО ПОЯВИЛАСЬ ПЕРВАЯ РЕПЛИКА.

	Класс ставит клиент на КОРЕНЬ, а не на ленту: тем же признаком
	пользуются и другие правила, а чинить их по одному классу дешевле
*/
.stw.stw--has-msg .stw-empty {
	display: none;
}

/*
	==== ЧЕРТЫ РАСКЛАДКИ ПРИХОДЯТ ОТ ТЕМЫ ====
	(2026-08-09)

	Разница между макетами тем — не в оттенках, а в том, КАК СОБРАН пустой
	экран: по центру или по левому краю, какой величины заголовок, где
	у плитки значок и есть ли уголковая стрелка. Каждая черта описана
	ЗДЕСЬ ОДИН РАЗ и не знает про остальные — поэтому владелец волен
	перебить любую по отдельности, не отказываясь от темы целиком
*/
.stw[data-stw-empty-align="left"] .stw-empty {
	align-items: flex-start;
	text-align: left;
}

.stw[data-stw-empty-align="right"] .stw-empty {
	align-items: flex-end;
	text-align: right;
}

/* Приветствие у края — не «подпись под заголовком», а вторая строка
   обращения: у нее шире мера и нет ограничения по центру */
.stw[data-stw-empty-align="left"] .stw-empty .stw-hello,
.stw[data-stw-empty-align="right"] .stw-empty .stw-hello {
	max-width: 100%;
}

/*
	ЛОГОТИП ВСЕГДА ПО ЦЕНТРУ, КАКИМ БЫ НИ БЫЛО ВЫРАВНИВАНИЕ ТЕКСТА.

	Это ЗНАК, а не строка текста: прижатый к краю, он читается как случайно
	уехавшая картинка — и именно так и выглядел. На всех макетах крупная
	фигура стоит по центру, а по краю выравнивается только ТЕКСТ.

	Правило написано БЕЗ привязки к выравниванию: так его не придется
	дописывать при появлении следующего варианта
*/
.stw-logo {
	align-self: center;
}

.stw-empty__title {
	font-size: 1.22rem;
	font-weight: 700;
	line-height: 1.3;
}

/* Размер заголовка — тоже черта темы: у строгих он равен реплике,
   у «разговорных» это крупное обращение на пол-экрана */
.stw[data-stw-title-size="lg"] .stw-empty__title { font-size: 1.5rem; }

.stw[data-stw-title-size="xl"] .stw-empty__title {
	font-size: 1.85rem;
	line-height: 1.2;
	letter-spacing: -0.02em;
}

/* Пустой чат — не лента, а страница: приветствие в нем выравнивается
   по центру и не носит вид «реплики от системы» */
.stw-empty .stw-hello {
	background-color: transparent;
	padding: 0;
	max-width: 34ch;
}

.stw-tiles {
	display: grid;
	gap: 8px;
	width: 100%;
	margin-top: 4px;
	text-align: left;
}

/* Сетка 2×2 — ровно то, что видно на всех референсах. На очень узкой
   панели вторая колонка превратила бы плитку в столбик из слогов,
   поэтому нижняя граница колонки задана в ch, а не в процентах */
.stw[data-stw-tiles="grid"] .stw-tiles {
	grid-template-columns: repeat(auto-fit, minmax(min(140px, 100%), 1fr));
}

.stw[data-stw-tiles="rows"] .stw-tiles {
	grid-template-columns: 1fr;
}

.stw[data-stw-tiles="chips"] .stw-tiles {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: 6px;
}

.stw .stw-tile {
	position: relative;
	display: flex;
	align-items: flex-start;
	gap: 10px;
	width: 100%;
	padding: 12px;
	border: 1px solid transparent;
	/* Скругление плиток задает ТЕМА (websiteAiStyle). Пусто — скругление
	   сайта, как было до появления тем */
	border-radius: var(--stw-tile-radius, var(--stw-radius-sm));
	background-color: var(--stw-tile-bg);
	color: var(--stw-tile-fg);
	font: inherit;
	font-size: 0.86rem;
	text-align: left;
	text-decoration: none;
	cursor: pointer;
	transition: transform 0.15s ease, border-color 0.15s ease, background-color 0.15s ease;
}

.stw-tile:hover {
	border-color: var(--stw-accent);
	transform: translateY(-1px);
}

.stw[data-stw-tiles="chips"] .stw-tile {
	width: auto;
	padding: 7px 12px;
	border-radius: 999px;
	align-items: center;
}

/* В ярлыке пояснению места нет физически — оно превратило бы строку
   в абзац. Это не потеря: владелец видит вид плиток при настройке */
.stw[data-stw-tiles="chips"] .stw-tile__desc {
	display: none;
}

/* ==== ВИДЫ ПЛИТОК ===================================================== */

.stw[data-stw-tiles-style="card"] .stw-tile {
	border-color: var(--stw-tile-border);
	box-shadow: 0 1px 2px rgba(15, 20, 30, 0.05);
}

.stw[data-stw-tiles-style="outline"] .stw-tile {
	background-color: transparent;
	border-color: var(--stw-tile-border);
}

/* «Мягкая заливка» — акцент, разбавленный поверхностью. Разложить цвет
   на каналы в CSS больше нечем: он приходит переменной */
.stw[data-stw-tiles-style="soft"] .stw-tile {
	background-color: color-mix(in srgb, var(--stw-accent) 12%, var(--stw-panel-bg));
	border-color: transparent;
}

.stw[data-stw-tiles-style="glass"] .stw-tile {
	background-color: color-mix(in srgb, var(--stw-tile-bg) 55%, transparent);
	border-color: color-mix(in srgb, var(--stw-text) 10%, transparent);
	backdrop-filter: blur(8px);
	-webkit-backdrop-filter: blur(8px);
}

.stw[data-stw-tiles-style="accent"] .stw-tile {
	background-color: var(--stw-accent);
	color: var(--stw-accent-text);
	border-color: transparent;
}

.stw[data-stw-tiles-style="accent"] .stw-tile__desc {
	opacity: 0.85;
}

.stw-tile__icon {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	flex: 0 0 auto;
	width: 28px;
	height: 28px;
	border-radius: 8px;
	background-color: color-mix(in srgb, var(--stw-accent) 14%, transparent);
	color: var(--stw-accent);
	font-size: 15px;
}

/* На акцентной плитке подложка значка невидима, а сам он обязан быть
   цвета текста: акцент по акценту не читается */
.stw[data-stw-tiles-style="accent"] .stw-tile__icon {
	background-color: rgba(255, 255, 255, 0.2);
	color: inherit;
}

.stw[data-stw-tiles="chips"] .stw-tile__icon {
	width: 18px;
	height: 18px;
	border-radius: 6px;
	background-color: transparent;
	font-size: 14px;
}

/*
	==== ЗНАЧОК СВЕРХУ — ВТОРАЯ СБОРКА ПЛИТКИ ====

	Строкой (значок слева) плитка читается как пункт списка, карточкой
	(значок сверху) — как самостоятельное действие. На макетах встречаются
	обе, и выбор делает тема
*/
.stw[data-stw-tile-icon="top"] .stw-tile {
	flex-direction: column;
	align-items: stretch;
	gap: 12px;
	padding: 14px;
}

.stw[data-stw-tile-icon="top"] .stw-tile__icon {
	width: 34px;
	height: 34px;
	border-radius: 10px;
	font-size: 17px;
}

/* В ярлыке значок остается слева при любой теме: ярлык — это строка,
   и колонка превратила бы его в квадрат */
.stw[data-stw-tiles="chips"][data-stw-tile-icon="top"] .stw-tile {
	flex-direction: row;
	align-items: center;
	gap: 8px;
	padding: 7px 12px;
}

/*
	УГОЛКОВАЯ СТРЕЛКА. Абсолютом в углу, а не в потоке: иначе она тянула бы
	на себя ширину заголовка, и длинная подпись переносилась бы раньше
	времени. Приглушена намеренно — это подсказка «плитка ведет дальше»,
	а не второй акцент рядом со значком
*/
.stw-tile__arrow {
	position: absolute;
	top: 12px;
	right: 12px;
	display: inline-flex;
	color: var(--stw-muted);
	opacity: 0.65;
	transition: opacity 0.15s ease, translate 0.15s ease;
}

.stw-tile__arrow svg {
	width: 14px;
	height: 14px;
	fill: none;
	stroke: currentColor;
	stroke-width: 2;
	stroke-linecap: round;
	stroke-linejoin: round;
}

.stw-tile:hover .stw-tile__arrow {
	opacity: 1;
	translate: 1px -1px;
}

/* Заголовку нельзя заезжать под стрелку — оставляем ей место справа.
   Общий соседний селектор ловит текст и через значок, и без него:
   стрелка в разметке всегда идет первой */
.stw-tile__arrow ~ .stw-tile__text .stw-tile__title {
	padding-right: 18px;
}

.stw-tile__text {
	display: block;
	min-width: 0;
}

.stw-tile__title {
	display: block;
	font-weight: 600;
	line-height: 1.25;
}

.stw-tile__desc {
	display: block;
	margin-top: 2px;
	color: var(--stw-muted);
	font-size: 0.76rem;
	line-height: 1.3;
}

/* ==== ЛЕНТА СООБЩЕНИЙ ================================================== */

.stw-log {
	flex: 1 1 auto;
	min-height: 0;
	overflow-y: auto;
	overscroll-behavior: contain;
	padding: 16px;
	display: flex;
	flex-direction: column;
	gap: 12px;
	font-size: 0.94rem;
}

/*
	ПУСТОЙ ЧАТ ЦЕНТРИРУЕТСЯ ПО ВЫСОТЕ, ПЕРЕПИСКА — НЕТ.

	Логотип с приветствием, прижатые к верхнему краю пустой панели,
	выглядят обрезком страницы. А в переписке центрирование, наоборот,
	увело бы первые реплики в середину экрана
*/
.stw:not(.stw--has-msg) .stw-log {
	justify-content: center;
}

.stw-hello {
	padding: 12px 14px;
	border-radius: var(--stw-radius-sm);
	background-color: var(--stw-head-bg);
	color: var(--stw-muted);
	font-size: 0.88rem;
}

/*
	==== РЕПЛИКА: КОРОБКА ИЗ АВАТАРА И ПУЗЫРЯ ====

	Аватар лежит СНАРУЖИ пузыря, а не внутри: внутри он поехал бы вместе
	с текстом при длинном ответе, а его место — у первой строки
*/
.stw-msg {
	display: flex;
	align-items: flex-end;
	gap: 8px;
	max-width: var(--stw-msg-width);
}

.stw-msg--user {
	align-self: flex-end;
	flex-direction: row-reverse;
}

.stw-msg--bot {
	align-self: flex-start;
}

/*
	КОЛОНКА РЕПЛИКИ: пузырь, под ним время и «копировать».

	Нужна именно колонка, а не поля внутри пузыря: время внутри попало бы
	под `white-space: pre-wrap` последней строки ответа и прилипло бы
	к тексту, а кнопка копирования — в область выделения текста
*/
.stw-msg__col {
	display: flex;
	flex-direction: column;
	min-width: 0;
}

.stw-msg--user .stw-msg__col {
	align-items: flex-end;
}

.stw-msg__body {
	min-width: 0;
	padding: 10px 14px;
	border-radius: var(--stw-radius-sm);
	/* Ответ модели приходит обычным текстом: переносы строк в нем значимы,
	   а вот разметку мы не рисуем намеренно — вставлять чужой HTML на сайт
	   владельца ассистент не вправе */
	white-space: pre-wrap;
	word-break: break-word;
}

.stw-msg--user .stw-msg__body {
	background-color: var(--stw-user-bg);
	color: var(--stw-user-fg);
}

.stw-msg--bot .stw-msg__body {
	background-color: var(--stw-bot-bg);
	color: var(--stw-bot-fg);
}

/*
	==== ВИДЫ СООБЩЕНИЙ ====

	Различаются РОВНО ОДНИМ: чем отделена реплика от фона. Пузырь —
	заливкой, «без заливки» — только выравниванием, карточка — контуром
	и тенью, линия — вертикальной чертой слева
*/
.stw[data-stw-msg="flat"] .stw-msg__body {
	background-color: transparent;
	padding: 2px 0;
}

.stw[data-stw-msg="flat"] .stw-msg--user .stw-msg__body {
	color: var(--stw-text);
	text-align: right;
}

.stw[data-stw-msg="card"] .stw-msg__body {
	border: 1px solid var(--stw-border);
	box-shadow: 0 1px 3px rgba(15, 20, 30, 0.06);
}

.stw[data-stw-msg="line"] .stw-msg__body {
	background-color: transparent;
	border-radius: 0;
	padding: 2px 0 2px 12px;
	border-left: 2px solid var(--stw-border);
}

.stw[data-stw-msg="line"] .stw-msg--user .stw-msg__body {
	border-left-color: var(--stw-accent);
	color: var(--stw-text);
}

/*
	ХВОСТИК ПУЗЫРЯ — СКРУГЛЕНИЕМ, А НЕ ТРЕУГОЛЬНИКОМ.

	Псевдоэлемент-треугольник пришлось бы красить тем же цветом, что
	и пузырь, и он ломался бы на каждой смене темы. Срезанный угол дает
	тот же смысл «сказал он / сказал я» и не зависит ни от чего
*/
.stw[data-stw-tail] .stw-msg--bot .stw-msg__body { border-bottom-left-radius: 4px; }
.stw[data-stw-tail] .stw-msg--user .stw-msg__body { border-bottom-right-radius: 4px; }

/* Ошибка — не реплика: у нее нет ни автора, ни аватара, и растянута она
   во всю ширину намеренно, чтобы ее нельзя было принять за ответ */
.stw-msg--fail {
	align-self: stretch;
	max-width: 100%;
}

/* Колонку тоже растягиваем: без нее рамка ошибки съеживается по тексту
   и перестает отличаться от реплики, чего мы как раз и добивались */
.stw-msg--fail .stw-msg__col {
	width: 100%;
}

.stw-msg--fail .stw-msg__body {
	width: 100%;
	background-color: transparent;
	border: 1px dashed var(--st-danger, #D64550);
	color: var(--st-danger, #D64550);
	font-size: 0.85rem;
}

/* ==== АВАТАР ========================================================== */

.stw-msg__avatar {
	flex: 0 0 auto;
	width: 28px;
	height: 28px;
	margin-bottom: 2px;
	border-radius: 999px;
	overflow: hidden;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	background-color: var(--stw-btn-bg);
	color: var(--stw-btn-fg);
	font-size: 15px;
}

.stw-msg__avatar img {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/* Логотип-аватар — та же кнопка, ужатая до 28 пикселей. Свечение и тень
   на этом размере превращаются в грязь вокруг кружка */
.stw-msg__avatar .stw-logo {
	--stw-logo-size: 28px;
}

.stw-msg__avatar .stw-btn {
	box-shadow: none;
}

/* Время реплики. Отдельной строкой под пузырем, а не внутри: внутри оно
   ломало бы `white-space: pre-wrap` последней строки ответа */
.stw-msg__time {
	margin-top: 3px;
	color: var(--stw-muted);
	font-size: 0.68rem;
}

.stw-msg--user .stw-msg__time {
	text-align: right;
}

/*
	КНОПКА «КОПИРОВАТЬ» ПОЯВЛЯЕТСЯ ПРИ НАВЕДЕНИИ, а на сенсорном экране —
	всегда: наведения там нет вовсе, и спрятанная кнопка была бы
	недоступна в принципе
*/
.stw .stw-msg__copy {
	margin-top: 4px;
	padding: 0;
	border: 0;
	background: transparent;
	color: var(--stw-muted);
	font: inherit;
	font-size: 0.7rem;
	cursor: pointer;
	opacity: 0;
	transition: opacity 0.15s ease;
}

.stw-msg:hover .stw-msg__copy,
.stw-msg__copy:focus-visible {
	opacity: 1;
}

@media (hover: none) {
	.stw-msg__copy { opacity: 1; }
}

/* Список вложений внутри реплики посетителя */
.stw-msg__files {
	margin-top: 6px;
	font-size: 0.78rem;
	opacity: 0.85;
}

/* ИНДИКАТОР ОЖИДАНИЯ. Обязателен именно потому, что ответ идет секундами:
   без него пауза читается как «кнопка не сработала» */
.stw-typing {
	align-self: flex-start;
	display: inline-flex;
	align-items: center;
	gap: 5px;
	padding: 12px 14px;
	border-radius: var(--stw-radius-sm);
	/* ФОН ТОТ ЖЕ, ЧТО У ОТВЕТА (правка 2026-08-09): точки — это будущая
	   реплика ассистента, и на своем цвете они читались бы как чужой
	   элемент, вклинившийся в переписку */
	background-color: var(--stw-bot-bg);
}

.stw-typing span {
	width: 7px;
	height: 7px;
	border-radius: 999px;
	background-color: var(--stw-muted);
	animation: stw-dot 1.2s ease-in-out infinite;
}

.stw-typing span:nth-child(2) { animation-delay: 0.15s; }
.stw-typing span:nth-child(3) { animation-delay: 0.3s; }

@keyframes stw-dot {
	0%, 60%, 100% { opacity: 0.35; translate: 0 0; }
	30% { opacity: 1; translate: 0 -4px; }
}

/* ==== ПРИВЕТСТВЕННЫЙ ЭКРАН ============================================ */

.stw-welcome {
	flex: 1 1 auto;
	min-height: 0;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 16px;
	padding: 24px 20px;
	overflow-y: auto;
	text-align: center;
}

.stw-welcome__title {
	font-size: 1.42rem;
	font-weight: 700;
	line-height: 1.25;
}

.stw-welcome__text {
	max-width: 36ch;
	color: var(--stw-muted);
	font-size: 0.92rem;
}

/*
	ПОДВАЛ ПРИВЕТСТВИЯ ПРИБИТ К НИЗУ ПАНЕЛИ, а не идет за текстом.

	Кнопка «Начать» — единственный выход с этого экрана, и искать ее
	прокруткой посетитель не должен ни при какой длине инструкции
*/
.stw-welcome__foot {
	flex: 0 0 auto;
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 8px;
	padding: 14px 16px 18px;
}

/* ==== ВИД «КРУПНЫЙ ЛОГОТИП»: ФИГУРА РАБОТАЕТ ФОНОМ ЭКРАНА ============== */
/*
	(2026-08-10)

	ЧЕМ ОН ОТЛИЧАЕТСЯ ОТ СТОПКИ ПО ЦЕНТРУ. Логотип перестает быть пунктом
	списка «фигура — заголовок — пояснение» и становится ФОНОМ: он во всю
	ширину панели, смещен влево и вверх и частью уходит за край, а весь
	текст съезжает вниз, к самой кнопке входа.

	ПОЧЕМУ ОБРЕЗАННАЯ ФИГУРА ЛУЧШЕ ВПИСАННОЙ. Аккуратно уместившийся
	по центру кружок читается как картинка НА экране. Та же фигура,
	уходящая за край, читается как продолжение ЗА пределами окна —
	панель получает глубину, которой у нее иначе нет. Так собраны заглавные
	экраны почти всех голосовых помощников, и это не мода, а следствие:
	у панели ширина телефона, и середину у нее занимать нечем
*/
.stw-screen--hero {
	/* Точка отсчета для фигуры И обрезка того, что вышло за край:
	   без `overflow` смещенный влево логотип вылез бы на страницу сайта */
	position: relative;
	overflow: hidden;
}

/*
	==== РАЗМЕР ФИГУРЫ РАСТЕТ ВМЕСТЕ С ВЫСОТОЙ ПАНЕЛИ ====
	(правка 2026-08-10, по первому же снимку экрана)

	ГРАБЛИ, РАДИ КОТОРЫХ ЭТО СДЕЛАНО. Размер фигуры считался ТОЛЬКО
	от ШИРИНЫ панели, а пустота образуется по ВЫСОТЕ. На телефоне эти две
	величины связаны (экран всегда примерно 2:1), а на ПК панель бывает
	любой высоты при той же ширине — и на высокой панели фигура занимала
	37% высоты вместо половины, оставляя посреди экрана дыру в треть окна.

	ПОЧЕМУ ОТ ОКНА (`vh`), А НЕ ОТ САМОЙ ПАНЕЛИ. Высоту родителя в CSS
	не спросить: `height: 100%` у экрана — это доля панели, а множителя
	к ней нет. Запросы к контейнеру (`cqh`) требуют `container-type: size`,
	а он ЛОМАЕТ вариант панели «по содержимому»: у контейнера с изоляцией
	размера содержимое перестает влиять на высоту, и панель схлопнулась бы
	в ноль. Скрипт ради раскладки заводить тем более незачем.

	Поэтому доля окна берется по КЛЮЧУ ВЫСОТЫ с корня виджета — он ее
	и задает: 100% окна, 78vh, 62vh. Множитель 0.83 подобран так, чтобы
	фигура растворялась примерно на половине высоты панели (растворение
	идет с 58% ее коробки, полностью гаснет к 88% — см. маску ниже).

	Потолок 200% обязателен: в узком и очень высоком окне доля высоты
	вырастает до трех ширин панели, и от фигуры остался бы кусок дуги
*/
.stw[data-stw-panel-height="full"] { --stw-hero-w: clamp(130%, 83vh, 200%); }
.stw[data-stw-panel-height="tall"] { --stw-hero-w: clamp(130%, 65vh, 200%); }
.stw[data-stw-panel-height="mid"] 	{ --stw-hero-w: clamp(130%, 51vh, 200%); }
/*
	«По содержимому» правила не получает НАМЕРЕННО: у такой панели высота
	равна высоте содержимого, пустоте взяться неоткуда, и фигура остается
	на запасном размере от ширины (`var(--stw-hero-w, 130%)`)
*/

/*
	У КАРТОЧКИ У КНОПКИ ОКНО НЕ ВСЕ. Она стоит НАД кнопкой, и ее высота
	ограничена вторым потолком (`max-height` в подаче «карточка»):
	окно минус кнопка, минус ее отступ, минус двойной отступ карточки.
	Выражение повторяет тот потолок ЗНАК В ЗНАК — разойдись они, фигура
	считалась бы от высоты, которой у панели нет
*/
.stw[data-stw-panel-mode="float"][data-stw-panel-height="full"] {
	--stw-hero-w: clamp(130%, calc((100vh - var(--stw-btn-size) - var(--stw-gap-y) - var(--stw-panel-gap) * 2) * 0.83), 200%);
}

.stw-screen--hero .stw-logo--hero {
	/*
		РАЗМЕР — ДОЛЯ ШИРИНЫ ПАНЕЛИ, А НЕ ПИКСЕЛИ. Настройка «размер
		логотипа» здесь не участвует вовсе: фигура обязана быть шире панели
		при любой ее ширине, а фиксированные 128 px на широкой панели
		дали бы обратно «картинку по центру».

		`--stw-btn-size: 100%` выведен ЗДЕСЬ РАДИ СКРУГЛЕНИЯ: форма
		«скругленный квадрат» считает радиус как `--stw-btn-size / 3`,
		и оставь мы там инлайновые 128 px — у фигуры во весь экран был бы
		радиус от кнопки. У квадратной коробки 100%/3 дает ровно треть
		стороны, то есть то же самое число, что и раньше
	*/
	--stw-btn-size: 100%;

	position: absolute;
	top: 0;
	left: 0;
	/* Под текстом: фон не спорит с заголовком за внимание */
	z-index: 0;
	width: var(--stw-hero-w, 130%);
	/* Высота от ширины, а не от `--stw-btn-size`: процент высоты считался
	   бы от ВЫСОТЫ экрана, и на длинной панели круг стал бы овалом */
	height: auto;
	aspect-ratio: 1 / 1;
	/*
		==== СДВИГ ДОЛЯМИ СОБСТВЕННОГО РАЗМЕРА, А НЕ ОТСТУПАМИ ====

		У `translate` проценты считаются от коробки САМОГО элемента —
		значит смещение всегда пропорционально фигуре, при любой ширине
		панели. Проценты у `left`/`top` считались бы от разных величин
		(ширины и ВЫСОТЫ родителя), и вертикальный сдвиг гулял бы
		вслед за высотой панели.

		Числа подобраны от НАИМЕНЬШЕГО размера фигуры: 130% ширины минус
		23% от них же — это 130 − 29.9 ≈ 100%, то есть правый край приходится
		ровно на правый край панели, а срез идет слева. Когда фигура растет
		вслед за высотой панели, она начинает уходить за край и справа —
		так и надо: чем крупнее фигура, тем больше она читается как
		продолжение за пределами окна
	*/
	translate: var(--stw-hero-x, -23%) var(--stw-hero-y, -28%);
	/*
		НИЗ ФИГУРЫ РАСТВОРЯЕТСЯ, А НЕ ОБРЫВАЕТСЯ. Иначе на короткой панели
		кромка фигуры прошла бы ровно по заголовку, и текст читался бы
		поверх яркой заливки. Растворение решает это без единого условия
		на высоту
	*/
	-webkit-mask-image: linear-gradient(to bottom, #000 58%, transparent 88%);
	mask-image: linear-gradient(to bottom, #000 58%, transparent 88%);
}

/*
	ТЕКСТ И КНОПКА — НАД ФИГУРОЙ. `position` обязателен: без него `z-index`
	у потомка потока не значит ничего, и заголовок ушел бы под заливку
*/
.stw-screen--hero .stw-welcome,
.stw-screen--hero .stw-welcome__foot {
	position: relative;
	z-index: 1;
}

/*
	==== ТЕКСТ ВСТАЕТ В СВОБОДНОЕ МЕСТО ПОД ФИГУРОЙ ====
	(правка 2026-08-10)

	СНАЧАЛА ОН БЫЛ ПРИЖАТ К САМОМУ НИЗУ — и на высокой панели между фигурой
	и обращением зияла дыра в треть экрана. Прижатие к краю вообще плохой
	способ разложить три вещи по высоте: оно собирает весь запас высоты
	в ОДНО место, и это место всегда посередине, то есть на самом виду.

	ЧТО ДЕЛАЕТСЯ ВМЕСТО ЭТОГО. Верхний отступ равен высоте фигуры — текст
	физически не может на нее налезть, — а дальше работает ОБЫЧНОЕ
	центрирование стопки (`justify-content: center` у `.stw-welcome`):
	запас высоты делится поровну над текстом и под ним. Так текст стоит
	примерно на трех четвертях высоты — ровно там, где он стоит на макетах
	голосовых помощников.

	МНОЖИТЕЛЬ 0.6, А НЕ 0.72. Коробка фигуры выше того, что видно:
	маска гасит ее полностью к 88% высоты, а сама коробка поднята на 28% —
	значит след фигуры кончается на 0.88 − 0.28 = 0.6 ее размера.
	Считать по коробке (0.72) означало бы отступ по пустому месту.

	ПРОЦЕНТ ОТСТУПА СЧИТАЕТСЯ ОТ ШИРИНЫ, И ЭТО НУЖНОЕ СВОЙСТВО: у любого
	`padding` проценты берутся от ШИРИНЫ родителя, даже у вертикального.
	Та же база, что у ширины фигуры, — значит отступ следует за ней
	точно, без второго набора чисел
*/
.stw-screen--hero .stw-welcome {
	gap: 10px;
	padding: calc(var(--stw-hero-w, 130%) * 0.6 + 12px) 20px 2px;
	/*
		`safe` НА СЛУЧАЙ, КОГДА МЕСТА НЕ ХВАТИЛО. У центрированной
		прокручиваемой коробки верхняя часть содержимого становится
		НЕДОСТУПНОЙ: браузер обрезает переполнение со стороны начала оси.
		Ключевое слово `safe` отменяет центрирование ровно в этом случае
		и прижимает содержимое к началу — прокрутка работает.
		Старые браузеры значение не поймут и просто оставят прежнее
		центрирование из `.stw-welcome`: терять нечего
	*/
	justify-content: safe center;
}

/*
	НА НИЗКОЙ ПАНЕЛИ ФИГУРА УМЕНЬШАЕТСЯ. Карточка у кнопки бывает высотой
	в половину экрана: фигура в 130% ширины съела бы его целиком,
	и приветствие превратилось бы в заливку с кнопкой.

	ПЕРЕМЕННАЯ ВЫВОДИТСЯ НА САМОМ ЭКРАНЕ, А НЕ НА ФИГУРЕ: ее читает
	и отступ текста выше, а он живет на соседнем узле. Объяви ее у фигуры —
	текст остался бы с прежним отступом и оторвался от нее
*/
@media (max-height: 620px) {
	.stw-screen--hero {
		--stw-hero-w: 104%;
		--stw-hero-y: -30%;
	}
}

.stw .stw-btn-main {
	width: 100%;
	padding: 12px 18px;
	border: 0;
	border-radius: 999px;
	background-color: var(--stw-accent);
	color: var(--stw-accent-text);
	font: inherit;
	font-size: 0.95rem;
	font-weight: 600;
	cursor: pointer;
	transition: filter 0.15s ease, transform 0.15s ease;
}

.stw-btn-main:hover {
	filter: brightness(1.06);
	transform: translateY(-1px);
}

.stw .stw-link {
	border: 0;
	padding: 4px 8px;
	background: transparent;
	color: var(--stw-muted);
	font: inherit;
	font-size: 0.82rem;
	cursor: pointer;
	text-decoration: underline;
	text-underline-offset: 3px;
}

/* ==== СЛАЙДЕР-ИНСТРУКЦИЯ ============================================== */
/*
	КАРТОЧКИ ПЕРЕКЛЮЧАЮТСЯ ПОДМЕНОЙ `hidden`, А НЕ ЛЕНТОЙ СО СДВИГОМ.

	Лента шириной в пять экранов означала бы, что четыре скрытых видео
	грузятся и играют вместе с показанным. На телефоне посетителя это
	разница между открывшейся панелью и заглохшей вкладкой
*/
.stw-slider {
	flex: 1 1 auto;
	min-height: 0;
	display: flex;
	flex-direction: column;
	overflow: hidden;
}

.stw-slider__track {
	flex: 1 1 auto;
	min-height: 0;
	overflow-y: auto;
}

.stw-slide {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 12px;
	padding: 20px 20px 8px;
	text-align: center;
	animation: stw-slide-in 0.28s ease;
}

/*
	`hidden` ОБЯЗАН ПЕРЕБИВАТЬ `display: flex` — ЯВНЫМ ПРАВИЛОМ.

	Атрибут `hidden` — всего лишь `display: none` из таблицы БРАУЗЕРА,
	и любое наше объявление display его молча отменяет. Без этой строки
	все пять карточек показались бы разом, столбиком. Ровно те же грабли,
	что у `.stw-boot` в начале файла
*/
.stw-slide[hidden],
.stw-kb[hidden] {
	display: none !important;
}

@keyframes stw-slide-in {
	from { opacity: 0; translate: 12px 0; }
	to { opacity: 1; translate: 0 0; }
}

/*
	СООТНОШЕНИЕ СТОРОН ЗАДАНО ЖЕСТКО, И ЭТО НЕ ПРИДИРКА К КРАСОТЕ:
	без него карточка прыгает по высоте на каждом переключении — картинки
	владельца бывают любых пропорций
*/
.stw-slide__media {
	width: 100%;
	aspect-ratio: 16 / 10;
	border-radius: var(--stw-radius);
	overflow: hidden;
	background-color: var(--stw-head-bg);
}

.stw-slide__media img,
.stw-slide__media video {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
}

.stw-slide__title {
	font-size: 1.12rem;
	font-weight: 700;
	line-height: 1.3;
}

.stw-slide__text {
	max-width: 38ch;
	color: var(--stw-muted);
	font-size: 0.88rem;
}

.stw-slider__dots {
	flex: 0 0 auto;
	display: flex;
	justify-content: center;
	gap: 6px;
	padding: 10px 0 2px;
}

.stw .stw-dot {
	width: 7px;
	height: 7px;
	padding: 0;
	border: 0;
	border-radius: 999px;
	background-color: var(--stw-border);
	cursor: pointer;
	transition: width 0.2s ease, background-color 0.2s ease;
}

/* Активная точка ВЫТЯГИВАЕТСЯ, а не просто темнеет: разницу в цвете
   на семи пикселях видно не на всяком экране, разницу в длине — на любом */
.stw .stw-dot--on {
	width: 18px;
	background-color: var(--stw-accent);
}

/* ==== ГОЛОСОВОЙ ЭКРАН ================================================= */

.stw-voice {
	flex: 1 1 auto;
	min-height: 0;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 14px;
	padding: 24px 20px;
	text-align: center;
}

/*
	==== ФИГУРА МЕРЯЕТСЯ ЭКРАНОМ, А НЕ ПИКСЕЛЯМИ ====
	(правка 2026-08-10)

	ГРАБЛИ, РАДИ КОТОРЫХ ПЕРЕДЕЛАНО. Размер приходил из общего справочника
	логотипов, где «очень крупный» — это 168 px. Рядом с текстом (шапка,
	пустой чат) такой размер верен, а на голосовом экране фигура —
	ЕДИНСТВЕННОЕ, что есть, и 168 px в панели шириной 510 читались как
	мелкий значок посреди пустого листа.

	Теперь размер приезжает готовым выражением `--stw-voice-stage`
	(websiteAiStyle): доля ширины панели с потолком по высоте окна.

	`width: 100%` У ПОДМОСТКОВ ОБЯЗАТЕЛЕН. Доля считается от родителя,
	а родитель у фигуры — этот узел; оставь его шириной по содержимому,
	и получилась бы ссылка размера на самого себя
*/
.stw-voice__stage {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 100%;
}

/*
	СПЕЦИФИЧНОСТЬ ДВУМЯ КЛАССАМИ НЕ ДЛЯ КРАСОТЫ: у `.stw-logo` внизу файла
	есть правило узкого экрана (`min(--stw-logo-size, 42vw)`), и с одним
	классом оно перебило бы этот размер по порядку в файле.

	`--stw-btn-size: 100%` — ради скругления «квадратной» формы кнопки:
	радиус считается как треть этой величины, а у квадратной коробки
	треть от 100% и есть треть стороны (тот же прием, что у вида `hero`)
*/
.stw .stw-logo--voice {
	--stw-btn-size: 100%;

	width: var(--stw-voice-stage, 168px);
	/* Высота — от ширины: процент высоты считался бы от ВЫСОТЫ подмостков,
	   а она сама зависит от фигуры */
	height: auto;
	aspect-ratio: 1 / 1;
}

.stw-voice__title {
	font-size: 1.3rem;
	font-weight: 700;
}

.stw-voice__hint {
	max-width: 34ch;
	color: var(--stw-muted);
	font-size: 0.88rem;
}

/* Микрофон и кольцо меряются ТЕМ ЖЕ выражением, что и логотип: размер
   фигуры задается ОДНОЙ настройкой на все три вида — иначе владельцу
   пришлось бы подбирать его заново после каждой смены вида */
.stw-voice__mic {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: var(--stw-voice-stage, 120px);
	height: auto;
	aspect-ratio: 1 / 1;
	border-radius: 999px;
	background-color: var(--stw-accent);
	color: var(--stw-accent-text);
	box-shadow: 0 0 0 12px color-mix(in srgb, var(--stw-accent) 16%, transparent);
	animation: stw-voice-pulse 2s ease-in-out infinite;
}

/* Значок долей круга, а не пикселями: круг теперь растет вместе
   с панелью, и значок обязан расти вместе с ним */
.stw-voice__mic svg {
	width: 38%;
	height: 38%;
	fill: none;
	stroke: currentColor;
	stroke-width: 1.6;
	stroke-linecap: round;
	stroke-linejoin: round;
}

@keyframes stw-voice-pulse {
	0%, 100% { box-shadow: 0 0 0 12px color-mix(in srgb, var(--stw-accent) 16%, transparent); }
	50% { box-shadow: 0 0 0 22px color-mix(in srgb, var(--stw-accent) 6%, transparent); }
}

/* Кольцо громкости: три вложенных окружности с разной задержкой —
   расходятся волной от центра */
.stw-voice__ring {
	position: relative;
	width: var(--stw-voice-stage, 140px);
	height: auto;
	aspect-ratio: 1 / 1;
}

.stw-voice__ring span {
	position: absolute;
	inset: 0;
	border: 2px solid var(--stw-accent);
	border-radius: 999px;
	opacity: 0;
	animation: stw-voice-ring 2.4s ease-out infinite;
}

.stw-voice__ring span:nth-child(2) { animation-delay: 0.8s; }
.stw-voice__ring span:nth-child(3) { animation-delay: 1.6s; }

@keyframes stw-voice-ring {
	0% { scale: 0.55; opacity: 0.75; }
	100% { scale: 1; opacity: 0; }
}

/*
	ПОЛОСКИ ГРОМКОСТИ. Высоту им ставит СКРИПТ по реальному уровню сигнала
	(переменная --v на каждой), а не анимация: «красивая волна» при
	выключенном микрофоне — это обман посетителя, а не украшение
*/
.stw-wave {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 4px;
	height: 34px;
}

.stw-wave span {
	width: 4px;
	height: calc(6px + var(--v, 0) * 26px);
	border-radius: 999px;
	background-color: var(--stw-accent);
	opacity: 0.75;
	transition: height 0.08s linear;
}

.stw-voice__foot {
	flex: 0 0 auto;
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 22px;
	padding: 16px 16px 22px;
}

/*
	==== РАЗМЕР КНОПОК — ОДНО ЧИСЛО, ОСТАЛЬНОЕ ОТ НЕГО ====
	(2026-08-10)

	Владелец задает размер ГЛАВНОЙ кнопки (`--stw-voice-btn`), а боковые
	и все значки считаются долями от него. Три независимых числа разошлись
	бы при первой же правке, и ряд перестал бы читаться как один узел.

	0.62 у боковых — ровно прежнее соотношение (48 при главной 64):
	у настроенных виджетов вид не меняется ни на пиксель
*/
.stw .stw-voice__act {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: calc(var(--stw-voice-btn, 78px) * 0.62);
	height: calc(var(--stw-voice-btn, 78px) * 0.62);
	padding: 0;
	border: 1px solid var(--stw-border);
	border-radius: 999px;
	background-color: var(--stw-panel-bg);
	color: var(--stw-muted);
	cursor: pointer;
	transition: color 0.15s ease, border-color 0.15s ease, background-color 0.15s ease;
}

/*
	`:not(.stw-voice__act--main)` — ЧТОБЫ ПРАВИЛО НЕ ЛЕЗЛО К ГЛАВНОЙ:
	у нее свой цвет значка, посчитанный под акцентную заливку, и подмена
	его на цвет текста дала бы темный значок на темной кнопке. Раньше
	это спасал только порядок правил в файле — то есть случайность
*/
.stw-voice__act:not(.stw-voice__act--main):hover {
	color: var(--stw-text);
	border-color: var(--stw-accent);
}

/* Главная кнопка крупнее соседних: «закончить» нажимают, не глядя,
   и промахнуться по ней быть не должно */
.stw .stw-voice__act--main {
	/* Точка отсчета для кольца наведения (`halo` ниже): оно рисуется
	   псевдоэлементом, а тому нужен позиционированный предок */
	position: relative;
	width: var(--stw-voice-btn, 78px);
	height: var(--stw-voice-btn, 78px);
	border-color: transparent;
	background-color: var(--stw-accent);
	color: var(--stw-accent-text);
	/*
		ПЕРЕХОД ПЕРЕЧИСЛЯЕТ СВОЙСТВА ПОИМЕННО, А НЕ `all`. Под `all`
		попали бы и кадры анимаций (`wobble`, `jelly`), и каждый их шаг
		получил бы вдогонку еще и плавный переход — движение становится
		вязким и «залипает» после увода курсора
	*/
	transition: scale 0.18s ease, translate 0.18s ease,
		box-shadow 0.2s ease, filter 0.18s ease,
		background-color 0.15s ease;
}

/*
	==== ОФОРМЛЕНИЕ БОКОВЫХ КНОПОК ====
	(2026-08-10)

	ЧЕТЫРЕ ВАРИАНТА — НЕ ПРИХОТЬ: на макетах голосовых помощников этот ряд
	собран по-разному, и от него зависит, читается панель строгой или
	воздушной. Правила описывают ТОЛЬКО заливку и рамку — размер, форма
	и значки к оформлению отношения не имеют и живут выше.

	ГЛАВНОЙ КНОПКИ ЭТО НЕ КАСАЕТСЯ НИ В ОДНОМ ВАРИАНТЕ: она всегда
	акцентная и всегда заметнее соседей — иначе «готово» пришлось бы искать
	глазами, а его нажимают вслепую
*/
.stw[data-stw-voice-btn="soft"] .stw-voice__act:not(.stw-voice__act--main) {
	border-color: transparent;
	background-color: var(--stw-bot-bg);
}

.stw[data-stw-voice-btn="glass"] .stw-voice__act:not(.stw-voice__act--main) {
	border-color: color-mix(in srgb, var(--stw-border) 60%, transparent);
	background-color: color-mix(in srgb, var(--stw-panel-bg) 45%, transparent);
	-webkit-backdrop-filter: blur(10px);
	backdrop-filter: blur(10px);
}

.stw[data-stw-voice-btn="plain"] .stw-voice__act:not(.stw-voice__act--main) {
	border-color: transparent;
	background-color: transparent;
}

/*
	ФОРМА — ОДНА НА ВЕСЬ РЯД. Радиус считается от размера самой кнопки
	(треть стороны), поэтому у крупной и мелкой он выглядит одинаково:
	жесткое число в пикселях у кнопки в 92 px читалось бы почти кругом
*/
.stw[data-stw-voice-btn-shape="squircle"] .stw-voice__act {
	border-radius: calc(var(--stw-voice-btn, 78px) * 0.62 / 3);
}

.stw[data-stw-voice-btn-shape="squircle"] .stw-voice__act--main {
	border-radius: calc(var(--stw-voice-btn, 78px) / 3);
}

.stw-voice__act svg {
	width: 42%;
	height: 42%;
	fill: none;
	stroke: currentColor;
	stroke-width: 1.8;
	stroke-linecap: round;
	stroke-linejoin: round;
}

/*
	ЗНАЧОК ГЛАВНОЙ КНОПКИ — ОБВОДКОЙ, А НЕ ЗАЛИВКОЙ (правка 2026-08-10).
	Раньше здесь стоял залитый квадрат «стоп», и правило гасило обводку.
	Теперь на кнопке микрофон — он рисуется линиями, и залей его,
	получилась бы черная клякса
*/
.stw-voice__act--main svg {
	width: 44%;
	height: 44%;
	fill: none;
	stroke: currentColor;
	stroke-width: 1.7;
}

/* ==== АНИМАЦИИ ГЛАВНОЙ КНОПКИ ГОЛОСОВОГО ЭКРАНА ======================= */
/*
	(2026-08-10)

	ЗАЧЕМ ОНИ ЗДЕСЬ, ЕСЛИ У ПЛАВАЮЩЕЙ КНОПКИ УЖЕ ЕСТЬ СВОИ. Те написаны
	как `.stw[data-stw-hover="…"] .stw-btn` и опираются на СЛУЖЕБНЫЕ СЛОИ
	кнопки: осветление красит `.stw-btn__bg`, всплеск кольца живет
	на `.stw-btn__fx::after`, поворот — на `.stw-btn__icon`. У кнопки
	голосового экрана нет ни одного из этих узлов: это обычный `button`
	со значком внутри.

	ПОЭТОМУ НАБОР СВОЙ И КОРОЧЕ, А КАДРЫ — ОБЩИЕ: `stw-wobble`,
	`stw-jelly`, `stw-pop`, `stw-shake`, `stw-flash`, `stw-squash`
	и `stw-ripple` уже описаны выше и переиспользуются как есть.
	Второй набор одинаковых кадров разошелся бы с первым при первой правке.

	АНИМАЦИИ ТОЛЬКО У ГЛАВНОЙ КНОПКИ. Боковые — служебные, и движение
	на них уводило бы внимание с той единственной, которую посетитель
	ищет пальцем, не глядя на экран
*/
.stw[data-stw-voice-hover="grow"] .stw-voice__act--main:hover { scale: 1.08; }
.stw[data-stw-voice-hover="lift"] .stw-voice__act--main:hover { translate: 0 -4px; }

/*
	СВЕЧЕНИЕ — УМОЛЧАНИЕ. Кнопка крупная, и рост на 8% на ней почти
	не читается, а мягкое кольцо вокруг видно сразу и ничего не двигает.
	Первая тень — плотное кольцо у самой кромки, вторая — рассеянный ореол
*/
.stw[data-stw-voice-hover="glow"] .stw-voice__act--main:hover {
	box-shadow: 0 0 0 7px color-mix(in srgb, var(--stw-accent) 18%, transparent),
		0 0 26px -4px var(--stw-accent);
}

/* ОСВЕТЛЕНИЕ идет фильтром по всей кнопке, а не подменой цвета фона:
   заливка бывает и градиентной от темы, и подмена стерла бы ее */
.stw[data-stw-voice-hover="bright"] .stw-voice__act--main:hover {
	filter: brightness(1.14) saturate(1.08);
}

.stw[data-stw-voice-hover="wobble"] .stw-voice__act--main:hover {
	animation: stw-wobble 0.7s ease-in-out;
}

.stw[data-stw-voice-hover="jelly"] .stw-voice__act--main:hover {
	animation: stw-jelly 0.6s ease-in-out;
}

/*
	ПОВОРОТ ЗНАЧКА, А НЕ КНОПКИ: круглая кнопка при повороте не меняется
	вовсе — эффект был бы виден только у «скругленного квадрата»
*/
.stw[data-stw-voice-hover="spin"] .stw-voice__act--main svg {
	transition: rotate 0.55s ease;
}

.stw[data-stw-voice-hover="spin"] .stw-voice__act--main:hover svg {
	rotate: 360deg;
}

/*
	КОЛЬЦО ВОКРУГ — расходящаяся волна на псевдоэлементе. Он заводится
	ТОЛЬКО в этом варианте: пустой слой в каждой кнопке ради возможности,
	которой владелец может не пользоваться, ни к чему.

	`border-radius: inherit` — чтобы кольцо повторяло форму кнопки:
	у «скругленного квадрата» круглая волна выглядела бы чужой деталью
*/
.stw[data-stw-voice-hover="halo"] .stw-voice__act--main::after {
	content: '';
	position: absolute;
	inset: 0;
	border: 2px solid var(--stw-accent);
	border-radius: inherit;
	opacity: 0;
	pointer-events: none;
}

.stw[data-stw-voice-hover="halo"] .stw-voice__act--main:hover::after {
	animation: stw-ripple 0.7s ease-out;
}

/* ==== НАЖАТИЕ ========================================================= */

.stw[data-stw-voice-active="press"] .stw-voice__act--main:active { scale: 0.94; }

.stw[data-stw-voice-active="sink"] .stw-voice__act--main:active {
	translate: 0 3px;
	scale: 0.97;
	box-shadow: none;
}

.stw[data-stw-voice-active="pop"] .stw-voice__act--main:active {
	animation: stw-pop 0.32s ease-out;
}

.stw[data-stw-voice-active="shake"] .stw-voice__act--main:active {
	animation: stw-shake 0.35s ease-in-out;
}

/* ВСПЫШКА гасит собой наведение НАМЕРЕННО: обе живут на `filter`,
   и одновременный пересвет с осветлением дал бы белый круг */
.stw[data-stw-voice-active="flash"] .stw-voice__act--main:active {
	animation: stw-flash 0.4s ease-out;
}

.stw[data-stw-voice-active="squash"] .stw-voice__act--main:active {
	animation: stw-squash 0.32s ease-out;
}

/* ==== КЛАВИАТУРА ВАРИАНТОВ ОТВЕТА ===================================== */
/*
	ЗАМЕЩАЕТ ФОРМУ ВВОДА, а не встает над ней (`.stw--kb` гасит форму ниже).
	Пока ассистент ждет выбора из списка, свободный ввод — это второй,
	конкурирующий способ ответить на тот же вопрос
*/
.stw-kb {
	flex: 0 0 auto;
	padding: 12px;
	border-top: 1px solid var(--stw-border);
	background-color: var(--stw-panel-bg);
	/* Вариантов может прийти восемь, и на невысокой карточке они съели бы
	   всю переписку: своя прокрутка честнее обрезки */
	max-height: 52vh;
	overflow-y: auto;
	animation: stw-kb-in 0.2s ease;
}

@keyframes stw-kb-in {
	from { opacity: 0; translate: 0 8px; }
	to { opacity: 1; translate: 0 0; }
}

.stw.stw--kb .stw-form {
	display: none;
}

.stw-kb__list {
	display: grid;
	gap: 6px;
}

.stw[data-stw-kb-style="grid"] .stw-kb__list {
	grid-template-columns: repeat(auto-fit, minmax(min(130px, 100%), 1fr));
}

.stw[data-stw-kb-style="chips"] .stw-kb__list {
	display: flex;
	flex-wrap: wrap;
}

.stw .stw-kb__item {
	width: 100%;
	padding: 11px 14px;
	border: 1px solid var(--stw-border);
	border-radius: var(--stw-radius-sm);
	background-color: var(--stw-tile-bg);
	color: var(--stw-tile-fg);
	font: inherit;
	font-size: 0.88rem;
	text-align: left;
	cursor: pointer;
	transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}

.stw-kb__item:hover {
	border-color: var(--stw-accent);
}

/*
	ПЕРВЫЙ ВАРИАНТ ВЫДЕЛЕН, КАК НА ПРИМЕРЕ ВЛАДЕЛЬЦА. Это не «правильный
	ответ», а подсказка, откуда начинать читать: список из восьми
	одинаковых кнопок взгляду не за что зацепиться
*/
.stw .stw-kb__item--first {
	background-color: var(--stw-accent);
	border-color: transparent;
	color: var(--stw-accent-text);
}

.stw[data-stw-kb-style="chips"] .stw-kb__item {
	width: auto;
	padding: 8px 14px;
	border-radius: 999px;
}

.stw-kb__own {
	display: flex;
	gap: 6px;
	margin-top: 6px;
}

.stw .stw-kb__input {
	flex: 1 1 auto;
	min-width: 0;
	padding: 10px 12px;
	border: 1px solid var(--stw-border);
	border-radius: var(--stw-radius-sm);
	background-color: var(--stw-panel-bg);
	color: var(--stw-text);
	font: inherit;
	font-size: 0.88rem;
}

.stw-kb__input:focus {
	outline: none;
	border-color: var(--stw-accent);
}

.stw .stw-kb__send {
	flex: 0 0 auto;
	padding: 10px 16px;
	border: 1px solid var(--stw-border);
	border-radius: var(--stw-radius-sm);
	background-color: var(--stw-panel-bg);
	color: var(--stw-text);
	font: inherit;
	font-size: 0.88rem;
	cursor: pointer;
}

.stw-kb__send:hover {
	border-color: var(--stw-accent);
}

/* ==== ФОРМА ВВОДА ====================================================== */

.stw-form {
	flex: 0 0 auto;
	padding: 12px;
	border-top: 1px solid var(--stw-border);
	background-color: var(--stw-panel-bg);
}

/* Прикрепленные файлы показываются ДО отправки: посетитель должен видеть,
   что именно уйдет, и иметь возможность передумать */
.stw-files {
	display: none;
	flex-wrap: wrap;
	gap: 6px;
	margin-bottom: 8px;
}

.stw-files.stw-files--on {
	display: flex;
}

.stw-file {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	max-width: 100%;
	padding: 4px 8px;
	border-radius: 999px;
	background-color: var(--stw-head-bg);
	font-size: 0.78rem;
}

.stw-file__name {
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
	max-width: 160px;
}

.stw .stw-file__drop {
	border: 0;
	background: transparent;
	color: var(--stw-muted);
	cursor: pointer;
	padding: 0;
	line-height: 1;
}

.stw-row {
	display: flex;
	align-items: flex-end;
	gap: 8px;
}

.stw .stw-input {
	flex: 1 1 auto;
	min-width: 0;
	/* Поле растет вместе с текстом (высоту считает скрипт), но не бесконечно:
	   после ~5 строк появляется своя прокрутка, иначе форма съест всю панель */
	max-height: 140px;
	/*
		==== НИЖНЯЯ ГРАНИЦА ВЫСОТЫ — СТРАХОВКА ОТ СХЛОПЫВАНИЯ ====
		(правка 2026-08-09)

		Высоту полю ставит скрипт инлайном, а инлайн сильнее любого правила.
		Стоит скрипту посчитать ее в скрытом виджете — и в поле уезжает
		`height: 0px`: у элемента внутри `display: none` нет ни высоты,
		ни прокрутки. Ровно это и происходило в конструкторе, где виджет
		спрятан до переключения в «Просмотр»: подсказка обрезалась пополам,
		а сбоку вылезала полоса прокрутки в две стрелки.

		Скрипт теперь пересчитывает высоту при открытии панели и не пишет
		ноль, но `min-height` оставлен НАМЕРЕННО: он делает поле пригодным
		к работе даже там, где скрипт не отработал вовсе
	*/
	min-height: 42px;
	padding: 10px 12px;
	border: 1px solid var(--stw-border);
	border-radius: var(--stw-radius-sm);
	background-color: var(--stw-panel-bg);
	color: var(--stw-text);
	font: inherit;
	font-size: 0.94rem;
	resize: none;
	/*
		==== ПРОКРУТКА ВЫКЛЮЧЕНА, ПОКА ПОЛЕ НЕ УПЕРЛОСЬ В ПОТОЛОК ====
		(правка 2026-08-09)

		Здесь стоял `auto`, и это давало полосу прокрутки В ПУСТОМ ПОЛЕ:
		высота поля равна `scrollHeight`, а браузер при таком совпадении
		сплошь и рядом считает содержимое «на волосок больше» и рисует
		полосу — на Windows это две стрелки посреди строки ввода.

		Полоса нужна ровно в одном случае — когда текст перерос
		`max-height`. Его и включает скрипт (`resize`), сравнив
		`scrollHeight` с фактической высотой ПОСЛЕ присвоения
	*/
	overflow-y: hidden;
}

.stw-input:focus {
	outline: none;
	border-color: var(--stw-accent);
}

.stw .stw-tool,
.stw .stw-send {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	flex: 0 0 auto;
	width: 40px;
	height: 40px;
	padding: 0;
	border: 1px solid var(--stw-border);
	border-radius: var(--stw-radius-sm);
	background-color: var(--stw-panel-bg);
	color: var(--stw-muted);
	cursor: pointer;
	transition: background-color 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}

.stw-tool:hover {
	color: var(--stw-text);
	border-color: var(--stw-accent);
}

/*
	==== КНОПКА ОТПРАВКИ ЖИВЕТ, ПОКА ЕСТЬ ЧТО ОТПРАВЛЯТЬ ====
	(2026-08-09)

	В пустом поле она предлагала сделать то, чего сделать нельзя: `send()`
	на пустом поле без вложений просто выходит. Класс на корне ставит
	скрипт (`syncSend`).

	`display: none`, А НЕ ПРОЗРАЧНОСТЬ: невидимая, но занимающая место
	кнопка оставляла бы дыру у края строки — а так поле ввода забирает
	освободившуюся ширину себе
*/
.stw .stw-send {
	display: none;
	border-color: transparent;
	background-color: var(--stw-accent);
	color: var(--stw-accent-text);
}

.stw.stw--ready .stw-send {
	display: inline-flex;
}


.stw-send:disabled,
.stw-tool:disabled {
	opacity: 0.5;
	cursor: default;
}

/* ЗАПИСЬ ИДЕТ — ЭТО ВИДНО. Кнопка микрофона меняет цвет и пульсирует:
   посетитель обязан понимать, что его слышат */
.stw .stw-tool--rec {
	background-color: var(--st-danger, #D64550);
	border-color: transparent;
	color: #FFFFFF;
	animation: stw-rec 1.2s ease-in-out infinite;
}

@keyframes stw-rec {
	0%, 100% { opacity: 1; }
	50% { opacity: 0.55; }
}

.stw-tool svg,
.stw-send svg {
	width: 18px;
	height: 18px;
	fill: none;
	stroke: currentColor;
	stroke-width: 1.8;
	stroke-linecap: round;
	stroke-linejoin: round;
}

/*
	ЗНАЧОК ОТПРАВКИ — ЗАЛИВКОЙ, А НЕ КОНТУРОМ.

	СТОИТ ПОСЛЕ ОБЩЕГО ПРАВИЛА НАМЕРЕННО: вес у селекторов одинаковый,
	и решает порядок. Поставь выше — общее правило вернуло бы `fill: none`,
	то есть ПРОЗРАЧНЫЙ самолетик, сквозь который просвечивает заливка
	кнопки. Именно так значок и читался как темный на синем
*/
.stw-send svg {
	width: 20px;
	height: 20px;
	fill: currentColor;
	stroke: none;
}

.stw-hint {
	margin-top: 6px;
	color: var(--stw-muted);
	font-size: 0.72rem;
}

/* ==== ВИДЫ ПОЛЯ ВВОДА ================================================== */
/*
	Меняется ТОЛЬКО оправа поля и кнопок — размеры, отступы и поведение
	остаются общими. Иначе четыре вида означали бы четыре копии правил
	формы, и первая же правка развела бы их
*/
.stw[data-stw-input-style="pill"] .stw-input,
.stw[data-stw-input-style="pill"] .stw-tool,
.stw[data-stw-input-style="pill"] .stw-send {
	border-radius: 999px;
}

.stw[data-stw-input-style="flat"] .stw-input {
	border-color: transparent;
	background-color: var(--stw-head-bg);
}

.stw[data-stw-input-style="flat"] .stw-tool {
	border-color: transparent;
	background-color: transparent;
}

/*
	«КАРТОЧКОЙ» — ЭТО ОДНА ОБЩАЯ ОПРАВА НА ВСЮ СТРОКУ, а не рамка вокруг
	каждой кнопки. Поэтому рамка переезжает на саму строку, а внутренние
	элементы свои теряют — иначе получилось бы четыре рамки в одной
*/
.stw[data-stw-input-style="card"] .stw-row {
	padding: 6px;
	border: 1px solid var(--stw-border);
	border-radius: var(--stw-radius);
	background-color: var(--stw-panel-bg);
}

.stw[data-stw-input-style="card"] .stw-input,
.stw[data-stw-input-style="card"] .stw-tool {
	border-color: transparent;
	background-color: transparent;
}

.stw[data-stw-input-style="card"] .stw-send {
	border-radius: 999px;
}

/* ==== УЗКИЙ ЭКРАН ====================================================== */
/*
	На телефоне боковая панель шириной 400px — это почти весь экран, но
	«почти» хуже, чем «весь»: остаток превращается в бесполезную полоску.
	Поэтому шторка занимает всю ширину, а закрывается кнопкой в шапке.

	КАРТОЧКА НА ТЕЛЕФОНЕ СТАНОВИТСЯ ЛИСТОМ, и это не самоуправство:
	карточка 400×600 в окне 360×640 — это и есть лист, только с полями
	по краям и оторванным от края скруглением
*/
@media (max-width: 575.98px) {
	.stw[data-stw-panel-mode="drawer"] .stw-panel {
		width: 100%;
	}

	/*
		`[data-stw-pos]` ЗДЕСЬ — СНОВА ВЕС, А НЕ УТОЧНЕНИЕ.

		На широком экране положение карточки зависит от того, где стоит
		кнопка (`[data-stw-pos^="t"]`, `[data-stw-pos^="m"]`), и те правила
		несут четыре и пять простых селекторов. Без «пустого» атрибута
		положения телефонный лист их бы не перебил, и карточка при кнопке
		сверху осталась бы висеть посреди экрана
	*/
	.stw[data-stw-panel-mode="float"][data-stw-pos] .stw-panel {
		left: 0;
		right: 0;
		bottom: 0;
		top: auto;
		width: 100%;
		max-height: 88vh;
		border-radius: var(--stw-panel-radius) var(--stw-panel-radius) 0 0;
		transform: translateY(105%);
	}

	.stw[data-stw-panel-mode="float"][data-stw-pos].stw--open .stw-panel {
		transform: none;
	}

	/*
		Логотип во весь экран телефона превращает приветствие в постер
		без текста. ОГРАНИЧИВАЕМ САМУ ПЕРЕМЕННУЮ, а не ширину коробки:
		от нее считается и высота, и — что важнее — буфер живой формы.
		Один `max-width` дал бы приплюснутый овал вместо круга
	*/
	.stw-logo {
		--stw-btn-size: min(var(--stw-logo-size, 128px), 42vw);
	}
}

/* ==== ДОСТУПНОСТЬ: ДВИЖЕНИЕ ВЫКЛЮЧАЕТ ПОСЕТИТЕЛЬ ======================= */
/*
	Настройки анимаций принадлежат владельцу сайта, но это правило —
	не настройка. Человек, который просил систему убрать анимацию, обязан
	получить неподвижный виджет независимо от чужих предпочтений
*/
@media (prefers-reduced-motion: reduce) {
	/*
		СПИСОК ПЕРЕЧИСЛЕН ПОИМЕННО И ДОЛЖЕН ПОПОЛНЯТЬСЯ ВМЕСТЕ С ЭФФЕКТАМИ.
		Кольца, искры и движущийся градиент живут на СВОИХ слоях, и без
		их упоминания здесь просьба посетителя убрать анимацию исполнялась
		бы наполовину: кнопка замирала, а вокруг нее продолжали крутиться
		кольцо и мерцать искры
	*/
	.stw-btn,
	.stw-btn__bg,
	.stw-btn__bg::before,
	.stw-btn__bg::after,
	.stw-btn__fx::before,
	.stw-btn__fx::after,
	.stw-btn__spark::before,
	.stw-btn__spark::after,
	.stw-btn__edge,
	.stw-btn__edge::before,
	.stw-typing span,
	.stw-tool--rec,
	/* ЭКРАНЫ ПАНЕЛИ (2026-08-09): появление карточки слайдера, всплытие
	   клавиатуры, пульс микрофона и кольца громкости. Забудь их здесь —
	   и просьба посетителя убрать движение исполнялась бы наполовину */
	.stw-slide,
	.stw-kb,
	.stw-voice__mic,
	.stw-voice__ring span,
	/* Наведение и нажатие на главной кнопке голосового экрана (2026-08-10):
	   покачивание, желе, хлопок, тряска, вспышка, сплющивание и кольцо */
	.stw-voice__act--main,
	.stw-voice__act--main::after,
	.stw-panel__bg.st-bg-on::before {
		animation: none !important;
	}

	/*
		КОЛЬЦА ГРОМКОСТИ БЕЗ АНИМАЦИИ ОСТАЛИСЬ БЫ ТРЕМЯ НЕПОДВИЖНЫМИ
		ОКРУЖНОСТЯМИ с нулевой прозрачностью — то есть пустым местом
		вместо картинки. Показываем одну, статичную
	*/
	.stw-voice__ring span {
		opacity: 0.5;
		scale: 1;
	}

	.stw-voice__ring span:nth-child(2),
	.stw-voice__ring span:nth-child(3) {
		display: none;
	}

	/* Полоски громкости продолжают ходить за голосом: это не украшение,
	   а единственное подтверждение того, что микрофон слышит */
	.stw-wave span {
		transition: none !important;
	}

	/* Мерцающие точки гасятся насовсем: без анимации они замерли бы
	   видимыми кляксами вокруг кнопки */
	.stw-btn__spark {
		display: none !important;
	}

	/*
		ЖИВАЯ ФОРМА И LOTTIE ОСТАНАВЛИВАЮТСЯ СКРИПТОМ, А НЕ ЭТИМ ПРАВИЛОМ:
		они рисуются не CSS-анимацией, и `animation: none` их не касается.
		HSSteWidget сам проверяет `prefers-reduced-motion` — живая форма
		рисует ОДИН статичный кадр, Lottie замирает на первом.
		Прятать их здесь нельзя: без движения это все еще значок и форма,
		которые владелец выбрал осознанно
	*/

	.stw-btn,
	.stw-btn__icon,
	.stw-panel,
	.stw-scrim {
		transition: none !important;
	}

	.stw-btn:hover,
	.stw-btn:active {
		scale: 1;
		rotate: 0deg;
		translate: 0 0;
	}

	/*
		ЗНАЧОК ОБЕЗДВИЖИВАЕТСЯ ПО ДВУМ СВОЙСТВАМ СРАЗУ: «поворот» идет
		через `rotate`, а «переворот» — через `transform` с перспективой.
		Снять одно и забыть второе значило бы исполнить просьбу наполовину
	*/
	.stw-btn:hover .stw-btn__icon {
		rotate: 0deg;
		transform: none;
	}
}
