/* ===========================================================================
   my-ui — формы

   Эталонные стили. Копируются в проект целиком, правятся только токены
   в tokens.css. Разметку под эти классы см. в markup.md.

   Ничего WordPress- или React-специфичного здесь нет: обычные классы
   и три состояния — is-invalid, is-loading, is-open.
   =========================================================================== */

/* ---------------------------------------------------------------------------
   1. Поле с уезжающей подписью

   Подпись стоит внутри поля на месте плейсхолдера и уезжает вверх при вводе.
   Отдельной подписи над полем нет: она удваивает высоту каждой строки.
   --------------------------------------------------------------------------- */

.ui-field {
	position: relative;
}

/* Абсолютной подпись становится только там, где под ней есть поле ввода:
   тем же классом часто набран заголовок группы чекбоксов, а он должен
   остаться в потоке — иначе ложится поверх них. */
.ui-field:has(> .ui-field__input) > .ui-field__label,
.ui-field:has(.ui-select) > .ui-field__label {
	position: absolute;
	z-index: 2;
	top: var(--ui-field-label);
	left: var(--ui-field-pad-x);
	right: var(--ui-field-pad-x);
	margin: 0;
	font-family: var(--ui-font);
	font-weight: var(--ui-w-normal);
	font-size: var(--ui-field-font);
	line-height: var(--ui-field-line);
	color: var(--ui-muted);
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
	pointer-events: none;
	transform-origin: left center;
	transition: transform var(--ui-slow) var(--ui-ease),
	            color var(--ui-slow) var(--ui-ease);
}

/* Уезд подписи. Масштаб .8 — подпись становится мельче наборного текста,
   но остаётся читаемой. У списка подпись уехавшая всегда: там либо значение,
   либо подсказка, пусто не бывает. */
.ui-field:has(.ui-field__input:focus) .ui-field__label,
.ui-field:has(.ui-field__input:not(:placeholder-shown)) .ui-field__label,
.ui-field:has(.ui-select) .ui-field__label {
	transform: translateY(-11px) scale(.8);
}

/* Заголовок группы без поля под ним — обычная строка в потоке */
.ui-field:not(:has(> .ui-field__input)):not(:has(.ui-select)) > .ui-field__label {
	display: block;
	margin: 0 0 4px;
	font-weight: var(--ui-w-ui);
	font-size: var(--ui-field-font);
	color: var(--ui-heading);
}

.ui-field__req {
	color: var(--ui-error);
}

.ui-field__input {
	width: 100%;
	border: 0;
	background: var(--ui-surface);
	border-radius: var(--ui-field-radius);
	padding: var(--ui-field-pad-top) var(--ui-field-pad-x) var(--ui-field-pad-bot);
	font-family: var(--ui-font);
	font-weight: var(--ui-w-normal);
	font-size: var(--ui-field-font);
	line-height: var(--ui-field-line);
	color: var(--ui-ink);
	transition: box-shadow var(--ui-base) var(--ui-ease);
}

/* Плейсхолдер виден только при вводе: в покое его место занимает подпись,
   и два текста в одной строке наложились бы друг на друга. */
.ui-field__input::placeholder {
	color: transparent;
	transition: color var(--ui-base) var(--ui-ease);
}

.ui-field__input:focus::placeholder {
	color: var(--ui-muted);
}

/* Кольцо ВНУТРЕННЕЕ. Наружное с разбросом раздвигает габарит элемента,
   и на клике всё поле вместе с текстом подпрыгивает.
   Заливка при этом не меняется — см. decisions.md. */
.ui-field__input:focus {
	outline: none;
	box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--ui-accent) 55%, transparent);
}

.ui-field__input.is-invalid {
	box-shadow: inset 0 0 0 1.5px var(--ui-error-line);
}

/* Приём вместо рамки фокуса из старых тем: input:focus-visible двигает текст
   при обычном клике мышью. Гасим через сам псевдокласс — селектор с классом
   слабее. */
.ui-field__input:focus-visible,
.ui-field__input:focus {
	text-indent: 0;
}

/* --- текстовая область ---------------------------------------------------- */

.ui-field__input--area {
	min-height: 132px;
	padding-top: 32px;
	resize: vertical;
}

/* Полоска закрывает уезжающие вверх строки: без неё текст проходит
   сквозь подпись. */
.ui-field:has(> .ui-field__input--area)::before {
	content: "";
	position: absolute;
	z-index: 1;
	top: 2px;
	left: 3px;
	right: 3px;
	height: 26px;
	background: var(--ui-surface);
	border-radius: var(--ui-field-radius) var(--ui-field-radius) 0 0;
	pointer-events: none;
}

/* --- подсказка и ошибка --------------------------------------------------- */

.ui-field__hint {
	margin: 6px 0 0;
	font-family: var(--ui-font);
	font-size: 13px;
	line-height: 1.4;
	color: var(--ui-muted);
}

.ui-field__error {
	margin: 5px 0 0;
	font-family: var(--ui-font);
	font-weight: var(--ui-w-normal);
	font-size: 12px;
	line-height: 1.3;
	color: var(--ui-error);
}

/* Место под сообщение живёт в разметке всегда и заполняется скриптом —
   так при повторной отправке абзацы не копятся друг под другом. */
.ui-field__error:empty {
	display: none;
}

/* Строка под кнопкой отправки. Заполняется ТОЛЬКО отказом, не привязанным
   ни к одному полю (сеть, сбой сервера). Когда ошибки расставлены по полям,
   общая строка читается третьей — после рамок и после подписей; правила
   в validation.md. */
.ui-form__status {
	margin: 12px 0 0;
	font-family: var(--ui-font);
	font-size: 15px;
	line-height: 1.4;
}

.ui-form__status--error { color: var(--ui-error); }
.ui-form__status--ok    { color: var(--ui-ok, #1e7b45); }

/* Пустой узел не должен занимать места: иначе под кнопкой дырка. */
.ui-form__status:empty {
	margin: 0;
}

/* ---------------------------------------------------------------------------
   2. Чекбокс

   Один квадрат на весь сайт: в форме (.ui-check, .ui-consent) — 24px,
   в фильтре каталога (.ui-filter__row, .ui-sticker) — 20px. В форме квадрат
   стоит один на строку рядом с длинной подписью, в него целятся пальцем —
   там он крупнее; в фильтре квадраты идут столбиком по три десятка,
   и лишние пиксели на каждом растянули бы список.

   Квадрат рисует сам input (appearance: none), галочку кладёт ::after —
   так она может расти и проявляться, а не появляться рывком вместе
   со сменой фона.

   Отметка = галочка + бледная заливка квадрата. Заливка бледно-голубая
   (--ui-check-fill), на несколько единиц темнее поверхности: отметка так
   читается на расстоянии, а не только по галочке. Насыщенный акцент не
   берём — залитый квадрат читался бы «тяжелее» кнопки рядом и ломал ряд.
   --------------------------------------------------------------------------- */

.ui-check input[type="checkbox"],
.ui-consent input[type="checkbox"],
.ui-filter__row input[type="checkbox"],
.ui-sticker input[type="checkbox"] {
	appearance: none;
	-webkit-appearance: none;
	position: relative;
	flex: 0 0 auto;
	width: 24px;
	height: 24px;
	margin: 0;
	border: 1px solid color-mix(in srgb, var(--ui-accent-active) 24%, transparent);
	border-radius: 3px;
	background: transparent;
	cursor: pointer;
	transition: border-color var(--ui-slow) var(--ui-ease),
	            background-color var(--ui-slow) var(--ui-ease);
}

.ui-filter__row input[type="checkbox"],
.ui-sticker input[type="checkbox"] {
	width: 20px;
	height: 20px;
}

/* Штрих галочки наследует currentColor через маску: перекрашивается
   одним свойством, а не переписыванием data-URI.

   Три вещи в этой картинке важны и проверены на экране:

   · Толщина штриха 3.5, а не 1.5. На двадцатипиксельном квадрате тонкая
     линия читается серой царапиной, а не отметкой.
   · Поля в viewBox: `-2 -2 22 18` вместо `0 0 18 14`. Круглые торцы штриха
     выходят за рамку рисунка на половину его толщины, и рамка их срезает —
     у галочки плоско обрублены оба конца. Поля добавлены симметрично,
     поэтому центр рисунка не сдвинулся.
   · Размер задаёт mask-size, а не сама картинка. 16.1×14.4 по рамке на
     квадрате 24 (13.4×12 на квадрате 20) — около 15×12 по самой галочке:
     она заметно меньше квадрата и не упирается в его рамку. Обе пары —
     одна доля квадрата.

   Появление и уход. Галочка не просто проявляется, а вырастает из середины
   квадрата: прозрачность и размер идут вместе, и отметка читается как жест,
   а не как подмена картинки. Появление 0.5 с по --ui-ease-pop (в конце чуть
   переходит через единицу), уход быстрее (0.34 с) и без перелёта: снятие
   отметки — отмена, её не разглядывают. Стартовый масштаб не ноль —
   с нуля первые кадры показывают точку, и вместо роста видно вспышку. */
.ui-check input[type="checkbox"]::after,
.ui-consent input[type="checkbox"]::after,
.ui-filter__row input[type="checkbox"]::after,
.ui-sticker input[type="checkbox"]::after {
	content: "";
	position: absolute;
	inset: 0;
	opacity: 0;
	background: currentColor;
	color: var(--ui-accent);
	transform: scale(.55);
	transition: opacity .34s var(--ui-ease), transform .34s var(--ui-ease);
	-webkit-mask: no-repeat center / 16.1px 14.4px
		url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='-2 -2 22 18'%3E%3Cpath d='M17.4 1L5.825 12.576a.6.6 0 0 1-.849 0L.6 8.2' fill='none' stroke='%23000' stroke-width='3.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
	mask: no-repeat center / 16.1px 14.4px
		url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='-2 -2 22 18'%3E%3Cpath d='M17.4 1L5.825 12.576a.6.6 0 0 1-.849 0L.6 8.2' fill='none' stroke='%23000' stroke-width='3.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

.ui-filter__row input[type="checkbox"]::after,
.ui-sticker input[type="checkbox"]::after {
	-webkit-mask-size: 13.4px 12px;
	mask-size: 13.4px 12px;
}

.ui-check input[type="checkbox"]:checked::after,
.ui-consent input[type="checkbox"]:checked::after,
.ui-filter__row input[type="checkbox"]:checked::after,
.ui-sticker input[type="checkbox"]:checked::after {
	opacity: 1;
	transform: scale(1);
	transition: opacity .5s var(--ui-ease), transform .5s var(--ui-ease-pop);
}

/* Отмеченный квадрат: бледная заливка и чуть плотнее рамка, чтобы край
   не растворялся в самой заливке */
.ui-check input[type="checkbox"]:checked,
.ui-consent input[type="checkbox"]:checked,
.ui-filter__row input[type="checkbox"]:checked,
.ui-sticker input[type="checkbox"]:checked {
	background: var(--ui-check-fill);
	border-color: color-mix(in srgb, var(--ui-accent-active) 32%, transparent);
}

.ui-check:hover input[type="checkbox"],
.ui-consent:hover input[type="checkbox"],
.ui-filter__row:hover input[type="checkbox"],
.ui-sticker:hover input[type="checkbox"] {
	border-color: color-mix(in srgb, var(--ui-accent-active) 55%, transparent);
}

.ui-check input[type="checkbox"]:focus-visible,
.ui-consent input[type="checkbox"]:focus-visible,
.ui-filter__row input[type="checkbox"]:focus-visible,
.ui-sticker input[type="checkbox"]:focus-visible {
	outline: 2px solid var(--ui-accent);
	outline-offset: 2px;
}

/* Ошибка — только собственная рамка, потолще. box-shadow поверх неё даёт
   второй контур с зазором, и квадрат читается обведённым дважды.
   2px, а не 1.5: дробную ширину браузер округляет вниз. */
.ui-check input[type="checkbox"].is-invalid,
.ui-consent input[type="checkbox"].is-invalid {
	border-color: var(--ui-error-line);
	border-width: 2px;
	box-shadow: none;
}

/* Кольцо фокуса поверх красной рамки — второй контур с зазором. Скрипт после
   неудачной отправки сам наводит фокус на первое неверное поле, и у согласия
   это квадрат. Кольцо оставляем — без него не видно, где фокус, — но красное
   и вплотную к рамке: получается один контур.

   :focus рядом с :focus-visible обязателен. Safari на iPhone после касания
   ставит элементу фокус, но :focus-visible к нему не применяет: правило,
   написанное только под :focus-visible, на телефоне молчит, и поверх рамки
   остаётся системное кольцо. */
.ui-check input[type="checkbox"].is-invalid:focus,
.ui-check input[type="checkbox"].is-invalid:focus-visible,
.ui-consent input[type="checkbox"].is-invalid:focus,
.ui-consent input[type="checkbox"].is-invalid:focus-visible {
	outline: 2px solid var(--ui-error-line);
	outline-offset: 0;
}

/* Тем, кто просил меньше движения: галочка остаётся в полном размере
   и только проявляется. Совсем без перехода нельзя — тогда отметка
   появляется рывком, а это и есть резкое движение. */
@media (prefers-reduced-motion: reduce) {
	.ui-check input[type="checkbox"]::after,
	.ui-consent input[type="checkbox"]::after,
	.ui-filter__row input[type="checkbox"]::after,
	.ui-sticker input[type="checkbox"]::after,
	.ui-check input[type="checkbox"]:checked::after,
	.ui-consent input[type="checkbox"]:checked::after,
	.ui-filter__row input[type="checkbox"]:checked::after,
	.ui-sticker input[type="checkbox"]:checked::after {
		transform: none;
		transition: opacity .2s var(--ui-ease);
	}
}

/* Строка с галочкой */
.ui-check {
	display: flex;
	align-items: center;
	gap: 12px;
	min-height: var(--ui-touch);
	font-family: var(--ui-font);
	font-weight: var(--ui-w-ui);
	font-size: 15px;
	line-height: 1.3;
	color: var(--ui-ink);
	cursor: pointer;
	transition: color var(--ui-fast) var(--ui-ease);
}

.ui-check:hover {
	color: var(--ui-accent);
}

/* ---------------------------------------------------------------------------
   3. Согласие на обработку данных
   --------------------------------------------------------------------------- */

.ui-consent {
	display: flex;
	align-items: flex-start;
	gap: 12px;
	font-family: var(--ui-font);
	font-size: 14px;
	line-height: 1.45;
	color: var(--ui-muted);
	cursor: pointer;
}

/* Квадрат по центру ПЕРВОЙ строки, а не по её верху:
   (высота строки − сторона квадрата) / 2. */
.ui-consent input[type="checkbox"] {
	margin-top: calc((1.45em - 24px) / 2);
}

/* Каждая половина фразы — inline-block БЕЗ переноса внутри: строка
   рвётся только между ними, перед «и даю». Вся фраза влезает — одна
   строка, нет — две. Третьей строки с одним «данных» не бывает: если
   даже половина не влезает в колонку (узкая форма на планшете), кегль
   чуть уменьшается, пока она не встанет.
     --consent-em     ширина длинной половины в em В ШРИФТЕ САЙТА + 3%
                      (замер — markup.md, «Согласие»); 28.7 — Helvetica Neue Cyr
     --consent-aside  квадрат + зазор (24 + 12); квадрат другой — пересчитать
   В разметке после «с» и «и» — неразрывный пробел (&nbsp;).
   Телефон — всегда ровно две строки, см. раздел 8. */
.ui-consent {
	--consent-em: 28.7;
	--consent-aside: 36px;
	container-type: inline-size;
}

.ui-consent > span {
	font-size: min(1em, calc((100cqi - var(--consent-aside)) / var(--consent-em)));
}

.ui-consent__clause {
	display: inline-block;
	white-space: nowrap;
}

.ui-consent a {
	color: var(--ui-heading);
	text-decoration: underline;
	text-underline-offset: 2px;
	transition: color var(--ui-fast) var(--ui-ease);
}

.ui-consent a:hover {
	color: var(--ui-accent);
}

/* ---------------------------------------------------------------------------
   4. Выпадающий список

   Родной select не стилизуется как поле с уезжающей подписью. Подменяем
   кнопкой-триггером, сам select оставляем в разметке скрытым: он держит
   значение и его проверяет сервер.
   --------------------------------------------------------------------------- */

.ui-select {
	position: relative;
}

.ui-select__native {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	opacity: 0;
	pointer-events: none;
}

.ui-select__trigger {
	position: relative;
	display: flex;
	align-items: center;
	width: 100%;
	border: 0;
	background: var(--ui-surface);
	border-radius: var(--ui-field-radius);
	/* справа запас под стрелку, иначе длинное значение заезжает под неё */
	padding: var(--ui-field-pad-top) calc(var(--ui-field-pad-x) + 22px)
	         var(--ui-field-pad-bot) var(--ui-field-pad-x);
	font-family: var(--ui-font);
	font-weight: var(--ui-w-ui);
	font-size: var(--ui-field-font);
	line-height: var(--ui-field-line);
	color: var(--ui-ink);
	text-align: left;
	cursor: pointer;
	transition: box-shadow var(--ui-base) var(--ui-ease);
}

.ui-select__trigger:focus-visible,
.ui-select.is-open .ui-select__trigger {
	outline: none;
	box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--ui-accent) 55%, transparent);
}

.ui-select.is-invalid .ui-select__trigger {
	box-shadow: inset 0 0 0 1.5px var(--ui-error-line);
}

.ui-select__value {
	flex: 1 1 auto;
	min-width: 0;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.ui-select.is-empty .ui-select__value {
	color: var(--ui-muted);
}

/* Стрелка выведена из потока и центрируется по всей высоте поля.
   Элементом flex-строки она выравнивалась бы по центру области содержимого,
   а та смещена вниз отступом под уехавшую подпись. */
.ui-select__arrow {
	position: absolute;
	top: 50%;
	right: var(--ui-field-pad-x);
	width: 12px;
	height: 8px;
	margin: 0;
	color: var(--ui-ink);
	transform: translateY(-50%);
	transition: transform var(--ui-base) var(--ui-ease);
}

.ui-select.is-open .ui-select__arrow {
	transform: translateY(-50%) rotate(180deg);
}

.ui-select__panel {
	position: absolute;
	top: calc(100% + 6px);
	left: 0;
	right: 0;
	z-index: 5;
	display: none;
	padding: 8px;
	border: 0;
	border-radius: var(--ui-field-radius);
	background: var(--ui-card);
	box-shadow: 0 22px 48px -20px rgba(0, 0, 0, .3);
}

.ui-select.is-open .ui-select__panel {
	display: block;
}

/* Снизу не помещается — раскрываем вверх */
.ui-select.is-up .ui-select__panel {
	top: auto;
	bottom: calc(100% + 6px);
}

.ui-select__search {
	width: 100%;
	margin-bottom: 8px;
	border: 0;
	border-radius: 11px;
	padding: 11px 14px;
	background: var(--ui-surface);
	font-family: var(--ui-font);
	font-size: 14px;
	color: var(--ui-ink);
}

.ui-select__search:focus {
	outline: none;
	box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--ui-accent) 55%, transparent);
}

.ui-select__opt {
	display: block;
	width: 100%;
	border: 0;
	background: none;
	border-radius: 11px;
	padding: 10px 12px;
	font-family: var(--ui-font);
	font-size: 15px;
	line-height: 1.35;
	color: var(--ui-ink);
	text-align: left;
	cursor: pointer;
	transition: background-color var(--ui-fast) var(--ui-ease);
}

.ui-select__opt:hover,
.ui-select__opt:focus-visible {
	outline: none;
	background: var(--ui-surface);
}

.ui-select__opt.is-active {
	background: var(--ui-accent);
	color: var(--ui-on-accent);
}

/* ---------------------------------------------------------------------------
   5. Кнопки формы

   Радиус кнопки повторяет радиус поля: в форме они одна семья.
   Пилюли оставьте навигации и фильтрам.
   --------------------------------------------------------------------------- */

.ui-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 10px;
	min-height: 54px;
	border: 0;
	border-radius: var(--ui-field-radius);
	padding: 0 34px;
	font-family: var(--ui-font);
	font-weight: var(--ui-w-ui);
	font-size: 15px;
	line-height: 1.2;
	cursor: pointer;
	transition: background-color var(--ui-base) var(--ui-ease),
	            color var(--ui-base) var(--ui-ease);
}

.ui-btn--primary {
	background: var(--ui-accent);
	color: var(--ui-on-accent);
}

.ui-btn--primary:hover:not(:disabled) { background: var(--ui-accent-hover); }
.ui-btn--primary:active:not(:disabled) { background: var(--ui-accent-active); }

.ui-btn--ghost {
	background: var(--ui-surface);
	color: var(--ui-ink);
}

.ui-btn--ghost:hover { background: var(--ui-surface-2); }

.ui-btn:disabled { opacity: .55; cursor: default; }

.ui-btn:focus-visible {
	outline: 2px solid var(--ui-accent-hover);
	outline-offset: 2px;
}

/* ---------------------------------------------------------------------------
   6. Модальное окно с формой
   --------------------------------------------------------------------------- */

.ui-modal {
	position: fixed;
	top: 50%;
	left: 50%;
	z-index: 60;
	width: min(980px, calc(100% - 32px));
	/* dvh, а не vh: на iOS адресная строка съедает часть экрана,
	   и низ окна уходит под неё. */
	max-height: 88dvh;
	transform: translate(-50%, -50%);
	border-radius: 32px;
	background: var(--ui-card);
	/* clip, а не hidden: hidden оставляет окно прокручиваемым из кода,
	   и любой scrollIntoView внутри уводит шапку за край. */
	overflow: clip;
}

/* Раскладываем колонкой ВНУТРЕННИЙ контейнер, а не само окно: показ через
   методы вроде fadeIn() выставляет display: block и затирает flex. */
.ui-modal__inner {
	display: flex;
	flex-direction: column;
	max-height: inherit;
	overflow: hidden;
}

/* Шапка вынесена из прокручиваемой области — иначе полоса тянется через неё
   насквозь. Ничем не отчёркнута: тень под ней ложится серой полосой
   во всю ширину и читается отдельным блоком. */
.ui-modal__head {
	flex: 0 0 auto;
	/* Левое поле шапки равно левому полю формы под ней (--ui-modal-pad):
	   заголовок начинается ровно над первым полем. Считать левый отступ
	   формы от полосы прокрутки — частая ошибка: форма уезжает правее
	   заголовка на ширину полосы, и шапка висит сама по себе.

	   По вертикали поля скромные. Шапка в две строки съедает пятую часть
	   окна, и прокручиваемая форма под ней на ноутбуке начинается
	   с обрезанного поля. */
	padding: 22px 80px 14px var(--ui-modal-pad);
	border: 0;
	box-shadow: none;
}

.ui-modal__title {
	/* Заголовок окна — наборным шрифтом сайта, не акцидентным. Акцидентный
	   на 30px даёт разреженную строку, которая спорит с плотным столбцом
	   полей прямо под ней. Проверьте это отдельно: общее правило
	   .modal__title в теме легко возвращает акцидентный шрифт молча. */
	margin: 0 0 4px;
	font-family: var(--ui-font);
	font-weight: var(--ui-w-strong);
	font-size: 30px;
	line-height: 1.3;
	letter-spacing: -.01em;
	color: var(--ui-ink);
}

/* Строка под заголовком — объяснение, зачем эта форма. Это не подсказка
   у поля: на 13px она читается мельче подписей в полях под ней и теряется.

   Чего в ней быть не должно — «Поля со звёздочкой обязательны». Звёздочка
   стоит у каждой обязательной подписи и говорит это сама, а строкой выше
   только удлиняет шапку на целую строку. */
.ui-form__note {
	margin: 0 0 24px;
	font-family: var(--ui-font);
	font-size: 15px;
	line-height: 1.45;
	color: var(--ui-muted);
}

/* Прокручивается сама форма, не окно. Отступ справа складывается из трёх
   частей и в сумме равен левому — иначе поля стоят не по центру окна:

       margin-right (20) + полоса (4) + padding-right (16) = 40 = padding-left

   При изменении --ui-modal-pad пересчитайте padding-right. */
.ui-modal__body {
	flex: 1 1 auto;
	min-height: 0;
	overflow-y: auto;
	margin: 16px 20px 20px 0;
	padding: 8px 16px 24px var(--ui-modal-pad);
}

/* Крестик — круглая кнопка того же цвета, что основные кнопки сайта.
   Не картинка: у неё штрих зашит в файл и на крупной кнопке разваливается. */
.ui-modal__close {
	position: absolute;
	top: 22px;
	right: 22px;
	z-index: 2;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 54px;
	height: 54px;
	border: 0;
	border-radius: 50%;
	background: var(--ui-accent);
	color: var(--ui-on-accent);
	cursor: pointer;
	transition: background-color var(--ui-base) var(--ui-ease),
	            transform var(--ui-turn) var(--ui-ease);
}

.ui-modal__close:hover {
	background: var(--ui-accent-hover);
	transform: rotate(90deg);
}

.ui-modal__close:active {
	background: var(--ui-accent-active);
	transform: rotate(90deg) scale(.94);
}

.ui-modal__close:focus-visible {
	outline: 2px solid var(--ui-accent);
	outline-offset: 3px;
}

.ui-modal__close svg {
	display: block;
	width: 24px;
	height: 24px;
}

.ui-modal__veil {
	position: fixed;
	inset: 0;
	z-index: 59;
	background: rgba(6, 16, 32, .45);
}

/* ---------------------------------------------------------------------------
   7. Полоса прокрутки внутри панелей

   Утилита: вешается на любой прокручиваемый список внутри панели —
   выпадашку, группу фильтра, подсказки поиска.

   Полосу самого модального окна не трогайте: там прокручивается вся форма,
   и широкая уместна.
   --------------------------------------------------------------------------- */

.ui-scroll {
	overflow-y: auto;
	-webkit-overflow-scrolling: touch;
	/* Прозрачная рамка отодвигает полосу от края: браузер ставит её
	   между padding-box и border-box. */
	border-right: 6px solid transparent;
	padding-right: 4px;
}

/* Дети прокручиваемой flex-колонки не должны сжиматься: иначе строки
   ужимаются под max-height вместо того, чтобы отдать себя прокрутке,
   и длинные названия налезают друг на друга. */
.ui-scroll > * {
	flex: 0 0 auto;
}

.ui-scroll::-webkit-scrollbar {
	width: var(--ui-scrollbar);
}

.ui-scroll::-webkit-scrollbar-track {
	background: var(--ui-surface);
	border-radius: var(--ui-pill);
	/* Дорожка не доходит до краёв — скругление угла остаётся видимым. */
	margin: 10px 0;
}

.ui-scroll::-webkit-scrollbar-thumb {
	background: var(--ui-line);
	border-radius: var(--ui-pill);
}

.ui-scroll::-webkit-scrollbar-thumb:hover {
	background: var(--ui-accent);
}

/* ---------------------------------------------------------------------------
   7a. Служебное

   Группа чекбоксов в форме — столбик, не пилюли: на референсе такие наборы
   идут тем же столбиком, что и остальные строки.
   Скрытый для глаз, но не для скринридера текст — заголовок панели фильтра,
   подпись у стрелки раскрытия.
   --------------------------------------------------------------------------- */

.ui-checks {
	display: flex;
	flex-direction: column;
	gap: 12px;
	margin-top: 10px;
}

.ui-visually-hidden {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	border: 0;
	overflow: hidden;
	clip: rect(0 0 0 0);
	clip-path: inset(50%);
	white-space: nowrap;
}

/* ---------------------------------------------------------------------------
   8. Мобильное
   --------------------------------------------------------------------------- */

@media (max-width: 767px) {
	:root {
		--ui-field-pad-x:   20px;
		--ui-field-pad-top: 24px;
		--ui-field-pad-bot: 12px;
		--ui-field-label:   20px;
	}

	/* 16px обязательны: на меньшем кегле Safari на iOS зумит страницу
	   при фокусе в поле и обратно не отматывает. */
	.ui-field__input,
	.ui-select__search {
		font-size: 16px;
	}

	/* Подписи длиннее поля и обрезались многоточием почти на середине */
	.ui-field > .ui-field__label {
		font-size: 14px;
	}

	.ui-modal {
		width: calc(100% - 24px);
		border-radius: 22px;
	}

	/* Подпись на телефоне 14px при поле 16px: на 15px она обрезалась
	   многоточием почти на середине. Токен --ui-field-label поднят до 20px:
	   при 18 подпись стояла на полтора пикселя выше середины поля, а глаз
	   видит строчные буквы ещё выше — подписи читались приподнятыми. */
	.ui-modal__head { padding: 22px 68px 16px 20px; }
	.ui-modal__title { font-size: 22px; }
	.ui-modal__body { margin: 12px 10px 14px 0; padding: 6px 14px 18px 20px; }
	.ui-modal__close { top: 14px; right: 14px; width: 46px; height: 46px; }

	/* Текст кнопки — всегда ОДНА строка. Поля 34px на 320 оставляли тексту
	   со стрелкой 164px, «Получить консультацию» переносилась уже на 375.
	   Поля 20px и запрет переноса: надпись до ~24 знаков встаёт от 320. */
	.ui-btn {
		width: 100%;
		padding: 0 20px;
		white-space: nowrap;
	}

	/* Согласие на ПД на телефоне — РОВНО ДВЕ СТРОКИ, строка = половина фразы:
	     Соглашаюсь с политикой обработки персональных данных
	     и даю согласие на обработку персональных данных.
	   Это служебная приписка, правило «не мельче 14px» на неё
	   не распространяется — читают её один раз.

	   Постоянный кегль две строки не держит: в сплошном потоке перенос
	   гуляет от ширины к ширине, фраза ложится то в две, то в три строки,
	   и в конце строки остаётся «и» или «с». Поэтому кегль считается
	   от ширины колонки: длинная половина встаёт в неё целиком.
	     --consent-em  ширина длинной половины в em В ШРИФТЕ САЙТА + 3%
	                   запаса (Safari рисует текст чуть шире). Замер —
	                   markup.md, «Согласие». 28.7 — Helvetica Neue Cyr.
	     100cqi        ширина label (он контейнер)
	     32px          квадрат 24 + зазор 8 — поменяли их, поменяйте число
	   Выше 12px кегль не растёт. Нижнего предела по сути нет (6px — от
	   вырожденных случаев): две строки ОБЯЗАТЕЛЬНЫ на любой ширине,
	   на 320 это ≈ 7.5px. Четыре строки на 320 заказчик отклонил.
	   Чтобы кегль на 320 был крупнее, на экранах уже 360 плита формы
	   ужимает внутренние поля до 16px (слой сайта).

	   Квадрат 24px — цель касания. Две строки ≈ высота квадрата,
	   поэтому квадрат стоит по середине обеих строк. */
	.ui-consent {
		align-items: center;
		gap: 8px;
		line-height: 1.4;
	}

	.ui-consent > span {
		font-size: clamp(6px, calc((100cqi - 32px) / var(--consent-em)), 12px);
	}

	.ui-consent input[type="checkbox"] {
		margin-top: 0;
	}

	.ui-consent__clause {
		display: block;
	}

}
