/* ============================================================
   POP / GEN-Z design language — print-split profiles
   Self-contained. Does NOT depend on landing.css / community.css.
   Prefix: pp-  (pop-profile)
   ============================================================ */

/* :root перенесён в tokens.css (Волна 1 дизайн-системы) — ЕДИНЫЙ источник токенов.
   tokens.css линкуется НЕПОСРЕДСТВЕННО ПЕРЕД pop.css в каждой Pop-странице, поэтому
   имена/значения (--card/--ink/--violet/--r/--pill/…) разрешаются идентично прежнему.
   НЕ возвращать :root сюда — единственный источник теперь tokens.css. */

*{ box-sizing:border-box; }

/* ══ БАЗОВЫЙ ИНВАРИАНТ: атрибут [hidden] ОБЯЗАН прятать. fail-closed, глобально ══
   UA-правило `[hidden]{display:none}` живёт в origin браузера, а ЛЮБОЙ авторский
   `display:flex/grid/inline-flex` на классе перебивает его по каскаду (origin автора
   > origin UA; специфичность тут ни при чём). Итог: `el.hidden = true` молча НЕ
   работает — узел остаётся ВИДИМЫМ. Это стоило денег: `.pp-row2` (обёртка поля
   «Цена», display:grid) не пряталась в режиме «Бесплатно», мастер вводил сумму,
   сейв слал price=0 → товар навсегда бесплатный. Линт `ds-audit.py --hidden` нашёл
   ЕЩЁ 11 таких мест на 8 страницах (кнопки, тайлы, чипы, дропзона загрузки), каждое
   подтверждено замером computed display в живом браузере.
   Лечим КЛАСС багов, а не по одному: ниже по файлу уже накопилось 20+ ручных заплаток
   `.foo[hidden]{display:none}` — значит правило «не забудь гард» не соблюдается людьми.
   `!important` тут обязателен и безопасен: он бьёт по origin/важности, поэтому не
   зависит от порядка линковки CSS, а во всём frontend/*.css (кроме редактора) НЕТ
   ни одного `display:<не-none> !important`, который мог бы с ним спорить — проверено
   грепом. Показ снимается снятием атрибута (`el.hidden = false` / removeAttribute),
   так это и делает весь код; ни одного места «оставить hidden, но показать через CSS/
   inline-style» в проекте нет — тоже проверено (скан reveal-паттернов + Playwright
   before/after на 13 живых страницах прода).
   Точечные `.foo[hidden]` ниже оставлены как есть: они уже верны, дублируют это
   правило и служат документацией на месте. Ровно так же закрыт редактор (styles.css).
   Гейт: `python3 backend/tools/ds-audit.py --hidden` (fail-closed).
   Осознанное исключение для отдельного класса — коммент `hidden-ok` на строке display. */
[hidden]{ display:none !important; }

/* ── Глобальный ремень против страничного H-скролла + PWA-руббербэнда (ux-pro overflow-fix) ──
   overflow-x:CLIP (не hidden): клипует горизонтальный выход контента, но НЕ создаёт скролл-
   контейнер → position:sticky (.pp-nav и пр.) продолжает работать (hidden его ломал).
   overscroll-behavior-x:none — в установленном PWA/standalone убирает резиновый «увод» экрана
   влево-вправо (жалоба владельца «ездит вправо-влево, уезжает в PWA»). Ремень — ДОПОЛНЕНИЕ к
   корневым фиксам виновников (модалки/100vw/min-width), не замена: без них контент бы молча резался. */
html,body{ margin:0; padding:0; overflow-x:clip; overscroll-behavior-x:none; }
body{
  /* КАНОН витрины (lp-body): тёплый холст + мягкие candy-подсветки коралл/фиолет */
  background:
    radial-gradient(1100px 520px at 12% -8%, rgba(124,92,255,.10), transparent 60%),
    radial-gradient(900px 480px at 96% 4%, rgba(255,94,126,.10), transparent 55%),
    var(--bg);
  background-attachment:fixed;
  color:var(--ink);
  font-family:var(--font);
  font-size:15px;
  line-height:1.45;
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
  overflow-x:clip;   /* было hidden — ломало position:sticky (.pp-nav); clip клипует без скролл-контейнера */
}
img{ max-width:100%; display:block; }
button{ font-family:inherit; }
a{ color:inherit; }

/* ---------- carrying column ---------- */
.pp-col{ max-width:var(--page-max); margin:0 auto; padding:0 16px;
  /* Тон-лестница профиля — ЛОКАЛЬНО на .pp-col (НЕ :root; tokens.css неприкосновенен, §6 спеки).
     T1=--pp-ink (имя/актив-таб), T3=--pp-t3 (счётчики/разделители), A1=--pp-star (звезда). */
  --pp-ink:#1F1D24; --pp-t3:#73737C; --pp-star:#F5A623; }
/* Читающая колонка (одиночный пост /@h/post/id + лента группы /g/slug): узкая,
   как в соц-лентах (IG/VK ≈600–680px), чтобы текст и медиа не разъезжались во всю
   ширину профиля (1040px). Модификатор поверх .pp-col — профиль/магазин не трогаем. */
.pp-col-read{ max-width:680px; }

/* decorative blobs */
.pp-blob{
  position:absolute; border-radius:50%;
  filter:blur(40px); pointer-events:none; z-index:0;
}

/* ---------- card ---------- */
.pp-card{
  position:relative;
  background:var(--card);
  border-radius:var(--r);
  box-shadow:var(--shadow);
  padding:15px;
  margin-bottom:12px;
}
.pp-card-title{
  font:800 15px var(--font-display);
  letter-spacing:-.01em;
  margin:0 0 10px;
}
.pp-card-sub{ color:var(--ink2); font:500 12px var(--font); margin:-8px 0 12px; }

/* ── ПОЛОСА-УВЕДОМЛЕНИЕ СТРАНИЦЫ (profile.js: pageNoticeHTML) ──────────────────────────────
   Для честных состояний, где раньше было либо враньё, либо тишина: «показано то, что отдал
   сервер — обновить не удалось» и «не смогли проверить, ваша ли это страница». Осознанно НЕ
   тост (важное не должно уезжать через 5с) и НЕ баннер на пол-экрана (D0): одна строка, тело
   36px, amber-тон статуса + текст, который сам себя объясняет (цвет не единственный сигнал).
   Ширина считается ОТ канона `--page-max` (минус паддинг колонки) → строка стоит ровно по
   рёбрам карточек, а не шире их на 32px. */
.pp-pagenote{
  width:calc(100% - 32px); max-width:calc(var(--page-max) - 32px); margin:8px auto 0;
  display:flex; align-items:center; gap:10px; flex-wrap:wrap;
  min-height:36px; padding:6px 14px;
  border:1px solid var(--amber-200); border-radius:var(--pill);
  background:var(--amber-50); color:var(--amber-800); font:600 13px var(--font);
}
.pp-pagenote-txt{ flex:1 1 220px; min-width:0; }
/* tertiary-тир: 32px тело (D0), тап-зона добирается до 44 псевдо-элементом — раздувать
   видимую кнопку ради тач-таргета нельзя. */
.pp-pagenote-btn{
  position:relative; flex:none; min-height:32px; padding:0 12px; cursor:pointer;
  border:1px solid var(--amber-300); border-radius:var(--pill);
  background:transparent; color:var(--amber-800); font:700 13px var(--font);
}
.pp-pagenote-btn::before{ content:""; position:absolute; inset:-6px; }
.pp-pagenote-btn:hover{ background:var(--amber-100); }
.pp-pagenote-btn:focus-visible{ outline:2px solid var(--violet); outline-offset:2px; }

/* spring hover */
.pp-spring{ transition:transform .18s cubic-bezier(.34,1.56,.64,1), box-shadow .18s; }
.pp-spring:hover{ transform:translateY(-2px); box-shadow:var(--shadow-lg); }

/* =====================================================
   STICKY NAV
   ===================================================== */
.pp-nav{
  position:sticky; top:0; z-index:50; height:56px;
  display:flex; align-items:center; justify-content:space-between;
  background:rgba(255,253,247,.8); backdrop-filter:blur(12px);
  -webkit-backdrop-filter:blur(12px);
  border-bottom:1px solid var(--line); padding:0 16px;
}
/* PWA standalone: sticky-шапка не должна уезжать под чёлку/Dynamic Island и под скруглённые углы
   в ландшафте. env()=0 в обычном браузере → на вебе НИЧЕГО не меняется, только в установленном PWA. */
@media (display-mode: standalone){
  .pp-nav{ height:calc(56px + env(safe-area-inset-top,0px)); padding-top:env(safe-area-inset-top,0px);
    padding-left:max(16px,env(safe-area-inset-left)); padding-right:max(16px,env(safe-area-inset-right)); }
}

/* ── РЕЗЕРВ ВЫСОТЫ ШАПКИ (CLS) — host пуст в первом кадре, .pp-nav приезжает JS-ом ────────
   Шапка Pop-страниц монтируется скриптом в <header data-cm-nav> (community.js::mountNav,
   crm.js, инлайн-модуль home.html). До монтирования host = 0px, после = 56px → ВСЯ страница
   уезжает вниз на 56px. Замер на проде 06.09 (Chromium, buffered layout-shift, desktop 1360):
   home 0.287 · marketplace 0.190 · market 0.111 · favorites 0.037 · people 0.029 ·
   community 0.028 — и на КАЖДОЙ первым и крупнейшим сдвигом стоит один и тот же
   `MAIN … y[0,h] → y[56,h]`. Порог Core Web Vitals «хорошо» — 0.1, а CLS у Яндекса и Google
   входит в оценку страницы. Лечение — забронировать РОВНО высоту .pp-nav на самом host'е:
     • min-height, а НЕ height: смонтированная шапка выше резерва (PWA + safe-area-inset-top,
       перенос строки) резерв не клипует, а перерастает. Двойного отступа не будет — host
       блочный и пустой, его высота = высоте единственного ребёнка .pp-nav, то есть тех же 56px;
     • селектор по data-атрибуту host'а: где шапки нет вовсе или она СТАТИЧНА в разметке
       (blog/*, pay, pricing, SSR-шаблоны с готовым <nav class="pp-nav">) правило не матчится
       и не резервирует ничего — резерв не может создать пустоту там, где её не было;
     • home.html заменяет host целиком (outerHTML): резерв держит место до замены, а .pp-nav
       ровно той же высоты встаёт на освободившееся место — сдвига опять нет.
   ⚠️ Мобайл ≤560: полосы нет — html[data-tabbar="on"] снимает у .pp-nav собственную геометрию
   (см. блок ниже), и у гостя ряд честные 0px. Бронировать нечего, резерв ОБНУЛЯЕМ — иначе мы
   сами создадим 56px пустоты вместо той, которую убираем. */
[data-cm-nav]{ min-height:56px; }
@media(max-width:560px){ [data-cm-nav]{ min-height:0; } }

.pp-brand{ display:flex; align-items:center; gap:9px; text-decoration:none; }
/* КАНОН бренда = логотип витрины (lp-brand): градиент-чип коралл→фиолет + белый кролик */
.pp-logo{ width:34px; height:34px; border-radius:11px; flex:none; background:var(--grad-hero);
  display:grid; place-items:center; box-shadow:0 6px 16px -6px rgba(124,92,255,.6); }
.pp-logo svg{ width:23px; height:23px; display:block; }
.pp-logo-dot{ width:12px; height:12px; border-radius:var(--pill); background:var(--grad-hero); flex:none; } /* legacy */
.pp-wordmark{ font:800 20px var(--font-display); letter-spacing:-.03em; color:var(--ink); }
.pp-dot{ color:var(--coral); }
/* Суффикс-система направлений после точки (канон брендбука §01 «01 · Логотип»):
   мелкий супер-индекс тем же Unbounded 800 — сегодня «3D», задел под .laser/.cnc/.resin.
   Единый примитив — меняется в ОДНОМ месте, а не хардкодом по страницам. */
.pp-suf{ font-weight:800; font-size:.45em; letter-spacing:0; color:var(--coral); vertical-align:super; margin-left:.06em; }
.on-grad .pp-suf{ color:#fff; } /* на градиентном фоне суффикс белый — как коралловая точка */
.pp-nav-links{ display:flex; align-items:center; gap:18px; }
.pp-nav-links a{ font:600 14px var(--font); color:var(--ink2); text-decoration:none; }
.pp-nav-links a:hover{ color:var(--ink); }
.pp-nav-cta{ display:flex; align-items:center; gap:8px; position:relative; }
/* «Войти» — чистая ссылка БЕЗ обводки (канон витрины lp-nav-links), а не плашка */
.pp-nav-login{
  font:600 14px var(--font); color:var(--ink2); text-decoration:none;
  border:none; border-radius:var(--pill); padding:8px 12px; transition:background .15s,color .15s;
}
.pp-nav-login:hover{ color:var(--ink); background:rgba(124,92,255,.08); }
/* «Регистрация» — градиент-пилюля с неоновой подсветкой (канон lp-nav-cta) */
.pp-nav-join{
  font:700 14px var(--font); color:#fff; text-decoration:none;
  background:var(--grad-hero); border-radius:var(--pill); padding:10px 18px;
  box-shadow:0 8px 20px -8px rgba(124,92,255,.7);
  transition:transform .18s cubic-bezier(.34,1.56,.64,1), box-shadow .18s;
}
.pp-nav-join:hover{ transform:translateY(-2px); box-shadow:0 12px 26px -8px rgba(124,92,255,.85); }
.pp-nav-join.is-icon{ display:none; }
/* 🔴 БЛЮР ШАПКИ СНИМАЕТСЯ НА МОБИЛЕ — и это не про красоту, а про позиционирование.
   `backdrop-filter` делает элемент containing block для ЛЮБОГО position:fixed потомка.
   Шторка .pp-nav-menu лежит внутри .pp-nav, поэтому её fixed-раскладка нижним листом
   считалась не от вьюпорта, а от 56-пиксельной шапки — лист уезжал ВЫШЕ экрана
   (замер: top −446, bottom 0, то есть целиком за кадром). Ровно та же грабля, из-за
   которой сама панель разделов цепляется к <body>, а не к разметке шапки.
   Заодно совпадает с решением по нижней панели: мобильный хром — сплошная заливка,
   а не стекло (полупрозрачная полоса сливается с тулбаром браузера, а блюр во всю
   ширину пересчитывается на каждом кадре скролла). На десктопе стекло остаётся. */
@media(max-width:560px){
  .pp-nav{ backdrop-filter:none; -webkit-backdrop-filter:none; background:var(--bg,#FFFDF7); }
  .cm-app-nav{ backdrop-filter:none; -webkit-backdrop-filter:none; }
  .pp-nav-links{ display:none; }
  .pp-nav-login{ display:none; }
  .pp-nav-join.is-text{ display:none; }
  .pp-nav-join.is-icon{ display:grid; place-items:center; width:40px; height:40px; padding:0; font-size:20px; }
}

/* ═══ ПОЛОСА С ЛОГОТИПОМ УХОДИТ С МОБИЛЫ (референс владельца — приложение WB, 2026-08-28) ═══
   ЗАМЕР ДО (layout 375, .pp-nav): 56px на КАЖДОЙ странице. У ГОСТЯ внутри ровно один
   элемент — a.pp-brand. Ссылки и «Войти» скрыты выше по файлу, бургер уехал в нижнюю
   панель — шапке стало нечего держать, осталась полоса ради логотипа. На маркетплейсе
   вдобавок ДВА одинаковых вордмарка в одном кадре: в шапке и внутри баннера, в 121px
   друг от друга. В приложении WB строки с логотипом нет ни на одном экране: бренд несут
   иконка приложения и акцентный цвет, а экран начинается сразу с функционального.
   У нас бренд несут баннер маркетплейса и градиентная пилюля активного слота панели,
   а дверь «домой» — слот «Маркет». Логотип в полосе не нёс ничего, чего нет рядом.

   🔴 УБИРАЕМ БРЕНД, А НЕ РЯД. Слепое `display:none` на .pp-nav было бы регрессией на
   двух уровнях:
     1) внутри .pp-nav лежит ШТОРКА [data-nav-menu] — тот самый лист, который открывает
        слот «Ещё». Скрыли бы контейнер — убили бы всю вторичную навигацию;
     2) у ЗАЛОГИНЕННОГО ряд не пустой: там .pp-bell (единственная дверь к уведомлениям
        на мобиле — другой нет) и .pp-nav-carttop (постоянная корзина, поставлена по
        отдельной претензии владельца «куда делась корзина»). Замер: guest → 1 элемент,
        buyer/master/admin → 3.
   Поэтому прячем ТОЛЬКО .pp-brand и снимаем с ряда собственную геометрию (height/padding/
   фон/линию). Высота ряда после этого = высоте самого высокого ВИДИМОГО ребёнка:
     • гость   → видимых детей нет → ряд 0px → страница отыгрывает все 56px;
     • вошедший → колокольчик+корзина 44px → ряд 44px (−12px и минус дубль вордмарка).
   Это самоочищающееся правило: появится/исчезнет контрол — высота сойдётся сама, без
   новой ветки в CSS. Условие на html[data-tabbar="on"] — тот же предохранитель, что у
   бургера: не доехал модуль панели → признака нет → шапка остаётся прежней и мобильная
   навигация жива по-старому. */
@media(max-width:560px){
  html[data-tabbar="on"] .pp-brand{ display:none; }
  html[data-tabbar="on"] .pp-nav{
    /* 🔴 position:static, а НЕ sticky. Полосы больше нет, липнуть нечему, а липкий
       прозрачный ряд с двумя кругами справа занимал бы верхнюю кромку и накрывал
       собственные sticky-бары страниц (control-bar ленты .fc-bar липнет на top:0).
       В приложении WB верхний ряд тоже уезжает со скроллом, а не висит. */
    position:static;
    height:auto; min-height:0; padding:0 12px;
    background:none; border-bottom:0;
    justify-content:flex-end;
  }
  /* Ряд стал прозрачным и остался sticky — значит контролы поедут поверх контента.
     Читаемость даёт не полоса-подложка (её больше нет), а собственная заливка каждой
     кнопки: белый круг + волосяная линия + мягкая тень. Ровно так живут плавающие
     контролы в мобильных приложениях. Пустой ряд гостя при этом не рисует НИЧЕГО —
     фон висит на детях, а не на контейнере. */
  html[data-tabbar="on"] .pp-nav-cta > .pp-bell,
  html[data-tabbar="on"] .pp-nav-cta > .pp-nav-carttop{
    /* Один размер на оба: колокольчик приходит 40×40, корзина 44×44 (своя мобильная
       ступень в cart-hub.js) — в общем ряду с align-items:center это давало сдвиг по
       вертикали на 2px и два разных круга рядом. Обе кнопки 44: и выровнены, и каждая
       сама по себе тач-таргет (§14.D), без добора зоной. */
    width:44px; height:44px; flex:0 0 auto;
    background:var(--card,#fff);
    border:1px solid var(--line2,rgba(20,20,20,.14));
    border-radius:var(--pill,999px);
    box-shadow:0 6px 18px -10px rgba(20,20,20,.45);
  }
  /* Верхний отступ страницы считался «под шапку»: community.css даёт .cm-wrap
     padding-top:3rem = 48px, и после сноса полосы эти 48px остались висеть пустотой
     первым, что видит человек. Референс WB: зазор между блоками 12–18px. Берём 16
     (--sp-4, наша шкала). Правило живёт здесь, а не в community.css: pop.css грузится
     ПОСЛЕ него на всех страницах, и условие html[data-tabbar="on"] держит правку строго
     в том состоянии, где полоса действительно снята. */
  /* 🔴 БЕЗ УСЛОВИЯ НА data-tabbar — И ЭТО ГЛАВНОЕ В ПРАВИЛЕ. Признак ставит JS ПОСЛЕ
     ответа /api/auth/me, то есть уже после первого кадра: страница успевала отрисоваться
     с 48px и потом подпрыгивала на −32px. Замер на проде 06.09 (393×852, buffered
     layout-shift): community 0.0397, market 0.2317, favorites 0.0129 — и в каждом верхний
     сдвиг это ровно `y[46,…] → y[14,…]`. Порог CWV «хорошо» 0.1.
     Отступ — свойство МОБИЛЬНОЙ раскладки (ширина ≤560), а не факта загрузки модуля панели:
     ширину браузер знает в первом кадре, признак — нет. Предохранитель data-tabbar остаётся
     там, где он реально нужен (скрытие бренда и геометрия ряда): не доехал модуль — шапка
     остаётся полосой, а верхний отступ 16px просто плотнее, чем был (канон D0). */
  .cm-wrap{ padding-top:var(--sp-4,16px); }
}

/* =====================================================
   НИЖНЯЯ ПАНЕЛЬ РАЗДЕЛОВ (мобайл ≤560px) — .bs-tabbar
   Разметку и данные даёт src/ui/tabbar.js (слоты — nav_items.navTabs).
   Здесь только вид. Точка изгиба 560px — ТА ЖЕ, что у .pp-nav-links выше:
   между «ссылки в шапке видны» и «панель внизу» не должно быть щели.

   ── D0 ПЛОТНОСТЬ (замер, канон frontend/brand/DENSITY.md) ──────────────
   строка 48px (5.7% высоты вьюпорта 844). Было 54 — ужато по референсу владельца
   (приложение WB, 2026-08-28): у WB нижняя панель ~44px.
   🔴 44 у них возможны ПОТОМУ ЧТО ТАМ НЕТ ПОДПИСЕЙ — пять иконок, узнаваемых годами.
   Наши «Биржа» и «Лента» из глифа не угадываются, подписи снимать нельзя (иконка без
   подписи в навигации теряет узнаваемость, §12), поэтому наш потолок — 48, не 44.
   Внутри: пилюля-индикатор 40×22 · глиф 20 · подпись 11/12 · зазор 2 → 36 + 6/6 = 48.
   Слот на 390px = 76×48, на 320px = 62×48 — оба измерения ≥44, тач-таргет цел (§1.3).

   ── ЗАЛИВКА СПЛОШНАЯ, НЕ СТЕКЛО ───────────────────────────────────────
   У шапки .pp-nav — rgba + backdrop-filter. Здесь НАМЕРЕННО плотный --card:
   (1) полупрозрачные нижние панели в мобильных браузерах садятся вплотную к
   собственному тулбару Safari/Chrome и читаются как его продолжение;
   (2) backdrop-filter во всю ширину у нижней кромки перерисовывается на КАЖДОМ
   кадре скролла — самый дорогой из возможных мест для блюра.
   ===================================================== */
.bs-tabbar{
  position:fixed; left:0; right:0; bottom:0; z-index:115;
  display:none;                                   /* включается только на мобиле, ниже */
  align-items:stretch; padding:0 4px;
  padding-bottom:env(safe-area-inset-bottom,0px); /* реальную высоту потом ЗАМЕРИТ tabbar.js */
  /* ── ОТДЕЛКА ПАНЕЛИ (претензия владельца 2026-08-28: «выглядит дёшево, это не наш стиль,
     ты сэкономил»). Было: плоская заливка + ТЁПЛО-СЕРАЯ волосяная линия + СЕРАЯ тень —
     набор из бутстрапа, ничего бренд-специфичного. Стало — две статические грани, и обе
     в фирменном цвете (сама заливка остаётся сплошной, см. абзац выше):
       1) кромка violet вместо gray-200 — фасция панели принадлежит бренду;
       2) подъём тоже в бренде (violet-700), плюс внутренняя светлая обводка по верхней
          кромке: панель читается как материал с фаской, а не как наклейка.
     Ни градиента, ни блюра в самом `background` НЕ заводим — панель обязана остаться
     непрозрачной (полупрозрачная полоса сливается с тулбаром браузера и ловится
     lint_mobile_nav N7/N7t). Оба свойства ниже рисуются ОДИН раз при композиции слоя и
     при скролле не пересчитываются — цена отделки нулевая, в отличие от backdrop-filter.
     Главный бренд-сигнал панели — активная пилюля на --grad-hero, см. .bs-tab.is-on. */
  background:var(--card,#fff);          /* СПЛОШНАЯ, не полупрозрачная (причина — блок выше) */
  border-top:1px solid rgba(124,92,255,.16);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.72), 0 -10px 30px -18px rgba(90,56,214,.5);
  /* уникальные рампы tokens.css вместо --ink/--line: на community/cabinet/crm/admin
     поверх грузится тёмная landing.css со своими одноимёнными переменными */
  font-family:var(--font,'Inter',system-ui,sans-serif);
}
.bs-tabbar[hidden]{ display:none; }               /* hidden-guard (ds-audit) */
.bs-tab{
  flex:1 1 0; min-width:0; height:48px;
  display:flex; flex-direction:column; align-items:center; justify-content:center; gap:2px;
  border:0; background:none; padding:0; margin:0; cursor:pointer;
  text-decoration:none; color:var(--gray-700,#5B5B66);
  -webkit-tap-highlight-color:transparent; touch-action:manipulation;
}
/* Пилюля-индикатор под глифом (модель активного индикатора Material 3): активность
   несёт НЕ только цвет, но и форма — требование «цвет не единственный сигнал» (§6). */
.bs-tab-ind{
  display:grid; place-items:center; width:40px; height:22px; border-radius:var(--pill,999px);
  background:transparent; transition:background .16s ease, transform .12s ease;
}
/* Глиф НЕактивного слота тише подписи: смысл в панели несёт ПОДПИСЬ (иконка без подписи в
   навигации теряет узнаваемость, §12), поэтому иконка — второй голос, а не равный. .72 от
   gray-700 ≈ #86868E на светлом = 3.6:1, выше порога 3:1 для графики; подпись остаётся
   6.6:1. Без этого пять одинаково тёмных глифов читались как пять активных слотов. */
.bs-tab-ico{ width:20px; height:20px; display:block; opacity:.72; transition:opacity .16s ease; }
.bs-tab.is-on .bs-tab-ico,
.bs-tab:active .bs-tab-ico{ opacity:1; }
/* 11px — на ступень ниже подписи-хинта (12px) канона DENSITY.md, и это ЕДИНСТВЕННОЕ
   место сервиса, где так: у слота 61-76px внутренней ширины, 12px туда не вмещается.
   Ориентир платформ тот же: подпись таба в iOS — 10pt, в Material — 12sp.
   ОДНО значение на все ширины (прежняя ступень 9.5px для ≤360 убрана): длину лечим
   КОРОТКИМ ИМЕНЕМ в nav_items.TAB_SHORT, а не уменьшением кегля. Кегль правит все пять
   подписей ради одной длинной и всё равно не спасает — при классическом скроллбаре
   (layout 305px) обрезалось и на 9.5px. Замер после сокращения — в TAB_SHORT. */
.bs-tab-lbl{
  max-width:100%; font:600 11px/12px var(--font,'Inter',system-ui,sans-serif);
  letter-spacing:-.01em; white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}
/* АКТИВНЫЙ слот. violet-700 на белом = 7.06:1 (замер) — проходит AA даже для 10px;
   бренд-violet 500 дал бы 4.33:1 и провалил бы порог, поэтому взята та же ступень,
   что у чипа «скоро» в шторке. Плюс вес 800 и заливка пилюли — три сигнала, не один.
   🔴 АКТИВНАЯ ПИЛЮЛЯ = --grad-hero, тот же, каким сервис метит активную опцию ВЕЗДЕ
   (.pp-seg-btn.is-active, .ad-period-chip.is-on, .bs-cc-primary). Плоская заливка
   --violet-50 была ДРЕЙФОМ от собственной системы — ровно та «экономия», которую увидел
   владелец. Градиент статический: ни анимации, ни блюра, ни перерисовки при скролле.
   Контраст: белый глиф на #FF5E7E = 3.16:1 и на #7C5CFF = 4.03:1 — оба выше порога 3:1
   для графики (WCAG 1.4.11). Подпись остаётся violet-700 на светлом = 7.06:1. */
.bs-tab.is-on{ color:var(--violet-700,#5A38D6); }
.bs-tab.is-on .bs-tab-ind{
  background:var(--grad-hero,linear-gradient(135deg,#FF5E7E 0%,#7C5CFF 100%));
  box-shadow:0 6px 14px -6px rgba(124,92,255,.75), inset 0 0 0 1px rgba(255,255,255,.22);
}
.bs-tab.is-on .bs-tab-ico{ color:#fff; }
.bs-tab.is-on .bs-tab-lbl{ font-weight:800; }
.bs-tab:focus-visible{ outline:2px solid var(--violet-700,#5A38D6); outline-offset:-3px; }

/* ── ДВИЖЕНИЕ: что взято из библиотеки frontend/src/ui/effects/ и что НЕ взято ──
   ВЗЯТО (одноразовые реакции на касание — у постоянно висящей панели не может быть
   ни одного бесконечного цикла, это прямой расход батареи):
     • волна от пальца — приём `ripple-button` (effects/buttons.js:47);
     • подъём активного слота — идея `dock` (effects/blocks.js:318), переведённая с
       hover на состояние: в доке рост ведёт курсор, на телефоне курсора нет;
     • лесенка строк шторки — приём `animated-list` (effects/blocks.js:288), ниже.
   НЕ ВЗЯТО, осознанно:
     • `progressive-blur` / стеклянная панель — backdrop-filter во всю ширину у нижней
       кромки пересчитывается на КАЖДОМ кадре скролла, а полупрозрачная полоса внизу
       сливается с собственным тулбаром браузера (мобильные панели надёжно держат
       только сплошную заливку). Отсюда плотный --card выше;
     • `blur-fade` + прятание панели при скролле — панель затем и появилась, чтобы
       разделы были достижимы ВСЕГДА; вдобавок она мигала бы вразнобой с автоскрытием
       тулбара Safari;
     • `pulsating/shimmer/rainbow` центральный слот — это был бы ВТОРОЙ primary рядом
       с градиентным флагманом «Стать мастером» в шторке (§14.A) плюс вечная анимация;
     • `number-ticker`/`glowing-badge` — на панели НЕТ счётчиков намеренно: у каждого
       уже есть ровно один дом (корзина → .pp-cart-pill, чаты → трей, уведомления →
       колокольчик). Второй счётчик того же числа — вторая дверь, а не украшение.
   ────────────────────────────────────────────────────────────────────────────── */
.bs-tab{ position:relative; overflow:hidden; border-radius:14px; }
.bs-tab-rp{
  position:absolute; border-radius:50%; pointer-events:none;
  background:var(--violet-100,#E4DEFF);
  transform:translate(-50%,-50%) scale(0);
  animation:bs-tab-rp .52s cubic-bezier(.22,1,.36,1) forwards;
}
@keyframes bs-tab-rp{ to{ transform:translate(-50%,-50%) scale(1); opacity:0; } }
/* Подъём — на АКТИВНОМ и на НАЖАТОМ, а не на hover: на тач-экране hover не наступает
   никогда, а «залипает» после тапа (мёртвое состояние, §12). */
.bs-tab.is-on .bs-tab-ind{ transform:translateY(-1px); }
.bs-tab:active .bs-tab-ind{ transform:scale(.92); }   /* отклик ≤120мс, соседей не двигает */
@media(prefers-reduced-motion:reduce){
  .bs-tab-ind{ transition:none; }
  .bs-tab.is-on .bs-tab-ind,
  .bs-tab:active .bs-tab-ind{ transform:none; }
  .bs-tab-rp{ display:none; }
}
@media(max-width:560px){
  .bs-tabbar{ display:flex; }
  /* Контент не должен уезжать под панель (fixed-element-offset). Высота приходит
     ЗАМЕРЕННОЙ из tabbar.js; панели нет → var пуст → 0 → ни одна страница не сдвинулась. */
  body{ padding-bottom:var(--bs-tab-h,0px); }
}
/* На узком экране (SE/mini) «Маркетплейс» в 62px слот влезает только в 9px. Уменьшаем
   ПОДПИСЬ, а не тач-таргет: строка остаётся 54px, слот кликабелен целиком. */
/* ≤360px (SE 1-го поколения, обложка Fold): слот сжимается до ~63px, и «Маркетплейс» —
   самое длинное имя раздела — упирается. Отдаём ему ВСЮ ширину слота (боковые поля
   панели в ноль) и ужимаем кегль с трекингом. Тач-таргет не трогаем: строка остаётся
   54px, слот кликабелен целиком. Обрезать имя раздела многоточием нельзя — «Маркетпле…»
   в главной навигации читается как поломка. */
/* ≤360px (SE 1-го поколения, обложка Fold, а также 375px с классическим скроллбаром):
   слот сжимается до ~61px. Отдаём подписи ВСЮ ширину слота и ужимаем пилюлю — но НЕ кегль:
   типографика панели одна на всех ширинах. Тач-таргет не трогаем, строка остаётся 54px. */
@media(max-width:360px){
  .bs-tabbar{ padding:0; }
  .bs-tab-ind{ width:36px; }
}
/* ── ВЕРХНИЙ БУРГЕР УХОДИТ, КОГДА ПАНЕЛЬ РЕАЛЬНО НА ЭКРАНЕ ──────────────────
   Два тумблера одной шторки = две двери в одну комнату (§14.A), поэтому на мобиле
   остаётся ОДИН — «Ещё» в зоне большого пальца. Условие на html[data-tabbar=on]
   (признак ставит tabbar.js после успешного замера) — предохранитель: не доехал
   модуль → признака нет → бургер на месте и мобильная навигация жива по-старому. */
@media(max-width:560px){
  html[data-tabbar="on"] .pp-burger{ display:none; }
  /* Строки шторки, ведущие туда же, куда слоты панели (метку ставит navHTML по
     ФАКТИЧЕСКИМ адресам слотов): «Маркетплейс/Биржа/Лента», «Войти», «Личный кабинет»
     у покупателя, «Управление» у мастера. Показывать их над панелью, где те же двери
     уже стоят подписанными кнопками, — это множить выбор, не добавляя возможностей
     (§14.A, закон Хика). Условие на data-tabbar — предохранитель: панели нет → строки
     на месте, ни одна дверь не потерялась. */
  html[data-tabbar="on"] .pp-nav-menu .pp-nav-dup{ display:none; }
  /* Пока открыт нижний лист — поднимаем ВЕСЬ слой шапки (это он, а не сама шторка,
     решает порядок наложения: .pp-nav / .cm-app-nav = sticky + z-index:50 = контекст
     наложения, внутри которого любые 119 остаются «пятьюдесятью» снаружи). 119 — вровень
     с cookie-плашкой (она в это время уступает через is-under) и НИЖЕ модалок (120):
     диалог обязан перекрывать навигацию, а не наоборот. Класс снимается вместе с
     закрытием листа — как бы его ни закрыли (кнопка, клик мимо, Esc). */
  html[data-tabbar="on"] .pp-nav.bs-sheet-open,
  html[data-tabbar="on"] .cm-app-nav.bs-sheet-open{ z-index:119; }
}
/* hidden-guard: класс имеет авторский display, а .pp-nav-menu прячут атрибутом hidden */
.pp-nav-dup[hidden]{ display:none; }

/* =====================================================
   HERO + AVATAR + REEL
   ===================================================== */
.pp-cover{
  height:150px; background:var(--grad-hero);
  border-radius:0 0 var(--r-lg) var(--r-lg);
  position:relative; overflow:hidden; margin-top:8px;
}
.pp-cover img{ width:100%; height:100%; object-fit:cover; }
.pp-cover::after{
  content:""; position:absolute; inset:0;
  background:linear-gradient(to bottom,transparent 55%,rgba(0,0,0,.18));
}
/* photo cover: collage of printed parts dimmed so the avatar/name pop */
.pp-cover.has-photo::after{
  background:linear-gradient(135deg,rgba(124,92,255,.28),rgba(255,94,126,.18) 60%,transparent),
    linear-gradient(to bottom,transparent 40%,rgba(0,0,0,.32));
}
.pp-avatar-wrap{ width:100px; height:100px; margin:-46px auto 0; position:relative; z-index:2; }
.pp-avatar-wrap.is-customer{ width:104px; height:104px; margin-top:-52px; }
.pp-reel{
  position:absolute; inset:0; border-radius:var(--pill);
  background:conic-gradient(var(--coral), var(--violet) var(--reel,86%), var(--line2) 0);
  padding:6px;
}
.pp-avatar{
  width:100%; height:100%; border-radius:var(--pill);
  border:4px solid #fff; object-fit:cover; background:var(--bg2);
}
.pp-ava-init{
  width:100%; height:100%; border-radius:var(--pill); border:4px solid #fff;
  background:var(--grad-2); color:#fff; display:grid; place-items:center;
  font:800 40px var(--font-display);
}
.pp-points{
  position:absolute; left:50%; bottom:-8px; transform:translateX(-50%);
  background:#fff; box-shadow:var(--shadow); border-radius:var(--pill);
  font:800 12px var(--font-display); padding:3px 10px; white-space:nowrap; z-index:3;
}
.pp-online{
  position:absolute; right:8px; bottom:14px; width:14px; height:14px;
  border-radius:var(--pill); background:var(--ok); border:3px solid #fff; z-index:3;
}
.is-customer .pp-online{ right:6px; bottom:8px; }

/* identity */
.pp-name{ font:800 23px var(--font-display); letter-spacing:-.02em; text-align:center; margin:16px 0 2px; }
.pp-handle{ text-align:center; color:var(--ink2); font:600 14px var(--font); }
.pp-tag{ text-align:center; color:var(--ink2); font:400 14px var(--font); margin:6px 0 12px; }
.pp-chips{ display:flex; flex-wrap:wrap; gap:6px; justify-content:center; }
.pp-chip{
  border:1px solid var(--line2); border-radius:var(--pill); padding:4px 10px;
  font:600 12px var(--font); color:var(--ink2);
}
/* иконка в чипе мельче базовых 16px: текст чипа 12px — 14px держит пропорцию «иконка ≈ строчная высота».
   :where(:not([width])) — тот же контракт, что у базы-страховки (см. §GROWTH/БАЗА ниже): контекст
   правит ТОЛЬКО безразмерные иконки. У group.js/groups.js в .pp-chip лежат `.pp-ic width="12|13"` —
   их авторский размер остаётся за ними, CSS в него не лезет. */
.pp-chip .pp-ic:where(:not([width])){ width:14px; height:14px; }
.pp-stickers{ display:flex; flex-wrap:wrap; gap:8px 6px; justify-content:center; margin-top:12px; }
.pp-ctx{
  text-align:center; color:var(--ink2); font:600 12px var(--font);
  text-transform:uppercase; letter-spacing:.08em; margin-top:14px;
}

/* =====================================================
   STICKERS (фирменные наклейки)
   ===================================================== */
.sticker{
  display:inline-flex; align-items:center; gap:5px; font:800 12px var(--font-display);
  padding:5px 11px; border-radius:var(--pill);
  box-shadow:0 0 0 2px #fff inset, 0 4px 12px rgba(0,0,0,.15);
  transition:transform .18s cubic-bezier(.34,1.56,.64,1); white-space:nowrap;
  border:none; cursor:default;
}
.sticker:hover{ transform:rotate(0) scale(1.06) !important; }
/* Иконка в наклейке (была сырым эмодзи ✅/🌈): 13px под 12px-шрифт наклейки — глиф не должен
   быть выше своей строки. Базовый дефолт svg.pp-ic = 16px, здесь перебиваем скоупом. */
.sticker .pp-ic:where(:not([width])){ width:13px; height:13px; }
.s-violet{ background:var(--violet); color:#fff; }
.s-blue  { background:var(--blue);   color:#fff; }
.s-sun   { background:var(--sun);    color:var(--ink); }
.s-lime  { background:var(--lime);   color:var(--ink); }
.s-coral { background:var(--coral);  color:#fff; }
.s-ok    { background:var(--ok);     color:#fff; }
.s-mini  { font-size:10px; padding:3px 8px; box-shadow:0 0 0 1.5px #fff inset, 0 2px 6px rgba(0,0,0,.12); }
.sticker.is-guarantee{ font-size:13px; padding:6px 13px; }

/* =====================================================
   TIER + CTA
   ===================================================== */
.pp-tier-row{ display:flex; align-items:center; gap:12px; }
.pp-medal{
  width:44px; height:44px; border-radius:var(--pill); display:grid; place-items:center;
  font-size:22px; flex:none;
}
.pp-medal.tier-new{ background:var(--line2); }
.pp-medal.tier-l1{ background:var(--sun); }
.pp-medal.tier-l2{ background:var(--blue); }
.pp-medal.tier-top{ background:linear-gradient(135deg,#FFC53D,#FF9F1C); }
.pp-medal.tier-pro{ background:var(--grad-hero); box-shadow:0 0 14px rgba(124,92,255,.5); }
.pp-tier-info{ flex:1; min-width:0; }
.pp-tier-label{ font:800 16px var(--font-display); }
.pp-tier-hint{ color:var(--ink2); font:500 12px var(--font); margin-top:2px; }
.pp-tier-mini{ height:6px; border-radius:var(--pill); background:var(--bg2); overflow:hidden; margin-top:6px; }
.pp-tier-mini i{ display:block; height:100%; background:var(--grad-hero); }

.pp-btn{
  min-height:52px; border-radius:var(--pill); font:700 16px var(--font); border:none;
  cursor:pointer; width:100%; display:inline-flex; align-items:center; justify-content:center; gap:8px;
  text-decoration:none;   /* глобальный сброс тут только `a{color:inherit}` → <a class="pp-btn"> шёл с подчёркиванием */
}
.pp-btn-primary{ background:var(--grad-hero); color:#fff; box-shadow:0 12px 28px -10px rgba(124,92,255,.7);
  transition:transform .18s cubic-bezier(.34,1.56,.64,1), box-shadow .18s; }
.pp-btn-primary:hover{ transform:translateY(-2px); box-shadow:0 18px 36px -10px rgba(124,92,255,.85); }
.pp-btn-secondary{ background:#fff; color:var(--ink); border:1.5px solid var(--line2); }
/* GROWTH-тир (Подписаться) — между primary(градиент) и contact(тихий): tinted бренд-контур,
   выделяет ростовое действие, но НЕ конкурирует с заливкой primary. Hover → заполняется.
   Тир один на весь сервис: сюда же подключена компактная пилюля .pp-prow-follow (строка человека
   в списке «Подписчики»/«Подписки») — её ГАБАРИТЫ живут в своём правиле, а ЦВЕТ берётся отсюда,
   чтобы secondary-действие в списке не могло разъехаться с каноном тира. */
.pp-btn-growth,
.pp-prow-follow{ background:var(--violet-soft,rgba(124,92,255,.1)); color:var(--violet); border:1.5px solid var(--violet); }
.pp-btn-growth:hover,
.pp-prow-follow:hover{ background:var(--violet); color:#fff; }
/* ── БАЗА-СТРАХОВКА размера бренд-иконки (рецидив-защита, НЕ УДАЛЯТЬ) ────────────────────
   inline-SVG с одним viewBox и БЕЗ width/height не имеет внутреннего размера: во flex-контейнере
   он схлопывается в 0×0 (иконка физически невидима), в инлайновом — раздувается до ширины
   контейнера (гигант на пол-экрана). Раньше размер .pp-ic существовал ТОЛЬКО в точечных
   контекстах (.pp-btn / .pp-prow-follow), поэтому каждый новый контекст ломался заново.
   Это правило даёт безопасный дефолт 16px ЛЮБОМУ такому .pp-ic, где бы он ни оказался.
   Два условия в селекторе — оба обязательны:
   (1) :not([width]) — НЕ трогаем иконки, которым размер задан АТРИБУТОМ
       (groups.js / group.js / post-comments.js: `<svg class="pp-ic" width="14" height="14">`);
       CSS-свойство перебивает презентационный атрибут, без :not они бы все стали 16px;
   (2) :where(...) — обнуляет вес селектора до (0,1,1), поэтому любое контекст-правило
       вида `.контейнер .pp-ic` (0,2,0) ниже спокойно переопределяет базу.
   vertical-align — тот же нюанс базовой линии, что groups.js задаёт инлайн-стилем (в flex игнор). */
svg.pp-ic:where(:not([width])){ width:16px; height:16px; flex:none; vertical-align:-.14em; }
/* монохром line-иконка в кнопке — единый размер, currentColor тянет цвет тира; зазор icon→label = gap:8px базовой .pp-btn */
.pp-btn .pp-ic{ width:18px; height:18px; flex:none; }
/* Компактный тир кнопки — auto-width, ниже тап-таргет 40px (не 52 «на всю ширину»).
   Для редких/раздельных действий (создать группу, действие раздела рядом с заголовком). */
.pp-btn-compact{ width:auto; min-height:40px; padding:0 16px; font-size:14px; white-space:nowrap; }
.pp-cta{ display:grid; grid-template-columns:1fr 1fr; gap:10px; margin-top:14px; }
@media(max-width:420px){ .pp-cta{ grid-template-columns:1fr; } }
/* ── КЛАСТЕР ДЕЙСТВИЙ В ШАПКЕ /@handle (заказчик · поставщик) — РЯД ПИЛЮЛЬ, НЕ СТОПКА ПОЛОС ──
   Было (замер 1440): .pp-cta.is-stack — колонка во всю ширину контента, каждая кнопка 1328x52;
   у поставщика три такие полосы = 1328x114, на 375px — 343x176 стопкой, ПОВЕРХ sticky-бара,
   который те же «Смотреть магазин»/«Написать» уже несёт. Кнопка шириной в 1328px — не действие,
   а баннер: цель по Фиттсу бесконечная, вес максимальный у ВСЕГО, приоритета нет (§14.A), и это
   прямой красный флаг D0 («пол-экрана под то, что влезает в пилюлю»).
   Стало: тот же ряд, что владельческий кластер .pp-acts выше по странице — auto-width пилюли
   40px, gap 8, центр по общей оси шапки (имя/чипы/стикеры центрированы), перенос на узком.
   Одна страница = один язык кластера действий (Якоб), гость и хозяин видят одну геометрию.
   Тир/цвет кнопок НЕ трогаем — только габарит и раскладку. */
.pp-cta.is-stack{ display:flex; flex-flow:row wrap; justify-content:center; align-items:center; gap:8px; }
/* вложенная пара (поставщик: «Написать» + «Подписаться») — тоже ряд, а не 1fr 1fr на всю ширину */
.pp-cta.is-stack .pp-cta{ margin-top:0; display:flex; flex-flow:row wrap; justify-content:center; gap:8px; }
.pp-cta.is-stack .pp-btn{ width:auto; min-height:40px; padding:0 15px; font-size:14px; white-space:nowrap; }
/* Тач: тело кнопки остаётся 40px (D0 — не раздуваем визуал), а ЗОНА ТАПА добирается до 44
   невидимым псевдо-элементом — тот же приём, что у .pp-acts .pp-act-ico и .pp-color-del.
   Только вертикально: горизонтальные зазоры между целями обязаны остаться >=8px. */
@media(pointer:coarse){
  .pp-cta.is-stack .pp-btn{ position:relative; }
  .pp-cta.is-stack .pp-btn::after{ content:""; position:absolute; inset:-2px 0; }
}

/* =====================================================
   STATS
   ===================================================== */
.pp-stats{ display:grid; grid-template-columns:repeat(3,1fr); gap:12px; }
.pp-num{ font:800 24px var(--font-display); font-variant-numeric:tabular-nums; line-height:1.1; }
.pp-num small{ display:block; font:500 11px var(--font); color:var(--ink2); margin-top:2px; }
/* textual stat (e.g. «до 1ч») reads smaller, in Inter, not a 24px display number */
.pp-num.is-text{ font:700 18px var(--font); letter-spacing:-.01em; }
@media(max-width:400px){
  .pp-stats{ grid-template-columns:1fr 1fr; }
}

/* =====================================================
   RATING BARS
   ===================================================== */
.pp-rate-row{ display:grid; grid-template-columns:1fr 120px auto; align-items:center; gap:10px; margin:8px 0; }
.pp-rate-row span:first-child{ font:600 13px var(--font); }
.pp-rate-row .pp-rate-val{ font:800 14px var(--font-display); font-variant-numeric:tabular-nums; }
.pp-bar{ height:10px; border-radius:var(--pill); background:var(--bg2); overflow:hidden; }
.pp-bar i{ display:block; height:100%; width:0; background:var(--grad-2);
  transition:width .9s cubic-bezier(.34,1.56,.64,1); }
@media(max-width:420px){
  .pp-rate-row{ grid-template-columns:1fr 84px auto; gap:8px; }
}

/* =====================================================
   PRINTERS
   ===================================================== */
.pp-printer{
  display:flex; align-items:center; gap:10px; padding:12px; border:1px solid var(--line);
  border-radius:var(--r); margin-bottom:10px;
}
.pp-printer-name{ font:700 15px var(--font); }
.pp-printer-bed{ font:500 12px var(--font); color:var(--ink2); margin-top:2px; }
.pp-tech{ padding:2px 8px; border-radius:var(--pill); color:#fff; font:700 11px var(--font); }
.pp-tech.fdm{ background:var(--blue); }
.pp-tech.sla{ background:var(--violet); }
.pp-qty{
  margin-left:auto; width:26px; height:26px; border-radius:var(--pill);
  background:var(--bg2); display:grid; place-items:center; font:700 13px var(--font); flex:none;
}

/* =====================================================
   MATERIALS
   ===================================================== */
.pp-mat-row{ display:flex; align-items:center; gap:10px; flex-wrap:wrap; margin:8px 0; }
.pp-mat-type{
  border-radius:var(--pill); padding:3px 11px; font:700 12px var(--font);
  border:1.5px solid var(--line2); color:var(--ink2); background:#fff;
}
.pp-mat-type.pla { border-color:var(--violet); color:var(--violet); }
.pp-mat-type.petg{ border-color:var(--blue);   color:var(--blue); }
.pp-mat-type.abs { border-color:var(--coral);  color:var(--coral); }
.pp-mat-type.resin{ border-color:var(--ink2);  color:var(--ink2); }
.pp-swatch{ width:20px; height:20px; border-radius:var(--pill); border:1px solid var(--line2); flex:none; }

/* =====================================================
   PORTFOLIO / DIFFERENTIATOR
   ===================================================== */
.pp-filter{ display:flex; flex-wrap:wrap; gap:8px; margin:0 0 14px; }
.pp-filter-chip{
  border:1.5px solid var(--line2); background:#fff; border-radius:var(--pill);
  padding:7px 14px; font:600 13px var(--font); color:var(--ink2); cursor:pointer;
  transition:all .15s;
}
.pp-filter-chip.is-active{ background:var(--ink); color:#fff; border-color:var(--ink); }

.pp-work{ position:relative; margin-bottom:18px; }
.pp-work model-viewer{
  width:100%; height:320px; border-radius:var(--r); background:var(--bg2); display:block;
  --poster-color:transparent;
}
.pp-work.is-exploded model-viewer{ background:linear-gradient(160deg,var(--bg2),#fff); }
.pp-work-mv{ position:relative; }
/* moat badge — ALWAYS visible over the viewer (main differentiator) */
.pp-moat-badge{
  position:absolute; left:12px; top:12px; z-index:3;
  display:inline-flex; align-items:center; gap:5px;
  background:var(--lime); color:var(--ink);
  font:800 12px var(--font-display); letter-spacing:-.01em;
  padding:6px 12px; border-radius:var(--pill); white-space:nowrap;
  box-shadow:0 0 0 2px #fff inset, 0 4px 12px rgba(0,0,0,.16);
}
.pp-moat-badge.is-draft{ background:#fff; color:var(--ink2); box-shadow:0 0 0 1.5px var(--line2) inset, 0 4px 12px rgba(0,0,0,.1); }
/* бейдж = 12px display-текст → иконка 14px, как в чипах/капсулах */
.pp-moat-badge .pp-ic:where(:not([width])){ width:14px; height:14px; }
.pp-cut-overlay{
  position:absolute; left:12px; bottom:12px; background:rgba(20,20,20,.7);
  backdrop-filter:blur(8px); -webkit-backdrop-filter:blur(8px);
  color:#fff; border-radius:var(--pill); padding:8px 14px;
  font:700 13px var(--font); border:none; cursor:pointer; z-index:2;
  transition:transform .18s cubic-bezier(.34,1.56,.64,1);
}
.pp-cut-overlay:hover{ transform:scale(1.05); }
.pp-work-title{ font:800 17px var(--font-display); margin:12px 0 6px; letter-spacing:-.01em; }
.pp-work-chips{ display:flex; flex-wrap:wrap; gap:6px; }
.pp-cut-btn{
  width:100%; margin-top:12px; border:1.5px solid var(--violet); color:var(--violet);
  background:#fff; border-radius:var(--pill); min-height:48px; font:700 15px var(--font); cursor:pointer;
  transition:all .15s;
}
.pp-cut-btn:hover{ background:rgba(124,92,255,.06); }
/* полноширинная кнопка тира .pp-btn (текст 15px, высота 48) → иконка 18px, как у .pp-btn .pp-ic.
   .pp-cut-overlay рядом остаётся на базовых 16px: текст 13px, компактная плашка над вьюером. */
.pp-cut-btn .pp-ic:where(:not([width])){ width:18px; height:18px; }
.pp-work.is-exploded .pp-cut-btn{ border-color:var(--line2); color:var(--ink2); }
.pp-cut-reveal{
  max-height:0; overflow:hidden; opacity:0;
  transition:max-height .4s ease, opacity .3s ease, margin .3s ease;
}
.pp-work.is-exploded .pp-cut-reveal{ max-height:260px; opacity:1; margin-top:12px; }
.pp-fact{ margin-top:8px; font:600 13px var(--font); color:var(--ink2); }
.pp-makes{ display:flex; gap:8px; margin-top:8px; }
.pp-makes img{ width:56px; height:56px; border-radius:14px; object-fit:cover; }
.pp-draft-chip{
  display:inline-flex; align-items:center; gap:5px; font:700 12px var(--font);
  color:var(--ink2); background:var(--bg2); border-radius:var(--pill); padding:5px 11px;
}
.pp-draft-chip .pp-ic:where(:not([width])){ width:13px; height:13px; }

/* =====================================================
   FEED
   ===================================================== */
.pp-feed-item{ position:relative; padding:14px; border:1px solid var(--line); border-radius:var(--r); margin-bottom:10px; overflow:hidden; }
.pp-feed-item.is-milestone{ background:linear-gradient(120deg,rgba(255,197,61,.1),transparent); border-color:rgba(255,197,61,.3); }
.pp-feed-text{ font:600 14px var(--font); }
.pp-feed-photo{ display:block; max-width:100%; width:auto; height:auto;
  max-height:min(70vh,560px); object-fit:contain; margin:var(--sp-3) auto 0;
  border-radius:var(--r); background:var(--bg2); }
.pp-feed-date{ float:right; color:var(--ink2); font:500 12px var(--font); }
.pp-feed-meta{ margin-top:10px; color:var(--ink2); font:600 12px var(--font); display:flex; gap:14px; }

/* =====================================================
   REVIEWS
   ===================================================== */
.pp-review{ border:1px solid var(--line); border-radius:var(--r); padding:14px; margin-bottom:10px; }
.pp-review-head{ display:flex; align-items:center; gap:10px; margin-bottom:8px; }
.pp-ava-mini{
  width:36px; height:36px; border-radius:var(--pill); background:var(--grad-2);
  color:#fff; display:grid; place-items:center; font:700 15px var(--font); flex:none;
}
.pp-review-author{ font:700 14px var(--font); }
.pp-review-date{ color:var(--ink2); font:500 12px var(--font); }
.pp-stars{ color:var(--sun); font-size:13px; letter-spacing:1px; }
.pp-review-cats{ display:flex; flex-wrap:wrap; gap:6px; margin:6px 0 8px; }
.pp-review-cat{ font:600 11px var(--font); color:var(--ink2); background:var(--bg2); border-radius:var(--pill); padding:3px 9px; }
.pp-review-text{ font:400 14px var(--font); color:var(--ink); }
.pp-rate-hero{ display:flex; align-items:baseline; gap:8px; margin-bottom:14px; }
.pp-rate-hero b{ font:800 34px var(--font-display); font-variant-numeric:tabular-nums; }
.pp-rate-hero span{ color:var(--ink2); font:500 13px var(--font); }

/* =====================================================
   ABOUT / PHOTOS / VERIFY
   ===================================================== */
.pp-about{ font:400 15px var(--font); color:var(--ink); white-space:pre-line; margin:0 0 12px; }
.pp-photos{
  display:flex; gap:10px; overflow-x:auto; scroll-snap-type:x mandatory;
  -webkit-overflow-scrolling:touch; padding-bottom:4px; margin:0 -2px;
}
.pp-photos img{
  width:160px; height:120px; object-fit:cover; border-radius:var(--r);
  scroll-snap-align:start; flex:none;
}
.pp-verify{ display:flex; flex-wrap:wrap; gap:8px; margin-top:12px; }
.pp-verify-item{
  display:inline-flex; align-items:center; gap:6px; font:600 12px var(--font);
  border:1px solid var(--line2); border-radius:var(--pill); padding:5px 11px;
}
.pp-verify-item.is-on{ color:var(--ok); border-color:rgba(31,191,117,.4); background:rgba(31,191,117,.06); }
.pp-verify-item.is-off{ color:var(--ink2); }

/* =====================================================
   LEAD / СРОКИ
   ===================================================== */
.pp-lead{ display:flex; flex-direction:column; gap:2px; }
.pp-lead-row{
  display:flex; align-items:center; justify-content:space-between; gap:10px;
  padding:9px 0; border-bottom:1px solid var(--line);
}
.pp-lead-row:last-child{ border-bottom:none; }
.pp-lead-key{ font:600 13px var(--font); color:var(--ink2); flex:none; }
.pp-lead-val{ font:700 14px var(--font); color:var(--ink); text-align:right; }

/* =====================================================
   PRICE
   ===================================================== */
.pp-price{ display:grid; grid-template-columns:1fr 1fr; gap:12px; }
.pp-price-cell{ background:var(--bg2); border-radius:var(--r); padding:14px; text-align:center; }
.pp-price-cell b{ font:800 22px var(--font-display); display:block; }
.pp-price-cell span{ font:500 12px var(--font); color:var(--ink2); }

/* =====================================================
   TRUST (customer)
   ===================================================== */
.pp-trust{ display:grid; grid-template-columns:1fr 1fr; gap:12px; }
.pp-trust-cell{ background:var(--bg2); border-radius:var(--r); padding:16px; text-align:center; }
.pp-trust .pp-num.is-hero{ font-size:34px; color:var(--ok); }

/* tags (customer) */
.pp-tags{ display:flex; flex-wrap:wrap; gap:8px; }
.pp-tag-chip{ border-radius:var(--pill); padding:6px 12px; font:600 13px var(--font); border:1.5px solid; background:#fff; }
.pp-tag-chip.t-violet{ border-color:var(--violet); color:var(--violet); }
.pp-tag-chip.t-blue  { border-color:var(--blue);   color:var(--blue); }
.pp-tag-chip.t-coral { border-color:var(--coral);  color:var(--coral); }

/* private (locked) */
.pp-locked-card{ background:var(--bg2); }
.pp-locked-row{ display:flex; justify-content:space-between; gap:10px; padding:8px 0; border-bottom:1px solid var(--line); }
.pp-locked-row:last-child{ border-bottom:none; }
.pp-locked-key{ font:600 13px var(--font); color:var(--ink2); flex:none; }
.pp-locked{ filter:blur(5px); user-select:none; pointer-events:none; color:var(--ink2); font:600 13px var(--font); }
.pp-lock-note{ display:flex; align-items:center; gap:8px; color:var(--ink2); font:500 12px var(--font); margin-top:8px; }
.pp-lock-note .pp-ic:where(:not([width])){ width:14px; height:14px; }

/* =====================================================
   STICKY CTA
   ===================================================== */
.pp-sticky-cta{
  position:sticky; bottom:0; z-index:30; width:100%;
  background:rgba(255,253,247,.9); backdrop-filter:blur(12px); -webkit-backdrop-filter:blur(12px);
  /* + var(--bs-bottom-reserve) = max(--bs-cc-h, --bs-tab-h): бар поднимается над тем,
     что реально занимает нижнюю кромку — cookie-плашкой и/или мобильной панелью
     разделов. Именно max, а не сумма: плашка сама встаёт над панелью и её высота
     панель уже включает (tokens.css, --bs-bottom-reserve). */
  padding:12px 0 calc(12px + env(safe-area-inset-bottom) + var(--bs-bottom-reserve,0px));
  display:flex; gap:10px; border-top:1px solid var(--line);
}
.pp-sticky-inner{ max-width:var(--page-max); margin:0 auto; width:100%; display:flex; align-items:center; gap:10px; padding:0 16px; }
/* D0: 44 (тач-таргет ровно по порогу), не 52 — у мастера этот размер уже принят на мобиле
   («компактный тап-таргет ≥44, не 52»), у заказчика/поставщика бар оставался 52px и на
   десктопе тоже: полоса кнопок толщиной с шапку. Приводим к одному числу. */
.pp-sticky-cta .pp-btn{ min-height:44px; }
.pp-share{ flex:none; width:44px; }
/* ── ПЕРВЫЙ КАДР ОТ СЕРВЕРА: кнопки без слушателей не должны выглядеть живыми ──────────────
   SSR рисует sticky-панель сразу, а обработчики приезжают только с гидрацией (profile.js).
   На медленном мобильном человек жал «живую» кнопку и не получал НИЧЕГО. До гидрации бар
   честно показан «готовится»: приглушён, курсор progress, нажатие не ловится (ложного
   нажатия нет). Класс `.pp-hydrated` вешает profile.js в момент, когда wire() отработал.
   Главная кнопка «Заказать печать» под это правило НЕ попадает: в SSR она markup-ссылка
   <a href="/@handle/shop"> и работает вообще без JS — ровно тот адрес, что ставит wire(). */
html:not(.pp-hydrated) .pp-sticky-cta,
html:not(.pp-hydrated) .pp-acts{ cursor:progress; }
html:not(.pp-hydrated) .pp-sticky-cta button[data-act],
html:not(.pp-hydrated) .pp-acts button[data-act]{ opacity:.5; pointer-events:none; }
/* МАСТЕР-sticky = модификатор .pp-sticky-master (customer/supplier ШАРЯТ .pp-sticky-cta — их не
   трогаем: у customer тут labeled «Написать», у supplier msg+share).
   ДЕСКТОП (≥641): бар СКРЫТ целиком — действия мастера живут в шапке (.pp-acts); нижний дубль убран
   (жалоба владельца). МОБАЙЛ (≤640): шапочные .pp-acts прячутся → sticky = единственный путь (ниже). */
.pp-stk-lbl{ display:none; }   /* текст-лейбл у иконочных sticky-кнопок — показываем ТОЛЬКО на мобиле */
@media(min-width:641px){ .pp-sticky-master{ display:none; } }
/* МОБАЙЛ (≤640): шапочные .pp-acts скрыты → sticky = единственный путь. ТРИ действия, аккуратно в
   2 ряда: primary «Заказать печать» сверху во всю ширину, ниже «Написать | Подписаться» ровными
   половинами. Компактно/выверено: h46 (не 52), у всех подписи (не голые иконки), тап ≥44 (§2/§7).
   Follow виден сразу (ряд 2), не спрятан. §14.A: 1 primary + ≤2 конкурирующих равных вторичных. */
@media(max-width:640px){
  /* 🔴 своя padding-строка ПЕРЕБИВАЕТ padding базового .pp-sticky-cta вместе с его
     резервом — поэтому резерв повторён здесь явно. Без этого мобильный CTA мастера
     уезжал под cookie-плашку (так было и до панели разделов) и под саму панель. */
  .pp-sticky-master{ padding:10px 0 calc(10px + env(safe-area-inset-bottom) + var(--bs-bottom-reserve,0px)); }
  .pp-sticky-master .pp-sticky-inner{ flex-wrap:wrap; gap:8px; }
  .pp-sticky-master .pp-share{ display:none; }
  .pp-sticky-master .pp-btn{ min-height:44px; font-size:15px; }             /* компактный тап-таргет ≥44, не 52 */
  .pp-sticky-master [data-act="order"]{ flex:1 0 100%; }                    /* ряд 1 — вся ширина */
  .pp-sticky-master [data-act="msg"],
  .pp-sticky-master [data-act="follow"]{ flex:1 1 0; width:auto; min-width:0; padding:0 12px; }  /* ряд 2 — ровные половины */
  .pp-sticky-master [data-act="msg"] .pp-stk-lbl{ display:inline; }         /* «Написать» — с подписью на мобиле */
}

/* PREVIEW SWITCHER профиля («ваш профиль / Как мастер / Как заказчик / ✏️ Редактировать», fixed
   снизу-справа) УДАЛЁН по запросу владельца — плавающий бар снят со страницы. Редактирование живёт
   в кабинете (/profile-edit.html). Оставшийся `.pp-switch` (ниже, ~стр.3015) — ЕДИНСТВЕННЫЙ
   компонент-тумблер сервиса (трек + бегунок, размер-модификатор `--sm`); второе определение
   этого же класса (простой чекбокс формы товара) удалено, коллизии имён больше нет. */

/* =====================================================
   SAVE BAR (profile-edit)
   Sticky ПОД навигацией (top:56), но ВЫРОВНЕН по колонке контента
   (max 1040) как мягкая плашка-пилюля — НЕ полноширинная полоса-хром.
   Контейнер прозрачный (боковые жёлоба пропускают клики), видимая
   плашка = .pp-actionbar-inner. Save = primary справа, Предпросмотр —
   тихая вторичная. Прогресс несут тиры → тут только тихий мини-индикатор.
   ===================================================== */
.pp-actionbar{
  position:fixed; left:0; right:0; bottom:0; top:auto; z-index:60;
  /* нижний бар: боковые жёлоба + home-indicator + место под чужую нижнюю кромку
     (cookie-плашка / панель разделов) — см. --bs-bottom-reserve в tokens.css */
  padding:0 16px calc(12px + env(safe-area-inset-bottom) + var(--bs-bottom-reserve,0px));
  pointer-events:none;              /* клики проходят сквозь прозрачный жёлоб */
}
.pp-actionbar-inner{
  pointer-events:auto;
  max-width:var(--page-max); margin:0 auto;
  display:flex; align-items:center; gap:12px;
  background:var(--card); border:1px solid var(--line); border-radius:var(--pill);
  box-shadow:var(--shadow); padding:7px 8px 7px 18px;
}
.pp-ab-prog{ display:flex; align-items:center; gap:8px; min-width:0; }
.pp-ab-track{ width:56px; height:5px; border-radius:var(--pill); background:var(--bg2); overflow:hidden; flex:none; }
.pp-ab-track i{ display:block; height:100%; background:var(--grad-hero); border-radius:var(--pill); transition:width .5s cubic-bezier(.34,1.56,.64,1); }
.pp-ab-mini{ font:600 12px var(--font); color:var(--ink2); font-variant-numeric:tabular-nums; white-space:nowrap; }
.pp-ab-mini b{ color:var(--ink); }
.pp-ab-btns{ margin-left:auto; display:flex; gap:8px; align-items:center; }
/* Инлайн-статус сохранения — рядом с прогрессом, СЛЕВА от кнопок (подтверждение живёт в той
   же зоне, где нажали «Сохранить»). В embed это единственный видимый канал: .pp-toast —
   fixed внутри рамки высотой во весь контент → физически уезжает за нижний край кадра. */
.pp-ab-status{ font:600 13px var(--font); color:var(--ink2); min-width:0;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.pp-ab-prog{ flex:1 1 auto; }
/* Ступень 800, а не 500/700: на белой карте --emerald-700 даёт 3.86:1 — под порогом AA
   для 13px (замер), --emerald-800 = 6.26:1. --rose-700 = 4.60:1, проходит. Цвет тут —
   усиление, а не единственный сигнал: смысл несёт сам текст «Сохранено»/причина ошибки. */
.pp-ab-status.is-ok{ color:var(--emerald-800); }
.pp-ab-status.is-err{ color:var(--rose-700); }
/* «Моя страница ↗» — тихая вторичная, тир НЕ повышаем. После успешного сохранения на
   несколько секунд подсвечиваем ЕЁ (бренд-контур, без движения — работает и с
   prefers-reduced-motion): это ответ на «а как теперь выглядит страница?», но primary
   остаётся один — «Сохранить» (§14.A). */
.pp-ab-btns.is-just-saved .pp-ab-ghost{ border-color:var(--violet); color:var(--violet-700); background:var(--violet-50); }
.pp-ab-ext{ display:inline-flex; color:var(--ink2); opacity:.75; margin-left:-2px; }
.pp-ab-btn{
  min-height:40px; border-radius:var(--pill); font:700 14px var(--font); border:none;
  cursor:pointer; padding:0 18px; display:inline-flex; align-items:center; justify-content:center; gap:6px;
  text-decoration:none;   /* «Моя страница» — <a>, а глобальный сброс тут только a{color:inherit} */
}
.pp-ab-ghost{ background:transparent; color:var(--ink2); border:1.5px solid var(--line2); }
.pp-ab-ghost:hover{ background:var(--bg2); color:var(--ink); }
.pp-ab-save{ background:var(--grad-hero); color:#fff; box-shadow:0 8px 20px -8px rgba(124,92,255,.6); }
.pp-ab-save:hover{ transform:translateY(-1px); box-shadow:0 12px 26px -8px rgba(124,92,255,.85); }
.pp-ab-save:disabled{ opacity:.6; cursor:default; transform:none; }
/* Бренд-фокус вместо UA-кольца: «Моя страница» — ссылка, её берут с клавиатуры чаще всего */
.pp-ab-btn:focus-visible{ outline:2px solid var(--violet); outline-offset:2px; }
@media(max-width:560px){
  .pp-actionbar{ padding:0 12px calc(10px + env(safe-area-inset-bottom)); }
  .pp-ab-track{ display:none; }
  .pp-ab-ghost .pp-ab-txt{ display:none; }
  .pp-ab-ext{ display:none; }          /* в icon-only пилюле 44px второму глифу места нет */
  .pp-ab-btn{ min-height:44px; }
  .pp-ab-ghost{ padding:0 12px; min-width:44px; }
  /* На узком статус в один ряд с кнопками обрезался бы в «Сохранено · н…» — а именно там
     живёт важное («новый адрес @ник»). Пока статус ПОКАЗАН (класс вешает JS на 6-9 сек),
     бар распускается во вторую строку и текст читается целиком; статус ушёл — бар снова
     однострочный, лишней высоты в покое нет (D0). */
  .pp-actionbar-inner.has-status{ flex-wrap:wrap; }
  .pp-actionbar-inner.has-status .pp-ab-status{ order:3; flex-basis:100%; white-space:normal;
    overflow:visible; line-height:1.35; }
  /* КУДА расти второй строке. В standalone бар прибит к нижнему краю и растёт ВВЕРХ — кнопки
     остаются на месте сами. В embed он стоит В ПОТОКЕ сверху, и рост вниз увёл бы «Сохранить»
     из-под пальца сразу после нажатия (сдвиг элемента, который только что трогали). Поэтому в
     embed меняем порядок: ряд кнопок — первой строкой, прогресс со статусом — второй. */
  .is-embed .pp-actionbar-inner.has-status .pp-ab-btns{ order:1; width:100%; margin-left:0;
    justify-content:flex-end; }
  .is-embed .pp-actionbar-inner.has-status .pp-ab-prog{ order:2; width:100%; }
}
@media(prefers-reduced-motion:reduce){
  .pp-ab-save:hover{ transform:none; }
  .pp-ab-track i{ transition:none; }
}

/* ── EMBED: редактор смонтирован в iframe хаба (/store.html?tab=profile) ──────────────────
   Рамка растёт под контент и своего скролла НЕ имеет — скроллит родитель. Значит «вьюпорт»
   этого документа = весь кадр целиком, и position:fixed;bottom:0 паркует save-бар в самом
   НИЗУ кадра: липкости в embed физически не существует, а бар с «Сохранить» и «Моя
   страница» уезжал на 3-4 тысячи пикселей вниз. Поэтому в embed бар — обычная полоса В
   ПОТОКЕ, НАВЕРХУ секции (sticky на случай, если у рамки когда-нибудь появится свой скролл;
   без скролл-контейнера sticky ведёт себя как обычный блок — деградация безопасная).
   Нижняя подложка под фиксированный бар в embed не нужна → 88px пустоты убираем (D0). */
.is-embed .pp-actionbar{ position:sticky; top:0; bottom:auto; left:auto; right:auto;
  padding:0 16px var(--sp-3); z-index:40; }   /* 16px — та же боковая линия, что у .pp-col ниже */
/* В потоке бар стоит НАД карточками — его рёбра обязаны совпасть с их рёбрами (в standalone
   он парит поверх контента, там нависание в 16px не читается как ошибка, а тут читалось бы).
   .pp-col = --page-max с padding 0 16 → полезная ширина ровно на 32px меньше. */
.is-embed .pp-actionbar-inner{ max-width:calc(var(--page-max) - 32px); }
.is-embed .pp-bottom-pad{ height:0; }

/* =====================================================
   PROFILE-EDIT density scope (класс .pp-edit на .pp-col в render())
   Уплотняем ТОЛЬКО страницу редактора. Общие .pp-card/.pp-card-title/
   .pp-field/.pp-label/.pp-check НЕ трогаем глобально — их делят 13
   поверхностей вкл. публичные SSR (правило «SSR ≠ статика»). Плотнее
   весь сервис — отдельным выверенным проходом, не тихим сайд-эффектом.
   ===================================================== */
.pp-edit .pp-card{ padding:14px; margin-bottom:12px; }
.pp-edit .pp-card-title{ font-size:15px; margin:0 0 10px; }
.pp-edit .pp-field{ margin-bottom:12px; }
.pp-edit .pp-label{ margin:0 0 5px; }
.pp-edit .pp-check{ padding:6px 0; font-size:13px; }

/* =====================================================
   FORM (edit)
   ===================================================== */
.pp-input, textarea.pp-input{
  width:100%; background:#fff; border:1.5px solid var(--line); border-radius:var(--r);
  padding:12px 14px; font:500 15px var(--font); color:var(--ink); resize:vertical;
}
.pp-input:focus{ outline:none; border-color:var(--violet); box-shadow:0 0 0 3px rgba(124,92,255,.15); }
.pp-label{ display:block; font:600 12px var(--font); color:var(--ink2); margin:0 0 6px; }
.pp-field{ margin-bottom:14px; }
.pp-row2{ display:grid; grid-template-columns:1fr 1fr; gap:12px; }
@media(max-width:420px){ .pp-row2{ grid-template-columns:1fr; } }
.pp-row3{ display:grid; grid-template-columns:1fr 1fr 1fr; gap:8px; }
/* [hidden]-guard (как .pp-cmt-toggle[hidden], стр. ~1293): авторский display:grid перебивает
   UA-правило [hidden]{display:none} → ряд с атрибутом hidden ОСТАВАЛСЯ ВИДИМЫМ. Денежная цена
   бага: в форме товара [data-price-wrap] = .pp-row2, и при «Бесплатно»/«Договорной» поле цены
   не пряталось — мастер вписывал сумму, а сейв молча слал price=0 (товар навсегда бесплатный). */
.pp-row2[hidden], .pp-row3[hidden]{ display:none; }
.pp-label-opt{ font-weight:400; opacity:.6; font-size:.85em; }

/* onboarding — компактная гейм-плашка (прогресс тут ambient, % и Save — в action-bar) */
.pp-onb{
  background:var(--card); border-radius:var(--r);
  box-shadow:var(--shadow); padding:14px; margin:12px 0;
}
/* уровень профиля — заголовок + пояснение + ?-тултип (смысл лестницы) */
.pp-tierbox{ margin-top:2px; }
.pp-tierhead{ display:flex; align-items:center; gap:6px; margin-bottom:8px; }
.pp-tierhead-title{ font:800 13px var(--font-display); color:var(--ink); letter-spacing:-.01em; }
.pp-tierhead-info{
  position:relative; flex:none; width:18px; height:18px; border-radius:50%;
  display:inline-grid; place-items:center; cursor:help;
  background:var(--bg2); color:var(--ink2); font:800 11px var(--font);
  border:1.5px solid var(--line2); transition:background-color .18s, color .18s, border-color .18s;
}
.pp-tierhead-info:hover, .pp-tierhead-info:focus-visible{
  background:var(--violet-50); color:var(--violet-700); border-color:var(--violet-200); outline:none;
}
.pp-tierhead-tip{
  position:absolute; left:-2px; top:calc(100% + 8px); z-index:6;
  width:min(240px,72vw); padding:9px 12px; border-radius:12px;
  background:var(--ink); color:#fff; font:500 12px var(--font); line-height:1.4; text-align:left;
  box-shadow:var(--shadow); opacity:0; visibility:hidden; transform:translateY(-4px);
  transition:opacity .18s, transform .18s, visibility .18s; pointer-events:none;
}
.pp-tierhead-info:hover .pp-tierhead-tip,
.pp-tierhead-info:focus .pp-tierhead-tip,
.pp-tierhead-info:focus-visible .pp-tierhead-tip{ opacity:1; visibility:visible; transform:translateY(0); }
.pp-tierhead-sub{ margin:6px 0 0; font:500 11.5px var(--font); color:var(--ink2); }
.pp-tiers{ display:flex; gap:6px; margin-top:2px; }
.pp-tier{ flex:1; text-align:center; font:600 11px var(--font); color:var(--ink2); padding:6px 0; border-radius:var(--pill); background:var(--bg2); }
.pp-tier.is-active{ background:var(--grad-hero); color:#fff; font-weight:700; }
/* чек-лист свёрнут по умолчанию — не жрёт пол-экрана */
.pp-checks-wrap{ margin-top:12px; border-top:1px solid var(--line); }
.pp-checks-sum{
  list-style:none; cursor:pointer; display:flex; align-items:center; gap:2px;
  padding:10px 0 2px; color:var(--ink);
}
/* робастно гасим дефолтный ▶/▾ маркер во всех движках */
.pp-checks-sum::-webkit-details-marker{ display:none; }
.pp-checks-sum::marker{ content:""; }
.pp-checks-title{ font:700 13px var(--font); color:var(--ink); }
/* свой chevron по брендбуку — круглый чип, плавно поворачивается при open */
.pp-checks-sum::after{
  content:""; margin-left:auto; flex:none; width:26px; height:26px; border-radius:50%;
  background:var(--bg2) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12' fill='none' stroke='%237C5CFF' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2.5 4.5 6 8l3.5-3.5'/%3E%3C/svg%3E") center/12px no-repeat;
  transition:transform .25s cubic-bezier(.34,1.56,.64,1), background-color .18s;
}
.pp-checks-sum:hover::after{ background-color:var(--violet-50); }
details[open] .pp-checks-sum::after{ transform:rotate(180deg); }
.pp-checks-sum:focus-visible{ outline:2px solid var(--violet); outline-offset:2px; border-radius:10px; }
.pp-checks-remain{ font:600 12px var(--font); color:var(--violet); white-space:nowrap; }
.pp-checks-remain.is-done{ color:var(--ok); }
.pp-checks{ padding:4px 0 6px; }
.pp-check{ display:flex; align-items:center; gap:8px; padding:8px 0; cursor:pointer; font:500 14px var(--font); }
.pp-check.is-done{ color:var(--ink2); }
.pp-check.is-todo{ color:var(--ink); font-weight:600; }
.pp-check-box{ width:18px; height:18px; border-radius:6px; flex:none; display:grid; place-items:center; font-size:11px; border:1.5px solid var(--line2); }
.pp-check.is-done .pp-check-box{ background:var(--ok); border-color:var(--ok); color:#fff; }
@media(prefers-reduced-motion:reduce){
  .pp-checks-sum::after{ transition:background-color .18s; }
}

/* repeatable rows (printers) */
.pp-rep{ display:grid; grid-template-columns:1.4fr .7fr .7fr .5fr auto; gap:8px; margin-bottom:10px; align-items:center; }
.pp-rep-del{ border:none; background:var(--bg2); color:var(--err); width:38px; height:38px; border-radius:12px; cursor:pointer; font-size:18px; flex:none; }
.pp-rep-del .pp-rep-del-txt{ display:none; }
/* phone: model full-width on top, then [tech][bed], then [qty][delete] full-width row */
@media(max-width:480px){
  .pp-rep{
    grid-template-columns:1fr 1fr;
    grid-template-areas:"model model" "tech bed" "qty qty" "del del";
    gap:8px 8px;
    padding:12px; border:1px solid var(--line); border-radius:var(--r);
  }
  .pp-rep > .pp-combo{ grid-area:model; }
  .pp-rep > [data-pk="tech"]{ grid-area:tech; }
  .pp-rep > [data-pk="bed"]{ grid-area:bed; }
  .pp-rep > [data-pk="qty"]{ grid-area:qty; }
  .pp-rep-del{
    grid-area:del; width:100%; height:auto; min-height:40px; border-radius:var(--r);
    display:flex; align-items:center; justify-content:center; gap:6px;
    font:700 14px var(--font);
  }
  .pp-rep-del .pp-rep-del-txt{ display:inline; }
}
.pp-add-btn{
  width:100%; border:1.5px dashed var(--line2); background:#fff; border-radius:var(--r);
  padding:12px; font:700 14px var(--font); color:var(--violet); cursor:pointer; margin-top:4px;
}
.pp-add-btn:hover{ background:rgba(124,92,255,.04); border-color:var(--violet); }

/* printers: пояснение к криптичному полю «рабочий стол» (мелкое, серое) */
.pp-rep-note{ margin:2px 0 8px; font:500 12px var(--font); color:var(--ink2); display:flex; align-items:center; }

/* =====================================================
   Printer combobox — поисковый автокомплит по базе принтеров.
   Обёртка relative; выпадающий listbox absolute поверх строки (карточка не режет).
   ===================================================== */
.pp-combo{ position:relative; min-width:0; }
.pp-combo > .pp-input{ width:100%; }
.pp-combo-list{
  position:absolute; z-index:40; top:calc(100% + 4px); left:0; right:0;
  margin:0; padding:6px; list-style:none;
  background:var(--card); border:1px solid var(--line2); border-radius:var(--r);
  box-shadow:var(--shadow-lg);
  max-height:264px; overflow-y:auto; overscroll-behavior:contain;
}
.pp-combo-list[hidden]{ display:none; }
.pp-combo-opt{
  display:flex; align-items:center; justify-content:space-between; gap:12px;
  min-height:40px; padding:8px 10px; border-radius:10px; cursor:pointer;
  font:600 14px var(--font); color:var(--ink);
}
.pp-combo-opt:hover,
.pp-combo-opt.is-active{ background:var(--bg2); }
.pp-combo-name{ min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.pp-combo-bed{ flex:none; font:500 12px var(--font); color:var(--ink2); font-variant-numeric:tabular-nums; }
.pp-combo-empty{ padding:12px 10px; font:500 13px var(--font); color:var(--ink2); text-align:center; line-height:1.4; }

/* =====================================================
   Reusable info tooltip (?) — hover + focus/tap, a11y.
   Значок рядом с лейблом; пояснение видно при наведении И при фокусе
   (tabindex=0 → работает по тапу на тач-экране). role=tooltip + describedby.
   ===================================================== */
.pp-info{
  position:relative; display:inline-grid; place-items:center; vertical-align:middle;
  width:18px; height:18px; margin-left:5px; border-radius:50%; flex:none;
  background:var(--bg2); color:var(--ink2); font:800 11px var(--font); cursor:help;
  border:1.5px solid var(--line2); transition:background-color .18s, color .18s, border-color .18s;
}
.pp-info:hover, .pp-info:focus-visible{
  background:var(--violet-50); color:var(--violet-700); border-color:var(--violet-200); outline:none;
}
.pp-tip{
  position:absolute; left:50%; top:calc(100% + 8px); z-index:20; transform:translate(-50%,-4px);
  width:min(240px,72vw); padding:9px 12px; border-radius:12px;
  background:var(--ink); color:#fff; font:500 12px var(--font); line-height:1.4; text-align:left;
  box-shadow:var(--shadow); opacity:0; visibility:hidden; pointer-events:none;
  transition:opacity .18s, transform .18s, visibility .18s;
}
.pp-tip::after{
  content:""; position:absolute; bottom:100%; left:50%; transform:translateX(-50%);
  border:5px solid transparent; border-bottom-color:var(--ink);
}
.pp-info:hover .pp-tip, .pp-info:focus .pp-tip, .pp-info:focus-visible .pp-tip{
  opacity:1; visibility:visible; transform:translate(-50%,0);
}
@media(max-width:480px){
  .pp-tip{ left:0; transform:translate(0,-4px); }
  .pp-tip::after{ left:12px; }
  .pp-info:hover .pp-tip, .pp-info:focus .pp-tip, .pp-info:focus-visible .pp-tip{ transform:translate(0,0); }
}
@media(prefers-reduced-motion:reduce){ .pp-tip{ transition:opacity .12s, visibility .12s; } }

/* locked field (Языки — пока только RU) */
.pp-locked{
  display:flex; align-items:center; justify-content:space-between; gap:10px;
  min-height:46px; padding:10px 14px; border-radius:var(--r);
  border:1.5px dashed var(--line2); background:var(--bg2); cursor:not-allowed;
}
.pp-locked-val{ display:inline-flex; align-items:center; gap:8px; font:600 15px var(--font); color:var(--ink2); }
.pp-lang-flag{ font:800 10px var(--font); letter-spacing:.04em; color:#fff; background:var(--violet); border-radius:6px; padding:3px 6px; }
.pp-locked-tag{ font:600 12px var(--font); color:var(--ink2); white-space:nowrap; }

/* material chips — СВОЙ класс .pp-mat-chip (НЕ .pp-toggle: та занята
   switch-компонентом ниже в файле → его width:38px ломал ряд чипов). */
.pp-mat-toggle{ display:flex; flex-wrap:wrap; gap:8px; margin:0 0 12px; }
.pp-mat-chip{
  min-height:40px; display:inline-flex; align-items:center; justify-content:center;
  border:1.5px solid var(--line2); background:#fff; border-radius:var(--pill); padding:0 16px;
  font:700 13px var(--font); color:var(--ink2); cursor:pointer; user-select:none; white-space:nowrap;
  transition:background-color .16s, color .16s, border-color .16s, transform .12s;
}
.pp-mat-chip:hover{ border-color:var(--violet-300); color:var(--ink); }
.pp-mat-chip.is-on{ background:var(--violet-600); color:#fff; border-color:var(--violet-600); }  /* -600 → белый ≥4.5:1 (AA) */
.pp-mat-chip:active{ transform:scale(.96); }
.pp-mat-chip:focus-visible{ outline:2px solid var(--violet); outline-offset:2px; }

/* AMS / мульти-цвет — отдельная широкая карточка-тумблер (не в ряду чипов, не наезжает) */
.pp-mat-ams{
  width:100%; display:flex; align-items:center; gap:12px; text-align:left;
  min-height:56px; margin:0 0 4px; padding:10px 14px; cursor:pointer;
  border:1.5px solid var(--line2); border-radius:var(--r); background:var(--bg2);
  transition:border-color .16s, background-color .16s;
}
.pp-mat-ams:hover{ border-color:var(--violet-300); }
.pp-mat-ams.is-on{ border-color:var(--violet); background:var(--violet-50); }
.pp-mat-ams:focus-visible{ outline:2px solid var(--violet); outline-offset:2px; }
.pp-mat-ams-ico{ font-size:22px; line-height:1; flex:none; }
.pp-mat-ams-txt{ display:flex; flex-direction:column; gap:1px; min-width:0; flex:1; }
.pp-mat-ams-txt b{ font:700 14px var(--font); color:var(--ink); }
.pp-mat-ams-txt small{ font:500 12px var(--font); color:var(--ink2); }
.pp-mat-ams-check{
  flex:none; width:24px; height:24px; border-radius:50%; display:grid; place-items:center;
  border:1.5px solid var(--line2); background:#fff; color:transparent; font:800 13px var(--font);
  transition:background-color .16s, border-color .16s, color .16s;
}
.pp-mat-ams.is-on .pp-mat-ams-check{ background:var(--violet); border-color:var(--violet); color:#fff; }

/* material type multi-select: строка выбранных + quick-чипы + панель «Ещё» */
.pp-mat-selected{ display:flex; flex-wrap:wrap; gap:6px; margin:0 0 10px; }
.pp-mat-empty{ font:500 13px var(--font); color:var(--ink2); padding:6px 2px; }
.pp-mat-tag{
  display:inline-flex; align-items:center; gap:2px; min-height:40px; padding:0 6px 0 14px;
  border-radius:var(--pill); background:var(--violet-600); color:#fff; font:700 13px var(--font);
}
.pp-mat-tag-x{
  width:32px; height:32px; min-width:32px; border:none; border-radius:50%; cursor:pointer;
  display:grid; place-items:center; padding:0; color:#fff; background:rgba(255,255,255,.18);
  font:700 15px/1 var(--font); transition:background-color .14s;
}
.pp-mat-tag-x:hover{ background:rgba(255,255,255,.34); }
.pp-mat-tag-x:focus-visible{ outline:2px solid #fff; outline-offset:1px; }

/* «＋ Ещё материалы» — тихая, вторична к чипам (ghost/dashed, не конкурирует) */
.pp-mat-more{
  min-height:40px; padding:0 16px; border-radius:var(--pill); cursor:pointer; white-space:nowrap;
  border:1.5px dashed var(--line2); background:var(--card); color:var(--violet);
  font:700 13px var(--font); transition:border-color .16s, background-color .16s;
}
.pp-mat-more:hover{ border-color:var(--violet); background:var(--violet-50); }
.pp-mat-more.is-on{ border-style:solid; border-color:var(--violet); background:var(--violet-50); }
.pp-mat-more:focus-visible{ outline:2px solid var(--violet); outline-offset:2px; }

.pp-mat-panel{
  margin:4px 0 12px; padding:14px; border:1.5px solid var(--line2);
  border-radius:var(--r); background:var(--bg2);
}
.pp-mat-panel[hidden]{ display:none; }
.pp-mat-search{ margin:0 0 14px; }
.pp-mat-group{ margin:0 0 14px; }
.pp-mat-group:last-child{ margin-bottom:0; }
.pp-mat-group[hidden]{ display:none; }
.pp-mat-group-h{
  font:700 11px var(--font); letter-spacing:.06em; text-transform:uppercase;
  color:var(--ink2); margin:0 0 8px;
}
.pp-mat-chip[hidden]{ display:none; }
.pp-mat-noresult{ font:500 13px var(--font); color:var(--ink2); text-align:center; padding:8px 0; }
.pp-mat-noresult[hidden]{ display:none; }

/* color pickers — ровная сетка ячеек ≥40px; кастомные удаляемы + «＋ свой цвет» */
.pp-colorpick{ display:grid; grid-template-columns:repeat(auto-fill,40px); gap:8px; margin-top:6px; }
.pp-color-cell{ position:relative; width:40px; height:40px; display:grid; place-items:center; cursor:pointer; }
.pp-colorpick input[type="checkbox"]{ display:none; }
.pp-color-dot{ width:28px; height:28px; border-radius:50%; border:2px solid var(--line2); display:block; box-sizing:border-box; }
.pp-color-cell input:checked + .pp-color-dot,
.pp-color-dot.is-on{ border-color:var(--ink); box-shadow:0 0 0 2px #fff,0 0 0 4px var(--ink); }
.pp-color-del{
  position:absolute; top:-3px; right:-3px; width:18px; height:18px; border-radius:50%;
  border:2px solid var(--card); background:var(--ink); color:#fff; font:700 11px/1 var(--font);
  cursor:pointer; display:grid; place-items:center; padding:0;
}
.pp-color-del:hover{ background:var(--err); }
.pp-color-del::before{ content:""; position:absolute; inset:-11px; border-radius:50%; }  /* невидимый хитбокс ~40px (AA), глиф остаётся 18px */
/* «＋ свой цвет»: свотч-пикер + явная кнопка «Добавить» на своём ряду под палитрой */
.pp-color-add-wrap{ grid-column:1 / -1; display:inline-flex; align-items:center; gap:8px; margin-top:4px; }
.pp-color-swatch{ width:34px; height:34px; padding:0; border:1.5px solid var(--line2); border-radius:9px; background:none; cursor:pointer; flex:none; }
.pp-color-swatch::-webkit-color-swatch-wrapper{ padding:3px; }
.pp-color-swatch::-webkit-color-swatch{ border:none; border-radius:6px; }
.pp-color-swatch::-moz-color-swatch{ border:none; border-radius:6px; }
.pp-color-add-btn{ min-height:36px; padding:0 14px; border-radius:var(--pill); border:1.5px dashed var(--line2);
  background:var(--card); color:var(--violet); font:700 13px var(--font); cursor:pointer; transition:border-color .16s, background-color .16s; }
.pp-color-add-btn:hover{ border-color:var(--violet); background:var(--violet-50); }

/* anti-bypass hint */
.pp-hint{
  background:rgba(255,159,28,.1); border:1px solid rgba(255,159,28,.3);
  border-radius:var(--r); padding:10px 12px; font:500 13px var(--font); color:#9a6500; margin-top:8px;
}
.pp-flag{ background:rgba(255,159,28,.25); border-radius:4px; padding:0 2px; }

/* upload zones */
.pp-drop{
  border:1.5px dashed var(--line2); border-radius:var(--r); background:var(--bg2);
  padding:20px; text-align:center; color:var(--ink2); font:600 13px var(--font); cursor:pointer;
}
.pp-drop:hover{ border-color:var(--violet); color:var(--violet); }
.pp-drop-row{ display:grid; grid-template-columns:1fr 1fr; gap:12px; }
@media(max-width:420px){ .pp-drop-row{ grid-template-columns:1fr; } }

/* role switch (edit) */
.pp-roleswitch{ display:flex; gap:8px; background:var(--bg2); border-radius:var(--pill); padding:4px; margin-bottom:12px; }
.pp-roleswitch button{
  flex:1; border:none; background:transparent; border-radius:var(--pill); padding:10px;
  font:700 14px var(--font); color:var(--ink2); cursor:pointer;
}
.pp-roleswitch button.is-active{ background:#fff; color:var(--ink); box-shadow:var(--shadow); }

/* portfolio gallery edit thumbs */
.pp-port-grid{ display:grid; grid-template-columns:repeat(3,1fr); gap:8px; margin-top:10px; }
.pp-port-grid img{ aspect-ratio:1; object-fit:cover; border-radius:14px; }

/* =====================================================
   TOAST
   ===================================================== */
/* 🔴 ТОСТ = ПОСЛЕДНИЙ КАНАЛ СВЯЗИ. Стоял на z-index:100 — ПОД подложкой модалки
   (.pp-modal-back z-120 + backdrop-filter:blur(3px)), поэтому любое сообщение об ошибке
   внутри открытой модалки было нечитаемо ПО ПОСТРОЕНИЮ: 45 нажатий «Сохранить» без единой
   видимой причины отказа (инцидент 30.08). Теперь --z-toast (10060) — выше медиа-редактора
   (10050), самого верхнего экрана сервиса. pointer-events:none → верхний слой ничего не
   перехватывает по кликам. Шкала слоёв целиком — tokens.css, блок «Z-СЛОИ».
   bottom: + --bs-bottom-reserve — тост не встаёт под мобильную панель разделов /
   cookie-плашку (тот же приём, что у .bs-toasts и .cm-toasts).
   Плотность D0: одна строка = 10+10 паддинг + 19.6 текст ≈ 40px (потолок шкалы контролов);
   радиус --rad-xl (22px) на однострочном 40px-теле CSS сам клампит до 20px = ТА ЖЕ пилюля,
   что была, но многострочный текст сервера уже не выгибается лозенгом.
   Длинный detail: max-width 420px (десктоп) / calc(100vw-32px) (360px → 328), перенос
   сбалансирован, потолок 4 строки с многоточием — сообщение читаемо и не раздувается.
   🔴 Центрируем margin-inline:auto, а НЕ left:50%+translateX. Причина замерена: у fixed-блока
   с left:50% доступная ширина = (вьюпорт − left) = 50vw, поэтому shrink-to-fit НИКОГДА не давал
   тосту больше половины экрана — на 360px это 180px, и фраза сервера превращалась в узкий
   столбик из обрезанных строк. left:0/right:0 + auto-поля дают полный вьюпорт, центр тот же. */
.pp-toast{
  position:fixed; left:0; right:0; margin-inline:auto; width:fit-content;
  bottom:calc(110px + env(safe-area-inset-bottom,0px) + var(--bs-bottom-reserve,0px));
  transform:translateY(20px);
  background:var(--ink); color:#fff; font:600 14px/1.4 var(--font); padding:10px 16px;
  border-radius:var(--rad-xl,22px); box-shadow:var(--shadow-lg); z-index:var(--z-toast,10060); opacity:0;
  transition:opacity .25s, transform .25s cubic-bezier(.34,1.56,.64,1); pointer-events:none;
  max-width:min(420px, calc(100vw - 32px)); text-align:center; text-wrap:balance;
  overflow-wrap:anywhere;
  display:-webkit-box; -webkit-box-orient:vertical; -webkit-line-clamp:4; line-clamp:4; overflow:hidden;
}
.pp-toast.is-show{ opacity:1; transform:translateY(0); }
/* причина отказа ≠ нейтральное «Сохранено»: тёмно-розовая подложка + rose-рамка.
   Цвет НЕ единственный сигнал — сам текст называет причину (WCAG «color-not-only»);
   белый на --rose-900 = контраст ≈10:1 (AA с запасом). */
.pp-toast.is-err{ background:var(--rose-900,#6E1922);
  box-shadow:var(--shadow-lg), inset 0 0 0 1px var(--rose-500,#FF4D5E); }
@media (prefers-reduced-motion:reduce){
  .pp-toast{ transition:opacity .12s linear; transform:none; }
  .pp-toast.is-show{ transform:none; }
}

/* spacer above sticky cta so content not hidden */
.pp-bottom-pad{ height:88px; }   /* очищает фиксированный нижний save-бар, чтобы он не перекрывал последнее поле */

/* section spacing helper */
.pp-mt0{ margin-top:0; }
.pp-divider{ height:1px; background:var(--line); margin:14px 0; }

/* desktop polish */
@media(min-width:768px){
  body{ font-size:15.5px; }
  .pp-name{ font-size:24px; }
}

/* =====================================================
   KLIKKO MASCOT — brand companion (Duolingo-moment)
   White rabbit w/ teal ears, transparent PNG → soft drop-shadow.
   ===================================================== */

/* pop-scale used when a pose swaps in */
@keyframes pp-klikko-pop{
  0%  { transform:scale(.6) rotate(-6deg); opacity:0; }
  60% { transform:scale(1.08) rotate(2deg); }
  100%{ transform:scale(1) rotate(0); opacity:1; }
}
@keyframes pp-klikko-float{
  0%,100%{ transform:translateY(0); }
  50%    { transform:translateY(-4px); }
}

/* --- onboarding companion: Klikko + speech bubble next to the bar --- */
.pp-klikko{
  display:flex; align-items:center; gap:12px; margin-bottom:12px;
}
.pp-klikko-img{
  width:64px; height:64px; flex:none; object-fit:contain;
  filter:drop-shadow(0 8px 14px rgba(124,92,255,.22));
  animation:pp-klikko-pop .5s cubic-bezier(.34,1.56,.64,1) both;
}
/* retrigger on pose change */
.pp-klikko-img.is-pop{ animation:pp-klikko-pop .5s cubic-bezier(.34,1.56,.64,1) both; }
.pp-klikko-bubble{
  position:relative; flex:1; min-width:0;
  background:#fff; border:1.5px solid var(--line); border-radius:var(--r);
  box-shadow:var(--shadow); padding:10px 13px;
  font:600 13px var(--font); color:var(--ink); line-height:1.35;
  animation:pp-klikko-pop .4s cubic-bezier(.34,1.56,.64,1) both;
}
/* speech-bubble tail pointing at Klikko */
.pp-klikko-bubble::before{
  content:""; position:absolute; left:-9px; top:50%; margin-top:-8px;
  width:16px; height:16px; background:#fff;
  border-left:1.5px solid var(--line); border-bottom:1.5px solid var(--line);
  transform:rotate(45deg); border-bottom-left-radius:3px;
}
@media(max-width:560px){
  .pp-klikko{ gap:10px; }
  .pp-klikko-img{ width:52px; height:52px; }
  .pp-klikko-bubble{ font-size:12.5px; padding:9px 11px; }
}

/* --- showcase accent: Klikko peeking at a section title --- */
.pp-title-klikko{ position:relative; padding-right:52px; }
.pp-klikko-peek{
  position:absolute; right:-2px; top:50%; width:46px; height:46px;
  transform:translateY(-58%) rotate(6deg); object-fit:contain;
  filter:drop-shadow(0 6px 10px rgba(124,92,255,.2));
  animation:pp-klikko-float 4s ease-in-out infinite; pointer-events:none;
}

/* --- empty / loading / error states with Klikko --- */
.pp-empty{
  display:flex; flex-direction:column; align-items:center; text-align:center;
  gap:6px; padding:24px 12px 12px;
}
.pp-empty-img{
  width:96px; height:96px; object-fit:contain;
  filter:drop-shadow(0 10px 16px rgba(124,92,255,.18));
  animation:pp-klikko-pop .5s cubic-bezier(.34,1.56,.64,1) both;
}
.pp-empty-img.is-loading{ animation:pp-klikko-float 1.4s ease-in-out infinite; }
.pp-empty-title{ font:800 15px var(--font-display); letter-spacing:-.01em; color:var(--ink); }
.pp-empty-sub{ font:500 13px var(--font); color:var(--ink2); max-width:280px; }

/* =====================================================
   MASTER PROFILE — LEFT-ANCHOR ШАПКА + 5 ВКЛАДОК (redesign 2026-07-17, ux-pro spec)
   Одноколоночная раскладка: старый грид 340/1fr снят. ВСЕ left-anchor правила скоупнуты на
   .pp-col-master → renderCustomer/renderSupplier (их центрированные .pp-name/.pp-tag/
   .pp-avatar-wrap) НЕ задеты. .pp-head/.pp-side/.pp-main остаются display:contents
   (layout-transparent); .pp-side убрана из разметки (её грид-правила удалены).
   ===================================================== */
.pp-head, .pp-side, .pp-main{ display:contents; }
@media(min-width:960px){
  .pp-col-master{ display:block; }
}

/* [1] ЦЕНТР-СТЕК ИДЕНТИЧНОСТИ — аватар ПО ЦЕНТРУ с наплывом на нижнюю кромку обложки
   (правило владельца 2026-08-25; логика маркетплейса, где поиск сажается на кромку баннера
   через `.pp-mk-search-seat{ margin:-26px auto 0 }` — тот же приём, тот же ярус z).
   БЫЛО: мастер — ЕДИНСТВЕННОЕ исключение в сервисе. Базовое `.pp-avatar-wrap{margin:-46px auto 0}`
   уже центрировано (по нему живут заказчик и поставщик), а `.pp-col-master` перебивал его на
   `margin:-40px 0 0` → левый якорь + два ряда «identity ↔ actions». Из-за этого шапка мастера
   разъезжалась сама с собой: аватар и имя слева, а tagline ниже — по центру.
   СТАЛО: оверрайд снят, шапка честно перекомпонована в вертикальный центр-стек
   аватар → имя → мета → действия (канон VK/Instagram-профиля, §1.5 Якоб). Не «аватар,
   брошенный посреди строки»: центрируются ВСЕ ярусы шапки, ритм один.
   ЧИСЛА (D0): аватар 100px, наплыв −52px (52% тела в обложке), аватар→имя 12px,
   имя→мета 6px, мета→действия 12px, высота действий 40px. Всё — шаги 4px-сетки. */
.pp-col-master{ max-width:var(--page-max); }
.pp-col-master .pp-avatar-wrap{ margin:-52px auto 0; }
.pp-col-master .pp-name{ text-align:center; white-space:normal; letter-spacing:-.02em; color:var(--pp-ink); }
.pp-col-master .pp-name .vf{ display:inline-block; vertical-align:-.12em; margin-left:.28em; color:var(--violet); width:19px; height:19px; }
/* idrow = вертикальная ось шапки (был горизонтальный ряд). Порядок DOM аватар → idcluster
   уже верный, поэтому центровка — чистый CSS: разметка profile.js и SSR-шаблона
   profile_ssr.html не меняется и остаётся бит-в-бит параллельной. */
.pp-idrow{ display:flex; flex-direction:column; align-items:center; padding:0 0 4px; }
/* idcluster = внутренний стек identity → actions. Один row-gap держит ритм (у .pp-acts
   своего margin нет), align-items:center — общая ось с аватаром. */
.pp-idcluster{ width:100%; min-width:0; display:flex; flex-direction:column; align-items:center; gap:12px; }
/* margin-top — не «воздух», а клиренс под чип очков: .pp-points висит на bottom:-8px и без
   зазора наехал бы на имя. Без чипа те же 12px читаются как обычный шаг сетки. */
.pp-idblock{ min-width:0; max-width:100%; margin-top:12px; text-align:center; }
.pp-nameline{ display:flex; align-items:center; justify-content:center; min-width:0; }
.pp-col-master .pp-nameline .pp-name{ margin:0; }   /* база .pp-name = margin:16px 0 2px → гасим */
.pp-meta{ display:flex; align-items:center; justify-content:center; flex-wrap:wrap; gap:6px; font-size:13px; font-weight:500; line-height:1; color:var(--ink2); margin-top:6px; }
.pp-meta-dot{ color:var(--pp-t3); }
/* Соц-счётчики живут в ЦЕНТР-стеке шапки. База `.pp-social` — просто flex-ряд без выравнивания,
   поэтому в центрированной колонке заказчика/поставщика он ОДИН уезжал к левому краю трека
   (имя по центру, «12 подписчиков» у левого ребра 1328px) — из-за этого шапка и читалась
   «сломанной». Одно правило центрирует обе шапки; у мастера узел появился только сейчас
   (раньше входа в «Подписки» у него не было вовсе). */
.pp-col > .pp-social,
.pp-col-master .pp-social{ justify-content:center; }
.pp-col-master .pp-social{ margin:8px 0 0; }
/* actions = НИЖНИЙ ярус стека, РАЗВЕДЁН ПО КРАЯМ ТРЕКА (правило владельца 2026-08-25 №3:
   «под авой кнопки разнеси на лево и право — как у нас с маркетплейсом»).
   МЕХАНИКА — ровно та же, что в control-bar маркетплейса `.pp-mk-toolbar`: там правый якорь
   отжимается `.pp-mk-sort{margin-left:auto}`, здесь зеркально — `margin-right:auto` на ПЕРВОМ
   элементе. Поэтому раскладка целиком на CSS: разметка profile.js и profile_ssr.html не
   меняется (группы-обёртки не нужны), паритет первого и второго кадра сохраняется сам.
   ПОЧЕМУ ТРЕК = ВСЯ КОНТЕНТ-ШИРИНА, а не «узкая полоса под именем»: якорь работает только
   когда делит РЕБРО с реальным соседом. Здесь левый край ряда == левый край .pp-cover ==
   левый край первой вкладки, правый == правый край обложки (замер 1440: 56 / 1384 у всех
   трёх). Проверенная альтернатива с max-width 840 висит в воздухе, не совпадая ни с чем, —
   это и есть «оторванный ряд», её отклонил.
   СЕМАНТИКА разведения (не декор, а два смысловых якоря — как «что смотрим» ↔ «как смотрим»
   в маркетплейсе): СЛЕВА — главное действие (гость: «Заказать печать»; хозяин:
   «Редактировать»), СПРАВА — сгруппированное второстепенное (гость: подписка+контакт;
   хозяин: «Поделиться» + overflow `⋯`). Один primary в кадре, тиры веса не тронуты.
   nowrap: ряд физически влезает в трек на всех ширинах вплоть до 320px (замер: 252.7 ≤ 288). */
.pp-acts{ width:100%; display:flex; flex-wrap:nowrap; justify-content:flex-start; gap:8px; align-items:center; }
/* Якорь разведения СКОУПНУТ НА МАСТЕРА. Приём работает, только когда ряд делит ребро с реальным
   соседом: у мастера левый край == левый край обложки == левый край первой вкладки, правый ==
   правое ребро обложки (замер 1440: 56 / 1384 у всех трёх ярусов) — таб-бар прямо под рядом
   ПОВТОРЯЕТ ту же линию, и ряд читается как control-bar.
   У ЗАКАЗЧИКА и ПОСТАВЩИКА таб-бара нет: владельческий кластер — прямой ребёнок .pp-col и висит
   между центрированными стикерами и первой карточкой. Разведённый по краям 1328px-трека он
   распадался на два острова с ~1000px пустоты посередине — при том, что вся шапка над ним (имя,
   чипы, соц-счётчики, стикеры) центрирована по одной оси. Замер и осмотр на трёх ролях:
   у мастера приём держится соседним ребром, у не-мастера — нет. Поэтому там кластер живёт
   ЦЕНТРИРОВАННОЙ группой на общей оси шапки (Гештальт-близость: связанные кнопки рядом). */
.pp-col-master .pp-acts > :first-child{ margin-right:auto; }
.pp-col > .pp-acts{ justify-content:center; }
.pp-acts .pp-btn{ width:auto; min-height:40px; padding:0 15px; font-size:14px; white-space:nowrap; }
/* icon-only действие в кластере (Поделиться): квадрат 40×40 по сетке, а тап-зона добирается
   до 44×44 псевдо-элементом — раздувать видимое тело кнопки ради тач-таргета нельзя (D0). */
.pp-acts .pp-act-ico{ position:relative; width:40px; padding:0; }
.pp-acts .pp-act-ico::before{ content:""; position:absolute; inset:-2px; }
@media(max-width:640px){
  .pp-col-master .pp-acts{ display:none; }          /* роль гостевых действий берёт .pp-sticky-cta */
  .pp-col-master .pp-acts.is-own{ display:flex; }   /* владельцу sticky-бар не рендерится → вход в редактор живёт в шапке */
}

/* ── ВЛАДЕЛЬЧЕСКИЙ КЛАСТЕР: [Редактировать] · [Поделиться] · [⋯ Ещё] ────────────────
   Кластер общий для мастера/поставщика/заказчика (у последних двух он прямой ребёнок
   .pp-col — оттого свой отступ сверху). Меню «Ещё» — details-поповер того же покроя,
   что фильтр CRM (.pp-crm-filter): нативный toggle, клавиатура из коробки, ноль
   hover-only входов; на тач открывается тапом. */
.pp-col > .pp-acts.is-own{ margin-top:var(--sp-3); }
.pp-own-more{ position:relative; flex:none; }
.pp-own-more > summary{
  list-style:none; cursor:pointer; display:inline-flex; align-items:center; justify-content:center;
  gap:6px; position:relative; height:40px; padding:0 14px; border:1.5px solid var(--line2);
  border-radius:var(--pill); background:var(--card); color:var(--ink2); font:700 14px var(--font);
}
.pp-own-more > summary::-webkit-details-marker{ display:none; }
.pp-own-more > summary::before{ content:""; position:absolute; inset:-2px; }   /* тап-зона 44 */
.pp-own-more > summary:hover{ color:var(--ink); border-color:var(--violet-200); }
/* открытое состояние: рамка бренд-violet, а ТЕКСТ на ступень темнее (--violet-700 = 7.1:1
   на белом; чистый --violet даёт 4.33:1 — под порогом AA для 14px). */
.pp-own-more[open] > summary{ border-color:var(--violet); color:var(--violet-700); }
.pp-own-more > summary:focus-visible{ outline:2px solid var(--violet); outline-offset:2px; }
.pp-own-menu{
  position:absolute; right:0; top:calc(100% + 6px); z-index:50; min-width:236px;
  background:var(--card); border:1px solid var(--line2); border-radius:var(--rad-md);
  box-shadow:var(--shadow); padding:6px; display:flex; flex-direction:column; text-align:left;
}
.pp-own-menu a{
  display:flex; align-items:center; gap:10px; min-height:38px; padding:8px 10px;
  border-radius:var(--rad-sm); font:600 var(--fs-sm) var(--font); color:var(--ink);
  text-decoration:none; white-space:nowrap;
}
.pp-own-menu a:hover{ background:var(--bg2); }
.pp-own-menu a:focus-visible{ outline:2px solid var(--violet); outline-offset:-2px; }
.pp-own-menu a .pp-ic{ color:var(--ink2); flex:none; }
.pp-own-menu hr{ border:0; border-top:1px solid var(--line); margin:6px 4px; }
/* появление меню — 120ms ease-out «из-под кнопки» (причина→следствие, не декор) */
.pp-own-more[open] > .pp-own-menu{ animation:pp-own-pop .12s ease-out; }
@keyframes pp-own-pop{ from{ opacity:0; transform:translateY(-4px); } to{ opacity:1; transform:none; } }
@media(prefers-reduced-motion:reduce){ .pp-own-more[open] > .pp-own-menu{ animation:none; } }
@media(max-width:479px){
  /* узкий экран: у «Ещё» остаётся глиф (кластер должен влезать в один ряд рядом с primary) */
  .pp-own-more-lbl{ display:none; }
  .pp-own-more > summary{ width:40px; padding:0; }
}
/* Хак «ужать primary на 320px» УДАЛЁН: он был нужен, пока ряд был слитной центрированной
   группой и на узком экране не влезал в контент. С разведением по краям ряд занимает
   164.7+88=252.7 при треке 288 — влезает штатно, ужимать нечего. */

/* [5] TAGLINE — центр + брендовые точки-буллеты (перекрыт базовый .pp-tag под .pp-col-master) */
.pp-col-master .pp-tag{ display:flex; align-items:center; gap:10px; width:fit-content; max-width:100%; margin:12px auto 16px; }
.pp-col-master .pp-tag::before, .pp-col-master .pp-tag::after{ content:""; flex:none; width:7px; height:7px; border-radius:50%; background:var(--grad-hero); }
.pp-col-master .pp-tag p{ margin:0; min-width:0; font-size:15px; line-height:1.5; color:var(--ink2); text-align:center; font-family:var(--font); }
@media(max-width:640px){
  .pp-col-master .pp-tag{ gap:8px; }
  .pp-col-master .pp-tag p{ font-size:14px; }
}

/* [2+3] ВКЛАДКИ (sticky top:56px — прямо под платформенным .pp-nav h56, не top:0) */
.pp-tabs{ position:sticky; top:56px; z-index:40; background:color-mix(in srgb,var(--bg) 90%,transparent); backdrop-filter:blur(10px); -webkit-backdrop-filter:blur(10px); border-bottom:1px solid var(--line); margin-top:8px; }
.pp-tabs-in{ max-width:var(--page-max); margin:0 auto; padding:0 16px; display:flex; gap:20px; overflow-x:auto; scrollbar-width:none; }
.pp-tabs-in::-webkit-scrollbar{ display:none; }
.pp-tab{ white-space:nowrap; font-weight:600; font-size:14px; color:var(--ink2); background:none; border:none; padding:12px 2px; cursor:pointer; position:relative; display:flex; align-items:center; gap:.4rem; font-family:var(--font); }
.pp-tab .pp-c{ font-size:12px; font-weight:600; color:var(--pp-t3); font-variant-numeric:tabular-nums; }
.pp-tab.on{ color:var(--pp-ink); }
.pp-tab.on .pp-c{ color:var(--violet); }
.pp-tab.on::after{ content:""; position:absolute; left:0; right:0; bottom:-1px; height:2px; background:var(--violet); border-radius:2px; }
.pp-panel{ padding-top:16px; }

/* рейтинг-ссылка в meta + newbadge (СКОУП на .pp-meta — базовый .pp-newbadge для customer НЕ трогаем) */
.pp-rating{ display:inline-flex; align-items:center; gap:5px; text-decoration:none; color:var(--ink2); }
.pp-rating .pp-star, .pp-star{ width:15px; height:15px; color:var(--pp-star); flex:none; }
.pp-rating b{ font-weight:500; color:var(--ink2); font-variant-numeric:tabular-nums; }
.pp-rating:hover b{ text-decoration:underline; }
.pp-col-master .pp-meta .pp-newbadge{ margin:0; border:0; font:600 12px var(--font); color:var(--violet); background:var(--violet-soft,rgba(124,92,255,.1)); border-radius:999px; padding:2px 9px; }

/* [4] «О МАСТЕРЕ» BENTO — класс .pp-about-bento (НЕ .pp-about: та занята <p> в customer/supplier) */
.pp-about-bento{ background:var(--card); border:1px solid var(--line); border-radius:var(--r); padding:32px; display:grid; grid-template-columns:1.1fr 0.9fr; column-gap:32px; }
.pp-about-bento.is-single{ grid-template-columns:1fr; }   /* нет правой колонки → одноколоночно, без висящего дивайдера */
.pp-about-l{ border-right:1px solid var(--line); padding-right:32px; }
.pp-about-bento.is-single .pp-about-l{ border-right:0; padding-right:0; }
.pp-about-r > div + .pp-hr{ margin:22px 0; }
.pp-hr{ height:1px; background:var(--line); }
.pp-since{ margin-top:12px; padding-top:12px; border-top:1px solid var(--line); font-size:12px; color:var(--pp-t3); font-variant-numeric:tabular-nums; }
.pp-oh{ font-size:12.5px; font-weight:600; color:var(--ink2); text-transform:uppercase; letter-spacing:.05em; margin:0 0 10px; }
.pp-about-prose{ max-width:60ch; margin:0 0 18px; }
.pp-skills{ margin-bottom:4px; }
.pp-about-bento .pp-pill{ font-weight:600; font-size:13px; color:var(--ink2); border:1px solid var(--line); border-radius:999px; padding:5px 12px; display:inline-block; margin:0 6px 6px 0; }
.pp-about-bento .pp-swatch{ display:inline-flex; gap:7px; vertical-align:middle; width:auto; height:auto; border:0; }   /* контейнер, не одиночный кружок */
.pp-about-bento .pp-swatch i{ width:20px; height:20px; border-radius:50%; border:1px solid var(--line); display:inline-block; }
.pp-ams-pill{ display:inline-block; font:600 10px var(--font); color:var(--violet); background:var(--violet-soft,rgba(124,92,255,.1)); border-radius:999px; padding:2px 7px; margin-left:6px; vertical-align:middle; letter-spacing:0; text-transform:none; }
.pp-about-r .pp-mp-row{ display:flex; align-items:center; gap:8px; flex-wrap:wrap; margin:8px 0; }
.pp-about-r .pp-mp-model{ font:600 14px var(--font); color:var(--ink); }
.pp-about-r .pp-mp-bed{ font:500 12.5px var(--font); color:var(--ink2); }
.pp-about-r .pp-mp-row .pp-tech{ margin-left:auto; }
.pp-about-r .pp-mp-mat{ display:flex; align-items:center; gap:10px; flex-wrap:wrap; margin:8px 0; }
@media(max-width:768px){
  .pp-about-bento{ grid-template-columns:1fr; padding:22px; }
  .pp-about-l{ border-right:0; padding-right:0; border-bottom:1px solid var(--line); padding-bottom:22px; margin-bottom:22px; }
}

/* =====================================================
   AUTH (вход / регистрация) — страница /account.html (P1)
   ===================================================== */
.pp-auth-wrap{
  min-height:calc(100vh - 64px);min-height:calc(100dvh - 64px);
  display:grid; place-items:center; padding:24px 16px 64px;
}
.pp-auth-card{
  width:100%; max-width:420px; background:var(--card);
  border-radius:var(--r); box-shadow:var(--shadow);
  border:1px solid var(--line2); padding:28px 24px;
}
.pp-auth-klikko{ display:block; width:84px; height:auto; margin:0 auto 10px; }
/* ── Эффект глубины «первый/второй план»: маскот выглядывает ИЗ-ЗА карточки ──────────────
   Сцена .pp-auth-stage: заяц (klikko-peek) — ЗАДНИЙ слой (z-index 1), карточка — ПЕРЕДНИЙ
   opaque-слой (z-index 2) и перекрывает нижнюю часть зайца → он выглядывает из-за верхней
   кромки. Маскот position:absolute → ВНЕ вертикального flow: высоту стопки не растит (D0),
   primary-кнопка поднимается в кадр и встаёт НАД cookie-плашкой. Мягкое violet-свечение
   (::before, z-index 0) за головой = «слой/фон» из референса, не баннер-простыня.
   Применяется ТОЛЬКО на /account.html; reset/verify/verify-code используют базовый
   центрированный .pp-auth-klikko (маскот внутри карты, в потоке) — их НЕ трогаем. */
/* padding-top резервирует «карман» под голову зайца НАД картой: заяц absolute top:0 живёт
   в нём, карта следует ниже → на десктопе голова гарантированно ниже верхней nav-полосы
   (не режется), высоту КОНТЕНТА карты padding не трогает. */
.pp-auth-stage{ position:relative; width:100%; max-width:420px; margin-inline:auto; padding-top:100px; }
.pp-auth-stage.is-wide{ max-width:520px; }
.pp-auth-stage > .pp-auth-card{ position:relative; z-index:2; width:100%; max-width:100%; }
/* D0-подрезка вертикали ТОЛЬКО на auth-карточке (reset/verify не трогаем): чтобы primary
   «Зарегистрироваться» встал НАД cookie-плашкой на 900px-вьюпорте. */
.pp-auth-stage > .pp-auth-card{ padding-top:22px; }
.pp-auth-stage .pp-auth-sub{ margin-bottom:14px; }
.pp-auth-stage .pp-auth-tabs{ margin-bottom:14px; }
.pp-auth-stage .pp-oauth-div{ margin:10px 0; }
/* задний план — тёплое violet-свечение за головой зайца (намёк на «слой/фон» из референса) */
.pp-auth-stage::before{
  content:""; position:absolute; z-index:0; left:50%; top:14px;
  width:180px; height:110px; transform:translateX(-50%);
  background:radial-gradient(58% 58% at 50% 44%, var(--violet-100) 0%, rgba(226,222,255,0) 72%);
  pointer-events:none;
}
.pp-auth-stage > .pp-auth-klikko{
  position:absolute; z-index:1; left:50%; top:0;
  width:112px; height:auto; margin:0; transform:translateX(-50%);
  filter:drop-shadow(0 12px 15px rgba(46,26,128,.20));
  pointer-events:none; -webkit-user-select:none; user-select:none;
}
/* ── Мобайл auth: заяц выглядывает ЛИЦОМ (не одними ушами) ────────────────────────────────
   На /account.html снят и нижний таб-бар (<body data-no-tabbar> → tabbar.js не монтируется,
   --bs-tab-h снят, cookie-плашка съезжает к кромке), и верхний ряд у гостя пуст (body.pp-auth-focused
   .pp-nav ниже). Весь верх — под «карман» головы: маскот absolute (в flow НЕ входит, высоту
   не растит — D0), карта — передний opaque-слой, поэтому reveal = высота кармана. Карман ≈78%
   от высоты зайца → над кромкой карты видно ЛИЦО (глаза+щёки), primary держится НАД плашкой.
   Заяц меньше десктопного (на 6″ вертикаль дороже) и МАСШТАБИРУЕТСЯ под высоту экрана:
   короткие режимы (вход/восстановление/письмо) → крупный; ВЫСОКИЕ (регистрация :has(consent)
   и выбор роли :has(.rolepick)) → компактный заяц + плотнее вертикаль, чтобы «Зарегистрироваться»
   осталась НАД cookie-плашкой без скролла (инвариант). :has не поддержан (очень старый браузер) →
   высокий режим отыграет крупный карман: primary впритык к плашке, но экран рабочий. */
@media(max-width:640px){
  /* короткие режимы — крупный заяц (пара пиксель-в-пиксель: карман = ширина зайца → reveal ~78%) */
  .pp-auth-stage{ padding-top:84px; }
  .pp-auth-stage > .pp-auth-card{ padding-top:14px; }
  .pp-auth-stage .pp-auth-sub{ margin-bottom:8px; }
  .pp-auth-stage .pp-auth-tabs{ margin-bottom:10px; }
  .pp-auth-stage .pp-field{ margin-bottom:9px; }
  .pp-auth-stage .pp-oauth-div{ margin:8px 0; }
  .pp-auth-stage > .pp-auth-klikko{ width:84px; top:0; }
  .pp-auth-stage::before{ top:6px; width:120px; height:84px; }

  /* высокие экраны (регистрация + выбор роли): компактнее заяц/карман + плотнее вертикаль */
  .pp-auth-stage:has([data-accept]),
  .pp-auth-stage:has(.rolepick){ padding-top:56px; }
  .pp-auth-stage:has([data-accept]) > .pp-auth-klikko,
  .pp-auth-stage:has(.rolepick) > .pp-auth-klikko{ width:56px; }
  .pp-auth-stage:has([data-accept])::before,
  .pp-auth-stage:has(.rolepick)::before{ top:4px; width:90px; height:60px; }
  .pp-auth-stage:has([data-accept]) > .pp-auth-card{ padding-bottom:18px; }
  .pp-auth-stage:has([data-accept]) .pp-auth-title{ font-size:22px; margin-bottom:2px; }
  .pp-auth-stage:has([data-accept]) .pp-auth-card .pp-btn-primary{ min-height:48px; }
  .pp-auth-stage:has([data-accept]) .pp-auth-alt{ margin-top:12px; }
}
/* ── Верхний ряд на auth-мобиле: держим ЧИСТЫМ (как было при таб-баре) ────────────────────
   Пока таб-бар был смонтирован, html[data-tabbar="on"] .pp-nav гасил 56px-полосу у гостя
   (бренд+бургер уезжали в панель). Сняли таб-бар → этот предохранитель отключился и полоса
   ожила бы, съев ровно ту вертикаль, что мы освобождаем под голову зайца. Возвращаем чистый
   верх ТОЛЬКО на фокус-экране входа (body.pp-auth-focused, account.html) и ТОЛЬКО на мобиле:
   гость входит в узкую воронку, глобальная навигация ему тут не нужна (mobile-nav: на экране
   входа нижней/верхней навигации разделов нет). ⚠️ Скоуп по КЛАССУ, а не по data-no-tabbar —
   его же ставит мессенджер, а ему верхний ряд нужен. Десктоп (>560) не трогаем: полная шапка. */
@media(max-width:560px){
  body.pp-auth-focused .pp-brand{ display:none; }
  body.pp-auth-focused .pp-nav-cta{ display:none; }
  body.pp-auth-focused .pp-nav{
    position:static; height:auto; min-height:0; padding:0;
    background:none; border-bottom:0;
  }
}
.pp-auth-title{ font:800 24px var(--font-display); letter-spacing:-.02em; color:var(--ink); text-align:center; margin:0 0 4px; }
.pp-auth-sub{ font:500 14px var(--font); color:var(--ink2); text-align:center; margin:0 0 20px; }
.pp-auth-tabs{ display:flex; gap:6px; background:var(--bg2); border-radius:var(--pill); padding:4px; margin-bottom:20px; }
.pp-auth-tabs button{
  flex:1; border:none; background:none; cursor:pointer; padding:9px 10px;
  border-radius:var(--pill); font:700 14px var(--font); color:var(--ink2);
}
.pp-auth-tabs button.is-active{ background:#fff; color:var(--ink); box-shadow:var(--shadow); }
.pp-auth-err{
  background:rgba(255,77,94,.10); color:#d23048; border:1px solid rgba(255,77,94,.30);
  border-radius:14px; padding:10px 12px; font:600 13px var(--font); margin-bottom:14px;
}
.pp-auth-card .pp-btn{ width:100%; margin-top:6px; }

/* ── .pp-linkbtn — текст-ссылка, но СЕМАНТИЧЕСКИ кнопка (a11y #142) ────────────────────
   Интерактивные «ссылки» auth-экрана были <a> без href → Tab их пропускал, скринридер
   не звал кнопкой, сброс пароля с клавиатуры был недостижим вообще (мышь работала —
   click-хендлер есть). Теперь это <button type="button" class="pp-linkbtn">: нативная
   клавиатура (Tab-фокус + Enter/Space) и роль button бесплатно, те же data-хендлеры.
   Класс = чистый сброс button-хрома; цвет/вес/подчёркивание НАСЛЕДУЮТСЯ от контекста
   (.pp-auth-alt / .pp-auth-err-act / инлайн), поэтому ВИД текст-ссылок не меняется (D0).
   Видимый focus-ring обязателен (WCAG 2.4.7). Переиспользуемо вне auth. */
.pp-linkbtn{
  -webkit-appearance:none; appearance:none;
  display:inline; margin:0; padding:0; border:0; background:none;
  font:inherit; color:inherit; text-align:inherit; letter-spacing:inherit;
  vertical-align:baseline; cursor:pointer;
}
.pp-linkbtn:focus-visible{ outline:2px solid var(--violet); outline-offset:2px; border-radius:4px; }

.pp-auth-alt{ text-align:center; font:500 13px var(--font); color:var(--ink2); margin-top:16px; }
/* включаем и <button class=pp-linkbtn> (a11y #142): свитч login↔register и «← ко входу» */
.pp-auth-alt a, .pp-auth-alt .pp-linkbtn{ color:var(--violet); font-weight:700; text-decoration:none; cursor:pointer; }
/* Действия ВНУТРИ err-плашки («Войти» · «Восстановить пароль» · «Отправить письмо ещё раз»).
   Были тремя копиями одного инлайн-блоба в account.js (showTakenEmailErr + две ветки
   handleOauthQuery) — вынесены в класс (§2 Atomic: не плодить дубликат).
   Цвет — rose-800 (#A82838 на подложке плашки = 6.2:1, AA); наследуемый #d23048 давал
   4.37:1 и не проходил на 13px. */
.pp-auth-err-act{ display:block; margin-top:8px; font-size:13px; }
/* и <button class=pp-linkbtn> (a11y #142): «Войти»/«Восстановить пароль»/«Отправить ещё раз» */
.pp-auth-err-act a, .pp-auth-err-act .pp-linkbtn{ color:var(--rose-800); font-weight:700; text-decoration:underline;
  text-underline-offset:2px; cursor:pointer; }
.pp-auth-err-act a:hover, .pp-auth-err-act .pp-linkbtn:hover{ text-decoration-thickness:2px; }
.pp-auth-err-act a:focus-visible, .pp-auth-err-act .pp-linkbtn:focus-visible{ outline:2px solid var(--rose-800); outline-offset:2px; border-radius:4px; }

/* ── Соц-вход (Яндекс ID / VK ID) — слот под формой в режимах login/register ─────────────
   Иерархия §14.A: primary в кадре ОДИН — submit формы (.pp-btn-primary, 52px, заливка
   градиентом). Провайдеры = SECONDARY тир: переиспользуем общий .pp-btn/.pp-btn-secondary
   и ужимаем ТОЛЬКО плотность (40px / 44 на тач), а не заводим третий «почти такой же»
   вид кнопки (§2 Atomic + D0). Разница 52 vs 40 + заливка vs контур = иерархия читается
   размером и весом, а не цветом. */
.pp-oauth-div{
  display:flex; align-items:center; gap:10px;
  /* SOCIAL-FIRST: «или» — РАЗДЕЛИТЕЛЬ между блоком соцсетей (сверху) и email-формой
     (снизу), поэтому зазор симметричный: он не принадлежит ни одной из групп */
  margin:12px 0; font:600 var(--fs-xs,12px)/1 var(--font); color:var(--ink2);
}
.pp-oauth-div::before, .pp-oauth-div::after{ content:""; flex:1 1 auto; height:1px; background:var(--line2); }
.pp-oauth{ display:flex; flex-direction:column; gap:var(--sp-2,8px); }
/* перебиваем .pp-auth-card .pp-btn{margin-top:6px} — внутри группы ритм держит gap */
.pp-auth-card .pp-oauth .pp-btn{ width:100%; margin-top:0; }
/* Знак ПРИБИТ влево, подпись центрирована. При centered-группе (иконка+текст одним
   блоком) знаки двух кнопок встают на РАЗНЫЕ x — подписи разной длины, колонка марок
   получается рваной. Симметричный padding 44px резервирует место под знак с обеих
   сторон: подпись остаётся по центру (под центрированным primary), знаки — в колонку. */
.pp-oauth-btn{
  position:relative; min-height:40px; padding:0 44px; gap:0;
  font:600 var(--fs-sm,14px)/1.2 var(--font);
  transition:border-color .15s, background .15s, transform .15s;
}
/* Кнопка ВСЕГДА живая и полноцветная — никакого disabled-призрака. Серая кнопка на
   opacity .45 читалась как «функции нет / сломано» (претензия владельца 26.08), а не
   как «сначала прими оферту»; гейт согласий переехал на клик (revealConsentGate). */
@media (hover:hover){
  .pp-oauth-btn:hover{ border-color:var(--violet); background:var(--violet-50); }
}
.pp-oauth-btn:active{ transform:translateY(1px); }
.pp-oauth-btn:focus-visible{ outline:2px solid var(--violet); outline-offset:2px; }
/* знак провайдера — чужая бренд-марка, размер фиксируем тут (svg без width схлопнулся бы в 0);
   центр по вертикали через top/bottom+margin:auto, БЕЗ transform — чтобы не конфликтовать
   с transform:translateY(1px) на :active самой кнопки */
.pp-oauth-mark{ position:absolute; left:14px; top:0; bottom:0; margin:auto 0; width:18px; height:18px; }

/* Плашка «почему клик не сработал» (регистрация). В покое 0px — появляется ТОЛЬКО после
   клика по соцсети без отметки согласий и уходит, как только галку отметили: постоянный
   хинт был бы шумом на экране, где 90% времени он не нужен. Тон — тот же violet-50/100,
   что у шага акцепта .rolepick-gate на этом же экране: один язык у двух гейтов согласия. */
.pp-oauth-note{
  display:flex; align-items:flex-start; gap:7px;
  margin:8px 0 0; padding:7px 10px;
  border:1px solid var(--violet-100); border-radius:var(--rad-md,12px);
  background:var(--violet-50); color:var(--ink2);
  font:500 var(--fs-xs,12px)/1.4 var(--font); text-align:left;
}
/* [hidden]-guard: авторский display:flex перебивает UA-правило [hidden]{display:none}
   (та же грабля, что .pp-row2[hidden] выше) → без него отмеченная галка НЕ убирала бы плашку. */
.pp-oauth-note[hidden]{ display:none; }
.pp-oauth-note .pp-ic{ margin-top:1px; color:var(--violet-700); }
.pp-oauth-note-link{
  /* зона тапа 27px без роста строки (WCAG 2.5.8): паддинг + отрицательный ТОЛЬКО
     вертикальный margin — горизонтальный воровал бы тапы у соседнего текста */
  border:0; background:none; padding:5px 0; margin:-5px 0;
  font:700 var(--fs-xs,12px)/1.4 var(--font); color:var(--violet-700);
  text-decoration:underline; text-underline-offset:2px; cursor:pointer;
}
.pp-oauth-note-link:hover{ color:var(--violet-800); text-decoration-thickness:2px; }
.pp-oauth-note-link:focus-visible{ outline:2px solid var(--violet); outline-offset:2px; border-radius:4px; }
/* короткая подсветка галки согласий после клика «отметьте согласие выше ↑» */
.pp-auth-card .pp-check.is-gate-flash{
  border-radius:var(--rad-md,12px);
  outline:2px solid var(--violet); outline-offset:3px;
  animation:pp-gate-flash 1.4s ease-out 1;
}
@keyframes pp-gate-flash{ 0%,100%{ background:transparent } 12%,58%{ background:var(--violet-50) } }
@media(max-width:600px){ .pp-oauth-btn{ min-height:44px; } }
@media(prefers-reduced-motion:reduce){
  .pp-oauth-btn{ transition:none; }
  .pp-oauth-btn:active{ transform:none; }
  .pp-auth-card .pp-check.is-gate-flash{ animation:none; background:var(--violet-50); }
}

/* ── Выбор роли сразу после регистрации (account.js roleStepHTML) ──────────────
   Было: инлайн-стили + обе карточки продавца рендерились СЕРЫМИ (disabled/opacity .5),
   а включатель — чекбокс акцепта оферты — лежал под ними мелким юр-текстом. Новичок
   упирался в неработающую кнопку раньше, чем видел причину, и уходил в «Пропустить».
   Стало: карточки живые и равные, акцепт — раскрываемый ШАГ (.rolepick-gate, hidden до
   выбора роли мастера). Значения — токены; тач-таргет карточки заведомо >44px. */
.rolepick{ display:flex; flex-direction:column; gap:var(--sp-2,8px); margin-top:14px; }
.rolepick-card{
  display:flex; gap:12px; align-items:flex-start; text-align:left; width:100%;
  padding:12px 14px; border:1px solid var(--line2); border-radius:var(--rad-lg,16px);
  background:var(--card); color:var(--ink); cursor:pointer;
  transition:border-color .15s, background .15s, transform .15s;
}
/* hover — только для настоящего курсора: на тач :hover залипает после тапа и подсвеченная
   карточка врала бы «выбрано» рядом с настоящим состоянием .is-picked. */
@media (hover:hover){ .rolepick-card:hover{ border-color:var(--violet); background:var(--violet-50); } }
.rolepick-card:focus-visible{ outline:2px solid var(--violet); outline-offset:2px; }
.rolepick-card:active{ transform:translateY(1px); }
/* выбранная роль — рамка+заливка+акцентная иконка (не только цвет: ещё и вес рамки) */
.rolepick-card.is-picked{ border-color:var(--violet); border-width:2px; padding:11px 13px;
  background:var(--violet-50); }
.rolepick-card.is-picked .rolepick-ico{ color:var(--violet); }
.rolepick-ico{ display:flex; flex:0 0 auto; color:var(--ink2); }
.rolepick-txt{ display:flex; flex-direction:column; gap:2px; min-width:0; }
.rolepick-txt b{ font:700 15px var(--font); color:var(--ink); }
.rolepick-txt span{ font:500 13px var(--font); color:var(--ink2); line-height:1.4; }
/* шаг акцепта оферты — появляется только после выбора роли мастера */
.rolepick-gate{ margin-top:10px; padding:12px 14px; border:1px solid var(--violet-100);
  border-radius:var(--rad-md,12px); background:var(--violet-50); }
.rolepick-gate[hidden]{ display:none; }
.rolepick-gate-h{ font:700 13px var(--font); color:var(--ink); margin-bottom:4px; }
.pp-auth-card .pp-btn.rolepick-go{ margin-top:10px; }
@media(prefers-reduced-motion:reduce){
  .rolepick-card{ transition:none; }
  .rolepick-card:active{ transform:none; }
}

/* ── ВВОД КОДА ИЗ ПИСЬМА (#129) — /verify-code.html ──────────────────────────────────
   Доминанта кадра ОДНА (§1.1) — шесть ячеек кода: 30px/700 tabular-nums против 24px
   заголовка и 14px текста. Всё управление ниже по весу: primary «Подтвердить» (52px,
   тир auth-страниц) → secondary Яндекс (40px контур, общий .pp-oauth-btn) → tertiary
   «Отправить снова» / «Письмо не пришло?» / выходы текстом. Ноль хардкод-hex — только
   var(--*) из tokens.css. */
.vc-sub{ margin-bottom:var(--sp-4,16px); }
/* payoff «зачем подтверждать» — тихая третичная строка у ввода кода (маркетплейс-рамка:
   действия площадки, без «токенов»/резака). Подтянута под подзаголовок, доминанту-ячейки
   не перебивает; fold-запас у формы ~265–335px (замер), одна 12px-строка его не трогает. */
.vc-payoff{
  margin:calc(var(--sp-4,16px) * -1 + 6px) 0 var(--sp-4,16px);
  text-align:center; font:500 var(--fs-xs,12px)/1.45 var(--font); color:var(--ink2);
}
/* «Изменить» — третичный вес рядом со своим объектом (адресом), тап-таргет добираем
   паддингом с отрицательным margin: строка подзаголовка от этого НЕ растёт. */
.vc-edit{
  border:0; background:none; cursor:pointer;
  font:700 var(--fs-xs,12px)/1.4 var(--font); color:var(--violet-700);
  text-decoration:underline; text-underline-offset:2px;
  padding:6px 5px; margin:-6px -5px; border-radius:var(--rad-xs,6px);
}
.vc-edit:hover{ color:var(--violet-800); }
.vc-edit:focus-visible{ outline:2px solid var(--violet); outline-offset:2px; }
.vc-email[hidden]{ display:none; }
.vc-email{ margin-bottom:var(--sp-3,12px); }
.vc-mini{ margin:6px 0 0; font:500 var(--fs-xs,12px)/1.4 var(--font); color:var(--ink2); }
.vc-mini a{ color:var(--violet-700); font-weight:700; }

.vc-cells{ display:flex; gap:var(--sp-2,8px); justify-content:center; margin:0 0 var(--sp-3,12px); }
/* flex:1 вместо фиксированной ширины: шесть ячеек ОБЯЗАНЫ остаться одним рядом и на 390px
   (6×48+5×8=328 при внутренней ширине карточки 372 desktop / ~310 mobile). */
.vc-cell{
  flex:1 1 0; min-width:0; max-width:48px; height:56px; box-sizing:border-box;
  border:1.5px solid var(--line2); border-radius:var(--rad-md,12px);
  background:var(--card); color:var(--ink); caret-color:var(--violet);
  font:700 var(--fs-2xl,30px)/1 var(--font); font-variant-numeric:tabular-nums;
  text-align:center; padding:0;
  transition:border-color .15s, box-shadow .15s;
}
.vc-cell:focus{ outline:none; border-color:var(--violet); box-shadow:0 0 0 3px var(--accent-soft); }
/* недозаполненная ячейка после сабмита: цвет НЕ единственный сигнал — под рядом печатается
   подпись «Код шестизначный…» (§6). amber-700 = 4.2:1 к белому (600-й давал 2.8 — мимо
   порога 3:1 для графики), рамка 2px — вес читается и без цвета */
.vc-cell.is-empty{ border-color:var(--amber-700); border-width:2px; background:var(--amber-50); }
.vc-hint{ margin:0 0 var(--sp-3,12px); text-align:center;
  font:500 var(--fs-xs,12px)/1.45 var(--font); color:var(--ink2); }
.vc-hint[hidden]{ display:none; }

.vc-resend-row{ margin:var(--sp-2,8px) 0 0; text-align:center; }
.vc-resend{
  border:0; background:none; cursor:pointer;
  font:700 13px/1.4 var(--font); color:var(--violet-700);
  text-decoration:underline; text-underline-offset:2px;
  padding:8px 6px; margin:-8px -6px; border-radius:var(--rad-xs,6px);
}
.vc-resend:hover{ color:var(--violet-800); }
.vc-resend:focus-visible{ outline:2px solid var(--violet); outline-offset:2px; }
/* тикающий кулдаун — не «сломанная кнопка», а тихая подпись: вес и цвет вниз, подчёркивание
   снято (иначе читается как живая ссылка), сам обработчик уже защищён resendLeft() */
.vc-resend[aria-disabled="true"]{
  color:var(--ink2); font-weight:500; text-decoration:none; cursor:default;
}
.vc-note{ margin:var(--sp-2,8px) 0 0; text-align:center;
  font:600 var(--fs-xs,12px)/1.45 var(--font); }
.vc-note[hidden]{ display:none; }
.vc-note.is-ok{ color:var(--emerald-800); }     /* цвет = статус, не декор; 700 давал 3.9:1 */
.vc-note.is-bad{ color:var(--rose-800); }

.vc-oauth-note{ margin:6px 0 0; text-align:center;
  font:500 var(--fs-xs,12px)/1.4 var(--font); color:var(--ink2); }

/* «Письмо не пришло?» — progressive disclosure: в покое одна 13px-строка (26px), три
   короткие подсказки появляются по запросу, а не висят простынёй (D0 §16.3). */
.vc-help{ margin-top:var(--sp-3,12px); border-top:1px solid var(--line); padding-top:var(--sp-2,8px); }
.vc-help > summary{
  display:flex; align-items:center; gap:6px; cursor:pointer; list-style:none;
  font:600 13px/1.4 var(--font); color:var(--ink2); padding:5px 0;
}
.vc-help > summary::-webkit-details-marker{ display:none; }
.vc-help > summary:focus-visible{ outline:2px solid var(--violet); outline-offset:2px;
  border-radius:var(--rad-xs,6px); }
.vc-chev{ width:16px; height:16px; flex:none; transition:transform .18s ease; }
.vc-help[open] > summary .vc-chev{ transform:rotate(180deg); }
.vc-help-body{ font:500 var(--fs-xs,12px)/1.5 var(--font); color:var(--ink2); }
.vc-help-body p{ margin:6px 0 0; }
.vc-inline-link{
  border:0; background:none; cursor:pointer; font:700 var(--fs-xs,12px)/1.5 var(--font);
  color:var(--violet-700); text-decoration:underline; text-underline-offset:2px;
  padding:5px 3px; margin:-5px -3px; border-radius:var(--rad-xs,6px);
}
.vc-inline-link:focus-visible{ outline:2px solid var(--violet); outline-offset:2px; }

/* занятие на время ожидания — маркетплейс-рамка, тихой строкой (не второй CTA) */
.vc-wait{ margin:var(--sp-3,12px) 0 0; text-align:center;
  font:500 var(--fs-xs,12px)/1.45 var(--font); color:var(--ink2); }
.vc-wait a{ color:var(--violet-700); font-weight:700; text-decoration:underline;
  text-underline-offset:2px; }
.vc-card .pp-auth-alt{ margin-top:var(--sp-2,8px); }

@media(max-width:600px){
  /* тело ячейки 46×52 (тап-цель по обеим осям ≥44), зазор 6 — ряд остаётся ОДНОЙ строкой */
  .vc-cells{ gap:6px; }
  .vc-cell{ max-width:46px; height:52px; }
}
@media(prefers-reduced-motion:reduce){
  .vc-cell, .vc-chev{ transition:none; }
}

/* ── Полоса «письмо ушло» после регистрации (account.js: role-step + checkout-return) ──
   Была ДВУМЯ копиями инлайн-блоба с hex-фолбэками (--border,#eee / --pp-soft,#faf7ff —
   несуществующие имена, то есть де-факто хардкод). Стала одним классом на токенах, а
   разметка — одной функцией mailNoteHTML (§2 Atomic). Геометрия — принятой владельцем
   полосы .sf-note.is-inline (padding 8/12, 12.5px/1.5, иконка 16), не карты.
   Иерархия внутри полосы: primary действия здесь НЕТ (он у карточки — «Стать мастером» /
   «Вернуться к оформлению»), поэтому «Ввести код» = сильная ссылка, «Отправить снова» —
   тихая рядом. */
.pp-mailnote{
  display:flex; gap:var(--sp-2,8px); align-items:flex-start;
  margin:var(--sp-3,12px) 0 2px; padding:8px 12px; text-align:left;
  border:1px solid var(--violet-100); border-radius:var(--rad-md,12px);
  background:var(--violet-50); color:var(--ink2);
  font:500 12.5px/1.5 var(--font);
}
/* иконка приходит из acIco() с width/height-атрибутами и без класса — цепляем по тегу */
.pp-mailnote > svg{ flex:none; margin-top:2px; color:var(--violet-700); }
.pp-mailnote b{ color:var(--ink); }
.pp-mailnote-go, .pp-mailnote-alt{
  border:0; background:none; cursor:pointer; white-space:nowrap;
  text-decoration:underline; text-underline-offset:2px;
  padding:6px 4px; margin:-6px -4px; border-radius:var(--rad-xs,6px);
}
.pp-mailnote-go{ font:700 12.5px/1.5 var(--font); color:var(--violet-700); }
.pp-mailnote-go:hover{ color:var(--violet-800); }
.pp-mailnote-alt{ font:500 12.5px/1.5 var(--font); color:var(--ink2); }
.pp-mailnote-alt:hover{ color:var(--ink); }
.pp-mailnote-go:focus-visible, .pp-mailnote-alt:focus-visible{
  outline:2px solid var(--violet); outline-offset:2px;
}
.pp-mailnote-sep{ color:var(--line2); padding:0 2px; }
/* На узком два действия физически не влезают в одну строку и встают друг под другом —
   точка-разделитель тогда повисает сиротой в конце первой строки. Убираем её: строки уже
   разделены переносом. (Замер 390: без правки «·» болталась хвостом «Ввести код из письма ·».) */
@media(max-width:600px){
  .pp-mailnote-sep{ display:none; }
  .pp-mailnote-go, .pp-mailnote-alt{ display:inline-block; }
}

/* «это вы» бейдж на собственном публичном профиле */
.pp-you-badge{
  display:inline-flex; align-items:center; gap:6px; padding:5px 12px;
  border-radius:var(--pill); background:var(--bg2); color:var(--ink2);
  font:700 12px var(--font); margin:10px auto 0;
}
.pp-you-badge a{ color:var(--violet); text-decoration:none; }

/* =====================================================
   SOCIAL (P1) — лента постов, compose, пост, комментарии, guest-gate
   ===================================================== */
/* compose */
.pp-compose{ border:1px solid var(--line); border-radius:var(--r); padding:12px; margin-bottom:14px; background:var(--bg2); }
.pp-compose-text{
  width:100%; min-height:64px; resize:vertical; border:1px solid var(--line);
  border-radius:var(--r); padding:10px 12px; font:500 14px var(--font);
  background:var(--bg); color:var(--ink); box-sizing:border-box;
}
.pp-compose-text:focus{ outline:none; border-color:var(--violet); }
.pp-compose-row{ display:flex; gap:8px; margin-top:8px; flex-wrap:wrap; }
.pp-compose-url{
  flex:1; min-width:160px; border:1px solid var(--line); border-radius:var(--pill);
  padding:8px 12px; font:500 12px var(--font); background:var(--bg); color:var(--ink); box-sizing:border-box;
}
.pp-compose-url:focus{ outline:none; border-color:var(--violet); }
.pp-compose-actions{ display:flex; align-items:center; justify-content:space-between; gap:10px; margin-top:10px; flex-wrap:wrap; }
/* D0: база .pp-btn = width:100% + min-height:52 → внутри flex-wrap кнопка уносилась на
   свою строку гигантской градиент-полосой во всю карточку (замер 1112×52). Композер стал
   виден на /@handle вместе с owner-режимом — гасим базу до компактного тира 40px auto. */
.pp-compose-actions .pp-btn{ width:auto; min-height:40px; padding:0 18px; font-size:14px; }
/* Заголовок записи — та же пилюля-поле, что ссылки медиа, но во всю ширину и на ступень
   заметнее (это первая строка поста). Высота ~34px — компактный тир D0, не 48. */
.pp-compose-title{ width:100%; margin-bottom:8px; font:600 13px var(--font); }
.pp-compose-hint{ color:var(--ink2); font:500 11px var(--font); }
/* Счётчик лимита включается только у порога: обычная подсказка → «N / 8000» → перебор.
   Цвет НЕ единственный сигнал — текст меняется вместе с ним (§6). */
.pp-compose-hint.is-warn{ color:var(--amber-700); font-weight:700; }
.pp-compose-hint.is-err{ color:var(--rose-700); font-weight:700; }

/* feed post item */
.pp-feed-link{ text-decoration:none; color:inherit; }
.pp-feed-title{ font:800 16px var(--font-display,var(--font)); margin:2px 0 6px; line-height:1.25; }
.pp-feed-video{ display:block; width:100%; max-height:min(70vh,560px); object-fit:contain;
  border-radius:var(--r); margin:var(--sp-3) auto 0; background:#000; }
.pp-feed-cap{ color:var(--ink2); font:500 12px var(--font); margin-top:4px; }
.pp-feed-btn{
  display:inline-flex; align-items:center; gap:5px; border:1px solid var(--line);
  background:var(--bg); color:var(--ink2); border-radius:var(--pill); padding:4px 10px;
  font:700 12px var(--font); line-height:1.1; cursor:pointer; text-decoration:none; transition:.15s;
}
.pp-feed-btn:hover{ border-color:var(--violet); color:var(--ink); }
.pp-feed-btn.is-on{ background:var(--coral,#FF5A7A); border-color:var(--coral,#FF5A7A); color:#fff; }
/* статичный readout (SSR до гидрации) — не выглядит кликабельным */
.pp-feed-btn--static{ cursor:default; }
.pp-feed-btn--static:hover{ border-color:var(--line); color:var(--ink2); }
.pp-pending{ color:var(--sun,#E89B00); font-weight:700; }
.pp-feed-ssr{ list-style:none; padding:0; margin:0; }
.pp-feed-ssr li{ padding:8px 0; border-bottom:1px solid var(--line); font:600 14px var(--font); }
.pp-feed-ssr a{ color:var(--violet); text-decoration:none; }

/* пост (SSR-страница /@handle/post/{id}) */
.pp-post-author{ display:flex; align-items:center; gap:8px; font:600 13px var(--font); flex-wrap:wrap; }
.pp-post-author-link{ color:var(--ink); text-decoration:none; font-weight:800; }
.pp-ava-mini-img{ width:34px; height:34px; border-radius:var(--pill); object-fit:cover; flex:none; }
.pp-post-title{ font:800 24px var(--font-display,var(--font)); margin:12px 0; line-height:1.2; }
/* Медиа поста: капим высоту (вертикальные фото не занимают пол-экрана) и центрируем.
   width:auto — не растягиваем маленькие фото; портрет упирается в max-height и сжимается. */
.pp-post-cover{ display:block; max-width:100%; width:auto; height:auto;
  max-height:min(70vh,560px); object-fit:contain; margin:var(--sp-4) auto;
  border-radius:var(--r); background:var(--bg2); }
.pp-post-body{ font:500 15px/1.6 var(--font); color:var(--ink); }
.pp-post-body p{ margin:0 0 12px; }
.pp-post-img{ display:block; max-width:100%; width:auto; height:auto;
  max-height:min(70vh,560px); object-fit:contain; margin:var(--sp-4) auto;
  border-radius:var(--r); background:var(--bg2); }
.pp-post-video{ display:block; width:100%; max-height:min(70vh,560px); object-fit:contain;
  border-radius:var(--r); margin:var(--sp-4) auto; background:#000; }
.pp-post-meta,.pp-post-actions{ display:flex; gap:10px; margin-top:14px; flex-wrap:wrap; align-items:center; }
.pp-post-back{ text-align:center; margin:8px 0 40px; }
.pp-post-back a{ color:var(--violet); text-decoration:none; font:700 14px var(--font); }

/* ══════════════════════════════════════════════════════════════════════════
   Реакции к постам (множественные эмодзи, ≤3 на человека) — .rx-* namespace.
   Единый компонент для community/profile/post_ssr/group_ssr (pop.css линкуется
   на всех). Значения — из tokens.css. Рендер/логика — frontend/src/reactions.js.
   ══════════════════════════════════════════════════════════════════════════ */
/* строка-стопка пилюль */
.rx-bar{ display:flex; flex-wrap:wrap; align-items:center; gap:var(--sp-2); margin-top:var(--sp-2); }

/* пилюля «эмодзи + счётчик»; тач-таргет ≥40px */
.rx-pill{
  display:inline-flex; align-items:center; gap:6px;
  min-height:40px; padding:6px 12px 6px 10px;
  border:1px solid var(--line); border-radius:var(--pill);
  background:var(--bg); color:var(--ink); cursor:pointer;
  font:800 13px var(--font); line-height:1; -webkit-tap-highlight-color:transparent;
  transition:transform .16s cubic-bezier(.34,1.56,.64,1), background .15s, border-color .15s, color .15s;
}
.rx-pill:hover{ border-color:var(--violet-300); background:var(--violet-50); }
.rx-pill .rx-emo{ font-size:16px; line-height:1;
  font-family:'BS Emoji','Apple Color Emoji','Segoe UI Emoji','Noto Color Emoji',sans-serif; }
.rx-pill .rx-cnt{ font-variant-numeric:tabular-nums; font-weight:800; color:var(--ink2); }
/* СВОЯ реакция — активный state (акцент = «моё») */
.rx-pill.is-mine{ background:var(--violet-50); border-color:var(--violet-400); color:var(--violet-800); }
.rx-pill.is-mine .rx-cnt{ color:var(--violet-700); }
.rx-pill.is-mine:hover{ background:var(--violet-100); border-color:var(--violet-500); }
/* тихая ❤️-quick при 0 реакций */
.rx-pill.is-quick.is-empty{ color:var(--ink2); background:transparent; }
.rx-pill.is-quick.is-empty:hover{ color:var(--coral-600); border-color:var(--coral-300); background:var(--coral-50); }

/* триггер пикера «＋🙂» — тихая ghost-иконка */
.rx-add{
  display:inline-flex; align-items:center; justify-content:center;
  min-width:40px; min-height:40px; padding:0 10px;
  border:1px dashed var(--line2); border-radius:var(--pill);
  background:transparent; color:var(--ink2); cursor:pointer; transition:.15s;
}
.rx-add:hover{ border-style:solid; border-color:var(--violet); color:var(--violet); background:var(--violet-50); }
.rx-pill:focus-visible,.rx-add:focus-visible{ outline:none; box-shadow:0 0 0 3px var(--violet-200); }

/* pop самой пилюли при постановке */
@keyframes rx-pop{ 0%{transform:scale(1)} 32%{transform:scale(1.3)} 62%{transform:scale(.93)} 100%{transform:scale(1)} }
.rx-pill.rx-pop{ animation:rx-pop .42s cubic-bezier(.34,1.56,.64,1); }

/* burst-частицы из точки клика (спавнятся JS в body, чистятся по animationend) */
.rx-burst{
  position:fixed; z-index:9998; pointer-events:none; user-select:none;
  line-height:1; will-change:transform,opacity;
  animation:rx-fly var(--rx-dur,560ms) cubic-bezier(.2,.7,.3,1) forwards;
}
@keyframes rx-fly{
  0%  { transform:translate(-50%,-50%) scale(.4); opacity:0; }
  16% { opacity:1; }
  100%{ transform:translate(calc(-50% + var(--rx-dx,0)), calc(-50% + var(--rx-dy,-60px))) scale(var(--rx-sc,1)) rotate(var(--rx-rot,0deg)); opacity:0; }
}

/* пикер: десктоп — поповер; мобайл — bottom-sheet (см. @media ниже) */
.rx-scrim{ position:fixed; inset:0; z-index:9996; background:transparent; }
.rx-picker{
  position:fixed; z-index:9997; left:0; top:0;
  background:var(--card); border:1px solid var(--line); border-radius:var(--rad-lg);
  box-shadow:var(--shadow-lg); padding:var(--sp-3);
  display:grid; grid-template-columns:repeat(6,1fr); gap:2px; width:min(320px,92vw);
  animation:rx-picker-in .15s ease-out;
}
@keyframes rx-picker-in{ from{ opacity:0; transform:translateY(-6px) scale(.97); } to{ opacity:1; transform:none; } }
.rx-picker-hint{ grid-column:1/-1; font:600 11px var(--font); color:var(--ink2); padding:4px 4px 6px; text-align:center; }
.rx-picker-cell{
  display:flex; align-items:center; justify-content:center;
  width:46px; height:46px; border:0; background:transparent; cursor:pointer;
  font-size:22px; border-radius:var(--rad-md); transition:transform .12s, background .12s;
  font-family:'BS Emoji','Apple Color Emoji','Segoe UI Emoji','Noto Color Emoji',sans-serif;
}
.rx-picker-cell:hover{ background:var(--violet-50); transform:scale(1.16); }
.rx-picker-cell.is-mine{ background:var(--violet-100); box-shadow:inset 0 0 0 2px var(--violet-400); }
.rx-picker-cell:focus-visible{ outline:none; box-shadow:0 0 0 3px var(--violet-200); }

/* компактная сводка реакций для SSR-списка группы (не интерактивна) */
.rx-mini{ display:inline-flex; gap:8px; margin-left:8px; color:var(--ink2);
  font:600 12px var(--font); vertical-align:middle; }
.rx-mini b{ font-variant-numeric:tabular-nums; font-weight:800; color:var(--ink); }

/* детальная страница поста: реакции сверху / действия снизу (места достаточно) */
.pp-post-actions--stack{ flex-direction:column; align-items:stretch; gap:var(--sp-2); }
/* ЛЕНТА (group/profile): реакции + действия в ОДИН горизонтальный ряд (не два этажа) —
   D0-плотность. Wrap на узком. Реакц-бар и строка действий инлайн в один flex-ряд. */
.pp-feed-meta--stack{ flex-direction:row; flex-wrap:wrap; align-items:center; gap:5px 8px; margin-top:5px; }
.pp-feed-meta--stack > .rx-bar{ margin-top:0; gap:5px; }
.pp-feed-meta--stack > .pp-meta-row{ margin-top:0; }
.pp-actions-row,.pp-meta-row{ display:flex; flex-wrap:wrap; align-items:center; gap:8px; }
.pp-meta-row{ margin-top:2px; }
/* компактные реакц-пилюли ТОЛЬКО в футере ленты (детальная/community — как были) */
.pp-feed-meta--stack .rx-pill{ min-height:26px; padding:3px 10px 3px 8px; font-size:12px; }
.pp-feed-meta--stack .rx-pill .rx-emo{ font-size:14px; }
.pp-feed-meta--stack .rx-add{ min-width:26px; min-height:26px; padding:0 8px; }

/* мобайл: пикер → bottom-sheet во всю ширину + тёмный scrim */
@media(max-width:600px){
  .rx-scrim{ background:rgba(20,20,20,.34); }
  .rx-picker{
    left:0; right:0; bottom:0; top:auto; width:100%;
    border-radius:var(--rad-2xl) var(--rad-2xl) 0 0;
    grid-template-columns:repeat(6,1fr); gap:4px;
    padding:var(--sp-4) var(--sp-4) calc(var(--sp-6) + env(safe-area-inset-bottom,0px));
    animation:rx-sheet-in .22s cubic-bezier(.2,.8,.2,1);
  }
  @keyframes rx-sheet-in{ from{ transform:translateY(100%); } to{ transform:none; } }
  .rx-picker-cell{ width:100%; height:52px; font-size:25px; }
}

/* reduced-motion: без частиц, только мягкий scale/fade */
@media(prefers-reduced-motion:reduce){
  .rx-burst{ display:none !important; }
  .rx-pill.rx-pop{ animation:rx-pop-soft .2s ease; }
  @keyframes rx-pop-soft{ 0%{transform:scale(1)} 50%{transform:scale(1.08)} 100%{transform:scale(1)} }
  .rx-picker,.rx-picker-cell,.rx-pill{ animation:none; transition:none; }
}

/* комментарии */
.pp-comment{ display:flex; gap:10px; padding:10px 0; border-bottom:1px solid var(--line); }
.pp-comment-body{ flex:1; min-width:0; }
.pp-comment-head{ font:700 13px var(--font); margin-bottom:3px; }
.pp-comment-head a{ color:var(--ink); text-decoration:none; }
.pp-comment-text{ font:500 14px/1.5 var(--font); color:var(--ink); white-space:pre-wrap; word-break:break-word; }
.pp-commentbox-wrap{ margin-top:14px; }
.pp-commentbox{ display:flex; gap:8px; align-items:flex-end; }
.pp-commentbox .pp-compose-text{ flex:1; min-height:44px; }

/* ── ИНЛАЙН-ТРЕД комментариев под постом ленты (ВК-паритет, компонент post-comments.js).
   ПЛОТНО по D0-эталону (кабинет/@handle): строка коммента ~36px, композер ~30px (десктоп),
   тач-таргеты ≥40px на мобилке. Отдельный namespace pp-cmt (не трогает .pp-comment/.pp-member-row). ── */
.pp-cmt-sec{ margin-top:3px; padding-top:3px; border-top:1px solid var(--line); }
.pp-cmt-toggle{ display:inline-flex; align-items:center; gap:6px; background:none; border:0;
  color:var(--ink2); font:700 12px var(--font); cursor:pointer; padding:1px 0; }
.pp-cmt-toggle:hover{ color:var(--violet); }
/* гость: слим-строка входа вместо полноценного композера (клик → гейт). Один компактный ряд ~20px. */
.pp-cmt-guest{ display:inline-flex; align-items:center; gap:6px; margin-top:4px; background:none;
  border:0; color:var(--ink2); font:600 12px var(--font); cursor:pointer; padding:1px 0; }
.pp-cmt-guest:hover{ color:var(--violet); }
/* [hidden]-guard: классы задают display:inline-flex/flex и перебивают UA-правило [hidden]{display:none}
   → без этого «Показать 0 комментариев» и «показать следующие» торчали бы всегда (визуальный мусор). */
.pp-cmt-toggle[hidden], .pp-cmt-more[hidden], .pp-cmt-list[hidden]{ display:none; }
.pp-cmt-list{ display:flex; flex-direction:column; }
.pp-cmt{ display:flex; gap:8px; padding:5px 0; }
.pp-cmt + .pp-cmt{ border-top:1px solid var(--line); }
.pp-ava-xmini{ width:26px; height:26px; border-radius:var(--pill); background:var(--grad-2);
  color:#fff; display:grid; place-items:center; font:700 11px var(--font); flex:none; overflow:hidden; }
.pp-ava-xmini--guest{ background:var(--bg2); color:var(--ink2); }
.pp-ava-xmini img{ width:100%; height:100%; object-fit:cover; }
.pp-cmt-main{ flex:1; min-width:0; }
.pp-cmt-head{ font:700 12px var(--font); color:var(--ink); line-height:1.3; }
.pp-cmt-head a{ color:var(--ink); text-decoration:none; }
.pp-cmt-head a:hover{ color:var(--violet); }
.pp-cmt-date{ color:var(--ink2); font-weight:500; }
.pp-cmt-pending{ color:var(--sun,#E89B00); font-weight:700; }
.pp-cmt-text{ font:500 13px/1.45 var(--font); color:var(--ink); white-space:pre-wrap;
  word-break:break-word; margin-top:1px; }
.pp-cmt-empty{ color:var(--ink2); font:500 12px var(--font); padding:4px 0; }
.pp-cmt-retry{ background:none; border:0; color:var(--violet); font:700 12px var(--font);
  cursor:pointer; padding:4px 0; text-align:left; }
.pp-cmt-retry:hover{ text-decoration:underline; }
/* ── ВЕТКИ-ОТВЕТЫ (1 уровень, ВК): тонкий indent, «Показать N ответов», reply-композер, фото-аватар.
   Плотность: строка ответа = та же .pp-cmt (~36px), «показать N» и «ответить» компактные. ── */
.pp-ava-xmini--img{ display:block; object-fit:cover; }
.pp-cmt-acts{ display:flex; align-items:center; gap:14px; margin-top:2px; }
.pp-cmt-reply{ display:inline-flex; align-items:center; min-height:22px; background:none; border:0;
  color:var(--ink2); font:700 11px var(--font); cursor:pointer; padding:0; }
.pp-cmt-reply:hover{ color:var(--violet); }
/* ❤️ лайк коммента/ответа: компактно, в один ряд с «Ответить». is-liked → залитое coral-сердце. */
.pp-cmt-like{ display:inline-flex; align-items:center; gap:4px; min-height:22px; background:none;
  border:0; color:var(--ink2); font:700 11px var(--font); cursor:pointer; padding:0; }
.pp-cmt-like:hover,.pp-cmt-like.is-liked{ color:var(--coral,#FF5A7A); }
.pp-cmt-like.is-liked .pp-ic{ fill:currentColor; }
.pp-cmt-like-n{ font-variant-numeric:tabular-nums; }
.pp-cmt-like-n[hidden]{ display:none; }
/* «Цитировать» — тихая ссылка в ряд с «Ответить» */
.pp-cmt-quote-btn{ display:inline-flex; align-items:center; min-height:22px; background:none; border:0;
  color:var(--ink2); font:700 11px var(--font); cursor:pointer; padding:0; }
.pp-cmt-quote-btn:hover{ color:var(--violet); }
/* блок-цитата в теле ответа: плотная, тонкая левая полоса, ink2 12px */
.pp-cmt-quote{ margin:0 0 4px; padding:4px 8px; border-left:2px solid var(--line);
  background:var(--bg2); border-radius:0 6px 6px 0; color:var(--ink2);
  font:500 12px/1.4 var(--font); white-space:pre-wrap; word-break:break-word; }
@media(max-width:600px){ .pp-cmt-like,.pp-cmt-reply,.pp-cmt-quote-btn{ min-height:32px; } }
/* ── МЕДИА в комментах: панель композера (фото/3D) + чипы прикреплённого + рендер фото/3D ── */
.pp-cmt-composer{ margin-top:4px; }
.pp-cmt-composer .pp-cmt-compose{ margin-top:0; }
.pp-cmt-mbtn{ flex:none; width:30px; height:30px; border-radius:var(--pill); border:0;
  background:var(--bg2); color:var(--ink2); display:grid; place-items:center; cursor:pointer; transition:.15s; }
.pp-cmt-mbtn:hover{ color:var(--violet); background:var(--violet-50); }
.pp-cmt-media-chips{ display:flex; flex-wrap:wrap; gap:6px; margin-bottom:6px; padding-left:34px; }
.pp-cmt-media-chips[hidden]{ display:none; }
.pp-cmt-chip{ position:relative; display:inline-flex; align-items:center;
  border:1px solid var(--line); border-radius:10px; overflow:hidden; background:var(--bg2); }
.pp-cmt-chip img{ width:44px; height:44px; object-fit:cover; display:block; }
.pp-cmt-chip--model{ gap:6px; padding:6px 8px; color:var(--ink); font:700 11px var(--font); }
.pp-cmt-chip--model .pp-ic{ color:var(--violet); }
.pp-cmt-chip--load{ padding:6px 10px; color:var(--ink2); font:600 11px var(--font); }
.pp-cmt-chip-lbl{ max-width:120px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.pp-cmt-chip-x{ position:absolute; top:2px; right:2px; width:18px; height:18px; border:0; border-radius:50%;
  background:rgba(20,20,20,.55); color:#fff; display:grid; place-items:center; cursor:pointer; padding:0; }
.pp-cmt-chip--model .pp-cmt-chip-x{ position:static; background:none; color:var(--ink2); }
.pp-cmt-chip--model .pp-cmt-chip-x:hover{ color:var(--coral,#FF5A7A); }
/* рендер фото в комменте (клик → лайтбокс) */
.pp-cmt-photos{ display:flex; flex-wrap:wrap; gap:6px; margin-top:6px; }
.pp-cmt-photo{ display:block; max-width:180px; max-height:180px; width:auto; height:auto;
  border-radius:10px; object-fit:cover; cursor:zoom-in; background:var(--bg2); }
.pp-cmt-photos.multi .pp-cmt-photo{ width:112px; height:112px; }
/* рендер 3D в комменте: компактный крутибельный тайл ≤200px */
.pp-cmt-model{ position:relative; width:100%; max-width:200px; aspect-ratio:1; margin-top:6px;
  border:1px solid var(--line); border-radius:12px; overflow:hidden; background:var(--bg2); }
.pp-cmt-model-ph{ position:absolute; inset:0; z-index:0; display:flex; flex-direction:column; gap:4px;
  align-items:center; justify-content:center; color:var(--ink2); font:600 11px var(--font); cursor:pointer; }
.pp-cmt-model-ph .pp-ic{ color:var(--violet); }
.pp-cmt-model-open{ position:absolute; z-index:2; right:6px; bottom:6px; display:inline-flex; align-items:center;
  gap:4px; padding:4px 8px; border:0; border-radius:var(--pill); background:rgba(20,20,20,.6);
  color:#fff; font:700 10px var(--font); cursor:pointer; }
.pp-cmt-model-open:hover{ background:rgba(20,20,20,.78); }
.pp-cmt-branch{ margin-left:32px; }
.pp-cmt-showreplies{ display:inline-flex; align-items:center; gap:5px; background:none; border:0;
  color:var(--violet); font:700 12px var(--font); cursor:pointer; padding:4px 0; }
.pp-cmt-showreplies:hover{ text-decoration:underline; }
.pp-cmt-showreplies[hidden], .pp-cmt-replies[hidden]{ display:none; }
.pp-cmt-compose--reply{ margin-top:4px; }
.pp-cmt-cancel{ flex:none; width:30px; height:30px; border-radius:var(--pill); border:0;
  background:var(--bg2); color:var(--ink2); display:grid; place-items:center; cursor:pointer; transition:.15s; }
.pp-cmt-cancel:hover{ color:var(--ink); }
@media(max-width:600px){
  .pp-cmt-branch{ margin-left:24px; }
  .pp-cmt-cancel{ width:40px; height:40px; }
}
.pp-cmt-del{ flex:none; align-self:flex-start; background:none; border:0; color:var(--ink2);
  cursor:pointer; padding:3px; border-radius:6px; opacity:.7; transition:.15s;
  min-width:28px; min-height:28px; display:grid; place-items:center; }
.pp-cmt-del:hover{ color:var(--coral,#FF5A7A); opacity:1; background:var(--bg2); }
.pp-cmt-more{ display:inline-flex; align-items:center; gap:5px; background:none; border:0;
  color:var(--violet); font:700 12px var(--font); cursor:pointer; padding:4px 0; }
.pp-cmt-more:hover{ text-decoration:underline; }
/* композер: аватар-мини + растущая textarea в одну строку + бренд-иконка send (плотно, ~30px) */
.pp-cmt-compose{ display:flex; gap:8px; align-items:flex-end; margin-top:4px; }
.pp-cmt-compose .pp-ava-xmini{ align-self:flex-end; }
.pp-cmt-input{ flex:1; min-width:0; resize:none; overflow:hidden; min-height:30px; max-height:140px;
  border:1px solid var(--line); border-radius:15px; padding:5px 11px; font:500 13px/1.3 var(--font);
  background:var(--bg); color:var(--ink); box-sizing:border-box; }
.pp-cmt-input:focus{ outline:none; border-color:var(--violet); }
.pp-cmt-send{ flex:none; width:30px; height:30px; border-radius:var(--pill); border:0;
  background:var(--violet); color:#fff; display:grid; place-items:center; cursor:pointer; transition:.15s; }
.pp-cmt-send:hover{ filter:brightness(1.06); }
.pp-cmt-send:disabled{ opacity:.5; cursor:default; }
.pp-cmt-send:focus-visible{ outline:none; box-shadow:0 0 0 3px var(--violet-200); }
/* мобайл: тач-таргеты ≥40px (§14.D) при сохранении визуальной плотности на десктопе */
@media(max-width:600px){
  .pp-cmt-input{ min-height:40px; font-size:16px; }   /* 16px — не триггерит iOS-зум */
  .pp-cmt-send{ width:40px; height:40px; }
  .pp-cmt-del{ min-width:36px; min-height:36px; }
  .pp-feed-meta--stack .rx-pill,.pp-feed-meta--stack .rx-add{ min-height:38px; }
  .pp-feed-meta--stack .pp-feed-btn{ padding-top:8px; padding-bottom:8px; }
  .pp-feed-meta--stack .pp-feed-btn--icon{ min-width:38px; min-height:38px; }
}

/* guest-gate модалка */
.pp-authgate{
  position:fixed; inset:0; z-index:9000; display:grid; place-items:center;
  background:rgba(20,16,40,.5); backdrop-filter:blur(4px);
  opacity:0; transition:opacity .18s; padding:20px;
}
.pp-authgate.is-show{ opacity:1; }
.pp-authgate-card{
  position:relative; width:min(420px,100%); background:var(--bg); border-radius:20px;
  padding:30px 26px; text-align:center; box-shadow:0 24px 80px rgba(20,16,40,.3);
  transform:translateY(10px) scale(.98); transition:transform .2s;
}
.pp-authgate.is-show .pp-authgate-card{ transform:none; }
.pp-authgate-x{
  position:absolute; top:12px; right:14px; border:none; background:none;
  font-size:24px; line-height:1; color:var(--ink2); cursor:pointer;
}
.pp-authgate-ico{ font-size:40px; }
.pp-authgate-title{ font:800 20px var(--font-display,var(--font)); margin:10px 0 6px; }
.pp-authgate-sub{ color:var(--ink2); font:500 14px/1.5 var(--font); margin:0 0 18px; }
.pp-authgate-cta{ display:flex; gap:10px; }
.pp-authgate-cta .pp-btn{ flex:1; }

/* группы — каталог */
.pp-feed-author{ font:700 12px var(--font); color:var(--ink2); margin:2px 0 4px; }
.pp-chip.s-ok{ background:rgba(46,196,134,.14); color:#1F9D63; }
/* Карточка группы = масштаб компактной строки товара ЛК (.pp-prod-row): одна строка
   [ава52] [название+метрики] [статусы справа], без раздутых паддингов/третьей строки. */
.pp-group-card{
  display:flex; gap:12px; align-items:center; padding:10px; border:1px solid var(--line);
  border-radius:var(--r); margin-bottom:8px; text-decoration:none; color:inherit; transition:.15s;
}
.pp-group-card:hover{ border-color:var(--violet); transform:translateY(-1px); }
.pp-group-ava{
  width:52px; height:52px; border-radius:12px; background:var(--grad-2); color:#fff;
  display:grid; place-items:center; font:800 22px var(--font-display,var(--font)); flex:none; overflow:hidden;
}
.pp-group-ava img{ width:100%; height:100%; object-fit:cover; }
.pp-group-info{ min-width:0; flex:1; }
.pp-group-name{ font:800 15px var(--font-display,var(--font)); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.pp-group-sub{ color:var(--ink2); font:600 12px var(--font); margin-top:2px; display:flex; align-items:center; gap:4px; }
/* статусы — inline справа (как .pp-prod-status), nowrap, без общего центрирующего .pp-chips */
.pp-group-tags{ margin-left:auto; flex:0 0 auto; display:flex; align-items:center; gap:6px; white-space:nowrap; }
@media(max-width:480px){
  .pp-group-card{ flex-wrap:wrap; }
  .pp-group-tags{ margin-left:64px; }   /* под текст (ава 52 + gap 12), влево, не по центру */
}

/* ── Соц-блок профиля: счётчики подписок + модалка списка людей (P4) ─────── */
.pp-social{ display:flex; gap:18px; margin:10px 0 4px; }
.pp-social-stat{ border:0; background:none; cursor:pointer; color:var(--ink2); font:600 13px var(--font); padding:0; }
.pp-social-stat:hover{ color:var(--ink); }
.pp-social-stat b{ color:var(--ink); font-weight:800; margin-right:3px; }
.pp-modal-back{ position:fixed; inset:0; z-index:120; background:rgba(20,12,40,.45); backdrop-filter:blur(3px);
  display:grid; place-items:center; overflow:auto;
  /* safe-area: в notch/standalone модалка не лезет под чёлку/скруглённые углы; в браузере env()=0 → без изменений */
  padding:max(18px,env(safe-area-inset-top)) max(18px,env(safe-area-inset-right)) max(18px,env(safe-area-inset-bottom)) max(18px,env(safe-area-inset-left)); }
/* min-width:0 + max-width:100% — КРИТИЧНО: карточка модалки = grid-item у .pp-modal-back, а grid-item
   имеет min-width:auto (min-content) по умолчанию → широкий внутренний контент РАЗДУВАЛ карточку шире
   вьюпорта, а place-items:center уводил её за правый край (баг «Новый товар» на скрине владельца).
   min-width:0 держит объявленную width:min(x,100%), max-width:100% — двойной ремень. */
.pp-modal{ width:min(440px,100%); min-width:0; max-width:100%; max-height:80vh; background:var(--card,#fff); border-radius:20px; overflow:hidden;
  display:flex; flex-direction:column; box-shadow:0 24px 70px rgba(40,20,90,.3); }
.pp-modal-head{ display:flex; align-items:center; justify-content:space-between; padding:16px 18px; border-bottom:1px solid var(--line2,#eee); }
.pp-modal-head h3{ margin:0; font:800 18px var(--font-display,var(--font)); }
/* Закрыть модалку. Кнопка НЕ имела своих габаритов и жила размером содержимого — когда внутрь
   кладут inline-SVG без размера (.pp-ic), она схлопывалась в 12×2px, а ✕ был физически невидим.
   Даём КОМПАКТНЫЙ квадрат 32px (D0 — не раздуваем), тап-таргет 44 добираем ЗОНОЙ ::after. */
.pp-modal-x{ border:0; background:none; cursor:pointer; font-size:18px; color:var(--ink2); line-height:1;
  display:inline-flex; align-items:center; justify-content:center; position:relative;
  width:32px; height:32px; flex:none; padding:0; border-radius:10px;
  transition:background .15s, color .15s; }
.pp-modal-x::after{ content:''; position:absolute; inset:-6px; }
.pp-modal-x:hover{ background:var(--bg2); color:var(--ink); }
.pp-modal-x:focus-visible{ outline:2px solid var(--violet); outline-offset:2px; }
.pp-modal-x .pp-ic:where(:not([width])){ width:18px; height:18px; }
.pp-modal-body{ overflow:auto; padding:8px; }
.pp-modal-load,.pp-modal-empty{ padding:28px; text-align:center; color:var(--ink2); }
.pp-prow{ display:flex; align-items:center; gap:10px; padding:8px 10px; border-radius:14px; }
.pp-prow:hover{ background:var(--bg2,#faf8f4); }
.pp-prow-link{ display:flex; align-items:center; gap:10px; text-decoration:none; color:inherit; flex:1; min-width:0; }
.pp-prow-ava{ width:42px; height:42px; border-radius:50%; overflow:hidden; flex:0 0 auto; display:grid; place-items:center;
  background:linear-gradient(135deg,#FF5E7E,#7C5CFF); }
.pp-prow-ava img{ width:100%; height:100%; object-fit:cover; }
.pp-prow-init{ color:#fff; font-weight:800; }
.pp-prow-id{ display:flex; flex-direction:column; min-width:0; }
.pp-prow-id b{ font:700 14px var(--font); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.pp-prow-id span{ color:var(--ink2); font-size:12px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.pp-prow-you{ color:var(--ink2); font-size:12px; font-style:italic; }
/* Компактная пилюля-действие в строке человека (вкладка/модалка «Подписчики»/«Подписки»).
   ЦВЕТ здесь НЕ задаётся: тир взят из GROWTH-группы (.pp-btn-growth, .pp-prow-follow) выше —
   violet-контур на violet-soft, hover заливается. Раньше пилюля несла --grad-hero, тот же
   градиент, что primary-CTA профиля, и вторичное действие в списке спорило с главным (§14.A).
   Здесь остаются ТОЛЬКО габариты: компактные 28px, 12px шрифт, тап-таргет зоной ::after. */
.pp-prow-follow{ cursor:pointer; min-height:28px; padding:4px 12px; border-radius:999px;
  font:700 12px var(--font); white-space:nowrap;
  display:inline-flex; align-items:center; justify-content:center; gap:4px; flex:0 0 auto; position:relative;
  transition:background .15s, color .15s, border-color .15s; }
.pp-prow-follow .pp-ic:where(:not([width])){ width:14px; height:14px; }
/* тап-таргет добирается ЗОНОЙ, а не раздуванием тела кнопки (D0): расширение ложится внутрь gap:10px и padding ряда */
.pp-prow-follow::after{ content:''; position:absolute; inset:-8px -4px; }
/* «Вы подписаны» — самый тихий вес: нейтральный фон/контур. Hover лишь намекает на действие. */
.pp-prow-follow.is-following{ background:var(--bg2,#f0eef6); color:var(--ink); border-color:var(--line2,#e3e0ee); padding:4px 8px; }
.pp-prow-follow.is-following:hover{ border-color:var(--violet); color:var(--violet); }
.pp-prow-follow:focus-visible{ outline:2px solid var(--violet); outline-offset:2px; }
.pp-prow-follow:disabled{ opacity:.6; }

/* ── Медиа-блок профиля: КРУПНОЕ превью-кнопка с overlay-призывом ─────────── */
.pp-mediabox{ position:relative; display:block; padding:0; overflow:hidden; cursor:pointer;
  border:1.5px solid var(--line2); background:var(--bg2); color:var(--ink); font:inherit;
  transition:border-color .18s, box-shadow .18s, transform .18s; }
.pp-mediabox:hover{ border-color:var(--violet); box-shadow:var(--shadow-lg); }
.pp-mediabox:active{ transform:translateY(1px); }
.pp-mediabox:focus-visible{ outline:2px solid var(--violet); outline-offset:3px; }
.pp-mediabox--avatar{ width:120px; height:120px; border-radius:50%; }
.pp-mediabox--cover{ width:100%; aspect-ratio:4/1; border-radius:var(--rad-lg); }
/* пустое состояние — мягкий тинт + пунктир, приятный плейсхолдер */
.pp-mediabox:not(.has-img){ background:var(--violet-50); border-style:dashed; }

.pp-mediabox-img{ width:100%; height:100%; object-fit:cover; display:block; }
.pp-mediabox-img.is-mascot{ object-fit:contain; background:var(--violet-50); padding:6px; }  /* маскот-поза целиком, не кроп */

/* пустой призыв — камера-значок + подпись по центру */
.pp-mediabox-empty{ position:absolute; inset:0; display:flex; flex-direction:column;
  align-items:center; justify-content:center; gap:7px; text-align:center; padding:8px; }
.pp-mediabox-glyph{ display:grid; place-items:center; width:34px; height:34px; border-radius:50%;
  background:var(--violet-100); color:var(--violet-700); }
.pp-mediabox--avatar .pp-mediabox-glyph{ width:30px; height:30px; }
.pp-mediabox-glyph svg{ width:18px; height:18px; display:block; }
.pp-mediabox-etxt{ font:700 12px var(--font); color:var(--violet-700); }
.pp-mediabox--avatar .pp-mediabox-etxt{ font-size:11px; }

/* overlay-призыв (заполненное состояние) */
.pp-mediabox-ov{ position:absolute; display:flex; align-items:center; gap:7px; color:#fff;
  font:700 13px var(--font); pointer-events:none; }
.pp-mediabox-ov-ico{ display:grid; place-items:center; border-radius:50%; }
.pp-mediabox-ov-ico svg{ display:block; }
/* аватар: круглый значок-камера в углу (всегда виден) */
.pp-mediabox--avatar .pp-mediabox-ov{ right:5px; bottom:5px; }
.pp-mediabox--avatar .pp-mediabox-ov-ico{ width:34px; height:34px; background:var(--violet);
  border:2.5px solid var(--card); box-shadow:0 3px 10px rgba(20,20,20,.22); }
.pp-mediabox--avatar .pp-mediabox-ov-ico svg{ width:17px; height:17px; }
.pp-mediabox--avatar .pp-mediabox-ov-txt{ display:none; }
.pp-mediabox--avatar:hover .pp-mediabox-ov-ico{ background:var(--violet-600); }
/* обложка: нижняя плашка-градиент с камерой + подписью */
.pp-mediabox--cover .pp-mediabox-ov{ left:0; right:0; bottom:0; padding:9px 14px;
  background:linear-gradient(to top, rgba(20,20,20,.5), rgba(20,20,20,0)); }
.pp-mediabox--cover .pp-mediabox-ov-ico{ width:26px; height:26px; background:rgba(255,255,255,.24); }
.pp-mediabox--cover .pp-mediabox-ov-ico svg{ width:15px; height:15px; }

/* ── Портфолио: превью загруженного фото работы + «Заменить / Удалить» ────── */
.pp-workmedia.has-photo{ display:flex; align-items:center; gap:14px; }
.pp-workmedia-prev{ flex:none; width:96px; height:96px; border-radius:var(--rad-md); overflow:hidden;
  border:1.5px solid var(--line2); background:var(--bg2); }
.pp-workmedia-prev img{ width:100%; height:100%; object-fit:cover; display:block; }
.pp-workmedia-acts{ display:flex; flex-direction:column; gap:8px; align-items:flex-start; }
.pp-workmedia-btn{ min-height:44px; padding:0 16px; border-radius:var(--rad-sm); cursor:pointer;
  border:1.5px solid var(--line2); background:#fff; font:700 13px var(--font); color:var(--ink);
  transition:border-color .16s, color .16s, background-color .16s; }
.pp-workmedia-btn:hover{ border-color:var(--violet); color:var(--violet); }
.pp-workmedia-btn:focus-visible{ outline:2px solid var(--violet); outline-offset:2px; }
.pp-workmedia-del{ color:var(--coral); }
.pp-workmedia-del:hover{ border-color:var(--coral); color:var(--coral); background:var(--coral-50); }

/* ── Модалка выбора медиа (готовые пресеты / загрузка своего) ─────────────── */
.pp-modal-media{ width:min(560px,100%); }
.pp-media-seg{ display:flex; margin:14px 16px 0; }
.pp-media-seg button{ flex:1; }
.pp-media-modalbody{ padding:14px 16px 16px; flex:1 1 auto; overflow-y:auto; min-height:0; }  /* тело скроллит, head+табы зафиксированы */
.pp-media-hint{ display:flex; align-items:flex-start; gap:6px; margin:0 0 12px; }
.pp-media-subhead{ font-size:var(--fs-xs); font-weight:700; letter-spacing:.04em;
  text-transform:uppercase; color:var(--gray-600); margin:14px 2px 8px; }
.pp-media-subhead:first-of-type{ margin-top:0; }
/* Мини-вкладки категорий аватара (чипы) — сегментируют «Наши готовые», не полотном */
.pp-media-mtabs{ display:flex; gap:6px; flex-wrap:wrap; margin:0 0 12px; }
.pp-media-mtab{ padding:9px 14px; border:1px solid var(--line2); border-radius:999px;
  background:var(--bg2); color:var(--gray-600); font:600 13px var(--font); cursor:pointer;
  transition:background .16s, color .16s, border-color .16s; }
.pp-media-mtab:hover{ border-color:var(--violet); }
.pp-media-mtab.is-active{ background:var(--violet); color:#fff; border-color:var(--violet); }
.pp-media-mtab:focus-visible{ outline:2px solid var(--violet); outline-offset:2px; }
@media(max-width:640px){ .pp-media-mtab{ min-height:44px; padding:10px 16px; } }
.pp-media-gallery{ display:grid; gap:10px; }
/* [hidden] бьётся с display:grid (author > UA) → скрытые пейны мини-вкладок не прятались */
.pp-media-gallery[hidden]{ display:none; }
.pp-gallery-avatar{ grid-template-columns:repeat(4,1fr); }
.pp-gallery-cover{ grid-template-columns:repeat(2,1fr); }
.pp-media-tile{ position:relative; padding:0; border:2px solid var(--line2);
  background:var(--bg2); border-radius:14px; overflow:hidden; cursor:pointer;
  transition:border-color .16s, transform .16s; }
.pp-media-tile img{ width:100%; height:100%; object-fit:cover; display:block; }
.pp-gallery-avatar .pp-media-tile{ aspect-ratio:1/1; }
.pp-gallery-avatar .pp-media-tile img{ object-fit:contain; padding:6px; }
/* Экшн-позы «В деле» — вертикальные силуэты: портретная плитка + «пол»-градиент,
   чтобы поза стояла на дне тайла, а не висела в пустом квадрате (ux-pro). */
.pp-gallery-action{ grid-template-columns:repeat(3,1fr); }
.pp-gallery-action .pp-media-tile{ aspect-ratio:3/4;
  background:linear-gradient(to bottom, var(--card), var(--bg2)); }
.pp-gallery-action .pp-media-tile img{ object-fit:contain; padding:8px 6px 0; }
.pp-gallery-cover .pp-media-tile{ aspect-ratio:4/1; }
.pp-media-tile:hover{ border-color:var(--violet); transform:translateY(-2px); }
.pp-media-tile:focus-visible{ outline:2px solid var(--violet); outline-offset:2px; }
.pp-media-tile.is-sel{ border-color:var(--violet); }
/* маркер выбранной плитки: бренд line-галка маской (было сырое '✓' в content) */
.pp-media-tile.is-sel::after{ content:''; position:absolute; top:4px; right:4px;
  width:20px; height:20px; border-radius:50%; background:var(--violet);
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='5 12.5 10 17.5 19 7'/%3E%3C/svg%3E");
  background-size:13px 13px; background-position:center; background-repeat:no-repeat; }
.pp-media-urlrow{ display:flex; gap:8px; margin-top:12px; }
.pp-media-urlrow .pp-input{ flex:1; }
.pp-media-apply{ flex:none; min-height:44px; padding:0 16px; border:0; border-radius:var(--r);
  background:var(--violet); color:#fff; font:700 14px var(--font); cursor:pointer;
  transition:filter .16s; }
.pp-media-apply:hover{ filter:brightness(1.06); }
.pp-media-apply:focus-visible{ outline:2px solid var(--violet); outline-offset:2px; }
@media(max-width:520px){
  .pp-gallery-avatar{ grid-template-columns:repeat(3,1fr); }
  .pp-gallery-action{ grid-template-columns:repeat(2,1fr); }
}

/* ── Единый бургер-меню платформенной шапки pp-nav (формат SITE_FORMAT) ──── */
/* .pp-nav уже position:sticky → служит контейнером абсолютного меню (не трогаем position). */
/* штрих иконки — фирменный фиолетовый (svg рисуется currentColor); коробка опрятная. */
.pp-burger{ display:grid; place-items:center; width:44px; height:44px; flex:none; cursor:pointer;
  background:var(--card,#fff); border:1.5px solid var(--line2,#e7e3f0); border-radius:12px; color:var(--violet,#7C5CFF);
  transition:border-color .15s, background .15s; }
.pp-burger svg{ width:22px; height:22px; }
.pp-burger:hover{ border-color:var(--violet,#7C5CFF); background:rgba(124,92,255,.06); }
.pp-nav-menu{ position:absolute; top:62px; right:18px; z-index:60; width:248px; max-height:80vh; overflow:auto;
  background:#fff; border:1px solid var(--line2,#e7e3f0); border-radius:16px; box-shadow:var(--shadow,0 18px 50px rgba(40,20,90,.18));
  padding:8px; display:flex; flex-direction:column; }
.pp-nav-menu[hidden]{ display:none; }
.pp-nav-menu a{ display:flex; align-items:center; min-height:44px; padding:8px 12px; border-radius:10px; font:600 14px var(--font); color:var(--ink); text-decoration:none; }
.pp-nav-menu a:hover{ background:var(--bg2,#faf8f4); }
/* клавиатура: у пунктов меню не было видимого фокуса — Tab шёл вслепую (§6 WCAG).
   Кольцо снаружи строки (offset), поэтому читается и на градиентном флагмане. */
.pp-nav-menu a:focus-visible{ outline:2px solid var(--violet); outline-offset:2px; }
/* «Стать мастером» — ЕДИНСТВЕННЫЙ primary бургера (§14.A): градиент-строка вверху меню.
   Тот же корпус, что был у «Резать модель» (высота/паддинги/радиус/тень не менялись —
   D0-плотность: сменился жилец слота, а не размер). Глиф на градиенте — белый.
   ОДНА строка: nowrap + ellipsis страхуют от заворота в баннер при длинной локали. */
.pp-nav-menu a.pp-nav-sell{ gap:10px; margin:2px 2px 8px; padding:12px 14px; border-radius:12px;
  background:var(--grad-hero); color:#fff; font-weight:700;
  box-shadow:0 8px 20px -10px rgba(124,92,255,.7);
  transition:transform .18s cubic-bezier(.34,1.56,.64,1), box-shadow .18s, filter .18s; }
.pp-nav-menu a.pp-nav-sell:hover{ background:var(--grad-hero); filter:brightness(1.05);
  transform:translateY(-1px); box-shadow:0 12px 26px -10px rgba(124,92,255,.85); }
.pp-nav-sell-ico{ width:19px; height:19px; flex:none; }
.pp-nav-sell-lbl{ flex:1 1 auto; min-width:0; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
/* чип «скоро» у пункта-анонса. Раньше жил на градиенте (белая полупрозрачная пилюля) —
   после переезда «Резать модель» в «Ещё» он стоит на светлой строке, поэтому взят
   фиолетовый вариант — ровно тот же язык, что .lp-soon на главной (violet-50/700/100).
   Текст+цвет, не только цвет (§6). Контраст violet-700 на violet-50 ≈ 8:1. */
.pp-nav-soon{ flex:none; margin-left:8px; font:800 10px var(--font); letter-spacing:.03em;
  text-transform:uppercase; line-height:1; padding:3px 8px; border-radius:999px;
  background:var(--violet-50); color:var(--violet-700); border:1px solid var(--violet-100); }
@media(prefers-reduced-motion:reduce){
  .pp-nav-menu a.pp-nav-sell, .pp-nav-menu a.pp-nav-sell:hover{ transition:none; transform:none; }
}
/* Группа БЕЗ заголовка («Мой магазин»): границу держит контейнер, а не первая строка —
   на мобиле первая строка прячется как дубль слота панели, и группа иначе слипалась бы
   с соседней. Тот же хайрлайн, что у .pp-nav-menu-lbl, чтобы ритм списка не менялся. */
.pp-nav-grp{ margin-top:4px; padding-top:4px; border-top:1px solid var(--line2,#e7e3f0); }
/* заголовок смыслового блока = тонкий разделитель сверху (кроме первого) */
.pp-nav-menu-lbl{ font:800 11px var(--font); letter-spacing:.04em; text-transform:uppercase; color:var(--ink2); padding:12px 12px 3px; margin-top:4px; border-top:1px solid var(--line2,#e7e3f0); }
.pp-nav-menu-lbl:first-child{ border-top:0; margin-top:0; }
/* Строка баланса токенов убрана из бургера — вернётся в блоке резки (/app). */
/* СЛУЖЕБНЫЙ ПОДВАЛ меню: «Настройки» аккаунта (модель профиль-панели WB — служебная утилита
   стоит внизу, вплотную к выходу, а не среди контентных пунктов). Тише обычного пункта (ink2),
   с бренд-шестерёнкой; хайрлайн сверху отделяет подвал от навигации. */
.pp-nav-menu-set{ gap:10px; margin-top:6px; border-top:1px solid var(--line2,#e7e3f0);
  color:var(--ink2,#5B5B66)!important; }
.pp-nav-menu-set:hover{ color:var(--ink,#141414)!important; }
.pp-nav-set-ico{ width:18px; height:18px; flex:none; }
/* один разделитель на весь подвал: у «Выйти» свою линию гасим, если над ним «Настройки» */
.pp-nav-menu-set + .pp-nav-menu-out{ margin-top:0; border-top:0; }
.pp-nav-menu-out{ color:var(--coral,#FF5E7E)!important; margin-top:6px; border-top:1px solid var(--line2,#e7e3f0); }
.pp-nav-menu-go{ color:var(--violet,#7C5CFF)!important; font-weight:700!important; }
/* «Площадь» в бургере ДУБЛИРУЕТ верхний бар — прячем на десктопе, где бар виден;
   показываем только на мобиле (≤560px), где .pp-nav-links display:none и бургер = единственная навигация. */
.pp-nav-only-mobile{ display:none; }
@media(max-width:560px){ .pp-nav-only-mobile{ display:block; } }
/* ── ШТОРКА «Ещё» НА МОБИЛЕ = НИЖНИЙ ЛИСТ ──────────────────────────────────────
   Раньше меню было дропдауном у ПРАВОГО ВЕРХНЕГО угла — под пальцем, который только
   что нажал бургер там же. Тумблер переехал вниз («Ещё» в панели разделов), значит и
   лист обязан открываться ОТТУДА ЖЕ, из-под пальца (§7: на мобиле — bottom-sheet, а
   не центр/угол). Условие html[data-tabbar="on"] — тот же предохранитель, что у
   скрытия бургера: панель не смонтировалась → меню остаётся прежним дропдауном
   под своим прежним бургером, никакого «шторка снизу, а кнопка сверху». */
@media(max-width:560px){
  .pp-nav-menu{ right:12px; left:12px; width:auto; }
  html[data-tabbar="on"] .pp-nav-menu{
    /* z-index здесь работает ТОЛЬКО между своими: шторка лежит внутри .pp-nav, а тот —
       контекст наложения. Реальный подъём слоя делает .bs-sheet-open на самом контейнере
       (ниже), иначе пилюля корзины (118) накрывала бы открытый лист — замерено. */
    z-index:119;
    position:fixed; left:0; right:0; top:auto;
    bottom:var(--bs-tab-h,0px);   /* ровно НАД панелью; её высота уже включает safe-area */
    width:auto; max-height:72vh; max-height:72dvh; overflow:auto;
    padding:8px 10px 12px;
    border:1px solid var(--gray-200,#E9E4D9); border-bottom:0;
    border-radius:18px 18px 0 0;
    box-shadow:0 -18px 44px -20px rgba(40,20,90,.45);
    animation:bs-sheet-up .2s cubic-bezier(.22,1,.36,1) both;
  }
  /* Лесенка строк — приём `animated-list` (effects/blocks.js), чистым CSS без таймеров.
     Шаг 22мс и ТОЛЬКО первым восьми строкам: в меню бывает 15+ пунктов, и сквозная
     лесенка тянулась бы ~350мс — навигация обязана быть быстрее взгляда. Остальные
     появляются вместе с восьмой, без задержки. */
  html[data-tabbar="on"] .pp-nav-menu > *{ animation:bs-sheet-row .22s ease-out both; }
  html[data-tabbar="on"] .pp-nav-menu > :nth-child(1){ animation-delay:.01s; }
  html[data-tabbar="on"] .pp-nav-menu > :nth-child(2){ animation-delay:.03s; }
  html[data-tabbar="on"] .pp-nav-menu > :nth-child(3){ animation-delay:.05s; }
  html[data-tabbar="on"] .pp-nav-menu > :nth-child(4){ animation-delay:.07s; }
  html[data-tabbar="on"] .pp-nav-menu > :nth-child(5){ animation-delay:.09s; }
  html[data-tabbar="on"] .pp-nav-menu > :nth-child(6){ animation-delay:.11s; }
  html[data-tabbar="on"] .pp-nav-menu > :nth-child(7){ animation-delay:.13s; }
  html[data-tabbar="on"] .pp-nav-menu > :nth-child(n+8){ animation-delay:.15s; }
}
@keyframes bs-sheet-up{ from{ transform:translateY(14px); opacity:0; } }
@keyframes bs-sheet-row{ from{ transform:translateY(7px); opacity:0; } }
@media(prefers-reduced-motion:reduce){
  html[data-tabbar="on"] .pp-nav-menu,
  html[data-tabbar="on"] .pp-nav-menu > *{ animation:none; }
}

/* =====================================================
   TRUST / COLD-START  (Надёжность: new-state + capability) — §6 masterplan
   ===================================================== */
.pp-trust-cell small{ display:block; margin-top:4px; font:500 11px var(--font); color:var(--ink2); }

/* «Новый на площадке» — дружелюбный, НЕ тревожный (violet затемнён до AA 4.5:1) */
.pp-newbadge{
  display:inline-flex; align-items:center; gap:6px; margin-bottom:12px;
  font:700 12.5px var(--font); line-height:1.25; color:#4326B8;
  background:rgba(124,92,255,.10); border:1px solid rgba(124,92,255,.22);
  border-radius:var(--pill); padding:7px 13px;
}
.pp-trust-lead{ font:500 13px var(--font); color:var(--ink2); margin:0 0 14px; line-height:1.4; }

/* уровень доверия мастера (anti-fraud): нейтральный значок «Мастер на площадке» + честная сноска
   для самоактивированных (не прошли admin-модерацию). Значок «Проверенный» — только при moderated. */
.pp-trustlvl{ margin:4px 0 2px; }
.pp-trustlvl-note{ display:block; margin-top:6px; font:500 11px var(--font); color:var(--ink2); line-height:1.4; max-width:42ch; }

/* лесенка верификации — степ-круги с коннектором, зелёные по мере прохождения */
.pp-vsteps{ display:flex; align-items:flex-start; margin:2px 0; }
.pp-vstep{ flex:1; display:flex; flex-direction:column; align-items:center; gap:7px; position:relative; text-align:center; }
.pp-vstep::before{ content:""; position:absolute; top:13px; left:-50%; width:100%; height:2px; background:var(--line2); z-index:0; }
.pp-vstep:first-child::before{ display:none; }
.pp-vstep.is-done::before{ background:var(--ok); }
.pp-vdot{
  position:relative; z-index:1; width:26px; height:26px; border-radius:var(--pill);
  display:grid; place-items:center; font:800 13px var(--font);
  background:var(--bg2); color:var(--ink2); border:2px solid var(--line2);
}
.pp-vstep.is-done .pp-vdot{ background:var(--ok); color:#fff; border-color:var(--ok); }
.pp-vlbl{ font:600 12px var(--font); color:var(--ink2); }
.pp-vstep.is-done .pp-vlbl{ color:var(--ink); }

/* capability-чипы (парк/материалы/AMS/гарант/быстрый ответ) */
.pp-caps{ display:flex; flex-wrap:wrap; gap:8px; margin-top:14px; }
.pp-cap{
  display:inline-flex; align-items:center; gap:5px; line-height:1.2;
  font:600 12px var(--font); color:var(--ink);
  background:#fff; border:1.5px solid var(--line2); border-radius:var(--pill); padding:6px 12px;
}
.pp-cap b{ font:800 12px var(--font-display); font-variant-numeric:tabular-nums; }
/* капсула = 12px текст → иконка 14px (базовые 16px раздували капсулу выше ряда чипов) */
.pp-cap .pp-ic:where(:not([width])){ width:14px; height:14px; }
.pp-cap.is-hi { border-color:rgba(124,92,255,.5);  color:#4326B8; background:rgba(124,92,255,.06); }
.pp-cap.is-ok { border-color:rgba(31,191,117,.5);  color:#0F7A49; background:rgba(31,191,117,.08); }
.pp-cap.is-sun{ border-color:rgba(255,159,28,.55); color:#A5650A; background:rgba(255,197,61,.14); }

/* QC-гарантия новичка */
.pp-qc{
  display:flex; gap:11px; align-items:flex-start; margin-top:14px;
  background:rgba(31,191,117,.06); border:1px solid rgba(31,191,117,.22);
  border-radius:var(--r); padding:12px 14px;
}
/* Был сырой эмодзи 🛡 в 20px шрифта — теперь бренд line-SVG того же кегля. Цвет берём
   emerald-800 (не сырой --ok): на светло-зелёной подложке .pp-qc он даёт 6.26:1, тогда как
   --ok/--emerald-500 провалился бы по AA. Смысл несёт текст рядом, иконка — усиление. */
/* Скоуп .pp-qc обязателен: соседнее правило `.pp-qc span` (0,1,1) специфичнее одиночного
   класса и перебивало и цвет, и display, и margin-top — сырому эмодзи это было незаметно
   (глиф не красится currentColor), а line-SVG красится, и щит выходил серым --ink2. */
.pp-qc .pp-qc-ico{ display:grid; place-items:center; flex:none; margin-top:0;
  color:var(--emerald-800); }
.pp-qc .pp-qc-ico .pp-ic:where(:not([width])){ width:20px; height:20px; }
.pp-qc b{ display:block; font:700 13px var(--font); color:var(--ink); }
.pp-qc span{ display:block; font:500 12px var(--font); color:var(--ink2); margin-top:2px; line-height:1.4; }

/* прогресс заполнения профиля */
.pp-fill{ margin-top:14px; }
.pp-fill-top{ display:flex; justify-content:space-between; align-items:baseline; }
.pp-fill-top span{ font:600 12px var(--font); color:var(--ink2); }
.pp-fill-top b{ font:800 14px var(--font-display); font-variant-numeric:tabular-nums; }
.pp-fill-bar{ height:8px; border-radius:var(--pill); background:var(--bg2); overflow:hidden; margin-top:6px; }
.pp-fill-bar i{ display:block; height:100%; width:0; background:var(--grad-hero); border-radius:var(--pill); }
.pp-fill-hint{ font:500 11.5px var(--font); color:var(--ink2); margin-top:6px; }

/* активный мастер: 5 метрик → 3-кол сетка, 2-кол на узком */
.pp-stats-4{ grid-template-columns:repeat(3,1fr); }
@media(max-width:400px){ .pp-stats-4{ grid-template-columns:1fr 1fr; } }

@media (prefers-reduced-motion: no-preference){
  .pp-fill-bar i{ transition:width .9s cubic-bezier(.34,1.56,.64,1); }
}

/* ============ ВИТРИНА / КАТАЛОГ (pp-catalog / pp-product) — storefront ============ */
/* ══ СТРАНИЦА-ПОДБОРКА ПЛОЩАДКИ (SSR /catalog/{code}, /stl/{object}, индекс /catalog/) ══
   🔴 ЗАЧЕМ ЭТОТ БЛОК ВООБЩЕ ПОЯВИЛСЯ. Шаблон collection_ssr.html делался по правилу «ноль
   новых строк CSS» и переиспользовал скелет витрины мастера — но взял оттуда классы
   .ssb-sec/.ssb-wrap/.ssb-sh/.ssb-eyebrow/.ssb-h2/.ssb-count и .pp-pager/.pp-pager-cur,
   а этот слой МЁРТВ: src/blocks/site/site-blocks.css прямо пишет, что классы s-* «замещают
   прежний ssb-* слой». Ни одного из восьми классов нет НИ В ОДНОМ css проекта. Правило
   формально соблюдалось, а страница молча ехала на дефолтах браузера: H1 без бренд-шрифта,
   надзаголовок того же кегля, что заголовок (нулевая иерархия), пейджер без ритма.
   Подходящих живых примитивов в pop.css нет: .pp-dash-title — 14px титул CRM-карточки,
   .pp-dash-count — РОЗОВЫЙ бейдж (цвет=статус «плохо»), .pp-hero-kicker — белый текст под
   тёмный герой. Поэтому шапка страницы-подборки — честно новый переиспользуемый примитив.
   Значения — только токены; кегли/веса/отступы по DENSITY.md §4 и §6. */
.pp-coll-head{ margin:0 0 var(--sp-4); }
.pp-coll-eyebrow{ margin:0 0 var(--sp-1); font:800 11px var(--font); letter-spacing:.12em;
  text-transform:uppercase; color:var(--ink2); }
.pp-coll-h1{ margin:0; font:800 var(--fs-xl)/var(--lh-tight) var(--font-display);
  letter-spacing:-.02em; color:var(--ink); }
/* счётчик НЕЙТРАЛЕН: это справка «сколько тут», а не статус. Цвет=статус — иначе число
   читалось бы как предупреждение (ошибка .pp-dash-count, где счётчик розовый). */
.pp-coll-count{ margin-left:var(--sp-2); font:600 var(--fs-sm) var(--font); color:var(--ink2);
  font-variant-numeric:tabular-nums; white-space:nowrap; }
@media(max-width:600px){ .pp-coll-h1{ font-size:var(--fs-lg); } }

/* Индекс подборок: НЕ карточки товара. Ссылка на подборку — навигация, а не товар; карточка
   .pp-product с генеративным постером и кнопкой «Смотреть» на месте «купить» обещает товар
   там, где его нет, и раздувает список ссылок в стену медиа-плиток (D0). Тайл-чип с
   названием и числом плотнее и честнее: тот же чип, что в ленте подборок на маркетплейсе. */
.pp-coll-grid{ display:flex; flex-wrap:wrap; gap:var(--sp-2); margin:0 0 var(--sp-4); }

/* ЧИП-ССЫЛКА подборки — ЕДИНЫЙ примитив для ленты маркетплейса, поповера и SSR-индекса.
   Живёт в pop.css, а не в marketplace.css, потому что SSR-страницы marketplace.css не
   линкуют: держать вторую копию правил = гарантированный расход дизайна между двумя
   поверхностями, показывающими ОДИН И ТОТ ЖЕ список. */
.pp-collchip{ display:inline-flex; align-items:center; gap:6px; height:32px; box-sizing:border-box;
  text-decoration:none; color:var(--ink2); }
.pp-collchip:hover{ border-color:var(--violet-300); color:var(--ink); }
.pp-collchip.is-active{ background:var(--ink); color:var(--card); border-color:var(--ink); }
.pp-collchip:focus-visible{ outline:2px solid var(--violet); outline-offset:2px; }
.pp-collchip-n{ display:inline-grid; place-items:center; min-width:16px; height:16px; padding:0 4px;
  border-radius:var(--pill); background:var(--violet-100); color:var(--violet-700);
  font:700 11px var(--font); font-variant-numeric:tabular-nums; }
.pp-collchip.is-active .pp-collchip-n{ background:var(--card); color:var(--ink); }
@media(max-width:767px){ .pp-collchip{ height:36px; padding:0 13px; } }

/* Пейджер подборки: crawlable prev/next. Ритм — 8pt, число страницы приглушено и tabular. */
.pp-pager{ display:flex; align-items:center; justify-content:center; gap:var(--sp-3);
  margin:var(--sp-5) 0 0; flex-wrap:wrap; }
/* 🔴 База .pp-btn — это КНОПКА ФОРМЫ: width:100% + min-height:52px. В пейджере она давала
   две кнопки во всю ширину колонки, друг под другом, по 52px — замер: ряд 81px вместо 40.
   И 52px прямо мимо DENSITY §3 («кнопка desktop 40px, не 52»). Возвращаем кнопке её
   натуральную ширину и рост ряда контролов. */
.pp-pager .pp-btn{ width:auto; min-height:40px; padding:0 var(--sp-4);
  font:700 var(--fs-sm) var(--font); }
@media(max-width:767px){ .pp-pager .pp-btn{ min-height:44px; } }
.pp-pager-cur{ font:600 var(--fs-sm) var(--font); color:var(--ink2);
  font-variant-numeric:tabular-nums; }
/* «Куда дальше» в конце списка: короткая подборка иначе обрывается пустотой справа от
   последней карточки (грид auto-fill держит 8 треков и на трёх товарах). Это не декор, а
   выход из тупика — и внутренняя перелинковка. */
.pp-coll-tail{ margin:var(--sp-5) 0 0; font:600 var(--fs-sm) var(--font); }
.pp-coll-tail a{ color:var(--violet-600); text-decoration:none; }
.pp-coll-tail a:hover{ color:var(--violet-700); }

/* ── СПРАВОЧНЫЙ ТЕКСТ ПОДБОРКИ (под гридом) ──────────────────────────────────────────────
   Приёмка на проде 06.09: этот абзац стоял НАД гридом и на iPhone занимал первый экран
   целиком (замер /stl/drakon: верх грида 628 px при вьюпорте 660 — ни одного товара в кадре).
   Переехал вниз; здесь он справка, а не заголовок раздела, поэтому:
   • отделён линией и воздухом — иначе читается как обрывок последней карточки;
   • де-эмфазис (--ink2, §14.E): грид остаётся доминантой, текст не спорит с товаром;
   • line-height 1.6 явно — база .pp-about идёт на `normal` (~1.2), а это 130 слов подряд:
     на такой длине канон §3 требует leading-relaxed, иначе строки слипаются.
   Ширину держит существующий .pp-about-prose (60ch) — новой колонки не заводим. */
.pp-coll-about{ margin:var(--sp-6) 0 0; padding-top:var(--sp-4); border-top:1px solid var(--line); }
.pp-coll-abouth{ margin:0 0 var(--sp-2); font:800 11px var(--font); letter-spacing:.12em;
  text-transform:uppercase; color:var(--ink2); }
.pp-coll-intro{ margin:0; color:var(--ink2); line-height:1.6; }

.pp-catalog-grid{ display:grid; gap:10px; grid-template-columns:repeat(auto-fill,minmax(164px,1fr)); }
@media(max-width:520px){ .pp-catalog-grid{ grid-template-columns:repeat(2,1fr); gap:10px; } }

/* ── Полка «Товары» на странице мастера (VK-showcase) — горизонтальная витрина НАД вкладками.
   Скроллится вверх и уезжает, вкладки .pp-tabs остаются sticky ниже. Карточки — единый .pp-product
   (product-card.js) фиксированной ширины в горизонтальном треке со скрытым скроллбаром + snap. */
.pp-mshelf{ max-width:var(--page-max); margin:8px auto 0; padding:0 16px 12px;
  border-bottom:1px solid var(--line); }
.pp-mshelf-head{ display:flex; align-items:center; justify-content:space-between; gap:12px; margin:0 0 10px; }
.pp-mshelf-title{ margin:0; font:800 16px var(--font-display); letter-spacing:-.01em; color:var(--ink);
  line-height:1.2; }
.pp-mshelf-count{ font-size:13px; font-weight:700; color:var(--ink2); font-variant-numeric:tabular-nums; margin-left:2px; }
.pp-mshelf-all{ flex:0 0 auto; display:inline-flex; align-items:center; gap:5px;
  font:700 13px var(--font); color:var(--blue); text-decoration:none;
  padding:9px 6px; border-radius:var(--pill); }   /* padding → тач-таргет ≥44px по высоте */
.pp-mshelf-all:hover{ color:color-mix(in srgb,var(--blue) 82%,#000); }
.pp-mshelf-all:hover .pp-mshelf-arr{ transform:translateX(2px); }
.pp-mshelf-all:focus-visible{ outline:none; box-shadow:0 0 0 3px color-mix(in srgb,var(--blue) 40%,transparent); }
.pp-mshelf-arr{ transition:transform .18s ease; }
@media (prefers-reduced-motion:reduce){ .pp-mshelf-arr{ transition:none; } }
.pp-mshelf-track{ display:flex; gap:10px; overflow-x:auto; overflow-y:hidden;
  scroll-snap-type:x proximity; -webkit-overflow-scrolling:touch;
  scrollbar-width:none; padding:2px 0 6px; }
.pp-mshelf-track::-webkit-scrollbar{ display:none; }
.pp-mshelf-track > .pp-product{ flex:0 0 150px; width:150px; scroll-snap-align:start; }
.pp-mshelf-track > .pp-product.pp-skel{ pointer-events:none; }
.pp-mshelf-title-skel{ display:inline-block; width:104px; height:22px; border-radius:8px;
  background:var(--bg2); animation:pp-skel 1.2s ease-in-out infinite; }
/* свой пустой магазин → лёгкая приманка-строка (не гигантский empty-card над вкладками) */
.pp-mshelf-appeal{ display:flex; align-items:center; gap:16px; flex-wrap:wrap;
  background:var(--bg2); border:1px solid var(--line); border-radius:var(--r); padding:16px 18px; }
.pp-mshelf-appeal-txt{ flex:1 1 240px; min-width:0; }
.pp-mshelf-appeal-txt .pp-mshelf-title{ font-size:18px; }
.pp-mshelf-appeal-txt p{ margin:4px 0 0; font:400 14px var(--font); color:var(--ink2); line-height:1.45; }
.pp-mshelf-appeal .pp-btn{ flex:0 0 auto; width:auto; padding:0 20px; }
@media(max-width:640px){
  .pp-mshelf{ padding:0 14px 12px; margin-top:8px; }
  .pp-mshelf-head{ margin-bottom:8px; }
  .pp-mshelf-title{ font-size:15px; }
  .pp-mshelf-track{ gap:9px; }
  .pp-mshelf-track > .pp-product{ flex-basis:132px; width:132px; }
  .pp-mshelf-all{ min-height:44px; padding-left:10px; padding-right:10px; }   /* тач-таргет ≥44px */
  .pp-mshelf-appeal{ padding:14px 16px; }
  .pp-mshelf-appeal .pp-btn{ width:100%; }   /* мобайл: приманка-CTA во всю ширину, удобный тап */
}

/* ── Вкладка «Товары» страницы мастера — товары ПО ГРУППАМ (renderCatalogSections переиспользован).
   Классы полок .pp-shelf*/.pp-catalog-sections стилизованы только под .site (сайт-витрина); здесь —
   master-нативный скоуп на тех же классах теми же токенами, что у полки .pp-mshelf выше. Ссылок
   наружу нет (linkAll:false → «Смотреть все» не рисуется). Инсет/ширину даёт .pp-col-master. ── */
.pp-goods-panel .pp-catalog-sections{ display:grid; gap:20px; }
.pp-goods-panel .pp-shelf{ min-width:0; }   /* грид-айтем секции: не раздуваться под трек (overflow живёт ВНУТРИ трека, страница вбок не едет) */
.pp-goods-panel .pp-shelf-head{ display:flex; align-items:baseline; justify-content:space-between;
  gap:14px; margin:0 0 9px; }
.pp-goods-panel .pp-shelf-title{ min-width:0; margin:0; font:800 15px var(--font-display);
  letter-spacing:-.01em; line-height:1.2; color:var(--ink); }
.pp-goods-panel .pp-shelf-count{ font-size:13px; font-weight:700; color:var(--ink2);
  font-variant-numeric:tabular-nums; margin-left:2px; }
/* КАТЕГОРИЙНЫЕ РЕЛЬСЫ (Ozon/WB category-rail) — каждая группа = горизонтальный трек узких карточек,
   ТОТ ЖЕ паттерн, что верхняя полка .pp-mshelf-track (flex + scroll-snap + скрытый скроллбар, карточка
   150/132px). Плотно при 1-2 товарах И при многих: длинная категория прокручивается ВНУТРИ трека,
   сама страница вбок НЕ едет. Заменяет 6-колоночную грид-сетку, которая при 1-2 товарах в категории
   зияла пустотой справа. Разметку renderCatalogSections НЕ трогаем — только раскладка .is-compact
   грид→трек; скоуп .pp-goods-panel (сайт /shop = .site-скоуп, здесь не задет). */
.pp-goods-panel .pp-catalog-grid.is-compact{
  display:flex; grid-template-columns:none; gap:10px;
  overflow-x:auto; overflow-y:hidden; scroll-snap-type:x proximity;
  -webkit-overflow-scrolling:touch; scrollbar-width:none; padding:2px 0 4px; }
.pp-goods-panel .pp-catalog-grid.is-compact::-webkit-scrollbar{ display:none; }
.pp-goods-panel .pp-catalog-grid.is-compact > .pp-product{
  flex:0 0 150px; width:150px; min-width:0; scroll-snap-align:start; }
/* Мобилка (≤640): 2-колоночная СЕТКА, НЕ рельсы — 2-товарная категория заполняет ширину
   (владелец: «2 кол не пустует», дефект был только на десктопе); трек на узком экране лишний.
   Сброс rail-флексов (flex/width/overflow/snap) обратно в грид-ячейку; min-width:0 из базы цел. */
@media(max-width:640px){
  .pp-goods-panel .pp-catalog-sections{ gap:16px; }
  .pp-goods-panel .pp-catalog-grid.is-compact{
    display:grid; grid-template-columns:repeat(2,1fr); gap:10px;
    overflow:visible; scroll-snap-type:none; padding:0; }
  .pp-goods-panel .pp-catalog-grid.is-compact > .pp-product{ flex:none; width:auto; }
}

.pp-filter-scroll{ flex-wrap:nowrap; overflow-x:auto; scroll-snap-type:x proximity;
  -webkit-overflow-scrolling:touch; scrollbar-width:none; padding-bottom:2px; }
.pp-filter-scroll::-webkit-scrollbar{ display:none; }
.pp-filter-scroll .pp-filter-chip{ scroll-snap-align:start; flex:0 0 auto; }

/* ── АФФОРДАНС «РЯД ПРОДОЛЖАЕТСЯ» для горизонтальных чип-полос ───────────────────────
   Замер ленты подборок на проде 06.09, 393px: полоса видна на 277px, прокручиваемая
   ширина 655px (за кадром 378px), из ПЯТИ чипов целиком виден ОДИН, а следом сразу стоит
   прижатый вправо триггер «Ещё 5» — ряд читается как законченный, и четыре категории
   достаются только неподсказанным свайпом. Обрезанный чип у самой кромки этого не лечит:
   он неотличим от чипа, который просто упёрся в край.
   Подсказка — размытая кромка ровно с той стороны, где ЕЩЁ ЕСТЬ контент. Классы вешает JS
   (marketplace.js::wireScrollHint) по scrollLeft/scrollWidth, поэтому подсказка не врёт:
   долистал до конца — кромка гаснет. Чистым CSS «всегда-градиент» так не умеет и на
   докрученной до упора полосе обещал бы несуществующее продолжение.
   Полосу прокрутки при этом не возвращаем: она ломает детерминированную высоту ленты
   (замер: +11px на Windows, 0px на macOS — одна вёрстка разной высоты).
   @supports — страховка: движок без mask-image просто не получит подсветку, ряд остаётся
   рабочим (прогрессивное улучшение, ноль регрессии). */
@supports ((mask-image: linear-gradient(#000,#000)) or (-webkit-mask-image: linear-gradient(#000,#000))) {
  .pp-filter-scroll{ --fs-fade:32px; }
  .pp-filter-scroll.is-cut-end{
    -webkit-mask-image:linear-gradient(to right,#000 calc(100% - var(--fs-fade)),transparent);
            mask-image:linear-gradient(to right,#000 calc(100% - var(--fs-fade)),transparent);
  }
  .pp-filter-scroll.is-cut-start{
    -webkit-mask-image:linear-gradient(to left,#000 calc(100% - var(--fs-fade)),transparent);
            mask-image:linear-gradient(to left,#000 calc(100% - var(--fs-fade)),transparent);
  }
  .pp-filter-scroll.is-cut-start.is-cut-end{
    -webkit-mask-image:linear-gradient(to right,transparent,#000 var(--fs-fade),#000 calc(100% - var(--fs-fade)),transparent);
            mask-image:linear-gradient(to right,transparent,#000 var(--fs-fade),#000 calc(100% - var(--fs-fade)),transparent);
  }
}

.pp-product{ background:var(--card); border:1px solid var(--line); border-radius:var(--r);
  overflow:hidden; cursor:pointer; display:flex; flex-direction:column; text-align:left; }
/* Фокус карточки. Был `outline:none` + мягкое свечение box-shadow rgba(124,92,255,.45) —
   три отдельных дефекта на одной строке (замер на проде 06.09):
   1) КОНТРАСТ. Свечение 45%-прозрачного фиолета на светлой странице даёт эффективный
      #C4B6FF → 1.83:1 к фону #FFFDF7. WCAG 2.2 SC 1.4.11 требует ≥3:1 для индикатора
      фокуса. Сплошной var(--violet) на том же фоне = 4.28:1 (и 4.35:1 на белой карточке).
   2) FORCED COLORS. В режиме высокой контрастности Windows box-shadow не рисуется вовсе,
      а outline принудительно перекрашивается системой — при `outline:none` кольца там НЕТ.
   3) ЗАДЕРЖКА. box-shadow входит в transition .pp-spring (.18s), и кольцо ПРОЯВЛЯЛОСЬ
      180 мс после Tab. outline не анимируется — появляется в том же кадре, что и фокус.
   box-shadow здесь больше не объявляем намеренно: иначе он перебивал бы лифт
   .pp-spring:hover (та же специфичность, но наше правило ниже по файлу). */
.pp-product:focus-visible{ outline:2px solid var(--violet); outline-offset:2px; }
/* Медиа портрет 4:5 (спека §B.1): обложка выведена из потока (absolute inset), поэтому натуральный
   аспект PNG не может растянуть бокс — все карточки равной высоты (фикс «плывущей» сетки).
   object-fit:cover — каждое изображение заполняет бокс ЕДИНО (шар/подставка/ваза/заяц одного
   визуального размера), убирает «пляшущие» мелкие/большие картинки в сетке (треб. владельца).
   Центр-кроп: широкие/высокие силуэты подрезаются по краям — полный кадр живёт на PDP. */
/* аудит п.1: медиа-бокс залит брендовым градиентом (как .pp-product-poster) — любой
   недогруженный/прозрачный слой (3D model-viewer, letterbox от object-fit:contain) читается
   как бренд, а не «мёртвый серый» var(--bg2). Реальное фото рисуется поверх. */
/* container-type:inline-size → тайл САМ решает, что помещается в оверлей бейджей (см. ниже):
   одна и та же карточка живёт в 2-кол мобайле (164px), в auto-fill гриде, в горизонтальной
   полке /@handle (150/132px) и в превью формы (272px) — вьюпорт-медиазапрос эти случаи не
   различает. Контейнер ИМЕНОВАННЫЙ (tile), чтобы не ловить чужие @container. */
.pp-product-media{ position:relative; aspect-ratio:1/1;
  container:tile / inline-size;
  --bdg-h:21px; --bdg-px:7px; --bdg-fs:11px; --bdg-ico:13px;
  background:
    radial-gradient(120px 120px at 30% 25%, rgba(124,92,255,.14), transparent 70%),
    radial-gradient(140px 140px at 75% 80%, rgba(255,94,126,.12), transparent 70%), var(--bg2);
  overflow:hidden; border-radius:inherit; }
/* object-fit:cover + центр — единый размер всех обложек в сетке (конец «пляшущим» тайлам).
   drop-shadow снят: контактная тень имела смысл только для contain-силуэта; под cover фото
   full-bleed и её край всё равно клипается overflow:hidden .pp-product-media. */
.pp-product-cover{ position:absolute; inset:0; width:100%; height:100%;
  object-fit:cover; object-position:center; }
.pp-product-poster{ position:absolute; inset:0; display:flex; align-items:center; justify-content:center;
  font-size:32px; color:var(--ink2);
  background:
    radial-gradient(120px 120px at 30% 25%, rgba(124,92,255,.18), transparent 70%),
    radial-gradient(140px 140px at 75% 80%, rgba(255,94,126,.16), transparent 70%), var(--bg2); }
/* WP-SP-02 «never-blank»: товар без обложки → детерминированный бренд-градиент + белая моно-буква
   (posterSurface). Ключ .is-generative → работает и на .pp-product-poster, и на inline feed-thumb
   (.fc-prod-thumb/.fc-tp-cover). --cover ставит JS (hash(id) → пара существующих рамп tokens.css).
   Носитель = query-container по inline-size → буква масштабируется под ЛЮБОЙ бокс (тайл/thumb/hero). */
.is-generative{ position:relative; display:flex; align-items:center; justify-content:center;
  overflow:hidden; container-type:inline-size; background:var(--cover, var(--grad-hero)); }
.is-generative::before{ content:""; position:absolute; inset:0; pointer-events:none;
  background:radial-gradient(58% 58% at 50% 46%, var(--cover-mono-scrim), transparent 74%); }
/* 🔴 ВОЗВРАТ ПОСТЕРУ ЕГО ГЕОМЕТРИИ. .pp-product-poster объявлен absolute+inset:0 (заполнить
   квадрат медиа-бокса), но идущий НИЖЕ .is-generative с той же специфичностью (0,1,0)
   перебивает position на relative — и постер схлопывается в высоту одной буквы. Замер на
   SSR-карточке без обложки: медиа 179.1×179.1, постер 179.1×75.2 — градиент занимал верхнюю
   треть, буква обрезана. В живом маркетплейсе не видно только потому, что там постер
   собирает JS (posterSurface); на серверной странице JS не участвует. Специфичность (0,2,0)
   возвращает absolute, не трогая .is-generative для остальных носителей (feed-thumb и пр.). */
.pp-product-poster.is-generative{ position:absolute; inset:0; }
.pp-poster-mono{ position:relative; z-index:1; margin:0;
  font-family:var(--font-display); font-weight:800; line-height:1; letter-spacing:.01em;
  font-size:clamp(26px, 42cqi, 104px); color:var(--cover-mono);
  text-shadow:0 2px 12px rgba(20,20,20,.30); -webkit-user-select:none; user-select:none; }
/* ══ ОВЕРЛЕЙ БЕЙДЖЕЙ НА ФОТО (верх-лево) ═══════════════════════════════════════════════
   Претензия владельца 2026-08-18 (полка /@handle): «невероятно большая плашка с обозначениями
   и маленькие иконки… не видно что там и как». Было: flex-wrap:wrap + метка-предложение
   «STL · цифровой» без nowrap → на тайле 132–164px пилюля ломалась во ВТОРУЮ строку, над ней
   вторым этажом глиф-полукруг «3D» — стена 48–70px на фото 132–164px (30–43% кадра) при нулевой пользе.
   Стало (замер): ОДНА строка 21px = 12.8% кадра при том же наборе фактов.

   Четыре правила слоя:
   1. 🔴 HARD-ИНВАРИАНТ: ряд НИКОГДА не переносится (flex-wrap:nowrap + white-space:nowrap
      на каждой пилюле). Переполнение решается ВЫПАДЕНИЕМ хвоста (см. container-queries ниже),
      а не второй строкой — высота оверлея постоянна при любых данных.
   2. Цвет = СТАТУС, не тип (§Refactoring UI «цвет что-то значит»): цветные только «−N%» (rose,
      крючок) и «По артикулу» (violet, прямой ответ на поиск). Тип/3D/Образец — одно нейтральное
      стекло. Побочно чинит AA: коралловый .is-service давал белым 3.73:1 (мимо WCAG AA),
      нейтральное стекло — 6.2:1 в худшем случае (белое фото), violet-700 — 7.1:1.
   3. Иконка соразмерна носителю: 13px в пилюле 21px (62%), было 12px в двухстрочном блоке.
   4. Геометрия — ОДИН источник: --bdg-* объявлены на .pp-product-media, их же читает
      .pp-product-sale (инжектится из product-card.js) — числа не дублируются по файлам.

   Порядок в DOM = приоритет: [По артикулу] [−N%] [3D] [тип] [Образец]. */
.pp-product-badges{ position:absolute; left:8px; top:8px; z-index:2;
  display:flex; flex-wrap:nowrap; align-items:center; gap:4px;
  max-width:calc(100% - 16px); overflow:hidden; }
/* карточка маркетплейса несёт ♥ в верх-право (36px + инсеты) — ряд обязан остановиться до него,
   иначе длинная пилюля уезжает под сердце (было: max-width считал только свои инсеты). */
.pp-product-badges:has(~ .pp-fav){ max-width:calc(100% - 56px); }
/* базовая пилюля оверлея. Классы .pp-product-3d/.pp-product-type самодостаточны (не зависят от
   родителя) — фолбэки var(--bdg-*,…) держат вид, даже если пилюля стоит вне ряда. */
.pp-product-3d, .pp-product-type{ box-sizing:border-box; flex:0 0 auto; min-width:0;
  height:var(--bdg-h,21px); padding:0 var(--bdg-px,8px);
  display:inline-flex; align-items:center; justify-content:center; gap:4px;
  background:rgba(20,20,20,.62); color:#fff;
  backdrop-filter:blur(6px); -webkit-backdrop-filter:blur(6px);
  font:800 var(--bdg-fs,11px)/1 var(--font-display); letter-spacing:.02em;
  border-radius:var(--pill); white-space:nowrap; }
.pp-product-3d .pp-ico, .pp-product-type .pp-ico{ width:var(--bdg-ico,13px); height:var(--bdg-ico,13px); }
/* слово пилюли: единственный текст переменной длины — метка подтипа снабжения; ужимается
   многоточием, полная форма в title (обрезка НИКОГДА не превращается в перенос). */
.pp-product-type{ flex:0 1 auto; }
.pp-b-txt{ min-width:0; overflow:hidden; text-overflow:ellipsis; }
/* «По артикулу» — единственная violet-пилюля: это ответ на поиск по коду, а не свойство товара */
.pp-product-type.is-match{ background:var(--violet-700); }

/* ── ЧТО ПОКАЗЫВАЕМ, КОГДА МЕСТА МАЛО (вместо переноса) ────────────────────────────────
   Замер пилюль (11px/800 Unbounded, иконка 13 + gap 4 + паддинг 2×8):
     −25%=51.5 · 3D=49.4 · STL=54 · Услуга=75 · Образец=65 · По артикулу=110 · icon-only=21.
   Доступно = ширина тайла − 16 (инсеты), на карточке с ♥ − 56 (сердце 36 + инсет 8 + 4 воздуха).
   Реальные ширины тайла в проекте: полка /@handle 132/150 · грид 164–200 · превью формы 272.

   Правило 1 — СТРУКТУРНОЕ, не по ширине (карточка обязана выглядеть одинаково на всех
   поверхностях, §13 паритет): тип ОДИН в ряду → показывает слово; тип с соседями →
   схлопывается в иконку 21×21, слово уходит в sr-only (скринридер и поиск по странице
   его слышат, десктоп читает title). «Образец» не схлопываем — он без иконки. */
.pp-product-badges:has(> :nth-child(2)) .pp-product-type:not(.is-sample){
  flex:0 0 auto; width:var(--bdg-h,21px); padding:0; gap:0; }
.pp-product-badges:has(> :nth-child(2)) .pp-product-type:not(.is-sample) .pp-b-txt{
  position:absolute; width:1px; height:1px; padding:0; margin:-1px;
  overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0; }
/* Правило 2 — ЁМКОСТЬ ряда по ширине САМОГО тайла. Выпадает всегда ХВОСТ = наименее
   приоритетное (порядок cjm: Образец → тип → 3D; скидка и совпадение по коду не выпадают).
   overflow:hidden на ряду — ремень безопасности на стыке диапазонов: подрежет край,
   но НЕ уронит вторую строку (HARD-инвариант). */
@container tile (max-width:299px){
  /* 3 пилюли: 49.5+47.4+21+2×4 = 126 ≤ 132 (самый узкий из «трёхпилюльных» — медиа 148) */
  .pp-product-badges > :nth-child(n+4){ display:none; }
}
@container tile (max-width:139px){
  /* полка /@handle на мобайле (карточка 132 → медиа 130): 2 пилюли, 49.5+47.4+4 = 101 ≤ 114 */
  .pp-product-badges > :nth-child(n+3){ display:none; }
}
@container tile (max-width:259px){
  /* карточка с ♥ (маркетплейс) теряет 56px строки → ёмкость 2: 101 ≤ 108 (медиа 164) */
  .pp-product-badges:has(~ .pp-fav) > :nth-child(n+3){ display:none; }
}
/* magic-card спотлайт (прод, НЕ demo/.fxc): мягкое пятно за курсором ТОЛЬКО на статичных тайлах
   (.pp-product.is-spotlight; у 3D-тайлов вместо него hover-turntable). Слой над обложкой (z0), ПОД
   бейджами 3D/тип (z2) → бейджи не замыливаются; pointer-events:none → клик/hover карты целы.
   Палитра приглушена под СВЕТЛУЮ var(--card) (demo был под тёмную gray-900): один мягкий violet-стоп,
   быстро гаснет, не спорит с ценой/CTA. Дефолт скрыт (opacity 0) → без idle-дрейфа; координаты --x/--y
   ведёт JS wireSpotlight (borders.js, только hover:hover). Переход глушит глобальный reduced-motion @media (§6). */
.pp-product.is-spotlight .pp-product-media::after{
  content:""; position:absolute; inset:0; z-index:1; pointer-events:none; border-radius:inherit;
  opacity:0; transition:opacity .3s ease;
  background:radial-gradient(150px circle at var(--x,50%) var(--y,50%),
    color-mix(in srgb,var(--violet) 30%,transparent), transparent 62%); }
.pp-product.is-spotlight:hover .pp-product-media::after{ opacity:1; }
.pp-product-body{ padding:8px 10px 10px; display:flex; flex-direction:column; gap:4px; flex:1 1 auto; }
/* атрибуция мастера (только маркетплейс) — ghost-ссылка, не конкурирует с CTA */
.pp-product-master{ display:inline-flex; align-items:center; gap:4px; max-width:100%;
  font:600 12px var(--font); color:var(--blue); text-decoration:none; overflow:hidden; }
.pp-product-master:hover .pp-product-master-name{ text-decoration:underline; }
.pp-product-master-name{ min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.pp-product-master .pp-ico{ opacity:.75; }
.pp-product-tags{ display:flex; flex-wrap:wrap; gap:5px; }
/* аудит п.3/п.11: «нет цены» (Договорная / Цена по запросу) — ТИХИЙ muted, не насыщенный
   violet: иначе не-готовые к покупке позиции кричат громче реальных ценников (инверсия иерархии). */
.pp-product-price.is-nego{ color:var(--ink2); font-weight:700; white-space:normal; min-width:0; }  /* текст-метка («Договорная») переносится, не режется у края узкой карточки (360px) */
.pp-product-price.is-free{ color:#16a34a; }  /* бесплатный STL — позитивный зелёный, не «0 ₽» */
.pp-product-title{ font:800 13px var(--font-display); letter-spacing:-.01em; margin:0; line-height:1.2;
  display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden;
  min-height:2.5em; }  /* резерв 2 строк → карточки пиксельно-равной высоты (треб. ux-pro «равная высота») */
/* seo-smith wave3: сниппет описания на ТАЙЛЕ витрины — крауло-видимый уникальный текст
   (добивает thin-content). ОТДЕЛЬНЫЙ класс от .pp-product-desc (та = ПОЛНОЕ описание в модалке
   quick-view, без clamp — не конфликтуем каскадом). Тихий muted 12px, 2 строки clamp; БЕЗ
   min-height-резерва → пустое описание не рисуется (элемента нет) и высота ЭТАЛОННОГО тайла НЕ
   растёт (D0). CTA приколот к низу (.pp-product-add margin-top:auto) → разная длина описаний не
   рвёт нижнюю кромку (карточки flex-column, CTA bottom-aligned). */
.pp-product-snippet{ margin:0; font:400 12px var(--font); line-height:1.35; color:var(--ink2);
  display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden; }
/* цена — первый ряд тела, самый крупный/жирный текст тайла (спека §B.2); cat-чип справа */
.pp-product-foot{ display:flex; align-items:baseline; justify-content:space-between; gap:8px; }
.pp-product-price{ font:800 16px var(--font-display); color:var(--ink); line-height:1.15;
  font-variant-numeric:tabular-nums; white-space:nowrap; }
.pp-product-price.is-lg{ font-size:20px; }
/* аудит п.5: категория — ТИХАЯ метка-kicker ПОД заголовком (не на строке цены). Без пилюли/фона,
   без max-width:55% (на мобайле схлопывалось в 1 букву «ф»); длинную метку переносим, не режем. */
.pp-product-cat{ display:block; margin:-1px 0 1px; font:700 10px var(--font); color:var(--ink2);
  letter-spacing:.04em; text-transform:uppercase; line-height:1.3; }
/* артикул — тихий микро-чип в нижней части тела (спека §B.6): 11px, muted, моно.
   CTA (.pp-product-add) остаётся приколот к низу своим margin-top:auto → артикул = последняя инфо-строка над кнопкой. */
.pp-product-art .bs-code{ font-size:11px; }

/* seo-smith wave3: FAQ-аккордеон витрины — брендовый collapse (нативный <details>, стоковый
   marker скрыт, свой line-SVG-каретка как .pdp-lic-details), 0 JS. Крауло-видимый текст даже в
   свёрнутом состоянии (Яндекс читает содержимое details) → бэкует FAQPage-схему. Де-эмфазис:
   тихая рамка, читаемая колонка --read-max, внизу витрины — не конкурирует с гридом (§14.A).
   Компакт (D0): свёрнуто по умолчанию, строка-вопрос ~44px (тач-таргет), не простыня. */
.pp-faq{ max-width:var(--read-max); margin:20px 0 4px; }
.pp-faq-h{ font:700 15px var(--font-display); color:var(--ink); margin:0 0 8px; letter-spacing:-.01em; }
.pp-faq-item{ background:var(--card); border:1px solid var(--line); border-radius:12px;
  margin:0 0 6px; overflow:hidden; }
.pp-faq-q{ display:flex; align-items:center; gap:10px; cursor:pointer; list-style:none; user-select:none;
  padding:11px 14px; min-height:44px; box-sizing:border-box; font:600 14px var(--font); color:var(--ink); }
.pp-faq-q::-webkit-details-marker{ display:none; }
.pp-faq-q-txt{ flex:1 1 auto; min-width:0; line-height:1.35; }
.pp-faq-caret{ flex:0 0 auto; display:inline-flex; color:var(--ink2); transition:transform .18s ease; }
.pp-faq-item[open] .pp-faq-caret{ transform:rotate(180deg); }
.pp-faq-a{ margin:0; padding:0 14px 12px; font:400 13px var(--font); line-height:1.5; color:var(--ink2); }
@media (prefers-reduced-motion: reduce){ .pp-faq-caret{ transition:none; } }

.pp-catalog-grid.is-skel .pp-product{ cursor:default; }
.pp-skel .pp-product-media{ animation:pp-skel 1.2s ease-in-out infinite; }
.pp-skel-line{ height:11px; border-radius:6px; margin:8px 12px 0; background:var(--bg2); animation:pp-skel 1.2s ease-in-out infinite; }
.pp-skel-line.w70{ width:70%; } .pp-skel-line.w40{ width:40%; }
@keyframes pp-skel{ 0%,100%{ opacity:1 } 50%{ opacity:.5 } }

.pp-modal-product{ width:min(560px,100%); max-height:90vh; max-height:90dvh; display:flex; flex-direction:column; }
.pp-product-hero{ position:relative; aspect-ratio:4/3; background:linear-gradient(160deg,var(--bg2),#fff); }
.pp-product-hero model-viewer{ width:100%; height:100%; --poster-color:transparent; }
.pp-product-hero img{ width:100%; height:100%; object-fit:contain; }
.pp-modal-product .pp-modal-x{ position:absolute; right:12px; top:12px; z-index:3; width:36px; height:36px;
  border-radius:50%; border:0; cursor:pointer; background:rgba(255,255,255,.85); backdrop-filter:blur(6px); }
.pp-product-detail{ padding:18px; display:flex; flex-direction:column; gap:10px; overflow:auto; }
.pp-modal-title{ font:800 22px var(--font-display); letter-spacing:-.02em; margin:2px 0 0; }
.pp-product-desc{ font:500 14px var(--font); color:var(--ink2); line-height:1.5; margin:0; }
.pp-product-attrs{ display:flex; flex-wrap:wrap; gap:6px; }
.pp-product-detail .pp-btn-primary{ margin-top:4px; min-height:52px; }
.pp-product-note{ font:500 12px var(--font); color:var(--ink2); text-align:center; margin:0; }
.pp-product-detail [data-cta-area]{ display:flex; flex-direction:column; gap:8px; }

/* ============ КОРЗИНА ПОКУПАТЕЛЯ (Волна-2) — pp-cart-* ============ */
/* «＋ В корзину» на карточке товара */
/* аудит п.10: кнопка меняет ТОЛЬКО заливку (лифт владеет карточкой .pp-spring — не дублируем
   двойной translateY). transition явный (background/color/border), не all → без лишних свойств. */
/* text-decoration:none — та же причина, что у .pp-btn: глобальный сброс задаёт только
   a{color:inherit}, поэтому <a class="pp-product-add"> на СЕРВЕРНЫХ страницах приезжал
   подчёркнутым внутри кнопки-пилюли. В клиентском гриде этого не видно: там product-card.js
   рисует <button>. Кнопка не должна выглядеть по-разному в зависимости от того, кто её отрисовал. */
/* 🔴 КОНТРАСТ ЛЕЙБЛА — В БАЗЕ, А НЕ ТОЛЬКО В JS. Сырой --violet (#7C5CFF) на почти-белом
   даёт 4.28:1 — ниже WCAG AA 4.5. Это знали: product-card.js:ensureCtaContrastStyle()
   инжектит --acc-ink/--violet-600 (5.4:1) поверх. Но инжектит ТОЛЬКО клиентский рендерер —
   на СЕРВЕРНЫХ страницах (страница-подборка /catalog|/stl, витрина мастера до гидрации) JS
   не участвует, и туда уезжал ровно тот дефект, ради которого написан фикс (замер на проде
   06.09: #7C5CFF на #FFFDF7 = 4.28:1). Поднимаем базу: тема даёт --acc-ink, дефолт-бренд —
   --violet-600. JS-инжект после этого совпадает с базой и остаётся no-op'ом. Фон-заливку не
   трогаем: на ней #6B4AEE = 5.0:1 (замер), а её смена дала бы мигание на витринах мастеров. */
.pp-product-add{ margin:5px 0 0; margin-top:auto; width:100%; min-height:38px; text-decoration:none;
  border:1.5px solid var(--acc-ink, var(--violet-600));
  background:rgba(124,92,255,.06); color:var(--acc-ink, var(--violet-600)); border-radius:10px; cursor:pointer;
  display:inline-flex; align-items:center; justify-content:center; gap:6px;
  font:800 12px var(--font-display); letter-spacing:-.01em;
  transition:background .15s, color .15s, border-color .15s; }
/* hover-заливка тоже поднята до AA: белый на сыром --violet = 4.35:1 (мимо 4.5 для 12px),
   на --violet-600 = 5.47:1. Пара --cta-bg/--cta-fg — тот же тема-контракт, что у JS-инжекта. */
.pp-product-add:hover{ background:var(--cta-bg, var(--violet-600)); color:var(--cta-fg,#fff); }
/* Тот же фикс, что у карточки выше (тут свечение было ещё бледнее — .35 ≈ 1.6:1).
   Кольцо цветом собственной ink-пары кнопки: --violet-600 на белом теле карточки = 5.0:1
   (замер зафиксирован в комментарии над .pp-product-add). offset 2px укладывается в
   padding .pp-product-body (10px) → overflow:hidden карточки его не режет. */
.pp-product-add:focus-visible{ outline:2px solid var(--acc-ink, var(--violet-600)); outline-offset:2px; }

/* ══════════════════════════════════════════════════════════════════════════════════════
   КАРТОЧКА ТОВАРА — СЛОИ, ПЕРЕЕХАВШИЕ ИЗ JS-ИНЪЕКЦИЙ В ОБЩИЙ CSS
   ──────────────────────────────────────────────────────────────────────────────────────
   🔴 ПОЧЕМУ ПЕРЕЕХАЛИ. Эти правила жили в `ensure*Style()` внутри product-card.js: модуль
   создавал <style> в <head> при первом рендере. На КЛИЕНТСКИХ поверхностях это работало,
   но у карточки появился второй рендерер — СЕРВЕРНЫЙ (_product_card.html), а на SSR-странице
   JS может не участвовать вовсе (краулер, no-JS, первый кадр). Классы приезжали, стилей —
   нет: ровно тот же класс дефекта, что мёртвый слой .ssb-* и «AA-фикс, живущий только в JS».
   Стиль карточки обязан лежать там, где его видят ОБА рендерера, — в общем pop.css, который
   линкует каждая поверхность с товаром.
   Перенос ДОСЛОВНЫЙ (значения не трогали). Проверено: ни один из этих селекторов не
   объявлен ни в marketplace.css / pro.css / catalog-page.css / blocks.css, поэтому позиция
   в каскаде роли не играет и «поздние» файлы ничего не перебивают.
   ══════════════════════════════════════════════════════════════════════════════════════ */

/* ── AA-контраст ghost-CTA. Базовый .pp-product-add выше красит текст сырым --violet
   (4.35:1 — ниже AA 4.5). Поднимаем ПЕРЕИСПОЛЬЗУЯ тема-контракт: --acc-ink (углублённый
   акцент темы) на --ssurf; hover — солид-пара --cta-bg/--cta-fg. Фолбэк вне тем —
   --violet-600 (#6B4AEE = 5.47:1 на белом). Идёт ПОСЛЕ базового правила → перебивает без
   !important, ровно как раньше инъекция в <head> после pop.css. ── */
.pp-product-add{ background:var(--ssurf,#ffffff);
  color:var(--acc-ink,var(--violet-600,#6B4AEE));
  border-color:var(--acc-ink,var(--violet-600,#6B4AEE)); }
.pp-product-add:hover{ background:var(--cta-bg,var(--violet-600,#6B4AEE));
  color:var(--cta-fg,#ffffff); border-color:transparent; }

/* ── Пульсирующая точка «Бесплатно». Единственный движущийся акцент карточки. Приехала из
   src/ui/effects/surfaces.js: там она жила ради карточки, а карточку модуль тянул целиком
   ради трёх строк — и на SSR не доезжал вовсе. --c задаёт цвет свечения. ── */
.fxs-dot{ position:relative; width:8px; height:8px; border-radius:50%; background:var(--c); box-shadow:0 0 8px var(--c); }
.fxs-dot::after{ content:""; position:absolute; inset:0; border-radius:50%; background:var(--c); animation:fxs-ping 2s ease-out infinite; }
@keyframes fxs-ping{ 0%{ transform:scale(1); opacity:.75; } 70%,100%{ transform:scale(2.6); opacity:0; } }
@media (prefers-reduced-motion:reduce){ .fxs-dot::after{ animation:none !important; } }

/* ── Тихая строка доставки под ценой. Была ИНЛАЙН-СТИЛЕМ в product-card.js (`style="${base}"`)
   и повторялась строкой в серверном макросе — то есть один вид в двух местах, которые нечем
   сверить. Правило одно, оба рендерера печатают только класс. ── */
.pp-product-deliv{ display:inline-flex; align-items:center; gap:5px; margin-top:3px;
  font:600 12px var(--font); color:var(--ink2); }

/* ── ★-рейтинг товара. Семантика — amber-рампа (оценка), намеренно отдельно от бренд-violet
   и от sale-rose. FAIL-CLOSED в рендерерах: нет отзывов → строки нет (не «0,0»). ── */
.pp-product-rating{ display:inline-flex; align-items:center; gap:4px; min-width:0; margin:1px 0 0;
  font:600 12.5px var(--font,sans-serif); color:var(--ink2,#64748B);
  font-variant-numeric:tabular-nums; line-height:1.2; }
.pp-product-rating-star{ flex:0 0 auto; width:13px; height:13px; color:var(--amber-500,#F59E0B); }
.pp-product-rating b{ font-weight:700; color:var(--ink,#0F172A); }
.pp-product-rating-sep{ color:var(--ink3,#9AA0AE); }
.pp-product-rating-c{ color:var(--ink2,#64748B); }

/* ── Мета-строка kicker: категория · лицензия. Второй сегмент существующей строки, а не
   своя — высота тайла не растёт (замер: своя строка = +17px на КАЖДОМ STL-тайле). ── */
.pp-product-meta{ display:flex; align-items:baseline; gap:5px; min-width:0; }
.pp-product-meta .pp-product-cat{ flex:0 1 auto; min-width:0; white-space:nowrap;
  overflow:hidden; text-overflow:ellipsis; }
.pp-product-meta-sep{ flex:0 0 auto; font:700 10px var(--font); color:var(--ink2); line-height:1.3;
  margin:-1px 0 1px; }
.pp-product-lic{ flex:0 0 auto; max-width:100%; min-width:0; white-space:nowrap; overflow:hidden;
  text-overflow:ellipsis; font:700 10px var(--font); color:var(--ink); letter-spacing:.01em;
  line-height:1.3; margin:-1px 0 1px; }
.pp-product-meta-sep + .pp-product-lic{ max-width:56%; }
.pp-lic-sr{ position:absolute; width:1px; height:1px; overflow:hidden; clip:rect(0 0 0 0); }
/* Узкий тайл (2 колонки, тело ~135px): два 10px-факта в строке дают два огрызка.
   Приоритет лицензии — категорию покупатель уже знает (пришёл по чипу/фильтру). */
@media (max-width:520px){
  .pp-product-meta .pp-product-cat,.pp-product-meta-sep{ display:none; }
  .pp-product-lic{ max-width:100%; }
}

/* ── Скидка: пилюля −N% (статус, rose-рампа ≠ бренд-акцент) + пара «стала/была». Геометрия
   пилюли — ОДИН источник --bdg-* с .pp-product-media выше; здесь только цвет и tabular-nums. ── */
.pp-product-sale{ display:inline-flex; align-items:center; justify-content:center; box-sizing:border-box;
  height:var(--bdg-h,21px); padding:0 var(--bdg-px,8px);
  font:800 var(--bdg-fs,11px)/1 var(--font-display,'Unbounded',sans-serif); letter-spacing:.02em; color:#fff;
  background:color-mix(in srgb,var(--rose-600,#F43F5E) 80%,#000);
  border-radius:var(--pill,999px); white-space:nowrap; font-variant-numeric:tabular-nums; }
.pp-sale{ display:flex; flex-direction:column; gap:2px; min-width:0; }
.pp-sale-row{ display:flex; align-items:baseline; gap:8px; flex-wrap:wrap; }
.pp-product-price.is-sale{ color:var(--rose-700,#D63A4A); }
.pp-price-was{ font:700 13px var(--font-display,'Unbounded',sans-serif);
  color:var(--ink2,#64748B); text-decoration:line-through; text-decoration-thickness:1.5px;
  font-variant-numeric:tabular-nums; white-space:nowrap; }
.pp-promo-note{ font:600 10.5px var(--font,sans-serif); color:var(--ink2,#64748B);
  letter-spacing:.01em; line-height:1.3; overflow:hidden; text-overflow:ellipsis;
  white-space:nowrap; max-width:100%; }

/* ── «Товар недели» — знак ровно на ОДНОЙ карточке выдачи, поэтому стоит вторым в ряду
   бейджей и схлопывается в иконку раньше остальных. ── */
.pp-product-week{ box-sizing:border-box; flex:0 0 auto; min-width:0;
  height:var(--bdg-h,21px); padding:0 var(--bdg-px,7px);
  display:inline-flex; align-items:center; justify-content:center; gap:4px;
  font:800 var(--bdg-fs,11px)/1 var(--font-display,'Unbounded',sans-serif); letter-spacing:.02em;
  color:var(--ink,#141414);
  background:linear-gradient(135deg,var(--amber-300,#FFD05C),var(--amber-500,#F59E0B));
  box-shadow:inset 0 0 0 1px var(--amber-700,#B36A00);
  border-radius:var(--pill,999px); white-space:nowrap; }
.pp-product-week .pp-ico{ width:var(--bdg-ico,13px); height:var(--bdg-ico,13px); }
.pp-product-badges:has(> :nth-child(2)) .pp-product-week{ width:var(--bdg-h,21px); padding:0; gap:0; }
.pp-product-badges:has(> :nth-child(2)) .pp-product-week .pp-b-txt{
  position:absolute; width:1px; height:1px; padding:0; margin:-1px;
  overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0; }
@container tile (max-width:199px){
  .pp-product-week{ width:var(--bdg-h,21px); padding:0; gap:0; }
  .pp-product-week .pp-b-txt{ position:absolute; width:1px; height:1px; padding:0; margin:-1px;
    overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0; }
}

/* ── Быстрый просмотр: пилюля по hover/фокусу на десктопе, постоянный круглый триггер на
   тач (hover недостижим). Сам триггер — РЕАЛЬНАЯ <a href="/a/{article}">, поэтому без JS
   и для краулера это обычная ссылка на страницу товара. ── */
.pp-product-qv{ position:absolute; inset:auto 0 0 0; z-index:2; padding:10px; display:flex;
  justify-content:center; pointer-events:none; opacity:0; transform:translateY(6px);
  transition:opacity .2s ease,transform .2s ease; }
.pp-product:hover .pp-product-qv,
.pp-product:focus-within .pp-product-qv,
.pp-product-qv:focus-within{ opacity:1; transform:none; }
.pp-product-qv-pill{ pointer-events:auto; display:inline-flex; align-items:center; gap:6px;
  box-sizing:border-box; min-height:36px;
  background:rgba(20,20,20,.62); color:#fff; backdrop-filter:blur(6px); -webkit-backdrop-filter:blur(6px);
  font:700 12px var(--font); letter-spacing:.01em; padding:7px 13px; border-radius:var(--pill);
  text-decoration:none; box-shadow:0 4px 14px -6px rgba(0,0,0,.5); cursor:pointer; }
.pp-product-qv-pill:hover{ background:rgba(20,20,20,.82); }
.pp-product-qv-pill:focus-visible{ outline:2px solid #fff; outline-offset:2px; }
.pp-product-qv-pill .pp-ico{ flex:0 0 auto; }
@media (prefers-reduced-motion:reduce){ .pp-product-qv{ transition:none; transform:none; } }
@media (hover:none){
  .pp-product-qv{ inset:auto 8px 8px auto; padding:0; justify-content:flex-end; opacity:1; transform:none; }
  .pp-product-qv-pill{ position:relative; width:36px; height:36px; min-height:0; padding:0; gap:0;
    justify-content:center; border-radius:50%; }
  .pp-product-qv-pill::before{ content:""; position:absolute; inset:-4px; border-radius:50%; }
  .pp-qv-txt{ position:absolute; width:1px; height:1px; padding:0; margin:-1px; overflow:hidden;
    clip:rect(0,0,0,0); white-space:nowrap; border:0; }
}

/* ── Карточка СНАБЖЕНИЯ: свотч цвета филамента (color-not-only — свотч всегда с текстом)
   + тихая «Подробнее» вместо ghost-CTA. ── */
.pp-product-cat.is-supply{ color:var(--violet,#7C5CFF); font-weight:700; }
.pp-product-fil{ display:flex; align-items:center; gap:7px; margin:4px 0 2px; min-height:20px; }
.pp-fil-swatch{ flex:0 0 auto; width:14px; height:14px; border-radius:50%; background:var(--sw,#ccc);
  box-shadow:inset 0 0 0 1px rgba(0,0,0,.18); }
.pp-product-fil-txt{ font-size:12px; font-weight:600; color:var(--ink2,#64748B);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.pp-product-add.is-view{ background:transparent; color:var(--ink,#0F172A);
  border:1px solid var(--line2,#E2E8F0); }
.pp-product-add.is-view:hover{ border-color:var(--violet,#7C5CFF); color:var(--violet,#7C5CFF); }
/* ═══ конец блока, переехавшего из product-card.js ════════════════════════════════════ */

/* Sticky cart-pill.
   --bs-bottom-reserve (tokens.css) = max(--bs-cc-h, --bs-tab-h) — сколько нижней кромки
   занято чужим хромом: cookie-плашкой и/или мобильной панелью разделов. Пилюля встаёт
   над ним и не перекрывается. Ни того, ни другого нет → 0, положение как было.
   🔴 Именно max, а не сумма: плашка сама поднимается над панелью, её высота панель уже
   включает — сложение подкинуло бы корзину на две высоты вверх. */
.pp-cart-pill{ position:fixed; z-index:118; right:16px;
  bottom:calc(16px + env(safe-area-inset-bottom) + var(--bs-bottom-reserve,0px));
  display:inline-flex; align-items:center; gap:8px; padding:12px 18px; border:0; cursor:pointer;
  background:var(--grad-hero); color:#fff; border-radius:var(--pill,999px);
  box-shadow:0 14px 30px -8px rgba(124,92,255,.75); font:800 15px var(--font-display);
  font-variant-numeric:tabular-nums; animation:pp-cart-pop .28s cubic-bezier(.2,1.3,.5,1); }
.pp-cart-pill:hover{ transform:translateY(-2px); box-shadow:0 20px 40px -10px rgba(124,92,255,.85); }
.pp-cart-pill[hidden]{ display:none; }
.pp-cart-pill-ico{ font-size:18px; }
@keyframes pp-cart-pop{ 0%{ transform:scale(.7); opacity:0 } 100%{ transform:scale(1); opacity:1 } }

/* Панель корзины (модалка) */
.pp-modal-cart{ width:min(480px,100%); }
.pp-modal-cart .pp-modal-body{ padding:14px 16px 16px; }
.pp-cart-list{ display:flex; flex-direction:column; gap:10px; }
.pp-cart-row{ display:flex; align-items:center; gap:12px; }
.pp-cart-thumb{ width:56px; height:56px; flex:0 0 auto; border-radius:12px; object-fit:cover; background:var(--bg2); }
.pp-cart-thumb.is-poster{ background:
    radial-gradient(80px 80px at 30% 25%, rgba(124,92,255,.18), transparent 70%),
    radial-gradient(90px 90px at 75% 80%, rgba(255,94,126,.16), transparent 70%), var(--bg2); }
.pp-cart-info{ flex:1 1 auto; min-width:0; }
.pp-cart-title{ font:800 14px var(--font-display); letter-spacing:-.01em; color:var(--ink);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.pp-cart-unit{ font:600 12px var(--font); color:var(--ink2); font-variant-numeric:tabular-nums; }
.pp-cart-qty{ display:inline-flex; align-items:center; gap:2px; flex:0 0 auto;
  background:var(--bg2); border-radius:12px; padding:2px; }
.pp-qty-btn{ width:32px; height:32px; border:0; background:#fff; border-radius:9px; cursor:pointer;
  font:800 16px var(--font); color:var(--violet); line-height:1; box-shadow:var(--shadow); }
.pp-qty-btn:hover{ background:var(--violet); color:#fff; }
.pp-qty-n{ min-width:26px; text-align:center; font:800 14px var(--font-display); font-variant-numeric:tabular-nums; }
.pp-cart-del{ width:32px; height:32px; flex:0 0 auto; border:0; background:none; cursor:pointer;
  color:var(--ink2); font-size:15px; border-radius:9px; }
.pp-cart-del:hover{ color:var(--err,#FF4D5E); background:rgba(255,77,94,.08); }
.pp-cart-sum{ display:flex; align-items:baseline; justify-content:space-between; gap:8px;
  margin-top:14px; padding-top:12px; border-top:1px solid var(--line2,#eee); }
.pp-cart-sum span{ font:700 13px var(--font); color:var(--ink2); }
.pp-cart-sum b{ font:800 22px var(--font-display); color:var(--ink); font-variant-numeric:tabular-nums; }
.pp-cart-note{ font:500 12px var(--font); color:var(--ink2); line-height:1.45; margin:6px 0 0; }
.pp-cart-form{ display:flex; flex-direction:column; gap:8px; margin-top:14px; }
.pp-cart-form .pp-btn-primary{ min-height:52px; }
.pp-cart-ok{ text-align:center; padding:20px 8px; display:flex; flex-direction:column; align-items:center; gap:8px; }
.pp-cart-ok-klikko{ width:120px; height:auto; }
.pp-cart-ok-title{ font:800 20px var(--font-display); color:var(--ink); }
.pp-cart-ok-sub{ font:500 14px var(--font); color:var(--ink2); line-height:1.5; margin:0; max-width:320px; }
.pp-cart-ok .pp-btn{ margin-top:8px; min-height:46px; }
/* НОМЕР ЗАКАЗА в подтверждении покупателю — чтобы можно было сослаться. Моно .bs-code
   наследует двухтоновый вид площадки; текст выделяемый (можно скопировать вручную). */
.pp-cart-ok-code{ font:600 14px var(--font); color:var(--ink2); display:inline-flex;
  align-items:center; gap:8px; padding:8px 14px; background:var(--bg2); border-radius:12px; }
.pp-cart-ok-code .bs-code{ font-size:15px; user-select:all; -webkit-user-select:all; }

/* ============ РЕДАКТОР КАТАЛОГА (кабинет мастера) ============ */
.pp-cat-toolbar{ display:flex; gap:8px; margin-bottom:10px; flex-wrap:wrap; }
/* D0: у .pp-btn база `width:100%`, а тулбар — flex-контейнер → owner-кнопка растягивалась
   на всю колонку (замер 1440: 1328×44 — полоса во всю ширину ради одного вторичного действия).
   Ширина по содержимому; тач-таргет держит min-height. */
.pp-cat-toolbar .pp-btn{ min-height:44px; width:auto; }
.pp-btn-ghost{ background:transparent; color:var(--ink2); border:1.5px solid transparent; }
.pp-btn-ghost:hover{ background:var(--bg2); }
.pp-btn-ghost.is-danger{ color:var(--err); }
.pp-btn-ghost.is-danger:hover{ background:rgba(255,77,94,.08); }
.pp-btn-sm{ min-height:40px; padding:0 14px; font-size:13px; }
.pp-icon-btn{ width:44px; height:44px; flex:0 0 auto; border:1.5px solid var(--line2); background:#fff;
  border-radius:12px; cursor:pointer; color:var(--ink2); font-size:18px; line-height:1; transition:all .15s; }
.pp-icon-btn:hover{ border-color:var(--violet); color:var(--violet); }
.pp-icon-btn.is-danger:hover{ border-color:var(--err); color:var(--err); }
.pp-icon-btn:focus-visible{ outline:none; box-shadow:0 0 0 3px rgba(124,92,255,.35); }
.pp-prod-list{ display:flex; flex-direction:column; gap:8px; }
.pp-prod-row{ display:flex; align-items:center; gap:12px; padding:10px; border:1px solid var(--line);
  border-radius:16px; background:#fff; }
.pp-prod-thumb{ width:52px; height:52px; flex:0 0 auto; border-radius:12px; object-fit:cover; background:var(--bg2); }
.pp-prod-thumb.is-3d{ display:flex; align-items:center; justify-content:center; font-size:22px; color:var(--violet); }
.pp-prod-meta{ flex:1 1 auto; min-width:0; }
.pp-prod-title{ font:700 14px var(--font); color:var(--ink); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.pp-prod-sub{ font:600 12px var(--font); color:var(--ink2); font-variant-numeric:tabular-nums; }
.pp-prod-status{ font:700 11px var(--font); padding:4px 9px; border-radius:var(--pill); white-space:nowrap; }
.pp-prod-status.is-pub{ color:#0F7A49; background:rgba(31,191,117,.12); }
.pp-prod-status.is-draft{ color:#8A6D00; background:rgba(255,159,28,.14); }
@media(max-width:520px){ .pp-prod-status{ display:none; } }
.pp-menu{ position:fixed; z-index:130; min-width:200px; background:#fff; border:1px solid var(--line2);
  border-radius:14px; box-shadow:var(--shadow-lg); padding:6px; }
.pp-menu button{ display:flex; width:100%; gap:8px; align-items:center; text-align:left; padding:11px 12px;
  border:0; background:none; border-radius:10px; cursor:pointer; font:600 13px var(--font); color:var(--ink); }
.pp-menu button:hover{ background:var(--bg2); }
.pp-menu button.is-danger{ color:var(--err); }
.pp-menu button.is-danger:hover{ background:rgba(255,77,94,.08); }
.pp-modal-form,.pp-modal-cats{ width:min(760px,100%); min-width:0; max-width:100%; max-height:92vh; max-height:92dvh; display:flex; flex-direction:column; }
.pp-modal-cats{ width:min(520px,100%); }
/* Превью-колонка = ширина боевой карточки маркетплейса. .pp-mk-grid фактически рендерит тайл
   246–311px по десктоп-брейкпоинтам (5-кол ≥1440 = 246; 4-кол 900–1439 = 289–311); 272px сидит
   в центре диапазона на всех ширинах. Раньше 240px → превью было у́же любого тайла («суженый»). */
.pp-form-wizard{ display:grid; grid-template-columns:1fr 272px; gap:18px; padding:16px; overflow:auto; }
@media(max-width:640px){ .pp-form-wizard{ grid-template-columns:1fr; } }
.pp-fieldset{ border:0; margin:0 0 14px; padding:0; }
.pp-fieldset legend{ font:800 13px var(--font-display); color:var(--ink); padding:0; margin:0 0 10px; }
.pp-form-preview{ position:sticky; top:0; align-self:start; }
/* Карточка превью = размер тайла маркетплейса. Десктоп: заполняет 272px-колонку. Мобайл
   (1 колонка, order:-1): НЕ растягиваем на всю ширину модалки — держим тайл-размер и центрируем,
   чтобы «как увидит покупатель» = реальный тайл, а не гигант. */
.pp-form-preview .pp-product{ width:272px; max-width:100%; margin-inline:auto; }
.pp-preview-tag{ font:700 11px var(--font); color:var(--ink2); text-transform:uppercase; letter-spacing:.04em; margin-bottom:8px; }
@media(max-width:640px){ .pp-form-preview{ order:-1; } .pp-form-preview .pp-preview-tag{ text-align:center; } }
.pp-seg{ display:inline-flex; background:var(--bg2); border-radius:14px; padding:4px; gap:4px; }
.pp-seg button{ border:0; background:none; padding:9px 14px; border-radius:10px; cursor:pointer;
  font:700 13px var(--font); color:var(--ink2); min-height:40px; }
.pp-seg button.is-active{ background:#fff; color:var(--ink); box-shadow:var(--shadow); }
.pp-modal-foot{ display:flex; align-items:center; justify-content:space-between; gap:8px;
  padding:12px 16px; border-top:1px solid var(--line2); }
.pp-foot-right{ display:flex; gap:8px; margin-left:auto; }
.pp-modal-foot .pp-btn{ min-height:44px; }
.pp-cat-rows{ display:flex; flex-direction:column; gap:8px; margin-bottom:12px; }
.pp-cat-row{ display:flex; gap:8px; align-items:center; }
.pp-cat-name{ flex:1 1 auto; }
.pp-cat-add{ display:flex; gap:8px; align-items:center; }
.pp-cat-add .pp-input{ flex:1 1 auto; }

/* =====================================================
   МИНИ-CRM МАСТЕРА (канбан · сделка · клиенты) — pp-crm/pp-board/pp-lane/pp-deal
   ===================================================== */
.pp-crm{ padding-top:4px; }
.pp-crm-bar{ display:flex; align-items:center; justify-content:space-between; gap:10px; margin:4px 0 14px; flex-wrap:wrap; }
.pp-crm-bar-l{ display:flex; align-items:center; gap:10px; min-width:0; }
.pp-crm-bar-r{ display:flex; align-items:center; gap:8px; flex:none; }
/* WP-REG-03: поиск сделки по номеру заказа — тихая find-зона между заголовком и действиями */
.pp-crm-find{ display:flex; align-items:center; gap:6px; flex:1 1 170px; min-width:0; max-width:260px; }
.pp-crm-find-in{ min-width:0; flex:1 1 auto; }
@media (max-width:640px){ .pp-crm-find{ order:3; flex-basis:100%; max-width:none; } }
.pp-crm-h{ font:800 20px var(--font-display); letter-spacing:-.02em; margin:0; }
.pp-crm-total{ font:700 13px var(--font); color:var(--ink2); background:var(--bg2); border-radius:var(--pill); padding:3px 10px; font-variant-numeric:tabular-nums; white-space:nowrap; }

.pp-board{ display:flex; gap:14px; overflow-x:auto; overflow-y:hidden; padding:2px 2px 10px; scroll-snap-type:x proximity; -webkit-overflow-scrolling:touch; scrollbar-width:thin; }
.pp-lane{ position:relative; flex:0 0 280px; scroll-snap-align:start; background:var(--bg2); border-radius:20px; padding:10px 10px 12px; display:flex; flex-direction:column; max-height:calc(100vh - 220px); max-height:calc(100dvh - 220px); }
@media(min-width:768px){ .pp-lane{ flex-basis:300px; } }
/* Цветной колонтитул стадии: 3px top-accent (C3), цвет = статус. Очередь печати — НЕ 5-hue радуга,
   а сдержанная палитра нейтраль+violet+amber+emerald: новый=нейтраль, в работе/печать=violet,
   отгрузка=amber, готово=emerald (цвет = смысл шага, не декор). */
.pp-lane::before{ content:""; position:absolute; left:14px; right:14px; top:0; height:3px;
  border-radius:0 0 3px 3px; background:var(--gray-300); }
.pp-lane.k-new::before{ background:var(--gray-300); } .pp-lane.k-work::before{ background:var(--violet); }
.pp-lane.k-print::before{ background:var(--violet); } .pp-lane.k-ship::before{ background:var(--amber-600); }
.pp-lane.k-done::before{ background:var(--emerald-600); }
/* Пустой лейн — колонтитул гаснет в нейтраль (нет активной работы на этом шаге). */
.pp-lane.pp-lane-empty::before{ background:var(--gray-200); }
.pp-lane-head{ display:flex; align-items:center; gap:7px; padding:2px 4px; }
.pp-lane-dot{ width:9px; height:9px; border-radius:50%; flex:none; background:var(--gray-400); }
.pp-lane-dot.k-new{ background:var(--gray-400); } .pp-lane-dot.k-work{ background:var(--violet); }
.pp-lane-dot.k-print{ background:var(--violet); } .pp-lane-dot.k-ship{ background:var(--amber-600); }
.pp-lane-dot.k-done{ background:var(--emerald-600); }
/* Бренд-иконка стадии (принтер/грузовик) вместо точки — очередь печати. Цвет = статус. */
.pp-lane-ico{ flex:none; display:inline-flex; align-items:center; justify-content:center;
  width:16px; height:16px; color:var(--ink2); }
.pp-lane.k-print .pp-lane-ico{ color:var(--violet); }
.pp-lane.k-ship .pp-lane-ico{ color:var(--amber-600); }
/* Пустой лейн — точка/иконка гаснет в нейтраль (тихо, §4). */
.pp-lane.pp-lane-empty .pp-lane-dot{ background:var(--gray-300); }
.pp-lane.pp-lane-empty .pp-lane-ico{ color:var(--gray-400); }
.pp-lane-name{ flex:1 1 auto; font:800 14px var(--font-display); letter-spacing:-.01em; color:var(--ink); min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.pp-lane-count{ font:700 12px var(--font); color:var(--ink2); background:#fff; border-radius:var(--pill); padding:1px 8px; font-variant-numeric:tabular-nums; }
.pp-lane-add{ flex:none; width:28px; height:28px; border:0; background:none; cursor:pointer; border-radius:9px; color:var(--ink2); font-size:18px; line-height:1; display:grid; place-items:center; }
.pp-lane-add:hover{ background:#fff; color:var(--ink); }
/* Сумма стадии — inline в шапке лейна (C3), не отдельным толстым блоком */
.pp-lane-sum{ flex:none; font:700 13px var(--font-display); color:var(--ink); font-variant-numeric:tabular-nums; white-space:nowrap; }
.pp-lane-body{ display:flex; flex-direction:column; gap:8px; overflow-y:auto; padding:2px; min-height:60px; }
/* Тихий drop-hint ТОЛЬКО в первом пустом лейне (C1): не «стена dashed-коробок» */
.pp-lane-drophint{ text-align:center; color:var(--ink2); font:500 12px var(--font);
  border:1px dashed var(--line); border-radius:12px; padding:12px 8px; opacity:.7; }

.pp-deal{ position:relative; background:var(--card); border-radius:var(--rad-sm); padding:10px; box-shadow:var(--shadow); cursor:pointer; border:1.5px solid transparent; }
.pp-deal:hover{ border-color:var(--line2); }
.pp-deal:focus-visible{ outline:none; border-color:var(--violet); box-shadow:0 0 0 3px rgba(124,92,255,.15); }
/* F-cockpit: миниатюра модели слева + колонка заголовка справа (flex-start, не baseline) */
.pp-deal-top{ display:flex; gap:10px; align-items:flex-start; padding-right:16px; }
.pp-deal-hd{ flex:1 1 auto; min-width:0; }
.pp-deal-title{ font:600 14px var(--font); color:var(--ink); line-height:1.25; overflow:hidden; display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; }
/* ── Миниатюра модели (обложка товара). thumb → <img> поверх; нет thumb → тихий штрих-плейсхолдер
   с бренд-кубом (данные-цвета сюда НЕ попадают — только серый куб). object-fit:cover, радиус. ── */
.pp-deal-thumb{ position:relative; flex:none; width:52px; height:52px; border-radius:var(--rad-xs);
  overflow:hidden; border:1px solid var(--line); display:grid; place-items:center; color:var(--ink2);
  background:repeating-linear-gradient(45deg,var(--bg2),var(--bg2) 5px,transparent 5px,transparent 10px),var(--card); }
.pp-deal-thumb.has-img{ background:var(--bg2); }
.pp-deal-thumb-ph{ display:grid; place-items:center; opacity:.6; }
.pp-deal-thumb-ph svg{ width:22px; height:22px; }
.pp-deal-thumb.has-img .pp-deal-thumb-ph{ opacity:0; }   /* img загрузилась → куб скрыт; onerror вернёт has-img=off → куб проступит */
.pp-deal-thumb-img{ position:absolute; inset:0; width:100%; height:100%; object-fit:cover; display:block; }
/* ── Строка филамента: свотчи физического колера пластика (перекрытые кружки) + чип материала.
   Свотчи = ЕДИНСТВЕННЫЕ литеральные data-цвета (из d.colors); остальное — токены. ── */
.pp-deal-fila{ display:flex; align-items:center; gap:8px; margin-top:8px; flex-wrap:wrap; }
.pp-deal-swatches{ display:inline-flex; align-items:center; }
.pp-deal-sw{ width:15px; height:15px; border-radius:50%; margin-left:-4px; border:2px solid var(--card);
  box-shadow:0 0 0 1px var(--line2); }
.pp-deal-sw:first-child{ margin-left:0; }
.pp-deal-sw-more{ margin-left:5px; font:700 10.5px var(--font); color:var(--ink2); font-variant-numeric:tabular-nums; }
.pp-deal-mat{ font:800 10.5px var(--font); letter-spacing:.03em; color:var(--ink2); background:var(--bg2);
  border-radius:var(--pill); padding:2px 7px; white-space:nowrap; }
/* Грамм-чип: вес модели в филаменте (d.grams). Иконка-катушка акцентом, число tabular. */
.pp-deal-grams{ display:inline-flex; align-items:center; gap:4px; font:800 10.5px var(--font);
  letter-spacing:.02em; color:var(--ink2); background:var(--bg2); border-radius:var(--pill);
  padding:2px 7px 2px 5px; white-space:nowrap; font-variant-numeric:tabular-nums; }
.pp-deal-grams svg{ color:var(--violet); flex:none; }
/* Чип материала (филамент): d.cost в ₽ = граммы × цена/кг ÷ 1000. Сестра .pp-deal-grams — ТА ЖЕ высота
   (карточка НЕ растёт: садится в тот же .pp-deal-fila рядом с грамм-чипом), но деньги ≠ вес → монета
   тёплым золотом (не фиолет катушки) + «₽» вместо «г». Только материал, НЕ полная себестоимость —
   квалификатор в title/aria карточки. Нейтральный bg2-пилл (не амбер-алерт .pp-deal-due) → не путается со статусом. */
.pp-deal-cost{ display:inline-flex; align-items:center; gap:4px; font:800 10.5px var(--font);
  letter-spacing:.02em; color:var(--ink2); background:var(--bg2); border-radius:var(--pill);
  padding:2px 7px 2px 5px; white-space:nowrap; font-variant-numeric:tabular-nums; }
.pp-deal-cost svg{ color:var(--amber-700); flex:none; }
/* Деньги-герой (C2): 16/800, emerald на выигрышной стадии */
.pp-deal-amount{ font:800 16px var(--font-display); color:var(--ink); flex:none; font-variant-numeric:tabular-nums; }
.pp-deal-amount.is-won{ color:var(--emerald-600); }
.pp-deal-foot{ display:flex; align-items:center; justify-content:space-between; gap:8px; margin-top:8px; padding-right:34px; }
/* Кто: цвет-хеш аватар + имя клиента (C2) */
.pp-deal-who{ display:inline-flex; align-items:center; gap:6px; min-width:0; flex:1 1 auto; }
.pp-deal-ava{ flex:none; width:20px; height:20px; border-radius:50%; display:grid; place-items:center;
  color:var(--cover-mono); font:800 10px var(--font-display); }
.pp-deal-client{ font:500 12px var(--font); color:var(--ink2); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; min-width:0; }
.pp-deal-client.is-muted{ opacity:.75; }
/* Мета: возраст сделки + источник-точка (C2) */
.pp-deal-meta{ flex:none; display:inline-flex; align-items:center; gap:8px; }
.pp-deal-age{ display:inline-flex; align-items:center; gap:3px; font:600 11px var(--font); color:var(--ink2); font-variant-numeric:tabular-nums; }
.pp-deal-age svg{ width:11px; height:11px; flex:none; }
/* Источник = точка+подпись (humanized), не тяжёлый пилл; подпись нейтральна, сигнал несёт точка */
.pp-src{ display:inline-flex; align-items:center; gap:4px; font:600 11px var(--font); color:var(--ink2); white-space:nowrap; flex:none; text-decoration:none; }
.pp-src:hover{ color:var(--ink); }
.pp-src-dot{ width:6px; height:6px; border-radius:50%; flex:none; background:var(--gray-400); }
.pp-src-store .pp-src-dot{ background:var(--blue); } .pp-src-direct .pp-src-dot{ background:var(--gray-400); }
.pp-deal-next{ position:absolute; right:6px; bottom:6px; width:32px; height:32px; border:0; cursor:pointer; background:var(--bg2); color:var(--ink2); border-radius:10px; font-size:16px; line-height:1; display:grid; place-items:center; transition:background .15s,color .15s,transform .15s; }
.pp-deal-next::before{ content:""; position:absolute; inset:-6px; }
.pp-deal-next:hover{ background:var(--violet); color:#fff; } .pp-deal-next:active{ transform:scale(.92); }
/* НОМЕР ЗАКАЗА (bo…) — тихий вторичный идентификатор. Моно-вид наследуется от
   .bs-chip--display; здесь только раскладка. 4px к заголовку = tight grouping
   (заголовок+номер = один смысловой блок), foot отделён своим 8px. */
.pp-deal-coderow{ margin-top:4px; display:flex; align-items:center; gap:6px; flex-wrap:wrap; }
.pp-deal-code{ max-width:100%; }
/* F2 «Оплачено» — glance-verdict бейдж на карточке (покупка эмитит attrs.paid=true).
   Метка-статус (role=text), НЕ тап-таргет → карточка сохраняет один primary (открыть сделку).
   Success-семантика: emerald + 💰 + слово «Оплачено» (цвет НЕ единственный сигнал, WCAG).
   emerald-800 на emerald-50 = 5.73:1 (проходит AA для мелкого текста). */
.pp-deal-badges{ display:flex; flex-wrap:wrap; gap:6px; margin-top:6px; }
.pp-deal-paid{ display:inline-flex; align-items:center; gap:5px; font:800 11px var(--font);
  color:var(--emerald-800); background:var(--emerald-50); border:1px solid var(--emerald-200);
  border-radius:var(--pill); padding:3px 9px; font-variant-numeric:tabular-nums; white-space:nowrap; }
.pp-deal-paid-ico{ font-size:11px; line-height:1; }
/* Amber-двойник «Срок» (C2) — рисуется только если derivable client-side (есть открытая задача-срок) */
.pp-deal-due{ display:inline-flex; align-items:center; gap:5px; font:800 11px var(--font);
  color:var(--amber-700); background:var(--amber-50); border:1px solid var(--amber-200);
  border-radius:var(--pill); padding:3px 9px; white-space:nowrap; }
.pp-deal-due svg{ width:11px; height:11px; flex:none; }
/* deep-link из колокольчика (/crm.html?deal=…) — краткая подсветка нужной карточки */
.pp-deal-flash{ animation:pp-deal-flash 2.4s ease-out 1; }
@keyframes pp-deal-flash{ 0%,12%{ box-shadow:0 0 0 3px rgba(124,92,255,.35); border-color:var(--violet); } 100%{ box-shadow:var(--shadow); border-color:transparent; } }
@media(prefers-reduced-motion:reduce){ .pp-deal-flash{ animation:none; border-color:var(--violet); } }
/* В модалке сделки — номер с подписью, отдельный блок под шапкой */
.pp-deal-modal-code{ display:flex; align-items:center; gap:8px; flex-wrap:wrap;
  margin-bottom:12px; padding-bottom:12px; border-bottom:1px solid var(--line); }
.pp-deal-modal-code-lbl{ font:600 12px var(--font); color:var(--ink2); }

.pp-deal-modal{ width:min(560px,100%); }
.pp-tl-wrap{ border-top:1px solid var(--line2); margin-top:6px; padding-top:14px; }
.pp-tl-lbl{ font:800 12px var(--font-display); color:var(--ink); margin-bottom:10px; }
.pp-timeline{ list-style:none; margin:0 0 12px; padding:0; display:flex; flex-direction:column; gap:12px; }
.pp-tl-item{ display:flex; gap:10px; align-items:flex-start; position:relative; }
.pp-tl-item:not(:last-child)::after{ content:""; position:absolute; left:11px; top:24px; bottom:-12px; width:2px; background:var(--line2); }
.pp-tl-dot{ width:24px; height:24px; border-radius:50%; flex:none; display:grid; place-items:center; font-size:12px; background:var(--bg2); color:var(--ink2); z-index:1; }
.pp-tl-dot.k-created{ background:rgba(124,92,255,.14); color:var(--violet); } .pp-tl-dot.k-stage{ background:rgba(46,107,255,.12); color:var(--blue); } .pp-tl-dot.k-note{ background:var(--bg2); color:var(--ink2); }
.pp-tl-body p{ margin:0; font:500 13px var(--font); color:var(--ink); } .pp-tl-time{ font:500 11px var(--font); color:var(--ink2); }
.pp-tl-muted{ color:var(--ink2); font:500 13px var(--font); }
.pp-note-add{ display:flex; gap:8px; } .pp-note-add .pp-input{ flex:1 1 auto; } .pp-note-add .pp-btn{ width:auto; flex:none; }

.pp-client-list{ display:flex; flex-direction:column; gap:8px; }
.pp-client-row{ display:flex; align-items:center; gap:12px; background:#fff; border-radius:16px; padding:10px 12px; box-shadow:var(--shadow); }
/* Аватар: базовый бренд-градиент; цвет-хеш .pp-av-N (ниже) переопределяет per-клиент (C4) */
.pp-client-av{ width:40px; height:40px; border-radius:50%; flex:none; display:grid; place-items:center; background:var(--grad-2); color:var(--cover-mono); font:800 16px var(--font-display); }
.pp-client-meta{ flex:1 1 auto; min-width:0; }
/* Имя = flex-строка: текст (ellipsis) + теги-чипы (C4) */
.pp-client-name{ display:flex; align-items:center; gap:6px; min-width:0; }
.pp-client-nm{ font:700 14px var(--font); color:var(--ink); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; min-width:0; }
.pp-client-tags{ flex:none; display:inline-flex; align-items:center; gap:4px; }
.pp-client-tag{ font:700 10px var(--font); color:var(--violet-700); background:var(--violet-50);
  border-radius:var(--pill); padding:1px 7px; white-space:nowrap; }
.pp-client-sub{ font:500 12px var(--font); color:var(--ink2); display:flex; align-items:center; gap:8px; overflow:hidden; white-space:nowrap; }
/* Источник-чип строки клиента (C4): пилл с точкой-статусом */
.pp-client-source{ flex:none; display:inline-flex; align-items:center; gap:5px; padding:2px 9px;
  border-radius:var(--pill); background:var(--bg2); color:var(--ink2); font:600 11px var(--font); white-space:nowrap; }
.pp-client-deals{ font:800 14px var(--font-display); color:var(--ink); background:var(--bg2); border-radius:var(--pill); padding:2px 11px; font-variant-numeric:tabular-nums; flex:none; }
.pp-client-row .pp-btn{ width:auto; flex:none; }
@media(prefers-reduced-motion:reduce){ .pp-deal-next,.pp-deal,.pp-spring{ transition:none; } }

/* форма заявки с витрины (петля витрина→CRM) */
.pp-order-form{ display:flex; flex-direction:column; gap:8px; margin-top:4px; }
.pp-order-form .pp-btn-primary{ min-height:50px; margin-top:2px; }
.pp-order-ok{ text-align:center; font:700 14px var(--font); color:#0F7A49;
  background:rgba(31,191,117,.10); border:1px solid rgba(31,191,117,.25);
  border-radius:var(--r); padding:16px; margin-top:4px; }

/* =====================================================
   CRM standalone /crm.html — шапка · control-bar · табы · задачи · воронка ·
   дашборд-плашки · скелеты · overflow-меню строки. Всё на токенах (ноль hex,
   белый = var(--card)). Плотность = эталон кабинета/@handle (D0-гейт).
   ===================================================== */
/* Шапка: H1 + подзаголовок слева, answer-strip/итог справа (C9) */
.pp-crm-head{ display:flex; align-items:flex-start; justify-content:space-between; gap:var(--sp-3);
  flex-wrap:wrap; margin:18px 0 8px; }
.pp-crm-head > div{ min-width:0; }
.pp-crm-head h1, .pp-crm-title{ font:800 var(--fs-xl)/1.1 var(--font-display);
  letter-spacing:-.02em; color:var(--ink); margin:0; }
.pp-crm-sub{ font:500 var(--fs-sm) var(--font); color:var(--ink2); margin:2px 0 0; }

/* Единая control-bar (sticky): tab-strip + поиск + Фильтр▾ + primary «＋Сделка» */
.pp-crm-toolbar{ display:flex; align-items:center; gap:var(--sp-2);
  position:sticky; top:0; z-index:20; background:var(--bg);
  padding:var(--sp-2) 0; margin-bottom:var(--sp-3); }
.pp-crm-tools{ display:flex; align-items:center; gap:var(--sp-2); flex:none; margin-left:auto; }

/* Табы (role=tablist): 4 вида Сделки/Клиенты/Задачи/Дашборд */
.pp-crm-nav{ display:flex; gap:6px; overflow-x:auto; flex:1 1 auto; min-width:0;
  scrollbar-width:none; -webkit-overflow-scrolling:touch; }
.pp-crm-nav::-webkit-scrollbar{ display:none; }
.pp-crm-tab{ flex:none; display:inline-flex; align-items:center; gap:6px;
  height:34px; padding:0 14px; border:0; background:none; border-radius:var(--pill);
  cursor:pointer; font:600 var(--fs-sm) var(--font); color:var(--ink2); white-space:nowrap; }
.pp-crm-tab:hover{ background:var(--bg2); color:var(--ink); }
.pp-crm-tab[aria-selected=true]{ background:var(--violet-50); color:var(--violet); font-weight:700; }
.pp-crm-tab:focus-visible{ outline:2px solid var(--violet); outline-offset:2px; }
.pp-crm-tab .count{ font:700 var(--fs-xs) var(--font); color:inherit; background:var(--bg2);
  border-radius:var(--pill); padding:1px 7px; font-variant-numeric:tabular-nums; }
.pp-crm-tab[aria-selected=true] .count{ background:var(--card); }

/* Фильтр — details-popover (progressive disclosure) + активные чипы + Сбросить */
.pp-crm-filter{ position:relative; flex:none; }
.pp-crm-filter > summary{ list-style:none; cursor:pointer; display:inline-flex;
  align-items:center; gap:6px; height:34px; padding:0 12px; border:1.5px solid var(--line2);
  border-radius:var(--pill); background:var(--card); font:600 var(--fs-sm) var(--font); color:var(--ink2); }
.pp-crm-filter > summary::-webkit-details-marker{ display:none; }
.pp-crm-filter[open] > summary{ border-color:var(--violet); color:var(--violet); }
.pp-crm-filter > summary:focus-visible{ outline:2px solid var(--violet); outline-offset:2px; }
.pp-crm-filter-pop{ position:absolute; right:0; top:calc(100% + 6px); z-index:30; min-width:210px;
  background:var(--card); border:1px solid var(--line2); border-radius:var(--rad-md);
  box-shadow:var(--shadow); padding:var(--sp-3); display:flex; flex-direction:column; gap:var(--sp-2); }
.pp-crm-filter-reset{ border:0; background:none; cursor:pointer; align-self:flex-start;
  font:600 var(--fs-xs) var(--font); color:var(--violet); padding:2px 0; }
.pp-crm-filter-reset:hover{ text-decoration:underline; }
/* Настройка «Цена филамента, ₽/кг» — реюз .pp-crm-filter (summary-пилл 34px + details-поповер).
   Тихий тертиарный контрол рядом с primary «Заказ»; свёрнут показывает текущее значение. */
.pp-fila > summary svg{ color:var(--amber-700); flex:none; }
.pp-fila-pop{ min-width:230px; gap:var(--sp-2); }
.pp-fila-lbl{ font:600 var(--fs-sm) var(--font); color:var(--ink); }
.pp-fila-hint{ font:500 var(--fs-xs) var(--font); color:var(--ink2); line-height:1.4; margin:-2px 0 2px; }
.pp-fila-row{ display:flex; align-items:center; gap:var(--sp-2); }
.pp-fila-in{ flex:1 1 auto; min-width:0; height:34px; padding:0 var(--sp-3);
  font:600 var(--fs-sm) var(--font); border-radius:var(--rad-md); font-variant-numeric:tabular-nums; }
.pp-fila-in::-webkit-outer-spin-button,.pp-fila-in::-webkit-inner-spin-button{ -webkit-appearance:none; margin:0; }
.pp-fila-in[type=number]{ -moz-appearance:textfield; appearance:textfield; }
.pp-fila-unit{ flex:none; font:600 var(--fs-sm) var(--font); color:var(--ink2); }
.pp-fila-actions{ display:flex; align-items:center; gap:var(--sp-3); }
.pp-fila-actions .pp-btn-sm{ min-height:34px; }
.pp-fila-clear{ border:0; background:none; cursor:pointer; font:600 var(--fs-xs) var(--font);
  color:var(--ink2); padding:2px 4px; }
.pp-fila-clear:hover{ color:var(--rose-600); text-decoration:underline; }
.pp-crm-chips{ display:flex; flex-wrap:wrap; gap:6px; margin:0 0 var(--sp-3); }
.pp-crm-chips:empty{ margin:0; }
.pp-crm-chip{ display:inline-flex; align-items:center; gap:5px; height:26px; padding:0 6px 0 10px;
  border-radius:var(--pill); background:var(--violet-50); color:var(--violet);
  font:600 var(--fs-xs) var(--font); }
.pp-crm-chip button{ border:0; background:none; cursor:pointer; color:inherit; line-height:0;
  display:grid; place-items:center; width:18px; height:18px; border-radius:var(--pill); }
.pp-crm-chip button:hover{ background:var(--violet-100); }

/* Вид «Задачи»: строки ~52px, чекбокс 20px (hit 44 через ::before) */
.pp-task-list{ display:flex; flex-direction:column; gap:var(--sp-2); }
.pp-task-row{ display:flex; align-items:center; gap:var(--sp-2); min-height:52px;
  background:var(--card); border:1.5px solid transparent; border-radius:var(--rad-md);
  padding:10px 12px; box-shadow:var(--shadow); }
.pp-task-row:hover{ border-color:var(--line2); }
.pp-task-check{ position:relative; flex:none; width:20px; height:20px; border-radius:6px;
  border:1.5px solid var(--line2); background:var(--card); cursor:pointer; }
.pp-task-check::before{ content:""; position:absolute; inset:-12px; }
.pp-task-check:focus-visible{ outline:2px solid var(--violet); outline-offset:2px; }
.pp-task-check[data-done]{ background:var(--emerald-500); border-color:var(--emerald-500); }
.pp-task-check[data-done]::after{ content:""; position:absolute; left:6px; top:2px;
  width:5px; height:10px; border:solid var(--card); border-width:0 2px 2px 0; transform:rotate(45deg); }
.pp-task-title{ flex:1 1 auto; min-width:0; font:600 var(--fs-sm) var(--font); color:var(--ink);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.pp-task-title[data-done]{ text-decoration:line-through; color:var(--ink2); }
.pp-task-due{ flex:none; display:inline-flex; align-items:center; gap:4px;
  font:500 var(--fs-xs) var(--font); color:var(--ink2); font-variant-numeric:tabular-nums; }
.pp-task-due.is-overdue{ background:var(--rose-50); color:var(--rose-700);
  border-radius:var(--pill); padding:2px 8px; }
.pp-task-deal{ flex:none; font:600 var(--fs-xs) var(--font); color:var(--violet); text-decoration:none; }
.pp-task-deal:hover{ text-decoration:underline; }

/* Вид «Дашборд»: плашки KPI + HERO-verdict в 1-й + воронка */
.pp-stats{ display:grid; grid-template-columns:repeat(4,1fr); gap:var(--sp-3); margin-bottom:var(--sp-5); }
@media(max-width:768px){ .pp-stats{ grid-template-columns:1fr 1fr; } }
.pp-stat{ background:var(--card); border:1.5px solid var(--line2); border-radius:var(--rad-lg);
  padding:var(--sp-4); }
.pp-stat.is-hero{ background:var(--violet-50); border-color:var(--violet-200); }
.pp-num{ font:800 var(--fs-xl)/1 var(--font-display); color:var(--ink); font-variant-numeric:tabular-nums; }
.pp-stat-label{ font:500 var(--fs-xs) var(--font); color:var(--ink2); margin-top:4px; }
.pp-stat-verdict{ display:inline-flex; align-items:center; gap:5px; margin-top:6px;
  font:700 var(--fs-xs) var(--font); }
.pp-stat-verdict.is-good{ color:var(--emerald-700); }
.pp-stat-verdict.is-bad{ color:var(--rose-700); }

.pp-funnel{ display:flex; flex-direction:column; gap:var(--sp-2); }
.pp-funnel-stage{ display:grid; grid-template-columns:120px 1fr auto; align-items:center; gap:var(--sp-3); }
.pp-funnel-stage > .label{ font:600 var(--fs-sm) var(--font); color:var(--ink);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.pp-funnel-bar{ height:28px; min-width:2px; border-radius:8px; background:var(--grad-2);
  display:flex; align-items:center; justify-content:flex-end; padding:0 8px;
  color:var(--card); font:700 var(--fs-xs)/1 var(--font); font-variant-numeric:tabular-nums; }
.pp-funnel-meta{ font:500 var(--fs-sm) var(--font); color:var(--ink2);
  font-variant-numeric:tabular-nums; white-space:nowrap; }

/* =====================================================
   ЗАХОД B — премиум-дашборд: период · дельты · «откуда деньги» · «требует внимания».
   Dense-кокпит (§16 D0): только токены, бренд-иконки, money-hero язык карточек борда.
   ===================================================== */
.pp-dash{ display:flex; flex-direction:column; gap:var(--sp-4); }
.pp-dash .pp-stats{ margin-bottom:0; }   /* вертикальный ритм держит gap контейнера */

/* Период сводки — компактный сегмент ~32px, оба варианта видимы (scope периода явен) */
.pp-dash-head{ display:flex; justify-content:flex-end; }
.pp-dash-period{ display:inline-flex; background:var(--bg2); border-radius:var(--rad-md); padding:3px; gap:3px; }
.pp-dash-period button{ border:0; background:none; cursor:pointer; height:30px; padding:0 12px;
  border-radius:var(--rad-sm); font:600 var(--fs-xs) var(--font); color:var(--ink2); font-variant-numeric:tabular-nums; }
.pp-dash-period button:hover{ color:var(--ink); }
.pp-dash-period button.is-active{ background:var(--card); color:var(--ink); box-shadow:var(--shadow); font-weight:700; }
.pp-dash-period button:focus-visible{ outline:2px solid var(--violet); outline-offset:2px; }

/* Дельты период-над-периодом — 3 компактных чипа (динамика); accent на левом канте */
.pp-dash-deltas{ display:grid; grid-template-columns:repeat(3,1fr); gap:var(--sp-3); }
.pp-delta{ background:var(--card); border:1.5px solid var(--line2); border-left-width:3px;
  border-radius:var(--rad-md); padding:var(--sp-3) var(--sp-4); }
.pp-delta-lbl{ font:600 var(--fs-xs) var(--font); color:var(--ink2); }
.pp-delta-val{ font:800 var(--fs-lg)/1.05 var(--font-display); color:var(--ink);
  font-variant-numeric:tabular-nums; margin-top:2px; white-space:nowrap; }
.pp-delta-trend{ display:inline-flex; align-items:center; gap:4px; margin-top:4px;
  font:700 var(--fs-xs) var(--font); font-variant-numeric:tabular-nums; }
.pp-delta-trend svg{ width:13px; height:13px; }
.pp-delta-new{ font-weight:600; }
.pp-delta.is-up{ border-left-color:var(--emerald-500); }
.pp-delta.is-up .pp-delta-trend{ color:var(--emerald-700); }
.pp-delta.is-down{ border-left-color:var(--rose-300); }
.pp-delta.is-down .pp-delta-trend{ color:var(--rose-600); }
.pp-delta.is-flat{ border-left-color:var(--line2); }
.pp-delta.is-flat .pp-delta-trend{ color:var(--ink2); }

/* Карточка секции дашборда — единый язык для «откуда деньги» / воронки / внимания */
.pp-dash-card{ background:var(--card); border:1.5px solid var(--line2); border-radius:var(--rad-lg);
  padding:var(--sp-4) var(--sp-5); }
.pp-dash-head-in{ margin-bottom:var(--sp-3); }
.pp-dash-title{ display:flex; align-items:center; gap:6px; margin:0;
  font:800 var(--fs-sm) var(--font-display); letter-spacing:-.01em; color:var(--ink); }
.pp-dash-title svg{ color:var(--violet); flex:none; }
.pp-dash-count{ margin-left:2px; font:700 var(--fs-xs) var(--font); color:var(--rose-700);
  background:var(--rose-50); border-radius:var(--pill); padding:1px 8px; font-variant-numeric:tabular-nums; }
.pp-dash-hint{ font:500 var(--fs-sm)/1.5 var(--font); color:var(--ink2); }

/* «Откуда приходят деньги» — money-hero бары (won_sum крупно emerald; бакет «Не указан» приглушён) */
.pp-srcmoney{ display:flex; flex-direction:column; gap:var(--sp-3); }
.pp-src-row{ display:grid; grid-template-columns:minmax(110px,1.1fr) 1.4fr auto; align-items:center; gap:var(--sp-3); }
.pp-src-row.is-muted{ opacity:.6; }
.pp-src-row-lbl{ min-width:0; font:700 var(--fs-sm) var(--font); color:var(--ink);
  overflow:hidden; text-overflow:ellipsis; }
.pp-src-row-sub{ display:block; font:500 var(--fs-xs) var(--font); color:var(--ink2);
  font-variant-numeric:tabular-nums; margin-top:1px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.pp-src-row-track{ height:10px; background:var(--bg2); border-radius:var(--pill); overflow:hidden; }
.pp-src-row-bar{ height:100%; min-width:4px; border-radius:var(--pill); background:var(--grad-2); }
.pp-src-row-money{ text-align:right; }
.pp-src-money-val{ font:800 var(--fs-md) var(--font-display); color:var(--emerald-600);
  font-variant-numeric:tabular-nums; white-space:nowrap; }
.pp-src-money-val.is-empty{ color:var(--ink2); font-weight:700; }

/* 2-колоночная зона: воронка | требует внимания */
.pp-dash-grid{ display:grid; grid-template-columns:1fr 1fr; gap:var(--sp-4); align-items:start; }

/* «Требует внимания» — список залипших сделок (клик → открыть сделку); пусто → спокойно */
.pp-attn-list{ display:flex; flex-direction:column; gap:var(--sp-2); max-height:340px; overflow-y:auto; }
.pp-attn-row{ display:flex; align-items:center; gap:var(--sp-3); padding:var(--sp-2) var(--sp-3);
  border:1px solid var(--line); border-radius:var(--rad-md); background:var(--card); cursor:pointer; }
.pp-attn-row:hover{ border-color:var(--line2); background:var(--bg2); }
.pp-attn-row:focus-visible{ outline:2px solid var(--violet); outline-offset:1px; }
.pp-attn-badge{ flex:none; display:inline-flex; align-items:center; gap:3px;
  font:700 11px var(--font); border-radius:var(--pill); padding:2px 8px; white-space:nowrap; }
.pp-attn-badge svg{ width:11px; height:11px; }
.pp-attn-badge.is-bad{ color:var(--rose-700); background:var(--rose-50); }
.pp-attn-badge.is-warn{ color:var(--amber-700); background:var(--amber-50); }
.pp-attn-body{ flex:1 1 auto; min-width:0; }
.pp-attn-title{ font:600 var(--fs-sm) var(--font); color:var(--ink);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.pp-attn-meta{ font:500 var(--fs-xs) var(--font); color:var(--ink2); margin-top:1px; }
.pp-attn-amount{ flex:none; font:800 var(--fs-sm) var(--font-display); color:var(--ink);
  font-variant-numeric:tabular-nums; white-space:nowrap; }
.pp-attn-ok{ display:flex; align-items:center; gap:var(--sp-3); padding:var(--sp-1) 0; }
.pp-attn-ok-ico{ flex:none; display:grid; place-items:center; width:38px; height:38px; border-radius:50%;
  background:var(--emerald-50); color:var(--emerald-600); }
.pp-attn-ok-title{ font:800 var(--fs-sm) var(--font-display); color:var(--ink); }
.pp-attn-ok-sub{ font:500 var(--fs-xs) var(--font); color:var(--ink2); margin-top:1px; }

@media(max-width:768px){
  .pp-dash-grid{ grid-template-columns:1fr; }
}
@media(max-width:520px){
  .pp-dash-deltas{ grid-template-columns:1fr; gap:var(--sp-2); }
  .pp-delta{ display:flex; align-items:center; gap:var(--sp-3); padding:var(--sp-2) var(--sp-4); }
  .pp-delta-lbl{ flex:1 1 auto; }
  .pp-delta-val{ margin-top:0; font-size:var(--fs-md); }
  .pp-delta-trend{ margin-top:0; }
  .pp-src-row{ grid-template-columns:1fr auto; }
  .pp-src-row-track{ display:none; }   /* узкий экран: бар прячем, метка+деньги остаются */
}

/* Overflow ⋯ строки клиента/задачи — icon-кнопка + popover-меню действий */
.pp-row-more{ position:relative; flex:none; }
.pp-row-more-btn{ position:relative; width:32px; height:32px; border:0; background:none;
  border-radius:var(--rad-sm); color:var(--ink2); cursor:pointer; display:grid; place-items:center; }
.pp-row-more-btn::before{ content:""; position:absolute; inset:-6px; }
.pp-row-more-btn:hover{ background:var(--bg2); color:var(--ink); }
.pp-row-more-btn:focus-visible{ outline:2px solid var(--violet); outline-offset:2px; }
.pp-row-more-menu{ position:absolute; right:0; top:calc(100% + 4px); z-index:30; min-width:172px;
  background:var(--card); border:1px solid var(--line2); border-radius:var(--rad-md);
  box-shadow:var(--shadow); padding:6px; display:flex; flex-direction:column; }
.pp-row-more-menu button{ display:flex; align-items:center; gap:8px; width:100%; border:0;
  background:none; cursor:pointer; text-align:left; padding:9px 10px; border-radius:var(--rad-sm);
  font:600 var(--fs-sm) var(--font); color:var(--ink); }
.pp-row-more-menu button:hover{ background:var(--bg2); }
.pp-row-more-menu button.is-danger{ color:var(--rose-700); }
.pp-row-more-menu button.is-danger:hover{ background:var(--rose-50); }

/* Loading = skeleton (плейсхолдеры размера контента, НЕ спиннер); shimmer из токенов */
.pp-crm-skel{ display:flex; flex-direction:column; gap:var(--sp-2); }
.pp-crm-skel-card, .pp-crm-skel-row, .pp-crm-skel-bar{
  background:linear-gradient(90deg, var(--bg2) 25%, var(--line) 37%, var(--bg2) 63%);
  background-size:400% 100%; animation:pp-crm-shimmer 1.4s ease-in-out infinite; }
.pp-crm-skel-card{ height:96px; border-radius:var(--rad-lg); }
.pp-crm-skel-row{ height:52px; border-radius:var(--rad-md); }
.pp-crm-skel-bar{ height:28px; border-radius:8px; }
@keyframes pp-crm-shimmer{ 0%{ background-position:100% 0; } 100%{ background-position:0 0; } }
@media(prefers-reduced-motion:reduce){
  .pp-crm-skel-card, .pp-crm-skel-row, .pp-crm-skel-bar{ animation:none; } }

/* Мобайл: control-bar в 2 ряда — tab-strip (скролл) сверху, поиск/фильтр/＋ снизу */
@media(max-width:640px){
  .pp-crm-toolbar{ flex-wrap:wrap; }
  .pp-crm-nav{ flex-basis:100%; order:1; }
  .pp-crm-tools{ order:2; width:100%; margin-left:0; }
  .pp-crm-tools .pp-btn{ flex:none; }
  .pp-funnel-stage{ grid-template-columns:92px 1fr auto; gap:var(--sp-2); }
}

/* =====================================================
   BUILD A — премиум-плотность CRM: answer-strip · единое поле поиска · онбординг-бэнд ·
   цвет-хеш аватары · CRM-scoped тихий primary. Только токены (§16 D0, brand-иконки).
   ===================================================== */
/* C9 answer-strip: «{сумма}₽ в работе · N сделок · N задач сегодня» (деньги — герой) */
.pp-crm-answer{ display:inline-flex; align-items:center; flex-wrap:wrap; gap:4px 0;
  font:600 var(--fs-sm) var(--font); color:var(--ink2); }
.pp-crm-answer-seg{ display:inline-flex; align-items:baseline; gap:5px; white-space:nowrap;
  padding:0 12px; font-variant-numeric:tabular-nums; }
.pp-crm-answer-seg:first-child{ padding-left:0; }
.pp-crm-answer-seg + .pp-crm-answer-seg{ border-left:1px solid var(--line2); }
.pp-crm-answer-money{ font:800 var(--fs-md) var(--font-display); color:var(--ink); }
.pp-crm-answer-money i{ font:600 var(--fs-xs) var(--font); font-style:normal; color:var(--ink2); }
.pp-crm-answer .is-muted{ color:var(--ink2); font-weight:600; }

/* C7 единое поле поиска: иконка ВНУТРИ + min-width floor → «Номер bo…» не клипается в «Нс» */
.pp-searchfield{ position:relative; display:inline-flex; align-items:center; flex:0 1 240px; min-width:200px; }
.pp-searchfield-ico{ position:absolute; left:11px; top:50%; transform:translateY(-50%);
  color:var(--ink2); pointer-events:none; line-height:0; }
.pp-searchfield-in{ width:100%; height:36px; padding:0 12px 0 34px; }
/* Заход B fix: type=search на iOS/WebKit добавляет нативную скруглённую «оболочку» + кружок-
   очистку → на мобиле свёрнутый клиент-поиск выглядел «бледным кружком». Гасим нативный chrome. */
.pp-searchfield-in{ -webkit-appearance:none; appearance:none; }
.pp-searchfield-in::-webkit-search-decoration,
.pp-searchfield-in::-webkit-search-cancel-button,
.pp-searchfield-in::-webkit-search-results-button{ -webkit-appearance:none; appearance:none; display:none; }
@media(max-width:640px){ .pp-searchfield{ flex-basis:100%; min-width:0; width:100%; } }

/* ── HERO пульс-стрип цеха (вид «Заказы») — герой-ответ над доской (§4). Один округлый
   дисплейный герой-число (var(--font-display)); лейблы/деньги = гротеск + tabular-nums.
   Плотность D0: высота полосы ~76px, паддинги --sp-3/--sp-5, пиллы 30px. ── */
.pp-pulse{ display:flex; align-items:stretch; gap:0; background:var(--card);
  border:1px solid var(--line2); border-radius:var(--rad-lg); box-shadow:var(--shadow);
  overflow:hidden; margin:var(--sp-1) 0 var(--sp-4); }
.pp-pulse-hero{ position:relative; flex:none; display:flex; align-items:center; gap:var(--sp-3);
  padding:var(--sp-3) var(--sp-5); }
.pp-pulse-hero::before{ content:""; position:absolute; inset:0; pointer-events:none;
  background:radial-gradient(120% 140% at 0% 0%, var(--violet-50), transparent 60%); }
.pp-pulse-num{ position:relative; font:600 40px/.9 var(--font-display); letter-spacing:-.03em;
  color:var(--ink); font-variant-numeric:tabular-nums; }
.pp-pulse-hero-meta{ position:relative; min-width:0; }
.pp-pulse-hero-lbl{ font:700 var(--fs-xs) var(--font); letter-spacing:.03em; text-transform:uppercase; color:var(--ink2); }
.pp-pulse-verdict{ display:inline-flex; align-items:center; gap:5px; margin-top:5px;
  font:700 var(--fs-xs) var(--font); padding:3px 8px; border-radius:var(--pill);
  background:var(--bg2); color:var(--ink2); }
.pp-pulse-verdict svg{ width:12px; height:12px; flex:none; }
.pp-pulse-verdict.is-good{ background:var(--emerald-50); color:var(--emerald-700); }
.pp-pulse-verdict.is-bad{ background:var(--rose-50); color:var(--rose-700); }
.pp-pulse-div{ flex:none; width:1px; background:var(--line); margin:var(--sp-3) 0; }
.pp-pulse-metrics{ flex:1 1 auto; min-width:0; display:flex; align-items:center; flex-wrap:wrap;
  gap:6px; padding:var(--sp-3) var(--sp-4); }
.pp-pulse-pill{ display:inline-flex; align-items:center; gap:6px; height:30px; padding:0 11px;
  border-radius:var(--pill); background:var(--bg2); font:600 var(--fs-sm) var(--font);
  color:var(--ink); white-space:nowrap; }
.pp-pulse-pill svg{ color:var(--ink2); flex:none; }
.pp-pulse-pill b{ font-weight:800; font-variant-numeric:tabular-nums; }
.pp-pulse-pill.is-print svg{ color:var(--violet); }
.pp-pulse-pill.is-ship svg{ color:var(--amber-600); }
.pp-pulse-pill.is-bad{ background:var(--rose-50); color:var(--rose-700); }
.pp-pulse-pill.is-bad svg{ color:var(--rose-700); }
.pp-pulse-money{ flex:none; display:flex; flex-direction:column; justify-content:center; gap:1px;
  padding:var(--sp-3) var(--sp-5); background:var(--gray-50); border-left:1px solid var(--line); min-width:150px; }
.pp-pulse-money-lbl{ font:700 var(--fs-xs) var(--font); letter-spacing:.03em; text-transform:uppercase; color:var(--ink2); }
.pp-pulse-money-val{ font:800 var(--fs-lg) var(--font); color:var(--ink); letter-spacing:-.02em; font-variant-numeric:tabular-nums; }
.pp-pulse-money-sub{ font:500 var(--fs-xs) var(--font); color:var(--ink2); }
@media(max-width:768px){
  .pp-pulse{ flex-wrap:wrap; }
  .pp-pulse-num{ font-size:34px; }
  .pp-pulse-metrics{ flex-basis:100%; order:3; border-top:1px solid var(--line); }
  .pp-pulse-money{ border-left:0; margin-left:auto; }
}

/* ── Честный пустой старт вида «Заказы» (замена barren): ghost-карточка «пример» + мост к моату
   + один primary. Компактная панель, НЕ герой на пол-экрана (D0). ── */
.pp-es{ display:grid; grid-template-columns:260px 1fr; gap:var(--sp-5); align-items:center;
  background:var(--card); border:1px solid var(--line2); border-radius:var(--rad-lg);
  box-shadow:var(--shadow); padding:var(--sp-6); margin:var(--sp-1) 0 0; }
.pp-es-ghost{ background:var(--bg2); border:1px solid var(--line); border-radius:var(--rad-lg); padding:var(--sp-3); }
.pp-es-ghost-head{ display:flex; align-items:center; gap:var(--sp-2); padding:2px 4px var(--sp-2); }
.pp-es-ghost-head .pp-lane-dot{ background:var(--gray-400); }
.pp-es-card{ position:relative; background:var(--card); border:1.5px dashed var(--line2);
  border-radius:var(--rad-md); padding:var(--sp-3); }
.pp-es-badge{ position:absolute; top:8px; right:8px; font:800 10px var(--font); letter-spacing:.05em;
  text-transform:uppercase; color:var(--ink2); background:var(--bg2); padding:2px 7px; border-radius:var(--pill); }
.pp-es-card-top{ display:flex; gap:var(--sp-2); align-items:flex-start; }
.pp-es-thumb{ flex:none; width:44px; height:44px; border-radius:var(--rad-sm); display:grid; place-items:center;
  color:var(--violet); border:1px solid var(--line);
  background:radial-gradient(120% 120% at 30% 20%, var(--violet-100), transparent 70%), var(--card); }
.pp-es-card-hd{ min-width:0; }
.pp-es-card-title{ font:700 var(--fs-sm) var(--font); color:var(--ink2); }
.pp-es-body{ min-width:0; }
.pp-es-mascot{ display:block; width:56px; height:56px; object-fit:contain; margin-bottom:var(--sp-2);
  filter:drop-shadow(0 8px 14px rgba(124,92,255,.18)); }
.pp-es-title{ font:800 var(--fs-lg) var(--font-display); letter-spacing:-.02em; color:var(--ink); margin:0; }
.pp-es-sub{ font:500 var(--fs-sm) var(--font); color:var(--ink2); margin:var(--sp-2) 0 0; max-width:48ch; }
.pp-es-moat{ display:flex; align-items:center; flex-wrap:wrap; gap:6px; margin:var(--sp-4) 0; }
.pp-es-step{ display:inline-flex; align-items:center; gap:6px; font:700 var(--fs-xs) var(--font);
  color:var(--ink2); background:var(--bg2); padding:5px 10px; border-radius:var(--pill); }
.pp-es-step svg{ color:var(--violet); flex:none; }
.pp-es-arrow{ display:inline-flex; color:var(--gray-400); flex:none; }
.pp-es-cta{ display:flex; align-items:center; flex-wrap:wrap; gap:var(--sp-2); }
.pp-es-cta .pp-btn{ text-decoration:none; }
@media(max-width:768px){ .pp-es{ grid-template-columns:1fr; gap:var(--sp-4); padding:var(--sp-4); }
  .pp-es-ghost{ max-width:320px; } }

/* C2/C4 цвет-хеш аватары: 6 бренд-градиентов (--cover-N). Определены ПОСЛЕ .pp-client-av →
   переопределяют его дефолтный --grad-2 per-клиент; на .pp-deal-ava красят напрямую. */
.pp-av-1{ background:var(--cover-1); } .pp-av-2{ background:var(--cover-2); }
.pp-av-3{ background:var(--cover-3); } .pp-av-4{ background:var(--cover-4); }
.pp-av-5{ background:var(--cover-5); } .pp-av-6{ background:var(--cover-6); }

/* C7 тихий primary В ПРЕДЕЛАХ CRM (глобальный .pp-btn-primary НЕ трогаем): убираем «жирное свечение» */
.pp-crm .pp-btn-primary{ box-shadow:0 6px 16px -8px rgba(124,92,255,.5); }

/* ── Модалка «Управление группой» (секции: оформление/приватность/теги/правила/участники) ── */
.pp-manage-sec{ padding:14px 0; border-top:1px solid var(--line); }
.pp-manage-sec:first-of-type{ border-top:0; }
.pp-manage-h{ font:700 15px var(--font-display,var(--font)); color:var(--ink); margin-bottom:8px; }
.pp-manage-lbl{ font:600 12px var(--font); color:var(--ink2); margin-bottom:5px; }
.pp-manage-hint{ font:500 12px var(--font); color:var(--ink2); margin:-2px 0 8px; }
.pp-manage-row{ display:flex; gap:8px; flex-wrap:wrap; align-items:center; margin-top:8px; }
.pp-manage .pp-compose-text{ width:100%; }

/* ── КОМПАКТ-ДЕФОЛТЫ модалок создания/управления группой (DENSITY §1,§7) ─────────
   Скоуп .pp-authgate-card.pp-manage → guest-gate (.pp-authgate-card без .pp-manage)
   НЕ задет. Централизует размеры, что раньше были inline в groups.js / group.js
   (там inline снят, чтобы этот слой был единым источником плотности). */
.pp-authgate-card.pp-manage{
  text-align:left; width:min(520px,94vw); max-width:none;
  max-height:88vh; overflow:auto;
  padding:20px 22px; border-radius:18px;
}
.pp-manage .pp-authgate-title{ font-size:18px; margin:2px 0 6px; }
.pp-manage .pp-manage-sec{ padding:12px 0; }
.pp-manage .pp-manage-h{ font-size:14px; margin-bottom:6px; }
.pp-manage .pp-manage-lbl{ margin-bottom:4px; }
.pp-manage .pp-manage-hint{ margin:-1px 0 6px; }
.pp-manage .pp-compose-text{ min-height:52px; }
/* Обложка-превью: полоса, не баннер на пол-модалки (было 16/6 ≈ 205px @520) */
.pp-manage .pp-cover-edit{ aspect-ratio:16/4.5; max-height:128px; }
.pp-manage .pp-ava-edit{ width:52px; height:52px; }
/* CTA снизу: auto-width компактные кнопки 40px (перебивает .pp-authgate-cta .pp-btn{flex:1}) */
.pp-manage .pp-authgate-cta .pp-btn{
  flex:0 0 auto; width:auto; min-height:40px; padding:0 18px; font-size:14px;
}
/* Обложка: широкое превью 16:6 с заглушкой */
.pp-cover-edit{ position:relative; width:100%; aspect-ratio:16/6; border-radius:var(--r,14px);
  overflow:hidden; border:1px dashed var(--line2);
  background:linear-gradient(135deg,var(--coral,#FF6B9A),var(--violet,#7C5CFF));
  display:flex; align-items:center; justify-content:center; }
.pp-cover-edit.has{ border-style:solid; background:var(--line); }
.pp-cover-edit img{ position:absolute; inset:0; width:100%; height:100%; object-fit:cover; }
.pp-cover-ph{ position:relative; z-index:1; color:#fff; font:600 13px var(--font); opacity:.9; }
/* Аватар: круглое превью */
.pp-ava-edit{ width:64px; height:64px; border-radius:50%; overflow:hidden; flex:none;
  border:1px solid var(--line2); background:var(--line);
  display:flex; align-items:center; justify-content:center; font-size:28px; position:relative; }
.pp-ava-edit img{ position:absolute; inset:0; width:100%; height:100%; object-fit:cover; }
/* Правило: заголовок + пояснение + удалить */
.pp-rule-row{ display:grid; grid-template-columns:1fr auto; gap:6px 8px; align-items:start;
  padding:8px 0; border-bottom:1px solid var(--line); }
.pp-rule-row .r-title{ grid-column:1; }
.pp-rule-row .r-text{ grid-column:1; min-height:52px; }
.pp-rule-row [data-rule-del]{ grid-column:2; grid-row:1; }
/* «Дополнительно» в модалке создания группы — свёрнутая шторка (progressive disclosure).
   Кастомный каретка-маркер на токенах, скрытый нативный треугольник, видимый focus-ring. */
.pp-cg-more > summary{ cursor:pointer; list-style:none; user-select:none;
  display:flex; align-items:center; gap:8px; padding:4px 0;
  font:700 14px var(--font-display,var(--font)); color:var(--ink); }
.pp-cg-more > summary::-webkit-details-marker{ display:none; }
.pp-cg-more > summary::before{ content:"›"; flex:0 0 auto; font-size:18px; line-height:1;
  color:var(--ink2); transition:transform .18s ease; }
.pp-cg-more[open] > summary::before{ transform:rotate(90deg); }
.pp-cg-more > summary:focus-visible{ outline:2px solid var(--violet); outline-offset:3px; border-radius:6px; }
@media(prefers-reduced-motion:reduce){ .pp-cg-more > summary::before{ transition:none; } }
/* Шапка каталога групп: заголовок+подзаголовок слева, компактная кнопка «Создать» справа.
   Ряд переносится на мобилке — кнопка уходит под текст, оставаясь auto-width (не полосой). */
.pp-gr-head{ display:flex; align-items:center; justify-content:space-between; gap:14px;
  flex-wrap:wrap; margin:18px 0 4px; }
.pp-gr-head-t{ flex:1 1 260px; min-width:0; }
.pp-gr-head .pp-name{ text-align:left; margin:0; }
.pp-gr-head .pp-tag{ text-align:left; margin:6px 0 0; }
.pp-gr-head [data-create]{ flex:0 0 auto; }
/* Поиск групп: бренд-иконка ВНЕ инпута (placeholder держит только текст), слева в обёртке. */
.pp-gr-search{ position:relative; margin-bottom:10px; }
.pp-gr-search > .pp-ic{ position:absolute; left:12px; top:50%; transform:translateY(-50%);
  color:var(--ink2); pointer-events:none; }
.pp-gr-search > .pp-compose-url{ width:100%; padding-left:38px; }
/* Закреплённый пост в ленте */
.pp-feed-item.is-pinned{ border:1px solid var(--line2); border-radius:var(--r,14px);
  padding:12px; background:rgba(124,92,255,.04); }
/* @упоминание в тексте поста/коммента */
.pp-mention{ color:var(--violet,#7C5CFF); font-weight:600; text-decoration:none; }
.pp-mention:hover{ text-decoration:underline; }

/* Композер: галерея превью загруженных фото + удаление */
.pp-gc-gallery{ display:flex; flex-wrap:wrap; gap:8px; margin:8px 0; }
.pp-gc-gallery:empty{ margin:0; }
.pp-gc-thumb{ position:relative; width:72px; height:72px; border-radius:10px; overflow:hidden;
  border:1px solid var(--line2); flex:none; }
.pp-gc-thumb img{ width:100%; height:100%; object-fit:cover; }
.pp-gc-rm{ position:absolute; top:2px; right:2px; width:20px; height:20px; border:none;
  border-radius:50%; background:rgba(0,0,0,.6); color:#fff; font:700 13px var(--font);
  line-height:1; cursor:pointer; display:flex; align-items:center; justify-content:center; }
/* Лента: несколько фото поста — сетка 2 колонки */
.pp-feed-gallery{ display:grid; gap:6px; margin:8px 0; }
.pp-feed-gallery.multi{ grid-template-columns:1fr 1fr; }
.pp-feed-gallery .pp-feed-photo{ width:100%; margin:0; border-radius:10px; object-fit:cover; aspect-ratio:1/1; }
/* Одиночное фото в посте группы: капим высоту + центрируем (не full-bleed портрет). */
.pp-feed-gallery:not(.multi) .pp-feed-photo{ aspect-ratio:auto; width:auto; max-width:100%;
  height:auto; max-height:min(70vh,560px); object-fit:contain; margin:0 auto; display:block;
  background:var(--bg2); border-radius:var(--r); }

/* Каталог групп: строка фильтра по категориям (горизонтальный скролл) */
.pp-cat-row{ display:flex; gap:6px; overflow-x:auto; padding:2px 0 10px; margin-bottom:4px;
  -webkit-overflow-scrolling:touch; scrollbar-width:thin; }
.pp-cat{ flex:none; border:1.5px solid var(--line2); background:#fff; color:var(--ink2);
  border-radius:var(--pill); padding:6px 12px; font:600 13px var(--font); cursor:pointer;
  white-space:nowrap; transition:all .12s; }
.pp-cat:hover{ color:var(--ink); border-color:var(--ink2); }
.pp-cat.is-on{ background:var(--ink); color:#fff; border-color:var(--ink); }

/* Правила на витрине группы (SSR) */
.pp-rules-list{ list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:10px; }
.pp-rules-list li{ display:flex; gap:10px; }
.pp-rules-list .n{ flex:none; width:22px; height:22px; border-radius:50%; background:var(--line);
  color:var(--ink2); font:700 12px var(--font); display:flex; align-items:center; justify-content:center; }
.pp-rules-list .t{ font:700 13px var(--font); color:var(--ink); }
.pp-rules-list .d{ font:500 13px var(--font); color:var(--ink2); }

/* ============================================================
   Page-builder витрины (Модуль C): кастом-блоки страницы + редактор оформления.
   ============================================================ */
/* --- кастом-блоки на публичной витрине --- */
.pp-hero-block{ text-align:center; background:var(--grad-hero,linear-gradient(135deg,#7C5CFF,#FF5E7E)); color:#fff; }
.pp-hero-block .pp-hero-title{ font:800 clamp(20px,4vw,30px)/1.15 var(--font-head,var(--font)); margin:0 0 8px; color:#fff; }
.pp-hero-block .pp-hero-sub{ font:500 15px/1.5 var(--font); opacity:.92; margin:0 auto 16px; max-width:44ch; }
.pp-hero-cta{ margin-top:4px; }
.pp-showcase-block .pp-showcase-mv{ width:100%; aspect-ratio:1/1; max-height:420px; border-radius:14px; overflow:hidden; background:var(--card2,#f4f1fb); }
.pp-showcase-block .pp-showcase-mv model-viewer{ width:100%; height:100%; }
.pp-showcase-cap{ font:500 13px var(--font); color:var(--ink2); margin:10px 2px 0; text-align:center; }
.pp-contact-block .pp-about{ margin-bottom:4px; }

/* --- редактор оформления (кабинет) --- */
.pp-blocks{ display:flex; flex-direction:column; gap:8px; margin-top:10px; }
.pp-block-row{ display:flex; align-items:center; gap:10px; padding:8px 10px; border:1px solid var(--line,#eceaf3);
  border-radius:12px; background:var(--card,#fff); transition:opacity .15s; }
.pp-block-row.is-off{ opacity:.5; }
.pp-block-move{ display:flex; flex-direction:column; gap:2px; }
.pp-block-move .pp-icon-btn{ width:22px; height:18px; font-size:10px; line-height:1; padding:0; }
.pp-block-move .pp-icon-btn:disabled{ opacity:.3; cursor:default; }
.pp-block-name{ flex:1; font:600 14px var(--font); color:var(--ink); }
.pp-block-badge{ font:700 10px var(--font); color:var(--violet,#7C5CFF); background:rgba(124,92,255,.12);
  padding:1px 6px; border-radius:6px; text-transform:uppercase; letter-spacing:.04em; }
.pp-toggle{ position:relative; display:inline-flex; width:38px; height:22px; flex:0 0 auto; cursor:pointer; }
.pp-toggle input{ position:absolute; opacity:0; width:100%; height:100%; margin:0; cursor:pointer; }
.pp-toggle-track{ width:38px; height:22px; border-radius:11px; background:var(--line,#d9d5e6); transition:background .18s; }
.pp-toggle-track::after{ content:''; position:absolute; top:3px; left:3px; width:16px; height:16px; border-radius:50%;
  background:#fff; box-shadow:0 1px 3px rgba(0,0,0,.25); transition:transform .18s; }
.pp-toggle input:checked + .pp-toggle-track{ background:var(--violet,#7C5CFF); }
.pp-toggle input:checked + .pp-toggle-track::after{ transform:translateX(16px); }
.pp-blocks-add{ margin-top:6px; }
.pp-chip-btn{ display:inline-flex; align-items:center; gap:4px; font:600 13px var(--font); color:var(--violet,#7C5CFF);
  background:rgba(124,92,255,.08); border:1px dashed rgba(124,92,255,.35); border-radius:20px;
  padding:6px 12px; margin:0 6px 6px 0; cursor:pointer; }
.pp-chip-btn:hover{ background:rgba(124,92,255,.16); }

/* ============================================================
   RICH SITE-BLOCK EDIT MODAL (openSiteBlockEdit) — редактор блоков витрины-сайта.
   Полировка ux-pro: 3 уровня иерархии (простое поле < группа-репитер <
   карта-пункт), видимый фокус, тихий destructive, тач-таргеты, мобайл.
   Скоуп [data-site-body] → НЕ задевает другие .pp-modal-form (товар/кастом-блок).
   Только токены tokens.css (без хардкод-hex).
   ============================================================ */
.pp-modal-body[data-site-body]{ padding:var(--sp-4) var(--sp-4) var(--sp-3); }
[data-site-body] > .pp-field{ margin-bottom:var(--sp-4); }
[data-site-body] > .pp-field:last-child{ margin-bottom:0; }
[data-site-body] .pp-label{ color:var(--ink2); }

/* группа-репитер (материалы / услуги / работы / вопросы): мягкая карт-подложка
   + усиленный заголовок (2-й уровень) отделяют «список» от простых полей */
[data-site-body] .pp-repeater{
  margin-bottom:var(--sp-4); padding:var(--sp-3);
  background:var(--gray-50); border:1px solid var(--line); border-radius:var(--rad-lg);
}
[data-site-body] .pp-repeater > .pp-label{
  font:700 var(--fs-sm) var(--font); color:var(--ink); margin-bottom:var(--sp-2);
}
[data-site-body] .pp-repeater [data-rows]{ counter-reset:ppobj; }

/* строковый репитер (тег / материал): input + тихое удаление в один ряд */
[data-site-body] .pp-rep-row{ display:flex; gap:var(--sp-2); align-items:center; margin-bottom:var(--sp-2); }
[data-site-body] .pp-rep-row > [data-delrow]{ border:0; background:transparent; color:var(--ink2); }
[data-site-body] .pp-rep-row > [data-delrow]:hover{ color:var(--err); background:var(--rose-50); }

/* карта-пункт объектного репитера (3-й уровень): бело, нумерация, фокус-хайлайт */
[data-site-body] .pp-rep-obj{
  position:relative; display:flex; flex-direction:column;
  margin-bottom:var(--sp-2); padding:var(--sp-6) var(--sp-3) var(--sp-3);
  background:var(--card); border:1px solid var(--line2); border-radius:var(--rad-lg);
  transition:border-color .16s, box-shadow .16s;
}
[data-site-body] .pp-rep-obj:focus-within{ border-color:var(--violet-300); box-shadow:0 0 0 3px var(--violet-50); }
[data-site-body] .pp-repeater[data-obj="1"] > [data-rows] > .pp-rep-obj::before{
  counter-increment:ppobj; content:"№ " counter(ppobj);
  position:absolute; top:var(--sp-2); left:var(--sp-3);
  font:800 var(--fs-xs) var(--font); color:var(--violet-700);
  letter-spacing:.02em; font-variant-numeric:tabular-nums;
}
[data-site-body] .pp-rep-obj .pp-field{ margin-bottom:var(--sp-3); }
[data-site-body] .pp-rep-obj .pp-field:last-of-type{ margin-bottom:var(--sp-2); }
/* вложенный список (теги внутри работы) — плоский, без второй карт-рамки */
[data-site-body] .pp-rep-obj .pp-repeater{ background:transparent; border:0; padding:0; margin-bottom:var(--sp-3); }
/* удаление карты — тихое, отделено, справа-снизу, красное только на hover (§14.A) */
[data-site-body] .pp-rep-obj > [data-delrow]{
  align-self:flex-end; width:auto; height:auto; min-height:44px; margin-top:var(--sp-1);
  padding:0 var(--sp-3); border:0; background:transparent; color:var(--ink2);
  border-radius:var(--rad-md); font:700 var(--fs-xs) var(--font);
  display:inline-flex; align-items:center; gap:4px;
}
[data-site-body] .pp-rep-obj > [data-delrow]:hover{ color:var(--err); background:var(--rose-50); }

/* «＋ добавить» пункт — полноширинный dashed-аффорданс, воздух вокруг, тач-таргет 44 */
[data-site-body] [data-addrow]{
  display:flex; width:100%; justify-content:center; align-items:center;
  min-height:44px; margin:var(--sp-1) 0 0; border-radius:var(--rad-md);
}

@media(max-width:480px){
  .pp-modal-body[data-site-body]{ padding:var(--sp-3); }
  [data-site-body] .pp-rep-obj{ padding:var(--sp-6) var(--sp-2) var(--sp-2); }
}

/* ============================================================
   СЕЛЕКТОР ВАРИАНТА СЛОТА — «тип контента» региона (site-smith slot-уровень).
   Segmented control (§15.B): 2–5 взаимоисключающих опций, single-select,
   мгновенно меняет ВИД одного множества (Фото+карточки / 3D / Видео) →
   именно сегмент, НЕ табы. Пока 1 вариант → контейнер [hidden] (не мешает).
   Bound к data.<slot>Variant. Разметка (owner вставит в тело модалки):

     <div class="pp-slot-variants" role="radiogroup" aria-label="Тип контента">
       <span class="pp-label">Тип контента</span>
       <div class="pp-seg">
         <button class="pp-seg-opt" type="button" role="radio"
                 aria-checked="true"  data-variant="image_cards">
           <svg …/><span>Фото + карточки</span></button>
         <button class="pp-seg-opt" type="button" role="radio"
                 aria-checked="false" data-variant="model3d">
           <svg …/><span>3D-модель</span></button>
         <button class="pp-seg-opt" type="button" role="radio"
                 aria-checked="false" data-variant="video">
           <svg …/><span>Видео</span></button>
       </div>
     </div>
   Только токены tokens.css. ============================================ */
[data-site-body] .pp-slot-variants{ margin-bottom:var(--sp-4); }
[data-site-body] .pp-slot-variants[hidden]{ display:none; }
[data-site-body] .pp-slot-variants > .pp-label{ display:block; margin-bottom:var(--sp-2); }

/* трек: утопленная дорожка, равные сегменты, воздух вокруг (§14.D) */
[data-site-body] .pp-seg{
  display:flex; gap:var(--sp-1);
  padding:var(--sp-1);
  background:var(--gray-100); border:1px solid var(--line);
  border-radius:var(--rad-lg);
}
/* сегмент: тач-таргет ≥44, тихий по умолчанию (ghost) — активный = поднятая карта */
[data-site-body] .pp-seg-opt{
  flex:1 1 0; min-width:0;
  display:inline-flex; align-items:center; justify-content:center; gap:6px;
  min-height:40px; padding:0 var(--sp-2);
  border:0; background:transparent; cursor:pointer;
  color:var(--ink2); font:600 var(--fs-sm) var(--font); white-space:nowrap;
  border-radius:calc(var(--rad-lg) - var(--sp-1));
  transition:background .14s ease, color .14s ease, box-shadow .14s ease;
}
[data-site-body] .pp-seg-opt svg{
  width:16px; height:16px; flex:none; fill:none; stroke:currentColor;
  stroke-width:2; stroke-linecap:round; stroke-linejoin:round; opacity:.85;
}
[data-site-body] .pp-seg-opt > span{ overflow:hidden; text-overflow:ellipsis; }
[data-site-body] .pp-seg-opt:hover{ color:var(--ink); }
[data-site-body] .pp-seg-opt:focus-visible{
  outline:2px solid var(--violet); outline-offset:2px;
}
/* выбранный вариант — белая приподнятая карта + бренд-акцент (единственный «primary») */
[data-site-body] .pp-seg-opt[aria-checked="true"]{
  background:var(--card); color:var(--violet-700);
  box-shadow:0 1px 2px color-mix(in srgb, var(--ink) 12%, transparent),
             0 0 0 1px color-mix(in srgb, var(--violet) 22%, transparent);
}
[data-site-body] .pp-seg-opt[aria-checked="true"] svg{ opacity:1; }

/* узкий модал → подписи под иконкой либо перенос: сегменты держат тап-таргет */
@media(max-width:400px){
  [data-site-body] .pp-seg-opt{ font-size:var(--fs-xs); gap:4px; padding:0 var(--sp-1); }
}

/* ============================================================
   ВИДЖЕТЫ ПОЛЕЙ site-редактора (тип icon/color/bool) — визуальный выбор вместо
   сырого текст-инпута, где юзер вынужден угадывать кодовое значение. Механику
   (сбор в [data-k], делегированный выбор, генерацию из SITE_IC/палитры) собирает
   storefront-edit.js; тут ВИД + selected-состояние. Только токены tokens.css.
   Работают и внутри репитеров (cards/фишки/принтеры) — по одному на поле.
   ============================================================ */

/* ---- ПИКЕР ИКОНОК (тип 'icon') — сетка бренд-иконок, значение = имя SITE_IC ----
   Скелет (owner генерит ячейки циклом по SITE_IC):
     <div class="pp-field pp-field--pick">
       <span class="pp-label">Иконка</span>
       <input type="hidden" data-k="cards.0.icon" value="box">
       <div class="pp-iconpick" role="radiogroup" aria-label="Выбор иконки">
         <button type="button" class="pp-iconpick-cell is-on" role="radio"
                 aria-checked="true" data-ic="box" title="box" aria-label="box">
           <svg viewBox="0 0 24 24" fill="none" stroke="currentColor"
                stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
             …SITE_IC['box']…</svg></button>
         … остальные ячейки … (опц. первая .pp-iconpick-cell--none = снять) …
       </div>
     </div>
   Выбор: owner ставит is-on + aria-checked=true на ячейку, пишет data-ic в [data-k]. */
[data-site-body] .pp-iconpick{
  display:grid;
  grid-template-columns:repeat(auto-fill, minmax(46px, 1fr));
  gap:var(--sp-1);
  max-height:220px; overflow-y:auto;
  padding:var(--sp-2);
  background:var(--gray-50); border:1px solid var(--line);
  border-radius:var(--rad-lg);
}
[data-site-body] .pp-iconpick-cell{
  all:unset; box-sizing:border-box;
  display:flex; align-items:center; justify-content:center;
  aspect-ratio:1/1; min-height:44px;
  border-radius:var(--rad-md);
  background:var(--card); color:var(--ink2); cursor:pointer;
  box-shadow:inset 0 0 0 1px var(--line2);
  transition:background .12s ease, color .12s ease, box-shadow .14s ease;
}
[data-site-body] .pp-iconpick-cell svg{ width:22px; height:22px; }
[data-site-body] .pp-iconpick-cell:hover{ background:var(--gray-100); color:var(--ink); }
[data-site-body] .pp-iconpick-cell:focus-visible{ outline:2px solid var(--violet); outline-offset:2px; }
[data-site-body] .pp-iconpick-cell.is-on{
  background:var(--violet-50); color:var(--violet-700);
  box-shadow:inset 0 0 0 2px var(--violet-300);
}
[data-site-body] .pp-iconpick-cell--none svg{ opacity:.45; }

/* ---- ПИКЕР ЦВЕТА (тип 'color') — чипы палитры + «тема/пусто» + «свой цвет» ----
   Скелет:
     <div class="pp-swatchpick" role="radiogroup" aria-label="Цвет плитки">
       <button class="pp-swatch pp-swatch--none is-on" role="radio"
               aria-checked="true" data-c="" title="Как в теме" aria-label="Как в теме"></button>
       <button class="pp-swatch" role="radio" data-c="#F2C14E"
               style="background:#F2C14E" title="#F2C14E"></button>
       … чипы палитры …
       <label class="pp-swatch pp-swatch--custom" title="Свой цвет">
         <input type="color" data-k-color aria-label="Свой цвет"></label>
     </div>
   Значение = data-c (hex или пусто=тема). */
[data-site-body] .pp-swatchpick{
  display:flex; flex-wrap:wrap; gap:var(--sp-2);
  padding:var(--sp-2);
  background:var(--gray-50); border:1px solid var(--line);
  border-radius:var(--rad-lg);
}
[data-site-body] .pp-swatch{
  all:unset; box-sizing:border-box; position:relative;
  width:34px; height:34px; border-radius:var(--rad-md); cursor:pointer;
  box-shadow:inset 0 0 0 1px color-mix(in srgb, var(--ink) 14%, transparent);
  transition:transform .1s ease, box-shadow .14s ease;
}
[data-site-body] .pp-swatch:hover{ transform:translateY(-1px); }
[data-site-body] .pp-swatch:focus-visible,
[data-site-body] .pp-swatch:focus-within{ outline:2px solid var(--violet); outline-offset:2px; }
[data-site-body] .pp-swatch.is-on{           /* двойное кольцо — читаемо на любом цвете */
  box-shadow:inset 0 0 0 1px color-mix(in srgb, var(--ink) 14%, transparent),
             0 0 0 2px var(--card), 0 0 0 4px var(--violet);
}
/* «как в теме / пусто» — нейтральный слэш поверх карточки */
[data-site-body] .pp-swatch--none{
  background:
    linear-gradient(45deg, transparent calc(50% - 1px), var(--ink2) calc(50% - 1px),
                    var(--ink2) calc(50% + 1px), transparent calc(50% + 1px)),
    var(--card);
}
/* «свой цвет» — обёртка нативного input[type=color], радужный намёк */
[data-site-body] .pp-swatch--custom{
  overflow:hidden;
  background:conic-gradient(from 210deg,
    #F26D6D,#F2C14E,#7ED957,#4EA8F2,#A67CF2,#F26D6D);
}
[data-site-body] .pp-swatch--custom input{
  position:absolute; inset:-4px; width:calc(100% + 8px); height:calc(100% + 8px);
  opacity:0; cursor:pointer; border:0; padding:0;
}

/* ---- ТУМБЛЕР (тип 'bool') — переключатель вместо текста; поле = ряд «подпись ↔ свитч» ----
   Скелет:
     <div class="pp-field pp-field--bool">
       <span class="pp-label">Крупная</span>
       <label class="pp-switch">
         <input type="checkbox" data-k="items.0.big"><span class="pp-switch-track"></span>
       </label>
     </div>  */
[data-site-body] .pp-field--bool{
  display:flex; align-items:center; justify-content:space-between; gap:var(--sp-3);
}
[data-site-body] .pp-field--bool > .pp-label{ margin:0; }
.pp-switch{
  position:relative; display:inline-flex; flex:none;
  width:46px; height:28px; cursor:pointer;
}
.pp-switch::before{ content:''; position:absolute; inset:-8px 0; }   /* тап-таргет ≥44 без роста визуала */
.pp-switch input{ position:absolute; inset:0; width:100%; height:100%; margin:0; opacity:0; cursor:pointer; }
.pp-switch-track{
  position:absolute; inset:0; border-radius:var(--pill,999px);
  /* hairline-контур: без него ВЫКЛ-трек (--gray-200 ≈1.3:1 к белой карточке) сливался с фоном и
     граница компонента не читалась (WCAG 1.4.11). На ВКЛ контур не нужен — заливка сама 4.3:1. */
  background:var(--gray-200); box-shadow:inset 0 0 0 1px var(--line2);
  transition:background .16s ease, box-shadow .16s ease;
}
.pp-switch-track::after{
  content:''; position:absolute; top:3px; left:3px; width:22px; height:22px;
  border-radius:50%; background:var(--card);
  box-shadow:0 1px 3px color-mix(in srgb, var(--ink) 30%, transparent);
  transition:transform .18s cubic-bezier(.3,.8,.4,1.2);
}
.pp-switch input:checked + .pp-switch-track{ background:var(--violet); box-shadow:none; }
.pp-switch input:checked + .pp-switch-track::after{ transform:translateX(18px); }
.pp-switch input:focus-visible + .pp-switch-track{ outline:2px solid var(--violet); outline-offset:2px; }
/* [hidden]-guard: display:inline-flex (author) перебивает UA [hidden]{display:none} → тумблер
   с атрибутом hidden оставался на экране (в форме товара «Бесплатно» светился у не-STL). */
.pp-switch[hidden]{ display:none; }
/* Компакт-размер атома (формы/модалки, density D0): 36×20 вместо 46×28 — тот же компонент,
   меньше габарит. Ход бегунка = 36 − 14 − 2·3 = 16px. */
.pp-switch--sm{ width:36px; height:20px; }
.pp-switch--sm .pp-switch-track::after{ width:14px; height:14px; }
.pp-switch--sm input:checked + .pp-switch-track::after{ transform:translateX(16px); }

@media (prefers-reduced-motion:reduce){
  .pp-switch-track,.pp-switch-track::after{ transition:none; }
  [data-site-body] .pp-swatch{ transition:none; }
}

/* ============================================================
   REVEAL «🎉 Ваш сайт готов → Поделиться» (showReveal) — момент гордости после
   «Собрать сайт по шаблону». Тактичный scale-in карты + мягкий burst-ринг за
   эмодзи + stagger контента. Токены; reduced-motion → без движения (burst скрыт).
   ============================================================ */
.pp-reveal{ width:min(440px,100%); text-align:center; }
.pp-reveal-head{ justify-content:flex-end; border-bottom:0; padding:var(--sp-3) var(--sp-3) 0; }
.pp-reveal-body{ padding:0 var(--sp-6) var(--sp-6); }
.pp-reveal-emoji{ position:relative; display:inline-flex; align-items:center; justify-content:center; margin-bottom:var(--sp-2); }
.pp-reveal-glyph{ position:relative; z-index:1; font-size:var(--fs-3xl); line-height:1; display:block; }
.pp-reveal-burst{ position:absolute; z-index:0; left:50%; top:50%; width:16px; height:16px; border-radius:50%;
  transform:translate(-50%,-50%); background:radial-gradient(circle, var(--violet-300), transparent 70%);
  opacity:0; pointer-events:none; }
.pp-reveal-title{ margin:0 0 var(--sp-1); font:800 var(--fs-xl) var(--font-display); color:var(--ink); }
.pp-reveal-sub{ margin:0 auto var(--sp-4); max-width:34ch; font:500 var(--fs-sm)/var(--lh-normal) var(--font); color:var(--ink2); }
.pp-reveal-link{ margin:0 0 var(--sp-4); padding:var(--sp-3); border:1px solid var(--line2); border-radius:var(--rad-md);
  background:var(--gray-50); font:600 var(--fs-sm) var(--font); color:var(--ink); word-break:break-all; }
.pp-reveal-cta{ display:flex; flex-wrap:wrap; justify-content:center; gap:var(--sp-2); }

@media(prefers-reduced-motion:no-preference){
  .pp-reveal{ animation:pp-reveal-in .42s cubic-bezier(.34,1.56,.64,1) both; }
  .pp-reveal-glyph{ animation:pp-reveal-pop .5s cubic-bezier(.34,1.7,.5,1) .08s both; }
  .pp-reveal-burst{ animation:pp-reveal-burst .7s ease-out .12s both; }
  .pp-reveal-title{ animation:pp-reveal-rise .4s ease-out .16s both; }
  .pp-reveal-sub{ animation:pp-reveal-rise .4s ease-out .22s both; }
  .pp-reveal-link{ animation:pp-reveal-rise .4s ease-out .28s both; }
  .pp-reveal-cta{ animation:pp-reveal-rise .4s ease-out .34s both; }
}
@keyframes pp-reveal-in{ from{ opacity:0; transform:scale(.92) translateY(8px); } to{ opacity:1; transform:none; } }
@keyframes pp-reveal-pop{ 0%{ transform:scale(.3); opacity:0; } 60%{ transform:scale(1.15); opacity:1; } 100%{ transform:scale(1); opacity:1; } }
@keyframes pp-reveal-burst{ 0%{ opacity:.65; transform:translate(-50%,-50%) scale(.4); } 100%{ opacity:0; transform:translate(-50%,-50%) scale(9); } }
@keyframes pp-reveal-rise{ from{ opacity:0; transform:translateY(6px); } to{ opacity:1; transform:none; } }

/* --- embed-сниппет (встроить витрину на чужой сайт) --- */
.pp-embed-block{ margin-top:12px; }
.pp-embed-label{ font:600 12px var(--font); color:var(--ink2); margin-bottom:5px; }
.pp-embed-code{ font:500 12px/1.4 ui-monospace,SFMono-Regular,Menlo,monospace; resize:vertical;
  background:var(--card2,#f7f5fc); color:var(--ink); margin-bottom:6px; }

/* --- партнёрка мастера (affiliate) --- */
.pp-aff-budget{ font:800 18px var(--font); color:var(--ink); padding:6px 0; }
.pp-aff-budget b{ color:var(--violet,#7C5CFF); }
.pp-aff-topup{ display:flex; gap:6px; }
.pp-aff-topup .pp-input{ flex:1; }
.pp-aff-stats{ display:flex; gap:10px; flex-wrap:wrap; margin-top:14px; }
.pp-aff-stat{ flex:1; min-width:74px; text-align:center; padding:10px 6px; border:1px solid var(--line,#eceaf3);
  border-radius:12px; background:var(--card2,#f7f5fc); }
.pp-aff-stat b{ display:block; font:800 20px var(--font); color:var(--ink); }
.pp-aff-stat span{ font:500 11px var(--font); color:var(--ink2); }
.pp-aff-cta-pill{ position:fixed; left:16px; bottom:calc(16px + var(--bs-bottom-reserve,0px)); z-index:60; border:0; cursor:pointer;
  font:700 13px var(--font); color:#fff; background:linear-gradient(135deg,#7C5CFF,#FF5E7E);
  border-radius:24px; padding:12px 18px; box-shadow:0 8px 24px rgba(124,92,255,.32); }
.pp-aff-cta-pill:hover{ transform:translateY(-1px); }
.pp-aff-cta-pill:disabled{ opacity:.6; cursor:default; }
@media(max-width:600px){ .pp-aff-cta-pill{ left:10px; bottom:calc(10px + var(--bs-bottom-reserve,0px)); font-size:12px; padding:10px 14px; } }

/* ============================================================
   ЛИЧНОСТЬ ↔ ВИТРИНА (WP-10/11/01) — сегмент-переключатель, мост-в-магазин,
   shop-view, тихая трест-лента, вход «стать продавцом».
   Палитра — существующие pop-токены (violet primary + coral акцент).
   ============================================================ */

/* Сегмент Профиль · Магазин — центрированная капсула над контентом. */
.pp-seg{ display:flex; gap:4px; justify-content:center; max-width:var(--page-max);
  margin:16px auto 0; padding:4px; width:max-content;
  background:var(--bg2); border:1px solid var(--line); border-radius:var(--pill); }
.pp-seg-btn{ appearance:none; text-decoration:none; cursor:pointer; border:0;
  font:700 14px var(--font); color:var(--ink2); background:transparent;
  padding:9px 22px; border-radius:var(--pill); min-height:40px; line-height:1;
  display:inline-flex; align-items:center; transition:.18s; }
.pp-seg-btn:hover{ color:var(--ink); }
.pp-seg-btn.is-active{ color:#fff; background:var(--grad-hero);
  box-shadow:0 8px 20px -8px rgba(124,92,255,.7); }

/* Тихая трест-лента витрины (WP-11) — 1 строка чипов, БЕЗ рейтинга. */
.pp-shop-trust{ display:flex; flex-wrap:wrap; gap:8px; justify-content:center;
  max-width:var(--page-max); margin:14px auto 0; padding:0 16px; }
.pp-shop-trust-item{ font:600 12px var(--font); color:var(--ink2);
  background:var(--card); border:1px solid var(--line2); border-radius:var(--pill);
  padding:6px 12px; }
.pp-shop-trust-item.is-guarantee{ color:#fff; background:var(--blue); border-color:transparent; }

/* Shop-view — идентичность продавца + сетка товаров (без трест-слоя личности). */
.pp-col-shop{ max-width:var(--page-max); margin:0 auto; padding:0 16px 40px; }
.pp-shop-head{ display:flex; align-items:center; gap:16px; margin:20px 0 4px; }
.pp-avatar-wrap.is-shop{ width:88px; height:88px; margin:0; flex:0 0 auto; }
.pp-shop-id{ min-width:0; }
.pp-col-shop .pp-name{ text-align:left; font-size:24px; margin:0; }
.pp-col-shop .pp-handle{ text-align:left; display:inline-block; text-decoration:none; }
.pp-col-shop .pp-handle:hover{ color:var(--ink); }
.pp-col-shop .pp-tag{ text-align:left; margin:4px 0 0; }
.pp-shop-ssr-list{ margin:8px 0 0; padding-left:18px; color:var(--ink); line-height:1.7; }

/* Hero-баннер магазина (WP-04) — своя картинка или матовый градиент бирюза→графит. */
.pp-shop-banner{ max-width:var(--page-max); margin:14px auto 0; height:180px; border-radius:20px;
  overflow:hidden; position:relative; background-size:cover; background-position:center;
  border:1px solid var(--line2); display:flex; align-items:flex-end; }
.pp-shop-banner.is-gradient{ background:linear-gradient(120deg,#19E3D6 0%,#0e8f88 42%,#2c2f38 100%); }
.pp-shop-banner-veil{ width:100%; padding:16px 20px;
  background:linear-gradient(to top,rgba(20,22,28,.62),rgba(20,22,28,0)); }
.pp-shop-banner-name{ font:800 26px var(--font); color:#fff;
  text-shadow:0 2px 12px rgba(0,0,0,.4); }
.pp-shop-banner.is-gradient .pp-shop-banner-name{ padding:16px 20px; }
@media(max-width:640px){ .pp-shop-banner{ height:130px; } .pp-shop-banner-name{ font-size:20px; } }

/* О магазине / группы мастера / закрытый магазин (WP-03/WP-12/WP-02). */
.pp-shop-about-text{ font:400 15px var(--font); color:var(--ink); line-height:1.6;
  margin:0; white-space:pre-line; }
.pp-shop-groups{ display:flex; flex-direction:column; gap:8px; }
.pp-shop-group{ display:flex; align-items:center; gap:12px; text-decoration:none;
  color:var(--ink); padding:8px; border-radius:14px; border:1px solid var(--line);
  transition:transform .12s,border-color .12s; }
.pp-shop-group:hover{ transform:translateY(-1px); border-color:var(--violet); }
.pp-shop-group-ava{ width:44px; height:44px; border-radius:12px; object-fit:cover;
  flex:0 0 auto; background:var(--bg2); }
.pp-shop-group-ava.is-init{ display:flex; align-items:center; justify-content:center;
  font:800 18px var(--font); color:#fff; background:var(--grad-hero); }
.pp-shop-group-meta{ min-width:0; }
.pp-shop-group-name{ font:700 15px var(--font); color:var(--ink); }
.pp-shop-group-role{ font:600 12px var(--font); color:var(--violet); }
.pp-shop-group-sub{ font:500 13px var(--font); color:var(--ink2); }
.pp-shop-closed{ text-align:center; }
.pp-shop-closed .pp-bridge-klikko{ width:88px; height:88px; margin:4px auto 8px; display:block; }
.pp-shop-closed .pp-bridge-sub{ margin:0 auto 14px; max-width:460px; }

/* Мост-в-магазин на личности (WP-10) — «витрина-открытка». */
.pp-shop-bridge{ display:flex; align-items:center; gap:16px; text-decoration:none;
  color:var(--ink); position:relative; overflow:hidden; }
.pp-shop-bridge:hover{ transform:translateY(-2px); }
.pp-bridge-thumbs{ display:flex; gap:6px; flex:0 0 auto; }
.pp-bridge-thumb{ width:56px; height:56px; border-radius:14px; object-fit:cover;
  background:var(--bg2); border:1px solid var(--line); }
.pp-bridge-thumb.is-poster{ background:
  repeating-linear-gradient(45deg,var(--bg2),var(--bg2) 6px,#fff 6px,#fff 12px); }
.pp-bridge-body{ flex:1; min-width:0; }
.pp-bridge-body .pp-card-title{ margin:0 0 4px; }
.pp-bridge-sub{ font:500 13px var(--font); color:var(--ink2); margin:0; }
.pp-bridge-cta{ flex:0 0 auto; font:700 14px var(--font); color:#fff;
  background:var(--grad-hero); border-radius:var(--pill); padding:10px 16px;
  box-shadow:0 10px 24px -10px rgba(124,92,255,.7); white-space:nowrap; }
.pp-shop-bridge.is-empty{ cursor:default; }
/* ── ЧЕСТНОЕ СОСТОЯНИЕ ВЛАДЕЛЬЦА вместо исчезнувшей витрины (profile.js: ownShopNoteHTML) ──
   «Магазин скрыт», «магазина ещё нет» и «витрина не загрузилась» раньше выглядели одинаково —
   никак: полка, вкладка «Товары» и мост просто пропадали. Карточка компактная (D0): заголовок
   15px + одна строка пояснения + одна secondary-кнопка 40px, без героя-пустоты и без иллюстрации
   на пол-экрана. Гостю не показывается вовсе. */
.pp-own-note{ display:flex; flex-direction:column; align-items:flex-start; gap:8px; }
.pp-own-note .pp-card-title{ margin:0; }
.pp-own-note-sub{ margin:0; font:500 13px var(--font); color:var(--ink2); max-width:62ch; }
.pp-own-note .pp-btn{ width:auto; }
.pp-shop-bridge.is-empty:hover{ transform:none; }
.pp-bridge-klikko{ width:64px; height:64px; object-fit:contain; flex:0 0 auto; }
.pp-shop-bridge.is-skel{ pointer-events:none; }
.pp-shop-bridge.is-skel .pp-bridge-thumb{ animation:pp-skel 1.2s ease-in-out infinite; }

/* WP-01 «Откройте свой магазин» — витрина-открытка для не-мастера на своей личности. */
.pp-become-seller{ display:flex; gap:18px; align-items:center; margin-top:16px;
  background:
    radial-gradient(120% 120% at 100% 0%, rgba(124,92,255,.10), transparent 55%),
    radial-gradient(120% 120% at 0% 100%, rgba(255,94,126,.10), transparent 55%),
    var(--card);
  border:1.5px dashed var(--line2); }
.pp-bs-preview{ flex:0 0 auto; width:120px; height:96px; border-radius:16px;
  background:var(--bg2); border:1px solid var(--line); position:relative; overflow:hidden; }
.pp-bs-shelf{ position:absolute; inset:auto 10px 14px 10px; display:flex; gap:6px; }
.pp-bs-shelf span{ flex:1; height:34px; border-radius:8px;
  background:linear-gradient(180deg,#fff,var(--bg2)); border:1px solid var(--line); }
.pp-bs-klikko{ position:absolute; right:-6px; top:-6px; width:48px; height:48px;
  object-fit:contain; transform:rotate(6deg); }
.pp-bs-body{ flex:1; min-width:0; }
.pp-bs-body .pp-card-title{ margin:6px 0 4px; }
.pp-bs-badge{ display:inline-block; font:700 11px var(--font); color:var(--violet);
  background:rgba(124,92,255,.10); border-radius:var(--pill); padding:4px 10px; }
.pp-bs-sub{ font:500 13px var(--font); color:var(--ink2); margin:0 0 12px; line-height:1.5; }

@media(max-width:600px){
  .pp-seg-btn{ padding:9px 18px; }
  .pp-shop-bridge{ flex-wrap:wrap; }
  .pp-bridge-cta{ width:100%; text-align:center; }
  .pp-become-seller{ flex-direction:column; align-items:flex-start; }
  .pp-bs-preview{ width:100%; height:110px; }
  .pp-shop-head{ flex-direction:column; text-align:center; }
  .pp-col-shop .pp-name, .pp-col-shop .pp-handle, .pp-col-shop .pp-tag{ text-align:center; }
}

/* ============ ВИТРИНА · ВИДИМЫЕ БЛОКИ (HERO / TRUST / КАК РАБОТАЕТ) ============ */
/* Одна доминанта экрана: hero-обложка = баннер/градиент + аватар + бренд + оффер + primary CTA. */
.pp-shop-hero{ max-width:var(--page-max); margin:16px auto 0; border-radius:var(--rad-2xl);
  overflow:hidden; position:relative; min-height:236px; display:flex; align-items:flex-end;
  background-size:cover; background-position:center; border:1px solid var(--line2);
  box-shadow:var(--shadow); }
.pp-shop-hero.is-gradient{ background:linear-gradient(120deg,#19E3D6 0%,#0e8f88 42%,#2c2f38 100%); }
.pp-shop-hero-inner{ width:100%; display:flex; align-items:flex-end; gap:16px;
  padding:28px 24px 22px;
  background:linear-gradient(to top,rgba(14,16,22,.84) 0%,rgba(14,16,22,.46) 55%,rgba(14,16,22,0) 100%); }
.pp-hero-ava-wrap{ flex:0 0 auto; }
.pp-hero-ava{ width:84px; height:84px; border-radius:20px; object-fit:cover;
  border:2.5px solid rgba(255,255,255,.92); box-shadow:0 6px 20px rgba(0,0,0,.35); background:var(--bg2); }
.pp-hero-ava.is-init{ display:flex; align-items:center; justify-content:center;
  font:800 34px var(--font-display); color:#fff; background:var(--grad-hero); }
.pp-hero-id{ flex:1; min-width:0; }
.pp-hero-eyebrow{ display:flex; align-items:center; gap:10px; flex-wrap:wrap; margin:0 0 4px; }
.pp-hero-kicker{ font:800 11px var(--font); letter-spacing:.12em; text-transform:uppercase;
  color:rgba(255,255,255,.82); }
.pp-hero-handle{ font:600 12px var(--font); color:rgba(255,255,255,.74);
  text-decoration:none; padding:3px 2px; }
.pp-hero-handle:hover{ color:#fff; text-decoration:underline; }
.pp-shop-hero-name{ font:800 30px/1.1 var(--font-display); color:#fff; margin:0;
  display:flex; align-items:center; gap:10px; flex-wrap:wrap; text-shadow:0 2px 14px rgba(0,0,0,.45); }
.pp-hero-pro{ font:800 12px var(--font); color:#fff; background:rgba(255,255,255,.18);
  border:1px solid rgba(255,255,255,.38); border-radius:var(--pill); padding:3px 10px; }
.pp-hero-tag{ font:500 15px var(--font); color:rgba(255,255,255,.93); margin:6px 0 0;
  max-width:52ch; line-height:1.45; text-shadow:0 1px 8px rgba(0,0,0,.4); }
.pp-hero-cta-row{ display:flex; flex-wrap:wrap; gap:10px; margin-top:16px; }
/* CTA по ширине контента (не full-width как дефолт .pp-btn) — не выглядят тяжело на десктопе. */
.pp-hero-cta-row .pp-btn{ width:auto; flex:0 0 auto; min-height:44px; padding-left:22px; padding-right:22px; }
.pp-shop-hero .pp-btn-ghost{ color:#fff; border:1.5px solid rgba(255,255,255,.6);
  background:rgba(255,255,255,.08); }
.pp-shop-hero .pp-btn-ghost:hover{ background:rgba(255,255,255,.16); border-color:#fff; }
@media(max-width:640px){
  .pp-shop-hero{ min-height:0; }
  .pp-shop-hero-inner{ flex-direction:column; align-items:flex-start; gap:12px; padding:22px 18px 18px; }
  .pp-hero-ava{ width:68px; height:68px; border-radius:16px; }
  .pp-shop-hero-name{ font-size:24px; }
  .pp-hero-tag{ font-size:14px; }
  .pp-hero-cta-row{ width:100%; flex-direction:column; }
  .pp-hero-cta-row .pp-btn{ width:100%; }
}

/* Трест-лента магазина — иконка+текст, cold-start: пустое НЕ рендерим (INV-RENDER). */
.pp-trust-strip{ display:flex; flex-wrap:wrap; gap:8px; max-width:var(--page-max);
  margin:14px auto 0; padding:0 16px; }
.pp-trust-chip{ display:inline-flex; align-items:center; gap:6px;
  font:600 13px var(--font); color:var(--ink); background:var(--card);
  border:1px solid var(--line2); border-radius:var(--pill); padding:7px 13px; }
.pp-trust-ico{ display:inline-flex; font-size:14px; line-height:1; }
.pp-trust-ico .pp-ic:where(:not([width])){ width:14px; height:14px; }
.pp-trust-chip.is-verified{ color:var(--emerald-700); background:var(--emerald-50);
  border-color:var(--emerald-200); }
.pp-trust-chip.is-guarantee{ color:#fff; background:var(--blue); border-color:transparent; }
@media(max-width:640px){
  .pp-trust-strip{ flex-wrap:nowrap; overflow-x:auto; scroll-snap-type:x proximity;
    -webkit-overflow-scrolling:touch; padding-bottom:2px; }
  .pp-trust-chip{ flex:0 0 auto; scroll-snap-align:start; }
}

/* «Как это работает» — 4 доменных шага, компактная лента. */
.pp-howto{ margin-top:16px; }
.pp-howto-steps{ list-style:none; margin:12px 0 0; padding:0;
  display:grid; grid-template-columns:repeat(4,1fr); gap:12px; }
.pp-howto-step{ display:flex; flex-direction:column; gap:6px; padding:14px;
  background:var(--bg2); border:1px solid var(--line); border-radius:var(--rad-lg); position:relative; }
.pp-howto-num{ position:absolute; top:10px; right:12px; font:800 12px var(--font);
  color:var(--violet); background:var(--violet-50); border-radius:var(--pill);
  width:22px; height:22px; display:flex; align-items:center; justify-content:center; }
.pp-howto-ico{ display:inline-flex; font-size:24px; line-height:1; color:var(--ink2); }
.pp-howto-ico .pp-ic:where(:not([width])){ width:22px; height:22px; }
.pp-howto-txt{ display:flex; flex-direction:column; gap:2px; }
.pp-howto-txt b{ font:700 14px var(--font); color:var(--ink); }
.pp-howto-txt span{ font:500 12.5px var(--font); color:var(--ink2); line-height:1.4; }
@media(max-width:760px){ .pp-howto-steps{ grid-template-columns:1fr 1fr; } }
@media(max-width:440px){
  .pp-howto-steps{ grid-template-columns:1fr; }
  .pp-howto-step{ flex-direction:row; align-items:center; }
  .pp-howto-ico{ font-size:20px; }
  .pp-howto-ico .pp-ic:where(:not([width])){ width:18px; height:18px; }
  .pp-howto-num{ position:static; margin-left:auto; }
}

/* ============ ДЕМО-ОПЛАТА (P2) — pp-pay-* ============ */
.pp-pay-back{ position:fixed; inset:0; z-index:1000; background:rgba(20,20,20,.55);
  backdrop-filter:blur(3px); display:flex; align-items:center; justify-content:center; padding:16px; }
.pp-modal-pay{ background:var(--card); border-radius:var(--r); width:min(420px,100%);
  max-height:92vh; max-height:92dvh; overflow:auto; position:relative; box-shadow:var(--shadow-lg); padding:20px; }
/* Крестик кассы — туда же, где он во всех модалках платформы (ср. .pp-modal-product):
   абсолютом в правом верхнем углу. До этого правила не было: кнопка стояла В ПОТОКЕ и
   занимала 32px-строку сверху СЛЕВА, а .pp-pay-head держал под неё холостой запас 28px
   СПРАВА — теперь этот запас работает по назначению (зазор до кнопки 4px). Тач-таргет
   44px даёт базовый .pp-modal-x::after{inset:-6px}, глиф не раздуваем (D0). Берём у
   .pp-modal-product ТОЛЬКО позицию: стеклянный кружок там — для крестика поверх медиа-героя. */
.pp-modal-pay .pp-modal-x{ position:absolute; right:12px; top:12px; z-index:3; }
/* Шапка кассы. Сумма — то, что человек проверяет ПЕРЕД тем как платить, поэтому она
   не сжимается и не режется никогда: flex:none + nowrap. Заголовок забирает остаток
   строки (min-width:0 — без него flex-элемент не уходит ниже min-content и выдавливал
   сумму за правый край: на 320px «249 000 ₽» теряла символ рубля). Не хватило места на
   строку (basis 132px — запас под целое слово, иначе рвало посередине: «Органайзе/р») —
   сумма переносится на свою строку ЦЕЛИКОМ, а не обрезается.
   Модалка 420px (десктоп/планшет) — строка одна, пиксель-в-пиксель как была. */
.pp-pay-head{ display:flex; flex-wrap:wrap; align-items:baseline; justify-content:space-between;
  gap:4px 10px; margin:0 28px 14px 0; }
.pp-pay-title{ font:800 16px var(--font-display); flex:1 1 132px; min-width:0;
  line-height:1.25; overflow-wrap:break-word; }
.pp-pay-amount{ font:800 20px var(--font-display); color:var(--ink); font-variant-numeric:tabular-nums;
  white-space:nowrap; flex:none; }
/* на телефоне длинное название не разрастается в простыню на пол-шапки — 2 строки (D0) */
@media (max-width:600px){
  .pp-pay-title{ display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden; }
}
.pp-pay-stage{ display:flex; flex-direction:column; gap:12px; }
.pp-pay-demo-note{ font:600 12px var(--font); color:var(--ink2); background:var(--bg2);
  border-radius:12px; padding:8px 12px; display:flex; align-items:center; gap:7px; }
.pp-pay-demo-note svg{ flex:none; color:var(--violet); }
.pp-pay-ok-ic{ line-height:0; }
.pp-pay-deliv-t, .pp-pay-card .pp-label{ font:700 12px var(--font); color:var(--ink2); }
.pp-pay-deliv{ display:flex; flex-direction:column; gap:8px; }
.pp-pay-card{ display:flex; flex-direction:column; gap:8px; }
.pp-pay-fill{ align-self:flex-start; }
.pp-pay-err{ color:var(--coral); font:600 13px var(--font); }
.pp-pay-submit{ min-height:48px; }
.pp-pay-proc{ display:flex; flex-direction:column; align-items:center; gap:12px; padding:24px 0; color:var(--ink2); }
.pp-pay-spin{ width:34px; height:34px; border:3px solid var(--line2); border-top-color:var(--violet);
  border-radius:50%; animation:pp-pay-rot .8s linear infinite; }
@keyframes pp-pay-rot{ to{ transform:rotate(360deg); } }
.pp-pay-ok, .pp-pay-fail{ display:flex; flex-direction:column; align-items:center; gap:10px; text-align:center; padding:8px 0; }
.pp-pay-ok h3, .pp-pay-fail h3{ margin:0; font:800 18px var(--font-display); }
.pp-pay-ok p, .pp-pay-fail p{ margin:0; color:var(--ink2); font:500 14px var(--font); }
.pp-pay-ok-ic{ font-size:40px; }
.pp-pay-ok .pp-btn, .pp-pay-fail .pp-btn{ width:100%; margin-top:4px; }

/* ============================================================
   ArticleChip — сквозной АРТИКУЛ площадки (bs######c). Единый компонент
   (frontend/src/article.js), variant: display | copy | hero. Палитро-нейтрально:
   моно + tabular-nums + графит; акцент (--violet) только на flash копирования и hero.
   ============================================================ */
.bs-code{
  font-family:ui-monospace,'SF Mono',SFMono-Regular,'JetBrains Mono',Menlo,Consolas,monospace;
  font-variant-numeric:tabular-nums; letter-spacing:.02em; white-space:nowrap;
  border-radius:6px; transition:color .15s ease-out, background-color .15s ease-out;
}
.bs-code-pre{ color:var(--ink2); }            /* «bs» — приглушённо (graphite-400) */
.bs-code-body{ color:var(--ink); font-weight:700; }  /* тело+контроль — насыщенно (graphite-900) */
/* flash подтверждения копирования (~1.6s, ease-out) */
.bs-code.is-flash{ animation:bs-flash 1.6s ease-out 1; }
@keyframes bs-flash{
  0%{ background:rgba(124,92,255,.20); }
  12%{ background:rgba(124,92,255,.20); }
  100%{ background:transparent; }
}
.bs-code.is-flash .bs-code-body{ animation:bs-flash-ink 1.6s ease-out 1; }
@keyframes bs-flash-ink{ 0%,12%{ color:var(--violet); } 100%{ color:var(--ink); } }
@media (prefers-reduced-motion: reduce){
  .bs-code, .bs-code.is-flash, .bs-code.is-flash .bs-code-body{ animation:none!important; transition:none; }
}

.bs-chip{ display:inline-flex; align-items:center; gap:8px; max-width:100%; }
.bs-chip-label{ font:600 12px var(--font); color:var(--ink2); }
.bs-live{ position:absolute; width:1px; height:1px; overflow:hidden; clip:rect(0 0 0 0); }

/* variant display — тихая моно-строка, без тап-таргета */
.bs-chip--display{ gap:0; }
.bs-chip--display .bs-code{ font-size:12px; color:var(--ink2); }
.bs-chip--display .bs-code-body{ font-weight:600; color:var(--ink2); }

/* variant copy — код + кнопка-secondary с micro-подтверждением */
.bs-chip--copy{
  flex-wrap:wrap; gap:8px 10px; padding:8px 10px; position:relative;
  background:var(--bg2); border:1px solid var(--line); border-radius:12px;
}
.bs-chip--copy .bs-code{ font-size:15px; }
.bs-copy{
  display:inline-flex; align-items:center; gap:6px; min-height:36px; padding:6px 12px;
  font:700 13px var(--font); color:var(--violet); cursor:pointer;
  background:#fff; border:1.5px solid var(--violet); border-radius:10px;
  transition:background-color .15s ease-out, color .15s ease-out, transform .12s ease-out;
}
.bs-copy:hover{ background:rgba(124,92,255,.06); }
.bs-copy:active{ transform:translateY(1px); }
.bs-copy:focus-visible{ outline:none; box-shadow:0 0 0 3px rgba(124,92,255,.30); }
.bs-copy.is-done{ background:var(--ok); border-color:var(--ok); color:#fff; }
.bs-copy-ico{ font-size:14px; line-height:1; }
@media (max-width:768px){ .bs-copy{ min-height:44px; } }

/* variant hero — крупный код для публичной страницы /a/{article} */
.bs-chip--hero{
  gap:12px; padding:14px 18px; position:relative;
  background:var(--bg2); border:1px solid var(--line2); border-radius:16px;
}
.bs-chip-key{ font-size:22px; line-height:1; }
.bs-chip-stack{ display:flex; flex-direction:column; gap:2px; }
.bs-code--hero{ font-size:28px; }
.bs-chip--hero .bs-copy{ min-height:44px; }

/* «Подпись для Instagram» tertiary-ссылка (в редакторе товара) */
.bs-ig-link{
  display:inline-flex; align-items:center; gap:6px; min-height:32px;
  font:700 13px var(--font); color:var(--violet); background:none; border:0;
  cursor:pointer; padding:4px 0; text-decoration:none;
}
.bs-ig-link:hover{ text-decoration:underline; }
.bs-ig-link:focus-visible{ outline:none; box-shadow:0 0 0 3px rgba(124,92,255,.25); border-radius:6px; }
@media (max-width:768px){ .bs-ig-link{ min-height:44px; } }

/* плашка-плейсхолдер артикула (черновик, ещё не сохранён) */
.bs-draft{
  display:flex; flex-direction:column; gap:2px; padding:12px 14px;
  border:1.5px dashed var(--line2); border-radius:12px; color:var(--ink2);
}
.bs-draft-title{ font:700 13px var(--font); color:var(--ink2); }
.bs-draft-sub{ font:500 12px var(--font); color:var(--ink2); opacity:.85; }
.bs-art-hint{ margin-top:6px; font:500 12px var(--font); color:var(--ink2); }

/* строка списка товаров — тихий артикул под ценой/категорией */
.bs-row-art{ margin-top:2px; }
.bs-row-art .bs-code{ font-size:11px; }

/* «Подпись для Instagram» шит */
.bs-cap-back{
  position:fixed; inset:0; z-index:1200; display:flex; align-items:center; justify-content:center;
  padding:20px; background:rgba(20,20,20,.5); backdrop-filter:blur(2px);
}
.bs-cap-sheet{
  width:min(520px,100%); background:var(--card); border-radius:20px;
  box-shadow:var(--shadow-lg); padding:20px; display:flex; flex-direction:column; gap:12px;
}
.bs-cap-head{ display:flex; align-items:center; justify-content:space-between; font:800 16px var(--font-display); }
.bs-cap-x{ border:0; background:none; font-size:18px; cursor:pointer; color:var(--ink2); line-height:1; padding:4px; }
.bs-cap-hint{ margin:0; font:500 13px var(--font); color:var(--ink2); }
.bs-cap-text{
  width:100%; box-sizing:border-box; resize:vertical; padding:12px; border-radius:12px;
  border:1.5px solid var(--line2); font:500 14px var(--font); color:var(--ink); line-height:1.5;
}
.bs-cap-text:focus{ outline:none; border-color:var(--violet); box-shadow:0 0 0 3px rgba(124,92,255,.15); }
.bs-cap-copy{
  min-height:44px; border:0; border-radius:12px; background:var(--violet); color:#fff;
  font:800 14px var(--font); cursor:pointer; transition:transform .12s ease-out, filter .15s ease-out;
}
.bs-cap-copy:hover{ filter:brightness(1.05); }
.bs-cap-copy:active{ transform:translateY(1px); }

/* ══════════ Публичная страница товара /a/{article} — ПОКУПАТЕЛЬ-FIRST ══════════
   Иерархия сверху вниз: медиа → название → мастер → цена+CTA → описание → артикул
   (компактный референс, НЕ герой). Двухколоночно на десктопе, одна колонка + тонкий
   sticky-бар покупки на мобайле. Своя чистая зона .pdp-* (не наследует catalog-карточку). */
.pdp{ padding-top:22px; padding-bottom:56px; }
.pdp-draft{
  max-width:var(--page-max); margin:12px auto 4px; padding:10px 14px; border-radius:12px;
  background:color-mix(in srgb,var(--violet) 10%,#fff);
  border:1px solid color-mix(in srgb,var(--violet) 28%,#fff);
  color:var(--ink); font:600 13px var(--font);
}

.pdp-grid{ display:grid; grid-template-columns:minmax(0,1.05fr) minmax(320px,.95fr); gap:32px; align-items:start; }
/* minmax(0,1fr), НЕ 1fr — иначе min-content колонки распирает сетку за вьюпорт (мобайл-overflow) */
@media(max-width:860px){ .pdp-grid{ grid-template-columns:minmax(0,1fr); gap:18px; } }

/* ── 1. Медиа ── */
.pdp-media{
  position:relative; margin:0; min-width:0; aspect-ratio:1/1; border-radius:20px; overflow:hidden;
  background:linear-gradient(160deg,var(--bg2),#fff); border:1px solid var(--line);
}
.pdp-media model-viewer{ width:100%; height:100%; --poster-color:transparent; }
.pdp-cover{ width:100%; height:100%; object-fit:cover; }
.pdp-media-badge{
  position:absolute; right:12px; top:12px; padding:5px 10px; border-radius:999px;
  font:700 12px var(--font); color:#fff; background:rgba(15,16,32,.60); backdrop-filter:blur(6px);
}
.pdp-media-empty{
  position:absolute; inset:0; display:flex; flex-direction:column; align-items:center;
  justify-content:center; gap:10px; color:var(--ink2); font:600 13px var(--font);
}
@media(max-width:860px){ .pdp-media{ aspect-ratio:4/3; } }

/* ── 2. Инфо-колонка ── */
.pdp-info{ display:flex; flex-direction:column; gap:13px; min-width:0; }
@media(min-width:861px){ .pdp-info{ position:sticky; top:86px; } }

.pdp-title{ margin:0; font:800 26px/1.2 var(--font-display); letter-spacing:-.02em; color:var(--ink); text-wrap:balance; }

.pdp-seller{
  display:inline-flex; align-items:center; gap:7px; margin-top:-3px; align-self:flex-start;
  text-decoration:none; font:600 14px var(--font);
}
.pdp-seller-av{ width:22px; height:22px; border-radius:50%; object-fit:cover; }
.pdp-seller-handle{ color:var(--violet); font-weight:700; }
.pdp-seller:hover .pdp-seller-handle{ text-decoration:underline; }
.pdp-seller-brand{ color:var(--ink2); }

/* ── 3. Цена + primary CTA (стили .pdp-buy/раскладку BUY BOX см. ниже, в блоке «BUY BOX») ── */
.pdp-price{ font:800 28px var(--font-display); color:var(--ink); font-variant-numeric:tabular-nums; letter-spacing:-.01em; }
.pdp-price.is-quote{ font-size:19px; color:var(--violet); }
.pdp-price.is-free{ color:var(--ok); }  /* бесплатный STL — позитивный зелёный, не «0 ₽» */
.pdp-cta{
  height:44px; padding:0 22px; border:0; border-radius:12px; cursor:pointer;
  font:700 15px var(--font); color:#fff; background:var(--grad-hero);
  display:inline-flex; align-items:center; justify-content:center; gap:8px;
  box-shadow:0 8px 20px -8px rgba(124,92,255,.62);
  transition:transform .16s cubic-bezier(.2,.8,.2,1), box-shadow .16s;
}
.pdp-cta:hover{ transform:translateY(-1px); box-shadow:0 14px 28px -10px rgba(124,92,255,.8); }
.pdp-cta:active{ transform:translateY(0); }
.pdp-cta:focus-visible{ outline:none; box-shadow:0 0 0 3px rgba(124,92,255,.4); }
@media (prefers-reduced-motion:reduce){ .pdp-cta{ transition:none; } }
/* вторичная кнопка-мост «оформить заявку» (после «в корзину») — outline, не толстая */
.pdp-cta-ghost{ background:#fff; color:var(--violet); border:1.5px solid color-mix(in srgb,var(--violet) 45%,var(--line2)); box-shadow:none; text-decoration:none; }
.pdp-cta-ghost:hover{ background:color-mix(in srgb,var(--violet) 6%,#fff); box-shadow:none; }
/* бесплатный STL: primary-CTA «Скачать бесплатно» — успех-зелёный (позитив, не «купить»); это <a>, снимаем подчёркивание */
.pdp-cta-free{ background:var(--ok); color:#fff; text-decoration:none;
  box-shadow:0 8px 20px -8px color-mix(in srgb,var(--ok) 62%,transparent); }
.pdp-cta-free:hover{ box-shadow:0 14px 28px -10px color-mix(in srgb,var(--ok) 80%,transparent); }
.pdp-cta-free:focus-visible{ box-shadow:0 0 0 3px color-mix(in srgb,var(--ok) 40%,transparent); }

/* маленькая share/QR-иконка в мини-чипе артикула — наследует ghost-стиль .pdp-art-mini .bs-copy */

/* ── 4. Описание + теги ── */
.pdp-desc{ margin:0; font:500 15px/1.55 var(--font); color:var(--ink2); max-width:62ch; }
.pdp-tags{ display:flex; flex-wrap:wrap; gap:6px; }
/* тег теперь ссылка → маркетплейс с фильтром по тегу (brandbook #10): affordance + focus-ring */
.pdp-tag{ display:inline-flex; align-items:center; padding:4px 10px; border-radius:999px;
  background:var(--bg2); border:1px solid var(--line); font:600 12px var(--font); color:var(--ink2);
  text-decoration:none; transition:color .15s ease, border-color .15s ease, background .15s ease; }
.pdp-tag:hover{ color:var(--violet); border-color:var(--violet); background:rgba(124,92,255,.07); }
.pdp-tag:focus-visible{ outline:none; box-shadow:0 0 0 3px rgba(124,92,255,.45); }

/* ── Артикул — МИНИ-ЧИП: справочная моно-строка «Арт. bs…», НЕ плашка (брендбук .art-mini).
   Без бордера/фона/слова «Копировать» — приглушённая строка + icon-only копи/QR (ghost). ── */
.pdp-art-mini{
  margin:-4px 0 2px; padding:0; gap:7px; align-self:flex-start; max-width:100%;
  background:none; border:0; border-radius:0;
}
.pdp-art-mini .pdp-art-label{
  font:600 13px var(--font-mono,ui-monospace,monospace);
  color:var(--ink2); letter-spacing:.01em;
}
.pdp-art-mini .bs-code{ font:700 13px var(--font-mono,ui-monospace,monospace); font-variant-numeric:tabular-nums; }
.pdp-art-mini .bs-code-pre{ color:var(--ink2); font-weight:600; }
.pdp-art-mini .bs-code-body{ color:var(--ink); font-weight:700; }
/* icon-only копи/QR — ghost: наследует приглушённый цвет строки; бордер/фон ТОЛЬКО на hover */
.pdp-art-mini .bs-copy{
  display:inline-flex; align-items:center; justify-content:center;
  min-height:0; padding:3px; border:0; border-radius:6px;
  background:none; color:var(--ink2); box-shadow:none; cursor:pointer;
  transition:color .15s ease-out, background-color .15s ease-out;
}
.pdp-art-mini .bs-copy:hover{ background:rgba(124,92,255,.10); color:var(--violet); }
.pdp-art-mini .bs-copy:active{ transform:none; }
.pdp-art-mini .bs-copy:focus-visible{ outline:none; box-shadow:0 0 0 3px rgba(124,92,255,.28); }
.pdp-art-mini .bs-copy.is-done{ background:none; color:var(--ok); }
.pdp-art-mini .bs-copy-svg,
.pdp-art-mini .bs-copy-check{ display:block; }
.pdp-art-mini .bs-copy-check{ display:none; }
.pdp-art-mini .bs-copy.is-done .bs-copy-svg{ display:none; }
.pdp-art-mini .bs-copy.is-done .bs-copy-check{ display:block; }
/* тач-таргет 44×44 без визуального веса — расширяем hit-area на мобайле */
@media(max-width:768px){
  .pdp-art-mini .bs-copy{ position:relative; }
  .pdp-art-mini .bs-copy::after{ content:''; position:absolute; inset:-15px; }
}

/* ── Публичный КОД ЧЕЛОВЕКА — моно-микрочип под ником (аналог артикула товара, article.js).
   Постоянный: не меняется при смене @ника; клик копирует ссылку /u/{code}. Тихий ghost-чип —
   моно + tabular-nums + графит; акцент (--violet) только на hover/фокусе, --ok на подтверждении.
   Палитро-нейтрально, только токены. Разметка — userCodeChipHTML() в src/profile.js. ── */
.pp-ucode-row{ text-align:center; margin:2px 0 0; line-height:1; }
/* Футер-обёртка: код продавца стоит в САМОМ НИЗУ карточки (верх и так плотный) —
   тихая сноска, отделённая воздухом от контента выше. */
.pp-ucode-foot{ margin:14px 0 4px; text-align:center; }
/* Максимально ТИХИЙ технический футер-чип (требование владельца: «прям очень
   маленьким незаметным»): кегль 11px, единый приглушённый графит (--gray-500),
   без веса и без двухтоновой подсветки в покое. Иконка копирования проявляется
   только на hover/фокусе. Аффорданс (копирование/hover/фокус/тач-таргет/aria) —
   сохранён; акцент (--violet) и подтверждение (--ok) — только по взаимодействию. */
.pp-ucode{
  display:inline-flex; align-items:center; gap:4px;
  padding:2px 5px; border:0; border-radius:var(--rad-xs);
  background:none; cursor:pointer; max-width:100%; vertical-align:middle;
  color:var(--gray-500);
  transition:background-color .15s ease-out, color .15s ease-out;
}
.pp-ucode:hover{ background:var(--violet-50); color:var(--violet); }
.pp-ucode:active{ transform:translateY(.5px); }
.pp-ucode:focus-visible{ outline:none; box-shadow:0 0 0 3px rgba(124,92,255,.28); }
.pp-ucode-code{
  font:500 11px var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  font-variant-numeric:tabular-nums; letter-spacing:.01em; white-space:nowrap;
}
/* в покое префикс и цифры одинаково тихие — никакого акцента внимания */
.pp-ucode-pre,
.pp-ucode-body{ color:var(--gray-500); font-weight:500; }
.pp-ucode:hover .pp-ucode-pre,
.pp-ucode:hover .pp-ucode-body{ color:var(--violet); }
.pp-ucode-i{ display:block; flex:none; }
.pp-ucode-copy{ width:11px; height:11px; opacity:0; transition:opacity .15s ease-out; } /* иконка — только на hover/фокусе */
.pp-ucode:hover .pp-ucode-copy,
.pp-ucode:focus-visible .pp-ucode-copy{ opacity:1; }
.pp-ucode-check{ display:none; width:11px; height:11px; }
.pp-ucode.is-done{ color:var(--ok); }                   /* подтверждение: цвет + иконка + aria-live (не только цвет) */
.pp-ucode.is-done .pp-ucode-pre,
.pp-ucode.is-done .pp-ucode-body{ color:var(--ok); }
.pp-ucode.is-done .pp-ucode-copy{ display:none; }
.pp-ucode.is-done .pp-ucode-check{ display:block; opacity:1; }
.pp-ucode-live{ position:absolute; width:1px; height:1px; overflow:hidden; clip:rect(0 0 0 0); }
/* Контекст КАБИНЕТА (profile-edit): тот же тихий чип, но left-align + микроподпись. */
.pp-ucode-edit{ display:flex; align-items:center; gap:8px; flex-wrap:wrap; margin:-2px 0 2px; }
.pp-ucode-note{ font:400 11px var(--font); color:var(--gray-500); line-height:1.3; }
/* тач-таргет ≥44×44 без визуального веса на мобайле (расширяем hit-area) */
@media(max-width:768px){
  .pp-ucode{ position:relative; min-height:34px; }
  .pp-ucode::after{ content:''; position:absolute; inset:-6px -8px; }
}
@media(prefers-reduced-motion: reduce){
  .pp-ucode,
  .pp-ucode-copy{ transition:none; }
  .pp-ucode:active{ transform:none; }
}

/* ── Бейдж моата на медиа (верх-лево): мультицвет без AMS ── */
.pdp-moat-badge{
  position:absolute; left:12px; top:12px; z-index:2;
  display:inline-flex; align-items:center; gap:6px; padding:6px 11px 6px 9px;
  border-radius:999px; font:700 12px var(--font); color:#3d5200;
  background:color-mix(in srgb,var(--lime,#C6F24E) 62%,#fff);
  border:1px solid color-mix(in srgb,var(--lime,#C6F24E) 70%,#8fb400);
  box-shadow:0 4px 12px -6px rgba(0,0,0,.3);
}
.pdp-moat-badge svg{ flex:none; }

/* ── 3. BUY BOX — единая белая карточка покупки (эталон brandbook) ── */
.pdp-buybox{
  display:flex; flex-direction:column; gap:12px;
  padding:18px; border-radius:18px; background:var(--card);
  border:1px solid var(--line); box-shadow:0 10px 30px -22px rgba(20,20,20,.5);
}
.pdp-buy{ display:flex; align-items:center; gap:12px; flex-wrap:wrap; padding:0; }
/* наличие — pill emerald + иконка (не только цвет, WCAG) */
.pdp-stock{
  display:inline-flex; align-items:center; gap:5px; padding:4px 11px; border-radius:999px;
  font:700 13px var(--font); color:#0a7a48;
  background:color-mix(in srgb,var(--ok) 16%,#fff);
  border:1px solid color-mix(in srgb,var(--ok) 32%,#fff);
}
.pdp-stock svg{ flex:none; }
.pdp-buy-sub{ margin:-4px 0 0; font:500 14px var(--font); color:var(--ink2); }
.pdp-buy-lbl{ font:700 11px var(--font); text-transform:uppercase; letter-spacing:.05em; color:var(--ink2); }

/* варианты цвета кнопками */
.pdp-var{ display:flex; flex-direction:column; gap:7px; }
.pdp-var-row{ display:flex; flex-wrap:wrap; gap:8px; }
.pdp-var-btn{
  display:inline-flex; align-items:center; gap:7px; min-height:38px; padding:7px 14px;
  border-radius:999px; border:1.5px solid var(--line2); background:#fff; cursor:pointer;
  font:600 13.5px var(--font); color:var(--ink);
  transition:border-color .15s ease-out, background-color .15s ease-out, color .15s ease-out;
}
.pdp-var-btn:hover{ border-color:color-mix(in srgb,var(--violet) 45%,var(--line2)); }
.pdp-var-btn:focus-visible{ outline:none; box-shadow:0 0 0 3px rgba(124,92,255,.28); }
.pdp-var-btn.is-active{
  border-color:var(--violet); color:var(--violet);
  background:color-mix(in srgb,var(--violet) 8%,#fff);
}
.pdp-var-dot{ width:14px; height:14px; border-radius:50%; flex:none; border:1px solid rgba(0,0,0,.12); }
@media(max-width:768px){ .pdp-var-btn{ min-height:44px; } }

/* количество + primary CTA в один ряд */
/* align-items:center (не stretch): qty-степпер и primary CTA оба 44px, центрируем — и ни один
   инородный вставленный child не сможет растянуть CTA по высоте (см. mountCartConfirm: подтверждение
   выносится ПОД ряд, а не внутрь него). */
.pdp-buy-row{ display:flex; align-items:center; gap:12px; flex-wrap:wrap; }
.pdp-qty{
  display:inline-flex; align-items:center; flex:none;
  border:1.5px solid var(--line2); border-radius:12px; overflow:hidden; background:#fff;
}
.pdp-qty-btn{
  width:44px; height:44px; border:0; background:none; cursor:pointer;
  font:600 20px var(--font); color:var(--ink2); line-height:1;
  transition:background-color .15s ease-out, color .15s ease-out;
}
.pdp-qty-btn:hover{ background:var(--bg2); color:var(--violet); }
.pdp-qty-btn:active{ background:color-mix(in srgb,var(--violet) 10%,#fff); }
.pdp-qty-btn:focus-visible{ outline:none; box-shadow:inset 0 0 0 2px rgba(124,92,255,.4); }
.pdp-qty-btn:disabled{ opacity:.4; cursor:not-allowed; }
.pdp-qty-val{ min-width:38px; text-align:center; font:700 15px var(--font); color:var(--ink); font-variant-numeric:tabular-nums; }
/* primary CTA растягивается на остаток строки, но остаётся ОДНИМ primary в зоне */
.pdp-buy-row .pdp-cta{ flex:1 1 auto; min-width:150px; }
.pdp-cta svg{ flex:none; }

/* избранное / поделиться — вторичные outline (subordinate primary CTA) */
.pdp-actions{ display:flex; gap:10px; }
.pdp-act{
  flex:1 1 0; display:inline-flex; align-items:center; justify-content:center; gap:8px;
  min-height:44px; padding:0 14px; border-radius:12px; cursor:pointer;
  border:1.5px solid var(--line2); background:#fff; color:var(--ink);
  font:600 14px var(--font);
  transition:border-color .15s ease-out, background-color .15s ease-out, color .15s ease-out;
}
.pdp-act:hover{ border-color:color-mix(in srgb,var(--violet) 40%,var(--line2)); background:color-mix(in srgb,var(--violet) 5%,#fff); }
.pdp-act:active{ transform:translateY(1px); }
.pdp-act:focus-visible{ outline:none; box-shadow:0 0 0 3px rgba(124,92,255,.28); }
.pdp-act svg{ flex:none; transition:color .15s ease-out; }
/* избранное активно — заполненное сердце coral */
.pdp-act[data-fav][aria-pressed="true"]{ color:var(--coral,#FF5E7E); border-color:color-mix(in srgb,var(--coral,#FF5E7E) 45%,var(--line2)); }
.pdp-act[data-fav][aria-pressed="true"] .pdp-act-ico{ fill:var(--coral,#FF5E7E); }
.pdp-fav-hint{ margin:-2px 0 0; display:flex; align-items:center; gap:6px; font:500 12.5px var(--font); color:var(--ink2); }
.pdp-fav-hint svg{ flex:none; }

/* ── 4. Карточка мастера — отдельная белая карточка ── */
.pdp-master{
  display:flex; align-items:center; gap:12px; padding:14px 16px;
  border-radius:16px; background:var(--card); border:1px solid var(--line);
}
.pdp-master .pdp-seller{ display:flex; align-items:center; gap:11px; flex:1 1 auto; min-width:0; margin:0; text-decoration:none; }
.pdp-seller-av--ph{ background:linear-gradient(135deg,var(--bg2),#fff); border:1px solid var(--line); }
.pdp-master .pdp-seller-av{ width:44px; height:44px; border-radius:50%; }
.pdp-master-info{ display:flex; flex-direction:column; gap:1px; min-width:0; }
.pdp-master-name{ font:700 14.5px var(--font); color:var(--ink); }
.pdp-master .pdp-seller-handle{ font:600 13px var(--font); }
.pdp-master-shop{ flex:none; font:700 13.5px var(--font); color:var(--ink2); text-decoration:none; white-space:nowrap; transition:color .15s ease-out; }
.pdp-master-shop:hover{ color:var(--violet); }

/* мини-УТП строкой */
.pdp-usps{ display:flex; align-items:center; flex-wrap:wrap; gap:8px; font:600 13px var(--font); color:var(--ink2); }
.pdp-usp{ display:inline-flex; align-items:center; gap:6px; }
.pdp-usp svg{ flex:none; color:var(--violet); }
.pdp-usp-dot{ color:var(--line2); }

/* ── 6. Магазин мастера / редактор — тонкая второстепенная ссылка ── */
.pdp-shop{
  align-self:flex-start; margin-top:1px; color:var(--ink2); font:600 14px var(--font);
  text-decoration:none; border-bottom:1px solid transparent; transition:color .15s, border-color .15s;
}
.pdp-shop:hover{ color:var(--violet); border-color:color-mix(in srgb,var(--violet) 40%,transparent); }

/* ── Инструменты продавца — только владельцу (viewer-aware, кнопки инжектит гидратор) ── */
.pdp-promo{
  margin-top:8px; padding:11px 13px; border-radius:14px;
  border:1px dashed color-mix(in srgb,var(--violet) 32%,var(--line2));
  background:color-mix(in srgb,var(--violet) 5%,#fff);
  display:flex; flex-direction:column; gap:9px;
}
.pdp-promo-head{ font:700 11px var(--font); text-transform:uppercase; letter-spacing:.05em; color:var(--violet); }
.pdp-promo-row{ display:flex; flex-wrap:wrap; gap:8px; }
.pdp-promo-btn{
  height:36px; padding:0 13px; border-radius:10px; cursor:pointer; gap:6px;
  display:inline-flex; align-items:center; font:700 13px var(--font);
  border:1px solid var(--line2); background:#fff; color:var(--ink);
  transition:background .15s, border-color .15s, transform .12s;
}
.pdp-promo-btn:hover{ background:var(--bg2); border-color:color-mix(in srgb,var(--violet) 40%,var(--line2)); }
.pdp-promo-btn:active{ transform:translateY(1px); }
.pdp-promo-btn:focus-visible{ outline:none; box-shadow:0 0 0 3px rgba(124,92,255,.3); }
@media(max-width:768px){ .pdp-promo-btn{ height:44px; } }

/* ── Тонкий sticky-бар покупки (мобайл): дублирует основной CTA ── */
.pdp-mbar{
  position:fixed; left:0; right:0; bottom:0; z-index:40; display:none;
  align-items:center; justify-content:space-between; gap:12px;
  /* + --bs-bottom-reserve: ни cookie-плашка, ни панель разделов не должны накрыть
     мобильный CTA покупки (max, не сумма — см. tokens.css) */
  padding:9px 16px calc(9px + env(safe-area-inset-bottom) + var(--bs-bottom-reserve,0px));
  background:rgba(255,255,255,.94); backdrop-filter:blur(10px); border-top:1px solid var(--line);
}
.pdp-mbar-price{ font:800 18px var(--font-display); color:var(--ink); font-variant-numeric:tabular-nums; }
.pdp-mbar-price.is-quote{ font-size:15px; color:var(--violet); }
.pdp-mbar .pdp-cta{ flex:0 0 auto; }
@media(max-width:860px){ .pdp-mbar.is-on{ display:flex; } .pdp{ padding-bottom:78px; } }

/* ══════════ WP-07/08/10/12 — новые секции карточки (вкус-первый, компактно) ══════════ */

/* ── WP-17. «← Назад к результатам» — ОТДЕЛЬНЫЙ контрол от крошек ниже (см. product_ssr.html):
   крошки = таксономия (статично, всегда), эта кнопка = возврат к КОНКРЕТНОЙ выдаче с фильтрами/
   скроллом; JS показывает её только когда реально пришли с внутренней выдачи (referrer-aware,
   listing-return.js) — пустой слот схлопывается в 0 без неё. Видна на ЛЮБОЙ ширине экрана
   (мобила — основной канал из историй/QR, там кнопка нужна БОЛЬШЕ, а не меньше). ── */
.pdp-back-slot:empty{ margin:0; }
.pdp-back-results{
  display:inline-flex; align-items:center; gap:6px; margin:0 0 10px; padding:7px 13px 7px 11px;
  border-radius:var(--pill); background:var(--card); border:1.5px solid rgba(124,92,255,.3);
  color:var(--violet); text-decoration:none; font:700 13px var(--font); white-space:nowrap;
  transition:background .14s,border-color .14s,transform .14s;
}
.pdp-back-results span{ font-size:15px; line-height:1; }
.pdp-back-results:hover{ background:rgba(124,92,255,.08); border-color:rgba(124,92,255,.55); transform:translateX(-1px); }
.pdp-back-results:focus-visible{ outline:none; box-shadow:0 0 0 3px rgba(124,92,255,.32); }
@media(prefers-reduced-motion:reduce){ .pdp-back-results{ transition:none; } .pdp-back-results:hover{ transform:none; } }

/* ── WP-12. Хлебные крошки (чистая таксономия, без «назад» — см. выше) ── */
.pdp-crumbs{ display:flex; align-items:center; justify-content:space-between; gap:12px; flex-wrap:wrap; margin:2px 0 14px; }
.pdp-crumbs-list{ display:flex; flex-wrap:wrap; align-items:center; gap:6px; margin:0; padding:0; list-style:none; min-width:0; font:600 12.5px var(--font); }
.pdp-crumbs-list li{ display:flex; align-items:center; gap:6px; min-width:0; }
.pdp-crumbs-list li + li::before{ content:"›"; color:var(--ink2); opacity:.55; }
.pdp-crumbs-list a{ color:var(--ink2); text-decoration:none; border-radius:6px; transition:color .14s; }
.pdp-crumbs-list a:hover{ color:var(--violet); }
.pdp-crumbs-list a:focus-visible{ outline:none; box-shadow:0 0 0 3px rgba(124,92,255,.32); }
.pdp-crumbs-list [aria-current="page"]{ color:var(--ink); font-weight:700; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; max-width:min(46vw,360px); }

/* ════════════════════════════════════════════════════════════════════════════════════
   ХЛЕБНЫЕ КРОШКИ — ЕДИНЫЙ КОМПОНЕНТ (partial _breadcrumbs.html, ux-pro)
   Тонкая компактная строка под шапкой, НАД H1 (D0-плотность: ~30px, 12px, приглушённый).
   Разделитель — CSS ::before «›» (без сырых эмодзи). Мобайл: горизонт-скролл, без стопки.
   Единая разметка .crumbs; в мире /printers эти же классы продублированы в printers.css
   на --pc-* токенах (там нет tokens.css). Видимая цепочка = зеркало BreadcrumbList (seo-smith).
   ════════════════════════════════════════════════════════════════════════════════════ */
.crumbs{ margin:var(--sp-4,16px) 0 var(--sp-3,12px); min-width:0; }
.crumbs__list{
  display:flex; align-items:center; flex-wrap:nowrap; gap:var(--sp-2,8px);
  margin:0; padding:0; list-style:none;
  font:500 var(--fs-xs,12px)/1.4 var(--font,'Inter',sans-serif);
  overflow-x:auto; scrollbar-width:none; -webkit-overflow-scrolling:touch;
}
.crumbs__list::-webkit-scrollbar{ display:none; }
.crumbs__item{ display:flex; align-items:center; gap:var(--sp-2,8px); min-width:0; white-space:nowrap; }
.crumbs__item + .crumbs__item::before{
  content:"\203A"; color:var(--ink2,#5B5B66); opacity:.5; font-weight:400; flex:none; line-height:1;
}
.crumbs__link{
  color:var(--ink2,#5B5B66); text-decoration:none; border-radius:var(--rad-xs,6px);
  padding-block:6px; transition:color .14s ease-out; white-space:nowrap;
}
.crumbs__link:hover{ color:var(--violet,#7C5CFF); }
.crumbs__link:focus-visible{ outline:none; box-shadow:0 0 0 3px rgba(124,92,255,.32); }
.crumbs__mid{ color:var(--ink2,#5B5B66); padding-block:6px; white-space:nowrap; }
.crumbs__cur{
  color:var(--ink,#141414); font-weight:600; padding-block:6px;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; max-width:min(52vw,340px);
}

/* ── WP-17. Подсветка карточки, к которой докрутили при возврате из PDP (маркетплейс/избранное) ── */
.pp-return-highlight{ animation:ppReturnPulse 1.6s ease-out; border-radius:var(--r); }
@keyframes ppReturnPulse{
  0%{ box-shadow:0 0 0 0 rgba(124,92,255,.5); }
  70%{ box-shadow:0 0 0 16px rgba(124,92,255,0); }
  100%{ box-shadow:0 0 0 0 rgba(124,92,255,0); }
}
@media(prefers-reduced-motion:reduce){ .pp-return-highlight{ animation:none; box-shadow:0 0 0 3px rgba(124,92,255,.5); } }

/* ── WP-07. Галерея: стейдж (переключаемые виды) + лента миниатюр ── */
.pdp-media.pdp-gallery{ aspect-ratio:auto; border:0; background:none; overflow:visible; border-radius:0; display:flex; flex-direction:column; gap:10px; }
.pdp-stage{ position:relative; aspect-ratio:1/1; border-radius:20px; overflow:hidden; background:linear-gradient(160deg,var(--bg2),#fff); border:1px solid var(--line); }
@media(max-width:860px){ .pdp-stage{ aspect-ratio:4/3; } }
.pdp-view{ position:absolute; inset:0; display:none; }
.pdp-view.is-active{ display:block; }
.pdp-stage model-viewer{ width:100%; height:100%; --poster-color:transparent; }
.pdp-stage .pdp-cover{ width:100%; height:100%; object-fit:cover; }
.pdp-thumbs{ display:flex; gap:8px; flex-wrap:wrap; }
.pdp-thumb{ position:relative; width:60px; height:60px; padding:0; border-radius:12px; overflow:hidden; cursor:pointer; background:var(--bg2); border:2px solid transparent; box-shadow:0 0 0 1px var(--line) inset; transition:border-color .15s, transform .12s; }
.pdp-thumb img{ width:100%; height:100%; object-fit:cover; display:block; }
.pdp-thumb:hover{ transform:translateY(-1px); }
.pdp-thumb.is-active{ border-color:var(--violet); box-shadow:0 0 0 1px var(--violet) inset; }
.pdp-thumb:focus-visible{ outline:none; border-color:var(--violet); box-shadow:0 0 0 3px rgba(124,92,255,.35); }
.pdp-thumb-tag{ position:absolute; left:0; right:0; bottom:0; padding:2px 0; text-align:center; font:800 9px var(--font); letter-spacing:.04em; color:#fff; background:rgba(15,16,32,.62); }
@media (prefers-reduced-motion:reduce){ .pdp-thumb{ transition:none; } }

/* ── LENS-зум фото: in-frame магнифайер на hover (JS гейтит pointer:fine + reduced-motion; тач = no-op).
   Стейдж overflow:hidden → scale остаётся в рамке; transform-origin JS двигает за курсором. ── */
.pdp-view.pdp-lens{ cursor:zoom-in; }
.pdp-view.pdp-lens .pdp-cover{ transition:transform .18s ease-out; will-change:transform; }
@media (prefers-reduced-motion:reduce){ .pdp-view.pdp-lens .pdp-cover{ transition:none; } }

/* ── SHIMMER-скелетон hero-фото: бегущий блик поверх стейджа, пока картинка декодится.
   JS вешает/снимает .is-loading (eager-hero снимается сразу по img.complete). Виден только на
   активном виде (неактивные .pdp-view = display:none). ── */
.pdp-view.is-loading::after{
  content:""; position:absolute; inset:0; z-index:2; pointer-events:none; border-radius:inherit;
  background:linear-gradient(100deg, transparent 25%, rgba(255,255,255,.6) 50%, transparent 75%);
  background-size:220% 100%;
  animation:pdp-shimmer 1.25s ease-in-out infinite;
}
@keyframes pdp-shimmer{ 0%{ background-position:160% 0; } 100%{ background-position:-60% 0; } }
@media (prefers-reduced-motion:reduce){ .pdp-view.is-loading::after{ animation:none; } }

/* ── WP-28. AR-кнопка «Примерить» — вторичная, стеклянная, в углу стейджа (инжектит JS) ── */
.pdp-ar-btn{
  position:absolute; left:12px; bottom:12px; z-index:3; display:inline-flex; align-items:center; gap:6px;
  height:36px; padding:0 13px; border:0; border-radius:999px; cursor:pointer;
  font:700 12.5px var(--font); color:var(--ink); background:rgba(255,255,255,.92); backdrop-filter:blur(6px);
  box-shadow:0 4px 14px -4px rgba(15,16,32,.4); transition:transform .14s, box-shadow .14s;
}
.pdp-ar-btn:hover{ transform:translateY(-1px); box-shadow:0 8px 20px -6px rgba(15,16,32,.5); }
.pdp-ar-btn:active{ transform:translateY(0); }
.pdp-ar-btn:focus-visible{ outline:none; box-shadow:0 0 0 3px rgba(124,92,255,.42); }
@media(max-width:768px){ .pdp-ar-btn{ height:44px; padding:0 16px; } }
@media (prefers-reduced-motion:reduce){ .pdp-ar-btn{ transition:none; } }

/* ── WP-10. Бейдж «Проверенный мастер» (emerald = good, не декор) ── */
.pdp-verified{
  display:inline-flex; align-items:center; gap:4px; margin-left:2px; padding:2px 9px; white-space:nowrap;
  border-radius:999px; font:700 11px var(--font); color:#0f7a44;
  background:rgba(16,163,90,.12); border:1px solid rgba(16,163,90,.30);
}

/* ── WP-08. Секции под покупкой ── */
.pdp-sections{ display:flex; flex-direction:column; gap:22px; margin-top:34px; }
.pdp-section{ padding-top:22px; border-top:1px solid var(--line); }
.pdp-sec-title{ margin:0 0 12px; font:800 17px var(--font-display); letter-spacing:-.01em; color:var(--ink); }
@media(max-width:860px){ .pdp-sections{ margin-top:24px; gap:18px; } }

/* хайлайты УТП — плитки иконка+заголовок+абзац */
.pdp-hl-grid{ display:grid; grid-template-columns:repeat(auto-fit,minmax(210px,1fr)); gap:12px; }
.pdp-hl{ display:flex; flex-direction:column; gap:5px; padding:14px 15px; border-radius:14px; background:var(--bg2); border:1px solid var(--line); }
.pdp-hl-ico{ font-size:20px; line-height:1; }
.pdp-hl-title{ font:700 14px var(--font); color:var(--ink); }
.pdp-hl-text{ margin:0; font:500 13px/1.5 var(--font); color:var(--ink2); }

/* характеристики — сканируемая zebra-таблица (моно-цифры) */
.pdp-spec-table{ margin:0; border:1px solid var(--line); border-radius:14px; overflow:hidden; }
.pdp-spec-row{ display:grid; grid-template-columns:minmax(116px,200px) 1fr; gap:12px; padding:10px 15px; }
.pdp-spec-row:nth-child(even){ background:var(--bg2); }
.pdp-spec-row dt{ margin:0; font:600 13.5px var(--font); color:var(--ink2); }
.pdp-spec-row dd{ margin:0; font:600 13.5px var(--font); color:var(--ink); font-variant-numeric:tabular-nums; }

/* лицензия — компактная строка */
.pdp-license{ display:block; }
.pdp-license-key{ font-size:15px; line-height:1; }
.pdp-license-lbl{ font:700 12px var(--font); text-transform:uppercase; letter-spacing:.04em; color:var(--ink2); }
.pdp-license-val{ font:600 14px var(--font); color:var(--ink); }
/* WP-18: раскрытие прав по лицензии — нативный <details>, SEO-видимый текст, 0 JS */
.pdp-lic-details{ border:1px solid var(--line,#e7e7ee); border-radius:12px; overflow:hidden; }
.pdp-lic-summary{ display:flex; align-items:center; gap:8px; flex-wrap:wrap; cursor:pointer;
  padding:12px 14px; min-height:44px; list-style:none; user-select:none; }
.pdp-lic-summary::-webkit-details-marker{ display:none; }
.pdp-lic-sum{ font:400 13px var(--font); color:var(--ink2); flex:1 1 100%; order:3; margin-top:2px; }
.pdp-lic-caret{ margin-left:auto; color:var(--ink2); transition:transform .18s ease; }
.pdp-lic-details[open] .pdp-lic-caret{ transform:rotate(180deg); }
.pdp-lic-body{ padding:4px 14px 14px; display:flex; flex-wrap:wrap; gap:14px 24px; }
.pdp-lic-col{ flex:1 1 200px; min-width:0; }
.pdp-lic-col-t{ display:block; font:700 11px var(--font); text-transform:uppercase; letter-spacing:.04em;
  color:var(--ink2); margin-bottom:4px; }
.pdp-lic-col ul{ list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:3px; }
.pdp-lic-col li{ font:500 13px var(--font); line-height:1.4; }
.pdp-lic-can li{ color:#1a7f52; }
.pdp-lic-cannot li{ color:#b23b3b; }
.pdp-lic-attr{ flex:1 1 100%; margin:0; font:500 12px var(--font); color:var(--ink2); }
.pdp-lic-disclaimer{ flex:1 1 100%; margin:6px 0 0; padding-top:8px; border-top:1px dashed var(--line,#e7e7ee);
  font:400 11px var(--font); line-height:1.5; color:var(--ink3,#9a9aa6); }
@media (prefers-reduced-motion: reduce){ .pdp-lic-caret{ transition:none; } }

/* ── WP-16: «Ещё от мастера» / «Похожие товары» — SSR-ряды карточек-ссылок внизу PDP.
   Каждая карточка = цельный <a> (Jakob: клик по всей карточке → страница товара, крупный
   тач-таргет). Десктоп/планшет — сетка (4/3 колонки), мобайл — горизонтальный scroll-snap
   ряд (стандарт e-commerce). INV-RENDER рисует секцию только при непустом наборе. ── */
.pdp-related{ margin-top:38px; padding-top:26px; border-top:1px solid var(--line);
  display:flex; flex-direction:column; gap:32px; }
@media(max-width:860px){ .pdp-related{ margin-top:26px; gap:26px; } }
.pdp-rel-head{ display:flex; align-items:baseline; justify-content:space-between; gap:12px; margin-bottom:14px; }
.pdp-rel-head .pdp-sec-title{ margin:0; }
.pdp-rel-head .pdp-sec-title a{ color:inherit; text-decoration:none; }
.pdp-rel-head .pdp-sec-title a:hover{ color:var(--violet); }
.pdp-rel-more{ flex:none; display:inline-flex; align-items:center; min-height:44px;
  font:700 13px var(--font); color:var(--violet); text-decoration:none; white-space:nowrap; }
.pdp-rel-more:hover{ text-decoration:underline; }
.pdp-rel-grid{ display:grid; grid-template-columns:repeat(4,minmax(0,1fr)); gap:14px; }
@media(max-width:900px){ .pdp-rel-grid{ grid-template-columns:repeat(3,minmax(0,1fr)); } }
@media(max-width:640px){
  /* мобайл: горизонтальный scroll-snap ряд — карточка ~62% ширины, край следующей виден */
  .pdp-rel-grid{ display:flex; overflow-x:auto; scroll-snap-type:x mandatory;
    gap:12px; margin:0 -16px; padding:2px 16px 8px;
    -webkit-overflow-scrolling:touch; scrollbar-width:none; }
  .pdp-rel-grid::-webkit-scrollbar{ display:none; }
  .pdp-rel-card{ flex:0 0 61%; scroll-snap-align:start; }
}
.pdp-rel-card{ display:flex; flex-direction:column; background:var(--card);
  border:1px solid var(--line); border-radius:16px; overflow:hidden;
  text-decoration:none; color:var(--ink);
  transition:transform .16s ease, box-shadow .16s ease, border-color .16s ease; }
.pdp-rel-card:hover{ transform:translateY(-3px); border-color:var(--line2);
  box-shadow:0 10px 26px rgba(20,20,20,.09); }
.pdp-rel-card:focus-visible{ outline:none; box-shadow:0 0 0 3px rgba(124,92,255,.45); }
.pdp-rel-media{ position:relative; aspect-ratio:4/5; background:var(--bg2);
  overflow:hidden; display:block; }
.pdp-rel-cover{ position:absolute; inset:0; width:100%; height:100%; object-fit:contain; }
.pdp-rel-poster{ position:absolute; inset:0; display:flex; align-items:center;
  justify-content:center; font-size:30px; color:var(--ink2); }
.pdp-rel-3d{ position:absolute; left:8px; top:8px; background:rgba(20,20,20,.62); color:#fff;
  backdrop-filter:blur(6px); font:800 10.5px var(--font-display); letter-spacing:.02em;
  padding:3px 8px; border-radius:var(--pill); }
.pdp-rel-body{ padding:9px 11px 12px; display:flex; flex-direction:column; gap:4px; }
.pdp-rel-price{ font:800 16px var(--font-display); color:var(--ink); line-height:1.15;
  font-variant-numeric:tabular-nums; white-space:nowrap; }
.pdp-rel-price.is-nego{ color:var(--violet); font-size:14px; }
.pdp-rel-title{ font:700 13px var(--font); color:var(--ink); line-height:1.3;
  display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden;
  min-height:2.6em; }
.pdp-rel-master{ font:600 11.5px var(--font); color:var(--ink2);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
@media(prefers-reduced-motion:reduce){
  .pdp-rel-card{ transition:none; }
  .pdp-rel-card:hover{ transform:none; }
}

/* ── brandbook #9: возврат/гарантия — компактная приглушённая строка в зоне лицензии ── */
.pdp-return{ padding-top:14px; }
.pdp-return-row{ display:flex; align-items:flex-start; gap:8px; margin:0;
  font:500 13px/1.5 var(--font); color:var(--ink2); }
.pdp-return-ico{ flex:none; margin-top:1px; color:var(--ink3,#9a9aa6); }

/* ── brandbook #12: отзывы + фото сборок (⚪ заглушка-приманка пока отзывов нет) ── */
.pdp-reviews{ margin-top:2px; }
.pdp-review-list{ list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:14px; }
.pdp-review{ padding:14px 16px; border:1px solid var(--line); border-radius:16px; background:var(--card); }
/* wrap обязателен: в голове может стоять до ТРЁХ блоков (имя+звёзды · «Проверенная покупка» ·
   «Скрыть» у владельца) — без переноса на 390px имя схлопывалось в ноль, звёзды уезжали под бейдж,
   а «Скрыть» обрезался краем карточки. Перенос включается только когда строка реально не влезла. */
.pdp-review-head{ display:flex; align-items:center; gap:10px; margin-bottom:8px; flex-wrap:wrap; }
.pdp-review-av{ width:36px; height:36px; border-radius:50%; object-fit:cover; flex:none; }
.pdp-review-av--ph{ background:var(--bg2); border:1px solid var(--line); }
.pdp-review-who{ display:flex; flex-direction:column; gap:1px; min-width:min(140px,100%); flex:1 1 auto; }
/* Голова карточки — flex без переноса, а бейдж «Проверенная покупка» flex:none. Без сжимаемой
   колонки имени длинное имя на узком экране НАЕЗЖАЛО на бейдж (замер 390px). Колонка сжимается,
   имя усекается многоточием — бейдж остаётся на месте и читается. */
.pdp-review-name{ font:700 13.5px var(--font); color:var(--ink); min-width:0; max-width:100%;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.pdp-review-stars{ font-size:12px; letter-spacing:1px; color:var(--carrot,#FF7A1A); }
.pdp-review-text{ margin:0; font:500 13.5px/1.5 var(--font); color:var(--ink2); }
.pdp-review-photos{ display:flex; flex-wrap:wrap; gap:8px; margin-top:10px; }
.pdp-review-photo{ width:72px; height:72px; border-radius:10px; object-fit:cover; border:1px solid var(--line); }
/* заглушка-приманка «будь первым» — тёплая пустота (canon §5: почему + приглашение) */
.pdp-review-empty{ display:flex; flex-direction:column; align-items:center; text-align:center;
  gap:6px; padding:26px 20px; border:1px dashed var(--line2,var(--line)); border-radius:18px;
  background:var(--bg2); }
.pdp-review-empty-ico{ color:var(--violet); line-height:0; }
.pdp-review-empty-t{ margin:0; font:800 15px var(--font-display); color:var(--ink); }
.pdp-review-empty-s{ margin:0; max-width:42ch; font:500 13px/1.5 var(--font); color:var(--ink2); }

/* ── #12 отзывы: интерактив (сводка · форма · проверенная покупка · свой отзыв) ── */
.pdp-review-top{ display:flex; align-items:baseline; flex-wrap:wrap; gap:10px 14px; margin-bottom:14px; }
.pdp-review-top .pdp-sec-title{ margin:0; }
.pdp-review-summary{ display:inline-flex; align-items:baseline; gap:8px; font:600 14px var(--font); }
.pdp-review-sum-avg{ display:inline-flex; align-items:baseline; gap:4px; font-weight:800; color:var(--ink);
  font-variant-numeric:tabular-nums; }
.pdp-review-sum-star{ color:var(--carrot,#FF7A1A); }
.pdp-review-sum-sep{ color:var(--ink3,#9a9aa6); }
.pdp-review-sum-count{ color:var(--ink2); }

/* зона «оставить отзыв» — тихий вторичный вес, не спорит с buy box выше */
.pdp-review-cta, .pdp-review-gate{ margin-bottom:16px; }
.pdp-review-cta .pp-btn{ min-height:44px; }
.pdp-review-gate{ display:flex; flex-wrap:wrap; align-items:center; gap:10px 14px;
  padding:14px 16px; border:1px dashed var(--line2,var(--line)); border-radius:16px; background:var(--bg2); }
.pdp-review-gate-t{ margin:0; font:600 14px var(--font); color:var(--ink); }
.pdp-review-gate-btn{ min-height:44px; }

/* форма отзыва */
.pdp-rev-form-slot[hidden]{ display:none; }
.pdp-rev-form{ display:flex; flex-direction:column; gap:16px; margin-bottom:18px;
  padding:18px; border:1px solid var(--line); border-radius:18px; background:var(--card); box-shadow:var(--shadow); }
.pdp-rev-field{ display:flex; flex-direction:column; gap:8px; }
.pdp-rev-lbl{ font:700 13px var(--font); color:var(--ink); }
.pdp-rev-req{ color:var(--coral); margin-left:2px; }
.pdp-rev-opt{ font-weight:500; color:var(--ink3,#9a9aa6); }

/* звёздный ВВОД: 44px тап-таргеты, current-status цвет = carrot, focus-ring виден */
.pdp-rev-stars{ display:inline-flex; gap:2px; }
.pdp-rev-star{ width:44px; height:44px; padding:0; border:0; background:none; cursor:pointer;
  font-size:30px; line-height:1; color:var(--line2,#d8d8e0);
  transition:color .12s ease-out, transform .12s ease-out; }
.pdp-rev-star.is-on{ color:var(--carrot,#FF7A1A); }
.pdp-rev-star:hover{ transform:scale(1.08); }
.pdp-rev-star:focus-visible{ outline:none; border-radius:8px; box-shadow:0 0 0 3px rgba(124,92,255,.45); }

.pdp-rev-text{ width:100%; box-sizing:border-box; resize:vertical; min-height:96px; padding:12px 14px;
  border-radius:12px; border:1.5px solid var(--line2); font:500 14px/1.5 var(--font); color:var(--ink); }
.pdp-rev-text:focus{ outline:none; border-color:var(--violet); box-shadow:0 0 0 3px rgba(124,92,255,.15); }
.pdp-rev-counter{ align-self:flex-end; font:600 12px var(--font); color:var(--ink3,#9a9aa6);
  font-variant-numeric:tabular-nums; }

.pdp-rev-thumbs{ display:flex; flex-wrap:wrap; gap:8px; }
.pdp-rev-thumbs[hidden]{ display:none; }
.pdp-rev-thumb{ position:relative; width:72px; height:72px; }
.pdp-rev-thumb img{ width:100%; height:100%; object-fit:cover; border-radius:10px; border:1px solid var(--line); }
.pdp-rev-thumb-x{ position:absolute; top:-6px; right:-6px; width:22px; height:22px; border-radius:50%;
  border:0; cursor:pointer; background:var(--ink); color:#fff; font-size:11px; line-height:1;
  display:inline-flex; align-items:center; justify-content:center; box-shadow:0 2px 6px rgba(20,20,20,.3); }
.pdp-rev-thumb-x:focus-visible{ outline:none; box-shadow:0 0 0 3px rgba(124,92,255,.5); }

/* Текст ошибки читаем: --coral на своей же 10%-подложке давал 2.6:1 (мимо WCAG AA 4.5), а тут
   живёт ответ бэкенда («Уберите контакты из ответа…») — его обязаны прочитать. rose-800 на той же
   подложке = 6.2:1; плашка (фон+рамка) остаётся сигналом помимо цвета текста. */
.pdp-rev-err{ margin:0; padding:10px 12px; border-radius:10px; font:600 13px/1.4 var(--font);
  color:var(--rose-800); background:color-mix(in srgb,var(--coral) 10%,#fff);
  border:1px solid color-mix(in srgb,var(--coral) 28%,#fff); }
.pdp-rev-err[hidden]{ display:none; }

.pdp-rev-actions{ display:flex; flex-wrap:wrap; gap:10px; }
.pdp-rev-actions .pp-btn{ min-height:44px; flex:0 1 auto; }
.pdp-rev-submit:disabled{ opacity:.6; cursor:progress; }

/* бейдж «✓ Проверенная покупка» — сильный сигнал доверия (иконка+текст, не только цвет) */
.pdp-review-verified{ display:inline-flex; align-items:center; gap:4px; margin-left:auto; flex:none;
  padding:3px 9px; border-radius:999px; font:800 11px var(--font); color:var(--ok);
  background:color-mix(in srgb,var(--ok) 12%,#fff); border:1px solid color-mix(in srgb,var(--ok) 26%,#fff); }

/* «Ваш отзыв» — маркер + inline-действия на своей карточке */
.pdp-review-nameline{ display:inline-flex; align-items:center; gap:8px; flex-wrap:wrap; min-width:0; max-width:100%; }
.pdp-review-mine{ padding:2px 8px; border-radius:999px; font:800 10.5px var(--font);
  letter-spacing:.02em; color:var(--violet); background:rgba(124,92,255,.10); border:1px solid rgba(124,92,255,.28); }
.pdp-review.is-mine{ border-color:rgba(124,92,255,.35); background:color-mix(in srgb,var(--violet) 4%,var(--card)); }
.pdp-review-own-acts{ display:flex; gap:14px; margin-top:10px; }
.pdp-review-edit, .pdp-review-del{ min-height:32px; padding:4px 2px; border:0; background:none; cursor:pointer;
  font:700 12.5px var(--font); }
.pdp-review-edit{ color:var(--violet); }
.pdp-review-del{ color:var(--ink2); }
.pdp-review-del:hover{ color:var(--coral); }
.pdp-review-edit:focus-visible, .pdp-review-del:focus-visible{ outline:none; border-radius:6px;
  box-shadow:0 0 0 3px rgba(124,92,255,.35); }

/* Модерация владельца: «Скрыть» — tertiary, приглушённая, в углу шапки. 44px тап-таргет
   (площадь тапа паддингом, глиф мелкий). Бордер/фон только на hover — де-эмфаза (не rose,
   скрытие обратимо на сервере). Идёт после verified в углу: сама уходит вправо margin:auto,
   а если рядом verified (у него свой margin-left:auto) — только фикс-зазор, без драки за space. */
.pdp-review-hide{ margin-left:auto; flex:none; min-height:44px; padding:0 10px; border:1px solid transparent;
  border-radius:10px; background:none; cursor:pointer; font:700 12.5px var(--font); color:var(--ink3,#9a9aa6);
  transition:color .12s ease, background .12s ease, border-color .12s ease; }
.pdp-review-verified + .pdp-review-hide{ margin-left:8px; }
.pdp-review-hide:hover{ color:var(--ink2); background:var(--bg2); border-color:var(--line); }
.pdp-review-hide:focus-visible{ outline:none; border-color:transparent;
  box-shadow:0 0 0 3px rgba(124,92,255,.35); }
.pdp-review.is-removing{ opacity:0; transform:translateX(10px); pointer-events:none;
  transition:opacity .2s ease, transform .2s ease; }
@media(prefers-reduced-motion:reduce){ .pdp-review-hide{ transition:none; } .pdp-review.is-removing{ transition:none; } }

/* ── WP-REV-E: «Ответ мастера» под отзывом — публичный, ДЕ-ЭМФАЗА (вторичный тон, приглушённый
   фон + левый акцент-бордер). Отступ + вложенность = «реплика на отзыв», не спорит с buy box. ── */
.pdp-review-reply{ margin-top:12px; padding:10px 14px; border-radius:12px;
  background:var(--bg2); border-left:3px solid var(--violet); }
.pdp-review-reply-head{ display:inline-flex; align-items:center; gap:5px; margin-bottom:3px;
  color:var(--violet); }
.pdp-review-reply-lbl{ font:800 11.5px var(--font); letter-spacing:.01em; }
.pdp-review-reply-text{ margin:0; font:500 13px/1.5 var(--font); color:var(--ink2); }
/* вход владельца «Ответить»/«Изменить ответ» — тихий tertiary, не rose, отдельной строкой */
.pdp-review-owner-acts{ display:flex; gap:14px; margin-top:10px; }
.pdp-review-reply-btn{ min-height:32px; padding:4px 2px; border:0; background:none; cursor:pointer;
  font:700 12.5px var(--font); color:var(--violet); }
.pdp-review-reply-btn:hover{ text-decoration:underline; }
.pdp-review-reply-btn:focus-visible{ outline:none; border-radius:6px; box-shadow:0 0 0 3px rgba(124,92,255,.35); }
/* тач: тап-таргет 44 добираем ЗОНОЙ (min-height+padding у прозрачной кнопки), а не крупным текстом */
@media(max-width:768px){ .pdp-review-reply-btn{ min-height:44px; padding:10px 2px; } }
/* inline-форма ответа владельца */
.pdp-reply-form{ display:flex; flex-direction:column; gap:10px; margin-top:12px;
  padding:14px; border:1px solid var(--line); border-radius:14px; background:var(--card); }
.pdp-reply-lbl{ font:700 13px var(--font); color:var(--ink); }
.pdp-reply-ta{ width:100%; box-sizing:border-box; resize:vertical; min-height:72px; padding:11px 13px;
  border-radius:12px; border:1.5px solid var(--line2); font:500 13.5px/1.5 var(--font); color:var(--ink); }
.pdp-reply-ta:focus{ outline:none; border-color:var(--violet); box-shadow:0 0 0 3px rgba(124,92,255,.15); }
.pdp-reply-actions{ display:flex; flex-wrap:wrap; align-items:center; gap:10px; }
/* D0: база .pp-btn = width:100% → во flex-wrap КАЖДАЯ кнопка получала свою строку во всю ширину
   (замер: строка действий 152px вместо 44, форма ответа 303px). Компактный тир проекта —
   auto-ширина, 40px, как .pp-btn-compact/.pp-acts: действия ответа умещаются в ОДНУ строку. */
.pdp-reply-actions .pp-btn{ min-height:40px; width:auto; flex:0 1 auto; padding:0 16px; font-size:14px; }
.pdp-reply-submit:disabled{ opacity:.6; cursor:progress; }
/* P3-13 «Удалить ответ» — ЯВНЫЙ путь снятия ответа. Деструктив отделён от primary: тихий ghost
   без заливки, rose-700 (4.6:1 на белом — AA, в отличие от --err 3.2:1), отодвинут margin-left:auto,
   иконка + текст (цвет не единственный сигнал), подтверждение в обработчике. Высоту берёт из
   .pdp-reply-actions .pp-btn (40px) — компактный тир, тело кнопки не раздуто. */
.pdp-reply-del{ width:auto; margin-left:auto; padding:0 12px; font-size:13px; color:var(--rose-700);
  border:1.5px solid transparent; background:transparent; }
.pdp-reply-del:hover{ background:var(--rose-50); }
.pdp-reply-del:focus-visible{ outline:none; border-color:transparent; box-shadow:0 0 0 3px rgba(214,58,74,.32); }
.pdp-reply-del:disabled{ opacity:.5; cursor:progress; }
.pdp-reply-del svg{ flex:none; }
/* мобайл: кнопка переносится на свою строку — прижимать её вправо там нечем и незачем */
@media(max-width:480px){ .pdp-reply-del{ margin-left:0; } }

/* ── B-2 «Пожаловаться на отзыв» — единственный ЗАКОННЫЙ ход мастера по несправедливому отзыву
   (скрывать может только модератор площадки). Тихий tertiary В ТОЙ ЖЕ строке, что «Ответить»:
   вторая кнопка не добавляет карточке НИ ОДНОГО пикселя высоты. Цвет — ink2, НЕ rose: это
   обращение к площадке, а не удаление; деструктивную окраску занимать нечем (§14.A). Тап-таргет
   44 добираем ЗОНОЙ (min-height у прозрачной кнопки), как у входа «Ответить», а не кеглем. ── */
.pdp-review-report-btn{ display:inline-flex; align-items:center; gap:5px; min-height:32px;
  padding:4px 2px; border:0; background:none; cursor:pointer; font:700 12.5px var(--font);
  color:var(--ink2); }
.pdp-review-report-btn:hover{ color:var(--rose-700); text-decoration:underline; }
.pdp-review-report-btn:focus-visible{ outline:none; border-radius:6px; box-shadow:0 0 0 3px rgba(124,92,255,.35); }
.pdp-review-report-btn svg{ flex:none; }
@media(max-width:768px){ .pdp-review-report-btn{ min-height:44px; padding:10px 2px; } }
/* состояние ПОСЛЕ отправки: не кнопка, а факт (жать второй раз незачем). ink2, а не ink3 —
   это текст-сообщение, ему нужен AA-контраст, и иконка несёт смысл вместе с надписью. */
.mrev-reported{ display:inline-flex; align-items:center; gap:5px; min-height:32px;
  font:600 12.5px var(--font); color:var(--ink2); }
.mrev-reported svg{ flex:none; }
/* инлайн-панель жалобы. Модалку не берём: полей два, а окно поверх карточки рвёт связь
   «жалуюсь ВОТ на этот отзыв» и по D0 занимает пол-экрана ради двух строк. Замер: 12+12
   паддинги + фраза последствия (18–36) + 32 + 32 + 36 кнопки + 3×8 гэпы ≈ 166–184px —
   компактнее формы ответа (~177px), которая уже принята. */
.mrev-report-form{ display:flex; flex-direction:column; gap:8px; margin-top:10px; padding:12px;
  border:1px solid var(--line); border-radius:14px; background:var(--card); }
.mrev-report-note{ margin:0; font:500 12.5px/1.45 var(--font); color:var(--ink2); }
.mrev-report-row{ display:flex; align-items:center; gap:8px; }
/* колонка подписей фиксирована → оба поля начинаются на одной вертикали (левый край не рвётся) */
.mrev-report-lbl{ flex:0 0 92px; font:700 12.5px var(--font); color:var(--ink); }
.mrev-report-sel, .mrev-report-inp{ min-width:0; box-sizing:border-box; height:32px;
  padding:0 10px; border:1.5px solid var(--line2); border-radius:10px; background:var(--card);
  font:500 13px var(--font); color:var(--ink); }
/* поля НЕ растягиваем во всю колонку отзыва: селект из 5 пунктов шириной 700px — это та самая
   раздутость, против которой D0 (замер до правки: 714px). Ширина по содержимому задачи. */
.mrev-report-sel{ flex:0 1 260px; }
.mrev-report-inp{ flex:1 1 auto; max-width:420px; }
.mrev-report-sel:focus, .mrev-report-inp:focus{ outline:none; border-color:var(--violet);
  box-shadow:0 0 0 3px rgba(124,92,255,.15); }
.mrev-report-acts{ display:flex; flex-wrap:wrap; align-items:center; gap:8px; }
/* база .pp-btn = width:100% → каждая кнопка забирала бы свою строку во всю ширину (см. тот же
   разбор у .pdp-reply-actions). Компактный тир: auto-ширина, 36px — панель служебная. */
.mrev-report-acts .pp-btn{ width:auto; flex:0 1 auto; min-height:36px; padding:0 14px; font-size:13.5px; }
.mrev-report-acts .pp-btn:disabled{ opacity:.6; cursor:progress; }
/* тач: у нативного контрола 44 нельзя добрать прозрачной зоной — только высотой. Кегль
   оставляем 14 (в семье остальных полей проекта): 16px тут «не зумит на iOS», но делает поле
   крупнее ВСЕХ соседних форм — ровно тот перекос, против которого D0. Зум-на-фокусе в iOS —
   общий долг всех форм проекта, чинить его надо одним проходом, а не в одном поле. */
@media(max-width:768px){
  .mrev-report-sel, .mrev-report-inp{ height:44px; font-size:14px; }
  .mrev-report-acts .pp-btn{ min-height:44px; }
}
@media(max-width:480px){
  .mrev-report-row{ flex-direction:column; align-items:stretch; gap:4px; }
  .mrev-report-lbl{ flex:none; }
  .mrev-report-sel, .mrev-report-inp{ flex:none; max-width:none; width:100%; }
}

/* ── WP-REV-B: разведение ДВУХ рейтингов мастера. pp-rating (profile_ssr.html) = рейтинг по
   СДЕЛКАМ Биржи; product-review-агрегат (витрина/карточки) = рейтинг по ТОВАРАМ. Обе шкалы
   несовместимы → каждой нужен явный scope-ярлык, чтобы числа не читались как одно и то же.
   Класс-хелпер: тихий muted-суффикс к строке рейтинга (по сделкам / по товарам). Подключается
   разметкой (см. handoff marketplace-steward — правки в profile_ssr.html и шапке /@handle/shop). */
.pp-rating-scope{ color:var(--ink3,#9a9aa6); font-weight:500; font-size:.92em; white-space:nowrap; }

/* ── Вкладка «Отзывы» страницы мастера: 2 секции (о товарах / о мастере). Переиспользует
   pdp-review-* карточки; тут — только оболочка секций, заголовки, summary, состояния. ── */
.mrev-root{ display:flex; flex-direction:column; gap:26px; }
.mrev-section{ display:flex; flex-direction:column; gap:12px; }
.mrev-sec-top{ display:flex; align-items:baseline; flex-wrap:wrap; gap:8px 12px; }
.mrev-sec-title{ margin:0; font:800 16px var(--font-display,var(--font)); color:var(--ink); }
.mrev-sec-sum{ display:inline-flex; align-items:baseline; gap:4px; font:600 13px var(--font);
  color:var(--ink2); font-variant-numeric:tabular-nums; }
.mrev-sec-sum .mrev-star{ color:var(--carrot,#FF7A1A); }
/* пустой скоуп-счётчик у заголовка секции: «Отзывы о мастере · пока нет» (не глобальное «нет») */
.mrev-sec-sum-none{ color:var(--ink3,#9a9aa6); font-weight:600; }
/* короткая скоуп-подпись НАД CTA (пустая секция «о мастере»): единственный зов, без плашки-дубля */
.mrev-cta-cap{ margin:0 0 8px; font:600 13px/1.4 var(--font); color:var(--ink2); }
.mrev-list{ margin-top:2px; }
/* ссылка на товар-источник в карточке product-review (компактная, вторичная) */
.mrev-product-link{ display:inline-flex; align-items:center; gap:5px; align-self:flex-start;
  margin:-2px 0 2px; padding:3px 9px; border:1px solid var(--line); border-radius:999px;
  font:700 12px var(--font); color:var(--violet); text-decoration:none; background:var(--bg2);
  max-width:100%; }
.mrev-product-link:hover{ border-color:var(--violet); }
.mrev-product-link svg{ flex:none; }
/* состояния секции */
.mrev-load{ padding:16px 4px; font:500 13px var(--font); color:var(--ink2); }
.mrev-empty{ display:flex; flex-direction:column; gap:4px; padding:18px 16px; text-align:center;
  border:1px dashed var(--line2,var(--line)); border-radius:16px; background:var(--bg2); }
.mrev-empty-t{ margin:0; font:800 14px var(--font-display,var(--font)); color:var(--ink); }
.mrev-empty-s{ margin:0; font:500 12.5px/1.45 var(--font); color:var(--ink2); }
.mrev-error{ padding:14px 16px; border:1px solid var(--line); border-radius:14px; background:var(--card);
  font:600 13px var(--font); color:var(--ink2); }
.mrev-more{ min-height:40px; align-self:center; margin-top:4px; }
.mrev-open{ min-height:44px; }
.mrev-form-slot[hidden]{ display:none; }

@media (prefers-reduced-motion:reduce){
  .pdp-rev-star, .pdp-rev-star:hover{ transition:none; transform:none; }
}

/* ── §15: активные теги-фильтры над сеткой маркетплейса (removable-чипы) ── */
.pp-mk-activetags{ display:flex; flex-wrap:wrap; gap:8px; margin:2px 0 4px; }
.pp-mk-tagchip{ display:inline-flex; align-items:center; gap:6px; min-height:34px;
  padding:5px 10px 5px 12px; border-radius:999px; cursor:pointer;
  background:rgba(124,92,255,.10); border:1px solid rgba(124,92,255,.30);
  font:700 12.5px var(--font); color:var(--violet);
  transition:background .15s ease, border-color .15s ease; }
.pp-mk-tagchip:hover{ background:rgba(124,92,255,.16); border-color:var(--violet); }
.pp-mk-tagchip:focus-visible{ outline:none; box-shadow:0 0 0 3px rgba(124,92,255,.4); }
.pp-mk-tagchip-x{ font-size:11px; line-height:1; opacity:.75; }

/* Шит QR — наследует .bs-cap-sheet, добавляет рамку кода и строку URL/действий. */
.bs-qr-frame{
  align-self:center; padding:14px; background:#fff; border:1px solid var(--line2);
  border-radius:16px; line-height:0;
}
.bs-qr-frame svg{ width:min(260px,60vw); height:auto; display:block; }
.bs-qr-url{
  text-align:center; word-break:break-all; font:600 12px var(--font-mono, ui-monospace, monospace);
  color:var(--ink2);
}
.bs-qr-acts{ display:flex; flex-wrap:wrap; gap:10px; }
.bs-qr-acts .pp-btn{ flex:1 1 180px; min-height:44px; }

/* Шит «товар создан» (catalog-edit): ряд действий под hero-чипом артикула. */
.bs-created-acts{ display:flex; flex-wrap:wrap; gap:10px; }
.bs-created-acts .pp-btn{ flex:1 1 180px; min-height:44px; }

/* .pp-product-artmatch УДАЛЁН: бейдж совпадения по артикулу переехал ПЕРВОЙ пилюлей в общий
   ряд .pp-product-badges (он стоял на тех же координатах top/left 8 + z2 и ложился ПОВЕРХ
   стопки бейджей). Стиль ушёл вместе с элементом — мёртвых классов не оставляем. */

/* подсказка/пустые состояния артикула под полем поиска маркетплейса */
.pp-mk-hint{
  display:flex; align-items:center; gap:6px; margin:6px 2px 0;
  font:600 13px var(--font); color:var(--violet);
}
.pp-mk-hint.is-warn{ color:var(--warn); }

/* self-contained тост article.js (clipboard-fallback / подтверждения) */
/* тот же закон, что у .pp-toast: уведомление живёт выше любого оверлея (было 1400 — ниже
   лайтбокса 9500 и медиа-редактора 10050, т.е. невидимо внутри них). */
.bs-toasts{ position:fixed; left:0; right:0; bottom:calc(24px + var(--bs-bottom-reserve,0px)); z-index:var(--z-toast,10060);
  display:flex; flex-direction:column; gap:8px; align-items:center; pointer-events:none; }
.bs-toast{
  padding:10px 16px; border-radius:var(--rad-xl,22px); background:var(--ink); color:#fff;
  max-width:min(420px, calc(100vw - 32px)); text-align:center; text-wrap:balance;
  font:600 13px/1.4 var(--font); box-shadow:var(--shadow); opacity:0; transform:translateY(8px);
  transition:opacity .2s ease-out, transform .2s ease-out;
}
.bs-toast.is-in{ opacity:1; transform:translateY(0); }

/* ═══════════ ♥ ИЗБРАННОЕ: оверлей-кнопка на карточке (верх-право медиа) ═══════════
   Тихий secondary: полупрозрачная плитка, НЕ конкурирует с primary-CTA карточки. 44px
   тап-таргет; залито = коралл (WP-13). */
.pp-fav{
  position:absolute; top:8px; right:8px; z-index:3;
  width:36px; height:36px; display:inline-flex; align-items:center; justify-content:center;
  border:0; border-radius:999px; cursor:pointer; color:var(--ink2);
  background:rgba(255,255,255,.88); backdrop-filter:blur(4px);
  box-shadow:0 2px 8px rgba(20,20,20,.14);
  transition:transform .14s ease-out, color .15s ease-out, background .15s ease-out;
}
/* область тапа 44px без раздувания визуала (Fitts / touch-target) */
.pp-fav::before{ content:""; position:absolute; inset:-4px; }
.pp-fav:hover{ color:var(--coral); background:#fff; }
.pp-fav:active{ transform:scale(.9); }
.pp-fav:focus-visible{ outline:none; box-shadow:0 0 0 3px rgba(124,92,255,.5); }
.pp-fav-ico{ transition:fill .15s ease-out; }
.pp-fav[aria-pressed="true"]{ color:var(--coral); }
.pp-fav[aria-pressed="true"] .pp-fav-ico{ fill:var(--coral); }

/* подзаголовок шапки листинга (маркетплейс/избранное) */
.pp-mk-sub{ margin:2px 0 0; font:500 14px var(--font); color:var(--ink2); }
/* ↗ вторичная кнопка «Поделиться» в футере модалки товара — не тянет вес primary */
.pp-mk-share{ flex:0 0 auto; }

/* ═══════════ ↗ ПОДЕЛИТЬСЯ: шит 3 блоков (наследует .bs-cap-back/.bs-cap-sheet) ═══════════
   Мобайл — bottom-sheet (снизу вверх), десктоп — центр. Блоки разделены линией; у каждого
   свой единственный primary (репост / в сообщество), внешние сети = сетка тихих плиток. */
.bs-share-back{ opacity:0; transition:opacity .2s ease-out; align-items:flex-end; }
.bs-share-back.is-in{ opacity:1; }
.bs-share-sheet{
  width:min(460px,100%); max-height:88vh; overflow:auto; gap:0;
  border-radius:20px 20px 0 0; transform:translateY(16px); transition:transform .2s ease-out;
}
.bs-share-back.is-in .bs-share-sheet{ transform:translateY(0); }
@media (min-width:768px){
  .bs-share-back{ align-items:center; }
  .bs-share-sheet{ border-radius:20px; transform:translateY(8px) scale(.98); }
}
.bs-share-sec{ padding:16px 2px; }
.bs-share-sec + .bs-share-sec{ border-top:1px solid var(--line); }
.bs-share-h{ margin:0 0 10px; font:800 13px var(--font); color:var(--ink2);
  text-transform:uppercase; letter-spacing:.04em; }

/* родной navigator.share — крупная первичная кнопка (мобайл) */
.bs-share-native{
  width:100%; min-height:48px; margin-bottom:12px; display:inline-flex; align-items:center;
  justify-content:center; gap:8px; border:0; border-radius:14px; cursor:pointer;
  background:var(--grad-hero,var(--violet)); color:#fff; font:800 15px var(--font);
  box-shadow:0 10px 24px -10px rgba(124,92,255,.7); transition:transform .12s ease-out, filter .15s;
}
.bs-share-native:hover{ filter:brightness(1.05); }
.bs-share-native:active{ transform:translateY(1px); }

/* сетка внешних целей */
.bs-share-grid{ display:grid; grid-template-columns:repeat(4,1fr); gap:10px 6px; }
@media (max-width:360px){ .bs-share-grid{ grid-template-columns:repeat(3,1fr); } }
.bs-share-tile{
  display:flex; flex-direction:column; align-items:center; gap:6px; padding:6px 2px;
  border:0; background:none; cursor:pointer; border-radius:12px; min-height:44px;
  transition:transform .12s ease-out;
}
.bs-share-tile:hover{ transform:translateY(-2px); }
.bs-share-tile:active{ transform:translateY(0) scale(.96); }
.bs-share-tile:focus-visible{ outline:none; box-shadow:0 0 0 3px rgba(124,92,255,.4); }
.bs-share-mono{
  width:46px; height:46px; display:inline-flex; align-items:center; justify-content:center;
  border-radius:14px; color:#fff; font:800 15px var(--font-display); letter-spacing:-.02em;
}
.bs-share-mono-copy{ background:var(--bg2); color:var(--ink2);
  border:1.5px solid var(--line2); font-size:18px; }
.bs-share-lbl{ font:600 11px var(--font); color:var(--ink2); text-align:center; line-height:1.2; }

/* блоки B/C — общие поля/действия */
.bs-share-cap{ margin-bottom:10px; }
.bs-share-do{ width:100%; min-height:44px; }
.bs-share-select{
  width:100%; box-sizing:border-box; min-height:44px; margin-bottom:10px; padding:0 12px;
  border:1.5px solid var(--line2); border-radius:12px; background:#fff;
  font:600 14px var(--font); color:var(--ink); cursor:pointer;
}
.bs-share-select:focus{ outline:none; border-color:var(--violet); box-shadow:0 0 0 3px rgba(124,92,255,.15); }
.bs-share-gate, .bs-share-done{
  display:inline-block; font:700 14px var(--font); color:var(--violet); text-decoration:none;
}
.bs-share-gate:hover, .bs-share-done:hover{ text-decoration:underline; }
.bs-share-empty{ margin:0; font:500 13px var(--font); color:var(--ink2); }
.bs-share-empty a{ color:var(--violet); font-weight:700; }
.bs-share-skel{ height:44px; border-radius:12px; background:var(--bg2);
  animation:pp-skel 1.2s ease-in-out infinite; }

/* ============ РЕДАКТОР ТОВАРА: загрузка/тумблер/тип (P2) ============ */
.pp-upload{ border:1.5px dashed var(--line2); border-radius:14px; padding:18px 14px; text-align:center;
  cursor:pointer; transition:all .15s; background:var(--bg2); }
.pp-upload:hover, .pp-upload.is-drag{ border-color:var(--violet); background:rgba(124,92,255,.05); }
.pp-upload:focus-visible{ outline:none; box-shadow:0 0 0 3px rgba(124,92,255,.35); }
.pp-upload-idle{ display:flex; flex-direction:column; gap:4px; font:700 14px var(--font-display); color:var(--ink); }
.pp-upload-idle span{ font:500 12px var(--font); color:var(--ink2); }
.pp-upload-busy{ display:flex; align-items:center; justify-content:center; gap:10px; color:var(--ink2); font:600 13px var(--font); }
.pp-upload-warn{ color:var(--coral); font:600 12px var(--font); margin-top:6px; }
/* ⚠️ Здесь ЖИЛО ВТОРОЕ определение `.pp-switch` (простой чекбокс 18×18 для лейблов формы
   товара). Оно КОЛЛИЗИРОВАЛО с компонентом-тумблером `.pp-switch`/`.pp-switch-track` выше
   (~стр.3010): позднее правило перебивало только width/height/accent-color, а `opacity:0`+
   `position:absolute` от компонента оставались → у формы товара индикатор состояния зависел
   от того, какой из двух блоков победит, и «Бесплатно» читалось как непонятная галка.
   Один класс = один компонент: строка-тумблер редактора товара теперь `.bs-toggle`
   (catalog-edit.js) и переиспользует атом `.pp-switch.pp-switch--sm` + `.pp-switch-track`. */
.pp-typeseg{ flex-wrap:wrap; }
.pp-typeseg button{ font-size:12px; }

/* Владелец группы на SSR-витрине /g/{slug} + счётчик в заголовке ростера участников */
.pp-owner-line{ margin:6px 0 2px; font:600 13px var(--font); color:var(--ink2); }
.pp-owner-line a{ color:var(--violet); text-decoration:none; }
.pp-owner-line a:hover{ text-decoration:underline; }
.pp-muted{ color:var(--ink2); font-weight:600; }

/* Owner-line как явный CTA (SSR группы): ссылка на профиль владельца читается как действие */
.pp-owner-cta{ display:inline-flex; align-items:center; gap:6px; }
.pp-owner-hint{ color:var(--ink2); font-weight:500; font-size:12px; }

/* ============================================================
   ХАБ «Мой магазин» /store.html — кокпит-шапка + sticky-рейка вкладок.
   Свои классы (НЕ .pp-seg — у того 3 конфликтующих определения и общий
   профиль/шоп-сегмент): чистая иерархия, воздух, тач-таргеты 44px.
   ============================================================ */
.store-cockpit{ display:flex; flex-wrap:wrap; align-items:center; gap:14px; margin:22px 0 6px; }
.store-cockpit-id{ display:flex; align-items:center; gap:12px; min-width:0; flex:1 1 auto; }
.store-cockpit-ava{ width:48px; height:48px; border-radius:var(--pill); flex:none; overflow:hidden;
  display:grid; place-items:center; background:var(--grad-2); color:#fff;
  font:800 20px var(--font-display); box-shadow:0 6px 16px -8px rgba(124,92,255,.6); }
.store-cockpit-ava img{ width:100%; height:100%; object-fit:cover; display:block; }
.store-cockpit-idtext{ min-width:0; }
.store-cockpit-name{ font:800 22px var(--font-display); letter-spacing:-.02em; color:var(--ink); line-height:1.12; }
.store-cockpit-handle{ font:600 13px var(--font); color:var(--ink2); text-decoration:none; }
.store-cockpit-handle:hover{ color:var(--violet); }
.store-cockpit-actions{ display:flex; align-items:center; gap:10px; flex:0 0 auto; }
.store-cockpit-actions .pp-chip{ min-height:38px; display:inline-flex; align-items:center;
  padding:6px 14px; text-decoration:none; transition:background .15s, border-color .15s, color .15s; }
.store-cockpit-actions .pp-chip:hover{ border-color:var(--violet); color:var(--violet); }
/* две публичные поверхности мастера — пара кнопок в одном пилл-контейнере (личная ↔ магазин) */
.store-cockpit-surfaces{ display:inline-flex; gap:4px; padding:3px; border:1px solid var(--line);
  border-radius:var(--pill); background:var(--bg2); }
.store-cockpit-surf{ display:inline-flex; align-items:center; gap:6px; min-height:38px; padding:0 12px;
  border-radius:var(--pill); text-decoration:none; font:700 13px var(--font); color:var(--ink2);
  transition:background .15s, color .15s, box-shadow .15s; }
.store-cockpit-surf:hover{ background:var(--card); color:var(--ink); box-shadow:var(--shadow); }
@media(max-width:600px){ .store-cockpit-surf{ min-height:44px; } .store-cockpit-surfaces{ width:100%; justify-content:center; } }
/* Иконки кокпита — бренд line-SVG (не emoji), currentColor; компактный размер под пилюли шапки. */
.store-cockpit-ico{ width:15px; height:15px; flex:none; display:block; }
/* Балансовый чип «Токены» — компактный, кликабелен (data-goto=tokens → вкладка tokens). Тот же
   пилл-язык, что и .pp-chip/.store-cockpit-surf; монеты-иконка violet, число tabular-nums. */
.store-cockpit-balance{ display:inline-flex; align-items:center; gap:6px; min-height:38px; padding:0 12px 0 10px;
  border:1px solid var(--line); border-radius:var(--pill); background:var(--bg2); text-decoration:none;
  color:var(--ink); transition:background .15s, border-color .15s, box-shadow .15s; }
.store-cockpit-balance:hover{ border-color:var(--violet); box-shadow:var(--shadow); }
.store-cockpit-balance .store-cockpit-ico{ width:16px; height:16px; color:var(--violet-600); }
.store-cockpit-bal-num{ font:800 15px var(--font); font-variant-numeric:tabular-nums; letter-spacing:-.01em; line-height:1; }
.store-cockpit-bal-lbl{ font:600 12px var(--font); color:var(--ink2); }
@media(max-width:600px){ .store-cockpit-balance{ min-height:44px; } }

.store-rail{ position:sticky; top:56px; z-index:20; display:flex; gap:4px;
  background:var(--bg2); border:1px solid var(--line); border-radius:var(--pill);
  padding:5px; margin:12px 0 20px; overflow-x:auto; -webkit-overflow-scrolling:touch;
  scrollbar-width:none; }
.store-rail::-webkit-scrollbar{ display:none; }
.store-rail-btn{ appearance:none; border:0; cursor:pointer; white-space:nowrap; flex:0 0 auto;
  font:700 14px var(--font); color:var(--ink2); background:transparent;
  padding:0 18px; min-height:44px; border-radius:var(--pill); line-height:1;
  display:inline-flex; align-items:center; transition:color .15s, background .15s, box-shadow .15s; }
.store-rail-btn:hover{ color:var(--ink); background:rgba(20,20,20,.045); }
.store-rail-btn.is-active{ color:var(--ink); background:var(--card); box-shadow:var(--shadow); font-weight:800; }
.store-rail-btn:focus-visible{ outline:2px solid var(--violet); outline-offset:2px; }
@media(max-width:600px){
  .store-cockpit-name{ font-size:20px; }
  .store-cockpit-actions{ width:100%; }
  .store-rail-btn{ padding:0 15px; }
}

/* ── Левый сайдбар-меню разделов магазина (заменил верхнюю .store-rail) ──────
   Тело = грид [сайдбар 232px | контент]. Сайдбар — тихий вертикальный список,
   сгруппирован (МАГАЗИН/ПРОДАЖИ/РОСТ); активное = левый акцент-бордер + tonal
   violet-50 (не «серым по размеру»). ≤900px схлопывается в горизонтальный
   sticky-пилл (мышечная память старой рейки). .store-rail оставлена как есть. */
.store-body{ max-width:var(--page-max); margin:0 auto; padding:0 16px; display:grid; gap:var(--sp-6);
  grid-template-columns:232px minmax(0,1fr); align-items:start; }
.store-body-solo{ grid-template-columns:1fr; }        /* не-продавец (fork) — без сайдбара */
/* ── Вкладка «Профиль и портфолио»: редактор личности встроен в хаб через iframe ──────────────
   /profile-edit.html?embed=1 прячет свою nav-шапку и САМ центрирует контент своим .pp-col
   (max-width 1040, паддинг 16) + шлёт высоту → рамка растёт под контент, БЕЗ внутреннего скролла
   (ведёт себя как нативная вкладка). Обёртка — обычный полноширинный блок колонки-вкладки: ширину
   и отступы держит сам редактор, тут не двоим (иначе двойное сужение/двойной паддинг). */
.store-embed-wrap{ width:100%; min-width:0; }
.store-embed-frame{ display:block; width:100%; border:0; background:transparent;
  min-height:70vh; }   /* min-height — фолбэк до прихода height-сообщения (без него iframe схлопнется в 0) */
/* Левый сайдбар кабинета — ОДИН брендовый компонент-панель (карточка), а не набор кнопок в
   пустоте. Свёрнутая рейка / раскрытая панель / закреплённая — три состояния одной карты:
   один surface (--card), одна рамка (--line), один радиус (--rad-xl, симметричный со всех сторон),
   одна бренд-тень. Иконки — inline-SVG (currentColor), не emoji. */
.store-side{ position:sticky; top:72px; display:flex; flex-direction:column; gap:2px;
  padding:var(--sp-3); background:var(--card); border:1px solid var(--line);
  border-radius:var(--rad-xl); box-shadow:var(--shadow); }
/* Лист разделов внутри карты-сайдбара — вертикальная колонка (десктоп). На мобиле медиазапрос
   ниже превращает его в выпадающую карту-навигатор поверх контента. */
.store-side-list{ display:flex; flex-direction:column; gap:2px; min-width:0; }
/* Мобильный триггер-навигатор скрыт на десктопе (там виден полный вертикальный лист). */
.store-side-mtoggle{ display:none; }
.store-side-label{ font:800 11px var(--font); letter-spacing:.06em; text-transform:uppercase;
  color:var(--gray-500); padding:0 12px; margin-top:var(--sp-3); margin-bottom:2px; }
.store-side-btn{ appearance:none; border:0; cursor:pointer; text-align:left; width:100%;
  display:flex; align-items:center; gap:12px; min-height:44px; padding:0 12px; border-radius:var(--rad-md);
  background:transparent; color:var(--ink2); font:700 14px var(--font);
  transition:background .16s, color .16s, box-shadow .16s; }
.store-side-ico{ display:flex; align-items:center; justify-content:center; width:22px; height:22px;
  flex:none; color:var(--gray-400); transition:color .16s; }
.store-side-glyph{ width:20px; height:20px; display:block; }
/* Лейбл занимает остаток строки и усекается многоточием (длинные — «Заказы на бирже» — не переносятся
   в 2 строки, не ломают плотную высоту; полный текст в title). Бейдж-счётчик пинится вправо. */
.store-side-txt{ flex:1 1 auto; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.store-side-count{ flex:none; margin-left:6px; font:800 11px var(--font); font-variant-numeric:tabular-nums;
  line-height:1; padding:3px 7px; border-radius:var(--pill); background:var(--gray-100); color:var(--gray-600); }
.store-side-btn.is-active .store-side-count{ background:var(--violet-100); color:var(--violet-700); }
.store-side-btn:hover .store-side-count{ background:var(--gray-200); }
.store-side-btn:hover{ background:var(--gray-100); color:var(--ink); }
.store-side-btn:hover .store-side-ico{ color:var(--violet-500); }
.store-side-btn.is-active{ background:var(--violet-50); color:var(--violet-700);
  box-shadow:inset 3px 0 0 var(--violet-500); font-weight:800; }
.store-side-btn.is-active .store-side-ico{ color:var(--violet-600); }
.store-side-btn:focus-visible{ outline:2px solid var(--violet); outline-offset:2px; }
.store-side-foot{ margin-top:var(--sp-3); border-top:1px solid var(--line); padding-top:var(--sp-3);
  display:flex; flex-direction:column; gap:2px; }
.store-side-foot .store-side-btn{ font-weight:600; color:var(--gray-600); }
/* ── МОБИЛЬНЫЙ навигатор разделов (≤900px) ─────────────────────────────────────
   Было: #store-side превращался в горизонтальную простыню пилюль-скролла (22 пункта, группы
   скрыты) → «конец страницы», без структуры. Стало: компактный sticky-ТРИГГЕР в первом экране
   (иконка+имя активного раздела+шеврон) → тап раскрывает СГРУППИРОВАННЫЙ лист выпадающей картой
   поверх контента (грид не двигается), группы читаются, переход в 1 тап. .m-collapsed ставит
   хук renderShell (по умолчанию свёрнуто); без хука лист виден развёрнутым (fail-open). */
@media(max-width:900px){
  /* minmax(0,1fr), а НЕ 1fr: у грид-элемента min-width:auto = ширина его контента, поэтому колонка
     раздувалась под самый длинный ряд суб-табов (на 390px панель становилась 444px+) и хвост
     control-bar ОБРЕЗАЛСЯ, а не скроллился — до последних вкладок было не добраться пальцем.
     С minmax(0,…) колонка сжимается до вьюпорта и горизонтальный скролл достаётся самому
     .store-subtab-bar (там он и задуман: overflow-x:auto + scrollIntoView активного). */
  .store-body{ grid-template-columns:minmax(0,1fr); gap:0; }
  .store-side{ position:sticky; top:56px; z-index:30; display:block; padding:0; margin:10px 0 14px;
    background:transparent; border:0; box-shadow:none; min-height:0; }
  .store-side-collapse{ display:none; }        /* десктоп-пин на мобиле не нужен */
  /* Триггер-бар: карта во всю ширину; активный раздел виден без раскрытия */
  .store-side-mtoggle{ display:flex; align-items:center; gap:10px; width:100%; min-height:48px;
    padding:0 14px; border:1px solid var(--line); border-radius:var(--rad-lg); background:var(--card);
    box-shadow:var(--shadow); color:var(--ink); cursor:pointer; -webkit-appearance:none; appearance:none;
    transition:border-color .15s, box-shadow .15s; }
  .store-side-mtoggle:focus-visible{ outline:2px solid var(--violet); outline-offset:2px; }
  .store-side-mtoggle .store-side-ico[data-side-current-ico]{ width:22px; height:22px; color:var(--violet-600); }
  .store-side-mtoggle-txt{ display:flex; flex-direction:column; align-items:flex-start; gap:1px; flex:1 1 auto; min-width:0; }
  .store-side-mtoggle-kicker{ font:800 10px var(--font); letter-spacing:.07em; text-transform:uppercase;
    color:var(--gray-500); line-height:1; }
  .store-side-mtoggle-cur{ font:800 15px var(--font); color:var(--ink); line-height:1.15;
    max-width:100%; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .store-side-mchev{ width:18px; height:18px; color:var(--gray-500); transition:transform .18s ease; }
  .store-side:not(.m-collapsed) .store-side-mchev{ transform:rotate(180deg); }   /* раскрыто → шеврон вверх */
  /* Лист = выпадающая карта поверх контента (абсолют внутри sticky-триггера); внутренний скролл */
  .store-side-list{ position:absolute; top:calc(100% + 6px); left:0; right:0; z-index:60;
    display:flex; flex-direction:column; gap:2px; padding:var(--sp-3);
    background:var(--card); border:1px solid var(--line); border-radius:var(--rad-xl);
    box-shadow:var(--shadow-lg); max-height:72vh; overflow:auto;
    -webkit-overflow-scrolling:touch; scrollbar-width:none; }
  .store-side-list::-webkit-scrollbar{ display:none; }
  .store-side.m-collapsed .store-side-list{ display:none; }        /* свёрнуто по умолчанию (хук) */
  /* Заголовки групп ВИДНЫ внутри листа (структура читается) */
  .store-side-label{ display:block; margin-top:var(--sp-3); }
  .store-side-list > .store-side-label:first-child{ margin-top:0; }
  /* Пункты — строки как на десктопе (иконка+лейбл), 44px тач; НЕ пилюли-простыня */
  .store-side-list .store-side-btn{ width:100%; justify-content:flex-start; min-height:44px;
    padding:0 12px; border-radius:var(--rad-md); white-space:nowrap; flex:none; }
  .store-side-list .store-side-btn.is-active{ background:var(--violet-50); color:var(--violet-700);
    box-shadow:inset 3px 0 0 var(--violet-500); }
  .store-side-foot{ margin-top:var(--sp-2); border-top:1px solid var(--line); padding-top:var(--sp-2);
    flex-direction:column; gap:2px; }
}
/* Кнопка-ПИН — каноничная бренд-кнопка (иконка + подпись «Закрепить/Открепить»), не сырой emoji.
   Живёт первой строкой панели. Свёрнуто → ghost с пунктиром (приглашает закрепить); закреплено →
   залитая violet .is-pinned (состояние читается однозначно). Десктоп-only. */
.store-side-collapse{ appearance:none; cursor:pointer; width:100%;
  display:flex; align-items:center; gap:12px; min-height:38px; padding:0 12px; flex:none;
  border-radius:var(--rad-md); background:transparent; border:1px dashed var(--gray-300);
  color:var(--gray-600); font:700 13px var(--font); margin-bottom:2px;
  transition:background .16s, color .16s, border-color .16s, box-shadow .16s, transform .12s; }
.store-side-collapse .store-side-ico{ color:var(--violet-500); }
.store-side-collapse:hover{ background:var(--violet-50); border-color:var(--violet-200);
  color:var(--violet-700); }
.store-side-collapse:active{ transform:scale(.98); }
.store-side-collapse:focus-visible{ outline:2px solid var(--violet); outline-offset:2px; }
.store-side-collapse.is-pinned{ background:var(--violet-500); border-style:solid; border-color:var(--violet-500);
  color:#fff; box-shadow:0 4px 14px rgba(124,92,255,.28); }
.store-side-collapse.is-pinned .store-side-ico{ color:#fff; }
@media(min-width:901px){
  .store-body{ transition:grid-template-columns .2s cubic-bezier(.4,0,.2,1); }
  /* Рейка/панель — высокая полоса слева ВО ВЕСЬ РОСТ (не короткий блок сверху): карта тянется
     минимум на всю высоту вьюпорта под кокпитом, sticky сохраняется (top:72). */
  .store-side{ min-height:calc(100vh - 88px); min-height:calc(100dvh - 88px); }
  /* D0-плотность: объединённый хаб держит ~18 пунктов в 6 группах → на десктопе строка 40px
     (эталон кабинета /@handle 38px, тач-минимум 44px остаётся на мобиле-пилюлях ниже). */
  .store-side-btn{ min-height:40px; }
  .store-side-label{ margin-top:var(--sp-2); }
  /* СВЁРНУТО (не закреплено): узкая рейка-карта, только иконки. Наведение раскрывает overlay-поверх.
     Радиус --rad-xl симметричен со ВСЕХ сторон (не «скруглён только правый край»). */
  .store-body.side-collapsed{ grid-template-columns:74px minmax(0,1fr); max-width:var(--page-max); }
  .side-collapsed .store-side{ width:74px; padding:var(--sp-3) var(--sp-2);
    transition:width .2s cubic-bezier(.4,0,.2,1), box-shadow .2s, padding .2s; }
  /* СВЁРНУТО — активный раздел = залитая violet-пилюля с белой иконкой (иначе в узкой рейке
     светлый wash терялся). Работает и в раскрытии-по-наведению: белый текст на violet читаем. */
  .side-collapsed .store-side-btn.is-active{ background:var(--violet-500); color:#fff; box-shadow:none; }
  .side-collapsed .store-side-btn.is-active .store-side-ico{ color:#fff; }
  .side-collapsed .store-side-txt{ display:none; }
  .side-collapsed .store-side-count{ display:none; }
  .side-collapsed .store-side-label{ display:none; }
  .side-collapsed .store-side-btn{ justify-content:center; padding:0; gap:0; }
  .side-collapsed .store-side-collapse{ justify-content:center; padding:0; gap:0; border-color:transparent; }
  .side-collapsed .store-side-collapse:not(.is-pinned){ background:transparent; }
  .side-collapsed .store-side-foot{ align-items:stretch; }
  /* НАВЕДЕНИЕ на свёрнутую рейку → раскрытие ПОВЕРХ контента (грид не сдвигается). Бренд-тень
     violet (--shadow-lg), тот же симметричный радиус — намеренная, «дорогая» карта, а не всплывшее
     инородное окно. */
  .side-collapsed .store-side:hover{ width:236px; z-index:60;
    box-shadow:var(--shadow-lg); padding:var(--sp-3); }
  .side-collapsed .store-side:hover .store-side-txt{ display:inline; }
  .side-collapsed .store-side:hover .store-side-count{ display:inline-block; }
  .side-collapsed .store-side:hover .store-side-label{ display:block; }
  .side-collapsed .store-side:hover .store-side-btn{ justify-content:flex-start; padding:0 12px; gap:12px; }
  .side-collapsed .store-side:hover .store-side-collapse{ justify-content:flex-start; padding:0 12px; gap:12px;
    border-color:var(--gray-300); }
  .side-collapsed .store-side:hover .store-side-collapse.is-pinned{ border-color:var(--violet-500); }
}
@media(max-width:900px){ .store-side-collapse{ display:none; } }
@media(prefers-reduced-motion:reduce){
  .store-body{ transition:none; }
  .side-collapsed .store-side{ transition:none; }
  .store-side-collapse{ transition:background .15s, color .15s, border-color .15s, box-shadow .15s; }
  .store-side-collapse:active{ transform:none; }
}

/* ── 2-уровневая навигация, НИЖНИЙ уровень: H1 раздела + control-bar СУБ-ТАБОВ ──────
   Верхний уровень — сайдбар (.store-side, 8 разделов). Нижний — этот горизонтальный
   underline-ряд суб-табов ПОД H1 активного раздела (role=tablist). Один видимый суб-таб
   (напр. «Личная страница») → бара нет, только H1. Всё на токенах (var(--*)), 0 хардкода. */
.store-section-head{ margin:var(--sp-5) 0 var(--sp-4); }
.store-section-h1{ margin:0; font:800 var(--fs-lg)/1.15 var(--font); letter-spacing:-.01em; color:var(--ink); }
.store-section-head:has(.store-subtab-bar) .store-section-h1{ margin-bottom:var(--sp-1); }

.store-subtab-bar{ display:flex; align-items:stretch; gap:var(--sp-5);
  box-shadow:inset 0 -1px 0 var(--line);           /* full-width baseline (не клипается overflow'ом) */
  overflow-x:auto; overflow-y:hidden; -webkit-overflow-scrolling:touch; scrollbar-width:none; }
.store-subtab-bar::-webkit-scrollbar{ display:none; }
.store-subtab{ appearance:none; border:0; background:none; cursor:pointer; flex:0 0 auto;
  display:inline-flex; align-items:center; gap:7px; white-space:nowrap;
  min-height:44px; padding:8px 2px;                 /* тач-таргет 44px паддингом (§14.D), визуально плотно */
  font:600 14px var(--font); color:var(--ink2); letter-spacing:-.005em;
  border-bottom:2px solid transparent;              /* underline-индикатор садится на baseline бара */
  transition:color .15s ease, border-color .15s ease; }
.store-subtab:hover{ color:var(--ink); }
.store-subtab.is-active{ color:var(--violet-700); font-weight:700; border-bottom-color:var(--violet-500); }
.store-subtab:focus-visible{ outline:2px solid var(--violet-500); outline-offset:3px; border-radius:var(--rad-sm); }
/* счётчик суб-таба — тот же пилюля-язык, что .store-side-count (11px tabular-nums) */
.store-subtab-count{ flex:none; font:800 11px var(--font); font-variant-numeric:tabular-nums;
  background:var(--gray-100); color:var(--gray-600); border-radius:var(--pill); padding:1px 7px; }
.store-subtab.is-active .store-subtab-count{ background:var(--violet-100); color:var(--violet-700); }
.store-subtab:hover .store-subtab-count{ background:var(--gray-200); }
/* СГРУППИРОВАННЫЙ control-bar (section.groups; сейчас — раздел «Настройки»): 8 плоских вкладок
   читались стеной без приоритета, поэтому суб-табы собраны в 2–3 смысловых кластера
   (Личное / Продавец / Сервис) — Миллер 7±2 + Гештальт-близость. Кластер = капс-подпись 10.5px
   + свои табы; между кластерами вертикальный хайрлайн. Ряд остаётся ОДНОЙ строкой (D0: без
   второго этажа контролов), переполнение уезжает в тот же горизонт-скролл. */
.store-subtab-bar.is-grouped{ gap:0; }
.store-subtab-group{ display:flex; align-items:stretch; gap:var(--sp-4); flex:0 0 auto; }
.store-subtab-bar.is-grouped .store-subtab-group + .store-subtab-group{
  margin-left:var(--sp-4); padding-left:var(--sp-4); border-left:1px solid var(--line2); }
.store-subtab-glbl{ display:inline-flex; align-items:center; flex:0 0 auto; white-space:nowrap;
  font:700 10.5px/1 var(--font); letter-spacing:.08em; text-transform:uppercase; color:var(--ink2); opacity:.7; }
/* Десктоп: control-bar суб-табов sticky (как сайдбар) — переключение без прокрутки вверх;
   H1 НЕ sticky (контекст уезжает — §15.D). ≤900px sticky снимаем (см. ниже). */
@media(min-width:901px){
  .store-subtab-bar{ position:sticky; top:56px; z-index:15; background:var(--bg); }
}
/* Мобайл ≤900px: суб-табы = горизонтальный скролл-ряд (overflow-x уже auto), НЕ sticky;
   активный авто-в-видимость (JS scrollIntoView). H1 компактнее (D0). Капс-подписи кластеров
   остаются: в скролл-ряду они работают как ориентиры «где я в настройках». */
@media(max-width:900px){
  .store-section-head{ margin:var(--sp-4) 0 var(--sp-3); }
  .store-section-h1{ font-size:var(--fs-md); }
  .store-subtab-bar{ gap:var(--sp-4); }
  .store-subtab-group{ gap:var(--sp-3); }
  .store-subtab-bar.is-grouped .store-subtab-group + .store-subtab-group{
    margin-left:var(--sp-4); padding-left:var(--sp-4); }
}
@media(prefers-reduced-motion:reduce){
  .store-subtab{ transition:none; }
}

/* ============================================================
   Заказы с биржи (store-orders-exchange.js) — свёрнутые ЗАВЕРШЁННЫЕ
   сделки под спойлером (progressive disclosure): вместо стены из
   десятков одинаковых full-width карточек «Завершён» — одна строка
   «Завершённые (N)», разворачивается в компактный плотный список.
   ============================================================ */
.pp-done{ background:var(--card); border:1px solid var(--line); border-radius:var(--rad-lg,16px);
  box-shadow:var(--shadow); overflow:hidden; margin-bottom:16px; }
.pp-done>summary{ list-style:none; cursor:pointer; display:flex; align-items:center; gap:10px;
  padding:12px 16px; min-height:52px; font:700 14px var(--font); color:var(--ink); user-select:none; }
.pp-done>summary::-webkit-details-marker{ display:none; }
.pp-done>summary:hover{ background:var(--bg2); }
.pp-done>summary:focus-visible{ outline:2px solid var(--violet); outline-offset:-2px; }
.pp-done-ico{ width:22px; height:22px; border-radius:var(--pill); flex:none; font-size:12px;
  background:rgba(31,191,117,.14); color:var(--ok); display:inline-flex; align-items:center; justify-content:center; }
.pp-done-lbl{ flex:1 1 auto; min-width:0; }
.pp-done-n{ font:700 12px var(--font); color:var(--ink2); background:var(--bg2); border-radius:var(--pill);
  padding:2px 9px; font-variant-numeric:tabular-nums; flex:none; }
.pp-done-chev{ color:var(--ink2); transition:transform .18s; flex:none; font-size:11px; }
.pp-done[open] .pp-done-chev{ transform:rotate(180deg); }
.pp-done-list{ border-top:1px solid var(--line); }
.pp-xrow{ display:flex; align-items:center; gap:12px; padding:0 16px; min-height:46px;
  text-decoration:none; color:inherit; border-top:1px solid var(--line); }
.pp-done-list .pp-xrow:first-child{ border-top:0; }
.pp-xrow:hover{ background:var(--bg2); }
.pp-xrow-title{ flex:1 1 auto; min-width:0; font:600 13px var(--font); color:var(--ink);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.pp-xrow-meta{ font:500 12px var(--font); color:var(--ink2); white-space:nowrap; flex:none;
  font-variant-numeric:tabular-nums; }
.pp-xrow-ok{ color:var(--ok); font-size:13px; flex:none; }
.pp-xnote{ font:500 13px var(--font); color:var(--ink2); padding:2px 2px 12px; }

/* ── Глобальный fail-safe prefers-reduced-motion (a11y). Гасит любую анимацию/переход/авто-скролл
   для пользователей с включённым «уменьшить движение» — страхует эффекты (галерея + прод),
   у которых нет поштучного гейта. Точечные reduced-motion выше остаются, этот — общий низ. ── */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
}

/* ============================================================================
   Конструктор «Сайт» мастера (.sb-*) — БРЕНД-ДОВОДКА (ux-pro gate, wave-2).
   shop-builder.js инъектит МИНИМАЛЬНЫЙ каркас (layout) в <style id=sb-builder-css>.
   Здесь: (1) чиним резолв токенов — каркас читает var(--surface)/var(--muted),
   которых НЕТ в tokens.css (там --card/--ink2) → падают в хардкод-hex; алиасим их
   ТОЛЬКО на поддереве .sb-wrap (без глобальной коллизии с community.css:--surface);
   (2) добавляем отсутствующие СОСТОЯНИЯ (hover/focus-visible/active) и иерархию
   контролов. Сам конструктор — БРЕНД (tokens), тема витрины живёт в iframe-превью.
   Правила ниже переопределяют каркас через specificity .sb-wrap … (0,2,0 > 0,1,0).
   ============================================================================ */
.sb-wrap {
  --surface: var(--card, #fff);   /* алиас под каркас: поверхность панелей/карточек */
  --muted: var(--ink2, #5B5B66);  /* алиас под каркас: приглушённый текст */
}

/* Табы панели: segmented — тихий tertiary, активный = «поднятая» вкладка на surface с
   акцент-подчёркиванием. Добавляем hover + видимый фокус. */
.sb-wrap .sb-ptab { transition: background .15s, color .15s, box-shadow .15s; }
.sb-wrap .sb-ptab:hover:not(.is-on) { background: var(--card, #fff); color: var(--ink, #141414); }
.sb-wrap .sb-ptab:focus-visible { outline: 2px solid var(--violet, #7C5CFF); outline-offset: -2px; }

/* Чипы «Добавить блок» / «Собрать по шаблону» — pill-кнопки с иконкой: аффорд + состояния. */
.sb-wrap .sb-chip { transition: transform .12s ease, box-shadow .15s ease, border-color .15s ease, background .15s ease; }
.sb-wrap .sb-chip:hover { transform: translateY(-1px); border-color: var(--violet-300, #AB9BFF); background: var(--violet-50, #F2EFFF); box-shadow: 0 4px 14px rgba(124,92,255,.14); }
.sb-wrap .sb-chip:active { transform: translateY(0); }
.sb-wrap .sb-chip:focus-visible { outline: 2px solid var(--violet, #7C5CFF); outline-offset: 2px; }

/* Свотчи пар акцент+фон (Дизайн): аффорд + состояния. */
.sb-wrap .sb-pre { transition: transform .12s ease, box-shadow .15s ease, border-color .15s ease; }
.sb-wrap .sb-pre:hover { transform: translateY(-1px); border-color: var(--violet, #7C5CFF); box-shadow: 0 4px 12px rgba(124,92,255,.16); }
.sb-wrap .sb-pre:focus-visible { outline: 2px solid var(--violet, #7C5CFF); outline-offset: 2px; }

/* Reorder-стрелки строки модуля: тихая иконка-кнопка, hover/фокус на бренд-акцент. */
.sb-wrap .sb-move-btn { transition: background .14s, color .14s, border-color .14s; }
.sb-wrap .sb-move-btn:hover:not(:disabled) { background: var(--violet-50, #F2EFFF); border-color: var(--violet-200, #C9BEFF); color: var(--violet-600, #6B4AEE); }
.sb-wrap .sb-move-btn:focus-visible { outline: 2px solid var(--violet, #7C5CFF); outline-offset: 1px; }

/* Строка-модуль блока: аккуратная карточка. Hover приподнимает границу+тень и красит иконку. */
.sb-wrap .sb-mod { transition: border-color .15s, box-shadow .15s; }
.sb-wrap .sb-mod:hover { border-color: var(--violet-200, #C9BEFF); box-shadow: var(--shadow, 0 8px 30px rgba(20,20,20,.06)); }
.sb-wrap .sb-mod:hover .sb-mod-ico { background: var(--violet-100, #E4DEFF); }
.sb-wrap .sb-mod:hover .sb-mod-edit { color: var(--violet-500, #7C5CFF); }
.sb-wrap .sb-mod-name:focus-visible { outline: 2px solid var(--violet, #7C5CFF); outline-offset: 2px; border-radius: var(--rad-sm, 9px); }

/* Карточка стиля темы (2-кол сетка): hover-подъём + фокус-кольцо (is-on = 2px акцент + чек-бейдж). */
.sb-wrap .sb-sty { transition: transform .14s ease, box-shadow .16s ease; }
.sb-wrap .sb-sty:hover { transform: translateY(-2px); box-shadow: var(--shadow-lg, 0 20px 50px -20px rgba(124,92,255,.35)); }
.sb-wrap .sb-sty:focus-visible { outline: 3px solid var(--violet, #7C5CFF); outline-offset: 2px; }

/* Ссылка «Профиль» в баре холста + hover/фокус на бренд-акцент. */
.sb-wrap .sb-canvas-link { transition: color .15s; }
.sb-wrap .sb-canvas-link:hover { color: var(--ink, #141414); }
.sb-wrap .sb-canvas-link:hover span { text-decoration: underline; }
.sb-wrap .sb-canvas-link:focus-visible { outline: 2px solid var(--violet, #7C5CFF); outline-offset: 2px; border-radius: var(--rad-sm, 9px); }

@media (prefers-reduced-motion: reduce) {
  .sb-wrap .sb-ptab, .sb-wrap .sb-chip, .sb-wrap .sb-pre, .sb-wrap .sb-move-btn,
  .sb-wrap .sb-mod, .sb-wrap .sb-sty, .sb-wrap .sb-canvas-link { transition: none; }
  .sb-wrap .sb-chip:hover, .sb-wrap .sb-pre:hover, .sb-wrap .sb-sty:hover { transform: none; }
}

/* ============================================================================
   bs-inline-edit — inline page-builder оверлей превью конструктора (дизайн ux-pro).
   Editor chrome = бренд-violet, независимо от превьюшной темы витрины. Слой
   pointer-events:none → прод-CTA/скролл проходят насквозь; клики ловят только
   карандаши и безвредные [data-field]-элементы. Живёт только в preview=builder.
   ============================================================================ */
.bs-ie-layer{
  position:fixed; inset:0; z-index:9000;
  pointer-events:none;                 /* клики падают на реальный сайт */
  --ie:var(--violet,#7C5CFF);          /* editor accent */
  --ie-on:#fff;
}
.bs-ie-layer[hidden]{ display:none; }

/* ---- рамка блока (внешняя) ---- */
.bs-ie-blockbox{
  position:fixed; left:0; top:0; width:0; height:0;
  border:2px solid var(--ie);
  border-radius:var(--rad-lg,14px);
  box-shadow:0 0 0 1px color-mix(in srgb, var(--ie) 22%, transparent),
             0 8px 30px -12px color-mix(in srgb, var(--ie) 45%, transparent);
  opacity:0; transition:opacity .12s ease;
}
.bs-ie-layer.on-block .bs-ie-blockbox{ opacity:1; }
/* когда таргетится вложенный элемент (слот/поле) — приглушаем рамку блока,
   ведёт внутренний уровень. Остаётся solid (dashed зарезервирован под слот). */
.bs-ie-layer.on-slot  .bs-ie-blockbox,
.bs-ie-layer.on-field .bs-ie-blockbox{ opacity:.4; }

/* ---- тулбар блока (иконка + имя + действия) ---- */
.bs-ie-bar{
  position:fixed; left:0; top:0;
  display:inline-flex; align-items:center; gap:2px;
  height:30px; padding:0 4px 0 8px;
  background:var(--ie); color:var(--ie-on);
  border-radius:var(--rad-md,10px);
  font:600 12px/1 var(--font,system-ui,sans-serif);
  letter-spacing:.01em; white-space:nowrap;
  box-shadow:0 6px 20px -6px color-mix(in srgb, var(--ie) 55%, transparent);
  pointer-events:auto;                 /* эта часть интерактивна */
  opacity:0; transform:translateY(3px) scale(.96);
  transform-origin:left bottom;
  transition:opacity .14s ease, transform .14s cubic-bezier(.2,.9,.3,1.2);
}
.bs-ie-layer.on-block .bs-ie-bar{ opacity:1; transform:none; }
.bs-ie-bar-ic{ display:inline-flex; width:15px; height:15px; margin-right:5px; opacity:.9; }
.bs-ie-bar-ic svg{ width:15px; height:15px; fill:none; stroke:currentColor;
  stroke-width:2; stroke-linecap:round; stroke-linejoin:round; }
.bs-ie-bar-name{ margin-right:6px; }
.bs-ie-bar-sep{ width:1px; height:16px; margin:0 3px;
  background:color-mix(in srgb, var(--ie-on) 30%, transparent); }
.bs-ie-btn{
  all:unset; box-sizing:border-box;
  display:inline-flex; align-items:center; justify-content:center;
  width:24px; height:24px; border-radius:7px;
  color:var(--ie-on); cursor:pointer;
  transition:background .12s ease;
}
.bs-ie-btn:hover{ background:color-mix(in srgb, var(--ie-on) 18%, transparent); }
.bs-ie-btn:focus-visible{ outline:2px solid var(--ie-on); outline-offset:1px; }
.bs-ie-btn.is-primary{                 /* карандаш = primary, filled-чип */
  background:color-mix(in srgb, var(--ie-on) 16%, transparent);
  width:auto; padding:0 9px 0 7px; gap:5px; font:600 12px/1 var(--font,system-ui);
}
.bs-ie-btn svg{ width:15px; height:15px; fill:none; stroke:currentColor;
  stroke-width:2; stroke-linecap:round; stroke-linejoin:round; }

/* ---- рамка поля (внутренняя) ---- */
.bs-ie-fieldbox{
  position:fixed; left:0; top:0; width:0; height:0;
  border:1.5px solid var(--ie);
  border-radius:var(--rad-md,9px);
  background:color-mix(in srgb, var(--ie) 7%, transparent);
  opacity:0; transition:opacity .1s ease;
}
.bs-ie-layer.on-field .bs-ie-fieldbox{ opacity:1; }

/* ---- мини-карандаш поля (правый-верхний угол элемента) ---- */
.bs-ie-pen{
  position:fixed; left:0; top:0;
  display:inline-flex; align-items:center; gap:4px;
  height:24px; padding:0 8px 0 6px;
  background:var(--ie); color:var(--ie-on);
  border-radius:var(--pill,999px);
  font:600 11px/1 var(--font,system-ui,sans-serif);
  box-shadow:0 4px 14px -4px color-mix(in srgb, var(--ie) 55%, transparent);
  pointer-events:auto; cursor:pointer;
  opacity:0; transform:scale(.8); transform-origin:right top;
  transition:opacity .12s ease, transform .16s cubic-bezier(.2,.9,.3,1.3);
}
.bs-ie-layer.on-field .bs-ie-pen{ opacity:1; transform:none; }
.bs-ie-pen svg{ width:13px; height:13px; fill:none; stroke:currentColor;
  stroke-width:2; stroke-linecap:round; stroke-linejoin:round; }

/* ---- СЛОТ: промежуточный уровень (регион контента, swappable) ----
   Читаемость 3 уровней: блок = solid 2px (внешний) · слот = DASHED 1.75px
   (регион/дроп-зона) · поле = solid 1.5px+fill (лист). Плюс разные глифы:
   слот-карандаш несёт «слои» + имя региона, поле-карандаш — перо «Изменить». */
.bs-ie-slotbox{
  position:fixed; left:0; top:0; width:0; height:0;
  border:1.75px dashed var(--ie);
  border-radius:var(--rad-md,11px);
  background:color-mix(in srgb, var(--ie) 5%, transparent);
  opacity:0; transition:opacity .11s ease;
}
.bs-ie-layer.on-slot .bs-ie-slotbox{ opacity:1; }
/* поле активно, но лежит внутри слота → слот как ghost-контур (вложенность видна) */
.bs-ie-layer.field-in-slot .bs-ie-slotbox{ opacity:.4; background:transparent; }

/* слот-карандаш: чип с именем региона (rad-md — «регион», не pill как у поля) */
.bs-ie-slotpen{
  position:fixed; left:0; top:0;
  display:inline-flex; align-items:center; gap:5px;
  height:26px; padding:0 9px 0 7px;
  background:var(--ie); color:var(--ie-on);
  border-radius:var(--rad-md,9px);
  font:600 11px/1 var(--font,system-ui,sans-serif);
  box-shadow:0 5px 16px -5px color-mix(in srgb, var(--ie) 55%, transparent);
  pointer-events:auto; cursor:pointer;
  opacity:0; transform:translateY(2px) scale(.9); transform-origin:right top;
  transition:opacity .12s ease, transform .16s cubic-bezier(.2,.9,.3,1.25);
}
.bs-ie-layer.on-slot .bs-ie-slotpen{ opacity:1; transform:none; }
.bs-ie-slotpen svg{ width:14px; height:14px; fill:none; stroke:currentColor;
  stroke-width:2; stroke-linecap:round; stroke-linejoin:round; opacity:.9; }
.bs-ie-slotpen-label{ letter-spacing:.01em; white-space:nowrap; }

/* редактируемый контент получает мягкий cursor-аффорданс когда слой живой */
.bs-ie-live [data-field]{ cursor:pointer; }

/* ---- тач: без hover → рамка блока + тулбар появляются по тапу (JS .on-block) ---- */
@media (hover:none){
  .bs-ie-bar{ opacity:1; transform:none; }   /* без pop-in на тач-устройствах */
}

/* ---- reduced motion: только opacity, без трансформов ---- */
@media (prefers-reduced-motion:reduce){
  .bs-ie-bar,.bs-ie-pen,.bs-ie-slotpen{ transition:opacity .1s linear; transform:none !important; }
  .bs-ie-blockbox,.bs-ie-slotbox,.bs-ie-fieldbox{ transition:none; }
}

/* --- bs-inline-edit: фикс достижимости карандаша/тулбара (hover-bridge, ux-pro) --- */
/* мостик под тулбаром: переход от тулбара вниз к блоку не пересекает мёртвую зону */
.bs-ie-bar::after{
  content:''; position:absolute; left:-4px; right:-4px; top:100%; height:8px;
}
/* карандаш теперь на углу элемента, а не в зазоре → масштаб-анимация из центра */
.bs-ie-pen{ transform-origin:center; }
/* тач: расширяем тап-таргет карандашей до ~46px без изменения визуального размера */
@media (hover:none){
  .bs-ie-pen::before,
  .bs-ie-slotpen::before{ content:''; position:absolute; inset:-11px; border-radius:inherit; }
  .bs-ie-slotpen{ opacity:1; transform:none; }   /* без pop-in на тач */
}

/* ============================================================================
   bs-inline-edit v2 (ux-pro) — контраст на ЛЮБОМ фоне + достижимость пустых
   слотов. Три data-field теперь висят на десятках элементов разных блоков:
   тёмный/violet баннер, светлые секции, тонкая полоса announce, плотная сетка
   about, owner-hint-заглушки. Правки чисто визуальные/оверлейные — не трогают
   блок-разметку (site-smith) и не меняют публичную витрину (всё под .bs-ie-live
   или на bs-ie-классах слоя).
   ============================================================================ */

/* --- 1) КОНТРАСТ-RING на рамках: violet-контур тонет на violet/тёмном баннере
   (is-themed / is-dark / grad-banner). Добавляем полупрозрачный СВЕТЛЫЙ + ТЁМНЫЙ
   hairline снаружи → рамка читается на light И на dark, не завися от фона. --- */
.bs-ie-blockbox{
  box-shadow:
    0 0 0 1px rgba(255,255,255,.65),                                   /* видно на тёмном/violet */
    0 0 0 2.5px color-mix(in srgb, var(--ie) 26%, transparent),        /* violet-подложка */
    0 0 0 3.5px rgba(15,12,30,.14),                                    /* видно на светлом */
    0 8px 30px -12px color-mix(in srgb, var(--ie) 45%, transparent);
}
.bs-ie-fieldbox{
  box-shadow:
    0 0 0 1.5px rgba(255,255,255,.6),
    0 0 0 3px rgba(15,12,30,.12);
}
.bs-ie-slotbox{
  box-shadow:
    0 0 0 1.5px rgba(255,255,255,.55),
    0 0 0 3px rgba(15,12,30,.12);
}
/* filled-чипы (тулбар/карандаши) на баннере ТОГО ЖЕ violet — тонкий светлый
   ring отделяет чип от одноцветного фона (на светлом фоне не мешает). Ring —
   через box-shadow (не outline!), чтобы не перебивать :focus-visible-обводку. */
.bs-ie-bar{
  box-shadow:0 0 0 1px rgba(255,255,255,.32),
    0 6px 20px -6px color-mix(in srgb, var(--ie) 55%, transparent);
}
.bs-ie-pen{
  box-shadow:0 0 0 1px rgba(255,255,255,.32),
    0 4px 14px -4px color-mix(in srgb, var(--ie) 55%, transparent);
}
.bs-ie-slotpen{
  box-shadow:0 0 0 1px rgba(255,255,255,.32),
    0 5px 16px -5px color-mix(in srgb, var(--ie) 55%, transparent);
}

/* --- 2) ПУСТОЙ .b-art (владелец удалил иконку, icon:'') рендерится как 0×0
   flex-элемент (flex:none, нет .b-badge) → неховерабелен → карандаш «вернуть
   иконку» недостижим, фича «удалил → верни inline» ломается. В режиме редактора
   даём пустому слоту кликабельную дашед-заглушку. Только .bs-ie-live → публичная
   витрина не трогается. Только brand/promo-варианты имеют .b-art (text/minimal
   его display:none — не переопределяем, свойство display не объявляем). --- */
.bs-ie-live .site .s-banner .b-art:empty{
  position:relative;
  min-width:clamp(64px, 9vw, 96px);
  min-height:clamp(64px, 9vw, 96px);
  border:1.75px dashed color-mix(in srgb, currentColor 46%, transparent);  /* currentColor=знак баннера → контраст на light И dark */
  border-radius:20px;
  box-sizing:border-box;
}
/* «+» — универсальный сигнал «добавить иконку» (типографский знак, НЕ эмодзи) */
.bs-ie-live .site .s-banner .b-art:empty::before{
  content:'+'; position:absolute; inset:0;
  display:grid; place-items:center;
  font:300 clamp(24px,3vw,32px)/1 var(--font, system-ui, sans-serif);
  color:color-mix(in srgb, currentColor 50%, transparent);
  pointer-events:none;
}

/* --- 3) Плотная сетка about (.stats: 8 полей <b>/<span> стопкой) и тонкая полоса
   announce (.tx с вложенным <b>): карандаш рендерится ОДИН за раз (самый глубокий
   таргет), потому коллизии 8-и карандашей физически нет. Но поле-бокс на очень
   коротком/узком листе не должен выходить за соседнюю ячейку — держим fill тише,
   чтобы плотная зебра-сетка не «зашумлялась» подсветкой при быстром проходе. --- */
.bs-ie-live .site .s-about .stats [data-field],
.bs-ie-live .site .s-announce .tx[data-field]{
  cursor:pointer;
  border-radius:6px;   /* мягкий контур поля-бокса на компактном листе */
}

/* ============================================================================
   POST-COMPOSER — большая фирменная модалка «Новый пост» (src/ui/post-composer.js).
   z-index 9000 (как pp-authgate): выше ленты/нава, НИЖЕ медиа-редактора (10050).
   Токены tokens.css; ноль хардкод-hex. Мобайл (≤600px) — на весь экран.
   ============================================================================ */
.pp-pc-back{
  position:fixed; inset:0; z-index:9000; display:grid; place-items:center;
  padding:var(--sp-5); background:rgba(20,16,40,.5); backdrop-filter:blur(4px);
  -webkit-backdrop-filter:blur(4px); opacity:0; transition:opacity .18s ease;
}
.pp-pc-back.is-show{ opacity:1; }
.pp-pc{
  position:relative; display:flex; flex-direction:column;
  width:min(560px,100%); max-height:88vh; background:var(--card);
  border-radius:20px; box-shadow:0 30px 90px -20px rgba(20,16,40,.4);
  transform:translateY(12px) scale(.98); opacity:.4;
  transition:transform .22s cubic-bezier(.23,1,.32,1), opacity .22s cubic-bezier(.23,1,.32,1);
}
.pp-pc-back.is-show .pp-pc{ transform:none; opacity:1; }
.pp-pc:focus{ outline:none; }
/* author display:flex/grid перебивает UA [hidden]{display:none} (author>UA) — как в
   image-uploader.js (.pp-upload-busy[hidden]). Возвращаем скрытие toggled-hidden узлам:
   пустой слот ошибки, сетка превью при пустой галерее, герой-дропзон при наличии медиа. */
.pp-pc-err[hidden], .pp-pc-grid[hidden], .pp-pc-drop[hidden]{ display:none !important; }

/* head */
.pp-pc-head{
  display:flex; align-items:center; justify-content:space-between;
  padding:var(--sp-3) var(--sp-5); border-bottom:1px solid var(--line);
}
.pp-pc-title{ margin:0; font:800 18px var(--font-display,var(--font)); letter-spacing:-.01em; color:var(--ink); }
.pp-pc-x{
  display:grid; place-items:center; width:36px; height:36px; flex:0 0 auto;
  border:none; border-radius:var(--pill); background:transparent; color:var(--ink2);
  cursor:pointer; transition:background .15s ease, color .15s ease;
}
.pp-pc-x:hover{ background:var(--bg2); color:var(--ink); }
.pp-pc-x:focus-visible{ outline:none; box-shadow:0 0 0 3px rgba(124,92,255,.35); }

/* body (скролл) */
.pp-pc-body{
  display:flex; flex-direction:column; gap:var(--sp-2);
  padding:var(--sp-4) var(--sp-5); overflow:auto; flex:1 1 auto;
}

/* инлайн-ошибка */
.pp-pc-err{
  display:flex; align-items:flex-start; gap:8px; margin:0;
  padding:10px 12px; border-radius:var(--rad-md); background:var(--rose-50);
  color:var(--rose-700); font:600 13px var(--font); line-height:1.4;
}

/* компактная зона загрузки (пусто) — полоса ~68px, НЕ квадрат на пол-окна (DENSITY §2) */
.pp-pc-drop{
  display:flex; flex-direction:row; align-items:center; gap:var(--sp-3);
  padding:var(--sp-3) var(--sp-4); text-align:left; cursor:pointer;
  border:1.5px dashed var(--line2); border-radius:14px;
  background:linear-gradient(180deg,var(--violet-50),var(--card));
  transition:border-color .16s ease, background .16s ease, transform .16s ease;
}
.pp-pc-drop:hover, .pp-pc-drop.is-drag{
  border-color:var(--violet); background:var(--violet-50);
}
.pp-pc-drop.is-drag{ transform:scale(1.005); }
.pp-pc-drop:focus-visible{ outline:none; box-shadow:0 0 0 3px rgba(124,92,255,.35); }
.pp-pc-drop-ico{
  display:grid; place-items:center; width:40px; height:40px; flex:0 0 auto;
  border-radius:var(--rad-md); background:var(--violet-100); color:var(--violet-700);
}
.pp-pc-drop-txt{ display:flex; flex-direction:column; gap:1px; min-width:0; }
.pp-pc-drop-t{ font:700 14px var(--font); color:var(--ink); }
.pp-pc-drop-d{ font:500 12px var(--font); color:var(--ink2); }

/* сетка превью (с медиа) */
.pp-pc-grid{ display:flex; flex-wrap:wrap; gap:var(--sp-2); }
.pp-pc-thumb{
  position:relative; width:88px; height:88px; flex:0 0 auto;
  border-radius:var(--rad-md); overflow:hidden; background:var(--bg2);
  border:1px solid var(--line); animation:pp-pc-pop .18s cubic-bezier(.23,1,.32,1);
}
.pp-pc-thumb img{ width:100%; height:100%; object-fit:cover; display:block; }
.pp-pc-thumb-rm{
  position:absolute; top:4px; right:4px; display:grid; place-items:center;
  width:22px; height:22px; border:none; border-radius:var(--pill); cursor:pointer;
  background:rgba(20,16,40,.55); color:#fff; backdrop-filter:blur(4px);
  -webkit-backdrop-filter:blur(4px); transition:background .15s ease;
}
.pp-pc-thumb-rm:hover{ background:rgba(20,16,40,.8); }
.pp-pc-thumb-rm:focus-visible{ outline:none; box-shadow:0 0 0 3px rgba(124,92,255,.5); }
.pp-pc-thumb.is-loading{ display:grid; place-items:stretch; }
.pp-pc-shimmer{
  display:block; width:100%; height:100%;
  background:linear-gradient(100deg,var(--bg2) 30%,var(--gray-100) 50%,var(--bg2) 70%);
  background-size:200% 100%; animation:pp-pc-shimmer 1.1s linear infinite;
}
.pp-pc-add{
  display:flex; flex-direction:column; align-items:center; justify-content:center; gap:2px;
  width:88px; height:88px; flex:0 0 auto; cursor:pointer;
  border:1.5px dashed var(--line2); border-radius:var(--rad-md);
  background:transparent; color:var(--ink2);
  font:600 12px var(--font); transition:border-color .15s ease, color .15s ease, background .15s ease;
}
.pp-pc-add:hover{ border-color:var(--violet); color:var(--violet); background:var(--violet-50); }
.pp-pc-add:focus-visible{ outline:none; box-shadow:0 0 0 3px rgba(124,92,255,.35); }

/* поля ввода (заголовок / текст / видео) */
.pp-pc-input, .pp-pc-text{
  width:100%; border:1.5px solid var(--line2); border-radius:var(--rad-md);
  background:var(--bg); color:var(--ink); font:500 14px var(--font);
  padding:9px 13px; transition:border-color .15s ease, box-shadow .15s ease;
}
.pp-pc-input::placeholder, .pp-pc-text::placeholder{ color:var(--gray-500); }
.pp-pc-input:focus, .pp-pc-text:focus{
  outline:none; border-color:var(--violet); box-shadow:0 0 0 3px rgba(124,92,255,.14);
}
.pp-pc-text{ min-height:88px; resize:vertical; line-height:1.5; }
.pp-pc-vidrow{ position:relative; display:block; }
.pp-pc-vidico{
  position:absolute; left:12px; top:50%; transform:translateY(-50%);
  display:grid; place-items:center; color:var(--gray-500); pointer-events:none;
}
.pp-pc-vid{ padding-left:40px; }

/* textarea + угловая кнопка эмодзи (line-SVG smile, НЕ эмодзи-контрол) */
.pp-pc-textwrap{ position:relative; display:block; }
.pp-pc-emoji{
  position:absolute; right:8px; bottom:8px; z-index:2;
  display:grid; place-items:center; width:36px; height:36px;
  border:none; border-radius:var(--pill); background:transparent; color:var(--gray-500);
  cursor:pointer; transition:background .15s ease, color .15s ease, transform .12s ease;
}
.pp-pc-emoji:hover{ background:var(--violet-50); color:var(--violet); }
.pp-pc-emoji[aria-expanded="true"]{ background:var(--violet-100); color:var(--violet); }
.pp-pc-emoji:active{ transform:scale(.92); }
.pp-pc-emoji:focus-visible{ outline:none; box-shadow:0 0 0 3px rgba(124,92,255,.35); }

/* ── Композер: контрол «Прикрепить 3D-модель» (фича #068) — компактная строка ~40px,
   НЕ второй дропзон, НЕ герой (DENSITY §2/§3). idle-кнопка → строка «готовим» → чип. ── */
.pp-pc-model{ display:block; }
.pp-pc-modeladd{
  display:flex; align-items:center; gap:8px; width:100%; min-height:40px;
  padding:8px 12px; cursor:pointer; text-align:left;
  border:1.5px dashed var(--line2); border-radius:var(--rad-md);
  background:transparent; color:var(--ink); font:700 13px var(--font);
  transition:border-color .15s ease, color .15s ease, background .15s ease;
}
.pp-pc-modeladd:hover{ border-color:var(--violet); color:var(--violet); background:var(--violet-50); }
.pp-pc-modeladd:focus-visible{ outline:none; box-shadow:0 0 0 3px rgba(124,92,255,.35); }
.pp-pc-modeladd svg{ color:var(--violet-700); flex:0 0 auto; }
.pp-pc-modeladd .pp-pc-modelhint{ margin-left:auto; font:500 12px var(--font); color:var(--ink2); flex:0 0 auto; }
.pp-pc-modelbar{
  display:flex; align-items:center; gap:10px; width:100%; min-height:40px;
  padding:8px 12px; border:1px solid var(--line); border-radius:var(--rad-md);
  background:var(--bg2); color:var(--ink2); font:600 13px var(--font);
}
.pp-pc-modelspin{
  width:16px; height:16px; flex:0 0 auto; border-radius:50%;
  border:2px solid var(--line2); border-top-color:var(--violet);
  animation:pp-pc-mspin .7s linear infinite;
}
@keyframes pp-pc-mspin{ to{ transform:rotate(360deg); } }
.pp-pc-modelchip{
  display:flex; align-items:center; gap:10px; width:100%; min-height:44px;
  padding:6px 6px 6px 6px; border:1px solid var(--line); border-radius:var(--rad-md);
  background:var(--card);
}
.pp-pc-modelchip-ico{
  display:grid; place-items:center; width:32px; height:32px; flex:0 0 auto;
  border-radius:8px; background:var(--violet-100); color:var(--violet-700);
}
.pp-pc-modelchip-name{
  flex:1 1 auto; min-width:0; display:flex; align-items:center; gap:6px;
  font:600 13px var(--font); color:var(--ink);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}
.pp-pc-modelchip-name .pp-pc-modelok{ color:var(--emerald-600,#059669); flex:0 0 auto; display:inline-flex; }
.pp-pc-modelchip-rm{
  display:grid; place-items:center; width:30px; height:30px; flex:0 0 auto;
  border:none; border-radius:var(--pill); background:transparent; color:var(--ink2);
  cursor:pointer; transition:background .15s ease, color .15s ease;
}
.pp-pc-modelchip-rm:hover{ background:var(--rose-50); color:var(--rose-700); }
.pp-pc-modelchip-rm:focus-visible{ outline:none; box-shadow:0 0 0 3px rgba(124,92,255,.35); }

/* ── Лента группы: крутибельный 3D-тайл (фича #068) — компактный, не билборд.
   Высота 240px desktop / 200px mobile (< трети вьюпорта, DENSITY). ── */
.pp-feed-model{
  position:relative; width:100%; height:240px; margin:8px 0; overflow:hidden;
  border:1px solid var(--line); border-radius:12px;
  background:radial-gradient(120% 120% at 50% 32%, var(--bg2), var(--card));
}
.pp-feed-model-ph{
  position:absolute; inset:0; z-index:0; cursor:pointer;
  display:flex; flex-direction:column; align-items:center; justify-content:center; gap:6px;
  color:var(--ink2); font:600 12px var(--font);
}
.pp-feed-model-ph svg{ opacity:.7; }
.pp-feed-model-open{
  position:absolute; right:8px; bottom:8px; z-index:2;
  display:inline-flex; align-items:center; gap:6px; height:36px; padding:0 13px;
  border:1px solid var(--line); border-radius:var(--pill); cursor:pointer;
  background:rgba(255,255,255,.88); color:var(--ink); font:700 12px var(--font);
  backdrop-filter:blur(6px); -webkit-backdrop-filter:blur(6px);
  transition:background .15s ease, box-shadow .15s ease;
}
.pp-feed-model-open:hover{ background:#fff; box-shadow:var(--shadow,0 2px 8px rgba(20,12,40,.12)); }
.pp-feed-model-open:focus-visible{ outline:none; box-shadow:0 0 0 3px rgba(124,92,255,.35); }
@media (max-width:600px){
  .pp-feed-model{ height:200px; }
  .pp-feed-model-open{ height:44px; }   /* тач-таргет ≥44px */
}
@media (prefers-reduced-motion: reduce){
  .pp-pc-modelspin{ animation:none; }
}

/* ── эмодзи-клавиатура (emoji-kbd.js) — переиспользуемый фрост-поповер ─────────
   z-index 9500: ВЫШЕ модалки композера (9000), ниже медиа-редактора (10050). */
.ek-scrim{ position:fixed; inset:0; z-index:9499; background:transparent; }
.ek-pop{
  position:fixed; z-index:9500; left:0; top:0;
  display:flex; flex-direction:column; width:min(360px,94vw); max-height:min(420px,72vh);
  background:var(--card); border:1px solid var(--line); border-radius:var(--rad-lg);
  box-shadow:var(--shadow-lg); overflow:hidden;
  animation:ek-in .15s ease-out;
}
@keyframes ek-in{ from{ opacity:0; transform:translateY(-6px) scale(.97); } to{ opacity:1; transform:none; } }
.ek-head{ display:flex; align-items:center; gap:var(--sp-2); padding:var(--sp-3) var(--sp-3) var(--sp-2); }
.ek-search{ position:relative; flex:1 1 auto; min-width:0; }
.ek-search-ic{ position:absolute; left:10px; top:50%; transform:translateY(-50%); display:grid; place-items:center; color:var(--gray-500); pointer-events:none; }
.ek-search-in{
  width:100%; border:1.5px solid var(--line2); border-radius:var(--pill);
  background:var(--bg); color:var(--ink); font:500 13px var(--font);
  padding:8px 12px 8px 32px; transition:border-color .15s ease, box-shadow .15s ease;
}
.ek-search-in::placeholder{ color:var(--gray-500); }
.ek-search-in:focus{ outline:none; border-color:var(--violet); box-shadow:0 0 0 3px rgba(124,92,255,.14); }
.ek-x{
  flex:0 0 auto; display:grid; place-items:center; width:34px; height:34px;
  border:none; border-radius:var(--pill); background:transparent; color:var(--ink2);
  cursor:pointer; transition:background .15s ease, color .15s ease;
}
.ek-x:hover{ background:var(--bg2); color:var(--ink); }
.ek-x:focus-visible{ outline:none; box-shadow:0 0 0 3px rgba(124,92,255,.35); }
.ek-tabs{
  display:flex; gap:2px; padding:0 var(--sp-2) var(--sp-2); overflow-x:auto;
  scrollbar-width:none; border-bottom:1px solid var(--line);
}
.ek-tabs::-webkit-scrollbar{ display:none; }
.ek-tab{
  flex:0 0 auto; display:grid; place-items:center; width:36px; height:36px;
  border:none; background:transparent; cursor:pointer; font-size:19px; line-height:1;
  font-family:'BS Emoji','Apple Color Emoji','Segoe UI Emoji','Noto Color Emoji',sans-serif;
  border-radius:var(--rad-md); opacity:.72; transition:background .12s, opacity .12s, transform .12s;
}
.ek-tab:hover{ background:var(--violet-50); opacity:1; transform:scale(1.08); }
.ek-tab.is-active{ background:var(--violet-100); opacity:1; box-shadow:inset 0 0 0 2px var(--violet-400); }
.ek-tab:focus-visible{ outline:none; box-shadow:0 0 0 3px var(--violet-200); }
.ek-body{ flex:1 1 auto; min-height:0; overflow:hidden; display:flex; }
.ek-grid{
  flex:1 1 auto; overflow-y:auto; overscroll-behavior:contain;
  display:grid; grid-template-columns:repeat(8,1fr); gap:2px;
  padding:var(--sp-2) var(--sp-3) var(--sp-3);
}
.ek-cell{
  display:flex; align-items:center; justify-content:center;
  width:100%; aspect-ratio:1; border:0; background:transparent; cursor:pointer;
  font-size:21px; line-height:1; border-radius:var(--rad-md);
  font-family:'BS Emoji','Apple Color Emoji','Segoe UI Emoji','Noto Color Emoji',sans-serif;
  transition:transform .1s ease, background .1s ease;
}
.ek-cell:hover{ background:var(--violet-50); transform:scale(1.18); }
.ek-cell:focus-visible{ outline:none; box-shadow:0 0 0 3px var(--violet-200); }
.ek-empty{ flex:1 1 auto; display:grid; place-items:center; padding:var(--sp-6);
  font:600 13px var(--font); color:var(--ink2); text-align:center; }
.ek-empty[hidden]{ display:none !important; }

/* мобайл: клавиатура → bottom-sheet во всю ширину, не вылезает за экран */
@media(max-width:600px){
  .pp-pc-emoji{ width:44px; height:44px; }
  .ek-scrim{ background:rgba(20,20,20,.34); }
  .ek-pop{
    left:0; right:0; bottom:0; top:auto !important; width:100%; max-height:62vh;
    border-radius:var(--rad-2xl) var(--rad-2xl) 0 0;
    padding-bottom:env(safe-area-inset-bottom,0px);
    animation:ek-sheet-in .22s cubic-bezier(.2,.8,.2,1);
  }
  @keyframes ek-sheet-in{ from{ transform:translateY(100%); } to{ transform:none; } }
  .ek-grid{ grid-template-columns:repeat(8,1fr); }
  .ek-cell{ font-size:25px; }
  .ek-tab{ width:40px; height:40px; font-size:21px; }
}
@media(prefers-reduced-motion:reduce){
  .ek-pop{ animation:none; }
  .ek-cell,.ek-tab{ transition:none; }
  .ek-cell:hover,.ek-tab:hover{ transform:none; }
}

/* подсказки (размер / модерация) — бренд-иконка + текст, без эмодзи */
.pp-pc-notes{ display:flex; flex-direction:column; gap:6px; margin-top:2px; }
.pp-pc-note{
  display:flex; align-items:flex-start; gap:8px; margin:0;
  font:500 12px var(--font); line-height:1.45; color:var(--ink2);
}
.pp-pc-note svg{ flex:0 0 auto; margin-top:1px; color:var(--gray-500); }

/* футер (sticky, primary справа) */
.pp-pc-foot{
  display:flex; align-items:center; justify-content:space-between; gap:var(--sp-3);
  padding:var(--sp-3) var(--sp-5); border-top:1px solid var(--line);
  background:var(--card); flex:0 0 auto;
}
.pp-pc-count{ font:600 12px var(--font); color:var(--ink2); }
.pp-pc-acts{ display:flex; align-items:center; gap:var(--sp-2); flex:0 0 auto; }
.pp-pc-btn{
  display:inline-flex; align-items:center; justify-content:center;
  min-height:40px; padding:0 18px; border-radius:var(--pill); cursor:pointer;
  font:700 14px var(--font); border:1.5px solid transparent;
  transition:transform .16s ease-out, box-shadow .18s ease, background .15s ease, opacity .15s ease;
}
.pp-pc-btn:active{ transform:scale(.97); }
.pp-pc-btn:focus-visible{ outline:none; box-shadow:0 0 0 3px rgba(124,92,255,.4); }
.pp-pc-btn-ghost{ background:transparent; color:var(--ink2); }
.pp-pc-btn-ghost:hover{ background:var(--bg2); color:var(--ink); }
.pp-pc-btn-primary{
  background:var(--grad-hero); color:#fff;
  box-shadow:0 12px 28px -12px rgba(124,92,255,.7);
}
.pp-pc-btn-primary:hover{ box-shadow:0 16px 34px -12px rgba(124,92,255,.85); }
.pp-pc-btn-primary:disabled{
  opacity:.45; cursor:not-allowed; box-shadow:none; transform:none;
}
.pp-pc-btn-primary.is-busy{ cursor:progress; }

@keyframes pp-pc-pop{ from{ transform:scale(.9); opacity:0; } to{ transform:none; opacity:1; } }
@keyframes pp-pc-shimmer{ from{ background-position:200% 0; } to{ background-position:-200% 0; } }

/* мобайл: модалка на весь экран */
@media(max-width:600px){
  .pp-pc-back{ padding:0; }
  .pp-pc{
    width:100%; height:100vh; height:100dvh; max-height:none; border-radius:0;
    transform:translateY(16px); opacity:.4;
  }
  .pp-pc-back.is-show .pp-pc{ transform:none; }
  .pp-pc-head{ padding:var(--sp-4) var(--sp-4); }
  .pp-pc-body{ padding:var(--sp-4); }
  .pp-pc-foot{
    padding:var(--sp-3) var(--sp-4) calc(var(--sp-3) + env(safe-area-inset-bottom));
  }
  .pp-pc-btn{ min-height:44px; }   /* тач-таргет ≥44 на мобиле (DENSITY §3) */
  .pp-pc-thumb, .pp-pc-add{ width:78px; height:78px; }
}

/* reduced-motion: только opacity, без трансформов */
@media(prefers-reduced-motion:reduce){
  .pp-pc, .pp-pc-back, .pp-pc-thumb, .pp-pc-btn, .pp-pc-drop{ transition:opacity .12s linear; transform:none !important; }
  .pp-pc-thumb{ animation:none; }
  .pp-pc-shimmer{ animation:none; }
}

/* ══════════════════════════════════════════════════════════════════════════════
   ГРУППЫ: лайтбокс фото · сегмент «кто публикует» · бейджи ролей · icon-кнопки
   Добавлено ux-pro. Все значения из токенов (var(--*)). Иконки — line-SVG.
   ══════════════════════════════════════════════════════════════════════════════ */

/* ── ПОЛНОЭКРАННЫЙ лайтбокс фото (ui/lightbox.js) ──────────────────────────────
   «На весь экран» = contain до краёв вьюпорта (без обрезки и без разрыва пропорций):
   стейдж занимает ВЕСЬ оверлей минус компактный хром, фото тянется по меньшей стороне.
   Хром намеренно плотный (D0): × 40, стрелки 44, счётчик 12px — тач-зона добирается
   ::before, а не раздутым телом кнопки. Подложки контролов ТЁМНЫЕ+blur: поверх светлого
   фото белая полупрозрачная кнопка исчезала.
   z-index 9500: выше ленты/композера (9000), ниже медиа-редактора (10050). */
.pp-lb-lock{ overflow:hidden !important; }
.pp-lb{
  position:fixed; inset:0; z-index:9500;
  display:grid; grid-template-columns:auto 1fr auto; align-items:center;
  background:rgba(12,10,20,.94); backdrop-filter:blur(4px); -webkit-backdrop-filter:blur(4px);
  opacity:0; transition:opacity .18s ease;
  padding:max(10px,env(safe-area-inset-top)) 10px max(10px,env(safe-area-inset-bottom));
}
.pp-lb.is-show{ opacity:1; }
.pp-lb-stage{
  grid-column:1 / -1; grid-row:1; margin:0;
  display:flex; align-items:center; justify-content:center;
  width:100%; height:100%; min-width:0; min-height:0; overflow:hidden; pointer-events:none;
}
.pp-lb-img{
  max-width:100%; max-height:100%; width:auto; height:auto;
  object-fit:contain; border-radius:8px; pointer-events:auto;
  cursor:zoom-in; touch-action:none; user-select:none; -webkit-user-select:none;
  -webkit-user-drag:none; will-change:transform;
  box-shadow:0 24px 70px -24px rgba(0,0,0,.7); background:#0c0a14;
}
.pp-lb.is-zoom .pp-lb-img{ cursor:grab; }
.pp-lb.is-pan  .pp-lb-img{ cursor:grabbing; }
.pp-lb-img.is-anim{ transition:transform .18s cubic-bezier(.22,.61,.36,1); }
.pp-lb-img.is-swap{ animation:ppLbSwap .18s ease-out; }
@keyframes ppLbSwap{ from{ opacity:.35; } to{ opacity:1; } }
.pp-lb-nav, .pp-lb-x{
  position:relative; z-index:1; display:grid; place-items:center; cursor:pointer;
  border:0; background:rgba(16,14,26,.55); color:#fff; border-radius:var(--pill);
  backdrop-filter:blur(8px); -webkit-backdrop-filter:blur(8px);
  transition:background .15s ease, opacity .15s ease, transform .15s ease;
  -webkit-tap-highlight-color:transparent;
}
/* тач-зона 44+ при компактном визуальном теле (§16.2: не раздуваем кнопку) */
.pp-lb-nav::before, .pp-lb-x::before{ content:""; position:absolute; inset:-4px; border-radius:inherit; }
.pp-lb-nav{ grid-row:1; width:44px; height:44px; }
.pp-lb-prev{ grid-column:1; justify-self:start; }
.pp-lb-next{ grid-column:3; justify-self:end; }
.pp-lb-x{ position:absolute; top:max(10px,env(safe-area-inset-top)); right:12px; width:40px; height:40px; }
.pp-lb-nav:hover, .pp-lb-x:hover{ background:rgba(38,34,56,.8); }
.pp-lb-nav:active{ transform:scale(.92); }
.pp-lb-nav:focus-visible, .pp-lb-x:focus-visible{ outline:2px solid #fff; outline-offset:2px; }
/* в зуме листалка уступает кадру, но остаётся видимой и тапаемой (не hover-only) */
.pp-lb.is-zoom .pp-lb-nav{ opacity:.45; }
.pp-lb.is-zoom .pp-lb-nav:hover, .pp-lb.is-zoom .pp-lb-nav:focus-visible{ opacity:1; }
.pp-lb-count{
  position:absolute; left:50%; bottom:max(10px,env(safe-area-inset-bottom)); transform:translateX(-50%);
  color:#fff; font:600 12px var(--font); background:rgba(16,14,26,.6);
  backdrop-filter:blur(8px); -webkit-backdrop-filter:blur(8px);
  padding:4px 10px; border-radius:var(--pill); letter-spacing:.02em; font-variant-numeric:tabular-nums;
}
@media(max-width:600px){
  .pp-lb{ padding:max(8px,env(safe-area-inset-top)) 6px max(8px,env(safe-area-inset-bottom)); }
  .pp-lb-nav{ width:44px; height:44px; }   /* тач-минимум, ниже опускать нельзя */
}
@media(prefers-reduced-motion:reduce){
  .pp-lb{ transition:none; } .pp-lb-img.is-swap{ animation:none; }
  .pp-lb-img.is-anim{ transition:none; }
  .pp-lb-nav, .pp-lb-x{ transition:none; }
}

/* ── Подсказка «открыть во весь экран» — общий блок для hero-медиа (PDP + быстрый
   просмотр). Видима ВСЕГДА (не hover-only: на тач курсора нет), компактная 32px,
   тач-зона 44 через ::before. Инжектит JS только когда фото реально есть. ── */
.pp-zoomcue{
  position:absolute; right:10px; bottom:10px; z-index:3;
  width:32px; height:32px; display:grid; place-items:center; padding:0;
  border:0; border-radius:var(--pill); cursor:zoom-in; color:var(--ink);
  background:color-mix(in srgb, var(--card) 88%, transparent);
  backdrop-filter:blur(6px); -webkit-backdrop-filter:blur(6px);
  box-shadow:0 4px 14px -4px rgba(15,16,32,.42);
  transition:transform .14s ease, background .14s ease;
}
.pp-zoomcue::before{ content:""; position:absolute; inset:-6px; border-radius:inherit; }
.pp-zoomcue:hover{ background:var(--card); transform:translateY(-1px); }
.pp-zoomcue:active{ transform:translateY(0); }
.pp-zoomcue:focus-visible{ outline:2px solid var(--violet); outline-offset:2px; }
.pp-zoomcue[hidden]{ display:none; }
@media(prefers-reduced-motion:reduce){ .pp-zoomcue{ transition:none; } .pp-zoomcue:hover{ transform:none; } }

/* фото поста кликабельно → лайтбокс (аффорданс: курсор + лёгкое затемнение) */
.pp-feed-gallery[data-lb] .pp-feed-photo{ cursor:zoom-in; transition:filter .15s ease; }
.pp-feed-gallery[data-lb] .pp-feed-photo:hover{ filter:brightness(.94); }

/* ── Сегмент «Кто может публиковать» (СВОИ классы — .pp-seg перегружен, не трогаем) ─
   single-select, мгновенный эффект. Прижат влево, компактный (§15.B). */
.pp-gr-seg{
  display:inline-flex; flex-wrap:wrap; gap:4px; background:var(--bg2);
  border-radius:12px; padding:4px; max-width:100%;
}
.pp-gr-seg-opt{
  border:0; background:none; cursor:pointer; border-radius:9px;
  padding:8px 13px; font:600 13px var(--font); color:var(--ink2);
  transition:background .15s ease, color .15s ease, box-shadow .15s ease;
}
.pp-gr-seg-opt:hover{ color:var(--ink); }
.pp-gr-seg-opt:focus-visible{ outline:none; box-shadow:0 0 0 2px var(--violet); }
.pp-gr-seg-opt.is-on{ background:#fff; color:var(--ink); box-shadow:var(--shadow,0 2px 8px rgba(20,12,40,.10)); }

/* ── Бейджи ролей участников (бренд, без сырых эмодзи) ─────────────────────────── */
.pp-role{
  display:inline-flex; align-items:center; gap:4px; vertical-align:middle;
  border-radius:var(--pill); padding:2px 8px; font:700 11px var(--font); white-space:nowrap;
}
.pp-role--owner{ background:var(--violet-50); color:var(--violet-700); }
.pp-role--admin{ background:var(--coral-50); color:var(--coral-700); }
.pp-role--member{ background:var(--bg2); color:var(--ink2); font-weight:600; }
/* акцентные чипы шапки (владелец/админ) */
.pp-chip--owner{ border-color:var(--violet-200); color:var(--violet-700); }
.pp-chip--mod{ border-color:var(--coral-200); color:var(--coral-700); }

/* ── Icon-only вариант pp-feed-btn: квадратный, ровный тач-таргет ──────────────── */
.pp-feed-btn--icon{ padding:4px; min-width:28px; justify-content:center; gap:0; }

/* ── Строка участника в модалке «Управление» (компактно, роль + действия) ─────── */
.pp-member-row{ align-items:center; gap:10px; }
.pp-member-row .pp-comment-body{ display:flex; flex-direction:column; gap:1px; }
.pp-member-row .pp-comment-head{ display:flex; align-items:center; gap:6px; flex-wrap:wrap; margin-bottom:0; overflow-wrap:anywhere; }
.pp-member-acts{ display:flex; flex-wrap:wrap; gap:6px; justify-content:flex-end; margin-left:auto; }
.pp-ava-mini--img{ object-fit:cover; }

/* пустые состояния ленты: SVG-иконка вместо эмодзи — мягкий тон */
.pp-gr-empty-ico{ display:inline-flex; color:var(--ink2); opacity:.72; }
.pp-gr-empty-ico svg{ width:30px; height:30px; }

/* ============================================================
   ФОРУМ-ВИД группы — переключатель «Форум / Лента» + плотный список ТЕМ.
   Канон веб-форума (Разделы→Темы→Сообщения): строка темы ~44px, много тем
   в кадре. Всё на токенах, ноль хардкод-hex. Эталон плотности — кабинет.
   ============================================================ */

/* правый блок шапки ленты: сегмент вида + счётчик записей в один ряд */
.pp-forum-headtools{ display:flex; align-items:center; gap:12px; flex:none; }

/* сегмент «Форум / Лента» (single-select, компактный ~34px — density-канон 32–36) */
.pp-forum-seg{ display:inline-flex; gap:3px; background:var(--bg2); border-radius:10px; padding:3px; }
.pp-forum-seg-opt{
  display:inline-flex; align-items:center; gap:5px; border:0; background:none; cursor:pointer;
  border-radius:8px; padding:6px 11px; font:600 12.5px var(--font); color:var(--ink2);
  transition:background .15s ease, color .15s ease, box-shadow .15s ease; white-space:nowrap;
}
.pp-forum-seg-opt:hover{ color:var(--ink); }
.pp-forum-seg-opt:focus-visible{ outline:none; box-shadow:0 0 0 2px var(--blue); }
.pp-forum-seg-opt.is-on{ background:var(--card); color:var(--ink); box-shadow:var(--shadow,0 2px 8px rgba(20,12,40,.10)); }
.pp-forum-seg-opt .pp-ic{ opacity:.85; }

/* контейнер списка тем — единая карта с разделителями (плотно, без зазоров между строк) */
.pp-forum-list{ border:1px solid var(--line); border-radius:var(--r); overflow:hidden; background:var(--card); }

/* строка ТЕМЫ: [аватар] [заголовок + автор·время] [N ответов]. Высота ~44px */
.pp-forum-row{
  display:grid; grid-template-columns:auto minmax(0,1fr) auto; align-items:center;
  gap:10px; padding:6px 12px; min-height:44px; border-top:1px solid var(--line);
}
.pp-forum-row:first-child{ border-top:0; }
.pp-forum-row.is-pinned{ background:var(--bg2); }

.pp-forum-avalink{ display:block; line-height:0; flex:none; }
.pp-forum-ava{
  width:26px; height:26px; border-radius:50%; background:var(--grad-2); color:#fff;
  display:grid; place-items:center; font:700 12px var(--font); flex:none;
}
.pp-forum-ava--img{ object-fit:cover; }

.pp-forum-body{ min-width:0; display:flex; flex-direction:column; gap:0; }
.pp-forum-title{
  display:flex; align-items:center; gap:5px; min-width:0; text-decoration:none;
  color:var(--ink); font:600 14px var(--font); line-height:1.25;
}
.pp-forum-tt{ overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.pp-forum-title:hover .pp-forum-tt{ color:var(--violet); text-decoration:underline; }
.pp-forum-pin,.pp-forum-mi{ flex:none; display:inline-flex; }
.pp-forum-pin{ color:var(--violet); }
.pp-forum-mi{ color:var(--ink2); }

.pp-forum-sub{
  display:flex; align-items:center; gap:5px; min-width:0;
  font:500 12px var(--font); line-height:1.2; color:var(--ink2);
}
.pp-forum-author{
  color:var(--ink2); text-decoration:none; white-space:nowrap;
  overflow:hidden; text-overflow:ellipsis; max-width:52%; flex:0 1 auto;
}
.pp-forum-author:hover{ color:var(--violet); }
.pp-forum-dot{ opacity:.55; flex:none; }
.pp-forum-time{ white-space:nowrap; flex:none; }

.pp-forum-repwrap{ flex:none; text-decoration:none; }
.pp-forum-replies{
  display:inline-flex; align-items:center; justify-content:center; gap:5px;
  min-width:44px; padding:4px 8px; border-radius:var(--pill);
  color:var(--ink2); font:700 13px var(--font); font-variant-numeric:tabular-nums;
  transition:background .15s ease, color .15s ease;
}
.pp-forum-repwrap:hover .pp-forum-replies{ background:var(--bg2); color:var(--ink); }

/* skeleton плотных строк форума */
.pp-forum-sk{ display:flex; align-items:center; gap:10px; padding:6px 12px; min-height:44px; border-top:1px solid var(--line); }
.pp-forum-sk:first-child{ border-top:0; }
.pp-forum-sk-ava{ width:26px; height:26px; border-radius:50%; background:var(--line); flex:none; }
.pp-forum-sk-lines{ flex:1; min-width:0; display:flex; flex-direction:column; gap:5px; }

/* мобайл: сегмент+счётчик уезжают на вторую строку шапки (не жмут заголовок) */
@media(max-width:560px){
  .pp-gr-feedhead{ flex-wrap:wrap; }
  .pp-forum-headtools{ width:100%; justify-content:space-between; }
}

/* ============================================================
   ЦЕНТР УВЕДОМЛЕНИЙ — колокольчик + дропдаун + панель настроек.
   Все значения — токены (var(--*)); ноль хардкода hex. Иконки line,
   currentColor. Тач-таргеты ≥40px, focus-ring виден, reduced-motion.
   ============================================================ */

/* ── Колокольчик в .pp-nav-cta (icon-only ghost, бейдж) ─────────────────────── */
.pp-bell{
  position:relative; display:grid; place-items:center; width:40px; height:40px;
  border:none; background:transparent; color:var(--ink2); border-radius:var(--rad-md);
  cursor:pointer; transition:background .15s, color .15s;
}
.pp-bell:hover{ color:var(--ink); background:rgba(124,92,255,.08); }
.pp-bell[aria-expanded="true"]{ color:var(--violet); background:rgba(124,92,255,.12); }
.pp-bell:focus-visible{ outline:2px solid var(--violet); outline-offset:2px; }
.pp-bell-ico{ width:21px; height:21px; }
.pp-bell[data-has-unread] .pp-bell-ico{ color:var(--ink); }
.pp-bell-badge{
  position:absolute; top:5px; right:5px; min-width:16px; height:16px; padding:0 4px;
  display:grid; place-items:center; box-sizing:border-box;
  font:700 10px/1 var(--font); font-variant-numeric:tabular-nums; letter-spacing:-.02em;
  color:#fff; background:var(--coral); border:2px solid var(--card);
  border-radius:var(--pill); pointer-events:none;
}
/* fail-closed: [hidden] обязан победить display:grid выше (UA display:none имеет
   низкую специфичность и проигрывал author-правилу → «0» светился при нуле). */
.pp-bell-badge[hidden]{ display:none; }

/* ── Дропдаун-поповер ───────────────────────────────────────────────────────── */
.pp-notifpop{
  position:absolute; top:calc(100% + 10px); right:0; z-index:1200;
  width:380px; max-width:calc(100vw - 24px);
  background:var(--card); border:1px solid var(--line);
  border-radius:var(--rad-xl); box-shadow:var(--shadow-lg), 0 4px 14px rgba(20,20,20,.06);
  display:flex; flex-direction:column; overflow:hidden;
  opacity:0; transform:translateY(-6px) scale(.985); transform-origin:top right;
  transition:opacity .16s ease, transform .16s cubic-bezier(.34,1.4,.64,1);
}
.pp-notifpop.is-show{ opacity:1; transform:translateY(0) scale(1); }
.pp-notifpop-scrim{ display:none; }

.pp-notifpop-head{
  display:flex; align-items:center; gap:10px; padding:14px 14px 10px;
  border-bottom:1px solid var(--line);
}
.pp-notifpop-title{ font:800 16px var(--font-display,var(--font)); color:var(--ink); margin-right:auto; }
.pp-notifpop-tools{ display:flex; align-items:center; gap:4px; }
.pp-notif-glyph{ width:18px; height:18px; flex:none; }
.pp-notifpop-act{
  display:inline-flex; align-items:center; gap:5px; height:34px; padding:0 10px;
  font:600 13px var(--font); color:var(--violet); background:transparent;
  border:none; border-radius:var(--rad-md); cursor:pointer; transition:background .15s;
}
.pp-notifpop-act:hover{ background:rgba(124,92,255,.10); }
.pp-notifpop-act:focus-visible{ outline:2px solid var(--violet); outline-offset:1px; }
.pp-notifpop-icobtn{
  display:grid; place-items:center; width:34px; height:34px;
  color:var(--ink2); background:transparent; border:none; border-radius:var(--rad-md);
  cursor:pointer; transition:background .15s, color .15s;
}
.pp-notifpop-icobtn:hover{ color:var(--ink); background:var(--bg2); }
.pp-notifpop-icobtn:focus-visible{ outline:2px solid var(--violet); outline-offset:1px; }
.pp-notifpop-close{ display:none; }  /* десктоп: закрытие кликом-вне/Esc; на мобиле показываем */

/* вкладки-фильтры (горизонтальный скролл при тесноте) */
.pp-notifpop-tabs{
  display:flex; gap:2px; padding:8px 10px; overflow-x:auto; scrollbar-width:none;
  border-bottom:1px solid var(--line);
}
.pp-notifpop-tabs::-webkit-scrollbar{ display:none; }
.pp-notifpop-tab{
  position:relative; display:inline-flex; align-items:center; gap:5px; flex:none;
  height:30px; padding:0 11px; font:600 13px var(--font); color:var(--ink2);
  background:transparent; border:none; border-radius:var(--pill); cursor:pointer;
  white-space:nowrap; transition:background .15s, color .15s;
}
.pp-notifpop-tab:hover{ color:var(--ink); background:var(--bg2); }
.pp-notifpop-tab.is-active{ color:#fff; background:var(--violet); }
.pp-notifpop-tab:focus-visible{ outline:2px solid var(--violet); outline-offset:2px; }
.pp-notifpop-tabn{
  min-width:16px; height:16px; padding:0 4px; box-sizing:border-box;
  display:grid; place-items:center; font:800 10px/1 var(--font);
  font-variant-numeric:tabular-nums; color:#fff; background:var(--coral);
  border-radius:var(--pill);
}
.pp-notifpop-tab.is-active .pp-notifpop-tabn{ background:rgba(255,255,255,.28); }

/* push-CTA баннер внутри дропдауна */
.pp-notif-push{
  display:flex; align-items:center; gap:10px; margin:10px 12px 2px; padding:10px 12px;
  background:var(--violet-50); border:1px solid var(--violet-100); border-radius:var(--rad-lg);
}
.pp-notif-push-ico{ display:grid; place-items:center; width:34px; height:34px; flex:none;
  color:var(--violet); background:var(--card); border-radius:var(--rad-md); }
.pp-notif-push-txt{ display:flex; flex-direction:column; line-height:1.25; margin-right:auto; }
.pp-notif-push-txt b{ font:700 13px var(--font); color:var(--ink); }
.pp-notif-push-txt span{ font:500 12px var(--font); color:var(--ink2); }

/* тело-список */
.pp-notifpop-body{ max-height:min(56vh,440px); overflow-y:auto; padding:6px; }
.pp-notif-row{
  position:relative; display:flex; align-items:flex-start; gap:11px; width:100%;
  padding:10px; text-align:left; background:transparent; border:none;
  border-radius:var(--rad-md); cursor:pointer; text-decoration:none;
  color:inherit; font:inherit; transition:background .13s;
}
.pp-notif-row:hover{ background:var(--bg2); }
.pp-notif-row:focus-visible{ outline:2px solid var(--violet); outline-offset:-2px; }
.pp-notif-row.is-unread{ background:rgba(124,92,255,.05); }
.pp-notif-row.is-unread:hover{ background:rgba(124,92,255,.09); }
.pp-notif-ico{ display:grid; place-items:center; width:34px; height:34px; flex:none;
  color:var(--ink2); background:var(--bg2); border-radius:var(--rad-md); }
.pp-notif-ico .pp-notif-glyph{ width:18px; height:18px; }
.pp-notif-row.is-unread .pp-notif-ico{ color:var(--violet); background:var(--violet-50); }
.pp-notif-main{ display:flex; flex-direction:column; gap:2px; min-width:0; flex:1; }
.pp-notif-txt{ font:500 13.5px/1.35 var(--font); color:var(--ink);
  overflow-wrap:anywhere; }
.pp-notif-time{ font:600 11.5px var(--font); font-variant-numeric:tabular-nums; color:var(--ink2); }
.pp-notif-udot{ width:8px; height:8px; flex:none; margin-top:6px; border-radius:50%;
  background:var(--coral); }

/* footer «вся история» */
.pp-notifpop-foot{
  display:block; padding:11px 14px; text-align:center; border-top:1px solid var(--line);
  font:700 13px var(--font); color:var(--violet); text-decoration:none;
  transition:background .15s;
}
.pp-notifpop-foot:hover{ background:var(--bg2); }
.pp-notifpop-foot:focus-visible{ outline:2px solid var(--violet); outline-offset:-2px; }

/* пусто / ошибка внутри дропдауна */
.pp-notif-empty{ display:flex; flex-direction:column; align-items:center; text-align:center;
  gap:6px; padding:40px 24px; }
.pp-notif-empty-ico{ display:grid; place-items:center; width:52px; height:52px; margin-bottom:2px;
  color:var(--ink2); background:var(--bg2); border-radius:var(--rad-lg); }
.pp-notif-empty-ico .pp-notif-glyph{ width:26px; height:26px; }
.pp-notif-empty-t{ font:700 15px var(--font); color:var(--ink); }
.pp-notif-empty-d{ font:500 13px/1.45 var(--font); color:var(--ink2); max-width:260px; }

/* skeleton загрузки (не спиннер) */
.pp-notif-skel{ display:flex; flex-direction:column; gap:4px; padding:4px; }
.pp-notif-skel-row{ height:56px; border-radius:var(--rad-md);
  background:linear-gradient(90deg,var(--bg2) 25%,var(--gray-100) 37%,var(--bg2) 63%);
  background-size:400% 100%; animation:pp-notif-skel 1.3s ease infinite; }
@keyframes pp-notif-skel{ 0%{background-position:100% 0} 100%{background-position:0 0} }

/* ── Панель «Настройки уведомлений» (модалка + вкладка store) ────────────────── */
.pp-nprefs{ display:flex; flex-direction:column; gap:18px; }
.pp-nprefs-group{ display:flex; flex-direction:column; gap:2px; }
.pp-nprefs-gt{ display:flex; align-items:center; gap:8px; margin:0 0 8px;
  font:800 12px var(--font); letter-spacing:.04em; text-transform:uppercase; color:var(--ink2); }
.pp-nprefs-glyph{ width:16px; height:16px; flex:none; color:var(--violet); }
.pp-nprefs-rows{ display:flex; flex-direction:column;
  border:1px solid var(--line); border-radius:var(--rad-lg); overflow:hidden; }
.pp-prefrow{ display:flex; align-items:center; gap:14px; padding:13px 14px;
  border-top:1px solid var(--line); background:var(--card); }
.pp-prefrow:first-child{ border-top:none; }
.pp-prefrow.is-muted{ background:var(--bg2); }
.pp-prefrow-main{ display:flex; flex-direction:column; gap:2px; min-width:0; margin-right:auto; }
.pp-prefrow-t{ font:600 14px var(--font); color:var(--ink); }
.pp-prefrow-d{ font:500 12.5px/1.4 var(--font); color:var(--ink2); }

/* ── Мобильный лист вместо поповера ─────────────────────────────────────────── */
@media(max-width:560px){
  /* Мобильный bottom-sheet. !important — чтобы ЛЮБОЙ inline top/left/right (если его
     выставил общий позиционер) не поборол лист и не вытолкнул панель за экран.
     Десктопный поповер (базовое правило .pp-notifpop) этим НЕ затрагивается. */
  .pp-notifpop{
    position:fixed !important; top:auto !important; right:0 !important; left:0 !important;
    bottom:0 !important; width:auto; max-width:none;
    border-radius:var(--rad-2xl) var(--rad-2xl) 0 0; transform-origin:bottom center;
    transform:translateY(12px); max-height:86vh;
  }
  .pp-notifpop.is-show{ transform:translateY(0); }
  .pp-notifpop-close{ display:grid; }
  .pp-notifpop-body{ max-height:none; flex:1; }
  .pp-notifpop-scrim{
    display:block; position:fixed; inset:0; z-index:1190; background:rgba(20,20,20,.42);
    opacity:0; transition:opacity .18s ease;
  }
  .pp-notifpop-scrim.is-show{ opacity:1; }
}

@media (prefers-reduced-motion: reduce){
  .pp-notifpop, .pp-notifpop-scrim, .pp-bell{ transition:none; }
  .pp-notif-skel-row{ animation:none; }
}

/* ── PDP: выравнивание бренд-иконок (line-SVG) в бейджах/строках, заменивших эмодзи.
   Только display/gap — цвета/фоны бейджей остаются из их исходных правил выше. ── */
.pdp-draft{ display:flex; align-items:center; gap:8px; }
.pdp-draft svg{ flex:none; color:var(--violet); }
.pdp-media-badge{ display:inline-flex; align-items:center; gap:4px; }
.pdp-thumb-tag{ display:flex; align-items:center; justify-content:center; gap:3px; }
.pdp-rel-3d{ display:inline-flex; align-items:center; gap:4px; }
.pdp-rel-master{ display:inline-flex; align-items:center; gap:4px; }
.pdp-review-stars{ display:inline-flex; align-items:center; gap:2px; }
.pdp-license-key{ display:inline-flex; align-items:center; color:var(--ink2); }
.pdp-lic-caret{ display:inline-flex; align-items:center; }
.pdp-lic-col li{ display:flex; align-items:flex-start; gap:6px; }
.pdp-lic-col li svg{ flex:none; margin-top:1px; }

/* ── Единый правовой подвал для commerce-страниц без своего footer (marketplace/биржа/
   магазин/прайсинг). YooKassa требует доступность оферты/контактов на всех страницах. ── */
.pp-foot-legal{ margin-top:48px; border-top:1px solid var(--line); background:var(--bg2); }
.pp-foot-legal-in{ max-width:var(--page-max); margin:0 auto; padding:20px; display:flex; align-items:center;
  flex-wrap:wrap; gap:8px 20px; }
.pp-foot-legal-brand{ font:800 15px var(--font-display); color:var(--ink); text-decoration:none;
  letter-spacing:-.01em; }
.pp-foot-legal-brand span{ color:var(--violet); }
.pp-foot-legal-links{ display:flex; flex-wrap:wrap; gap:2px 18px; }
.pp-foot-legal-links a{ font:600 13px var(--font); color:var(--ink2); text-decoration:none;
  min-height:32px; display:inline-flex; align-items:center; }
.pp-foot-legal-links a:hover{ color:var(--violet); text-decoration:underline; }
.pp-foot-legal-links a:focus-visible{ outline:2px solid var(--violet); outline-offset:2px; border-radius:var(--rad-xs); }
.pp-foot-legal-copy{ margin-left:auto; font:500 12px var(--font); color:var(--ink2); font-variant-numeric:tabular-nums; }
@media (max-width:600px){ .pp-foot-legal-copy{ margin-left:0; width:100%; } }

/* ── Доп. живые блоки личной страницы (profile-edit «sec-blocks») ─────────────
   Раскрываемая строка: [бренд-иконка] Название [chevron] · toggle показа · удалить.
   Тело с полями раскрывается под шапкой. Иконки — line-SVG (SITE_IC), без emoji. */
.pp-cblocks{ margin-top:4px; }
.pp-cblocks-empty{ margin:8px 0 2px; }
.pp-cblock{ border:1.5px solid var(--line2,#eceaf3); border-radius:14px; background:#fff; margin-bottom:10px; overflow:hidden; transition:border-color .15s; }
.pp-cblock.is-open{ border-color:var(--violet); }
.pp-cblock.is-off{ opacity:.6; }
.pp-cblock-head{ display:flex; align-items:center; gap:8px; padding:8px 10px; }
.pp-cblock-open{ flex:1 1 auto; min-width:0; display:flex; align-items:center; gap:10px; min-height:44px; padding:4px 6px; margin:0; background:none; border:0; border-radius:10px; cursor:pointer; text-align:left; font:inherit; color:var(--ink); }
.pp-cblock-open:hover{ background:rgba(124,92,255,.06); }
.pp-cblock-open:focus-visible{ outline:none; box-shadow:0 0 0 3px rgba(124,92,255,.32); }
.pp-cblock-ico{ width:36px; height:36px; flex:0 0 auto; display:inline-flex; align-items:center; justify-content:center; border-radius:10px; background:rgba(124,92,255,.10); color:var(--violet); }
.pp-cblock-ico svg{ width:19px; height:19px; }
.pp-cblock-name{ flex:1 1 auto; min-width:0; font:600 15px var(--font); color:var(--ink); }
.pp-cblock-chev{ flex:0 0 auto; display:inline-flex; color:var(--ink2); transition:transform .18s; }
.pp-cblock-chev svg{ width:18px; height:18px; }
.pp-cblock.is-open .pp-cblock-chev{ transform:rotate(180deg); }
.pp-cblock-body{ padding:2px 12px 12px; border-top:1.5px solid var(--line2,#eceaf3); }
.pp-cblock-body .pp-hint{ margin:10px 0 4px; }
.pp-cblocks-add-row{ display:flex; flex-wrap:wrap; gap:8px; }
.pp-chip-ico{ display:inline-flex; align-items:center; }
.pp-chip-ico svg{ width:15px; height:15px; }
@media (prefers-reduced-motion: reduce){
  .pp-cblock-chev, .pp-cblock{ transition:none; }
}

/* =====================================================
   CRM standalone /crm.html — добор Frontend B (crm.js): шапка-раскладка, drag&reorder
   канбана, toggle overflow-меню, опции фильтра задач, воронка-обёртка, контакты клиента,
   пустые состояния, плотная модалка сделки. Всё на токенах (ноль hex). Плотность = §16.
   ===================================================== */
/* Шапка: H1-блок слева + сводный чип справа (реюз .pp-crm-total) */
.pp-crm-head{ display:flex; align-items:flex-start; justify-content:space-between; gap:var(--sp-3); flex-wrap:wrap; }

/* Опции фильтра задач внутри .pp-crm-filter (details-popover) */
.pp-crm-filter-pop button{ display:flex; align-items:center; gap:8px; width:100%; border:0;
  background:none; cursor:pointer; text-align:left; padding:8px 10px; border-radius:var(--rad-sm);
  font:600 var(--fs-sm) var(--font); color:var(--ink); }
.pp-crm-filter-pop button:hover{ background:var(--bg2); }
.pp-crm-filter-pop button.is-active{ background:var(--violet-50); color:var(--violet); }

/* Overflow ⋯ меню: по умолчанию скрыто, раскрывается классом .is-open (тач-достижимо) */
.pp-row-more-menu{ display:none; }
.pp-row-more-menu.is-open{ display:flex; }
.pp-row-more-menu button svg{ flex:none; }

/* Drag & reorder канбана: grip-сигнификатор (desktop hover), ghost-клон, подсветка лейна */
.pp-deal-grip{ position:absolute; top:6px; right:8px; color:var(--line2); opacity:0;
  transition:opacity .12s ease; cursor:grab; line-height:0; }
.pp-deal:hover .pp-deal-grip, .pp-deal:focus-within .pp-deal-grip{ opacity:.85; }
/* Кнопка «→»: на hover-устройствах прячем до наведения/фокуса; на тач (hover:none) — ВСЕГДА видна (C2). */
@media (hover: hover){
  .pp-deal-next{ opacity:0; }
  .pp-deal:hover .pp-deal-next, .pp-deal:focus-within .pp-deal-next{ opacity:1; }
}
.pp-deal-dragging{ opacity:.35; }
.pp-deal-ghost{ position:fixed; z-index:60; margin:0; pointer-events:none; cursor:grabbing;
  box-shadow:0 18px 40px -12px rgba(20,20,40,.35); transform:rotate(1.5deg); }
.pp-lane.pp-lane-drop{ outline:2px dashed var(--violet); outline-offset:-2px; }
.pp-lane.pp-lane-drop > .pp-lane-body{ background:var(--violet-50); border-radius:12px; }
body.pp-dnd{ cursor:grabbing; user-select:none; }

/* Воронка дашборда — обёртка + заголовок секции */
.pp-funnel-wrap{ margin-top:var(--sp-4); }
.pp-funnel-title{ font:700 var(--fs-sm) var(--font-display, var(--font)); color:var(--ink); margin:0 0 var(--sp-3); }
.pp-task-deal{ display:inline-flex; align-items:center; gap:2px; }

/* Структурные контакты клиента — мелкие line-иконки + значение */
.pp-client-contacts{ display:inline-flex; align-items:center; gap:10px; min-width:0; overflow:hidden; }
.pp-client-c{ display:inline-flex; align-items:center; gap:3px; color:var(--ink2);
  font:500 var(--fs-xs) var(--font); white-space:nowrap; }
.pp-client-c svg{ flex:none; opacity:.75; }

/* Пустые состояния: иконка + CTA-кнопка */
.pp-empty-ico{ color:var(--violet); display:flex; justify-content:center; margin-bottom:var(--sp-2); }
.pp-empty-ico svg{ width:26px; height:26px; }
.pp-empty-cta{ margin-top:var(--sp-3); }

/* Плотная модалка сделки (§16 D0): фикс-шапка/футер, скролл только тело, ≤88vh */
.pp-deal-modal{ display:flex; flex-direction:column; max-height:88vh; }
.pp-deal-modal .pp-modal-body{ flex:1 1 auto; overflow:auto; }
.pp-deal-modal .pp-modal-head,
.pp-deal-modal .pp-modal-foot{ flex:0 0 auto; }

@media (prefers-reduced-motion: reduce){
  .pp-deal-grip{ transition:none; }
  .pp-deal-ghost{ transform:none; }
}

/* =====================================================
   CRM v1 — редактируемые Заметки (crm_notes) + редактор структурных контактов.
   Плотность = эталон DENSITY.md: строки ~40px (как .pp-input), заметка компактной
   карточкой, add — тихий текст-контрол. Всё на токенах (var(--*)), ноль хардкод-hex.
   ===================================================== */

/* ── Заметки (crm_notes): секция + список + inline-правка ── */
.pp-notes{ border-top:1px solid var(--line2); margin-top:var(--sp-2); padding-top:var(--sp-3); }
.pp-notes-head{ display:flex; align-items:center; justify-content:space-between; margin-bottom:var(--sp-2); }
.pp-notes-lbl{ font:800 12px var(--font-display, var(--font)); color:var(--ink); }
.pp-notes-list{ list-style:none; margin:0 0 var(--sp-2); padding:0; display:flex; flex-direction:column; gap:var(--sp-2); }
.pp-note{ background:var(--bg2); border-radius:var(--rad-md); padding:8px 10px; }
.pp-note.is-editing{ background:var(--violet-50); }
.pp-note-text{ font:500 13px var(--font); color:var(--ink); white-space:pre-wrap; overflow-wrap:anywhere; }
.pp-note-foot{ display:flex; align-items:center; gap:4px; margin-top:4px; }
.pp-note-time{ font:500 11px var(--font); color:var(--ink2); font-variant-numeric:tabular-nums; }
.pp-note-act{ position:relative; width:28px; height:28px; border:0; background:none; border-radius:var(--rad-sm);
  color:var(--ink2); cursor:pointer; display:inline-grid; place-items:center; flex:none; }
.pp-note-act::before{ content:""; position:absolute; inset:-8px; }   /* тач-таргет 44×44 без роста карточки */
.pp-note-act:first-of-type{ margin-left:auto; }
.pp-note-act:hover{ background:var(--card); color:var(--ink); }
.pp-note-act.is-danger:hover{ color:var(--err); background:var(--rose-50); }
.pp-note-act:focus-visible{ outline:2px solid var(--violet); outline-offset:2px; }
.pp-note-editrow{ display:flex; justify-content:flex-end; gap:var(--sp-2); margin-top:var(--sp-2); }
.pp-note-muted{ font:500 13px var(--font); color:var(--ink2); padding:2px 0; }
.pp-note-err{ color:var(--err); }                                   /* ошибка загрузки заметок — отличима от нейтрального «пусто» */
.pp-note-retry{ border:0; background:none; color:var(--violet); cursor:pointer; font:700 13px var(--font); padding:0; }
.pp-note-retry:hover{ color:var(--violet-700); }
.pp-notes-add{ display:flex; gap:var(--sp-2); align-items:flex-start; }
.pp-notes-ta{ flex:1 1 auto; min-height:40px; }
.pp-notes-addbtn{ flex:none; }

/* ── Редактор структурных контактов клиента (type · value · label · удалить) ── */
.pp-contacts{ display:flex; flex-direction:column; gap:var(--sp-2); }
.pp-contact-row{ display:flex; gap:var(--sp-2); align-items:center; flex-wrap:wrap; }
.pp-contact-type{ flex:0 0 118px; }
.pp-contact-val{ flex:2 1 150px; min-width:0; }
.pp-contact-label{ flex:1 1 88px; min-width:0; }
.pp-contact-del{ position:relative; flex:none; width:38px; height:38px; border:0; background:var(--bg2); color:var(--ink2);
  border-radius:var(--rad-sm); cursor:pointer; display:inline-grid; place-items:center; }
.pp-contact-del::before{ content:""; position:absolute; inset:-3px; }   /* тач-таргет 44×44 */
.pp-contact-del:hover{ color:var(--err); background:var(--rose-50); }
.pp-contact-del:focus-visible{ outline:2px solid var(--violet); outline-offset:2px; }
.pp-contacts-add{ align-self:flex-start; margin-top:6px; display:inline-flex; align-items:center; gap:4px;
  border:0; background:none; color:var(--violet); cursor:pointer; font:700 13px var(--font);
  padding:4px 2px; border-radius:var(--rad-sm); }
.pp-contacts-add:hover{ color:var(--violet-700); }
.pp-contacts-add:focus-visible{ outline:2px solid var(--violet); outline-offset:2px; }
@media(max-width:480px){
  .pp-contact-type{ flex:0 0 104px; }
  .pp-contact-label{ flex:1 1 100%; }
}

/* ============================================================================
   CRM МЕТАДВИЖОК — Волна 1. Аддитивно к pp-crm/pp-board/pp-deal выше.
   Имена классов = РОВНО то, что эмитит src/crm.js (объект-рейл · view-bar ·
   дата-грид · inline field-editor · рендер ячеек · тип/иконка-пикер · опции).
   Иконки = .bs-ico (currentColor, инлайн w/h). 0 hex — всё var(--*).
   Плотность = эталон кабинета/@handle (D0): рейл-строка 32 · view-bar 48 ·
   сегмент 32 · хедер 38 · строка 40 · ячейка pad 0/12 · editor 28 · тип-плитка 52.
   ============================================================================ */

/* ── Оболочка CRM: рейл (208) слева + основная колонка (pp-crm-shell/pp-crm-main) ── */
.pp-crm-shell{ display:flex; gap:var(--sp-4); align-items:flex-start; min-height:0; }
.pp-crm-main{ flex:1 1 auto; min-width:0; }

/* ── Левый рейл объектов: секции Стандартные/Мои + строки-объекты 32px ── */
.pp-objrail{ flex:0 0 208px; width:208px; align-self:stretch; display:flex; flex-direction:column;
  gap:var(--sp-1); min-height:0; }
.pp-objrail-sec{ display:flex; flex-direction:column; gap:2px; }
.pp-objrail-title{ font:700 var(--fs-xs) var(--font); color:var(--ink2); text-transform:uppercase;
  letter-spacing:.04em; padding:var(--sp-3) var(--sp-2) var(--sp-1); }
.pp-objrail-sec:first-child .pp-objrail-title{ padding-top:var(--sp-1); }
.pp-obj-row{ position:relative; display:flex; align-items:center; gap:var(--sp-2); height:32px;
  padding:0 var(--sp-2); width:100%; border:0; background:none; cursor:pointer; text-align:left;
  border-radius:var(--rad-sm); color:var(--ink); }
.pp-obj-row:hover{ background:var(--bg2); }
.pp-obj-row:focus-visible{ outline:2px solid var(--violet); outline-offset:-2px; }
.pp-obj-ico{ flex:none; display:inline-flex; align-items:center; justify-content:center;
  width:18px; height:18px; color:var(--ink2); }
.pp-obj-lbl{ flex:1 1 auto; min-width:0; font:600 var(--fs-sm) var(--font);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.pp-obj-count{ flex:none; font:700 var(--fs-xs) var(--font); color:var(--ink2);
  font-variant-numeric:tabular-nums; }
.pp-obj-row[aria-current=true],.pp-obj-row.is-active{ background:var(--violet-50);
  color:var(--violet-700); box-shadow:inset 2px 0 0 var(--violet); }
.pp-obj-row[aria-current=true] .pp-obj-ico,.pp-obj-row.is-active .pp-obj-ico,
.pp-obj-row[aria-current=true] .pp-obj-count,.pp-obj-row.is-active .pp-obj-count{ color:var(--violet-700); }
.pp-obj-muted{ padding:var(--sp-1) var(--sp-2); font:500 var(--fs-xs) var(--font); color:var(--ink2); }
.pp-objrail-foot{ margin-top:auto; padding-top:var(--sp-2); border-top:1px solid var(--line);
  display:flex; align-items:center; gap:var(--sp-1); }
.pp-objrail-foot > .pp-btn{ flex:1 1 auto; }
.pp-objrail-cog{ flex:0 0 auto; }

/* ── «Ещё» — прогрессивное раскрытие: заметки + метадвижок (свои таблицы, +таблица, поля-стадии)
   спрятаны за summary (§1.8). Плоский верх рейла остаётся чистым: Заказы·Клиенты·Задачи·Дашборд. ── */
.pp-rail-more{ margin-top:var(--sp-1); }
.pp-rail-more > summary{ list-style:none; cursor:pointer; display:flex; align-items:center;
  gap:var(--sp-2); height:32px; padding:0 var(--sp-2); border-radius:var(--rad-sm);
  color:var(--ink2); font:600 var(--fs-sm) var(--font); }
.pp-rail-more > summary::-webkit-details-marker{ display:none; }
.pp-rail-more > summary:hover{ background:var(--bg2); color:var(--ink); }
.pp-rail-more > summary:focus-visible{ outline:2px solid var(--violet); outline-offset:-2px; }
.pp-rail-more-lbl{ flex:1 1 auto; }
.pp-rail-more-chev{ flex:none; display:inline-flex; color:var(--ink2); transition:transform .2s; }
.pp-rail-more[open] > summary .pp-rail-more-chev{ transform:rotate(180deg); }
.pp-rail-more-body{ display:flex; flex-direction:column; gap:2px; padding-top:2px; }
.pp-rail-more-body .pp-objrail-title{ padding:var(--sp-2) var(--sp-2) var(--sp-1); }
.pp-rail-more-body .pp-objrail-foot{ margin-top:var(--sp-2); }
@media(prefers-reduced-motion:reduce){ .pp-rail-more-chev{ transition:none; } }

/* ── P1: мобильный переключатель объектов (<768, десктоп-рейл скрыт) ──
   trigger «текущий объект ▾» (44 тач-таргет) + bottom-sheet со списком рейла (railBodyHTML).
   Базово display:none → включается в @media(max-width:768px) ниже. Десктоп-рейл не трогаем. */
.pp-objswitch{ display:none; }
.pp-objswitch:hover{ border-color:var(--violet-200); }
.pp-objswitch:focus-visible{ outline:2px solid var(--violet); outline-offset:2px; }
.pp-objswitch-ico{ flex:none; display:inline-flex; align-items:center; justify-content:center;
  width:18px; height:18px; color:var(--violet-700); }
.pp-objswitch-lbl{ flex:1 1 auto; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
  font:700 var(--fs-sm) var(--font); }
.pp-objswitch-cnt{ flex:none; font:700 var(--fs-xs) var(--font); color:var(--ink2); font-variant-numeric:tabular-nums; }
.pp-objswitch-chev{ flex:none; display:inline-flex; color:var(--ink2); }
/* Bottom-sheet (в body, как pp-recpanel-scrim; слайд снизу, reduced-motion уважает @media) */
.pp-objsheet-scrim{ position:fixed; inset:0; z-index:130; display:flex; align-items:flex-end; justify-content:center;
  background:rgba(20,12,40,.35); opacity:0; transition:opacity .2s ease; }
.pp-objsheet-scrim.is-open{ opacity:1; }
.pp-objsheet{ width:100%; max-width:520px; max-height:80vh; background:var(--card);
  border-radius:var(--rad-lg) var(--rad-lg) 0 0; display:flex; flex-direction:column;
  box-shadow:var(--shadow-lg); transform:translateY(100%); transition:transform .22s ease; }
.pp-objsheet-scrim.is-open .pp-objsheet{ transform:none; }
.pp-objsheet-head{ flex:0 0 auto; display:flex; align-items:center; justify-content:space-between;
  gap:var(--sp-2); padding:var(--sp-3) var(--sp-4); border-bottom:1px solid var(--line2); }
.pp-objsheet-title{ font:800 var(--fs-md) var(--font-display); color:var(--ink); }
.pp-objsheet-body{ flex:1 1 auto; min-height:0; overflow:auto;
  padding:var(--sp-2) var(--sp-3) calc(var(--sp-3) + env(safe-area-inset-bottom,0px));
  display:flex; flex-direction:column; gap:var(--sp-1); }
/* Тач-таргеты в шторке ≥44 (мобайл); строки десктоп-рейла остаются 32 (мышь) */
.pp-objsheet .pp-obj-row{ height:44px; }
.pp-objsheet .pp-rail-more > summary{ height:44px; }
.pp-objsheet .pp-objrail-foot{ padding-top:var(--sp-3); }
.pp-objsheet .pp-objrail-foot .pp-btn{ min-height:44px; }
.pp-objsheet .pp-objrail-cog{ min-width:44px; }
@media(prefers-reduced-motion:reduce){ .pp-objsheet-scrim,.pp-objsheet{ transition:none; } }

/* ── View-bar (48px sticky): сегмент Таблица|Канбан(влево) · поиск · правый кластер · primary ── */
.pp-viewbar{ position:sticky; top:0; z-index:20; display:flex; align-items:center; gap:var(--sp-2);
  height:48px; background:var(--bg); border-bottom:1px solid var(--line); padding:0 var(--sp-1);
  margin-bottom:var(--sp-3); }
.pp-viewseg{ flex:none; display:inline-flex; align-items:center; gap:2px; height:32px; padding:3px;
  background:var(--bg2); border-radius:var(--rad-sm); }
.pp-viewseg button{ display:inline-flex; align-items:center; gap:6px; height:26px; padding:0 10px;
  border:0; background:none; cursor:pointer; border-radius:var(--rad-xs); color:var(--ink2);
  font:600 var(--fs-sm) var(--font); }
.pp-viewseg button .bs-ico{ flex:none; }
.pp-viewseg button:hover{ color:var(--ink); }
.pp-viewseg button[aria-pressed=true],.pp-viewseg button.is-active{ background:var(--card);
  color:var(--violet-700); box-shadow:var(--shadow); }
.pp-viewseg button:focus-visible{ outline:2px solid var(--violet); outline-offset:2px; }
.pp-viewseg button:disabled{ opacity:.45; cursor:not-allowed; }
.pp-viewbar-search{ flex:0 1 240px; min-width:0; max-width:240px; }
.pp-viewbar-search .pp-input{ height:34px; padding:0 var(--sp-3); font:500 var(--fs-sm) var(--font); }
@media(min-width:769px){ .pp-viewbar-search{ flex-basis:200px; } }
.pp-viewbar-right{ display:flex; align-items:center; gap:var(--sp-1); flex:none; margin-left:auto; }

/* ── Дата-грид (pp-table*): обёртка scroll-x · thead В ПОТОКЕ (НЕ sticky) · хедер 38 · строка 40 · ячейка ──
   Хедер НЕ sticky: у таблицы нет bounded-scroll-контейнера (record-region .pp-obj-records = overflow:visible,
   position:static — нет скролл-порта), а sticky+border-collapse без реального скролл-порта в Chrome наезжал
   на 1-ю строку и рисовал пустую полосу над хедером. Короткой generic-CRM-таблице frozen-хедер не нужен;
   страница скроллится целиком (одна полоса прокрутки — плотность D0, как кабинет). thead сидит в нормальном
   потоке НАД tbody → 0 наложения, 0 фантомной полосы. Весь вид хедера держит .pp-th ниже. */
.pp-table-wrap{ border:1px solid var(--line2); border-radius:var(--rad-lg); overflow-x:auto;
  background:var(--card); }
.pp-table{ width:100%; border-collapse:collapse; font:500 var(--fs-sm) var(--font); }
.pp-th{ height:38px; background:var(--gray-50); color:var(--ink2); text-align:left;
  font:700 var(--fs-xs) var(--font); padding:0 var(--sp-3); white-space:nowrap; cursor:pointer;
  user-select:none; border-bottom:1px solid var(--line2); }
.pp-th:focus-visible{ outline:2px solid var(--violet); outline-offset:-2px; }
.pp-th[aria-sort=ascending],.pp-th[aria-sort=descending]{ color:var(--violet-700); }
.pp-th.is-num{ text-align:right; }
.pp-th-caret{ display:inline-flex; align-items:center; margin-left:4px; vertical-align:-2px; opacity:.8; }
.pp-th-more{ width:44px; cursor:default; }
.pp-tr{ height:40px; border-bottom:1px solid var(--line); }
.pp-tr:last-child{ border-bottom:0; }
.pp-tr:hover{ background:var(--gray-50); }
.pp-td{ padding:0 var(--sp-3); max-width:0; font:500 var(--fs-sm) var(--font); color:var(--ink);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.pp-td.is-num{ text-align:right; font-variant-numeric:tabular-nums; }
.pp-td.is-editing{ overflow:visible; padding:0 var(--sp-1); }
.pp-td-more{ width:44px; padding:0; text-align:center; overflow:visible; }

/* ── Рендер ячеек (renderCell): тире-empty · bool · ссылки · rel · txt · badge · kanban-meta ── */
.pp-cell-empty{ color:var(--ink2); }                                /* тире, не 0 */
.pp-cell-bool{ display:inline-flex; align-items:center; color:var(--ok); }
.pp-cell-link{ color:var(--violet-700); text-decoration:none; }
.pp-cell-link:hover{ text-decoration:underline; }
.pp-cell-link .bs-ico{ margin-left:3px; opacity:.65; vertical-align:-1px; }
.pp-cell-rel{ color:var(--ink); }
.pp-cell-txt{ color:var(--ink); }
.pp-cell-primary{ display:inline-block; max-width:100%; border:0; background:none; padding:0; margin:0;
  cursor:pointer; font:600 var(--fs-sm) var(--font); color:var(--violet-700); text-align:left;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.pp-cell-primary:hover{ text-decoration:underline; }
.pp-cell-primary:focus-visible{ outline:2px solid var(--violet); outline-offset:2px; border-radius:var(--rad-xs); }
.pp-badges{ display:inline-flex; flex-wrap:wrap; gap:4px; align-items:center; max-width:100%; }
.pp-badge{ display:inline-flex; align-items:center; height:20px; padding:0 8px; border-radius:999px;
  background:var(--chip,var(--violet-50)); color:var(--violet-700); font:600 var(--fs-xs) var(--font);
  white-space:nowrap; max-width:100%; overflow:hidden; text-overflow:ellipsis; }
.pp-rec-field{ display:inline-block; max-width:100%; font:500 var(--fs-xs) var(--font); color:var(--ink2);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }

/* ── Inline field-editor: обёртка pp-cell-edit + элемент pp-fe (28px, violet «редактирую») ── */
.pp-cell-edit{ display:flex; align-items:center; width:100%; }
.pp-cell-edit .pp-fe{ height:28px; padding:0 8px; font:500 var(--fs-sm) var(--font);
  border-color:var(--violet); box-shadow:0 0 0 3px var(--accent-soft); }
.pp-cell-edit textarea.pp-fe{ height:auto; min-height:56px; padding:6px 8px; line-height:1.4; }
.pp-fe-mono{ font-family:ui-monospace,SFMono-Regular,Menlo,monospace; }
.pp-fe-multi{ display:flex; flex-wrap:wrap; gap:var(--sp-2) var(--sp-3); padding:6px 2px; }
.pp-fe-multi .pp-check{ margin:0; }

/* ── Тип-пикер поля (pp-fieldtype-tile): плитки ~64×52, 5-в-ряд, иконка 20 + лейбл 12 ── */
.pp-fieldtype-grid{ display:grid; grid-template-columns:repeat(5,1fr); gap:var(--sp-2); }
.pp-fieldtype-tile{ display:flex; flex-direction:column; align-items:center; justify-content:center;
  gap:4px; height:52px; padding:var(--sp-1); border:1.5px solid var(--line2); border-radius:var(--rad-md);
  background:var(--card); cursor:pointer; color:var(--ink2); }
.pp-fieldtype-tile .bs-ico{ flex:none; width:20px; height:20px; }
.pp-fieldtype-tile span{ max-width:100%; font:600 var(--fs-xs)/1 var(--font); color:var(--ink2);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.pp-fieldtype-tile:hover{ border-color:var(--violet-200); color:var(--ink); }
.pp-fieldtype-tile:hover span{ color:var(--ink); }
.pp-fieldtype-tile[aria-pressed=true],.pp-fieldtype-tile.is-active{ border-color:var(--violet);
  background:var(--violet-50); color:var(--violet-700); }
.pp-fieldtype-tile[aria-pressed=true] span,.pp-fieldtype-tile.is-active span{ color:var(--violet-700); }
.pp-fieldtype-tile:focus-visible{ outline:2px solid var(--violet); outline-offset:2px; }

/* ── Иконка-пикер объекта (pp-ico-grid/tile): 8-в-ряд, тайл 36px ── */
.pp-ico-grid{ display:grid; grid-template-columns:repeat(8,1fr); gap:var(--sp-1); }
.pp-ico-tile{ display:inline-flex; align-items:center; justify-content:center; height:36px;
  border:1.5px solid var(--line2); border-radius:var(--rad-sm); background:var(--card);
  cursor:pointer; color:var(--ink2); }
.pp-ico-tile:hover{ border-color:var(--violet-200); color:var(--ink); }
.pp-ico-tile.is-active{ border-color:var(--violet); background:var(--violet-50); color:var(--violet-700); }
.pp-ico-tile:focus-visible{ outline:2px solid var(--violet); outline-offset:2px; }

/* ── Редактор опций select/multiselect (pp-opts): строка swatch + input + удалить ── */
.pp-opts{ display:flex; flex-direction:column; gap:var(--sp-2); }
.pp-opt-row{ display:flex; align-items:center; gap:var(--sp-2); }
.pp-opt-row > .pp-input{ flex:1 1 auto; min-width:0; }
.pp-opt-swatch{ flex:none; width:14px; height:14px; border-radius:50%;
  background:var(--sw,transparent); border:1px solid var(--line2); }

/* ── Респонсив <768: рейл скрыт, шелл в колонку, thead скрыт (таблица → карточки в JS) ── */
@media(max-width:768px){
  .pp-crm-shell{ display:block; }
  .pp-objrail{ display:none; }
  .pp-objswitch{ display:flex; align-items:center; gap:var(--sp-2); width:100%; height:44px;
    padding:0 var(--sp-3); margin-bottom:var(--sp-3); border:1.5px solid var(--line2);
    background:var(--card); border-radius:var(--rad-sm); cursor:pointer; color:var(--ink); text-align:left; }
  .pp-viewbar{ height:auto; flex-wrap:wrap; padding:var(--sp-2) var(--sp-1); }
  .pp-viewbar-search{ order:3; flex-basis:100%; max-width:none; }
  .pp-viewbar-right{ order:2; margin-left:auto; }
  .pp-table thead{ display:none; }
  .pp-fieldtype-grid{ grid-template-columns:repeat(4,1fr); }
  .pp-ico-grid{ grid-template-columns:repeat(6,1fr); }
}

/* ============================================================================
   CRM МЕТАДВИЖОК — Волна 2A. Аддитивно к блоку Волны-1 выше.
   Имена классов = РОВНО то, что эмитит src/crm.js:
   виды-табы (pp-viewtabs) · чипы фильтра (pp-filterbar) · поповеры фильтр/колонки
   (pp-pop) · триггеры (pp-ctlbtn) · панель записи-шторка (pp-recpanel).
   Меню вида реюзит pp-row-more; «Сбросить» реюзит pp-crm-filter-reset; X панели —
   pp-modal-x; inline-редактор поля — pp-cell-edit/pp-fe. 0 hex — всё var(--*).
   Плотность D0: таб 34 · ctlbtn 32 · чип 26 · поповер-инпут 32 · панель 400 · поле 30.
   ============================================================================ */

/* ── D) Сохранённые виды (pp-viewtabs): tablist с подчёркиванием активного ── */
.pp-viewtabs{ display:flex; align-items:stretch; flex-wrap:wrap; gap:2px;
  margin:0 0 var(--sp-3); border-bottom:1px solid var(--line); }
.pp-viewtab-wrap{ position:relative; display:inline-flex; align-items:center; }
.pp-viewtab{ display:inline-flex; align-items:center; height:34px; padding:0 10px; border:0;
  background:none; cursor:pointer; color:var(--ink2); font:600 var(--fs-sm) var(--font);
  border-bottom:2px solid transparent; margin-bottom:-1px; white-space:nowrap; }
.pp-viewtab:hover{ color:var(--ink); }
.pp-viewtab[aria-selected=true],.pp-viewtab.is-active{ color:var(--violet-700); border-bottom-color:var(--violet); }
.pp-viewtab:focus-visible{ outline:2px solid var(--violet); outline-offset:-2px; border-radius:var(--rad-xs); }
.pp-viewtab-wrap .pp-row-more{ margin-left:-6px; }
.pp-viewtab-wrap .pp-row-more-btn{ width:26px; height:26px; }
.pp-viewtab-add{ display:inline-flex; align-items:center; gap:4px; height:34px; padding:0 10px; border:0;
  background:none; cursor:pointer; color:var(--violet-700); font:600 var(--fs-sm) var(--font); white-space:nowrap; }
.pp-viewtab-add .bs-ico{ flex:none; }
.pp-viewtab-add:hover{ text-decoration:underline; }
.pp-viewtab-add:focus-visible{ outline:2px solid var(--violet); outline-offset:2px; border-radius:var(--rad-xs); }

/* ── Компактные control-триггеры (Фильтр · Колонки): 32px outline-кнопка + счётчик ── */
.pp-pop-ctl{ position:relative; flex:none; }
.pp-ctlbtn{ display:inline-flex; align-items:center; gap:6px; height:32px; padding:0 10px;
  border:1.5px solid var(--line2); background:var(--card); border-radius:var(--rad-sm); cursor:pointer;
  color:var(--ink2); font:600 var(--fs-sm) var(--font); white-space:nowrap; }
.pp-ctlbtn .bs-ico{ flex:none; }
.pp-ctlbtn:hover{ border-color:var(--violet-200); color:var(--ink); }
.pp-ctlbtn.is-active{ border-color:var(--violet); color:var(--violet-700); background:var(--violet-50); }
.pp-ctlbtn:focus-visible{ outline:2px solid var(--violet); outline-offset:2px; }
.pp-ctlbtn:disabled{ opacity:.45; cursor:not-allowed; }
.pp-ctlbtn:disabled:hover{ border-color:var(--line2); color:var(--ink2); }
.pp-ctlbtn-n{ display:inline-flex; align-items:center; justify-content:center; min-width:16px; height:16px;
  padding:0 4px; border-radius:var(--rad-pill); background:var(--violet); color:var(--card);
  font:700 10px var(--font); font-variant-numeric:tabular-nums; }

/* ── Общий поповер (pp-pop): якорь справа под триггером, компактная карточка ── */
.pp-pop{ position:absolute; right:0; top:calc(100% + 6px); z-index:40; width:288px;
  max-width:calc(100vw - 2*var(--sp-4)); background:var(--card); border:1px solid var(--line2);
  border-radius:var(--rad-md); box-shadow:var(--shadow-lg); padding:var(--sp-3);
  display:none; flex-direction:column; gap:var(--sp-2); }
.pp-pop.is-open{ display:flex; }
.pp-pop-head{ font:700 var(--fs-xs) var(--font); color:var(--ink2); text-transform:uppercase; letter-spacing:.04em; }
.pp-pop-empty{ font:500 var(--fs-xs) var(--font); color:var(--ink2); padding:var(--sp-1) 2px; }
.pp-pop-foot{ display:flex; align-items:center; justify-content:space-between; gap:var(--sp-2);
  padding-top:var(--sp-2); border-top:1px solid var(--line); }
.pp-pop .pp-input,.pp-pop select.pp-input{ height:32px; padding:0 var(--sp-2); font:500 var(--fs-sm) var(--font); margin:0; }
.pp-pop .pp-btn-sm{ min-height:32px; }

/* ── C) Конструктор условий фильтра (pp-fcond) ── */
.pp-fcond{ display:flex; flex-wrap:wrap; align-items:center; gap:var(--sp-2); padding:var(--sp-2);
  border:1px solid var(--line); border-radius:var(--rad-sm); background:var(--gray-50); }
.pp-fcond [data-fcond-field]{ flex:1 1 100%; min-width:0; }
.pp-fcond [data-fcond-cmp]{ flex:1 1 44%; min-width:0; }
.pp-fcond [data-fcond-val]{ flex:1 1 44%; min-width:0; }
.pp-fcond-novalue{ flex:1 1 44%; color:var(--ink2); font:500 var(--fs-xs) var(--font); }
.pp-fcond-add{ display:inline-flex; align-items:center; gap:6px; align-self:flex-start; border:0;
  background:none; cursor:pointer; color:var(--violet-700); font:600 var(--fs-sm) var(--font); padding:2px; }
.pp-fcond-add .bs-ico{ flex:none; }
.pp-fcond-add:hover{ text-decoration:underline; }
.pp-fchip-x{ display:inline-flex; align-items:center; justify-content:center; width:24px; height:24px;
  flex:none; border:0; background:none; cursor:pointer; color:var(--ink2); border-radius:var(--rad-xs); }
.pp-fchip-x:hover{ background:var(--rose-50); color:var(--rose-700); }
.pp-fchip-x:focus-visible{ outline:2px solid var(--violet); outline-offset:1px; }

/* ── C) Полоса активных фильтров (pp-filterbar) — removable-чипы + сбросить ── */
.pp-filterbar{ display:flex; flex-wrap:wrap; align-items:center; gap:var(--sp-2); margin:0 0 var(--sp-3); }
.pp-fchip{ display:inline-flex; align-items:center; gap:2px; height:26px; padding:0 2px 0 10px;
  background:var(--violet-50); border:1px solid var(--violet-100); border-radius:var(--rad-pill);
  color:var(--violet-700); font:600 var(--fs-xs) var(--font); max-width:260px; }
.pp-fchip-t{ overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.pp-fchip .pp-fchip-x{ width:20px; height:20px; color:var(--violet-700); }
.pp-fchip .pp-fchip-x:hover{ background:var(--rose-100); color:var(--rose-700); }

/* ── B) Пикер колонок (pp-colpick): чекбокс видимости + порядок ↑/↓ ── */
.pp-colpick{ display:flex; flex-direction:column; gap:2px; max-height:280px; overflow:auto; }
.pp-colpick-row{ display:flex; align-items:center; gap:var(--sp-2); }
.pp-colpick-row .pp-check{ flex:1 1 auto; min-width:0; padding:var(--sp-1) 0; gap:var(--sp-2); }
.pp-colpick-row .pp-check span{ overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.pp-colpick-move{ display:inline-flex; gap:2px; flex:none; }
.pp-colpick-move button{ display:inline-flex; align-items:center; justify-content:center; width:24px; height:24px;
  border:0; background:none; cursor:pointer; color:var(--ink2); border-radius:var(--rad-xs); }
.pp-colpick-move button:hover:not(:disabled){ background:var(--bg2); color:var(--ink); }
.pp-colpick-move button:disabled{ opacity:.3; cursor:default; }
.pp-colpick-move button:focus-visible{ outline:2px solid var(--violet); outline-offset:1px; }
.pp-colpick-move button[data-col-up] .bs-ico{ transform:rotate(180deg); }

/* ── Курсор строки/ячейки (клик по строке → панель; по editable → инлайн-правка) ── */
[data-obj-records] .pp-tr{ cursor:pointer; }
[data-obj-records] .pp-td[data-editable]{ cursor:text; }

/* ── A) Панель записи (pp-recpanel): правая шторка-шит, компактная ── */
.pp-recpanel-scrim{ position:fixed; inset:0; z-index:130; display:flex; justify-content:flex-end;
  background:rgba(20,12,40,.35); opacity:0; transition:opacity .2s ease; }
.pp-recpanel-scrim.is-open{ opacity:1; }
.pp-recpanel{ width:min(400px,100vw); max-width:100%; height:100%; background:var(--card);
  display:flex; flex-direction:column; box-shadow:var(--shadow-lg);
  transform:translateX(100%); transition:transform .2s ease; }
.pp-recpanel-scrim.is-open .pp-recpanel{ transform:none; }
.pp-recpanel-head{ flex:0 0 auto; display:flex; align-items:flex-start; gap:var(--sp-2);
  padding:var(--sp-3) var(--sp-4); border-bottom:1px solid var(--line2); }
.pp-recpanel-htext{ flex:1 1 auto; min-width:0; }
.pp-recpanel-obj{ font:700 var(--fs-xs) var(--font); color:var(--ink2); text-transform:uppercase; letter-spacing:.04em; }
.pp-recpanel-title{ margin-top:2px; font:800 var(--fs-md) var(--font-display); color:var(--ink);
  line-height:1.2; overflow-wrap:anywhere; }
.pp-recpanel-body{ flex:1 1 auto; overflow:auto; padding:var(--sp-1) var(--sp-2); }
.pp-recpanel-field{ display:grid; grid-template-columns:120px 1fr; gap:var(--sp-2); align-items:start;
  padding:6px var(--sp-2); border-radius:var(--rad-sm); }
.pp-recpanel-lbl{ padding-top:5px; font:600 var(--fs-xs) var(--font); color:var(--ink2);
  overflow-wrap:anywhere; }
.pp-recpanel-val{ min-height:30px; padding:5px var(--sp-2); border-radius:var(--rad-xs);
  font:500 var(--fs-sm) var(--font); color:var(--ink); cursor:pointer; overflow-wrap:anywhere; }
.pp-recpanel-val:hover{ background:var(--bg2); }
.pp-recpanel-val:focus-visible{ outline:2px solid var(--violet); outline-offset:1px; }
.pp-recpanel-val.is-readonly{ cursor:default; color:var(--ink2); }
.pp-recpanel-val.is-readonly:hover{ background:none; }
.pp-recpanel-val.is-editing{ padding:0; }
.pp-recpanel-val .pp-cell-edit .pp-fe{ height:32px; }
.pp-recpanel-val .pp-cell-edit textarea.pp-fe{ height:auto; }
.pp-recpanel-actions{ flex:0 0 auto; display:flex; align-items:center; justify-content:space-between;
  gap:var(--sp-2); padding:var(--sp-3) var(--sp-4); border-top:1px solid var(--line2); }

@media(prefers-reduced-motion:reduce){
  .pp-recpanel-scrim,.pp-recpanel{ transition:none; }
}
@media(max-width:768px){
  .pp-recpanel{ width:100vw; }
  .pp-recpanel-field{ grid-template-columns:100px 1fr; }
  .pp-pop{ width:min(288px,calc(100vw - 2*var(--sp-4))); }
}

/* ============================================================================
   CRM МЕТАДВИЖОК — Slice C: вид «Календарь». Аддитивно к Волне 2A.
   Имена классов = РОВНО то, что эмитит src/crm.js (recordsCalendarHTML/calGridHTML/
   calAgendaHTML/calNavHTML). Чипы записи → data-rec-open (та же панель). 0 hex — var(--*).
   Плотность D0: nav 32 · клетка мин-высота 88 · чип 18 · агенда-строка 44 (тач-таргет).
   Reduced-motion: собственных анимаций нет (ховер — только цвет). Календарь ≠ пол-экрана —
   компактная месячная сетка, как таблица/канбан этого же вида. ============================ */
.pp-cal{ display:flex; flex-direction:column; gap:var(--sp-3); }

/* ── Навигация ← месяц → + «Сегодня» + скоуп-подпись справа ── */
.pp-cal-nav{ display:flex; align-items:center; gap:var(--sp-2); flex-wrap:wrap; }
.pp-cal-navseg{ display:inline-flex; align-items:center; gap:2px; }
.pp-cal-navbtn{ display:inline-flex; align-items:center; justify-content:center; width:32px; height:32px;
  border:1.5px solid var(--line2); background:var(--card); border-radius:var(--rad-sm); cursor:pointer; color:var(--ink2); }
.pp-cal-navbtn:hover{ border-color:var(--violet-200); color:var(--ink); }
.pp-cal-navbtn:focus-visible{ outline:2px solid var(--violet); outline-offset:2px; }
.pp-cal-month{ min-width:150px; text-align:center; font:800 var(--fs-md) var(--font-display);
  color:var(--ink); letter-spacing:-.01em; }
.pp-cal-today{ height:32px; padding:0 12px; border:1.5px solid var(--line2); background:var(--card);
  border-radius:var(--rad-sm); cursor:pointer; color:var(--violet-700); font:600 var(--fs-sm) var(--font); }
.pp-cal-today:hover{ border-color:var(--violet-200); }
.pp-cal-today:focus-visible{ outline:2px solid var(--violet); outline-offset:2px; }
.pp-cal-by{ display:inline-flex; align-items:center; gap:5px; margin-left:auto;
  font:500 var(--fs-xs) var(--font); color:var(--ink2); }
.pp-cal-by .bs-ico{ flex:none; opacity:.75; }

/* ── Месячная сетка: 7 колонок, gap 1px рисует линии (cell=card поверх line2-фона) ── */
.pp-cal-grid{ display:block; }
.pp-cal-dowrow{ display:grid; grid-template-columns:repeat(7,minmax(0,1fr)); gap:1px; margin-bottom:4px; }
.pp-cal-dow{ text-align:center; padding:5px 0; font:700 var(--fs-xs) var(--font); color:var(--ink2);
  text-transform:uppercase; letter-spacing:.03em; }
.pp-cal-weeks{ display:grid; grid-template-columns:repeat(7,minmax(0,1fr)); gap:1px;
  background:var(--line2); border:1px solid var(--line2); border-radius:var(--rad-md); overflow:hidden; }
.pp-cal-cell{ background:var(--card); min-height:88px; padding:4px 5px 6px; display:flex;
  flex-direction:column; gap:3px; overflow:hidden; }
.pp-cal-cell.is-out{ background:var(--bg2); }
.pp-cal-cell.is-out .pp-cal-daynum{ color:var(--ink2); opacity:.55; }
.pp-cal-cell.is-today{ box-shadow:inset 0 0 0 2px var(--violet); }
.pp-cal-daynum{ font:700 var(--fs-xs) var(--font); color:var(--ink2); font-variant-numeric:tabular-nums; }
.pp-cal-cell.is-today .pp-cal-daynum{ color:var(--violet-700); }
.pp-cal-chips{ display:flex; flex-direction:column; gap:2px; min-width:0; }
.pp-cal-chip{ display:block; width:100%; text-align:left; border:0; cursor:pointer; height:18px;
  line-height:18px; padding:0 6px; border-radius:var(--rad-xs); background:var(--violet-50);
  color:var(--violet-700); font:600 var(--fs-xs) var(--font);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.pp-cal-chip:hover{ background:var(--violet-100); }
.pp-cal-chip:focus-visible{ outline:2px solid var(--violet); outline-offset:1px; }
.pp-cal-more{ font:600 var(--fs-xs) var(--font); color:var(--ink2); padding:0 4px; }

/* ── Подсказка (пустой месяц) — не голая сетка ── */
.pp-cal-hint{ display:flex; align-items:center; justify-content:center; gap:4px; padding:var(--sp-3) var(--sp-2);
  font:500 var(--fs-sm) var(--font); color:var(--ink2); text-align:center; }
.pp-cal-hint .bs-ico{ flex:none; vertical-align:middle; opacity:.7; }

/* ── Мобайл-агенда (<768): дни с записями списком, тач-таргет 44 ── */
.pp-cal-agenda{ display:flex; flex-direction:column; gap:2px; }
.pp-cal-agenda-day{ display:grid; grid-template-columns:44px 1fr; gap:var(--sp-2);
  padding:var(--sp-2) 2px; border-bottom:1px solid var(--line); }
.pp-cal-agenda-day:last-child{ border-bottom:0; }
.pp-cal-agenda-date{ display:flex; flex-direction:column; align-items:center; padding-top:3px; }
.pp-cal-agenda-dnum{ font:800 var(--fs-md) var(--font-display); color:var(--ink); line-height:1;
  font-variant-numeric:tabular-nums; }
.pp-cal-agenda-day.is-today .pp-cal-agenda-dnum{ color:var(--violet-700); }
.pp-cal-agenda-dow{ margin-top:2px; font:600 var(--fs-xs) var(--font); color:var(--ink2); text-transform:uppercase; }
.pp-cal-agenda-items{ display:flex; flex-direction:column; gap:4px; min-width:0; }
.pp-cal-agenda-item{ display:block; width:100%; text-align:left; border:1px solid var(--line);
  background:var(--card); border-radius:var(--rad-sm); cursor:pointer; min-height:44px; padding:9px 12px;
  font:600 var(--fs-sm) var(--font); color:var(--ink);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.pp-cal-agenda-item:hover{ background:var(--bg2); border-color:var(--violet-200); }
.pp-cal-agenda-item:focus-visible{ outline:2px solid var(--violet); outline-offset:1px; }

/* Узкий десктоп: чуть плотнее клетки + компактнее сегмент, чтобы view-bar не переносило */
@media(min-width:769px) and (max-width:960px){
  .pp-cal-cell{ min-height:76px; }
  .pp-viewseg button{ padding:0 8px; }
}
@media(max-width:768px){
  .pp-cal-month{ min-width:0; flex:1 1 auto; }
  .pp-cal-by{ flex-basis:100%; margin-left:0; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   ЛЮДИ (/people.html) — ранг топ-авторов и кнопка подписки.
   Разметка — src/people.js. pop.css грузится ПОСЛЕ community.css на этой
   странице, поэтому доводка базовых .cm-*-правил живёт здесь.
   Было: сырые эмодзи-медали наклейкой в углу карточки и fullwidth-плюс/галка в кнопке —
   нарушение канона «только бренд line-SVG». Стало: медаль-иконка + ЦИФРА
   места (цвет не единственный сигнал, §6 color-not-only) в углу карточки, под
   который зарезервирован паддинг — имя автора под бейдж не заезжает.
   ═══════════════════════════════════════════════════════════════════════════ */
.cm-person .cm-ic{ width:14px; height:14px; flex:none; }

/* ранг-бейдж: компактная пилюля 22px в верхнем-правом углу; не конкурирует
   с primary «Подписаться» (тихий вес, без тени и градиента) */
.cm-person.is-top{ padding-right:calc(1.1rem + 34px); }
.cm-rank{ position:absolute; top:10px; right:10px; z-index:2;
  display:inline-flex; align-items:center; gap:2px;
  height:22px; padding:0 7px 0 4px; border-radius:var(--pill,999px);
  border:1px solid transparent; font:800 12px/1 var(--font); font-variant-numeric:tabular-nums; }
.cm-rank .cm-ic{ width:15px; height:15px; }
/* три состояния одной медали: золото → серебро → бронза */
.cm-rank-1{ background:var(--amber-400); border-color:var(--amber-500); color:var(--gray-900); }
.cm-rank-2{ background:var(--gray-200); border-color:var(--gray-300); color:var(--gray-800); }
.cm-rank-3{ background:var(--amber-50);  border-color:var(--amber-300); color:var(--amber-800); }

/* кнопка подписки: иконка + подпись в один ряд, тач-таргет 32/44 без раздувания */
.cm-person .cm-follow-btn{ display:inline-flex; align-items:center; gap:6px;
  min-height:32px; padding:0 12px; }
@media(max-width:600px){ .cm-person .cm-follow-btn{ min-height:36px; } }

/* ── Быстрая реакция БЕЗ счётчика = КОНТРОЛ «нравится», а не данные ──────────
   Было: сырое эмодзи-сердце в кнопке (страница публикации /pub/{id}, лента, группы) —
   нарушение канона «в контролах только бренд line-SVG». Стало: line-сердце
   тем же currentColor (наследует coral на hover / violet в is-mine).
   ПИЛЮЛИ СО СЧЁТЧИКОМ трогать нельзя: там эмодзи — это ДАННЫЕ (какую именно
   реакцию поставили люди), их рисуем как есть. Правка ЧИСТО стилевая, поэтому
   работает и на SSR-скелете, и после гидрации reactions.js — байт-в-байт
   разметка постов сохранена, JS не трогаем.
   @supports — страховка: браузер без mask-image оставляет прежний глиф, а не
   пустой квадрат (деградация, а не поломка контрола). */
@supports ((mask-image: url("")) or (-webkit-mask-image: url(""))) {
  .rx-pill.is-quick.is-empty .rx-emo{
    --rx-heart:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M19 14c1.49-1.46 3-3.21 3-5.5A5.5 5.5 0 0 0 16.5 3c-1.76 0-3 .5-4.5 2-1.5-1.5-2.74-2-4.5-2A5.5 5.5 0 0 0 2 8.5c0 2.3 1.5 4.05 3 5.5l7 7Z'/%3E%3C/svg%3E");
    display:inline-block; width:17px; height:17px; font-size:0;
    background-color:currentColor;
    -webkit-mask:var(--rx-heart) center / 17px 17px no-repeat;
    mask:var(--rx-heart) center / 17px 17px no-repeat;
  }
}


/* ── ПОЧИНКА БАЗЫ .btn ВНУТРИ ХАБА /store.html (скоуп .store-section-body — класс есть ТОЛЬКО
   там, store.js:442; community/cabinet/лендинги НЕ затрагиваются) ────────────────────────────
   Баг вида: store.html линкует community.css + tokens.css + pop.css, но НЕ landing.css, где
   лежит БАЗА `.btn` (display/padding/cursor). community.css её лишь дополняет («наследуем .btn
   из landing.css»). Итог — кнопка любого empty-state хаба (emptyHTML: `.btn.btn-primary`)
   рендерилась инлайновым текстом с градиентной подложкой без паддингов: «Найти мастера»,
   «В маркетплейс», «Открыть редактор» во ВСЕХ покупательских панелях. Возвращаем ровно базу
   landing.css, значениями из tokens.css; варианты (btn-primary/ghost/sm) уже есть в community.css. */
.store-section-body .btn{ display:inline-flex; align-items:center; justify-content:center;
  gap:.45em; border:0; cursor:pointer; font:inherit; font-weight:700; text-decoration:none;
  padding:.7em 1.25em; line-height:1.2; }
.store-section-body .btn-sm{ padding:.5em .9em; }

/* ══════════════════════════════════════════════════════════════════════════════════════
   .bsf-* — суб-таб «Файлы» хаба /store.html (src/cabinet-files.js): МОИ СКАЧАННЫЕ МОДЕЛИ.
   Выполняет обещание гейта скачивания («сохраним в кабинете — скачаете снова»).

   D0-плотность (замер, десктоп 1280): строка 68px = thumb 48 + паддинг 10×2; шаг списка 69px
   (68 + 1px хайрлайн). Соседние панели того же раздела «Покупки» (.cm-card в renderLeads)
   идут шагом ~101px (карточка ~85 + gap 16) — новый раздел ПЛОТНЕЕ соседа на 32%, как и
   требует канон frontend/brand/DENSITY.md («строка списка ~69»). Мобайл (≤600px): строка 64px
   (thumb 40, кнопка 44 — тач-минимум добран ЗОНОЙ ТАПА, не раздутым телом контрола).
   Список — ОДИН бордер-контейнер с хайрлайнами, а не стопка карточек: экономит ~10px на строку
   и читается как список файлов (Якоб), а не как лента постов.

   Все значения — из tokens.css (var(--*)), ноль хардкод-hex.
   ══════════════════════════════════════════════════════════════════════════════════════ */

/* Верхняя строка-мета: слева ЧТО это за список (снимает вопрос «а где купленные?»),
   справа тихий мост в «Покупки». Один ярус, не три этажа контролов (§15.A). */
.bsf-bar{ display:flex; align-items:center; justify-content:space-between; gap:var(--sp-3);
  flex-wrap:wrap; margin:0 0 var(--sp-2); }
.bsf-bar-solo{ justify-content:center; margin-top:var(--sp-3); }
.bsf-count{ font:700 var(--fs-xs)/1.35 var(--font); color:var(--ink2); letter-spacing:.01em; }
.bsf-count b{ color:var(--ink); font-variant-numeric:tabular-nums; }
/* Мост — tertiary-вес (текст-ссылка), НЕ кнопка: не конкурирует с primary в строках (§14.A).
   Акцент текста — --violet-700 (7.07:1 на белом), НЕ --violet-500 (4.34:1 — мимо AA 4.5 для
   12-14px). Рамки/фокус-кольца остаются на --accent: для не-текста порог 3:1, там он проходит. */
.bsf-bridge{ font:600 var(--fs-xs)/1.35 var(--font); color:var(--ink2); text-decoration:none; }
.bsf-bridge b{ color:var(--violet-700); font-weight:700; white-space:nowrap; }
.bsf-bridge:hover b{ text-decoration:underline; }
.bsf-bridge:focus-visible{ outline:2px solid var(--accent); outline-offset:3px; border-radius:var(--rad-xs); }

/* Мягкий потолок ширины блока: на широком хабе (панель ~992-1072px) строка «обложка + название
   + одна кнопка» растягивалась в поле пустоты между мета-строкой и действием. 920px держит
   связку «что это» ↔ «что с этим сделать» в одном взгляде; левый край с соседними панелями
   раздела не разъезжается (ограничен только правый), канон --page-max не затронут. */
.bsf-bar,.bsf-list,.bsf-note,.bsf-more{ max-width:920px; }
.bsf-list{ border:1px solid var(--line); border-radius:var(--rad-md); background:var(--card);
  overflow:hidden; }
.bsf-row{ display:flex; align-items:center; gap:var(--sp-3); padding:10px var(--sp-3); min-height:68px; }
.bsf-row + .bsf-row{ border-top:1px solid var(--line); }

/* Обложка. Реальная картинка — <img>; пусто → posterSurface даёт .is-generative (бренд-градиент
   + монограмма). Размер/радиус общие, фон и display НЕ трогаем у генеративного варианта, иначе
   затрём его градиент (правило .is-generative объявлено выше в этом же файле). */
.bsf-thumb{ width:48px; height:48px; flex:none; border-radius:var(--rad-sm); overflow:hidden; }
img.bsf-thumb{ display:block; object-fit:cover; background:var(--bg2); }
.bsf-thumb .pp-poster-mono{ font-size:clamp(15px, 44cqi, 21px); text-shadow:none; }

.bsf-main{ flex:1; min-width:0; }
.bsf-title{ display:block; font:700 var(--fs-sm)/1.25 var(--font); color:var(--ink);
  text-decoration:none; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
a.bsf-title:hover{ color:var(--violet-700); }
a.bsf-title:focus-visible{ outline:2px solid var(--accent); outline-offset:2px; border-radius:var(--rad-xs); }
.bsf-meta{ margin-top:3px; font:500 var(--fs-xs)/1.35 var(--font); color:var(--ink2);
  font-variant-numeric:tabular-nums; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.bsf-meta a{ color:var(--ink2); text-decoration:none; }
.bsf-meta a:hover{ color:var(--violet-700); text-decoration:underline; }
.bsf-meta i{ font-style:normal; opacity:.45; }

/* ОДИН primary в строке — «Скачать снова». Вес secondary-outline: строк много, filled-градиент
   в каждой превратил бы список в стену CTA (§14.E де-эмфазис). */
.bsf-act{ flex:none; }
.bsf-dl{ display:inline-flex; align-items:center; justify-content:center; gap:6px;
  min-height:32px; padding:0 14px; border:1.5px solid var(--line2); border-radius:var(--rad-pill);
  background:var(--card); color:var(--ink); font:700 var(--fs-xs)/1 var(--font);
  white-space:nowrap; cursor:pointer; transition:border-color .15s, color .15s; }
.bsf-dl:hover{ border-color:var(--accent); color:var(--violet-700); }
.bsf-dl:focus-visible{ outline:2px solid var(--accent); outline-offset:2px; }
.bsf-dl[disabled]{ opacity:.55; cursor:default; }
/* Закрытая строка: НЕ мёртвая кнопка, а причина. Цвет тихий (это не ошибка человека),
   иконка обязательна — смысл не держится на одном цвете (§6 color-not-only). */
.bsf-off{ display:inline-flex; align-items:center; gap:5px; padding:0 2px;
  font:600 var(--fs-xs)/1.3 var(--font); color:var(--ink2); white-space:nowrap; cursor:help; }
.bsf-off svg{ flex:none; opacity:.6; }

.bsf-note{ margin:var(--sp-2) 0 0; font:500 var(--fs-xs)/1.45 var(--font); color:var(--ink2); }
.bsf-more{ display:flex; justify-content:center; margin-top:var(--sp-3); }

/* LOADING — скелет ровно тех же 68px, что финальная строка (никакого прыжка вёрстки). */
.bsf-sk{ display:flex; align-items:center; gap:var(--sp-3); padding:10px var(--sp-3); min-height:68px; }
.bsf-sk + .bsf-sk{ border-top:1px solid var(--line); }
.bsf-sk i{ display:block; background:var(--gray-100); border-radius:var(--rad-xs);
  animation:bsfPulse 1.3s ease-in-out infinite; }
.bsf-sk .s-th{ width:48px; height:48px; flex:none; border-radius:var(--rad-sm); }
.bsf-sk .s-tx{ flex:1; height:12px; max-width:280px; }
.bsf-sk .s-bt{ width:112px; height:32px; flex:none; border-radius:var(--rad-pill); }
@keyframes bsfPulse{ 0%,100%{ opacity:1 } 50%{ opacity:.5 } }

@media (max-width:600px){
  .bsf-row,.bsf-sk{ gap:10px; padding:10px; min-height:64px; }
  .bsf-thumb,.bsf-sk .s-th{ width:40px; height:40px; }
  .bsf-dl{ min-height:44px; padding:0 12px; }   /* тач-минимум 44 — зоной тапа, не раздутым глифом */
  .bsf-sk .s-bt{ height:44px; width:96px; }
  .bsf-hide-sm{ display:none; }                 /* «Скачать снова» → «Скачать»: узкий экран */
  .bsf-bar{ gap:var(--sp-2); }
}
@media (prefers-reduced-motion:reduce){
  .bsf-sk i{ animation:none; }
  .bsf-dl{ transition:none; }
}

/* ══════════════════════════════════════════════════════════════════════════════════════
   .bsrf-* — ЗАЯВКИ НА ВОЗВРАТ. ОДИН словарь на ТРИ поверхности одного контура:
     • покупатель — полоса внизу карточки заказа  (/store.html → Покупки; src/refund-request.js)
     • мастер     — очередь решений                (/store.html → Сделки → Возвраты; src/store-refunds.js)
     • площадка   — очередь разбора                (/admin.html → Возвраты;        src/admin-refunds.js)
   Три роли смотрят на ОДНУ заявку, поэтому и чип статуса, и строка списка, и модалка обязаны
   выглядеть одинаково: расхождение вида читается как «это разные объекты» (Якоб).

   D0-ПЛОТНОСТЬ (замер, десктоп 1280 · эталон = .bsf-row 68/64 и панели /store.html):
     строка очереди        68px desktop / 64px mobile   = эталон .bsf-row, шаг списка 69px
     полоса в карточке     34px (чип 23 + 8 отступ)     — не «ещё одна карточка», а строка
     кнопка действия       32px desktop / 44px mobile   — тач добран ЗОНОЙ, не телом (§14.D)
     сегмент фильтра       28px                          — ярус .dr-seg (27.6), не 40
     чип статуса           ~23px (ui-badge 11px/700)     — DENSITY §3 «чип 22–26»
     кнопки футера модалки 40px desktop / 44px mobile    — база .pp-modal-foot даёт 44, сужаем
     модалки: подтверждение min(420) · решение мастера min(480) · карточка площадки min(560)
     высота модалки        ≤80vh базовой .pp-modal (шапка/футер фикс, скролл только тело)
   Ноль хардкод-hex: всё через var(--*) из tokens.css.
   ══════════════════════════════════════════════════════════════════════════════════════ */

/* ── ОБЩЕЕ: чип статуса рисует ui-badge (не свой дубль), тут только выравнивание ─────── */
.bsrf-strip .ui-badge, .bsrf-row .ui-badge, .bsrf-m .ui-badge{ flex:none; }

/* ── ПОКУПАТЕЛЬ: полоса в карточке заказа ─────────────────────────────────────────────
   Отдельной карточкой возврат не рисуем: у заказа уже есть карточка, и вторая рядом
   читалась бы как второй заказ. Полоса = ярус ПОД содержимым карточки, хайрлайн сверху. */
.bsrf-strip{ display:flex; align-items:center; gap:var(--sp-2); flex-wrap:wrap;
  min-height:34px; margin-top:var(--sp-2); padding-top:var(--sp-2);
  border-top:1px solid var(--line); }
.bsrf-strip .bsrf-act{ margin-left:auto; }
/* мета-строка полосы: срок/решение — тихо, тонко, tabular (даты и суммы не прыгают) */
.bsrf-meta{ font:500 var(--fs-xs)/1.35 var(--font); color:var(--ink2);
  font-variant-numeric:tabular-nums; min-width:0; overflow:hidden; text-overflow:ellipsis;
  white-space:nowrap; }
.bsrf-meta.is-late{ color:var(--amber-800); font-weight:700; }
/* причина отказа / ответ продавца — вторая строка на всю ширину, максимум 3 строки текста */
.bsrf-why{ flex:1 1 100%; margin:0; font:500 var(--fs-xs)/1.4 var(--font); color:var(--ink2);
  display:-webkit-box; -webkit-line-clamp:3; -webkit-box-orient:vertical; overflow:hidden; }
.bsrf-why b{ color:var(--ink); font-weight:700; }
.bsrf-why a{ color:var(--violet-700); font-weight:700; }
/* вход закрыт — НЕ мёртвая кнопка, а причина словами (тот же приём, что .bsf-off) */
.bsrf-off{ display:inline-flex; align-items:center; gap:5px; min-width:0;
  font:600 var(--fs-xs)/1.35 var(--font); color:var(--ink2); }
.bsrf-off svg{ flex:none; opacity:.6; }

/* ── ДЕЙСТВИЕ (общее для всех трёх поверхностей) ──────────────────────────────────────
   Вес secondary-outline: заявок в списке много, filled-градиент в каждой строке
   превратил бы очередь в стену CTA (§14.E де-эмфазис). Один primary живёт в модалке. */
.bsrf-act{ display:inline-flex; align-items:center; justify-content:center; gap:6px;
  min-height:32px; padding:0 14px; border:1.5px solid var(--line2); border-radius:var(--rad-pill);
  background:var(--card); color:var(--ink); font:700 var(--fs-xs)/1 var(--font);
  white-space:nowrap; cursor:pointer; transition:border-color .15s, color .15s; }
.bsrf-act:hover{ border-color:var(--accent); color:var(--violet-700); }
.bsrf-act:focus-visible{ outline:2px solid var(--accent); outline-offset:2px; }
.bsrf-act[disabled]{ opacity:.55; cursor:default; }
.bsrf-act svg{ flex:none; }
/* третичный тир (отозвать заявку, заметка) — текст без рамки, не конкурирует (§14.A) */
.bsrf-act.is-quiet{ border-color:transparent; background:none; color:var(--ink2);
  padding:0 8px; text-decoration:underline; text-underline-offset:3px; }
.bsrf-act.is-quiet:hover{ color:var(--violet-700); }
/* акцентный тир — «Ответить» в очереди мастера: единственное, ради чего он сюда зашёл */
.bsrf-act.is-key{ border-color:var(--accent); color:var(--violet-700); background:var(--violet-50); }
.bsrf-act.is-key:hover{ background:var(--violet-100); }

/* ── ОЧЕРЕДЬ (мастер): один ярус управления + список-контейнер с хайрлайнами ──────────
   Не стопка карточек: контейнер с хайрлайнами экономит ~10px на строку и читается как
   очередь дел, а не как лента (§15.A — одна control-bar, не три этажа). */
.bsrf-wrap{ max-width:920px; }
.bsrf-bar{ display:flex; align-items:center; justify-content:space-between; gap:var(--sp-3);
  flex-wrap:wrap; min-height:32px; margin:0 0 var(--sp-2); }
.bsrf-count{ font:700 var(--fs-xs)/1.35 var(--font); color:var(--ink2); letter-spacing:.01em; }
.bsrf-count b{ color:var(--ink); font-variant-numeric:tabular-nums; }
/* сегмент «Открытые | Все» — вид ОДНОГО множества, поэтому сегмент, а не табы (§15.B) */
.bsrf-seg{ display:inline-flex; gap:2px; padding:2px; border-radius:var(--rad-pill);
  background:var(--bg2); }
.bsrf-seg button{ min-height:28px; padding:0 12px; border:0; border-radius:var(--rad-pill);
  background:none; color:var(--ink2); font:600 var(--fs-xs)/1 var(--font); cursor:pointer;
  position:relative; transition:background .15s, color .15s; }
.bsrf-seg button::after{ content:''; position:absolute; inset:-8px -2px; }   /* тач-зона 44 */
.bsrf-seg button.is-active{ background:var(--card); color:var(--ink); box-shadow:var(--shadow); }
.bsrf-seg button:focus-visible{ outline:2px solid var(--accent); outline-offset:2px; }

.bsrf-list{ border:1px solid var(--line); border-radius:var(--rad-md); background:var(--card);
  overflow:hidden; }
.bsrf-row{ display:flex; align-items:center; gap:var(--sp-3); padding:10px var(--sp-3);
  min-height:68px; }
.bsrf-row + .bsrf-row{ border-top:1px solid var(--line); }
.bsrf-row.is-hot{ background:var(--amber-50); }        /* срок ответа уже горит */
.bsrf-main{ flex:1; min-width:0; }
.bsrf-title{ display:block; font:700 var(--fs-sm)/1.25 var(--font); color:var(--ink);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.bsrf-sub{ display:flex; align-items:center; gap:6px; margin-top:3px; min-width:0;
  font:500 var(--fs-xs)/1.35 var(--font); color:var(--ink2); font-variant-numeric:tabular-nums; }
.bsrf-sub span{ min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.bsrf-sub i{ font-style:normal; opacity:.45; flex:none; }
.bsrf-rowact{ flex:none; display:flex; align-items:center; gap:var(--sp-2); }
.bsrf-note{ margin:var(--sp-2) 0 0; font:500 var(--fs-xs)/1.45 var(--font); color:var(--ink2);
  max-width:920px; }

/* ── LOADING: скелет РОВНО той же высоты, что финальная строка (нет прыжка вёрстки) ─── */
.bsrf-sk{ display:flex; align-items:center; gap:var(--sp-3); padding:10px var(--sp-3);
  min-height:68px; }
.bsrf-sk + .bsrf-sk{ border-top:1px solid var(--line); }
.bsrf-sk i{ display:block; background:var(--gray-100); border-radius:var(--rad-xs);
  animation:bsrfPulse 1.3s ease-in-out infinite; }
.bsrf-sk .s-tx{ flex:1; height:12px; max-width:300px; }
.bsrf-sk .s-bt{ width:104px; height:32px; flex:none; border-radius:var(--rad-pill); }
@keyframes bsrfPulse{ 0%,100%{ opacity:1 } 50%{ opacity:.5 } }

/* ── МОДАЛКИ (все три роли) ───────────────────────────────────────────────────────────
   Ширина = ТИП модалки (DENSITY §1), не «побольше на всякий». Тело плотное: gap 8-10,
   подсказка — одна строка, а не абзац. */
.bsrf-modal{ width:min(420px,100%); }        /* подтверждение: один вопрос + 1-2 кнопки  */
.bsrf-modal.is-form{ width:min(480px,100%); }/* решение мастера: факты + два действия    */
.bsrf-modal.is-wide{ width:min(560px,100%); }/* карточка площадки: факты + заметка       */
.bsrf-m{ display:flex; flex-direction:column; gap:var(--sp-2);
  padding:var(--sp-2) var(--sp-3) var(--sp-3); }
/* HERO — ответ на «о чём это»: сумма доминантой, всё остальное тише (§1.1) */
.bsrf-m-hero{ margin:0; font:600 var(--fs-sm)/1.4 var(--font); color:var(--ink);
  font-variant-numeric:tabular-nums; }
.bsrf-m-hero b{ font-weight:800; }
.bsrf-m-sub{ margin:0; font:500 var(--fs-xs)/1.4 var(--font); color:var(--ink2);
  font-variant-numeric:tabular-nums; }
/* ПРАВИЛО МАШИНЫ — не «мелкий шрифт», а несущий факт: у мастера отказа НЕТ, есть маршрут.
   Тихая рамка-засечка, а не заливка: это не ошибка и не блокер, а объяснение (§14.E). */
.bsrf-m-rule{ margin:0; padding:0 0 0 9px; border-left:2px solid var(--violet-200);
  font:500 var(--fs-xs)/1.45 var(--font); color:var(--ink2); }
.bsrf-m-rule b{ color:var(--ink); font-weight:700; }
/* предупреждение про долг — амбер-засечка (называет последствие, не останавливает) */
.bsrf-warn{ margin:0; padding:0 0 0 9px; border-left:2px solid var(--amber-200);
  font:500 var(--fs-xs)/1.45 var(--font); color:var(--amber-800); }
/* отказ сервера — заливка: она останавливает действие (§8 error-placement, у поля).
   Текст --rose-800: на --rose-50 это 6.44:1, тогда как --rose-700 даёт 4.27 — мимо AA для 12px. */
.bsrf-err{ margin:0; padding:6px 9px; border-radius:var(--rad-sm); background:var(--rose-50);
  color:var(--rose-800); font:600 var(--fs-xs)/1.4 var(--font); }
/* цитата покупателя/продавца — отделена рамкой, обрезается до 6 строк со «Показать всё» */
.bsrf-quote{ margin:0; padding:8px 10px; border:1px solid var(--line); border-radius:var(--rad-sm);
  background:var(--bg2); font:500 var(--fs-xs)/1.45 var(--font); color:var(--ink);
  white-space:pre-wrap; overflow-wrap:anywhere; }
/* 4 строки, а не 6: длинная цитата тянула карточку решения к 69% высоты экрана. Хвост не
   теряется — под обрезкой стоит «Показать полностью» (и она появляется ТОЛЬКО когда текст
   реально не влез, см. rfTrimExpanders). */
.bsrf-quote.is-clamp,.bsrf-int.is-clamp{ display:-webkit-box; -webkit-line-clamp:4;
  -webkit-box-orient:vertical; overflow:hidden; }
.bsrf-qlbl{ margin:0; font:700 var(--fs-xs)/1.35 var(--font); color:var(--ink2); }
/* «Показать полностью» — тихий текст-контрол ПОД обрезанной цитатой, а не hover-подсказка:
   на тач-устройстве title недостижим, а по этому тексту принимают решение о деньгах. */
.bsrf-quote + [data-rf-expand], .bsrf-int + [data-rf-expand]{ align-self:flex-start; margin-top:-2px; }
.bsrf-why-more{ flex:1 1 100%; justify-content:flex-start; }

/* состав заказа — строки 22px в одной рамке (идиома .adm-rf-l админского расчёта) */
.bsrf-lines{ border:1px solid var(--line); border-radius:var(--rad-sm); padding:2px 8px; }
.bsrf-l{ display:flex; align-items:center; gap:var(--sp-2); min-height:22px; padding:2px 0;
  border-top:1px solid var(--line2); font:500 var(--fs-xs) var(--font); color:var(--ink); }
.bsrf-l:first-child{ border-top:0; }
.bsrf-l-t{ flex:1 1 auto; min-width:0; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.bsrf-l-v{ flex:none; font-weight:700; font-variant-numeric:tabular-nums; }
.bsrf-l.is-dlv .bsrf-l-t{ color:var(--ink2); }
/* контраст: --gray-500 (#8A8A92) на белом даёт 3.43:1 — мимо AA 4.5 для 11-12px.
   --gray-600 (#6B6B73) = 4.83:1 ✓. Тише этого тира тихого текста на светлом фоне нет. */
.bsrf-more{ font:500 11px var(--font); color:var(--gray-600); padding:3px 0; }

/* факты триажа — ряд тихих чипов; пустое НЕ рисуем вовсе (INV-RENDER) */
.bsrf-facts{ display:flex; flex-wrap:wrap; gap:6px; }
.bsrf-fact{ display:inline-flex; align-items:center; gap:4px; padding:2px 8px;
  border-radius:var(--rad-pill); background:var(--bg2); color:var(--ink2);
  font:600 11px/1.5 var(--font); white-space:nowrap; }

/* поле формы — компактное (DENSITY §3: textarea 64px, label 12/600, hint одной строкой) */
.bsrf-f{ display:block; }
.bsrf-f > span{ display:block; margin-bottom:4px; font:600 var(--fs-xs) var(--font); color:var(--ink2); }
.bsrf-f textarea{ display:block; width:100%; min-height:64px; resize:vertical; padding:8px 10px;
  border:1px solid var(--line2); border-radius:var(--rad-sm); background:var(--card);
  color:var(--ink); font:500 var(--fs-sm)/1.45 var(--font); }
.bsrf-f textarea:focus-visible{ outline:2px solid var(--accent); outline-offset:1px;
  border-color:var(--accent); }
.bsrf-hint{ margin:0; font:500 11px/1.4 var(--font); color:var(--gray-600); }
/* прогрессивное раскрытие: редкое (сообщение покупателю) свёрнуто, 26px в закрытом виде
   (DENSITY §5) — не простыня из полей ради одного необязательного текста */
.bsrf-det{ border-top:1px solid var(--line); padding-top:6px; }
.bsrf-det > summary{ list-style:none; cursor:pointer; min-height:26px; display:flex;
  align-items:center; gap:6px; font:700 var(--fs-xs) var(--font); color:var(--ink2); }
.bsrf-det > summary::-webkit-details-marker{ display:none; }
.bsrf-det > summary::before{ content:'+'; font-weight:800; color:var(--violet-700); }
.bsrf-det[open] > summary::before{ content:'−'; }
.bsrf-det > summary:hover{ color:var(--violet-700); }
.bsrf-det > summary:focus-visible{ outline:2px solid var(--accent); outline-offset:2px;
  border-radius:var(--rad-xs); }
.bsrf-det .bsrf-f{ margin-top:6px; }
/* состав заказа под раскрытием: «что купили» читается в самом summary одной строкой и
   не переносится (иначе свёрнутый блок стоил бы столько же, сколько развёрнутый) */
.bsrf-det .bsrf-lines{ margin-top:6px; }
.bsrf-det > summary > .bsrf-det-t{ min-width:0; overflow:hidden; text-overflow:ellipsis;
  white-space:nowrap; }
.bsrf-hint label{ display:inline-flex; align-items:center; gap:6px; cursor:pointer; }
.bsrf-hint input[type=checkbox]{ accent-color:var(--accent); margin:0; }
.bsrf-hint .bsrf-act.is-quiet{ min-height:22px; font-size:11px; }

/* футер модалки: база даёт 44px и width:100% — на десктопе это выше канона D0 (40) */
.bsrf-modal .pp-modal-foot .pp-btn{ width:auto; }
/* фокус-кольцо кнопок футера: у базовой .pp-btn своего нет (остаётся UA-обводка). Свой ring
   ставим ТОЛЬКО внутри своих модалок — глобальное поведение кнопок платформы не трогаем. */
.bsrf-modal .pp-modal-foot .pp-btn:focus-visible{ outline:2px solid var(--violet-700);
  outline-offset:2px; }
@media (min-width:721px){ .bsrf-modal .pp-modal-foot .pp-btn{ min-height:40px; } }

/* ── ПЛОЩАДКА: сводка очереди одной строкой (числа не дублируем карточками) ──────────── */
.bsrf-sum{ display:flex; align-items:center; flex-wrap:wrap; gap:4px 10px; min-width:0;
  font:500 var(--fs-xs)/1.4 var(--font); color:var(--ink2); font-variant-numeric:tabular-nums; }
.bsrf-sum b{ color:var(--ink); font-weight:800; }
.bsrf-sum .is-late{ color:var(--rose-800); font-weight:700; }   /* 6.79:1 на --bg (rose-700 = 4.5 впритык) */
.bsrf-sum i{ opacity:.45; font-style:normal; }
/* внутренняя заметка оператора — ВИДНА ТОЛЬКО ПЛОЩАДКЕ (ни покупателю, ни мастеру) */
.bsrf-int{ padding:6px 9px; border-radius:var(--rad-sm); background:var(--amber-50);
  color:var(--amber-800); font:500 var(--fs-xs)/1.45 var(--font); white-space:pre-wrap; }
/* короткие ячейки очереди площадки НЕ переносим: «#811 · 5 400 ₽» в две строки удваивал
   высоту строки таблицы (42 → 63) и ломал скан очереди сверху вниз */
.bsrf-nw{ white-space:nowrap; }

@media (max-width:600px){
  .bsrf-row,.bsrf-sk{ gap:10px; padding:10px; min-height:64px; }
  /* 390px: чип статуса («Продавец согласен — оформляем возврат» = ~210px) + сумма + срок в
     ОДНУ строку не влезают — чип уезжал ПОД кнопку. Разрешаем мета-строке переноситься:
     строка растёт до ~88px, но растёт СОДЕРЖИМЫМ, а не воздухом. Точки-разделители на
     переносе оказывались в начале строки — на узком их не рисуем, разделяет gap. */
  .bsrf-sub{ flex-wrap:wrap; row-gap:4px; }
  .bsrf-sub i{ display:none; }
  /* 🔴 Чип статуса — nowrap и flex:none (ui-badge), поэтому длинная серверная подпись
     («Продавец согласен — оформляем возврат» = 240px при 190px свободных) ВЫЛЕЗАЛА ПОД кнопку
     строки: статус и действие налезали друг на друга. На узком разрешаем чипу переноситься —
     обрезать статус нельзя (он и есть ответ на «что с моей заявкой»). */
  .bsrf-sub .ui-badge{ flex:0 1 auto; max-width:100%; white-space:normal; text-align:left; }
  .bsrf-hide-sm{ display:none; }   /* дата подачи: на 390px место важнее её */
  .bsrf-act{ min-height:44px; padding:0 12px; }   /* тач-минимум ЗОНОЙ тапа, не раздутым глифом */
  .bsrf-act.is-quiet{ padding:0 8px; }
  .bsrf-sk .s-bt{ height:44px; width:92px; }
  .bsrf-bar{ gap:var(--sp-2); }
  .bsrf-rowact{ flex-direction:column; align-items:flex-end; gap:6px; }
  .bsrf-modal .pp-modal-foot{ flex-wrap:wrap; }
  .bsrf-modal .pp-modal-foot .pp-btn{ min-height:44px; }
}
@media (prefers-reduced-motion:reduce){
  .bsrf-sk i{ animation:none; }
  .bsrf-act,.bsrf-seg button{ transition:none; }
}
