/* 50-a11y.css — накладной слой доступности для светлого языка TeamON One.
   Подключается ПОСЛЕ app.css (index.html:13) и после остальных файлов redesign/.
   Боевые файлы не редактируются: всё здесь перебивает app.css за счёт порядка
   подключения при равной специфичности. Файл решает ровно четыре задачи:
   видимое кольцо фокуса (в т.ч. в forced-colors), универсальный reduced-motion,
   контраст приглушённого текста на молочной подложке и режим prefers-contrast.
   Ни один класс не переименован, новых имён классов нет. */


/* ============================================================
   1. КОНТРАСТ: приглушённый текст на молочном фоне
   ============================================================
   Все коэффициенты ниже посчитаны по WCAG 2.x: относительная яркость
   L = 0.2126·R + 0.7152·G + 0.0722·B, где каждый канал c/255 линеаризован
   как c ≤ 0.03928 ? c/12.92 : ((c+0.055)/1.055)^2.4;
   контраст = (L_светлого + 0.05) / (L_тёмного + 0.05).

   Подложка — молочный --milk #f5f8ef, L = 0.9278.
   Это худший случай для тёмного текста: бумага --paper #ffffff имеет L = 1.0,
   то есть на карточках контраст всегда чуть ВЫШЕ, чем посчитано здесь.
   Порог: мелкий текст ≥ 4.5:1, крупный (≥24px или ≥18.66px bold) ≥ 3:1.

   Что было в боевом CSS (app.css:5-7, значения для тёмной темы):
     --muted   #a2a2ad, L = 0.36539 → (0.9278+0.05)/(0.36539+0.05) = 2.35:1  ПРОВАЛ
     --muted-2 #74747f, L = 0.17734 → 0.9778/0.22734               = 4.30:1  ПРОВАЛ
   Обратите внимание на инверсию: в тёмной теме --muted-2 «глуше», но на светлом
   фоне он оказывается ТЕМНЕЕ и почти проходит, а --muted проваливается вдвое.
   Поэтому пара пересобрана заново, чтобы иерархия «muted-2 глуше muted»
   сохранилась уже на светлом. */
:root {
  /* #5f6b64, L = 0.13869 → 0.9778 / 0.18869 = 5.18:1 — вторичный текст */
  --muted: #5f6b64;
  /* #67736b, L = 0.16207 → 0.9778 / 0.21207 = 4.61:1 — третичный текст,
     светлее --muted, но всё ещё выше порога 4.5:1 для 9-12px подписей */
  --muted-2: #67736b;

  /* Статусные цвета. В app.css:15-17 они рассчитаны на тёмный фон и на молоке
     нечитаемы, при этом используются и как текст (app.css:46 .error 13px,
     app.css:1325, app.css:1435), и как заливка точек 7px (app.css:298-300,
     app.css:1200-1204). Затемнение улучшает оба применения сразу:
     тёмная точка на молоке заметнее пастельной. */
  /* было #57d3a4, L = 0.51294 → 1.74:1 ПРОВАЛ; стало #0d6547 (Emerald из
     брендбука), L = 0.09848 → 0.9778 / 0.14848 = 6.59:1 */
  --success: #0d6547;
  /* было #f0ae6d, L = 0.49902 → 1.78:1 ПРОВАЛ; стало #8a5300,
     L = 0.11589 → 0.9778 / 0.16589 = 5.89:1 */
  --warning: #8a5300;
  /* было #ff7a86, L = 0.36900 → 2.33:1 ПРОВАЛ; стало #b3261e,
     L = 0.11064 → 0.9778 / 0.16064 = 6.09:1 */
  --danger: #b3261e;

  /* app.css:2463 ссылается на --accent-bright, который нигде не объявлен.
     Неразрешимый var() делает всё объявление outline невалидным на этапе
     вычисления значения, то есть кольцо фокуса у того summary просто исчезает.
     Объявляем токен, чтобы починить ссылку в самом боевом файле. */
  --accent-bright: #101713;

  /* Двухтоновое кольцо Ink/Milk — тот же приём, что зафиксирован в
     TEAMON-BRAND-SYSTEM.md («two-tone Ink/Milk focus rings»).
     Ink #101713, L = 0.00770:
       против молока  0.9778 / 0.05770 = 16.9:1
       против ON Green #16d34f (L = 0.47323) → 0.52323 / 0.05770 = 9.07:1
       против Violet  #7657e8 (L = 0.16501) → 0.21501 / 0.05770 = 3.73:1
     То есть Ink проходит порог 3:1 (WCAG 1.4.11) на любой поверхности продукта.
     Молочная прокладка отделяет кольцо от самого элемента: даже если элемент
     залит тем же Ink, полоса молока даёт 16.9:1 с обеих сторон.
     Бренд-фиолетовый как кольцо не берём: #7657e8 на молоке даёт 4.55:1,
     а боевой --accent #8b7cff — всего 3.04:1, то есть на пределе. */
  --a11y-ring: #101713;
  --a11y-ring-inset: #f5f8ef;
  --a11y-ring-width: 3px;
  --a11y-ring-gap: 2px;
}

/* Мелкие подписи с зашитым светлым hex. Это те самые 8-10px из боевого CSS,
   на молоке они читаются хуже всего.
   #aaa1ff, L = 0.41256 → 0.9778 / 0.46256 = 2.11:1 ПРОВАЛ.
   Берём фиолетовый бренда, затемнённый до прохода порога для мелкого текста:
   #5b40cf, L = 0.10395 → 0.9778 / 0.15395 = 6.35:1. Оттенок тот же, что у
   Violet #7657e8, изменена только светлота. */
.eyebrow,
.brand-lockup small,
.brand-name small {
  color: #5b40cf;
}

/* Плейсхолдер — это тоже текст, исключения в WCAG для него нет.
   app.css:1391 задаёт #85858e: L = 0.23715 → 0.9778 / 0.28715 = 3.41:1 ПРОВАЛ.
   Отдаём ему --muted-2 (4.61:1) — минимальный проходной уровень, чтобы
   плейсхолдер не спорил по весу с реально введённым значением. */
::placeholder {
  color: var(--muted-2);
  opacity: 1; /* Firefox по умолчанию гасит плейсхолдер до .54 и ломает расчёт */
}


/* ============================================================
   2. КОЛЬЦО ФОКУСА
   ============================================================
   Боевое поведение: app.css:30 снимает outline у button/textarea/input/select,
   а app.css:32-34 заменяет его на box-shadow 0 0 0 3px rgba(accent, .28).
   Две проблемы. Первая: полупрозрачный акцент при 28% на светлой подложке
   даёт около 1,5:1 при требуемых 3:1. Вторая: в forced-colors браузер
   принудительно обнуляет box-shadow, поэтому индикатор фокуса там исчезает
   полностью. Ниже возвращаем настоящий outline; box-shadow остаётся только
   как молочная прокладка, и его пропажа в forced-colors уже не критична. */

/* Нативные фокусируемые элементы. Специфичность (0,1,1) — ровно как у
   app.css:32, побеждаем порядком подключения, без !important. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
summary:focus-visible,
[tabindex]:focus-visible,
[role="tab"]:focus-visible,
[role="option"]:focus-visible,
[contenteditable]:focus-visible {
  outline: var(--a11y-ring-width) solid var(--a11y-ring);
  outline-offset: var(--a11y-ring-gap);
  /* прокладка ровно шириной зазора: заполняет промежуток между элементом
     и кольцом, поэтому кольцо всегда граничит с молоком, а не с поверхностью
     элемента. Как и в app.css:32-34, на время фокуса собственная тень
     элемента при этом не показывается. */
  box-shadow: 0 0 0 var(--a11y-ring-gap) var(--a11y-ring-inset);
}

/* Компонентные кольца из app.css с собственным цветом или с outline: none.
   Все они специфичнее (0,1,1), поэтому собраны в один :is() — он принимает
   специфичность самого сложного аргумента (.workbench.canvas-full
   .studio-dialogue-resizer, три класса), итог (0,4,0) перекрывает всю группу
   одним правилом вместо двенадцати отдельных.
   Перебиваются: app.css:201, 786, 1883, 1955, 1990, 2463, 2836, 2851. */
:is(
  .account-menu-toggle,
  .team-rail-toggle,
  .team-rail-space-trigger,
  .team-space-option,
  .studio-dialogue-toggle,
  .journey-fields > summary,
  [data-teamon-studio-selectable],
  .work-surface-header h2,
  .workbench.canvas-full .studio-dialogue-header
):focus-visible {
  outline: var(--a11y-ring-width) solid var(--a11y-ring);
  outline-offset: var(--a11y-ring-gap);
  box-shadow: 0 0 0 var(--a11y-ring-gap) var(--a11y-ring-inset);
}

/* app.css:605-606 намеренно переносит индикатор с самого рельса на дочерний
   шеврон — паттерн сохраняем, меняем только цвет на кольцевой Ink. */
.work-surface-rail:focus-visible .work-surface-rail-chevron {
  outline: 2px solid var(--a11y-ring);
  outline-offset: 2px;
}

/* Оба резайзера — узкие полосы у края панели. Вынесенное наружу кольцо там
   обрезалось бы родительским overflow: hidden (app.css:147), поэтому им, как
   и в app.css:2828, отдаём кольцо внутрь. Цвет и толщину наследуют от общего
   правила выше; заодно оставляем внутреннюю полосу из app.css:666, но
   непрозрачную: rgba(accent, .42) на светлом фоне не набирает 3:1.
   Перебивается app.css:666 и app.css:2827-2829. */
.work-resizer:focus-visible {
  outline-offset: -2px;
  box-shadow: inset 3px 0 0 var(--a11y-ring);
}
.workbench.canvas-full .studio-dialogue-resizer:focus-visible {
  outline: var(--a11y-ring-width) solid var(--a11y-ring);
  outline-offset: -2px;
}

/* Клавиатурный фокус никогда не должен быть слабее, чем состояние hover. */
.team-space-option:focus-visible {
  color: var(--ink);
}


/* ============================================================
   3. FORCED-COLORS (режим высокой контрастности ОС)
   ============================================================
   В боевом CSS этой ветки нет вообще. В forced-colors браузер обнуляет
   box-shadow и подменяет цвета системными, поэтому здесь работает только
   outline и только системные ключевые слова. forced-color-adjust: none
   сознательно не используем нигде — смысл режима в том, чтобы отдать выбор
   цветов системе. */
@media (forced-colors: active) {
  /* Фокус — системный Highlight, снаружи элемента. */
  a:focus-visible,
  button:focus-visible,
  input:focus-visible,
  select:focus-visible,
  textarea:focus-visible,
  summary:focus-visible,
  [tabindex]:focus-visible,
  [role="tab"]:focus-visible,
  [role="option"]:focus-visible,
  [contenteditable]:focus-visible {
    outline: 3px solid Highlight;
    outline-offset: 2px;
  }

  /* Отдельным правилом, а не одним списком с нативными элементами выше:
     список селекторов не является forgiving, и если бы движок не понял :is(),
     он выбросил бы вместе с ним и кольцо фокуса нативных контролов. */
  :is(
    .account-menu-toggle,
    .team-rail-toggle,
    .team-rail-space-trigger,
    .team-space-option,
    .studio-dialogue-toggle,
    .journey-fields > summary,
    [data-teamon-studio-selectable],
    .work-surface-header h2,
    .workbench.canvas-full .studio-dialogue-header
  ):focus-visible {
    outline: 3px solid Highlight;
    outline-offset: 2px;
  }

  .work-surface-rail:focus-visible .work-surface-rail-chevron {
    outline: 3px solid Highlight;
    outline-offset: 2px;
  }

  /* Резайзеру возвращаем именно outline: его box-shadow здесь обнулён. */
  .work-resizer:focus-visible,
  .workbench.canvas-full .studio-dialogue-resizer:focus-visible {
    outline: 2px solid Highlight;
    outline-offset: -2px;
  }

  /* Выбранное состояние в боевом CSS показано только заливкой или цветом
     текста, а заливка в forced-colors принудительно становится Canvas —
     то есть состояние пропадает. Возвращаем его рамкой внутрь, CanvasText,
     чтобы визуально не совпадать с Highlight-кольцом фокуса снаружи. */
  .task-tab.active,
  .work-tab.active,
  .nav-item.active,
  .conversation-lane.active,
  .space-surface-tab.active,
  .space-surface-tab[aria-selected="true"],
  .studio-input-mode button.active,
  .segmented button.active,
  .accent-list button.active,
  .team-space-option[aria-selected="true"],
  .team-project.active,
  .team-project[aria-current="page"],
  .journey-stage.current,
  .academy-path-step.current,
  [aria-pressed="true"],
  [aria-checked="true"] {
    outline: 2px solid CanvasText;
    outline-offset: -2px;
  }

  /* Недоступные элементы в боевом CSS различаются только прозрачностью
     (app.css:143, 281, 428, 926, 1137, 1434, 1748). Прозрачность
     в forced-colors ничего не сообщает — нужен системный GrayText. */
  :disabled,
  [aria-disabled="true"] {
    color: GrayText;
    opacity: 1;
  }

  /* Декоративные слои. Градиенты и так будут обнулены системой, но
     #particle-canvas (index.html:79) — это <canvas>, его пиксели системой
     не подменяются, и он может закрасить страницу произвольными цветами
     поверх системной палитры. Гасим весь декоративный набор целиком:
     app.css:84-92, 114-122, 153-156, 157-162, 163-168. */
  .particle-canvas,
  #particle-canvas,
  .ambient-grid,
  .boot-cosmos,
  .login-orbit {
    display: none;
  }

  /* Фирменный знак собран градиентом (app.css:50) и белым штрихом
     (app.css:55) — после подмены цветов он рискует остаться пустым пятном. */
  .brand-mark {
    background: Canvas;
    border-color: CanvasText;
  }
  .brand-mark ellipse {
    stroke: CanvasText;
  }
}


/* ============================================================
   4. PREFERS-REDUCED-MOTION
   ============================================================
   В боевом CSS (app.css:2932-2950) стоит ручной allowlist из полутора десятков
   селекторов — всё, что добавлено позже, автоматически мимо него. Заменяем
   универсальным правилом.

   !important здесь неизбежен и осознан: селектор * имеет специфичность (0,0,0)
   и проигрывает буквально любому объявлению анимации в app.css, а сам
   app.css:2942-2949 уже использует !important внутри своего allowlist.

   Гасим не в none, а в .01ms намеренно: событие transitionend/animationend
   при этом всё-таки выстреливает, а animation-fill-mode доигрывает конечный
   кадр, поэтому элементы, появляющиеся через `animation: … both`
   (например app.css:567-570), не остаются невидимыми.
   JS-анимации это правило не покрывает, но они уже под собственной защитой:
   app.js:1198 и particle-scene.js:7,44 сами проверяют prefers-reduced-motion. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: .01ms !important;
    animation-delay: 0s !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    transition-delay: 0s !important;
  }

  html,
  .app-shell,
  .chat-stage,
  .work-surface {
    scroll-behavior: auto !important;
  }
}


/* ============================================================
   5. PREFERS-CONTRAST: MORE
   ============================================================
   Пользователь явно попросил больше контраста — поднимаем текст и границы
   выше минимальных порогов и утолщаем кольцо фокуса. */
@media (prefers-contrast: more) {
  :root {
    /* #39443e, L = 0.05351 → 0.9778 / 0.10351 = 9.45:1 */
    --muted: #39443e;
    /* #46524b, L = 0.07848 → 0.9778 / 0.12848 = 7.61:1 */
    --muted-2: #46524b;

    /* Границы. app.css:10-12 объявляет --line и --line-strong как
       полупрозрачный белый, на молоке это ноль. 124 объявления border: 1px
       и 68 обращений к var(--line) зависят от этих двух токенов, так что
       здесь достаточно переопределить сами токены.
       #7f8b83, L = 0.24616 → 0.9778 / 0.29616 = 3.30:1 — порог 1.4.11
       для границ элементов управления;
       #5f6b64 → 5.18:1 для усиленной линии. */
    --line: #7f8b83;
    --line-strong: #5f6b64;

    --a11y-ring-width: 4px;
    --a11y-ring-gap: 3px;
  }

  /* Мелкие подписи подтягиваем к уровню основного текста:
     #3b2a86, L = 0.04307 → 0.9778 / 0.09307 = 10.5:1 */
  .eyebrow,
  .brand-lockup small,
  .brand-name small {
    color: #3b2a86;
  }

  /* Прозрачность 0.35-0.62 у выключенных элементов при усиленном контрасте
     опускает их ниже 4.5:1. Поднимаем нижнюю границу; смысл «выключено»
     остаётся на курсоре, атрибуте disabled и отсутствии реакции. */
  :disabled,
  [aria-disabled="true"] {
    opacity: .75;
  }
}


/* ============================================================
   ЧТО СОЗНАТЕЛЬНО НЕ ТРОНУТО
   ============================================================
   - Палитра и фон. --cosmos-base, --ink, --surface, --surface-soft, --line,
     --accent, --accent-rgb, все 203 зашитых hex и 326 rgba-литералов остаются
     зоне палитры. Здесь переопределены ровно те токены, у которых значение
     диктуется расчётом контраста: --muted, --muted-2, --success, --warning,
     --danger. Если слой палитры тоже их задаёт, он должен грузиться РАНЬШЕ
     этого файла либо держать те же коэффициенты 4.5:1 / 3:1 на молоке.
   - Кегль. 22 объявления по 8px и 117 в диапазоне 9-10px — реальная проблема
     читаемости (брендбук требует не мельче 9px для машинных подписей и 11px
     для пояснений), но это правка типографики, а не цвета: здесь такие подписи
     только докрашены до порога. Отдаётся агенту типографики.
   - Тач-цели и мобильные ширины. Ни одного @media (max-width) в файле нет,
     блоки app.css:2215-2249 и app.css:2292+ не затронуты — по условию задачи.
   - Радиусы, тени, backdrop-filter, градиенты. 244 border-radius, 85 box-shadow,
     22 backdrop-filter и 65 градиентов не изменены: единственная тень, которую
     файл трогает, — это тень фокуса из app.css:32-34, и то как замена
     индикатора, а не как декор.
   - body { overflow: hidden } (app.css:24) и .app-shell { height: 100dvh;
     overflow: hidden } (app.css:146-147). Это ограничивает кольцо фокуса
     у элементов на самом краю контейнера и мешает масштабированию текста
     до 200% (WCAG 1.4.4), но снятие overflow — правка раскладки, а не стилей
     доступности; она сломает позиционирование work-surface и chat-stage.
     Зафиксировано как известное ограничение слоя.
   - Skip-link к основному содержимому добавлен: запрет на правку разметки снят,
     узел появился в index.html внутри #app, стили — в конце этого файла.
   - .sr-only (app.css:36-39) оставлен как есть — реализация корректная.
   - [data-teamon-studio-focus] (app.css:2852-2859) не тронут: это подсветка
     смыслового объекта, а не индикатор клавиатурного фокуса. */


/* ССЫЛКА В ОБХОД РЕЛЬСА
   Спрятана над верхней кромкой окна и выезжает только по фокусу. z-index взят
   выше рельса и шапки, но ниже загрузочной шторки: шторка перекрывает #app
   целиком, и на ней ссылки быть не должно. Кольцо фокуса ссылка получает от
   общего правила выше — своего не заводим, чтобы индикатор остался единым. */
.skip-link {
  position: fixed;
  left: var(--sp-3, 12px);
  top: -100px;
  z-index: 40;
  padding: var(--sp-2, 8px) var(--sp-4, 16px);
  border: 1px solid var(--line);
  border-radius: var(--r-sm, 12px);
  background: var(--paper);
  color: var(--ink);
  font-size: var(--t-secondary, 14px);
  text-decoration: none;
  transition: top var(--dur-fast, .16s) var(--ease, ease);
}

.skip-link:focus-visible,
.skip-link:focus {
  top: var(--sp-3, 12px);
}
