/* ============================================================================
   ui-kit.css — компоненты ДС v3 BunnySplit (префикс .bs-*). Только токены tokens.css.
   Решения владельца (20.10): контролы — пилюли одной высоты (кнопки, поля, списки);
   статусы — ступень 600 на мягком фоне + значок; дисплейный шрифт — только от 20px.
   Старые системы (.pp-btn, .btn-*, .pr-btn-*, .pp-input …) живут как есть и переводятся
   сюда по одной (шаги 3–6 плана редизайна).
   Порядок подключения: tokens.css → ui-kit.css (→ CSS страницы).
   ============================================================================ */

/* ── Кнопка ───────────────────────────────────────────────────────────────── */
.bs-btn{
  display:inline-flex; align-items:center; justify-content:center; gap:var(--sp-2);
  min-height:var(--ctl-md); padding:0 var(--sp-5);
  border:var(--bw-strong) solid transparent; border-radius:var(--rad-pill);
  font:600 var(--fs-sm)/1 var(--font); color:var(--ink); background:transparent;
  text-decoration:none; white-space:nowrap; cursor:pointer; position:relative;
  transition:background var(--dur) var(--ease), box-shadow var(--dur) var(--ease),
             transform var(--dur-spring) var(--ease-spring), border-color var(--dur) var(--ease), color var(--dur) var(--ease);
}
.bs-btn:hover:not(:disabled):not([aria-disabled="true"]){ transform:var(--btn-hover-grow); }   /* пружина (30.10): любая кнопка чуть растёт */
.bs-btn:active:not(:disabled):not([aria-disabled="true"]){ transform:scale(var(--press-scale)); transition-duration:var(--dur-fast); }   /* нажатие — сжатие, отпускается пружиной */
.bs-btn:focus-visible{ outline:none; box-shadow:var(--focus-ring); }
.bs-btn:disabled,.bs-btn[aria-disabled="true"]{ opacity:.45; cursor:not-allowed; transform:none; box-shadow:none; }
.bs-btn svg{ width:var(--icon-sm); height:var(--icon-sm); flex:none; }
.bs-btn--primary{ background:var(--grad-btn) border-box; color:var(--accent-ink); box-shadow:var(--shadow-btn); }   /* border-box: градиент под прозрачной рамкой, без полоски по краям пилюли */
.bs-btn--primary:hover:not(:disabled){ transform:var(--btn-hover-grow); }   /* рост от центра, не подскок (22.10) */
.bs-btn--primary:focus-visible{ box-shadow:var(--focus-ring), var(--shadow-btn); }
/* Недоступная главная — нейтральная плашка (--bg2, подпись --text-muted), а не «бледный градиент»
   (владелец 22.10, снимок 99: полупрозрачная заливка читалась как сбой). Причину — строкой .bs-field__hint рядом. */
.bs-btn--primary:disabled,.bs-btn--primary[aria-disabled="true"]{ background:var(--bg2); color:var(--text-muted); opacity:1; }
/* Второстепенные контролы — «белая поверхность» (решение владельца 22.10, вариант Б): фон --card,
   тонкая рамка --line2, мягкая тень --shadow-1 — как поиск маркетплейса. Одинаково у .bs-btn--secondary,
   .bs-seg (трек), .bs-filter, .bs-select--btn. Наведение у всех одно: рамка темнее (--line2 + 22% --ink).
   Шрифт 500, подпись --ink; 600 — только главная кнопка и ВЫБРАННОЕ. Выбранное = --accent-strong
   на --accent-soft, рамка --violet-100. Тень — var(--bs-raise): внутри карточек/окон её нет (ниже). */
.bs-btn--secondary{ background:var(--card); border-width:var(--bw); border-color:var(--line2); box-shadow:var(--bs-raise); font-weight:500; }
.bs-btn--secondary:hover:not(:disabled){ border-color:color-mix(in srgb, var(--ink) 22%, var(--line2)); }
/* выбранное состояние вторичной кнопки: «Фильтры ②», когда фильтры выбраны (.is-active), или
   кнопка-переключатель (aria-pressed="true"). Кнопке, что открывает окно, aria-pressed не ставить — только класс. */
.bs-btn--secondary.is-active,.bs-btn--secondary[aria-pressed="true"]{ background:var(--accent-soft); border-color:var(--violet-100); color:var(--accent-strong); font-weight:600; }
.bs-btn--secondary.is-active:hover:not(:disabled),.bs-btn--secondary[aria-pressed="true"]:hover:not(:disabled){ border-color:var(--violet-200); }
.bs-btn--ghost{ color:var(--ink2); }
.bs-btn--ghost:hover:not(:disabled){ background:var(--hover-fill); color:var(--ink); }   /* как у пунктов .bs-seg (22.10) */
/* --danger — необратимое действие (подтверждение «Удалить»): заливка красным, белый текст
   (решение владельца 22.10, 5.2 А). Тихое «Удалить» в строке списка — не сюда, а --ghost/--secondary. */
.bs-btn--danger{ background:var(--err-text); color:var(--on-accent); border-color:var(--err-text); }
.bs-btn--danger:hover:not(:disabled){ background:var(--rose-700); border-color:var(--rose-700); }
/* --tonal — «мягкий акцент» (решение 22.10, 7.1 Б): призыв ВНУТРИ карточки — «Вступить» в группу,
   «Подписаться», «Откликнуться». Заметнее серой secondary, тише главной; без тени. Уже вступили —
   обычная --secondary («Вы участник ✓»). */
.bs-btn--tonal{ background:var(--accent-soft); border-width:var(--bw); border-color:var(--violet-100); color:var(--accent-strong); font-weight:600; }
.bs-btn--tonal:hover:not(:disabled){ border-color:var(--violet-200); }
.bs-btn--tonal.is-loading::after{ border-color:var(--accent-strong) transparent var(--accent-strong) transparent; }
.bs-btn--growth{ background:var(--accent-soft); color:var(--violet-700); border-color:var(--violet-200); }
.bs-btn--growth:hover:not(:disabled){ background:var(--violet-600); color:var(--accent-ink); border-color:var(--violet-600); }
.bs-btn--sm{ min-height:var(--ctl-sm); padding:0 var(--sp-3); font-size:var(--fs-ctl); }
.bs-btn--lg{ min-height:var(--ctl-lg); padding:0 var(--sp-7); font-size:var(--fs-base); font-weight:700; }
/* Оптическая компенсация (владелец 22.10: «+ Заказ» — слева отступ кажется больше): у значка свои
   пустые поля внутри квадрата, поэтому ведущая иконка в кнопке с текстом сдвинута влево на --sp-1.
   Сдвигаем ИКОНКУ, а не отступ кнопки — работает при любых локальных padding (.tb-add и т.п.). */
:is(.bs-btn, .pp-btn):not(.bs-btn--icon):not(.pp-icon-btn) > :is(svg, .bs-ico):first-child{ margin-left:calc(-1 * var(--sp-1)); }   /* у кнопок-иконок (--icon) сдвига нет */
.bs-btn--block{ width:100%; }
/* --dashed: «+ Добавить …» (принтер, реакцию, блок, тег) — пунктирная рамка, акцентный текст. Не главное
   действие экрана, а приглашение дополнить список; добавлено в PR «кнопки» (21.10). */
.bs-btn--dashed{ background:transparent; color:var(--accent-text); border:var(--bw-strong) dashed var(--border-strong); }
.bs-btn--dashed:hover:not(:disabled){ border-color:var(--violet-600); background:var(--accent-soft); }
.bs-btn--icon{ padding:0; width:var(--ctl-md); }
.bs-btn--icon.bs-btn--sm{ width:var(--ctl-sm); }
.bs-btn--icon.bs-btn--lg{ width:var(--ctl-lg); }
.bs-btn.is-loading{ color:transparent !important; pointer-events:none; }
.bs-btn.is-loading::after{
  content:""; position:absolute; width:var(--icon-sm); height:var(--icon-sm); border-radius:50%;
  border:2px solid var(--accent-ink); border-color:var(--accent-ink) transparent var(--accent-ink) transparent;
  animation:bs-spin .8s linear infinite;
}
.bs-btn--secondary.is-loading::after,.bs-btn--ghost.is-loading::after{ border-color:var(--ink2) transparent var(--ink2) transparent; }
@keyframes bs-spin{ to{ transform:rotate(360deg); } }
/* карточка товара · кнопка покупки · 26.10 (вариант Е) — .bs-btn--buy: ТОЛЬКО действие в карточке товара
   («В корзину», «Скачать», «Заказать», «Выбрать размер»). Не главная кнопка страницы (та — --primary, одна
   на экран). Сплошная заливка бренда, белый текст и значок, без градиента и тени; высота обычная (44),
   600, пилюля. Фокус — общее кольцо .bs-btn (только с клавиатуры). Товар уже в корзине — .is-active
   (src/ui/cart-cta.js): мягкий фиолетовый фон, фиолетовый текст и галочка, клик открывает корзину. */
.bs-btn--buy{ background:var(--buy-bg); color:var(--buy-ink); }
.bs-btn--buy:hover:not(:disabled){ background:var(--buy-bg-hover); }
.bs-btn--buy:not(.is-active):active:not(:disabled){ background:var(--buy-bg-active); }
.bs-btn--buy:disabled,.bs-btn--buy[aria-disabled="true"]{ background:var(--bg2); color:var(--text-muted); opacity:1; }
.bs-btn--buy.is-active{ background:var(--buy-done-bg); border-width:var(--bw); border-color:var(--buy-done-line); color:var(--buy-done-ink); }
.bs-btn--buy.is-active:hover:not(:disabled){ background:var(--buy-done-bg); border-color:var(--buy-done-line-hover); }
.bs-btn--buy.is-loading::after{ border-color:var(--buy-ink) transparent var(--buy-ink) transparent; }
/* телефон (26.10, владелец: «на телефоне размер поменьше»): в узкой карточке — малая ступень 32 и кегль
   контрола; на тач-экране добирается до 40 тем же правилом, что .bs-btn--sm (тап-зона) */
@media (max-width:600px){ .bs-btn--buy{ min-height:var(--ctl-sm); padding:0 var(--sp-3); font-size:var(--fs-ctl); } }
@media (max-width:600px) and (pointer:coarse){ .bs-btn--buy{ min-height:40px; } }

/* ── Счётчик количества «− 1 +»: пилюля высотой кнопки, круглые кнопки внутри ──
   <div class="bs-stepper"><button class="bs-stepper__btn">−</button><span class="bs-stepper__val">1</span><button class="bs-stepper__btn">+</button></div>
   Размеры как у кнопок: md 44 (по умолчанию) и --sm 32 (строки корзины). */
.bs-stepper{ display:inline-flex; align-items:center; flex:none; min-height:var(--ctl-md); padding:2px;
  border:var(--bw-strong) solid var(--border-strong); border-radius:var(--rad-pill); background:var(--card); }
.bs-stepper__btn{ width:calc(var(--ctl-md) - 8px); height:calc(var(--ctl-md) - 8px); display:grid; place-items:center;
  border:0; border-radius:var(--rad-pill); background:none; color:var(--ink2); font:600 var(--fs-lg)/1 var(--font); cursor:pointer;
  transition:background var(--dur) var(--ease), color var(--dur) var(--ease); }
.bs-stepper__btn:hover:not(:disabled){ background:var(--bg2); color:var(--ink); }
.bs-stepper__btn:focus-visible{ outline:none; box-shadow:var(--focus-ring); }
.bs-stepper__btn:disabled{ opacity:.4; cursor:not-allowed; }
.bs-stepper__val{ min-width:32px; text-align:center; font:700 var(--fs-sm) var(--font); color:var(--ink); font-variant-numeric:tabular-nums; }
.bs-stepper--sm{ min-height:var(--ctl-sm); padding:1px; }
.bs-stepper--sm .bs-stepper__btn{ width:26px; height:26px; font-size:var(--fs-base); }
.bs-stepper--sm .bs-stepper__val{ min-width:24px; }
.bs-stepper--lg{ min-height:var(--ctl-lg); }   /* рядом с главной кнопкой --lg (страница товара, 23.10): одна высота 52 */
.bs-stepper--lg .bs-stepper__btn{ width:calc(var(--ctl-lg) - 12px); height:calc(var(--ctl-lg) - 12px); }
.bs-stepper--lg .bs-stepper__val{ min-width:36px; font-size:var(--fs-base); }

/* ── Поле: пилюля той же высоты, что кнопка ──────────────────────────────── */
.bs-field{ display:flex; flex-direction:column; gap:var(--sp-1); min-width:0; }
/* ПРАВИЛО БЛИЗОСТИ: подпись→поле 4–6px, поле→подсказка 8px, между группами полей — не меньше --sp-5 (20px).
   Контейнер формы задаёт gap:var(--sp-5), чтобы подсказка не «прилипала» к следующему полю (старые .pp-field — margin-bottom --sp-5). */
.bs-field__label{ font:600 var(--fs-sm)/var(--lh-tight) var(--font); color:var(--ink); }
.bs-field__label .req{ color:var(--err-ink); margin-left:2px; }
/* Подсказка и ошибка — по ОДНОЙ левой линии с подписью поля, отступ от поля --sp-2 (владелец 22.10:
   было — вровень с текстом внутри пилюли, padding 16, и 4px от поля: читалось как «не выровнено») */
.bs-field__hint{ font:400 var(--fs-xs)/var(--lh-normal) var(--font); color:var(--text-muted); padding-left:0; margin-top:var(--sp-2); }
/* подсказка-кнопка: строка-причина у неактивной кнопки (клик ведёт к галке) — вид подсказки, без рамки кнопки.
   --inline — слева от кнопки в одной строке с ней (ревью мастера A24: было cssText в seller-offer.js) */
button.bs-field__hint{ display:block; margin-top:0; background:none; border:0; padding:0; cursor:pointer; text-align:left; }
button.bs-field__hint--inline{ margin-right:auto; flex:1 1 auto; min-width:0; font-weight:600; }
/* вводный абзац над полями формы (окно «Договор мастера» и др.) — крупнее подсказки, тише текста */
.bs-field__lead{ margin:0; font:400 var(--fs-sm)/var(--lh-normal) var(--font); color:var(--ink2); }
/* текст ошибки — под полем, со значком (svg первым ребёнком): «⚠ Укажите цену больше нуля» */
.bs-field__error{ display:flex; align-items:center; gap:var(--sp-1); font:500 var(--fs-xs)/var(--lh-normal) var(--font); color:var(--err-text); padding-left:0; margin-top:var(--sp-2); }
/* в .bs-field (колонка с gap --sp-1) итог тот же 8px */
.bs-field > :is(.bs-field__hint, .bs-field__error){ margin-top:var(--sp-1); }
.bs-field__error svg{ width:14px; height:14px; flex:none; }
.bs-field__error[hidden]{ display:none; }   /* display:flex бьёт UA-правило [hidden] (окно жалобы, редактор записи — 05.11) */
/* пометка в подписи: «— необязательно», «— чем лучше печатать» */
.bs-field__opt{ font-weight:400; color:var(--text-muted); }
/* подпись вне .bs-field (legend, подпись над группой полей) — своей строкой, до поля --sp-1-5 */
.bs-field__label--block{ display:block; margin:0 0 var(--sp-1-5); padding:0; }
/* поле в обычном потоке (контейнер без gap): до следующей группы --sp-5. В .bs-form отступ даёт gap. */
.bs-field--stack{ margin-bottom:var(--sp-5); }
.bs-form .bs-field--stack{ margin-bottom:0; }
/* ряд таких полей: на телефоне отступ между ними даёт сам --stack, gap строк не добавляем */
:not(.bs-form) > .bs-form__row:has(> .bs-field--stack){ row-gap:0; }
.bs-field > .bs-field__label--block{ margin-bottom:0; }
.bs-field[hidden]{ display:none; }   /* display:flex бьёт UA-правило [hidden] */
/* колонка .bs-field растягивает детей: сегмент и кнопка остаются по содержимому, как в строке */
.bs-field > :is(.bs-seg, .bs-btn:not(.bs-btn--block)){ align-self:flex-start; }

/* ── Форма: столбец полей и ряд из 2–3 полей ──────────────────────────────────────────────────
   .bs-form — поля столбцом, между группами --sp-5 (правило близости выше). .bs-form__row — 2 поля
   в ряд (--3 — три), на телефоне ≤560 двойной ряд встаёт столбцом. [hidden] прячет ряд (display:grid
   бьёт UA-правило). .bs-form__inline — поле + кнопка одной высоты строкой, узко — кнопка ниже.
   <div class="bs-form">
     <div class="bs-form__row"><div class="bs-field">…</div><div class="bs-field">…</div></div>
     <div class="bs-field">…</div></div> */
.bs-form{ display:flex; flex-direction:column; gap:var(--sp-5); min-width:0; }
.bs-form[hidden]{ display:none; }
.bs-form__row{ display:grid; grid-template-columns:repeat(2, minmax(0, 1fr)); gap:var(--sp-5) var(--sp-3); align-items:start; }
.bs-form__row--3{ grid-template-columns:repeat(3, minmax(0, 1fr)); column-gap:var(--sp-2); }
.bs-form__row[hidden]{ display:none; }
/* --align — поля ряда «подпись → поле → подсказка» на общих строках (subgrid): подпись в 2 строки
   не сдвигает поле соседа вниз. Только для полей ровно из этих трёх частей. */
.bs-form__row--align{ grid-template-rows:repeat(3, auto); }
.bs-form__row--align > .bs-field{ display:grid; grid-row:span 3; grid-template-rows:subgrid; row-gap:var(--sp-1); align-content:start; }
.bs-form__row--align > .bs-field > .bs-field__label{ align-self:end; }
@media (max-width:560px){ .bs-form__row:not(.bs-form__row--3){ grid-template-columns:minmax(0, 1fr); grid-template-rows:none; } }
.bs-form__inline{ display:flex; flex-wrap:wrap; gap:var(--sp-2); align-items:center; }
.bs-form__inline > .bs-input{ flex:1 1 160px; min-width:0; }
.bs-form__inline > .bs-btn{ flex:none; }
/* Поле (решение владельца 22.10): 2.1 Б — белое, тонкая рамка 1px --line-field, без тени; наведение —
   рамка --ink2. 2.2 А — фокус: рамка --violet-600 + мягкий ореол --focus-ring-soft (без белого
   зазора); ошибка — рамка --err-text, в фокусе ореол --focus-ring-err. Тот же вид у .pp-input (pop.css)
   и «Выбора» (.ts-wrapper.bs-select ниже). Кнопки/ссылки остаются на резком --focus-ring. */
.bs-input{
  width:100%; min-height:var(--ctl-md); padding:0 var(--sp-4);
  border:var(--bw) solid var(--line-field); border-radius:var(--rad-pill);
  background:var(--card); color:var(--ink); font:400 var(--fs-sm) var(--font);
  transition:border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.bs-input::placeholder{ color:var(--text-muted); }
.bs-input:hover:not(:disabled):not([readonly]):not(:focus){ border-color:var(--ink2); }
.bs-input:focus,.bs-input:focus-visible{ outline:none; border-color:var(--violet-600); box-shadow:var(--focus-ring-soft); }
.bs-input[aria-invalid="true"]{ border-color:var(--err-text); }
.bs-input[aria-invalid="true"]:focus{ border-color:var(--err-text); box-shadow:var(--focus-ring-err); }
.bs-input:disabled{ background:var(--bg2); color:var(--text-muted); border-color:var(--line2); cursor:not-allowed; }
.bs-input[readonly]{ background:var(--bg2); border-color:var(--line2); }
.bs-input--sm{ min-height:var(--ctl-sm); font-size:var(--fs-xs); padding:0 var(--sp-3); }
/* Многострочное поле растёт само по мере набора (field-sizing), браузерного «уголка» растягивания нет —
   он залезал на скруглённую рамку (владелец 22.10). Где field-sizing не поддерживается — обычная высота
   с прокруткой; потолок высоты — чтобы длинный текст не выталкивал форму за экран. */
textarea.bs-input{ border-radius:var(--rad-xl); padding:var(--sp-3) var(--sp-4); min-height:96px; max-height:60vh;
  resize:none; field-sizing:content; line-height:var(--lh-normal); }
.bs-input-wrap{ position:relative; display:flex; align-items:center; }
.bs-input-wrap > svg{ position:absolute; left:var(--sp-4); width:var(--icon-sm); height:var(--icon-sm); color:var(--text-muted); pointer-events:none; }
.bs-input-wrap > svg + .bs-input{ padding-left:calc(var(--sp-4) + var(--icon-sm) + var(--sp-2)); }
.bs-input-wrap > .bs-input-suffix{ position:absolute; right:var(--sp-4); color:var(--text-muted); font:500 var(--fs-sm) var(--font); pointer-events:none; }
.bs-input-wrap > .bs-input:has(+ .bs-input-suffix){ padding-right:calc(var(--sp-4) + var(--sp-6)); }

/* ── Поиск (решение владельца 22.10, группа 8) — один компонент на весь сайт ─────────────
   8.1 Б: поиск — элемент ПАНЕЛИ, а не поле анкеты: «белая поверхность» как .bs-btn--secondary
   (--card, рамка 1px --line2, тень --bs-raise — внутри карточек/окон гаснет), пилюля 44 (--sm 32).
   ВСЕГДА лупа слева и крестик «Очистить поиск» справа — крестик виден, только когда в поле есть текст
   (:placeholder-shown, поэтому placeholder обязателен). Фокус — как у полей: рамка --violet-600 +
   мягкий ореол --focus-ring-soft. Плейсхолдер --text-muted. На тач-экране кегль 16 — iOS не зумит.
   8.2 А: --action — кнопка-действие ВНУТРИ пилюли слева («Каталог» на маркетплейсе:
   .bs-btn.bs-btn--primary.bs-btn--sm.bs-search__action), дальше лупа и поле.
   8.3 А: --collapsed — для узких панелей (CRM, группа): свёрнут в круглую кнопку-лупу 44 (--sm 32);
   нажатие ставит фокус в поле и разворачивает его; развёрнут, пока в поле фокус или текст.
   Крестик в развёрнутом пустом — «Свернуть поиск»; Esc очищает, на пустом — сворачивает.
   Разметка — searchHTML() из src/ui/ui-search.js; крестик и Esc — wireSearch() (там же).
   <div class="bs-search" role="search">
     <label class="bs-search__field">{icon('search')}<input class="bs-search__input" type="search"
       placeholder="Поиск по названию" aria-label="Поиск по названию"></label>
     <button class="bs-search__clear" type="button" aria-label="Очистить поиск">{icon('x')}</button>
   </div>
   Ширину задаёт страница (flex/width на своём классе рядом с .bs-search). */
.bs-search{ position:relative; display:flex; align-items:center; min-width:0; min-height:var(--ctl-md);
  background:var(--card); border:var(--bw) solid var(--line2); border-radius:var(--rad-pill); box-shadow:var(--bs-raise);
  transition:border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease); }
.bs-search:hover{ border-color:color-mix(in srgb, var(--ink) 22%, var(--line2)); }
/* фокус в поле (не на кнопке-действии и не на крестике — у них своё резкое кольцо) */
.bs-search:focus-within:not(:has(.bs-search__action:focus, .bs-search__clear:focus)){ border-color:var(--violet-600); box-shadow:var(--focus-ring-soft); }
.bs-search__field{ flex:1 1 auto; align-self:stretch; display:flex; align-items:center; gap:var(--sp-2); min-width:0;
  padding:0 var(--sp-4); color:var(--ink2); cursor:text; }
.bs-search__field > svg{ width:var(--icon-sm); height:var(--icon-sm); flex:none; }
.bs-search__input{ flex:1 1 auto; width:100%; min-width:0; margin:0; padding:0; border:0; border-radius:0; background:transparent;
  -webkit-appearance:none; appearance:none; outline:none; box-shadow:none;
  font:400 var(--fs-sm)/var(--lh-tight) var(--font); color:var(--ink); }
.bs-search__input::placeholder{ color:var(--text-muted); opacity:1; }
.bs-search__input::-webkit-search-decoration,
.bs-search__input::-webkit-search-cancel-button,
.bs-search__input::-webkit-search-results-button{ -webkit-appearance:none; appearance:none; display:none; }
.bs-search__clear{ flex:none; display:none; place-items:center; width:var(--ctl-sm); height:var(--ctl-sm);
  margin-right:calc((var(--ctl-md) - var(--ctl-sm)) / 2 - var(--bw)); padding:0; border:0; border-radius:var(--rad-pill);
  background:transparent; color:var(--ink2); cursor:pointer;
  transition:background var(--dur) var(--ease), color var(--dur) var(--ease); }
.bs-search__clear svg{ width:var(--icon-sm); height:var(--icon-sm); }
.bs-search__clear:hover{ background:var(--bg2); color:var(--ink); }
.bs-search__clear:focus-visible{ outline:none; box-shadow:var(--focus-ring); }
.bs-search:has(.bs-search__input:not(:placeholder-shown)) .bs-search__clear,
.bs-search--collapsed .bs-search__clear{ display:grid; }
.bs-search:has(.bs-search__input:not(:placeholder-shown)) .bs-search__field,
.bs-search--collapsed .bs-search__field{ padding-right:var(--sp-1); }
.bs-search__clear[hidden]{ display:none !important; }   /* страница прячет крестик сама (старый JS) — уважаем */
/* --sm: 32 — ряды фильтров, в пару к .bs-btn--sm */
.bs-search--sm{ min-height:var(--ctl-sm); }
.bs-search--sm .bs-search__field{ padding-left:var(--sp-3); }
.bs-search--sm .bs-search__input{ font-size:var(--fs-ctl); }
.bs-search--sm .bs-search__clear{ width:calc(var(--ctl-sm) - 2 * var(--sp-1)); height:calc(var(--ctl-sm) - 2 * var(--sp-1));
  margin-right:calc(var(--sp-1) - var(--bw)); }
/* --action (8.2 А): кнопка слева внутри пилюли — отступ до края как у крестика, без своей тени (часть поля) */
.bs-search--action{ padding-left:calc((var(--ctl-md) - var(--ctl-sm)) / 2 - var(--bw)); }
.bs-search__action{ flex:none; box-shadow:none; }
/* тач (23.10, «неравные отступы у Каталога»): общее правило pointer:coarse растит --sm до 40 —
   в пилюле 44 это давало 2 сверху/снизу против 6 слева. Видимая кнопка остаётся 32 (отступ ровный
   со всех сторон), зона касания добирается до краёв пилюли невидимым ::before. */
@media (pointer:coarse){
  .bs-search .bs-search__action{ position:relative; min-height:var(--ctl-sm); }
  .bs-search .bs-search__action::before{ content:""; position:absolute; inset:calc((var(--ctl-sm) - var(--ctl-md)) / 2) 0 calc((var(--ctl-sm) - var(--ctl-md)) / 2) calc((var(--ctl-sm) - var(--ctl-md)) / 2); }
}
.bs-search--action .bs-search__field{ padding-left:var(--sp-3); }
/* --collapsed (8.3 А): свёрнут = нет фокуса внутри И поле пустое → круг-лупа (вид .bs-btn--secondary --icon) */
.bs-search--collapsed:not(:focus-within):has(.bs-search__input:placeholder-shown){ flex:none; width:var(--ctl-md); min-width:var(--ctl-md); cursor:pointer; }
.bs-search--collapsed.bs-search--sm:not(:focus-within):has(.bs-search__input:placeholder-shown){ width:var(--ctl-sm); min-width:var(--ctl-sm); }
.bs-search--collapsed:not(:focus-within):has(.bs-search__input:placeholder-shown) .bs-search__field{
  justify-content:center; gap:0; padding:0; color:var(--ink); cursor:pointer; }
.bs-search--collapsed:not(:focus-within):has(.bs-search__input:placeholder-shown) .bs-search__input{ flex:0 0 0; width:0; opacity:0; }
.bs-search--collapsed:not(:focus-within):has(.bs-search__input:placeholder-shown) .bs-search__clear{ display:none; }
/* iOS зумит страницу при фокусе в поле с кеглем < 16px — на тач-экране и телефоне кегль 16 */
@media (pointer:coarse), (max-width:599px){ .bs-search__input,.bs-search--sm .bs-search__input{ font-size:var(--fs-base); } }

/* ── Список: нативный select в форме поля, своя стрелка ───────────────────── */
select.bs-input{
  -webkit-appearance:none; appearance:none; cursor:pointer;
  padding-right:calc(var(--sp-4) + var(--icon-sm) + var(--sp-2));
  background:var(--card) var(--icon-chevron-down) no-repeat right var(--sp-4) center/var(--icon-sm) var(--icon-sm);
}

/* ── Чекбокс, радио, тумблер (нативные input, оформлены токенами) ─────────── */
.bs-check,.bs-radio,.bs-switch{ display:inline-flex; align-items:center; gap:var(--sp-3); min-height:var(--ctl-md); cursor:pointer; font:400 var(--fs-sm) var(--font); color:var(--ink); }
.bs-check input,.bs-radio input{
  -webkit-appearance:none; appearance:none; margin:0; flex:none; width:20px; height:20px;
  border:var(--bw) solid var(--line-field); background:var(--card); display:grid; place-content:center;
  transition:background var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}
.bs-check input{ border-radius:var(--rad-xs); }
.bs-radio input{ border-radius:50%; }
.bs-check input::before{ content:""; width:12px; height:12px; background:var(--accent-ink); -webkit-mask:var(--icon-check) center/contain no-repeat; mask:var(--icon-check) center/contain no-repeat; transform:scale(0); transition:transform var(--dur-fast) var(--ease-bounce); }
.bs-radio input::before{ content:""; width:10px; height:10px; border-radius:50%; background:var(--accent-ink); transform:scale(0); transition:transform var(--dur-fast) var(--ease-bounce); }
.bs-check input:checked,.bs-radio input:checked{ background:var(--violet-600); border-color:var(--violet-600); }
.bs-check input:checked::before,.bs-radio input:checked::before{ transform:scale(1); }
.bs-check input:indeterminate{ background:var(--violet-600); border-color:var(--violet-600); }
.bs-check input:indeterminate::before{ -webkit-mask:none; mask:none; height:2px; transform:scale(1); }
.bs-check input:hover:not(:checked):not(:disabled),.bs-radio input:hover:not(:checked):not(:disabled){ border-color:var(--ink2); }
.bs-check input:focus-visible,.bs-radio input:focus-visible,.bs-switch input:focus-visible{ outline:none; box-shadow:var(--focus-ring); }
.bs-check input[aria-invalid="true"]{ border-color:var(--err-text); }
.bs-check:has(input:disabled),.bs-radio:has(input:disabled),.bs-switch:has(input:disabled){ opacity:.45; cursor:not-allowed; }
/* согласие длинным текстом (оферта, политика, рассылка): галка по первой строке, текст переносится,
   ссылки — 600 --ink. Одна разметка для регистрации и договора мастера (пачка 1, п.2.6). */
/* плотный список выбора (фильтры в поповере, ~10 пунктов): строка 32 вместо 44 (28.10) */
.bs-check--sm,.bs-radio--sm{ min-height:var(--ctl-sm); gap:var(--sp-2); }
.bs-check--long{ display:flex; align-items:flex-start; min-height:0; line-height:var(--lh-normal); color:var(--ink2); }
.bs-check--long a{ font-weight:600; color:var(--ink); }
/* тумблер (решение 22.10, 2.4 Б): выкл — дорожка --gray-200 без рамки, белый кружок с тенью;
   вкл — --violet-600. Чекбокс/радио — рамка 1px --line-field (как поле), выбранное --violet-600. */
.bs-switch input{
  -webkit-appearance:none; appearance:none; margin:0; flex:none; position:relative; cursor:pointer;
  width:46px; height:28px; border-radius:var(--rad-pill); background:var(--control-track); border:0;
  transition:background var(--dur) var(--ease);
}
.bs-switch input::before{ content:""; position:absolute; top:3px; left:3px; width:22px; height:22px; border-radius:50%;
  background:var(--card); box-shadow:var(--shadow-knob); transition:transform var(--dur) var(--ease-bounce);
  -webkit-mask:none; mask:none; transform:none; }   /* снять «галочку» общего правила чекбоксов (:where ниже) */
.bs-switch input:hover:not(:checked):not(:disabled){ background:var(--gray-300); }
.bs-switch input:checked{ background:var(--violet-600); }
.bs-switch input:checked::before{ transform:translateX(18px); }
.bs-switch--sm input{ width:36px; height:22px; }
.bs-switch--sm input::before{ width:16px; height:16px; }
.bs-switch--sm input:checked::before{ transform:translateX(14px); }

/* ── Сегмент: пилюля в пилюле (одно правило, раскладку задаёт страница) ────── */
/* трек — «белая поверхность» (см. .bs-btn--secondary); отступ внутри уменьшен на рамку → высота трека та же 44 */
.bs-seg{ display:inline-flex; padding:calc(var(--sp-1) - var(--bw)); gap:var(--sp-1); background:var(--card); border:var(--bw) solid var(--line2);
  box-shadow:var(--bs-raise); border-radius:var(--rad-pill); max-width:100%; overflow-x:auto; scrollbar-width:none;
  transition:border-color var(--dur) var(--ease); }
.bs-seg:hover{ border-color:color-mix(in srgb, var(--ink) 22%, var(--line2)); }
.bs-seg button,.bs-seg label{
  min-height:calc(var(--ctl-md) - 2 * var(--sp-1)); padding:0 var(--sp-4); border:0; border-radius:var(--rad-pill);
  background:transparent; color:var(--ink); font:500 var(--fs-sm) var(--font); cursor:pointer; white-space:nowrap;
  display:inline-flex; align-items:center; gap:var(--sp-1-5); transition:background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.bs-seg button:hover:not([aria-pressed="true"]):not([aria-selected="true"]):not([aria-checked="true"]),.bs-seg label:hover:not(:has(input:checked)){ background:var(--hover-fill); }
/* выбранный пункт — мягкий акцент (как нажатый фильтр), не белая «таблетка».
   7.3 Б (решение 22.10): у пунктов, что «жирнеют» при выборе (.bs-seg, .bs-filter, .bs-tabs__item),
   ширина НЕ должна прыгать. Приём без смены разметки: вес остаётся 500, жирность выбранного рисует
   обводка глифа -webkit-text-stroke (визуально ≈600, метрики текста те же) — соседние пункты не
   сдвигаются. Во всех движках (Chrome/Safari/Firefox понимают -webkit-префикс). */
.bs-seg button[aria-pressed="true"],.bs-seg button[aria-selected="true"],.bs-seg button[aria-checked="true"],.bs-seg label:has(input:checked){ background:var(--accent-soft); color:var(--accent-strong); -webkit-text-stroke:var(--bs-bold-stroke) currentColor; }
.bs-seg input{ position:absolute; opacity:0; pointer-events:none; }
.bs-seg button:focus-visible,.bs-seg label:has(input:focus-visible){ outline:none; box-shadow:var(--focus-ring); }
.bs-seg--sm button,.bs-seg--sm label{ min-height:calc(var(--ctl-sm) - 2 * var(--sp-1)); padding:0 var(--sp-3); font-size:var(--fs-xs); }
/* палец (ревью C24): малый сегмент («Приоритет» в окне заказа) был 24 px — на тач-экране сегмент в рост
   обычного контрола (--ctl-md = 44 на coarse), чтобы не промахиваться */
@media (pointer:coarse){ .bs-seg--sm button,.bs-seg--sm label{ min-height:calc(var(--ctl-md) - 2 * var(--sp-1)); } }

/* ── Вкладки РАЗДЕЛОВ страницы (подчёркивание) — решение владельца 22.10, 4.1 Б ──────────
   «Где я» на странице: Лента / Группы / Люди, Товары / Заказы / Отзывы. Переключение ВЫДАЧИ
   (что показать в списке) — не сюда, а .bs-seg. Строка с нижней линией 1px --line2; пункт — текст
   --ink 500, выбранный — --accent-strong + подчёркивание 2px --violet-600 (жирность — обводкой, ширина
   не прыгает, см. .bs-seg). Счётчик внутри — .bs-count. На узком экране ряд листается вбок, край,
   за которым есть ещё, затухает (CSS scroll-timeline; где не поддерживается — просто прокрутка).
   <nav class="bs-tabs" aria-label="Разделы"><a class="bs-tabs__item" href="…" aria-current="page">Лента</a>…</nav>
   <div class="bs-tabs" role="tablist"><button class="bs-tabs__item" role="tab" aria-selected="true">Товары <span class="bs-count">24</span></button>…</div> */
.bs-tabs{ display:flex; gap:var(--sp-6); margin:0 0 var(--sp-4); box-shadow:inset 0 calc(-1 * var(--bw)) 0 var(--line2);
  overflow-x:auto; overflow-y:hidden; scrollbar-width:none; }
.bs-tabs::-webkit-scrollbar{ display:none; }
.bs-tabs__item,.bs-tabs > button{ position:relative; flex:none; display:inline-flex; align-items:center; gap:var(--sp-1-5);
  min-height:var(--ctl-md); padding:0; border:0; background:none; cursor:pointer; text-decoration:none; white-space:nowrap;
  color:var(--ink); font:500 var(--fs-sm)/1 var(--font); transition:color var(--dur) var(--ease); }
.bs-tabs__item:hover,.bs-tabs > button:hover{ color:var(--accent-strong); }
.bs-tabs__item:is([aria-selected="true"],[aria-current]:not([aria-current="false"]),.is-active),
.bs-tabs > button[aria-selected="true"]{ color:var(--accent-strong); -webkit-text-stroke:var(--bs-bold-stroke) currentColor; }
.bs-tabs__item:is([aria-selected="true"],[aria-current]:not([aria-current="false"]),.is-active)::after,
.bs-tabs > button[aria-selected="true"]::after{ content:""; position:absolute; left:0; right:0; bottom:0; height:2px;
  border-radius:var(--rad-pill); background:var(--violet-600); }
.bs-tabs__item:focus-visible,.bs-tabs > button:focus-visible{ outline:none; box-shadow:var(--focus-ring); border-radius:var(--rad-xs); }
.bs-tabs .count{ margin-left:var(--sp-1); color:var(--text-muted); font-weight:500; }
@media (max-width:599px){ .bs-tabs{ gap:var(--sp-5); } }
/* затухание края: маска только пока есть куда листать (scroll-timeline; ds-ok — маска, не цвет).
   То же правило у сегмента .bs-seg (ревью главной 23.10: на телефоне трек обрезался «3D-об» без
   подсказки, что ряд листается) — одно поведение у всех листаемых рядов ДС. */
@supports (animation-timeline: scroll()){
  .bs-tabs,.bs-seg{ --bs-fade-l:0px; --bs-fade-r:0px;
    -webkit-mask-image:linear-gradient(to right, transparent, black var(--bs-fade-l), black calc(100% - var(--bs-fade-r)), transparent);   /* ds-ok: маска, не цвет */
            mask-image:linear-gradient(to right, transparent, black var(--bs-fade-l), black calc(100% - var(--bs-fade-r)), transparent);   /* ds-ok: маска, не цвет */
    animation:bs-tabs-fade linear both; animation-timeline:scroll(self inline); }
  /* 23.10: доводка активной вкладки в видимость (scrollIntoView 'nearest') оставляет запас под
     затухание — иначе вкладка в середине ряда встаёт впритык к краю и гаснет («Адрес отправк…»). */
  .bs-tabs,.bs-seg{ scroll-padding-inline:var(--sp-8); }
}
@property --bs-fade-l{ syntax:'<length>'; inherits:false; initial-value:0px; }
@property --bs-fade-r{ syntax:'<length>'; inherits:false; initial-value:0px; }
@keyframes bs-tabs-fade{ 0%{ --bs-fade-l:0px; --bs-fade-r:var(--sp-8); } 8%,92%{ --bs-fade-l:var(--sp-8); --bs-fade-r:var(--sp-8); } 100%{ --bs-fade-l:var(--sp-8); --bs-fade-r:0px; } }

/* ── Метка (статичная, 5 тонов, значок), фильтр (интерактивный), тег (ссылка) ─ */
.bs-badge{ display:inline-flex; align-items:center; gap:var(--sp-1); height:24px; padding:0 var(--sp-2); border-radius:var(--rad-pill); font:600 var(--fs-xs)/1 var(--font); background:var(--bg2); color:var(--ink2); white-space:nowrap; }
.bs-badge svg{ width:14px; height:14px; flex:none; }
/* длинная подпись (название заказа, 23.10): метка не шире строки, текст в __t режется многоточием */
.bs-badge{ max-width:100%; }
.bs-badge__t{ min-width:0; overflow:hidden; text-overflow:ellipsis; }
/* статусы (решение 22.10, 3.1 А): мягкая пилюля 24 — фон -soft, текст -text, 600 --fs-xs; нейтральный — --bg2/--ink2 */
.bs-badge--accent{ background:var(--accent-soft); color:var(--accent-strong); }
.bs-badge--ok{ background:var(--ok-soft); color:var(--ok-text); }
.bs-badge--warn{ background:var(--warn-soft); color:var(--warn-text); }
.bs-badge--err{ background:var(--err-soft); color:var(--err-text); }
/* ── Метка поверх медиа (фото товара, кадр, превью) — этап 3, 29.10. Светлый скрим с размытием
   и тенью: читается на любом фото. Тон (--accent/--ok/--warn/--err) меняет только цвет текста.
   --solid — сплошная заливка тона (−N%, «По артикулу», «Товар недели»): важное, что должно кричать.
   --dark — поверх тёмной сцены (лайтбокс, камера, кадр редактора). --sm — 20 вместо 24 (ряд меток
   на маленькой карточке). Положение (угол, отступ) задаёт место: .bs-badge--media.свой{position:…}.
   <span class="bs-badge bs-badge--media bs-badge--sm">STL</span> · <span class="bs-badge bs-badge--solid bs-badge--err">−20%</span> */
.bs-badge--media{ background:color-mix(in srgb, var(--card) 90%, transparent); color:var(--ink);
  -webkit-backdrop-filter:blur(6px); backdrop-filter:blur(6px); box-shadow:var(--shadow-1); }
.bs-badge--media.bs-badge--accent{ color:var(--accent-strong); }
.bs-badge--media.bs-badge--ok{ color:var(--ok-text); }
.bs-badge--media.bs-badge--warn{ color:var(--warn-text); }
.bs-badge--media.bs-badge--err{ color:var(--err-text); }
.bs-badge--solid{ background:var(--accent-strong); color:var(--on-accent); box-shadow:var(--shadow-1); }
.bs-badge--solid.bs-badge--ok{ background:var(--ok-text); color:var(--on-accent); }
.bs-badge--solid.bs-badge--warn{ background:var(--warn); color:var(--ink); }
.bs-badge--solid.bs-badge--err{ background:var(--err-text); color:var(--on-accent); }
.bs-badge--dark{ background:color-mix(in srgb, var(--ink) 62%, transparent); color:var(--on-accent);
  -webkit-backdrop-filter:blur(8px); backdrop-filter:blur(8px); }
.bs-badge--sm{ height:20px; padding:0 var(--sp-1-5); font-size:var(--fs-2xs); }
.bs-badge--sm svg{ width:var(--icon-xs); height:var(--icon-xs); }
.bs-filter{
  display:inline-flex; align-items:center; gap:var(--sp-1); min-height:var(--ctl-sm); padding:0 var(--sp-4); border-radius:var(--rad-pill);
  border:var(--bw) solid var(--line2); background:var(--card); box-shadow:var(--bs-raise); color:var(--ink); font:500 var(--fs-sm) var(--font); cursor:pointer;
  position:relative; transition:background var(--dur) var(--ease), border-color var(--dur) var(--ease), color var(--dur) var(--ease);
}
.bs-filter::before{ content:""; position:absolute; inset:-6px 0; }
.bs-filter:hover{ border-color:color-mix(in srgb, var(--ink) 22%, var(--line2)); }
.bs-filter[aria-pressed="true"]{ background:var(--accent-soft); border-color:var(--violet-100); color:var(--accent-strong); -webkit-text-stroke:var(--bs-bold-stroke) currentColor; }   /* жирность без сдвига — см. .bs-seg */
.bs-filter[aria-pressed="true"]:hover{ border-color:var(--violet-200); }
.bs-filter > .tick{ display:none; width:14px; height:14px; background:currentColor; -webkit-mask:var(--icon-check) center/contain no-repeat; mask:var(--icon-check) center/contain no-repeat; }
.bs-filter[aria-pressed="true"] > .tick{ display:inline-block; }
.bs-filter:focus-visible{ outline:none; box-shadow:var(--focus-ring); }
.bs-filter .count{ color:var(--text-muted); font-weight:500; }
/* пачка 3 · Сообщество · 23.10 — ряд быстрых фильтров .bs-frow (категории групп): одна строка .bs-filter,
   на узком экране листается вбок, край, за которым есть ещё, затухает — как у .bs-tabs / .bs-seg.
   <div class="bs-frow" role="group" aria-label="Категория"><button class="bs-filter" aria-pressed="true">Все</button>…</div> */
.bs-frow{ display:flex; gap:var(--sp-2); overflow-x:auto; overflow-y:hidden; scrollbar-width:none; padding:var(--sp-1) 0; }
.bs-frow::-webkit-scrollbar{ display:none; }
.bs-frow > .bs-filter{ flex:none; white-space:nowrap; }
@supports (animation-timeline: scroll()){
  .bs-frow{ --bs-fade-l:0px; --bs-fade-r:0px;
    -webkit-mask-image:linear-gradient(to right, transparent, black var(--bs-fade-l), black calc(100% - var(--bs-fade-r)), transparent);   /* ds-ok: маска, не цвет */
            mask-image:linear-gradient(to right, transparent, black var(--bs-fade-l), black calc(100% - var(--bs-fade-r)), transparent);   /* ds-ok: маска, не цвет */
    animation:bs-tabs-fade linear both; animation-timeline:scroll(self inline); }
}
/* ── Образец цвета · .bs-swatch (страница товара, 23.10): круг 32 с цветом варианта (--swatch), выбранный —
   кольцо акцента + галочка; светлые цвета видны благодаря тонкой внутренней обводке. Подпись — рядом
   («Цвет: Белый»), у кнопки — aria-label. Не-цветовые варианты — .bs-filter.
   <button class="bs-swatch" aria-pressed="true" aria-label="Белый" style="--swatch:{цвет варианта}"></button> */
.bs-swatch{ position:relative; flex:none; width:var(--ctl-sm); height:var(--ctl-sm); padding:0; border:0; border-radius:50%; cursor:pointer;
  background:var(--swatch, var(--bg2)); box-shadow:inset 0 0 0 var(--bw) color-mix(in srgb, var(--ink) 18%, transparent);
  transition:box-shadow var(--dur) var(--ease); }
.bs-swatch::before{ content:""; position:absolute; inset:-6px; border-radius:50%; }   /* зона нажатия 44 */
.bs-swatch:hover{ box-shadow:inset 0 0 0 var(--bw) color-mix(in srgb, var(--ink) 18%, transparent), 0 0 0 var(--bw-strong) var(--card), 0 0 0 calc(var(--bw-strong) * 2) var(--line2); }
.bs-swatch[aria-pressed="true"]{ box-shadow:inset 0 0 0 var(--bw) color-mix(in srgb, var(--ink) 18%, transparent), 0 0 0 var(--bw-strong) var(--card), 0 0 0 calc(var(--bw-strong) * 2) var(--accent); }
.bs-swatch[aria-pressed="true"]::after{ content:""; position:absolute; inset:25%; border-radius:50%; background:var(--card) var(--icon-check) center/70% no-repeat; box-shadow:var(--shadow-1); }
.bs-swatch:focus-visible{ outline:none; box-shadow:var(--focus-ring); }
.bs-tag{ color:var(--accent-text); font:500 var(--fs-sm) var(--font); text-decoration:underline; text-decoration-color:var(--violet-200); text-underline-offset:3px; }
.bs-tag:hover{ text-decoration-color:currentColor; }
.bs-tag:focus-visible{ outline:none; box-shadow:var(--focus-ring); border-radius:var(--rad-xs); }

/* ── Ссылка ───────────────────────────────────────────────────────────────── */
.bs-link{ color:var(--accent-text); text-decoration:underline; text-underline-offset:3px; text-decoration-color:var(--violet-200); font-weight:500; }
.bs-link:hover{ text-decoration-color:currentColor; }
.bs-link:focus-visible{ outline:none; box-shadow:var(--focus-ring); border-radius:var(--rad-xs); }
button.bs-link{ padding:0; border:0; background:none; font:inherit; font-weight:600; cursor:pointer; }   /* ссылка-действие на <button> (окно скачивания, 30.10) */

/* ── Плашка статуса (+одно действие) и тост ───────────────────────────────── */
.bs-note{
  display:grid; grid-template-columns:auto minmax(0,1fr); gap:var(--sp-1) var(--sp-3); align-items:start;
  padding:var(--sp-3) var(--sp-4); border-radius:var(--rad-lg); border-left:0;   /* 22.10: без полосы слева — на скруглённой плашке односторонняя рамка гнётся «скобкой»; тон задают фон и значок */
  background:var(--bg2); color:var(--ink); font:400 var(--fs-sm)/var(--lh-normal) var(--font);
}
.bs-note[hidden]{ display:none; }
.bs-note__icon{ grid-row:span 2; width:var(--icon-md); height:var(--icon-md); }
.bs-note__title{ font-weight:700; }
.bs-note__body{ grid-column:2; color:var(--ink2); }
.bs-note__action{ grid-column:2; justify-self:start; margin-top:var(--sp-1); 
  display:flex; flex-wrap:wrap; align-items:center; gap:var(--sp-2) var(--sp-4); }   /* 23.10: кнопка + тихая ссылка рядом, на узком — переносом */
/* 26.10: плашку-подсказку можно закрыть — ✕ третьей колонкой справа (.bs-btn--ghost.bs-btn--icon.bs-btn--sm) */
/* плотная плашка (этап 3, 29.10): в таблице/строке/дашборде — --sp-1-5 × --sp-3, шрифт --fs-xs */
.bs-note--sm{ padding:var(--sp-1-5) var(--sp-3); gap:var(--sp-1) var(--sp-2); font-size:var(--fs-xs); }
.bs-note--closable{ grid-template-columns:auto minmax(0,1fr) auto; }
.bs-note__close{ grid-column:3; grid-row:1 / span 3; align-self:start; margin:calc(-1 * var(--sp-1)) calc(-1 * var(--sp-2)) 0 0; }
.bs-note--ok{ background:var(--ok-soft); border-left-color:var(--ok); } .bs-note--ok .bs-note__icon{ color:var(--ok-ink); }
.bs-note--warn{ background:var(--warn-soft); border-left-color:var(--warn-line); } .bs-note--warn .bs-note__icon{ color:var(--warn-ink); }
.bs-note--err{ background:var(--err-soft); border-left-color:var(--err); } .bs-note--err .bs-note__icon{ color:var(--err-ink); }
.bs-note--info{ background:var(--accent-soft); border-left-color:var(--violet-500); } .bs-note--info .bs-note__icon{ color:var(--violet-700); }
.bs-toast{
  display:inline-flex; align-items:center; gap:var(--sp-3); min-height:var(--ctl-md); padding:var(--sp-2) var(--sp-2) var(--sp-2) var(--sp-4);
  border-radius:var(--rad-pill); background:var(--ink); color:var(--card); box-shadow:var(--shadow-2); font:500 var(--fs-sm) var(--font);
}
.bs-toast svg{ width:var(--icon-sm); height:var(--icon-sm); flex:none; }
.bs-toast--ok svg{ color:var(--emerald-300); } .bs-toast--err svg{ color:var(--rose-300); }
.bs-toast .bs-btn{ min-height:var(--ctl-sm); color:var(--violet-200); }
.bs-toast .bs-btn:hover{ background:color-mix(in srgb, var(--card) 10%, transparent); color:var(--card); }
/* пачка 3 · корзина · 23.10: канал тостов — ОДИН на сайт (src/ui/toast.js showToast; toast() из
   pop_toolkit/community/pdp-blocks/social-actions/article — обёртки над ним). Низ по центру, над
   нижним меню телефона и cookie-плашкой (--bs-bottom-reserve), выше всех оверлеев (--z-toast).
   Один тост за раз; текст длиннее 4 строк ужимается (полный — в title). */
.bs-toasts{ position:fixed; left:0; right:0; bottom:calc(var(--sp-6) + env(safe-area-inset-bottom,0px) + var(--bs-bottom-reserve,0px));
  z-index:var(--z-toast,10060); display:flex; flex-direction:column; align-items:center; gap:var(--sp-2);
  padding-inline:var(--sp-4); pointer-events:none; }
.bs-toasts > .bs-toast{ pointer-events:auto; max-width:min(420px, 100%); box-sizing:border-box;
  opacity:0; }
.bs-toasts > .bs-toast.is-in{ opacity:1; transform:none; }
.bs-toast__text{ min-width:0; overflow-wrap:anywhere; line-height:var(--lh-normal);
  display:-webkit-box; -webkit-box-orient:vertical; -webkit-line-clamp:4; line-clamp:4; overflow:hidden; }
.bs-toast .bs-btn{ flex:none; }
@media (prefers-reduced-motion:reduce){ .bs-toasts > .bs-toast{ transition:opacity var(--dur-fast) linear; transform:none; } }

/* ── Карточка, панель ─────────────────────────────────────────────────────── */
/* 7.2 Б (решение 22.10): ВНУТРИ приподнятой поверхности (карточка с тенью, окно) у вторичных
   контролов «белая поверхность» нет своей тени — только линия: тень на тени даёт «вату». Правило —
   через --bs-raise (tokens.css): поверхность гасит его для всех потомков. Старые карточки (товар,
   группа, человек, окна .pp-modal/.cm-modal) ставят --bs-raise:none в своих CSS. */
.bs-card,.bs-pcard,.bs-dialog{ --bs-raise:none; }
.bs-card{ background:var(--card); border:var(--bw) solid var(--line); border-radius:var(--rad-lg); box-shadow:var(--edge-light), var(--shadow-1); padding:var(--sp-5); }
.bs-card .bs-btn--primary:not(:focus-visible){ box-shadow:none; }
/* плотность карточки (этап 3, 29.10): по умолчанию --sp-5; --md 16 (карточка в ленте/списке), --sm 12 (плитка,
   строка товара/сделки), --row 8×12 (строка списка: клиент, задача, вопрос) — вместо ручных padding у каждого места */
.bs-card--md{ padding:var(--sp-4); }
/* части карточки (29.10): заголовок и текст — один вид для карточек шагов, фактов, «как это работает».
   <div class="bs-card bs-card--md"><h3 class="bs-card__title">Загрузка модели</h3><p class="bs-card__text">…</p></div>
   --sm у заголовка — для плотных карточек (сетка 4 в ряд, строки списка). */
.bs-card__title{ margin:0 0 var(--sp-1); font:700 var(--fs-base)/var(--lh-tight) var(--font); color:var(--ink); text-wrap:balance; }
.bs-card__title--sm{ font-size:var(--fs-sm); }
.bs-card__text{ margin:0; font:400 var(--fs-sm)/var(--lh-normal) var(--font); color:var(--ink2); }
.bs-card__text--sm{ font-size:var(--fs-xs); }
/* тело карточки под заголовком и вводным текстом (форма, список) — отступ --sp-4 */
.bs-card__body{ margin-top:var(--sp-4); min-width:0; }
.bs-card--sm{ padding:var(--sp-3); }
.bs-card--row{ padding:var(--sp-2) var(--sp-3); }   /* 7.2 Б: и у главной кнопки внутри карточки с тенью своей тени нет */
.bs-panel{ background:var(--card); border:var(--bw) solid var(--line); border-radius:var(--rad-lg); padding:var(--sp-4); box-shadow:var(--edge-light), var(--shadow-1); }
/* ── Значение «только чтение» с действием · .bs-readonly — этап 3, 29.10 ────────────────────────────────
   Сохранённое значение, которое не правится прямо здесь (ИНН, адрес витрины): та же пилюля 44, что у .bs-input,
   но с мягкой заливкой --bg2 (видно, что не поле ввода) и кнопкой справа («Изменить», «Скопировать»).
   <div class="bs-readonly"><span class="bs-readonly__v">7701…</span><span class="bs-readonly__meta">✓ сохранён</span>
     <button class="bs-btn bs-btn--ghost bs-btn--sm">Изменить</button></div> */
.bs-readonly{ display:flex; align-items:center; gap:var(--sp-2); min-height:var(--ctl-md); box-sizing:border-box;
  padding:0 var(--sp-1-5) 0 var(--sp-4); background:var(--bg2); border:var(--bw) solid var(--line2); border-radius:var(--rad-pill); }
.bs-readonly__v{ flex:1 1 auto; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
  font:500 var(--fs-sm)/1.2 var(--font); color:var(--ink); font-variant-numeric:tabular-nums; }
.bs-readonly__meta{ flex:none; display:inline-flex; align-items:center; gap:var(--sp-1); font:600 var(--fs-xs)/1 var(--font); color:var(--ok-text); white-space:nowrap; }
.bs-readonly__meta svg{ width:var(--icon-xs); height:var(--icon-xs); }
.bs-readonly > .bs-btn{ flex:none; }

/* ── Всплывающая панель · .bs-pop — этап 3, 29.10. Окно, привязанное к кнопке (фильтры, «Вид», выбор периода,
   колонки таблицы): поверхность .bs-panel + рамка --line2 + тень --shadow-2, ниже кнопки на --sp-1-5.
   По умолчанию — от левого края кнопки; --end — от правого (кнопка у правого края экрана).
   <div class="bs-menu-host"><button …>Фильтры</button><div class="bs-pop [bs-pop--end]">…</div></div> */
.bs-pop{ position:absolute; top:calc(100% + var(--sp-1-5)); left:0; z-index:var(--z-popover); max-width:calc(100vw - 2 * var(--sp-4));
  box-sizing:border-box; padding:var(--sp-3); background:var(--card); border:var(--bw) solid var(--line2); border-radius:var(--rad-lg);
  box-shadow:var(--shadow-2); }
.bs-pop--end{ left:auto; right:0; }
.bs-pop[hidden]{ display:none; }

/* ── Карточка товара v3: картинка → название → цена → одна мета → тихая кнопка.
      Карточка не кнопка: ссылка-заголовок растянута на всю карточку (::after),
      избранное и кнопка — поверх неё. ─────────────────────────────────────── */
.bs-pcard{ position:relative; display:flex; flex-direction:column; background:var(--card); border:var(--bw) solid var(--line); border-radius:var(--rad-lg); overflow:hidden; transition:box-shadow var(--dur) var(--ease), transform var(--dur) var(--ease); }
.bs-pcard:hover{ box-shadow:var(--shadow-2);  }
.bs-pcard{ transition:box-shadow var(--dur) var(--ease), transform var(--dur-spring) var(--ease-spring); }
@media (hover:hover) and (pointer:fine){ .bs-pcard:hover{ transform:translateY(calc(-1 * var(--lift))); } }
.bs-pcard:active{ transform:translateY(calc(-.5 * var(--lift))) scale(.99); transition-duration:var(--dur-fast); }   /* 26.10: «подпрыгивание» карточки, как .pp-product */
.bs-pcard__media{ position:relative; aspect-ratio:var(--card-media-ratio); background:var(--bg2); }
.bs-pcard__media img{ width:100%; height:100%; object-fit:cover; display:block; }
.bs-pcard__badge{ position:absolute; left:var(--sp-2); top:var(--sp-2); }
.bs-pcard__fav{ position:absolute; right:var(--sp-2); top:var(--sp-2); z-index:2; width:var(--ctl-sm); height:var(--ctl-sm); border-radius:50%; border:0; background:var(--card); color:var(--ink); display:grid; place-items:center; cursor:pointer; box-shadow:var(--shadow-1); }
.bs-pcard__fav svg{ width:var(--icon-sm); height:var(--icon-sm); }
.bs-pcard__fav:focus-visible{ outline:none; box-shadow:var(--focus-ring); }
.bs-pcard__body{ display:flex; flex-direction:column; gap:var(--sp-1); padding:var(--sp-3); flex:1; }
.bs-pcard__title{ margin:0; font:500 var(--fs-sm)/1.35 var(--font); color:var(--ink); display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden; min-height:2.7em; }
.bs-pcard__title a{ color:inherit; text-decoration:none; }
.bs-pcard__title a::after{ content:""; position:absolute; inset:0; z-index:1; }
.bs-pcard__title a:focus-visible{ outline:none; }
.bs-pcard:has(.bs-pcard__title a:focus-visible){ box-shadow:var(--focus-ring); }
.bs-pcard__price{ font:700 var(--fs-md)/var(--lh-tight) var(--font); font-variant-numeric:tabular-nums; color:var(--ink); }
.bs-pcard__price.is-free{ color:var(--ok-ink); }
.bs-pcard__meta{ font:400 var(--fs-xs)/var(--lh-normal) var(--font); color:var(--text-muted); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.bs-pcard__cta{ margin-top:var(--sp-2); position:relative; z-index:2; }

/* ── Пустое состояние ─────────────────────────────────────────────────────── */
/* «ДС дороже» п.3 (30.10, владелец: «давай по твоему»): Кликко на светящемся диске, тон диска — по смыслу состояния:
   фиолетовый — пусто/ничего не нашлось/долгое ожидание, зелёный — успех, коралловый — ошибка. Короткая загрузка —
   по-прежнему скелет формы контента (stateHTML kind:'loading'), не маскот. В блоках — компактный --inline. */
.bs-empty{ --state-tone:var(--violet-500); display:flex; flex-direction:column; align-items:center; text-align:center; gap:var(--sp-2); padding:var(--sp-8) var(--sp-4); }
.bs-empty--success{ --state-tone:var(--ok); }
.bs-empty--error{ --state-tone:var(--coral-500); }
/* Кликко: живой webp или статичная PNG (выбирает <picture> по prefers-reduced-motion) */
.bs-empty picture{ display:contents; }
.bs-empty__art{ width:calc(var(--sp-11) * 2 + var(--sp-6) * 2); height:auto; aspect-ratio:1; max-width:100%; box-sizing:border-box; padding:var(--sp-3);   /* диск 176, Кликко ~150; в узкой колонке — меньше, но круг */
  object-fit:contain; margin-bottom:var(--sp-2); border-radius:var(--rad-pill);
  background:radial-gradient(circle at 50% 45%, color-mix(in srgb, var(--state-tone) 22%, var(--card)) 0 55%, transparent 72%);
  box-shadow:inset 0 0 0 var(--bw) color-mix(in srgb, var(--state-tone) 18%, transparent);
  animation:bs-klikko-in var(--dur-slow) var(--ease-bounce) both; }
.bs-empty__title{ margin:0; font:var(--fw-display) var(--fs-lg)/var(--lh-tight) var(--font-display); letter-spacing:-.01em; color:var(--ink); text-wrap:balance; }
.bs-empty__text{ margin:0; max-width:40ch; font:400 var(--fs-sm)/var(--lh-normal) var(--font); color:var(--text-muted); text-wrap:pretty; }
.bs-empty__cta{ margin-top:var(--sp-3); display:flex; gap:var(--sp-3); flex-wrap:wrap; justify-content:center; }
.bs-empty--sm{ padding:var(--sp-5) var(--sp-3); }
.bs-empty--sm .bs-empty__art{ width:calc(var(--sp-12) + var(--sp-7)); padding:var(--sp-2); }   /* 128 */
.bs-empty--sm .bs-empty__title{ font-size:var(--fs-base); }
.bs-empty--wait .bs-empty__art{ width:calc(var(--sp-12) + var(--sp-1)); padding:var(--sp-1-5); }   /* 100 */
/* ── Пустое состояние ВНУТРИ блока (решение 22.10, 6.1 Б): кабинет, списки, вкладки панелей.
   Иконка в кружке 48 (--accent-soft, значок --accent-strong) слева, справа заголовок + текст + малая
   кнопка. Заяц (.bs-empty с позой) — только для целых пустых страниц и выдач.
   stateHTML({compact:true, icon:'package', title, text, cta}) из src/ui/ui-empty.js. */
.bs-empty--inline{ flex-direction:row; align-items:flex-start; text-align:left; gap:var(--sp-4); padding:var(--sp-4) var(--sp-5); }
.bs-empty__ico{ flex:none; display:grid; place-items:center; width:48px; height:48px; border-radius:50%;
  background:color-mix(in srgb, var(--state-tone) 14%, var(--card)); color:color-mix(in srgb, var(--state-tone) 75%, var(--ink)); }   /* тон — по смыслу, как диск */
.bs-empty__ico svg{ width:var(--icon-lg); height:var(--icon-lg); }
.bs-empty__main{ display:flex; flex-direction:column; align-items:flex-start; gap:var(--sp-1); min-width:0; padding-top:var(--sp-1); }
.bs-empty--inline .bs-empty__title{ font:600 var(--fs-base)/var(--lh-tight) var(--font); letter-spacing:0; }
.bs-empty--inline .bs-empty__text{ max-width:60ch; }
.bs-empty--inline .bs-empty__cta{ margin-top:var(--sp-2); justify-content:flex-start; }
@keyframes bs-klikko-in{ 0%{ transform:scale(.7) translateY(8px); opacity:0; } 100%{ transform:none; opacity:1; } }
@media (max-width:560px){ .bs-empty__art{ width:136px; height:136px; } }
@media (prefers-reduced-motion:reduce){ .bs-empty__art{ animation:none; } }

/* Скелет загрузки списков */
.bs-skel{ display:flex; flex-direction:column; gap:var(--sp-3); padding:var(--sp-5); width:100%; }
.bs-skel__row{ height:14px; border-radius:var(--rad-sm);
  background:linear-gradient(90deg, var(--bg2) 25%, var(--gray-200) 37%, var(--bg2) 63%); background-size:400% 100%;
  animation:bs-skel 1.3s ease infinite; }
@keyframes bs-skel{ 0%{ background-position:100% 0; } 100%{ background-position:0 0; } }
@media (prefers-reduced-motion:reduce){ .bs-skel__row{ animation:none; } }

/* ── Диалог: по центру (компьютер), шторкой снизу (телефон). Поверх нативный <dialog>. ── */
.bs-dialog{ margin:auto;   /* по центру и под сбросом *{margin:0} (landing.css): без него нативный <dialog> прилипал к левому верху */
  border:0; padding:0; border-radius:var(--rad-xl); background:var(--card); color:var(--ink); box-shadow:var(--shadow-3); width:min(480px, calc(100vw - 2 * var(--sp-4))); max-height:calc(100dvh - 2 * var(--sp-6)); }
.bs-dialog::backdrop{ background:var(--overlay-scrim); -webkit-backdrop-filter:var(--overlay-blur); backdrop-filter:var(--overlay-blur); }
.bs-dialog__head{ display:flex; align-items:center; justify-content:space-between; gap:var(--sp-3); padding:var(--sp-5) var(--sp-5) var(--sp-2); }
.bs-dialog__title{ margin:0; font:var(--fw-display) var(--fs-lg)/var(--lh-tight) var(--font-display); }
.bs-dialog__body{ padding:0 var(--sp-5) var(--sp-4); color:var(--ink2); font:400 var(--fs-sm)/var(--lh-normal) var(--font); }
.bs-dialog__foot{ display:flex; justify-content:flex-end; gap:var(--sp-2); padding:var(--sp-3) var(--sp-5) var(--sp-5); }
@media (max-width:599px){
  .bs-dialog{ margin:auto 0 0; width:100%; max-width:none; border-radius:var(--rad-xl) var(--rad-xl) 0 0; }
  .bs-dialog__foot .bs-btn{ flex:1; }
}
/* Подтверждение (решение 22.10, 5.2 А): кнопки справа — «Отмена» .bs-btn--ghost, действие
   .bs-btn--primary, необратимое — .bs-btn--danger (заливка красным). Порядок в DOM: Отмена → действие. */
.bs-dialog--confirm{ width:min(420px, calc(100vw - 2 * var(--sp-4))); }
/* ревью мастера A22 (04.11): правило выше стоит ПОСЛЕ телефонного и возвращало узкое окно —
   шторка прилипала к левому краю с полосой подложки справа. На телефоне — во всю ширину, как все шторки. */
@media (max-width:599px){ .bs-dialog--confirm{ width:100%; } }
/* Окно-форма (мастер «Оформляем заказ», 23.10): ширина формы по DENSITY.md (560), шапка и подвал
   на месте, листается только тело; подвал отделён линией — кнопки не «плавают» в прокрутке.
   <dialog class="bs-dialog bs-dialog--form">head · body · foot</dialog> */
.bs-dialog--form{ width:min(560px, calc(100vw - 2 * var(--sp-4))); flex-direction:column; overflow:hidden; }
dialog.bs-dialog--form[open]{ display:flex; }
.bs-dialog--form > .bs-dialog__body{ flex:1 1 auto; min-height:0; overflow:auto; padding-top:var(--sp-2); }
.bs-dialog--form > .bs-dialog__foot{ border-top:var(--bw) solid var(--line); padding-top:var(--sp-4); }
@media (max-width:599px){ .bs-dialog--form{ width:100%; max-height:92dvh; } }   /* телефон: шторка снизу во всю ширину */
/* Широкое окно (быстрый просмотр товара, 23.10): вместе с --form — шапка с ✕ на месте, листается тело;
   на телефоне — та же шторка снизу. <dialog class="bs-dialog bs-dialog--form bs-dialog--wide"> */
.bs-dialog--wide{ width:min(960px, calc(100vw - 2 * var(--sp-4))); }
@media (max-width:599px){ .bs-dialog--wide{ width:100%; } }
/* пачка 3 · биржа · 23.10: вопрос-подтверждение в окне bs-dialog.js (там всегда --form) — узкий, как --confirm */
.bs-dialog--form.bs-dialog--confirm{ width:min(420px, calc(100vw - 2 * var(--sp-4))); }
@media (max-width:599px){ .bs-dialog--form.bs-dialog--confirm{ width:100%; } }
/* Окно поверх страницы без нативного <dialog> (быстрый просмотр, QR, выбор размера — 23.10): подложка
   .bs-dialog-back держит .bs-dialog по центру (телефон — шторкой снизу). Нужна там, где из окна открываются
   другие слои страницы (корзина, лайтбокс): у нативного showModal() они оказались бы ПОД окном.
   <div class="bs-dialog-back"><div class="bs-dialog bs-dialog--form" role="dialog" aria-modal="true">…</div></div> */
.bs-dialog-back{ position:fixed; inset:0; z-index:var(--z-dialog); display:flex; align-items:center; justify-content:center;
  padding:var(--sp-4); background:var(--overlay-scrim); -webkit-backdrop-filter:var(--overlay-blur); backdrop-filter:var(--overlay-blur); overscroll-behavior:contain; }
.bs-dialog-back > .bs-dialog{ display:flex; flex-direction:column; margin:0; overflow:hidden; }
@media (max-width:599px){ .bs-dialog-back{ align-items:flex-end; padding:0; } }

/* ── Шаги процесса · .bs-steps (мастер заказа, 23.10): ряд «1 Идея — 2 Детали — 3 Готово» от левого
   края контента. Текущий — aria-current="step" (кружок --accent), пройденный — .is-done (мягкий).
   <ol class="bs-steps"><li class="bs-steps__item is-done"><span class="bs-steps__num">1</span>Идея</li>
     <li class="bs-steps__item" aria-current="step"><span class="bs-steps__num">2</span>Детали</li>…</ol> */
.bs-steps{ display:flex; flex-wrap:wrap; align-items:center; gap:var(--sp-2); margin:0; padding:0; list-style:none;
  font:600 var(--fs-sm)/var(--lh-tight) var(--font); color:var(--text-muted); }
.bs-steps__item{ display:inline-flex; align-items:center; gap:var(--sp-2); }
.bs-steps__item + .bs-steps__item::before{ content:""; width:var(--sp-5); height:var(--bw); background:var(--line2); }
.bs-steps__num{ display:grid; place-items:center; width:var(--icon-lg); height:var(--icon-lg); border-radius:50%;
  background:var(--bg2); color:var(--ink2); font:600 var(--fs-xs)/1 var(--font); font-variant-numeric:tabular-nums; }
.bs-steps__item.is-done{ color:var(--ink2); }
.bs-steps__item.is-done .bs-steps__num{ background:var(--accent-soft); color:var(--accent-strong); }
.bs-steps__item[aria-current="step"]{ color:var(--ink); }
.bs-steps__item[aria-current="step"] .bs-steps__num{ background:var(--grad-btn); color:var(--accent-ink); }   /* текущий — фирменный градиент, как главная кнопка (владелец 23.10) */
.bs-steps__num svg{ width:var(--icon-sm); height:var(--icon-sm); }
/* шаг не нужен (например, доставка у цифрового заказа): приглушён, номер «—», без зачёркивания */
.bs-steps__item.is-skip{ color:var(--text-muted); }
.bs-steps__item.is-skip .bs-steps__num{ background:transparent; box-shadow:inset 0 0 0 var(--bw) var(--line2); color:var(--text-muted); }

/* ── Кнопка поверх фото · .bs-mbtn (23.10) ───────────────────────────────────────────────────
   Действие прямо на картинке (быстрый просмотр, AR, «развернуть»): пилюля 32, значок Lucide 16 + подпись.
   Светлая (по умолчанию) — в тон значкам на фото (тип, «В избранное»); --dark — полупрозрачное «стекло»
   с размытием, читается на любом фото. --icon — круг 32 без подписи (на тач-экранах).
   <a class="bs-mbtn bs-mbtn--dark" href="…"><svg class="bs-ico">…</svg>Быстрый просмотр</a> */
.bs-mbtn{ display:inline-flex; align-items:center; justify-content:center; gap:var(--sp-1-5); box-sizing:border-box;
  height:var(--ctl-sm); padding:0 var(--sp-3); border:0; border-radius:var(--rad-pill); cursor:pointer; text-decoration:none;
  background:var(--onmedia-bg); color:var(--onmedia-ink); box-shadow:var(--shadow-1);
  -webkit-backdrop-filter:blur(8px); backdrop-filter:blur(8px);
  font:600 var(--fs-xs)/1 var(--font); white-space:nowrap;
  transition:background var(--dur) var(--ease), transform var(--dur-fast) var(--ease); }
.bs-mbtn:hover{ background:var(--onmedia-bg-hover); transform:var(--btn-hover-grow); }
.bs-mbtn:focus-visible{ outline:none; box-shadow:var(--focus-ring); }
.bs-mbtn svg{ width:var(--icon-sm); height:var(--icon-sm); flex:none; }
.bs-mbtn--dark{ background:var(--onmedia-dark-bg); color:var(--onmedia-dark-ink); box-shadow:none; }
.bs-mbtn--dark:hover{ background:var(--onmedia-dark-bg-hover); }
.bs-mbtn--icon{ width:var(--ctl-sm); padding:0; gap:0; }

/* ── Карточка-вариант · .bs-choice (выбор одного из нескольких крупных вариантов, 23.10) ─────────
   Радиогруппа: role="radiogroup" на .bs-choices, role="radio" + aria-checked на .bs-choice, стрелки
   переключают. Выбранная — как выбранный .bs-filter/.bs-seg: мягкая заливка --accent-soft и рамка
   --violet-100, БЕЗ ореола (одна обводка). Значок слева (Lucide 24), название 600, пояснение тише.
   <div class="bs-choices" role="radiogroup" aria-label="…"><button class="bs-choice" role="radio" aria-checked="true">
     <svg class="bs-ico bs-choice__icon">…</svg><span class="bs-choice__title">…</span><span class="bs-choice__desc">…</span></button></div> */
.bs-choices{ display:grid; gap:var(--sp-2); }
.bs-choice{ display:grid; grid-template-columns:auto minmax(0, 1fr); align-items:center; column-gap:var(--sp-4); row-gap:var(--sp-1);
  width:100%; min-height:var(--ctl-lg); padding:var(--sp-3) var(--sp-4); text-align:left; cursor:pointer;
  background:var(--card); color:var(--ink); border:var(--bw) solid var(--line2); border-radius:var(--rad-lg);
  font:400 var(--fs-sm)/var(--lh-normal) var(--font);
  transition:background var(--dur) var(--ease), border-color var(--dur) var(--ease); }
.bs-choice:hover{ border-color:color-mix(in srgb, var(--ink) 22%, var(--line2)); }
.bs-choice:focus-visible{ outline:none; box-shadow:var(--focus-ring); }
.bs-choice__icon{ grid-row:span 2; width:var(--icon-lg); height:var(--icon-lg); color:var(--ink2); }
.bs-choice__title{ font:600 var(--fs-base)/var(--lh-tight) var(--font); color:var(--ink); }
.bs-choice__desc{ grid-column:2; color:var(--text-muted); }
.bs-choice[aria-checked="true"]{ background:var(--accent-soft); border-color:var(--violet-100); }
.bs-choice[aria-checked="true"]:hover{ border-color:var(--violet-200); }
.bs-choice[aria-checked="true"] .bs-choice__icon{ color:var(--accent-strong); }
@media (prefers-reduced-motion:reduce){ .bs-choice{ transition:none; } }

/* ── Мультикарта в форме товара · .bs-mcpick (решение 26.10: МК-1 «Мультикарта», МК-2 развёрнут) ──
   Блок «Это вариант другого товара?» в шаге 1: .bs-choices «Отдельный товар / Вариант мультикарты»,
   под ним поиск, строки-радио .bs-mcpick__row (миниатюры + название + пояснение), «+ Новая
   мультикарта» и превью полосы покупателя (.pdp-mc из pop.css — ровно то, что он увидит). */
/* ── выбор нескольких и действия с ними (ревью мастера B15, 04.11) ──
   .bs-pickmark — метка выбора в углу плитки/карточки (внутри — .bs-check), сама клики не ловит:
   выбирает вся плитка. .bs-bulkbar — панель «Выбрано: N · действия», липнет к низу экрана над
   нижней навигацией телефона (--bs-bottom-reserve). Счётчик — .bs-bulkbar__count. */
.bs-pickmark{ position:absolute; top:var(--sp-2); left:var(--sp-2); z-index:2; display:flex;
  padding:var(--sp-1); border-radius:var(--rad-sm); background:var(--card); box-shadow:var(--shadow-1); pointer-events:none; }
.bs-bulkbar{ position:sticky; bottom:calc(var(--sp-3) + env(safe-area-inset-bottom, 0px) + var(--bs-bottom-reserve, 0px)); z-index:5;
  display:flex; flex-wrap:wrap; align-items:center; gap:var(--sp-2); margin-top:var(--sp-3);
  padding:var(--sp-2) var(--sp-3); border:var(--bw) solid var(--line); border-radius:var(--rad-lg);
  background:var(--card); box-shadow:var(--shadow-2); }
.bs-bulkbar__count{ margin-right:auto; font:600 var(--fs-sm) var(--font); color:var(--ink); }

.bs-mcpick{ display:grid; gap:var(--sp-3); padding:var(--sp-4); background:var(--accent-soft); border-radius:var(--rad-lg); min-width:0; }
.bs-mcpick > *{ min-width:0; }
.bs-mcpick__head{ display:grid; grid-template-columns:auto minmax(0,1fr); column-gap:var(--sp-3); row-gap:var(--sp-1); align-items:start; }
.bs-mcpick__ic{ grid-row:span 2; display:grid; place-items:center; width:var(--ctl-md); height:var(--ctl-md); border-radius:50%; background:var(--card); color:var(--accent-strong); }
.bs-mcpick__ic .bs-ico{ width:var(--icon-md); height:var(--icon-md); }
.bs-mcpick__t{ margin:0; display:flex; flex-wrap:wrap; align-items:center; gap:var(--sp-2); font:600 var(--fs-md)/var(--lh-tight) var(--font); color:var(--ink); }
.bs-mcpick__sub{ margin:0; font-size:var(--fs-sm); line-height:var(--lh-normal); color:var(--text-muted); }
/* свёрнутый вид (ревью мастера B09): одна строка «Это вариант другого товара? [Да, это вариант]» —
   для большинства товаров ответ «отдельный», крупный выбор раскрывается только по кнопке */
.bs-mcpick--compact{ grid-template-columns:auto minmax(0,1fr) auto; align-items:center; padding:var(--sp-3); }
.bs-mcpick--compact .bs-mcpick__ic{ grid-row:auto; }
.bs-mcpick--compact .bs-mcpick__t{ font-size:var(--fs-base); }
.bs-mcpick--compact .bs-mcpick__sub{ flex-basis:100%; font-weight:400; }
@media (max-width:480px){
  .bs-mcpick--compact{ grid-template-columns:auto minmax(0,1fr); }
  .bs-mcpick--compact > .bs-btn{ grid-column:1 / -1; }
}
.bs-mcpick .bs-choices{ grid-template-columns:repeat(auto-fit, minmax(200px, 1fr)); }
.bs-mcpick__list{ display:grid; gap:var(--sp-2); margin:0; padding:0; list-style:none; max-height:300px; overflow:auto; }
.bs-mcpick__row{ display:grid; grid-template-columns:auto auto minmax(0,1fr); align-items:center; gap:var(--sp-3); min-height:var(--ctl-lg);
  padding:var(--sp-2) var(--sp-3); background:var(--card); border:var(--bw) solid var(--line2); border-radius:var(--rad-md); cursor:pointer;
  transition:border-color var(--dur) var(--ease); }
.bs-mcpick__row:hover{ border-color:color-mix(in srgb, var(--ink) 22%, var(--line2)); }
.bs-mcpick__row:has(input:checked){ border-color:var(--accent); }
.bs-mcpick__row:has(input:focus-visible){ box-shadow:var(--focus-ring); }
.bs-mcpick__row.bs-radio,.bs-mcpick__row.bs-check{ display:grid; min-height:var(--ctl-lg); }
/* Подгруппы витрины (окно «Подгруппы», 26.10): карточка папки — имя + «Сохранить», ниже тумблер
   «Мультикарта», счётчик товаров, «Добавить товары» и «Удалить». */
.bs-folders{ display:grid; gap:var(--sp-2); }
.bs-folder{ display:grid; gap:var(--sp-2); padding:var(--sp-3); background:var(--card); border:var(--bw) solid var(--line); border-radius:var(--rad-md); min-width:0; }
.bs-folder__top{ display:flex; gap:var(--sp-2); align-items:center; min-width:0; }
.bs-folder__top .bs-input{ flex:1 1 auto; min-width:0; }
.bs-folder__bar{ display:flex; flex-wrap:wrap; align-items:center; gap:var(--sp-1) var(--sp-3); }
.bs-folder__bar .bs-switch{ margin-right:auto; }
.bs-folder__n{ font-size:var(--fs-xs); color:var(--text-muted); }
.bs-folder__add{ display:flex; gap:var(--sp-2); align-items:center; }
.bs-folder__add .bs-input{ flex:1 1 auto; min-width:0; }
.bs-mcpick__thumbs{ display:flex; }
.bs-mcpick__thumbs img, .bs-mcpick__thumbs span{ width:32px; height:32px; border-radius:var(--rad-sm); object-fit:cover; background:var(--bg2); border:2px solid var(--card); }   /* ds-ok: миниатюра 32 (картинка, не контрол) */
.bs-mcpick__thumbs > * + *{ margin-left:calc(-1 * var(--sp-2)); }
.bs-mcpick__name{ display:block; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; font-weight:600; color:var(--ink); }
.bs-mcpick__meta{ display:block; font-size:var(--fs-xs); color:var(--text-muted); }
.bs-mcpick__new{ display:flex; flex-wrap:wrap; gap:var(--sp-2); align-items:center; }
.bs-mcpick__new .pp-input, .bs-mcpick__new .bs-input{ flex:1 1 200px; min-width:0; }
.bs-mcpick__prev{ display:grid; gap:var(--sp-2); padding:var(--sp-3); background:var(--card); border-radius:var(--rad-md); }
.bs-mcpick__prevt{ margin:0; display:flex; align-items:center; gap:var(--sp-2); font:600 var(--fs-xs)/var(--lh-tight) var(--font); color:var(--ink2); }
.bs-mcpick__prevt .bs-ico{ width:var(--icon-sm); height:var(--icon-sm); }
.bs-mcpick__empty{ margin:0; font-size:var(--fs-sm); color:var(--text-muted); }
@media (prefers-reduced-motion:reduce){ .bs-mcpick__row{ transition:none; } }

/* ── Шторка справа (решение 22.10, 5.1 А): фильтры каталога, корзина ─────────────────────────
   На ПК — панель во всю высоту у правого края (каталог виден слева), на телефоне — шторка снизу.
   Модификатор на ПАНЕЛЬ любого окна: <dialog class="bs-dialog bs-dialog--side">, а у старых окон —
   на .pp-modal / .cm-modal (подложку они рисуют сами). Панель — flex-колонка: шапка и подвал на
   месте, тело листается (своё правило тела — у окна). position:fixed — от вьюпорта (подложка
   окна — во весь экран), поэтому раскладка подложки не важна. Вход — выезд с края; «уменьшить
   движение» — без анимации. */
.bs-dialog--side{ position:fixed; inset:0 0 0 auto; margin:0; width:min(440px, 100vw); max-width:none;
  height:100vh; height:100dvh; max-height:none; min-height:0; border-radius:var(--rad-xl) 0 0 var(--rad-xl);
  display:flex; flex-direction:column; overflow:hidden; box-shadow:var(--shadow-3);
  animation:bs-side-in var(--dur-slow) var(--ease) both; }
.bs-dialog--side > .bs-dialog__body{ flex:1 1 auto; min-height:0; overflow:auto; }
dialog.bs-dialog--side:not([open]){ display:none; }   /* display:flex выше перебил бы скрытие закрытого <dialog> */
@keyframes bs-side-in{ from{ transform:translateX(100%); } to{ transform:none; } }
@keyframes bs-sheet-in{ from{ transform:translateY(100%); } to{ transform:none; } }
@media (max-width:599px){
  .bs-dialog--side{ inset:auto 0 0 0; width:100%; height:auto; max-height:88vh; max-height:88dvh;
    border-radius:var(--rad-xl) var(--rad-xl) 0 0; padding-bottom:env(safe-area-inset-bottom); animation-name:bs-sheet-in; }
}
@media (prefers-reduced-motion:reduce){ .bs-dialog--side{ animation:none; } }

/* ── Таблица (решение владельца 22.10, 11.1 А / 11.2 А) ───────────────────────────────────────
   Списки заказов, пользователей, покупок, возвратов. Обёртка .bs-table-wrap — белая поверхность
   (--card, 1px --line, --rad-lg) и горизонтальная прокрутка на узком. Шапка — --fs-2xs 600 капсом
   --text-muted с разрядкой; строки через 1px --line; текст --fs-sm. Числа — .is-num (tabular-nums,
   вправо). Статусы — .bs-badge. Наведение строки — --bg2; выбранная (aria-selected="true" /
   .is-selected) — --accent-soft, текст --accent-strong. Действия строки — последняя ячейка
   .bs-table__actions: тихие кнопки и «⋯» с меню .bs-menu (опасное — только в меню).
   На телефоне (≤600px) строки становятся карточками: подпись ячейки берётся из data-label
   (td::before). Ячейка без data-label — во всю ширину (название строки). --scroll — оставить
   таблицей с прокруткой вбок (широкие сводки, где карточки не читаются).
   <div class="bs-table-wrap"><table class="bs-table">
     <thead><tr><th>Заказ</th><th class="is-num">Сумма</th><th><span class="bs-sr">Действия</span></th></tr></thead>
     <tbody><tr><td>Ваза</td><td class="is-num" data-label="Сумма">780 ₽</td>
       <td class="bs-table__actions">…</td></tr></tbody></table></div> */
.bs-table-wrap{ --bs-raise:none; overflow-x:auto; background:var(--card); border:var(--bw) solid var(--line); border-radius:var(--rad-lg); }
.bs-table{ width:100%; border-collapse:collapse; font:400 var(--fs-sm)/var(--lh-normal) var(--font); color:var(--ink); }
.bs-table th{ padding:var(--sp-3) var(--sp-4); text-align:left; vertical-align:bottom; white-space:nowrap;
  font:600 var(--fs-2xs)/var(--lh-tight) var(--font); letter-spacing:.06em; text-transform:uppercase; color:var(--text-muted);
  border-bottom:var(--bw) solid var(--line); }
.bs-table td{ padding:var(--sp-3) var(--sp-4); vertical-align:middle; border-bottom:var(--bw) solid var(--line); }
.bs-table tbody tr:last-child > td{ border-bottom:0; }
.bs-table .is-num{ text-align:right; font-variant-numeric:tabular-nums; white-space:nowrap; }
.bs-table tbody tr{ transition:background var(--dur-fast) var(--ease); }
.bs-table tbody tr:hover{ background:var(--bg2); }
.bs-table tbody tr:is([aria-selected="true"],.is-selected){ background:var(--accent-soft); color:var(--accent-strong); }
.bs-table__actions{ width:1%; text-align:right; white-space:nowrap; }
.bs-table__actions > *{ vertical-align:middle; }
.bs-table__actions > * + *{ margin-left:var(--sp-1); }
/* подпись колонки только для скринридера (колонка действий, чекбокс) */
.bs-sr{ position:absolute; width:1px; height:1px; margin:-1px; padding:0; overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0; }
@media (max-width:600px){
  .bs-table-wrap:has(> .bs-table:not(.bs-table--scroll)){ overflow:visible; background:none; border:0; border-radius:0; }
  .bs-table:not(.bs-table--scroll),
  .bs-table:not(.bs-table--scroll) > tbody,
  .bs-table:not(.bs-table--scroll) > tbody > tr,
  .bs-table:not(.bs-table--scroll) > tbody > tr > td{ display:block; }
  .bs-table:not(.bs-table--scroll) > thead{ position:absolute; width:1px; height:1px; overflow:hidden; clip:rect(0 0 0 0); }
  .bs-table:not(.bs-table--scroll) > tbody > tr{ position:relative; margin-bottom:var(--sp-2); padding:var(--sp-3) var(--sp-4);
    background:var(--card); border:var(--bw) solid var(--line); border-radius:var(--rad-lg); }
  .bs-table:not(.bs-table--scroll) > tbody > tr:hover{ background:var(--card); }
  .bs-table:not(.bs-table--scroll) > tbody > tr:is([aria-selected="true"],.is-selected){ background:var(--accent-soft); }
  .bs-table:not(.bs-table--scroll) > tbody > tr > td{ padding:var(--sp-1) 0; border:0; text-align:left; }
  .bs-table:not(.bs-table--scroll) > tbody > tr > td[data-label]{ display:flex; align-items:baseline; justify-content:space-between; gap:var(--sp-3); text-align:right; }
  .bs-table:not(.bs-table--scroll) > tbody > tr > td[data-label]::before{ content:attr(data-label); flex:none; max-width:45%; text-align:left;
    font:600 var(--fs-2xs)/var(--lh-tight) var(--font); letter-spacing:.06em; text-transform:uppercase; color:var(--text-muted); }
  /* действия — в правый верхний угол карточки, рядом с названием */
  .bs-table:not(.bs-table--scroll) > tbody > tr > td.bs-table__actions{ position:absolute; top:var(--sp-2); right:var(--sp-2); width:auto; padding:0; }
  .bs-table:not(.bs-table--scroll) > tbody > tr:has(> td.bs-table__actions) > td:first-child{ padding-right:calc(var(--ctl-md) + var(--sp-2)); }
}

/* ── Меню действий «⋯» (решение 22.10, 11.3 А) ────────────────────────────────────────────────
   Кнопка — .bs-btn.bs-btn--ghost.bs-btn--icon.bs-btn--sm (aria-haspopup="menu"), меню — белая
   --card, тень --shadow-2, --rad-md; пункты 40, опасный пункт — .bs-menu__item--danger (--err-text).
   Опасные и редкие действия строки («Блок», «Удалить», «Возврат») живут здесь, а не в ряду кнопок.
   Разметка и поведение (открыть/закрыть, Esc, клик мимо, стрелки) — src/ui/ui-menu.js
   (rowMenuHTML / menuItemHTML). Меню position:fixed — не обрезается прокручиваемой обёрткой таблицы.
   <span class="bs-menu-host"><button class="bs-btn bs-btn--ghost bs-btn--icon bs-btn--sm" aria-haspopup="menu" aria-expanded="false" aria-label="Действия">…</button>
     <div class="bs-menu" role="menu" hidden><button class="bs-menu__item" role="menuitem">Роль</button>
       <button class="bs-menu__item bs-menu__item--danger" role="menuitem">Заблокировать</button></div></span> */
.bs-menu-host{ position:relative; display:inline-flex; }
.bs-menu-host > .bs-btn[aria-expanded="true"]{ background:var(--bg2); color:var(--ink); }
.bs-menu{ position:fixed; z-index:var(--z-popover); display:flex; flex-direction:column; gap:1px;
  min-width:200px; max-width:min(280px, calc(100vw - 2 * var(--sp-2))); padding:var(--sp-1);
  background:var(--card); border:var(--bw) solid var(--line); border-radius:var(--rad-md); box-shadow:var(--shadow-2);
  text-align:left; white-space:normal; color:var(--ink); }
.bs-menu[hidden]{ display:none; }
.bs-menu__item{ display:flex; align-items:center; gap:var(--sp-2); width:100%; min-height:calc(var(--ctl-sm) + var(--sp-2));
  padding:0 var(--sp-3); margin:0; border:0; border-radius:var(--rad-sm); background:none; cursor:pointer; text-align:left; text-decoration:none;
  font:500 var(--fs-sm)/var(--lh-tight) var(--font); color:var(--ink); transition:background var(--dur-fast) var(--ease); }
.bs-menu__item svg{ width:var(--icon-sm); height:var(--icon-sm); flex:none; color:var(--ink2); }
.bs-menu__item:hover:not(:disabled),.bs-menu__item:focus-visible{ background:var(--bg2); outline:none; }
.bs-menu__item:focus-visible{ box-shadow:var(--focus-ring); }
.bs-menu__item:disabled,.bs-menu__item[aria-disabled="true"]{ color:var(--text-muted); cursor:not-allowed; }
.bs-menu__item--danger,.bs-menu__item--danger svg{ color:var(--err-text); }
.bs-menu__item--danger:hover:not(:disabled),.bs-menu__item--danger:focus-visible{ background:var(--err-soft); }
/* шапка меню (меню профиля, 27.10): аватар --sm + имя и подпись */
.bs-menu__head{ display:flex; align-items:center; gap:var(--sp-3); padding:var(--sp-2) var(--sp-3); min-width:0; }
.bs-menu__head-t{ display:grid; min-width:0; }
.bs-menu__head-t b{ font:600 var(--fs-sm)/var(--lh-tight) var(--font); color:var(--ink); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.bs-menu__head-t span{ font-size:var(--fs-xs); color:var(--text-muted); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
a.bs-menu__item{ text-decoration:none; color:var(--ink); }
.pp-nav-avmenu{ width:min(280px, calc(100vw - 2 * var(--sp-4))); }
.bs-menu__sep{ height:1px; margin:var(--sp-1) var(--sp-2); background:var(--line); }
@media (prefers-reduced-motion:reduce){ .bs-table tbody tr,.bs-menu__item{ transition:none; } }
/* пачка 3 · Сообщество · 23.10 — меню ВЫБОРА одного варианта (кнопка-значок + список, напр. «Тип записей»
   в ленте): пункты role="menuitemradio", выбранный aria-checked="true" — как выбранный вариант сортировки
   маркетплейса (.bs-select-dd .option.selected): --accent-soft, --violet-700, 600 и галочка справа.
   Кнопка-триггер — .bs-btn--secondary --sm со значком; выбрано не «по умолчанию» — .is-active. */
.bs-menu__item[aria-checked]{ justify-content:space-between; }
.bs-menu__item[aria-checked="true"]{ background:var(--accent-soft); color:var(--violet-700); font-weight:600; }
.bs-menu__item[aria-checked="true"]::after{ content:""; flex:none; width:var(--icon-sm); height:var(--icon-sm); margin-left:var(--sp-2);
  background:currentColor; -webkit-mask:var(--icon-check) center/contain no-repeat; mask:var(--icon-check) center/contain no-repeat; }
.bs-menu__item[aria-checked="true"]:hover,.bs-menu__item[aria-checked="true"]:focus-visible{ background:var(--accent-soft); }
.bs-menu-host > .bs-btn--secondary.is-active[aria-expanded="true"]{ background:var(--accent-soft); color:var(--accent-strong); }   /* открыто — подсветка выбора не пропадает */

/* ── «Выбор» с поиском (Tom Select) — для длинных списков; вид поля-пилюли ─── */
.ts-wrapper.bs-select{ width:100%; }
.ts-wrapper.bs-select .ts-control{
  min-height:var(--ctl-md); padding:0 calc(var(--sp-4) + var(--icon-sm) + var(--sp-2)) 0 var(--sp-4);
  border:var(--bw) solid var(--line-field); border-radius:var(--rad-pill); box-shadow:none;
  background:var(--card); position:relative;
  font:400 var(--fs-sm) var(--font); color:var(--ink); display:flex; align-items:center; cursor:pointer;
}
.ts-wrapper.bs-select.single .ts-control::after{ display:none; }
.ts-wrapper.bs-select .ts-control::before{
  content:""; position:absolute; right:var(--sp-4); top:50%; width:var(--icon-sm); height:var(--icon-sm); margin-top:calc(var(--icon-sm) / -2);
  background:var(--ink2); -webkit-mask:var(--icon-chevron-down) center/contain no-repeat; mask:var(--icon-chevron-down) center/contain no-repeat;
  transition:transform var(--dur) var(--ease); pointer-events:none;
}
.ts-wrapper.bs-select.dropdown-active .ts-control::before{ transform:rotate(180deg); }
.ts-wrapper.bs-select .ts-control:hover{ border-color:var(--ink2); }
.ts-wrapper.bs-select.focus .ts-control{ border-color:var(--violet-600); box-shadow:var(--focus-ring-soft); }   /* фокус поля — мягкий ореол (2.2 А) */
.ts-wrapper.bs-select .ts-control > input{ font:inherit; color:var(--ink); flex:1 1 auto; min-width:var(--sp-4); }
.ts-wrapper.bs-select .ts-control input::placeholder{ color:var(--text-muted); }
.ts-wrapper.bs-select.is-searching .bs-select-item{ display:none; }
.bs-select-item small,.bs-select-opt small{ color:var(--text-muted); font-size:var(--fs-xs); white-space:nowrap; }
.ts-dropdown.bs-select-dd{
  margin-top:var(--sp-1); border:var(--bw) solid var(--line2); border-radius:var(--rad-lg);
  background:var(--card); box-shadow:var(--shadow-2); overflow:hidden; z-index:var(--z-popover);
  font:400 var(--fs-sm) var(--font); color:var(--ink);
}
.ts-dropdown.bs-select-dd .ts-dropdown-content{ max-height:min(360px,60vh); padding:var(--sp-1); }
.ts-dropdown.bs-select-dd .optgroup-header{ padding:var(--sp-2) var(--sp-3) var(--sp-1); background:var(--card); font:700 var(--fs-2xs) var(--font); letter-spacing:.06em; text-transform:uppercase; color:var(--text-muted); }
.ts-dropdown.bs-select-dd .option{ padding:var(--sp-2) var(--sp-3); border-radius:var(--rad-sm); display:flex; align-items:center; }
.ts-dropdown.bs-select-dd .bs-select-opt{ display:flex; justify-content:space-between; gap:var(--sp-3); align-items:baseline; }
.ts-dropdown.bs-select-dd .bs-select-opt > span{ flex:1 1 auto; white-space:nowrap; }
.ts-dropdown.bs-select-dd .option.active{ background:var(--bg2); color:var(--ink); }
.ts-dropdown.bs-select-dd .option.selected{ background:var(--accent-soft); color:var(--violet-700); font-weight:600; }
.ts-dropdown.bs-select-dd .option.selected small{ color:var(--violet-700); }
.ts-dropdown.bs-select-dd .option.selected::after{ content:""; flex:none; width:var(--icon-sm); height:var(--icon-sm); margin-left:var(--sp-2); background:currentColor; -webkit-mask:var(--icon-check) center/contain no-repeat; mask:var(--icon-check) center/contain no-repeat; }
.ts-dropdown.bs-select-dd .highlight{ background:var(--warn-soft); color:inherit; border-radius:var(--rad-2xs); }
.ts-dropdown.bs-select-dd .no-results{ padding:var(--sp-3); color:var(--ink2); font-size:var(--fs-sm); }

/* ── Сообщение · .bs-msg и цитата · .bs-quote — этап 3, 29.10 ─────────────────────────────────────────
   ОДИН пузырь для мессенджера и плавающего чата (были разные радиусы/отступы/фиолетовые). Чужой — карточка
   с рамкой --line, свой — заливка --count-bg (тот же фиолетовый, что у счётчика: белый текст ≥ 4.5:1).
   Цитата — мягкий фон + полоса акцента слева (inset-тень, без отдельного элемента-полосы); внутри своего
   пузыря — светлая. --lg — цитата поста в ленте (крупнее, до 3 строк).
   <div class="bs-msg [bs-msg--mine]"><span class="bs-msg__who">Анна</span>
     <div class="bs-quote" role="button"><span class="bs-quote__who">Кто</span><span class="bs-quote__text">Что…</span></div>
     <span class="bs-msg__text">Текст</span><span class="bs-msg__foot">12:40 ✓✓</span></div> */
.bs-msg{ position:relative; max-width:min(560px, 80%); box-sizing:border-box; padding:var(--sp-2) var(--sp-3);
  border-radius:var(--rad-lg); background:var(--card); border:var(--bw) solid var(--line); color:var(--ink); }
.bs-msg--mine{ background:var(--count-bg); border-color:transparent; color:var(--on-accent); }
.bs-msg__who{ display:block; margin-bottom:2px; font:600 var(--fs-xs)/var(--lh-tight) var(--font); color:var(--accent-strong); }
.bs-msg__text{ display:block; font:400 var(--fs-sm)/var(--lh-normal) var(--font); white-space:pre-wrap; overflow-wrap:anywhere; }
.bs-msg__foot{ display:flex; align-items:center; justify-content:flex-end; gap:var(--sp-1); margin-top:2px;
  font:500 var(--fs-2xs)/1 var(--font); color:var(--text-muted); font-variant-numeric:tabular-nums; }
.bs-msg--mine .bs-msg__who, .bs-msg--mine .bs-msg__foot{ color:color-mix(in srgb, var(--on-accent) 80%, transparent); }
.bs-quote{ display:flex; flex-direction:column; gap:2px; min-width:0; margin:0 0 var(--sp-1); padding:var(--sp-1) var(--sp-2) var(--sp-1) var(--sp-3);
  border-radius:var(--rad-sm); background:color-mix(in srgb, var(--ink) 5%, transparent); box-shadow:inset var(--bw-strong) 0 0 var(--accent);
  color:inherit; text-decoration:none; cursor:pointer; transition:background var(--dur-fast) var(--ease); }
.bs-quote:hover{ background:color-mix(in srgb, var(--ink) 8%, transparent); }
.bs-quote:focus-visible{ outline:none; box-shadow:inset var(--bw-strong) 0 0 var(--accent), var(--focus-ring); }
.bs-quote__who{ min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; font:600 var(--fs-2xs)/1.3 var(--font); color:var(--accent-strong); }
.bs-quote__text{ min-width:0; overflow:hidden; display:-webkit-box; -webkit-box-orient:vertical; -webkit-line-clamp:2;
  font:400 var(--fs-xs)/var(--lh-normal) var(--font); color:var(--ink2); overflow-wrap:anywhere; }
.bs-msg--mine .bs-quote{ background:color-mix(in srgb, var(--on-accent) 14%, transparent); box-shadow:inset var(--bw-strong) 0 0 var(--on-accent); }
.bs-msg--mine .bs-quote:hover{ background:color-mix(in srgb, var(--on-accent) 22%, transparent); }
.bs-msg--mine .bs-quote__who, .bs-msg--mine .bs-quote__text{ color:var(--on-accent); }
.bs-quote--lg{ gap:var(--sp-1); padding:var(--sp-3) var(--sp-4); border-radius:var(--rad-md); background:var(--bg2);
  box-shadow:inset calc(2 * var(--bw-strong)) 0 0 var(--accent); }
.bs-quote--lg .bs-quote__who{ font-size:var(--fs-ctl); color:var(--ink); }
.bs-quote--lg .bs-quote__text{ font-size:var(--fs-sm); -webkit-line-clamp:3; }
/* --static: цитата-текст без перехода (цитата в ответе комментария) — без наведения, текст целиком */
.bs-quote--static{ cursor:default; }
.bs-quote--static:hover{ background:color-mix(in srgb, var(--ink) 5%, transparent); }
.bs-quote--static .bs-quote__text{ display:block; white-space:pre-wrap; -webkit-line-clamp:unset; }
@media (prefers-reduced-motion:reduce){ .bs-quote{ transition:none; } }

/* ── Реакция · .bs-react и плавающая панель · .bs-toolbar — этап 3, 29.10 ─────────────────────────────
   Реакция под сообщением/постом: эмодзи + число, чип 24 с рамкой; своя — как выбранный фильтр (--accent-soft).
   Плавающая панель — пилюля над сообщением (действия, быстрые реакции): --card, рамка --line2, --shadow-2;
   внутри — обычные кнопки-кружки ДС (.bs-btn--ghost --icon --sm). --emoji — кнопки с эмодзи, при наведении
   эмодзи чуть растёт.
   <button class="bs-react" aria-pressed="true"><span>👍</span><span class="bs-react__n">3</span></button>
   <div class="bs-toolbar [bs-toolbar--emoji]"><button class="bs-btn bs-btn--ghost bs-btn--icon bs-btn--sm">…</button></div> */
.bs-react{ display:inline-flex; align-items:center; gap:var(--sp-1); height:24px; padding:0 var(--sp-2); box-sizing:border-box;
  border:var(--bw) solid var(--line2); border-radius:var(--rad-pill); background:var(--card); color:var(--ink2);
  font:600 var(--fs-xs)/1 var(--font); cursor:pointer; transition:background var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease); }
.bs-react:hover{ background:var(--bg2); }
.bs-react:focus-visible{ outline:none; box-shadow:var(--focus-ring); }
.bs-react[aria-pressed="true"], .bs-react.is-mine{ background:var(--accent-soft); border-color:var(--violet-100); color:var(--accent-strong); }
.bs-react__n{ font-variant-numeric:tabular-nums; }
/* внутри своего пузыря (заливка --count-bg) мягкий тон --accent-soft полупрозрачен и сливается — подложка белая */
.bs-msg--mine .bs-react{ background:var(--card); border-color:transparent; }
.bs-msg--mine .bs-react[aria-pressed="true"], .bs-msg--mine .bs-react.is-mine{ background:var(--card); color:var(--accent-strong);
  box-shadow:inset 0 0 0 var(--bw-strong) var(--violet-200); }
.bs-react.is-static{ cursor:default; }
.bs-react.is-static:hover{ background:var(--card); }
.bs-react.is-static.is-mine:hover{ background:var(--accent-soft); }
.bs-toolbar{ display:inline-flex; align-items:center; gap:2px; padding:var(--sp-1); border-radius:var(--rad-pill);
  background:var(--card); border:var(--bw) solid var(--line2); box-shadow:var(--shadow-2); }
.bs-toolbar--emoji > button:not(.bs-btn){ display:grid; place-items:center; width:var(--ctl-sm); height:var(--ctl-sm); padding:0; border:0;
  border-radius:50%; background:transparent; cursor:pointer; font-size:var(--fs-lg); line-height:1;
  transition:background var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease); }
.bs-toolbar--emoji > button:not(.bs-btn):hover{ background:var(--bg2); transform:scale(1.12); }
.bs-toolbar--emoji > button:not(.bs-btn):focus-visible{ outline:none; box-shadow:var(--focus-ring); }
@media (prefers-reduced-motion:reduce){ .bs-react, .bs-toolbar--emoji > button{ transition:none; } }

/* ── Календарь (выбор даты / периода) · .bs-cal — этап 3, 29.10 ───────────────────────────────────────
   Месячная сетка в поповере выбора периода (src/ui/date-range.js). Стрелки месяцев — .bs-btn--secondary --icon --sm
   (кружки-листалки, как ‹ › доски CRM). День — КРУГ 32 (тач 44); наведение --bg2; «сегодня» — кольцо --accent;
   выходные — тон --err-text; чужой месяц — приглушён; тело диапазона — сплошная полоса --accent-soft со
   скруглёнными концами; края — залитый круг --count-bg
   (ступень темнее --accent, белый текст ≥ 4.5:1, тот же цвет, что у счётчика .bs-count).
   <div class="bs-cal"><div class="bs-cal__head"><button class="bs-btn bs-btn--ghost bs-btn--icon bs-btn--sm">‹</button>
     <span class="bs-cal__title">октябрь 2026</span><button …>›</button></div>
     <div class="bs-cal__week"><span class="bs-cal__wd">пн</span>…<span class="bs-cal__wd is-wknd">вс</span></div>
     <div class="bs-cal__days"><button class="bs-cal__d [is-out|is-wknd|is-today|is-in|is-edge is-start|is-end]">21</button>…</div></div> */
.bs-cal{ min-width:0; }
.bs-cal__head{ display:flex; align-items:center; justify-content:space-between; gap:var(--sp-2); margin-bottom:var(--sp-3); }
.bs-cal__title{ font:600 var(--fs-sm)/var(--lh-tight) var(--font); color:var(--ink); text-transform:capitalize; }
.bs-cal__week{ display:grid; grid-template-columns:repeat(7, 1fr); margin-bottom:var(--sp-2); }
.bs-cal__wd{ padding:var(--sp-1) 0; text-align:center; font:600 var(--fs-2xs)/1 var(--font); letter-spacing:.04em;
  text-transform:uppercase; color:var(--text-muted); }
.bs-cal__wd.is-wknd{ color:var(--text-muted); }   /* 30.10: выходные приглушённо, не «ошибкой» */
.bs-cal__days{ display:grid; grid-template-columns:repeat(7, 1fr); row-gap:var(--sp-1); }   /* 29.10: «больше воздуха» */
/* день — КРУГ (как остальные элементы ДС: пилюли, кружки-кнопки). Круг рисует ::before, ячейка —
   фон полосы периода: тело — сплошная мягкая полоса, края — полкруга полосы + залитый круг поверх */
.bs-cal__d{ position:relative; isolation:isolate; height:var(--ctl-sm); padding:0; border:0; background:transparent; cursor:pointer;
  color:var(--ink); font:500 var(--fs-xs)/1 var(--font); font-variant-numeric:tabular-nums; }
.bs-cal__d::before{ content:""; position:absolute; z-index:-1; top:0; bottom:0; left:50%; width:var(--ctl-sm); transform:translateX(-50%);
  border-radius:50%; transition:background var(--dur-fast) var(--ease); }
.bs-cal__d:hover:not([disabled]):not(.is-edge)::before{ background:var(--bg2); }
.bs-cal__d:focus-visible{ outline:none; }
.bs-cal__d:focus-visible::before{ box-shadow:var(--focus-ring); }
.bs-cal__d.is-out{ color:var(--text-muted); }
.bs-cal__d.is-wknd{ color:var(--ink2); }
.bs-cal__d.is-today::before{ box-shadow:inset 0 0 0 var(--bw-strong) var(--accent); }
.bs-cal__d.is-today{ color:var(--accent-strong); font-weight:700; }
.bs-cal__d.is-in{ background:var(--accent-soft); color:var(--accent-strong); }
.bs-cal__d.is-in:hover:not([disabled])::before{ background:color-mix(in srgb, var(--accent) 16%, transparent); }
.bs-cal__d.is-edge{ color:var(--on-accent); font-weight:700; }
.bs-cal__d.is-edge::before{ background:var(--count-bg); }
.bs-cal__d.is-start:not(.is-end){ background:linear-gradient(90deg, transparent 50%, var(--accent-soft) 50%); }
.bs-cal__d.is-end:not(.is-start){ background:linear-gradient(90deg, var(--accent-soft) 50%, transparent 50%); }
.bs-cal__d.is-start.is-end{ background:transparent; }
/* полоса не обрывается углом у края недели: первый/последний день ряда — скруглённый конец */
.bs-cal__d.is-in:nth-child(7n+1){ border-radius:var(--rad-pill) 0 0 var(--rad-pill); }
.bs-cal__d.is-in:nth-child(7n){ border-radius:0 var(--rad-pill) var(--rad-pill) 0; }
.bs-cal__d[disabled]{ color:var(--text-muted); opacity:.4; cursor:not-allowed; }
@media (pointer:coarse), (max-width:600px){ .bs-cal__d{ height:var(--ctl-md); font-size:var(--fs-sm); } .bs-cal__d::before{ width:var(--ctl-md); } }
@media (prefers-reduced-motion:reduce){ .bs-cal__d{ transition:none; } }

/* ── Поле со списком (комбобокс) · .bs-combo — этап 3, 29.10 ─────────────────────────────────────────
   Ввод с подсказками / поиском по длинному списку (раздел товара, адрес, модель принтера, сравнение).
   Список — ОДИН В ОДИН как у «Выбора» .bs-select выше (.ts-dropdown.bs-select-dd): рамка --line2, --rad-lg,
   --shadow-2, пункт --sp-2/--sp-3 с --rad-sm, наведение/стрелки — --bg2, выбранный — --accent-soft + галочка,
   совпадение — подсветка --warn-soft. Стрелка справа (__btn) — как у «Выбора»-кнопки: поворот при раскрытии.
   <div class="bs-combo [is-open|is-up]"><input class="bs-input" role="combobox" aria-expanded aria-controls>
     <button class="bs-combo__btn" tabindex="-1">chevron-down</button>
     <ul class="bs-combo__list" role="listbox"><li class="bs-combo__group">FDM</li>
       <li class="bs-combo__opt [is-active]" role="option" aria-selected>
         <span class="bs-combo__main"><span class="bs-combo__name">…</span><span class="bs-combo__sub">…</span></span>
         <span class="bs-combo__meta">256 мм</span></li>
       <li class="bs-combo__empty">Ничего не нашли</li></ul></div> */
.bs-combo{ position:relative; min-width:0; }
.bs-combo > .bs-input, .bs-combo > .bs-search{ width:100%; }
.bs-combo:has(> .bs-combo__btn) > .bs-input{ padding-right:calc(var(--sp-4) + var(--icon-sm) + var(--sp-2)); text-overflow:ellipsis; }
.bs-combo__btn{ position:absolute; top:0; right:0; bottom:0; width:var(--ctl-md); display:flex; align-items:center;
  justify-content:center; padding:0; border:0; background:none; color:var(--ink2); cursor:pointer; border-radius:0 var(--rad-pill) var(--rad-pill) 0; }
.bs-combo__btn .bs-ico, .bs-combo__btn svg{ width:var(--icon-sm); height:var(--icon-sm); transition:transform var(--dur) var(--ease); }
.bs-combo.is-open .bs-combo__btn .bs-ico, .bs-combo.is-open .bs-combo__btn svg{ transform:rotate(180deg); }
.bs-combo__list{ position:absolute; z-index:var(--z-popover); top:calc(100% + var(--sp-1)); left:0; right:0; margin:0;
  padding:var(--sp-1); list-style:none; max-height:min(360px, 60vh); overflow-y:auto; overscroll-behavior:contain;
  background:var(--card); border:var(--bw) solid var(--line2); border-radius:var(--rad-lg); box-shadow:var(--shadow-2);
  font:400 var(--fs-sm) var(--font); color:var(--ink); text-align:left; }
.bs-combo__list[hidden]{ display:none; }
.bs-combo.is-up .bs-combo__list{ top:auto; bottom:calc(100% + var(--sp-1)); }
.bs-combo__group{ position:sticky; top:calc(-1 * var(--sp-1)); z-index:1; padding:var(--sp-2) var(--sp-3) var(--sp-1); background:var(--card);
  font:700 var(--fs-2xs) var(--font); letter-spacing:.06em; text-transform:uppercase; color:var(--text-muted); }
.bs-combo__opt{ display:flex; align-items:center; gap:var(--sp-3); padding:var(--sp-2) var(--sp-3); border-radius:var(--rad-sm); cursor:pointer; }
.bs-combo__opt:hover, .bs-combo__opt.is-active{ background:var(--bg2); color:var(--ink); }
.bs-combo__opt[aria-selected="true"]{ background:var(--accent-soft); color:var(--violet-700); font-weight:600; }
.bs-combo__opt[aria-selected="true"]:not(:has(.bs-ico))::after{ content:""; flex:none; width:var(--icon-sm); height:var(--icon-sm); margin-left:auto;
  background:currentColor; -webkit-mask:var(--icon-check) center/contain no-repeat; mask:var(--icon-check) center/contain no-repeat; }
.bs-combo__main{ flex:1 1 auto; min-width:0; display:flex; flex-direction:column; gap:2px; }
.bs-combo__name{ min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.bs-combo__sub{ min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; font-size:var(--fs-xs); font-weight:400; color:var(--text-muted); }
.bs-combo__meta{ flex:none; font-size:var(--fs-xs); color:var(--text-muted); font-variant-numeric:tabular-nums; }
.bs-combo__opt[aria-selected="true"] .bs-combo__sub, .bs-combo__opt[aria-selected="true"] .bs-combo__meta{ color:var(--violet-700); }
.bs-combo__empty{ padding:var(--sp-3); text-align:center; font-size:var(--fs-sm); color:var(--text-muted); line-height:var(--lh-normal); }
.bs-combo__list mark, .bs-combo__hl{ background:var(--warn-soft); color:inherit; border-radius:var(--rad-2xs); }
@media (prefers-reduced-motion:reduce){ .bs-combo__btn .bs-ico, .bs-combo__btn svg{ transition:none; } }

/* ── «Раздел маркетплейса» с поиском · .bs-catc (src/ui/category-combo.js, форма товара; перенос 28.10) ──
   Поле-пилюля .pp-input + стрелка «Показать все разделы» справа — тот же вид, что у «Выбора» .bs-select выше:
   иконка --ink2, при раскрытии поворачивается на 180°. Стрелка вне Tab-порядка (tabindex=-1): с клавиатуры
   список открывают ↓/Enter в самом поле. Выпадающий список — .pp-combo-list (pop.css) + правки модуля.
   <div class="pp-combo bs-catc"><input class="pp-input bs-catc__q" role="combobox">
     <button type="button" class="bs-catc__btn" tabindex="-1" aria-label="Показать все разделы">…chevron-down…</button></div> */
.bs-catc__q{ padding-right:calc(var(--sp-4) + var(--icon-sm) + var(--sp-2)); text-overflow:ellipsis; }
.bs-catc__btn{ position:absolute; top:0; right:0; bottom:0; width:var(--ctl-md); display:flex; align-items:center;
  justify-content:center; padding:0; border:0; background:none; color:var(--ink2); cursor:pointer;
  border-radius:0 var(--rad-pill) var(--rad-pill) 0; }
.bs-catc__btn .bs-ico{ width:var(--icon-sm); height:var(--icon-sm); transition:transform var(--dur) var(--ease); }
.bs-catc.is-open .bs-catc__btn .bs-ico{ transform:rotate(180deg); }
@media (prefers-reduced-motion:reduce){ .bs-catc__btn .bs-ico{ transition:none; } }

@media (pointer:coarse){ .bs-btn--sm,.bs-input--sm{ min-height:40px; } }
/* 29.10: кружок-значок --sm на тач-экране остаётся КРУГОМ 40×40 (раньше 32 в ширину × 40 в высоту = овал) */
@media (pointer:coarse){ .bs-btn--icon.bs-btn--sm{ width:40px; } }
@media (prefers-reduced-motion:reduce){
  .bs-btn,.bs-input,.bs-switch input,.bs-switch input::before,.bs-pcard,.bs-check input::before,.bs-radio input::before,.bs-tabs__item,.bs-search,.bs-search__clear{ transition:none; }
  .bs-btn--primary:hover:not(:disabled),.bs-pcard:hover{ transform:none; }
  .bs-btn.is-loading::after{ animation-duration:2s; }
}
.bs-toast:not(:has(.bs-btn)){ padding-right:var(--sp-5); }

/* ── Иконки: спрайт /icons.svg (Lucide 0.460.0 + бренд bs-*), вставка — icon() из src/ui/icon.js.
   Одна толщина линии и цвет текста; по умолчанию размер = размер шрифта. */
:where(.bs-ico){ width:1em; height:1em; flex:none; display:inline-block; vertical-align:-0.125em;
  fill:none; stroke:currentColor; stroke-width:var(--icon-stroke,2); stroke-linecap:round; stroke-linejoin:round; }
/* :where — нулевая специфичность: старые классы размеров (.pn-ico, .cm-ico…) продолжают работать */
.bs-ico--sm{ width:var(--icon-sm); height:var(--icon-sm); }
.bs-ico--md{ width:var(--icon-md); height:var(--icon-md); }
.bs-ico--lg{ width:var(--icon-lg); height:var(--icon-lg); }
.bs-ico.is-spin{ animation:bs-ico-spin 1s linear infinite; }
@keyframes bs-ico-spin{ to{ transform:rotate(360deg); } }
@media (prefers-reduced-motion:reduce){ .bs-ico.is-spin{ animation:none; } }

/* ── Чекбокс и радио по всему сайту (шаг 3) ─────────────────────────────────
   Любой нативный input[type=checkbox|radio] получает вид .bs-check/.bs-radio. :where — нулевая
   специфичность: скрытые input внутри тумблеров (.pp-switch/.cm-switch: opacity 0, размер по
   классу) и особые чекбоксы со своими классами не затрагиваются. */
:where(input[type="checkbox"], input[type="radio"]){
  -webkit-appearance:none; appearance:none; margin:0; flex:none; width:20px; height:20px;
  display:inline-grid; place-content:center; vertical-align:-0.3em; cursor:pointer;
  border:var(--bw) solid var(--line-field); background:var(--card);
  transition:background var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}
:where(input[type="checkbox"]){ border-radius:var(--rad-xs); }
:where(input[type="radio"]){ border-radius:50%; }
:where(input[type="checkbox"])::before{ content:""; width:12px; height:12px; background:var(--accent-ink);
  -webkit-mask:var(--icon-check) center/contain no-repeat; mask:var(--icon-check) center/contain no-repeat;
  transform:scale(0); transition:transform var(--dur-fast) var(--ease-bounce); }
:where(input[type="radio"])::before{ content:""; width:10px; height:10px; border-radius:50%; background:var(--accent-ink);
  transform:scale(0); transition:transform var(--dur-fast) var(--ease-bounce); }
:where(input[type="checkbox"], input[type="radio"]):checked{ background:var(--violet-600); border-color:var(--violet-600); }
:where(input[type="checkbox"], input[type="radio"]):checked::before{ transform:scale(1); }
:where(input[type="checkbox"]):indeterminate{ background:var(--violet-600); border-color:var(--violet-600); }
:where(input[type="checkbox"]):indeterminate::before{ -webkit-mask:none; mask:none; height:2px; transform:scale(1); }
:where(input[type="checkbox"], input[type="radio"]):hover:not(:checked):not(:disabled){ border-color:var(--ink2); }
:where(input[type="checkbox"], input[type="radio"]):focus-visible{ outline:none; box-shadow:var(--focus-ring); }
:where(input[type="checkbox"], input[type="radio"]):disabled{ opacity:.45; cursor:not-allowed; }
/* малый «Выбор» (32) — для рядов фильтров, в пару к .bs-btn--sm и .bs-input--sm */
.ts-wrapper.bs-select.bs-select--sm .ts-control{ min-height:var(--ctl-sm); padding-left:var(--sp-3); font-size:var(--fs-ctl); }

/* ── Подразделы (ревью C-01): вкладки-ссылки внутри раздела, вид = .bs-seg («белая поверхность»).
   Шапка сообщества «Лента / Группы / Люди» переехала на .bs-tabs (22.10, 4.2 Б); класс остаётся для
   ссылочных подразделов и как база --brand (хабы).
   <nav class="bs-subnav" aria-label="…"><a href aria-current="page">Лента</a>…</nav> */
.bs-subnav{ display:inline-flex; gap:var(--sp-1); padding:calc(var(--sp-1) - var(--bw)); margin:0 0 var(--sp-4); background:var(--card);
  border:var(--bw) solid var(--line2); box-shadow:var(--bs-raise);
  border-radius:var(--rad-pill); max-width:100%; overflow-x:auto; scrollbar-width:none;
  transition:border-color var(--dur) var(--ease); }
/* наведение — как у .bs-seg (вкладки маркетплейса стали ссылками, Ф2 23.10): рамка дорожки темнее,
   пункт — лёгкое затемнение --hover-fill. Иначе кнопки и ссылки одного сегмента отвечали бы по-разному. */
.bs-subnav:not(.bs-subnav--brand):hover{ border-color:color-mix(in srgb, var(--ink) 22%, var(--line2)); }
.bs-subnav::-webkit-scrollbar{ display:none; }
.bs-subnav a{ display:inline-flex; align-items:center; min-height:calc(var(--ctl-md) - 2 * var(--sp-1)); padding:0 var(--sp-4);
  border-radius:var(--rad-pill); font:500 var(--fs-sm)/1 var(--font); color:var(--ink); text-decoration:none; white-space:nowrap;
  transition:background var(--dur) var(--ease), color var(--dur) var(--ease); }
.bs-subnav a:hover:not([aria-current]){ background:var(--hover-fill); }
.bs-subnav a[aria-current]{ background:var(--accent-soft); color:var(--accent-strong); -webkit-text-stroke:var(--bs-bold-stroke) currentColor; }
.bs-subnav a:focus-visible{ outline:none; box-shadow:var(--focus-ring); }
/* вариант --brand: активный раздел — фирменный градиент (как главная кнопка). Для верхнего
   уровня разделов, где навигация — заметный элемент страницы (хаб базы знаний).
   <nav class="bs-subnav bs-subnav--brand">…</nav> */
.bs-subnav--brand{ background:var(--accent-soft); border-color:transparent; box-shadow:none; padding:var(--sp-1); }   /* хабы: вид решён владельцем ранее — не меняется */
.bs-subnav--brand a{ font-weight:600; color:var(--ink2); -webkit-text-stroke:0; }
.bs-subnav--brand a:hover:not([aria-current]){ background:transparent; color:var(--ink); }
.bs-subnav--brand a[aria-current]{ background:var(--grad-btn); color:var(--on-accent); box-shadow:var(--shadow-btn); -webkit-text-stroke:0; }

/* ── Плашки мастера (A-23): «Проверен» (bs-badge--ok) и «Новичок» (bs-badge--accent) рядом.
   Одна разметка на профиле, товаре и витрине: SSR-макрос _master_badges.html и
   frontend/src/ui/master-badges.js. */
.bs-mbadges{ display:inline-flex; flex-wrap:wrap; align-items:center; gap:var(--sp-1); vertical-align:middle; }

/* ── Чип выбранного фильтра (снимаемый) — ряд «что выбрано» под панелью каталога ──
   <span class="bs-fchip"><span class="bs-fchip__label">PLA</span>
     <button class="bs-fchip__x" type="button" aria-label="Убрать фильтр PLA">{icon('x')}</button></span>
   Пилюля 32 (на тач-экране 40), мягкий акцент; крестик — отдельная кнопка-круг 20 с зоной нажатия 32.
   Не путать с .bs-filter: тот — переключатель (вкл/выкл), этот — уже выбранное значение. (пилот «каталог», 21.10) */
.bs-fchip{ display:inline-flex; align-items:center; gap:var(--sp-1); min-height:var(--ctl-sm); max-width:100%;
  padding:0 var(--sp-1) 0 var(--sp-3); border-radius:var(--rad-pill); background:var(--accent-soft); color:var(--violet-700);
  font:600 var(--fs-ctl)/1 var(--font); white-space:nowrap; }
.bs-fchip__label{ min-width:0; overflow:hidden; text-overflow:ellipsis; }
.bs-fchip__x{ flex:none; position:relative; display:grid; place-items:center; width:20px; height:20px; padding:0;
  border:0; border-radius:50%; background:transparent; color:inherit; cursor:pointer;
  transition:background var(--dur) var(--ease), color var(--dur) var(--ease); }
.bs-fchip__x::before{ content:""; position:absolute; inset:calc((20px - var(--ctl-sm)) / 2); }   /* зона нажатия 32 */
.bs-fchip__x svg{ width:14px; height:14px; }
.bs-fchip__x:hover{ background:var(--violet-600); color:var(--accent-ink); }
.bs-fchip__x:focus-visible{ outline:none; box-shadow:var(--focus-ring); }

/* ── Поле цвета: <input type="color" class="bs-colorin"> — квадрат высотой поля (44, --sm 32),
   рамка как у .bs-input, образец внутри скруглён. Рядом обычно .bs-swatch (готовые цвета). (28.10) */
.bs-colorin{ flex:none; width:var(--ctl-md); height:var(--ctl-md); padding:var(--bw-strong); cursor:pointer;
  background:var(--card); border:var(--bw) solid var(--line-field); border-radius:var(--rad-sm);
  transition:border-color var(--dur) var(--ease); }
.bs-colorin:hover{ border-color:color-mix(in srgb, var(--ink) 22%, var(--line-field)); }
.bs-colorin:focus-visible{ outline:none; box-shadow:var(--focus-ring); }
.bs-colorin::-webkit-color-swatch-wrapper{ padding:0; }
.bs-colorin::-webkit-color-swatch{ border:0; border-radius:var(--rad-xs); }
.bs-colorin::-moz-color-swatch{ border:0; border-radius:var(--rad-xs); }
.bs-colorin--sm{ width:var(--ctl-sm); height:var(--ctl-sm); }

/* ── Счётчик: «Фильтры ②», «Заказы 5», колокольчик и корзина в шапке. Кружок 20, ОДИН вид везде —
   фиолетовая заливка --count-bg (ступень темнее --accent, 12.3 Б), цифра --on-accent (решение владельца 22.10, 3.2 А: «везде фиолетовые»;
   мягкий вариант --soft снят — класс оставлен псевдонимом, чтобы старая разметка не пропала).
   <button class="bs-btn bs-btn--secondary">Фильтры <span class="bs-count">2</span></button>
   В углу значка (колокольчик, корзина в шапке) — тот же цвет, геометрия угла своя (16 + белый ободок). */
.bs-count,.bs-count--soft{ display:inline-grid; place-items:center; flex:none; min-width:20px; height:20px; padding:0 var(--sp-1);
  border-radius:var(--rad-pill); background:var(--count-bg); color:var(--on-accent);
  font:700 var(--fs-2xs)/1 var(--font); font-variant-numeric:tabular-nums; }
.bs-count[hidden]{ display:none; }
/* тоны: --quiet — второстепенное число (рельс объектов, заглушённый чат); --warn / --bad — «внимание» / «проблема»
   (срезы CRM, тревоги сторожа); --inverse — белая пилюля с фиолетовой цифрой. На выбранном фильтре, текущем пункте
   навигации и залитой кнопке счётчик становится --inverse сам — классы на месте не нужны. */
.bs-count--quiet{ background:var(--bg2); color:var(--ink2); }
.bs-count--warn{ background:var(--amber-100); color:var(--amber-800); }
.bs-count--bad{ background:var(--rose-100); color:var(--rose-700); }
.bs-count--inverse,
:is(.bs-filter[aria-pressed="true"],.bs-filter.is-on,.bs-filter.is-active,.bs-navlist__item[aria-current="true"],.bs-navlist__item.is-active,.bs-btn--primary,.bs-btn--buy) .bs-count{
  background:var(--card); color:var(--accent-strong); }
/* в углу кнопки-значка (колокольчик, корзина в шапке): поверх правого верхнего угла, ободок цветом фона */
.bs-count--corner{ position:absolute; top:var(--sp-1); left:calc(50% + var(--sp-1)); right:auto;   /* от правого плеча значка вправо: «9+» растёт наружу, а не поверх значка */
  min-width:18px; height:18px; box-shadow:0 0 0 2px var(--bg); pointer-events:none; }   /* ds-ok: счётчик, не контрол */
/* у маленькой кнопки-значка (32, шапка с 30.10) — выше и ближе к центру: «9+» не вылезает на соседнюю кнопку */
.bs-btn--sm > .bs-count--corner{ top:calc(-1 * var(--sp-1)); left:50%; }

/* ── «Выбор» в виде кнопки secondary (сортировка в панели каталога): высота 44, пилюля, «белая
   поверхность» (рамка --line2, тень --shadow-1), текст 500 — стоит в одном ряду с .bs-btn--secondary
   и не отличается от неё.
   Нативный <select class="bs-select bs-select--btn">; если страница включает Tom Select
   (enhanceSelect), классы переходят на обёртку — правило для .ts-wrapper ниже. */
select.bs-select--btn{ -webkit-appearance:none; appearance:none; width:auto; max-width:100%; min-height:var(--ctl-md);
  padding:0 calc(var(--sp-4) + var(--icon-sm) + var(--sp-2)) 0 var(--sp-4);
  border:var(--bw) solid var(--line2); border-radius:var(--rad-pill); box-shadow:var(--bs-raise); cursor:pointer;
  background:var(--card) var(--icon-chevron-down) no-repeat right var(--sp-4) center/var(--icon-sm) var(--icon-sm);
  color:var(--ink); font:500 var(--fs-sm) var(--font);
  transition:border-color var(--dur) var(--ease), background-color var(--dur) var(--ease); }
select.bs-select--btn:hover{ border-color:color-mix(in srgb, var(--ink) 22%, var(--line2)); }
select.bs-select--btn:focus-visible{ outline:none; box-shadow:var(--focus-ring); }
.ts-wrapper.bs-select.bs-select--btn{ width:auto; }
.ts-wrapper.bs-select.bs-select--btn .ts-control{ --ts-pr-min:calc(var(--sp-4) + var(--icon-sm) + var(--sp-2)); --ts-pr-clear-button:0px; --ts-pr-caret:0px; }
/* ↑ место под стрелку. tom-select.css ставит padding-right:max(--ts-pr-min, --ts-pr-clear-button + --ts-pr-caret) !important,
   а его «0 + 0» без единиц делает max() недействительным → padding-right 0 и текст под стрелкой. Единицы чинят. */
.ts-wrapper.bs-select.bs-select--btn .ts-control{ border:var(--bw) solid var(--line2); box-shadow:var(--bs-raise); }
.ts-wrapper.bs-select.bs-select--btn .ts-control,
.ts-wrapper.bs-select.bs-select--btn .ts-control .item{ font-weight:500; white-space:nowrap; }
/* 22.10 (владелец: «двойная обводка у нас в ДС?»): у селекта-КНОПКИ нет «фокуса поля» (тёмная рамка
   + ореол, 2.2 А — это для полей ввода). Открыт/нажат — рамка темнее, как при наведении; кольцо
   фокуса — только с клавиатуры, одно, как у .bs-btn. */
.ts-wrapper.bs-select.bs-select--btn.focus .ts-control,
.ts-wrapper.bs-select.bs-select--btn.dropdown-active .ts-control{ border-color:color-mix(in srgb, var(--ink) 22%, var(--line2)); box-shadow:var(--bs-raise); outline:none; }
.ts-wrapper.bs-select.bs-select--btn .ts-control:focus{ outline:none; }
html[data-kbd] .ts-wrapper.bs-select.bs-select--btn:not(.dropdown-active) .ts-control:focus{ box-shadow:var(--focus-ring); }   /* data-kbd ставит src/ui/select.js по Tab, снимает по клику: Tom Select фокусирует поле программно, и :focus-visible срабатывал и от мыши */
.ts-wrapper.bs-select.bs-select--btn .ts-control:hover{ border-color:color-mix(in srgb, var(--ink) 22%, var(--line2)); }
@media (pointer:coarse){ .bs-fchip{ min-height:40px; } .bs-fchip__x::before{ inset:-10px; } }

/* ── Список разделов (решение 22.10, К1 Б + 15.4 Б) ─────────────────────────────────────────────
   Один вид списка разделов на ПК (меню слева) и на телефоне (шторка выбора раздела): подписи групп
   капсом (--fs-2xs, --text-muted), пункты-строки «иконка + подпись» со скруглением --rad-md, выбранный —
   как выбранное в .bs-seg (--accent-soft / --accent-strong, жирность обводкой — ширина не прыгает),
   счётчик — .bs-count, тихое значение (баланс токенов) — .bs-navlist__meta. НЕ сетка плиток.
   <div class="bs-navlist"><div class="bs-navlist__group">Продажи</div>
     <button class="bs-navlist__item" aria-current="page"><span class="bs-navlist__ico">svg</span>
       <span class="bs-navlist__label">Заказы</span><span class="bs-count">4</span></button>…</div> */
.bs-navlist{ display:flex; flex-direction:column; gap:var(--sp-1); min-width:0; }
.bs-navlist__group{ padding:var(--sp-3) var(--sp-3) var(--sp-1); font:600 var(--fs-2xs)/var(--lh-tight) var(--font);
  letter-spacing:.06em; text-transform:uppercase; color:var(--text-muted); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.bs-navlist__group:first-child{ padding-top:0; }
.bs-navlist__item{ appearance:none; display:flex; align-items:center; gap:var(--sp-3); width:100%; min-height:var(--ctl-md);
  padding:0 var(--sp-3); border:0; border-radius:var(--rad-md); background:transparent; cursor:pointer; text-align:left;
  text-decoration:none; color:var(--ink); font:500 var(--fs-sm)/var(--lh-tight) var(--font); position:relative;
  transition:background var(--dur) var(--ease), color var(--dur) var(--ease); }
.bs-navlist__item:hover{ background:var(--bg2); }
.bs-navlist__item:is([aria-current="page"],[aria-pressed="true"],.is-active){ background:var(--accent-soft); color:var(--accent-strong);
  -webkit-text-stroke:var(--bs-bold-stroke) currentColor; }
.bs-navlist__item:focus-visible{ outline:none; box-shadow:var(--focus-ring); }
.bs-navlist__ico{ flex:none; display:grid; place-items:center; width:var(--icon-md); height:var(--icon-md); color:var(--ink2); }
.bs-navlist__ico svg{ width:var(--icon-md); height:var(--icon-md); display:block; }
.bs-navlist__item:is([aria-current="page"],[aria-pressed="true"],.is-active) .bs-navlist__ico{ color:var(--accent-strong); }
.bs-navlist__label{ flex:1 1 auto; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.bs-navlist__meta{ flex:none; font:500 var(--fs-xs)/1 var(--font); color:var(--text-muted); -webkit-text-stroke:0; font-variant-numeric:tabular-nums; }
.bs-navlist__item .bs-count{ -webkit-text-stroke:0; }
.bs-navlist__item--quiet{ color:var(--ink2); }
@media (prefers-reduced-motion:reduce){ .bs-navlist__item{ transition:none; } }
/* пачка 3 · админка · 23.10 — плотный список (--sm: много разделов, в админке 24) и сворачиваемая
   группа: подпись-кнопка <button class="bs-navlist__group" aria-expanded> + шеврон .bs-navlist__chev,
   пункты группы — в .bs-navlist__sub (hidden, когда свёрнута).
   <div class="bs-navlist bs-navlist--sm"><button class="bs-navlist__group" aria-expanded="true">
     <span class="bs-navlist__label">Деньги</span><span class="bs-navlist__chev">svg</span></button>
     <div class="bs-navlist__sub">…пункты…</div></div> */
.bs-navlist--sm{ gap:2px; }
.bs-navlist--sm .bs-navlist__item{ min-height:var(--ctl-sm); padding:0 var(--sp-2); gap:var(--sp-2); font-size:var(--fs-ctl); border-radius:var(--rad-sm); }
.bs-navlist--sm .bs-navlist__ico,
.bs-navlist--sm .bs-navlist__ico svg{ width:var(--icon-sm); height:var(--icon-sm); }
.bs-navlist--sm .bs-navlist__group{ padding:var(--sp-3) var(--sp-2) var(--sp-1); }
.bs-navlist__sub{ display:flex; flex-direction:column; gap:inherit; }
.bs-navlist__sub[hidden]{ display:none; }
button.bs-navlist__group{ appearance:none; display:flex; align-items:center; gap:var(--sp-2); width:100%; border:0; background:none;
  cursor:pointer; text-align:left; border-radius:var(--rad-sm); }
button.bs-navlist__group:hover{ color:var(--ink); }
button.bs-navlist__group:focus-visible{ outline:none; box-shadow:var(--focus-ring); }
button.bs-navlist__group .bs-count{ letter-spacing:0; }
.bs-navlist__chev{ flex:none; display:inline-flex; margin-left:auto; transition:transform var(--dur) var(--ease); }
.bs-navlist__chev svg{ width:var(--icon-sm); height:var(--icon-sm); }
.bs-navlist__group[aria-expanded="false"] .bs-navlist__chev{ transform:rotate(-90deg); }
@media (prefers-reduced-motion:reduce){ .bs-navlist__chev{ transition:none; } }

/* ── Меню разделов кабинета (решение 22.10, К1 Б; телефон — 15.4 Б) ──────────────────────────────
   Колонка слева от рабочей области (ширину ~200 задаёт страница): вверху карточка владельца
   (аватар + имя + «Открыть витрину ↗», «Моя страница ↗»), ниже .bs-navlist, внизу тихие действия и
   «Свернуть в иконки». Свёрнуто (.is-collapsed) — только иконки, подпись в title, счётчик — точкой.
   На телефоне (≤900) колонки нет: кнопка «Раздел: <текущий> ▾» (.bs-btn--secondary во всю ширину,
   иконка раздела слева) открывает шторку .bs-dialog--side (на телефоне — снизу) с тем же списком.
   <nav class="bs-sidenav"><button class="bs-btn bs-btn--secondary bs-btn--block bs-sidenav__toggle">…</button>
     <div class="bs-sidenav__panel"><div class="bs-sidenav__head">…</div><div class="bs-navlist">…</div>
       <div class="bs-sidenav__foot">…</div></div></nav>
   <dialog class="bs-dialog bs-dialog--side bs-sidenav__sheet">…тот же список…</dialog> */
.bs-sidenav{ display:flex; flex-direction:column; gap:var(--sp-1); min-width:0; }
.bs-sidenav__panel{ display:flex; flex-direction:column; gap:var(--sp-1); min-width:0; }
.bs-sidenav__head{ display:flex; align-items:center; gap:var(--sp-3); min-width:0;
  padding:0 var(--sp-2) var(--sp-3); margin-bottom:var(--sp-2); border-bottom:var(--bw) solid var(--line); }
.bs-sidenav__ava{ flex:none; width:40px; height:40px; border-radius:50%; overflow:hidden; display:grid; place-items:center;
  background:var(--accent-soft); color:var(--accent-strong); font:var(--fw-bold) var(--fs-base)/1 var(--font); }
.bs-sidenav__ava img{ width:100%; height:100%; object-fit:cover; display:block; }
.bs-sidenav__who{ display:flex; flex-direction:column; gap:var(--sp-1); min-width:0; }
.bs-sidenav__name{ font:600 var(--fs-sm)/var(--lh-tight) var(--font); color:var(--ink);
  display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden; overflow-wrap:anywhere; }
.bs-sidenav__links{ display:flex; flex-direction:column; align-items:flex-start; gap:var(--sp-1); }
.bs-sidenav__link{ display:inline-flex; align-items:center; gap:var(--sp-1); font:500 var(--fs-xs)/var(--lh-tight) var(--font);
  color:var(--accent-text); text-decoration:none; white-space:nowrap; }
.bs-sidenav__link:hover{ text-decoration:underline; text-underline-offset:3px; }
.bs-sidenav__link:focus-visible{ outline:none; box-shadow:var(--focus-ring); border-radius:var(--rad-xs); }
.bs-sidenav__link svg{ width:var(--icon-sm); height:var(--icon-sm); flex:none; }
.bs-sidenav__foot{ display:flex; flex-direction:column; gap:var(--sp-1); margin-top:var(--sp-2); padding-top:var(--sp-2); border-top:var(--bw) solid var(--line); }
.bs-sidenav__toggle{ display:none; }
.bs-sidenav__toggle .bs-sidenav__current{ flex:1 1 auto; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; text-align:left; }
.bs-sidenav__toggle .bs-sidenav__kicker{ color:var(--ink2); font-weight:500; }
.bs-sidenav__sheet > .bs-dialog__body{ padding-top:0; color:var(--ink); }
/* свёрнуто в иконки (ПК) */
.bs-sidenav.is-collapsed .bs-sidenav__head{ justify-content:center; padding-inline:0; }
.bs-sidenav.is-collapsed :is(.bs-sidenav__who,.bs-navlist__label,.bs-navlist__meta,.bs-navlist__group){ display:none; }
.bs-sidenav.is-collapsed .bs-navlist__item{ justify-content:center; padding:0; }
.bs-sidenav.is-collapsed .bs-navlist__item .bs-count{ position:absolute; top:var(--sp-1); right:var(--sp-1); min-width:var(--sp-2); height:var(--sp-2);
  padding:0; font-size:0; }   /* в узкой рейке — точка-сигнал, число в подсказке */
@media (max-width:900px){
  .bs-sidenav__toggle{ display:flex; justify-content:flex-start; }
  .bs-sidenav__panel{ display:none; }
}
/* ── Полоса прогресса (статичная: «сделано N из M») и полоса запуска (решение 22.10, К3 Б) ─────────
   .bs-progressbar — трек 6 (--bg2 → --line2) с заливкой --ok; ширину заливки задаёт страница
   (style="--bs-progress:40%"), role="progressbar" + aria-valuenow/max — на треке. Не путать с
   полосой ожидания загрузки (src/ui/ui-progress.js, проценты байт).
   .bs-setup — одна строка «Заголовок · прогресс · N из M · Дальше: шаг →»; нажатие на строку
   раскрывает список шагов (.bs-setup__list, ссылки; сделанное — .is-done). Показывается, пока
   настройка не завершена.
   <section class="bs-setup"><div class="bs-setup__row">
     <button class="bs-setup__toggle" aria-expanded="false" aria-controls="steps">
       <span class="bs-setup__title">Запуск витрины</span>
       <span class="bs-progressbar" role="progressbar" aria-valuenow="2" aria-valuemax="5" style="--bs-progress:40%"></span>
       <span class="bs-setup__count">2 из 5</span><span class="bs-setup__chev">svg</span></button>
     <a class="bs-btn bs-btn--tonal bs-btn--sm" href="…">Дальше: адрес →</a></div>
     <ol class="bs-setup__list" id="steps" hidden><li class="bs-setup__step is-done">…</li></ol></section> */
.bs-progressbar{ display:block; position:relative; height:6px; min-width:64px; border-radius:var(--rad-pill); background:var(--line2); overflow:hidden; }
.bs-progressbar::after{ content:""; position:absolute; inset:0 auto 0 0; width:var(--bs-progress, 0%); border-radius:inherit; background:var(--ok);
  transition:width var(--dur-slow) var(--ease); }
.bs-setup{ --bs-raise:none; background:var(--card); border:var(--bw) solid var(--line); border-radius:var(--rad-lg); }
.bs-setup__row{ display:flex; align-items:center; gap:var(--sp-3); padding:var(--sp-2) var(--sp-2) var(--sp-2) var(--sp-4); }
.bs-setup__toggle{ appearance:none; flex:1 1 auto; min-width:0; display:flex; align-items:center; gap:var(--sp-3); min-height:var(--ctl-sm);
  padding:0; border:0; background:none; color:var(--ink); cursor:pointer; text-align:left; font:600 var(--fs-sm)/var(--lh-tight) var(--font); border-radius:var(--rad-sm); }
.bs-setup__toggle:focus-visible{ outline:none; box-shadow:var(--focus-ring); }
.bs-setup__title{ flex:none; white-space:nowrap; }
.bs-setup__toggle .bs-progressbar{ flex:1 1 auto; max-width:220px; }
.bs-setup__count{ flex:none; font:500 var(--fs-sm)/1 var(--font); color:var(--ink2); font-variant-numeric:tabular-nums; white-space:nowrap; }
.bs-setup__chev{ flex:none; display:grid; color:var(--ink2); transition:transform var(--dur) var(--ease); }
.bs-setup__chev svg{ width:var(--icon-sm); height:var(--icon-sm); }
.bs-setup__toggle[aria-expanded="true"] .bs-setup__chev{ transform:rotate(180deg); }
.bs-setup__row > .bs-btn{ flex:none; }
.bs-setup__list{ list-style:none; margin:0; padding:var(--sp-1) var(--sp-2) var(--sp-3); display:grid; grid-template-columns:repeat(auto-fit, minmax(180px, 1fr));
  gap:var(--sp-2); border-top:var(--bw) solid var(--line); padding-top:var(--sp-3); }
.bs-setup__list[hidden]{ display:none; }
.bs-setup__step{ min-width:0; }
.bs-setup__link{ display:flex; align-items:flex-start; gap:var(--sp-2); height:100%; padding:var(--sp-2) var(--sp-3); border-radius:var(--rad-md);
  color:var(--ink); text-decoration:none; font:600 var(--fs-sm)/var(--lh-tight) var(--font); }
a.bs-setup__link:hover{ background:var(--bg2); }
a.bs-setup__link:focus-visible{ outline:none; box-shadow:var(--focus-ring); }
.bs-setup__mark{ flex:none; display:grid; place-items:center; width:var(--icon-md); height:var(--icon-md); border-radius:50%;
  border:var(--bw-strong) solid var(--line2); color:var(--on-accent); }
.bs-setup__mark svg{ width:12px; height:12px; }
.bs-setup__step.is-done .bs-setup__mark{ background:var(--ok); border-color:var(--ok); }
.bs-setup__step.is-done .bs-setup__link{ color:var(--ink2); }
.bs-setup__txt{ display:flex; flex-direction:column; gap:var(--sp-1); min-width:0; }
.bs-setup__hint{ font:400 var(--fs-xs)/var(--lh-normal) var(--font); color:var(--ink2); }
@media (max-width:600px){
  .bs-setup__row{ flex-wrap:wrap; padding:var(--sp-3); }
  .bs-setup__toggle{ flex-basis:100%; }
  .bs-setup__row > .bs-btn{ flex:1 1 auto; }
  .bs-setup__list{ grid-template-columns:1fr; }
}
@media (prefers-reduced-motion:reduce){ .bs-progressbar::after,.bs-setup__chev{ transition:none; } }

/* ── Экран-форма (решение 22.10, К6 Б) ───────────────────────────────────────────────────────────
   Формы кабинета (реквизиты, отправитель, мастерская, моя страница, партнёрка, акции, настройки,
   уведомления): колонка формы до 640 слева, подсказки — колонка справа рядом (липкая, .bs-note
   --info), а не плашки внутри формы. Таблицы, доски, статистика, конструктор — во всю ширину (без
   этого класса). На узком (≤900) — одна колонка, подсказки под формой.
   <div class="bs-formpage"><div class="bs-formpage__main">форма</div>
     <aside class="bs-formpage__aside"><div class="bs-note bs-note--info">…</div></aside></div> */
.bs-formpage{ display:grid; grid-template-columns:minmax(0, 640px) minmax(220px, 320px); gap:var(--sp-8); align-items:start; }
/* колонка подсказок — у ПРАВОГО края раздела, на одной линии с концом ряда вкладок над ней (пачка 1, п.5.5:
   было 640+32+320 = 992 при ширине 1008 → подсказка обрывалась на 8px раньше линии вкладок) */
.bs-formpage:not(.bs-formpage--solo){ justify-content:space-between; }
.bs-formpage__main{ min-width:0; display:flex; flex-direction:column; gap:var(--sp-4); }
.bs-formpage__aside{ position:sticky; top:80px;   /* под липкой шапкой сайта (56) + ряд вкладок */ display:flex; flex-direction:column; gap:var(--sp-3); min-width:0; }
.bs-formpage__aside:empty{ display:none; }
.bs-formpage--solo{ grid-template-columns:minmax(0, 640px); }
@media (max-width:900px){
  .bs-formpage{ grid-template-columns:minmax(0, 1fr); gap:var(--sp-4); }
  .bs-formpage__aside{ position:static; }
}

/* ── Полоса «Сохранить» (решение 22.10, К7 Б) ────────────────────────────────────────────────────
   Липкая полоса снизу: «Есть несохранённые изменения · Отменить (ghost) · Сохранить (primary)».
   Появляется только при изменениях формы ([hidden] — нет изменений), уход со страницы с
   несохранённым — с предупреждением. Поведение — src/ui/ui-savebar.js (attachSavebar). Белая
   пилюля по ширине колонки контента; классы-крючки .pp-actionbar / .pp-actionbar-inner на
   разметке — чтобы кнопка «Чаты» поднималась над полосой (chat-tray меряет их).
   <div class="bs-savebar pp-actionbar" hidden><div class="bs-savebar__in pp-actionbar-inner">
     <span class="bs-savebar__msg">Есть несохранённые изменения</span>
     <button class="bs-btn bs-btn--ghost">Отменить</button><button class="bs-btn bs-btn--primary">Сохранить</button></div></div> */
.bs-savebar{ position:fixed; left:0; right:0; bottom:0; z-index:var(--z-chrome); pointer-events:none;
  padding:0 var(--sp-4) calc(var(--sp-3) + env(safe-area-inset-bottom) + var(--bs-bottom-reserve, 0px)); }
.bs-savebar[hidden]{ display:none; }
.bs-savebar__in{ pointer-events:auto; max-width:var(--page-max); margin:0 auto; display:flex; align-items:center; gap:var(--sp-2);
  padding:var(--sp-2) var(--sp-2) var(--sp-2) var(--sp-5); background:var(--card); border:var(--bw) solid var(--line2);
  border-radius:var(--rad-pill); box-shadow:var(--shadow-3); animation:bs-savebar-in var(--dur) var(--ease) both; }
.bs-savebar__msg{ flex:1 1 auto; min-width:0; font:500 var(--fs-sm)/var(--lh-tight) var(--font); color:var(--ink); }
.bs-savebar__msg.is-err{ color:var(--err-text); }
.bs-savebar__in > .bs-btn{ flex:none; }
@keyframes bs-savebar-in{ from{ transform:translateY(var(--sp-4)); opacity:0; } to{ transform:none; opacity:1; } }
@media (max-width:600px){
  .bs-savebar{ padding-inline:var(--sp-3); }
  .bs-savebar__in{ flex-wrap:wrap; padding:var(--sp-3); border-radius:var(--rad-lg); }
  .bs-savebar__msg{ flex-basis:100%; }
  .bs-savebar__in > .bs-btn{ flex:1 1 0; }
}
@media (prefers-reduced-motion:reduce){ .bs-savebar__in{ animation:none; } }

/* Экран-форма внутри окна (форма товара): колонка справа липнет к верху прокрутки окна, а не под шапку сайта */
.bs-formpage--dialog{ grid-template-columns:minmax(0, 1fr) minmax(260px, 320px); gap:var(--sp-6); }
.bs-formpage--dialog > .bs-formpage__aside{ top:0; }
@media (max-width:900px){ .bs-formpage--dialog{ grid-template-columns:minmax(0, 1fr); } }

/* ── Шаг формы в одну колонку (решение 22.10, К8 Б): «1 Фото и модель · 2 О товаре · 3 Где найдут…» ──
   Открытый шаг (.is-open) показывает поля; заполненный и закрытый (.is-done) сворачивается в строку-
   резюме («3 фото · модель STL») с кнопкой «Изменить»; ещё не начатый — просто заголовок. Номер —
   кружок 28 (--accent-soft / --accent-strong), сделанный — --ok с галочкой. Советы — внутри шага
   компактной .bs-note --info, не отдельными блоками.
   <section class="bs-step is-open"><div class="bs-step__head"><span class="bs-step__num">1</span>
     <h3 class="bs-step__title">Фото и модель</h3><span class="bs-step__summary">3 фото</span>
     <button class="bs-btn bs-btn--ghost bs-btn--sm bs-step__edit">Изменить</button></div>
     <div class="bs-step__body">…</div></section> */
.bs-step{ --bs-raise:none; background:var(--card); border:var(--bw) solid var(--line); border-radius:var(--rad-lg); }
.bs-step + .bs-step{ margin-top:var(--sp-3); }
.bs-step.is-open{ border-color:var(--line2); box-shadow:var(--shadow-1); }
.bs-step__head{ display:flex; align-items:center; gap:var(--sp-3); min-height:var(--ctl-lg); padding:var(--sp-2) var(--sp-4); }
.bs-step__num{ flex:none; display:grid; place-items:center; width:28px; height:28px; border-radius:50%;
  background:var(--accent-soft); color:var(--accent-strong); font:700 var(--fs-xs)/1 var(--font); font-variant-numeric:tabular-nums; }
.bs-step.is-done .bs-step__num{ background:var(--ok); color:var(--on-accent); }
.bs-step__num svg{ width:14px; height:14px; }
.bs-step__title{ margin:0; flex:none; font:600 var(--fs-base)/var(--lh-tight) var(--font); color:var(--ink); }
.bs-step__summary{ flex:1 1 auto; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
  font:400 var(--fs-sm)/var(--lh-tight) var(--font); color:var(--ink2); }
.bs-step.is-open .bs-step__summary,.bs-step:not(.is-done) .bs-step__summary{ visibility:hidden; }
.bs-step__edit{ flex:none; margin-left:auto; }
.bs-step.is-open .bs-step__edit,.bs-step:not(.is-done) .bs-step__edit{ display:none; }
.bs-step__body{ padding:0 var(--sp-4) var(--sp-4); display:flex; flex-direction:column; gap:var(--sp-4); }
.bs-step:not(.is-open) > .bs-step__body{ display:none; }
/* «Дальше» — .bs-btn--secondary обычной высоты (44), по левому краю тела шага, под последним полем (владелец 22.10: маленькая 32 в углу терялась) */
.bs-step__next{ align-self:flex-start; }
/* шаг с ошибкой после «Сохранить» (ревью мастера B01): рамка и номер — цвет ошибки, в свёрнутом шаге
   вместо резюме — «Нужно заполнить: …» */
.bs-step.bs-step--err{ border-color:var(--err-text); }
.bs-step.bs-step--err .bs-step__num{ background:var(--err-soft); color:var(--err-text); }
.bs-step.bs-step--err:not(.is-open) .bs-step__summary{ visibility:visible; color:var(--err-text); }
.bs-step__title[role="button"]{ cursor:pointer; }   /* заголовок — переключатель шага */
.bs-step__title[role="button"]:focus-visible{ outline:none; box-shadow:var(--focus-ring); border-radius:var(--rad-xs); }
.bs-formpage__main:has(> .bs-step){ gap:0; }
@media (max-width:600px){
  .bs-step__head{ flex-wrap:wrap; padding:var(--sp-2) var(--sp-3); }
  .bs-step__title{ flex:1 1 0; min-width:0; }
  .bs-step__summary{ order:3; flex-basis:100%; padding-left:calc(var(--sp-7) + var(--sp-3)); }
  .bs-step__body{ padding:0 var(--sp-3) var(--sp-3); }
}

/* ── Зона загрузки файлов (решение 22.10, 16.1 Б) ───────────────────────────────────────────────
   Белая поверхность, пунктир цвета рамки полей, по центру: значок в кружке → заголовок → кнопка
   «Выбрать файлы» → строка форматов. JS — mountUploader() из src/image-uploader.js (фото) или своя
   обвязка (3D-файлы формы товара); состояние — классами на самой зоне.
   Простая зона — сама кнопка (role="button" tabindex="0", Enter/Space открывают выбор), «Выбрать
   файлы» внутри — span с видом кнопки (вложенных интерактивных нет). Если у зоны есть второе
   действие («Вставить ссылку»), зона — role="group", а «Выбрать файлы» — настоящая <button>.
   <div class="bs-dropzone" role="button" tabindex="0" aria-label="…" aria-describedby="h1">
     <input type="file" hidden>
     <div class="bs-dropzone__idle">
       <span class="bs-dropzone__icon">svg</span>
       <span class="bs-dropzone__text"><b class="bs-dropzone__title">Перетащите фото сюда</b>
         <span class="bs-dropzone__hint" id="h1">JPG, PNG, WebP · до 8 МБ</span></span>
       <span class="bs-dropzone__actions"><span class="bs-btn bs-btn--secondary bs-btn--sm">Выбрать файлы</span></span></div>
     <div class="bs-dropzone__busy" hidden>…полоса ui-progress…</div></div>
   <p class="bs-field__error">…</p>   ← ошибка: зона .is-invalid + текст под ней
   Состояния: :hover (рамка --ink2) · .is-dragover (файл над зоной: фиолетовая рамка, мягкий фон)
   · :focus-visible (--focus-ring-soft) · .is-invalid · .is-busy (вместо idle — полоса прогресса)
   · .is-attn («вот сюда»: путь починки ведёт к зоне). --compact — строкой (композер, «+ ещё файл»):
   значок · заголовок с подсказкой · действия справа. */
.bs-dropzone{ display:flex; flex-direction:column; align-items:center; justify-content:center; gap:var(--sp-2);
  padding:var(--sp-5) var(--sp-4); text-align:center; background:var(--card);
  border:var(--bw-strong) dashed var(--line-field); border-radius:var(--rad-lg); cursor:pointer;
  transition:border-color var(--dur) var(--ease), background var(--dur) var(--ease), box-shadow var(--dur) var(--ease); }
.bs-dropzone[hidden]{ display:none !important; }
.bs-dropzone:hover{ border-color:var(--ink2); }
.bs-dropzone.is-dragover{ border-color:var(--violet-600); background:var(--accent-soft); }
.bs-dropzone:focus-visible{ outline:none; border-color:var(--violet-600); box-shadow:var(--focus-ring-soft); }
.bs-dropzone.is-invalid{ border-color:var(--err-text); }
.bs-dropzone.is-invalid:focus-visible{ box-shadow:var(--focus-ring-err); }
.bs-dropzone.is-attn{ border-color:var(--warn-line); box-shadow:0 0 0 4px var(--warn-soft); }
.bs-dropzone.is-busy{ cursor:default; border-style:solid; border-color:var(--line2); }
.bs-dropzone__idle{ display:flex; flex-direction:column; align-items:center; gap:var(--sp-2); min-width:0; max-width:100%; }
.bs-dropzone__idle[hidden],.bs-dropzone__busy[hidden]{ display:none !important; }
.bs-dropzone__icon{ flex:none; display:grid; place-items:center; width:40px; height:40px; border-radius:50%;
  background:var(--accent-soft); color:var(--accent-strong); }
.bs-dropzone__icon svg{ width:var(--icon-md); height:var(--icon-md); }
/* разметка одна на оба вида: значок · __text(заголовок + подсказка) · __actions. В колонке __text
   растворяется (contents), и подсказка уходит под кнопку (order) — порядок 16.1 Б. */
.bs-dropzone__text{ display:contents; }
.bs-dropzone__title{ font:600 var(--fs-sm)/var(--lh-tight) var(--font); color:var(--ink); }
.bs-dropzone__hint{ order:1; font:400 var(--fs-xs)/var(--lh-normal) var(--font); color:var(--text-muted); }
.bs-dropzone__actions{ display:flex; flex-wrap:wrap; align-items:center; justify-content:center; gap:var(--sp-2); }
.bs-dropzone__busy{ display:flex; align-items:center; justify-content:center; width:100%; }
.bs-dropzone--compact{ flex-direction:row; justify-content:flex-start; padding:var(--sp-3) var(--sp-4); text-align:left; }
.bs-dropzone--compact .bs-dropzone__idle{ flex-direction:row; flex:1 1 auto; gap:var(--sp-3); }
.bs-dropzone--compact .bs-dropzone__text{ display:flex; flex-direction:column; gap:2px; flex:1 1 auto; min-width:0; }
.bs-dropzone--compact .bs-dropzone__hint{ order:0; }
.bs-dropzone--compact .bs-dropzone__actions{ flex:none; margin-left:auto; }
@media (prefers-reduced-motion:reduce){ .bs-dropzone{ transition:none; } }

/* ── Миниатюры загруженного (16.2 Б): ряд под зоной загрузки ─────────────────────────────────────
   Фото — превью; файл модели — карточка .bs-thumb--file («3D» / формат). Первое фото — метка
   «Главное» (.bs-badge внутри .bs-thumb__badge). Удалить — × в кружке (.bs-thumb__del), порядок —
   перетаскиванием (draggable, .is-dragging / .is-over) и кнопками ←/→ (.bs-thumb__bar; видны при
   наведении и фокусе, на тач-экране всегда). Стрелки — по краям посередине (--prev / --next), правка —
   слева сверху (--edit): углы снизу и справа сверху заняты «Главное» и ×, налезать не на что.
   Двигать некуда — стрелку не рисуют (у первой нет «левее», у последней «правее», у единственной обеих).
   <div class="bs-thumbs"><div class="bs-thumb" draggable="true"><img alt="Фото 1">
     <span class="bs-thumb__badge bs-badge">Главное</span>
     <button class="bs-thumb__del" aria-label="Удалить фото 1">×</button>
     <span class="bs-thumb__bar"><button class="bs-thumb__act bs-thumb__act--next" aria-label="Правее">→</button></span></div></div> */
.bs-thumbs{ display:flex; flex-wrap:wrap; gap:var(--sp-2); }
/* ряд миниатюр под зоной загрузки (сама зона или её обёртка-загрузчик) — отступ --sp-3, не вплотную (полировка 22.10) */
:is(.bs-dropzone, :has(> .bs-dropzone), :has(> * > .bs-dropzone)) ~ .bs-thumbs{ margin-top:var(--sp-3); }
.bs-thumbs:not(:has(.bs-thumb)){ display:none; }
.bs-thumbs__set{ display:contents; }
.bs-thumb{ position:relative; flex:none; width:96px; height:96px; border-radius:var(--rad-md); overflow:hidden;
  border:var(--bw) solid var(--line2); background:var(--bg2); }
.bs-thumb[draggable="true"]{ cursor:grab; }
.bs-thumb img{ display:block; width:100%; height:100%; object-fit:cover; pointer-events:none; }
.bs-thumb.is-dragging{ opacity:.5; }
.bs-thumb.is-over{ border-color:var(--violet-600); box-shadow:var(--focus-ring-soft); }
.bs-thumb__badge{ position:absolute; left:var(--sp-1); bottom:var(--sp-1); height:20px; background:var(--card); color:var(--ink); box-shadow:var(--shadow-1); }
.bs-thumb__del{ position:absolute; top:var(--sp-1); right:var(--sp-1); display:grid; place-items:center; width:24px; height:24px;
  padding:0; border:0; border-radius:50%; background:var(--card); color:var(--ink); box-shadow:var(--shadow-1); cursor:pointer; }
.bs-thumb__del::before{ content:""; position:absolute; inset:-6px; }   /* зона нажатия 36 */
.bs-thumb__del svg{ width:14px; height:14px; }
.bs-thumb__del:hover{ color:var(--err-text); }
.bs-thumb__del:focus-visible,.bs-thumb__act:focus-visible{ outline:none; box-shadow:var(--focus-ring); }
.bs-thumb__bar{ position:absolute; inset:0; pointer-events:none; opacity:0;
  transition:opacity var(--dur) var(--ease); }
.bs-thumb:hover .bs-thumb__bar,.bs-thumb:focus-within .bs-thumb__bar{ opacity:1; }
.bs-thumb__act{ position:absolute; pointer-events:auto; display:grid; place-items:center; width:24px; height:24px; padding:0; border:0; border-radius:50%;
  background:var(--card); color:var(--ink); box-shadow:var(--shadow-1); cursor:pointer; }
.bs-thumb__act svg{ width:14px; height:14px; }
.bs-thumb__act--prev{ left:var(--sp-1); top:50%; transform:translateY(-50%); }
.bs-thumb__act--next{ right:var(--sp-1); top:50%; transform:translateY(-50%); }
.bs-thumb__act--edit{ left:var(--sp-1); top:var(--sp-1); }
.bs-thumb__act:hover:not(:disabled){ color:var(--accent-strong); }
.bs-thumb__act:disabled{ opacity:.4; cursor:default; }
.bs-thumb--file{ display:flex; flex-direction:column; align-items:center; justify-content:center; gap:var(--sp-1);
  padding:var(--sp-2); background:var(--card); text-align:center; }
.bs-thumb__ico{ display:grid; place-items:center; width:32px; height:32px; border-radius:50%; background:var(--accent-soft); color:var(--accent-strong); }
.bs-thumb__ico svg{ width:var(--icon-sm); height:var(--icon-sm); }
.bs-thumb__label{ font:700 var(--fs-xs)/1 var(--font); color:var(--ink); }
.bs-thumb__sub{ max-width:100%; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; font:400 var(--fs-xs)/1.2 var(--font); color:var(--text-muted); }
@media (hover:none){ .bs-thumb__bar{ opacity:1; } }
@media (prefers-reduced-motion:reduce){ .bs-thumb__bar{ transition:none; } }

/* ── Пусто внутри УЗКОГО блока: .bs-empty--inline.bs-empty--sm (колонка канбана, узкая панель) ──
   Тот же вид 6.1 Б, плотнее: кружок 32, заголовок --fs-sm 600, текст --fs-xs. Решение К17 А. */
.bs-empty--inline.bs-empty--sm{ gap:var(--sp-3); padding:var(--sp-3); }
.bs-empty--inline.bs-empty--sm .bs-empty__ico{ width:var(--ctl-sm); height:var(--ctl-sm); }
.bs-empty--inline.bs-empty--sm .bs-empty__ico svg{ width:var(--icon-sm); height:var(--icon-sm); }
.bs-empty--inline.bs-empty--sm .bs-empty__main{ gap:2px; padding-top:var(--sp-1); }
.bs-empty--inline.bs-empty--sm .bs-empty__title{ margin:0; font:600 var(--fs-sm)/var(--lh-tight) var(--font); color:var(--ink); }
.bs-empty--inline.bs-empty--sm .bs-empty__text{ margin:0; font:400 var(--fs-xs)/var(--lh-normal) var(--font); color:var(--ink2); }

/* ── Плитка-показатель (KPI) · .bs-stat (решение К17 А) ───────────────────────────────────────
   Белая поверхность (--card, 1px --line, --rad-lg, без тени): подпись --fs-xs --ink2 → число --fs-xl 700
   tabular-nums → подсказка/изменение --fs-xs. Ряд плиток — .bs-stats (grid, gap --sp-3); ряд НЕ кладут
   в другую карточку. Изменение к прошлому периоду — .bs-stat__delta --up/--down/--flat: стрелка + знак +
   цвет (цвет не единственный сигнал). Короткая подсказка в строке числа («откроется 27 окт.») —
   .bs-stat__hint внутри .bs-stat__value. Тоны числа: --muted (второстепенное), --ok, --err.
   --wide — главная плитка ряда на 2 колонки (на телефоне — на всю строку).
   <div class="bs-stats">
     <div class="bs-stat"><span class="bs-stat__label">Новых за период</span>
       <span class="bs-stat__value">+4 <span class="bs-stat__delta bs-stat__delta--up">svg +33%</span></span>
       <span class="bs-stat__hint">было 3</span></div></div> */
.bs-stats{ display:grid; grid-template-columns:repeat(auto-fit, minmax(150px, 1fr)); gap:var(--sp-3); }   /* auto-fit: ряд плиток до правого края, как таблица/плашка под ним (полировка 22.10) */
.bs-stat{ display:flex; flex-direction:column; gap:var(--sp-1); min-width:0; padding:var(--sp-3) var(--sp-4);
  background:var(--card); border:var(--bw) solid var(--line); border-radius:var(--rad-lg); color:var(--ink); }
.bs-stat__label{ display:flex; align-items:center; gap:var(--sp-1-5); min-width:0; font:500 var(--fs-xs)/var(--lh-tight) var(--font); color:var(--ink2); }
.bs-stat__label svg{ flex:none; width:var(--icon-sm); height:var(--icon-sm); }
.bs-stat__value{ display:flex; flex-wrap:wrap; align-items:baseline; column-gap:var(--sp-2); min-width:0;
  font:700 var(--fs-xl)/var(--lh-tight) var(--font); color:var(--ink); font-variant-numeric:tabular-nums; letter-spacing:-.01em; }
.bs-stat__label + .bs-stat__value{ margin-top:auto; }   /* подпись в 2 строки не сдвигает число: числа ряда — на одной линии */
.bs-stat__hint{ font:500 var(--fs-xs)/var(--lh-tight) var(--font); color:var(--text-muted); font-variant-numeric:tabular-nums; letter-spacing:0; }
.bs-stat__value .bs-stat__hint{ white-space:nowrap; }
.bs-stat__delta{ display:inline-flex; align-items:center; gap:2px; font:600 var(--fs-xs)/1 var(--font); letter-spacing:0; white-space:nowrap; }
.bs-stat__delta svg{ flex:none; width:12px; height:12px; fill:none; stroke:currentColor; stroke-width:2.4; stroke-linecap:round; stroke-linejoin:round; }
.bs-stat__delta--up{ color:var(--ok-text); }
.bs-stat__delta--down{ color:var(--err-text); }
.bs-stat__delta--flat{ color:var(--text-muted); }
.bs-stat--muted .bs-stat__value{ color:var(--ink2); }
.bs-stat--ok .bs-stat__value{ color:var(--ok-text); }
.bs-stat--err .bs-stat__value{ color:var(--err-text); }
.bs-stat--wide{ grid-column:span 2; }
/* --inline — итоги строкой внутри карточки: под тонкой линией, без вложенных плиток (решение ДС 22.10:
   ряд плиток в карточку не кладут). Подпись под числом не нужна — порядок тот же: подпись → число. */
.bs-stats--inline{ grid-template-columns:repeat(auto-fit, minmax(110px, 1fr)); padding-top:var(--sp-4); border-top:var(--bw) solid var(--line); }
.bs-stats--inline > .bs-stat{ padding:0; background:none; border:0; border-radius:0; }
@media (max-width:560px){
  .bs-stats{ grid-template-columns:repeat(2, minmax(0, 1fr)); }
  .bs-stat--wide{ grid-column:1 / -1; }
}

/* ── Стадия заказа компактно · .bs-stage (решение К17 А): бейдж текущей стадии + полоса прогресса +
   «Шаг N из M» (+ необязательная подпись, напр. трек-номер). Полоса — .bs-progressbar (ширина
   --bs-progress, role="progressbar" + aria-*). Перенос на узком экране — подпись уходит строкой ниже.
   <div class="bs-stage"><span class="bs-badge bs-badge--accent">В работе</span>
     <span class="bs-progressbar" role="progressbar" aria-valuenow="2" aria-valuemax="5" style="--bs-progress:40%"></span>
     <span class="bs-stage__step">Шаг 2 из 5</span><span class="bs-stage__meta">Трек: <b>RA123</b></span></div> */
.bs-stage{ display:flex; align-items:center; flex-wrap:wrap; gap:var(--sp-2) var(--sp-3); min-width:0; }
.bs-stage > .bs-progressbar{ flex:1 1 120px; max-width:220px; }
.bs-stage__step,.bs-stage__meta{ font:500 var(--fs-xs)/1 var(--font); color:var(--ink2); font-variant-numeric:tabular-nums; white-space:nowrap; }
.bs-stage__meta b{ color:var(--ink); font-weight:600; }

/* ══ ПРОСЬБА ОЦЕНИТЬ «Как вам?» (28.10) — src/ui/review-ask.js собирает разметку ═══════════════════
   Страница товара, строка заказа, «Ждут вашего отзыва» в кабинете и в пустой корзине. Просим мнение,
   а не пятёрку: звёзды одного веса, ни одна не подсвечена заранее. Вид — ПРИЗЫВ, а не плашка
   (владелец 28.10: «скучно, призыва нет, теряется»): бренд-растяжка + акцентные звёзды + Кликко. */

/* ── Поверхность просьбы · .bs-asksurf: мягкая растяжка коралл → фиолет (эхо --grad-hero, только декор)
   и неоновая рамка. Текст на ней — --ink / --ink2 (≥ 6:1), звёзды --accent-text (≥ 4,5:1). Тёмная тема —
   сама: растяжка смешивает роли с --card. */
.bs-asksurf{ border:var(--bw) solid var(--line-neon); border-radius:var(--rad-lg);
  background:linear-gradient(115deg, color-mix(in srgb, var(--coral-ink) 9%, var(--card)) 0%,
    color-mix(in srgb, var(--accent) 14%, var(--card)) 55%, color-mix(in srgb, var(--accent) 8%, var(--card)) 100%); }

/* ── Оценка звёздами · .bs-rate: 5 звёзд — ссылки в форму (`&rate=N`) или кнопки `data-rate`.
   Пустая звезда — акцентный контур --accent-text (зовёт нажать; 5,5:1 на белом). Наведение и фокус
   заливают звёзды ДО указателя цветом оценки (--warn — как у показа рейтинга и звёзд в
   форме) слева направо: у каждой звезды задержка --i × 25 мс. Тап-зона 32 на ПК, 44 на таче; звёзды
   вплотную: промах на соседнюю = ±1 звезда, форма даёт поправить. --lg (44 и на ПК) — где ряд звёзд и
   есть действие блока. .is-awake — одна «волна» по звёздам, когда блок впервые попал в кадр.
   <span class="bs-rate" role="group" aria-label="Оцените «…»"><a class="bs-rate__star" style="--i:0"
     href="…&rate=1" aria-label="Оценить: 1 звезда из 5"><svg class="bs-ico">…</svg></a>…</span> */
.bs-rate{ --bs-rate-box:var(--ctl-sm); --bs-rate-ico:var(--icon-md); display:inline-flex; align-items:center; flex:none; }
.bs-rate--lg{ --bs-rate-box:var(--ctl-md); --bs-rate-ico:28px; }
.bs-rate__star{ display:inline-grid; place-items:center; width:var(--bs-rate-box); height:var(--bs-rate-box); margin:0; padding:0;
  border:0; border-radius:var(--rad-sm); background:none; color:var(--accent-text); cursor:pointer; text-decoration:none;
  -webkit-tap-highlight-color:transparent; touch-action:manipulation; }
.bs-rate__star .bs-ico{ width:var(--bs-rate-ico); height:var(--bs-rate-ico); }
.bs-rate__star:focus-visible{ outline:none; box-shadow:var(--focus-ring); }
.bs-rate__star:active{ transform:scale(.88); }
@media (hover:hover){
  .bs-rate__star,.bs-rate__star .bs-ico{ transition:color var(--dur-fast) var(--ease), fill var(--dur-fast) var(--ease),
    transform var(--dur-fast) var(--ease); }
  .bs-rate:hover .bs-rate__star,.bs-rate:hover .bs-rate__star .bs-ico{ transition-delay:calc(var(--i, 0) * 25ms); }
  .bs-rate:hover .bs-rate__star{ color:var(--warn); }
  .bs-rate:hover .bs-rate__star .bs-ico{ fill:var(--warn); }
  .bs-rate .bs-rate__star:hover ~ .bs-rate__star{ color:var(--accent-text); }
  .bs-rate .bs-rate__star:hover ~ .bs-rate__star .bs-ico{ fill:none; }
  .bs-rate .bs-rate__star:hover{ transform:scale(1.12); }
}
/* клавиатура: та же подсказка «до какой звезды», без анимации (фокус — не жест) */
.bs-rate:has(.bs-rate__star:focus-visible) .bs-rate__star{ color:var(--warn); transition:none; }
.bs-rate:has(.bs-rate__star:focus-visible) .bs-rate__star .bs-ico{ fill:var(--warn); transition:none; }
.bs-rate .bs-rate__star:focus-visible ~ .bs-rate__star{ color:var(--accent-text); }
.bs-rate .bs-rate__star:focus-visible ~ .bs-rate__star .bs-ico{ fill:none; }
/* Волна-приглашение (владелец 28.10: «подсвечивай все 5»): когда ряд впервые в кадре, звёзды по очереди
   (шаг --i × 60 мс) загораются цветом оценки, весь ряд горит ~540 мс и так же по очереди гаснет до
   пустого контура. Один раз. Исходное и конечное состояние — ПУСТОЕ: заранее выбранной оценки нет
   (юр-граница, досье marketplace-reviews). Рядов несколько — следующий стартует позже на
   --bs-rate-row × 240 мс (ставит wakeRates). Наведение/фокус гасят волну сразу: выбор человека главнее. */
@keyframes bs-rate-glow{
  0%{ color:var(--accent-text); transform:none; }
  10%{ color:var(--warn); transform:translateY(-3px) scale(1.14); }
  22%{ color:var(--warn); transform:none; }
  75%{ color:var(--warn); transform:none; }
  100%{ color:var(--accent-text); transform:none; } }
@keyframes bs-rate-glow-ico{
  0%{ fill:var(--warn); fill-opacity:0; }
  10%{ fill:var(--warn); fill-opacity:1; }
  75%{ fill:var(--warn); fill-opacity:1; }
  100%{ fill:var(--warn); fill-opacity:0; } }
.bs-rate.is-awake .bs-rate__star,.bs-rate.is-awake .bs-rate__star .bs-ico{ animation-duration:1200ms; animation-timing-function:var(--ease);
  animation-fill-mode:backwards; animation-delay:calc(var(--i, 0) * 60ms + var(--bs-rate-row, 0) * 240ms + 160ms); }
.bs-rate.is-awake .bs-rate__star{ animation-name:bs-rate-glow; }
.bs-rate.is-awake .bs-rate__star .bs-ico{ animation-name:bs-rate-glow-ico; }
.bs-rate.is-awake:is(:hover,:focus-within) .bs-rate__star,
.bs-rate.is-awake:is(:hover,:focus-within) .bs-rate__star .bs-ico{ animation:none; }
@media (pointer:coarse){ .bs-rate{ --bs-rate-box:var(--ctl-md); } }
@media (prefers-reduced-motion:reduce){
  .bs-rate__star,.bs-rate__star .bs-ico{ transition:none; }
  .bs-rate__star:active,.bs-rate .bs-rate__star:hover{ transform:none; }
  .bs-rate.is-awake .bs-rate__star,.bs-rate.is-awake .bs-rate__star .bs-ico{ animation:none; }
}

/* ── Поставленная оценка · .bs-rate-show: мелкие звёзды без действия (смысл — в aria-label) ── */
.bs-rate-show{ display:inline-flex; align-items:center; gap:1px; flex:none; color:var(--line2); }
.bs-rate-show .bs-ico{ width:14px; height:14px; }
.bs-rate-show .bs-ico.is-on{ color:var(--warn); fill:currentColor; }

/* ── Строка под позицией заказа · .bs-askline: «Как напечаталась? ☆☆☆☆☆» / тихо «Ваша оценка ★★★★☆ ·
   Изменить». Прижата к своей позиции (близость), шрифт мельче строки товара — не спорит с ценой
   и «Скачать». */
.bs-askline{ display:flex; align-items:center; flex-wrap:wrap; gap:0 var(--sp-2); min-width:0;
  font:500 var(--fs-xs)/var(--lh-tight) var(--font); color:var(--ink2); }
.bs-askline__q{ font-weight:600; color:var(--accent-strong); }
/* мордочка Кликко у «Как вам?» (klikko-avatar-96.webp, 19×32): тот же призыв, что на странице товара, но тише */
.bs-askline__klk{ flex:none; display:block; width:19px; height:32px; object-fit:contain; margin-right:calc(-1 * var(--sp-1)); }
.bs-askline__t{ max-width:22ch; overflow:hidden; color:var(--ink2); text-overflow:ellipsis; white-space:nowrap; }
.bs-askline > .bs-rate{ margin-left:calc((var(--bs-rate-ico) - var(--bs-rate-box)) / 2); }
.bs-askline--done{ min-height:var(--ctl-sm); color:var(--text-muted); }
.bs-askline--done .bs-askline__q{ font-weight:500; color:var(--ink2); }

/* ── Список «Ждут вашего отзыва» · .bs-asklist: обложка 48 · название + «мастер · скачали 12 окт» ·
   звёзды справа. Узкий контейнер (корзина, телефон) — звёзды строкой под названием. */
.bs-asklist{ container-type:inline-size; margin:0; padding:0; list-style:none; }
.bs-asklist__row{ display:grid; grid-template-columns:48px minmax(0,1fr) auto; align-items:center;
  gap:var(--sp-1) var(--sp-3); margin:0; padding:var(--sp-2) 0; }
.bs-asklist__row::before{ content:none; }
.bs-asklist__row + .bs-asklist__row{ border-top:var(--bw) solid var(--line); }
.bs-asklist__media{ display:block; width:48px; height:48px; overflow:hidden; border-radius:var(--rad-sm); background:var(--bg2); }
.bs-asklist__media img{ display:block; width:100%; height:100%; object-fit:cover; }
.bs-asklist__ph{ display:grid; place-items:center; width:100%; height:100%; color:var(--text-muted); }
.bs-asklist__main{ display:flex; flex-direction:column; gap:2px; min-width:0; }
.bs-asklist__t{ overflow:hidden; font:600 var(--fs-sm)/var(--lh-tight) var(--font); color:var(--ink);
  text-decoration:none; text-overflow:ellipsis; white-space:nowrap; }
a.bs-asklist__t:hover{ color:var(--accent-text); }
a.bs-asklist__t:focus-visible{ outline:none; box-shadow:var(--focus-ring); border-radius:var(--rad-xs); }
.bs-asklist__m{ overflow:hidden; font:400 var(--fs-xs)/var(--lh-tight) var(--font); color:var(--text-muted);
  text-overflow:ellipsis; white-space:nowrap; }
.bs-asklist__row > .bs-link{ font-size:var(--fs-sm); }   /* «Оценить» у снятого товара — не крупнее названия */
@container (max-width:440px){
  .bs-asklist__row{ grid-template-columns:48px minmax(0,1fr); }
  .bs-asklist__media{ grid-row:span 2; align-self:start; }
  .bs-asklist__row > .bs-rate{ margin-left:calc((var(--bs-rate-ico) - var(--bs-rate-box)) / 2); }
  .bs-asklist__row > .bs-rate,.bs-asklist__row > .bs-link{ grid-column:2; justify-self:start; }
}

/* ══ БАЗА ЗНАНИЙ (пачка 1, 22.10; решения В1–В8) — компоненты хабов и статей ══════════════════
   Блог, вики, вопросы, разборы, принтеры. Раскладка страниц (ширина, колонки, отступы) — в
   /hub-sections.css (хабы) и /blog/article.css (статьи); здесь только сами блоки. */

/* ── Хлебные крошки · .bs-crumbs — одна строка «Главная › Раздел › Страница»; разделитель › рисует
   CSS, текущая страница — aria-current. Видимая цепочка = зеркало BreadcrumbList JSON-LD.
   <nav class="bs-crumbs" aria-label="Хлебные крошки"><ol><li><a href="/">Главная</a></li>
     <li><span aria-current="page">Блог</span></li></ol></nav> */
.bs-crumbs{ font:500 var(--fs-xs)/var(--lh-normal) var(--font); color:var(--text-muted); min-width:0; }
.bs-crumbs ol{ display:flex; flex-wrap:wrap; align-items:center; gap:var(--sp-1) var(--sp-2); margin:0; padding:0; list-style:none; }
.bs-crumbs li{ display:inline-flex; align-items:center; gap:var(--sp-2); min-width:0; margin:0; padding:0; }
.bs-crumbs li::before{ content:none; }
/* разделитель — хвостом ПРЕДЫДУЩЕГО пункта: при переносе строка не начинается с «›» (ревью 02.11, T15) */
.bs-crumbs li:not(:last-child)::after{ content:"›"; position:static; width:auto; height:auto; background:none; transform:none; color:var(--text-muted); }
.bs-crumbs a{ color:var(--ink2); text-decoration:none; border:0; border-radius:var(--rad-xs); }
.bs-crumbs a:hover{ color:var(--accent-text); text-decoration:underline; text-underline-offset:3px; }
.bs-crumbs a:focus-visible{ outline:none; box-shadow:var(--focus-ring); }
.bs-crumbs [aria-current]{ color:var(--text-muted); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; max-width:48ch; }

/* ── Карточка статьи · .bs-acard (решения 10.1 Б, В8 А) — одна на все хабы базы знаний: метка темы
   (.bs-badge --accent; тема = фильтр хаба), название основным шрифтом 600 (не Unbounded), описание
   до 3 строк, мета снизу. Вся карточка — ссылка; карточки ряда одной высоты (тянет сетка).
   <a class="bs-acard" href="…"><span class="bs-badge bs-badge--accent">Мультицвет</span>
     <h3 class="bs-acard__title">…</h3><p class="bs-acard__text">…</p><span class="bs-acard__meta">5 мин</span></a> */
.bs-acard{ display:flex; flex-direction:column; align-items:flex-start; gap:var(--sp-2); min-width:0; height:100%; box-sizing:border-box;
  padding:var(--sp-5); background:var(--card); border:var(--bw) solid var(--line); border-radius:var(--rad-lg);
  box-shadow:var(--shadow-1); color:var(--ink); text-decoration:none;
  transition:border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease); }
.bs-acard:hover{ border-color:var(--violet-200); box-shadow:var(--shadow-2); }
.bs-acard:focus-visible{ outline:none; box-shadow:var(--focus-ring); }
.bs-acard[hidden]{ display:none; }
.bs-acard__title{ margin:0; padding:0; font:600 var(--fs-base)/var(--lh-tight) var(--font); letter-spacing:0; color:var(--ink);
  display:-webkit-box; -webkit-line-clamp:3; -webkit-box-orient:vertical; overflow:hidden; }
.bs-acard__text{ margin:0; font:400 var(--fs-sm)/var(--lh-normal) var(--font); color:var(--ink2);
  display:-webkit-box; -webkit-line-clamp:3; -webkit-box-orient:vertical; overflow:hidden; }
.bs-acard__meta{ margin-top:auto; padding-top:var(--sp-1); font:500 var(--fs-xs)/var(--lh-tight) var(--font); color:var(--text-muted); font-variant-numeric:tabular-nums; }

/* ── Оглавление статьи · .bs-toc (решение В7 А): на ПК — липкая колонка справа (nav.bs-toc),
   на телефоне — свёрнутое «Содержание» (details.bs-toc). Текущий раздел — aria-current="true".
   <nav class="bs-toc" aria-label="Содержание"><p class="bs-toc__title">Содержание</p><ol class="bs-toc__list"><li><a href="#…">…</a></li></ol></nav>
   <details class="bs-toc"><summary class="bs-toc__title">Содержание</summary><ol class="bs-toc__list">…</ol></details> */
.bs-toc{ font:500 var(--fs-sm)/var(--lh-normal) var(--font); color:var(--ink2); }
.bs-toc__title{ margin:0 0 var(--sp-2); font:600 var(--fs-xs)/var(--lh-tight) var(--font); letter-spacing:.06em; text-transform:uppercase; color:var(--text-muted); }
.bs-toc__list{ display:flex; flex-direction:column; gap:var(--sp-1); margin:0; padding:0 0 0 var(--sp-3); list-style:none; border-left:var(--bw) solid var(--line); }
.bs-toc__list li{ margin:0; padding:0; }
.bs-toc__list li::before{ content:none; }
.bs-toc__list a{ display:block; margin-left:calc(-1 * var(--sp-3) - var(--bw)); padding:var(--sp-1) 0 var(--sp-1) var(--sp-3);
  border:0; border-left:var(--bw-strong) solid transparent; color:var(--ink2); text-decoration:none; }
.bs-toc__list a:hover{ color:var(--ink); }
.bs-toc__list a:focus-visible{ outline:none; box-shadow:var(--focus-ring); border-radius:var(--rad-xs); }
.bs-toc__list a[aria-current="true"]{ color:var(--accent-text); border-left-color:var(--accent); }
details.bs-toc{ background:var(--card); border:var(--bw) solid var(--line); border-radius:var(--rad-lg); }
details.bs-toc > summary{ display:flex; align-items:center; justify-content:space-between; gap:var(--sp-2); min-height:var(--ctl-md); margin:0;
  padding:0 var(--sp-4); cursor:pointer; list-style:none; border-radius:inherit; }
details.bs-toc > summary::-webkit-details-marker{ display:none; }
details.bs-toc > summary::after{ content:""; flex:none; width:var(--icon-sm); height:var(--icon-sm); background:var(--icon-chevron-down) center/contain no-repeat;
  transition:transform var(--dur) var(--ease); }
details.bs-toc[open] > summary::after{ transform:rotate(180deg); }
details.bs-toc > summary:focus-visible{ outline:none; box-shadow:var(--focus-ring); }
details.bs-toc > .bs-toc__list{ margin:0 var(--sp-4) var(--sp-4); }

/* ── Частые вопросы · .bs-faq (один вид на всю базу знаний): аккордеон из <details>, шеврон справа.
   <div class="bs-faq"><details class="bs-faq__item"><summary>Вопрос?</summary><div class="bs-faq__a"><p>Ответ</p></div></details></div> */
.bs-faq{ display:flex; flex-direction:column; border-top:var(--bw) solid var(--line); }
.bs-faq__item{ border-bottom:var(--bw) solid var(--line); }
.bs-faq__item > summary{ display:flex; align-items:center; justify-content:space-between; gap:var(--sp-4); min-height:var(--ctl-lg);
  padding:var(--sp-3) 0; cursor:pointer; list-style:none; font:600 var(--fs-base)/var(--lh-tight) var(--font); color:var(--ink); }
.bs-faq__item > summary::-webkit-details-marker{ display:none; }
.bs-faq__item > summary::after{ content:""; flex:none; width:var(--icon-sm); height:var(--icon-sm); background:var(--icon-chevron-down) center/contain no-repeat;
  transition:transform var(--dur) var(--ease); }
.bs-faq__item[open] > summary::after{ transform:rotate(180deg); }
.bs-faq__item > summary:hover{ color:var(--accent-text); }
.bs-faq__item > summary:focus-visible{ outline:none; box-shadow:var(--focus-ring); border-radius:var(--rad-xs); }
.bs-faq__a{ padding:0 0 var(--sp-4); font:400 var(--fs-base)/var(--lh-relaxed) var(--font); color:var(--ink2); }
.bs-faq__a > :first-child{ margin-top:0; }
.bs-faq__a > :last-child{ margin-bottom:0; }
/* --panel (страница товара, 23.10): тот же аккордеон в рамке панели — рядом с .bs-panel (мастер, доставка)
   одна рамка и один радиус; строки внутри — с отступом панели. */
.bs-faq--panel{ border:var(--bw) solid var(--line); border-radius:var(--rad-lg); background:var(--card); }
.bs-faq--panel > .bs-faq__item{ padding:0 var(--sp-4); }
.bs-faq--panel > .bs-faq__item:last-child{ border-bottom:0; }
.bs-faq--panel > .bs-faq__item > summary{ min-height:var(--ctl-md); font-size:var(--fs-sm); }
.bs-faq--panel .bs-faq__a{ font-size:var(--fs-sm); line-height:var(--lh-normal); }

/* ── Строка-раскрывашка · .bs-expand: строка списка, которая разворачивает подробности под собой.
   Не контрол: без рамки и пилюли, наведение — фоном строки, раскрытая — подложка --bg2, шеврон вниз ↔ вверх.
   <button class="bs-expand" aria-expanded="false" aria-controls="id">…<svg class="bs-expand__chev">…</svg></button>
   или <details><summary class="bs-expand">…<svg class="bs-expand__chev">…</svg></summary>…</details> */
.bs-expand{ display:flex; align-items:center; gap:var(--sp-2); width:100%; min-height:var(--ctl-sm); box-sizing:border-box; margin:0;
  padding:var(--sp-1) var(--sp-2); border:0; border-radius:var(--rad-sm); background:transparent; list-style:none;
  font:500 var(--fs-xs)/var(--lh-normal) var(--font); color:var(--ink); text-align:left; cursor:pointer;
  transition:background-color var(--dur) var(--ease); }
.bs-expand::-webkit-details-marker{ display:none; }
.bs-expand:hover{ background:var(--hover-fill); }
.bs-expand:focus-visible{ outline:none; box-shadow:var(--focus-ring); }
.bs-expand[aria-expanded="true"],details[open] > .bs-expand{ background:var(--bg2); }
.bs-expand__chev{ flex:none; display:inline-flex; width:var(--icon-xs); height:var(--icon-xs); margin-left:auto; color:var(--ink2);
  fill:none; stroke:currentColor; stroke-width:var(--icon-stroke); stroke-linecap:round; stroke-linejoin:round; transition:transform var(--dur) var(--ease); }
.bs-expand__chev svg{ width:100%; height:100%; }
.bs-expand[aria-expanded="true"] .bs-expand__chev,details[open] > .bs-expand .bs-expand__chev{ transform:rotate(180deg); }
@media (pointer:coarse){ .bs-expand{ min-height:var(--ctl-md); } }
@media (prefers-reduced-motion:reduce){ .bs-expand,.bs-expand__chev{ transition:none; } }

/* ── Значение с правкой по клику · .bs-editable: текст карточки/шторки, который по клику становится полем.
   Покой — просто текст; наведение — мягкая подложка; фокус — кольцо ДС; правка (.is-editing) — внутри обычный .bs-input.
   <div class="bs-editable" role="button" tabindex="0">Иван</div> · только чтение — .is-readonly без role/tabindex */
.bs-editable{ display:block; min-height:var(--ctl-sm); box-sizing:border-box; padding:var(--sp-1-5) var(--sp-2); border-radius:var(--rad-sm);
  font:500 var(--fs-sm)/var(--lh-normal) var(--font); color:var(--ink); overflow-wrap:anywhere; cursor:text;
  transition:background-color var(--dur) var(--ease); }
.bs-editable:hover{ background:var(--hover-fill); }
.bs-editable:focus-visible{ outline:none; box-shadow:var(--focus-ring); }
.bs-editable.is-readonly{ cursor:default; color:var(--ink2); }
.bs-editable.is-readonly:hover{ background:transparent; }
.bs-editable.is-editing{ padding:0; background:transparent; }
@media (prefers-reduced-motion:reduce){ .bs-editable{ transition:none; } }

/* ── Нижняя панель разделов · .bs-tabbar (телефон ≤560px). Разметку и замер высоты (--bs-tab-h) даёт src/ui/tabbar.js.
   Строка 48 (пилюля 40×22 · глиф 20 · подпись 11 · зазор 2): подписи не снимаем — «Биржа»/«Лента» из глифа не угадываются.
   Заливка СПЛОШНАЯ --card, без блюра: полупрозрачная полоса сливается с тулбаром браузера, а backdrop-filter во всю
   ширину пересчитывается на каждом кадре скролла. Отделка — кромка и подъём в цвете бренда.
   Активный слот — как выбранное везде в ДС (.bs-seg/.bs-filter): пилюля --accent-soft, глиф и подпись --accent-strong, 600.
   Цвета — из рамп (--gray-700, --violet-*), не --ink/--line: на тёмных страницах landing.css переопределяет семантику.
   <nav class="bs-tabbar"><a class="bs-tab is-on"><span class="bs-tab-ind"><svg class="bs-tab-ico">…</svg></span><span class="bs-tab-lbl">Лента</span></a>…</nav> */
.bs-tabbar{ position:fixed; left:0; right:0; bottom:0; z-index:var(--z-bottom-bar); display:none; align-items:stretch;
  padding:0 var(--sp-1); padding-bottom:env(safe-area-inset-bottom,0px); background:var(--card);
  border-top:var(--bw) solid color-mix(in srgb, var(--violet-500) 16%, transparent);
  box-shadow:inset 0 var(--bw) 0 color-mix(in srgb, var(--white) 72%, transparent), 0 calc(-2.5 * var(--sp-1)) calc(7.5 * var(--sp-1)) calc(-4.5 * var(--sp-1)) color-mix(in srgb, var(--violet-700) 50%, transparent);
  font-family:var(--font); }
.bs-tabbar[hidden]{ display:none; }
.bs-tab{ position:relative; flex:1 1 0; min-width:0; height:var(--sp-9); display:flex; flex-direction:column; align-items:center; justify-content:center;
  gap:calc(var(--sp-1) / 2); margin:0; padding:0; overflow:hidden; border:0; border-radius:var(--rad-md); background:none; cursor:pointer;
  text-decoration:none; color:var(--gray-700); -webkit-tap-highlight-color:transparent; touch-action:manipulation; }
.bs-tab-ind{ display:grid; place-items:center; width:var(--sp-8); height:calc(var(--icon-md) + 2 * var(--bw)); border-radius:var(--rad-pill);
  background:transparent; transition:background var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease); }
.bs-tab-ico{ display:block; width:var(--icon-md); height:var(--icon-md); opacity:.72; transition:opacity var(--dur-fast) var(--ease); }   /* глиф тише подписи: смысл несёт подпись */
.bs-tab-lbl{ max-width:100%; font:600 var(--fs-2xs)/1.1 var(--font); letter-spacing:-.01em; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.bs-tab.is-on .bs-tab-ico,.bs-tab:active .bs-tab-ico{ opacity:1; }
.bs-tab.is-on{ color:var(--accent-strong); }
.bs-tab.is-on .bs-tab-ind{ background:var(--accent-soft); transform:translateY(calc(-1 * var(--bw))); }
.bs-tab.is-on .bs-tab-ico{ color:var(--accent-strong); }
.bs-tab:active .bs-tab-ind{ transform:scale(.92); }   /* отклик на нажатие, не на hover: на тач hover «залипает» */
.bs-tab:focus-visible{ outline:calc(2 * var(--bw)) solid var(--focus-color); outline-offset:calc(-3 * var(--bw)); }
/* волна от пальца (одноразовая реакция, вечных анимаций на постоянной панели нет) */
.bs-tab-rp{ position:absolute; border-radius:50%; pointer-events:none; background:var(--violet-100);
  transform:translate(-50%,-50%) scale(0); animation:bs-tab-rp .52s var(--ease) forwards; }
@keyframes bs-tab-rp{ to{ transform:translate(-50%,-50%) scale(1); opacity:0; } }
@media (max-width:560px){ .bs-tabbar{ display:flex; } }   /* та же точка, где из шапки уходят ссылки разделов */
@media (max-width:360px){ .bs-tabbar{ padding-inline:0; } .bs-tab-ind{ width:calc(var(--sp-8) - var(--sp-1)); } }
@media (prefers-reduced-motion:reduce){ .bs-tab-ind,.bs-tab-ico{ transition:none; } .bs-tab.is-on .bs-tab-ind,.bs-tab:active .bs-tab-ind{ transform:none; } .bs-tab-rp{ display:none; } }

/* ── Номер шага · .bs-num (решение владельца 29.10: круг 28, вариант А) — один вид на весь сайт:
   мягкий --accent-soft, цифра --accent-strong 700. Шаги «Скоро», «Мастерам», «Как начать» в профиле, промо.
   --sm (24) — нумерация внутри текста инструкции. Номер шага мастера товара (.bs-step__num) — тот же вид.
   <span class="bs-num" aria-hidden="true">1</span> */
.bs-num{ display:inline-grid; place-items:center; flex:none; box-sizing:border-box; width:calc(var(--sp-6) + var(--sp-1)); height:calc(var(--sp-6) + var(--sp-1));
  border-radius:var(--rad-pill); background:var(--accent-soft); color:var(--accent-strong);
  font:700 var(--fs-xs)/1 var(--font); font-variant-numeric:tabular-nums; }
.bs-num--sm{ width:var(--sp-6); height:var(--sp-6); }   /* 24: рядом со строкой текста, цифра та же 12 */

/* ── Значок в плашке · .bs-icon-tile (решение владельца 29.10: круг) — один вид на весь сайт: значок-подпись к
   карточке/строке/пустому состоянию. 40 — в карточках; --sm 32 — в строках и плотных списках; --lg 56 — пустые состояния.
   Тон: по умолчанию акцент; --quiet (серый — непрочитанное/«скоро»), --ok, --warn, --err.
   <span class="bs-icon-tile" aria-hidden="true"><svg>…</svg></span> */
.bs-icon-tile{ display:inline-grid; place-items:center; flex:none; box-sizing:border-box; width:var(--sp-8); height:var(--sp-8);
  border-radius:var(--rad-pill); background:var(--accent-soft); color:var(--accent-strong); }
.bs-icon-tile svg{ width:var(--icon-md); height:var(--icon-md); }
.bs-icon-tile--sm{ width:var(--sp-7); height:var(--sp-7); }
.bs-icon-tile--sm svg{ width:var(--icon-sm); height:var(--icon-sm); }
.bs-icon-tile--lg{ width:var(--sp-10); height:var(--sp-10); }
.bs-icon-tile--lg svg{ width:calc(var(--icon-lg) + var(--sp-1)); height:calc(var(--icon-lg) + var(--sp-1)); }
.bs-icon-tile--quiet{ background:var(--bg2); color:var(--ink2); }
.bs-icon-tile--ok{ background:var(--ok-soft); color:var(--ok-text); }
.bs-icon-tile--warn{ background:var(--warn-soft); color:var(--warn-text); }
.bs-icon-tile--err{ background:var(--err-soft); color:var(--err-text); }

/* ── Промо-баннер · .bs-banner (выбор владельца 30.10, «ДС дороже» п.2). Один «материал» на все промо-полосы:
   --accent — сочный градиент коралл→фиолет с бликом (полоса маркетплейса);
   --dark — тёмная сцена со свечением, как экран AR (финалы «Скоро» и промтов);
   --soft — светлая сцена: белая поверхность с двумя мягкими свечениями (первый экран и «Новый шедевр» главной,
   «Сообщество мастеров», квадратные иллюстрации «Скоро» и промтов). «Инструменты» главной — --accent.
   Раскладку (текст, Кликко, кнопки) задаёт место; компонент — поверхность, свет, цвет текста и кнопок на нём.
   <section class="bs-banner bs-banner--dark"><h2>…</h2><p>…</p><a class="bs-btn bs-btn--primary">…</a></section> */
.bs-banner{ position:relative; isolation:isolate; overflow:hidden; border-radius:var(--rad-2xl); color:var(--on-accent); }
.bs-banner :is(h1,h2,h3){ color:inherit; }
.bs-banner p{ color:color-mix(in srgb, var(--on-accent) 78%, transparent); }
.bs-banner--accent{ background:radial-gradient(120% 140% at 0% 0%, color-mix(in srgb, var(--white) 22%, transparent), transparent 45%),
    linear-gradient(120deg, var(--coral-500), var(--violet-500) 70%, var(--violet-600));
  background-image:radial-gradient(120% 140% at 0% 0%, color-mix(in srgb, var(--white) 22%, transparent), transparent 45%),
    linear-gradient(120deg in oklch, var(--coral-500), var(--violet-500) 70%, var(--violet-600));   /* чистый градиент; без поддержки — строкой выше */
  box-shadow:inset 0 var(--bw) 0 color-mix(in srgb, var(--white) 35%, transparent), var(--shadow-2); }
.bs-banner--dark{ background:radial-gradient(60% 140% at 0% 0%, color-mix(in srgb, var(--violet-500) 45%, transparent), transparent 70%),
    radial-gradient(50% 120% at 100% 100%, color-mix(in srgb, var(--coral-500) 30%, transparent), transparent 70%),
    color-mix(in srgb, var(--scene-bg) 88%, var(--violet-900));
  border:var(--bw) solid var(--scene-line); box-shadow:0 30px 60px -28px color-mix(in srgb, var(--violet-700) 70%, transparent); }
.bs-banner--soft{ color:var(--ink); background:radial-gradient(60% 120% at 0% 0%, color-mix(in srgb, var(--violet-500) 16%, transparent), transparent 70%),
    radial-gradient(55% 120% at 100% 100%, color-mix(in srgb, var(--coral-500) 14%, transparent), transparent 70%), var(--card);
  border:var(--bw) solid var(--line); box-shadow:var(--edge-light), var(--shadow-2); }
.bs-banner--soft p{ color:var(--ink2); }
.bs-banner--dark .bs-btn--secondary{ background:var(--scene-surface); color:var(--scene-ink); border-color:var(--scene-line); box-shadow:none; }
.bs-banner--dark .bs-btn--secondary:hover:not(:disabled){ background:var(--scene-surface-hover); }

/* ── Файл-вложение · .bs-file (30.10): любой файл в переписке. В сообщении — ссылка «скачать» на мягкой подложке;
   в поле ввода до отправки — .bs-file--chip (карточка с рамкой и крестиком). Значок — .bs-icon-tile--sm (круг, как все значки).
   В своём (фиолетовом) пузыре — светлый, как цитата и реакции. Идёт загрузка — .is-up (размер → проценты акцентом).
   <a class="bs-file" href download><span class="bs-icon-tile bs-icon-tile--sm bs-file__icon">…</span>
     <span class="bs-file__id"><span class="bs-file__name">отчёт.pdf</span><span class="bs-file__meta">1,2 МБ · PDF</span></span>
     <span class="bs-file__act">↓</span></a> */
.bs-file{ display:grid; grid-template-columns:auto minmax(0,1fr) auto; align-items:center; gap:var(--sp-2); box-sizing:border-box;
  width:calc(var(--sp-12) * 2 + var(--sp-7)); max-width:100%; min-height:var(--sp-8); padding:var(--sp-1) var(--sp-2) var(--sp-1) var(--sp-1);
  border-radius:var(--rad-md); background:color-mix(in srgb, var(--ink) 5%, transparent); color:inherit; text-decoration:none; white-space:normal;
  transition:background-color var(--dur) var(--ease); }
a.bs-file:hover{ background:color-mix(in srgb, var(--ink) 9%, transparent); }
a.bs-file:focus-visible{ outline:none; box-shadow:var(--focus-ring); }
.bs-file__id{ min-width:0; display:flex; flex-direction:column; line-height:var(--lh-tight); }
.bs-file__name{ font:600 var(--fs-xs)/var(--lh-tight) var(--font); color:inherit; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.bs-file__meta{ font:500 var(--fs-2xs)/var(--lh-tight) var(--font); color:var(--text-muted); font-variant-numeric:tabular-nums; white-space:nowrap; }
.bs-file__act{ display:grid; color:var(--text-muted); }
.bs-file__act svg{ width:var(--icon-sm); height:var(--icon-sm); }
.bs-file.is-up .bs-file__meta{ color:var(--accent-strong); }
.bs-file--chip{ min-height:var(--ctl-md); padding:0 0 0 var(--sp-1-5); background:var(--card); border:var(--bw) solid var(--line2); }
.bs-msg--mine .bs-file{ background:color-mix(in srgb, var(--on-accent) 16%, transparent); }
.bs-msg--mine a.bs-file:hover{ background:color-mix(in srgb, var(--on-accent) 24%, transparent); }
.bs-msg--mine .bs-file .bs-icon-tile{ background:color-mix(in srgb, var(--on-accent) 22%, transparent); color:var(--on-accent); }
.bs-msg--mine .bs-file__meta,.bs-msg--mine .bs-file__act{ color:color-mix(in srgb, var(--on-accent) 80%, transparent); }
@media (prefers-reduced-motion:reduce){ .bs-file{ transition:none; } }

/* ── Миниатюра · .bs-thumb: квадратное превью-картинка (галерея товара, вложения, медиа-сетки).
   img — во всю плитку; выбранная (.is-active / aria-selected / aria-pressed / в ссылке с aria-current) — рамка --accent;
   кнопкой или в ссылке — наведение рамкой темнее и кольцо фокуса. Размер — --thumb (64), --sm — 44, --fill — во всю ячейку сетки.
   <button class="bs-thumb" aria-selected="true"><img src="…" alt=""></button>
   Убрать вложение — <button class="bs-thumb__x" aria-label="Убрать">…</button> (тёмный кружок в углу, хитбокс 40). */
.bs-thumb{ --thumb:var(--sp-11); position:relative; display:grid; place-items:center; flex:none; width:var(--thumb); height:var(--thumb);
  box-sizing:border-box; margin:0; padding:0; overflow:hidden; border:var(--bw-strong) solid var(--line); border-radius:var(--rad-md);
  background:var(--bg2); color:var(--text-muted); font:inherit; transition:border-color var(--dur) var(--ease); }
.bs-thumb > img{ display:block; width:100%; height:100%; object-fit:cover; }
:is(button,a).bs-thumb{ cursor:pointer; }
:is(button,a).bs-thumb:hover,a:hover > .bs-thumb{ border-color:color-mix(in srgb, var(--ink) 22%, var(--line2)); }
.bs-thumb:focus-visible,a:focus-visible > .bs-thumb{ outline:none; box-shadow:var(--focus-ring); }
.bs-thumb.is-active,.bs-thumb[aria-selected="true"],.bs-thumb[aria-pressed="true"],[aria-current] > .bs-thumb{ border-color:var(--accent); }
.bs-thumb--sm{ --thumb:var(--ctl-md); border-width:var(--bw); border-radius:var(--rad-sm); }
.bs-thumb--fill{ width:100%; height:auto; aspect-ratio:1; }
.bs-thumb__x{ position:absolute; top:calc(var(--sp-1) / 2); right:calc(var(--sp-1) / 2); z-index:1; display:grid; place-items:center;
  width:var(--sp-5); height:var(--sp-5); margin:0; padding:0; border:0; border-radius:var(--rad-pill);
  background:var(--onmedia-dark-bg); color:var(--onmedia-dark-ink); cursor:pointer; transition:background var(--dur-fast) var(--ease); }
.bs-thumb__x::before{ content:""; position:absolute; inset:calc(-1 * var(--sp-2)); }
.bs-thumb__x:hover{ background:var(--onmedia-dark-bg-hover); }
.bs-thumb__x:focus-visible{ outline:none; box-shadow:var(--focus-ring); }
.bs-thumb__x svg{ width:var(--icon-xs); height:var(--icon-xs); }
@media (prefers-reduced-motion:reduce){ .bs-thumb,.bs-thumb__x{ transition:none; } }

/* ── Блок-призыв · .bs-cta (один на всю базу знаний; внизу хаба и статьи): мягкий акцентный фон,
   заголовок, строка текста, одна главная кнопка (+ необязательная тихая строка снизу).
   <section class="bs-cta"><h2 class="bs-cta__title">…</h2><p class="bs-cta__text">…</p>
     <div class="bs-cta__actions"><a class="bs-btn bs-btn--primary bs-btn--lg" href="…">…</a></div>
     <p class="bs-cta__aside">Печатаете на заказ? <a class="bs-link" href="/for-makers/">…</a></p></section> */
.bs-cta{ display:flex; flex-direction:column; align-items:flex-start; gap:var(--sp-3); box-sizing:border-box;
  padding:var(--sp-7); background:var(--accent-soft); border:var(--bw) solid var(--violet-100); border-radius:var(--rad-xl); color:var(--ink); }
.bs-cta__title{ margin:0; padding:0; font:700 var(--fs-xl)/var(--lh-tight) var(--font); letter-spacing:-.01em; color:var(--ink); }
.bs-cta__title::before{ content:none; }
.bs-cta__text{ margin:0; max-width:60ch; font:400 var(--fs-base)/var(--lh-normal) var(--font); color:var(--ink2); }
.bs-cta__actions{ display:flex; flex-wrap:wrap; gap:var(--sp-3); margin-top:var(--sp-2); }
.bs-cta__aside{ margin:var(--sp-2) 0 0; font:400 var(--fs-sm)/var(--lh-normal) var(--font); color:var(--ink2); }
@media (max-width:600px){
  .bs-cta{ padding:var(--sp-5); }
  .bs-cta__title{ font-size:var(--fs-lg); }
  .bs-cta__actions, .bs-cta__actions > .bs-btn{ width:100%; }
}

/* ── Предложение площадки в статье · .bs-promo (23.10: «каждая статья рано и явно показывает, что
   делать у нас»). Один компонент, два варианта по СОДЕРЖАНИЮ (вид один): data-promo="buyer" — сразу
   после лида, data-promo="seller" — перед FAQ. Белая приподнятая карточка (не --accent-soft: под ней
   стоит «Коротко» .bs-note--info, две фиолетовые плашки подряд слипаются), заголовок 700 --fs-md,
   3 факта со значком в мягком квадрате 24, одна главная кнопка 44 + тихая ссылка .bs-link.
     ПК (>640): факты слева, действия колонкой справа по центру — высота ~150 вместо ~210.
     ≤640: одна колонка, кнопка тянется, ссылка рядом; не влезла — переносится под кнопку.
   Внутренние правила под .bs-promo (0,2,0): перебивают типографику статьи (.article p/ul/li — 0,1,1)
   без !important. Цифры в фактах вписывает автор текста (не вычисляются).
   <aside class="bs-promo" data-promo="buyer" aria-label="Нужна модель сегодня?">
     <p class="bs-promo__title">Нужна модель сегодня?</p>
     <ul class="bs-promo__facts"><li class="bs-promo__fact"><svg class="bs-ico bs-promo__ico" aria-hidden="true" focusable="false"><use href="/icons.svg?v=2bc424ce59#credit-card"/></svg><span>…</span></li>…</ul>
     <div class="bs-promo__actions"><a class="bs-btn bs-btn--primary" href="/stl/">Смотреть каталог</a><a class="bs-link" href="/stl/besplatno">Бесплатные модели</a></div>
   </aside> */
.bs-promo{ display:grid; grid-template-columns:minmax(0,1fr) auto; grid-template-areas:"title actions" "facts actions";
  align-items:center; gap:var(--sp-3) var(--sp-6); box-sizing:border-box; padding:var(--sp-5);
  background:var(--card); border:var(--bw) solid var(--line); border-radius:var(--rad-lg); box-shadow:var(--shadow-1);
  color:var(--ink); font:400 var(--fs-sm)/var(--lh-normal) var(--font); }
.bs-promo .bs-promo__title{ grid-area:title; margin:0; padding:0; font:700 var(--fs-md)/var(--lh-tight) var(--font); letter-spacing:-.01em; color:var(--ink); text-wrap:balance; }
.bs-promo .bs-promo__title::before{ content:none; }
.bs-promo .bs-promo__facts{ grid-area:facts; display:flex; flex-direction:column; gap:var(--sp-1); margin:0; padding:0; list-style:none;
  font:500 var(--fs-sm)/var(--lh-relaxed) var(--font); color:var(--ink); font-variant-numeric:tabular-nums; }
.bs-promo .bs-promo__fact{ display:flex; align-items:flex-start; gap:var(--sp-2); margin:0; padding:0; line-height:inherit; text-wrap:pretty; }
.bs-promo .bs-promo__fact::before{ content:none; }
/* значок: 16 в мягком квадрате 24 (= высота строки факта --lh-relaxed, первая строка ровно по центру значка) */
.bs-promo .bs-promo__ico{ box-sizing:content-box; flex:none; width:var(--icon-sm); height:var(--icon-sm); padding:var(--sp-1);
  border-radius:var(--rad-xs); background:var(--accent-soft); color:var(--accent-strong); vertical-align:top; }
.bs-promo .bs-promo__actions{ grid-area:actions; display:flex; flex-direction:column; align-items:stretch; gap:var(--sp-2); margin:0; }
.bs-promo .bs-promo__actions > .bs-link{ align-self:center; font-size:var(--fs-sm); }
/* тихая ссылка = вид .bs-link и внутри статьи: (0,2,0) перебивает .article a (--violet ~4:1, без подчёркивания) */
.bs-promo .bs-link{ color:var(--accent-text); text-decoration:underline; text-underline-offset:3px; text-decoration-color:var(--violet-200); }
.bs-promo .bs-link:hover{ color:var(--accent-text); text-decoration-color:currentColor; }
@media (max-width:640px){
  .bs-promo{ grid-template-columns:minmax(0,1fr); grid-template-areas:"title" "facts" "actions"; padding:var(--sp-4); }
  .bs-promo .bs-promo__actions{ flex-direction:row; flex-wrap:wrap; align-items:center; justify-content:center; gap:0 var(--sp-4); margin-top:var(--sp-1); }
  .bs-promo .bs-promo__actions > .bs-btn{ flex:1 1 auto; }
  .bs-promo .bs-promo__actions > .bs-link{ display:inline-flex; align-items:center; align-self:auto; min-height:var(--ctl-md); }   /* тап-зона 44 у тихой ссылки */
}

/* ── Аватар · .bs-avatar (главная 23.10, решение В1): круглая кнопка-аватар в шапке у вошедшего —
   вход в кабинет. Высота --ctl-md (44), как ☰ и колокольчик рядом. Внутри — фото или первая буква
   имени (буква — основной шрифт 600 на --accent-soft). --sm — 32.
   <a class="bs-avatar" href="/cabinet.html" aria-label="Кабинет — Анна"><span class="bs-avatar__l" aria-hidden="true">А</span></a>
   <a class="bs-avatar" href="…"><img src="…" alt=""></a> */
.bs-avatar{ display:inline-grid; place-items:center; flex:none; width:var(--ctl-md); height:var(--ctl-md); padding:0; overflow:hidden;
  border-radius:50%; border:var(--bw) solid var(--line2); background:var(--accent-soft); color:var(--accent-strong);
  box-shadow:var(--bs-raise); text-decoration:none; cursor:pointer;
  transition:border-color var(--dur) var(--ease), transform var(--dur) var(--ease); }
.bs-avatar:hover{ border-color:color-mix(in srgb, var(--ink) 22%, var(--line2)); transform:var(--btn-hover-grow); }
.bs-avatar:focus-visible{ outline:none; box-shadow:var(--focus-ring); }
.bs-avatar img{ width:100%; height:100%; object-fit:cover; display:block; }
.bs-avatar__l{ font:600 var(--fs-base)/1 var(--font); text-transform:uppercase; }
.bs-avatar--sm{ width:var(--ctl-sm); height:var(--ctl-sm); }
.bs-avatar--sm .bs-avatar__l{ font-size:var(--fs-xs); }
@media (prefers-reduced-motion:reduce){ .bs-avatar{ transition:none; } .bs-avatar:hover{ transform:none; } }

/* ── Строка фактов · .bs-facts (главная 23.10): «значок + короткий факт» подряд — строка доверия под
   баннером, факты в карточке цен. Значки — спрайт (.bs-ico), цвет --accent-text; текст --ink2.
   --col — столбиком (список «что входит»).
   <ul class="bs-facts"><li><svg class="bs-ico">…</svg>Оплата картой в рублях</li>…</ul> */
.bs-facts{ display:flex; flex-wrap:wrap; align-items:center; gap:var(--sp-2) var(--sp-5); margin:0; padding:0; list-style:none;
  font:500 var(--fs-sm)/var(--lh-tight) var(--font); color:var(--ink2); }
.bs-facts > li{ display:inline-flex; align-items:center; gap:var(--sp-2); margin:0; padding:0; min-width:0; }
.bs-facts > li::before{ content:none; }
.bs-facts .bs-ico{ width:var(--icon-sm); height:var(--icon-sm); color:var(--accent-text); }
.bs-facts--col{ flex-direction:column; align-items:flex-start; gap:var(--sp-2); }
.bs-facts--col > li{ align-items:flex-start; }
.bs-facts--col .bs-ico{ margin-top:calc((1em * var(--lh-tight) - var(--icon-sm)) / 2); }
/* --split (чек «за что списали», 23.10): строки во всю ширину под линией — «значок + факт» слева
   (подпись мелко — __sub), значение справа (__v; пометка под ним — <small>).
   <ul class="bs-facts bs-facts--col bs-facts--split"><li><svg class="bs-ico">…</svg>
     <span><b>Товары</b><span class="bs-facts__sub">Органайзер</span></span>
     <span class="bs-facts__v">1 490 ₽<small>оплачено картой</small></span></li>…</ul> */
.bs-facts--split{ align-items:stretch; gap:0; }
.bs-facts--split > li{ padding:var(--sp-2) 0; border-top:var(--bw) solid var(--line2); }
.bs-facts--split b{ color:var(--ink); font-weight:600; }
.bs-facts__sub{ display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden;
  font:400 var(--fs-xs)/var(--lh-tight) var(--font); color:var(--ink2); }
.bs-facts__v{ flex:none; margin-left:auto; display:flex; flex-direction:column; align-items:flex-end; text-align:right;
  font-weight:700; color:var(--ink); font-variant-numeric:tabular-nums; }
.bs-facts__v small{ font:600 var(--fs-2xs)/1 var(--font); color:var(--ok-text); }

/* ── Шаги списком · .bs-steps--list (главная /how 23.10): та же нумерация .bs-steps, но столбиком и
   с пояснением — «как это работает» по шагам. Номер — мягкий кружок (не текущий шаг процесса).
   <ol class="bs-steps bs-steps--list"><li class="bs-steps__item"><span class="bs-steps__num">1</span>
     <span class="bs-steps__body"><b class="bs-steps__title">Найдите нужное</b><span class="bs-steps__text">…</span></span></li>…</ol> */
.bs-steps--list{ flex-direction:column; align-items:stretch; gap:var(--sp-4); color:var(--ink); }
.bs-steps--list .bs-steps__item{ align-items:flex-start; gap:var(--sp-3); }
.bs-steps--list .bs-steps__item + .bs-steps__item::before{ content:none; }
.bs-steps--list .bs-steps__num{ flex:none; background:var(--accent-soft); color:var(--accent-strong); }   /* пачка 3 · блог · 23.10: длинный текст шага не сжимает кружок */
.bs-steps__body{ display:flex; flex-direction:column; gap:var(--sp-1); min-width:0; padding-top:calc((var(--icon-lg) - 1em * var(--lh-tight)) / 2); }
.bs-steps__title{ font:600 var(--fs-base)/var(--lh-tight) var(--font); color:var(--ink); }
.bs-steps__text{ font:400 var(--fs-sm)/var(--lh-normal) var(--font); color:var(--ink2); }
/* --list как ПРОГРЕСС (трек заказа, 23.10): есть текущий шаг (aria-current) → пройденные — мягкий кружок
   с галочкой, текущий — градиент, будущие — нейтральные (как в ряду); кружки связаны линией.
   Подпись под шагом («сейчас», «ожидается», дата) — .bs-steps__text. */
.bs-steps--list:has([aria-current="step"]){ gap:var(--sp-3); }
.bs-steps--list:has([aria-current="step"]) .bs-steps__item{ position:relative; }
.bs-steps--list:has([aria-current="step"]) .bs-steps__item:not(:last-child)::after{ content:""; position:absolute;
  left:calc((var(--icon-lg) - var(--bw-strong)) / 2); top:var(--icon-lg); bottom:calc(-1 * var(--sp-3)); width:var(--bw-strong); background:var(--line2); }
.bs-steps--list:has([aria-current="step"]) .bs-steps__item.is-done:not(:last-child)::after{ background:var(--violet-200); }
.bs-steps--list:has([aria-current="step"]) .bs-steps__item:not(.is-done):not([aria-current="step"]) .bs-steps__num{ background:var(--bg2); color:var(--ink2); }
.bs-steps--list:has([aria-current="step"]) .bs-steps__item:not(.is-done):not([aria-current="step"]) .bs-steps__title{ color:var(--ink2); font-weight:500; }
/* прогресс — компактный: шкала служебная, не заголовок экрана (кегль как у строк чека рядом) */
.bs-steps--list:has([aria-current="step"]) .bs-steps__title{ font-size:var(--fs-sm); }
.bs-steps--list:has([aria-current="step"]) .bs-steps__text{ font-size:var(--fs-xs); }
.bs-steps--list .bs-steps__item[aria-current="step"] .bs-steps__text{ color:var(--accent-text); font-weight:600; }

/* ── Скелет карточки товара · .bs-skel-card (главная 23.10): пока грузится сетка — заглушки формы
   карточки (фото 4:5 + цена + название + кнопка), а не спиннер. Ставится в ту же сетку, что карточки.
   <div class="bs-skel-card" aria-hidden="true"><div class="bs-skel-card__media"></div>
     <div class="bs-skel__row" style="width:40%"></div><div class="bs-skel__row"></div><div class="bs-skel-card__btn"></div></div> */
.bs-skel-card{ display:flex; flex-direction:column; gap:var(--sp-3); padding:var(--sp-2) var(--sp-2) var(--sp-3); box-sizing:border-box;
  background:var(--card); border:var(--bw) solid var(--line); border-radius:var(--rad-lg); }
.bs-skel-card__media{ aspect-ratio:var(--card-media-ratio); border-radius:var(--rad-md); }
.bs-skel-card__btn{ height:var(--ctl-sm); border-radius:var(--rad-pill); }
.bs-skel-card > .bs-skel__row{ margin:0 var(--sp-2); }
.bs-skel-card__media,.bs-skel-card__btn{ background:linear-gradient(90deg, var(--bg2) 25%, var(--gray-200) 37%, var(--bg2) 63%); background-size:400% 100%;
  animation:bs-skel 1.3s ease infinite; }
@media (prefers-reduced-motion:reduce){ .bs-skel-card__media,.bs-skel-card__btn{ animation:none; } }

/* ── «Поделиться» · .bs-share-net (моя страница · поделиться · 23.10, Под-1…7) ──────────────────
   Окно «Поделиться» (src/social-actions.js) — обычное окно ДС openBsDialog (bs-dialog.js), на телефоне
   шторка снизу. Площадки — круги 44 одного размера в цвете площадки, подпись под кругом (Под-3 А).
   Знак — бренд-символ спрайта (bs-tg, bs-vk, bs-wa, bs-pin, bs-ok, bs-x; Simple Icons, CC0), белым в круге.
   Круглые знаки Telegram и Pinterest (--disc) рисуются целиком, в цвете площадки — круг и есть знак.
   Цвет площадки — модификатор (--tg…--viber) → токен --brand-* (tokens.css). «Копировать» — нейтральный круг.
   <div class="bs-share-nets"><button class="bs-share-net bs-share-net--tg bs-share-net--disc" type="button">
     <span class="bs-share-net__c"><svg class="bs-ico">…#bs-tg</svg></span><span class="bs-share-net__l">Telegram</span></button>…</div>
   Разделы окна (.bs-share-sec) — через тонкую линию; подпись раздела — .bs-field__label. */
.bs-share-sec{ display:flex; flex-direction:column; gap:var(--sp-3); padding:var(--sp-4) 0; }
.bs-share-sec:first-child{ padding-top:0; }
.bs-share-sec + .bs-share-sec{ border-top:var(--bw) solid var(--line); }
.bs-share-slot{ display:flex; flex-direction:column; gap:var(--sp-3); }   /* раздел: поле → кнопка */
.bs-share-nets{ display:grid; grid-template-columns:repeat(4, minmax(0, 1fr)); gap:var(--sp-3) var(--sp-1); }
.bs-share-net{ --net:var(--bg2); --net-ink:var(--on-accent);
  display:flex; flex-direction:column; align-items:center; gap:var(--sp-1); min-width:0; padding:var(--sp-1) 0;
  border:0; border-radius:var(--rad-md); background:none; cursor:pointer; color:var(--ink2); text-decoration:none;
  transition:background var(--dur-fast) var(--ease); }
.bs-share-net:hover{ background:var(--hover-fill); }
.bs-share-net:focus-visible{ outline:none; box-shadow:var(--focus-ring); }
.bs-share-net__c{ display:grid; place-items:center; width:var(--ctl-md); height:var(--ctl-md); border-radius:var(--rad-pill);
  background:var(--net); color:var(--net-ink); }
.bs-share-net__c .bs-ico{ width:var(--icon-lg); height:var(--icon-lg); }
.bs-share-net--disc .bs-share-net__c{ background:none; color:var(--net); }
.bs-share-net--disc .bs-share-net__c .bs-ico{ width:100%; height:100%; }
/* подпись не режется многоточием: «Одноклассники» на телефоне чуть шире колонки — выходит в зазор,
   соседние подписи короткие (порядок площадок задан в NETWORKS) */
.bs-share-net__l{ white-space:nowrap; font:500 var(--fs-xs)/var(--lh-tight) var(--font); }
.bs-share-net--tg{ --net:var(--brand-tg); }
.bs-share-net--vk{ --net:var(--brand-vk); }
.bs-share-net--wa{ --net:var(--brand-wa); }
.bs-share-net--pin{ --net:var(--brand-pin); }
.bs-share-net--ok{ --net:var(--brand-ok); }
.bs-share-net--x{ --net:var(--brand-x); }
.bs-share-net--viber{ --net:var(--brand-viber); }
.bs-share-net--copy{ --net-ink:var(--ink2); }
.bs-share-net--copy .bs-share-net__c{ box-shadow:inset 0 0 0 var(--bw) var(--line2); }
.bs-share-net.is-done{ color:var(--ok-text); }
@media (max-width:359px){ .bs-share-nets{ grid-template-columns:repeat(3, minmax(0, 1fr)); } }
@media (prefers-reduced-motion:reduce){ .bs-share-net{ transition:none; } }

/* ── Окно входа · .bs-authgate (моя страница · окно входа · 23.10, Вход-1…4) ──────────────────
   authModal() (pop_toolkit.js) — узкое окно ДС openBsDialog(…, cls 'bs-dialog--confirm bs-authgate'),
   на телефоне шторка снизу. Сверху — Кликко выглядывает из норки (assets/klikko-peek.png, Вход-3 Б),
   под ним текст; внизу .bs-dialog__foot: «Войти» — вторичная, «Зарегистрироваться» — главная справа.
   Заголовок окна — «Войдите, чтобы …» по действию; шапка окна без заголовка-строки сверху (он под картинкой). */
.bs-authgate{ position:relative; }
.bs-authgate .bs-dialog__head{ position:absolute; top:0; right:0; padding:var(--sp-3); }
.bs-authgate .bs-dialog__head .bs-dialog__title{ display:none; }
.bs-authgate .bs-dialog__body{ display:flex; flex-direction:column; align-items:center; gap:var(--sp-2); text-align:center;
  padding-top:var(--sp-6); }
.bs-authgate__art{ width:120px; height:auto; aspect-ratio:553 / 709; object-fit:contain; margin-bottom:var(--sp-1);
  animation:bs-klikko-in var(--dur-slow) var(--ease-bounce) both; }
.bs-authgate__title{ margin:0; font:var(--fw-display) var(--fs-lg)/var(--lh-tight) var(--font-display); color:var(--ink); text-wrap:balance; }
.bs-authgate__text{ margin:0; color:var(--ink2); text-wrap:pretty; }
.bs-authgate > .bs-dialog__foot{ border-top:0; padding-top:var(--sp-2); }
.bs-authgate > .bs-dialog__foot .bs-btn{ flex:1; }   /* две кнопки поровну, как на телефоне (макет Вход-3 Б) */
@media (prefers-reduced-motion:reduce){ .bs-authgate__art{ animation:none; } }

/* моя страница · поделиться · 23.10 (Под-7): пункты меню ДС на телефоне и тач-экране — 44 (тап-зона), на ПК остаются 40 */
@media (pointer:coarse), (max-width:599px){ .bs-menu__item{ min-height:var(--ctl-md); } }

/* ── моя страница · AR · 23.10 — ТЁМНАЯ СЦЕНА · .bs-scene (решение AR-1 «да») ───────────────────────
   Полноэкранная тёмная подложка со свечением сверху (примерка в комнате, дальше — 3D на весь экран).
   Внутри переназначены роли ДС → обычные компоненты работают без отдельных классов:
     .bs-btn--primary — градиент сцены (--scene-grad); --secondary — «стекло» сцены (--scene-surface);
     --ghost — светлый текст, наведение светлее; выбранное (aria-pressed) — акцентом; .bs-badge--warn/--accent,
     .bs-note, .bs-link, .bs-mbtn--dark — в цветах сцены. Токены — раздел «ТЁМНАЯ СЦЕНА» в tokens.css.
   <div class="bs-scene">…</div>   (позиционирует страница: fixed/inset — её слой) */
.bs-scene{
  --ink:var(--scene-ink); --ink2:var(--scene-ink2); --text-muted:var(--scene-ink2);
  --line:var(--scene-line); --line2:var(--scene-line); --card:var(--scene-surface); --bg2:var(--scene-surface);
  --hover-fill:var(--scene-surface-hover);
  --accent-soft:var(--scene-accent-soft); --accent-strong:var(--scene-accent); --accent-text:var(--scene-accent);
  --warn-soft:var(--scene-warn-soft); --warn-text:var(--scene-warn-text);
  --grad-btn:var(--scene-grad); --shadow-btn:var(--scene-shadow); --bs-raise:none;
  --focus-color:var(--scene-ink); --focus-ring:0 0 0 2px var(--scene-bg), 0 0 0 4px var(--scene-ink);
  color:var(--ink); background:var(--scene-glow), var(--scene-bg);
  font-family:var(--font); -webkit-font-smoothing:antialiased;
}
.bs-scene .bs-btn--secondary:hover:not(:disabled){ background:var(--scene-surface-hover); border-color:var(--scene-line); }
.bs-scene .bs-btn--secondary[aria-pressed="true"]{ border-color:var(--scene-accent); }
.bs-scene .bs-link{ text-decoration-color:var(--scene-line); }
.bs-scene .bs-note{ border:var(--bw) solid var(--scene-line); }
.bs-scene .bs-mbtn[aria-pressed="true"]{ background:var(--scene-accent-soft); color:var(--scene-accent); }
/* круглая кнопка поверх кадра крупнее (тач-экран, камера на весь экран): .bs-mbtn--md — 44 */
.bs-mbtn--md{ height:var(--ctl-md); }
.bs-mbtn--md.bs-mbtn--icon{ width:var(--ctl-md); }
.bs-mbtn--md svg{ width:var(--icon-md); height:var(--icon-md); }

/* ── Состояние на сцене · .bs-scene-state (AR-2/AR-3): плитка-значок (+ мягкий силуэт Кликко позади),
   заголовок, текст, действия. Одно на «Откройте на смартфоне», «Нет доступа к камере», загрузку,
   «Разрешите камеру». Главная кнопка — одна (.bs-btn--primary .bs-btn--lg), «Закрыть» — тихая --ghost.
   Крестик — круглая .bs-btn--ghost --icon --sm с классом .bs-scene-state__close (правый верх).
   --busy — плитка спокойно покачивается (загрузка).
   <section class="bs-scene-state">
     <button class="bs-btn bs-btn--ghost bs-btn--icon bs-btn--sm bs-scene-state__close" aria-label="Закрыть">…x…</button>
     <div class="bs-scene-state__media"><img class="bs-scene-state__glow" src="/assets/klikko-….png" alt="">
       <span class="bs-scene-state__tile">…значок…</span></div>
     <h2 class="bs-scene-state__title">…</h2><p class="bs-scene-state__text">…</p>
     <div class="bs-scene-state__actions">…кнопки…</div></section> */
.bs-scene-state{ display:flex; flex-direction:column; align-items:center; justify-content:center; gap:var(--sp-2);
  text-align:center; box-sizing:border-box;
  padding:calc(var(--sp-6) + env(safe-area-inset-top,0px)) var(--sp-7) calc(var(--sp-6) + env(safe-area-inset-bottom,0px)); }
.bs-scene-state__close{ position:absolute; top:calc(var(--sp-3) + env(safe-area-inset-top,0px)); right:var(--sp-3); }
.bs-scene-state__media{ position:relative; display:grid; place-items:center; margin-bottom:var(--sp-3); }
.bs-scene-state__glow{ position:absolute; left:50%; top:50%; width:auto; max-width:none; object-fit:contain; height:calc(var(--scene-tile) * 3.6);   /* max-width:none — общее img{max-width:100%} сжимало ширину до плитки, заяц вытягивался */
  transform:translate(-50%, -44%); opacity:.24; filter:blur(4px) saturate(.5); pointer-events:none; user-select:none; }
.bs-scene-state__tile{ position:relative; display:grid; place-items:center; width:var(--scene-tile); height:var(--scene-tile);
  border-radius:calc(var(--scene-tile) * .3); background:var(--scene-grad); color:var(--white);
  box-shadow:var(--scene-shadow), inset 0 1px 0 color-mix(in srgb, var(--white) 35%, transparent);
  animation:bs-scene-pop .5s var(--ease-bounce) both; }
.bs-scene-state__tile svg{ width:var(--scene-tile-icon); height:var(--scene-tile-icon); }
.bs-scene-state--busy .bs-scene-state__tile{ animation:bs-scene-float 1.8s ease-in-out infinite; }
.bs-scene-state__title{ margin:var(--sp-1) 0 0; font:var(--fw-display) var(--fs-lg)/var(--lh-tight) var(--font-display); letter-spacing:-.02em; color:var(--ink); text-wrap:balance; }
.bs-scene-state__text{ margin:0 0 var(--sp-1-5); max-width:320px; font:500 var(--fs-sm)/var(--lh-normal) var(--font); color:var(--ink2); text-wrap:pretty; }
.bs-scene-state__actions{ display:flex; flex-direction:column; align-items:center; gap:var(--sp-2); margin-top:var(--sp-2); }
.bs-scene-state .bs-note{ max-width:320px; text-align:left; }
@keyframes bs-scene-pop{ 0%{ transform:scale(.6) rotate(-6deg); opacity:0; } 60%{ transform:scale(1.08) rotate(2deg); } 100%{ transform:none; opacity:1; } }
@keyframes bs-scene-float{ 0%,100%{ transform:translateY(0); } 50%{ transform:translateY(-7px); } }
@media (prefers-reduced-motion:reduce){ .bs-scene-state__tile{ animation:none; } }

/* ── QR-карточка · .bs-qr-card (AR-2): белая карточка с кодом на тёмной сцене (и где угодно).
   Код — svg из qrSvg() (src/qr-mini.js) или <img>. Под ней — ссылка .bs-link и «Скопировать ссылку». */
.bs-qr-card{ display:grid; place-items:center; box-sizing:border-box; width:172px; height:172px; margin:var(--sp-1-5) 0 var(--sp-1);
  padding:var(--sp-3); border-radius:var(--rad-lg); background:var(--white); color:var(--gray-900);
  box-shadow:0 14px 34px -12px color-mix(in srgb, var(--gray-950) 60%, transparent); }
.bs-qr-card > :is(svg, img, canvas){ display:block; width:100%; height:100%; image-rendering:pixelated; }

/* моя страница · одна зона загрузки · 23.10 — метка вида на миниатюре (.bs-thumb__tag): «3D» в
   левом верхнем углу плитки модели (постер модели + метка; «Главное» — снизу, как у фото).
   <span class="bs-badge bs-badge--accent bs-thumb__tag">3D</span> */
.bs-thumb__tag{ position:absolute; left:var(--sp-1); top:var(--sp-1); height:20px; box-shadow:var(--shadow-1); }

/* ══ ВИТРИНА /home И ШАПКА ГОСТЯ (27.10, макет утверждён владельцем) — компоненты ═══════════════════
   Контролы, которые завела витрина для новичка, живут здесь, а не в CSS страницы (сторож ДС
   tests/test_ds_new_guards.py: новый кликабельный компонент — только в ui-kit.css). Вид перенесён
   бит-в-бит из frontend/vitrina.css и frontend/pop.css; раскладка рядов (сетки, ленты на телефоне,
   отступы блоков) осталась в vitrina.css. Имена — по канону ДС .bs-* (28.10: .vt-all/cat/tool/master/join/pcard/order → .bs-morelink/cattile/
   tooltile/mtile/jointile/posttile/ordertile; размеры — токены --tile-*); разметка — templates/vitrina_ssr.html.
   «Стать мастером» в шапке — .bs-btn.bs-btn--secondary + крючок .pp-nav-join (_nav.html, site_chrome.guest_nav, navHTML). ══ */

/* ── «Стать мастером» в шапке · .pp-nav-join — на всех поверхностях с .pp-nav ── */
/* Единственная СПЛОШНАЯ кнопка шапки (владелец 27.10: макет витрины — «Регистрация», второй заход —
   «нет ни одной кнопки стать мастером»): гостю и вошедшему без роли мастера «Стать мастером», мастеру
   кнопки нет. Компактная (36 на ПК, DENSITY §3), на ВСЕХ поверхностях — SSR _nav.html,
   site_chrome.guest_nav, navHTML. «Войти · Регистрация» рядом — тихие ссылки (.pp-nav-login).
   Не градиент: градиентная главная на экране одна (CTA самой страницы), а шапка стоит на каждой
   странице и спорила бы с ней (§14.A).
   Ревью 02.11 (V04): вид — вторичная .bs-btn--secondary. Заливка покупки (--buy-*) была того же цвета, что
   «В корзину», и спорила с покупкой; цвет покупки — только у покупки. Заметная дверь — флагман шторки ☰.
   .pp-nav-join — только крючок раскладки шапки: видимость --auth и тап-зона ниже. */
/* вошедшему (колокольчик + аватар + ☰ справа) кнопке нет места уже на планшете: дверь — флагман шторки ☰ */
.pp-nav-join--auth{ display:none; }
@media(min-width:1100px){ .pp-nav-join--auth{ display:inline-flex; } }
@media(max-width:560px){
  /* «Стать мастером» остаётся справа от логотипа: 32 на вид, тап-зона 44 невидимым полем (§14.D).
     «Войти» на телефоне живёт в нижней панели (слот 4) у большого пальца, «Регистрация» — вкладкой
     на том же экране входа; «Стать мастером» — разовое действие, ему место в шапке, а не шестой слот
     панели (mobile-nav: ≤5). */
  .pp-nav-join{ position:relative; padding:0 var(--sp-3); }
  .pp-nav-join::after{ content:""; position:absolute; left:0; right:0; top:50%; height:var(--ctl-md); transform:translateY(-50%); }
}

/* ── «Смотреть все ›» · .bs-morelink — ссылка-продолжение в шапке блока (место в строке задаёт страница) ── */
.bs-morelink{ display:inline-flex; align-items:center; gap:var(--sp-1);
  min-height:var(--ctl-sm); padding:0 var(--sp-2) 0 var(--sp-3); border-radius:var(--rad-pill);
  font:600 var(--fs-ctl)/1 var(--font); color:var(--accent-text); text-decoration:none; white-space:nowrap;
  transition:background var(--dur) var(--ease); }
.bs-morelink .bs-ico{ width:var(--icon-sm); height:var(--icon-sm); transition:transform var(--dur) var(--ease); }
.bs-morelink:hover{ background:var(--hover-fill); }
.bs-morelink:hover .bs-ico{ transform:translateX(calc(var(--sp-1) / 2)); }
.bs-morelink:focus-visible{ outline:none; box-shadow:var(--focus-ring); }

/* ── Плитка категории · .bs-cattile — картинка 64, подпись в 2 строки, число справа сверху; «Все категории» ── */
.bs-cattile{ position:relative; display:flex; flex-direction:column; align-items:center; gap:var(--sp-1-5);
  height:100%; box-sizing:border-box; padding:var(--sp-3) var(--sp-2);
  background:var(--card); border:var(--bw) solid var(--line); border-radius:var(--rad-xl);
  text-align:center; text-decoration:none; color:var(--ink);
  transition:border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease), transform var(--dur) var(--ease-bounce); }
.bs-cattile__img{ width:var(--tile-img); height:var(--tile-img); object-fit:contain; transition:transform var(--dur-slow) var(--ease-bounce); }
.bs-cattile__l{ font:600 var(--fs-ctl)/1.25 var(--font); display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden; min-height:2.5em; text-wrap:balance; }
.bs-cattile__n{ position:absolute; top:var(--sp-2); right:var(--sp-2); font:600 var(--fs-2xs)/1 var(--font); color:var(--text-muted); font-variant-numeric:tabular-nums; }
.bs-cattile:hover{ border-color:var(--line-neon); box-shadow:var(--shadow-1); transform:translateY(calc(-1 * var(--sp-1))); }
.bs-cattile:hover .bs-cattile__img{ transform:scale(1.07) rotate(-4deg); }
.bs-cattile:focus-visible{ outline:none; box-shadow:var(--focus-ring); }
/* «Все категории» и заглушка иконки — тот же круг 64, чтобы ряд не прыгал */
.bs-cattile__ph{ display:grid; place-items:center; width:var(--tile-img); height:var(--tile-img); border-radius:50%; flex:none; }
.bs-cattile__ph .bs-ico{ width:var(--icon-lg); height:var(--icon-lg); }
.bs-cattile__ph--all{ background:var(--accent-soft); color:var(--accent-strong); }
.bs-cattile__ph--wip{ background:var(--bg2); color:var(--text-muted); box-shadow:inset 0 0 0 var(--bw-strong) var(--line2); }
.bs-cattile--all .bs-cattile__l{ color:var(--accent-text); }

/* ── Плитка инструмента · .bs-tooltile — значок-«кубик» 40 + метка, название, описание в 2 строки ── */
.bs-tooltile{ display:flex; flex-direction:column; gap:var(--sp-1); height:100%; box-sizing:border-box; padding:var(--sp-3) var(--sp-4) var(--sp-4) var(--sp-3);
  background:var(--card); border:var(--bw) solid var(--line); border-radius:var(--rad-xl); text-decoration:none; color:var(--ink);
  transition:border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease), transform var(--dur) var(--ease-bounce); }
.bs-tooltile__top{ display:flex; align-items:flex-start; justify-content:space-between; gap:var(--sp-2); margin-bottom:var(--sp-1); }
.bs-tooltile__ic{ flex:none; display:grid; place-items:center; width:var(--tile-ic); height:var(--tile-ic); border-radius:var(--rad-lg);
  background:var(--accent-soft); color:var(--accent-strong); }
.bs-tooltile__ic .bs-ico{ width:var(--icon-md); height:var(--icon-md); }
.bs-tooltile__l{ min-width:0; max-width:60%; padding:var(--sp-1) var(--sp-2); border-radius:var(--rad-pill); background:var(--bg2);
  font:600 var(--fs-2xs)/1.2 var(--font); color:var(--ink2); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.bs-tooltile__t{ font:600 var(--fs-sm)/1.3 var(--font); }
.bs-tooltile__d{ font:400 var(--fs-xs)/var(--lh-normal) var(--font); color:var(--ink2);
  display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden; }
.bs-tooltile:hover{ border-color:var(--line-neon); box-shadow:var(--shadow-2); transform:translateY(calc(-1 * var(--sp-1))); }   /* плитка лежит на фирменном градиенте полосы: --shadow-1 на нём не виден, подъём без тени читался прыжком */
.bs-tooltile:focus-visible{ outline:none; box-shadow:var(--focus-ring); }

/* ── Плитка мастера · .bs-mtile — аватар 56 (или буква), имя, город, число товаров ── */
.bs-mtile{ display:flex; flex-direction:column; align-items:center; gap:var(--sp-1); height:100%; box-sizing:border-box;
  padding:var(--sp-4) var(--sp-3); background:var(--card); border:var(--bw) solid var(--line); border-radius:var(--rad-xl);
  text-align:center; text-decoration:none; color:var(--ink);
  transition:border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease), transform var(--dur) var(--ease-bounce); }
.bs-mtile:hover{ border-color:var(--line-neon); box-shadow:var(--shadow-1); transform:translateY(calc(-1 * var(--sp-1))); }
.bs-mtile:focus-visible{ outline:none; box-shadow:var(--focus-ring); }
.bs-mtile__av{ width:var(--tile-av); height:var(--tile-av); border-radius:50%; overflow:hidden; flex:none; margin-bottom:var(--sp-1);
  display:grid; place-items:center; background:var(--cover-1); color:var(--cover-mono); font:var(--fw-display) var(--fs-lg)/1 var(--font-display); }
.bs-mtile__av img{ width:100%; height:100%; object-fit:cover; display:block; }
.bs-mtile__n{ max-width:100%; font:600 var(--fs-sm)/1.3 var(--font); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.bs-mtile__m{ max-width:100%; font:400 var(--fs-xs)/1.3 var(--font); color:var(--text-muted); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.bs-mtile__s{ font:500 var(--fs-xs)/1.3 var(--font); color:var(--ink2); font-variant-numeric:tabular-nums; }

/* ── Плитка-призыв в ряду мастеров · .bs-jointile — «Ваше место — здесь» (владелец 27.10) ──
   Тот же габарит, что .bs-mtile (стоит первой в его сетке), но читается как ПУСТОЕ МЕСТО: мягкая заливка
   акцента + пунктирная рамка, вместо аватара — круг с «+». Сама плитка не кликабельна — действие одно,
   кнопка внизу (.bs-btn --primary --sm): на тач-экране это ясная цель, а не «вся плитка где-то ведёт».
   Подпись кнопки может быть длиннее ширины плитки («Присоединиться к сообществу») — переносится в 2 строки. */
.bs-jointile{ display:flex; flex-direction:column; align-items:center; gap:var(--sp-1); height:100%; box-sizing:border-box;
  padding:var(--sp-4) var(--sp-3); text-align:center; border-radius:var(--rad-xl);
  background:var(--accent-soft); border:var(--bw-strong) dashed var(--line-neon); }
.bs-jointile__av{ display:grid; place-items:center; width:var(--tile-av); height:var(--tile-av); flex:none; margin-bottom:var(--sp-1); border-radius:50%;
  background:var(--grad-btn); color:var(--on-accent); }
.bs-jointile__av .bs-ico{ width:var(--icon-lg); height:var(--icon-lg); }
.bs-jointile__t{ margin:0; font:700 var(--fs-sm)/1.3 var(--font); color:var(--ink); text-wrap:balance; }
.bs-jointile__d{ margin:0 0 var(--sp-2); font:400 var(--fs-xs)/1.4 var(--font); color:var(--ink2); text-wrap:pretty; }
.bs-jointile__btn{ margin-top:auto; max-width:100%; white-space:normal; line-height:1.2; text-align:center; padding-block:var(--sp-1-5); }

/* ── Карточка записи сообщества · .bs-posttile — обложка 16:10, заголовок в 2 строки, автор · дата ──
   Переделка блока «Сообщество» 27.10 (владелец: «каша»): одна форма карточки на все записи вместо
   «главная + список» — ряд читается сразу, без разбора, где что. */
.bs-posttile{ display:flex; flex-direction:column; height:100%; box-sizing:border-box; overflow:hidden;
  background:var(--card); border:var(--bw) solid var(--line); border-radius:var(--rad-xl); text-decoration:none; color:var(--ink);
  transition:border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease), transform var(--dur) var(--ease-bounce); }
.bs-posttile__img{ display:block; width:100%; aspect-ratio:16 / 10; object-fit:cover; background:var(--bg2);
  transition:transform var(--dur-slow) var(--ease); }
.bs-posttile__img--ph{ display:grid; place-items:center; color:var(--text-muted); }
.bs-posttile__img--ph .bs-ico{ width:var(--icon-lg); height:var(--icon-lg); }
.bs-posttile__b{ display:flex; flex-direction:column; gap:var(--sp-2); flex:1; padding:var(--sp-3) var(--sp-4) var(--sp-4); }
.bs-posttile__t{ margin:0; font:600 var(--fs-sm)/1.35 var(--font); min-height:2.7em;
  display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden; }
.bs-posttile__m{ margin-top:auto; font:400 var(--fs-xs)/1.3 var(--font); color:var(--text-muted);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.bs-posttile:hover{ border-color:var(--line-neon); box-shadow:var(--shadow-1); transform:translateY(calc(-1 * var(--sp-1))); }
.bs-posttile:hover .bs-posttile__img{ transform:scale(1.03); }
.bs-posttile:hover .bs-posttile__t{ color:var(--accent-strong); }
.bs-posttile:focus-visible{ outline:none; box-shadow:var(--focus-ring); }

/* ── Карточка заказа покупателя · .bs-purchase (ревью покупателя C05/C19, 04.11) — одна на все состояния
   (ждёт оплаты · оплачен · в работе · завершён): шапка (название, мета), справа статус и «⋯», ниже — слоты
   (стадия, файл, отзыв, возврат) и строка действий. Ставится на .bs-card: <div class="bs-card bs-purchase">.
   Номер заказа — обычным текстом «Заказ № …», не моноширинным кодом. */
.bs-purchase{ display:flex; flex-direction:column; gap:var(--sp-3); }
.bs-purchase__head{ display:flex; justify-content:space-between; align-items:flex-start; gap:var(--sp-3); }
.bs-purchase__main{ min-width:0; display:flex; flex-direction:column; gap:var(--sp-1); }
.bs-purchase__title{ margin:0; font:600 var(--fs-base)/var(--lh-tight) var(--font); color:var(--ink); overflow-wrap:anywhere; text-decoration:none; }
a.bs-purchase__title:hover{ color:var(--accent); }
.bs-purchase__meta{ display:flex; flex-wrap:wrap; align-items:center; gap:var(--sp-1) var(--sp-3); font:400 var(--fs-sm)/1.35 var(--font); color:var(--text-muted); }
.bs-purchase__meta b{ color:var(--ink); font-weight:600; }
.bs-purchase__meta a{ color:inherit; text-decoration:underline; text-underline-offset:2px; }
.bs-purchase__meta a:hover{ color:var(--accent); }
.bs-purchase__aside{ display:flex; align-items:center; gap:var(--sp-1); flex:none; }
.bs-purchase__actions{ display:flex; flex-wrap:wrap; align-items:center; gap:var(--sp-2); }
.bs-purchase__actions:empty{ display:none; }

/* ── Карточка заказа биржи · .bs-ordertile — бюджет, задача в 2 строки, город и дата ── */
.bs-ordertile{ display:flex; flex-direction:column; gap:var(--sp-2); height:100%; box-sizing:border-box; padding:var(--sp-4);
  background:var(--card); border:var(--bw) solid var(--line); border-radius:var(--rad-xl); text-decoration:none; color:var(--ink);
  transition:border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease); }
.bs-ordertile:hover{ border-color:var(--line-neon); box-shadow:var(--shadow-1); }
.bs-ordertile:focus-visible{ outline:none; box-shadow:var(--focus-ring); }
.bs-ordertile__t{ margin:0; font:600 var(--fs-sm)/1.35 var(--font); display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden; min-height:2.7em; }
.bs-ordertile__b{ font:700 var(--fs-base)/1 var(--font); font-variant-numeric:tabular-nums; }
.bs-ordertile__m{ display:flex; flex-wrap:wrap; gap:var(--sp-1) var(--sp-3); margin-top:auto; font:400 var(--fs-xs)/1.3 var(--font); color:var(--text-muted); }
.bs-ordertile__m span{ display:inline-flex; align-items:center; gap:var(--sp-1); }
.bs-ordertile__m .bs-ico{ width:var(--icon-xs); height:var(--icon-xs); }
@media (max-width:767px){
  .bs-cattile{ padding:var(--sp-2) var(--sp-1) var(--sp-2); border-radius:var(--rad-lg); }
  .bs-cattile__img,.bs-cattile__ph{ width:var(--ctl-lg); height:var(--ctl-lg); }
  .bs-cattile__l{ font-size:var(--fs-xs); }
}
@media (prefers-reduced-motion:reduce){
  .bs-cattile,.bs-cattile__img,.bs-mtile,.bs-tooltile,.bs-posttile,.bs-posttile__img,.bs-morelink .bs-ico{ transition:none; }
  .bs-cattile:hover,.bs-mtile:hover,.bs-tooltile:hover,.bs-posttile:hover{ transform:none; }
  .bs-cattile:hover .bs-cattile__img,.bs-posttile:hover .bs-posttile__img{ transform:none; }
}


/* ── Движение · одна пружина (ДС дороже 30.10, выбран «Б · пружина») ─────────────────────────────────────
   Нажатие — сжатие до --press-scale и отдача пружиной; появление окон и тостов — снизу на --appear-y, чуть из глубины.
   Токены — tokens.css 1.10. «Уменьшить движение» в системе — всё это выключено. */
:is(.bs-seg button, .bs-seg label, .bs-filter > *, .bs-tabs__item, .bs-mbtn, .bs-chip){
  transition:background-color var(--dur) var(--ease), border-color var(--dur) var(--ease), color var(--dur) var(--ease),
    box-shadow var(--dur) var(--ease), transform var(--dur-spring) var(--ease-spring); }
:is(.bs-seg button, .bs-seg label, .bs-filter > *, .bs-tabs__item, .bs-mbtn, .bs-chip):active{ transform:scale(var(--press-scale)); transition-duration:var(--dur-fast); }
.bs-switch input::before{ transition:transform var(--dur-spring) var(--ease-spring); }
@keyframes bs-appear{ from{ opacity:0; transform:translateY(var(--appear-y)) scale(var(--appear-scale)); } to{ opacity:1; transform:none; } }
@keyframes bs-fade-in{ from{ opacity:0; } to{ opacity:1; } }
:is(.bs-dialog-back > .bs-dialog, dialog.bs-dialog[open]):not(.bs-dialog--side){ animation:bs-appear var(--dur-spring) var(--ease-spring) backwards; }
.bs-dialog-back{ animation:bs-fade-in var(--dur) var(--ease) backwards; }
.bs-toasts > .bs-toast{ transform:translateY(var(--appear-y)) scale(var(--appear-scale));
  transition:opacity var(--dur) var(--ease), transform var(--dur-spring) var(--ease-spring); }
.bs-toasts > .bs-toast.is-in{ transform:none; }
@media (prefers-reduced-motion:reduce){
  :is(.bs-dialog-back > .bs-dialog, dialog.bs-dialog[open], .bs-dialog-back){ animation:none; }
  .bs-btn:hover:not(:disabled), .bs-btn:active:not(:disabled), :is(.bs-seg button, .bs-seg label, .bs-filter > *, .bs-tabs__item, .bs-mbtn, .bs-chip):active{ transform:none; }
  .bs-toasts > .bs-toast{ transform:none; } }

/* Список-кнопка (.bs-select--btn: «Сначала новые») ведёт себя как кнопка ДС — растёт при наведении и сжимается
   при нажатии на той же пружине; поле-список (.bs-select) — плавная смена рамки, как у .bs-input (30.10). */
select.bs-select--btn, .ts-wrapper.bs-select.bs-select--btn .ts-control{
  transition:border-color var(--dur) var(--ease), background-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease), transform var(--dur-spring) var(--ease-spring); }
select.bs-select--btn:hover, .ts-wrapper.bs-select.bs-select--btn:not(.dropdown-active) .ts-control:hover{ transform:var(--btn-hover-grow); }
select.bs-select--btn:active, .ts-wrapper.bs-select.bs-select--btn .ts-control:active{ transform:scale(var(--press-scale)); transition-duration:var(--dur-fast); }
.ts-wrapper.bs-select .ts-control{ transition:border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease), transform var(--dur-spring) var(--ease-spring); }
@media (prefers-reduced-motion:reduce){ select.bs-select--btn, .ts-wrapper.bs-select .ts-control{ transform:none !important; } }

/* ── Детали «дороже» (30.10, пункты 5–9 ревизии элементов) ──────────────────────────────────────────────
   5 · волосяные линии поверхностей и разделителей (на ретине полпикселя); контролы — прежняя 1px рамка. */
.bs-card, .bs-panel, .bs-menu, .bs-dialog, .bs-acard, .bs-pcard{ border-width:var(--bw-hair); }
.bs-menu__sep{ height:var(--bw-hair); }
.bs-dialog--form > .bs-dialog__foot{ border-top-width:var(--bw-hair); }
/* 6 · выделение текста — фирменным фиолетовым, а не системным синим (кольцо фокуса уже двойное: --focus-ring) */
::selection{ background:var(--selection-bg); color:inherit; }
/* 7 · метка поверх фото — одно «стекло»: сильнее размытие, тонкая светлая кромка, мягкая тень */
.bs-badge--media{ background:color-mix(in srgb, var(--card) 78%, transparent); -webkit-backdrop-filter:var(--glass-blur); backdrop-filter:var(--glass-blur);
  box-shadow:inset 0 0 0 var(--bw-hair) var(--glass-edge), var(--shadow-1); font-weight:var(--fw-semibold); }
/* 8 · цифры одинаковой ширины во всех счётчиках, метках, ценах и таблицах — не «прыгают» */
.bs-count, .bs-badge, .bs-stat__value, .bs-table td, .bs-num, .bs-rate{ font-variant-numeric:tabular-nums; }
/* 9 · полосы прокрутки — тонкие, в цвет интерфейса */
html{ scrollbar-color:var(--scrollbar-thumb) transparent; }
*{ scrollbar-width:thin; }
@supports not (scrollbar-color:red red){
  ::-webkit-scrollbar{ width:var(--scrollbar-size); height:var(--scrollbar-size); }
  ::-webkit-scrollbar-thumb{ background:var(--scrollbar-thumb); border-radius:var(--rad-pill); border:calc(var(--scrollbar-size) * .3) solid transparent; background-clip:content-box; }
  ::-webkit-scrollbar-track{ background:transparent; } }

/* Цена: знак валюты — .bs-cur (разметку даёт priceHTML()/price_html). 30.10 владелец вернул ₽ как был — без своего
   вида; «лёгкий ₽» при желании: .bs-cur{ font-size:.78em; font-weight:var(--fw-medium); opacity:.72; } */

/* ── Три факта для продавца · .bs-factcards (ревью этапа 5, A16, 05.11) ─────────────────────────
   Один блок «Размещение бесплатно / Комиссия 15% / Выплата на реквизиты» на учебнике (/prodavcam/)
   и тарифах (/pricing.html): карточки .bs-card.bs-card--sm, значок слева, ключ 700 и пояснение --ink2.
   Ряд из трёх равной высоты, на телефоне — столбиком. Не путать со строкой доверия .bs-facts (главная). */
.bs-factcards{ display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:var(--sp-2); margin:0; padding:0; list-style:none; }
.bs-card.bs-factcard{ display:flex; align-items:flex-start; gap:var(--sp-2); }
.bs-factcard > svg{ flex:none; width:var(--icon-md); height:var(--icon-md); color:var(--accent-text); margin-top:1px; }
.bs-factcard__b{ display:flex; flex-direction:column; gap:2px; min-width:0; }
.bs-factcard__k{ font-size:var(--fs-sm); font-weight:700; color:var(--ink); line-height:var(--lh-tight); }
.bs-factcard__v{ font-size:var(--fs-xs); color:var(--ink2); line-height:1.4; }
@media (max-width:640px){ .bs-factcards{ grid-template-columns:1fr; } }
