/**
 * Слой исправлений: живая проверка на стенде плюс четыре независимых ревью.
 *
 * Сюда попадает только то, что подтверждено измерением или разбором кода.
 * Каждое правило снабжено числом или ссылкой на строку боевого файла,
 * чтобы правку можно было перепроверить.
 *
 * Подключается последним. Порядок остальных файлов задан в index.html и важен:
 * сгенерированный 61-legacy-text-colors.css стоит ДО компонентного слоя.
 */

/* ==================================================================
   1. ТОКЕНЫ
   ================================================================== */

:root {
  /* Акцент как цвет ТЕКСТА.
     Замер: «90%» в настройках — зелёный #16d34f на белом даёт 2.01:1
     при требуемых 4.5:1. Зелёный бренда рассчитан на заливку, а не на буквы. */
  --accent-text: #0d6547;

  /* Ступени приглушённого текста.
     50-a11y.css задаёт --muted #5f6b64 (5.18:1) и --muted-2 #67736b (4.61:1).
     Замер на стенде: подпись роли в шапке набрана --muted-2 и на своей
     фактической подложке даёт 4.39:1 — запаса нет.
     Затемняем ОБЕ ступени, сохраняя порядок: вторичный текст обязан быть
     темнее третичного, иначе иерархия переворачивается.
       --muted   #4d5751 — 6.99:1 на молоке, 7.51:1 на бумаге
       --muted-2 #566158 — 6.02:1 на молоке, 6.47:1 на бумаге */
  --muted: #4d5751;
  --muted-2: #566158;
}

/* Одна шкала скруглений вместо трёх.
   00-tokens.css:123–126 задаёт --r-lg/--r-md/--r-sm/--r-pill,
   10-surfaces.css:70–74 завело собственную пятиступенчатую шкалу,
   30-components.css:51–54 уже ссылается на первую. Сводим вторую к первой,
   чтобы значение жило в одном месте, и доопределяем --r-xs, на который
   компонентный слой ссылается с запасным значением. */
:root {
  --r-xs: 8px;
  --r-shell: var(--r-lg);
  --r-card: var(--r-md);
  --r-inset: var(--r-sm);
  --r-control: var(--r-sm);
  --r-chip: var(--r-xs);
}

/* Усиленный контраст: ступени должны становиться ещё темнее, а не
   возвращаться к значениям из 50-a11y.css. */
@media (prefers-contrast: more) {
  :root {
    --muted: #333c37;
    --muted-2: #3d463f;
  }
}

/* ==================================================================
   2. ЦВЕТ ТЕКСТА, КОТОРЫЙ НЕ ЗАКРЫЛИ ОСТАЛЬНЫЕ СЛОИ
   ================================================================== */

.continuity-form output,
.browser-pairing a,
.chatgpt-device a,
.turn-status-pulse,
.space-item-chip {
  color: var(--accent-text);
}

/* Аватар пользователя.
   Замер: текст rgb(241,239,248) на подложке rgb(238,243,233) = 1.01:1 —
   буква была физически не видна. Зелёный кружок с чернильной буквой даёт 8.2:1. */
.session-avatar {
  background: var(--green);
  color: var(--ink);
}

/* Вертикальная подпись и знак на рельсе Холста.
   Замер: «Холст» rgb(170,166,182) на белом = 2.38:1; иконка #d7d3e3 = 1.3:1. */
.work-surface-rail-core > span {
  color: var(--ink);
  letter-spacing: .01em;
  text-transform: none;
  font-size: 11px;
  font-weight: 600;
}

.work-surface-rail-core svg {
  color: var(--ink);
}

/* Ссылки внутри ответов агента и артефактов.
   Цвет на светлом фоне — слабый носитель смысла, поэтому подчёркивание. */
.bubble a,
.artifact-card a,
.canvas-body a,
.canvas-artifact a,
.shared-message-bubble a {
  color: var(--accent-text);
  text-decoration: underline;
  text-underline-offset: 2px;
  text-decoration-thickness: 1px;
}

/* ==================================================================
   3. ТЁМНЫЕ ПЛАШКИ, ОСТАВШИЕСЯ ОТ ТЁМНОЙ ТЕМЫ
   Текст на них уже перекрашен в тёмный, а подложка осталась чёрной —
   получается чёрное на чёрном. Перекрашиваем именно подложки.
   ================================================================== */

/* Экран входа: два декоративных слоя фиолетово-бирюзовых пятен (app.css:102–112).
   Гасим тем же приёмом, каким уже погашены .ambient-grid и .app-shell::after. */
.login-shell {
  background: var(--milk);
}

.login-shell::before {
  display: none;
}

@media (max-width: 760px) {
  /* Подсказка режима студии: фон rgba(22,21,27,.97) — app.css:2276. */
  .studio-mode-toggle .control-tooltip {
    background: var(--ink);
    color: var(--milk);
    border-color: transparent;
    backdrop-filter: none;
  }

  /* Статус композера: фон rgba(19,24,32,.92) — app.css:2324–2328. */
  .composer-status {
    background: var(--paper);
    border-color: var(--line-strong);
    color: var(--ink);
    backdrop-filter: none;
  }
}

/* Состояние ожидания у кнопки входа.
   Обработчик теперь ставит data-pending на время запроса (app.js), чтобы
   повторное нажатие не создавало вторую сессию. Показываем это состояние:
   кнопка гаснет и курсор меняется, но текст не подменяется — подмена длиной
   в одно слово дёргает раскладку. */
/* Специфичность (0,2,1): иначе .primary:disabled из 30-components.css
   перебивает opacity, и состояние ожидания не видно вовсе. */
button[data-pending="true"],
button.primary[data-pending="true"] {
  opacity: .62;
  cursor: progress;
}

/* Collapsed Worlds Navigator is one quiet dock, not a stack of miniature
   cards. Selection uses a single edge marker; the home orb and owner avatar
   do not gain permanent outer frames. */
.app-shell.team-edition.team-rail-collapsed .team-rail-toggle {
  border-color: transparent;
  background: transparent;
}
.app-shell.team-edition.team-rail-collapsed .team-rail-toggle:hover {
  border-color: transparent;
  background: var(--mist);
}
.app-shell.team-edition.team-rail-collapsed .team-project,
.app-shell.team-edition.team-rail-collapsed .team-project.space-home,
.app-shell.team-edition.team-rail-collapsed .team-project.active,
.app-shell.team-edition.team-rail-collapsed .team-project[aria-current="page"],
.app-shell.team-edition.team-rail-collapsed .team-project.space-home.active,
.app-shell.team-edition.team-rail-collapsed .team-project.space-home[aria-current="page"] {
  border-color: transparent;
  background: transparent;
  box-shadow: none;
}
.app-shell.team-edition.team-rail-collapsed .team-project:hover {
  border-color: transparent;
  background: var(--mist);
}
.app-shell.team-edition.team-rail-collapsed .team-project::before {
  background: var(--accent);
}
.app-shell.team-edition.team-rail-collapsed .team-project-monogram {
  border-color: var(--line);
  color: var(--ink);
  background: var(--mist);
}
.app-shell.team-edition.team-rail-collapsed .team-project.active:not(.space-home) .team-project-monogram,
.app-shell.team-edition.team-rail-collapsed .team-project[aria-current="page"]:not(.space-home) .team-project-monogram {
  border-color: color-mix(in srgb, var(--accent) 22%, var(--line));
  color: var(--ink);
  background: color-mix(in srgb, var(--accent) 12%, var(--paper));
}
.app-shell.team-edition.team-rail-collapsed .team-project.space-home .team-project-monogram,
.app-shell.team-edition.team-rail-collapsed .team-project.space-home.active .team-project-monogram,
.app-shell.team-edition.team-rail-collapsed .team-project.space-home[aria-current="page"] .team-project-monogram {
  border-color: transparent;
  color: var(--ink);
  background: var(--accent);
  box-shadow: none;
}
.app-shell.team-edition.team-rail-collapsed .team-project-list::before {
  background: var(--line);
}
.app-shell.team-edition.team-rail-collapsed .session-account {
  border-color: transparent;
  background: transparent;
}
.app-shell.team-edition.team-rail-collapsed .session-account .account-menu-toggle:hover {
  background: var(--mist);
}

/* Галочка выбранного пространства рисуется из JS и осталась фиолетовой #a99cff
   из тёмной темы: разметку Codex перерисовал, а созданные скриптом узлы — нет.
   Правим цветом, не трогая JS. */
.team-space-option svg,
.team-space-option svg path {
  stroke: currentColor;
}

.team-space-option[aria-selected="true"],
.team-space-option.current {
  color: var(--accent-text);
}

/* Затемняющие подложки под выезжающими панелями.
   Замер: подложка рельса rgba(1,7,14,.58) — почти чёрная плёнка из тёмной темы.
   Поверх молочного интерфейса это выглядит как провал, а не как затемнение.
   Оставляем сам приём, но приводим к чернилам бренда и убираем размытие. */
.team-rail-backdrop,
.drawer-backdrop {
  background: rgba(16, 23, 19, .32);
  backdrop-filter: none;
}

/* Липкие полосы Академии на узком экране: два почти чёрных градиента
   (app.css:3022–3026 и 3095–3100). Мобильный слой цвета не задаёт вообще,
   поэтому долг закрываем здесь, повторяя исходные селекторы и границы. */
@media (max-width: 820px) {
  .academy-focus-bar {
    background: linear-gradient(var(--milk) 75%, transparent);
  }

  .academy-primary-dock,
  .academy-space-view[data-academy-focus="activity"] .academy-primary-dock {
    background: linear-gradient(transparent, var(--milk) 32%);
  }
}

/* Team chat is the same conversation shell with bounded World metadata.
   The roster opens above the compact lane control and author colors remain
   stable across the roster, avatar, name and message accent. */
.conversation-team-tooltip {
  border-color: var(--line);
  background: color-mix(in srgb, var(--paper) 96%, transparent);
  color: var(--ink);
  box-shadow: 0 18px 42px rgba(24, 34, 29, .15), inset 0 1px rgba(255,255,255,.8);
}
.conversation-team-tooltip-title,
.conversation-team-tooltip-status,
.conversation-team-tooltip-member small { color: var(--muted); }
.conversation-team-tooltip-member {
  background: color-mix(in srgb, var(--team-author-color) 9%, var(--paper));
}
.conversation-team-tooltip-member > span:first-child {
  background: color-mix(in srgb, var(--team-author-color) 11%, var(--paper));
}
.shared-message-avatar {
  background: color-mix(in srgb, var(--team-author-color) 11%, var(--paper));
  color: var(--team-author-color);
}
.shared-message-meta strong { color: var(--team-author-color); }
.shared-message-meta time { color: var(--muted-2); }
.shared-message.human .shared-message-bubble {
  border-color: color-mix(in srgb, var(--team-author-color) 18%, var(--line));
  box-shadow: inset 2px 0 var(--team-author-color);
}
.shared-message.own .shared-message-bubble { box-shadow: inset -2px 0 var(--team-author-color); }

/* ==================================================================
   4. ГРАДИЕНТЫ ТЁМНОЙ ТЕМЫ В ЗНАКЕ И ОРБЕ
   app.css:47–56 и 944–949 — радиальные градиенты из трёх чужих цветов.
   В новом языке такого приёма нет, даём плоскую заливку.
   ================================================================== */

.brand-mark {
  background: var(--green-dark);
}

.academy-agent-orb {
  background: var(--green);
}

/* ==================================================================
   5. ПРИВЕТСТВЕННЫЙ ЭКРАН
   .welcome-card попала в общую группу карточек и получила белую коробку
   с прямыми углами и нулевым отступом. Приветствие — это глава, а не карточка.
   ================================================================== */

.welcome-card {
  padding: 0;
  border: 0;
  border-radius: 0;
  background: transparent;
  box-shadow: none;
}

/* Здесь стояло правило на .support-prompts button, .prompt-chip и
   button[data-prompt] — «возвращаем подсказкам подложку». Ни одного из трёх
   селекторов в проекте нет: греп по всему web-public находит их только в этом
   файле и только в самом правиле. Настоящий класс — .starter-prompt, и фон
   с рамкой он получает в 30-components.css. Правило удалено, а не переписано
   на живой селектор: подложка ему уже задана, и второй источник цвета опять
   развёл бы покой и наведение по разным файлам. */

/* ==================================================================
   6. РАСТРОВЫЕ ИЛЛЮСТРАЦИИ
   Все пять PNG перерисованы: раньше это были светящиеся сферы и
   стеклянные объёмы, запечённые на непрозрачном чёрном (проверялось
   пиксельной пробой через canvas — альфа 255, RGB около 8–12), и их
   приходилось ставить на тёмную плашку. Теперь исходники векторные,
   лежат в art/*.svg и растеризуются скриптом art/rasterize.mjs в те же
   пути и те же размеры, так что разметка и sw.js не менялись.
   Фон у растра свой, молочный, поэтому плашка под ним больше не красит
   картинку, а только держит форму и радиус.
   ВАЖНО: только background-color. Сокращённое background стирает
   background-image из app.css:1047 и оставляет пустую плиту.
   ================================================================== */

.team-rail-space-symbol,
.team-space-option-symbol {
  overflow: hidden;
  /* Замер: в развёрнутом рельсе плашка 18x18, крупный радиус дал бы круг. */
  border-radius: 6px;
  background-color: var(--milk);
}

.team-rail-space-symbol img,
.team-space-option-symbol img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Generated celestial assets own their silhouette. Transparent padding keeps
   the Sun's corona and the Worlds' atmosphere clean on both paper and night;
   inherited control fills would recreate the hard discs removed in v2. */
.team-project-monogram.is-sun,
.team-project-monogram.is-world,
.team-project.space-home .team-project-monogram.is-sun,
.app-shell.team-edition.team-rail-collapsed .team-project-monogram.is-sun,
.app-shell.team-edition.team-rail-collapsed .team-project-monogram.is-world,
.app-shell.team-edition.team-rail-collapsed .team-project.space-home .team-project-monogram.is-sun {
  border-color: transparent;
  background: transparent;
  box-shadow: none;
}

.academy-activity-art {
  overflow: hidden;
  border-radius: var(--inset-radius, 36px);
  background-color: var(--milk);
  /* Снимаем тёмный скрим тёмной темы, оставляя саму картинку.
     Версия в адресе обязательна: растр перерисован под светлую тему, а
     капсула не отдаёт для картинок ни Cache-Control, ни ETag — по прежнему
     адресу браузер вправе бесконечно показывать старую тёмную версию. */
  background-image: url('/assets/academy-learning-constellation-v1.png?v=2');
  background-size: cover;
  background-position: center;
}

/* ==================================================================
   7. КЕГЛЬ: ЧЕТЫРЕ МЕСТА НИЖЕ БРЕНДОВОГО ПОЛА И НАВИГАЦИЯ
   Пол из TEAMON-BRAND-SYSTEM.md: лейблы и навигация от 12px,
   пояснительный текст от 11px.
   ================================================================== */

/* Величина берётся из шкалы, а не прибивается числом: те же селекторы уже
   принадлежат роли «метка» в 25-type-scale.css, и дубль числом означал, что
   любая будущая правка шкалы молча не подействует на навигацию и вкладки.
   Запасное значение оставлено на случай, если файл шкалы не подключён. */
.soft-pill,
.onboarding-complete {
  font-size: var(--t-label, 12px);
}

.nav-item,
.work-tab,
.space-surface-tab,
.memory-receipt-action {
  font-size: var(--t-label, 12px);
}

@media (max-width: 820px) {
  .academy-focus-progress,
  .academy-family-metrics span {
    font-size: 11px;
  }
}

/* ==================================================================
   8. ТАЧ-ЦЕЛИ
   WCAG 2.2, критерий 2.5.8 — минимум 24x24. На устройствах с грубым
   указателем поднимаем до 44px независимо от ширины окна: на планшете
   768px палец такой же, как на телефоне.
   ================================================================== */

.text-button {
  min-height: 24px;
  padding-block: 4px;
}

.knowledge-view summary,
.settings-list summary,
details > summary {
  min-height: 24px;
  padding-block: 4px;
}

input[type="range"] {
  min-height: 24px;
}

.team-rail-space-trigger {
  min-height: 24px;
}

@media (pointer: coarse), (max-width: 900px) {
  .team-rail-space-trigger,
  .studio-mode-toggle,
  .space-surface-tab,
  .drawer button.primary,
  .drawer .text-button,
  .identity-form button {
    min-height: 44px;
  }

  /* .studio-mode-toggle отсюда убран: раздел 24 задаёт ему размер
     через --control-size, и запись здесь была мёртвой. */
  .space-surface-tab {
    min-width: 44px;
  }

  /* Элементы, до которых не доставал ни один из полов. */
  .account-menu-toggle,
  .session-logout,
  .glass-button,
  .memory-receipt-action,
  .journal-filters button,
  .soft-pill[type] {
    min-height: 44px;
  }

  /* Круглые кнопки композера и отправка размер получают в разделе 24
     из --control-size; повтор здесь только вводил бы в заблуждение.

     Без этого min-height не создаёт видимой области нажатия. */
  .session-logout,
  .soft-pill[type] {
    display: inline-flex;
    align-items: center;
  }
}

/* ==================================================================
   9. ПРИВЯЗКИ К ВЫСОТЕ ШАПКИ ПОД ЧЁЛКОЙ
   40-mobile.css ввёл --m-header-h с учётом safe-area, но всё, что в боевом
   CSS привязано к шапке, осталось на плоских 60/64/66/72px и под чёлкой
   наезжает. Видно только в установленном на домашний экран приложении,
   в обычном Safari inset-top равен нулю.
   ================================================================== */

@media (max-width: 900px) {
  .app-shell.studio-has-section-tabs .space-surface-tabs {
    top: calc(var(--m-header-h) + 4px);
  }

  .studio-input-mode {
    top: calc(var(--m-header-h) + 6px);
  }

  /* Плавающий диалог студии: снизу домашняя полоса. */
  .workbench.canvas-full .chat-stage {
    padding-bottom: calc(12px + var(--m-safe-bottom));
  }
}

/* canvas-full — это Studio, а не обычный мобильный Canvas. Поэтому шапка не
   резервирует здесь отдельную строку: Studio владеет visual viewport, а её
   единственный выход и остальные полезные controls плавают поверх результата.
   Точный edge-to-edge контракт находится в разделе 32 ниже. */

/* Поля ввода на мобильном: всё, что мельче 16px, заставляет iOS увеличивать
   страницу при фокусе. Замер: поле композера 15px. */
@media (pointer: coarse), (max-width: 900px) {
  .composer textarea,
  .composer input,
  .chat-stage textarea,
  .chat-stage input[type="text"] {
    font-size: 16px;
  }
}

/* ==================================================================
   10. ПЕРЕКЛЮЧАТЕЛЬ АКЦЕНТА
   После перехода на светлую тему он ничего не делает: app.js:7473 пишет цвет
   инлайном в documentElement, а слой токенов перебивает это через !important,
   иначе в 149 местах остался бы фиолетовый тёмной темы. Все три предлагаемых
   цвета — из тёмной темы. Скрываем, а не оставляем мёртвую кнопку.
   Вернуть фичу можно, но это правка JS, то есть уже не дизайн.
   ================================================================== */

fieldset:has(#accent-control) {
  display: none;
}

/* ==================================================================
   11. ВЫБРАННЫЙ РЕЖИМ ВВОДА В СТУДИИ
   Замер на живом стенде: у активной кнопки #studio-user-toggle текст
   белый (app.css:757) на заливке rgba(var(--accent-rgb), .2). После
   перехода на светлую тему акцент — брендовый зелёный, и 20% зелёного
   поверх молока дают почти белый фон: контраст 1.17:1 при требуемых 4.5.
   Подпись выбранного режима читалась хуже невыбранного.

   Приводим к языку сегментированного контрола, который уже используется
   в этом дизайне (30-components.css:280): выбранный сегмент — бумажная
   плашка с чернильным текстом, поднятая тенью над подложкой --mist.
   Акцентную рамку сохраняем, но берём тёмно-зелёный: на белом он держит
   3:1 для графики, в отличие от брендового #16d34f.
   ================================================================== */

/* ИСПРАВЛЕНО ПОСЛЕ РЕВЬЮ. Первая версия красила выбранный сегмент в --paper,
   но сама панель тоже --paper (10-surfaces.css:252), а невыбранные кнопки —
   --mist. Состояние выворачивалось: невыбранные читались как плашки, а
   выбранная растворялась в фоне панели. Приём «поднятая бумажная плашка»
   работает на серой дорожке, здесь дорожка белая, поэтому берём обратный
   ход: невыбранное — просто подпись на панели, выбранное — мягкая зелёная
   плашка бренда с изумрудной рамкой. */
.studio-input-mode button {
  background: transparent;
}

.studio-input-mode button.active,
.studio-input-mode button[aria-pressed="true"] {
  border-color: var(--green-dark);
  background: var(--green-soft);
  color: var(--ink);
}

/* Наведение на уже выбранный сегмент не должно возвращать его к невыбранному
   виду: правило ховера из 10-surfaces.css:593 имеет тот же вес и лежит раньше. */
.studio-input-mode button.active:hover,
.studio-input-mode button[aria-pressed="true"]:hover {
  background: var(--green-soft);
  color: var(--ink);
}

.studio-input-mode button:not(.active):hover {
  background: var(--mist, #eef3e9);
}

/* ==================================================================
   12. ТАЧ-ЦЕЛИ, ДО КОТОРЫХ НЕ ДОСТАЛ ПОЛ ИЗ РАЗДЕЛА 8
   Замер на 390px после того, как стали доступны экраны Академии.
   Все три промаха — про специфичность или про отсутствие правила:

   1. Вкладки раздела, пристыкованные к шапке в режиме Студии.
      app.css:2762 задаёт им min-height: 32px селектором (0,3,0),
      а пол из раздела 8 записан как .space-surface-tab — (0,1,0).
      Более слабое правило проигрывало, и на телефоне вкладки
      оставались 32px вместо 44.
   2. Ссылки-действия внутри карточек семейной Академии:
      app.css:882 задаёт 36px селектором (0,2,0). В списке раздела 8
      их не было вовсе — экран был недоступен, пока в фикстурах
      не появилось пространство academy.
   3. Свернуть/развернуть диалог в Студии: 28x28 (app.css:2845),
      не покрыт ни одним полом.
   ================================================================== */

/* Верхняя граница обязательна. Полоса вкладок уходит в position: fixed
   только ниже 1100px (app.css:3114); выше она остаётся элементом грида шапки
   с контентной строкой 45px, и 44px внутри неё вместе с рамками и отступами
   дают 52px — шапка распирается. На сенсорном ноутбуке шириной 1440
   условие (pointer: coarse) срабатывало и ломало раскладку. */
@media (pointer: coarse) and (max-width: 1099px), (max-width: 900px) {
  .app-shell.studio-has-section-tabs .space-surface-tab {
    min-height: 44px;
  }

  .academy-family-item .academy-family-link {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
  }

  .studio-dialogue-toggle {
    width: 44px;
    height: 44px;
  }
}

/* Отказ от приглашения — единственная текстовая кнопка на экране входа,
   и она не попадала ни под один пол: раздел 8 поднимает до 44px только
   .drawer .text-button, а эта живёт в .login-shell. Замер на 390: 194x27. */
@media (pointer: coarse), (max-width: 900px) {
  .login-shell .text-button {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }
}

/* ==================================================================
   13. КАРТОЧКА УЧАСТНИКА: ИМЯ, ОБРЕЗАННОЕ РЯДОМ С КНОПКАМИ
   Замер на стенде (профиль team, вкладка «Участники» в Холсте):
   строка 431px, колонка действий 277px, имени остаётся 68px при
   нужных 108 — «Марина, редактор» превращалось в «Марина, ...».
   У владельца, где действий нет, то же имя получает 345px.

   Разметка задаёт перенос действий на свою строку, но условие записано
   как @media (max-width: 620px) — это ширина ОКНА (app.css:732-735).
   Панель Холста узкая при любом окне, поэтому правило не срабатывало
   никогда. Условие должно смотреть на ширину контейнера, а не экрана.

   Порог 560px: строке нужно 38 + 11 + имя + 11 + действия, и при
   действиях в 277px этого хватает на имя длиннее измеренного.
   ================================================================== */

/* Контейнер объявлен на всей секции, а не только на списке: панель
   «Добавить» — БРАТ списка, а не его потомок (обе создаются в app.js и
   кладутся в .world-members). Запрос по списку до неё физически не доставал,
   и её собственная колоночная раскладка так и осталась привязанной к ширине
   окна. */
.world-members {
  container-type: inline-size;
  container-name: member-panel;
}

/* Перенесены ВСЕ пять объявлений из @media (max-width: 620px) в app.css:733-739,
   а не два: без остальных трёх в узкой панели оставались 36px у кнопок и
   селекта роли и двухколоночная раскладка контролов приглашения. */
@container member-panel (max-width: 560px) {
  .world-member {
    grid-template-columns: 38px minmax(0, 1fr);
  }

  .world-member-actions {
    grid-column: 1 / -1;
    flex-wrap: wrap;
    justify-content: end;
  }

  .world-member-actions .text-button {
    min-height: 44px;
    padding-inline: 8px;
  }

  .world-member-role {
    min-height: 44px;
  }

  .world-member-add-controls {
    grid-template-columns: 1fr;
  }

  .world-members > header {
    display: grid;
  }
}

/* ==================================================================
   14. ЕЩЁ ТРИ ТАЧ-ЦЕЛИ С ЭКРАНА УЧАСТНИКОВ
   Экран стал доступен только сейчас — до этого фикстуры не давали
   профиль участника World, и промахи было не увидеть. Замер на 390:
     .conversation-lane        43x46 — не хватает ровно пикселя ширины;
     .world-member-add-close   28x28;
     .text-button «Копировать» 77x27 — раздел 8 поднимал до 44 только
                                       .drawer .text-button.
   Пол для .text-button и .icon-button делаем общим, а не точечным:
   оба класса переиспользуются, и следующий такой промах должен
   закрываться сам.
   ================================================================== */

@media (pointer: coarse) and (max-width: 1099px), (max-width: 900px) {
  .conversation-lane {
    min-width: 44px;
  }

  /* Компенсирующая раскладка меню профиля живёт в 40-mobile.css внутри
     max-width: 900px. Без верхней границы сенсорный экран шириной 1440
     получал мобильный крестик 44x44 в десктопном меню. */
  .icon-button {
    min-width: 44px;
    min-height: 44px;
  }

  .text-button {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
  }
}

/* ==================================================================
   15. ТАЧ-ЦЕЛИ ЯЩИКА: ПОСЛЕДНИЕ ШЕСТЬ
   Замер на 390 по вкладкам «Знания», «Подключения» и «Настройки».
   Все шесть — типы контролов, которых не было в списке раздела 8:
     summary внутри карточек            118x25 и 326x38
     .secondary (кнопка и ссылка)       105x39, 127x40
     input[type=range]                  328x24
     .segmented button                  46x28, 52x28, 54x28
     .danger-button                     358x42
   Полы даём по типу контрола, а не по конкретному узлу: иначе
   следующая такая же кнопка снова окажется недотянутой.

   Два места пришлось повторить точнее — там боевые селекторы тяжелее
   типового и первый заход проиграл по специфичности:
     .provider-access summary   (0,1,1) — min-height: 38px, app.css:1728
     .browser-control .secondary (0,2,0) — min-height: 30px, app.css:1644

   Сегментированный контрол: цель нажатия — сама кнопка, поэтому 44 берёт
   она, а дорожка растёт до 52, чтобы кнопки остались внутри рамки.
   ================================================================== */

@media (pointer: coarse), (max-width: 900px) {
  details > summary,
  .knowledge-view summary,
  .settings-list summary,
  .provider-access summary {
    min-height: 44px;
  }

  .secondary,
  .danger-button,
  .browser-control .secondary {
    min-height: 44px;
  }

  a.secondary {
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }

  input[type="range"] {
    min-height: 44px;
  }

  .segmented {
    min-height: 52px;
  }

  .segmented button {
    min-height: 44px;
  }
}

/* ==================================================================
   16. СТАТУСНАЯ ПИЛЮЛЯ В ШАПКЕ ПАНЕЛИ
   Замер на 390, вкладка «Настройки»: «Без лимита ходов» ужимается
   до 78px и переносится на три строки, превращаясь в пятно рядом
   с заголовком. Пилюля — короткая метка состояния, она не должна
   переноситься: сжиматься обязан текстовый столбец, а не она.
   ================================================================== */

.panel-heading .soft-pill {
  flex: 0 0 auto;
  white-space: nowrap;
}

/* ==================================================================
   17. ЛЕНТА ДИАЛОГА УХОДИТ ПОД ФИКСИРОВАННУЮ ШАПКУ
   Замер на 390 и на 900 (сразу после закрытия Холста):
   .product-header — position: fixed, высота 54px; .chat-stage лежит
   в потоке от top: 0, и первое сообщение оказывается на 16px и 26px
   от верха, то есть целиком под шапкой. На скриншоте от него виден
   обрезок между гамбургером и кнопкой действий.
   Раздел 9 закрыл это для .work-surface и не закрыл для ленты.

   Заодно исправлена сама величина --m-header-h. 40-mobile.css считает
   её от базы 64px (полоса 761–1099) и 60px (до 760) — это значения
   app.css:170 и app.css:2292. Фактическая шапка в обеих полосах 54px:
   grid-template-rows: 46px плюс padding 8px сверху и 0 снизу. Разница
   в 6 и 10 пикселей и есть тот зазор, с которым Холст открывался
   ниже шапки. Формула ниже описывает шапку как она есть: строка
   содержимого плюс верхний отступ, который под чёлкой растёт до выреза.
   Проверено подстановкой safe-area-inset-top = 59px (qa/safe-area-sim.css):
   шапка становится 105px, содержимое шапки не обрезается, лента
   начинается ровно под ней.
   ================================================================== */

/* ИСПРАВЛЕНО ПОСЛЕ РЕВЬЮ. Первая версия переопределяла --m-header-h для всей
   полосы до 1099px и для обоих режимов оболочки, а формула снята с одного
   правила — app.css:2230-2232, где padding задан как max(8px, вырез) сверху
   и 0 снизу. Это правило действует только для .app-shell.team-edition и
   только до 900px. В остальных трёх комбинациях отступы другие (9/7 до 760,
   11/8 в полосе 761–1099, 12/12 у team-edition выше 900), и общая формула
   там врала: рабочая область вычиталась не на ту величину.

   Сузили до той же области, где действует исходное правило. Для остальных
   полос снова работает база из 40-mobile.css, как и было. */
@media (max-width: 900px) {
  .app-shell.team-edition[data-teamon-workspace-shell] {
    --m-header-row: 46px;
    --m-header-pad: 8px;
    --m-header-h: calc(var(--m-header-row) + max(var(--m-header-pad), var(--m-safe-top)));
  }
}

/* Отступ ленты под шапку — только для team-edition. В этом режиме шапка
   position: fixed (app.css:2163), лента лежит от нуля и уходит под неё.
   В обычном режиме шапка стоит в потоке, а 40-mobile.css уже укорачивает
   .workbench на высоту шапки — там отступ вычёл бы её второй раз и оставил
   пустую полосу над первым сообщением.

   Исключение для Студии: .workbench.canvas-full .chat-stage становится
   position: fixed (app.css:2766) — это плавающая панель диалога, она шапкой
   не закрыта, и отступ съедал бы 54px её собственной высоты: замер на 390
   дал панель 374x371 с пустотой сверху. */
@media (max-width: 1099px) {
  .app-shell.team-edition[data-teamon-workspace-shell] .workbench:not(.canvas-full) .chat-stage {
    padding-top: var(--m-header-h);
  }
}

/* Потолок 1099px у правила выше был лишним: шапка зафиксирована на ВСЕХ
   ширинах, а компенсация обрывалась. Замер в headless Chrome:

     360   шапка fixed, низ 54,  padding-top сцены 54px  — верно
     1440  шапка fixed, низ 68,  padding-top сцены 0px   — содержимое под шапкой

   Выше 1099px --m-header-h не объявлен (его задаёт мобильная ветка), поэтому
   высота считается из размера контрола и вертикальных отступов шапки:
   44 + 12 + 12 = 68, ровно измеренное значение. Исключение для Студии то же,
   что и выше: там сцена — плавающая панель и шапкой не закрыта. */
@media (min-width: 1100px) {
  .app-shell.team-edition[data-teamon-workspace-shell] .workbench:not(.canvas-full) .chat-stage {
    padding-top: calc(var(--control-size, 44px) + 24px);
  }
}

/* ==================================================================
   18. НАДСТРОЧНАЯ ПОДПИСЬ ЗАДАНИЯ АКАДЕМИИ
   Замер на живом стенде во всех четырёх механиках: подпись над
   заголовком задания красится в rgb(var(--academy-card-rgb))
   (app.css:1036), а это цвет-идентификатор механики, подобранный
   под тёмный фон:
     ответ по тексту      брендовый зелёный  2.01:1
     голос и чтение       161,137,255        2.79:1
     найди доказательство 87,211,164         1.87:1
     собери смысл         204,166,255        2.01:1
   При требуемых 4.5:1 читаемой не была ни одна.

   Сам приём — свой цвет у каждой механики — оставляем: он полезен,
   пользователь по нему узнаёт тип задания. Меняем только светлоту,
   сохраняя оттенок. Замеры на фактической подложке карточки (белая):
     #0d6547 — 7.07   #5a3fc0 — 7.22   #0f6b57 — 6.44   #6a3fa8 — 7.27
   Заливки и рамки на тех же rgb остаются как есть: они идут с альфой
   0.07–0.26, читаются как тон и под требование к тексту не подпадают.
   ================================================================== */

.academy-activity {
  --academy-card-text: var(--accent-text, #0d6547);
}

.academy-activity[data-academy-mechanic="read-aloud"] {
  --academy-card-text: #5a3fc0;
}

.academy-activity[data-academy-mechanic="find-evidence"] {
  --academy-card-text: #0f6b57;
}

.academy-activity[data-academy-mechanic="order-meaning"] {
  --academy-card-text: #6a3fa8;
}

/* Специфичность (0,2,0) — ровно как у боевого правила app.css:1036,
   и наш файл подключён позже. */
.academy-activity-heading .eyebrow {
  color: var(--academy-card-text);
}

/* ==================================================================
   19. ТЁМНОЕ, ЧТО ПРОИГРАЛО ПО СПЕЦИФИЧНОСТИ ИЛИ НЕ ВИДНО АУДИТОРУ
   Найдено разбором каскада, а не замером: аудитор читает только
   background-color, поэтому градиент в фоне для него невидим, а
   затемняющие плёнки лежат в списке осознанных исключений.

   1. Плёнка под рельсом Worlds на узком экране. Раздел 3 чинит
      .team-rail-backdrop весом (0,1,0), а боевое правило app.css:2226
      записано как .app-shell.team-edition .team-rail-backdrop — (0,3,0),
      да ещё внутри @media (max-width: 900px). То есть починка не работала
      ровно там, где была нужна: на телефоне поверх молочного интерфейса
      ложилась почти чёрная плёнка rgba(1,7,14,.58) с размытием.
   2. Нижний док Академии в фокусе оценки. Раздел 3 закрыл близнеца
      [data-academy-focus="activity"] и голый .academy-primary-dock,
      а вариант "feedback" (app.css:3099) пропущен — а он живой:
      в него попадает любой цикл со статусом awaiting_judgment.
   3. Кнопки в подвалах семейных диалогов: рамка rgba(255,255,255,.12)
      и заливка rgba(255,255,255,.045) — на бумаге белое по белому,
      от кнопки остаётся один текст. Третий селектор той же группы,
      .academy-family-stage-row button, уже починен в 10-surfaces.css:565.
   4. Наведение на кнопку сворачивания диалога: подложка была белым
      оверлеем 5.5%, на светлом это ничто — аффорданс пропал.
   5. Фокус поля на карточке входа: rgba(255,255,255,.065) весом (0,2,1)
      перебивает бумажную заливку из 30-components.css. Сейчас незаметно,
      потому что карточка белая, но правило ложное и сломается при первой
      же смене цвета карточки.
   ================================================================== */

@media (max-width: 900px) {
  .app-shell.team-edition .team-rail-backdrop {
    background: rgba(16, 23, 19, .32);
    backdrop-filter: none;
  }
}

@media (max-width: 820px) {
  .academy-space-view[data-academy-focus="feedback"] .academy-primary-dock {
    background: linear-gradient(transparent, var(--milk) 32%);
  }
}

.academy-family-stage-heading button,
.academy-family-dialog footer button {
  border-color: var(--line-strong);
  background: var(--mist, #eef3e9);
  color: var(--ink);
}

/* Главная кнопка того же подвала задана отдельно и тяжелее — (0,3,0),
   app.css:919, с цветами тёмной темы. Общее правило выше её не достаёт. */
.academy-family-dialog footer button.primary {
  border-color: transparent;
  background: var(--green);
  color: var(--ink);
}

.studio-dialogue-toggle:hover {
  background: var(--mist, #eef3e9);
}

.login-card input:focus {
  background: var(--paper);
}

/* ==================================================================
   20. СПЕЦРЕЖИМЫ: ПРАВИЛА ЭТОГО ФАЙЛА ПЕРЕБИВАЛИ СЛОЙ ДОСТУПНОСТИ
   50-a11y.css подключён РАНЬШЕ этого файла, поэтому при равной
   специфичности выигрывает он — то есть мы. Три места из-за этого
   отменяли то, что слой доступности задумал.

   1. Знак приложения. 50-a11y.css задаёт ему background: Canvas
      в forced-colors, а раздел 4 этого файла ставит тёмно-зелёный
      тем же весом (0,1,0) и позже — системный фон терялся.
   2. Состояние ожидания кнопки. Раздел 3 ставит opacity: .62 весом
      (0,1,1) и (0,2,1), а слой доступности нормализует прозрачность
      отключённых элементов до 1 весом (0,1,0): в forced-colors и в
      усиленном контрасте прозрачность — плохой носитель состояния,
      его несёт GrayText. Кнопка входа получает pending и disabled
      одновременно (app.js), так что случай живой.
   3. Иллюстрация Академии. Раздел 6 вернул растровую подложку, но
      url() в forced-colors не гасится (гасятся только градиенты),
      и картинка со своей палитрой ложится поверх системной.
      В списке декоративного из 50-a11y.css её нет — узел появился
      позже самого списка.
   ================================================================== */

/* Прозрачность отменяется в ОБОИХ режимах, а не только в forced-colors:
   в усиленном контрасте слой доступности тоже нормализует её до .75,
   и правило раздела 3 весом (0,2,1) его перебивало. */
@media (prefers-contrast: more) {
  button[data-pending="true"],
  button.primary[data-pending="true"] {
    opacity: 1;
  }
}

@media (forced-colors: active) {
  .brand-mark {
    background: Canvas;
  }

  button[data-pending="true"],
  button.primary[data-pending="true"] {
    opacity: 1;
  }

  .academy-activity-art {
    background-image: none;
  }
}

/* Усиленный контраст: раздел 18 задаёт цвет надстрочной подписи весом
   (0,2,0) и перебивает ветку .eyebrow из 50-a11y.css. Само по себе это
   не нарушение — все четыре цвета дают от 6.0 до 7.3 на молоке. Но в этом
   режиме соседние ступени текста уходят на 9.1–11.4, и цветная подпись
   оказывается СВЕТЛЕЕ обычного приглушённого текста, то есть иерархия
   переворачивается. Затемняем весь набор, сохраняя оттенки. */
@media (prefers-contrast: more) {
  :root {
    --accent-text: #084733;
  }

  .academy-activity {
    --academy-card-text: #084733;
  }

  .academy-activity[data-academy-mechanic="read-aloud"] {
    --academy-card-text: #3b2a86;
  }

  .academy-activity[data-academy-mechanic="find-evidence"] {
    --academy-card-text: #0a4a3c;
  }

  .academy-activity[data-academy-mechanic="order-meaning"] {
    --academy-card-text: #4a2b76;
  }
}

/* Кольцо фокуса у свёртки в мастере: 50-a11y.css даёт положительный
   outline-offset, а родитель .journey-fields обрезает содержимое
   (app.css:2447-2449) — кольцо срезалось с трёх сторон. Боевой файл
   ставил здесь отрицательный offset именно поэтому; возвращаем его,
   а внутреннюю тень оставляем: она рисуется внутри и не обрезается.

   ПРО ВЕС. Первая версия правила была записана как
   `.journey-fields > summary:focus-visible`, то есть (0,2,1), и проигрывала:
   в 50-a11y.css:135 та же свёртка входит в список `:is(...)`, а `:is()`
   принимает вес самого тяжёлого аргумента — там это
   `.workbench.canvas-full .studio-dialogue-header`, то есть (0,4,0).
   Замер это подтвердил: вычисленный outline-offset равнялся 2px при
   `overflow: hidden` у родителя, то есть кольцо действительно срезалось,
   несмотря на комментарий выше.

   Идентификатор `#app` поднимает вес до (1,2,1). Против (0,4,0) выигрывает
   не числом классов, а разрядом: один идентификатор старше любого их
   количества. Свёртка живёт только внутри приложения, поэтому префикс
   ничего не отсекает. */
#app .journey-fields > summary:focus-visible {
  outline-offset: -3px;
}

/* ==================================================================
   21. ТАЧ-ЦЕЛИ: ЧЕТЫРНАДЦАТЬ ПРОМАХОВ, НАЙДЕННЫХ РАЗБОРОМ КАСКАДА
   Замер аудитором их не поймал: часть узлов создаётся скриптом и
   появляется только в редких состояниях, часть живёт в диалогах,
   которые обход не открывает.

   Общая причина одна — специфичность. Полы разделов 8, 12, 14 и 15
   записаны одним классом (0,1,0), а боевые размеры заданы парами
   вида `.identity-actions .primary` (0,2,0) или `.memory-actions button`
   (0,1,1). Ниже каждый случай повторяет боевой селектор.

     .studio-input-mode button            36px  app.css:749
     .identity-actions .primary           34px  app.css:1524
     .provider-actions .primary           34px  app.css:1752
     .work-empty .space-item-action       34px  app.css:1217
     .memory-actions button               30px  app.css:1627
     .shared-message-reply                28px  app.css:469
     .shared-message-quote               ~28px  app.css:476
     .world-member-add select             30px  app.css:713
     .space-winner-choice                ~18px  app.css:1265
     .chatgpt-button                      36px  app.css:1747
     .browser-request-actions button      28px  app.css:1672
     .onboarding-complete                 40px  app.css:1328
     .academy-family-dialog header>button 40px  app.css:896
     .academy-family-stage-heading button 42px  app.css:914
   ================================================================== */

@media (pointer: coarse), (max-width: 900px) {
  .studio-input-mode button,
  .identity-actions .primary,
  .provider-actions .primary,
  .work-empty .space-item-action,
  .memory-actions button,
  .shared-message-reply,
  .shared-message-quote,
  .world-member-add select,
  .chatgpt-button,
  .browser-request-actions button,
  .browser-request-actions a,
  .onboarding-complete,
  .academy-family-stage-heading button,
  .academy-family-dialog footer button,
  .academy-family-stage-row button {
    min-height: 44px;
  }

  /* Крестики закрытия семейных диалогов заданы жёсткими width/height
     (app.css:896), поэтому min-* здесь мало — нужен тот же способ. */
  .academy-family-dialog header > button {
    width: 44px;
    height: 44px;
  }

  /* Метка с радиокнопкой: высоты нет вообще, растим отступами, иначе
     цель нажатия равна высоте строки. */
  .space-winner-choice {
    min-height: 44px;
    padding-block: 4px;
  }

  /* Цитата в общей ленте: недобор только по высоте, ширина уже во всю
     строку. Перевод во флекс здесь запрещён — app.css:476 держит на узле
     text-overflow: ellipsis с overflow: hidden и nowrap, а многоточие
     работает только на блочном контейнере: во флексе текст становится
     анонимным элементом с overflow: visible, и длинная цитата обрезается
     срезом вместо многоточия. Высоту добираем отступами. */
  .shared-message-quote {
    padding-block: 9px;
  }
}

/* ==================================================================
   22. ПЛАНШЕТ С ГРУБЫМ УКАЗАТЕЛЕМ ШИРЕ 900px
   Полы в 40-mobile.css записаны как @media (max-width: 900px) без
   ветки pointer: coarse. На iPad в альбомной ориентации (1024px)
   они выключаются целиком, и элементы возвращаются к боевым
   размерам: навигация 32px, дорожки диалога 30px, вкладки задач 30px,
   оценка 30x30, действие карточки 32px, сворачивание рельса 26x26,
   стартовая подсказка ~36px, крестик меню 28x28. Палец на планшете
   такой же, как на телефоне, поэтому повторяем полы для этой полосы.
   Верхняя граница не нужна: условие само по себе означает касание.
   ================================================================== */

@media (pointer: coarse) and (min-width: 901px) {
  /* Значение то же, что в 40-mobile.css: --m-tap, брендовые 46px.
     Жёсткие 44 давали ровно тот разнобой, ради устранения которого
     написан раздел 24. Свернуть рельс из списка убран: его трек в гриде
     шапки расширяется только до 900px, выше кнопка вылезет за рельс. */
  .nav-item,
  .conversation-lane,
  .task-tab,
  .space-item-action,
  .starter-prompt,
  .ask-teamon {
    min-height: var(--m-tap, 46px);
  }

  .space-rating button,
  .account-menu .icon-button {
    min-width: var(--m-tap, 46px);
    min-height: var(--m-tap, 46px);
  }
}

/* ==================================================================
   27. СЕНСОРНЫЙ УКАЗАТЕЛЬ НА ШИРОКОМ ЭКРАНЕ: ЗАМЕР, А НЕ ДОГАДКА
   Раздел 24 писался по рассуждению: панель агентского браузера
   включает мобильную эмуляцию только ниже 768px, поэтому ветка
   `(pointer: coarse) and (min-width: 901px)` не исполнялась ни разу
   и проверить список было нечем.

   Теперь есть чем: probe-coarse включает эмуляцию касаний протоколом
   отладчика при mobile: false, то есть ровно так, как выглядит
   сенсорный ноутбук — десктопная раскладка плюс палец. Замер на 1280
   дал десять целей ниже брендовых 46px:

     26x26    #team-rail-toggle
     42x42    #account-menu-toggle
     44x44    #team-current-project и .team-project
     44x44    .space-surface-tab (три штуки, одна 64x44)
     154x40   .skip-link
     588x44   #message
     12x900   #work-resizer

   Первые шесть строк закрываются полом. Про две оставшиеся — ниже.
   ================================================================== */

@media (pointer: coarse) and (min-width: 901px) {
  .account-menu-toggle,
  .team-project,
  .space-surface-tab,
  #message {
    min-height: var(--m-tap, 46px);
  }

  /* У вкладок раздела короткие подписи — «Сейчас», «Опыт», — и после подъёма
     высоты они остались 44x46: не хватало двух пикселей по ширине. Правило
     живёт только в сенсорной ветке выше 900px, поэтому узкие полосы, где
     четыре вкладки делят 254px, оно не трогает. */
  .space-surface-tab {
    min-width: var(--m-tap, 46px);
  }

  /* Свёрнутый рельс — отдельный случай, и первая версия правки его не взяла.
     Там боевые правила делают обе кнопки квадратными за счёт width, а не
     только высоты, и записаны весом (0,3,0): app.css:2124 даёт .team-project
     44x44, app.css:2154 — .account-menu-toggle 42x42. Класс весом (0,1,0)
     им проигрывает, поэтому повторяем цепочку целиком. */
  .app-shell.team-edition.team-rail-collapsed .team-project {
    width: var(--m-tap, 46px);
    min-height: var(--m-tap, 46px);
  }

  .app-shell.team-edition.team-rail-collapsed .session-account .account-menu-toggle {
    width: var(--m-tap, 46px);
    min-height: var(--m-tap, 46px);
  }

  /* Переключатель рельса — единственный, кому мало поднять высоту:
     он лежит в треке грида шириной 26px (app.css:1846), и кнопка 46px
     вылезла бы за рельс, где её срежет overflow: hidden. Мобильный слой
     расширяет этот трек, но только до 900px. Повторяем расширение для
     сенсорной ветки — тогда кнопка растёт вместе со своим местом. */
  .app-shell[data-teamon-workspace-shell] .team-rail-brand {
    grid-template-columns: 34px minmax(0, 1fr) var(--m-tap, 46px);
  }

  #team-rail-toggle {
    min-width: var(--m-tap, 46px);
    min-height: var(--m-tap, 46px);
  }

  /* Ссылка в обход рельса — своя же недоработка: 154x40 при поле 46. */
  .skip-link {
    min-height: var(--m-tap, 46px);
    display: inline-flex;
    align-items: center;
  }
}

/* #work-resizer (12x900) сознательно оставлен узким и в раздел 27 не вошёл.
   Это не кнопка, а перетаскиваемая граница: расширение до 46px съело бы
   полосу содержимого с обеих сторон панели. Клавиатурный путь у неё полный —
   role="separator" с aria-valuemin/valuemax/valuenow, которые app.js
   переустанавливает при каждом изменении размера, — а на касании ширину
   границы задаёт сама платформа. Зафиксировано как осознанное решение,
   чтобы следующий замер не открывал его заново. */

/* ==================================================================
   29. ЗНАК БРЕНДА НА ЭКРАНАХ ВХОДА БЫЛ НАБРАН КАК СНОСКА
   Замер на 1280: карточка входа 400px, заголовок 42px, знак 52x52,
   а само имя продукта — 15px, приписка ONE — 10px. Имя продукта
   оказывалось мельче любой подписи на экране и втрое мельче заголовка,
   хотя на этих трёх карточках оно единственное, что представляет
   продукт: шапки и рельса здесь ещё нет.

   Опора — лендинг: там вордмарк в шапке занимает 209x32, то есть звучит
   на уровне заголовка, а не сноски. Повторяем эту роль, а не пиксели:
   лендинг рисует имя картинкой и приписку ONE прячет вовсе, здесь же
   обе части набраны текстом и обе нужны.

   Правило ограничено карточками входа. В рельсе и шапке тот же блок бренда
   стоит в узких треках грида, и подъём кегля выдавил бы его за края —
   там имя работает подписью, и это верно.
   ================================================================== */
.login-card .brand-lockup {
  gap: 16px;
}

/* Имя набирается не шрифтом, а тем же вордмарком, что стоит в шапке
   лендинга: /assets/brand/teamon-wordmark.svg, viewBox 0 0 418 64,
   чернильный #101713. Файл скопирован из marketing-site как есть, без
   пересохранения, чтобы буквы совпадали до узла.

   Приём повторяет лендинг буквально (marketing-site/public/app.css:221):
   текст остаётся в разметке ради доступного имени, но не рисуется —
   font-size: 0 и прозрачный цвет, — а глиф даёт фоновая картинка.
   Размер 209x32 — тот же, что у лендинга в шапке; пропорция 418:64
   сохраняется через contain. */
.login-card .brand-lockup strong {
  display: block;
  width: 209px;
  height: 32px;
  overflow: hidden;
  background: url("/assets/brand/teamon-wordmark.svg?v=1") left center / contain no-repeat;
  color: transparent;
  font-size: 0;
  line-height: 0;
}

.login-card .brand-lockup small {
  /* ONE лендинг прячет вовсе, здесь он нужен: в капсуле это различитель
     редакции — ONE против TEAM на карточках приглашения.

     Цвет фиолетовый по решению владельца. Вес доведён до предельного,
     кегль поднят трижды: 13 → 15, затем на 20% до 18 и ещё на 20% до 22.
     Приписка стоит под вордмарком высотой 32px, и мелкой она читалась
     сноской, а не второй строкой знака. На 22px её высота — две трети
     высоты вордмарка, то есть это уже вторая строка знака, а не подпись.

     ПРО СНЯТЫЕ БЛЁСТКИ. Здесь стояла заливка, обрезанная по контуру букв:
     неподвижный фиолетовый, косой глинт и четыре мерцающие искры. На пробе
     всё это работало, но на 22px эффект читается не как приём, а как смаз
     или артефакт отрисовки — светлое пятно поперёк слова. Снято целиком,
     вместе с кадрами анимации и переменными размеров плиток. Осталась
     обычная фиолетовая надпись. */
  margin-top: 9px;
  font-size: 22px;
  font-weight: 900;
  line-height: 1;
}
/* Цвет здесь НЕ переобъявляется намеренно. Он принадлежит слою доступности:
   50-a11y.css:84 ставит #5b40cf и объясняет почему — боевой #aaa1ff давал
   на молоке 2.11:1, а затемнённый бренд-фиолетовый даёт 6.35:1. Токен
   --violet тут не годится: это исходный #7657e8, на молоке около 4.5:1,
   то есть впритык к порогу для мелкого текста и мимо принятого решения. */

/* Здесь стояли блёстки внутри ONE: шесть слоёв заливки, обрезанной по
   контуру букв, плюс кадры анимации. Приём снят целиком по решению
   владельца — на 22px он читался смазом, а не фактурой. Вместе с ним
   ушли @supports на обрезку фона, keyframes one-sparkle, переменные
   размеров плиток и отдельное правило под prefers-reduced-motion:
   ни одно из них больше ни на что не влияет. */

/* Знак растёт вместе с именем, иначе кружок 52px оказывается меньше
   строки, к которой он приставлен, и блок разъезжается по вертикали. */
.login-card .brand-mark {
  width: 64px;
  height: 64px;
}

/* Ниже 480px карточка 350px: знак 56 плюс зазор 16 оставляют имени 278,
   поэтому вордмарк ужимается пропорционально, а не обрезается. */
@media (max-width: 480px) {
  .login-card .brand-lockup strong {
    width: 170px;
    height: 26px;
  }

  .login-card .brand-mark {
    width: 56px;
    height: 56px;
  }
}

/* ==================================================================
   30. ЗНАК ОЖИВЛЁН: КОЛЬЦА ВРАЩАЮТСЯ ОТНОСИТЕЛЬНО ДРУГ ДРУГА
   Знак собран из двух одинаковых эллипсов, повёрнутых атрибутом на +45
   и -45 градусов (index.html, все семь вхождений).

   ПОЧЕМУ НЕ ВСТРЕЧНОЕ ВРАЩЕНИЕ. Первым делом кольца были пущены навстречу
   с одинаковой скоростью — самое очевидное прочтение просьбы. Отрисовка
   фаз показала, что так нельзя: при встречном ходе взаимный угол меняется
   вдвое быстрее собственного, и за 12-секундный цикл кольца совпадают
   ЧЕТЫРЕ раза. На отрисованной ленте (0, 2, 4, 6, 8, 10 секунд) знак
   узнаваем только на 0 и 6: остальные две трети времени на экране
   одиночный эллипс, то вертикальный, то горизонтальный. Для логотипа
   это неприемлемо, и на 16px особенно.

   ЧТО СДЕЛАНО ВМЕСТО. Кольца идут в одну сторону, но с разной скоростью:
   12 и 16 секунд. Взаимный угол меняется на 7.5 градуса в секунду вместо
   60, полный взаимный цикл — 48 секунд, совпадение случается вдвое реже
   и наступает плавно. Знак читается как объёмная фигура, которая
   переваливается, а не как мигающая пульсация. Совпадение колец
   принципиально неустранимо: любое взаимное вращение обязано провести
   угол через ноль, — вопрос только в частоте и резкости.

   Про базовый угол. CSS-свойство transform перекрывает одноимённый
   ПРЕЗЕНТАЦИОННЫЙ АТРИБУТ, а не складывается с ним, поэтому исходные
   +45 и -45 обязаны быть началом кадров — иначе кольца прыгнули бы
   в положение 0 в первый же момент.

   Про центр. transform-box: fill-box берёт рамку самого эллипса,
   а её центр совпадает с cx/cy = 12,12, то есть с центром знака.
   Без этой строки началом отсчёта был бы угол области рисования,
   и кольца ушли бы по дуге за пределы знака.

   Про запрет движения. Отдельного правила здесь нет намеренно:
   50-a11y.css:307 глобально сводит длительность к .01ms и число
   повторов к единице, а конечные кадры равны 405 и 315 градусам —
   то есть ровно исходным +45 и -45 по модулю оборота. Знак замирает
   в точности в том виде, в каком он нарисован в разметке; проверено
   замером computed transform в режиме prefers-reduced-motion.
   ================================================================== */
@keyframes brand-orbit-outer {
  from { transform: rotate(45deg); }
  to { transform: rotate(405deg); }
}

@keyframes brand-orbit-inner {
  from { transform: rotate(-45deg); }
  to { transform: rotate(315deg); }
}

.brand-mark svg ellipse {
  transform-box: fill-box;
  transform-origin: center;
  animation: brand-orbit-outer 12s linear infinite;
}

.brand-mark svg ellipse:nth-of-type(2) {
  animation-name: brand-orbit-inner;
  animation-duration: 16s;
}

/* ==================================================================
   28. КОМПОЗЕР И КОЛОНКА ЧТЕНИЯ НЕ ИМЕЛИ ОБЩЕГО КРАЯ
   Слой композиции сузил колонку чтения до 620px (35-composition.css:155),
   а поле ввода осталось боевым — min(780px, 100% - 48px) (app.css:1365).
   Замер в headless Chrome на 1440: сцена 1322 от 64, композер 780 от 335,
   первое сообщение от 415. Расхождение 80px с каждой стороны — текст
   и поле, в которое его пишут, стоят на разных вертикалях.

   Это расхождение внёс сам редизайн: до него обе величины были боевыми
   и сходились. Поэтому правка возвращает согласие, а не вводит новое
   правило. Формула повторяет боевую с подставленным числом колонки,
   чтобы поведение на узких ширинах осталось прежним.
   ================================================================== */
@media (min-width: 901px) {
  .workbench:not(.canvas-full) .composer {
    width: min(620px, calc(100% - 48px));
  }
}

/* ==================================================================
   23. ФОН ЛЕНТЫ ДИАЛОГА
   В тёмной теме за лентой работала сцена на canvas: россыпь точек
   со свечением и радиальными градиентами. На светлом языке этот приём
   не живёт, поэтому сцена погашена (10-surfaces.css:144) — и пустая
   лента осталась просто белым полем.

   Возвращаем ощущение фона, но средствами языка: очень тихая россыпь
   точек, без движения, без свечения, без градиентных пятен. Точка здесь
   не звезда, а узел — тот же элемент, из которого собран фирменный знак.
   Четыре слоя с разным шагом дают неповторяющийся рисунок; шаг взят
   заведомо взаимно непериодичным, чтобы сетка не читалась.

   Плотность выбрана по замеру: на молоке точки различимы вблизи и
   полностью растворяются на расстоянии вытянутой руки. Контраст точек
   к фону 1.06:1 — они декоративны и под требования к тексту не подпадают.
   ================================================================== */

/* Специфичность (0,3,0): app.css:2191 задаёт .app-shell.team-edition
   .chat-stage { background: transparent } сокращённой записью, а она
   обнуляет и background-image. Повторяем предка, иначе рисунок не доедет. */
/* Рисунок кладётся на рабочую область, а не на саму ленту: .chat-stage
   ограничена min(100%, 1120px) с автополями (app.css:407), поэтому на
   мониторе 1920 текстура ложилась полосой по центру с чистыми краями и
   двумя вертикальными швами, а на телефоне оставляла нетекстурированные
   48px справа под кнопкой Холста. Рабочая область занимает всё, что не
   закрыто панелями, и швов не даёт. */
.app-shell.team-edition .workbench,
.app-shell .workbench {
  background-image:
    radial-gradient(circle, rgba(17, 196, 91, .055) 1.25px, transparent 1.4px),
    radial-gradient(circle, rgba(118, 87, 232, .038) .9px, transparent 1.05px),
    radial-gradient(circle, rgba(16, 23, 19, .03) .65px, transparent .8px);
  background-size: 263px 241px, 389px 337px, 521px 463px;
  background-position: 31px 17px, 173px 91px, 67px 219px;
  background-repeat: repeat;
}

/* В Студии лента — плавающая панель 430px шириной. Россыпь на таком
   лоскуте читается как грязь на стекле, а не как фон. */
.app-shell .workbench.canvas-full {
  background-image: none;
}

/* Экономия краски там, где пользователь просил тишины. */
@media (prefers-contrast: more), (forced-colors: active) {
  .app-shell.team-edition .workbench,
  .app-shell .workbench {
    background-image: none;
  }
}

/* ==================================================================
   24. ОДНА ГЕОМЕТРИЯ ДЛЯ КНОПОК
   Замер показал три радиуса и два размера на одном экране:
     свернуть рельс   46x46  скруглённый квадрат 12px, заливка mist
     развернуть рельс 46x46  круг, бумага с рамкой
     режим студии     44x44  скруглённый квадрат 12px, бумага
     закрыть Холст    46x46  круг
     закрыть ящик     46x46  круг
     вложение, голос  46x46  круг, без заливки
     отправить        46x46  круг, сплошной зелёный
   Свернуть и развернуть рельс — одно и то же действие, показанное
   двумя разными формами. Это и бросается в глаза.

   Правило простое и запоминающееся:
     круг            — субъект (знак приложения, аватар) и всё, что
                       лежит ВНУТРИ капсулы композера: она сама скруглена
                       до упора, и квадраты внутри неё спорят с формой;
     квадрат 12px    — любая кнопка на плоскости;
     сплошная заливка — только у главного действия экрана.
   Размер один: 44.
   ================================================================== */

/* Один размер на все кнопки-действия. Значение живёт в переменной, потому
   что на касании оно другое: 46px — брендовый минимум владельца, он же
   --m-tap в мобильном слое. Без общей переменной половина кнопок оставалась
   44, половина 46, и ряд получался рваным. */
:root {
  --control-size: 44px;
}

@media (pointer: coarse), (max-width: 900px) {
  :root {
    --control-size: var(--m-tap, 46px);
  }
}

/* ИСПРАВЛЕНО ПОСЛЕ РЕВЬЮ, два дефекта.

   1. #team-rail-toggle из общего списка убран. Он не свободная кнопка,
      а элемент грида шапки рельса с треком 26px (app.css:1846); 44-46px
      в нём дают 18px вылета, который срезает overflow: hidden рельса.
      Мобильный слой расширяет этот трек до --m-tap, но только до 900px,
      поэтому размер задаётся ровно там, где трек к нему готов.
   2. .round-button задан как flex: 0 0 39px (app.css:1404), а закрыть
      Холст и закрыть ящик лежат во флекс-строках. При нулевых grow и
      shrink главный размер берётся из flex-basis, width игнорируется —
      кнопки оставались 39px по ширине при 44px по высоте, то есть
      скруглённым прямоугольником вместо квадрата. Задаём flex-basis. */
.app-shell #team-rail-open,
.app-shell #work-surface-close,
.app-shell #drawer-close,
.app-shell #account-menu-close {
  flex-basis: var(--control-size);
  width: var(--control-size);
  height: var(--control-size);
  border-radius: var(--r-control, 12px);
}

@media (max-width: 900px) {
  .app-shell #team-rail-toggle {
    width: var(--control-size);
    height: var(--control-size);
    border-radius: var(--r-control, 12px);
  }
}

/* Кнопка режима студии несёт подпись и потому шире: фиксируем только высоту. */
.app-shell #studio-open {
  width: auto;
  min-width: var(--control-size);
  height: var(--control-size);
  border-radius: var(--r-control, 12px);
}

/* Внутри капсулы композера остаются круги. Селектор повторяет .composer,
   потому что настоящий конкурент — не
   мобильный слой, а app.css:2889: в Студии композер сжимается до 34px
   селектором .workbench.canvas-full .composer .round-button весом (0,4,0).
   Простой id по ширине его не перебивает, пара «класс плюс id» — да.
   Кнопка «Стоп» в списке обязательна: без неё она одна оставалась 34px,
   и ряд из четырёх кнопок получался ступенькой. */
.composer #attach,
.composer #voice,
.composer #send,
.composer #stop,
.composer .round-button,
.composer .send-button {
  width: var(--control-size);
  height: var(--control-size);
  flex-basis: var(--control-size);
  border-radius: 50%;
}

/* Знак действия везде одной силы: до правки вложение и голос были на тон
   светлее остальных иконок и читались как отключённые. */
#attach,
#voice {
  color: var(--ink);
}

/* ==================================================================
   25. КОМПОЗИЦИЯ СТУДИИ
   Аудитор этого не ловит: он считает контраст, тёмные плашки, тач-цели
   и переполнение, но не отвечает на вопрос «выглядит ли ровно». Замеры
   на 1440 в полноэкранном режиме Академии:

   1. Полоса вкладок раздела, пристыкованная к шапке, растянута на всю
      среднюю колонку грида: контейнер 420px, содержимое кончается на
      993 при правом крае 1269 — 276px пустой белой пилюли. Ширина
      задана как width: 100% (app.css:2757), хотя вкладок всего три
      и им нужно 144px.
   2. Панель режима ввода висит на 120px сверху и заходит на карточку
      Холста, которая начинается на 157. Отступ 120 задан на случай
      пристыкованных вкладок (app.css:2660), но сами вкладки кончаются
      на 54 — панели хватает 70, и тогда она стоит между шапкой
      и карточкой, а не поверх содержимого.
   3. Свёрнутый диалог занимает нижние 114px справа, а рабочая область
      резервирует под него 92px (app.css:2656) — правая колонка
      карточки уходит под панель на 221px по ширине.
   4. Три показателя семейной программы разложены по равным колонкам
      на всю ширину карточки: число и подпись в ячейке 287px читаются
      как пустое место, а не как строка показателей.
   ================================================================== */

/* 1. Пилюля вкладок по содержимому, а не на всю колонку. */
.app-shell.studio-has-section-tabs .space-surface-tabs {
  width: max-content;
  max-width: 100%;
  justify-self: center;
}

/* 2. Панель режима ввода встаёт под шапку, а не на карточку. */
.app-shell.studio-has-section-tabs .workbench.canvas-full .studio-input-mode {
  top: 70px;
}

/* 3. Нижний резерв под свёрнутый диалог: его высота 114px плюс отступ. */
.workbench.canvas-full.academy-active.studio-dialogue-collapsed .academy-stage {
  padding-bottom: 140px;
}

/* 4. Показатели прижимаются друг к другу и к левому краю: строка
   показателей — это строка, а не три пустых колонки во всю ширину. */
.academy-family-metrics {
  grid-template-columns: repeat(3, minmax(0, max-content));
  justify-content: start;
  gap: 12px;
}

/* Плавающее окно диалога стоит белым по белому: рамка снята
   (10-surfaces.css:282), тень мягкая, и содержимое карточки под ним
   выглядит не «уехавшим под панель», а обрезанным на полуслове.
   Замер: панель 360x114 в правом нижнем углу накрывает правую колонку
   карточки на 221px. Само перекрытие законно — это плавающее окно, —
   но граница между ним и содержимым обязана читаться. */
.workbench.canvas-full .chat-stage {
  border: 1px solid var(--line);
  box-shadow: 0 18px 48px rgba(16, 23, 19, .14);
}

/* Кнопка обновления семейной панели стояла одна в правом верхнем углу
   карточки, в 450px от заголовка, к которому относится: шапка растянута
   на всю ширину карточки с раскладкой по краям. Ограничиваем текстовый
   столбец удобной мерой — кнопка встаёт сразу за ним. */
.academy-family-heading > div {
  max-width: 560px;
}

.academy-family-heading {
  justify-content: flex-start;
  gap: 20px;
}


/* ==================================================================
   26. СВОДНОЕ РЕВЬЮ ИНТЕРФЕЙСА: ЦВЕТ, ПОВЕРХНОСТИ, СОСТОЯНИЯ
   Правки по шести доменным проходам. Всё, что здесь, — либо коллизия
   имён между файлами слоя, либо роль без второго признака, либо
   состояние, которого нет вовсе. Геометрия и композиция не трогаются:
   это разделы 24 и 25.
   ================================================================== */

/* 26.1 ТОКЕН «ЯРКИЙ АКЦЕНТ» ХРАНИЛ САМЫЙ ТЁМНЫЙ ЧЕРНИЛЬНЫЙ
   За имя --accent-bright спорят три файла: 00-tokens.css:116 объявляет
   var(--violet), 10-surfaces.css:63 — #7657e8, 50-a11y.css:56 — #101713.
   Побеждает последний, и вычисленное значение на стенде равно #101713.
   Фиолетовое кольцо фокуса, задокументированное в 00-tokens.css, до
   экрана не доезжает ни при каком состоянии.

   Спор решается в пользу чернильного, но явно: имя больше не обещает
   яркости, которой нет, а ссылается на кольцо фокуса слоя доступности —
   тот же цвет, что и у остальных колец, поэтому фокус всюду один. */
:root {
  --accent-bright: var(--a11y-ring, #101713);
}

/* 26.2 «ВЫБРАНО» И «ПРОСТО ПОДЛОЖКА» БЫЛИ ОДНИМ ЦВЕТОМ
   00-tokens.css:67 объявляет --surface-soft как var(--green-soft) —
   мягкую зелёную плашку выбранного состояния. 10-surfaces.css:44
   переобъявляет её как #eef3e9, то есть ровно как --mist, общий токен
   группировки. На стенде оба вернули #eef3e9 при --green-soft #e9f8e7.
   Возвращаем роли её цвет: выбранное состояние обязано отличаться от
   соседней сгруппированной подложки. */
:root {
  --surface-soft: var(--green-soft, #e9f8e7);
}

/* 26.3 СТАТУСНЫЙ ЗЕЛЁНЫЙ РАБОТАЛ ОБЩИМ ЗЕЛЁНЫМ ТЕКСТОМ
   61-legacy-text-colors.css генерируется скриптом и правится только
   через генератор, поэтому исправляем здесь. Там var(--success) роздан
   восьми элементам Академии, из которых статусом является ровно один
   (.academy-family-status). Остальные — ссылка, кнопка-иконка, цифры
   показателей, заголовок пункта, узлы пути, свидетельство, метка
   ревизии: у них зелёный означает «это наш акцент», а не «успех».
   Пока успех и ссылка одного цвета, успех не сообщает ничего. */
.academy-family-icon-button,
.academy-family-metrics strong,
.academy-family-item-heading span,
.academy-family-item .academy-family-link,
.academy-path-history-node,
.academy-path-node,
.academy-current-evidence strong,
.academy-revision-mark {
  color: var(--accent-text);
}

/* 26.4 ТРИ СОСТОЯНИЯ РАЗЛИЧАЛИСЬ ТОЛЬКО ОТТЕНКОМ
   Здоровье сборщика и состояние пилюли — по три значения, и признак
   один: цвет. При дейтеранопии зелёный и янтарный сливаются, при
   монохромной печати сливаются все три. Добавляем форму: круг, треугольник,
   квадрат. Знак ставится перед словом и не заменяет его — текст остаётся
   основным носителем смысла, форма лишь дублирует цвет. */
.builder-health.healthy::before,
.soft-pill[data-state="ready"]::before {
  content: "\25CF\00A0";
}

.builder-health.degraded::before,
.soft-pill[data-state="draft"]::before {
  content: "\25B2\00A0";
}

.builder-health.unreachable::before,
.soft-pill[data-state="blocked"]::before {
  content: "\25A0\00A0";
}

/* 26.5 СТАТУСЫ НЕ ПОПАДАЛИ В РЕЖИМ УСИЛЕННОГО КОНТРАСТА
   Раздел 4 этого файла и 50-a11y.css:332 опускают светлоту приглушённого
   текста, но --success, --warning и --danger в режим не входят ни в одном
   файле. Из-за этого статус оказывается СВЕТЛЕЕ рядового текста — та же
   инверсия иерархии, которую раздел 22 уже чинил для .eyebrow.
   Оттенки те же, светлота опущена вровень со ступенями текста. */
@media (prefers-contrast: more) {
  :root {
    --success: #084733;
    --warning: #613a00;
    --danger: #7d1a14;
  }
}

/* 26.6 ВСПЛЫВАЮЩИЕ ПАНЕЛИ СТОЯЛИ БЕЛЫМ ПО БЕЛОМУ
   10-surfaces.css:196 выдаёт одну и ту же мягкую --card-shadow и
   поверхностям покоя, и всплывающим слоям. Меню профиля, меню пространств
   и панель режима ввода — белая бумага с 6-процентной тенью поверх белого
   рельса: край панели читается только по обрезке текста.
   Тот же приём, что уже применён к плавающему окну диалога Студии
   (раздел 25): тонкая линия плюс заметно более глубокая тень. */
.account-menu,
.team-space-menu,
.studio-input-mode {
  border: 1px solid var(--line);
  box-shadow: 0 24px 70px rgba(16, 23, 19, .12);
}

/* 26.7 ПРАВКА КОМПОЗИЦИИ СТУДИИ ОТМЕНЯЛА NOTCH-СОВМЕСТИМЫЙ ОТСТУП
   Раздел 25 писался по замеру на 1440 и поставил панели режима ввода
   безусловные top: 70px весом (0,5,0). Раздел 9 задаёт той же панели
   top: calc(var(--m-header-h) + 6px) весом (0,1,0) — правило для экрана
   с чёлкой, где шапка доходит до 105px. Безусловное правило его гасило,
   и на телефоне панель уезжала под шапку.
   max() решает обе задачи одним значением: на десктопе побеждают 70px,
   на телефоне с вырезом — высота шапки. */
.app-shell.studio-has-section-tabs .workbench.canvas-full .studio-input-mode {
  top: max(70px, calc(var(--m-header-h, 64px) + 6px));
}

/* 26.8 ДВА ПЕРЕКЛЮЧАТЕЛЯ ИЗ ПЯТИ НЕ ОТВЕЧАЛИ НА КУРСОР
   .conversation-lane, .nav-item, .journal-filters button и
   .space-surface-tab наведение получили ещё в 30-components.css.
   .task-tab и .segmented button не получили его ни там, ни в app.css
   (строки 307 и 1777) — соседняя родня читается как неактивная. */
.task-tab:hover:not(.active),
.segmented button:hover:not(.active) {
  background: var(--rc-paper, var(--paper));
  color: var(--rc-ink, var(--ink));
}

/* 26.9 СТАРТОВАЯ ПОДСКАЗКА МЕНЯЛА ФОН ОТ ЧУЖОГО ПРАВИЛА
   Пара «покой --mist → наведение --mist-strong» задумана целиком в
   10-surfaces.css:648. Поздний файл переопределил только покой, переведя
   его на бумагу, а фон наведения из раннего файла остался живым: подсказка
   при наведении темнеет с белого до #e4ebdf И обводится чернильной рамкой —
   вдвое громче, чем .glass-button, где фон намеренно неподвижен.
   Оставляем бумагу и на наведении: реагирует рамка и цвет текста. */
.starter-prompt:hover {
  background: var(--rc-paper, var(--paper));
}

/* 26.10 ЧЕТЫРЕ КРИВЫЕ ДВИЖЕНИЯ НА ОДНОЙ КАПСУЛЕ КОМПОЗЕРА
   Токены --dur-fast и --ease заведены в 00-tokens.css:163 и не
   использовались ни разу. При этом на кнопках композера одновременно
   работают .15s ease (30-components.css:77), 110ms ease-out и 160ms
   cubic-bezier(.2,0,0,1) (80-icons.css), .16s и .18s ease (app.css):
   соседние элементы разгоняются и тормозят по-разному.
   Переводим на общую кривую. Значения токенов совпадают с кривой
   оболочки teamon-workspace-shell.css, поэтому оболочка и содержимое
   начинают двигаться одинаково. */
.primary,
.secondary,
.glass-button,
.round-button,
.send-button,
.text-button,
.icon-button {
  transition:
    background-color var(--dur-fast) var(--ease),
    border-color var(--dur-fast) var(--ease),
    color var(--dur-fast) var(--ease),
    transform var(--dur-fast) var(--ease),
    box-shadow var(--dur-fast) var(--ease);
}

/* 26.11 ОТКЛИК НА НАЖАТИЕ БЫЛ РАЗНЫМ У СОСЕДНИХ КНОПОК
   scale(.985) на кнопке 44px даёт сдвиг 0.66px — отклик не читается.
   Рядом у кнопки отправки scale(.94), то есть 2.6px, — преувеличенно.
   Одно значение на обе: 0.96 даёт около 1.8px, заметно и не суетливо. */
.primary:active:not(:disabled),
.secondary:active:not(:disabled),
.glass-button:active:not(:disabled),
.round-button:active:not(:disabled),
.send-button:active:not(:disabled) {
  transform: scale(.96);
}

/* 26.12 БЕЙДЖ И КНОПКА В ШАПКЕ ВЫГЛЯДЕЛИ ОДИНАКОВО
   #work-pill — это span, #task-attention — button, и стоят они рядом
   через 9px. Обоим достаётся .soft-pill с прозрачной рамкой, поэтому
   пользователь жмёт по «Работа сохранена» и ничего не получает.
   Признак кликабельности даём только тому, что кликается: атрибутный
   селектор [type] отбирает кнопки, потому что button без type всё равно
   получает type=submit только внутри формы, а здесь кнопки самостоятельные —
   поэтому берём и элемент, и атрибут. */
button.soft-pill,
.soft-pill[type] {
  border-color: var(--line-strong, var(--line));
  cursor: pointer;
}

button.soft-pill:hover,
.soft-pill[type]:hover {
  border-color: var(--ink);
  color: var(--ink);
}

/* 26.13 ЗУМ ВВОДА НА iOS В ДВУХ СПИСКАХ ВЫБОРА
   30-components.css:377 поднимает поля до 16px, но два селекта мимо
   списка: 20-typography.css:361 ставит роли участника 12px, а
   .academy-judgment-fields select наследует базовые 15px через
   font: inherit (app.css:29). Ниже 16px Safari на iOS зумит страницу
   при фокусе и ломает вёрстку целиком. */
   Правим ровно два промаха, а не все поля разом: остальные пятнадцать
   селекторов уже подняты компонентным слоем, а список ролей участника
   стоит в узкой колонке, и общее правило на все select там дало бы
   переполнение. */
@media (pointer: coarse) {
  .world-member-add select,
  .world-member-role,
  .academy-judgment-fields select {
    font-size: 16px;
  }
}

/* 26.14 ЦИФРЫ, МЕНЯЮЩИЕСЯ НА МЕСТЕ, ПРЫГАЛИ ПО ГОРИЗОНТАЛИ
   Счётчики живут в кружках и пилюлях фиксированной ширины, и при переходе
   9 → 10 пропорциональные цифры сдвигают содержимое. app.css уже применяет
   табличные цифры к соседним значкам (строки 433 и 460), так что правка
   заодно убирает несогласованность внутри одного ряда. */
.button-count,
.nav-item span,
.journey-fields-count,
.onboarding-progress {
  font-variant-numeric: tabular-nums;
}

/* 26.16 ПОСЛЕДНЯЯ ВКЛАДКА ЯЩИКА БЫЛА НЕДОСТУПНА ГЛАЗУ
   Замер в headless Chrome на 360: контейнер .drawer-tabs 360px, содержимое
   461px, последняя вкладка «Настройки» начинается на 370 — то есть на 10px
   за правым краем, и при нулевой прокрутке от неё видно РОВНО НОЛЬ пикселей.
   Полоса прокручивается вбок (app.css:1475 overflow-x: auto), но признака
   прокрутки нет ни одного: пользователь видит пять разделов из шести
   и не знает, что шестой существует.

   На 1440 содержимое 519 при контейнере 519 — переполнения нет, поэтому
   правило ограничено узкой полосой и на десктопе не появляется.

   Затухание у правого края плюс запас отступа: край последней вкладки
   перестаёт совпадать с краем контейнера, и обрезка становится видимой.
   scroll-padding держит вкладку, до которой доскроллил revealSettingsTab,
   на комфортном расстоянии от края. */
@media (max-width: 900px) {
  .drawer-tabs {
    padding-inline: 12px 28px;
    scroll-padding-inline: 12px;
    -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 24px), transparent);
    mask-image: linear-gradient(to right, #000 calc(100% - 24px), transparent);
  }
}

/* 26.15 ЗАМЕТКА О ШКАЛЕ КЕГЛЕЙ
   Дубль величины 12px, стоявший в разделе 7 рядом с ролью «метка» из
   25-type-scale.css, снят в самом разделе 7: там теперь var(--t-label).
   Отдельного правила здесь не нужно — одна величина в одном месте. */

/* ==================================================================
   31. УЗЛЫ, ПРИШЕДШИЕ С РЕЛИЗОМ 1.14.3

   Слой редизайна собирался поверх снимка 1.13.1. За это время прод
   получил чипы хода, переключатель тарифа, паспорт пространства
   «Проекты» и вход через Clerk — около 19 КБ новых правил в app.css,
   которых слой никогда не видел.

   Генератор 61-legacy-text-colors.css часть работы закрыл: он захватил
   23 новых объявления color со светлым значением, включая
   .plan-control-copy small (#93dfca → var(--success)). Но генератор
   разбирает ТОЛЬКО color. Заливки, границы и тени остаются как есть,
   а в новых правилах их задают через rgba(255,255,255,.02…07) — приём
   тёмной темы, где белая плёнка поверх почти чёрного даёт различимую
   поверхность. На молоке #f5f8ef белое с прозрачностью 2% не даёт
   ничего: разница с фоном меньше одной ступени яркости.
   Ниже — поверхности и границы для этих узлов из палитры слоя.
   ================================================================== */

/* 31.1 ПЕРЕКЛЮЧАТЕЛЬ ТАРИФА
   Карточка и обе кнопки выбора стояли на белой плёнке и на молоке
   сливались с меню в одно пятно: рамка есть, содержимое неразличимо. */
.plan-control {
  background: var(--paper, #fff);
}

.plan-options button {
  border-color: var(--line, #dfe5dc);
  background: var(--milk, #f5f8ef);
}

.plan-options button:hover {
  background: var(--green-soft, #e9f8e7);
}

/* Выбранный тариф: рамку берём насыщеннее, потому что именно она несёт
   состояние, а заливку — мягкой зелёной плашкой, на которой чернильный
   текст остаётся читаемым. */
.plan-options button[aria-checked="true"] {
  border-color: var(--accent-text, #0d6547);
  background: var(--green-soft, #e9f8e7);
  box-shadow: none;
}

/* 31.2 ЧИПЫ ХОДА
   Устроены на двух переменных: --chip задаёт цвет текста через
   color-mix, --chip-rgb — заливку и рамку. Значения --chip идут из
   токенов и перекрашиваются сами, а все четыре тройки --chip-rgb
   выписаны числами тёмной темы: 162,162,173 (светло-серый),
   87,211,164 (мятный), 240,174,109 (песочный). На молоке заливка
   в 8% от таких цветов неотличима от фона, а рамка в 22% еле видна.
   Переопределяем сами тройки — правила прода при этом работают
   как написаны, включая состояние is-live. */
.turn-chip {
  --chip-rgb: 77, 87, 81;
  border-color: rgba(var(--chip-rgb), .34);
  background: var(--paper, #fff);
}

/* ON Green на молоке даёт около 2:1 и для текста не годится: берём
   Emerald, тот же тон в тёмной ступени. */
.turn-chip-kind-context,
.turn-chip-kind-tool,
.turn-chip-kind-skill {
  --chip: var(--accent-text, #0d6547);
  --chip-rgb: 13, 101, 71;
}

/* Тройка совпадает с фактическим значением --warning: слой доступности
   затемняет его до #8a5300, и брать сюда #8f5a12 из 00-tokens.css значило бы
   красить рамку и заливку чуть другим янтарём, чем текст рядом. */
.turn-chip-kind-artifact,
.turn-chip-boundary {
  --chip: var(--warning, #8a5300);
  --chip-rgb: 138, 83, 0;
}

.turn-chip-quiet {
  --chip-rgb: 77, 87, 81;
  /* Прод гасит тихий чип до .68 прозрачности. На тёмном фоне это
     приглушение, на молоке — потеря контраста: #4d5751 на #f5f8ef даёт
     7.4:1, а он же на 68% прозрачности — около 4.1:1, ниже нормы для
     мелкого текста. Приглушаем цветом, а не прозрачностью. */
  opacity: 1;
  color: var(--muted-2, #67736b);
}

/* Текущий шаг: заливка заметная, текст остаётся чернильным. */
.turn-chip.is-live {
  border-color: rgba(var(--chip-rgb), .5);
  background: rgba(var(--chip-rgb), .1);
  box-shadow: none;
}

@media (prefers-reduced-motion: no-preference) {
  /* Дыхание построено на box-shadow, который выше снят. Возвращаем его
     только внутри анимации, иначе у живого чипа осталась бы статичная
     тень от прод-правила. */
  .turn-chip.is-live {
    animation: turn-chip-breath-milk 2.4s ease-in-out infinite;
  }

  @keyframes turn-chip-breath-milk {
    0%, 100% { box-shadow: 0 0 0 3px rgba(var(--chip-rgb), .08); }
    50% { box-shadow: 0 0 0 5px rgba(var(--chip-rgb), .04); }
  }
}

/* 31.3 ПАСПОРТ ПРОСТРАНСТВА «ПРОЕКТЫ»
   Блоки паспорта разделены рамками rgba(255,255,255,.055…075). На молоке
   ни одна из них не видна, и список задач, документов и материалов
   читается как сплошное полотно без структуры. */
/* Раздел паспорта — подложка, его содержимое — бумага. Первая версия ставила
   белым и то, и другое, и замер показал 1:1: карточка задачи на карточке
   раздела не отличалась ничем, кроме волосяной линии в 1.19:1. Структура,
   которая держится на одной линии, на светлом экране пропадает первой.
   Разводим на две ступени: раздел уходит на подложку, элементы остаются
   бумагой, и вложенность читается сменой поверхности, а не рамкой. */
.project-passport-section {
  border-color: var(--line, #dfe5dc);
  background: var(--mist, #eef3e9);
}

.project-task,
.project-document,
.project-material,
.project-person,
.project-primary-result,
.project-capability-list > li,
.project-session-list > li {
  border-color: var(--line, #dfe5dc);
  background: var(--paper, #fff);
}

/* Статус задачи несёт состояние цветом, а заливка у него та же белая
   плёнка — на молоке кружок пропадал целиком, оставался только текст. */
.project-task-status {
  background: var(--line-strong, #cfd7cd);
}

.project-task-status.running,
.project-task-status.active {
  background: var(--accent-text, #0d6547);
  box-shadow: none;
}

.project-material-mark {
  border-color: var(--line, #dfe5dc);
  background: var(--green-soft, #e9f8e7);
  color: var(--accent-text, #0d6547);
}

/* Заголовочная плашка паспорта шла градиентом от мятного к белой плёнке.
   Второй стоп на молоке не работает, а первый даёт полосу поперёк карточки.
   Ровная мягкая заливка — но замер показал, что её одной мало: #e9f8e7
   на молоке #f5f8ef даёт 1.03:1, то есть полосы на экране нет вовсе.
   Мягкие тона на светлом фоне низкоконтрастны по своей природе, поэтому
   границу несёт линия, а заливка остаётся подсказкой, а не разделителем. */
.project-passport-hero {
  background: var(--green-soft, #e9f8e7);
  border-bottom: 1px solid var(--line, #dfe5dc);
}

.project-passport-empty,
.project-unavailable-card {
  border-color: var(--line, #dfe5dc);
  /* У карточки недоступного проекта background — сокращённая запись из двух
     частей: лавандовый радиальный градиент старой темы поверх почти чёрного
     rgba(17,16,25,.78). Подменить половину нельзя, объявление переписывается
     целиком, и градиент уходит вместе с подложкой. */
  background: var(--paper, #fff);
  /* Прод вешает сюда 0 24px 80px rgba(0,0,0,.2) — тень тёмной темы, на молоке
     она читается как грязное пятно. Берём тень слоя. */
  box-shadow: var(--shadow, 0 18px 60px rgba(16, 23, 19, .06));
}

/* Знак недоступного проекта остался на лавандовой заливке старой темы. */
.project-unavailable-mark {
  border-color: var(--line, #dfe5dc);
  background: var(--green-soft, #e9f8e7);
  color: var(--accent-text, #0d6547);
}

/* Отмеченный документ: ON Green в 4% на молоке не читается как выделение,
   а рамка в 20% почти не видна. Состояние несёт рамка — она единственная
   отличается от соседних карточек заметно; заливку оставляем бумажной,
   иначе отмеченный документ сливается с зелёной шапкой паспорта. */
.project-document.featured {
  border-color: var(--accent-text, #0d6547);
  background: var(--paper, #fff);
}

/* 31.4 СНЯТАЯ ЗАЯВКА
   Кнопка отзыва стоит на белой плёнке в 2.5%. На молоке от неё остаётся
   только текст, и жест «отозвать» перестаёт читаться как кнопка. */
.queued-withdraw {
  border-color: var(--line, #dfe5dc);
  background: var(--paper, #fff);
}

.queued-withdraw:hover {
  background: var(--green-soft, #e9f8e7);
}

/* Project rail identity: keep accessible text, render the accepted wordmark,
   and remove decorative thumbnails that collapse at navigation size. */
#team-brand > .team-brand-copy > strong {
  display: block;
  width: 104px;
  height: 16px;
  overflow: hidden;
  background: url("/assets/brand/teamon-wordmark.svg?v=1") left center / contain no-repeat;
  color: transparent;
  font-size: 0;
  line-height: 0;
}

.app-shell:not(.team-rail-collapsed) #team-brand > .brand-mark {
  display: none;
}

.app-shell:not(.team-rail-collapsed)[data-teamon-workspace-shell] .team-rail-brand,
.app-shell:not(.team-rail-collapsed) #team-brand {
  grid-template-columns: minmax(0, 1fr) var(--m-tap, 46px);
}

#rail-space-switcher {
  margin-top: 8px;
}

#rail-space-menu {
  left: 0;
}

#team-rail-space-symbol {
  display: none;
}

#rail-space-trigger {
  grid-template-columns: minmax(0, auto) 12px;
  min-height: 24px;
  padding: 0 7px;
  border: 1px solid rgba(16, 23, 19, .09);
  border-radius: 8px;
  background: rgba(245, 248, 239, .72);
  cursor: pointer;
}

#rail-space-trigger:hover,
#rail-space-trigger[aria-expanded="true"] {
  border-color: rgba(13, 101, 71, .22);
  background: #fff;
}

.team-space-option-symbol {
  display: none;
}

.team-space-option {
  grid-template-columns: minmax(0, 1fr) 16px;
}

/* ==================================================================
   32. MOBILE STUDIO = THE WHOLE VISUAL VIEWPORT

   Full Studio used to inherit two pieces of ordinary shell geometry: the
   product header and the Space/World heading. On a phone this pushed the live
   Preview down by roughly a quarter of the screen even though the surface was
   already position:fixed. Studio is the work mode, not a page inside the
   shell: the same work surface owns the visual viewport and shell controls are
   overlays. The Preview iframe is not duplicated and no second route appears.

   Browser/OS chrome remains outside the Web viewport. In an installed PWA the
   safe-area insets keep the exit and dialogue clear of the notch/home bar.
   ================================================================== */

@media (max-width: 820px) {
  /* The shell still owns auth and state, but it no longer owns visible space. */
  .app-shell.studio-active .product-header,
  .app-shell.team-edition.studio-active .product-header {
    position: fixed;
    z-index: 24;
    inset: 0;
    width: auto;
    height: 0;
    min-height: 0;
    padding: 0;
    pointer-events: none;
  }

  .app-shell.studio-active .product-header > :not(.header-actions),
  .app-shell.studio-active .header-actions > :not(#studio-open) {
    display: none;
  }

  .app-shell.studio-active .header-actions {
    display: contents;
  }

  /* One reachable exit remains; it floats instead of reserving a header. */
  .app-shell.studio-active #studio-open {
    position: fixed;
    z-index: 25;
    top: calc(env(safe-area-inset-top, 0px) + 8px);
    right: calc(env(safe-area-inset-right, 0px) + 8px);
    width: var(--m-tap, 46px);
    min-width: var(--m-tap, 46px);
    height: var(--m-tap, 46px);
    min-height: var(--m-tap, 46px);
    pointer-events: auto;
  }

  .app-shell.studio-active .workbench,
  .app-shell.team-edition.studio-active .workbench {
    grid-column: 1 / -1;
    width: 100%;
    height: 100vh;
    height: 100dvh;
  }

  .app-shell.studio-active .workbench.canvas-full .work-surface,
  .app-shell.team-edition.studio-active .workbench.canvas-full .work-surface {
    inset: 0;
    width: 100%;
    height: 100vh;
    height: 100dvh;
    padding: 0;
    border: 0;
    border-radius: 0;
  }

  /* A live site or an onboarding document fills every intermediate layout
     box. Neither the Journey card nor the onboarding wrapper may create a
     second frame around the exact Preview. */
  .app-shell.studio-active .workbench.canvas-full.studio-has-live-site #work-view-canvas,
  .app-shell.studio-active .workbench.canvas-full.studio-has-live-site .work-canvas,
  .app-shell.studio-active .workbench.canvas-full.studio-has-live-site .journey-canvas.studio.has-live-site,
  .app-shell.studio-active .workbench.canvas-full.studio-has-live-site .builder-panel,
  .app-shell.studio-active .workbench.canvas-full #work-view-canvas:has(.onboarding-canvas.has-document),
  .app-shell.studio-active .workbench.canvas-full .work-canvas:has(> .onboarding-canvas.has-document),
  .app-shell.studio-active .workbench.canvas-full .onboarding-canvas.has-document {
    width: 100%;
    height: 100%;
    min-height: 0;
    margin: 0;
    padding: 0;
    overflow: hidden;
    border: 0;
    border-radius: 0;
  }

  .app-shell.studio-active .workbench.canvas-full.studio-has-live-site #work-view-canvas,
  .app-shell.studio-active .workbench.canvas-full #work-view-canvas:has(.onboarding-canvas.has-document) {
    display: block;
  }

  .app-shell.studio-active .workbench.canvas-full.studio-has-live-site .work-canvas,
  .app-shell.studio-active .workbench.canvas-full.studio-has-live-site .journey-canvas.studio.has-live-site,
  .app-shell.studio-active .workbench.canvas-full.studio-has-live-site .builder-panel,
  .app-shell.studio-active .workbench.canvas-full .work-canvas:has(> .onboarding-canvas.has-document),
  .app-shell.studio-active .workbench.canvas-full .onboarding-canvas.has-document {
    display: grid;
    grid-template-rows: minmax(0, 1fr);
  }

  .app-shell.studio-active .workbench.canvas-full.studio-has-live-site .journey-progress-rail,
  .app-shell.studio-active .workbench.canvas-full.studio-has-live-site .builder-panel > footer {
    display: none;
  }

  .app-shell.studio-active .workbench.canvas-full .onboarding-canvas.has-document::before {
    display: none;
  }

  .app-shell.studio-active .workbench.canvas-full.studio-has-live-site .builder-site,
  .app-shell.studio-active .workbench.canvas-full.studio-has-live-site .builder-site-loading {
    display: block;
    width: 100%;
    height: 100%;
    min-height: 0;
    margin: 0;
    border: 0;
    border-radius: 0;
  }

  .app-shell.studio-active .workbench.canvas-full .onboarding-document {
    display: block;
    width: 100%;
    height: 100%;
    min-height: 0;
    margin: 0;
    border: 0;
    border-radius: 0;
  }

  /* Creator mode, live operation and dialogue stay reachable as overlays; the
     site continues underneath them instead of being resized around them. */
  .app-shell.studio-active .workbench.canvas-full .studio-input-mode {
    top: calc(env(safe-area-inset-top, 0px) + 8px);
    right: calc(env(safe-area-inset-right, 0px) + var(--m-tap, 46px) + 16px);
    left: calc(env(safe-area-inset-left, 0px) + 8px);
    width: auto;
  }

  .app-shell.studio-active .workbench.canvas-full .work-surface-actions {
    top: calc(env(safe-area-inset-top, 0px) + var(--m-tap, 46px) + 16px);
    right: calc(env(safe-area-inset-right, 0px) + 8px);
  }

  .app-shell.studio-active .workbench.canvas-full.studio-dialogue-collapsed .chat-stage {
    bottom: calc(env(safe-area-inset-bottom, 0px) + 8px);
  }
}

/* A collapsed Studio dialogue is a launcher, not a smaller composer. Keep the
   singleton dialogue in the DOM and turn its existing toggle into the TeamON
   orb, so reopening restores the same conversation, frame and position. */
.workbench.canvas-full.studio-dialogue-collapsed .chat-stage {
  width: 64px !important;
  height: 64px !important;
  min-width: 64px;
  min-height: 64px;
  padding: 0;
  overflow: visible;
  border: 0;
  border-radius: 50%;
  background: transparent;
  box-shadow: none;
}

.workbench.canvas-full.studio-dialogue-collapsed .studio-dialogue-header {
  width: 64px;
  height: 64px;
  min-height: 64px;
  padding: 0;
  overflow: visible;
  border: 0;
  cursor: default;
}

.workbench.canvas-full.studio-dialogue-collapsed .studio-dialogue-header strong,
.workbench.canvas-full.studio-dialogue-collapsed .composer {
  display: none;
}

.workbench.canvas-full.studio-dialogue-collapsed .studio-dialogue-toggle {
  position: relative;
  width: 64px;
  height: 64px;
  flex: 0 0 64px;
  overflow: hidden;
  border: 1px solid rgba(255,255,255,.2);
  border-radius: 50%;
  background: radial-gradient(circle at 35% 28%, #b5abff, var(--accent) 52%, #483d9f);
  box-shadow: 0 12px 36px rgba(0,0,0,.34), 0 0 30px rgba(var(--accent-rgb),.28), inset 0 1px 1px rgba(255,255,255,.58);
  color: transparent;
  font-size: 0;
  cursor: pointer;
  transition: transform .16s ease, box-shadow .16s ease;
}

.workbench.canvas-full.studio-dialogue-collapsed .studio-dialogue-toggle::before {
  content: "";
  position: absolute;
  inset: 13px;
  background: center / contain no-repeat url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Cellipse cx='16' cy='16' rx='8.5' ry='3.75' transform='rotate(45 16 16)' fill='none' stroke='rgba(255,255,255,.88)' stroke-width='1.4'/%3E%3Cellipse cx='16' cy='16' rx='8.5' ry='3.75' transform='rotate(-45 16 16)' fill='none' stroke='rgba(255,255,255,.88)' stroke-width='1.4'/%3E%3C/svg%3E");
}

.workbench.canvas-full.studio-dialogue-collapsed .studio-dialogue-toggle:hover {
  background: radial-gradient(circle at 35% 28%, #c4bcff, #8d7dff 52%, #5145aa);
  box-shadow: 0 15px 42px rgba(0,0,0,.38), 0 0 38px rgba(var(--accent-rgb),.38), inset 0 1px 1px rgba(255,255,255,.64);
  transform: translateY(-1px) scale(1.025);
}

.workbench.canvas-full.studio-dialogue-collapsed .studio-dialogue-toggle:active {
  transform: scale(.97);
}

@media (max-width: 820px) {
  .workbench.canvas-full.studio-dialogue-collapsed .chat-stage {
    right: max(10px, env(safe-area-inset-right));
    bottom: max(10px, env(safe-area-inset-bottom));
    width: 58px !important;
    height: 58px !important;
    min-width: 58px;
    min-height: 58px;
  }

  .workbench.canvas-full.studio-dialogue-collapsed .studio-dialogue-header,
  .workbench.canvas-full.studio-dialogue-collapsed .studio-dialogue-toggle {
    width: 58px;
    height: 58px;
    min-height: 58px;
    flex-basis: 58px;
  }
}

/* The fullscreen mobile shell normally hides every product-header child except
   the exit action. Worlds with sections need their one compact navigation row
   as well; it is an interactive overlay, not a second reserved header. */
@media (max-width: 820px) {
  .app-shell.studio-active.studio-has-section-tabs
    .product-header > .space-surface-tabs {
    display: flex;
    pointer-events: auto;
  }
}
