/* CyberAI design tokens - light theme.

   Контраст: --faint был #A39A8B, это 2.3:1 на бумажном фоне - ниже минимума
   WCAG AA (4.5:1) для мелкого текста, а именно им набраны подписи под
   цифрами, даты и пояснения. 05.08 затемнён до 4.6:1. Разница на глаз
   невелика, а читаемость меняется заметно - особенно на ноутбуке при
   боковом свете. Проверять новые цвета обязательно на обеих темах. */
:root{
  --paper:#F7F3EC;--card:#FFFFFF;--ink:#17130E;--on-ink:#F7F3EC;--body:#3D362C;
  --muted:#6B6255;--faint:#746B5C;--line:#E6DECF;--line2:#D9CFBB;--soft:#F0EADF;
  --soft2:#FBF7EF;--field:#FDFCF9;--accent:#FF4D1C;--accent-dark:#D8390B;--accent-soft:#FFE7DD;
  --green:#1E9E6F;--green-soft:#DFF3EA;--green-text:#1D7A4F;
  --amber:#E8A013;--amber-soft:#FBF0D8;--amber-text:#B07C0A;
  --red:#D8452B;--red-soft:#FADFD8;
  --diff-del-bg:#FDEDE8;--diff-del-text:#8A3B28;--diff-add-bg:#E4F4EC;--diff-add-text:#1D5C40;

  /* Оранжевый на белом даёт 3.32:1 - ниже минимума WCAG AA (4.5) для текста.
     Кнопка «Оплатить картой» белыми буквами на фирменном цвете читается хуже,
     чем кажется, и первым это замечает не дизайнер, а человек на солнце.
     Поэтому цвета два: --accent остаётся фирменным и живёт там, где текста
     нет (полосы, точки, иконки, рамки), а под белый текст идёт --accent-btn
     (4.66:1). Ссылки акцентом - --accent-link (4.9:1). */
  --accent-btn:#D8390B;--accent-btn-hover:#B4300A;--accent-link:#C63308;

  /* Шкала радиусов. Была стихийной: 6, 7, 8, 9, 10, 11, 12, 13, 14, 16, 18,
     20, 22 - тринадцать значений, отличить которые на глаз невозможно, а
     совпадать они перестают при первой же правке. Четыре ступени и «кругло». */
  --r-xs:8px;--r-sm:10px;--r-md:14px;--r-lg:18px;--r-pill:999px;

  /* Тени. Ровно три: приподнятая карточка, всплывающее меню, окно поверх
     экрана. Больше уровней глаз всё равно не различает, а разнобой заметен. */
  --sh-1:0 1px 2px rgba(23,19,14,.06);
  --sh-2:0 8px 24px rgba(23,19,14,.10);
  --sh-3:0 24px 60px rgba(23,19,14,.22);
}
html[data-theme="dark"]{
  --paper:#141110;--card:#1E1A16;--ink:#F2EDE4;--on-ink:#17130E;--body:#D8D0C2;
  --muted:#ABA091;--faint:#8E8474;
  /* В тёмной теме фон уже тёмный, и белый текст на оранжевом не нужен:
     кнопки красятся тем же акцентом, а текст на них тёмный. */
  --accent-btn:#FF5A2D;--accent-btn-hover:#FF7A50;--accent-link:#FF8A63;
  --line:#332D26;--line2:#403830;--soft:#2A241E;
  --soft2:#191512;--field:#252019;--accent:#FF5A2D;--accent-dark:#FF7A50;--accent-soft:#3D231A;
  --green:#2FB582;--green-soft:#1C332A;--green-text:#7ED2AC;
  --amber-soft:#39301B;--amber-text:#E0B45B;
  --red:#E0563A;--red-soft:#3B221C;
  --diff-del-bg:#3A211B;--diff-del-text:#E09A85;--diff-add-bg:#1C332A;--diff-add-text:#7ED2AC;
}
html{color-scheme:light}
/* Цветовую схему переключаем ОТДЕЛЬНО от темы: при её смене браузер заново
   растрирует весь текст, и на фоне плавного перехода это выглядит как резкий
   скачок шрифта. site.js ставит data-scheme в конце перехода.
   Пока data-scheme ещё не выставлен (первая загрузка страницы) - берём тему,
   там перехода нет и растрировать нечего. */
html[data-scheme="dark"],
html[data-theme="dark"]:not([data-scheme]){color-scheme:dark}
/* Типографика: перенос по смыслу, а не по ширине. text-wrap работает не
   везде, и это нормально - там, где нет, остаётся прежнее поведение. */
body{margin:0;background:var(--paper);-webkit-font-smoothing:antialiased;
  -moz-osx-font-smoothing:grayscale;font-family:'Golos Text',sans-serif;color:var(--ink);
  text-rendering:optimizeLegibility}
h1,h2,h3,h4{text-wrap:balance}
p,li{text-wrap:pretty}
/* Мельче 11px в интерфейсе не бывает: подписи под столбиками графика были
   9px - это уже не «мелкий шрифт», а «текст, который не читают».
   Цифры - табличными: в столбце чисел разной ширины глаз спотыкается
   на каждой строке, потому что колонка «пляшет». */
.bal,.stat .v,.tile .v,.ref-v,.mono{font-variant-numeric:tabular-nums}
/* Ссылка акцентом на бумаге даёт 3.0:1 - для текста мало. Отдельный цвет
   ссылок (4.9:1), фирменный остаётся у некстовых элементов. */
a{color:var(--accent-link);text-decoration:none}
a:hover{color:var(--accent-btn-hover)}
::selection{background:#FFD9CC}
html[data-theme="dark"] ::selection{background:#5A2C1B}
button{font-family:'Golos Text',sans-serif}
input,textarea,select{font-family:'Golos Text',sans-serif;color:var(--ink)}
@keyframes blinkdot{50%{opacity:.3}}
@keyframes shimmer{0%{background-position:100% 0}100%{background-position:-100% 0}}
@keyframes spin{to{transform:rotate(360deg)}}

/* toast
   Уведомление уходит левее, когда в правом нижнем углу сидит кнопка виджета:
   они стояли друг на друге, и «В очередь» читалось из-под кружка чата -
   находка владельца 21.08.

   Отступ приходит переменной, которую ставит сам виджет (`w.js`), а не
   зашит числом: виджета на странице может не быть вовсе, а может быть слева -
   тогда сдвигать нечего и незачем. Умолчание `0px` - страницы без виджета
   ведут себя как раньше. */
.ca-toast{position:fixed;right:calc(24px + var(--ca-widget-gap, 0px));bottom:24px;z-index:9999;display:flex;align-items:center;gap:9px;
  background:var(--ink);color:var(--on-ink);border-radius:13px;padding:12px 18px;font-size:13.5px;font-weight:500;
  box-shadow:0 12px 32px rgba(23,19,14,.25);opacity:0;transform:translateY(8px);transition:opacity .25s,transform .25s}
.ca-toast.on{opacity:1;transform:none}
.ca-toast svg{flex-shrink:0}
/* На телефоне вбок уходить некуда - уводим вверх, над кнопкой виджета.
   Кнопка занимает низ до 78 пикселей, поэтому 92: остаётся зазор, и палец,
   тянущийся к чату, не попадает в уведомление. */
@media(max-width:600px){
  .ca-toast{right:16px;left:16px;bottom:92px;justify-content:center}
}

/* шапка сайта (компонент <site-nav> из site.js) */
/* Место под шапку, пока её не дорисовал site.js. Шапку собирает скрипт, и
   до него тег пуст: страница рисовалась без шапки, а потом вся съезжала
   вниз на её высоту - на телефоне на 130 пикселей (замер 01.10: сдвиг
   вёрстки 0,16 при норме до 0,1). Высоты - замеренные на проде по ширинам;
   шапка зависит от языка и страницы, поэтому взяты русские значения. На
   главной шапка на телефоне ниже (там спрятана кнопка) - своё число в ней.
   Правило действует, только пока тег пуст (:empty): у нарисованной шапки
   всё как раньше, включая прилипание к верху при прокрутке - блочный
   site-nav запер бы .sn внутри себя, и прилипать ей было бы некуда. */
site-nav:empty{display:block;min-height:73px}
@media(max-width:1100px){site-nav:empty{min-height:104px}}
@media(max-width:1000px){site-nav:empty{min-height:100px}}
@media(max-width:760px){site-nav:empty{min-height:96px}}
@media(max-width:480px){site-nav:empty{min-height:176px}}
.sn{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:18px 48px;
  border-bottom:1px solid var(--line);position:sticky;top:0;background:var(--paper);z-index:40}
.sn-left{display:flex;align-items:center;gap:34px;min-width:0}
.sn-logo{font-family:'Unbounded',sans-serif;font-weight:700;font-size:20px;color:var(--ink);white-space:nowrap}
.sn-logo span{color:var(--accent)}
.sn-nav{display:flex;gap:22px;font-size:13.5px;font-weight:500}
.sn-a{color:var(--muted);white-space:nowrap}
.sn-a:hover{color:var(--ink)}
/* Текущая страница: цветом и подчёркиванием снизу. Одного цвета мало -
   на «Тарифах» акцентная ссылка сливается с оранжевыми кнопками рядом. */
.sn-a.on{color:var(--ink);font-weight:600;box-shadow:inset 0 -2px 0 var(--accent)}
.sn-right{display:flex;align-items:center;gap:12px}
/* Контакты в шапке - указание владельца 18.08. Телефон крупнее и темнее
   мессенджеров: по нему звонят, а не читают. */
.sn-phone{font-size:13.5px;font-weight:700;color:var(--ink);white-space:nowrap}
.sn-phone:hover{color:var(--accent-dark)}
.sn-msg{font-size:12.5px;font-weight:600;color:var(--muted);white-space:nowrap}
.sn-msg:hover{color:var(--accent-dark)}
/* «Войти» - обведённая кнопка, а не строка текста. Замечание владельца
   20.09: её не видно в шапке. И не мудрено - голая надпись стояла между
   переключателями темы и языка и чёрной кнопкой «Попробовать бесплатно»,
   то есть между четырьмя нарисованными элементами управления. Глаз читает
   рамку как кнопку, а текст - как подпись, и ищет вход там, где рамка.
   Обводка, а не заливка: заливок в шапке должно остаться ровно одна -
   у главного действия. Два одинаково заметных действия рядом - это ноль
   заметных.

   Цвет обводки - `--faint`, а не `--line2`, которым обведены карточки.
   Замер контраста к фону шапки: `--line2` даёт 1.4 в светлой теме и 1.61
   в тёмной - рамка есть в разметке и почти не видна глазом, то есть
   правка была бы сделана вхолостую. У `--faint` 4.75 и 5.02: рамка
   читается в обеих темах и при этом не спорит с заливкой соседней
   кнопки. */
.sn-login{font-size:13.5px;font-weight:600;color:var(--ink);padding:9px 18px;
  white-space:nowrap;border:1.5px solid var(--faint);border-radius:999px}
.sn-login:hover{color:var(--accent-dark);border-color:var(--accent-dark)}
.sn-try{background:var(--ink);color:var(--on-ink);border-radius:999px;padding:10px 22px;
  font-size:13.5px;font-weight:600;white-space:nowrap}
.sn-try:hover{background:var(--accent);color:#fff}
/* Шапка на средних экранах. Замер 20.08 headless-браузером на стейдже:
   между 901 и 1365 пикселями меню заезжало под правую группу - «Справка»
   печаталась поверх телефона, а пункт «API» не был виден вовсе. Ниже 901
   шапка переносится в две строки правилом `body.pub header` (в конце
   файла), выше 1365 всё помещается само - сломана была ровно середина, то
   есть ноутбуки 1280 и 1366 и половина неразвёрнутых окон.

   Почему это не ловилось: `.sn-left` умеет сжиматься (`min-width:0`), а
   `.sn-nav` внутри - нет, поэтому меню не обрезается и не переносится, а
   просто рисуется поверх соседа. Замер вёрстки смотрит выход за край
   экрана, а выхода за край тут нет.

   Порядок уступок тот же, что на телефоне: сначала уходят мессенджеры,
   телефон остаётся - по нему звонят, а не читают. Не хватило и этого -
   шапка переносится в две строки.

   Порог 1439, а не 1365, хотя ломалось с 1365: на 1366 - а это самая
   частая ширина ноутбука - запас между «API» и телефоном был 15 пикселей.
   Это не запас, а совпадение: одно слово в меню длиннее, и шапка снова
   поверх себя. На 1440 запас 89 пикселей, вот там мессенджеры и остаются. */
@media(max-width:1439px){
  .sn{padding:18px 24px}
  .sn-left{gap:22px}
  .sn-nav{gap:16px}
  .sn-msg{display:none}
}
@media(max-width:1100px){.sn{flex-wrap:wrap;row-gap:10px}}
@media(max-width:1000px){.sn{padding:14px 18px}.sn-left{gap:18px}.sn-nav{gap:14px;font-size:13px}}
@media(max-width:760px){
  /* Шапка на телефоне. До 23.08 она занимала 207 пикселей на экране в 800 -
     четверть первого экрана, - и это была не задумка, а конфликт двух
     правил. Здесь стояло `overflow-x:auto` в расчёте на одну прокручиваемую
     строку меню, а ниже по файлу правило `body.pub header nav` включало
     перенос через `!important` и побеждало. Прокрутка не работала никогда:
     пункты просто уезжали на вторую строку.

     Теперь строк две вместо четырёх: логотип с меню и ряд с
     переключателями и кнопкой. Меню прокручивается пальцем. */
  .sn{flex-wrap:wrap;padding:12px 16px;row-gap:8px}
  .sn-left{width:100%;gap:14px;flex-wrap:nowrap;min-width:0}
  .sn-nav{overflow-x:auto;flex-wrap:nowrap!important;min-width:0;gap:16px;
    padding-bottom:2px;scrollbar-width:none;-webkit-overflow-scrolling:touch}
  /* Полоса прокрутки под меню - лишняя рамка в шапке: пальцем и так видно,
     что список едет. */
  .sn-nav::-webkit-scrollbar{display:none}
  /* «Войти» на телефоне пряталась совсем (`display:none`), и войти в
     кабинет с телефона было нельзя вовсе - ни с лендинга, ни с любой
     другой публичной страницы. Найдено 20.09 по замечанию владельца о
     заметности кнопки. Место под неё есть: ниже 560 главная кнопка и так
     уходит на свою строку целиком, а в верхнем ряду остаются только два
     переключателя. Поэтому не прячем, а ужимаем. */
  .sn-login{padding:8px 14px;font-size:13px}
  .sn-right{width:100%;justify-content:space-between;gap:8px}
  /* И главное: на телефоне шапка НЕ липкая. Липкая шапка в три ряда
     занимает пятую часть экрана всегда - не только когда на неё смотрят.
     На широком экране она остаётся приклеенной: там это стоит 60
     пикселей из тысячи, а не 170 из 800. */
  .sn{position:static}
}

/* контакт поддержки в шапке (компонент <tg-support> из site.js) */
.tg-sup{display:inline-flex;align-items:center;gap:6px;border:1px solid var(--line);border-radius:999px;
  padding:6px 12px;font-size:13px;font-weight:600;color:var(--muted);white-space:nowrap}
.tg-sup:hover{color:var(--ink);border-color:var(--line2)}
/* Ник вытесняет из шапки кнопку «Попробовать бесплатно» - на узком экране
   остаётся один значок, ссылка при этом никуда не девается. */
/* Совсем узкие экраны: кнопка не помещается рядом с переключателями
   (76 + 91 + 206 против 328 доступных на 360), и её отправляем на свою
   строку целиком - на телефоне это привычная и удобная цель для пальца.
   На 560 и шире она помещается рядом, и там строка остаётся одна. */
@media(max-width:560px){
  .sn-try{flex:1 1 100%;text-align:center;padding:11px 16px}
}
@media(max-width:1100px){.tg-sup-nick{display:none}.tg-sup{padding:7px 9px}}

/* cookie-плашка
   Слева внизу, а не полосой во всю ширину: полоса перекрывает содержимое
   и на телефоне съедает пол-экрана. Появляется с задержкой и плавно -
   выскочившая в первую секунду плашка читается как ошибка страницы. */
.ca-cookie{position:fixed;left:24px;bottom:24px;z-index:9998;width:300px;
  background:var(--card);color:var(--ink);border:1px solid var(--line);border-radius:14px;
  padding:16px;font-size:13px;line-height:1.5;box-shadow:0 14px 36px rgba(23,19,14,.18);
  opacity:0;transform:translateY(10px);transition:opacity .3s,transform .3s}
.ca-cookie.on{opacity:1;transform:none}
.ca-cookie a{color:var(--accent)}
.ca-ck-line{margin-bottom:12px}
/* Кнопка во всю ширину и высотой в 48 - указание владельца 15.08: по ней
   должно попадать пальцем не глядя. 48px - нижняя граница, ниже которой
   попадание становится делом удачи. */
.ca-cookie .ca-ck-yes{display:block;width:100%;min-height:48px;border:0;border-radius:12px;
  background:var(--accent);color:#fff;font-family:inherit;font-size:15px;font-weight:700;cursor:pointer}
.ca-cookie .ca-ck-yes:hover{filter:brightness(1.06)}
/* Отказ - мелкой ссылкой под кнопкой: выбор есть, но он не спорит
   с основным действием за внимание. */
.ca-cookie .ca-ck-no{display:block;margin:8px auto 0;border:0;background:transparent;
  color:var(--muted);font-family:inherit;font-size:12px;cursor:pointer;text-decoration:underline;
  padding:4px 8px}
.ca-cookie .ca-ck-no:hover{color:var(--ink)}
/* Плашка cookie на телефоне поднята над кнопкой чата. Круглая кнопка
   виджета стоит в правом нижнем углу (56 пикселей плюс отступ 22), и при
   `bottom:12px` она ложилась прямо на ссылку «Только необходимые» - то
   есть на выбор, который человек по закону должен иметь возможность
   сделать. Тем же способом 21.08 подняли уведомления сервиса. */
@media(max-width:560px){.ca-cookie{left:12px;right:12px;bottom:88px;width:auto}}

/* sidebar */
/* Место под сайдбар занимаем стилями, не дожидаясь скрипта.
   Разметку сайдбара рисует site.js, и пока он не выполнился, <app-sidebar> -
   пустой строчный элемент нулевой ширины: страница успевает отрисоваться
   прижатой к левому краю, а потом прыгает на 264px вправо. Со стороны это
   выглядит как «вёрстка сломалась и починилась». Размеры те же, что у .sb
   внутри, поэтому кадр до скрипта совпадает с кадром после. */
app-sidebar{display:block;width:264px;flex:0 0 264px;min-height:100vh;background:var(--paper);box-sizing:border-box}
.sb{width:264px;min-height:100vh;background:var(--paper);border-right:1px solid var(--line);display:flex;flex-direction:column;padding:20px 14px 16px;box-sizing:border-box;font-family:'Golos Text',sans-serif;flex-shrink:0}
.sb-logo{font-family:'Unbounded',sans-serif;font-weight:700;font-size:19px;color:var(--ink);letter-spacing:-0.02em}
.sb-logo:hover{color:var(--ink)}
.sb-bot{display:flex;align-items:center;gap:10px;background:var(--card);border:1px solid var(--line);border-radius:14px;padding:10px 12px;margin-bottom:16px;color:var(--ink)}
.sb-bot:hover{border-color:var(--ink);color:var(--ink)}
/* Переключатель проектов в карточке бота: список раскрывается под ней */
.sb-bot-wrap{position:relative}
.sb-bot[role="button"]{cursor:pointer;width:100%}
.sb-projects{position:absolute;left:0;right:0;top:calc(100% - 8px);z-index:20;background:var(--card);border:1px solid var(--line);border-radius:14px;padding:6px;box-shadow:0 10px 30px rgba(0,0,0,.12);display:flex;flex-direction:column;gap:2px;max-height:320px;overflow:auto}
.sb-projects.hide{display:none}
.sb-proj{border:0;background:transparent;text-align:left;font:inherit;font-size:13.5px;color:var(--ink);padding:9px 12px;border-radius:10px;cursor:pointer;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.sb-proj:hover{background:var(--soft)}
.sb-proj.on{background:var(--soft);font-weight:700}
.sb-proj-new{color:var(--accent);font-weight:600;border-top:1px solid var(--line);border-radius:0 0 10px 10px;margin-top:2px}
.sb-nav{display:flex;flex-direction:column;gap:2px}
.sb-nav a{display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:11px;font-size:14px;font-weight:500;background:transparent;color:var(--muted)}
.sb-nav a:hover{color:var(--ink)}
.sb-nav a.on{background:var(--card);color:var(--ink)}
/* Подписи групп меню кабинета (22.10). */
.sb-group{font-size:11px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--faint);padding:14px 12px 4px}
.sb-group:first-child{padding-top:2px}
/* Метка у пункта меню - красная, а не акцентная (указание владельца 18.08):
   акцентным оранжевым в кабинете покрашено всё активное - кнопки, ссылки,
   выбранная площадка, - и метка в этом ряду читается как оформление.
   Красный здесь значит одно: вас ждут. Тот же цвет у счётчика вкладок
   (.kind-n) и у метки в суперадминке. */
.sb-badge{background:var(--red);color:#fff;font-size:10.5px;font-weight:700;border-radius:999px;padding:1px 7px}
.sb-badge:empty{display:none}
.sb-credits{background:var(--card);border:1px solid var(--line);border-radius:14px;padding:14px;margin-bottom:10px}
.sb-topup{display:block;text-align:center;background:var(--ink);color:var(--on-ink);border-radius:999px;padding:8px 0;font-size:13px;font-weight:600}
.sb-topup:hover{background:var(--accent);color:#fff}
.sb-profile{display:flex;align-items:center;gap:10px;padding:8px 10px;border-radius:11px;color:var(--muted)}
.sb-profile:hover{background:var(--soft);color:var(--muted)}

/* Плавное переключение светлой и тёмной темы.
   Класс theme-anim ставит site.js на время переключения и снимает через секунду.
   Постоянный переход вешать нельзя: вместе с темой замедлились бы наведения
   на кнопки и ссылки, и интерфейс стал бы вязким.
   Анимируем только цветовые свойства - тени и трансформации не трогаем,
   иначе браузер перерисовывает лишнее и переход дёргается. */
/* Селектор * здесь НЕ применяем, хотя соблазн велик.
   При переходе браузер выносит каждый анимируемый элемент на отдельный слой
   и меняет способ сглаживания шрифта: текст перерисовывается другой толщиной,
   а в конце возвращается обратно. Когда таких элементов сотни, это видно
   как резкие скачки шрифта по всей странице.
   Поэтому анимируем считанные элементы. Цвет текста наследуется, так что
   достаточно вести его у body - весь вложенный текст перекрасится сам,
   не попадая при этом под анимацию и не теряя сглаживания.
   Прозрачность вдобавок интерполируется через чёрный, поэтому фон трогаем
   только там, где он действительно задан. */
/* Чекбоксы рисуем сами, а не отдаём браузеру.
   Нативный чекбокс красится по color-scheme, а её мы намеренно переключаем в
   самом конце перехода темы (иначе браузер перерисовывает весь текст и шрифт
   скачет). Из-за этого чекбоксы меняли цвет через секунду после всего
   остального. Свои цвета едут вместе со страницей: они из тех же токенов. */
input[type=checkbox]{
  -webkit-appearance:none;appearance:none;
  width:16px;height:16px;flex:0 0 auto;margin:0;padding:0;
  border:1.5px solid var(--line2);border-radius:5px;background:var(--field);
  cursor:pointer;vertical-align:-3px;
  background-repeat:no-repeat;background-position:center;background-size:11px 11px;
}
input[type=checkbox]:hover{border-color:var(--accent)}
input[type=checkbox]:checked{
  background-color:var(--accent);border-color:var(--accent);
  /* белая галочка; SVG внутри data: - CSP разрешает data: для картинок */
  background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='3.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 13l4 4L19 7'/%3E%3C/svg%3E");
}
input[type=checkbox]:focus-visible{outline:2px solid var(--accent);outline-offset:1px}
/* Неотключаемая галочка. Указание владельца 20.08: она нажата, но должна быть
   серой, чтобы человек видел - убрать нельзя, и не гадал, почему не нажимается.
   Оранжевая выглядела как обычный включённый выключатель. Курсор тоже меняем:
   он говорит то же самое до первого щелчка. */
input[type=checkbox]:disabled{
  cursor:not-allowed;border-color:var(--line2);
}
input[type=checkbox]:disabled:hover{border-color:var(--line2)}
input[type=checkbox]:checked:disabled{
  background-color:var(--muted);border-color:var(--muted);
}

html.theme-anim,
html.theme-anim body,
html.theme-anim .card,
html.theme-anim .panel,
html.theme-anim .btn,
html.theme-anim input,
html.theme-anim textarea,
html.theme-anim select,
html.theme-anim .sb,
html.theme-anim .sb-bot,
html.theme-anim .sb-credits,
html.theme-anim .sb-profile,
html.theme-anim .sb-topup,
html.theme-anim .sb-nav a,
html.theme-anim .sb-badge,
html.theme-anim .kb-table,
html.theme-anim .kb-tr,
html.theme-anim .kb-open,
html.theme-anim .kb-type,
html.theme-anim .kb-st,
html.theme-anim .kb-chip,
html.theme-anim .sec-item,
html.theme-anim .kb-size,
html.theme-anim .ca-toast{
  transition:background-color .9s ease, color .9s ease,
             border-color .9s ease !important;
}

/* Видимый фокус с клавиатуры. Дописано в КОНЕЦ файла намеренно: вставка блока
   в середину длинного списка селекторов уже ломала вёрстку целиком 31.07 -
   комментарий и правило разорвали список, и всей странице на секунду
   доставалось width:16px. Разбор в ops/DECISIONS.md.

   `:focus-visible`, а не `:focus`: кольцо нужно тому, кто ходит табом, и не
   нужно тому, кто нажал мышкой - иначе после каждого клика остаётся рамка,
   и её начинают убирать целиком, вместе с доступностью. */
a:focus-visible,
button:focus-visible,
[role="button"]:focus-visible,
input:focus-visible,
textarea:focus-visible,
select:focus-visible,
summary:focus-visible{
  outline:2px solid var(--accent);
  outline-offset:2px;
  border-radius:6px;
}

/* Уважаем системную настройку «меньше движения» */
@media (prefers-reduced-motion: reduce){
  html.theme-anim, html.theme-anim body, html.theme-anim .card, html.theme-anim .panel,
  html.theme-anim .btn, html.theme-anim input, html.theme-anim textarea,
  html.theme-anim select, html.theme-anim .sb, html.theme-anim .sb-bot, html.theme-anim .sb-credits,
  html.theme-anim .sb-profile, html.theme-anim .sb-topup, html.theme-anim .sb-nav a,
  html.theme-anim .sb-badge, html.theme-anim .kb-table, html.theme-anim .kb-tr,
  html.theme-anim .kb-open, html.theme-anim .kb-type, html.theme-anim .kb-st,
  html.theme-anim .kb-chip, html.theme-anim .sec-item, html.theme-anim .kb-size,
  html.theme-anim .ca-toast{ transition:none !important; }
}

/* Левое меню суперадминки. Рисуется скриптом на всех её страницах сразу
   (assets/superadmin.js), поэтому стили лежат здесь, а не в разметке одной
   из десяти страниц. Меню фиксированное: разделы длинные, и уезжающее
   вместе с таблицей меню заставляет скроллить вверх ради перехода. */
#sa-nav{position:fixed;left:0;top:0;bottom:0;width:210px;overflow-y:auto;z-index:40;
  background:var(--card);border-right:1px solid var(--line);
  padding:64px 10px 16px;display:flex;flex-direction:column;gap:2px}
#sa-nav a{display:block;padding:8px 12px;border-radius:9px;font-size:13px;
  color:var(--muted);text-decoration:none;line-height:1.35}
#sa-nav a:hover{background:var(--soft);color:var(--ink)}
#sa-nav a.on{background:var(--soft2);color:var(--ink);font-weight:600}
/* Метка непрочитанного на пункте меню. Красная и с числом: точка говорит
   «что-то есть», а число - сколько именно, и по нему сразу понятно, идти
   сейчас или потом.

   Стоит здесь по той же причине, что и само меню: до 21.08 правило `.badge`
   лежало в разметке ОДНОЙ страницы (superadmin/index.html), а меню рисуется
   на всех десяти. На главной метка была красной, на остальных - серым числом
   в строке, и выглядело это как «единица» в названии раздела. Замечено на
   кадре стейджа в тот же день, когда метку завели второму пункту. */
#sa-nav .badge{display:inline-block;min-width:18px;text-align:center;
  background:var(--red);color:#fff;border-radius:999px;padding:1px 6px;
  font-size:10.5px;font-weight:700;line-height:1.5;vertical-align:1px}
body.sa-with-nav{padding-left:210px}
@media (max-width:900px){
  /* На узком экране меню становится обычной строкой сверху: держать
     фиксированную колонку в 210px там, где вся ширина 360, нельзя. */
  #sa-nav{position:static;width:auto;flex-direction:row;flex-wrap:wrap;
    padding:10px 12px;border-right:0;border-bottom:1px solid var(--line)}
  body.sa-with-nav{padding-left:0}
}

/* ---------- Публичные страницы на узком экране ----------
   Замер 10.08 в браузере на живом проде: при ширине 375 главная
   раскладывалась на 977 пикселей - страница уезжала боком в два с половиной
   раза. Виноваты были не блоки, а шапка и футер: flex без переноса, и меню
   с кнопками рядом не влезали никуда уже. Медиазапросов на публичных
   страницах не было ни одного, кроме одного на /faq/.

   Почему `!important`: вёрстка публичных страниц лежит в атрибутах `style`,
   а атрибут сильнее любого правила из файла. Переделывать двенадцать страниц
   на классы ради этого - работа на день и риск на неделю.

   Почему через `body.pub`: тот же файл читают кабинет, суперадминка и виджет,
   и правило по одному тегу `header` задело бы их тоже. Класс стоит только
   на публичных страницах. */
@media (max-width:900px){
  /* Шапка и футер переносятся, отступы по бокам уменьшаются. */
  body.pub header, body.pub footer > div{
    flex-wrap:wrap!important;row-gap:12px!important}
  body.pub header{padding-left:16px!important;padding-right:16px!important}
  /* Меню шапки из этого правила исключено (23.08). Оно писалось для
     разметки другого времени, а по нынешней побеждало по силе правило
     выше: меню шапки переносилось на вторую строку вопреки заявленной
     прокрутке, и шапка занимала четверть экрана телефона. Остальным
     рядам перенос по-прежнему нужен. */
  body.pub header > div, body.pub header nav:not(.sn-nav), body.pub footer div{
    flex-wrap:wrap!important}
  body.pub header nav:not(.sn-nav){gap:14px!important}
  body.pub header > div:first-child{gap:16px!important}

  /* Секции и главный блок: отступы по бокам вместо сорока восьми. */
  body.pub section, body.pub main{
    padding-left:16px!important;padding-right:16px!important}

  /* Два столбца рядом на телефоне - это два нечитаемых столбца. Секции
     и их первые дети, которые были рядами, становятся колонками. Всё, что
     глубже, просто получает право на перенос: там кнопки и плашки, и им
     переноса достаточно. */
  body.pub section[style*="display:flex"],
  body.pub section > div[style*="display:flex"],
  body.pub main[style*="display:flex"]{
    flex-direction:column!important;align-items:stretch!important;
    gap:20px!important}
  /* Внутренним рядам нужен не перенос, а право сжаться: у flex-детей
     `min-width` по умолчанию `auto`, и длинная строка распирает ряд вместо
     того, чтобы перенестись внутри себя. Перенос здесь вредит: строка списка
     это «галочка - текст», и при переносе галочка остаётся одна на пустой
     строке. Так и вышло на первом кадре тарифов. */
  body.pub div[style*="display:flex"] > *{min-width:0}
  /* А вот ряды ссылок и кнопок переносить надо: сжимать их значит рвать
     подпись кнопки на три строки. */
  body.pub div[style*="display:flex"]:has(> a),
  body.pub div[style*="display:flex"]:has(> button){flex-wrap:wrap!important}

  /* Жёсткие ширины из макета - форма входа 380, отзыв рядом 300 - шире
     телефона. `max-width` не спорит с `width` за приоритет, а ограничивает
     его: элемент становится по меньшему из двух. Поэтому без !important -
     собственные `max-width:1120px` у секций остаются как были. */
  body.pub div, body.pub main, body.pub section, body.pub img,
  body.pub pre, body.pub textarea{max-width:100%}

  /* Одного `max-width` мало: у карточек вёрстка на content-box, и padding
     складывается с шириной сверху. Карточка входа - 380 плюс 36 с каждой
     стороны, то есть 452 при экране в 375. Замер: ops/mobile-probe.sh. */
  body.pub div, body.pub form, body.pub input, body.pub textarea,
  body.pub button, body.pub header, body.pub footer, body.pub main,
  body.pub section{box-sizing:border-box}

  /* Заголовок в 44 пикселя шрифтом Unbounded не влезает: слово
     «ИИ-консультант,» шире экрана телефона, и страница уезжала на восемь
     пикселей уже только из-за него. Замер в контейнере этого не видел, пока
     в нём блокировались шрифты Google - системный шрифт уже. */
  body.pub h1{font-size:clamp(25px,6.8vw,34px)!important;overflow-wrap:break-word}
  body.pub h2{font-size:clamp(21px,5.6vw,28px)!important;overflow-wrap:break-word}

}
/* Сетки карточек считаем отдельно от остального: четыре тарифа в ряд при
   ширине 375 - это полоски по семьдесят пикселей, а один столбец на планшете -
   растянутые на всю ширину карточки. Поэтому три ступени, а не две. */
/* Правила ловят сетку по ПОДСТРОКЕ инлайн-стиля, поэтому каждый новый вид
   записи нужно вписывать сюда руками. 19.08 на этом уехала главная: блок
   тарифов сменился на три карточки `repeat(3,1fr)`, которых в списке не было,
   и на 375px они торчали за край экрана. Ставите новую сетку на публичной
   странице - проверьте, что её запись здесь есть, или дайте ей свой класс. */
@media (max-width:600px){
  body.pub [style*="repeat(4,1fr)"],
  body.pub [style*="repeat(3,1fr)"],
  body.pub [style*="grid-template-columns:1fr 1fr"],
  body.pub [style*="grid-template-columns:1fr 1fr 1fr"]{
    grid-template-columns:1fr!important}
}
@media (min-width:601px) and (max-width:1100px){
  body.pub [style*="repeat(4,1fr)"],
  body.pub [style*="repeat(3,1fr)"],
  body.pub [style*="grid-template-columns:1fr 1fr 1fr"]{
    grid-template-columns:1fr 1fr!important}
}
@media (min-width:901px) and (max-width:1100px){
  body.pub section, body.pub main{
    padding-left:28px!important;padding-right:28px!important}
}

/* Выключенная кнопка должна выглядеть выключенной.
   Правил на `disabled` в файле не было вовсе, и погашенная кнопка ничем
   не отличалась от рабочей: человек нажимал и не понимал, почему ничего
   не происходит. Находка владельца 12.08 на кнопке «Новый проект» при
   исчерпанном тарифе - но касается это всех кнопок кабинета сразу.
   Курсор меняем тоже: он говорит о недоступности раньше, чем цвет. */
button:disabled, .btn:disabled, .sb-proj:disabled{
  opacity:.45; cursor:not-allowed; filter:grayscale(.35)}
/* Фон при наведении гасим ТОЛЬКО у кнопки в переключателе проектов: у неё
   базовый фон прозрачный, а при наведении подсвечивается, и вернуть его
   безопасно. Кнопкам с заливкой фон не трогаем вовсе - `inherit` брал фон
   родителя, кнопка сливалась со страницей и вместе с белым текстом
   пропадала. Находка владельца 12.08, моя же ошибка часом раньше. */
.sb-proj:disabled:hover{background:transparent}

/* Мессенджеры прячутся не здесь, а выше - с 1365 пикселей: они не помещались
   задолго до телефона. Правило было тут с отметкой 900, и полоса 901-1365
   оставалась сломанной. Телефон уходит следующим, ниже. */
@media(max-width:600px){
  .sn-phone{display:none}
}

/* ---------- Шапки таблиц ----------
   Задача владельца 21.08: шапка должна визуально отличаться от строк данных
   на ВСЕХ страницах, а не только на «Аналитике», где образец и появился.
   Иначе первая строка данных читается как продолжение заголовка - и в
   таблице клиентов, где строк много, глаз каждый раз спотыкается о неё.

   Здесь, а не в разметке каждой страницы: таблиц в суперадминке десять, и
   девять одинаковых копий этого правила однажды разъедутся - ровно так
   `.badge` жил в разметке одной страницы из десяти и на остальных был серым
   числом (21.08). Правило описывает ТОЛЬКО вид шапки. Сетка колонок
   остаётся у страницы: она у каждой своя, и общей быть не может.

   Две формы, потому что таблицы в проекте двух видов: настоящие `<table>`
   («Аналитика», «Сервер») и сетки из div'ов с классом `.thead` - их семь.
   Выглядеть они должны одинаково: человек не знает, из чего сделан экран.

   Селекторы нарочно усилены `html`. Без него правило проигрывает: у страниц
   есть своё `.thead,.trow{... font-size:12.5px}` - оно задаёт сетку колонок и
   обязано остаться, - объявлено оно ниже подключённого tokens.css и той же
   силы, поэтому побеждало. На кадре это выглядело так: на «Клиентах» шапка
   10,5 пикселя, на «Платежах» и «Моделях» - 12,5, то есть ровно того же
   кегля, что строки данных. Проверки этого не видят: правило в файле есть,
   а меряется computed style только на живой странице. Третий случай за две
   сессии, и лечится он силой правила, а не перестановкой строк. */
html thead th, html .thead{
  font-size:10.5px;
  font-weight:700;
  letter-spacing:.05em;
  text-transform:uppercase;
  color:var(--muted);
  background:var(--soft2);
  /* Двойная линия снизу - главное отличие от строк: у них линия обычная.
     Толщина, а не цвет: цвет в тёмной теме читается хуже. */
  border-bottom:2px solid var(--line2);
  /* Длинное слово в узкой колонке рвём ПО БУКВАМ - решение владельца 21.08:
     «пусть переносятся не по правилам, а по буквам, это не страшно».
     «РЕГИСТРАЦИ И» читается хуже, чем целое слово, но выбор здесь не между
     красотой и уродством, а между этим и разъехавшейся таблицей: в шапке
     клиентов тринадцать колонок, и перенос по словам заставил бы колонку
     раздаться под самое длинное слово, отняв место у данных.

     Раньше это правило стояло в разметке ОДНОЙ страницы и было её
     случайностью: на остальных таблицах длинное слово вело себя иначе.
     Теперь оно общее и осознанное. */
  overflow-wrap:anywhere;
}
thead th{text-align:left;padding:8px 10px}
