/* Общие токены оформления и базовые элементы оболочки.
   Источник значений — 04_Цветовая_система.md, тёмная тема всегда
   (решение владельца 2026-08-04). Тот же набор продублирован внутри
   public/upload/index.html: монолит переводится на этот файл отдельным
   шагом, чтобы не трогать живое приложение заодно с новым модулем. */
:root{
  color-scheme: dark;
  --surface-page:#121215; --surface-card:#1A1A1E; --surface-sunken:#232329; --surface-hover:#2B2B33;
  --text-primary:#F0F0F4; --text-secondary:#A2A2AC; --text-muted:#75757F; --text-disabled:#56565F;
  --border:#2E2E36; --border-strong:#3A3A44;
  --accent:#5A93E8; --accent-bg:#16304F; --accent-text:#9CC3F5;
  --success:#56B37B; --success-bg:#14301F; --success-text:#8ED4AA;
  --warning:#E0A040; --warning-bg:#3A2A0C; --warning-text:#EFC584;
  --danger:#E8695C; --danger-bg:#3B1815; --danger-text:#F2A29A;
  --radius:12px;

  /* ВЕРХНИЙ ОТСТУП — правило владельца из 04_Цветовая_система.md, §11.
     У Telegram ДВЕ переменные, и они СКЛАДЫВАЮТСЯ: безопасная зона устройства
     (статусбар, чёлка) + зона контролов Telegram (Закрыть, ⌄, …). Сверху 16px воздуха.
     Никаких других верхних отступов не изобретать — иначе содержимое уезжает
     под кнопки Telegram, как и случилось на витрине 2026-08-07. */
  --page-top: calc(var(--tg-safe-area-inset-top, 0px) + var(--tg-content-safe-area-inset-top, 46px) + 16px);
}
*{box-sizing:border-box}
html,body{margin:0}
body{
  font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
  background:var(--surface-page); color:var(--text-primary);
  -webkit-font-smoothing:antialiased; line-height:1.45;
  padding:22px 16px 40px; max-width:760px; margin:0 auto;
}
/* класс .fs ставит оболочка, когда Telegram развернул мини-апп на весь экран */
body.fs{padding-top:var(--page-top)}

/* ── «Потяни вниз»: свечение вверху экрана. Разметку добавляет shared/ptr.js ── */
#ptr{position:fixed; top:0; left:0; right:0; height:225px; z-index:19;
  pointer-events:none; overflow:hidden; opacity:var(--i, 0);
  transition:opacity .18s linear}
/* Гаснет заметно дольше, чем разгорается: резкое исчезновение читается как обрыв */
#ptr.fading{transition:opacity 1.1s cubic-bezier(.25,0,.2,1)}
#ptr i{position:absolute; display:block; border-radius:50%}
#ptr .breath{left:-25%; right:-25%; top:-172px; height:315px;
  background:radial-gradient(closest-side, rgba(90,147,232,.95), rgba(90,147,232,.35) 55%, transparent 78%);
  filter:blur(26px)}
#ptr .flow{left:-35%; width:70%; top:-157px; height:285px;
  background:radial-gradient(closest-side, rgba(127,119,221,.85), rgba(127,119,221,.25) 55%, transparent 78%);
  filter:blur(30px)}
#ptr.loading .breath{animation:ptrBreath 2.1s ease-in-out infinite}
#ptr.loading .flow{animation:ptrFlow 3.4s ease-in-out infinite}
@keyframes ptrBreath{
  0%,100%{transform:scale(.86); opacity:.55}
  50%    {transform:scale(1.12); opacity:1}
}
@keyframes ptrFlow{
  0%,100%{transform:translateX(0)}
  50%    {transform:translateX(135%)}
}
@media (prefers-reduced-motion:reduce){
  #ptr.loading .breath, #ptr.loading .flow{animation:none}
}
/* Ошибка обновления — короткая строка вверху, не модалка. Сдвиг прятки большой
   намеренно: top считается от безопасной зоны, и при маленьком сдвиге на телефоне
   с чёлкой «спрятанная» плашка оказывается ровно на виду. */
#refreshErr{position:fixed; top:calc(10px + env(safe-area-inset-top)); left:50%;
  transform:translateX(-50%) translateY(-200px); z-index:21; background:var(--danger-bg);
  color:var(--danger-text); font-size:13px; font-weight:600; border-radius:99px;
  padding:9px 16px; white-space:nowrap; pointer-events:none;
  transition:transform .25s ease}
#refreshErr.show{transform:translateX(-50%) translateY(0)}

/* ── шапка ── */
.top{display:flex; align-items:center; gap:12px; margin-bottom:20px}
.ava{width:46px; height:46px; border-radius:50%; background:var(--accent-bg);
  color:var(--accent-text); display:flex; align-items:center; justify-content:center;
  font-weight:700; font-size:16px; flex:0 0 46px; overflow:hidden; position:relative}
/* Фото профиля из Telegram. Оно приходит НЕ всегда (Telegram отдаёт photo_url
   не при каждом способе запуска), поэтому под ним всегда лежат инициалы — если
   картинки нет, экран не пустеет. */
.ava img{position:absolute; inset:0; width:100%; height:100%; object-fit:cover; display:none}
.ava img.on{display:block}
/* Место под плашки тарифа и группы отдано сразу: они приходят с сервера и,
   появляясь, сдвигали бы вниз всю витрину (LOADING.md). */
.who{flex:1; min-width:0; min-height:66px}
.who .hi{font-size:12.5px; color:var(--text-muted)}
.who .nm{font-size:17px; font-weight:650; letter-spacing:-.2px;
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis}

/* Плашка тарифа под именем */
.plan{display:inline-block; margin-top:4px; padding:2px 8px; border-radius:6px;
  font-size:10.5px; font-weight:750; letter-spacing:.6px; text-transform:uppercase;
  background:var(--surface-sunken); color:var(--text-secondary)}
.plan.pro{background:var(--accent-bg); color:var(--accent-text)}
.plan.max{background:#2A2140; color:#C0B2F5}
/* Плашка группы рядом с тарифом: сестрёнка — тёплая, остальные — сдержанные */
.plan.cohort{margin-left:5px}
/* «Создатель» — плашка владельца на витрине (2026-08-08): тёплое золото,
   в тон FOTOGAME, ни с одной группой не путается */
.plan.cohort.creator{background:#3A2A14; color:#F0C45C}
.plan.cohort.family{background:#3A2140; color:#E8B2F0}
.plan.cohort.tester{background:var(--accent-bg); color:var(--accent-text)}
.plan.cohort.partner{background:var(--success-bg); color:var(--success-text)}

/* Круглая кнопка в углу шапки (приглашение) */
.round{width:42px; height:42px; flex:0 0 42px; border-radius:50%; cursor:pointer;
  display:flex; align-items:center; justify-content:center; padding:0;
  background:var(--surface-card); border:0.5px solid var(--border);
  color:var(--text-secondary); text-decoration:none; -webkit-tap-highlight-color:transparent}
.round:active{background:var(--surface-hover)}
/* Подарок — единственная цветная кнопка в шапке: это подарок, и он должен звать нажать.
   Розовый берём приглушённый, чтобы не спорить с синим акцентом приложения. */
.round.gift{background:linear-gradient(145deg, #E86F9E, #C0559A); border-color:transparent;
  color:#fff; box-shadow:0 4px 14px rgba(224,111,158,.28)}
.round.gift:active{background:linear-gradient(145deg, #D96491, #AE4A8B)}
/* Сводка по продукту — только у владельца (правило А2). Оранжевая, как была в меню
   «Отбора», но БЕЗ сияния: она служебная и звать нажать не должна — в отличие
   от подарка, который зовёт. */
.round.adm{background:var(--warning); border-color:transparent; color:#1A1A19}
.round.adm:active{filter:brightness(.92)}

/* ═══════════ ОБЛОЖКА ВИТРИНЫ ═══════════
   Любимая работа автора на его домашнем экране. Единственное место в приложении,
   которое ничего от человека не требует и существует только ради него.

   Соотношение 16:9 задано жёстко (решение владельца): при любой ширине экрана блок
   занимает предсказуемую высоту, и витрина не прыгает, пока грузится картинка. */
.cover{margin-bottom:22px}
/* Пока состояние обложки неизвестно — рамка мерцает и молчит: ни приглашения,
   ни кнопки. Иначе тот, у кого обложка есть, каждый раз видел бы вспышку
   «Поставьте сюда работу» (LOADING.md). */
.cover[aria-busy="true"] .invite, .cover[aria-busy="true"] .edit{visibility:hidden}
.covsk{position:absolute; inset:0; border-radius:inherit; display:none; z-index:2}
.cover[aria-busy="true"] .covsk{display:block}
.cover .frame{position:relative; aspect-ratio:16/9; border-radius:18px; overflow:hidden;
  background:var(--surface-card); -webkit-tap-highlight-color:transparent}

/* ── Пустое состояние: пунктир и приглашение ──
   Класс называется .nopic, а НЕ .empty: `.empty` в этом же файле уже занят под
   пустое состояние модуля (серая подложка со своими отступами), и на витрине он
   подмешивался к обложке — вокруг пунктира появлялся лишний тёмный прямоугольник.
   Поймано в браузере 2026-08-07. */
.cover.nopic .frame{border:1.5px dashed var(--border-strong); background:transparent;
  display:flex; flex-direction:column; align-items:center; justify-content:center;
  text-align:center; padding:16px; gap:9px; cursor:pointer}
.cover.nopic .frame:active{background:var(--surface-card)}
/* Центрируем содержимое ЗДЕСЬ, а не на .frame: там центрируется сама обёртка
   .invite, а внутри неё значок и текст остаются обычным потоком — и «плюс»
   прижимался к левому краю (поймано в браузере 2026-08-07). */
.cover .invite{display:flex; flex-direction:column; align-items:center; gap:9px}
.cover .plus{width:38px; height:38px; border-radius:50%; flex:0 0 38px;
  background:var(--accent-bg); color:var(--accent-text);
  display:flex; align-items:center; justify-content:center}
.cover .ct{font-size:15px; font-weight:650; letter-spacing:-.1px}
.cover .cs{font-size:12.5px; color:var(--text-secondary); line-height:1.45; max-width:25em}
/* Приглашение живёт только в пустом состоянии, картинка — только в заполненном */
.cover:not(.nopic) .invite{display:none}
.cover.nopic .shot{display:none}

/* ── Заполненное состояние ──
   Два слоя картинки: пока верхний гаснет, нижний уже показан, и смена не мигает
   фоном карточки. Меняем только opacity — её считает видеокарта. */
.cover .shot{position:absolute; inset:0}
.cover .shot img{position:absolute; inset:0; width:100%; height:100%; object-fit:cover;
  opacity:0; transition:opacity .8s ease}
.cover .shot img.on{opacity:1}
@media (prefers-reduced-motion:reduce){ .cover .shot img{transition:none} }

/* Затемнение внизу — под кнопку настройки. Линейное: радиальный градиент на тёмном
   полосит видимой дугой (грабли 2026-08-07).
   Точек-индикаторов здесь нет и не должно быть (решение владельца 2026-08-08):
   работа меняется на входе, а не перелистыванием, и ряд точек обещал бы жест,
   которого нет. */
.cover .veil{position:absolute; left:0; right:0; bottom:0; height:52%; pointer-events:none;
  background:linear-gradient(transparent, rgba(0,0,0,.5))}
/* Кнопка настройки. Полупрозрачная с размытием — поверх любой картинки читается. */
.cover .edit{position:absolute; right:10px; bottom:10px; width:32px; height:32px;
  border-radius:50%; border:none; padding:0; cursor:pointer; color:#fff;
  background:rgba(0,0,0,.42); -webkit-backdrop-filter:blur(6px); backdrop-filter:blur(6px);
  display:flex; align-items:center; justify-content:center; -webkit-tap-highlight-color:transparent}
.cover .edit:active{background:rgba(0,0,0,.6)}
/* Панель открыта — карандаш прячется; закрыл «Готово» — снова появляется */
.cover.open .edit{display:none}

/* ── Панель управления: разворачивается ПОД обложкой ──
   Не шторка намеренно: шторка перекрывает саму обложку, а человек здесь как раз
   выбирает, как она выглядит, — и должен видеть результат сразу. */
.cover .panel{display:none; margin-top:11px; background:var(--surface-card);
  border:0.5px solid var(--border); border-radius:16px; padding:13px 14px}
.cover.open .panel{display:block}
.cover .pseg{display:flex; background:var(--surface-sunken); border-radius:11px;
  padding:4px; gap:4px; margin-bottom:12px}
.cover .pseg button{flex:1; min-width:0; border:none; border-radius:8px; padding:9px 4px;
  font-size:13.5px; font-weight:600; cursor:pointer; background:transparent;
  color:var(--text-secondary); font-family:inherit; -webkit-tap-highlight-color:transparent}
.cover .pseg button.on{background:var(--accent); color:#fff}
.cover .thumbs{display:grid; grid-template-columns:repeat(5, 1fr); gap:7px}
.cover .thumbs .th{position:relative; aspect-ratio:1; border-radius:9px; overflow:hidden;
  background:var(--surface-sunken); cursor:pointer}
.cover .thumbs .th img{width:100%; height:100%; object-fit:cover; display:block}
/* Обводка внутрь (outline-offset отрицательный), иначе она съедает соседний зазор */
.cover .thumbs .th.pin{outline:2px solid var(--accent); outline-offset:-2px}
.cover .thumbs .th .x{position:absolute; top:2px; right:2px; width:18px; height:18px;
  border-radius:50%; border:none; padding:0; cursor:pointer; color:#fff; font-size:11px;
  line-height:18px; text-align:center; background:rgba(0,0,0,.6)}
.cover .thumbs .add{display:flex; align-items:center; justify-content:center;
  border:1.5px dashed var(--border-strong); color:var(--text-muted); font-size:19px}
.cover .phint{font-size:11.5px; color:var(--text-muted); line-height:1.45; margin:10px 0 0}
.cover .pmsg{font-size:12px; color:var(--warning-text); margin:8px 0 0}
.cover .pmsg:empty{display:none}
/* Синяя «Готово» — закрывает панель обложки, чтобы не жать карандаш повторно */
.cover .cvdone{display:block; width:100%; margin-top:12px; border:none; border-radius:11px;
  background:var(--accent); color:#fff; font:inherit; font-size:15px; font-weight:600;
  padding:12px; cursor:pointer}
.cover .cvdone:active{opacity:.85}

/* ═══════════ ВЫБОР ЧАСТИ РАБОТЫ ДЛЯ ОБЛОЖКИ ═══════════
   Работы бывают вертикальные, квадратные, панорамные, а окно обложки — 16:9.
   Обрезать «по центру» молча нельзя: у портрета так отрежется голова. Поэтому
   человек видит работу ЦЕЛИКОМ и сам двигает по ней полосу 16:9.

   Полоса всегда занимает работу во всю её ширину (а у панорам — во всю высоту):
   двигать её нужно только по одной оси, и жест получается однозначный. */
.cropview{position:fixed; inset:0; z-index:70; display:none;
  background:var(--surface-page); overflow-y:auto;
  padding:calc(24px + env(safe-area-inset-top)) 16px calc(20px + env(safe-area-inset-bottom))}
.cropview.show{display:flex; flex-direction:column; justify-content:center}
.cropview .cnum{font-size:12.5px; color:var(--text-muted); margin-bottom:4px}
.cropview h2{font-size:20px; margin:0 0 4px; letter-spacing:-.3px}
.cropview .csub{font-size:13px; color:var(--text-secondary); margin:0 0 16px; line-height:1.45}
/* Рабочая площадка: работа целиком, вокруг — фон страницы */
.cropbox{position:relative; margin:0 auto; overflow:hidden; border-radius:12px;
  touch-action:none; user-select:none; -webkit-user-select:none; cursor:grab}
.cropbox:active{cursor:grabbing}
.cropbox canvas{display:block; width:100%; height:100%; pointer-events:none}
/* Затемнение снаружи полосы делает сама полоса — огромной тенью, обрезанной
   контейнером. Один элемент вместо четырёх масок, и они не разъезжаются. */
.cropbox .band{position:absolute; border:2px solid #fff; border-radius:3px;
  box-shadow:0 0 0 9999px rgba(0,0,0,.62); pointer-events:none}
/* Полоски-«ручки» на той стороне, куда можно тянуть */
.cropbox .band::before, .cropbox .band::after{content:''; position:absolute;
  background:rgba(255,255,255,.9); border-radius:2px}
.cropbox.vert .band::before{left:50%; top:6px; width:34px; height:3px; margin-left:-17px}
.cropbox.vert .band::after{left:50%; bottom:6px; width:34px; height:3px; margin-left:-17px}
.cropbox.horz .band::before{top:50%; left:6px; height:34px; width:3px; margin-top:-17px}
.cropbox.horz .band::after{top:50%; right:6px; height:34px; width:3px; margin-top:-17px}
.cropview .chint{font-size:12.5px; color:var(--text-muted); text-align:center;
  margin:12px 0 0; line-height:1.45}
.cropview .cbtns{margin-top:16px}
.cropview .btn{width:100%}
/* Кнопки общего слоя: в оболочке их до сих пор не было — только ссылки и карточки */
.btn{display:block; border:none; border-radius:10px; cursor:pointer;
  background:var(--accent); color:#fff; font-size:15px; font-weight:600;
  padding:13px 18px; margin-top:10px; font-family:inherit;
  -webkit-tap-highlight-color:transparent}
.btn.secondary{background:var(--surface-sunken); color:var(--text-primary)}
.btn:disabled{opacity:.5; cursor:default}

/* ── Быстрые действия: значок на плитке, подпись под ним ──
   Раскладка в четыре колонки: подписи короткие, в две строки максимум. */
/* Быстрые действия — строкой: значок слева, подпись рядом (2026-08-09).
   Раньше сетка была в четыре колонки при двух действиях, и справа зияла дыра;
   колонок теперь ровно столько, сколько действий. */
/* ЧЕТЫРЕ В РЯД: светлая плитка со значком, подпись под ней мелко и по центру
   (образец владельца 2026-08-09). Плитки СВЕТЛЕЕ остальных кнопок интерфейса —
   это самый частый путь, и он должен подсвечиваться сам собой.
   Подпись вынесена ПОД плитку, а не рядом со значком: в четыре колонки текст
   рядом со значком не помещается ни на одном телефоне. */
.quick{display:grid; grid-template-columns:repeat(4, 1fr); gap:8px; margin-bottom:22px}
/* Плиткой может быть и ссылка, и кнопка: «Новый проект» уводит в модуль,
   «Поиск» открывает слой прямо на витрине. Выглядят они одинаково. */
.quick a, .quick button{display:flex; flex-direction:column; align-items:center; gap:7px;
  padding:0; background:none; border:none; text-decoration:none; color:inherit;
  -webkit-tap-highlight-color:transparent; font:inherit; cursor:pointer; min-width:0}
.quick .qi{width:100%; height:52px; border-radius:16px; display:flex;
  align-items:center; justify-content:center;
  background:var(--surface-hover); color:var(--accent)}
.quick a:active .qi, .quick button:active .qi{background:var(--border-strong)}
.quick .ql{font-size:11.5px; font-weight:500; line-height:1.25; text-align:center;
  color:var(--text-secondary); min-width:0}
.iconbtn{width:38px; height:38px; border-radius:12px; background:var(--surface-card);
  border:0.5px solid var(--border); display:flex; align-items:center; justify-content:center;
  color:var(--text-secondary); flex:0 0 38px; cursor:pointer}

/* ── заголовок группы ── */
.grp{font-size:11.5px; font-weight:650; color:var(--text-muted); text-transform:uppercase;
  letter-spacing:.7px; margin:0 2px 10px}

/* ── карточка ── */
.card{background:var(--surface-card); border:0.5px solid var(--border);
  border-radius:var(--radius); padding:16px; margin-bottom:14px}

/* ── строка «продолжить»: аналог активной поездки у Яндекс Go ── */
.resume{background:var(--surface-card); border:0.5px solid var(--border); border-radius:18px;
  padding:14px 16px; margin-bottom:22px; display:flex; align-items:center; gap:13px;
  cursor:pointer; text-decoration:none; color:inherit}
.resume .ic{width:38px; height:38px; border-radius:11px; background:var(--accent-bg);
  color:var(--accent-text); display:flex; align-items:center; justify-content:center; flex:0 0 38px}
.resume .body{flex:1; min-width:0}
.resume .t{font-size:14.5px; font-weight:600; white-space:nowrap; overflow:hidden; text-overflow:ellipsis}
.resume .s{font-size:12.5px; color:var(--text-secondary); margin-top:2px}
.resume .chev{color:var(--text-muted); font-size:16px}
.prog{height:3px; border-radius:2px; background:var(--surface-sunken); margin-top:8px; overflow:hidden}
.prog i{display:block; height:100%; background:var(--success); border-radius:2px}

/* ── карточки модулей ── */
.mods{display:grid; grid-template-columns:1fr 1fr; gap:11px; margin-bottom:22px}
.mod{background:var(--surface-card); border:0.5px solid var(--border); border-radius:18px;
  padding:15px; position:relative; min-height:132px; display:flex; flex-direction:column;
  text-decoration:none; color:inherit; cursor:pointer}
/* Название и подпись прижаты к низу плитки: у соседей подпись то в одну строку,
   то в две, и без этого их строки разъезжались по высоте (2026-08-09). */
.mod .mt{margin-top:auto}
.mod.wide{grid-column:1 / -1; min-height:0; flex-direction:row; align-items:center; gap:14px}

/* ── ГЛАВНЫЙ СЕРВИС: во всю ширину и заметнее остальных ──
   Выделяем не размером шрифта, а поверхностью: лёгкая подсветка в акцент и цветная
   рамка. Так карточка читается как главная, но не кричит — рядом стоят такие же
   сервисы, просто менее частые. */
.mod.main{min-height:0; margin-bottom:11px; padding:17px 18px; overflow:hidden;
  /* Выделяем СВЕТОМ, а не цветом. Синяя подсветка и синяя рамка перетягивали
     внимание сильнее, чем нужно: карточка главная, но это не тревога.
     Заодно ушёл радиальный градиент — на тёмном экране его граница прозрачности
     видна дугой (полосит). У линейного центра нет, кольца не будет. */
  background:linear-gradient(165deg, rgba(255,255,255,.055), rgba(255,255,255,.015) 60%,
                             rgba(255,255,255,0) 100%), var(--surface-card);
  border-color:var(--border-strong)}
.mod.main .mt{font-size:17px}
.mod.main .ms{max-width:15em}

/* «Дыхание» внутри главной карточки — тот же язык, что в шапке «Памяти о клиентах»:
   размытые пятна с разными периодами. Контур карточки остаётся чётким: свечение
   лежит ПОД содержимым и обрезается скруглением (overflow:hidden на .mod.main).

   Периоды взаимно простые (19, 23, 31 с) — рисунок не повторяется на глазах.
   Двигаем только transform и opacity: их считает видеокарта, экран не тормозит. */
.mod.main .glow{position:absolute; inset:0; z-index:0; pointer-events:none; overflow:hidden;
  border-radius:inherit}
.mod.main .glow i{position:absolute; display:block; border-radius:50%;
  will-change:transform, opacity}
.mod.main .glow i:nth-child(1){left:-10%; top:-60%; width:70%; height:220%;
  background:radial-gradient(closest-side, rgba(90,147,232,.42), rgba(90,147,232,.16) 45%, transparent 82%);
  animation:mainGlow1 19s ease-in-out infinite}
.mod.main .glow i:nth-child(2){left:35%; top:-80%; width:60%; height:240%;
  background:radial-gradient(closest-side, rgba(127,119,221,.38), rgba(127,119,221,.14) 45%, transparent 82%);
  animation:mainGlow2 23s ease-in-out infinite}
.mod.main .glow i:nth-child(3){left:62%; top:-40%; width:55%; height:200%;
  background:radial-gradient(closest-side, rgba(90,147,232,.3), rgba(90,147,232,.1) 45%, transparent 82%);
  animation:mainGlow3 31s ease-in-out infinite}
/* содержимое карточки — над свечением */
.mod.main .mic, .mod.main .mt, .mod.main .ms, .mod.main .badge{position:relative; z-index:1}
@keyframes mainGlow1{
  0%,100%{transform:translate3d(0,0,0) scale(.92);      opacity:.5}
  35%    {transform:translate3d(18%,4%,0) scale(1.18);  opacity:.9}
  70%    {transform:translate3d(-6%,-3%,0) scale(1);    opacity:.6}
}
@keyframes mainGlow2{
  0%,100%{transform:translate3d(0,0,0) scale(1.05);     opacity:.75}
  40%    {transform:translate3d(-20%,-5%,0) scale(.85); opacity:.35}
  75%    {transform:translate3d(10%,4%,0) scale(1.2);   opacity:.85}
}
@keyframes mainGlow3{
  0%,100%{transform:translate3d(0,0,0) scale(1);        opacity:.4}
  45%    {transform:translate3d(-16%,6%,0) scale(1.22); opacity:.7}
  80%    {transform:translate3d(8%,-4%,0) scale(.9);    opacity:.3}
}
@media (prefers-reduced-motion:reduce){
  .mod.main .glow i{animation:none; opacity:.45}
}
.mod .mic{width:40px; height:40px; border-radius:12px; display:flex; align-items:center;
  justify-content:center; margin-bottom:11px; flex:0 0 40px}
.mod.wide .mic{margin-bottom:0}
.mic.blue{background:var(--accent-bg); color:var(--accent-text)}
.mic.green{background:var(--success-bg); color:var(--success-text)}
.mic.grey{background:var(--surface-sunken); color:var(--text-disabled)}
.mic.violet{background:#241E3F; color:#B6A8F0}
.mod .mt{font-size:15px; font-weight:650; letter-spacing:-.1px}
/* Две строки зарезервированы всегда: подпись плитки меняется с одной строки на две
   («3 проекта в работе» или «2 проекта ждут вашего ответа»), и без запаса плитки
   ряда прыгали бы по высоте после ответа сервера (LOADING.md). */
.mod .ms{font-size:12.5px; color:var(--text-secondary); margin-top:3px; line-height:1.4;
  min-height:2.8em}
.mod .body{flex:1; min-width:0}
.mod.soon{cursor:default}
.mod.soon .mt, .mod.soon .ms{color:var(--text-disabled)}
/* ЗНАЧОК С ЧИСЛОМ = «вас ждут», а не «здесь что-то есть» (правило витрины,
   2026-08-09). Он появляется только там, где нужно ДЕЙСТВИЕ человека: клиент
   закончил отбор, созрело напоминание. Счётчики «сколько всего» живут словами
   в подписи — иначе значки горят постоянно и перестают что-либо значить. */
.badge{position:absolute; top:12px; right:12px; min-width:21px; height:21px; padding:0 6px;
  border-radius:11px; background:var(--accent); color:#fff; font-size:12px; font-weight:750;
  line-height:1; display:flex; align-items:center; justify-content:center;
  font-variant-numeric:tabular-nums; box-shadow:0 0 0 3px var(--surface-card)}
.badge.warn{background:var(--warning); color:#2A1D06}
/* На главной карточке счётчик НЕ показываем: он стоит в том же правом верхнем углу,
   что и ряд работ, и синей плашкой выглядывал из-за последней плитки — читалось как
   непонятный синий полукруг. Число и так написано словами в подписи. */
.mod.main .badge{display:none}
.soonlbl{position:absolute; top:15px; right:14px; font-size:10.5px; color:var(--text-disabled)}

/* ═══════════ ЗАГЛУШКИ ЗАГРУЗКИ ═══════════
   Базовое правило интерфейса (LOADING.md): каждый элемент занимает своё место
   с первого кадра. Пока данных нет — на их месте заглушка ТЕХ ЖЕ размеров,
   поэтому после ответа сервера ничего не сдвигается.

   Мерцание синхронно на всём экране: у всех заглушек одна анимация и общая
   фаза — её задаёт `--sk-delay` из shared/skeleton.js (отрицательная задержка
   от общего нуля времени). Без этого заглушки, созданные в разные моменты,
   мерцали бы вразнобой, и экран рябил бы. */
.sk{position:relative; overflow:hidden; border-radius:8px;
  background:var(--surface-sunken)}
.sk::after{content:''; position:absolute; inset:0;
  background:linear-gradient(90deg, var(--surface-sunken), var(--surface-hover),
                             var(--surface-sunken));
  transform:translateX(-100%);
  animation:skshine 1.6s linear infinite;
  animation-delay:var(--sk-delay, 0s)}
@keyframes skshine{
  from{transform:translateX(-100%)}
  to  {transform:translateX(200%)}
}
@media (prefers-reduced-motion:reduce){ .sk::after{animation:none} }

/* Пока блок в состоянии заглушки — он не нажимается и не берёт фокус:
   человек не должен попасть по кнопке, которая через миг станет другой. */
[aria-busy="true"]{pointer-events:none; user-select:none}

/* Готовые формы. Повторяют то, что появится вместо них. */
.sk-row{display:flex; align-items:center; gap:13px; padding:14px 16px;
  background:var(--surface-card); border:0.5px solid var(--border);
  border-radius:18px; margin-bottom:9px}
.sk-av{width:38px; height:38px; flex:0 0 38px; border-radius:11px}
.sk-av.round{border-radius:50%}
.sk-body{flex:1; min-width:0}
.sk-l{height:11px; border-radius:6px}
.sk-l + .sk-l{margin-top:8px}
.sk-w70{width:70%} .sk-w50{width:50%} .sk-w40{width:40%} .sk-w90{width:90%}
/* Карточка целиком — под блоки вроде «Щита автора» или брифа недели */
.sk-card{border-radius:18px; margin-bottom:12px}
.sk-grp{height:12px; width:34%; border-radius:6px; margin:0 2px 10px}

/* ── пустое состояние и ошибка модуля ── */
.empty{padding:13px 15px; border-radius:14px; background:var(--surface-sunken);
  font-size:12.5px; color:var(--text-secondary); line-height:1.5}
.modfail{padding:13px 15px; border-radius:14px; background:var(--danger-bg);
  color:var(--danger-text); font-size:12.5px; line-height:1.5}

.hidden{display:none !important}
